/** * @license * Cesium - https://github.com/CesiumGS/cesium * Version 1.144.0 * * Copyright 2011-2022 Cesium Contributors * * 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. * * Columbus View (Pat. Pend.) * * Portions licensed separately. * See https://github.com/CesiumGS/cesium/blob/main/LICENSE.md for full licensing details. */ "use strict"; var Cesium = (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a3, b) => (typeof require !== "undefined" ? require : a3)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); var __commonJS = (cb, mod) => function __require2() { try { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; } catch (e) { throw mod = 0, e; } }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // Build/InlineWorkers.js var require_InlineWorkers = __commonJS({ "Build/InlineWorkers.js"() { "use strict"; globalThis.CESIUM_WORKERS = atob("dmFyIENlc2l1bVdvcmtlcnMgPSAoKCkgPT4gewogIHZhciBfX2NyZWF0ZSA9IE9iamVjdC5jcmVhdGU7CiAgdmFyIF9fZGVmUHJvcCA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0eTsKICB2YXIgX19nZXRPd25Qcm9wRGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7CiAgdmFyIF9fZ2V0T3duUHJvcE5hbWVzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXM7CiAgdmFyIF9fZ2V0UHJvdG9PZiA9IE9iamVjdC5nZXRQcm90b3R5cGVPZjsKICB2YXIgX19oYXNPd25Qcm9wID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTsKICB2YXIgX19kZWZOb3JtYWxQcm9wID0gKG9iaiwga2V5LCB2YWx1ZSkgPT4ga2V5IGluIG9iaiA/IF9fZGVmUHJvcChvYmosIGtleSwgeyBlbnVtZXJhYmxlOiB0cnVlLCBjb25maWd1cmFibGU6IHRydWUsIHdyaXRhYmxlOiB0cnVlLCB2YWx1ZSB9KSA6IG9ialtrZXldID0gdmFsdWU7CiAgdmFyIF9fcmVxdWlyZSA9IC8qIEBfX1BVUkVfXyAqLyAoKHgyKSA9PiB0eXBlb2YgcmVxdWlyZSAhPT0gInVuZGVmaW5lZCIgPyByZXF1aXJlIDogdHlwZW9mIFByb3h5ICE9PSAidW5kZWZpbmVkIiA/IG5ldyBQcm94eSh4MiwgewogICAgZ2V0OiAoYTQsIGIyKSA9PiAodHlwZW9mIHJlcXVpcmUgIT09ICJ1bmRlZmluZWQiID8gcmVxdWlyZSA6IGE0KVtiMl0KICB9KSA6IHgyKShmdW5jdGlvbih4MikgewogICAgaWYgKHR5cGVvZiByZXF1aXJlICE9PSAidW5kZWZpbmVkIikgcmV0dXJuIHJlcXVpcmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTsKICAgIHRocm93IEVycm9yKCdEeW5hbWljIHJlcXVpcmUgb2YgIicgKyB4MiArICciIGlzIG5vdCBzdXBwb3J0ZWQnKTsKICB9KTsKICB2YXIgX19nbG9iID0gKG1hcCkgPT4gKHBhdGgpID0+IHsKICAgIHZhciBmbiA9IG1hcFtwYXRoXTsKICAgIGlmIChmbikgcmV0dXJuIGZuKCk7CiAgICB0aHJvdyBuZXcgRXJyb3IoIk1vZHVsZSBub3QgZm91bmQgaW4gYnVuZGxlOiAiICsgcGF0aCk7CiAgfTsKICB2YXIgX19lc20gPSAoZm4sIHJlcywgZXJyKSA9PiBmdW5jdGlvbiBfX2luaXQoKSB7CiAgICBpZiAoZXJyKSB0aHJvdyBlcnJbMF07CiAgICB0cnkgewogICAgICByZXR1cm4gZm4gJiYgKHJlcyA9ICgwLCBmbltfX2dldE93blByb3BOYW1lcyhmbilbMF1dKShmbiA9IDApKSwgcmVzOwogICAgfSBjYXRjaCAoZTIpIHsKICAgICAgdGhyb3cgZXJyID0gW2UyXSwgZTI7CiAgICB9CiAgfTsKICB2YXIgX19jb21tb25KUyA9IChjYiwgbW9kKSA9PiBmdW5jdGlvbiBfX3JlcXVpcmUyKCkgewogICAgdHJ5IHsKICAgICAgcmV0dXJuIG1vZCB8fCAoMCwgY2JbX19nZXRPd25Qcm9wTmFtZXMoY2IpWzBdXSkoKG1vZCA9IHsgZXhwb3J0czoge30gfSkuZXhwb3J0cywgbW9kKSwgbW9kLmV4cG9ydHM7CiAgICB9IGNhdGNoIChlMikgewogICAgICB0aHJvdyBtb2QgPSAwLCBlMjsKICAgIH0KICB9OwogIHZhciBfX2V4cG9ydCA9ICh0YXJnZXQsIGFsbCkgPT4gewogICAgZm9yICh2YXIgbmFtZSBpbiBhbGwpCiAgICAgIF9fZGVmUHJvcCh0YXJnZXQsIG5hbWUsIHsgZ2V0OiBhbGxbbmFtZV0sIGVudW1lcmFibGU6IHRydWUgfSk7CiAgfTsKICB2YXIgX19jb3B5UHJvcHMgPSAodG8sIGZyb20sIGV4Y2VwdCwgZGVzYykgPT4gewogICAgaWYgKGZyb20gJiYgdHlwZW9mIGZyb20gPT09ICJvYmplY3QiIHx8IHR5cGVvZiBmcm9tID09PSAiZnVuY3Rpb24iKSB7CiAgICAgIGZvciAobGV0IGtleSBvZiBfX2dldE93blByb3BOYW1lcyhmcm9tKSkKICAgICAgICBpZiAoIV9faGFzT3duUHJvcC5jYWxsKHRvLCBrZXkpICYmIGtleSAhPT0gZXhjZXB0KQogICAgICAgICAgX19kZWZQcm9wKHRvLCBrZXksIHsgZ2V0OiAoKSA9PiBmcm9tW2tleV0sIGVudW1lcmFibGU6ICEoZGVzYyA9IF9fZ2V0T3duUHJvcERlc2MoZnJvbSwga2V5KSkgfHwgZGVzYy5lbnVtZXJhYmxlIH0pOwogICAgfQogICAgcmV0dXJuIHRvOwogIH07CiAgdmFyIF9fdG9FU00gPSAobW9kLCBpc05vZGVNb2RlLCB0YXJnZXQpID0+ICh0YXJnZXQgPSBtb2QgIT0gbnVsbCA/IF9fY3JlYXRlKF9fZ2V0UHJvdG9PZihtb2QpKSA6IHt9LCBfX2NvcHlQcm9wcygKICAgIC8vIElmIHRoZSBpbXBvcnRlciBpcyBpbiBub2RlIGNvbXBhdGliaWxpdHkgbW9kZSBvciB0aGlzIGlzIG5vdCBhbiBFU00KICAgIC8vIGZpbGUgdGhhdCBoYXMgYmVlbiBjb252ZXJ0ZWQgdG8gYSBDb21tb25KUyBmaWxlIHVzaW5nIGEgQmFiZWwtCiAgICAvLyBjb21wYXRpYmxlIHRyYW5zZm9ybSAoaS5lLiAiX19lc01vZHVsZSIgaGFzIG5vdCBiZWVuIHNldCksIHRoZW4gc2V0CiAgICAvLyAiZGVmYXVsdCIgdG8gdGhlIENvbW1vbkpTICJtb2R1bGUuZXhwb3J0cyIgZm9yIG5vZGUgY29tcGF0aWJpbGl0eS4KICAgIGlzTm9kZU1vZGUgfHwgIW1vZCB8fCAhbW9kLl9fZXNNb2R1bGUgPyBfX2RlZlByb3AodGFyZ2V0LCAiZGVmYXVsdCIsIHsgdmFsdWU6IG1vZCwgZW51bWVyYWJsZTogdHJ1ZSB9KSA6IHRhcmdldCwKICAgIG1vZAogICkpOwogIHZhciBfX3RvQ29tbW9uSlMgPSAobW9kKSA9PiBfX2NvcHlQcm9wcyhfX2RlZlByb3Aoe30sICJfX2VzTW9kdWxlIiwgeyB2YWx1ZTogdHJ1ZSB9KSwgbW9kKTsKICB2YXIgX19wdWJsaWNGaWVsZCA9IChvYmosIGtleSwgdmFsdWUpID0+IF9fZGVmTm9ybWFsUHJvcChvYmosIHR5cGVvZiBrZXkgIT09ICJzeW1ib2wiID8ga2V5ICsgIiIgOiBrZXksIHZhbHVlKTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2RlZmluZWQuanMKICBmdW5jdGlvbiBkZWZpbmVkKHZhbHVlKSB7CiAgICByZXR1cm4gdmFsdWUgIT09IHZvaWQgMCAmJiB2YWx1ZSAhPT0gbnVsbDsKICB9CiAgdmFyIGRlZmluZWRfZGVmYXVsdDsKICB2YXIgaW5pdF9kZWZpbmVkID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9kZWZpbmVkLmpzIigpIHsKICAgICAgZGVmaW5lZF9kZWZhdWx0ID0gZGVmaW5lZDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0RldmVsb3BlckVycm9yLmpzCiAgZnVuY3Rpb24gRGV2ZWxvcGVyRXJyb3IobWVzc2FnZSkgewogICAgdGhpcy5uYW1lID0gIkRldmVsb3BlckVycm9yIjsKICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7CiAgICBsZXQgc3RhY2s7CiAgICB0cnkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoKTsKICAgIH0gY2F0Y2ggKGUyKSB7CiAgICAgIHN0YWNrID0gZTIuc3RhY2s7CiAgICB9CiAgICB0aGlzLnN0YWNrID0gc3RhY2s7CiAgfQogIHZhciBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0OwogIHZhciBpbml0X0RldmVsb3BlckVycm9yID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9EZXZlbG9wZXJFcnJvci5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KE9iamVjdC5jcmVhdGUpKSB7CiAgICAgICAgRGV2ZWxvcGVyRXJyb3IucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShFcnJvci5wcm90b3R5cGUpOwogICAgICAgIERldmVsb3BlckVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERldmVsb3BlckVycm9yOwogICAgICB9CiAgICAgIERldmVsb3BlckVycm9yLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uKCkgewogICAgICAgIGxldCBzdHIgPSBgJHt0aGlzLm5hbWV9OiAke3RoaXMubWVzc2FnZX1gOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGhpcy5zdGFjaykpIHsKICAgICAgICAgIHN0ciArPSBgCiR7dGhpcy5zdGFjay50b1N0cmluZygpfWA7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzdHI7CiAgICAgIH07CiAgICAgIERldmVsb3BlckVycm9yLnRocm93SW5zdGFudGlhdGlvbkVycm9yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yKAogICAgICAgICAgIlRoaXMgZnVuY3Rpb24gZGVmaW5lcyBhbiBpbnRlcmZhY2UgYW5kIHNob3VsZCBub3QgYmUgY2FsbGVkIGRpcmVjdGx5LiIKICAgICAgICApOwogICAgICB9OwogICAgICBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0ID0gRGV2ZWxvcGVyRXJyb3I7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DaGVjay5qcwogIGZ1bmN0aW9uIGdldFVuZGVmaW5lZEVycm9yTWVzc2FnZShuYW1lKSB7CiAgICByZXR1cm4gYCR7bmFtZX0gaXMgcmVxdWlyZWQsIGFjdHVhbCB2YWx1ZSB3YXMgdW5kZWZpbmVkYDsKICB9CiAgZnVuY3Rpb24gZ2V0RmFpbGVkVHlwZUVycm9yTWVzc2FnZShhY3R1YWwsIGV4cGVjdGVkLCBuYW1lKSB7CiAgICByZXR1cm4gYEV4cGVjdGVkICR7bmFtZX0gdG8gYmUgdHlwZW9mICR7ZXhwZWN0ZWR9LCBhY3R1YWwgdHlwZW9mIHdhcyAke2FjdHVhbH1gOwogIH0KICB2YXIgQ2hlY2ssIENoZWNrX2RlZmF1bHQ7CiAgdmFyIGluaXRfQ2hlY2sgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NoZWNrLmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgQ2hlY2sgPSB7fTsKICAgICAgQ2hlY2sudHlwZU9mID0ge307CiAgICAgIENoZWNrLmRlZmluZWQgPSBmdW5jdGlvbihuYW1lLCB0ZXN0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodGVzdCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KGdldFVuZGVmaW5lZEVycm9yTWVzc2FnZShuYW1lKSk7CiAgICAgICAgfQogICAgICB9OwogICAgICBDaGVjay50eXBlT2YuZnVuYyA9IGZ1bmN0aW9uKG5hbWUsIHRlc3QpIHsKICAgICAgICBpZiAodHlwZW9mIHRlc3QgIT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICBnZXRGYWlsZWRUeXBlRXJyb3JNZXNzYWdlKHR5cGVvZiB0ZXN0LCAiZnVuY3Rpb24iLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5zdHJpbmcgPSBmdW5jdGlvbihuYW1lLCB0ZXN0KSB7CiAgICAgICAgaWYgKHR5cGVvZiB0ZXN0ICE9PSAic3RyaW5nIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGdldEZhaWxlZFR5cGVFcnJvck1lc3NhZ2UodHlwZW9mIHRlc3QsICJzdHJpbmciLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIgPSBmdW5jdGlvbihuYW1lLCB0ZXN0KSB7CiAgICAgICAgaWYgKHR5cGVvZiB0ZXN0ICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGdldEZhaWxlZFR5cGVFcnJvck1lc3NhZ2UodHlwZW9mIHRlc3QsICJudW1iZXIiLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIubGVzc1RoYW4gPSBmdW5jdGlvbihuYW1lLCB0ZXN0LCBsaW1pdCkgewogICAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIobmFtZSwgdGVzdCk7CiAgICAgICAgaWYgKHRlc3QgPj0gbGltaXQpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICBgRXhwZWN0ZWQgJHtuYW1lfSB0byBiZSBsZXNzIHRoYW4gJHtsaW1pdH0sIGFjdHVhbCB2YWx1ZSB3YXMgJHt0ZXN0fWAKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9OwogICAgICBDaGVjay50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMgPSBmdW5jdGlvbihuYW1lLCB0ZXN0LCBsaW1pdCkgewogICAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIobmFtZSwgdGVzdCk7CiAgICAgICAgaWYgKHRlc3QgPiBsaW1pdCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGBFeHBlY3RlZCAke25hbWV9IHRvIGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAke2xpbWl0fSwgYWN0dWFsIHZhbHVlIHdhcyAke3Rlc3R9YAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW4gPSBmdW5jdGlvbihuYW1lLCB0ZXN0LCBsaW1pdCkgewogICAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIobmFtZSwgdGVzdCk7CiAgICAgICAgaWYgKHRlc3QgPD0gbGltaXQpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICBgRXhwZWN0ZWQgJHtuYW1lfSB0byBiZSBncmVhdGVyIHRoYW4gJHtsaW1pdH0sIGFjdHVhbCB2YWx1ZSB3YXMgJHt0ZXN0fWAKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9OwogICAgICBDaGVjay50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMgPSBmdW5jdGlvbihuYW1lLCB0ZXN0LCBsaW1pdCkgewogICAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIobmFtZSwgdGVzdCk7CiAgICAgICAgaWYgKHRlc3QgPCBsaW1pdCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGBFeHBlY3RlZCAke25hbWV9IHRvIGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAke2xpbWl0fSwgYWN0dWFsIHZhbHVlIHdhcyAke3Rlc3R9YAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5vYmplY3QgPSBmdW5jdGlvbihuYW1lLCB0ZXN0KSB7CiAgICAgICAgaWYgKHR5cGVvZiB0ZXN0ICE9PSAib2JqZWN0IikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGdldEZhaWxlZFR5cGVFcnJvck1lc3NhZ2UodHlwZW9mIHRlc3QsICJvYmplY3QiLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5ib29sID0gZnVuY3Rpb24obmFtZSwgdGVzdCkgewogICAgICAgIGlmICh0eXBlb2YgdGVzdCAhPT0gImJvb2xlYW4iKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgZ2V0RmFpbGVkVHlwZUVycm9yTWVzc2FnZSh0eXBlb2YgdGVzdCwgImJvb2xlYW4iLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5iaWdpbnQgPSBmdW5jdGlvbihuYW1lLCB0ZXN0KSB7CiAgICAgICAgaWYgKHR5cGVvZiB0ZXN0ICE9PSAiYmlnaW50IikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGdldEZhaWxlZFR5cGVFcnJvck1lc3NhZ2UodHlwZW9mIHRlc3QsICJiaWdpbnQiLCBuYW1lKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENoZWNrLnR5cGVPZi5udW1iZXIuZXF1YWxzID0gZnVuY3Rpb24obmFtZTEsIG5hbWUyLCB0ZXN0MSwgdGVzdDIpIHsKICAgICAgICBDaGVjay50eXBlT2YubnVtYmVyKG5hbWUxLCB0ZXN0MSk7CiAgICAgICAgQ2hlY2sudHlwZU9mLm51bWJlcihuYW1lMiwgdGVzdDIpOwogICAgICAgIGlmICh0ZXN0MSAhPT0gdGVzdDIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICBgJHtuYW1lMX0gbXVzdCBiZSBlcXVhbCB0byAke25hbWUyfSwgdGhlIGFjdHVhbCB2YWx1ZXMgYXJlICR7dGVzdDF9IGFuZCAke3Rlc3QyfWAKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9OwogICAgICBDaGVja19kZWZhdWx0ID0gQ2hlY2s7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXJzZW5uZS10d2lzdGVyL3NyYy9tZXJzZW5uZS10d2lzdGVyLmpzCiAgdmFyIHJlcXVpcmVfbWVyc2VubmVfdHdpc3RlciA9IF9fY29tbW9uSlMoewogICAgIm5vZGVfbW9kdWxlcy9tZXJzZW5uZS10d2lzdGVyL3NyYy9tZXJzZW5uZS10d2lzdGVyLmpzIihleHBvcnRzMiwgbW9kdWxlKSB7CiAgICAgIHZhciBNZXJzZW5uZVR3aXN0ZXIyID0gZnVuY3Rpb24oc2VlZCkgewogICAgICAgIGlmIChzZWVkID09IHZvaWQgMCkgewogICAgICAgICAgc2VlZCA9ICgvKiBAX19QVVJFX18gKi8gbmV3IERhdGUoKSkuZ2V0VGltZSgpOwogICAgICAgIH0KICAgICAgICB0aGlzLk4gPSA2MjQ7CiAgICAgICAgdGhpcy5NID0gMzk3OwogICAgICAgIHRoaXMuTUFUUklYX0EgPSAyNTY3NDgzNjE1OwogICAgICAgIHRoaXMuVVBQRVJfTUFTSyA9IDIxNDc0ODM2NDg7CiAgICAgICAgdGhpcy5MT1dFUl9NQVNLID0gMjE0NzQ4MzY0NzsKICAgICAgICB0aGlzLm10ID0gbmV3IEFycmF5KHRoaXMuTik7CiAgICAgICAgdGhpcy5tdGkgPSB0aGlzLk4gKyAxOwogICAgICAgIGlmIChzZWVkLmNvbnN0cnVjdG9yID09IEFycmF5KSB7CiAgICAgICAgICB0aGlzLmluaXRfYnlfYXJyYXkoc2VlZCwgc2VlZC5sZW5ndGgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLmluaXRfc2VlZChzZWVkKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIE1lcnNlbm5lVHdpc3RlcjIucHJvdG90eXBlLmluaXRfc2VlZCA9IGZ1bmN0aW9uKHMyKSB7CiAgICAgICAgdGhpcy5tdFswXSA9IHMyID4+PiAwOwogICAgICAgIGZvciAodGhpcy5tdGkgPSAxOyB0aGlzLm10aSA8IHRoaXMuTjsgdGhpcy5tdGkrKykgewogICAgICAgICAgdmFyIHMyID0gdGhpcy5tdFt0aGlzLm10aSAtIDFdIF4gdGhpcy5tdFt0aGlzLm10aSAtIDFdID4+PiAzMDsKICAgICAgICAgIHRoaXMubXRbdGhpcy5tdGldID0gKCgoczIgJiA0Mjk0OTAxNzYwKSA+Pj4gMTYpICogMTgxMjQzMzI1MyA8PCAxNikgKyAoczIgJiA2NTUzNSkgKiAxODEyNDMzMjUzICsgdGhpcy5tdGk7CiAgICAgICAgICB0aGlzLm10W3RoaXMubXRpXSA+Pj49IDA7CiAgICAgICAgfQogICAgICB9OwogICAgICBNZXJzZW5uZVR3aXN0ZXIyLnByb3RvdHlwZS5pbml0X2J5X2FycmF5ID0gZnVuY3Rpb24oaW5pdF9rZXksIGtleV9sZW5ndGgpIHsKICAgICAgICB2YXIgaTIsIGoyLCBrMjsKICAgICAgICB0aGlzLmluaXRfc2VlZCgxOTY1MDIxOCk7CiAgICAgICAgaTIgPSAxOwogICAgICAgIGoyID0gMDsKICAgICAgICBrMiA9IHRoaXMuTiA+IGtleV9sZW5ndGggPyB0aGlzLk4gOiBrZXlfbGVuZ3RoOwogICAgICAgIGZvciAoOyBrMjsgazItLSkgewogICAgICAgICAgdmFyIHMyID0gdGhpcy5tdFtpMiAtIDFdIF4gdGhpcy5tdFtpMiAtIDFdID4+PiAzMDsKICAgICAgICAgIHRoaXMubXRbaTJdID0gKHRoaXMubXRbaTJdIF4gKCgoczIgJiA0Mjk0OTAxNzYwKSA+Pj4gMTYpICogMTY2NDUyNSA8PCAxNikgKyAoczIgJiA2NTUzNSkgKiAxNjY0NTI1KSArIGluaXRfa2V5W2oyXSArIGoyOwogICAgICAgICAgdGhpcy5tdFtpMl0gPj4+PSAwOwogICAgICAgICAgaTIrKzsKICAgICAgICAgIGoyKys7CiAgICAgICAgICBpZiAoaTIgPj0gdGhpcy5OKSB7CiAgICAgICAgICAgIHRoaXMubXRbMF0gPSB0aGlzLm10W3RoaXMuTiAtIDFdOwogICAgICAgICAgICBpMiA9IDE7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoajIgPj0ga2V5X2xlbmd0aCkgajIgPSAwOwogICAgICAgIH0KICAgICAgICBmb3IgKGsyID0gdGhpcy5OIC0gMTsgazI7IGsyLS0pIHsKICAgICAgICAgIHZhciBzMiA9IHRoaXMubXRbaTIgLSAxXSBeIHRoaXMubXRbaTIgLSAxXSA+Pj4gMzA7CiAgICAgICAgICB0aGlzLm10W2kyXSA9ICh0aGlzLm10W2kyXSBeICgoKHMyICYgNDI5NDkwMTc2MCkgPj4+IDE2KSAqIDE1NjYwODM5NDEgPDwgMTYpICsgKHMyICYgNjU1MzUpICogMTU2NjA4Mzk0MSkgLSBpMjsKICAgICAgICAgIHRoaXMubXRbaTJdID4+Pj0gMDsKICAgICAgICAgIGkyKys7CiAgICAgICAgICBpZiAoaTIgPj0gdGhpcy5OKSB7CiAgICAgICAgICAgIHRoaXMubXRbMF0gPSB0aGlzLm10W3RoaXMuTiAtIDFdOwogICAgICAgICAgICBpMiA9IDE7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRoaXMubXRbMF0gPSAyMTQ3NDgzNjQ4OwogICAgICB9OwogICAgICBNZXJzZW5uZVR3aXN0ZXIyLnByb3RvdHlwZS5yYW5kb21faW50ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdmFyIHkyOwogICAgICAgIHZhciBtYWcwMSA9IG5ldyBBcnJheSgwLCB0aGlzLk1BVFJJWF9BKTsKICAgICAgICBpZiAodGhpcy5tdGkgPj0gdGhpcy5OKSB7CiAgICAgICAgICB2YXIga2s7CiAgICAgICAgICBpZiAodGhpcy5tdGkgPT0gdGhpcy5OICsgMSkKICAgICAgICAgICAgdGhpcy5pbml0X3NlZWQoNTQ4OSk7CiAgICAgICAgICBmb3IgKGtrID0gMDsga2sgPCB0aGlzLk4gLSB0aGlzLk07IGtrKyspIHsKICAgICAgICAgICAgeTIgPSB0aGlzLm10W2trXSAmIHRoaXMuVVBQRVJfTUFTSyB8IHRoaXMubXRba2sgKyAxXSAmIHRoaXMuTE9XRVJfTUFTSzsKICAgICAgICAgICAgdGhpcy5tdFtra10gPSB0aGlzLm10W2trICsgdGhpcy5NXSBeIHkyID4+PiAxIF4gbWFnMDFbeTIgJiAxXTsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAoOyBrayA8IHRoaXMuTiAtIDE7IGtrKyspIHsKICAgICAgICAgICAgeTIgPSB0aGlzLm10W2trXSAmIHRoaXMuVVBQRVJfTUFTSyB8IHRoaXMubXRba2sgKyAxXSAmIHRoaXMuTE9XRVJfTUFTSzsKICAgICAgICAgICAgdGhpcy5tdFtra10gPSB0aGlzLm10W2trICsgKHRoaXMuTSAtIHRoaXMuTildIF4geTIgPj4+IDEgXiBtYWcwMVt5MiAmIDFdOwogICAgICAgICAgfQogICAgICAgICAgeTIgPSB0aGlzLm10W3RoaXMuTiAtIDFdICYgdGhpcy5VUFBFUl9NQVNLIHwgdGhpcy5tdFswXSAmIHRoaXMuTE9XRVJfTUFTSzsKICAgICAgICAgIHRoaXMubXRbdGhpcy5OIC0gMV0gPSB0aGlzLm10W3RoaXMuTSAtIDFdIF4geTIgPj4+IDEgXiBtYWcwMVt5MiAmIDFdOwogICAgICAgICAgdGhpcy5tdGkgPSAwOwogICAgICAgIH0KICAgICAgICB5MiA9IHRoaXMubXRbdGhpcy5tdGkrK107CiAgICAgICAgeTIgXj0geTIgPj4+IDExOwogICAgICAgIHkyIF49IHkyIDw8IDcgJiAyNjM2OTI4NjQwOwogICAgICAgIHkyIF49IHkyIDw8IDE1ICYgNDAyMjczMDc1MjsKICAgICAgICB5MiBePSB5MiA+Pj4gMTg7CiAgICAgICAgcmV0dXJuIHkyID4+PiAwOwogICAgICB9OwogICAgICBNZXJzZW5uZVR3aXN0ZXIyLnByb3RvdHlwZS5yYW5kb21faW50MzEgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gdGhpcy5yYW5kb21faW50KCkgPj4+IDE7CiAgICAgIH07CiAgICAgIE1lcnNlbm5lVHdpc3RlcjIucHJvdG90eXBlLnJhbmRvbV9pbmNsID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMucmFuZG9tX2ludCgpICogKDEgLyA0Mjk0OTY3Mjk1KTsKICAgICAgfTsKICAgICAgTWVyc2VubmVUd2lzdGVyMi5wcm90b3R5cGUucmFuZG9tID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMucmFuZG9tX2ludCgpICogKDEgLyA0Mjk0OTY3Mjk2KTsKICAgICAgfTsKICAgICAgTWVyc2VubmVUd2lzdGVyMi5wcm90b3R5cGUucmFuZG9tX2V4Y2wgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gKHRoaXMucmFuZG9tX2ludCgpICsgMC41KSAqICgxIC8gNDI5NDk2NzI5Nik7CiAgICAgIH07CiAgICAgIE1lcnNlbm5lVHdpc3RlcjIucHJvdG90eXBlLnJhbmRvbV9sb25nID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdmFyIGE0ID0gdGhpcy5yYW5kb21faW50KCkgPj4+IDUsIGIyID0gdGhpcy5yYW5kb21faW50KCkgPj4+IDY7CiAgICAgICAgcmV0dXJuIChhNCAqIDY3MTA4ODY0ICsgYjIpICogKDEgLyA5MDA3MTk5MjU0NzQwOTkyKTsKICAgICAgfTsKICAgICAgbW9kdWxlLmV4cG9ydHMgPSBNZXJzZW5uZVR3aXN0ZXIyOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvTWF0aC5qcwogIHZhciBpbXBvcnRfbWVyc2VubmVfdHdpc3RlciwgQ2VzaXVtTWF0aCwgZmFjdG9yaWFscywgcmFuZG9tTnVtYmVyR2VuZXJhdG9yLCBNYXRoX2RlZmF1bHQ7CiAgdmFyIGluaXRfTWF0aCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvTWF0aC5qcyIoKSB7CiAgICAgIGltcG9ydF9tZXJzZW5uZV90d2lzdGVyID0gX190b0VTTShyZXF1aXJlX21lcnNlbm5lX3R3aXN0ZXIoKSwgMSk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgQ2VzaXVtTWF0aCA9IHt9OwogICAgICBDZXNpdW1NYXRoLkVQU0lMT04xID0gMC4xOwogICAgICBDZXNpdW1NYXRoLkVQU0lMT04yID0gMC4wMTsKICAgICAgQ2VzaXVtTWF0aC5FUFNJTE9OMyA9IDFlLTM7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjQgPSAxZS00OwogICAgICBDZXNpdW1NYXRoLkVQU0lMT041ID0gMWUtNTsKICAgICAgQ2VzaXVtTWF0aC5FUFNJTE9ONiA9IDFlLTY7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjcgPSAxZS03OwogICAgICBDZXNpdW1NYXRoLkVQU0lMT044ID0gMWUtODsKICAgICAgQ2VzaXVtTWF0aC5FUFNJTE9OOSA9IDFlLTk7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjEwID0gMWUtMTA7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjExID0gMWUtMTE7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjEyID0gMWUtMTI7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjEzID0gMWUtMTM7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE0ID0gMWUtMTQ7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE1ID0gMWUtMTU7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE2ID0gMWUtMTY7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE3ID0gMWUtMTc7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE4ID0gMWUtMTg7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjE5ID0gMWUtMTk7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjIwID0gMWUtMjA7CiAgICAgIENlc2l1bU1hdGguRVBTSUxPTjIxID0gMWUtMjE7CiAgICAgIENlc2l1bU1hdGguR1JBVklUQVRJT05BTFBBUkFNRVRFUiA9IDM5ODYwMDQ0MThlNTsKICAgICAgQ2VzaXVtTWF0aC5TT0xBUl9SQURJVVMgPSA2OTU1ZTU7CiAgICAgIENlc2l1bU1hdGguTFVOQVJfUkFESVVTID0gMTczNzQwMDsKICAgICAgQ2VzaXVtTWF0aC5TSVhUWV9GT1VSX0tJTE9CWVRFUyA9IDY0ICogMTAyNDsKICAgICAgQ2VzaXVtTWF0aC5GT1VSX0dJR0FCWVRFUyA9IDQgKiAxMDI0ICogMTAyNCAqIDEwMjQ7CiAgICAgIENlc2l1bU1hdGguc2lnbiA9IE1hdGguc2lnbiA/PyBmdW5jdGlvbiBzaWduKHZhbHVlKSB7CiAgICAgICAgdmFsdWUgPSArdmFsdWU7CiAgICAgICAgaWYgKHZhbHVlID09PSAwIHx8IHZhbHVlICE9PSB2YWx1ZSkgewogICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdmFsdWUgPiAwID8gMSA6IC0xOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLnNpZ25Ob3RaZXJvID0gZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICByZXR1cm4gdmFsdWUgPCAwID8gLTEgOiAxOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLnRvU05vcm0gPSBmdW5jdGlvbih2YWx1ZSwgcmFuZ2VNYXhpbXVtKSB7CiAgICAgICAgcmFuZ2VNYXhpbXVtID0gcmFuZ2VNYXhpbXVtID8/IDI1NTsKICAgICAgICByZXR1cm4gTWF0aC5yb3VuZCgKICAgICAgICAgIChDZXNpdW1NYXRoLmNsYW1wKHZhbHVlLCAtMSwgMSkgKiAwLjUgKyAwLjUpICogcmFuZ2VNYXhpbXVtCiAgICAgICAgKTsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5mcm9tU05vcm0gPSBmdW5jdGlvbih2YWx1ZSwgcmFuZ2VNYXhpbXVtKSB7CiAgICAgICAgcmFuZ2VNYXhpbXVtID0gcmFuZ2VNYXhpbXVtID8/IDI1NTsKICAgICAgICByZXR1cm4gQ2VzaXVtTWF0aC5jbGFtcCh2YWx1ZSwgMCwgcmFuZ2VNYXhpbXVtKSAvIHJhbmdlTWF4aW11bSAqIDIgLSAxOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKHZhbHVlLCByYW5nZU1pbmltdW0sIHJhbmdlTWF4aW11bSkgewogICAgICAgIHJhbmdlTWF4aW11bSA9IE1hdGgubWF4KHJhbmdlTWF4aW11bSAtIHJhbmdlTWluaW11bSwgMCk7CiAgICAgICAgcmV0dXJuIHJhbmdlTWF4aW11bSA9PT0gMCA/IDAgOiBDZXNpdW1NYXRoLmNsYW1wKCh2YWx1ZSAtIHJhbmdlTWluaW11bSkgLyByYW5nZU1heGltdW0sIDAsIDEpOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLnNpbmggPSBNYXRoLnNpbmggPz8gZnVuY3Rpb24gc2luaCh2YWx1ZSkgewogICAgICAgIHJldHVybiAoTWF0aC5leHAodmFsdWUpIC0gTWF0aC5leHAoLXZhbHVlKSkgLyAyOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmNvc2ggPSBNYXRoLmNvc2ggPz8gZnVuY3Rpb24gY29zaCh2YWx1ZSkgewogICAgICAgIHJldHVybiAoTWF0aC5leHAodmFsdWUpICsgTWF0aC5leHAoLXZhbHVlKSkgLyAyOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmxlcnAgPSBmdW5jdGlvbihwMiwgcTMsIHRpbWUpIHsKICAgICAgICByZXR1cm4gKDEgLSB0aW1lKSAqIHAyICsgdGltZSAqIHEzOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLnNtb290aERhbXAgPSBmdW5jdGlvbihwMiwgcTMsIHZlbG9jaXR5LCBkZWx0YVRpbWUgPSAwLCBtYXhpbXVtU3BlZWQgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksIHNtb290aFRpbWUgPSAxZS00LCByZXN1bHQgPSB7fSkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigicCIsIHAyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInEiLCBxMyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ2ZWxvY2l0eSIsIHZlbG9jaXR5KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiZGVsdGFUaW1lIiwgZGVsdGFUaW1lLCAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygibWF4aW11bVNwZWVkIiwgbWF4aW11bVNwZWVkLCAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygic21vb3RoVGltZSIsIHNtb290aFRpbWUsIDFlLTQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBzbW9vdGhUaW1lID0gTWF0aC5tYXgoMWUtNCwgc21vb3RoVGltZSk7CiAgICAgICAgY29uc3Qgb21lZ2EgPSAyIC8gc21vb3RoVGltZTsKICAgICAgICBjb25zdCB4MiA9IG9tZWdhICogZGVsdGFUaW1lOwogICAgICAgIGNvbnN0IGV4cCA9IDEgLyAoMSArIHgyICsgMC40OCAqIHgyICogeDIgKyAwLjIzNSAqIHgyICogeDIgKiB4Mik7CiAgICAgICAgY29uc3QgbWF4Q2hhbmdlID0gbWF4aW11bVNwZWVkICogc21vb3RoVGltZTsKICAgICAgICBsZXQgY2hhbmdlID0gcDIgLSBxMzsKICAgICAgICBjaGFuZ2UgPSBDZXNpdW1NYXRoLmNsYW1wKGNoYW5nZSwgLW1heENoYW5nZSwgbWF4Q2hhbmdlKTsKICAgICAgICBjb25zdCB0YXJnZXQgPSBwMiAtIGNoYW5nZTsKICAgICAgICBjb25zdCB0ZW1wID0gKHZlbG9jaXR5ICsgb21lZ2EgKiBjaGFuZ2UpICogZGVsdGFUaW1lOwogICAgICAgIHZlbG9jaXR5ID0gKHZlbG9jaXR5IC0gb21lZ2EgKiB0ZW1wKSAqIGV4cDsKICAgICAgICByZXN1bHQudmFsdWUgPSB0YXJnZXQgKyAoY2hhbmdlICsgdGVtcCkgKiBleHA7CiAgICAgICAgcmVzdWx0LnZlbG9jaXR5ID0gdmVsb2NpdHk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5QSSA9IE1hdGguUEk7CiAgICAgIENlc2l1bU1hdGguT05FX09WRVJfUEkgPSAxIC8gTWF0aC5QSTsKICAgICAgQ2VzaXVtTWF0aC5QSV9PVkVSX1RXTyA9IE1hdGguUEkgLyAyOwogICAgICBDZXNpdW1NYXRoLlBJX09WRVJfVEhSRUUgPSBNYXRoLlBJIC8gMzsKICAgICAgQ2VzaXVtTWF0aC5QSV9PVkVSX0ZPVVIgPSBNYXRoLlBJIC8gNDsKICAgICAgQ2VzaXVtTWF0aC5QSV9PVkVSX1NJWCA9IE1hdGguUEkgLyA2OwogICAgICBDZXNpdW1NYXRoLlRIUkVFX1BJX09WRVJfVFdPID0gMyAqIE1hdGguUEkgLyAyOwogICAgICBDZXNpdW1NYXRoLlRXT19QSSA9IDIgKiBNYXRoLlBJOwogICAgICBDZXNpdW1NYXRoLk9ORV9PVkVSX1RXT19QSSA9IDEgLyAoMiAqIE1hdGguUEkpOwogICAgICBDZXNpdW1NYXRoLlJBRElBTlNfUEVSX0RFR1JFRSA9IE1hdGguUEkgLyAxODA7CiAgICAgIENlc2l1bU1hdGguREVHUkVFU19QRVJfUkFESUFOID0gMTgwIC8gTWF0aC5QSTsKICAgICAgQ2VzaXVtTWF0aC5SQURJQU5TX1BFUl9BUkNTRUNPTkQgPSBDZXNpdW1NYXRoLlJBRElBTlNfUEVSX0RFR1JFRSAvIDM2MDA7CiAgICAgIENlc2l1bU1hdGgudG9SYWRpYW5zID0gZnVuY3Rpb24oZGVncmVlcykgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRlZ3JlZXMpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGVncmVlcyBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGRlZ3JlZXMgKiBDZXNpdW1NYXRoLlJBRElBTlNfUEVSX0RFR1JFRTsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC50b0RlZ3JlZXMgPSBmdW5jdGlvbihyYWRpYW5zKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmFkaWFucykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyYWRpYW5zIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmFkaWFucyAqIENlc2l1bU1hdGguREVHUkVFU19QRVJfUkFESUFOOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmNvbnZlcnRMb25naXR1ZGVSYW5nZSA9IGZ1bmN0aW9uKGFuZ2xlKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYW5nbGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYW5nbGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHR3b1BpID0gQ2VzaXVtTWF0aC5UV09fUEk7CiAgICAgICAgY29uc3Qgc2ltcGxpZmllZCA9IGFuZ2xlIC0gTWF0aC5mbG9vcihhbmdsZSAvIHR3b1BpKSAqIHR3b1BpOwogICAgICAgIGlmIChzaW1wbGlmaWVkIDwgLU1hdGguUEkpIHsKICAgICAgICAgIHJldHVybiBzaW1wbGlmaWVkICsgdHdvUGk7CiAgICAgICAgfQogICAgICAgIGlmIChzaW1wbGlmaWVkID49IE1hdGguUEkpIHsKICAgICAgICAgIHJldHVybiBzaW1wbGlmaWVkIC0gdHdvUGk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzaW1wbGlmaWVkOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmNsYW1wVG9MYXRpdHVkZVJhbmdlID0gZnVuY3Rpb24oYW5nbGUpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhbmdsZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhbmdsZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIENlc2l1bU1hdGguY2xhbXAoCiAgICAgICAgICBhbmdsZSwKICAgICAgICAgIC0xICogQ2VzaXVtTWF0aC5QSV9PVkVSX1RXTywKICAgICAgICAgIENlc2l1bU1hdGguUElfT1ZFUl9UV08KICAgICAgICApOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLm5lZ2F0aXZlUGlUb1BpID0gZnVuY3Rpb24oYW5nbGUpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhbmdsZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhbmdsZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKGFuZ2xlID49IC1DZXNpdW1NYXRoLlBJICYmIGFuZ2xlIDw9IENlc2l1bU1hdGguUEkpIHsKICAgICAgICAgIHJldHVybiBhbmdsZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIENlc2l1bU1hdGguemVyb1RvVHdvUGkoYW5nbGUgKyBDZXNpdW1NYXRoLlBJKSAtIENlc2l1bU1hdGguUEk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguemVyb1RvVHdvUGkgPSBmdW5jdGlvbihhbmdsZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFuZ2xlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFuZ2xlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoYW5nbGUgPj0gMCAmJiBhbmdsZSA8PSBDZXNpdW1NYXRoLlRXT19QSSkgewogICAgICAgICAgcmV0dXJuIGFuZ2xlOwogICAgICAgIH0KICAgICAgICBjb25zdCBtb2QgPSBDZXNpdW1NYXRoLm1vZChhbmdsZSwgQ2VzaXVtTWF0aC5UV09fUEkpOwogICAgICAgIGlmIChNYXRoLmFicyhtb2QpIDwgQ2VzaXVtTWF0aC5FUFNJTE9OMTQgJiYgTWF0aC5hYnMoYW5nbGUpID4gQ2VzaXVtTWF0aC5FUFNJTE9OMTQpIHsKICAgICAgICAgIHJldHVybiBDZXNpdW1NYXRoLlRXT19QSTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG1vZDsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5tb2QgPSBmdW5jdGlvbihtMiwgbjIpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtMikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJtIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChuMikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJuIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAobjIgPT09IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkaXZpc29yIGNhbm5vdCBiZSAwLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoQ2VzaXVtTWF0aC5zaWduKG0yKSA9PT0gQ2VzaXVtTWF0aC5zaWduKG4yKSAmJiBNYXRoLmFicyhtMikgPCBNYXRoLmFicyhuMikpIHsKICAgICAgICAgIHJldHVybiBtMjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIChtMiAlIG4yICsgbjIpICUgbjI7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguZXF1YWxzRXBzaWxvbiA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0LCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxlZnQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibGVmdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmlnaHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmlnaHQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJlbGF0aXZlRXBzaWxvbiA9IHJlbGF0aXZlRXBzaWxvbiA/PyAwOwogICAgICAgIGFic29sdXRlRXBzaWxvbiA9IGFic29sdXRlRXBzaWxvbiA/PyByZWxhdGl2ZUVwc2lsb247CiAgICAgICAgY29uc3QgYWJzRGlmZiA9IE1hdGguYWJzKGxlZnQgLSByaWdodCk7CiAgICAgICAgcmV0dXJuIGFic0RpZmYgPD0gYWJzb2x1dGVFcHNpbG9uIHx8IGFic0RpZmYgPD0gcmVsYXRpdmVFcHNpbG9uICogTWF0aC5tYXgoTWF0aC5hYnMobGVmdCksIE1hdGguYWJzKHJpZ2h0KSk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGgubGVzc1RoYW4gPSBmdW5jdGlvbihsZWZ0LCByaWdodCwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobGVmdCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJmaXJzdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmlnaHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgic2Vjb25kIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhYnNvbHV0ZUVwc2lsb24pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYWJzb2x1dGVFcHNpbG9uIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbGVmdCAtIHJpZ2h0IDwgLWFic29sdXRlRXBzaWxvbjsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5sZXNzVGhhbk9yRXF1YWxzID0gZnVuY3Rpb24obGVmdCwgcmlnaHQsIGFic29sdXRlRXBzaWxvbikgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxlZnQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZmlyc3QgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInNlY29uZCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYWJzb2x1dGVFcHNpbG9uKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFic29sdXRlRXBzaWxvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGxlZnQgLSByaWdodCA8IGFic29sdXRlRXBzaWxvbjsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5ncmVhdGVyVGhhbiA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0LCBhYnNvbHV0ZUVwc2lsb24pIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChsZWZ0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImZpcnN0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyaWdodCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzZWNvbmQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFic29sdXRlRXBzaWxvbikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhYnNvbHV0ZUVwc2lsb24gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBsZWZ0IC0gcmlnaHQgPiBhYnNvbHV0ZUVwc2lsb247CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguZ3JlYXRlclRoYW5PckVxdWFscyA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0LCBhYnNvbHV0ZUVwc2lsb24pIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChsZWZ0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImZpcnN0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyaWdodCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzZWNvbmQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFic29sdXRlRXBzaWxvbikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhYnNvbHV0ZUVwc2lsb24gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBsZWZ0IC0gcmlnaHQgPiAtYWJzb2x1dGVFcHNpbG9uOwogICAgICB9OwogICAgICBmYWN0b3JpYWxzID0gWzFdOwogICAgICBDZXNpdW1NYXRoLmZhY3RvcmlhbCA9IGZ1bmN0aW9uKG4yKSB7CiAgICAgICAgaWYgKHR5cGVvZiBuMiAhPT0gIm51bWJlciIgfHwgbjIgPCAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgIkEgbnVtYmVyIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAwIGlzIHJlcXVpcmVkLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGxlbmd0aCA9IGZhY3RvcmlhbHMubGVuZ3RoOwogICAgICAgIGlmIChuMiA+PSBsZW5ndGgpIHsKICAgICAgICAgIGxldCBzdW0gPSBmYWN0b3JpYWxzW2xlbmd0aCAtIDFdOwogICAgICAgICAgZm9yIChsZXQgaTIgPSBsZW5ndGg7IGkyIDw9IG4yOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IG5leHQgPSBzdW0gKiBpMjsKICAgICAgICAgICAgZmFjdG9yaWFscy5wdXNoKG5leHQpOwogICAgICAgICAgICBzdW0gPSBuZXh0OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFjdG9yaWFsc1tuMl07CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguaW5jcmVtZW50V3JhcCA9IGZ1bmN0aW9uKG4yLCBtYXhpbXVtVmFsdWUsIG1pbmltdW1WYWx1ZSkgewogICAgICAgIG1pbmltdW1WYWx1ZSA9IG1pbmltdW1WYWx1ZSA/PyAwOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG4yKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm4gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChtYXhpbXVtVmFsdWUgPD0gbWluaW11bVZhbHVlKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibWF4aW11bVZhbHVlIG11c3QgYmUgZ3JlYXRlciB0aGFuIG1pbmltdW1WYWx1ZS4iKTsKICAgICAgICB9CiAgICAgICAgKytuMjsKICAgICAgICBpZiAobjIgPiBtYXhpbXVtVmFsdWUpIHsKICAgICAgICAgIG4yID0gbWluaW11bVZhbHVlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbjI7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguaXNQb3dlck9mVHdvID0gZnVuY3Rpb24objIpIHsKICAgICAgICBpZiAodHlwZW9mIG4yICE9PSAibnVtYmVyIiB8fCBuMiA8IDAgfHwgbjIgPiA0Mjk0OTY3Mjk1KSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiQSBudW1iZXIgYmV0d2VlbiAwIGFuZCAoMl4zMiktMSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG4yICE9PSAwICYmIChuMiAmIG4yIC0gMSkgPT09IDA7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGgubmV4dFBvd2VyT2ZUd28gPSBmdW5jdGlvbihuMikgewogICAgICAgIGlmICh0eXBlb2YgbjIgIT09ICJudW1iZXIiIHx8IG4yIDwgMCB8fCBuMiA+IDIxNDc0ODM2NDgpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJBIG51bWJlciBiZXR3ZWVuIDAgYW5kIDJeMzEgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIC0tbjI7CiAgICAgICAgbjIgfD0gbjIgPj4gMTsKICAgICAgICBuMiB8PSBuMiA+PiAyOwogICAgICAgIG4yIHw9IG4yID4+IDQ7CiAgICAgICAgbjIgfD0gbjIgPj4gODsKICAgICAgICBuMiB8PSBuMiA+PiAxNjsKICAgICAgICArK24yOwogICAgICAgIHJldHVybiBuMjsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5wcmV2aW91c1Bvd2VyT2ZUd28gPSBmdW5jdGlvbihuMikgewogICAgICAgIGlmICh0eXBlb2YgbjIgIT09ICJudW1iZXIiIHx8IG4yIDwgMCB8fCBuMiA+IDQyOTQ5NjcyOTUpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJBIG51bWJlciBiZXR3ZWVuIDAgYW5kICgyXjMyKS0xIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBuMiB8PSBuMiA+PiAxOwogICAgICAgIG4yIHw9IG4yID4+IDI7CiAgICAgICAgbjIgfD0gbjIgPj4gNDsKICAgICAgICBuMiB8PSBuMiA+PiA4OwogICAgICAgIG4yIHw9IG4yID4+IDE2OwogICAgICAgIG4yIHw9IG4yID4+IDMyOwogICAgICAgIG4yID0gKG4yID4+PiAwKSAtIChuMiA+Pj4gMSk7CiAgICAgICAgcmV0dXJuIG4yOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmNsYW1wID0gZnVuY3Rpb24odmFsdWUsIG1pbjMsIG1heDMpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibWluIiwgbWluMyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJtYXgiLCBtYXgzKTsKICAgICAgICByZXR1cm4gdmFsdWUgPCBtaW4zID8gbWluMyA6IHZhbHVlID4gbWF4MyA/IG1heDMgOiB2YWx1ZTsKICAgICAgfTsKICAgICAgcmFuZG9tTnVtYmVyR2VuZXJhdG9yID0gbmV3IGltcG9ydF9tZXJzZW5uZV90d2lzdGVyLmRlZmF1bHQoKTsKICAgICAgQ2VzaXVtTWF0aC5zZXRSYW5kb21OdW1iZXJTZWVkID0gZnVuY3Rpb24oc2VlZCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHNlZWQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgic2VlZCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmFuZG9tTnVtYmVyR2VuZXJhdG9yID0gbmV3IGltcG9ydF9tZXJzZW5uZV90d2lzdGVyLmRlZmF1bHQoc2VlZCk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGgubmV4dFJhbmRvbU51bWJlciA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiByYW5kb21OdW1iZXJHZW5lcmF0b3IucmFuZG9tKCk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGgucmFuZG9tQmV0d2VlbiA9IGZ1bmN0aW9uKG1pbjMsIG1heDMpIHsKICAgICAgICByZXR1cm4gQ2VzaXVtTWF0aC5uZXh0UmFuZG9tTnVtYmVyKCkgKiAobWF4MyAtIG1pbjMpICsgbWluMzsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5hY29zQ2xhbXBlZCA9IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmFsdWUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmFsdWUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBNYXRoLmFjb3MoQ2VzaXVtTWF0aC5jbGFtcCh2YWx1ZSwgLTEsIDEpKTsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5hc2luQ2xhbXBlZCA9IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmFsdWUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmFsdWUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBNYXRoLmFzaW4oQ2VzaXVtTWF0aC5jbGFtcCh2YWx1ZSwgLTEsIDEpKTsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5jaG9yZExlbmd0aCA9IGZ1bmN0aW9uKGFuZ2xlLCByYWRpdXMpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhbmdsZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhbmdsZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmFkaXVzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJhZGl1cyBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIDIgKiByYWRpdXMgKiBNYXRoLnNpbihhbmdsZSAqIDAuNSk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGgubG9nQmFzZSA9IGZ1bmN0aW9uKG51bWJlciwgYmFzZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG51bWJlcikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJudW1iZXIgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJhc2UpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYmFzZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIE1hdGgubG9nKG51bWJlcikgLyBNYXRoLmxvZyhiYXNlKTsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5jYnJ0ID0gTWF0aC5jYnJ0ID8/IGZ1bmN0aW9uIGNicnQobnVtYmVyKSB7CiAgICAgICAgY29uc3QgcmVzdWx0ID0gTWF0aC5wb3coTWF0aC5hYnMobnVtYmVyKSwgMSAvIDMpOwogICAgICAgIHJldHVybiBudW1iZXIgPCAwID8gLXJlc3VsdCA6IHJlc3VsdDsKICAgICAgfTsKICAgICAgQ2VzaXVtTWF0aC5sb2cyID0gTWF0aC5sb2cyID8/IGZ1bmN0aW9uIGxvZzIobnVtYmVyKSB7CiAgICAgICAgcmV0dXJuIE1hdGgubG9nKG51bWJlcikgKiBNYXRoLkxPRzJFOwogICAgICB9OwogICAgICBDZXNpdW1NYXRoLmZvZyA9IGZ1bmN0aW9uKGRpc3RhbmNlVG9DYW1lcmEsIGRlbnNpdHkpIHsKICAgICAgICBjb25zdCBzY2FsYXIgPSBkaXN0YW5jZVRvQ2FtZXJhICogZGVuc2l0eTsKICAgICAgICByZXR1cm4gMSAtIE1hdGguZXhwKC0oc2NhbGFyICogc2NhbGFyKSk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguZmFzdEFwcHJveGltYXRlQXRhbiA9IGZ1bmN0aW9uKHgyKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ4IiwgeDIpOwogICAgICAgIHJldHVybiB4MiAqICgtMC4xNzg0ICogTWF0aC5hYnMoeDIpIC0gMC4wNjYzICogeDIgKiB4MiArIDEuMDMwMSk7CiAgICAgIH07CiAgICAgIENlc2l1bU1hdGguZmFzdEFwcHJveGltYXRlQXRhbjIgPSBmdW5jdGlvbih4MiwgeTIpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIngiLCB4Mik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ5IiwgeTIpOwogICAgICAgIGxldCBvcHBvc2l0ZTsKICAgICAgICBsZXQgdDIgPSBNYXRoLmFicyh4Mik7CiAgICAgICAgb3Bwb3NpdGUgPSBNYXRoLmFicyh5Mik7CiAgICAgICAgY29uc3QgYWRqYWNlbnQgPSBNYXRoLm1heCh0Miwgb3Bwb3NpdGUpOwogICAgICAgIG9wcG9zaXRlID0gTWF0aC5taW4odDIsIG9wcG9zaXRlKTsKICAgICAgICBjb25zdCBvcHBvc2l0ZU92ZXJBZGphY2VudCA9IG9wcG9zaXRlIC8gYWRqYWNlbnQ7CiAgICAgICAgaWYgKGlzTmFOKG9wcG9zaXRlT3ZlckFkamFjZW50KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImVpdGhlciB4IG9yIHkgbXVzdCBiZSBub256ZXJvIik7CiAgICAgICAgfQogICAgICAgIHQyID0gQ2VzaXVtTWF0aC5mYXN0QXBwcm94aW1hdGVBdGFuKG9wcG9zaXRlT3ZlckFkamFjZW50KTsKICAgICAgICB0MiA9IE1hdGguYWJzKHkyKSA+IE1hdGguYWJzKHgyKSA/IENlc2l1bU1hdGguUElfT1ZFUl9UV08gLSB0MiA6IHQyOwogICAgICAgIHQyID0geDIgPCAwID8gQ2VzaXVtTWF0aC5QSSAtIHQyIDogdDI7CiAgICAgICAgdDIgPSB5MiA8IDAgPyAtdDIgOiB0MjsKICAgICAgICByZXR1cm4gdDI7CiAgICAgIH07CiAgICAgIE1hdGhfZGVmYXVsdCA9IENlc2l1bU1hdGg7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DYXJ0ZXNpYW4zLmpzCiAgdmFyIENhcnRlc2lhbjMsIGRpc3RhbmNlU2NyYXRjaCwgbGVycFNjcmF0Y2gsIGFuZ2xlQmV0d2VlblNjcmF0Y2gsIGFuZ2xlQmV0d2VlblNjcmF0Y2gyLCBtb3N0T3J0aG9nb25hbEF4aXNTY3JhdGNoLCBzY3JhdGNoTiwgc2NyYXRjaEssIENhcnRlc2lhbjNfZGVmYXVsdDsKICB2YXIgaW5pdF9DYXJ0ZXNpYW4zID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DYXJ0ZXNpYW4zLmpzIigpIHsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgQ2FydGVzaWFuMyA9IGNsYXNzIF9DYXJ0ZXNpYW4zIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3g9MC4wXSBUaGUgWCBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt5PTAuMF0gVGhlIFkgY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbej0wLjBdIFRoZSBaIGNvbXBvbmVudC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcih4MiwgeTIsIHoyKSB7CiAgICAgICAgICB0aGlzLnggPSB4MiA/PyAwOwogICAgICAgICAgdGhpcy55ID0geTIgPz8gMDsKICAgICAgICAgIHRoaXMueiA9IHoyID8/IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBTcGhlcmljYWwgaW50byBDYXJ0ZXNpYW4zIGNvb3JkaW5hdGVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtTcGhlcmljYWx9IHNwaGVyaWNhbCBUaGUgU3BoZXJpY2FsIHRvIGJlIGNvbnZlcnRlZCB0byBDYXJ0ZXNpYW4zLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21TcGhlcmljYWwoc3BoZXJpY2FsLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic3BoZXJpY2FsIiwgc3BoZXJpY2FsKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9DYXJ0ZXNpYW4zKCk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBjbG9jayA9IHNwaGVyaWNhbC5jbG9jazsKICAgICAgICAgIGNvbnN0IGNvbmUgPSBzcGhlcmljYWwuY29uZTsKICAgICAgICAgIGNvbnN0IG1hZ25pdHVkZSA9IHNwaGVyaWNhbC5tYWduaXR1ZGUgPz8gMTsKICAgICAgICAgIGNvbnN0IHJhZGlhbCA9IG1hZ25pdHVkZSAqIE1hdGguc2luKGNvbmUpOwogICAgICAgICAgcmVzdWx0LnggPSByYWRpYWwgKiBNYXRoLmNvcyhjbG9jayk7CiAgICAgICAgICByZXN1bHQueSA9IHJhZGlhbCAqIE1hdGguc2luKGNsb2NrKTsKICAgICAgICAgIHJlc3VsdC56ID0gbWFnbml0dWRlICogTWF0aC5jb3MoY29uZSk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgQ2FydGVzaWFuMyBpbnN0YW5jZSBmcm9tIHgsIHkgYW5kIHogY29vcmRpbmF0ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geCBUaGUgeCBjb29yZGluYXRlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IFRoZSB5IGNvb3JkaW5hdGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHogVGhlIHogY29vcmRpbmF0ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4zIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tRWxlbWVudHMoeDIsIHkyLCB6MiwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NhcnRlc2lhbjMoeDIsIHkyLCB6Mik7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJlc3VsdC56ID0gejI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIGEgQ2FydGVzaWFuMyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gdG8gZHVwbGljYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuIChSZXR1cm5zIHVuZGVmaW5lZCBpZiBjYXJ0ZXNpYW4gaXMgdW5kZWZpbmVkKQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjbG9uZShjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjYXJ0ZXNpYW4xMSkpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfQ2FydGVzaWFuMyhjYXJ0ZXNpYW4xMS54LCBjYXJ0ZXNpYW4xMS55LCBjYXJ0ZXNpYW4xMS56KTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0gY2FydGVzaWFuMTEueDsKICAgICAgICAgIHJlc3VsdC55ID0gY2FydGVzaWFuMTEueTsKICAgICAgICAgIHJlc3VsdC56ID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2UgaW50byB0aGUgcHJvdmlkZWQgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHZhbHVlIFRoZSB2YWx1ZSB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSB0byBwYWNrIGludG8uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBpbmRleCBpbnRvIHRoZSBhcnJheSBhdCB3aGljaCB0byBzdGFydCBwYWNraW5nIHRoZSBlbGVtZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIGFycmF5IHRoYXQgd2FzIHBhY2tlZCBpbnRvCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2sodmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUueDsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS55OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS56OwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4zIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQ2FydGVzaWFuMygpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0LnkgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0LnogPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEZsYXR0ZW5zIGFuIGFycmF5IG9mIENhcnRlc2lhbjNzIGludG8gYW4gYXJyYXkgb2YgY29tcG9uZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM1tdfSBhcnJheSBUaGUgYXJyYXkgb2YgY2FydGVzaWFucyB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtyZXN1bHRdIFRoZSBhcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuIElmIHRoaXMgaXMgYSB0eXBlZCBhcnJheSwgaXQgbXVzdCBoYXZlIGFycmF5Lmxlbmd0aCAqIDMgY29tcG9uZW50cywgZWxzZSBhIHtAbGluayBEZXZlbG9wZXJFcnJvcn0gd2lsbCBiZSB0aHJvd24uIElmIGl0IGlzIGEgcmVndWxhciBhcnJheSwgaXQgd2lsbCBiZSByZXNpemVkIHRvIGhhdmUgKGFycmF5Lmxlbmd0aCAqIDMpIGVsZW1lbnRzLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBjb25zdCByZXN1bHRMZW5ndGggPSBsZW5ndGggKiAzOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkocmVzdWx0TGVuZ3RoKTsKICAgICAgICAgIH0gZWxzZSBpZiAoIUFycmF5LmlzQXJyYXkocmVzdWx0KSAmJiByZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgIklmIHJlc3VsdCBpcyBhIHR5cGVkIGFycmF5LCBpdCBtdXN0IGhhdmUgZXhhY3RseSBhcnJheS5sZW5ndGggKiAzIGVsZW1lbnRzIgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IHJlc3VsdExlbmd0aDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgX0NhcnRlc2lhbjMucGFjayhhcnJheVtpMl0sIHJlc3VsdCwgaTIgKiAzKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFVucGFja3MgYW4gYXJyYXkgb2YgY2FydGVzaWFuIGNvbXBvbmVudHMgaW50byBhbiBhcnJheSBvZiBDYXJ0ZXNpYW4zcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSBvZiBjb21wb25lbnRzIHRvIHVucGFjay4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjNbXX0gW3Jlc3VsdF0gVGhlIGFycmF5IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM1tdfSBUaGUgdW5wYWNrZWQgYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiYXJyYXkubGVuZ3RoIiwgYXJyYXkubGVuZ3RoLCAzKTsKICAgICAgICAgIGlmIChhcnJheS5sZW5ndGggJSAzICE9PSAwKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBsZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDMuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShsZW5ndGggLyAzKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSBsZW5ndGggLyAzOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IGkyIC8gMzsKICAgICAgICAgICAgcmVzdWx0W2luZGV4XSA9IF9DYXJ0ZXNpYW4zLnVucGFjayhhcnJheSwgaTIsIHJlc3VsdFtpbmRleF0pOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHZhbHVlIG9mIHRoZSBtYXhpbXVtIGNvbXBvbmVudCBmb3IgdGhlIHN1cHBsaWVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBjYXJ0ZXNpYW4gdG8gdXNlLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSB2YWx1ZSBvZiB0aGUgbWF4aW11bSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1heGltdW1Db21wb25lbnQoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgcmV0dXJuIE1hdGgubWF4KGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnksIGNhcnRlc2lhbjExLnopOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgdmFsdWUgb2YgdGhlIG1pbmltdW0gY29tcG9uZW50IGZvciB0aGUgc3VwcGxpZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIGNhcnRlc2lhbiB0byB1c2UuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIHZhbHVlIG9mIHRoZSBtaW5pbXVtIGNvbXBvbmVudC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWluaW11bUNvbXBvbmVudChjYXJ0ZXNpYW4xMSkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICByZXR1cm4gTWF0aC5taW4oY2FydGVzaWFuMTEueCwgY2FydGVzaWFuMTEueSwgY2FydGVzaWFuMTEueik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHR3byBDYXJ0ZXNpYW5zIGFuZCBjb21wdXRlcyBhIENhcnRlc2lhbiB3aGljaCBjb250YWlucyB0aGUgbWluaW11bSBjb21wb25lbnRzIG9mIHRoZSBzdXBwbGllZCBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBmaXJzdCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gc2Vjb25kIEEgY2FydGVzaWFuIHRvIGNvbXBhcmUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IEEgY2FydGVzaWFuIHdpdGggdGhlIG1pbmltdW0gY29tcG9uZW50cy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWluaW11bUJ5Q29tcG9uZW50KGZpcnN0LCBzZWNvbmQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJmaXJzdCIsIGZpcnN0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic2Vjb25kIiwgc2Vjb25kKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gTWF0aC5taW4oZmlyc3QueCwgc2Vjb25kLngpOwogICAgICAgICAgcmVzdWx0LnkgPSBNYXRoLm1pbihmaXJzdC55LCBzZWNvbmQueSk7CiAgICAgICAgICByZXN1bHQueiA9IE1hdGgubWluKGZpcnN0LnosIHNlY29uZC56KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHR3byBDYXJ0ZXNpYW5zIGFuZCBjb21wdXRlcyBhIENhcnRlc2lhbiB3aGljaCBjb250YWlucyB0aGUgbWF4aW11bSBjb21wb25lbnRzIG9mIHRoZSBzdXBwbGllZCBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBmaXJzdCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gc2Vjb25kIEEgY2FydGVzaWFuIHRvIGNvbXBhcmUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IEEgY2FydGVzaWFuIHdpdGggdGhlIG1heGltdW0gY29tcG9uZW50cy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWF4aW11bUJ5Q29tcG9uZW50KGZpcnN0LCBzZWNvbmQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJmaXJzdCIsIGZpcnN0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic2Vjb25kIiwgc2Vjb25kKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gTWF0aC5tYXgoZmlyc3QueCwgc2Vjb25kLngpOwogICAgICAgICAgcmVzdWx0LnkgPSBNYXRoLm1heChmaXJzdC55LCBzZWNvbmQueSk7CiAgICAgICAgICByZXN1bHQueiA9IE1hdGgubWF4KGZpcnN0LnosIHNlY29uZC56KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnN0cmFpbiBhIHZhbHVlIHRvIGxpZSBiZXR3ZWVuIHR3byB2YWx1ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHZhbHVlIFRoZSB2YWx1ZSB0byBjbGFtcC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IG1pbiBUaGUgbWluaW11bSBib3VuZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IG1heCBUaGUgbWF4aW11bSBib3VuZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IGludG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIGNsYW1wZWQgdmFsdWUgc3VjaCB0aGF0IG1pbiA8PSB2YWx1ZSA8PSBtYXguCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsYW1wKHZhbHVlLCBtaW4zLCBtYXgzLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1pbiIsIG1pbjMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXgiLCBtYXgzKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHgyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLngsIG1pbjMueCwgbWF4My54KTsKICAgICAgICAgIGNvbnN0IHkyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLnksIG1pbjMueSwgbWF4My55KTsKICAgICAgICAgIGNvbnN0IHoyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLnosIG1pbjMueiwgbWF4My56KTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4ncyBzcXVhcmVkIG1hZ25pdHVkZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gaW5zdGFuY2Ugd2hvc2Ugc3F1YXJlZCBtYWduaXR1ZGUgaXMgdG8gYmUgY29tcHV0ZWQuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIHNxdWFyZWQgbWFnbml0dWRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtYWduaXR1ZGVTcXVhcmVkKGNhcnRlc2lhbjExKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIHJldHVybiBjYXJ0ZXNpYW4xMS54ICogY2FydGVzaWFuMTEueCArIGNhcnRlc2lhbjExLnkgKiBjYXJ0ZXNpYW4xMS55ICsgY2FydGVzaWFuMTEueiAqIGNhcnRlc2lhbjExLno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBDYXJ0ZXNpYW4ncyBtYWduaXR1ZGUgKGxlbmd0aCkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIGluc3RhbmNlIHdob3NlIG1hZ25pdHVkZSBpcyB0byBiZSBjb21wdXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbWFnbml0dWRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtYWduaXR1ZGUoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIHJldHVybiBNYXRoLnNxcnQoX0NhcnRlc2lhbjMubWFnbml0dWRlU3F1YXJlZChjYXJ0ZXNpYW4xMSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBsZWZ0IFRoZSBmaXJzdCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSBmcm9tLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHNlY29uZCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSB0by4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBSZXR1cm5zIDEuMAogICAgICAgICAqIGNvbnN0IGQgPSBDZXNpdW0uQ2FydGVzaWFuMy5kaXN0YW5jZShuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMS4wLCAwLjAsIDAuMCksIG5ldyBDZXNpdW0uQ2FydGVzaWFuMygyLjAsIDAuMCwgMC4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRpc3RhbmNlKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBfQ2FydGVzaWFuMy5zdWJ0cmFjdChsZWZ0LCByaWdodCwgZGlzdGFuY2VTY3JhdGNoKTsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuMy5tYWduaXR1ZGUoZGlzdGFuY2VTY3JhdGNoKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHNxdWFyZWQgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLiAgQ29tcGFyaW5nIHNxdWFyZWQgZGlzdGFuY2VzCiAgICAgICAgICogdXNpbmcgdGhpcyBmdW5jdGlvbiBpcyBtb3JlIGVmZmljaWVudCB0aGFuIGNvbXBhcmluZyBkaXN0YW5jZXMgdXNpbmcge0BsaW5rIENhcnRlc2lhbjMjZGlzdGFuY2V9LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBsZWZ0IFRoZSBmaXJzdCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSBmcm9tLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHNlY29uZCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSB0by4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBSZXR1cm5zIDQuMCwgbm90IDIuMAogICAgICAgICAqIGNvbnN0IGQgPSBDZXNpdW0uQ2FydGVzaWFuMy5kaXN0YW5jZVNxdWFyZWQobmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDEuMCwgMC4wLCAwLjApLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMy4wLCAwLjAsIDAuMCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXN0YW5jZVNxdWFyZWQobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIF9DYXJ0ZXNpYW4zLnN1YnRyYWN0KGxlZnQsIHJpZ2h0LCBkaXN0YW5jZVNjcmF0Y2gpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLm1hZ25pdHVkZVNxdWFyZWQoZGlzdGFuY2VTY3JhdGNoKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIG5vcm1hbGl6ZWQgZm9ybSBvZiB0aGUgc3VwcGxpZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBub3JtYWxpemVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbm9ybWFsaXplKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgbWFnbml0dWRlID0gX0NhcnRlc2lhbjMubWFnbml0dWRlKGNhcnRlc2lhbjExKTsKICAgICAgICAgIHJlc3VsdC54ID0gY2FydGVzaWFuMTEueCAvIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC55ID0gY2FydGVzaWFuMTEueSAvIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC56ID0gY2FydGVzaWFuMTEueiAvIG1hZ25pdHVkZTsKICAgICAgICAgIGlmIChpc05hTihyZXN1bHQueCkgfHwgaXNOYU4ocmVzdWx0LnkpIHx8IGlzTmFOKHJlc3VsdC56KSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibm9ybWFsaXplZCByZXN1bHQgaXMgbm90IGEgbnVtYmVyIik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgZG90IChzY2FsYXIpIHByb2R1Y3Qgb2YgdHdvIENhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGxlZnQgVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJpZ2h0IFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBkb3QgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZG90KGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICByZXR1cm4gbGVmdC54ICogcmlnaHQueCArIGxlZnQueSAqIHJpZ2h0LnkgKyBsZWZ0LnogKiByaWdodC56OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBwcm9kdWN0IG9mIHR3byBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBsZWZ0IFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByaWdodCBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5Q29tcG9uZW50cyhsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAqIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAqIHJpZ2h0Lnk7CiAgICAgICAgICByZXN1bHQueiA9IGxlZnQueiAqIHJpZ2h0Lno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBxdW90aWVudCBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVDb21wb25lbnRzKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gbGVmdC54IC8gcmlnaHQueDsKICAgICAgICAgIHJlc3VsdC55ID0gbGVmdC55IC8gcmlnaHQueTsKICAgICAgICAgIHJlc3VsdC56ID0gbGVmdC56IC8gcmlnaHQuejsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHN1bSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhZGQobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBsZWZ0LnggKyByaWdodC54OwogICAgICAgICAgcmVzdWx0LnkgPSBsZWZ0LnkgKyByaWdodC55OwogICAgICAgICAgcmVzdWx0LnogPSBsZWZ0LnogKyByaWdodC56OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGNvbXBvbmVudHdpc2UgZGlmZmVyZW5jZSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzdWJ0cmFjdChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAtIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAtIHJpZ2h0Lnk7CiAgICAgICAgICByZXN1bHQueiA9IGxlZnQueiAtIHJpZ2h0Lno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBzY2FsZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxhciBUaGUgc2NhbGFyIHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKGNhcnRlc2lhbjExLCBzY2FsYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxhciIsIHNjYWxhcik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLnggKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnkgKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQueiA9IGNhcnRlc2lhbjExLnogKiBzY2FsYXI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEaXZpZGVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBkaXZpZGVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXIgVGhlIHNjYWxhciB0byBkaXZpZGUgYnkuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVCeVNjYWxhcihjYXJ0ZXNpYW4xMSwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJzY2FsYXIiLCBzY2FsYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBjYXJ0ZXNpYW4xMS54IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LnkgPSBjYXJ0ZXNpYW4xMS55IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LnogPSBjYXJ0ZXNpYW4xMS56IC8gc2NhbGFyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTmVnYXRlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBuZWdhdGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbmVnYXRlKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSAtY2FydGVzaWFuMTEueDsKICAgICAgICAgIHJlc3VsdC55ID0gLWNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHQueiA9IC1jYXJ0ZXNpYW4xMS56OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHdob3NlIGFic29sdXRlIHZhbHVlIGlzIHRvIGJlIGNvbXB1dGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWJzKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBNYXRoLmFicyhjYXJ0ZXNpYW4xMS54KTsKICAgICAgICAgIHJlc3VsdC55ID0gTWF0aC5hYnMoY2FydGVzaWFuMTEueSk7CiAgICAgICAgICByZXN1bHQueiA9IE1hdGguYWJzKGNhcnRlc2lhbjExLnopOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGxpbmVhciBpbnRlcnBvbGF0aW9uIG9yIGV4dHJhcG9sYXRpb24gYXQgdCB1c2luZyB0aGUgcHJvdmlkZWQgY2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gc3RhcnQgVGhlIHZhbHVlIGNvcnJlc3BvbmRpbmcgdG8gdCBhdCAwLjAuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBlbmQgVGhlIHZhbHVlIGNvcnJlc3BvbmRpbmcgdG8gdCBhdCAxLjAuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHQgVGhlIHBvaW50IGFsb25nIHQgYXQgd2hpY2ggdG8gaW50ZXJwb2xhdGUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBsZXJwKHN0YXJ0LCBlbmQsIHQyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic3RhcnQiLCBzdGFydCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImVuZCIsIGVuZCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInQiLCB0Mik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBfQ2FydGVzaWFuMy5tdWx0aXBseUJ5U2NhbGFyKGVuZCwgdDIsIGxlcnBTY3JhdGNoKTsKICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW4zLm11bHRpcGx5QnlTY2FsYXIoc3RhcnQsIDEgLSB0MiwgcmVzdWx0KTsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuMy5hZGQobGVycFNjcmF0Y2gsIHJlc3VsdCwgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgYW5nbGUsIGluIHJhZGlhbnMsIGJldHdlZW4gdGhlIHByb3ZpZGVkIENhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGxlZnQgVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJpZ2h0IFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBhbmdsZSBiZXR3ZWVuIHRoZSBDYXJ0ZXNpYW5zLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhbmdsZUJldHdlZW4obGVmdCwgcmlnaHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIF9DYXJ0ZXNpYW4zLm5vcm1hbGl6ZShsZWZ0LCBhbmdsZUJldHdlZW5TY3JhdGNoKTsKICAgICAgICAgIF9DYXJ0ZXNpYW4zLm5vcm1hbGl6ZShyaWdodCwgYW5nbGVCZXR3ZWVuU2NyYXRjaDIpOwogICAgICAgICAgY29uc3QgY29zaW5lID0gX0NhcnRlc2lhbjMuZG90KGFuZ2xlQmV0d2VlblNjcmF0Y2gsIGFuZ2xlQmV0d2VlblNjcmF0Y2gyKTsKICAgICAgICAgIGNvbnN0IHNpbmUgPSBfQ2FydGVzaWFuMy5tYWduaXR1ZGUoCiAgICAgICAgICAgIF9DYXJ0ZXNpYW4zLmNyb3NzKAogICAgICAgICAgICAgIGFuZ2xlQmV0d2VlblNjcmF0Y2gsCiAgICAgICAgICAgICAgYW5nbGVCZXR3ZWVuU2NyYXRjaDIsCiAgICAgICAgICAgICAgYW5nbGVCZXR3ZWVuU2NyYXRjaAogICAgICAgICAgICApCiAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIE1hdGguYXRhbjIoc2luZSwgY29zaW5lKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgYXhpcyB0aGF0IGlzIG1vc3Qgb3J0aG9nb25hbCB0byB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiBvbiB3aGljaCB0byBmaW5kIHRoZSBtb3N0IG9ydGhvZ29uYWwgYXhpcy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1vc3Qgb3J0aG9nb25hbCBheGlzLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtb3N0T3J0aG9nb25hbEF4aXMoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBmMiA9IF9DYXJ0ZXNpYW4zLm5vcm1hbGl6ZShjYXJ0ZXNpYW4xMSwgbW9zdE9ydGhvZ29uYWxBeGlzU2NyYXRjaCk7CiAgICAgICAgICBfQ2FydGVzaWFuMy5hYnMoZjIsIGYyKTsKICAgICAgICAgIGlmIChmMi54IDw9IGYyLnkpIHsKICAgICAgICAgICAgaWYgKGYyLnggPD0gZjIueikgewogICAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW4zLmNsb25lKF9DYXJ0ZXNpYW4zLlVOSVRfWCwgcmVzdWx0KTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXN1bHQgPSBfQ2FydGVzaWFuMy5jbG9uZShfQ2FydGVzaWFuMy5VTklUX1osIHJlc3VsdCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAoZjIueSA8PSBmMi56KSB7CiAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW4zLmNsb25lKF9DYXJ0ZXNpYW4zLlVOSVRfWSwgcmVzdWx0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW4zLmNsb25lKF9DYXJ0ZXNpYW4zLlVOSVRfWiwgcmVzdWx0KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFByb2plY3RzIHZlY3RvciBhIG9udG8gdmVjdG9yIGIKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGEgVGhlIHZlY3RvciB0aGF0IG5lZWRzIHByb2plY3RpbmcKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGIgVGhlIHZlY3RvciB0byBwcm9qZWN0IG9udG8KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgcmVzdWx0IGNhcnRlc2lhbgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlcgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwcm9qZWN0VmVjdG9yKGE0LCBiMiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImEiLCBhNCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImIiLCBiMik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBzY2FsYXIgPSBfQ2FydGVzaWFuMy5kb3QoYTQsIGIyKSAvIF9DYXJ0ZXNpYW4zLmRvdChiMiwgYjIpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLm11bHRpcGx5QnlTY2FsYXIoYjIsIHNjYWxhciwgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIENhcnRlc2lhbnMgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbbGVmdF0gVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyaWdodF0gVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIGxlZnQgYW5kIHJpZ2h0IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgbGVmdC54ID09PSByaWdodC54ICYmIGxlZnQueSA9PT0gcmlnaHQueSAmJiBsZWZ0LnogPT09IHJpZ2h0Lno7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gb2Zmc2V0CiAgICAgICAgICogQGlnbm9yZQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHNBcnJheShjYXJ0ZXNpYW4xMSwgYXJyYXksIG9mZnNldCkgewogICAgICAgICAgcmV0dXJuIGNhcnRlc2lhbjExLnggPT09IGFycmF5W29mZnNldF0gJiYgY2FydGVzaWFuMTEueSA9PT0gYXJyYXlbb2Zmc2V0ICsgMV0gJiYgY2FydGVzaWFuMTEueiA9PT0gYXJyYXlbb2Zmc2V0ICsgMl07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW5zIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IHBhc3MgYW4gYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG9sZXJhbmNlIHRlc3QsCiAgICAgICAgICogPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW2xlZnRdIFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbcmlnaHRdIFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbcmVsYXRpdmVFcHNpbG9uPTBdIFRoZSByZWxhdGl2ZSBlcHNpbG9uIHRvbGVyYW5jZSB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFthYnNvbHV0ZUVwc2lsb249cmVsYXRpdmVFcHNpbG9uXSBUaGUgYWJzb2x1dGUgZXBzaWxvbiB0b2xlcmFuY2UgdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHNFcHNpbG9uKGxlZnQsIHJpZ2h0LCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBsZWZ0LngsCiAgICAgICAgICAgIHJpZ2h0LngsCiAgICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBsZWZ0LnksCiAgICAgICAgICAgIHJpZ2h0LnksCiAgICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBsZWZ0LnosCiAgICAgICAgICAgIHJpZ2h0LnosCiAgICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY3Jvc3MgKG91dGVyKSBwcm9kdWN0IG9mIHR3byBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBsZWZ0IFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByaWdodCBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIGNyb3NzIHByb2R1Y3QuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNyb3NzKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGxlZnRYID0gbGVmdC54OwogICAgICAgICAgY29uc3QgbGVmdFkgPSBsZWZ0Lnk7CiAgICAgICAgICBjb25zdCBsZWZ0WiA9IGxlZnQuejsKICAgICAgICAgIGNvbnN0IHJpZ2h0WCA9IHJpZ2h0Lng7CiAgICAgICAgICBjb25zdCByaWdodFkgPSByaWdodC55OwogICAgICAgICAgY29uc3QgcmlnaHRaID0gcmlnaHQuejsKICAgICAgICAgIGNvbnN0IHgyID0gbGVmdFkgKiByaWdodFogLSBsZWZ0WiAqIHJpZ2h0WTsKICAgICAgICAgIGNvbnN0IHkyID0gbGVmdFogKiByaWdodFggLSBsZWZ0WCAqIHJpZ2h0WjsKICAgICAgICAgIGNvbnN0IHoyID0gbGVmdFggKiByaWdodFkgLSBsZWZ0WSAqIHJpZ2h0WDsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBtaWRwb2ludCBiZXR3ZWVuIHRoZSByaWdodCBhbmQgbGVmdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBsZWZ0IFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByaWdodCBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1pZHBvaW50LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtaWRwb2ludChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IChsZWZ0LnggKyByaWdodC54KSAqIDAuNTsKICAgICAgICAgIHJlc3VsdC55ID0gKGxlZnQueSArIHJpZ2h0LnkpICogMC41OwogICAgICAgICAgcmVzdWx0LnogPSAobGVmdC56ICsgcmlnaHQueikgKiAwLjU7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGEgQ2FydGVzaWFuMyBwb3NpdGlvbiBmcm9tIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgdmFsdWVzIGdpdmVuIGluIGRlZ3JlZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbG9uZ2l0dWRlIFRoZSBsb25naXR1ZGUsIGluIGRlZ3JlZXMKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGF0aXR1ZGUgVGhlIGxhdGl0dWRlLCBpbiBkZWdyZWVzCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtoZWlnaHQ9MC4wXSBUaGUgaGVpZ2h0LCBpbiBtZXRlcnMsIGFib3ZlIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgb24gd2hpY2ggdGhlIHBvc2l0aW9uIGxpZXMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIHBvc2l0aW9uCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IHBvc2l0aW9uID0gQ2VzaXVtLkNhcnRlc2lhbjMuZnJvbURlZ3JlZXMoLTExNS4wLCAzNy4wKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbURlZ3JlZXMobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCBlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJsb25naXR1ZGUiLCBsb25naXR1ZGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJsYXRpdHVkZSIsIGxhdGl0dWRlKTsKICAgICAgICAgIGxvbmdpdHVkZSA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMobG9uZ2l0dWRlKTsKICAgICAgICAgIGxhdGl0dWRlID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhsYXRpdHVkZSk7CiAgICAgICAgICByZXR1cm4gX0NhcnRlc2lhbjMuZnJvbVJhZGlhbnMoCiAgICAgICAgICAgIGxvbmdpdHVkZSwKICAgICAgICAgICAgbGF0aXR1ZGUsCiAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICByZXN1bHQKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBDYXJ0ZXNpYW4zIHBvc2l0aW9uIGZyb20gbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSB2YWx1ZXMgZ2l2ZW4gaW4gcmFkaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsb25naXR1ZGUgVGhlIGxvbmdpdHVkZSwgaW4gcmFkaWFucwogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsYXRpdHVkZSBUaGUgbGF0aXR1ZGUsIGluIHJhZGlhbnMKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2hlaWdodD0wLjBdIFRoZSBoZWlnaHQsIGluIG1ldGVycywgYWJvdmUgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW2VsbGlwc29pZD1FbGxpcHNvaWQuZGVmYXVsdF0gVGhlIGVsbGlwc29pZCBvbiB3aGljaCB0aGUgcG9zaXRpb24gbGllcy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgcG9zaXRpb24KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgcG9zaXRpb24gPSBDZXNpdW0uQ2FydGVzaWFuMy5mcm9tUmFkaWFucygtMi4wMDcsIDAuNjQ1KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVJhZGlhbnMobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCBlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJsb25naXR1ZGUiLCBsb25naXR1ZGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJsYXRpdHVkZSIsIGxhdGl0dWRlKTsKICAgICAgICAgIGhlaWdodCA9IGhlaWdodCA/PyAwOwogICAgICAgICAgY29uc3QgcmFkaWlTcXVhcmVkID0gIWRlZmluZWRfZGVmYXVsdChlbGxpcHNvaWQpID8gX0NhcnRlc2lhbjMuX2VsbGlwc29pZFJhZGlpU3F1YXJlZCA6IGVsbGlwc29pZC5yYWRpaVNxdWFyZWQ7CiAgICAgICAgICBjb25zdCBjb3NMYXRpdHVkZSA9IE1hdGguY29zKGxhdGl0dWRlKTsKICAgICAgICAgIHNjcmF0Y2hOLnggPSBjb3NMYXRpdHVkZSAqIE1hdGguY29zKGxvbmdpdHVkZSk7CiAgICAgICAgICBzY3JhdGNoTi55ID0gY29zTGF0aXR1ZGUgKiBNYXRoLnNpbihsb25naXR1ZGUpOwogICAgICAgICAgc2NyYXRjaE4ueiA9IE1hdGguc2luKGxhdGl0dWRlKTsKICAgICAgICAgIHNjcmF0Y2hOID0gX0NhcnRlc2lhbjMubm9ybWFsaXplKHNjcmF0Y2hOLCBzY3JhdGNoTik7CiAgICAgICAgICBfQ2FydGVzaWFuMy5tdWx0aXBseUNvbXBvbmVudHMocmFkaWlTcXVhcmVkLCBzY3JhdGNoTiwgc2NyYXRjaEspOwogICAgICAgICAgY29uc3QgZ2FtbWEgPSBNYXRoLnNxcnQoX0NhcnRlc2lhbjMuZG90KHNjcmF0Y2hOLCBzY3JhdGNoSykpOwogICAgICAgICAgc2NyYXRjaEsgPSBfQ2FydGVzaWFuMy5kaXZpZGVCeVNjYWxhcihzY3JhdGNoSywgZ2FtbWEsIHNjcmF0Y2hLKTsKICAgICAgICAgIHNjcmF0Y2hOID0gX0NhcnRlc2lhbjMubXVsdGlwbHlCeVNjYWxhcihzY3JhdGNoTiwgaGVpZ2h0LCBzY3JhdGNoTik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQ2FydGVzaWFuMygpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLmFkZChzY3JhdGNoSywgc2NyYXRjaE4sIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2YgQ2FydGVzaWFuMyBwb3NpdGlvbnMgZ2l2ZW4gYW4gYXJyYXkgb2YgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSB2YWx1ZXMgZ2l2ZW4gaW4gZGVncmVlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGNvb3JkaW5hdGVzIEEgbGlzdCBvZiBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIHZhbHVlcy4gVmFsdWVzIGFsdGVybmF0ZSBbbG9uZ2l0dWRlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlLCBsYXRpdHVkZS4uLl0uCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgb24gd2hpY2ggdGhlIGNvb3JkaW5hdGVzIGxpZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjNbXX0gW3Jlc3VsdF0gQW4gYXJyYXkgb2YgQ2FydGVzaWFuMyBvYmplY3RzIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjNbXX0gVGhlIGFycmF5IG9mIHBvc2l0aW9ucy4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgcG9zaXRpb25zID0gQ2VzaXVtLkNhcnRlc2lhbjMuZnJvbURlZ3JlZXNBcnJheShbLTExNS4wLCAzNy4wLCAtMTA3LjAsIDMzLjBdKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbURlZ3JlZXNBcnJheShjb29yZGluYXRlcywgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY29vcmRpbmF0ZXMiLCBjb29yZGluYXRlcyk7CiAgICAgICAgICBpZiAoY29vcmRpbmF0ZXMubGVuZ3RoIDwgMiB8fCBjb29yZGluYXRlcy5sZW5ndGggJSAyICE9PSAwKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJ0aGUgbnVtYmVyIG9mIGNvb3JkaW5hdGVzIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAyIGFuZCBhdCBsZWFzdCAyIgogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbGVuZ3RoID0gY29vcmRpbmF0ZXMubGVuZ3RoOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkobGVuZ3RoIC8gMik7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoIC8gMjsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDIpIHsKICAgICAgICAgICAgY29uc3QgbG9uZ2l0dWRlID0gY29vcmRpbmF0ZXNbaTJdOwogICAgICAgICAgICBjb25zdCBsYXRpdHVkZSA9IGNvb3JkaW5hdGVzW2kyICsgMV07CiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gaTIgLyAyOwogICAgICAgICAgICByZXN1bHRbaW5kZXhdID0gX0NhcnRlc2lhbjMuZnJvbURlZ3JlZXMoCiAgICAgICAgICAgICAgbG9uZ2l0dWRlLAogICAgICAgICAgICAgIGxhdGl0dWRlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgIHJlc3VsdFtpbmRleF0KICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2YgQ2FydGVzaWFuMyBwb3NpdGlvbnMgZ2l2ZW4gYW4gYXJyYXkgb2YgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSB2YWx1ZXMgZ2l2ZW4gaW4gcmFkaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGNvb3JkaW5hdGVzIEEgbGlzdCBvZiBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIHZhbHVlcy4gVmFsdWVzIGFsdGVybmF0ZSBbbG9uZ2l0dWRlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlLCBsYXRpdHVkZS4uLl0uCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgb24gd2hpY2ggdGhlIGNvb3JkaW5hdGVzIGxpZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjNbXX0gW3Jlc3VsdF0gQW4gYXJyYXkgb2YgQ2FydGVzaWFuMyBvYmplY3RzIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjNbXX0gVGhlIGFycmF5IG9mIHBvc2l0aW9ucy4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgcG9zaXRpb25zID0gQ2VzaXVtLkNhcnRlc2lhbjMuZnJvbVJhZGlhbnNBcnJheShbLTIuMDA3LCAwLjY0NSwgLTEuODY3LCAuNTc1XSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21SYWRpYW5zQXJyYXkoY29vcmRpbmF0ZXMsIGVsbGlwc29pZCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImNvb3JkaW5hdGVzIiwgY29vcmRpbmF0ZXMpOwogICAgICAgICAgaWYgKGNvb3JkaW5hdGVzLmxlbmd0aCA8IDIgfHwgY29vcmRpbmF0ZXMubGVuZ3RoICUgMiAhPT0gMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgICAidGhlIG51bWJlciBvZiBjb29yZGluYXRlcyBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgMiBhbmQgYXQgbGVhc3QgMiIKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGNvb3JkaW5hdGVzLmxlbmd0aDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEFycmF5KGxlbmd0aCAvIDIpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IGxlbmd0aCAvIDI7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMiArPSAyKSB7CiAgICAgICAgICAgIGNvbnN0IGxvbmdpdHVkZSA9IGNvb3JkaW5hdGVzW2kyXTsKICAgICAgICAgICAgY29uc3QgbGF0aXR1ZGUgPSBjb29yZGluYXRlc1tpMiArIDFdOwogICAgICAgICAgICBjb25zdCBpbmRleCA9IGkyIC8gMjsKICAgICAgICAgICAgcmVzdWx0W2luZGV4XSA9IF9DYXJ0ZXNpYW4zLmZyb21SYWRpYW5zKAogICAgICAgICAgICAgIGxvbmdpdHVkZSwKICAgICAgICAgICAgICBsYXRpdHVkZSwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICByZXN1bHRbaW5kZXhdCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIENhcnRlc2lhbjMgcG9zaXRpb25zIGdpdmVuIGFuIGFycmF5IG9mIGxvbmdpdHVkZSwgbGF0aXR1ZGUgYW5kIGhlaWdodCB2YWx1ZXMgd2hlcmUgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBhcmUgZ2l2ZW4gaW4gZGVncmVlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGNvb3JkaW5hdGVzIEEgbGlzdCBvZiBsb25naXR1ZGUsIGxhdGl0dWRlIGFuZCBoZWlnaHQgdmFsdWVzLiBWYWx1ZXMgYWx0ZXJuYXRlIFtsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQsIGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGhlaWdodC4uLl0uCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgb24gd2hpY2ggdGhlIHBvc2l0aW9uIGxpZXMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zW119IFtyZXN1bHRdIEFuIGFycmF5IG9mIENhcnRlc2lhbjMgb2JqZWN0cyB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zW119IFRoZSBhcnJheSBvZiBwb3NpdGlvbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IHBvc2l0aW9ucyA9IENlc2l1bS5DYXJ0ZXNpYW4zLmZyb21EZWdyZWVzQXJyYXlIZWlnaHRzKFstMTE1LjAsIDM3LjAsIDEwMDAwMC4wLCAtMTA3LjAsIDMzLjAsIDE1MDAwMC4wXSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21EZWdyZWVzQXJyYXlIZWlnaHRzKGNvb3JkaW5hdGVzLCBlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjb29yZGluYXRlcyIsIGNvb3JkaW5hdGVzKTsKICAgICAgICAgIGlmIChjb29yZGluYXRlcy5sZW5ndGggPCAzIHx8IGNvb3JkaW5hdGVzLmxlbmd0aCAlIDMgIT09IDApIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgInRoZSBudW1iZXIgb2YgY29vcmRpbmF0ZXMgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDMgYW5kIGF0IGxlYXN0IDMiCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBjb29yZGluYXRlcy5sZW5ndGg7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShsZW5ndGggLyAzKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSBsZW5ndGggLyAzOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgICAgICBjb25zdCBsb25naXR1ZGUgPSBjb29yZGluYXRlc1tpMl07CiAgICAgICAgICAgIGNvbnN0IGxhdGl0dWRlID0gY29vcmRpbmF0ZXNbaTIgKyAxXTsKICAgICAgICAgICAgY29uc3QgaGVpZ2h0ID0gY29vcmRpbmF0ZXNbaTIgKyAyXTsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSBpMiAvIDM7CiAgICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBfQ2FydGVzaWFuMy5mcm9tRGVncmVlcygKICAgICAgICAgICAgICBsb25naXR1ZGUsCiAgICAgICAgICAgICAgbGF0aXR1ZGUsCiAgICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICByZXN1bHRbaW5kZXhdCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIENhcnRlc2lhbjMgcG9zaXRpb25zIGdpdmVuIGFuIGFycmF5IG9mIGxvbmdpdHVkZSwgbGF0aXR1ZGUgYW5kIGhlaWdodCB2YWx1ZXMgd2hlcmUgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBhcmUgZ2l2ZW4gaW4gcmFkaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGNvb3JkaW5hdGVzIEEgbGlzdCBvZiBsb25naXR1ZGUsIGxhdGl0dWRlIGFuZCBoZWlnaHQgdmFsdWVzLiBWYWx1ZXMgYWx0ZXJuYXRlIFtsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQsIGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGhlaWdodC4uLl0uCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgb24gd2hpY2ggdGhlIHBvc2l0aW9uIGxpZXMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zW119IFtyZXN1bHRdIEFuIGFycmF5IG9mIENhcnRlc2lhbjMgb2JqZWN0cyB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zW119IFRoZSBhcnJheSBvZiBwb3NpdGlvbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IHBvc2l0aW9ucyA9IENlc2l1bS5DYXJ0ZXNpYW4zLmZyb21SYWRpYW5zQXJyYXlIZWlnaHRzKFstMi4wMDcsIDAuNjQ1LCAxMDAwMDAuMCwgLTEuODY3LCAuNTc1LCAxNTAwMDAuMF0pOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUmFkaWFuc0FycmF5SGVpZ2h0cyhjb29yZGluYXRlcywgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY29vcmRpbmF0ZXMiLCBjb29yZGluYXRlcyk7CiAgICAgICAgICBpZiAoY29vcmRpbmF0ZXMubGVuZ3RoIDwgMyB8fCBjb29yZGluYXRlcy5sZW5ndGggJSAzICE9PSAwKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJ0aGUgbnVtYmVyIG9mIGNvb3JkaW5hdGVzIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzIGFuZCBhdCBsZWFzdCAzIgogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbGVuZ3RoID0gY29vcmRpbmF0ZXMubGVuZ3RoOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkobGVuZ3RoIC8gMyk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoIC8gMzsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDMpIHsKICAgICAgICAgICAgY29uc3QgbG9uZ2l0dWRlID0gY29vcmRpbmF0ZXNbaTJdOwogICAgICAgICAgICBjb25zdCBsYXRpdHVkZSA9IGNvb3JkaW5hdGVzW2kyICsgMV07CiAgICAgICAgICAgIGNvbnN0IGhlaWdodCA9IGNvb3JkaW5hdGVzW2kyICsgMl07CiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gaTIgLyAzOwogICAgICAgICAgICByZXN1bHRbaW5kZXhdID0gX0NhcnRlc2lhbjMuZnJvbVJhZGlhbnMoCiAgICAgICAgICAgICAgbG9uZ2l0dWRlLAogICAgICAgICAgICAgIGxhdGl0dWRlLAogICAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgcmVzdWx0W2luZGV4XQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyB0aGlzIENhcnRlc2lhbjMgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4zIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIGNsb25lKHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLmNsb25lKHRoaXMsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgQ2FydGVzaWFuIGFnYWluc3QgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhyaWdodCkgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLmVxdWFscyh0aGlzLCByaWdodCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgQ2FydGVzaWFuIGFnYWluc3QgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBwYXNzIGFuIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvbGVyYW5jZSB0ZXN0LAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtyZWxhdGl2ZUVwc2lsb249MF0gVGhlIHJlbGF0aXZlIGVwc2lsb24gdG9sZXJhbmNlIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Fic29sdXRlRXBzaWxvbj1yZWxhdGl2ZUVwc2lsb25dIFRoZSBhYnNvbHV0ZSBlcHNpbG9uIHRvbGVyYW5jZSB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHNFcHNpbG9uKHJpZ2h0LCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4zLmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIHRoaXMsCiAgICAgICAgICAgIHJpZ2h0LAogICAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBDYXJ0ZXNpYW4gaW4gdGhlIGZvcm1hdCAnKHgsIHksIHopJy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIENhcnRlc2lhbiBpbiB0aGUgZm9ybWF0ICcoeCwgeSwgeiknLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIGAoJHt0aGlzLnh9LCAke3RoaXMueX0sICR7dGhpcy56fSlgOwogICAgICAgIH0KICAgICAgfTsKICAgICAgQ2FydGVzaWFuMy5mcm9tQ2FydGVzaWFuNCA9IENhcnRlc2lhbjMuY2xvbmU7CiAgICAgIENhcnRlc2lhbjMucGFja2VkTGVuZ3RoID0gMzsKICAgICAgQ2FydGVzaWFuMy5mcm9tQXJyYXkgPSBDYXJ0ZXNpYW4zLnVucGFjazsKICAgICAgZGlzdGFuY2VTY3JhdGNoID0gbmV3IENhcnRlc2lhbjMoKTsKICAgICAgbGVycFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuMygpOwogICAgICBhbmdsZUJldHdlZW5TY3JhdGNoID0gbmV3IENhcnRlc2lhbjMoKTsKICAgICAgYW5nbGVCZXR3ZWVuU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuMygpOwogICAgICBtb3N0T3J0aG9nb25hbEF4aXNTY3JhdGNoID0gbmV3IENhcnRlc2lhbjMoKTsKICAgICAgc2NyYXRjaE4gPSBuZXcgQ2FydGVzaWFuMygpOwogICAgICBzY3JhdGNoSyA9IG5ldyBDYXJ0ZXNpYW4zKCk7CiAgICAgIENhcnRlc2lhbjMuX2VsbGlwc29pZFJhZGlpU3F1YXJlZCA9IG5ldyBDYXJ0ZXNpYW4zKAogICAgICAgIDYzNzgxMzcgKiA2Mzc4MTM3LAogICAgICAgIDYzNzgxMzcgKiA2Mzc4MTM3LAogICAgICAgIDYzNTY3NTIzMTQyNDUxNzllLTkgKiA2MzU2NzUyMzE0MjQ1MTc5ZS05CiAgICAgICk7CiAgICAgIENhcnRlc2lhbjMuWkVSTyA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjMoMCwgMCwgMCkpOwogICAgICBDYXJ0ZXNpYW4zLk9ORSA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjMoMSwgMSwgMSkpOwogICAgICBDYXJ0ZXNpYW4zLlVOSVRfWCA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjMoMSwgMCwgMCkpOwogICAgICBDYXJ0ZXNpYW4zLlVOSVRfWSA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjMoMCwgMSwgMCkpOwogICAgICBDYXJ0ZXNpYW4zLlVOSVRfWiA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjMoMCwgMCwgMSkpOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQgPSBDYXJ0ZXNpYW4zOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvc2NhbGVUb0dlb2RldGljU3VyZmFjZS5qcwogIGZ1bmN0aW9uIHNjYWxlVG9HZW9kZXRpY1N1cmZhY2UoY2FydGVzaWFuMTEsIG9uZU92ZXJSYWRpaSwgb25lT3ZlclJhZGlpU3F1YXJlZCwgY2VudGVyVG9sZXJhbmNlU3F1YXJlZCwgcmVzdWx0KSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjYXJ0ZXNpYW4xMSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNhcnRlc2lhbiBpcyByZXF1aXJlZC4iKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9uZU92ZXJSYWRpaSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9uZU92ZXJSYWRpaSBpcyByZXF1aXJlZC4iKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9uZU92ZXJSYWRpaVNxdWFyZWQpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvbmVPdmVyUmFkaWlTcXVhcmVkIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2VudGVyVG9sZXJhbmNlU3F1YXJlZCkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNlbnRlclRvbGVyYW5jZVNxdWFyZWQgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBjb25zdCBwb3NpdGlvblggPSBjYXJ0ZXNpYW4xMS54OwogICAgY29uc3QgcG9zaXRpb25ZID0gY2FydGVzaWFuMTEueTsKICAgIGNvbnN0IHBvc2l0aW9uWiA9IGNhcnRlc2lhbjExLno7CiAgICBjb25zdCBvbmVPdmVyUmFkaWlYID0gb25lT3ZlclJhZGlpLng7CiAgICBjb25zdCBvbmVPdmVyUmFkaWlZID0gb25lT3ZlclJhZGlpLnk7CiAgICBjb25zdCBvbmVPdmVyUmFkaWlaID0gb25lT3ZlclJhZGlpLno7CiAgICBjb25zdCB4MiA9IHBvc2l0aW9uWCAqIHBvc2l0aW9uWCAqIG9uZU92ZXJSYWRpaVggKiBvbmVPdmVyUmFkaWlYOwogICAgY29uc3QgeTIgPSBwb3NpdGlvblkgKiBwb3NpdGlvblkgKiBvbmVPdmVyUmFkaWlZICogb25lT3ZlclJhZGlpWTsKICAgIGNvbnN0IHoyID0gcG9zaXRpb25aICogcG9zaXRpb25aICogb25lT3ZlclJhZGlpWiAqIG9uZU92ZXJSYWRpaVo7CiAgICBjb25zdCBzcXVhcmVkTm9ybSA9IHgyICsgeTIgKyB6MjsKICAgIGNvbnN0IHJhdGlvID0gTWF0aC5zcXJ0KDEgLyBzcXVhcmVkTm9ybSk7CiAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgY2FydGVzaWFuMTEsCiAgICAgIHJhdGlvLAogICAgICBzY2FsZVRvR2VvZGV0aWNTdXJmYWNlSW50ZXJzZWN0aW9uCiAgICApOwogICAgaWYgKHNxdWFyZWROb3JtIDwgY2VudGVyVG9sZXJhbmNlU3F1YXJlZCkgewogICAgICByZXR1cm4gIWlzRmluaXRlKHJhdGlvKSA/IHZvaWQgMCA6IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShpbnRlcnNlY3Rpb24sIHJlc3VsdCk7CiAgICB9CiAgICBjb25zdCBvbmVPdmVyUmFkaWlTcXVhcmVkWCA9IG9uZU92ZXJSYWRpaVNxdWFyZWQueDsKICAgIGNvbnN0IG9uZU92ZXJSYWRpaVNxdWFyZWRZID0gb25lT3ZlclJhZGlpU3F1YXJlZC55OwogICAgY29uc3Qgb25lT3ZlclJhZGlpU3F1YXJlZFogPSBvbmVPdmVyUmFkaWlTcXVhcmVkLno7CiAgICBjb25zdCBncmFkaWVudCA9IHNjYWxlVG9HZW9kZXRpY1N1cmZhY2VHcmFkaWVudDsKICAgIGdyYWRpZW50LnggPSBpbnRlcnNlY3Rpb24ueCAqIG9uZU92ZXJSYWRpaVNxdWFyZWRYICogMjsKICAgIGdyYWRpZW50LnkgPSBpbnRlcnNlY3Rpb24ueSAqIG9uZU92ZXJSYWRpaVNxdWFyZWRZICogMjsKICAgIGdyYWRpZW50LnogPSBpbnRlcnNlY3Rpb24ueiAqIG9uZU92ZXJSYWRpaVNxdWFyZWRaICogMjsKICAgIGxldCBsYW1iZGEgPSAoMSAtIHJhdGlvKSAqIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoY2FydGVzaWFuMTEpIC8gKDAuNSAqIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoZ3JhZGllbnQpKTsKICAgIGxldCBjb3JyZWN0aW9uID0gMDsKICAgIGxldCBmdW5jOwogICAgbGV0IGRlbm9taW5hdG9yOwogICAgbGV0IHhNdWx0aXBsaWVyOwogICAgbGV0IHlNdWx0aXBsaWVyOwogICAgbGV0IHpNdWx0aXBsaWVyOwogICAgbGV0IHhNdWx0aXBsaWVyMjsKICAgIGxldCB5TXVsdGlwbGllcjI7CiAgICBsZXQgek11bHRpcGxpZXIyOwogICAgbGV0IHhNdWx0aXBsaWVyMzsKICAgIGxldCB5TXVsdGlwbGllcjM7CiAgICBsZXQgek11bHRpcGxpZXIzOwogICAgZG8gewogICAgICBsYW1iZGEgLT0gY29ycmVjdGlvbjsKICAgICAgeE11bHRpcGxpZXIgPSAxIC8gKDEgKyBsYW1iZGEgKiBvbmVPdmVyUmFkaWlTcXVhcmVkWCk7CiAgICAgIHlNdWx0aXBsaWVyID0gMSAvICgxICsgbGFtYmRhICogb25lT3ZlclJhZGlpU3F1YXJlZFkpOwogICAgICB6TXVsdGlwbGllciA9IDEgLyAoMSArIGxhbWJkYSAqIG9uZU92ZXJSYWRpaVNxdWFyZWRaKTsKICAgICAgeE11bHRpcGxpZXIyID0geE11bHRpcGxpZXIgKiB4TXVsdGlwbGllcjsKICAgICAgeU11bHRpcGxpZXIyID0geU11bHRpcGxpZXIgKiB5TXVsdGlwbGllcjsKICAgICAgek11bHRpcGxpZXIyID0gek11bHRpcGxpZXIgKiB6TXVsdGlwbGllcjsKICAgICAgeE11bHRpcGxpZXIzID0geE11bHRpcGxpZXIyICogeE11bHRpcGxpZXI7CiAgICAgIHlNdWx0aXBsaWVyMyA9IHlNdWx0aXBsaWVyMiAqIHlNdWx0aXBsaWVyOwogICAgICB6TXVsdGlwbGllcjMgPSB6TXVsdGlwbGllcjIgKiB6TXVsdGlwbGllcjsKICAgICAgZnVuYyA9IHgyICogeE11bHRpcGxpZXIyICsgeTIgKiB5TXVsdGlwbGllcjIgKyB6MiAqIHpNdWx0aXBsaWVyMiAtIDE7CiAgICAgIGRlbm9taW5hdG9yID0geDIgKiB4TXVsdGlwbGllcjMgKiBvbmVPdmVyUmFkaWlTcXVhcmVkWCArIHkyICogeU11bHRpcGxpZXIzICogb25lT3ZlclJhZGlpU3F1YXJlZFkgKyB6MiAqIHpNdWx0aXBsaWVyMyAqIG9uZU92ZXJSYWRpaVNxdWFyZWRaOwogICAgICBjb25zdCBkZXJpdmF0aXZlID0gLTIgKiBkZW5vbWluYXRvcjsKICAgICAgY29ycmVjdGlvbiA9IGZ1bmMgLyBkZXJpdmF0aXZlOwogICAgfSB3aGlsZSAoTWF0aC5hYnMoZnVuYykgPiBNYXRoX2RlZmF1bHQuRVBTSUxPTjEyKTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgcmV0dXJuIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoCiAgICAgICAgcG9zaXRpb25YICogeE11bHRpcGxpZXIsCiAgICAgICAgcG9zaXRpb25ZICogeU11bHRpcGxpZXIsCiAgICAgICAgcG9zaXRpb25aICogek11bHRpcGxpZXIKICAgICAgKTsKICAgIH0KICAgIHJlc3VsdC54ID0gcG9zaXRpb25YICogeE11bHRpcGxpZXI7CiAgICByZXN1bHQueSA9IHBvc2l0aW9uWSAqIHlNdWx0aXBsaWVyOwogICAgcmVzdWx0LnogPSBwb3NpdGlvblogKiB6TXVsdGlwbGllcjsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBzY2FsZVRvR2VvZGV0aWNTdXJmYWNlSW50ZXJzZWN0aW9uLCBzY2FsZVRvR2VvZGV0aWNTdXJmYWNlR3JhZGllbnQsIHNjYWxlVG9HZW9kZXRpY1N1cmZhY2VfZGVmYXVsdDsKICB2YXIgaW5pdF9zY2FsZVRvR2VvZGV0aWNTdXJmYWNlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9zY2FsZVRvR2VvZGV0aWNTdXJmYWNlLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBzY2FsZVRvR2VvZGV0aWNTdXJmYWNlSW50ZXJzZWN0aW9uID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY2FsZVRvR2VvZGV0aWNTdXJmYWNlR3JhZGllbnQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlVG9HZW9kZXRpY1N1cmZhY2VfZGVmYXVsdCA9IHNjYWxlVG9HZW9kZXRpY1N1cmZhY2U7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DYXJ0b2dyYXBoaWMuanMKICB2YXIgX0NhcnRvZ3JhcGhpYywgQ2FydG9ncmFwaGljLCBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY04sIGNhcnRlc2lhblRvQ2FydG9ncmFwaGljUCwgY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWNILCBDYXJ0b2dyYXBoaWNfZGVmYXVsdDsKICB2YXIgaW5pdF9DYXJ0b2dyYXBoaWMgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NhcnRvZ3JhcGhpYy5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKCk7CiAgICAgIF9DYXJ0b2dyYXBoaWMgPSBjbGFzcyBfQ2FydG9ncmFwaGljIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2xvbmdpdHVkZT0wLjBdIFRoZSBsb25naXR1ZGUsIGluIHJhZGlhbnMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtsYXRpdHVkZT0wLjBdIFRoZSBsYXRpdHVkZSwgaW4gcmFkaWFucy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2hlaWdodD0wLjBdIFRoZSBoZWlnaHQsIGluIG1ldGVycywgYWJvdmUgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcihsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQpIHsKICAgICAgICAgIHRoaXMubG9uZ2l0dWRlID0gbG9uZ2l0dWRlID8/IDA7CiAgICAgICAgICB0aGlzLmxhdGl0dWRlID0gbGF0aXR1ZGUgPz8gMDsKICAgICAgICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0ID8/IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgQ2FydG9ncmFwaGljIGluc3RhbmNlIGZyb20gbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZQogICAgICAgICAqIHNwZWNpZmllZCBpbiByYWRpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxvbmdpdHVkZSBUaGUgbG9uZ2l0dWRlLCBpbiByYWRpYW5zLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsYXRpdHVkZSBUaGUgbGF0aXR1ZGUsIGluIHJhZGlhbnMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtoZWlnaHQ9MC4wXSBUaGUgaGVpZ2h0LCBpbiBtZXRlcnMsIGFib3ZlIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVJhZGlhbnMobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibG9uZ2l0dWRlIiwgbG9uZ2l0dWRlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibGF0aXR1ZGUiLCBsYXRpdHVkZSk7CiAgICAgICAgICBoZWlnaHQgPSBoZWlnaHQgPz8gMDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfQ2FydG9ncmFwaGljKGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGhlaWdodCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gbG9uZ2l0dWRlOwogICAgICAgICAgcmVzdWx0LmxhdGl0dWRlID0gbGF0aXR1ZGU7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIG5ldyBDYXJ0b2dyYXBoaWMgaW5zdGFuY2UgZnJvbSBsb25naXR1ZGUgYW5kIGxhdGl0dWRlCiAgICAgICAgICogc3BlY2lmaWVkIGluIGRlZ3JlZXMuICBUaGUgdmFsdWVzIGluIHRoZSByZXN1bHRpbmcgb2JqZWN0IHdpbGwKICAgICAgICAgKiBiZSBpbiByYWRpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxvbmdpdHVkZSBUaGUgbG9uZ2l0dWRlLCBpbiBkZWdyZWVzLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsYXRpdHVkZSBUaGUgbGF0aXR1ZGUsIGluIGRlZ3JlZXMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtoZWlnaHQ9MC4wXSBUaGUgaGVpZ2h0LCBpbiBtZXRlcnMsIGFib3ZlIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbURlZ3JlZXMobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibG9uZ2l0dWRlIiwgbG9uZ2l0dWRlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibGF0aXR1ZGUiLCBsYXRpdHVkZSk7CiAgICAgICAgICBsb25naXR1ZGUgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKGxvbmdpdHVkZSk7CiAgICAgICAgICBsYXRpdHVkZSA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMobGF0aXR1ZGUpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0b2dyYXBoaWMuZnJvbVJhZGlhbnMobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBmcm9tIGEgQ2FydGVzaWFuIHBvc2l0aW9uLiBUaGUgdmFsdWVzIGluIHRoZQogICAgICAgICAqIHJlc3VsdGluZyBvYmplY3Qgd2lsbCBiZSBpbiByYWRpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiBwb3NpdGlvbiB0byBjb252ZXJ0IHRvIGNhcnRvZ3JhcGhpYyByZXByZXNlbnRhdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW2VsbGlwc29pZD1FbGxpcHNvaWQuZGVmYXVsdF0gVGhlIGVsbGlwc29pZCBvbiB3aGljaCB0aGUgcG9zaXRpb24gbGllcy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRvZ3JhcGhpY30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG5ldyBDYXJ0b2dyYXBoaWMgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQsIG9yIHVuZGVmaW5lZCBpZiB0aGUgY2FydGVzaWFuIGlzIGF0IHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUNhcnRlc2lhbihjYXJ0ZXNpYW4xMSwgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICAgIGNvbnN0IG9uZU92ZXJSYWRpaSA9IGRlZmluZWRfZGVmYXVsdChlbGxpcHNvaWQpID8gZWxsaXBzb2lkLm9uZU92ZXJSYWRpaSA6IF9DYXJ0b2dyYXBoaWMuX2VsbGlwc29pZE9uZU92ZXJSYWRpaTsKICAgICAgICAgIGNvbnN0IG9uZU92ZXJSYWRpaVNxdWFyZWQgPSBkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSA/IGVsbGlwc29pZC5vbmVPdmVyUmFkaWlTcXVhcmVkIDogX0NhcnRvZ3JhcGhpYy5fZWxsaXBzb2lkT25lT3ZlclJhZGlpU3F1YXJlZDsKICAgICAgICAgIGNvbnN0IGNlbnRlclRvbGVyYW5jZVNxdWFyZWQgPSBkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSA/IGVsbGlwc29pZC5fY2VudGVyVG9sZXJhbmNlU3F1YXJlZCA6IF9DYXJ0b2dyYXBoaWMuX2VsbGlwc29pZENlbnRlclRvbGVyYW5jZVNxdWFyZWQ7CiAgICAgICAgICBjb25zdCBwMiA9IHNjYWxlVG9HZW9kZXRpY1N1cmZhY2VfZGVmYXVsdCgKICAgICAgICAgICAgY2FydGVzaWFuMTEsCiAgICAgICAgICAgIG9uZU92ZXJSYWRpaSwKICAgICAgICAgICAgb25lT3ZlclJhZGlpU3F1YXJlZCwKICAgICAgICAgICAgY2VudGVyVG9sZXJhbmNlU3F1YXJlZCwKICAgICAgICAgICAgY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWNQCiAgICAgICAgICApOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDIpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgbjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlDb21wb25lbnRzKAogICAgICAgICAgICBwMiwKICAgICAgICAgICAgb25lT3ZlclJhZGlpU3F1YXJlZCwKICAgICAgICAgICAgY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWNOCiAgICAgICAgICApOwogICAgICAgICAgbjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG4yLCBuMik7CiAgICAgICAgICBjb25zdCBoMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjYXJ0ZXNpYW4xMSwgcDIsIGNhcnRlc2lhblRvQ2FydG9ncmFwaGljSCk7CiAgICAgICAgICBjb25zdCBsb25naXR1ZGUgPSBNYXRoLmF0YW4yKG4yLnksIG4yLngpOwogICAgICAgICAgY29uc3QgbGF0aXR1ZGUgPSBNYXRoLmFzaW4objIueik7CiAgICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoX2RlZmF1bHQuc2lnbihDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGgyLCBjYXJ0ZXNpYW4xMSkpICogQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShoMik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NhcnRvZ3JhcGhpYyhsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGxvbmdpdHVkZTsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IGxhdGl0dWRlOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgQ2FydGVzaWFuMyBpbnN0YW5jZSBmcm9tIGEgQ2FydG9ncmFwaGljIGlucHV0LiBUaGUgdmFsdWVzIGluIHRoZSBpbnB1dHRlZAogICAgICAgICAqIG9iamVjdCBzaG91bGQgYmUgaW4gcmFkaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBjYXJ0b2dyYXBoaWMgSW5wdXQgdG8gYmUgY29udmVydGVkIGludG8gYSBDYXJ0ZXNpYW4zIG91dHB1dC4KICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW2VsbGlwc29pZD1FbGxpcHNvaWQuZGVmYXVsdF0gVGhlIGVsbGlwc29pZCBvbiB3aGljaCB0aGUgcG9zaXRpb24gbGllcy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgcG9zaXRpb24KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdG9DYXJ0ZXNpYW4oY2FydG9ncmFwaGljMiwgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydG9ncmFwaGljIiwgY2FydG9ncmFwaGljMik7CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21SYWRpYW5zKAogICAgICAgICAgICBjYXJ0b2dyYXBoaWMyLmxvbmdpdHVkZSwKICAgICAgICAgICAgY2FydG9ncmFwaGljMi5sYXRpdHVkZSwKICAgICAgICAgICAgY2FydG9ncmFwaGljMi5oZWlnaHQsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIGEgQ2FydG9ncmFwaGljIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IGNhcnRvZ3JhcGhpYyBUaGUgY2FydG9ncmFwaGljIHRvIGR1cGxpY2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRvZ3JhcGhpY30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydG9ncmFwaGljIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLiAoUmV0dXJucyB1bmRlZmluZWQgaWYgY2FydG9ncmFwaGljIGlzIHVuZGVmaW5lZCkKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY2xvbmUoY2FydG9ncmFwaGljMiwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjYXJ0b2dyYXBoaWMyKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9DYXJ0b2dyYXBoaWMoCiAgICAgICAgICAgICAgY2FydG9ncmFwaGljMi5sb25naXR1ZGUsCiAgICAgICAgICAgICAgY2FydG9ncmFwaGljMi5sYXRpdHVkZSwKICAgICAgICAgICAgICBjYXJ0b2dyYXBoaWMyLmhlaWdodAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlOwogICAgICAgICAgcmVzdWx0LmxhdGl0dWRlID0gY2FydG9ncmFwaGljMi5sYXRpdHVkZTsKICAgICAgICAgIHJlc3VsdC5oZWlnaHQgPSBjYXJ0b2dyYXBoaWMyLmhlaWdodDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBjYXJ0b2dyYXBoaWNzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbbGVmdF0gVGhlIGZpcnN0IGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3JpZ2h0XSBUaGUgc2Vjb25kIGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgbGVmdCBhbmQgcmlnaHQgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHMobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBsZWZ0LmxvbmdpdHVkZSA9PT0gcmlnaHQubG9uZ2l0dWRlICYmIGxlZnQubGF0aXR1ZGUgPT09IHJpZ2h0LmxhdGl0dWRlICYmIGxlZnQuaGVpZ2h0ID09PSByaWdodC5oZWlnaHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBjYXJ0b2dyYXBoaWNzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sCiAgICAgICAgICogPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbbGVmdF0gVGhlIGZpcnN0IGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3JpZ2h0XSBUaGUgc2Vjb25kIGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MF0gVGhlIGVwc2lsb24gdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHNFcHNpbG9uKGxlZnQsIHJpZ2h0LCBlcHNpbG9uKSB7CiAgICAgICAgICBlcHNpbG9uID0gZXBzaWxvbiA/PyAwOwogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIE1hdGguYWJzKGxlZnQubG9uZ2l0dWRlIC0gcmlnaHQubG9uZ2l0dWRlKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnQubGF0aXR1ZGUgLSByaWdodC5sYXRpdHVkZSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0LmhlaWdodCAtIHJpZ2h0LmhlaWdodCkgPD0gZXBzaWxvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyB0aGlzIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfQ2FydG9ncmFwaGljLmNsb25lKHRoaXMsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBhZ2FpbnN0IHRoaXMgY2FydG9ncmFwaGljIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbcmlnaHRdIFRoZSBzZWNvbmQgY2FydG9ncmFwaGljLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzKHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gX0NhcnRvZ3JhcGhpYy5lcXVhbHModGhpcywgcmlnaHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgYWdhaW5zdCB0aGlzIGNhcnRvZ3JhcGhpYyBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3JpZ2h0XSBUaGUgc2Vjb25kIGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MF0gVGhlIGVwc2lsb24gdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFsc0Vwc2lsb24ocmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiBfQ2FydG9ncmFwaGljLmVxdWFsc0Vwc2lsb24odGhpcywgcmlnaHQsIGVwc2lsb24pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIGNhcnRvZ3JhcGhpYyBpbiB0aGUgZm9ybWF0ICcobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0KScuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHByb3ZpZGVkIGNhcnRvZ3JhcGhpYyBpbiB0aGUgZm9ybWF0ICcobG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0KScuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICByZXR1cm4gYCgke3RoaXMubG9uZ2l0dWRlfSwgJHt0aGlzLmxhdGl0dWRlfSwgJHt0aGlzLmhlaWdodH0pYDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIC8vIFRvIGF2b2lkIGNpcmN1bGFyIGRlcGVuZGVuY2llcywgdGhlc2UgYXJlIHNldCBieSBFbGxpcHNvaWQgd2hlbiBFbGxpcHNvaWQuZGVmYXVsdCBpcyBzZXQuCiAgICAgIF9fcHVibGljRmllbGQoX0NhcnRvZ3JhcGhpYywgIl9lbGxpcHNvaWRPbmVPdmVyUmFkaWkiLCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KAogICAgICAgIDEgLyA2Mzc4MTM3LAogICAgICAgIDEgLyA2Mzc4MTM3LAogICAgICAgIDEgLyA2MzU2NzUyMzE0MjQ1MTc5ZS05CiAgICAgICkpOwogICAgICBfX3B1YmxpY0ZpZWxkKF9DYXJ0b2dyYXBoaWMsICJfZWxsaXBzb2lkT25lT3ZlclJhZGlpU3F1YXJlZCIsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoCiAgICAgICAgMSAvICg2Mzc4MTM3ICogNjM3ODEzNyksCiAgICAgICAgMSAvICg2Mzc4MTM3ICogNjM3ODEzNyksCiAgICAgICAgMSAvICg2MzU2NzUyMzE0MjQ1MTc5ZS05ICogNjM1Njc1MjMxNDI0NTE3OWUtOSkKICAgICAgKSk7CiAgICAgIF9fcHVibGljRmllbGQoX0NhcnRvZ3JhcGhpYywgIl9lbGxpcHNvaWRDZW50ZXJUb2xlcmFuY2VTcXVhcmVkIiwgTWF0aF9kZWZhdWx0LkVQU0lMT04xKTsKICAgICAgQ2FydG9ncmFwaGljID0gX0NhcnRvZ3JhcGhpYzsKICAgICAgQ2FydG9ncmFwaGljLlpFUk8gPSBPYmplY3QuZnJlZXplKG5ldyBDYXJ0b2dyYXBoaWMoMCwgMCwgMCkpOwogICAgICBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY04gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhblRvQ2FydG9ncmFwaGljUCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWNIID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBDYXJ0b2dyYXBoaWNfZGVmYXVsdCA9IENhcnRvZ3JhcGhpYzsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NhcnRlc2lhbjIuanMKICB2YXIgQ2FydGVzaWFuMiwgZGlzdGFuY2VTY3JhdGNoMiwgbGVycFNjcmF0Y2gyLCBhbmdsZUJldHdlZW5TY3JhdGNoMywgYW5nbGVCZXR3ZWVuU2NyYXRjaDIyLCBtb3N0T3J0aG9nb25hbEF4aXNTY3JhdGNoMiwgQ2FydGVzaWFuMl9kZWZhdWx0OwogIHZhciBpbml0X0NhcnRlc2lhbjIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NhcnRlc2lhbjIuanMiKCkgewogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBDYXJ0ZXNpYW4yID0gY2xhc3MgX0NhcnRlc2lhbjIgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbeD0wLjBdIFRoZSBYIGNvbXBvbmVudC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3k9MC4wXSBUaGUgWSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3IoeDIsIHkyKSB7CiAgICAgICAgICB0aGlzLnggPSB4MiA/PyAwOwogICAgICAgICAgdGhpcy55ID0geTIgPz8gMDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIENhcnRlc2lhbjIgaW5zdGFuY2UgZnJvbSB4IGFuZCB5IGNvb3JkaW5hdGVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHggVGhlIHggY29vcmRpbmF0ZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geSBUaGUgeSBjb29yZGluYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjIgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21FbGVtZW50cyh4MiwgeTIsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9DYXJ0ZXNpYW4yKHgyLCB5Mik7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIER1cGxpY2F0ZXMgYSBDYXJ0ZXNpYW4yIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBkdXBsaWNhdGUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydGVzaWFuMiBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4gKFJldHVybnMgdW5kZWZpbmVkIGlmIGNhcnRlc2lhbiBpcyB1bmRlZmluZWQpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsb25lKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNhcnRlc2lhbjExKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9DYXJ0ZXNpYW4yKGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnkpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgcmVzdWx0LnkgPSBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU3RvcmVzIHRoZSBwcm92aWRlZCBpbnN0YW5jZSBpbnRvIHRoZSBwcm92aWRlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gdmFsdWUgVGhlIHZhbHVlIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIGFycmF5IHRvIHBhY2sgaW50by4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIGluZGV4IGludG8gdGhlIGFycmF5IGF0IHdoaWNoIHRvIHN0YXJ0IHBhY2tpbmcgdGhlIGVsZW1lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgYXJyYXkgdGhhdCB3YXMgcGFja2VkIGludG8KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFjayh2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS54OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS55OwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4yIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQ2FydGVzaWFuMigpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0LnkgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEZsYXR0ZW5zIGFuIGFycmF5IG9mIENhcnRlc2lhbjJzIGludG8gYW4gYXJyYXkgb2YgY29tcG9uZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMltdfSBhcnJheSBUaGUgYXJyYXkgb2YgY2FydGVzaWFucyB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtyZXN1bHRdIFRoZSBhcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuIElmIHRoaXMgaXMgYSB0eXBlZCBhcnJheSwgaXQgbXVzdCBoYXZlIGFycmF5Lmxlbmd0aCAqIDIgY29tcG9uZW50cywgZWxzZSBhIHtAbGluayBEZXZlbG9wZXJFcnJvcn0gd2lsbCBiZSB0aHJvd24uIElmIGl0IGlzIGEgcmVndWxhciBhcnJheSwgaXQgd2lsbCBiZSByZXNpemVkIHRvIGhhdmUgKGFycmF5Lmxlbmd0aCAqIDIpIGVsZW1lbnRzLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBjb25zdCByZXN1bHRMZW5ndGggPSBsZW5ndGggKiAyOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkocmVzdWx0TGVuZ3RoKTsKICAgICAgICAgIH0gZWxzZSBpZiAoIUFycmF5LmlzQXJyYXkocmVzdWx0KSAmJiByZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgIklmIHJlc3VsdCBpcyBhIHR5cGVkIGFycmF5LCBpdCBtdXN0IGhhdmUgZXhhY3RseSBhcnJheS5sZW5ndGggKiAyIGVsZW1lbnRzIgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IHJlc3VsdExlbmd0aDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgX0NhcnRlc2lhbjIucGFjayhhcnJheVtpMl0sIHJlc3VsdCwgaTIgKiAyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFVucGFja3MgYW4gYXJyYXkgb2YgY2FydGVzaWFuIGNvbXBvbmVudHMgaW50byBhbiBhcnJheSBvZiBDYXJ0ZXNpYW4ycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSBvZiBjb21wb25lbnRzIHRvIHVucGFjay4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJbXX0gW3Jlc3VsdF0gVGhlIGFycmF5IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMltdfSBUaGUgdW5wYWNrZWQgYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiYXJyYXkubGVuZ3RoIiwgYXJyYXkubGVuZ3RoLCAyKTsKICAgICAgICAgIGlmIChhcnJheS5sZW5ndGggJSAyICE9PSAwKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBsZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDIuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShsZW5ndGggLyAyKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSBsZW5ndGggLyAyOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMikgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IGkyIC8gMjsKICAgICAgICAgICAgcmVzdWx0W2luZGV4XSA9IF9DYXJ0ZXNpYW4yLnVucGFjayhhcnJheSwgaTIsIHJlc3VsdFtpbmRleF0pOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHZhbHVlIG9mIHRoZSBtYXhpbXVtIGNvbXBvbmVudCBmb3IgdGhlIHN1cHBsaWVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gY2FydGVzaWFuIFRoZSBjYXJ0ZXNpYW4gdG8gdXNlLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSB2YWx1ZSBvZiB0aGUgbWF4aW11bSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1heGltdW1Db21wb25lbnQoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgcmV0dXJuIE1hdGgubWF4KGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgdmFsdWUgb2YgdGhlIG1pbmltdW0gY29tcG9uZW50IGZvciB0aGUgc3VwcGxpZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIGNhcnRlc2lhbiB0byB1c2UuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIHZhbHVlIG9mIHRoZSBtaW5pbXVtIGNvbXBvbmVudC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWluaW11bUNvbXBvbmVudChjYXJ0ZXNpYW4xMSkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICByZXR1cm4gTWF0aC5taW4oY2FydGVzaWFuMTEueCwgY2FydGVzaWFuMTEueSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHR3byBDYXJ0ZXNpYW5zIGFuZCBjb21wdXRlcyBhIENhcnRlc2lhbiB3aGljaCBjb250YWlucyB0aGUgbWluaW11bSBjb21wb25lbnRzIG9mIHRoZSBzdXBwbGllZCBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBmaXJzdCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gc2Vjb25kIEEgY2FydGVzaWFuIHRvIGNvbXBhcmUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IEEgY2FydGVzaWFuIHdpdGggdGhlIG1pbmltdW0gY29tcG9uZW50cy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWluaW11bUJ5Q29tcG9uZW50KGZpcnN0LCBzZWNvbmQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJmaXJzdCIsIGZpcnN0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic2Vjb25kIiwgc2Vjb25kKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gTWF0aC5taW4oZmlyc3QueCwgc2Vjb25kLngpOwogICAgICAgICAgcmVzdWx0LnkgPSBNYXRoLm1pbihmaXJzdC55LCBzZWNvbmQueSk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0d28gQ2FydGVzaWFucyBhbmQgY29tcHV0ZXMgYSBDYXJ0ZXNpYW4gd2hpY2ggY29udGFpbnMgdGhlIG1heGltdW0gY29tcG9uZW50cyBvZiB0aGUgc3VwcGxpZWQgQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gZmlyc3QgQSBjYXJ0ZXNpYW4gdG8gY29tcGFyZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHNlY29uZCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmVzdWx0IFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBBIGNhcnRlc2lhbiB3aXRoIHRoZSBtYXhpbXVtIGNvbXBvbmVudHMuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1heGltdW1CeUNvbXBvbmVudChmaXJzdCwgc2Vjb25kLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZmlyc3QiLCBmaXJzdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNlY29uZCIsIHNlY29uZCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IE1hdGgubWF4KGZpcnN0LngsIHNlY29uZC54KTsKICAgICAgICAgIHJlc3VsdC55ID0gTWF0aC5tYXgoZmlyc3QueSwgc2Vjb25kLnkpOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29uc3RyYWluIGEgdmFsdWUgdG8gbGllIGJldHdlZW4gdHdvIHZhbHVlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNsYW1wLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbWluIFRoZSBtaW5pbXVtIGJvdW5kLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbWF4IFRoZSBtYXhpbXVtIGJvdW5kLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmVzdWx0IFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgY2xhbXBlZCB2YWx1ZSBzdWNoIHRoYXQgbWluIDw9IHJlc3VsdCA8PSBtYXguCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsYW1wKHZhbHVlLCBtaW4zLCBtYXgzLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1pbiIsIG1pbjMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXgiLCBtYXgzKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHgyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLngsIG1pbjMueCwgbWF4My54KTsKICAgICAgICAgIGNvbnN0IHkyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLnksIG1pbjMueSwgbWF4My55KTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHByb3ZpZGVkIENhcnRlc2lhbidzIHNxdWFyZWQgbWFnbml0dWRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiBpbnN0YW5jZSB3aG9zZSBzcXVhcmVkIG1hZ25pdHVkZSBpcyB0byBiZSBjb21wdXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgc3F1YXJlZCBtYWduaXR1ZGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1hZ25pdHVkZVNxdWFyZWQoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgcmV0dXJuIGNhcnRlc2lhbjExLnggKiBjYXJ0ZXNpYW4xMS54ICsgY2FydGVzaWFuMTEueSAqIGNhcnRlc2lhbjExLnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBDYXJ0ZXNpYW4ncyBtYWduaXR1ZGUgKGxlbmd0aCkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIGluc3RhbmNlIHdob3NlIG1hZ25pdHVkZSBpcyB0byBiZSBjb21wdXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbWFnbml0dWRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtYWduaXR1ZGUoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIHJldHVybiBNYXRoLnNxcnQoX0NhcnRlc2lhbjIubWFnbml0dWRlU3F1YXJlZChjYXJ0ZXNpYW4xMSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBsZWZ0IFRoZSBmaXJzdCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSBmcm9tLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmlnaHQgVGhlIHNlY29uZCBwb2ludCB0byBjb21wdXRlIHRoZSBkaXN0YW5jZSB0by4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gcG9pbnRzLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBSZXR1cm5zIDEuMAogICAgICAgICAqIGNvbnN0IGQgPSBDZXNpdW0uQ2FydGVzaWFuMi5kaXN0YW5jZShuZXcgQ2VzaXVtLkNhcnRlc2lhbjIoMS4wLCAwLjApLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjIoMi4wLCAwLjApKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZGlzdGFuY2UobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIF9DYXJ0ZXNpYW4yLnN1YnRyYWN0KGxlZnQsIHJpZ2h0LCBkaXN0YW5jZVNjcmF0Y2gyKTsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuMi5tYWduaXR1ZGUoZGlzdGFuY2VTY3JhdGNoMik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBzcXVhcmVkIGRpc3RhbmNlIGJldHdlZW4gdHdvIHBvaW50cy4gIENvbXBhcmluZyBzcXVhcmVkIGRpc3RhbmNlcwogICAgICAgICAqIHVzaW5nIHRoaXMgZnVuY3Rpb24gaXMgbW9yZSBlZmZpY2llbnQgdGhhbiBjb21wYXJpbmcgZGlzdGFuY2VzIHVzaW5nIHtAbGluayBDYXJ0ZXNpYW4yI2Rpc3RhbmNlfS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbGVmdCBUaGUgZmlyc3QgcG9pbnQgdG8gY29tcHV0ZSB0aGUgZGlzdGFuY2UgZnJvbS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJpZ2h0IFRoZSBzZWNvbmQgcG9pbnQgdG8gY29tcHV0ZSB0aGUgZGlzdGFuY2UgdG8uCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIGRpc3RhbmNlIGJldHdlZW4gdHdvIHBvaW50cy4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gUmV0dXJucyA0LjAsIG5vdCAyLjAKICAgICAgICAgKiBjb25zdCBkID0gQ2VzaXVtLkNhcnRlc2lhbjIuZGlzdGFuY2UobmV3IENlc2l1bS5DYXJ0ZXNpYW4yKDEuMCwgMC4wKSwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4yKDMuMCwgMC4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRpc3RhbmNlU3F1YXJlZChsZWZ0LCByaWdodCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgX0NhcnRlc2lhbjIuc3VidHJhY3QobGVmdCwgcmlnaHQsIGRpc3RhbmNlU2NyYXRjaDIpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4yLm1hZ25pdHVkZVNxdWFyZWQoZGlzdGFuY2VTY3JhdGNoMik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBub3JtYWxpemVkIGZvcm0gb2YgdGhlIHN1cHBsaWVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gdG8gYmUgbm9ybWFsaXplZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5vcm1hbGl6ZShjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IG1hZ25pdHVkZSA9IF9DYXJ0ZXNpYW4yLm1hZ25pdHVkZShjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLnggLyBtYWduaXR1ZGU7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnkgLyBtYWduaXR1ZGU7CiAgICAgICAgICBpZiAoaXNOYU4ocmVzdWx0LngpIHx8IGlzTmFOKHJlc3VsdC55KSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibm9ybWFsaXplZCByZXN1bHQgaXMgbm90IGEgbnVtYmVyIik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgZG90IChzY2FsYXIpIHByb2R1Y3Qgb2YgdHdvIENhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGxlZnQgVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJpZ2h0IFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBkb3QgcHJvZHVjdC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZG90KGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICByZXR1cm4gbGVmdC54ICogcmlnaHQueCArIGxlZnQueSAqIHJpZ2h0Lnk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGNyb3NzIHByb2R1Y3QgdGhhdCB3b3VsZCByZXN1bHQgZnJvbSBpbXBsaWNpdGx5IHNldHRpbmcgdGhlIFogY29vcmRpbmF0ZSBvZiB0aGUgaW5wdXQgdmVjdG9ycyB0byAwCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGxlZnQgVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJpZ2h0IFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBjcm9zcyBwcm9kdWN0LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjcm9zcyhsZWZ0LCByaWdodCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgcmV0dXJuIGxlZnQueCAqIHJpZ2h0LnkgLSBsZWZ0LnkgKiByaWdodC54OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBwcm9kdWN0IG9mIHR3byBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBsZWZ0IFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByaWdodCBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5Q29tcG9uZW50cyhsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAqIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAqIHJpZ2h0Lnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBxdW90aWVudCBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVDb21wb25lbnRzKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gbGVmdC54IC8gcmlnaHQueDsKICAgICAgICAgIHJlc3VsdC55ID0gbGVmdC55IC8gcmlnaHQueTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHN1bSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhZGQobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBsZWZ0LnggKyByaWdodC54OwogICAgICAgICAgcmVzdWx0LnkgPSBsZWZ0LnkgKyByaWdodC55OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGNvbXBvbmVudHdpc2UgZGlmZmVyZW5jZSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzdWJ0cmFjdChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAtIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAtIHJpZ2h0Lnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBzY2FsZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxhciBUaGUgc2NhbGFyIHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKGNhcnRlc2lhbjExLCBzY2FsYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxhciIsIHNjYWxhcik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLnggKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnkgKiBzY2FsYXI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEaXZpZGVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBkaXZpZGVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXIgVGhlIHNjYWxhciB0byBkaXZpZGUgYnkuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVCeVNjYWxhcihjYXJ0ZXNpYW4xMSwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJzY2FsYXIiLCBzY2FsYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBjYXJ0ZXNpYW4xMS54IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LnkgPSBjYXJ0ZXNpYW4xMS55IC8gc2NhbGFyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTmVnYXRlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBuZWdhdGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbmVnYXRlKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSAtY2FydGVzaWFuMTEueDsKICAgICAgICAgIHJlc3VsdC55ID0gLWNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIHByb3ZpZGVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gd2hvc2UgYWJzb2x1dGUgdmFsdWUgaXMgdG8gYmUgY29tcHV0ZWQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhYnMoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IE1hdGguYWJzKGNhcnRlc2lhbjExLngpOwogICAgICAgICAgcmVzdWx0LnkgPSBNYXRoLmFicyhjYXJ0ZXNpYW4xMS55KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBsaW5lYXIgaW50ZXJwb2xhdGlvbiBvciBleHRyYXBvbGF0aW9uIGF0IHQgdXNpbmcgdGhlIHByb3ZpZGVkIGNhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHN0YXJ0IFRoZSB2YWx1ZSBjb3JyZXNwb25kaW5nIHRvIHQgYXQgMC4wLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gZW5kIFRoZSB2YWx1ZSBjb3JyZXNwb25kaW5nIHRvIHQgYXQgMS4wLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0IFRoZSBwb2ludCBhbG9uZyB0IGF0IHdoaWNoIHRvIGludGVycG9sYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbGVycChzdGFydCwgZW5kLCB0MiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInN0YXJ0Iiwgc3RhcnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJlbmQiLCBlbmQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ0IiwgdDIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgX0NhcnRlc2lhbjIubXVsdGlwbHlCeVNjYWxhcihlbmQsIHQyLCBsZXJwU2NyYXRjaDIpOwogICAgICAgICAgcmVzdWx0ID0gX0NhcnRlc2lhbjIubXVsdGlwbHlCeVNjYWxhcihzdGFydCwgMSAtIHQyLCByZXN1bHQpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4yLmFkZChsZXJwU2NyYXRjaDIsIHJlc3VsdCwgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgYW5nbGUsIGluIHJhZGlhbnMsIGJldHdlZW4gdGhlIHByb3ZpZGVkIENhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGxlZnQgVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJpZ2h0IFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBhbmdsZSBiZXR3ZWVuIHRoZSBDYXJ0ZXNpYW5zLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhbmdsZUJldHdlZW4obGVmdCwgcmlnaHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIF9DYXJ0ZXNpYW4yLm5vcm1hbGl6ZShsZWZ0LCBhbmdsZUJldHdlZW5TY3JhdGNoMyk7CiAgICAgICAgICBfQ2FydGVzaWFuMi5ub3JtYWxpemUocmlnaHQsIGFuZ2xlQmV0d2VlblNjcmF0Y2gyMik7CiAgICAgICAgICByZXR1cm4gTWF0aF9kZWZhdWx0LmFjb3NDbGFtcGVkKAogICAgICAgICAgICBfQ2FydGVzaWFuMi5kb3QoYW5nbGVCZXR3ZWVuU2NyYXRjaDMsIGFuZ2xlQmV0d2VlblNjcmF0Y2gyMikKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIGF4aXMgdGhhdCBpcyBtb3N0IG9ydGhvZ29uYWwgdG8gdGhlIHByb3ZpZGVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gb24gd2hpY2ggdG8gZmluZCB0aGUgbW9zdCBvcnRob2dvbmFsIGF4aXMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb3N0IG9ydGhvZ29uYWwgYXhpcy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbW9zdE9ydGhvZ29uYWxBeGlzKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgZjIgPSBfQ2FydGVzaWFuMi5ub3JtYWxpemUoY2FydGVzaWFuMTEsIG1vc3RPcnRob2dvbmFsQXhpc1NjcmF0Y2gyKTsKICAgICAgICAgIF9DYXJ0ZXNpYW4yLmFicyhmMiwgZjIpOwogICAgICAgICAgaWYgKGYyLnggPD0gZjIueSkgewogICAgICAgICAgICByZXN1bHQgPSBfQ2FydGVzaWFuMi5jbG9uZShfQ2FydGVzaWFuMi5VTklUX1gsIHJlc3VsdCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQgPSBfQ2FydGVzaWFuMi5jbG9uZShfQ2FydGVzaWFuMi5VTklUX1ksIHJlc3VsdCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFucyBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtsZWZ0XSBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gW3JpZ2h0XSBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgbGVmdCBhbmQgcmlnaHQgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHMobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBsZWZ0LnggPT09IHJpZ2h0LnggJiYgbGVmdC55ID09PSByaWdodC55OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGNhcnRlc2lhbgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5CiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG9mZnNldAogICAgICAgICAqIEBpZ25vcmUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzQXJyYXkoY2FydGVzaWFuMTEsIGFycmF5LCBvZmZzZXQpIHsKICAgICAgICAgIHJldHVybiBjYXJ0ZXNpYW4xMS54ID09PSBhcnJheVtvZmZzZXRdICYmIGNhcnRlc2lhbjExLnkgPT09IGFycmF5W29mZnNldCArIDFdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFucyBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBwYXNzIGFuIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvbGVyYW5jZSB0ZXN0LAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtsZWZ0XSBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gW3JpZ2h0XSBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3JlbGF0aXZlRXBzaWxvbj0wXSBUaGUgcmVsYXRpdmUgZXBzaWxvbiB0b2xlcmFuY2UgdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYWJzb2x1dGVFcHNpbG9uPXJlbGF0aXZlRXBzaWxvbl0gVGhlIGFic29sdXRlIGVwc2lsb24gdG9sZXJhbmNlIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgbGVmdCBhbmQgcmlnaHQgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzRXBzaWxvbihsZWZ0LCByaWdodCwgcmVsYXRpdmVFcHNpbG9uLCBhYnNvbHV0ZUVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgICAgbGVmdC54LAogICAgICAgICAgICByaWdodC54LAogICAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICAgKSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgICAgbGVmdC55LAogICAgICAgICAgICByaWdodC55LAogICAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyB0aGlzIENhcnRlc2lhbjIgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4yIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIGNsb25lKHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4yLmNsb25lKHRoaXMsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgQ2FydGVzaWFuIGFnYWluc3QgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhyaWdodCkgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4yLmVxdWFscyh0aGlzLCByaWdodCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgQ2FydGVzaWFuIGFnYWluc3QgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBwYXNzIGFuIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvbGVyYW5jZSB0ZXN0LAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtyZWxhdGl2ZUVwc2lsb249MF0gVGhlIHJlbGF0aXZlIGVwc2lsb24gdG9sZXJhbmNlIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Fic29sdXRlRXBzaWxvbj1yZWxhdGl2ZUVwc2lsb25dIFRoZSBhYnNvbHV0ZSBlcHNpbG9uIHRvbGVyYW5jZSB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHNFcHNpbG9uKHJpZ2h0LCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW4yLmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIHRoaXMsCiAgICAgICAgICAgIHJpZ2h0LAogICAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBDYXJ0ZXNpYW4gaW4gdGhlIGZvcm1hdCAnKHgsIHkpJy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuIGluIHRoZSBmb3JtYXQgJyh4LCB5KScuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICByZXR1cm4gYCgke3RoaXMueH0sICR7dGhpcy55fSlgOwogICAgICAgIH0KICAgICAgfTsKICAgICAgQ2FydGVzaWFuMi5mcm9tQ2FydGVzaWFuMyA9IENhcnRlc2lhbjIuY2xvbmU7CiAgICAgIENhcnRlc2lhbjIuZnJvbUNhcnRlc2lhbjQgPSBDYXJ0ZXNpYW4yLmNsb25lOwogICAgICBDYXJ0ZXNpYW4yLnBhY2tlZExlbmd0aCA9IDI7CiAgICAgIENhcnRlc2lhbjIuZnJvbUFycmF5ID0gQ2FydGVzaWFuMi51bnBhY2s7CiAgICAgIGRpc3RhbmNlU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuMigpOwogICAgICBsZXJwU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuMigpOwogICAgICBhbmdsZUJldHdlZW5TY3JhdGNoMyA9IG5ldyBDYXJ0ZXNpYW4yKCk7CiAgICAgIGFuZ2xlQmV0d2VlblNjcmF0Y2gyMiA9IG5ldyBDYXJ0ZXNpYW4yKCk7CiAgICAgIG1vc3RPcnRob2dvbmFsQXhpc1NjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjIoKTsKICAgICAgQ2FydGVzaWFuMi5aRVJPID0gT2JqZWN0LmZyZWV6ZShuZXcgQ2FydGVzaWFuMigwLCAwKSk7CiAgICAgIENhcnRlc2lhbjIuT05FID0gT2JqZWN0LmZyZWV6ZShuZXcgQ2FydGVzaWFuMigxLCAxKSk7CiAgICAgIENhcnRlc2lhbjIuVU5JVF9YID0gT2JqZWN0LmZyZWV6ZShuZXcgQ2FydGVzaWFuMigxLCAwKSk7CiAgICAgIENhcnRlc2lhbjIuVU5JVF9ZID0gT2JqZWN0LmZyZWV6ZShuZXcgQ2FydGVzaWFuMigwLCAxKSk7CiAgICAgIENhcnRlc2lhbjJfZGVmYXVsdCA9IENhcnRlc2lhbjI7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWQuanMKICBmdW5jdGlvbiBpbml0aWFsaXplKGVsbGlwc29pZCwgeDIsIHkyLCB6MikgewogICAgeDIgPSB4MiA/PyAwOwogICAgeTIgPSB5MiA/PyAwOwogICAgejIgPSB6MiA/PyAwOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIngiLCB4MiwgMCk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygieSIsIHkyLCAwKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJ6IiwgejIsIDApOwogICAgZWxsaXBzb2lkLl9yYWRpaSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoeDIsIHkyLCB6Mik7CiAgICBlbGxpcHNvaWQuX3JhZGlpU3F1YXJlZCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoeDIgKiB4MiwgeTIgKiB5MiwgejIgKiB6Mik7CiAgICBlbGxpcHNvaWQuX3JhZGlpVG9UaGVGb3VydGggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KAogICAgICB4MiAqIHgyICogeDIgKiB4MiwKICAgICAgeTIgKiB5MiAqIHkyICogeTIsCiAgICAgIHoyICogejIgKiB6MiAqIHoyCiAgICApOwogICAgZWxsaXBzb2lkLl9vbmVPdmVyUmFkaWkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KAogICAgICB4MiA9PT0gMCA/IDAgOiAxIC8geDIsCiAgICAgIHkyID09PSAwID8gMCA6IDEgLyB5MiwKICAgICAgejIgPT09IDAgPyAwIDogMSAvIHoyCiAgICApOwogICAgZWxsaXBzb2lkLl9vbmVPdmVyUmFkaWlTcXVhcmVkID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgKICAgICAgeDIgPT09IDAgPyAwIDogMSAvICh4MiAqIHgyKSwKICAgICAgeTIgPT09IDAgPyAwIDogMSAvICh5MiAqIHkyKSwKICAgICAgejIgPT09IDAgPyAwIDogMSAvICh6MiAqIHoyKQogICAgKTsKICAgIGVsbGlwc29pZC5fbWluaW11bVJhZGl1cyA9IE1hdGgubWluKHgyLCB5MiwgejIpOwogICAgZWxsaXBzb2lkLl9tYXhpbXVtUmFkaXVzID0gTWF0aC5tYXgoeDIsIHkyLCB6Mik7CiAgICBlbGxpcHNvaWQuX2NlbnRlclRvbGVyYW5jZVNxdWFyZWQgPSBNYXRoX2RlZmF1bHQuRVBTSUxPTjE7CiAgICBpZiAoZWxsaXBzb2lkLl9yYWRpaVNxdWFyZWQueiAhPT0gMCkgewogICAgICBlbGxpcHNvaWQuX3NxdWFyZWRYT3ZlclNxdWFyZWRaID0gZWxsaXBzb2lkLl9yYWRpaVNxdWFyZWQueCAvIGVsbGlwc29pZC5fcmFkaWlTcXVhcmVkLno7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGdhdXNzTGVnZW5kcmVRdWFkcmF0dXJlKGE0LCBiMiwgZnVuYykgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJhIiwgYTQpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJiIiwgYjIpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuZnVuYygiZnVuYyIsIGZ1bmMpOwogICAgY29uc3QgeE1lYW4gPSAwLjUgKiAoYjIgKyBhNCk7CiAgICBjb25zdCB4UmFuZ2UgPSAwLjUgKiAoYjIgLSBhNCk7CiAgICBsZXQgc3VtID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCA1OyBpMisrKSB7CiAgICAgIGNvbnN0IGR4ID0geFJhbmdlICogYWJzY2lzc2FzW2kyXTsKICAgICAgc3VtICs9IHdlaWdodHNbaTJdICogKGZ1bmMoeE1lYW4gKyBkeCkgKyBmdW5jKHhNZWFuIC0gZHgpKTsKICAgIH0KICAgIHN1bSAqPSB4UmFuZ2U7CiAgICByZXR1cm4gc3VtOwogIH0KICB2YXIgRWxsaXBzb2lkLCBjYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbk5vcm1hbCwgY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW5LLCBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY04yLCBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY1AyLCBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY0gyLCBzY3JhdGNoRW5kcG9pbnQsIGFic2Npc3Nhcywgd2VpZ2h0cywgRWxsaXBzb2lkX2RlZmF1bHQ7CiAgdmFyIGluaXRfRWxsaXBzb2lkID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWQuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfc2NhbGVUb0dlb2RldGljU3VyZmFjZSgpOwogICAgICBFbGxpcHNvaWQgPSBjbGFzcyBfRWxsaXBzb2lkIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3g9MF0gVGhlIHJhZGl1cyBpbiB0aGUgeCBkaXJlY3Rpb24uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt5PTBdIFRoZSByYWRpdXMgaW4gdGhlIHkgZGlyZWN0aW9uLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbej0wXSBUaGUgcmFkaXVzIGluIHRoZSB6IGRpcmVjdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBBbGwgcmFkaWkgY29tcG9uZW50cyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB6ZXJvLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHgyLCB5MiwgejIpIHsKICAgICAgICAgIHRoaXMuX3JhZGlpID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fcmFkaWlTcXVhcmVkID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fcmFkaWlUb1RoZUZvdXJ0aCA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMuX29uZU92ZXJSYWRpaSA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMuX29uZU92ZXJSYWRpaVNxdWFyZWQgPSB2b2lkIDA7CiAgICAgICAgICB0aGlzLl9taW5pbXVtUmFkaXVzID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fbWF4aW11bVJhZGl1cyA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMuX2NlbnRlclRvbGVyYW5jZVNxdWFyZWQgPSB2b2lkIDA7CiAgICAgICAgICB0aGlzLl9zcXVhcmVkWE92ZXJTcXVhcmVkWiA9IHZvaWQgMDsKICAgICAgICAgIGluaXRpYWxpemUodGhpcywgeDIsIHkyLCB6Mik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHJhZGlpIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHR5cGUge0NhcnRlc2lhbjN9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgZ2V0IHJhZGlpKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX3JhZGlpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBzcXVhcmVkIHJhZGlpIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHR5cGUge0NhcnRlc2lhbjN9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgZ2V0IHJhZGlpU3F1YXJlZCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9yYWRpaVNxdWFyZWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHJhZGlpIG9mIHRoZSBlbGxpcHNvaWQgcmFpc2UgdG8gdGhlIGZvdXJ0aCBwb3dlci4KICAgICAgICAgKiBAdHlwZSB7Q2FydGVzaWFuM30KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBnZXQgcmFkaWlUb1RoZUZvdXJ0aCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9yYWRpaVRvVGhlRm91cnRoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIG9uZSBvdmVyIHRoZSByYWRpaSBvZiB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqIEB0eXBlIHtDYXJ0ZXNpYW4zfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGdldCBvbmVPdmVyUmFkaWkoKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fb25lT3ZlclJhZGlpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIG9uZSBvdmVyIHRoZSBzcXVhcmVkIHJhZGlpIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHR5cGUge0NhcnRlc2lhbjN9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgZ2V0IG9uZU92ZXJSYWRpaVNxdWFyZWQoKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fb25lT3ZlclJhZGlpU3F1YXJlZDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgbWluaW11bSByYWRpdXMgb2YgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGdldCBtaW5pbXVtUmFkaXVzKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX21pbmltdW1SYWRpdXM7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIG1heGltdW0gcmFkaXVzIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBnZXQgbWF4aW11bVJhZGl1cygpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9tYXhpbXVtUmFkaXVzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIGFuIEVsbGlwc29pZCBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7RWxsaXBzb2lkfSBlbGxpcHNvaWQgVGhlIGVsbGlwc29pZCB0byBkdXBsaWNhdGUuCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYSBuZXcKICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge0VsbGlwc29pZH0gVGhlIGNsb25lZCBFbGxpcHNvaWQuIChSZXR1cm5zIHVuZGVmaW5lZCBpZiBlbGxpcHNvaWQgaXMgdW5kZWZpbmVkKQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjbG9uZShlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgcmFkaWkgPSBlbGxpcHNvaWQuX3JhZGlpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9FbGxpcHNvaWQocmFkaWkueCwgcmFkaWkueSwgcmFkaWkueik7CiAgICAgICAgICB9CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocmFkaWksIHJlc3VsdC5fcmFkaWkpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVsbGlwc29pZC5fcmFkaWlTcXVhcmVkLCByZXN1bHQuX3JhZGlpU3F1YXJlZCk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLl9yYWRpaVRvVGhlRm91cnRoLCByZXN1bHQuX3JhZGlpVG9UaGVGb3VydGgpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVsbGlwc29pZC5fb25lT3ZlclJhZGlpLCByZXN1bHQuX29uZU92ZXJSYWRpaSk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgICAgICAgIGVsbGlwc29pZC5fb25lT3ZlclJhZGlpU3F1YXJlZCwKICAgICAgICAgICAgcmVzdWx0Ll9vbmVPdmVyUmFkaWlTcXVhcmVkCiAgICAgICAgICApOwogICAgICAgICAgcmVzdWx0Ll9taW5pbXVtUmFkaXVzID0gZWxsaXBzb2lkLl9taW5pbXVtUmFkaXVzOwogICAgICAgICAgcmVzdWx0Ll9tYXhpbXVtUmFkaXVzID0gZWxsaXBzb2lkLl9tYXhpbXVtUmFkaXVzOwogICAgICAgICAgcmVzdWx0Ll9jZW50ZXJUb2xlcmFuY2VTcXVhcmVkID0gZWxsaXBzb2lkLl9jZW50ZXJUb2xlcmFuY2VTcXVhcmVkOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYW4gRWxsaXBzb2lkIGZyb20gYSBDYXJ0ZXNpYW4gc3BlY2lmeWluZyB0aGUgcmFkaWkgaW4geCwgeSwgYW5kIHogZGlyZWN0aW9ucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW2NhcnRlc2lhbj1DYXJ0ZXNpYW4zLlpFUk9dIFRoZSBlbGxpcHNvaWQncyByYWRpdXMgaW4gdGhlIHgsIHksIGFuZCB6IGRpcmVjdGlvbnMuCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYSBuZXcKICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge0VsbGlwc29pZH0gQSBuZXcgRWxsaXBzb2lkIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IEFsbCByYWRpaSBjb21wb25lbnRzIG11c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHplcm8uCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIEVsbGlwc29pZC5XR1M4NAogICAgICAgICAqIEBzZWUgRWxsaXBzb2lkLlVOSVRfU1BIRVJFCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21DYXJ0ZXNpYW4zKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9FbGxpcHNvaWQoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNhcnRlc2lhbjExKSkgewogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgaW5pdGlhbGl6ZShyZXN1bHQsIGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnksIGNhcnRlc2lhbjExLnopOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGRlZmF1bHQgZWxsaXBzb2lkIHVzZWQgd2hlbiBub3Qgb3RoZXJ3aXNlIHNwZWNpZmllZC4KICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogQ2VzaXVtLkVsbGlwc29pZC5kZWZhdWx0ID0gQ2VzaXVtLkVsbGlwc29pZC5NT09OOwogICAgICAgICAqCiAgICAgICAgICogLy8gQXBvbGxvIDExIGxhbmRpbmcgc2l0ZQogICAgICAgICAqIGNvbnN0IHBvc2l0aW9uID0gQ2VzaXVtLkNhcnRlc2lhbjMuZnJvbVJhZGlhbnMoCiAgICAgICAgICogICAwLjY3NDE2LAogICAgICAgICAqICAgMjMuNDczMTUsCiAgICAgICAgICogKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0IGRlZmF1bHQoKSB7CiAgICAgICAgICByZXR1cm4gX0VsbGlwc29pZC5fZGVmYXVsdDsKICAgICAgICB9CiAgICAgICAgc3RhdGljIHNldCBkZWZhdWx0KHZhbHVlKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgICAgX0VsbGlwc29pZC5fZGVmYXVsdCA9IHZhbHVlOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Ll9lbGxpcHNvaWRSYWRpaVNxdWFyZWQgPSB2YWx1ZS5yYWRpaVNxdWFyZWQ7CiAgICAgICAgICBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5fZWxsaXBzb2lkT25lT3ZlclJhZGlpID0gdmFsdWUub25lT3ZlclJhZGlpOwogICAgICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuX2VsbGlwc29pZE9uZU92ZXJSYWRpaVNxdWFyZWQgPSB2YWx1ZS5vbmVPdmVyUmFkaWlTcXVhcmVkOwogICAgICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuX2VsbGlwc29pZENlbnRlclRvbGVyYW5jZVNxdWFyZWQgPSB2YWx1ZS5fY2VudGVyVG9sZXJhbmNlU3F1YXJlZDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhbiBFbGxpcHNvaWQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQsIG9yIHVuZGVmaW5lZCBpZiBhIG5ldwogICAgICAgICAqICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZSBzaG91bGQgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7RWxsaXBzb2lkfSBUaGUgY2xvbmVkIEVsbGlwc29pZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfRWxsaXBzb2lkLmNsb25lKHRoaXMsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2UgaW50byB0aGUgcHJvdmlkZWQgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gdmFsdWUgVGhlIHZhbHVlIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIGFycmF5IHRvIHBhY2sgaW50by4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIGluZGV4IGludG8gdGhlIGFycmF5IGF0IHdoaWNoIHRvIHN0YXJ0IHBhY2tpbmcgdGhlIGVsZW1lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgYXJyYXkgdGhhdCB3YXMgcGFja2VkIGludG8KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFjayh2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9yYWRpaSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0VsbGlwc29pZH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgRWxsaXBzb2lkIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBjb25zdCByYWRpaSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgICAgcmV0dXJuIF9FbGxpcHNvaWQuZnJvbUNhcnRlc2lhbjMocmFkaWksIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBub3JtYWwgb2YgdGhlIHBsYW5lIHRhbmdlbnQgdG8gdGhlIHN1cmZhY2Ugb2YgdGhlIGVsbGlwc29pZCBhdCB0aGUgcHJvdmlkZWQgcG9zaXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gY2FydG9ncmFwaGljIFRoZSBjYXJ0b2dyYXBoaWMgcG9zaXRpb24gZm9yIHdoaWNoIHRvIHRvIGRldGVybWluZSB0aGUgZ2VvZGV0aWMgbm9ybWFsLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjMgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsQ2FydG9ncmFwaGljKGNhcnRvZ3JhcGhpYzIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0b2dyYXBoaWMiLCBjYXJ0b2dyYXBoaWMyKTsKICAgICAgICAgIGNvbnN0IGxvbmdpdHVkZSA9IGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlOwogICAgICAgICAgY29uc3QgbGF0aXR1ZGUgPSBjYXJ0b2dyYXBoaWMyLmxhdGl0dWRlOwogICAgICAgICAgY29uc3QgY29zTGF0aXR1ZGUgPSBNYXRoLmNvcyhsYXRpdHVkZSk7CiAgICAgICAgICBjb25zdCB4MiA9IGNvc0xhdGl0dWRlICogTWF0aC5jb3MobG9uZ2l0dWRlKTsKICAgICAgICAgIGNvbnN0IHkyID0gY29zTGF0aXR1ZGUgKiBNYXRoLnNpbihsb25naXR1ZGUpOwogICAgICAgICAgY29uc3QgejIgPSBNYXRoLnNpbihsYXRpdHVkZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHJlc3VsdCwgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIG5vcm1hbCBvZiB0aGUgcGxhbmUgdGFuZ2VudCB0byB0aGUgc3VyZmFjZSBvZiB0aGUgZWxsaXBzb2lkIGF0IHRoZSBwcm92aWRlZCBwb3NpdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gcG9zaXRpb24gZm9yIHdoaWNoIHRvIHRvIGRldGVybWluZSB0aGUgc3VyZmFjZSBub3JtYWwuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydGVzaWFuMyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZCwgb3IgdW5kZWZpbmVkIGlmIGEgbm9ybWFsIGNhbm5vdCBiZSBmb3VuZC4KICAgICAgICAgKi8KICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWwoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBpZiAoaXNOYU4oY2FydGVzaWFuMTEueCkgfHwgaXNOYU4oY2FydGVzaWFuMTEueSkgfHwgaXNOYU4oY2FydGVzaWFuMTEueikpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNhcnRlc2lhbiBoYXMgYSBOYU4gY29tcG9uZW50Iik7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24oY2FydGVzaWFuMTEsIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlDb21wb25lbnRzKAogICAgICAgICAgICBjYXJ0ZXNpYW4xMSwKICAgICAgICAgICAgdGhpcy5fb25lT3ZlclJhZGlpU3F1YXJlZCwKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmVzdWx0LCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgY2FydG9ncmFwaGljIHRvIENhcnRlc2lhbiByZXByZXNlbnRhdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBjYXJ0b2dyYXBoaWMgVGhlIGNhcnRvZ3JhcGhpYyBwb3NpdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW4zIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL0NyZWF0ZSBhIENhcnRvZ3JhcGhpYyBhbmQgZGV0ZXJtaW5lIGl0J3MgQ2FydGVzaWFuIHJlcHJlc2VudGF0aW9uIG9uIGEgV0dTODQgZWxsaXBzb2lkLgogICAgICAgICAqIGNvbnN0IHBvc2l0aW9uID0gbmV3IENlc2l1bS5DYXJ0b2dyYXBoaWMoQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDIxKSwgQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDc4KSwgNTAwMCk7CiAgICAgICAgICogY29uc3QgY2FydGVzaWFuUG9zaXRpb24gPSBDZXNpdW0uRWxsaXBzb2lkLldHUzg0LmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKHBvc2l0aW9uKTsKICAgICAgICAgKi8KICAgICAgICBjYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihjYXJ0b2dyYXBoaWMyLCByZXN1bHQpIHsKICAgICAgICAgIGNvbnN0IG4yID0gY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW5Ob3JtYWw7CiAgICAgICAgICBjb25zdCBrMiA9IGNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuSzsKICAgICAgICAgIHRoaXMuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsQ2FydG9ncmFwaGljKGNhcnRvZ3JhcGhpYzIsIG4yKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUNvbXBvbmVudHModGhpcy5fcmFkaWlTcXVhcmVkLCBuMiwgazIpOwogICAgICAgICAgY29uc3QgZ2FtbWEgPSBNYXRoLnNxcnQoQ2FydGVzaWFuM19kZWZhdWx0LmRvdChuMiwgazIpKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kaXZpZGVCeVNjYWxhcihrMiwgZ2FtbWEsIGsyKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG4yLCBjYXJ0b2dyYXBoaWMyLmhlaWdodCwgbjIpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChrMiwgbjIsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBhcnJheSBvZiBjYXJ0b2dyYXBoaWNzIHRvIGFuIGFycmF5IG9mIENhcnRlc2lhbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY1tdfSBjYXJ0b2dyYXBoaWNzIEFuIGFycmF5IG9mIGNhcnRvZ3JhcGhpYyBwb3NpdGlvbnMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zW119IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zW119IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEFycmF5IGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL0NvbnZlcnQgYW4gYXJyYXkgb2YgQ2FydG9ncmFwaGljcyBhbmQgZGV0ZXJtaW5lIHRoZWlyIENhcnRlc2lhbiByZXByZXNlbnRhdGlvbiBvbiBhIFdHUzg0IGVsbGlwc29pZC4KICAgICAgICAgKiBjb25zdCBwb3NpdGlvbnMgPSBbbmV3IENlc2l1bS5DYXJ0b2dyYXBoaWMoQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDIxKSwgQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDc4KSwgMCksCiAgICAgICAgICogICAgICAgICAgICAgICAgICBuZXcgQ2VzaXVtLkNhcnRvZ3JhcGhpYyhDZXNpdW0uTWF0aC50b1JhZGlhbnMoMjEuMzIxKSwgQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDc4LjEyMyksIDEwMCksCiAgICAgICAgICogICAgICAgICAgICAgICAgICBuZXcgQ2VzaXVtLkNhcnRvZ3JhcGhpYyhDZXNpdW0uTWF0aC50b1JhZGlhbnMoMjEuNjQ1KSwgQ2VzaXVtLk1hdGgudG9SYWRpYW5zKDc4LjQ1NiksIDI1MCldOwogICAgICAgICAqIGNvbnN0IGNhcnRlc2lhblBvc2l0aW9ucyA9IENlc2l1bS5FbGxpcHNvaWQuV0dTODQuY2FydG9ncmFwaGljQXJyYXlUb0NhcnRlc2lhbkFycmF5KHBvc2l0aW9ucyk7CiAgICAgICAgICovCiAgICAgICAgY2FydG9ncmFwaGljQXJyYXlUb0NhcnRlc2lhbkFycmF5KGNhcnRvZ3JhcGhpY3MsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjYXJ0b2dyYXBoaWNzIiwgY2FydG9ncmFwaGljcyk7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBjYXJ0b2dyYXBoaWNzLmxlbmd0aDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICByZXN1bHRbaTJdID0gdGhpcy5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihjYXJ0b2dyYXBoaWNzW2kyXSwgcmVzdWx0W2kyXSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgY2FydGVzaWFuIHRvIGNhcnRvZ3JhcGhpYyByZXByZXNlbnRhdGlvbi4KICAgICAgICAgKiBUaGUgY2FydGVzaWFuIGlzIHVuZGVmaW5lZCBhdCB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHBvc2l0aW9uIHRvIGNvbnZlcnQgdG8gY2FydG9ncmFwaGljIHJlcHJlc2VudGF0aW9uLgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydG9ncmFwaGljfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZCwgb3IgdW5kZWZpbmVkIGlmIHRoZSBjYXJ0ZXNpYW4gaXMgYXQgdGhlIGNlbnRlciBvZiB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL0NyZWF0ZSBhIENhcnRlc2lhbiBhbmQgZGV0ZXJtaW5lIGl0J3MgQ2FydG9ncmFwaGljIHJlcHJlc2VudGF0aW9uIG9uIGEgV0dTODQgZWxsaXBzb2lkLgogICAgICAgICAqIGNvbnN0IHBvc2l0aW9uID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDE3ODMyLjEyLCA4MzIzNC41MiwgOTUyMzEzLjczKTsKICAgICAgICAgKiBjb25zdCBjYXJ0b2dyYXBoaWNQb3NpdGlvbiA9IENlc2l1bS5FbGxpcHNvaWQuV0dTODQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocG9zaXRpb24pOwogICAgICAgICAqLwogICAgICAgIGNhcnRlc2lhblRvQ2FydG9ncmFwaGljKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIGNvbnN0IHAyID0gdGhpcy5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKGNhcnRlc2lhbjExLCBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY1AyKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHAyKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbjIgPSB0aGlzLmdlb2RldGljU3VyZmFjZU5vcm1hbChwMiwgY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWNOMik7CiAgICAgICAgICBjb25zdCBoMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjYXJ0ZXNpYW4xMSwgcDIsIGNhcnRlc2lhblRvQ2FydG9ncmFwaGljSDIpOwogICAgICAgICAgY29uc3QgbG9uZ2l0dWRlID0gTWF0aC5hdGFuMihuMi55LCBuMi54KTsKICAgICAgICAgIGNvbnN0IGxhdGl0dWRlID0gTWF0aC5hc2luKG4yLnopOwogICAgICAgICAgY29uc3QgaGVpZ2h0ID0gTWF0aF9kZWZhdWx0LnNpZ24oQ2FydGVzaWFuM19kZWZhdWx0LmRvdChoMiwgY2FydGVzaWFuMTEpKSAqIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoaDIpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGhlaWdodCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gbG9uZ2l0dWRlOwogICAgICAgICAgcmVzdWx0LmxhdGl0dWRlID0gbGF0aXR1ZGU7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgdGhlIHByb3ZpZGVkIGFycmF5IG9mIGNhcnRlc2lhbnMgdG8gYW4gYXJyYXkgb2YgY2FydG9ncmFwaGljcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM1tdfSBjYXJ0ZXNpYW5zIEFuIGFycmF5IG9mIENhcnRlc2lhbiBwb3NpdGlvbnMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWNbXX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRvZ3JhcGhpY1tdfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBBcnJheSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy9DcmVhdGUgYW4gYXJyYXkgb2YgQ2FydGVzaWFucyBhbmQgZGV0ZXJtaW5lIHRoZWlyIENhcnRvZ3JhcGhpYyByZXByZXNlbnRhdGlvbiBvbiBhIFdHUzg0IGVsbGlwc29pZC4KICAgICAgICAgKiBjb25zdCBwb3NpdGlvbnMgPSBbbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDE3ODMyLjEyLCA4MzIzNC41MiwgOTUyMzEzLjczKSwKICAgICAgICAgKiAgICAgICAgICAgICAgICAgIG5ldyBDZXNpdW0uQ2FydGVzaWFuMygxNzgzMi4xMywgODMyMzQuNTMsIDk1MjMxMy43MyksCiAgICAgICAgICogICAgICAgICAgICAgICAgICBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMTc4MzIuMTQsIDgzMjM0LjU0LCA5NTIzMTMuNzMpXQogICAgICAgICAqIGNvbnN0IGNhcnRvZ3JhcGhpY1Bvc2l0aW9ucyA9IENlc2l1bS5FbGxpcHNvaWQuV0dTODQuY2FydGVzaWFuQXJyYXlUb0NhcnRvZ3JhcGhpY0FycmF5KHBvc2l0aW9ucyk7CiAgICAgICAgICovCiAgICAgICAgY2FydGVzaWFuQXJyYXlUb0NhcnRvZ3JhcGhpY0FycmF5KGNhcnRlc2lhbnMsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjYXJ0ZXNpYW5zIiwgY2FydGVzaWFucyk7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBjYXJ0ZXNpYW5zLmxlbmd0aDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICByZXN1bHRbaTJdID0gdGhpcy5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhjYXJ0ZXNpYW5zW2kyXSwgcmVzdWx0W2kyXSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBwb3NpdGlvbiBhbG9uZyB0aGUgZ2VvZGV0aWMgc3VyZmFjZSBub3JtYWwKICAgICAgICAgKiBzbyB0aGF0IGl0IGlzIG9uIHRoZSBzdXJmYWNlIG9mIHRoaXMgZWxsaXBzb2lkLiAgSWYgdGhlIHBvc2l0aW9uIGlzCiAgICAgICAgICogYXQgdGhlIGNlbnRlciBvZiB0aGUgZWxsaXBzb2lkLCB0aGlzIGZ1bmN0aW9uIHJldHVybnMgdW5kZWZpbmVkLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiBwb3NpdGlvbiB0byBzY2FsZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgYSBuZXcgQ2FydGVzaWFuMyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZCwgb3IgdW5kZWZpbmVkIGlmIHRoZSBwb3NpdGlvbiBpcyBhdCB0aGUgY2VudGVyLgogICAgICAgICAqLwogICAgICAgIHNjYWxlVG9HZW9kZXRpY1N1cmZhY2UoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIHNjYWxlVG9HZW9kZXRpY1N1cmZhY2VfZGVmYXVsdCgKICAgICAgICAgICAgY2FydGVzaWFuMTEsCiAgICAgICAgICAgIHRoaXMuX29uZU92ZXJSYWRpaSwKICAgICAgICAgICAgdGhpcy5fb25lT3ZlclJhZGlpU3F1YXJlZCwKICAgICAgICAgICAgdGhpcy5fY2VudGVyVG9sZXJhbmNlU3F1YXJlZCwKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTY2FsZXMgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBwb3NpdGlvbiBhbG9uZyB0aGUgZ2VvY2VudHJpYyBzdXJmYWNlIG5vcm1hbAogICAgICAgICAqIHNvIHRoYXQgaXQgaXMgb24gdGhlIHN1cmZhY2Ugb2YgdGhpcyBlbGxpcHNvaWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHBvc2l0aW9uIHRvIHNjYWxlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjMgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc2NhbGVUb0dlb2NlbnRyaWNTdXJmYWNlKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBwb3NpdGlvblggPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgY29uc3QgcG9zaXRpb25ZID0gY2FydGVzaWFuMTEueTsKICAgICAgICAgIGNvbnN0IHBvc2l0aW9uWiA9IGNhcnRlc2lhbjExLno7CiAgICAgICAgICBjb25zdCBvbmVPdmVyUmFkaWlTcXVhcmVkID0gdGhpcy5fb25lT3ZlclJhZGlpU3F1YXJlZDsKICAgICAgICAgIGNvbnN0IGJldGEgPSAxIC8gTWF0aC5zcXJ0KAogICAgICAgICAgICBwb3NpdGlvblggKiBwb3NpdGlvblggKiBvbmVPdmVyUmFkaWlTcXVhcmVkLnggKyBwb3NpdGlvblkgKiBwb3NpdGlvblkgKiBvbmVPdmVyUmFkaWlTcXVhcmVkLnkgKyBwb3NpdGlvblogKiBwb3NpdGlvblogKiBvbmVPdmVyUmFkaWlTcXVhcmVkLnoKICAgICAgICAgICk7CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoY2FydGVzaWFuMTEsIGJldGEsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFRyYW5zZm9ybXMgYSBDYXJ0ZXNpYW4gWCwgWSwgWiBwb3NpdGlvbiB0byB0aGUgZWxsaXBzb2lkLXNjYWxlZCBzcGFjZSBieSBtdWx0aXBseWluZwogICAgICAgICAqIGl0cyBjb21wb25lbnRzIGJ5IHRoZSByZXN1bHQgb2Yge0BsaW5rIEVsbGlwc29pZCNvbmVPdmVyUmFkaWl9LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBwb3NpdGlvbiBUaGUgcG9zaXRpb24gdG8gdHJhbnNmb3JtLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gVGhlIHBvc2l0aW9uIHRvIHdoaWNoIHRvIGNvcHkgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIHRvIGNyZWF0ZSBhbmQKICAgICAgICAgKiAgICAgICAgcmV0dXJuIGEgbmV3IGluc3RhbmNlLgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgcG9zaXRpb24gZXhwcmVzc2VkIGluIHRoZSBzY2FsZWQgc3BhY2UuICBUaGUgcmV0dXJuZWQgaW5zdGFuY2UgaXMgdGhlCiAgICAgICAgICogICAgICAgICAgb25lIHBhc3NlZCBhcyB0aGUgcmVzdWx0IHBhcmFtZXRlciBpZiBpdCBpcyBub3QgdW5kZWZpbmVkLCBvciBhIG5ldyBpbnN0YW5jZSBvZiBpdCBpcy4KICAgICAgICAgKi8KICAgICAgICB0cmFuc2Zvcm1Qb3NpdGlvblRvU2NhbGVkU3BhY2UocG9zaXRpb24sIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5Q29tcG9uZW50cyhwb3NpdGlvbiwgdGhpcy5fb25lT3ZlclJhZGlpLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2Zvcm1zIGEgQ2FydGVzaWFuIFgsIFksIFogcG9zaXRpb24gZnJvbSB0aGUgZWxsaXBzb2lkLXNjYWxlZCBzcGFjZSBieSBtdWx0aXBseWluZwogICAgICAgICAqIGl0cyBjb21wb25lbnRzIGJ5IHRoZSByZXN1bHQgb2Yge0BsaW5rIEVsbGlwc29pZCNyYWRpaX0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHBvc2l0aW9uIFRoZSBwb3NpdGlvbiB0byB0cmFuc2Zvcm0uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbcmVzdWx0XSBUaGUgcG9zaXRpb24gdG8gd2hpY2ggdG8gY29weSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgdG8gY3JlYXRlIGFuZAogICAgICAgICAqICAgICAgICByZXR1cm4gYSBuZXcgaW5zdGFuY2UuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBwb3NpdGlvbiBleHByZXNzZWQgaW4gdGhlIHVuc2NhbGVkIHNwYWNlLiAgVGhlIHJldHVybmVkIGluc3RhbmNlIGlzIHRoZQogICAgICAgICAqICAgICAgICAgIG9uZSBwYXNzZWQgYXMgdGhlIHJlc3VsdCBwYXJhbWV0ZXIgaWYgaXQgaXMgbm90IHVuZGVmaW5lZCwgb3IgYSBuZXcgaW5zdGFuY2Ugb2YgaXQgaXMuCiAgICAgICAgICovCiAgICAgICAgdHJhbnNmb3JtUG9zaXRpb25Gcm9tU2NhbGVkU3BhY2UocG9zaXRpb24sIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5Q29tcG9uZW50cyhwb3NpdGlvbiwgdGhpcy5fcmFkaWksIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgRWxsaXBzb2lkIGFnYWluc3QgdGhlIHByb3ZpZGVkIEVsbGlwc29pZCBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW3JpZ2h0XSBUaGUgb3RoZXIgRWxsaXBzb2lkLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHMocmlnaHQpIHsKICAgICAgICAgIHJldHVybiB0aGlzID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHModGhpcy5fcmFkaWksIHJpZ2h0Ll9yYWRpaSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoaXMgRWxsaXBzb2lkIGluIHRoZSBmb3JtYXQgJyhyYWRpaS54LCByYWRpaS55LCByYWRpaS56KScuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBlbGxpcHNvaWQgaW4gdGhlIGZvcm1hdCAnKHJhZGlpLngsIHJhZGlpLnksIHJhZGlpLnopJy4KICAgICAgICAgKi8KICAgICAgICB0b1N0cmluZygpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9yYWRpaS50b1N0cmluZygpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIHBvaW50IHdoaWNoIGlzIHRoZSBpbnRlcnNlY3Rpb24gb2YgdGhlIHN1cmZhY2Ugbm9ybWFsIHdpdGggdGhlIHotYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcG9zaXRpb24gdGhlIHBvc2l0aW9uLiBtdXN0IGJlIG9uIHRoZSBzdXJmYWNlIG9mIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtidWZmZXIgPSAwLjBdIEEgYnVmZmVyIHRvIHN1YnRyYWN0IGZyb20gdGhlIGVsbGlwc29pZCBzaXplIHdoZW4gY2hlY2tpbmcgaWYgdGhlIHBvaW50IGlzIGluc2lkZSB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiBlYXJ0aCBjYXNlLCB3aXRoIGNvbW1vbiBlYXJ0aCBkYXR1bXMsIHRoZXJlIGlzIG5vIG5lZWQgZm9yIHRoaXMgYnVmZmVyIHNpbmNlIHRoZSBpbnRlcnNlY3Rpb24gcG9pbnQgaXMgYWx3YXlzIChyZWxhdGl2ZWx5KSB2ZXJ5IGNsb3NlIHRvIHRoZSBjZW50ZXIuCiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluIFdHUzg0IGRhdHVtLCBpbnRlcnNlY3Rpb24gcG9pbnQgaXMgYXQgbWF4IHogPSArLTQyODQxLjMxMTUxMzMxMzgyICgwLjY3MyUgb2Ygei1heGlzKS4KICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW50ZXJzZWN0aW9uIHBvaW50IGNvdWxkIGJlIG91dHNpZGUgdGhlIGVsbGlwc29pZCBpZiB0aGUgcmF0aW8gb2YgTWFqb3JBeGlzIC8gQXhpc09mUm90YXRpb24gaXMgYmlnZ2VyIHRoYW4gdGhlIHNxdWFyZSByb290IG9mIDIKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBjYXJ0ZXNpYW4gdG8gd2hpY2ggdG8gY29weSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgdG8gY3JlYXRlIGFuZAogICAgICAgICAqICAgICAgICByZXR1cm4gYSBuZXcgaW5zdGFuY2UuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjMgfCB1bmRlZmluZWR9IHRoZSBpbnRlcnNlY3Rpb24gcG9pbnQgaWYgaXQncyBpbnNpZGUgdGhlIGVsbGlwc29pZCwgdW5kZWZpbmVkIG90aGVyd2lzZQogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IHBvc2l0aW9uIGlzIHJlcXVpcmVkLgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBFbGxpcHNvaWQgbXVzdCBiZSBhbiBlbGxpcHNvaWQgb2YgcmV2b2x1dGlvbiAocmFkaWkueCA9PSByYWRpaS55KS4KICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gRWxsaXBzb2lkLnJhZGlpLnogbXVzdCBiZSBncmVhdGVyIHRoYW4gMC4KICAgICAgICAgKi8KICAgICAgICBnZXRTdXJmYWNlTm9ybWFsSW50ZXJzZWN0aW9uV2l0aFpBeGlzKHBvc2l0aW9uLCBidWZmZXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwb3NpdGlvbiIsIHBvc2l0aW9uKTsKICAgICAgICAgIGlmICghTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIHRoaXMuX3JhZGlpLngsCiAgICAgICAgICAgIHRoaXMuX3JhZGlpLnksCiAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTUKICAgICAgICAgICkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgIkVsbGlwc29pZCBtdXN0IGJlIGFuIGVsbGlwc29pZCBvZiByZXZvbHV0aW9uIChyYWRpaS54ID09IHJhZGlpLnkpIgogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuKCJFbGxpcHNvaWQucmFkaWkueiIsIHRoaXMuX3JhZGlpLnosIDApOwogICAgICAgICAgYnVmZmVyID0gYnVmZmVyID8/IDA7CiAgICAgICAgICBjb25zdCBzcXVhcmVkWE92ZXJTcXVhcmVkWiA9IHRoaXMuX3NxdWFyZWRYT3ZlclNxdWFyZWRaOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IDA7CiAgICAgICAgICByZXN1bHQueSA9IDA7CiAgICAgICAgICByZXN1bHQueiA9IHBvc2l0aW9uLnogKiAoMSAtIHNxdWFyZWRYT3ZlclNxdWFyZWRaKTsKICAgICAgICAgIGlmIChNYXRoLmFicyhyZXN1bHQueikgPj0gdGhpcy5fcmFkaWkueiAtIGJ1ZmZlcikgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGVsbGlwc29pZCBjdXJ2YXR1cmVzIGF0IGEgZ2l2ZW4gcG9zaXRpb24gb24gdGhlIHN1cmZhY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHN1cmZhY2VQb3NpdGlvbiBUaGUgcG9zaXRpb24gb24gdGhlIGVsbGlwc29pZCBzdXJmYWNlIHdoZXJlIGN1cnZhdHVyZXMgd2lsbCBiZSBjYWxjdWxhdGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gW3Jlc3VsdF0gVGhlIGNhcnRlc2lhbiB0byB3aGljaCB0byBjb3B5IHRoZSByZXN1bHQsIG9yIHVuZGVmaW5lZCB0byBjcmVhdGUgYW5kIHJldHVybiBhIG5ldyBpbnN0YW5jZS4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIGxvY2FsIGN1cnZhdHVyZSBvZiB0aGUgZWxsaXBzb2lkIHN1cmZhY2UgYXQgdGhlIHByb3ZpZGVkIHBvc2l0aW9uLCBpbiBlYXN0IGFuZCBub3J0aCBkaXJlY3Rpb25zLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IHBvc2l0aW9uIGlzIHJlcXVpcmVkLgogICAgICAgICAqLwogICAgICAgIGdldExvY2FsQ3VydmF0dXJlKHN1cmZhY2VQb3NpdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInN1cmZhY2VQb3NpdGlvbiIsIHN1cmZhY2VQb3NpdGlvbik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHByaW1lVmVydGljYWxFbmRwb2ludCA9IHRoaXMuZ2V0U3VyZmFjZU5vcm1hbEludGVyc2VjdGlvbldpdGhaQXhpcygKICAgICAgICAgICAgc3VyZmFjZVBvc2l0aW9uLAogICAgICAgICAgICAwLAogICAgICAgICAgICBzY3JhdGNoRW5kcG9pbnQKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwcmltZVZlcnRpY2FsUmFkaXVzID0gQ2FydGVzaWFuM19kZWZhdWx0LmRpc3RhbmNlKAogICAgICAgICAgICBzdXJmYWNlUG9zaXRpb24sCiAgICAgICAgICAgIHByaW1lVmVydGljYWxFbmRwb2ludAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHJhZGl1c1JhdGlvID0gdGhpcy5taW5pbXVtUmFkaXVzICogcHJpbWVWZXJ0aWNhbFJhZGl1cyAvIHRoaXMubWF4aW11bVJhZGl1cyAqKiAyOwogICAgICAgICAgY29uc3QgbWVyaWRpb25hbFJhZGl1cyA9IHByaW1lVmVydGljYWxSYWRpdXMgKiByYWRpdXNSYXRpbyAqKiAyOwogICAgICAgICAgcmV0dXJuIENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgICAgICAgIDEgLyBwcmltZVZlcnRpY2FsUmFkaXVzLAogICAgICAgICAgICAxIC8gbWVyaWRpb25hbFJhZGl1cywKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhbiBhcHByb3hpbWF0aW9uIG9mIHRoZSBzdXJmYWNlIGFyZWEgb2YgYSByZWN0YW5nbGUgb24gdGhlIHN1cmZhY2Ugb2YgYW4gZWxsaXBzb2lkIHVzaW5nCiAgICAgICAgICogR2F1c3MtTGVnZW5kcmUgMTB0aCBvcmRlciBxdWFkcmF0dXJlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBUaGUgcmVjdGFuZ2xlIHVzZWQgZm9yIGNvbXB1dGluZyB0aGUgc3VyZmFjZSBhcmVhLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBhcHByb3hpbWF0ZSBhcmVhIG9mIHRoZSByZWN0YW5nbGUgb24gdGhlIHN1cmZhY2Ugb2YgdGhpcyBlbGxpcHNvaWQuCiAgICAgICAgICovCiAgICAgICAgc3VyZmFjZUFyZWEocmVjdGFuZ2xlKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlY3RhbmdsZSIsIHJlY3RhbmdsZSk7CiAgICAgICAgICBjb25zdCBtaW5Mb25naXR1ZGUgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGxldCBtYXhMb25naXR1ZGUgPSByZWN0YW5nbGUuZWFzdDsKICAgICAgICAgIGNvbnN0IG1pbkxhdGl0dWRlID0gcmVjdGFuZ2xlLnNvdXRoOwogICAgICAgICAgY29uc3QgbWF4TGF0aXR1ZGUgPSByZWN0YW5nbGUubm9ydGg7CiAgICAgICAgICB3aGlsZSAobWF4TG9uZ2l0dWRlIDwgbWluTG9uZ2l0dWRlKSB7CiAgICAgICAgICAgIG1heExvbmdpdHVkZSArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgcmFkaWlTcXVhcmVkID0gdGhpcy5fcmFkaWlTcXVhcmVkOwogICAgICAgICAgY29uc3QgYTIyID0gcmFkaWlTcXVhcmVkLng7CiAgICAgICAgICBjb25zdCBiMiA9IHJhZGlpU3F1YXJlZC55OwogICAgICAgICAgY29uc3QgYzIgPSByYWRpaVNxdWFyZWQuejsKICAgICAgICAgIGNvbnN0IGEyYjIgPSBhMjIgKiBiMjsKICAgICAgICAgIHJldHVybiBnYXVzc0xlZ2VuZHJlUXVhZHJhdHVyZShtaW5MYXRpdHVkZSwgbWF4TGF0aXR1ZGUsIGZ1bmN0aW9uKGxhdCkgewogICAgICAgICAgICBjb25zdCBzaW5QaGkgPSBNYXRoLmNvcyhsYXQpOwogICAgICAgICAgICBjb25zdCBjb3NQaGkgPSBNYXRoLnNpbihsYXQpOwogICAgICAgICAgICByZXR1cm4gTWF0aC5jb3MobGF0KSAqIGdhdXNzTGVnZW5kcmVRdWFkcmF0dXJlKG1pbkxvbmdpdHVkZSwgbWF4TG9uZ2l0dWRlLCBmdW5jdGlvbihsb24pIHsKICAgICAgICAgICAgICBjb25zdCBjb3NUaGV0YSA9IE1hdGguY29zKGxvbik7CiAgICAgICAgICAgICAgY29uc3Qgc2luVGhldGEgPSBNYXRoLnNpbihsb24pOwogICAgICAgICAgICAgIHJldHVybiBNYXRoLnNxcnQoCiAgICAgICAgICAgICAgICBhMmIyICogY29zUGhpICogY29zUGhpICsgYzIgKiAoYjIgKiBjb3NUaGV0YSAqIGNvc1RoZXRhICsgYTIyICogc2luVGhldGEgKiBzaW5UaGV0YSkgKiBzaW5QaGkgKiBzaW5QaGkKICAgICAgICAgICAgICApOwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfTsKICAgICAgRWxsaXBzb2lkLldHUzg0ID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgRWxsaXBzb2lkKDYzNzgxMzcsIDYzNzgxMzcsIDYzNTY3NTIzMTQyNDUxNzllLTkpCiAgICAgICk7CiAgICAgIEVsbGlwc29pZC5VTklUX1NQSEVSRSA9IE9iamVjdC5mcmVlemUobmV3IEVsbGlwc29pZCgxLCAxLCAxKSk7CiAgICAgIEVsbGlwc29pZC5NT09OID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgRWxsaXBzb2lkKAogICAgICAgICAgTWF0aF9kZWZhdWx0LkxVTkFSX1JBRElVUywKICAgICAgICAgIE1hdGhfZGVmYXVsdC5MVU5BUl9SQURJVVMsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuTFVOQVJfUkFESVVTCiAgICAgICAgKQogICAgICApOwogICAgICBFbGxpcHNvaWQuTUFSUyA9IE9iamVjdC5mcmVlemUobmV3IEVsbGlwc29pZCgzMzk2MTkwLCAzMzk2MTkwLCAzMzc2MjAwKSk7CiAgICAgIEVsbGlwc29pZC5fZGVmYXVsdCA9IEVsbGlwc29pZC5XR1M4NDsKICAgICAgRWxsaXBzb2lkLnBhY2tlZExlbmd0aCA9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgIEVsbGlwc29pZC5wcm90b3R5cGUuZ2VvY2VudHJpY1N1cmZhY2VOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplOwogICAgICBjYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbk5vcm1hbCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW5LID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY04yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY1AyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpY0gyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRW5kcG9pbnQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGFic2Npc3NhcyA9IFsKICAgICAgICAwLjE0ODg3NDMzODk4MTYzLAogICAgICAgIDAuNDMzMzk1Mzk0MTI5MjUsCiAgICAgICAgMC42Nzk0MDk1NjgyOTkwMiwKICAgICAgICAwLjg2NTA2MzM2NjY4ODk4LAogICAgICAgIDAuOTczOTA2NTI4NTE3MTcsCiAgICAgICAgMAogICAgICBdOwogICAgICB3ZWlnaHRzID0gWwogICAgICAgIDAuMjk1NTI0MjI0NzE0NzUsCiAgICAgICAgMC4yNjkyNjY3MTkzMDk5OSwKICAgICAgICAwLjIxOTA4NjM2MjUxNTk4LAogICAgICAgIDAuMTQ5NDUxMzQ5MTUwNTgsCiAgICAgICAgMC4wNjY2NzEzNDQzMDg2ODQsCiAgICAgICAgMAogICAgICBdOwogICAgICBFbGxpcHNvaWRfZGVmYXVsdCA9IEVsbGlwc29pZDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0dlb2dyYXBoaWNQcm9qZWN0aW9uLmpzCiAgdmFyIEdlb2dyYXBoaWNQcm9qZWN0aW9uLCBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0OwogIHZhciBpbml0X0dlb2dyYXBoaWNQcm9qZWN0aW9uID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9ncmFwaGljUHJvamVjdGlvbi5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBHZW9ncmFwaGljUHJvamVjdGlvbiA9IGNsYXNzIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW2VsbGlwc29pZD1FbGxpcHNvaWQuZGVmYXVsdF0gVGhlIGVsbGlwc29pZC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihlbGxpcHNvaWQpIHsKICAgICAgICAgIHRoaXMuX2VsbGlwc29pZCA9IGVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgICAgdGhpcy5fc2VtaW1ham9yQXhpcyA9IHRoaXMuX2VsbGlwc29pZC5tYXhpbXVtUmFkaXVzOwogICAgICAgICAgdGhpcy5fb25lT3ZlclNlbWltYWpvckF4aXMgPSAxIC8gdGhpcy5fc2VtaW1ham9yQXhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUge0BsaW5rIEVsbGlwc29pZH0uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGdldCBlbGxpcHNvaWQoKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fZWxsaXBzb2lkOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBQcm9qZWN0cyBhIHNldCBvZiB7QGxpbmsgQ2FydG9ncmFwaGljfSBjb29yZGluYXRlcywgaW4gcmFkaWFucywgdG8gbWFwIGNvb3JkaW5hdGVzLCBpbiBtZXRlcnMuCiAgICAgICAgICogWCBhbmQgWSBhcmUgdGhlIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUsIHJlc3BlY3RpdmVseSwgbXVsdGlwbGllZCBieSB0aGUgbWF4aW11bSByYWRpdXMgb2YgdGhlCiAgICAgICAgICogZWxsaXBzb2lkLiAgWiBpcyB0aGUgdW5tb2RpZmllZCBoZWlnaHQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gY2FydG9ncmFwaGljIFRoZSBjb29yZGluYXRlcyB0byBwcm9qZWN0LgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW3Jlc3VsdF0gQW4gaW5zdGFuY2UgaW50byB3aGljaCB0byBjb3B5IHRoZSByZXN1bHQuICBJZiB0aGlzIHBhcmFtZXRlciBpcwogICAgICAgICAqICAgICAgICB1bmRlZmluZWQsIGEgbmV3IGluc3RhbmNlIGlzIGNyZWF0ZWQgYW5kIHJldHVybmVkLgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgcHJvamVjdGVkIGNvb3JkaW5hdGVzLiAgSWYgdGhlIHJlc3VsdCBwYXJhbWV0ZXIgaXMgbm90IHVuZGVmaW5lZCwgdGhlCiAgICAgICAgICogICAgICAgICAgY29vcmRpbmF0ZXMgYXJlIGNvcGllZCB0aGVyZSBhbmQgdGhhdCBpbnN0YW5jZSBpcyByZXR1cm5lZC4gIE90aGVyd2lzZSwgYSBuZXcgaW5zdGFuY2UgaXMKICAgICAgICAgKiAgICAgICAgICBjcmVhdGVkIGFuZCByZXR1cm5lZC4KICAgICAgICAgKi8KICAgICAgICBwcm9qZWN0KGNhcnRvZ3JhcGhpYzIsIHJlc3VsdCkgewogICAgICAgICAgY29uc3Qgc2VtaW1ham9yQXhpcyA9IHRoaXMuX3NlbWltYWpvckF4aXM7CiAgICAgICAgICBjb25zdCB4MiA9IGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlICogc2VtaW1ham9yQXhpczsKICAgICAgICAgIGNvbnN0IHkyID0gY2FydG9ncmFwaGljMi5sYXRpdHVkZSAqIHNlbWltYWpvckF4aXM7CiAgICAgICAgICBjb25zdCB6MiA9IGNhcnRvZ3JhcGhpYzIuaGVpZ2h0OwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCh4MiwgeTIsIHoyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFVucHJvamVjdHMgYSBzZXQgb2YgcHJvamVjdGVkIHtAbGluayBDYXJ0ZXNpYW4zfSBjb29yZGluYXRlcywgaW4gbWV0ZXJzLCB0byB7QGxpbmsgQ2FydG9ncmFwaGljfQogICAgICAgICAqIGNvb3JkaW5hdGVzLCBpbiByYWRpYW5zLiAgTG9uZ2l0dWRlIGFuZCBMYXRpdHVkZSBhcmUgdGhlIFggYW5kIFkgY29vcmRpbmF0ZXMsIHJlc3BlY3RpdmVseSwKICAgICAgICAgKiBkaXZpZGVkIGJ5IHRoZSBtYXhpbXVtIHJhZGl1cyBvZiB0aGUgZWxsaXBzb2lkLiAgSGVpZ2h0IGlzIHRoZSB1bm1vZGlmaWVkIFogY29vcmRpbmF0ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gcG9zaXRpb24gdG8gdW5wcm9qZWN0IHdpdGggaGVpZ2h0ICh6KSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIEFuIGluc3RhbmNlIGludG8gd2hpY2ggdG8gY29weSB0aGUgcmVzdWx0LiAgSWYgdGhpcyBwYXJhbWV0ZXIgaXMKICAgICAgICAgKiAgICAgICAgdW5kZWZpbmVkLCBhIG5ldyBpbnN0YW5jZSBpcyBjcmVhdGVkIGFuZCByZXR1cm5lZC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydG9ncmFwaGljfSBUaGUgdW5wcm9qZWN0ZWQgY29vcmRpbmF0ZXMuICBJZiB0aGUgcmVzdWx0IHBhcmFtZXRlciBpcyBub3QgdW5kZWZpbmVkLCB0aGUKICAgICAgICAgKiAgICAgICAgICBjb29yZGluYXRlcyBhcmUgY29waWVkIHRoZXJlIGFuZCB0aGF0IGluc3RhbmNlIGlzIHJldHVybmVkLiAgT3RoZXJ3aXNlLCBhIG5ldyBpbnN0YW5jZSBpcwogICAgICAgICAqICAgICAgICAgIGNyZWF0ZWQgYW5kIHJldHVybmVkLgogICAgICAgICAqLwogICAgICAgIHVucHJvamVjdChjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjYXJ0ZXNpYW4xMSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNhcnRlc2lhbiBpcyByZXF1aXJlZCIpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgb25lT3ZlckVhcnRoU2VtaW1ham9yQXhpcyA9IHRoaXMuX29uZU92ZXJTZW1pbWFqb3JBeGlzOwogICAgICAgICAgY29uc3QgbG9uZ2l0dWRlID0gY2FydGVzaWFuMTEueCAqIG9uZU92ZXJFYXJ0aFNlbWltYWpvckF4aXM7CiAgICAgICAgICBjb25zdCBsYXRpdHVkZSA9IGNhcnRlc2lhbjExLnkgKiBvbmVPdmVyRWFydGhTZW1pbWFqb3JBeGlzOwogICAgICAgICAgY29uc3QgaGVpZ2h0ID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdChsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGxvbmdpdHVkZTsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IGxhdGl0dWRlOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICB9OwogICAgICBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0ID0gR2VvZ3JhcGhpY1Byb2plY3Rpb247CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9JbnRlcnNlY3QuanMKICB2YXIgSW50ZXJzZWN0LCBJbnRlcnNlY3RfZGVmYXVsdDsKICB2YXIgaW5pdF9JbnRlcnNlY3QgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0ludGVyc2VjdC5qcyIoKSB7CiAgICAgIEludGVyc2VjdCA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHRoYXQgYW4gb2JqZWN0IGlzIG5vdCBjb250YWluZWQgd2l0aGluIHRoZSBmcnVzdHVtLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBPVVRTSURFOiAtMSwKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHRoYXQgYW4gb2JqZWN0IGludGVyc2VjdHMgb25lIG9mIHRoZSBmcnVzdHVtJ3MgcGxhbmVzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBJTlRFUlNFQ1RJTkc6IDAsCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyB0aGF0IGFuIG9iamVjdCBpcyBmdWxseSB3aXRoaW4gdGhlIGZydXN0dW0uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIElOU0lERTogMQogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKEludGVyc2VjdCk7CiAgICAgIEludGVyc2VjdF9kZWZhdWx0ID0gSW50ZXJzZWN0OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSW50ZXJ2YWwuanMKICBmdW5jdGlvbiBJbnRlcnZhbChzdGFydCwgc3RvcCkgewogICAgdGhpcy5zdGFydCA9IHN0YXJ0ID8/IDA7CiAgICB0aGlzLnN0b3AgPSBzdG9wID8/IDA7CiAgfQogIHZhciBJbnRlcnZhbF9kZWZhdWx0OwogIHZhciBpbml0X0ludGVydmFsID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9JbnRlcnZhbC5qcyIoKSB7CiAgICAgIEludGVydmFsX2RlZmF1bHQgPSBJbnRlcnZhbDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL01hdHJpeDMuanMKICBmdW5jdGlvbiBjb21wdXRlRnJvYmVuaXVzTm9ybShtYXRyaXgpIHsKICAgIGxldCBub3JtID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCA5OyArK2kyKSB7CiAgICAgIGNvbnN0IHRlbXAgPSBtYXRyaXhbaTJdOwogICAgICBub3JtICs9IHRlbXAgKiB0ZW1wOwogICAgfQogICAgcmV0dXJuIE1hdGguc3FydChub3JtKTsKICB9CiAgZnVuY3Rpb24gb2ZmRGlhZ29uYWxGcm9iZW5pdXNOb3JtKG1hdHJpeCkgewogICAgbGV0IG5vcm0gPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IDM7ICsraTIpIHsKICAgICAgY29uc3QgdGVtcCA9IG1hdHJpeFtNYXRyaXgzLmdldEVsZW1lbnRJbmRleChjb2xWYWxbaTJdLCByb3dWYWxbaTJdKV07CiAgICAgIG5vcm0gKz0gMiAqIHRlbXAgKiB0ZW1wOwogICAgfQogICAgcmV0dXJuIE1hdGguc3FydChub3JtKTsKICB9CiAgZnVuY3Rpb24gc2h1ckRlY29tcG9zaXRpb24obWF0cml4LCByZXN1bHQpIHsKICAgIGNvbnN0IHRvbGVyYW5jZSA9IE1hdGhfZGVmYXVsdC5FUFNJTE9OMTU7CiAgICBsZXQgbWF4RGlhZ29uYWwgPSAwOwogICAgbGV0IHJvdEF4aXMyID0gMTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCAzOyArK2kyKSB7CiAgICAgIGNvbnN0IHRlbXAgPSBNYXRoLmFicygKICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIFRPRE8odHNkLWpzZG9jKTogUmVxdWlyZXMgaW5kZXggc2lnbmF0dXJlIHN1cHBvcnQuCiAgICAgICAgbWF0cml4W01hdHJpeDMuZ2V0RWxlbWVudEluZGV4KGNvbFZhbFtpMl0sIHJvd1ZhbFtpMl0pXQogICAgICApOwogICAgICBpZiAodGVtcCA+IG1heERpYWdvbmFsKSB7CiAgICAgICAgcm90QXhpczIgPSBpMjsKICAgICAgICBtYXhEaWFnb25hbCA9IHRlbXA7CiAgICAgIH0KICAgIH0KICAgIGxldCBjMiA9IDE7CiAgICBsZXQgczIgPSAwOwogICAgY29uc3QgcDIgPSByb3dWYWxbcm90QXhpczJdOwogICAgY29uc3QgcTMgPSBjb2xWYWxbcm90QXhpczJdOwogICAgaWYgKE1hdGguYWJzKG1hdHJpeFtNYXRyaXgzLmdldEVsZW1lbnRJbmRleChxMywgcDIpXSkgPiB0b2xlcmFuY2UpIHsKICAgICAgY29uc3QgcXEgPSBtYXRyaXhbTWF0cml4My5nZXRFbGVtZW50SW5kZXgocTMsIHEzKV07CiAgICAgIGNvbnN0IHBwID0gbWF0cml4W01hdHJpeDMuZ2V0RWxlbWVudEluZGV4KHAyLCBwMildOwogICAgICBjb25zdCBxcCA9IG1hdHJpeFtNYXRyaXgzLmdldEVsZW1lbnRJbmRleChxMywgcDIpXTsKICAgICAgY29uc3QgdGF1ID0gKHFxIC0gcHApIC8gMiAvIHFwOwogICAgICBsZXQgdDI7CiAgICAgIGlmICh0YXUgPCAwKSB7CiAgICAgICAgdDIgPSAtMSAvICgtdGF1ICsgTWF0aC5zcXJ0KDEgKyB0YXUgKiB0YXUpKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0MiA9IDEgLyAodGF1ICsgTWF0aC5zcXJ0KDEgKyB0YXUgKiB0YXUpKTsKICAgICAgfQogICAgICBjMiA9IDEgLyBNYXRoLnNxcnQoMSArIHQyICogdDIpOwogICAgICBzMiA9IHQyICogYzI7CiAgICB9CiAgICByZXN1bHQgPSBNYXRyaXgzLmNsb25lKE1hdHJpeDMuSURFTlRJVFksIHJlc3VsdCk7CiAgICByZXN1bHRbTWF0cml4My5nZXRFbGVtZW50SW5kZXgocDIsIHAyKV0gPSByZXN1bHRbTWF0cml4My5nZXRFbGVtZW50SW5kZXgocTMsIHEzKV0gPSBjMjsKICAgIHJlc3VsdFtNYXRyaXgzLmdldEVsZW1lbnRJbmRleChxMywgcDIpXSA9IHMyOwogICAgcmVzdWx0W01hdHJpeDMuZ2V0RWxlbWVudEluZGV4KHAyLCBxMyldID0gLXMyOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgdmFyIE1hdHJpeDMsIHNjYWxlU2NyYXRjaDEsIHNjYWxlU2NyYXRjaDIsIHNjcmF0Y2hDb2x1bW4sIHNjYWxlU2NyYXRjaDMsIHNjYWxlU2NyYXRjaDQsIHNjYWxlU2NyYXRjaDUsIGpNYXRyaXgsIGpNYXRyaXhUcmFuc3Bvc2UsIHNjcmF0Y2hUcmFuc3Bvc2VNYXRyaXgsIHJvd1ZhbCwgY29sVmFsLCBNYXRyaXgzX2RlZmF1bHQ7CiAgdmFyIGluaXRfTWF0cml4MyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvTWF0cml4My5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBNYXRyaXgzID0gY2xhc3MgX01hdHJpeDMgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzA9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3cwPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDAuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4yUm93MD0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDIsIHJvdyAwLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzE9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3cxPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDEuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4yUm93MT0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDIsIHJvdyAxLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzI9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMi4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3cyPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDIuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4yUm93Mj0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDIsIHJvdyAyLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKGNvbHVtbjBSb3cwLCBjb2x1bW4xUm93MCwgY29sdW1uMlJvdzAsIGNvbHVtbjBSb3cxLCBjb2x1bW4xUm93MSwgY29sdW1uMlJvdzEsIGNvbHVtbjBSb3cyLCBjb2x1bW4xUm93MiwgY29sdW1uMlJvdzIpIHsKICAgICAgICAgIHRoaXNbMF0gPSBjb2x1bW4wUm93MCA/PyAwOwogICAgICAgICAgdGhpc1sxXSA9IGNvbHVtbjBSb3cxID8/IDA7CiAgICAgICAgICB0aGlzWzJdID0gY29sdW1uMFJvdzIgPz8gMDsKICAgICAgICAgIHRoaXNbM10gPSBjb2x1bW4xUm93MCA/PyAwOwogICAgICAgICAgdGhpc1s0XSA9IGNvbHVtbjFSb3cxID8/IDA7CiAgICAgICAgICB0aGlzWzVdID0gY29sdW1uMVJvdzIgPz8gMDsKICAgICAgICAgIHRoaXNbNl0gPSBjb2x1bW4yUm93MCA/PyAwOwogICAgICAgICAgdGhpc1s3XSA9IGNvbHVtbjJSb3cxID8/IDA7CiAgICAgICAgICB0aGlzWzhdID0gY29sdW1uMlJvdzIgPz8gMDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU3RvcmVzIHRoZSBwcm92aWRlZCBpbnN0YW5jZSBpbnRvIHRoZSBwcm92aWRlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gdmFsdWUgVGhlIHZhbHVlIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIGFycmF5IHRvIHBhY2sgaW50by4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIGluZGV4IGludG8gdGhlIGFycmF5IGF0IHdoaWNoIHRvIHN0YXJ0IHBhY2tpbmcgdGhlIGVsZW1lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgYXJyYXkgdGhhdCB3YXMgcGFja2VkIGludG8KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFjayh2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVswXTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVsxXTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVsyXTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVszXTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVs0XTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVs1XTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVs2XTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVs3XTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWVbOF07CiAgICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhbiBpbnN0YW5jZSBmcm9tIGEgcGFja2VkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIHN0YXJ0aW5nIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIGJlIHVucGFja2VkLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9NYXRyaXgzKCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzFdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbM10gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzRdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFs1XSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbNl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzddID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFs4XSA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRmxhdHRlbnMgYW4gYXJyYXkgb2YgTWF0cml4M3MgaW50byBhbiBhcnJheSBvZiBjb21wb25lbnRzLiBUaGUgY29tcG9uZW50cwogICAgICAgICAqIGFyZSBzdG9yZWQgaW4gY29sdW1uLW1ham9yIG9yZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzW119IGFycmF5IFRoZSBhcnJheSBvZiBtYXRyaWNlcyB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtyZXN1bHRdIFRoZSBhcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuIElmIHRoaXMgaXMgYSB0eXBlZCBhcnJheSwgaXQgbXVzdCBoYXZlIGFycmF5Lmxlbmd0aCAqIDkgY29tcG9uZW50cywgZWxzZSBhIHtAbGluayBEZXZlbG9wZXJFcnJvcn0gd2lsbCBiZSB0aHJvd24uIElmIGl0IGlzIGEgcmVndWxhciBhcnJheSwgaXQgd2lsbCBiZSByZXNpemVkIHRvIGhhdmUgKGFycmF5Lmxlbmd0aCAqIDkpIGVsZW1lbnRzLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBjb25zdCByZXN1bHRMZW5ndGggPSBsZW5ndGggKiA5OwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkocmVzdWx0TGVuZ3RoKTsKICAgICAgICAgIH0gZWxzZSBpZiAoIUFycmF5LmlzQXJyYXkocmVzdWx0KSAmJiByZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgIklmIHJlc3VsdCBpcyBhIHR5cGVkIGFycmF5LCBpdCBtdXN0IGhhdmUgZXhhY3RseSBhcnJheS5sZW5ndGggKiA5IGVsZW1lbnRzIgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IHJlc3VsdExlbmd0aDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgX01hdHJpeDMucGFjayhhcnJheVtpMl0sIHJlc3VsdCwgaTIgKiA5KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFVucGFja3MgYW4gYXJyYXkgb2YgY29sdW1uLW1ham9yIG1hdHJpeCBjb21wb25lbnRzIGludG8gYW4gYXJyYXkgb2YgTWF0cml4M3MuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheSBUaGUgYXJyYXkgb2YgY29tcG9uZW50cyB0byB1bnBhY2suCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzW119IFtyZXN1bHRdIFRoZSBhcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDNbXX0gVGhlIHVucGFja2VkIGFycmF5LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2tBcnJheShhcnJheSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImFycmF5Lmxlbmd0aCIsIGFycmF5Lmxlbmd0aCwgOSk7CiAgICAgICAgICBpZiAoYXJyYXkubGVuZ3RoICUgOSAhPT0gMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgbGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA5LiIpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkobGVuZ3RoIC8gOSk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoIC8gOTsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDkpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSBpMiAvIDk7CiAgICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBfTWF0cml4My51bnBhY2soYXJyYXksIGkyLCByZXN1bHRbaW5kZXhdKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIER1cGxpY2F0ZXMgYSBNYXRyaXgzIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byBkdXBsaWNhdGUuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgTWF0cml4MyBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4gKFJldHVybnMgdW5kZWZpbmVkIGlmIG1hdHJpeCBpcyB1bmRlZmluZWQpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsb25lKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtYXRyaXgpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX01hdHJpeDMoCiAgICAgICAgICAgICAgbWF0cml4WzBdLAogICAgICAgICAgICAgIG1hdHJpeFszXSwKICAgICAgICAgICAgICBtYXRyaXhbNl0sCiAgICAgICAgICAgICAgbWF0cml4WzFdLAogICAgICAgICAgICAgIG1hdHJpeFs0XSwKICAgICAgICAgICAgICBtYXRyaXhbN10sCiAgICAgICAgICAgICAgbWF0cml4WzJdLAogICAgICAgICAgICAgIG1hdHJpeFs1XSwKICAgICAgICAgICAgICBtYXRyaXhbOF0KICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBNYXRyaXgzIGluc3RhbmNlIGZyb20gYSBjb2x1bW4tbWFqb3Igb3JkZXIgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSB2YWx1ZXMgVGhlIGNvbHVtbi1tYWpvciBvcmRlciBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Db2x1bW5NYWpvckFycmF5KHZhbHVlcywgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlcyIsIHZhbHVlcyk7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDMuY2xvbmUodmFsdWVzLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgTWF0cml4MyBpbnN0YW5jZSBmcm9tIGEgcm93LW1ham9yIG9yZGVyIGFycmF5LgogICAgICAgICAqIFRoZSByZXN1bHRpbmcgbWF0cml4IHdpbGwgYmUgaW4gY29sdW1uLW1ham9yIG9yZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gdmFsdWVzIFRoZSByb3ctbWFqb3Igb3JkZXIgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXgzIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm93TWFqb3JBcnJheSh2YWx1ZXMsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2YWx1ZXMiLCB2YWx1ZXMpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKAogICAgICAgICAgICAgIHZhbHVlc1swXSwKICAgICAgICAgICAgICB2YWx1ZXNbMV0sCiAgICAgICAgICAgICAgdmFsdWVzWzJdLAogICAgICAgICAgICAgIHZhbHVlc1szXSwKICAgICAgICAgICAgICB2YWx1ZXNbNF0sCiAgICAgICAgICAgICAgdmFsdWVzWzVdLAogICAgICAgICAgICAgIHZhbHVlc1s2XSwKICAgICAgICAgICAgICB2YWx1ZXNbN10sCiAgICAgICAgICAgICAgdmFsdWVzWzhdCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSB2YWx1ZXNbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSB2YWx1ZXNbM107CiAgICAgICAgICByZXN1bHRbMl0gPSB2YWx1ZXNbNl07CiAgICAgICAgICByZXN1bHRbM10gPSB2YWx1ZXNbMV07CiAgICAgICAgICByZXN1bHRbNF0gPSB2YWx1ZXNbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSB2YWx1ZXNbN107CiAgICAgICAgICByZXN1bHRbNl0gPSB2YWx1ZXNbMl07CiAgICAgICAgICByZXN1bHRbN10gPSB2YWx1ZXNbNV07CiAgICAgICAgICByZXN1bHRbOF0gPSB2YWx1ZXNbOF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIDN4MyByb3RhdGlvbiBtYXRyaXggZnJvbSB0aGUgcHJvdmlkZWQgcXVhdGVybmlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UXVhdGVybmlvbn0gcXVhdGVybmlvbiB0aGUgcXVhdGVybmlvbiB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSAzeDMgcm90YXRpb24gbWF0cml4IGZyb20gdGhpcyBxdWF0ZXJuaW9uLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUXVhdGVybmlvbihxdWF0ZXJuaW9uLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicXVhdGVybmlvbiIsIHF1YXRlcm5pb24pOwogICAgICAgICAgY29uc3QgeDIgPSBxdWF0ZXJuaW9uLnggKiBxdWF0ZXJuaW9uLng7CiAgICAgICAgICBjb25zdCB4eSA9IHF1YXRlcm5pb24ueCAqIHF1YXRlcm5pb24ueTsKICAgICAgICAgIGNvbnN0IHh6ID0gcXVhdGVybmlvbi54ICogcXVhdGVybmlvbi56OwogICAgICAgICAgY29uc3QgeHcgPSBxdWF0ZXJuaW9uLnggKiBxdWF0ZXJuaW9uLnc7CiAgICAgICAgICBjb25zdCB5MiA9IHF1YXRlcm5pb24ueSAqIHF1YXRlcm5pb24ueTsKICAgICAgICAgIGNvbnN0IHl6ID0gcXVhdGVybmlvbi55ICogcXVhdGVybmlvbi56OwogICAgICAgICAgY29uc3QgeXcgPSBxdWF0ZXJuaW9uLnkgKiBxdWF0ZXJuaW9uLnc7CiAgICAgICAgICBjb25zdCB6MiA9IHF1YXRlcm5pb24ueiAqIHF1YXRlcm5pb24uejsKICAgICAgICAgIGNvbnN0IHp3ID0gcXVhdGVybmlvbi56ICogcXVhdGVybmlvbi53OwogICAgICAgICAgY29uc3QgdzIgPSBxdWF0ZXJuaW9uLncgKiBxdWF0ZXJuaW9uLnc7CiAgICAgICAgICBjb25zdCBtMDAgPSB4MiAtIHkyIC0gejIgKyB3MjsKICAgICAgICAgIGNvbnN0IG0wMSA9IDIgKiAoeHkgLSB6dyk7CiAgICAgICAgICBjb25zdCBtMDIgPSAyICogKHh6ICsgeXcpOwogICAgICAgICAgY29uc3QgbTEwID0gMiAqICh4eSArIHp3KTsKICAgICAgICAgIGNvbnN0IG0xMSA9IC14MiArIHkyIC0gejIgKyB3MjsKICAgICAgICAgIGNvbnN0IG0xMiA9IDIgKiAoeXogLSB4dyk7CiAgICAgICAgICBjb25zdCBtMjAgPSAyICogKHh6IC0geXcpOwogICAgICAgICAgY29uc3QgbTIxID0gMiAqICh5eiArIHh3KTsKICAgICAgICAgIGNvbnN0IG0yMiA9IC14MiAtIHkyICsgejIgKyB3MjsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4MyhtMDAsIG0wMSwgbTAyLCBtMTAsIG0xMSwgbTEyLCBtMjAsIG0yMSwgbTIyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IG0wMDsKICAgICAgICAgIHJlc3VsdFsxXSA9IG0xMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IG0yMDsKICAgICAgICAgIHJlc3VsdFszXSA9IG0wMTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG0xMTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG0yMTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG0wMjsKICAgICAgICAgIHJlc3VsdFs3XSA9IG0xMjsKICAgICAgICAgIHJlc3VsdFs4XSA9IG0yMjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgM3gzIHJvdGF0aW9uIG1hdHJpeCBmcm9tIHRoZSBwcm92aWRlZCBoZWFkaW5nUGl0Y2hSb2xsLiAoc2VlIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29udmVyc2lvbl9iZXR3ZWVuX3F1YXRlcm5pb25zX2FuZF9FdWxlcl9hbmdsZXMgKQogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtIZWFkaW5nUGl0Y2hSb2xsfSBoZWFkaW5nUGl0Y2hSb2xsIHRoZSBoZWFkaW5nUGl0Y2hSb2xsIHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIDN4MyByb3RhdGlvbiBtYXRyaXggZnJvbSB0aGlzIGhlYWRpbmdQaXRjaFJvbGwuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21IZWFkaW5nUGl0Y2hSb2xsKGhlYWRpbmdQaXRjaFJvbGwsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJoZWFkaW5nUGl0Y2hSb2xsIiwgaGVhZGluZ1BpdGNoUm9sbCk7CiAgICAgICAgICBjb25zdCBjb3NUaGV0YSA9IE1hdGguY29zKC1oZWFkaW5nUGl0Y2hSb2xsLnBpdGNoKTsKICAgICAgICAgIGNvbnN0IGNvc1BzaSA9IE1hdGguY29zKC1oZWFkaW5nUGl0Y2hSb2xsLmhlYWRpbmcpOwogICAgICAgICAgY29uc3QgY29zUGhpID0gTWF0aC5jb3MoaGVhZGluZ1BpdGNoUm9sbC5yb2xsKTsKICAgICAgICAgIGNvbnN0IHNpblRoZXRhID0gTWF0aC5zaW4oLWhlYWRpbmdQaXRjaFJvbGwucGl0Y2gpOwogICAgICAgICAgY29uc3Qgc2luUHNpID0gTWF0aC5zaW4oLWhlYWRpbmdQaXRjaFJvbGwuaGVhZGluZyk7CiAgICAgICAgICBjb25zdCBzaW5QaGkgPSBNYXRoLnNpbihoZWFkaW5nUGl0Y2hSb2xsLnJvbGwpOwogICAgICAgICAgY29uc3QgbTAwID0gY29zVGhldGEgKiBjb3NQc2k7CiAgICAgICAgICBjb25zdCBtMDEgPSAtY29zUGhpICogc2luUHNpICsgc2luUGhpICogc2luVGhldGEgKiBjb3NQc2k7CiAgICAgICAgICBjb25zdCBtMDIgPSBzaW5QaGkgKiBzaW5Qc2kgKyBjb3NQaGkgKiBzaW5UaGV0YSAqIGNvc1BzaTsKICAgICAgICAgIGNvbnN0IG0xMCA9IGNvc1RoZXRhICogc2luUHNpOwogICAgICAgICAgY29uc3QgbTExID0gY29zUGhpICogY29zUHNpICsgc2luUGhpICogc2luVGhldGEgKiBzaW5Qc2k7CiAgICAgICAgICBjb25zdCBtMTIgPSAtc2luUGhpICogY29zUHNpICsgY29zUGhpICogc2luVGhldGEgKiBzaW5Qc2k7CiAgICAgICAgICBjb25zdCBtMjAgPSAtc2luVGhldGE7CiAgICAgICAgICBjb25zdCBtMjEgPSBzaW5QaGkgKiBjb3NUaGV0YTsKICAgICAgICAgIGNvbnN0IG0yMiA9IGNvc1BoaSAqIGNvc1RoZXRhOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKG0wMCwgbTAxLCBtMDIsIG0xMCwgbTExLCBtMTIsIG0yMCwgbTIxLCBtMjIpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gbTAwOwogICAgICAgICAgcmVzdWx0WzFdID0gbTEwOwogICAgICAgICAgcmVzdWx0WzJdID0gbTIwOwogICAgICAgICAgcmVzdWx0WzNdID0gbTAxOwogICAgICAgICAgcmVzdWx0WzRdID0gbTExOwogICAgICAgICAgcmVzdWx0WzVdID0gbTIxOwogICAgICAgICAgcmVzdWx0WzZdID0gbTAyOwogICAgICAgICAgcmVzdWx0WzddID0gbTEyOwogICAgICAgICAgcmVzdWx0WzhdID0gbTIyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXgzIGluc3RhbmNlIHJlcHJlc2VudGluZyBhIG5vbi11bmlmb3JtIHNjYWxlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBzY2FsZSBUaGUgeCwgeSwgYW5kIHogc2NhbGUgZmFjdG9ycy4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIENyZWF0ZXMKICAgICAgICAgKiAvLyAgIFs3LjAsIDAuMCwgMC4wXQogICAgICAgICAqIC8vICAgWzAuMCwgOC4wLCAwLjBdCiAgICAgICAgICogLy8gICBbMC4wLCAwLjAsIDkuMF0KICAgICAgICAgKiBjb25zdCBtID0gQ2VzaXVtLk1hdHJpeDMuZnJvbVNjYWxlKG5ldyBDZXNpdW0uQ2FydGVzaWFuMyg3LjAsIDguMCwgOS4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21TY2FsZShzY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNjYWxlIiwgc2NhbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKAogICAgICAgICAgICAgIHNjYWxlLngsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgc2NhbGUueSwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICBzY2FsZS56CiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IDA7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFs1XSA9IDA7CiAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IHNjYWxlLno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDMgaW5zdGFuY2UgcmVwcmVzZW50aW5nIGEgdW5pZm9ybSBzY2FsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsZSBUaGUgdW5pZm9ybSBzY2FsZSBmYWN0b3IuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXgzIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBDcmVhdGVzCiAgICAgICAgICogLy8gICBbMi4wLCAwLjAsIDAuMF0KICAgICAgICAgKiAvLyAgIFswLjAsIDIuMCwgMC4wXQogICAgICAgICAqIC8vICAgWzAuMCwgMC4wLCAyLjBdCiAgICAgICAgICogY29uc3QgbSA9IENlc2l1bS5NYXRyaXgzLmZyb21Vbmlmb3JtU2NhbGUoMi4wKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVVuaWZvcm1TY2FsZShzY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxlIiwgc2NhbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKHNjYWxlLCAwLCAwLCAwLCBzY2FsZSwgMCwgMCwgMCwgc2NhbGUpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gc2NhbGU7CiAgICAgICAgICByZXN1bHRbMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgIHJlc3VsdFszXSA9IDA7CiAgICAgICAgICByZXN1bHRbNF0gPSBzY2FsZTsKICAgICAgICAgIHJlc3VsdFs1XSA9IDA7CiAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IHNjYWxlOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXgzIGluc3RhbmNlIHJlcHJlc2VudGluZyB0aGUgY3Jvc3MgcHJvZHVjdCBlcXVpdmFsZW50IG1hdHJpeCBvZiBhIENhcnRlc2lhbjMgdmVjdG9yLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSB2ZWN0b3IgdGhlIHZlY3RvciBvbiB0aGUgbGVmdCBoYW5kIHNpZGUgb2YgdGhlIGNyb3NzIHByb2R1Y3Qgb3BlcmF0aW9uLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4MyBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gQ3JlYXRlcwogICAgICAgICAqIC8vICAgWzAuMCwgLTkuMCwgIDguMF0KICAgICAgICAgKiAvLyAgIFs5LjAsICAwLjAsIC03LjBdCiAgICAgICAgICogLy8gICBbLTguMCwgNy4wLCAgMC4wXQogICAgICAgICAqIGNvbnN0IG0gPSBDZXNpdW0uTWF0cml4My5mcm9tQ3Jvc3NQcm9kdWN0KG5ldyBDZXNpdW0uQ2FydGVzaWFuMyg3LjAsIDguMCwgOS4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Dcm9zc1Byb2R1Y3QodmVjdG9yLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmVjdG9yIiwgdmVjdG9yKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4MygKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIC12ZWN0b3IueiwKICAgICAgICAgICAgICB2ZWN0b3IueSwKICAgICAgICAgICAgICB2ZWN0b3IueiwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIC12ZWN0b3IueCwKICAgICAgICAgICAgICAtdmVjdG9yLnksCiAgICAgICAgICAgICAgdmVjdG9yLngsCiAgICAgICAgICAgICAgMAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gMDsKICAgICAgICAgIHJlc3VsdFsxXSA9IHZlY3Rvci56OwogICAgICAgICAgcmVzdWx0WzJdID0gLXZlY3Rvci55OwogICAgICAgICAgcmVzdWx0WzNdID0gLXZlY3Rvci56OwogICAgICAgICAgcmVzdWx0WzRdID0gMDsKICAgICAgICAgIHJlc3VsdFs1XSA9IHZlY3Rvci54OwogICAgICAgICAgcmVzdWx0WzZdID0gdmVjdG9yLnk7CiAgICAgICAgICByZXN1bHRbN10gPSAtdmVjdG9yLng7CiAgICAgICAgICByZXN1bHRbOF0gPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJvdGF0aW9uIG1hdHJpeCBhcm91bmQgdGhlIHgtYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhbmdsZSBUaGUgYW5nbGUsIGluIHJhZGlhbnMsIG9mIHRoZSByb3RhdGlvbi4gIFBvc2l0aXZlIGFuZ2xlcyBhcmUgY291bnRlcmNsb2Nrd2lzZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIFJvdGF0ZSBhIHBvaW50IDQ1IGRlZ3JlZXMgY291bnRlcmNsb2Nrd2lzZSBhcm91bmQgdGhlIHgtYXhpcy4KICAgICAgICAgKiBjb25zdCBwID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDUsIDYsIDcpOwogICAgICAgICAqIGNvbnN0IG0gPSBDZXNpdW0uTWF0cml4My5mcm9tUm90YXRpb25YKENlc2l1bS5NYXRoLnRvUmFkaWFucyg0NS4wKSk7CiAgICAgICAgICogY29uc3Qgcm90YXRlZCA9IENlc2l1bS5NYXRyaXgzLm11bHRpcGx5QnlWZWN0b3IobSwgcCwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm90YXRpb25YKGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYW5nbGUiLCBhbmdsZSk7CiAgICAgICAgICBjb25zdCBjb3NBbmdsZSA9IE1hdGguY29zKGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHNpbkFuZ2xlID0gTWF0aC5zaW4oYW5nbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKAogICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgY29zQW5nbGUsCiAgICAgICAgICAgICAgLXNpbkFuZ2xlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgc2luQW5nbGUsCiAgICAgICAgICAgICAgY29zQW5nbGUKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IDE7CiAgICAgICAgICByZXN1bHRbMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgIHJlc3VsdFszXSA9IDA7CiAgICAgICAgICByZXN1bHRbNF0gPSBjb3NBbmdsZTsKICAgICAgICAgIHJlc3VsdFs1XSA9IHNpbkFuZ2xlOwogICAgICAgICAgcmVzdWx0WzZdID0gMDsKICAgICAgICAgIHJlc3VsdFs3XSA9IC1zaW5BbmdsZTsKICAgICAgICAgIHJlc3VsdFs4XSA9IGNvc0FuZ2xlOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJvdGF0aW9uIG1hdHJpeCBhcm91bmQgdGhlIHktYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhbmdsZSBUaGUgYW5nbGUsIGluIHJhZGlhbnMsIG9mIHRoZSByb3RhdGlvbi4gIFBvc2l0aXZlIGFuZ2xlcyBhcmUgY291bnRlcmNsb2Nrd2lzZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIFJvdGF0ZSBhIHBvaW50IDQ1IGRlZ3JlZXMgY291bnRlcmNsb2Nrd2lzZSBhcm91bmQgdGhlIHktYXhpcy4KICAgICAgICAgKiBjb25zdCBwID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDUsIDYsIDcpOwogICAgICAgICAqIGNvbnN0IG0gPSBDZXNpdW0uTWF0cml4My5mcm9tUm90YXRpb25ZKENlc2l1bS5NYXRoLnRvUmFkaWFucyg0NS4wKSk7CiAgICAgICAgICogY29uc3Qgcm90YXRlZCA9IENlc2l1bS5NYXRyaXgzLm11bHRpcGx5QnlWZWN0b3IobSwgcCwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm90YXRpb25ZKGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYW5nbGUiLCBhbmdsZSk7CiAgICAgICAgICBjb25zdCBjb3NBbmdsZSA9IE1hdGguY29zKGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHNpbkFuZ2xlID0gTWF0aC5zaW4oYW5nbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKAogICAgICAgICAgICAgIGNvc0FuZ2xlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgc2luQW5nbGUsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgLXNpbkFuZ2xlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgY29zQW5nbGUKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IGNvc0FuZ2xlOwogICAgICAgICAgcmVzdWx0WzFdID0gMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IC1zaW5BbmdsZTsKICAgICAgICAgIHJlc3VsdFszXSA9IDA7CiAgICAgICAgICByZXN1bHRbNF0gPSAxOwogICAgICAgICAgcmVzdWx0WzVdID0gMDsKICAgICAgICAgIHJlc3VsdFs2XSA9IHNpbkFuZ2xlOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IGNvc0FuZ2xlOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJvdGF0aW9uIG1hdHJpeCBhcm91bmQgdGhlIHotYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhbmdsZSBUaGUgYW5nbGUsIGluIHJhZGlhbnMsIG9mIHRoZSByb3RhdGlvbi4gIFBvc2l0aXZlIGFuZ2xlcyBhcmUgY291bnRlcmNsb2Nrd2lzZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIFJvdGF0ZSBhIHBvaW50IDQ1IGRlZ3JlZXMgY291bnRlcmNsb2Nrd2lzZSBhcm91bmQgdGhlIHotYXhpcy4KICAgICAgICAgKiBjb25zdCBwID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDUsIDYsIDcpOwogICAgICAgICAqIGNvbnN0IG0gPSBDZXNpdW0uTWF0cml4My5mcm9tUm90YXRpb25aKENlc2l1bS5NYXRoLnRvUmFkaWFucyg0NS4wKSk7CiAgICAgICAgICogY29uc3Qgcm90YXRlZCA9IENlc2l1bS5NYXRyaXgzLm11bHRpcGx5QnlWZWN0b3IobSwgcCwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm90YXRpb25aKGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYW5nbGUiLCBhbmdsZSk7CiAgICAgICAgICBjb25zdCBjb3NBbmdsZSA9IE1hdGguY29zKGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHNpbkFuZ2xlID0gTWF0aC5zaW4oYW5nbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgzKAogICAgICAgICAgICAgIGNvc0FuZ2xlLAogICAgICAgICAgICAgIC1zaW5BbmdsZSwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIHNpbkFuZ2xlLAogICAgICAgICAgICAgIGNvc0FuZ2xlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDEKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IGNvc0FuZ2xlOwogICAgICAgICAgcmVzdWx0WzFdID0gc2luQW5nbGU7CiAgICAgICAgICByZXN1bHRbMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzNdID0gLXNpbkFuZ2xlOwogICAgICAgICAgcmVzdWx0WzRdID0gY29zQW5nbGU7CiAgICAgICAgICByZXN1bHRbNV0gPSAwOwogICAgICAgICAgcmVzdWx0WzZdID0gMDsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSAxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhbiBBcnJheSBmcm9tIHRoZSBwcm92aWRlZCBNYXRyaXgzIGluc3RhbmNlLgogICAgICAgICAqIFRoZSBhcnJheSB3aWxsIGJlIGluIGNvbHVtbi1tYWpvciBvcmRlci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLi4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBbcmVzdWx0XSBUaGUgQXJyYXkgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIG1vZGlmaWVkIEFycmF5IHBhcmFtZXRlciBvciBhIG5ldyBBcnJheSBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdG9BcnJheShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gWwogICAgICAgICAgICAgIG1hdHJpeFswXSwKICAgICAgICAgICAgICBtYXRyaXhbMV0sCiAgICAgICAgICAgICAgbWF0cml4WzJdLAogICAgICAgICAgICAgIG1hdHJpeFszXSwKICAgICAgICAgICAgICBtYXRyaXhbNF0sCiAgICAgICAgICAgICAgbWF0cml4WzVdLAogICAgICAgICAgICAgIG1hdHJpeFs2XSwKICAgICAgICAgICAgICBtYXRyaXhbN10sCiAgICAgICAgICAgICAgbWF0cml4WzhdCiAgICAgICAgICAgIF07CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl07CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbNl07CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbOF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgYXJyYXkgaW5kZXggb2YgdGhlIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIHJvdyBhbmQgY29sdW1uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbiBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByb3cgVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIHJvdy4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgaW5kZXggb2YgdGhlIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIHJvdyBhbmQgY29sdW1uLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IHJvdyBtdXN0IGJlIDAsIDEsIG9yIDIuCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IGNvbHVtbiBtdXN0IGJlIDAsIDEsIG9yIDIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IG15TWF0cml4ID0gbmV3IENlc2l1bS5NYXRyaXgzKCk7CiAgICAgICAgICogY29uc3QgY29sdW1uMVJvdzBJbmRleCA9IENlc2l1bS5NYXRyaXgzLmdldEVsZW1lbnRJbmRleCgxLCAwKTsKICAgICAgICAgKiBjb25zdCBjb2x1bW4xUm93MCA9IG15TWF0cml4W2NvbHVtbjFSb3cwSW5kZXhdCiAgICAgICAgICogbXlNYXRyaXhbY29sdW1uMVJvdzBJbmRleF0gPSAxMC4wOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRFbGVtZW50SW5kZXgoY29sdW1uLCByb3cpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJyb3ciLCByb3csIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoInJvdyIsIHJvdywgMik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiY29sdW1uIiwgY29sdW1uLCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJjb2x1bW4iLCBjb2x1bW4sIDIpOwogICAgICAgICAgcmV0dXJuIGNvbHVtbiAqIDMgKyByb3c7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhIGNvcHkgb2YgdGhlIG1hdHJpeCBjb2x1bW4gYXQgdGhlIHByb3ZpZGVkIGluZGV4IGFzIGEgQ2FydGVzaWFuMyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uIHRvIHJldHJpZXZlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAsIDEsIG9yIDIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldENvbHVtbihtYXRyaXgsIGluZGV4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHN0YXJ0SW5kZXggPSBpbmRleCAqIDM7CiAgICAgICAgICBjb25zdCB4MiA9IG1hdHJpeFtzdGFydEluZGV4XTsKICAgICAgICAgIGNvbnN0IHkyID0gbWF0cml4W3N0YXJ0SW5kZXggKyAxXTsKICAgICAgICAgIGNvbnN0IHoyID0gbWF0cml4W3N0YXJ0SW5kZXggKyAyXTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbmV3IG1hdHJpeCB0aGF0IHJlcGxhY2VzIHRoZSBzcGVjaWZpZWQgY29sdW1uIGluIHRoZSBwcm92aWRlZCBtYXRyaXggd2l0aCB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuMyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uIHRvIHNldC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHdob3NlIHZhbHVlcyB3aWxsIGJlIGFzc2lnbmVkIHRvIHRoZSBzcGVjaWZpZWQgY29sdW1uLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAsIDEsIG9yIDIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldENvbHVtbihtYXRyaXgsIGluZGV4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdCA9IF9NYXRyaXgzLmNsb25lKG1hdHJpeCwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHN0YXJ0SW5kZXggPSBpbmRleCAqIDM7CiAgICAgICAgICByZXN1bHRbc3RhcnRJbmRleF0gPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgcmVzdWx0W3N0YXJ0SW5kZXggKyAxXSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHRbc3RhcnRJbmRleCArIDJdID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhIGNvcHkgb2YgdGhlIG1hdHJpeCByb3cgYXQgdGhlIHByb3ZpZGVkIGluZGV4IGFzIGEgQ2FydGVzaWFuMyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgcm93IHRvIHJldHJpZXZlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAsIDEsIG9yIDIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldFJvdyhtYXRyaXgsIGluZGV4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4W2luZGV4XTsKICAgICAgICAgIGNvbnN0IHkyID0gbWF0cml4W2luZGV4ICsgM107CiAgICAgICAgICBjb25zdCB6MiA9IG1hdHJpeFtpbmRleCArIDZdOwogICAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgICByZXN1bHQueiA9IHoyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBuZXcgbWF0cml4IHRoYXQgcmVwbGFjZXMgdGhlIHNwZWNpZmllZCByb3cgaW4gdGhlIHByb3ZpZGVkIG1hdHJpeCB3aXRoIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4zIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IFRoZSB6ZXJvLWJhc2VkIGluZGV4IG9mIHRoZSByb3cgdG8gc2V0LgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gd2hvc2UgdmFsdWVzIHdpbGwgYmUgYXNzaWduZWQgdG8gdGhlIHNwZWNpZmllZCByb3cuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IGluZGV4IG11c3QgYmUgMCwgMSwgb3IgMi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2V0Um93KG1hdHJpeCwgaW5kZXgsIGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0ID0gX01hdHJpeDMuY2xvbmUobWF0cml4LCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0W2luZGV4XSA9IGNhcnRlc2lhbjExLng7CiAgICAgICAgICByZXN1bHRbaW5kZXggKyAzXSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHRbaW5kZXggKyA2XSA9IGNhcnRlc2lhbjExLno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIG5ldyBtYXRyaXggdGhhdCByZXBsYWNlcyB0aGUgc2NhbGUgd2l0aCB0aGUgcHJvdmlkZWQgc2NhbGUuCiAgICAgICAgICogVGhpcyBhc3N1bWVzIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBzY2FsZSBUaGUgc2NhbGUgdGhhdCByZXBsYWNlcyB0aGUgc2NhbGUgb2YgdGhlIHByb3ZpZGVkIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDMuc2V0VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFNjYWxlKG1hdHJpeCwgc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGV4aXN0aW5nU2NhbGUgPSBfTWF0cml4My5nZXRTY2FsZShtYXRyaXgsIHNjYWxlU2NyYXRjaDEpOwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1ggPSBzY2FsZS54IC8gZXhpc3RpbmdTY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1kgPSBzY2FsZS55IC8gZXhpc3RpbmdTY2FsZS55OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1ogPSBzY2FsZS56IC8gZXhpc3RpbmdTY2FsZS56OwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV0gKiBzY2FsZVJhdGlvWDsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdICogc2NhbGVSYXRpb1k7CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4WzZdICogc2NhbGVSYXRpb1o7CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN10gKiBzY2FsZVJhdGlvWjsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XSAqIHNjYWxlUmF0aW9aOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBuZXcgbWF0cml4IHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIHdpdGggdGhlIHByb3ZpZGVkIHVuaWZvcm0gc2NhbGUuCiAgICAgICAgICogVGhpcyBhc3N1bWVzIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlIFRoZSB1bmlmb3JtIHNjYWxlIHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgzLnNldFNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFVuaWZvcm1TY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBleGlzdGluZ1NjYWxlID0gX01hdHJpeDMuZ2V0U2NhbGUobWF0cml4LCBzY2FsZVNjcmF0Y2gyKTsKICAgICAgICAgIGNvbnN0IHNjYWxlUmF0aW9YID0gc2NhbGUgLyBleGlzdGluZ1NjYWxlLng7CiAgICAgICAgICBjb25zdCBzY2FsZVJhdGlvWSA9IHNjYWxlIC8gZXhpc3RpbmdTY2FsZS55OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1ogPSBzY2FsZSAvIGV4aXN0aW5nU2NhbGUuejsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl0gKiBzY2FsZVJhdGlvWDsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmVzdWx0WzRdID0gbWF0cml4WzRdICogc2NhbGVSYXRpb1k7CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNV0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XSAqIHNjYWxlUmF0aW9aOwogICAgICAgICAgcmVzdWx0WzddID0gbWF0cml4WzddICogc2NhbGVSYXRpb1o7CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbOF0gKiBzY2FsZVJhdGlvWjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIHRoZSBub24tdW5pZm9ybSBzY2FsZSBhc3N1bWluZyB0aGUgbWF0cml4IGlzIGFuIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgzLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLnNldFNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgzLnNldFVuaWZvcm1TY2FsZQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRTY2FsZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKG1hdHJpeFswXSwgbWF0cml4WzFdLCBtYXRyaXhbMl0sIHNjcmF0Y2hDb2x1bW4pCiAgICAgICAgICApOwogICAgICAgICAgcmVzdWx0LnkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKG1hdHJpeFszXSwgbWF0cml4WzRdLCBtYXRyaXhbNV0sIHNjcmF0Y2hDb2x1bW4pCiAgICAgICAgICApOwogICAgICAgICAgcmVzdWx0LnogPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKG1hdHJpeFs2XSwgbWF0cml4WzddLCBtYXRyaXhbOF0sIHNjcmF0Y2hDb2x1bW4pCiAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIG1heGltdW0gc2NhbGUgYXNzdW1pbmcgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICogVGhlIG1heGltdW0gc2NhbGUgaXMgdGhlIG1heGltdW0gbGVuZ3RoIG9mIHRoZSBjb2x1bW4gdmVjdG9ycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXguCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIG1heGltdW0gc2NhbGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldE1heGltdW1TY2FsZShtYXRyaXgpIHsKICAgICAgICAgIF9NYXRyaXgzLmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoMyk7CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm1heGltdW1Db21wb25lbnQoc2NhbGVTY3JhdGNoMyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFNldHMgdGhlIHJvdGF0aW9uIGFzc3VtaW5nIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJvdGF0aW9uIFRoZSByb3RhdGlvbiBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgzLmdldFJvdGF0aW9uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFJvdGF0aW9uKG1hdHJpeCwgcm90YXRpb24sIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3Qgc2NhbGUgPSBfTWF0cml4My5nZXRTY2FsZShtYXRyaXgsIHNjYWxlU2NyYXRjaDQpOwogICAgICAgICAgcmVzdWx0WzBdID0gcm90YXRpb25bMF0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gcm90YXRpb25bMV0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzJdID0gcm90YXRpb25bMl0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzNdID0gcm90YXRpb25bM10gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzRdID0gcm90YXRpb25bNF0gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzVdID0gcm90YXRpb25bNV0gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzZdID0gcm90YXRpb25bNl0gKiBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzddID0gcm90YXRpb25bN10gKiBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzhdID0gcm90YXRpb25bOF0gKiBzY2FsZS56OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgdGhlIHJvdGF0aW9uIG1hdHJpeCBhc3N1bWluZyB0aGUgbWF0cml4IGlzIGFuIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgzLnNldFJvdGF0aW9uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldFJvdGF0aW9uKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBzY2FsZSA9IF9NYXRyaXgzLmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoNSk7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF0gLyBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdIC8gc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAvIHNjYWxlLng7CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM10gLyBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzRdID0gbWF0cml4WzRdIC8gc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XSAvIHNjYWxlLnk7CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbNl0gLyBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzddID0gbWF0cml4WzddIC8gc2NhbGUuejsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XSAvIHNjYWxlLno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiB0d28gbWF0cmljZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IGxlZnQgVGhlIGZpcnN0IG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJpZ2h0IFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHkobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzAgPSBsZWZ0WzBdICogcmlnaHRbMF0gKyBsZWZ0WzNdICogcmlnaHRbMV0gKyBsZWZ0WzZdICogcmlnaHRbMl07CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MSA9IGxlZnRbMV0gKiByaWdodFswXSArIGxlZnRbNF0gKiByaWdodFsxXSArIGxlZnRbN10gKiByaWdodFsyXTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cyID0gbGVmdFsyXSAqIHJpZ2h0WzBdICsgbGVmdFs1XSAqIHJpZ2h0WzFdICsgbGVmdFs4XSAqIHJpZ2h0WzJdOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzAgPSBsZWZ0WzBdICogcmlnaHRbM10gKyBsZWZ0WzNdICogcmlnaHRbNF0gKyBsZWZ0WzZdICogcmlnaHRbNV07CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MSA9IGxlZnRbMV0gKiByaWdodFszXSArIGxlZnRbNF0gKiByaWdodFs0XSArIGxlZnRbN10gKiByaWdodFs1XTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cyID0gbGVmdFsyXSAqIHJpZ2h0WzNdICsgbGVmdFs1XSAqIHJpZ2h0WzRdICsgbGVmdFs4XSAqIHJpZ2h0WzVdOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzAgPSBsZWZ0WzBdICogcmlnaHRbNl0gKyBsZWZ0WzNdICogcmlnaHRbN10gKyBsZWZ0WzZdICogcmlnaHRbOF07CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MSA9IGxlZnRbMV0gKiByaWdodFs2XSArIGxlZnRbNF0gKiByaWdodFs3XSArIGxlZnRbN10gKiByaWdodFs4XTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cyID0gbGVmdFsyXSAqIHJpZ2h0WzZdICsgbGVmdFs1XSAqIHJpZ2h0WzddICsgbGVmdFs4XSAqIHJpZ2h0WzhdOwogICAgICAgICAgcmVzdWx0WzBdID0gY29sdW1uMFJvdzA7CiAgICAgICAgICByZXN1bHRbMV0gPSBjb2x1bW4wUm93MTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGNvbHVtbjBSb3cyOwogICAgICAgICAgcmVzdWx0WzNdID0gY29sdW1uMVJvdzA7CiAgICAgICAgICByZXN1bHRbNF0gPSBjb2x1bW4xUm93MTsKICAgICAgICAgIHJlc3VsdFs1XSA9IGNvbHVtbjFSb3cyOwogICAgICAgICAgcmVzdWx0WzZdID0gY29sdW1uMlJvdzA7CiAgICAgICAgICByZXN1bHRbN10gPSBjb2x1bW4yUm93MTsKICAgICAgICAgIHJlc3VsdFs4XSA9IGNvbHVtbjJSb3cyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHN1bSBvZiB0d28gbWF0cmljZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IGxlZnQgVGhlIGZpcnN0IG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJpZ2h0IFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWRkKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IGxlZnRbMF0gKyByaWdodFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IGxlZnRbMV0gKyByaWdodFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGxlZnRbMl0gKyByaWdodFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IGxlZnRbM10gKyByaWdodFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IGxlZnRbNF0gKyByaWdodFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IGxlZnRbNV0gKyByaWdodFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IGxlZnRbNl0gKyByaWdodFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IGxlZnRbN10gKyByaWdodFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IGxlZnRbOF0gKyByaWdodFs4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBkaWZmZXJlbmNlIG9mIHR3byBtYXRyaWNlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbGVmdCBUaGUgZmlyc3QgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmlnaHQgVGhlIHNlY29uZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzdWJ0cmFjdChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBsZWZ0WzBdIC0gcmlnaHRbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSBsZWZ0WzFdIC0gcmlnaHRbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSBsZWZ0WzJdIC0gcmlnaHRbMl07CiAgICAgICAgICByZXN1bHRbM10gPSBsZWZ0WzNdIC0gcmlnaHRbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBsZWZ0WzRdIC0gcmlnaHRbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSBsZWZ0WzVdIC0gcmlnaHRbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSBsZWZ0WzZdIC0gcmlnaHRbNl07CiAgICAgICAgICByZXN1bHRbN10gPSBsZWZ0WzddIC0gcmlnaHRbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBsZWZ0WzhdIC0gcmlnaHRbOF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCBhbmQgYSBjb2x1bW4gdmVjdG9yLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgY29sdW1uLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVZlY3RvcihtYXRyaXgsIGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgdlggPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgY29uc3QgdlkgPSBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgY29uc3QgdlogPSBjYXJ0ZXNpYW4xMS56OwogICAgICAgICAgY29uc3QgeDIgPSBtYXRyaXhbMF0gKiB2WCArIG1hdHJpeFszXSAqIHZZICsgbWF0cml4WzZdICogdlo7CiAgICAgICAgICBjb25zdCB5MiA9IG1hdHJpeFsxXSAqIHZYICsgbWF0cml4WzRdICogdlkgKyBtYXRyaXhbN10gKiB2WjsKICAgICAgICAgIGNvbnN0IHoyID0gbWF0cml4WzJdICogdlggKyBtYXRyaXhbNV0gKiB2WSArIG1hdHJpeFs4XSAqIHZaOwogICAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgICByZXN1bHQueiA9IHoyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHByb2R1Y3Qgb2YgYSBtYXRyaXggYW5kIGEgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGFyIFRoZSBudW1iZXIgdG8gbXVsdGlwbHkgYnkuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKG1hdHJpeCwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGFyIiwgc2NhbGFyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XSAqIHNjYWxhcjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIGEgbWF0cml4IHRpbWVzIGEgKG5vbi11bmlmb3JtKSBzY2FsZSwgYXMgaWYgdGhlIHNjYWxlIHdlcmUgYSBzY2FsZSBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IG1hdHJpeCBUaGUgbWF0cml4IG9uIHRoZSBsZWZ0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHNjYWxlIFRoZSBub24tdW5pZm9ybSBzY2FsZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBJbnN0ZWFkIG9mIENlc2l1bS5NYXRyaXgzLm11bHRpcGx5KG0sIENlc2l1bS5NYXRyaXgzLmZyb21TY2FsZShzY2FsZSksIG0pOwogICAgICAgICAqIENlc2l1bS5NYXRyaXgzLm11bHRpcGx5QnlTY2FsZShtLCBzY2FsZSwgbSk7CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDMubXVsdGlwbHlCeVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5mcm9tU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDMuZnJvbVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5zZXRTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5zZXRVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDMuZ2V0U2NhbGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVNjYWxlKG1hdHJpeCwgc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxlLng7CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxlLnk7CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF0gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzVdID0gbWF0cml4WzVdICogc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XSAqIHNjYWxlLno7CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN10gKiBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzhdID0gbWF0cml4WzhdICogc2NhbGUuejsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIGEgbWF0cml4IHRpbWVzIGEgdW5pZm9ybSBzY2FsZSwgYXMgaWYgdGhlIHNjYWxlIHdlcmUgYSBzY2FsZSBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IG1hdHJpeCBUaGUgbWF0cml4IG9uIHRoZSBsZWZ0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgVGhlIHVuaWZvcm0gc2NhbGUgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIEluc3RlYWQgb2YgQ2VzaXVtLk1hdHJpeDMubXVsdGlwbHkobSwgQ2VzaXVtLk1hdHJpeDMuZnJvbVVuaWZvcm1TY2FsZShzY2FsZSksIG0pOwogICAgICAgICAqIENlc2l1bS5NYXRyaXgzLm11bHRpcGx5QnlVbmlmb3JtU2NhbGUobSwgc2NhbGUsIG0pOwogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgzLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5mcm9tU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDMuZnJvbVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5zZXRTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4My5zZXRVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDMuZ2V0U2NhbGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVVuaWZvcm1TY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGU7CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM10gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzVdID0gbWF0cml4WzVdICogc2NhbGU7CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbNl0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzhdID0gbWF0cml4WzhdICogc2NhbGU7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbmVnYXRlZCBjb3B5IG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IG1hdHJpeCBUaGUgbWF0cml4IHRvIG5lZ2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5lZ2F0ZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gLW1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IC1tYXRyaXhbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSAtbWF0cml4WzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gLW1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IC1tYXRyaXhbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSAtbWF0cml4WzVdOwogICAgICAgICAgcmVzdWx0WzZdID0gLW1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IC1tYXRyaXhbN107CiAgICAgICAgICByZXN1bHRbOF0gPSAtbWF0cml4WzhdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHRyYW5zcG9zZSBvZiB0aGUgcHJvdmlkZWQgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byB0cmFuc3Bvc2UuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0cmFuc3Bvc2UobWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cwID0gbWF0cml4WzBdOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzEgPSBtYXRyaXhbM107CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MiA9IG1hdHJpeFs2XTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cwID0gbWF0cml4WzFdOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzEgPSBtYXRyaXhbNF07CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MiA9IG1hdHJpeFs3XTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cwID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzEgPSBtYXRyaXhbNV07CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MiA9IG1hdHJpeFs4XTsKICAgICAgICAgIHJlc3VsdFswXSA9IGNvbHVtbjBSb3cwOwogICAgICAgICAgcmVzdWx0WzFdID0gY29sdW1uMFJvdzE7CiAgICAgICAgICByZXN1bHRbMl0gPSBjb2x1bW4wUm93MjsKICAgICAgICAgIHJlc3VsdFszXSA9IGNvbHVtbjFSb3cwOwogICAgICAgICAgcmVzdWx0WzRdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXN1bHRbNV0gPSBjb2x1bW4xUm93MjsKICAgICAgICAgIHJlc3VsdFs2XSA9IGNvbHVtbjJSb3cwOwogICAgICAgICAgcmVzdWx0WzddID0gY29sdW1uMlJvdzE7CiAgICAgICAgICByZXN1bHRbOF0gPSBjb2x1bW4yUm93MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBlaWdlbnZlY3RvcnMgYW5kIGVpZ2VudmFsdWVzIG9mIGEgc3ltbWV0cmljIG1hdHJpeC4KICAgICAgICAgKiA8cD4KICAgICAgICAgKiBSZXR1cm5zIGEgZGlhZ29uYWwgbWF0cml4IGFuZCB1bml0YXJ5IG1hdHJpeCBzdWNoIHRoYXQ6CiAgICAgICAgICogPGNvZGU+bWF0cml4ID0gdW5pdGFyeSBtYXRyaXggKiBkaWFnb25hbCBtYXRyaXggKiB0cmFuc3Bvc2UodW5pdGFyeSBtYXRyaXgpPC9jb2RlPgogICAgICAgICAqIDwvcD4KICAgICAgICAgKiA8cD4KICAgICAgICAgKiBUaGUgdmFsdWVzIGFsb25nIHRoZSBkaWFnb25hbCBvZiB0aGUgZGlhZ29uYWwgbWF0cml4IGFyZSB0aGUgZWlnZW52YWx1ZXMuIFRoZSBjb2x1bW5zCiAgICAgICAgICogb2YgdGhlIHVuaXRhcnkgbWF0cml4IGFyZSB0aGUgY29ycmVzcG9uZGluZyBlaWdlbnZlY3RvcnMuCiAgICAgICAgICogPC9wPgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB0byBkZWNvbXBvc2UgaW50byBkaWFnb25hbCBhbmQgdW5pdGFyeSBtYXRyaXguIEV4cGVjdGVkIHRvIGJlIHN5bW1ldHJpYy4KICAgICAgICAgKiBAcGFyYW0ge0VpZ2VuRGVjb21wb3NpdGlvblJlc3VsdH0gW3Jlc3VsdF0gQW4gb2JqZWN0IHdpdGggdW5pdGFyeSBhbmQgZGlhZ29uYWwgcHJvcGVydGllcyB3aGljaCBhcmUgbWF0cmljZXMgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtFaWdlbkRlY29tcG9zaXRpb25SZXN1bHR9IEFuIG9iamVjdCB3aXRoIHVuaXRhcnkgYW5kIGRpYWdvbmFsIHByb3BlcnRpZXMgd2hpY2ggYXJlIHRoZSB1bml0YXJ5IGFuZCBkaWFnb25hbCBtYXRyaWNlcywgcmVzcGVjdGl2ZWx5LgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiBjb25zdCBhID0gLy8uLi4gc3ltZXRyaWMgbWF0cml4CiAgICAgICAgICogY29uc3QgcmVzdWx0ID0gewogICAgICAgICAqICAgICB1bml0YXJ5IDogbmV3IENlc2l1bS5NYXRyaXgzKCksCiAgICAgICAgICogICAgIGRpYWdvbmFsIDogbmV3IENlc2l1bS5NYXRyaXgzKCkKICAgICAgICAgKiB9OwogICAgICAgICAqIENlc2l1bS5NYXRyaXgzLmNvbXB1dGVFaWdlbkRlY29tcG9zaXRpb24oYSwgcmVzdWx0KTsKICAgICAgICAgKgogICAgICAgICAqIGNvbnN0IHVuaXRhcnlUcmFuc3Bvc2UgPSBDZXNpdW0uTWF0cml4My50cmFuc3Bvc2UocmVzdWx0LnVuaXRhcnksIG5ldyBDZXNpdW0uTWF0cml4MygpKTsKICAgICAgICAgKiBjb25zdCBiID0gQ2VzaXVtLk1hdHJpeDMubXVsdGlwbHkocmVzdWx0LnVuaXRhcnksIHJlc3VsdC5kaWFnb25hbCwgbmV3IENlc2l1bS5NYXRyaXgzKCkpOwogICAgICAgICAqIENlc2l1bS5NYXRyaXgzLm11bHRpcGx5KGIsIHVuaXRhcnlUcmFuc3Bvc2UsIGIpOyAvLyBiIGlzIG5vdyBlcXVhbCB0byBhCiAgICAgICAgICoKICAgICAgICAgKiBjb25zdCBsYW1iZGEgPSBDZXNpdW0uTWF0cml4My5nZXRDb2x1bW4ocmVzdWx0LmRpYWdvbmFsLCAwLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoKSkueDsgIC8vIGZpcnN0IGVpZ2VudmFsdWUKICAgICAgICAgKiBjb25zdCB2ID0gQ2VzaXVtLk1hdHJpeDMuZ2V0Q29sdW1uKHJlc3VsdC51bml0YXJ5LCAwLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoKSk7ICAgICAgICAgIC8vIGZpcnN0IGVpZ2VudmVjdG9yCiAgICAgICAgICogY29uc3QgYyA9IENlc2l1bS5DYXJ0ZXNpYW4zLm11bHRpcGx5QnlTY2FsYXIodiwgbGFtYmRhLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoKSk7ICAgICAgICAvLyBlcXVhbCB0byBDZXNpdW0uTWF0cml4My5tdWx0aXBseUJ5VmVjdG9yKGEsIHYpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbXB1dGVFaWdlbkRlY29tcG9zaXRpb24obWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIGNvbnN0IHRvbGVyYW5jZSA9IE1hdGhfZGVmYXVsdC5FUFNJTE9OMjA7CiAgICAgICAgICBjb25zdCBtYXhTd2VlcHMgPSAxMDsKICAgICAgICAgIGxldCBjb3VudCA9IDA7CiAgICAgICAgICBsZXQgc3dlZXAgPSAwOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSB7fTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHVuaXRhcnlNYXRyaXggPSByZXN1bHQudW5pdGFyeSA9IF9NYXRyaXgzLmNsb25lKAogICAgICAgICAgICBfTWF0cml4My5JREVOVElUWSwKICAgICAgICAgICAgcmVzdWx0LnVuaXRhcnkKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBkaWFnTWF0cml4ID0gcmVzdWx0LmRpYWdvbmFsID0gX01hdHJpeDMuY2xvbmUoCiAgICAgICAgICAgIG1hdHJpeCwKICAgICAgICAgICAgcmVzdWx0LmRpYWdvbmFsCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgZXBzaWxvbiA9IHRvbGVyYW5jZSAqIGNvbXB1dGVGcm9iZW5pdXNOb3JtKGRpYWdNYXRyaXgpOwogICAgICAgICAgd2hpbGUgKHN3ZWVwIDwgbWF4U3dlZXBzICYmIG9mZkRpYWdvbmFsRnJvYmVuaXVzTm9ybShkaWFnTWF0cml4KSA+IGVwc2lsb24pIHsKICAgICAgICAgICAgc2h1ckRlY29tcG9zaXRpb24oZGlhZ01hdHJpeCwgak1hdHJpeCk7CiAgICAgICAgICAgIF9NYXRyaXgzLnRyYW5zcG9zZShqTWF0cml4LCBqTWF0cml4VHJhbnNwb3NlKTsKICAgICAgICAgICAgX01hdHJpeDMubXVsdGlwbHkoZGlhZ01hdHJpeCwgak1hdHJpeCwgZGlhZ01hdHJpeCk7CiAgICAgICAgICAgIF9NYXRyaXgzLm11bHRpcGx5KGpNYXRyaXhUcmFuc3Bvc2UsIGRpYWdNYXRyaXgsIGRpYWdNYXRyaXgpOwogICAgICAgICAgICBfTWF0cml4My5tdWx0aXBseSh1bml0YXJ5TWF0cml4LCBqTWF0cml4LCB1bml0YXJ5TWF0cml4KTsKICAgICAgICAgICAgaWYgKCsrY291bnQgPiAyKSB7CiAgICAgICAgICAgICAgKytzd2VlcDsKICAgICAgICAgICAgICBjb3VudCA9IDA7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbWF0cml4LCB3aGljaCBjb250YWlucyB0aGUgYWJzb2x1dGUgKHVuc2lnbmVkKSB2YWx1ZXMgb2YgdGhlIHByb3ZpZGVkIG1hdHJpeCdzIGVsZW1lbnRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBtYXRyaXggVGhlIG1hdHJpeCB3aXRoIHNpZ25lZCBlbGVtZW50cy4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGFicyhtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gTWF0aC5hYnMobWF0cml4WzBdKTsKICAgICAgICAgIHJlc3VsdFsxXSA9IE1hdGguYWJzKG1hdHJpeFsxXSk7CiAgICAgICAgICByZXN1bHRbMl0gPSBNYXRoLmFicyhtYXRyaXhbMl0pOwogICAgICAgICAgcmVzdWx0WzNdID0gTWF0aC5hYnMobWF0cml4WzNdKTsKICAgICAgICAgIHJlc3VsdFs0XSA9IE1hdGguYWJzKG1hdHJpeFs0XSk7CiAgICAgICAgICByZXN1bHRbNV0gPSBNYXRoLmFicyhtYXRyaXhbNV0pOwogICAgICAgICAgcmVzdWx0WzZdID0gTWF0aC5hYnMobWF0cml4WzZdKTsKICAgICAgICAgIHJlc3VsdFs3XSA9IE1hdGguYWJzKG1hdHJpeFs3XSk7CiAgICAgICAgICByZXN1bHRbOF0gPSBNYXRoLmFicyhtYXRyaXhbOF0pOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGRldGVybWluYW50IG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgdmFsdWUgb2YgdGhlIGRldGVybWluYW50IG9mIHRoZSBtYXRyaXguCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRldGVybWluYW50KG1hdHJpeCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgY29uc3QgbTExID0gbWF0cml4WzBdOwogICAgICAgICAgY29uc3QgbTIxID0gbWF0cml4WzNdOwogICAgICAgICAgY29uc3QgbTMxID0gbWF0cml4WzZdOwogICAgICAgICAgY29uc3QgbTEyID0gbWF0cml4WzFdOwogICAgICAgICAgY29uc3QgbTIyID0gbWF0cml4WzRdOwogICAgICAgICAgY29uc3QgbTMyID0gbWF0cml4WzddOwogICAgICAgICAgY29uc3QgbTEzID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgbTIzID0gbWF0cml4WzVdOwogICAgICAgICAgY29uc3QgbTMzID0gbWF0cml4WzhdOwogICAgICAgICAgcmV0dXJuIG0xMSAqIChtMjIgKiBtMzMgLSBtMjMgKiBtMzIpICsgbTEyICogKG0yMyAqIG0zMSAtIG0yMSAqIG0zMykgKyBtMTMgKiAobTIxICogbTMyIC0gbTIyICogbTMxKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGludmVyc2Ugb2YgdGhlIHByb3ZpZGVkIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gaW52ZXJ0LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgzfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBtYXRyaXggaXMgbm90IGludmVydGlibGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGludmVyc2UobWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IG0xMSA9IG1hdHJpeFswXTsKICAgICAgICAgIGNvbnN0IG0yMSA9IG1hdHJpeFsxXTsKICAgICAgICAgIGNvbnN0IG0zMSA9IG1hdHJpeFsyXTsKICAgICAgICAgIGNvbnN0IG0xMiA9IG1hdHJpeFszXTsKICAgICAgICAgIGNvbnN0IG0yMiA9IG1hdHJpeFs0XTsKICAgICAgICAgIGNvbnN0IG0zMiA9IG1hdHJpeFs1XTsKICAgICAgICAgIGNvbnN0IG0xMyA9IG1hdHJpeFs2XTsKICAgICAgICAgIGNvbnN0IG0yMyA9IG1hdHJpeFs3XTsKICAgICAgICAgIGNvbnN0IG0zMyA9IG1hdHJpeFs4XTsKICAgICAgICAgIGNvbnN0IGRldGVybWluYW50ID0gX01hdHJpeDMuZGV0ZXJtaW5hbnQobWF0cml4KTsKICAgICAgICAgIGlmIChNYXRoLmFicyhkZXRlcm1pbmFudCkgPD0gTWF0aF9kZWZhdWx0LkVQU0lMT04xNSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibWF0cml4IGlzIG5vdCBpbnZlcnRpYmxlIik7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBtMjIgKiBtMzMgLSBtMjMgKiBtMzI7CiAgICAgICAgICByZXN1bHRbMV0gPSBtMjMgKiBtMzEgLSBtMjEgKiBtMzM7CiAgICAgICAgICByZXN1bHRbMl0gPSBtMjEgKiBtMzIgLSBtMjIgKiBtMzE7CiAgICAgICAgICByZXN1bHRbM10gPSBtMTMgKiBtMzIgLSBtMTIgKiBtMzM7CiAgICAgICAgICByZXN1bHRbNF0gPSBtMTEgKiBtMzMgLSBtMTMgKiBtMzE7CiAgICAgICAgICByZXN1bHRbNV0gPSBtMTIgKiBtMzEgLSBtMTEgKiBtMzI7CiAgICAgICAgICByZXN1bHRbNl0gPSBtMTIgKiBtMjMgLSBtMTMgKiBtMjI7CiAgICAgICAgICByZXN1bHRbN10gPSBtMTMgKiBtMjEgLSBtMTEgKiBtMjM7CiAgICAgICAgICByZXN1bHRbOF0gPSBtMTEgKiBtMjIgLSBtMTIgKiBtMjE7CiAgICAgICAgICBjb25zdCBzY2FsZSA9IDEgLyBkZXRlcm1pbmFudDsKICAgICAgICAgIHJldHVybiBfTWF0cml4My5tdWx0aXBseUJ5U2NhbGFyKHJlc3VsdCwgc2NhbGUsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBpbnZlcnNlIHRyYW5zcG9zZSBvZiBhIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gbWF0cml4IFRoZSBtYXRyaXggdG8gdHJhbnNwb3NlIGFuZCBpbnZlcnQuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBpbnZlcnNlVHJhbnNwb3NlKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDMuaW52ZXJzZSgKICAgICAgICAgICAgX01hdHJpeDMudHJhbnNwb3NlKG1hdHJpeCwgc2NyYXRjaFRyYW5zcG9zZU1hdHJpeCksCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIG1hdHJpY2VzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gW2xlZnRdIFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbcmlnaHRdIFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFscyhsZWZ0LCByaWdodCkgewogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIGxlZnRbMF0gPT09IHJpZ2h0WzBdICYmIGxlZnRbMV0gPT09IHJpZ2h0WzFdICYmIGxlZnRbMl0gPT09IHJpZ2h0WzJdICYmIGxlZnRbM10gPT09IHJpZ2h0WzNdICYmIGxlZnRbNF0gPT09IHJpZ2h0WzRdICYmIGxlZnRbNV0gPT09IHJpZ2h0WzVdICYmIGxlZnRbNl0gPT09IHJpZ2h0WzZdICYmIGxlZnRbN10gPT09IHJpZ2h0WzddICYmIGxlZnRbOF0gPT09IHJpZ2h0WzhdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgbWF0cmljZXMgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwKICAgICAgICAgKiA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSBbbGVmdF0gVGhlIGZpcnN0IG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyaWdodF0gVGhlIHNlY29uZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtlcHNpbG9uPTBdIFRoZSBlcHNpbG9uIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgbGVmdCBhbmQgcmlnaHQgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzRXBzaWxvbihsZWZ0LCByaWdodCwgZXBzaWxvbikgewogICAgICAgICAgZXBzaWxvbiA9IGVwc2lsb24gPz8gMDsKICAgICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBNYXRoLmFicyhsZWZ0WzBdIC0gcmlnaHRbMF0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFsxXSAtIHJpZ2h0WzFdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMl0gLSByaWdodFsyXSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzNdIC0gcmlnaHRbM10pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFs0XSAtIHJpZ2h0WzRdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbNV0gLSByaWdodFs1XSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzZdIC0gcmlnaHRbNl0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFs3XSAtIHJpZ2h0WzddKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbOF0gLSByaWdodFs4XSkgPD0gZXBzaWxvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIHRoZSBjb2xsZWN0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKi8KICAgICAgICBnZXQgbGVuZ3RoKCkgewogICAgICAgICAgcmV0dXJuIF9NYXRyaXgzLnBhY2tlZExlbmd0aDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyB0aGUgcHJvdmlkZWQgTWF0cml4MyBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IE1hdHJpeDMgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUocmVzdWx0KSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDMuY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhpcyBtYXRyaXggdG8gdGhlIHByb3ZpZGVkIG1hdHJpeCBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBtYXRyaXguCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhyaWdodCkgewogICAgICAgICAgcmV0dXJuIF9NYXRyaXgzLmVxdWFscyh0aGlzLCByaWdodCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHByb3ZpZGVkIG1hdHJpeCBhbmQgYXJyYXksIHN0YXJ0aW5nIGZyb20gYSBnaXZlbiBhcnJheSBvZmZzZXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IG1hdHJpeAogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5CiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG9mZnNldAogICAgICAgICAqIEBpZ25vcmUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzQXJyYXkobWF0cml4LCBhcnJheSwgb2Zmc2V0KSB7CiAgICAgICAgICByZXR1cm4gbWF0cml4WzBdID09PSBhcnJheVtvZmZzZXRdICYmIG1hdHJpeFsxXSA9PT0gYXJyYXlbb2Zmc2V0ICsgMV0gJiYgbWF0cml4WzJdID09PSBhcnJheVtvZmZzZXQgKyAyXSAmJiBtYXRyaXhbM10gPT09IGFycmF5W29mZnNldCArIDNdICYmIG1hdHJpeFs0XSA9PT0gYXJyYXlbb2Zmc2V0ICsgNF0gJiYgbWF0cml4WzVdID09PSBhcnJheVtvZmZzZXQgKyA1XSAmJiBtYXRyaXhbNl0gPT09IGFycmF5W29mZnNldCArIDZdICYmIG1hdHJpeFs3XSA9PT0gYXJyYXlbb2Zmc2V0ICsgN10gJiYgbWF0cml4WzhdID09PSBhcnJheVtvZmZzZXQgKyA4XTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhpcyBtYXRyaXggdG8gdGhlIHByb3ZpZGVkIG1hdHJpeCBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtlcHNpbG9uPTBdIFRoZSBlcHNpbG9uIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFsc0Vwc2lsb24ocmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiBfTWF0cml4My5lcXVhbHNFcHNpbG9uKHRoaXMsIHJpZ2h0LCBlcHNpbG9uKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBNYXRyaXggd2l0aCBlYWNoIHJvdyBiZWluZwogICAgICAgICAqIG9uIGEgc2VwYXJhdGUgbGluZSBhbmQgaW4gdGhlIGZvcm1hdCAnKGNvbHVtbjAsIGNvbHVtbjEsIGNvbHVtbjIpJy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgcHJvdmlkZWQgTWF0cml4IHdpdGggZWFjaCByb3cgYmVpbmcgb24gYSBzZXBhcmF0ZSBsaW5lIGFuZCBpbiB0aGUgZm9ybWF0ICcoY29sdW1uMCwgY29sdW1uMSwgY29sdW1uMiknLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIGAoJHt0aGlzWzBdfSwgJHt0aGlzWzNdfSwgJHt0aGlzWzZdfSkKKCR7dGhpc1sxXX0sICR7dGhpc1s0XX0sICR7dGhpc1s3XX0pCigke3RoaXNbMl19LCAke3RoaXNbNV19LCAke3RoaXNbOF19KWA7CiAgICAgICAgfQogICAgICB9OwogICAgICBNYXRyaXgzLnBhY2tlZExlbmd0aCA9IDk7CiAgICAgIE1hdHJpeDMuZnJvbUFycmF5ID0gTWF0cml4My51bnBhY2s7CiAgICAgIE1hdHJpeDMuSURFTlRJVFkgPSBPYmplY3QuZnJlZXplKAogICAgICAgIG5ldyBNYXRyaXgzKDEsIDAsIDAsIDAsIDEsIDAsIDAsIDAsIDEpCiAgICAgICk7CiAgICAgIE1hdHJpeDMuWkVSTyA9IE9iamVjdC5mcmVlemUoCiAgICAgICAgbmV3IE1hdHJpeDMoMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCkKICAgICAgKTsKICAgICAgTWF0cml4My5DT0xVTU4wUk9XMCA9IDA7CiAgICAgIE1hdHJpeDMuQ09MVU1OMFJPVzEgPSAxOwogICAgICBNYXRyaXgzLkNPTFVNTjBST1cyID0gMjsKICAgICAgTWF0cml4My5DT0xVTU4xUk9XMCA9IDM7CiAgICAgIE1hdHJpeDMuQ09MVU1OMVJPVzEgPSA0OwogICAgICBNYXRyaXgzLkNPTFVNTjFST1cyID0gNTsKICAgICAgTWF0cml4My5DT0xVTU4yUk9XMCA9IDY7CiAgICAgIE1hdHJpeDMuQ09MVU1OMlJPVzEgPSA3OwogICAgICBNYXRyaXgzLkNPTFVNTjJST1cyID0gODsKICAgICAgc2NhbGVTY3JhdGNoMSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENvbHVtbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoNSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgak1hdHJpeCA9IG5ldyBNYXRyaXgzKCk7CiAgICAgIGpNYXRyaXhUcmFuc3Bvc2UgPSBuZXcgTWF0cml4MygpOwogICAgICBzY3JhdGNoVHJhbnNwb3NlTWF0cml4ID0gbmV3IE1hdHJpeDMoKTsKICAgICAgcm93VmFsID0gWzEsIDAsIDBdOwogICAgICBjb2xWYWwgPSBbMiwgMiwgMV07CiAgICAgIE1hdHJpeDNfZGVmYXVsdCA9IE1hdHJpeDM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DYXJ0ZXNpYW40LmpzCiAgdmFyIENhcnRlc2lhbjQsIGRpc3RhbmNlU2NyYXRjaDMsIGxlcnBTY3JhdGNoMywgbW9zdE9ydGhvZ29uYWxBeGlzU2NyYXRjaDMsIHNjcmF0Y2hGMzJBcnJheSwgc2NyYXRjaFU4QXJyYXksIHRlc3RVMzIsIHRlc3RVOCwgbGl0dGxlRW5kaWFuLCBDYXJ0ZXNpYW40X2RlZmF1bHQ7CiAgdmFyIGluaXRfQ2FydGVzaWFuNCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ2FydGVzaWFuNC5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIENhcnRlc2lhbjQgPSBjbGFzcyBfQ2FydGVzaWFuNCB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt4PTAuMF0gVGhlIFggY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbeT0wLjBdIFRoZSBZIGNvbXBvbmVudC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3o9MC4wXSBUaGUgWiBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt3PTAuMF0gVGhlIFcgY29tcG9uZW50LgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHgyLCB5MiwgejIsIHcyKSB7CiAgICAgICAgICB0aGlzLnggPSB4MiA/PyAwOwogICAgICAgICAgdGhpcy55ID0geTIgPz8gMDsKICAgICAgICAgIHRoaXMueiA9IHoyID8/IDA7CiAgICAgICAgICB0aGlzLncgPSB3MiA/PyAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgQ2FydGVzaWFuNCBpbnN0YW5jZSBmcm9tIHgsIHksIHogYW5kIHcgY29vcmRpbmF0ZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geCBUaGUgeCBjb29yZGluYXRlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IFRoZSB5IGNvb3JkaW5hdGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHogVGhlIHogY29vcmRpbmF0ZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gdyBUaGUgdyBjb29yZGluYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRlc2lhbjQgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21FbGVtZW50cyh4MiwgeTIsIHoyLCB3MiwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NhcnRlc2lhbjQoeDIsIHkyLCB6MiwgdzIpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgICByZXN1bHQueiA9IHoyOwogICAgICAgICAgcmVzdWx0LncgPSB3MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBDYXJ0ZXNpYW40IGluc3RhbmNlIGZyb20gYSB7QGxpbmsgQ29sb3J9LiA8Y29kZT5yZWQ8L2NvZGU+LCA8Y29kZT5ncmVlbjwvY29kZT4sIDxjb2RlPmJsdWU8L2NvZGU+LAogICAgICAgICAqIGFuZCA8Y29kZT5hbHBoYTwvY29kZT4gbWFwIHRvIDxjb2RlPng8L2NvZGU+LCA8Y29kZT55PC9jb2RlPiwgPGNvZGU+ejwvY29kZT4sIGFuZCA8Y29kZT53PC9jb2RlPiwgcmVzcGVjdGl2ZWx5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gY29sb3IgVGhlIHNvdXJjZSBjb2xvci4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW40IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tQ29sb3IoY29sb3IsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjb2xvciIsIGNvbG9yKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfQ2FydGVzaWFuNChjb2xvci5yZWQsIGNvbG9yLmdyZWVuLCBjb2xvci5ibHVlLCBjb2xvci5hbHBoYSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IGNvbG9yLnJlZDsKICAgICAgICAgIHJlc3VsdC55ID0gY29sb3IuZ3JlZW47CiAgICAgICAgICByZXN1bHQueiA9IGNvbG9yLmJsdWU7CiAgICAgICAgICByZXN1bHQudyA9IGNvbG9yLmFscGhhOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhIENhcnRlc2lhbjQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHRvIGR1cGxpY2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0ZXNpYW40IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLiAoUmV0dXJucyB1bmRlZmluZWQgaWYgY2FydGVzaWFuIGlzIHVuZGVmaW5lZCkKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY2xvbmUoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2FydGVzaWFuMTEpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NhcnRlc2lhbjQoY2FydGVzaWFuMTEueCwgY2FydGVzaWFuMTEueSwgY2FydGVzaWFuMTEueiwgY2FydGVzaWFuMTEudyk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLng7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHQueiA9IGNhcnRlc2lhbjExLno7CiAgICAgICAgICByZXN1bHQudyA9IGNhcnRlc2lhbjExLnc7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdG9yZXMgdGhlIHByb3ZpZGVkIGluc3RhbmNlIGludG8gdGhlIHByb3ZpZGVkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSB2YWx1ZSBUaGUgdmFsdWUgdG8gcGFjay4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheSBUaGUgYXJyYXkgdG8gcGFjayBpbnRvLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRpbmdJbmRleD0wXSBUaGUgaW5kZXggaW50byB0aGUgYXJyYXkgYXQgd2hpY2ggdG8gc3RhcnQgcGFja2luZyB0aGUgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBhcnJheSB0aGF0IHdhcyBwYWNrZWQgaW50bwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwYWNrKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLng7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUueTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS56OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS53OwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSAgVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydGVzaWFuNCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0NhcnRlc2lhbjQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdC55ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdC56ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdC53ID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBGbGF0dGVucyBhbiBhcnJheSBvZiBDYXJ0ZXNpYW40cyBpbnRvIGFuIGFycmF5IG9mIGNvbXBvbmVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjRbXX0gYXJyYXkgVGhlIGFycmF5IG9mIGNhcnRlc2lhbnMgdG8gcGFjay4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBbcmVzdWx0XSBUaGUgYXJyYXkgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LiBJZiB0aGlzIGlzIGEgdHlwZWQgYXJyYXksIGl0IG11c3QgaGF2ZSBhcnJheS5sZW5ndGggKiA0IGNvbXBvbmVudHMsIGVsc2UgYSB7QGxpbmsgRGV2ZWxvcGVyRXJyb3J9IHdpbGwgYmUgdGhyb3duLiBJZiBpdCBpcyBhIHJlZ3VsYXIgYXJyYXksIGl0IHdpbGwgYmUgcmVzaXplZCB0byBoYXZlIChhcnJheS5sZW5ndGggKiA0KSBlbGVtZW50cy4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2tBcnJheShhcnJheSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgY29uc3QgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOwogICAgICAgICAgY29uc3QgcmVzdWx0TGVuZ3RoID0gbGVuZ3RoICogNDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEFycmF5KHJlc3VsdExlbmd0aCk7CiAgICAgICAgICB9IGVsc2UgaWYgKCFBcnJheS5pc0FycmF5KHJlc3VsdCkgJiYgcmVzdWx0Lmxlbmd0aCAhPT0gcmVzdWx0TGVuZ3RoKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJJZiByZXN1bHQgaXMgYSB0eXBlZCBhcnJheSwgaXQgbXVzdCBoYXZlIGV4YWN0bHkgYXJyYXkubGVuZ3RoICogNCBlbGVtZW50cyIKICAgICAgICAgICAgKTsKICAgICAgICAgIH0gZWxzZSBpZiAocmVzdWx0Lmxlbmd0aCAhPT0gcmVzdWx0TGVuZ3RoKSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSByZXN1bHRMZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIF9DYXJ0ZXNpYW40LnBhY2soYXJyYXlbaTJdLCByZXN1bHQsIGkyICogNCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBVbnBhY2tzIGFuIGFycmF5IG9mIGNhcnRlc2lhbiBjb21wb25lbnRzIGludG8gYW4gYXJyYXkgb2YgQ2FydGVzaWFuNHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheSBUaGUgYXJyYXkgb2YgY29tcG9uZW50cyB0byB1bnBhY2suCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40W119IFtyZXN1bHRdIFRoZSBhcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjRbXX0gVGhlIHVucGFja2VkIGFycmF5LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2tBcnJheShhcnJheSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImFycmF5Lmxlbmd0aCIsIGFycmF5Lmxlbmd0aCwgNCk7CiAgICAgICAgICBpZiAoYXJyYXkubGVuZ3RoICUgNCAhPT0gMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgbGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA0LiIpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkobGVuZ3RoIC8gNCk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoIC8gNDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDQpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXggPSBpMiAvIDQ7CiAgICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBfQ2FydGVzaWFuNC51bnBhY2soYXJyYXksIGkyLCByZXN1bHRbaW5kZXhdKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSB2YWx1ZSBvZiB0aGUgbWF4aW11bSBjb21wb25lbnQgZm9yIHRoZSBzdXBwbGllZCBDYXJ0ZXNpYW4uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgY2FydGVzaWFuIHRvIHVzZS4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgdmFsdWUgb2YgdGhlIG1heGltdW0gY29tcG9uZW50LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtYXhpbXVtQ29tcG9uZW50KGNhcnRlc2lhbjExKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIHJldHVybiBNYXRoLm1heChjYXJ0ZXNpYW4xMS54LCBjYXJ0ZXNpYW4xMS55LCBjYXJ0ZXNpYW4xMS56LCBjYXJ0ZXNpYW4xMS53KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHZhbHVlIG9mIHRoZSBtaW5pbXVtIGNvbXBvbmVudCBmb3IgdGhlIHN1cHBsaWVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gY2FydGVzaWFuIFRoZSBjYXJ0ZXNpYW4gdG8gdXNlLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSB2YWx1ZSBvZiB0aGUgbWluaW11bSBjb21wb25lbnQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1pbmltdW1Db21wb25lbnQoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgcmV0dXJuIE1hdGgubWluKGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnksIGNhcnRlc2lhbjExLnosIGNhcnRlc2lhbjExLncpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0d28gQ2FydGVzaWFucyBhbmQgY29tcHV0ZXMgYSBDYXJ0ZXNpYW4gd2hpY2ggY29udGFpbnMgdGhlIG1pbmltdW0gY29tcG9uZW50cyBvZiB0aGUgc3VwcGxpZWQgQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gZmlyc3QgQSBjYXJ0ZXNpYW4gdG8gY29tcGFyZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHNlY29uZCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmVzdWx0IFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBBIGNhcnRlc2lhbiB3aXRoIHRoZSBtaW5pbXVtIGNvbXBvbmVudHMuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG1pbmltdW1CeUNvbXBvbmVudChmaXJzdCwgc2Vjb25kLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZmlyc3QiLCBmaXJzdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNlY29uZCIsIHNlY29uZCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IE1hdGgubWluKGZpcnN0LngsIHNlY29uZC54KTsKICAgICAgICAgIHJlc3VsdC55ID0gTWF0aC5taW4oZmlyc3QueSwgc2Vjb25kLnkpOwogICAgICAgICAgcmVzdWx0LnogPSBNYXRoLm1pbihmaXJzdC56LCBzZWNvbmQueik7CiAgICAgICAgICByZXN1bHQudyA9IE1hdGgubWluKGZpcnN0LncsIHNlY29uZC53KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHR3byBDYXJ0ZXNpYW5zIGFuZCBjb21wdXRlcyBhIENhcnRlc2lhbiB3aGljaCBjb250YWlucyB0aGUgbWF4aW11bSBjb21wb25lbnRzIG9mIHRoZSBzdXBwbGllZCBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBmaXJzdCBBIGNhcnRlc2lhbiB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gc2Vjb25kIEEgY2FydGVzaWFuIHRvIGNvbXBhcmUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBpbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IEEgY2FydGVzaWFuIHdpdGggdGhlIG1heGltdW0gY29tcG9uZW50cy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWF4aW11bUJ5Q29tcG9uZW50KGZpcnN0LCBzZWNvbmQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJmaXJzdCIsIGZpcnN0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic2Vjb25kIiwgc2Vjb25kKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gTWF0aC5tYXgoZmlyc3QueCwgc2Vjb25kLngpOwogICAgICAgICAgcmVzdWx0LnkgPSBNYXRoLm1heChmaXJzdC55LCBzZWNvbmQueSk7CiAgICAgICAgICByZXN1bHQueiA9IE1hdGgubWF4KGZpcnN0LnosIHNlY29uZC56KTsKICAgICAgICAgIHJlc3VsdC53ID0gTWF0aC5tYXgoZmlyc3Qudywgc2Vjb25kLncpOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29uc3RyYWluIGEgdmFsdWUgdG8gbGllIGJldHdlZW4gdHdvIHZhbHVlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gdmFsdWUgVGhlIHZhbHVlIHRvIGNsYW1wLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbWluIFRoZSBtaW5pbXVtIGJvdW5kLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbWF4IFRoZSBtYXhpbXVtIGJvdW5kLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmVzdWx0IFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgY2xhbXBlZCB2YWx1ZSBzdWNoIHRoYXQgbWluIDw9IHJlc3VsdCA8PSBtYXguCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsYW1wKHZhbHVlLCBtaW4zLCBtYXgzLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1pbiIsIG1pbjMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXgiLCBtYXgzKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHgyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLngsIG1pbjMueCwgbWF4My54KTsKICAgICAgICAgIGNvbnN0IHkyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLnksIG1pbjMueSwgbWF4My55KTsKICAgICAgICAgIGNvbnN0IHoyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLnosIG1pbjMueiwgbWF4My56KTsKICAgICAgICAgIGNvbnN0IHcyID0gTWF0aF9kZWZhdWx0LmNsYW1wKHZhbHVlLncsIG1pbjMudywgbWF4My53KTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJlc3VsdC53ID0gdzI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuJ3Mgc3F1YXJlZCBtYWduaXR1ZGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIGluc3RhbmNlIHdob3NlIHNxdWFyZWQgbWFnbml0dWRlIGlzIHRvIGJlIGNvbXB1dGVkLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBzcXVhcmVkIG1hZ25pdHVkZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWFnbml0dWRlU3F1YXJlZChjYXJ0ZXNpYW4xMSkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICByZXR1cm4gY2FydGVzaWFuMTEueCAqIGNhcnRlc2lhbjExLnggKyBjYXJ0ZXNpYW4xMS55ICogY2FydGVzaWFuMTEueSArIGNhcnRlc2lhbjExLnogKiBjYXJ0ZXNpYW4xMS56ICsgY2FydGVzaWFuMTEudyAqIGNhcnRlc2lhbjExLnc7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBDYXJ0ZXNpYW4ncyBtYWduaXR1ZGUgKGxlbmd0aCkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIGluc3RhbmNlIHdob3NlIG1hZ25pdHVkZSBpcyB0byBiZSBjb21wdXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbWFnbml0dWRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtYWduaXR1ZGUoY2FydGVzaWFuMTEpIHsKICAgICAgICAgIHJldHVybiBNYXRoLnNxcnQoX0NhcnRlc2lhbjQubWFnbml0dWRlU3F1YXJlZChjYXJ0ZXNpYW4xMSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgNC1zcGFjZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGxlZnQgVGhlIGZpcnN0IHBvaW50IHRvIGNvbXB1dGUgdGhlIGRpc3RhbmNlIGZyb20uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByaWdodCBUaGUgc2Vjb25kIHBvaW50IHRvIGNvbXB1dGUgdGhlIGRpc3RhbmNlIHRvLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIFJldHVybnMgMS4wCiAgICAgICAgICogY29uc3QgZCA9IENlc2l1bS5DYXJ0ZXNpYW40LmRpc3RhbmNlKAogICAgICAgICAqICAgbmV3IENlc2l1bS5DYXJ0ZXNpYW40KDEuMCwgMC4wLCAwLjAsIDAuMCksCiAgICAgICAgICogICBuZXcgQ2VzaXVtLkNhcnRlc2lhbjQoMi4wLCAwLjAsIDAuMCwgMC4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRpc3RhbmNlKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBfQ2FydGVzaWFuNC5zdWJ0cmFjdChsZWZ0LCByaWdodCwgZGlzdGFuY2VTY3JhdGNoMyk7CiAgICAgICAgICByZXR1cm4gX0NhcnRlc2lhbjQubWFnbml0dWRlKGRpc3RhbmNlU2NyYXRjaDMpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgc3F1YXJlZCBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHMuICBDb21wYXJpbmcgc3F1YXJlZCBkaXN0YW5jZXMKICAgICAgICAgKiB1c2luZyB0aGlzIGZ1bmN0aW9uIGlzIG1vcmUgZWZmaWNpZW50IHRoYW4gY29tcGFyaW5nIGRpc3RhbmNlcyB1c2luZyB7QGxpbmsgQ2FydGVzaWFuNCNkaXN0YW5jZX0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGxlZnQgVGhlIGZpcnN0IHBvaW50IHRvIGNvbXB1dGUgdGhlIGRpc3RhbmNlIGZyb20uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByaWdodCBUaGUgc2Vjb25kIHBvaW50IHRvIGNvbXB1dGUgdGhlIGRpc3RhbmNlIHRvLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIFJldHVybnMgNC4wLCBub3QgMi4wCiAgICAgICAgICogY29uc3QgZCA9IENlc2l1bS5DYXJ0ZXNpYW40LmRpc3RhbmNlKAogICAgICAgICAqICAgbmV3IENlc2l1bS5DYXJ0ZXNpYW40KDEuMCwgMC4wLCAwLjAsIDAuMCksCiAgICAgICAgICogICBuZXcgQ2VzaXVtLkNhcnRlc2lhbjQoMy4wLCAwLjAsIDAuMCwgMC4wKSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGRpc3RhbmNlU3F1YXJlZChsZWZ0LCByaWdodCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgX0NhcnRlc2lhbjQuc3VidHJhY3QobGVmdCwgcmlnaHQsIGRpc3RhbmNlU2NyYXRjaDMpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW40Lm1hZ25pdHVkZVNxdWFyZWQoZGlzdGFuY2VTY3JhdGNoMyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBub3JtYWxpemVkIGZvcm0gb2YgdGhlIHN1cHBsaWVkIENhcnRlc2lhbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gY2FydGVzaWFuIFRoZSBDYXJ0ZXNpYW4gdG8gYmUgbm9ybWFsaXplZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5vcm1hbGl6ZShjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IG1hZ25pdHVkZSA9IF9DYXJ0ZXNpYW40Lm1hZ25pdHVkZShjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLnggLyBtYWduaXR1ZGU7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnkgLyBtYWduaXR1ZGU7CiAgICAgICAgICByZXN1bHQueiA9IGNhcnRlc2lhbjExLnogLyBtYWduaXR1ZGU7CiAgICAgICAgICByZXN1bHQudyA9IGNhcnRlc2lhbjExLncgLyBtYWduaXR1ZGU7CiAgICAgICAgICBpZiAoaXNOYU4ocmVzdWx0LngpIHx8IGlzTmFOKHJlc3VsdC55KSB8fCBpc05hTihyZXN1bHQueikgfHwgaXNOYU4ocmVzdWx0LncpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJub3JtYWxpemVkIHJlc3VsdCBpcyBub3QgYSBudW1iZXIiKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBkb3QgKHNjYWxhcikgcHJvZHVjdCBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIGRvdCBwcm9kdWN0LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkb3QobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIHJldHVybiBsZWZ0LnggKiByaWdodC54ICsgbGVmdC55ICogcmlnaHQueSArIGxlZnQueiAqIHJpZ2h0LnogKyBsZWZ0LncgKiByaWdodC53OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBwcm9kdWN0IG9mIHR3byBDYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBsZWZ0IFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByaWdodCBUaGUgc2Vjb25kIENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5Q29tcG9uZW50cyhsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAqIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAqIHJpZ2h0Lnk7CiAgICAgICAgICByZXN1bHQueiA9IGxlZnQueiAqIHJpZ2h0Lno7CiAgICAgICAgICByZXN1bHQudyA9IGxlZnQudyAqIHJpZ2h0Lnc7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgY29tcG9uZW50d2lzZSBxdW90aWVudCBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVDb21wb25lbnRzKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gbGVmdC54IC8gcmlnaHQueDsKICAgICAgICAgIHJlc3VsdC55ID0gbGVmdC55IC8gcmlnaHQueTsKICAgICAgICAgIHJlc3VsdC56ID0gbGVmdC56IC8gcmlnaHQuejsKICAgICAgICAgIHJlc3VsdC53ID0gbGVmdC53IC8gcmlnaHQudzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHN1bSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhZGQobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBsZWZ0LnggKyByaWdodC54OwogICAgICAgICAgcmVzdWx0LnkgPSBsZWZ0LnkgKyByaWdodC55OwogICAgICAgICAgcmVzdWx0LnogPSBsZWZ0LnogKyByaWdodC56OwogICAgICAgICAgcmVzdWx0LncgPSBsZWZ0LncgKyByaWdodC53OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGNvbXBvbmVudHdpc2UgZGlmZmVyZW5jZSBvZiB0d28gQ2FydGVzaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gbGVmdCBUaGUgZmlyc3QgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmlnaHQgVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzdWJ0cmFjdChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGxlZnQueCAtIHJpZ2h0Lng7CiAgICAgICAgICByZXN1bHQueSA9IGxlZnQueSAtIHJpZ2h0Lnk7CiAgICAgICAgICByZXN1bHQueiA9IGxlZnQueiAtIHJpZ2h0Lno7CiAgICAgICAgICByZXN1bHQudyA9IGxlZnQudyAtIHJpZ2h0Lnc7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBzY2FsZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxhciBUaGUgc2NhbGFyIHRvIG11bHRpcGx5IHdpdGguCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKGNhcnRlc2lhbjExLCBzY2FsYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxhciIsIHNjYWxhcik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IGNhcnRlc2lhbjExLnggKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQueSA9IGNhcnRlc2lhbjExLnkgKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQueiA9IGNhcnRlc2lhbjExLnogKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQudyA9IGNhcnRlc2lhbjExLncgKiBzY2FsYXI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEaXZpZGVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBkaXZpZGVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXIgVGhlIHNjYWxhciB0byBkaXZpZGUgYnkuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVCeVNjYWxhcihjYXJ0ZXNpYW4xMSwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJzY2FsYXIiLCBzY2FsYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBjYXJ0ZXNpYW4xMS54IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LnkgPSBjYXJ0ZXNpYW4xMS55IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LnogPSBjYXJ0ZXNpYW4xMS56IC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LncgPSBjYXJ0ZXNpYW4xMS53IC8gc2NhbGFyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogTmVnYXRlcyB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB0byBiZSBuZWdhdGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbmVnYXRlKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSAtY2FydGVzaWFuMTEueDsKICAgICAgICAgIHJlc3VsdC55ID0gLWNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHQueiA9IC1jYXJ0ZXNpYW4xMS56OwogICAgICAgICAgcmVzdWx0LncgPSAtY2FydGVzaWFuMTEudzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB3aG9zZSBhYnNvbHV0ZSB2YWx1ZSBpcyB0byBiZSBjb21wdXRlZC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGFicyhjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gTWF0aC5hYnMoY2FydGVzaWFuMTEueCk7CiAgICAgICAgICByZXN1bHQueSA9IE1hdGguYWJzKGNhcnRlc2lhbjExLnkpOwogICAgICAgICAgcmVzdWx0LnogPSBNYXRoLmFicyhjYXJ0ZXNpYW4xMS56KTsKICAgICAgICAgIHJlc3VsdC53ID0gTWF0aC5hYnMoY2FydGVzaWFuMTEudyk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgbGluZWFyIGludGVycG9sYXRpb24gb3IgZXh0cmFwb2xhdGlvbiBhdCB0IHVzaW5nIHRoZSBwcm92aWRlZCBjYXJ0ZXNpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBzdGFydCBUaGUgdmFsdWUgY29ycmVzcG9uZGluZyB0byB0IGF0IDAuMC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9ZW5kIFRoZSB2YWx1ZSBjb3JyZXNwb25kaW5nIHRvIHQgYXQgMS4wLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0IFRoZSBwb2ludCBhbG9uZyB0IGF0IHdoaWNoIHRvIGludGVycG9sYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbGVycChzdGFydCwgZW5kLCB0MiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInN0YXJ0Iiwgc3RhcnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJlbmQiLCBlbmQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ0IiwgdDIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgX0NhcnRlc2lhbjQubXVsdGlwbHlCeVNjYWxhcihlbmQsIHQyLCBsZXJwU2NyYXRjaDMpOwogICAgICAgICAgcmVzdWx0ID0gX0NhcnRlc2lhbjQubXVsdGlwbHlCeVNjYWxhcihzdGFydCwgMSAtIHQyLCByZXN1bHQpOwogICAgICAgICAgcmV0dXJuIF9DYXJ0ZXNpYW40LmFkZChsZXJwU2NyYXRjaDMsIHJlc3VsdCwgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0dXJucyB0aGUgYXhpcyB0aGF0IGlzIG1vc3Qgb3J0aG9nb25hbCB0byB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiBvbiB3aGljaCB0byBmaW5kIHRoZSBtb3N0IG9ydGhvZ29uYWwgYXhpcy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vc3Qgb3J0aG9nb25hbCBheGlzLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtb3N0T3J0aG9nb25hbEF4aXMoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBmMiA9IF9DYXJ0ZXNpYW40Lm5vcm1hbGl6ZShjYXJ0ZXNpYW4xMSwgbW9zdE9ydGhvZ29uYWxBeGlzU2NyYXRjaDMpOwogICAgICAgICAgX0NhcnRlc2lhbjQuYWJzKGYyLCBmMik7CiAgICAgICAgICBpZiAoZjIueCA8PSBmMi55KSB7CiAgICAgICAgICAgIGlmIChmMi54IDw9IGYyLnopIHsKICAgICAgICAgICAgICBpZiAoZjIueCA8PSBmMi53KSB7CiAgICAgICAgICAgICAgICByZXN1bHQgPSBfQ2FydGVzaWFuNC5jbG9uZShfQ2FydGVzaWFuNC5VTklUX1gsIHJlc3VsdCk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW40LmNsb25lKF9DYXJ0ZXNpYW40LlVOSVRfVywgcmVzdWx0KTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZjIueiA8PSBmMi53KSB7CiAgICAgICAgICAgICAgcmVzdWx0ID0gX0NhcnRlc2lhbjQuY2xvbmUoX0NhcnRlc2lhbjQuVU5JVF9aLCByZXN1bHQpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW40LmNsb25lKF9DYXJ0ZXNpYW40LlVOSVRfVywgcmVzdWx0KTsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmIChmMi55IDw9IGYyLnopIHsKICAgICAgICAgICAgaWYgKGYyLnkgPD0gZjIudykgewogICAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW40LmNsb25lKF9DYXJ0ZXNpYW40LlVOSVRfWSwgcmVzdWx0KTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXN1bHQgPSBfQ2FydGVzaWFuNC5jbG9uZShfQ2FydGVzaWFuNC5VTklUX1csIHJlc3VsdCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAoZjIueiA8PSBmMi53KSB7CiAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW40LmNsb25lKF9DYXJ0ZXNpYW40LlVOSVRfWiwgcmVzdWx0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdCA9IF9DYXJ0ZXNpYW40LmNsb25lKF9DYXJ0ZXNpYW40LlVOSVRfVywgcmVzdWx0KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW5zIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gW2xlZnRdIFRoZSBmaXJzdCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBbcmlnaHRdIFRoZSBzZWNvbmQgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFscyhsZWZ0LCByaWdodCkgewogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIGxlZnQueCA9PT0gcmlnaHQueCAmJiBsZWZ0LnkgPT09IHJpZ2h0LnkgJiYgbGVmdC56ID09PSByaWdodC56ICYmIGxlZnQudyA9PT0gcmlnaHQudzsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheQogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQKICAgICAgICAgKiBAaWdub3JlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0FycmF5KGNhcnRlc2lhbjExLCBhcnJheSwgb2Zmc2V0KSB7CiAgICAgICAgICByZXR1cm4gY2FydGVzaWFuMTEueCA9PT0gYXJyYXlbb2Zmc2V0XSAmJiBjYXJ0ZXNpYW4xMS55ID09PSBhcnJheVtvZmZzZXQgKyAxXSAmJiBjYXJ0ZXNpYW4xMS56ID09PSBhcnJheVtvZmZzZXQgKyAyXSAmJiBjYXJ0ZXNpYW4xMS53ID09PSBhcnJheVtvZmZzZXQgKyAzXTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIENhcnRlc2lhbnMgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgcGFzcyBhbiBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0b2xlcmFuY2UgdGVzdCwKICAgICAgICAgKiA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBbbGVmdF0gVGhlIGZpcnN0IENhcnRlc2lhbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IFtyaWdodF0gVGhlIHNlY29uZCBDYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtyZWxhdGl2ZUVwc2lsb249MF0gVGhlIHJlbGF0aXZlIGVwc2lsb24gdG9sZXJhbmNlIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Fic29sdXRlRXBzaWxvbj1yZWxhdGl2ZUVwc2lsb25dIFRoZSBhYnNvbHV0ZSBlcHNpbG9uIHRvbGVyYW5jZSB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIGxlZnQgYW5kIHJpZ2h0IGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0Vwc2lsb24obGVmdCwgcmlnaHQsIHJlbGF0aXZlRXBzaWxvbiwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIGxlZnQueCwKICAgICAgICAgICAgcmlnaHQueCwKICAgICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIGxlZnQueSwKICAgICAgICAgICAgcmlnaHQueSwKICAgICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIGxlZnQueiwKICAgICAgICAgICAgcmlnaHQueiwKICAgICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIGxlZnQudywKICAgICAgICAgICAgcmlnaHQudywKICAgICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIER1cGxpY2F0ZXMgdGhpcyBDYXJ0ZXNpYW40IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydGVzaWFuNCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuNC5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGlzIENhcnRlc2lhbiBhZ2FpbnN0IHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBbcmlnaHRdIFRoZSByaWdodCBoYW5kIHNpZGUgQ2FydGVzaWFuLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHMocmlnaHQpIHsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuNC5lcXVhbHModGhpcywgcmlnaHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGlzIENhcnRlc2lhbiBhZ2FpbnN0IHRoZSBwcm92aWRlZCBDYXJ0ZXNpYW4gY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgcGFzcyBhbiBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0b2xlcmFuY2UgdGVzdCwKICAgICAgICAgKiA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBbcmlnaHRdIFRoZSByaWdodCBoYW5kIHNpZGUgQ2FydGVzaWFuLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbcmVsYXRpdmVFcHNpbG9uPTBdIFRoZSByZWxhdGl2ZSBlcHNpbG9uIHRvbGVyYW5jZSB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFthYnNvbHV0ZUVwc2lsb249cmVsYXRpdmVFcHNpbG9uXSBUaGUgYWJzb2x1dGUgZXBzaWxvbiB0b2xlcmFuY2UgdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzRXBzaWxvbihyaWdodCwgcmVsYXRpdmVFcHNpbG9uLCBhYnNvbHV0ZUVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiBfQ2FydGVzaWFuNC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICB0aGlzLAogICAgICAgICAgICByaWdodCwKICAgICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoaXMgQ2FydGVzaWFuIGluIHRoZSBmb3JtYXQgJyh4LCB5LCB6LCB3KScuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHByb3ZpZGVkIENhcnRlc2lhbiBpbiB0aGUgZm9ybWF0ICcoeCwgeSwgeiwgdyknLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIGAoJHt0aGlzLnh9LCAke3RoaXMueX0sICR7dGhpcy56fSwgJHt0aGlzLnd9KWA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFBhY2tzIGFuIGFyYml0cmFyeSBmbG9hdGluZyBwb2ludCB2YWx1ZSB0byA0IHZhbHVlcyByZXByZXNlbnRhYmxlIHVzaW5nIHVpbnQ4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIEEgZmxvYXRpbmcgcG9pbnQgbnVtYmVyLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gW3Jlc3VsdF0gVGhlIENhcnRlc2lhbjQgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHBhY2tlZCBmbG9hdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gQSBDYXJ0ZXNpYW40IHJlcHJlc2VudGluZyB0aGUgZmxvYXQgcGFja2VkIHRvIHZhbHVlcyBpbiB4LCB5LCB6LCBhbmQgdy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgcGFja0Zsb2F0KHZhbHVlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQ2FydGVzaWFuNCgpOwogICAgICAgICAgfQogICAgICAgICAgc2NyYXRjaEYzMkFycmF5WzBdID0gdmFsdWU7CiAgICAgICAgICBpZiAobGl0dGxlRW5kaWFuKSB7CiAgICAgICAgICAgIHJlc3VsdC54ID0gc2NyYXRjaFU4QXJyYXlbMF07CiAgICAgICAgICAgIHJlc3VsdC55ID0gc2NyYXRjaFU4QXJyYXlbMV07CiAgICAgICAgICAgIHJlc3VsdC56ID0gc2NyYXRjaFU4QXJyYXlbMl07CiAgICAgICAgICAgIHJlc3VsdC53ID0gc2NyYXRjaFU4QXJyYXlbM107CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXN1bHQueCA9IHNjcmF0Y2hVOEFycmF5WzNdOwogICAgICAgICAgICByZXN1bHQueSA9IHNjcmF0Y2hVOEFycmF5WzJdOwogICAgICAgICAgICByZXN1bHQueiA9IHNjcmF0Y2hVOEFycmF5WzFdOwogICAgICAgICAgICByZXN1bHQudyA9IHNjcmF0Y2hVOEFycmF5WzBdOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVW5wYWNrcyBhIGZsb2F0IHBhY2tlZCB1c2luZyBDYXJ0ZXNpYW40LnBhY2tGbG9hdC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcGFja2VkRmxvYXQgQSBDYXJ0ZXNpYW40IGNvbnRhaW5pbmcgYSBmbG9hdCBwYWNrZWQgdG8gNCB2YWx1ZXMgcmVwcmVzZW50YWJsZSB1c2luZyB1aW50OC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgdW5wYWNrZWQgZmxvYXQuCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdW5wYWNrRmxvYXQocGFja2VkRmxvYXQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicGFja2VkRmxvYXQiLCBwYWNrZWRGbG9hdCk7CiAgICAgICAgICBpZiAobGl0dGxlRW5kaWFuKSB7CiAgICAgICAgICAgIHNjcmF0Y2hVOEFycmF5WzBdID0gcGFja2VkRmxvYXQueDsKICAgICAgICAgICAgc2NyYXRjaFU4QXJyYXlbMV0gPSBwYWNrZWRGbG9hdC55OwogICAgICAgICAgICBzY3JhdGNoVThBcnJheVsyXSA9IHBhY2tlZEZsb2F0Lno7CiAgICAgICAgICAgIHNjcmF0Y2hVOEFycmF5WzNdID0gcGFja2VkRmxvYXQudzsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHNjcmF0Y2hVOEFycmF5WzBdID0gcGFja2VkRmxvYXQudzsKICAgICAgICAgICAgc2NyYXRjaFU4QXJyYXlbMV0gPSBwYWNrZWRGbG9hdC56OwogICAgICAgICAgICBzY3JhdGNoVThBcnJheVsyXSA9IHBhY2tlZEZsb2F0Lnk7CiAgICAgICAgICAgIHNjcmF0Y2hVOEFycmF5WzNdID0gcGFja2VkRmxvYXQueDsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBzY3JhdGNoRjMyQXJyYXlbMF07CiAgICAgICAgfQogICAgICB9OwogICAgICBDYXJ0ZXNpYW40LnBhY2tlZExlbmd0aCA9IDQ7CiAgICAgIENhcnRlc2lhbjQuZnJvbUFycmF5ID0gQ2FydGVzaWFuNC51bnBhY2s7CiAgICAgIGRpc3RhbmNlU2NyYXRjaDMgPSBuZXcgQ2FydGVzaWFuNCgpOwogICAgICBsZXJwU2NyYXRjaDMgPSBuZXcgQ2FydGVzaWFuNCgpOwogICAgICBtb3N0T3J0aG9nb25hbEF4aXNTY3JhdGNoMyA9IG5ldyBDYXJ0ZXNpYW40KCk7CiAgICAgIENhcnRlc2lhbjQuWkVSTyA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMCwgMCwgMCwgMCkpOwogICAgICBDYXJ0ZXNpYW40Lk9ORSA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMSwgMSwgMSwgMSkpOwogICAgICBDYXJ0ZXNpYW40LlVOSVRfWCA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMSwgMCwgMCwgMCkpOwogICAgICBDYXJ0ZXNpYW40LlVOSVRfWSA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMCwgMSwgMCwgMCkpOwogICAgICBDYXJ0ZXNpYW40LlVOSVRfWiA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMCwgMCwgMSwgMCkpOwogICAgICBDYXJ0ZXNpYW40LlVOSVRfVyA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjQoMCwgMCwgMCwgMSkpOwogICAgICBzY3JhdGNoRjMyQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDEpOwogICAgICBzY3JhdGNoVThBcnJheSA9IG5ldyBVaW50OEFycmF5KHNjcmF0Y2hGMzJBcnJheS5idWZmZXIpOwogICAgICB0ZXN0VTMyID0gbmV3IFVpbnQzMkFycmF5KFsyODc0NTQwMjBdKTsKICAgICAgdGVzdFU4ID0gbmV3IFVpbnQ4QXJyYXkodGVzdFUzMi5idWZmZXIpOwogICAgICBsaXR0bGVFbmRpYW4gPSB0ZXN0VThbMF0gPT09IDY4OwogICAgICBDYXJ0ZXNpYW40X2RlZmF1bHQgPSBDYXJ0ZXNpYW40OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRnJvemVuLmpzCiAgdmFyIEZyb3plbiwgRnJvemVuX2RlZmF1bHQ7CiAgdmFyIGluaXRfRnJvemVuID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Gcm96ZW4uanMiKCkgewogICAgICBGcm96ZW4gPSB7fTsKICAgICAgRnJvemVuLkVNUFRZX09CSkVDVCA9IE9iamVjdC5mcmVlemUoe30pOwogICAgICBGcm96ZW4uRU1QVFlfQVJSQVkgPSBPYmplY3QuZnJlZXplKFtdKTsKICAgICAgRnJvemVuX2RlZmF1bHQgPSBGcm96ZW47CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SdW50aW1lRXJyb3IuanMKICBmdW5jdGlvbiBSdW50aW1lRXJyb3IobWVzc2FnZSkgewogICAgdGhpcy5uYW1lID0gIlJ1bnRpbWVFcnJvciI7CiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlOwogICAgbGV0IHN0YWNrOwogICAgdHJ5IHsKICAgICAgdGhyb3cgbmV3IEVycm9yKCk7CiAgICB9IGNhdGNoIChlMikgewogICAgICBzdGFjayA9IGUyLnN0YWNrOwogICAgfQogICAgdGhpcy5zdGFjayA9IHN0YWNrOwogIH0KICB2YXIgUnVudGltZUVycm9yX2RlZmF1bHQ7CiAgdmFyIGluaXRfUnVudGltZUVycm9yID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SdW50aW1lRXJyb3IuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChPYmplY3QuY3JlYXRlKSkgewogICAgICAgIFJ1bnRpbWVFcnJvci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEVycm9yLnByb3RvdHlwZSk7CiAgICAgICAgUnVudGltZUVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFJ1bnRpbWVFcnJvcjsKICAgICAgfQogICAgICBSdW50aW1lRXJyb3IucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7CiAgICAgICAgbGV0IHN0ciA9IGAke3RoaXMubmFtZX06ICR7dGhpcy5tZXNzYWdlfWA7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh0aGlzLnN0YWNrKSkgewogICAgICAgICAgc3RyICs9IGAKJHt0aGlzLnN0YWNrLnRvU3RyaW5nKCl9YDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHN0cjsKICAgICAgfTsKICAgICAgUnVudGltZUVycm9yX2RlZmF1bHQgPSBSdW50aW1lRXJyb3I7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9NYXRyaXg0LmpzCiAgdmFyIE1hdHJpeDQsIGZyb21DYW1lcmFGLCBmcm9tQ2FtZXJhUiwgZnJvbUNhbWVyYVUsIHNjYWxlU2NyYXRjaDEyLCBzY2FsZVNjcmF0Y2gyMiwgc2NyYXRjaENvbHVtbjIsIHNjYWxlU2NyYXRjaDMyLCBzY2FsZVNjcmF0Y2g0Miwgc2NhbGVTY3JhdGNoNTIsIHNjcmF0Y2hJbnZlcnNlUm90YXRpb24sIHNjcmF0Y2hNYXRyaXgzWmVybywgc2NyYXRjaEJvdHRvbVJvdywgc2NyYXRjaEV4cGVjdGVkQm90dG9tUm93LCBzY3JhdGNoVHJhbnNwb3NlTWF0cml4MiwgTWF0cml4NF9kZWZhdWx0OwogIHZhciBpbml0X01hdHJpeDQgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL01hdHJpeDQuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW40KCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBNYXRyaXg0ID0gY2xhc3MgX01hdHJpeDQgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzA9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3cwPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDAuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4yUm93MD0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDIsIHJvdyAwLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uM1JvdzA9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAzLCByb3cgMC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjBSb3cxPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMCwgcm93IDEuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4xUm93MT0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDEsIHJvdyAxLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMlJvdzE9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAyLCByb3cgMS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjNSb3cxPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMywgcm93IDEuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4wUm93Mj0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDAsIHJvdyAyLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMVJvdzI9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAxLCByb3cgMi4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjJSb3cyPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMiwgcm93IDIuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4zUm93Mj0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDMsIHJvdyAyLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzM9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3czPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4yUm93Mz0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDIsIHJvdyAzLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uM1JvdzM9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAzLCByb3cgMy4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcihjb2x1bW4wUm93MCwgY29sdW1uMVJvdzAsIGNvbHVtbjJSb3cwLCBjb2x1bW4zUm93MCwgY29sdW1uMFJvdzEsIGNvbHVtbjFSb3cxLCBjb2x1bW4yUm93MSwgY29sdW1uM1JvdzEsIGNvbHVtbjBSb3cyLCBjb2x1bW4xUm93MiwgY29sdW1uMlJvdzIsIGNvbHVtbjNSb3cyLCBjb2x1bW4wUm93MywgY29sdW1uMVJvdzMsIGNvbHVtbjJSb3czLCBjb2x1bW4zUm93MykgewogICAgICAgICAgdGhpc1swXSA9IGNvbHVtbjBSb3cwID8/IDA7CiAgICAgICAgICB0aGlzWzFdID0gY29sdW1uMFJvdzEgPz8gMDsKICAgICAgICAgIHRoaXNbMl0gPSBjb2x1bW4wUm93MiA/PyAwOwogICAgICAgICAgdGhpc1szXSA9IGNvbHVtbjBSb3czID8/IDA7CiAgICAgICAgICB0aGlzWzRdID0gY29sdW1uMVJvdzAgPz8gMDsKICAgICAgICAgIHRoaXNbNV0gPSBjb2x1bW4xUm93MSA/PyAwOwogICAgICAgICAgdGhpc1s2XSA9IGNvbHVtbjFSb3cyID8/IDA7CiAgICAgICAgICB0aGlzWzddID0gY29sdW1uMVJvdzMgPz8gMDsKICAgICAgICAgIHRoaXNbOF0gPSBjb2x1bW4yUm93MCA/PyAwOwogICAgICAgICAgdGhpc1s5XSA9IGNvbHVtbjJSb3cxID8/IDA7CiAgICAgICAgICB0aGlzWzEwXSA9IGNvbHVtbjJSb3cyID8/IDA7CiAgICAgICAgICB0aGlzWzExXSA9IGNvbHVtbjJSb3czID8/IDA7CiAgICAgICAgICB0aGlzWzEyXSA9IGNvbHVtbjNSb3cwID8/IDA7CiAgICAgICAgICB0aGlzWzEzXSA9IGNvbHVtbjNSb3cxID8/IDA7CiAgICAgICAgICB0aGlzWzE0XSA9IGNvbHVtbjNSb3cyID8/IDA7CiAgICAgICAgICB0aGlzWzE1XSA9IGNvbHVtbjNSb3czID8/IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2UgaW50byB0aGUgcHJvdmlkZWQgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHZhbHVlIFRoZSB2YWx1ZSB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSB0byBwYWNrIGludG8uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBpbmRleCBpbnRvIHRoZSBhcnJheSBhdCB3aGljaCB0byBzdGFydCBwYWNraW5nIHRoZSBlbGVtZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIGFycmF5IHRoYXQgd2FzIHBhY2tlZCBpbnRvCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2sodmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMF07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMV07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMl07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbM107CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbNF07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbNV07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbNl07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbN107CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbOF07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbOV07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMTBdOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlWzExXTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZVsxMl07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMTNdOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlWzE0XTsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWVbMTVdOwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfTWF0cml4NCgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzNdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbNV0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzZdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFs3XSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbOF0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzldID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzExXSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbMTJdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFsxM10gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbMTVdID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBGbGF0dGVucyBhbiBhcnJheSBvZiBNYXRyaXg0cyBpbnRvIGFuIGFycmF5IG9mIGNvbXBvbmVudHMuIFRoZSBjb21wb25lbnRzCiAgICAgICAgICogYXJlIHN0b3JlZCBpbiBjb2x1bW4tbWFqb3Igb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDRbXX0gYXJyYXkgVGhlIGFycmF5IG9mIG1hdHJpY2VzIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gW3Jlc3VsdF0gVGhlIGFycmF5IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4gSWYgdGhpcyBpcyBhIHR5cGVkIGFycmF5LCBpdCBtdXN0IGhhdmUgYXJyYXkubGVuZ3RoICogMTYgY29tcG9uZW50cywgZWxzZSBhIHtAbGluayBEZXZlbG9wZXJFcnJvcn0gd2lsbCBiZSB0aHJvd24uIElmIGl0IGlzIGEgcmVndWxhciBhcnJheSwgaXQgd2lsbCBiZSByZXNpemVkIHRvIGhhdmUgKGFycmF5Lmxlbmd0aCAqIDE2KSBlbGVtZW50cy4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2tBcnJheShhcnJheSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgY29uc3QgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOwogICAgICAgICAgY29uc3QgcmVzdWx0TGVuZ3RoID0gbGVuZ3RoICogMTY7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShyZXN1bHRMZW5ndGgpOwogICAgICAgICAgfSBlbHNlIGlmICghQXJyYXkuaXNBcnJheShyZXN1bHQpICYmIHJlc3VsdC5sZW5ndGggIT09IHJlc3VsdExlbmd0aCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgICAiSWYgcmVzdWx0IGlzIGEgdHlwZWQgYXJyYXksIGl0IG11c3QgaGF2ZSBleGFjdGx5IGFycmF5Lmxlbmd0aCAqIDE2IGVsZW1lbnRzIgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQubGVuZ3RoICE9PSByZXN1bHRMZW5ndGgpIHsKICAgICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IHJlc3VsdExlbmd0aDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgX01hdHJpeDQucGFjayhhcnJheVtpMl0sIHJlc3VsdCwgaTIgKiAxNik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBVbnBhY2tzIGFuIGFycmF5IG9mIGNvbHVtbi1tYWpvciBtYXRyaXggY29tcG9uZW50cyBpbnRvIGFuIGFycmF5IG9mIE1hdHJpeDRzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIGFycmF5IG9mIGNvbXBvbmVudHMgdG8gdW5wYWNrLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NFtdfSBbcmVzdWx0XSBUaGUgYXJyYXkgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0W119IFRoZSB1bnBhY2tlZCBhcnJheS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdW5wYWNrQXJyYXkoYXJyYXksIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJhcnJheS5sZW5ndGgiLCBhcnJheS5sZW5ndGgsIDE2KTsKICAgICAgICAgIGlmIChhcnJheS5sZW5ndGggJSAxNiAhPT0gMCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgbGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAxNi4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGFycmF5Lmxlbmd0aDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IEFycmF5KGxlbmd0aCAvIDE2KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSBsZW5ndGggLyAxNjsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDE2KSB7CiAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gaTIgLyAxNjsKICAgICAgICAgICAgcmVzdWx0W2luZGV4XSA9IF9NYXRyaXg0LnVucGFjayhhcnJheSwgaTIsIHJlc3VsdFtpbmRleF0pOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIGR1cGxpY2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLiAoUmV0dXJucyB1bmRlZmluZWQgaWYgbWF0cml4IGlzIHVuZGVmaW5lZCkKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY2xvbmUobWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG1hdHJpeCkpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4NCgKICAgICAgICAgICAgICBtYXRyaXhbMF0sCiAgICAgICAgICAgICAgbWF0cml4WzRdLAogICAgICAgICAgICAgIG1hdHJpeFs4XSwKICAgICAgICAgICAgICBtYXRyaXhbMTJdLAogICAgICAgICAgICAgIG1hdHJpeFsxXSwKICAgICAgICAgICAgICBtYXRyaXhbNV0sCiAgICAgICAgICAgICAgbWF0cml4WzldLAogICAgICAgICAgICAgIG1hdHJpeFsxM10sCiAgICAgICAgICAgICAgbWF0cml4WzJdLAogICAgICAgICAgICAgIG1hdHJpeFs2XSwKICAgICAgICAgICAgICBtYXRyaXhbMTBdLAogICAgICAgICAgICAgIG1hdHJpeFsxNF0sCiAgICAgICAgICAgICAgbWF0cml4WzNdLAogICAgICAgICAgICAgIG1hdHJpeFs3XSwKICAgICAgICAgICAgICBtYXRyaXhbMTFdLAogICAgICAgICAgICAgIG1hdHJpeFsxNV0KICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XTsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeFs5XTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtYXRyaXhbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IG1hdHJpeFsxMV07CiAgICAgICAgICByZXN1bHRbMTJdID0gbWF0cml4WzEyXTsKICAgICAgICAgIHJlc3VsdFsxM10gPSBtYXRyaXhbMTNdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IG1hdHJpeFsxNF07CiAgICAgICAgICByZXN1bHRbMTVdID0gbWF0cml4WzE1XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgTWF0cml4NCBpbnN0YW5jZSBmcm9tIGEgY29sdW1uLW1ham9yIG9yZGVyIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gdmFsdWVzIFRoZSBjb2x1bW4tbWFqb3Igb3JkZXIgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tQ29sdW1uTWFqb3JBcnJheSh2YWx1ZXMsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2YWx1ZXMiLCB2YWx1ZXMpOwogICAgICAgICAgcmV0dXJuIF9NYXRyaXg0LmNsb25lKHZhbHVlcywgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIGZyb20gYSByb3ctbWFqb3Igb3JkZXIgYXJyYXkuCiAgICAgICAgICogVGhlIHJlc3VsdGluZyBtYXRyaXggd2lsbCBiZSBpbiBjb2x1bW4tbWFqb3Igb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSB2YWx1ZXMgVGhlIHJvdy1tYWpvciBvcmRlciBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDQgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Sb3dNYWpvckFycmF5KHZhbHVlcywgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlcyIsIHZhbHVlcyk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX01hdHJpeDQoCiAgICAgICAgICAgICAgdmFsdWVzWzBdLAogICAgICAgICAgICAgIHZhbHVlc1sxXSwKICAgICAgICAgICAgICB2YWx1ZXNbMl0sCiAgICAgICAgICAgICAgdmFsdWVzWzNdLAogICAgICAgICAgICAgIHZhbHVlc1s0XSwKICAgICAgICAgICAgICB2YWx1ZXNbNV0sCiAgICAgICAgICAgICAgdmFsdWVzWzZdLAogICAgICAgICAgICAgIHZhbHVlc1s3XSwKICAgICAgICAgICAgICB2YWx1ZXNbOF0sCiAgICAgICAgICAgICAgdmFsdWVzWzldLAogICAgICAgICAgICAgIHZhbHVlc1sxMF0sCiAgICAgICAgICAgICAgdmFsdWVzWzExXSwKICAgICAgICAgICAgICB2YWx1ZXNbMTJdLAogICAgICAgICAgICAgIHZhbHVlc1sxM10sCiAgICAgICAgICAgICAgdmFsdWVzWzE0XSwKICAgICAgICAgICAgICB2YWx1ZXNbMTVdCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSB2YWx1ZXNbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSB2YWx1ZXNbNF07CiAgICAgICAgICByZXN1bHRbMl0gPSB2YWx1ZXNbOF07CiAgICAgICAgICByZXN1bHRbM10gPSB2YWx1ZXNbMTJdOwogICAgICAgICAgcmVzdWx0WzRdID0gdmFsdWVzWzFdOwogICAgICAgICAgcmVzdWx0WzVdID0gdmFsdWVzWzVdOwogICAgICAgICAgcmVzdWx0WzZdID0gdmFsdWVzWzldOwogICAgICAgICAgcmVzdWx0WzddID0gdmFsdWVzWzEzXTsKICAgICAgICAgIHJlc3VsdFs4XSA9IHZhbHVlc1syXTsKICAgICAgICAgIHJlc3VsdFs5XSA9IHZhbHVlc1s2XTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSB2YWx1ZXNbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IHZhbHVlc1sxNF07CiAgICAgICAgICByZXN1bHRbMTJdID0gdmFsdWVzWzNdOwogICAgICAgICAgcmVzdWx0WzEzXSA9IHZhbHVlc1s3XTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSB2YWx1ZXNbMTFdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IHZhbHVlc1sxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgZnJvbSBhIE1hdHJpeDMgcmVwcmVzZW50aW5nIHRoZSByb3RhdGlvbgogICAgICAgICAqIGFuZCBhIENhcnRlc2lhbjMgcmVwcmVzZW50aW5nIHRoZSB0cmFuc2xhdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4M30gcm90YXRpb24gVGhlIHVwcGVyIGxlZnQgcG9ydGlvbiBvZiB0aGUgbWF0cml4IHJlcHJlc2VudGluZyB0aGUgcm90YXRpb24uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbdHJhbnNsYXRpb249Q2FydGVzaWFuMy5aRVJPXSBUaGUgdXBwZXIgcmlnaHQgcG9ydGlvbiBvZiB0aGUgbWF0cml4IHJlcHJlc2VudGluZyB0aGUgdHJhbnNsYXRpb24uCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm90YXRpb25UcmFuc2xhdGlvbihyb3RhdGlvbiwgdHJhbnNsYXRpb24yLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicm90YXRpb24iLCByb3RhdGlvbik7CiAgICAgICAgICB0cmFuc2xhdGlvbjIgPSB0cmFuc2xhdGlvbjIgPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk87CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX01hdHJpeDQoCiAgICAgICAgICAgICAgcm90YXRpb25bMF0sCiAgICAgICAgICAgICAgcm90YXRpb25bM10sCiAgICAgICAgICAgICAgcm90YXRpb25bNl0sCiAgICAgICAgICAgICAgdHJhbnNsYXRpb24yLngsCiAgICAgICAgICAgICAgcm90YXRpb25bMV0sCiAgICAgICAgICAgICAgcm90YXRpb25bNF0sCiAgICAgICAgICAgICAgcm90YXRpb25bN10sCiAgICAgICAgICAgICAgdHJhbnNsYXRpb24yLnksCiAgICAgICAgICAgICAgcm90YXRpb25bMl0sCiAgICAgICAgICAgICAgcm90YXRpb25bNV0sCiAgICAgICAgICAgICAgcm90YXRpb25bOF0sCiAgICAgICAgICAgICAgdHJhbnNsYXRpb24yLnosCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gcm90YXRpb25bMF07CiAgICAgICAgICByZXN1bHRbMV0gPSByb3RhdGlvblsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IHJvdGF0aW9uWzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IHJvdGF0aW9uWzNdOwogICAgICAgICAgcmVzdWx0WzVdID0gcm90YXRpb25bNF07CiAgICAgICAgICByZXN1bHRbNl0gPSByb3RhdGlvbls1XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSByb3RhdGlvbls2XTsKICAgICAgICAgIHJlc3VsdFs5XSA9IHJvdGF0aW9uWzddOwogICAgICAgICAgcmVzdWx0WzEwXSA9IHJvdGF0aW9uWzhdOwogICAgICAgICAgcmVzdWx0WzExXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTJdID0gdHJhbnNsYXRpb24yLng7CiAgICAgICAgICByZXN1bHRbMTNdID0gdHJhbnNsYXRpb24yLnk7CiAgICAgICAgICByZXN1bHRbMTRdID0gdHJhbnNsYXRpb24yLno7CiAgICAgICAgICByZXN1bHRbMTVdID0gMTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgTWF0cml4NCBpbnN0YW5jZSBmcm9tIGEgdHJhbnNsYXRpb24sIHJvdGF0aW9uLCBhbmQgc2NhbGUgKFRSUykKICAgICAgICAgKiByZXByZXNlbnRhdGlvbiB3aXRoIHRoZSByb3RhdGlvbiByZXByZXNlbnRlZCBhcyBhIHF1YXRlcm5pb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHRyYW5zbGF0aW9uIFRoZSB0cmFuc2xhdGlvbiB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge1F1YXRlcm5pb259IHJvdGF0aW9uIFRoZSByb3RhdGlvbiB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHNjYWxlIFRoZSBub24tdW5pZm9ybSBzY2FsZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDQgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IHJlc3VsdCA9IENlc2l1bS5NYXRyaXg0LmZyb21UcmFuc2xhdGlvblF1YXRlcm5pb25Sb3RhdGlvblNjYWxlKAogICAgICAgICAqICAgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDEuMCwgMi4wLCAzLjApLCAvLyB0cmFuc2xhdGlvbgogICAgICAgICAqICAgQ2VzaXVtLlF1YXRlcm5pb24uSURFTlRJVFksICAgICAgICAgICAvLyByb3RhdGlvbgogICAgICAgICAqICAgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDcuMCwgOC4wLCA5LjApLCAvLyBzY2FsZQogICAgICAgICAqICAgcmVzdWx0KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVRyYW5zbGF0aW9uUXVhdGVybmlvblJvdGF0aW9uU2NhbGUodHJhbnNsYXRpb24yLCByb3RhdGlvbiwgc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ0cmFuc2xhdGlvbiIsIHRyYW5zbGF0aW9uMik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJvdGF0aW9uIiwgcm90YXRpb24pOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9NYXRyaXg0KCk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBzY2FsZVggPSBzY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVZID0gc2NhbGUueTsKICAgICAgICAgIGNvbnN0IHNjYWxlWiA9IHNjYWxlLno7CiAgICAgICAgICBjb25zdCB4MiA9IHJvdGF0aW9uLnggKiByb3RhdGlvbi54OwogICAgICAgICAgY29uc3QgeHkgPSByb3RhdGlvbi54ICogcm90YXRpb24ueTsKICAgICAgICAgIGNvbnN0IHh6ID0gcm90YXRpb24ueCAqIHJvdGF0aW9uLno7CiAgICAgICAgICBjb25zdCB4dyA9IHJvdGF0aW9uLnggKiByb3RhdGlvbi53OwogICAgICAgICAgY29uc3QgeTIgPSByb3RhdGlvbi55ICogcm90YXRpb24ueTsKICAgICAgICAgIGNvbnN0IHl6ID0gcm90YXRpb24ueSAqIHJvdGF0aW9uLno7CiAgICAgICAgICBjb25zdCB5dyA9IHJvdGF0aW9uLnkgKiByb3RhdGlvbi53OwogICAgICAgICAgY29uc3QgejIgPSByb3RhdGlvbi56ICogcm90YXRpb24uejsKICAgICAgICAgIGNvbnN0IHp3ID0gcm90YXRpb24ueiAqIHJvdGF0aW9uLnc7CiAgICAgICAgICBjb25zdCB3MiA9IHJvdGF0aW9uLncgKiByb3RhdGlvbi53OwogICAgICAgICAgY29uc3QgbTAwID0geDIgLSB5MiAtIHoyICsgdzI7CiAgICAgICAgICBjb25zdCBtMDEgPSAyICogKHh5IC0gencpOwogICAgICAgICAgY29uc3QgbTAyID0gMiAqICh4eiArIHl3KTsKICAgICAgICAgIGNvbnN0IG0xMCA9IDIgKiAoeHkgKyB6dyk7CiAgICAgICAgICBjb25zdCBtMTEgPSAteDIgKyB5MiAtIHoyICsgdzI7CiAgICAgICAgICBjb25zdCBtMTIgPSAyICogKHl6IC0geHcpOwogICAgICAgICAgY29uc3QgbTIwID0gMiAqICh4eiAtIHl3KTsKICAgICAgICAgIGNvbnN0IG0yMSA9IDIgKiAoeXogKyB4dyk7CiAgICAgICAgICBjb25zdCBtMjIgPSAteDIgLSB5MiArIHoyICsgdzI7CiAgICAgICAgICByZXN1bHRbMF0gPSBtMDAgKiBzY2FsZVg7CiAgICAgICAgICByZXN1bHRbMV0gPSBtMTAgKiBzY2FsZVg7CiAgICAgICAgICByZXN1bHRbMl0gPSBtMjAgKiBzY2FsZVg7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gbTAxICogc2NhbGVZOwogICAgICAgICAgcmVzdWx0WzVdID0gbTExICogc2NhbGVZOwogICAgICAgICAgcmVzdWx0WzZdID0gbTIxICogc2NhbGVZOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IG0wMiAqIHNjYWxlWjsKICAgICAgICAgIHJlc3VsdFs5XSA9IG0xMiAqIHNjYWxlWjsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtMjIgKiBzY2FsZVo7CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSB0cmFuc2xhdGlvbjIueDsKICAgICAgICAgIHJlc3VsdFsxM10gPSB0cmFuc2xhdGlvbjIueTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSB0cmFuc2xhdGlvbjIuejsKICAgICAgICAgIHJlc3VsdFsxNV0gPSAxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgZnJvbSBhIHtAbGluayBUcmFuc2xhdGlvblJvdGF0aW9uU2NhbGV9IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtUcmFuc2xhdGlvblJvdGF0aW9uU2NhbGV9IHRyYW5zbGF0aW9uUm90YXRpb25TY2FsZSBUaGUgaW5zdGFuY2UuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tVHJhbnNsYXRpb25Sb3RhdGlvblNjYWxlKHRyYW5zbGF0aW9uUm90YXRpb25TY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zbGF0aW9uUm90YXRpb25TY2FsZSIsIHRyYW5zbGF0aW9uUm90YXRpb25TY2FsZSk7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDQuZnJvbVRyYW5zbGF0aW9uUXVhdGVybmlvblJvdGF0aW9uU2NhbGUoCiAgICAgICAgICAgIHRyYW5zbGF0aW9uUm90YXRpb25TY2FsZS50cmFuc2xhdGlvbiwKICAgICAgICAgICAgdHJhbnNsYXRpb25Sb3RhdGlvblNjYWxlLnJvdGF0aW9uLAogICAgICAgICAgICB0cmFuc2xhdGlvblJvdGF0aW9uU2NhbGUuc2NhbGUsCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgZnJvbSBhIENhcnRlc2lhbjMgcmVwcmVzZW50aW5nIHRoZSB0cmFuc2xhdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gdHJhbnNsYXRpb24gVGhlIHVwcGVyIHJpZ2h0IHBvcnRpb24gb2YgdGhlIG1hdHJpeCByZXByZXNlbnRpbmcgdGhlIHRyYW5zbGF0aW9uLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4NCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBzZWUgTWF0cml4NC5tdWx0aXBseUJ5VHJhbnNsYXRpb24KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVRyYW5zbGF0aW9uKHRyYW5zbGF0aW9uMiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zbGF0aW9uIiwgdHJhbnNsYXRpb24yKTsKICAgICAgICAgIHJldHVybiBfTWF0cml4NC5mcm9tUm90YXRpb25UcmFuc2xhdGlvbigKICAgICAgICAgICAgTWF0cml4M19kZWZhdWx0LklERU5USVRZLAogICAgICAgICAgICB0cmFuc2xhdGlvbjIsCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIHJlcHJlc2VudGluZyBhIG5vbi11bmlmb3JtIHNjYWxlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBzY2FsZSBUaGUgeCwgeSwgYW5kIHogc2NhbGUgZmFjdG9ycy4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDQgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIENyZWF0ZXMKICAgICAgICAgKiAvLyAgIFs3LjAsIDAuMCwgMC4wLCAwLjBdCiAgICAgICAgICogLy8gICBbMC4wLCA4LjAsIDAuMCwgMC4wXQogICAgICAgICAqIC8vICAgWzAuMCwgMC4wLCA5LjAsIDAuMF0KICAgICAgICAgKiAvLyAgIFswLjAsIDAuMCwgMC4wLCAxLjBdCiAgICAgICAgICogY29uc3QgbSA9IENlc2l1bS5NYXRyaXg0LmZyb21TY2FsZShuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoNy4wLCA4LjAsIDkuMCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tU2NhbGUoc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4NCgKICAgICAgICAgICAgICBzY2FsZS54LAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgc2NhbGUueSwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIHNjYWxlLnosCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAxCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IDA7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gMDsKICAgICAgICAgIHJlc3VsdFs1XSA9IHNjYWxlLnk7CiAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IDA7CiAgICAgICAgICByZXN1bHRbOV0gPSAwOwogICAgICAgICAgcmVzdWx0WzEwXSA9IHNjYWxlLno7CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzEzXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTRdID0gMDsKICAgICAgICAgIHJlc3VsdFsxNV0gPSAxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIHJlcHJlc2VudGluZyBhIHVuaWZvcm0gc2NhbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgVGhlIHVuaWZvcm0gc2NhbGUgZmFjdG9yLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4NCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gQ3JlYXRlcwogICAgICAgICAqIC8vICAgWzIuMCwgMC4wLCAwLjAsIDAuMF0KICAgICAgICAgKiAvLyAgIFswLjAsIDIuMCwgMC4wLCAwLjBdCiAgICAgICAgICogLy8gICBbMC4wLCAwLjAsIDIuMCwgMC4wXQogICAgICAgICAqIC8vICAgWzAuMCwgMC4wLCAwLjAsIDEuMF0KICAgICAgICAgKiBjb25zdCBtID0gQ2VzaXVtLk1hdHJpeDQuZnJvbVVuaWZvcm1TY2FsZSgyLjApOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tVW5pZm9ybVNjYWxlKHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX01hdHJpeDQoCiAgICAgICAgICAgICAgc2NhbGUsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICBzY2FsZSwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIHNjYWxlLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gc2NhbGU7CiAgICAgICAgICByZXN1bHRbMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgIHJlc3VsdFszXSA9IDA7CiAgICAgICAgICByZXN1bHRbNF0gPSAwOwogICAgICAgICAgcmVzdWx0WzVdID0gc2NhbGU7CiAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IDA7CiAgICAgICAgICByZXN1bHRbOV0gPSAwOwogICAgICAgICAgcmVzdWx0WzEwXSA9IHNjYWxlOwogICAgICAgICAgcmVzdWx0WzExXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTJdID0gMDsKICAgICAgICAgIHJlc3VsdFsxM10gPSAwOwogICAgICAgICAgcmVzdWx0WzE0XSA9IDA7CiAgICAgICAgICByZXN1bHRbMTVdID0gMTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSByb3RhdGlvbiBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJvdGF0aW9uIFRoZSByb3RhdGlvbiBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUm90YXRpb24ocm90YXRpb24sIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyb3RhdGlvbiIsIHJvdGF0aW9uKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9NYXRyaXg0KCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSByb3RhdGlvblswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IHJvdGF0aW9uWzFdOwogICAgICAgICAgcmVzdWx0WzJdID0gcm90YXRpb25bMl07CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gcm90YXRpb25bM107CiAgICAgICAgICByZXN1bHRbNV0gPSByb3RhdGlvbls0XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IHJvdGF0aW9uWzVdOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IHJvdGF0aW9uWzZdOwogICAgICAgICAgcmVzdWx0WzldID0gcm90YXRpb25bN107CiAgICAgICAgICByZXN1bHRbMTBdID0gcm90YXRpb25bOF07CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzEzXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTRdID0gMDsKICAgICAgICAgIHJlc3VsdFsxNV0gPSAxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIGZyb20gYSBDYW1lcmEuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhbWVyYX0gY2FtZXJhIFRoZSBjYW1lcmEgdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4NCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUNhbWVyYShjYW1lcmEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYW1lcmEiLCBjYW1lcmEpOwogICAgICAgICAgY29uc3QgcG9zaXRpb24gPSBjYW1lcmEucG9zaXRpb247CiAgICAgICAgICBjb25zdCBkaXJlY3Rpb24yID0gY2FtZXJhLmRpcmVjdGlvbjsKICAgICAgICAgIGNvbnN0IHVwID0gY2FtZXJhLnVwOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYW1lcmEucG9zaXRpb24iLCBwb3NpdGlvbik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhbWVyYS5kaXJlY3Rpb24iLCBkaXJlY3Rpb24yKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FtZXJhLnVwIiwgdXApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShkaXJlY3Rpb24yLCBmcm9tQ2FtZXJhRik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoZnJvbUNhbWVyYUYsIHVwLCBmcm9tQ2FtZXJhUiksCiAgICAgICAgICAgIGZyb21DYW1lcmFSCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGZyb21DYW1lcmFSLCBmcm9tQ2FtZXJhRiwgZnJvbUNhbWVyYVUpLAogICAgICAgICAgICBmcm9tQ2FtZXJhVQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHNYID0gZnJvbUNhbWVyYVIueDsKICAgICAgICAgIGNvbnN0IHNZID0gZnJvbUNhbWVyYVIueTsKICAgICAgICAgIGNvbnN0IHNaID0gZnJvbUNhbWVyYVIuejsKICAgICAgICAgIGNvbnN0IGZYID0gZnJvbUNhbWVyYUYueDsKICAgICAgICAgIGNvbnN0IGZZID0gZnJvbUNhbWVyYUYueTsKICAgICAgICAgIGNvbnN0IGZaID0gZnJvbUNhbWVyYUYuejsKICAgICAgICAgIGNvbnN0IHVYID0gZnJvbUNhbWVyYVUueDsKICAgICAgICAgIGNvbnN0IHVZID0gZnJvbUNhbWVyYVUueTsKICAgICAgICAgIGNvbnN0IHVaID0gZnJvbUNhbWVyYVUuejsKICAgICAgICAgIGNvbnN0IHBvc2l0aW9uWCA9IHBvc2l0aW9uLng7CiAgICAgICAgICBjb25zdCBwb3NpdGlvblkgPSBwb3NpdGlvbi55OwogICAgICAgICAgY29uc3QgcG9zaXRpb25aID0gcG9zaXRpb24uejsKICAgICAgICAgIGNvbnN0IHQwID0gc1ggKiAtcG9zaXRpb25YICsgc1kgKiAtcG9zaXRpb25ZICsgc1ogKiAtcG9zaXRpb25aOwogICAgICAgICAgY29uc3QgdDEgPSB1WCAqIC1wb3NpdGlvblggKyB1WSAqIC1wb3NpdGlvblkgKyB1WiAqIC1wb3NpdGlvblo7CiAgICAgICAgICBjb25zdCB0MiA9IGZYICogcG9zaXRpb25YICsgZlkgKiBwb3NpdGlvblkgKyBmWiAqIHBvc2l0aW9uWjsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4NCgKICAgICAgICAgICAgICBzWCwKICAgICAgICAgICAgICBzWSwKICAgICAgICAgICAgICBzWiwKICAgICAgICAgICAgICB0MCwKICAgICAgICAgICAgICB1WCwKICAgICAgICAgICAgICB1WSwKICAgICAgICAgICAgICB1WiwKICAgICAgICAgICAgICB0MSwKICAgICAgICAgICAgICAtZlgsCiAgICAgICAgICAgICAgLWZZLAogICAgICAgICAgICAgIC1mWiwKICAgICAgICAgICAgICB0MiwKICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAxCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBzWDsKICAgICAgICAgIHJlc3VsdFsxXSA9IHVYOwogICAgICAgICAgcmVzdWx0WzJdID0gLWZYOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IHNZOwogICAgICAgICAgcmVzdWx0WzVdID0gdVk7CiAgICAgICAgICByZXN1bHRbNl0gPSAtZlk7CiAgICAgICAgICByZXN1bHRbN10gPSAwOwogICAgICAgICAgcmVzdWx0WzhdID0gc1o7CiAgICAgICAgICByZXN1bHRbOV0gPSB1WjsKICAgICAgICAgIHJlc3VsdFsxMF0gPSAtZlo7CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSB0MDsKICAgICAgICAgIHJlc3VsdFsxM10gPSB0MTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSB0MjsKICAgICAgICAgIHJlc3VsdFsxNV0gPSAxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIHJlcHJlc2VudGluZyBhIHBlcnNwZWN0aXZlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBmb3ZZIFRoZSBmaWVsZCBvZiB2aWV3IGFsb25nIHRoZSBZIGF4aXMgaW4gcmFkaWFucy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYXNwZWN0UmF0aW8gVGhlIGFzcGVjdCByYXRpby4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbmVhciBUaGUgZGlzdGFuY2UgdG8gdGhlIG5lYXIgcGxhbmUgaW4gbWV0ZXJzLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBmYXIgVGhlIGRpc3RhbmNlIHRvIHRoZSBmYXIgcGxhbmUgaW4gbWV0ZXJzLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gZm92WSBtdXN0IGJlIGluICgwLCBQSV0uCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IGFzcGVjdFJhdGlvIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IG5lYXIgbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4KICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gZmFyIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbXB1dGVQZXJzcGVjdGl2ZUZpZWxkT2ZWaWV3KGZvdlksIGFzcGVjdFJhdGlvLCBuZWFyLCBmYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuKCJmb3ZZIiwgZm92WSwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW4oImZvdlkiLCBmb3ZZLCBNYXRoLlBJKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbigibmVhciIsIG5lYXIsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuKCJmYXIiLCBmYXIsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgYm90dG9tID0gTWF0aC50YW4oZm92WSAqIDAuNSk7CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MSA9IDEgLyBib3R0b207CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MCA9IGNvbHVtbjFSb3cxIC8gYXNwZWN0UmF0aW87CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MiA9IChmYXIgKyBuZWFyKSAvIChuZWFyIC0gZmFyKTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3cyID0gMiAqIGZhciAqIG5lYXIgLyAobmVhciAtIGZhcik7CiAgICAgICAgICByZXN1bHRbMF0gPSBjb2x1bW4wUm93MDsKICAgICAgICAgIHJlc3VsdFsxXSA9IDA7CiAgICAgICAgICByZXN1bHRbMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IDA7CiAgICAgICAgICByZXN1bHRbNV0gPSBjb2x1bW4xUm93MTsKICAgICAgICAgIHJlc3VsdFs2XSA9IDA7CiAgICAgICAgICByZXN1bHRbN10gPSAwOwogICAgICAgICAgcmVzdWx0WzhdID0gMDsKICAgICAgICAgIHJlc3VsdFs5XSA9IDA7CiAgICAgICAgICByZXN1bHRbMTBdID0gY29sdW1uMlJvdzI7CiAgICAgICAgICByZXN1bHRbMTFdID0gLTE7CiAgICAgICAgICByZXN1bHRbMTJdID0gMDsKICAgICAgICAgIHJlc3VsdFsxM10gPSAwOwogICAgICAgICAgcmVzdWx0WzE0XSA9IGNvbHVtbjNSb3cyOwogICAgICAgICAgcmVzdWx0WzE1XSA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgcmVwcmVzZW50aW5nIGFuIG9ydGhvZ3JhcGhpYyB0cmFuc2Zvcm1hdGlvbiBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGVmdCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgbGVmdCBvZiB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByaWdodCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgcmlnaHQgb2YgdGhlIGNhbWVyYSB0aGF0IHdpbGwgYmUgaW4gdmlldy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYm90dG9tIFRoZSBudW1iZXIgb2YgbWV0ZXJzIGJlbG93IG9mIHRoZSBjYW1lcmEgdGhhdCB3aWxsIGJlIGluIHZpZXcuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHRvcCBUaGUgbnVtYmVyIG9mIG1ldGVycyBhYm92ZSBvZiB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuZWFyIFRoZSBkaXN0YW5jZSB0byB0aGUgbmVhciBwbGFuZSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGZhciBUaGUgZGlzdGFuY2UgdG8gdGhlIGZhciBwbGFuZSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY29tcHV0ZU9ydGhvZ3JhcGhpY09mZkNlbnRlcihsZWZ0LCByaWdodCwgYm90dG9tLCB0b3AsIG5lYXIsIGZhciwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImJvdHRvbSIsIGJvdHRvbSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInRvcCIsIHRvcCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIm5lYXIiLCBuZWFyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiZmFyIiwgZmFyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGxldCBhNCA9IDEgLyAocmlnaHQgLSBsZWZ0KTsKICAgICAgICAgIGxldCBiMiA9IDEgLyAodG9wIC0gYm90dG9tKTsKICAgICAgICAgIGxldCBjMiA9IDEgLyAoZmFyIC0gbmVhcik7CiAgICAgICAgICBjb25zdCB0eCA9IC0ocmlnaHQgKyBsZWZ0KSAqIGE0OwogICAgICAgICAgY29uc3QgdHkgPSAtKHRvcCArIGJvdHRvbSkgKiBiMjsKICAgICAgICAgIGNvbnN0IHR6ID0gLShmYXIgKyBuZWFyKSAqIGMyOwogICAgICAgICAgYTQgKj0gMjsKICAgICAgICAgIGIyICo9IDI7CiAgICAgICAgICBjMiAqPSAtMjsKICAgICAgICAgIHJlc3VsdFswXSA9IGE0OwogICAgICAgICAgcmVzdWx0WzFdID0gMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IDA7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gMDsKICAgICAgICAgIHJlc3VsdFs1XSA9IGIyOwogICAgICAgICAgcmVzdWx0WzZdID0gMDsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSAwOwogICAgICAgICAgcmVzdWx0WzldID0gMDsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBjMjsKICAgICAgICAgIHJlc3VsdFsxMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzEyXSA9IHR4OwogICAgICAgICAgcmVzdWx0WzEzXSA9IHR5OwogICAgICAgICAgcmVzdWx0WzE0XSA9IHR6OwogICAgICAgICAgcmVzdWx0WzE1XSA9IDE7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgcmVwcmVzZW50aW5nIGFuIG9mZiBjZW50ZXIgcGVyc3BlY3RpdmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGVmdCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgbGVmdCBvZiB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByaWdodCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgcmlnaHQgb2YgdGhlIGNhbWVyYSB0aGF0IHdpbGwgYmUgaW4gdmlldy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYm90dG9tIFRoZSBudW1iZXIgb2YgbWV0ZXJzIGJlbG93IHRoZSBjYW1lcmEgdGhhdCB3aWxsIGJlIGluIHZpZXcuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHRvcCBUaGUgbnVtYmVyIG9mIG1ldGVycyBhYm92ZSB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuZWFyIFRoZSBkaXN0YW5jZSB0byB0aGUgbmVhciBwbGFuZSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGZhciBUaGUgZGlzdGFuY2UgdG8gdGhlIGZhciBwbGFuZSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY29tcHV0ZVBlcnNwZWN0aXZlT2ZmQ2VudGVyKGxlZnQsIHJpZ2h0LCBib3R0b20sIHRvcCwgbmVhciwgZmFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYm90dG9tIiwgYm90dG9tKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigidG9wIiwgdG9wKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibmVhciIsIG5lYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJmYXIiLCBmYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzAgPSAyICogbmVhciAvIChyaWdodCAtIGxlZnQpOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzEgPSAyICogbmVhciAvICh0b3AgLSBib3R0b20pOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzAgPSAocmlnaHQgKyBsZWZ0KSAvIChyaWdodCAtIGxlZnQpOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzEgPSAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzIgPSAtKGZhciArIG5lYXIpIC8gKGZhciAtIG5lYXIpOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzMgPSAtMTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3cyID0gLTIgKiBmYXIgKiBuZWFyIC8gKGZhciAtIG5lYXIpOwogICAgICAgICAgcmVzdWx0WzBdID0gY29sdW1uMFJvdzA7CiAgICAgICAgICByZXN1bHRbMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgIHJlc3VsdFszXSA9IDA7CiAgICAgICAgICByZXN1bHRbNF0gPSAwOwogICAgICAgICAgcmVzdWx0WzVdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IGNvbHVtbjJSb3cwOwogICAgICAgICAgcmVzdWx0WzldID0gY29sdW1uMlJvdzE7CiAgICAgICAgICByZXN1bHRbMTBdID0gY29sdW1uMlJvdzI7CiAgICAgICAgICByZXN1bHRbMTFdID0gY29sdW1uMlJvdzM7CiAgICAgICAgICByZXN1bHRbMTJdID0gMDsKICAgICAgICAgIHJlc3VsdFsxM10gPSAwOwogICAgICAgICAgcmVzdWx0WzE0XSA9IGNvbHVtbjNSb3cyOwogICAgICAgICAgcmVzdWx0WzE1XSA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDQgaW5zdGFuY2UgcmVwcmVzZW50aW5nIGFuIGluZmluaXRlIG9mZiBjZW50ZXIgcGVyc3BlY3RpdmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGVmdCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgbGVmdCBvZiB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByaWdodCBUaGUgbnVtYmVyIG9mIG1ldGVycyB0byB0aGUgcmlnaHQgb2YgdGhlIGNhbWVyYSB0aGF0IHdpbGwgYmUgaW4gdmlldy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYm90dG9tIFRoZSBudW1iZXIgb2YgbWV0ZXJzIGJlbG93IG9mIHRoZSBjYW1lcmEgdGhhdCB3aWxsIGJlIGluIHZpZXcuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHRvcCBUaGUgbnVtYmVyIG9mIG1ldGVycyBhYm92ZSBvZiB0aGUgY2FtZXJhIHRoYXQgd2lsbCBiZSBpbiB2aWV3LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuZWFyIFRoZSBkaXN0YW5jZSB0byB0aGUgbmVhciBwbGFuZSBpbiBtZXRlcnMuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY29tcHV0ZUluZmluaXRlUGVyc3BlY3RpdmVPZmZDZW50ZXIobGVmdCwgcmlnaHQsIGJvdHRvbSwgdG9wLCBuZWFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYm90dG9tIiwgYm90dG9tKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigidG9wIiwgdG9wKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibmVhciIsIG5lYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzAgPSAyICogbmVhciAvIChyaWdodCAtIGxlZnQpOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzEgPSAyICogbmVhciAvICh0b3AgLSBib3R0b20pOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzAgPSAocmlnaHQgKyBsZWZ0KSAvIChyaWdodCAtIGxlZnQpOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzEgPSAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pOwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzIgPSAtMTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3czID0gLTE7CiAgICAgICAgICBjb25zdCBjb2x1bW4zUm93MiA9IC0yICogbmVhcjsKICAgICAgICAgIHJlc3VsdFswXSA9IGNvbHVtbjBSb3cwOwogICAgICAgICAgcmVzdWx0WzFdID0gMDsKICAgICAgICAgIHJlc3VsdFsyXSA9IDA7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gMDsKICAgICAgICAgIHJlc3VsdFs1XSA9IGNvbHVtbjFSb3cxOwogICAgICAgICAgcmVzdWx0WzZdID0gMDsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSBjb2x1bW4yUm93MDsKICAgICAgICAgIHJlc3VsdFs5XSA9IGNvbHVtbjJSb3cxOwogICAgICAgICAgcmVzdWx0WzEwXSA9IGNvbHVtbjJSb3cyOwogICAgICAgICAgcmVzdWx0WzExXSA9IGNvbHVtbjJSb3czOwogICAgICAgICAgcmVzdWx0WzEyXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTNdID0gMDsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBjb2x1bW4zUm93MjsKICAgICAgICAgIHJlc3VsdFsxNV0gPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBNYXRyaXg0IGluc3RhbmNlIHRoYXQgdHJhbnNmb3JtcyBmcm9tIG5vcm1hbGl6ZWQgZGV2aWNlIGNvb3JkaW5hdGVzIHRvIHdpbmRvdyBjb29yZGluYXRlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Vmlld3BvcnR9IFt2aWV3cG9ydCA9IHsgeCA6IDAuMCwgeSA6IDAuMCwgd2lkdGggOiAwLjAsIGhlaWdodCA6IDAuMCB9XSBUaGUgdmlld3BvcnQncyBjb3JuZXJzIGFzIHNob3duIGluIEV4YW1wbGUgMS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW25lYXJEZXB0aFJhbmdlPTAuMF0gVGhlIG5lYXIgcGxhbmUgZGlzdGFuY2UgaW4gd2luZG93IGNvb3JkaW5hdGVzLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZmFyRGVwdGhSYW5nZT0xLjBdIFRoZSBmYXIgcGxhbmUgZGlzdGFuY2UgaW4gd2luZG93IGNvb3JkaW5hdGVzLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gQ3JlYXRlIHZpZXdwb3J0IHRyYW5zZm9ybWF0aW9uIHVzaW5nIGFuIGV4cGxpY2l0IHZpZXdwb3J0IGFuZCBkZXB0aCByYW5nZS4KICAgICAgICAgKiBjb25zdCBtID0gQ2VzaXVtLk1hdHJpeDQuY29tcHV0ZVZpZXdwb3J0VHJhbnNmb3JtYXRpb24oewogICAgICAgICAqICAgICB4IDogMC4wLAogICAgICAgICAqICAgICB5IDogMC4wLAogICAgICAgICAqICAgICB3aWR0aCA6IDEwMjQuMCwKICAgICAgICAgKiAgICAgaGVpZ2h0IDogNzY4LjAKICAgICAgICAgKiB9LCAwLjAsIDEuMCwgbmV3IENlc2l1bS5NYXRyaXg0KCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjb21wdXRlVmlld3BvcnRUcmFuc2Zvcm1hdGlvbih2aWV3cG9ydCwgbmVhckRlcHRoUmFuZ2UsIGZhckRlcHRoUmFuZ2UsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX01hdHJpeDQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHZpZXdwb3J0ID0gdmlld3BvcnQgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgICAgY29uc3QgeDIgPSB2aWV3cG9ydC54ID8/IDA7CiAgICAgICAgICBjb25zdCB5MiA9IHZpZXdwb3J0LnkgPz8gMDsKICAgICAgICAgIGNvbnN0IHdpZHRoID0gdmlld3BvcnQud2lkdGggPz8gMDsKICAgICAgICAgIGNvbnN0IGhlaWdodCA9IHZpZXdwb3J0LmhlaWdodCA/PyAwOwogICAgICAgICAgbmVhckRlcHRoUmFuZ2UgPSBuZWFyRGVwdGhSYW5nZSA/PyAwOwogICAgICAgICAgZmFyRGVwdGhSYW5nZSA9IGZhckRlcHRoUmFuZ2UgPz8gMTsKICAgICAgICAgIGNvbnN0IGhhbGZXaWR0aCA9IHdpZHRoICogMC41OwogICAgICAgICAgY29uc3QgaGFsZkhlaWdodCA9IGhlaWdodCAqIDAuNTsKICAgICAgICAgIGNvbnN0IGhhbGZEZXB0aCA9IChmYXJEZXB0aFJhbmdlIC0gbmVhckRlcHRoUmFuZ2UpICogMC41OwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzAgPSBoYWxmV2lkdGg7CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MSA9IGhhbGZIZWlnaHQ7CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MiA9IGhhbGZEZXB0aDsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3cwID0geDIgKyBoYWxmV2lkdGg7CiAgICAgICAgICBjb25zdCBjb2x1bW4zUm93MSA9IHkyICsgaGFsZkhlaWdodDsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3cyID0gbmVhckRlcHRoUmFuZ2UgKyBoYWxmRGVwdGg7CiAgICAgICAgICBjb25zdCBjb2x1bW4zUm93MyA9IDE7CiAgICAgICAgICByZXN1bHRbMF0gPSBjb2x1bW4wUm93MDsKICAgICAgICAgIHJlc3VsdFsxXSA9IDA7CiAgICAgICAgICByZXN1bHRbMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IDA7CiAgICAgICAgICByZXN1bHRbNV0gPSBjb2x1bW4xUm93MTsKICAgICAgICAgIHJlc3VsdFs2XSA9IDA7CiAgICAgICAgICByZXN1bHRbN10gPSAwOwogICAgICAgICAgcmVzdWx0WzhdID0gMDsKICAgICAgICAgIHJlc3VsdFs5XSA9IDA7CiAgICAgICAgICByZXN1bHRbMTBdID0gY29sdW1uMlJvdzI7CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSBjb2x1bW4zUm93MDsKICAgICAgICAgIHJlc3VsdFsxM10gPSBjb2x1bW4zUm93MTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBjb2x1bW4zUm93MjsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBjb2x1bW4zUm93MzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgTWF0cml4NCBpbnN0YW5jZSB0aGF0IHRyYW5zZm9ybXMgZnJvbSB3b3JsZCBzcGFjZSB0byB2aWV3IHNwYWNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBwb3NpdGlvbiBUaGUgcG9zaXRpb24gb2YgdGhlIGNhbWVyYS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGRpcmVjdGlvbiBUaGUgZm9yd2FyZCBkaXJlY3Rpb24uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSB1cCBUaGUgdXAgZGlyZWN0aW9uLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmlnaHQgVGhlIHJpZ2h0IGRpcmVjdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjb21wdXRlVmlldyhwb3NpdGlvbiwgZGlyZWN0aW9uMiwgdXAsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicG9zaXRpb24iLCBwb3NpdGlvbik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImRpcmVjdGlvbiIsIGRpcmVjdGlvbjIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ1cCIsIHVwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSByaWdodC54OwogICAgICAgICAgcmVzdWx0WzFdID0gdXAueDsKICAgICAgICAgIHJlc3VsdFsyXSA9IC1kaXJlY3Rpb24yLng7CiAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgcmVzdWx0WzRdID0gcmlnaHQueTsKICAgICAgICAgIHJlc3VsdFs1XSA9IHVwLnk7CiAgICAgICAgICByZXN1bHRbNl0gPSAtZGlyZWN0aW9uMi55OwogICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgIHJlc3VsdFs4XSA9IHJpZ2h0Lno7CiAgICAgICAgICByZXN1bHRbOV0gPSB1cC56OwogICAgICAgICAgcmVzdWx0WzEwXSA9IC1kaXJlY3Rpb24yLno7CiAgICAgICAgICByZXN1bHRbMTFdID0gMDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdChyaWdodCwgcG9zaXRpb24pOwogICAgICAgICAgcmVzdWx0WzEzXSA9IC1DYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHVwLCBwb3NpdGlvbik7CiAgICAgICAgICByZXN1bHRbMTRdID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCBwb3NpdGlvbik7CiAgICAgICAgICByZXN1bHRbMTVdID0gMTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGFuIEFycmF5IGZyb20gdGhlIHByb3ZpZGVkIE1hdHJpeDQgaW5zdGFuY2UuCiAgICAgICAgICogVGhlIGFycmF5IHdpbGwgYmUgaW4gY29sdW1uLW1ham9yIG9yZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtyZXN1bHRdIFRoZSBBcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgbW9kaWZpZWQgQXJyYXkgcGFyYW1ldGVyIG9yIGEgbmV3IEFycmF5IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL2NyZWF0ZSBhbiBhcnJheSBmcm9tIGFuIGluc3RhbmNlIG9mIE1hdHJpeDQKICAgICAgICAgKiAvLyBtID0gWzEwLjAsIDE0LjAsIDE4LjAsIDIyLjBdCiAgICAgICAgICogLy8gICAgIFsxMS4wLCAxNS4wLCAxOS4wLCAyMy4wXQogICAgICAgICAqIC8vICAgICBbMTIuMCwgMTYuMCwgMjAuMCwgMjQuMF0KICAgICAgICAgKiAvLyAgICAgWzEzLjAsIDE3LjAsIDIxLjAsIDI1LjBdCiAgICAgICAgICogY29uc3QgYSA9IENlc2l1bS5NYXRyaXg0LnRvQXJyYXkobSk7CiAgICAgICAgICoKICAgICAgICAgKiAvLyBtIHJlbWFpbnMgdGhlIHNhbWUKICAgICAgICAgKiAvL2NyZWF0ZXMgYSA9IFsxMC4wLCAxMS4wLCAxMi4wLCAxMy4wLCAxNC4wLCAxNS4wLCAxNi4wLCAxNy4wLCAxOC4wLCAxOS4wLCAyMC4wLCAyMS4wLCAyMi4wLCAyMy4wLCAyNC4wLCAyNS4wXQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0b0FycmF5KG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBbCiAgICAgICAgICAgICAgbWF0cml4WzBdLAogICAgICAgICAgICAgIG1hdHJpeFsxXSwKICAgICAgICAgICAgICBtYXRyaXhbMl0sCiAgICAgICAgICAgICAgbWF0cml4WzNdLAogICAgICAgICAgICAgIG1hdHJpeFs0XSwKICAgICAgICAgICAgICBtYXRyaXhbNV0sCiAgICAgICAgICAgICAgbWF0cml4WzZdLAogICAgICAgICAgICAgIG1hdHJpeFs3XSwKICAgICAgICAgICAgICBtYXRyaXhbOF0sCiAgICAgICAgICAgICAgbWF0cml4WzldLAogICAgICAgICAgICAgIG1hdHJpeFsxMF0sCiAgICAgICAgICAgICAgbWF0cml4WzExXSwKICAgICAgICAgICAgICBtYXRyaXhbMTJdLAogICAgICAgICAgICAgIG1hdHJpeFsxM10sCiAgICAgICAgICAgICAgbWF0cml4WzE0XSwKICAgICAgICAgICAgICBtYXRyaXhbMTVdCiAgICAgICAgICAgIF07CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl07CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbNl07CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbOF07CiAgICAgICAgICByZXN1bHRbOV0gPSBtYXRyaXhbOV07CiAgICAgICAgICByZXN1bHRbMTBdID0gbWF0cml4WzEwXTsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBtYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IG1hdHJpeFsxMl07CiAgICAgICAgICByZXN1bHRbMTNdID0gbWF0cml4WzEzXTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBtYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IG1hdHJpeFsxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgYXJyYXkgaW5kZXggb2YgdGhlIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIHJvdyBhbmQgY29sdW1uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHJvdyBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgcm93LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2x1bW4gVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIGNvbHVtbi4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgaW5kZXggb2YgdGhlIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIHJvdyBhbmQgY29sdW1uLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IHJvdyBtdXN0IGJlIDAsIDEsIDIsIG9yIDMuCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IGNvbHVtbiBtdXN0IGJlIDAsIDEsIDIsIG9yIDMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IG15TWF0cml4ID0gbmV3IENlc2l1bS5NYXRyaXg0KCk7CiAgICAgICAgICogY29uc3QgY29sdW1uMVJvdzBJbmRleCA9IENlc2l1bS5NYXRyaXg0LmdldEVsZW1lbnRJbmRleCgxLCAwKTsKICAgICAgICAgKiBjb25zdCBjb2x1bW4xUm93MCA9IG15TWF0cml4W2NvbHVtbjFSb3cwSW5kZXhdOwogICAgICAgICAqIG15TWF0cml4W2NvbHVtbjFSb3cwSW5kZXhdID0gMTAuMDsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0RWxlbWVudEluZGV4KGNvbHVtbiwgcm93KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygicm93Iiwgcm93LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJyb3ciLCByb3csIDMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImNvbHVtbiIsIGNvbHVtbiwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiY29sdW1uIiwgY29sdW1uLCAzKTsKICAgICAgICAgIHJldHVybiBjb2x1bW4gKiA0ICsgcm93OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBtYXRyaXggY29sdW1uIGF0IHRoZSBwcm92aWRlZCBpbmRleCBhcyBhIENhcnRlc2lhbjQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIGNvbHVtbiB0byByZXRyaWV2ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuNH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gaW5kZXggbXVzdCBiZSAwLCAxLCAyLCBvciAzLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL3JldHVybnMgYSBDYXJ0ZXNpYW40IGluc3RhbmNlIHdpdGggdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCBjb2x1bW4KICAgICAgICAgKiAvLyBtID0gWzEwLjAsIDExLjAsIDEyLjAsIDEzLjBdCiAgICAgICAgICogLy8gICAgIFsxNC4wLCAxNS4wLCAxNi4wLCAxNy4wXQogICAgICAgICAqIC8vICAgICBbMTguMCwgMTkuMCwgMjAuMCwgMjEuMF0KICAgICAgICAgKiAvLyAgICAgWzIyLjAsIDIzLjAsIDI0LjAsIDI1LjBdCiAgICAgICAgICoKICAgICAgICAgKiAvL0V4YW1wbGUgMTogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBDYXJ0ZXNpYW4KICAgICAgICAgKiBjb25zdCBhID0gQ2VzaXVtLk1hdHJpeDQuZ2V0Q29sdW1uKG0sIDIsIG5ldyBDZXNpdW0uQ2FydGVzaWFuNCgpKTsKICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy9FeGFtcGxlIDI6IFNldHMgdmFsdWVzIGZvciBDYXJ0ZXNpYW4gaW5zdGFuY2UKICAgICAgICAgKiBjb25zdCBhID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW40KCk7CiAgICAgICAgICogQ2VzaXVtLk1hdHJpeDQuZ2V0Q29sdW1uKG0sIDIsIGEpOwogICAgICAgICAqCiAgICAgICAgICogLy8gYS54ID0gMTIuMDsgYS55ID0gMTYuMDsgYS56ID0gMjAuMDsgYS53ID0gMjQuMDsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0Q29sdW1uKG1hdHJpeCwgaW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3Qgc3RhcnRJbmRleCA9IGluZGV4ICogNDsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4W3N0YXJ0SW5kZXhdOwogICAgICAgICAgY29uc3QgeTIgPSBtYXRyaXhbc3RhcnRJbmRleCArIDFdOwogICAgICAgICAgY29uc3QgejIgPSBtYXRyaXhbc3RhcnRJbmRleCArIDJdOwogICAgICAgICAgY29uc3QgdzIgPSBtYXRyaXhbc3RhcnRJbmRleCArIDNdOwogICAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgICByZXN1bHQueiA9IHoyOwogICAgICAgICAgcmVzdWx0LncgPSB3MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbmV3IG1hdHJpeCB0aGF0IHJlcGxhY2VzIHRoZSBzcGVjaWZpZWQgY29sdW1uIGluIHRoZSBwcm92aWRlZCBtYXRyaXggd2l0aCB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuNCBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uIHRvIHNldC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHdob3NlIHZhbHVlcyB3aWxsIGJlIGFzc2lnbmVkIHRvIHRoZSBzcGVjaWZpZWQgY29sdW1uLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAsIDEsIDIsIG9yIDMuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vY3JlYXRlcyBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIHdpdGggbmV3IGNvbHVtbiB2YWx1ZXMgZnJvbSB0aGUgQ2FydGVzaWFuNCBpbnN0YW5jZQogICAgICAgICAqIC8vIG0gPSBbMTAuMCwgMTEuMCwgMTIuMCwgMTMuMF0KICAgICAgICAgKiAvLyAgICAgWzE0LjAsIDE1LjAsIDE2LjAsIDE3LjBdCiAgICAgICAgICogLy8gICAgIFsxOC4wLCAxOS4wLCAyMC4wLCAyMS4wXQogICAgICAgICAqIC8vICAgICBbMjIuMCwgMjMuMCwgMjQuMCwgMjUuMF0KICAgICAgICAgKgogICAgICAgICAqIGNvbnN0IGEgPSBDZXNpdW0uTWF0cml4NC5zZXRDb2x1bW4obSwgMiwgbmV3IENlc2l1bS5DYXJ0ZXNpYW40KDk5LjAsIDk4LjAsIDk3LjAsIDk2LjApLCBuZXcgQ2VzaXVtLk1hdHJpeDQoKSk7CiAgICAgICAgICoKICAgICAgICAgKiAvLyBtIHJlbWFpbnMgdGhlIHNhbWUKICAgICAgICAgKiAvLyBhID0gWzEwLjAsIDExLjAsIDk5LjAsIDEzLjBdCiAgICAgICAgICogLy8gICAgIFsxNC4wLCAxNS4wLCA5OC4wLCAxNy4wXQogICAgICAgICAqIC8vICAgICBbMTguMCwgMTkuMCwgOTcuMCwgMjEuMF0KICAgICAgICAgKiAvLyAgICAgWzIyLjAsIDIzLjAsIDk2LjAsIDI1LjBdCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldENvbHVtbihtYXRyaXgsIGluZGV4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMyk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdCA9IF9NYXRyaXg0LmNsb25lKG1hdHJpeCwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHN0YXJ0SW5kZXggPSBpbmRleCAqIDQ7CiAgICAgICAgICByZXN1bHRbc3RhcnRJbmRleF0gPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgcmVzdWx0W3N0YXJ0SW5kZXggKyAxXSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXN1bHRbc3RhcnRJbmRleCArIDJdID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIHJlc3VsdFtzdGFydEluZGV4ICsgM10gPSBjYXJ0ZXNpYW4xMS53OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogUmV0cmlldmVzIGEgY29weSBvZiB0aGUgbWF0cml4IHJvdyBhdCB0aGUgcHJvdmlkZWQgaW5kZXggYXMgYSBDYXJ0ZXNpYW40IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IFRoZSB6ZXJvLWJhc2VkIGluZGV4IG9mIHRoZSByb3cgdG8gcmV0cmlldmUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IGluZGV4IG11c3QgYmUgMCwgMSwgMiwgb3IgMy4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy9yZXR1cm5zIGEgQ2FydGVzaWFuNCBpbnN0YW5jZSB3aXRoIHZhbHVlcyBmcm9tIHRoZSBzcGVjaWZpZWQgY29sdW1uCiAgICAgICAgICogLy8gbSA9IFsxMC4wLCAxMS4wLCAxMi4wLCAxMy4wXQogICAgICAgICAqIC8vICAgICBbMTQuMCwgMTUuMCwgMTYuMCwgMTcuMF0KICAgICAgICAgKiAvLyAgICAgWzE4LjAsIDE5LjAsIDIwLjAsIDIxLjBdCiAgICAgICAgICogLy8gICAgIFsyMi4wLCAyMy4wLCAyNC4wLCAyNS4wXQogICAgICAgICAqCiAgICAgICAgICogLy9FeGFtcGxlIDE6IFJldHVybnMgYW4gaW5zdGFuY2Ugb2YgQ2FydGVzaWFuCiAgICAgICAgICogY29uc3QgYSA9IENlc2l1bS5NYXRyaXg0LmdldFJvdyhtLCAyLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjQoKSk7CiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vRXhhbXBsZSAyOiBTZXRzIHZhbHVlcyBmb3IgYSBDYXJ0ZXNpYW4gaW5zdGFuY2UKICAgICAgICAgKiBjb25zdCBhID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW40KCk7CiAgICAgICAgICogQ2VzaXVtLk1hdHJpeDQuZ2V0Um93KG0sIDIsIGEpOwogICAgICAgICAqCiAgICAgICAgICogLy8gYS54ID0gMTguMDsgYS55ID0gMTkuMDsgYS56ID0gMjAuMDsgYS53ID0gMjEuMDsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0Um93KG1hdHJpeCwgaW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgeDIgPSBtYXRyaXhbaW5kZXhdOwogICAgICAgICAgY29uc3QgeTIgPSBtYXRyaXhbaW5kZXggKyA0XTsKICAgICAgICAgIGNvbnN0IHoyID0gbWF0cml4W2luZGV4ICsgOF07CiAgICAgICAgICBjb25zdCB3MiA9IG1hdHJpeFtpbmRleCArIDEyXTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJlc3VsdC53ID0gdzI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIG5ldyBtYXRyaXggdGhhdCByZXBsYWNlcyB0aGUgc3BlY2lmaWVkIHJvdyBpbiB0aGUgcHJvdmlkZWQgbWF0cml4IHdpdGggdGhlIHByb3ZpZGVkIENhcnRlc2lhbjQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIHJvdyB0byBzZXQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB3aG9zZSB2YWx1ZXMgd2lsbCBiZSBhc3NpZ25lZCB0byB0aGUgc3BlY2lmaWVkIHJvdy4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gaW5kZXggbXVzdCBiZSAwLCAxLCAyLCBvciAzLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL2NyZWF0ZSBhIG5ldyBNYXRyaXg0IGluc3RhbmNlIHdpdGggbmV3IHJvdyB2YWx1ZXMgZnJvbSB0aGUgQ2FydGVzaWFuNCBpbnN0YW5jZQogICAgICAgICAqIC8vIG0gPSBbMTAuMCwgMTEuMCwgMTIuMCwgMTMuMF0KICAgICAgICAgKiAvLyAgICAgWzE0LjAsIDE1LjAsIDE2LjAsIDE3LjBdCiAgICAgICAgICogLy8gICAgIFsxOC4wLCAxOS4wLCAyMC4wLCAyMS4wXQogICAgICAgICAqIC8vICAgICBbMjIuMCwgMjMuMCwgMjQuMCwgMjUuMF0KICAgICAgICAgKgogICAgICAgICAqIGNvbnN0IGEgPSBDZXNpdW0uTWF0cml4NC5zZXRSb3cobSwgMiwgbmV3IENlc2l1bS5DYXJ0ZXNpYW40KDk5LjAsIDk4LjAsIDk3LjAsIDk2LjApLCBuZXcgQ2VzaXVtLk1hdHJpeDQoKSk7CiAgICAgICAgICoKICAgICAgICAgKiAvLyBtIHJlbWFpbnMgdGhlIHNhbWUKICAgICAgICAgKiAvLyBhID0gWzEwLjAsIDExLjAsIDEyLjAsIDEzLjBdCiAgICAgICAgICogLy8gICAgIFsxNC4wLCAxNS4wLCAxNi4wLCAxNy4wXQogICAgICAgICAqIC8vICAgICBbOTkuMCwgOTguMCwgOTcuMCwgOTYuMF0KICAgICAgICAgKiAvLyAgICAgWzIyLjAsIDIzLjAsIDI0LjAsIDI1LjBdCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFJvdyhtYXRyaXgsIGluZGV4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMyk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdCA9IF9NYXRyaXg0LmNsb25lKG1hdHJpeCwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFtpbmRleF0gPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgcmVzdWx0W2luZGV4ICsgNF0gPSBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgcmVzdWx0W2luZGV4ICsgOF0gPSBjYXJ0ZXNpYW4xMS56OwogICAgICAgICAgcmVzdWx0W2luZGV4ICsgMTJdID0gY2FydGVzaWFuMTEudzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbmV3IG1hdHJpeCB0aGF0IHJlcGxhY2VzIHRoZSB0cmFuc2xhdGlvbiBpbiB0aGUgcmlnaHRtb3N0IGNvbHVtbiBvZiB0aGUgcHJvdmlkZWQKICAgICAgICAgKiBtYXRyaXggd2l0aCB0aGUgcHJvdmlkZWQgdHJhbnNsYXRpb24uIFRoaXMgYXNzdW1lcyB0aGUgbWF0cml4IGlzIGFuIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gdHJhbnNsYXRpb24gVGhlIHRyYW5zbGF0aW9uIHRoYXQgcmVwbGFjZXMgdGhlIHRyYW5zbGF0aW9uIG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBzZXRUcmFuc2xhdGlvbihtYXRyaXgsIHRyYW5zbGF0aW9uMiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zbGF0aW9uIiwgdHJhbnNsYXRpb24yKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XTsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeFs5XTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtYXRyaXhbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IG1hdHJpeFsxMV07CiAgICAgICAgICByZXN1bHRbMTJdID0gdHJhbnNsYXRpb24yLng7CiAgICAgICAgICByZXN1bHRbMTNdID0gdHJhbnNsYXRpb24yLnk7CiAgICAgICAgICByZXN1bHRbMTRdID0gdHJhbnNsYXRpb24yLno7CiAgICAgICAgICByZXN1bHRbMTVdID0gbWF0cml4WzE1XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbmV3IG1hdHJpeCB0aGF0IHJlcGxhY2VzIHRoZSBzY2FsZSB3aXRoIHRoZSBwcm92aWRlZCBzY2FsZS4KICAgICAgICAgKiBUaGlzIGFzc3VtZXMgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHNjYWxlIFRoZSBzY2FsZSB0aGF0IHJlcGxhY2VzIHRoZSBzY2FsZSBvZiB0aGUgcHJvdmlkZWQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBzZWUgTWF0cml4NC5zZXRVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZnJvbVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmZyb21Vbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQubXVsdGlwbHlCeVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0Lm11bHRpcGx5QnlVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZ2V0U2NhbGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2V0U2NhbGUobWF0cml4LCBzY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNjYWxlIiwgc2NhbGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgZXhpc3RpbmdTY2FsZSA9IF9NYXRyaXg0LmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoMTIpOwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1ggPSBzY2FsZS54IC8gZXhpc3RpbmdTY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1kgPSBzY2FsZS55IC8gZXhpc3RpbmdTY2FsZS55OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1ogPSBzY2FsZS56IC8gZXhpc3RpbmdTY2FsZS56OwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV0gKiBzY2FsZVJhdGlvWDsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdOwogICAgICAgICAgcmVzdWx0WzRdID0gbWF0cml4WzRdICogc2NhbGVSYXRpb1k7CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNV0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmVzdWx0WzddID0gbWF0cml4WzddOwogICAgICAgICAgcmVzdWx0WzhdID0gbWF0cml4WzhdICogc2NhbGVSYXRpb1o7CiAgICAgICAgICByZXN1bHRbOV0gPSBtYXRyaXhbOV0gKiBzY2FsZVJhdGlvWjsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtYXRyaXhbMTBdICogc2NhbGVSYXRpb1o7CiAgICAgICAgICByZXN1bHRbMTFdID0gbWF0cml4WzExXTsKICAgICAgICAgIHJlc3VsdFsxMl0gPSBtYXRyaXhbMTJdOwogICAgICAgICAgcmVzdWx0WzEzXSA9IG1hdHJpeFsxM107CiAgICAgICAgICByZXN1bHRbMTRdID0gbWF0cml4WzE0XTsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBtYXRyaXhbMTVdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBuZXcgbWF0cml4IHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIHdpdGggdGhlIHByb3ZpZGVkIHVuaWZvcm0gc2NhbGUuCiAgICAgICAgICogVGhpcyBhc3N1bWVzIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlIFRoZSB1bmlmb3JtIHNjYWxlIHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXg0LnNldFNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0Lm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFVuaWZvcm1TY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBleGlzdGluZ1NjYWxlID0gX01hdHJpeDQuZ2V0U2NhbGUobWF0cml4LCBzY2FsZVNjcmF0Y2gyMik7CiAgICAgICAgICBjb25zdCBzY2FsZVJhdGlvWCA9IHNjYWxlIC8gZXhpc3RpbmdTY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1kgPSBzY2FsZSAvIGV4aXN0aW5nU2NhbGUueTsKICAgICAgICAgIGNvbnN0IHNjYWxlUmF0aW9aID0gc2NhbGUgLyBleGlzdGluZ1NjYWxlLno7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF0gKiBzY2FsZVJhdGlvWDsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4WzZdICogc2NhbGVSYXRpb1k7CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbOF0gKiBzY2FsZVJhdGlvWjsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeFs5XSAqIHNjYWxlUmF0aW9aOwogICAgICAgICAgcmVzdWx0WzEwXSA9IG1hdHJpeFsxMF0gKiBzY2FsZVJhdGlvWjsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBtYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IG1hdHJpeFsxMl07CiAgICAgICAgICByZXN1bHRbMTNdID0gbWF0cml4WzEzXTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBtYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IG1hdHJpeFsxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBFeHRyYWN0cyB0aGUgbm9uLXVuaWZvcm0gc2NhbGUgYXNzdW1pbmcgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlcgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXg0Lm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LnNldFNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LnNldFVuaWZvcm1TY2FsZQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRTY2FsZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKG1hdHJpeFswXSwgbWF0cml4WzFdLCBtYXRyaXhbMl0sIHNjcmF0Y2hDb2x1bW4yKQogICAgICAgICAgKTsKICAgICAgICAgIHJlc3VsdC55ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cyhtYXRyaXhbNF0sIG1hdHJpeFs1XSwgbWF0cml4WzZdLCBzY3JhdGNoQ29sdW1uMikKICAgICAgICAgICk7CiAgICAgICAgICByZXN1bHQueiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMobWF0cml4WzhdLCBtYXRyaXhbOV0sIG1hdHJpeFsxMF0sIHNjcmF0Y2hDb2x1bW4yKQogICAgICAgICAgKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBtYXhpbXVtIHNjYWxlIGFzc3VtaW5nIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqIFRoZSBtYXhpbXVtIHNjYWxlIGlzIHRoZSBtYXhpbXVtIGxlbmd0aCBvZiB0aGUgY29sdW1uIHZlY3RvcnMgaW4gdGhlIHVwcGVyLWxlZnQKICAgICAgICAgKiAzeDMgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbWF4aW11bSBzY2FsZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0TWF4aW11bVNjYWxlKG1hdHJpeCkgewogICAgICAgICAgX01hdHJpeDQuZ2V0U2NhbGUobWF0cml4LCBzY2FsZVNjcmF0Y2gzMik7CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm1heGltdW1Db21wb25lbnQoc2NhbGVTY3JhdGNoMzIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTZXRzIHRoZSByb3RhdGlvbiBhc3N1bWluZyB0aGUgbWF0cml4IGlzIGFuIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4IFRoZSBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByb3RhdGlvbiBUaGUgcm90YXRpb24gbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBzZWUgTWF0cml4NC5mcm9tUm90YXRpb24KICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZ2V0Um90YXRpb24KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2V0Um90YXRpb24obWF0cml4LCByb3RhdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBzY2FsZSA9IF9NYXRyaXg0LmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoNDIpOwogICAgICAgICAgcmVzdWx0WzBdID0gcm90YXRpb25bMF0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gcm90YXRpb25bMV0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzJdID0gcm90YXRpb25bMl0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdOwogICAgICAgICAgcmVzdWx0WzRdID0gcm90YXRpb25bM10gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzVdID0gcm90YXRpb25bNF0gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzZdID0gcm90YXRpb25bNV0gKiBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzddID0gbWF0cml4WzddOwogICAgICAgICAgcmVzdWx0WzhdID0gcm90YXRpb25bNl0gKiBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzldID0gcm90YXRpb25bN10gKiBzY2FsZS56OwogICAgICAgICAgcmVzdWx0WzEwXSA9IHJvdGF0aW9uWzhdICogc2NhbGUuejsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBtYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IG1hdHJpeFsxMl07CiAgICAgICAgICByZXN1bHRbMTNdID0gbWF0cml4WzEzXTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBtYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IG1hdHJpeFsxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBFeHRyYWN0cyB0aGUgcm90YXRpb24gbWF0cml4IGFzc3VtaW5nIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4M30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuc2V0Um90YXRpb24KICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZnJvbVJvdGF0aW9uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldFJvdGF0aW9uKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBzY2FsZSA9IF9NYXRyaXg0LmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoNTIpOwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdIC8gc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAvIHNjYWxlLng7CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl0gLyBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzRdIC8gc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs1XSAvIHNjYWxlLnk7CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNl0gLyBzY2FsZS55OwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4WzhdIC8gc2NhbGUuejsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs5XSAvIHNjYWxlLno7CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbMTBdIC8gc2NhbGUuejsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIHR3byBtYXRyaWNlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbGVmdCBUaGUgZmlyc3QgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmlnaHQgVGhlIHNlY29uZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseShsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBsZWZ0MCA9IGxlZnRbMF07CiAgICAgICAgICBjb25zdCBsZWZ0MSA9IGxlZnRbMV07CiAgICAgICAgICBjb25zdCBsZWZ0MiA9IGxlZnRbMl07CiAgICAgICAgICBjb25zdCBsZWZ0MyA9IGxlZnRbM107CiAgICAgICAgICBjb25zdCBsZWZ0NCA9IGxlZnRbNF07CiAgICAgICAgICBjb25zdCBsZWZ0NSA9IGxlZnRbNV07CiAgICAgICAgICBjb25zdCBsZWZ0NiA9IGxlZnRbNl07CiAgICAgICAgICBjb25zdCBsZWZ0NyA9IGxlZnRbN107CiAgICAgICAgICBjb25zdCBsZWZ0OCA9IGxlZnRbOF07CiAgICAgICAgICBjb25zdCBsZWZ0OSA9IGxlZnRbOV07CiAgICAgICAgICBjb25zdCBsZWZ0MTAgPSBsZWZ0WzEwXTsKICAgICAgICAgIGNvbnN0IGxlZnQxMSA9IGxlZnRbMTFdOwogICAgICAgICAgY29uc3QgbGVmdDEyID0gbGVmdFsxMl07CiAgICAgICAgICBjb25zdCBsZWZ0MTMgPSBsZWZ0WzEzXTsKICAgICAgICAgIGNvbnN0IGxlZnQxNCA9IGxlZnRbMTRdOwogICAgICAgICAgY29uc3QgbGVmdDE1ID0gbGVmdFsxNV07CiAgICAgICAgICBjb25zdCByaWdodDAgPSByaWdodFswXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MSA9IHJpZ2h0WzFdOwogICAgICAgICAgY29uc3QgcmlnaHQyID0gcmlnaHRbMl07CiAgICAgICAgICBjb25zdCByaWdodDMgPSByaWdodFszXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0NCA9IHJpZ2h0WzRdOwogICAgICAgICAgY29uc3QgcmlnaHQ1ID0gcmlnaHRbNV07CiAgICAgICAgICBjb25zdCByaWdodDYgPSByaWdodFs2XTsKICAgICAgICAgIGNvbnN0IHJpZ2h0NyA9IHJpZ2h0WzddOwogICAgICAgICAgY29uc3QgcmlnaHQ4ID0gcmlnaHRbOF07CiAgICAgICAgICBjb25zdCByaWdodDkgPSByaWdodFs5XTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MTAgPSByaWdodFsxMF07CiAgICAgICAgICBjb25zdCByaWdodDExID0gcmlnaHRbMTFdOwogICAgICAgICAgY29uc3QgcmlnaHQxMiA9IHJpZ2h0WzEyXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MTMgPSByaWdodFsxM107CiAgICAgICAgICBjb25zdCByaWdodDE0ID0gcmlnaHRbMTRdOwogICAgICAgICAgY29uc3QgcmlnaHQxNSA9IHJpZ2h0WzE1XTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cwID0gbGVmdDAgKiByaWdodDAgKyBsZWZ0NCAqIHJpZ2h0MSArIGxlZnQ4ICogcmlnaHQyICsgbGVmdDEyICogcmlnaHQzOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzEgPSBsZWZ0MSAqIHJpZ2h0MCArIGxlZnQ1ICogcmlnaHQxICsgbGVmdDkgKiByaWdodDIgKyBsZWZ0MTMgKiByaWdodDM7CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MiA9IGxlZnQyICogcmlnaHQwICsgbGVmdDYgKiByaWdodDEgKyBsZWZ0MTAgKiByaWdodDIgKyBsZWZ0MTQgKiByaWdodDM7CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MyA9IGxlZnQzICogcmlnaHQwICsgbGVmdDcgKiByaWdodDEgKyBsZWZ0MTEgKiByaWdodDIgKyBsZWZ0MTUgKiByaWdodDM7CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MCA9IGxlZnQwICogcmlnaHQ0ICsgbGVmdDQgKiByaWdodDUgKyBsZWZ0OCAqIHJpZ2h0NiArIGxlZnQxMiAqIHJpZ2h0NzsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cxID0gbGVmdDEgKiByaWdodDQgKyBsZWZ0NSAqIHJpZ2h0NSArIGxlZnQ5ICogcmlnaHQ2ICsgbGVmdDEzICogcmlnaHQ3OwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzIgPSBsZWZ0MiAqIHJpZ2h0NCArIGxlZnQ2ICogcmlnaHQ1ICsgbGVmdDEwICogcmlnaHQ2ICsgbGVmdDE0ICogcmlnaHQ3OwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzMgPSBsZWZ0MyAqIHJpZ2h0NCArIGxlZnQ3ICogcmlnaHQ1ICsgbGVmdDExICogcmlnaHQ2ICsgbGVmdDE1ICogcmlnaHQ3OwogICAgICAgICAgY29uc3QgY29sdW1uMlJvdzAgPSBsZWZ0MCAqIHJpZ2h0OCArIGxlZnQ0ICogcmlnaHQ5ICsgbGVmdDggKiByaWdodDEwICsgbGVmdDEyICogcmlnaHQxMTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cxID0gbGVmdDEgKiByaWdodDggKyBsZWZ0NSAqIHJpZ2h0OSArIGxlZnQ5ICogcmlnaHQxMCArIGxlZnQxMyAqIHJpZ2h0MTE7CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MiA9IGxlZnQyICogcmlnaHQ4ICsgbGVmdDYgKiByaWdodDkgKyBsZWZ0MTAgKiByaWdodDEwICsgbGVmdDE0ICogcmlnaHQxMTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3czID0gbGVmdDMgKiByaWdodDggKyBsZWZ0NyAqIHJpZ2h0OSArIGxlZnQxMSAqIHJpZ2h0MTAgKyBsZWZ0MTUgKiByaWdodDExOwogICAgICAgICAgY29uc3QgY29sdW1uM1JvdzAgPSBsZWZ0MCAqIHJpZ2h0MTIgKyBsZWZ0NCAqIHJpZ2h0MTMgKyBsZWZ0OCAqIHJpZ2h0MTQgKyBsZWZ0MTIgKiByaWdodDE1OwogICAgICAgICAgY29uc3QgY29sdW1uM1JvdzEgPSBsZWZ0MSAqIHJpZ2h0MTIgKyBsZWZ0NSAqIHJpZ2h0MTMgKyBsZWZ0OSAqIHJpZ2h0MTQgKyBsZWZ0MTMgKiByaWdodDE1OwogICAgICAgICAgY29uc3QgY29sdW1uM1JvdzIgPSBsZWZ0MiAqIHJpZ2h0MTIgKyBsZWZ0NiAqIHJpZ2h0MTMgKyBsZWZ0MTAgKiByaWdodDE0ICsgbGVmdDE0ICogcmlnaHQxNTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3czID0gbGVmdDMgKiByaWdodDEyICsgbGVmdDcgKiByaWdodDEzICsgbGVmdDExICogcmlnaHQxNCArIGxlZnQxNSAqIHJpZ2h0MTU7CiAgICAgICAgICByZXN1bHRbMF0gPSBjb2x1bW4wUm93MDsKICAgICAgICAgIHJlc3VsdFsxXSA9IGNvbHVtbjBSb3cxOwogICAgICAgICAgcmVzdWx0WzJdID0gY29sdW1uMFJvdzI7CiAgICAgICAgICByZXN1bHRbM10gPSBjb2x1bW4wUm93MzsKICAgICAgICAgIHJlc3VsdFs0XSA9IGNvbHVtbjFSb3cwOwogICAgICAgICAgcmVzdWx0WzVdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXN1bHRbNl0gPSBjb2x1bW4xUm93MjsKICAgICAgICAgIHJlc3VsdFs3XSA9IGNvbHVtbjFSb3czOwogICAgICAgICAgcmVzdWx0WzhdID0gY29sdW1uMlJvdzA7CiAgICAgICAgICByZXN1bHRbOV0gPSBjb2x1bW4yUm93MTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBjb2x1bW4yUm93MjsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBjb2x1bW4yUm93MzsKICAgICAgICAgIHJlc3VsdFsxMl0gPSBjb2x1bW4zUm93MDsKICAgICAgICAgIHJlc3VsdFsxM10gPSBjb2x1bW4zUm93MTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBjb2x1bW4zUm93MjsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBjb2x1bW4zUm93MzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBzdW0gb2YgdHdvIG1hdHJpY2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBsZWZ0IFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByaWdodCBUaGUgc2Vjb25kIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGFkZChsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBsZWZ0WzBdICsgcmlnaHRbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSBsZWZ0WzFdICsgcmlnaHRbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSBsZWZ0WzJdICsgcmlnaHRbMl07CiAgICAgICAgICByZXN1bHRbM10gPSBsZWZ0WzNdICsgcmlnaHRbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBsZWZ0WzRdICsgcmlnaHRbNF07CiAgICAgICAgICByZXN1bHRbNV0gPSBsZWZ0WzVdICsgcmlnaHRbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSBsZWZ0WzZdICsgcmlnaHRbNl07CiAgICAgICAgICByZXN1bHRbN10gPSBsZWZ0WzddICsgcmlnaHRbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBsZWZ0WzhdICsgcmlnaHRbOF07CiAgICAgICAgICByZXN1bHRbOV0gPSBsZWZ0WzldICsgcmlnaHRbOV07CiAgICAgICAgICByZXN1bHRbMTBdID0gbGVmdFsxMF0gKyByaWdodFsxMF07CiAgICAgICAgICByZXN1bHRbMTFdID0gbGVmdFsxMV0gKyByaWdodFsxMV07CiAgICAgICAgICByZXN1bHRbMTJdID0gbGVmdFsxMl0gKyByaWdodFsxMl07CiAgICAgICAgICByZXN1bHRbMTNdID0gbGVmdFsxM10gKyByaWdodFsxM107CiAgICAgICAgICByZXN1bHRbMTRdID0gbGVmdFsxNF0gKyByaWdodFsxNF07CiAgICAgICAgICByZXN1bHRbMTVdID0gbGVmdFsxNV0gKyByaWdodFsxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgZGlmZmVyZW5jZSBvZiB0d28gbWF0cmljZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IGxlZnQgVGhlIGZpcnN0IG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJpZ2h0IFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc3VidHJhY3QobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gbGVmdFswXSAtIHJpZ2h0WzBdOwogICAgICAgICAgcmVzdWx0WzFdID0gbGVmdFsxXSAtIHJpZ2h0WzFdOwogICAgICAgICAgcmVzdWx0WzJdID0gbGVmdFsyXSAtIHJpZ2h0WzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gbGVmdFszXSAtIHJpZ2h0WzNdOwogICAgICAgICAgcmVzdWx0WzRdID0gbGVmdFs0XSAtIHJpZ2h0WzRdOwogICAgICAgICAgcmVzdWx0WzVdID0gbGVmdFs1XSAtIHJpZ2h0WzVdOwogICAgICAgICAgcmVzdWx0WzZdID0gbGVmdFs2XSAtIHJpZ2h0WzZdOwogICAgICAgICAgcmVzdWx0WzddID0gbGVmdFs3XSAtIHJpZ2h0WzddOwogICAgICAgICAgcmVzdWx0WzhdID0gbGVmdFs4XSAtIHJpZ2h0WzhdOwogICAgICAgICAgcmVzdWx0WzldID0gbGVmdFs5XSAtIHJpZ2h0WzldOwogICAgICAgICAgcmVzdWx0WzEwXSA9IGxlZnRbMTBdIC0gcmlnaHRbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IGxlZnRbMTFdIC0gcmlnaHRbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IGxlZnRbMTJdIC0gcmlnaHRbMTJdOwogICAgICAgICAgcmVzdWx0WzEzXSA9IGxlZnRbMTNdIC0gcmlnaHRbMTNdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IGxlZnRbMTRdIC0gcmlnaHRbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IGxlZnRbMTVdIC0gcmlnaHRbMTVdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHByb2R1Y3Qgb2YgdHdvIG1hdHJpY2VzIGFzc3VtaW5nIHRoZSBtYXRyaWNlcyBhcmUgYWZmaW5lIHRyYW5zZm9ybWF0aW9uIG1hdHJpY2VzLAogICAgICAgICAqIHdoZXJlIHRoZSB1cHBlciBsZWZ0IDN4MyBlbGVtZW50cyBhcmUgYW55IG1hdHJpeCwgYW5kCiAgICAgICAgICogdGhlIHVwcGVyIHRocmVlIGVsZW1lbnRzIGluIHRoZSBmb3VydGggY29sdW1uIGFyZSB0aGUgdHJhbnNsYXRpb24uCiAgICAgICAgICogVGhlIGJvdHRvbSByb3cgaXMgYXNzdW1lZCB0byBiZSBbMCwgMCwgMCwgMV0uCiAgICAgICAgICogVGhlIG1hdHJpeCBpcyBub3QgdmVyaWZpZWQgdG8gYmUgaW4gdGhlIHByb3BlciBmb3JtLgogICAgICAgICAqIFRoaXMgbWV0aG9kIGlzIGZhc3RlciB0aGFuIGNvbXB1dGluZyB0aGUgcHJvZHVjdCBmb3IgZ2VuZXJhbCA0eDQKICAgICAgICAgKiBtYXRyaWNlcyB1c2luZyB7QGxpbmsgTWF0cml4NC5tdWx0aXBseX0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IGxlZnQgVGhlIGZpcnN0IG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJpZ2h0IFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgbTEgPSBuZXcgQ2VzaXVtLk1hdHJpeDQoMS4wLCA2LjAsIDcuMCwgMC4wLCAyLjAsIDUuMCwgOC4wLCAwLjAsIDMuMCwgNC4wLCA5LjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMS4wKTsKICAgICAgICAgKiBjb25zdCBtMiA9IENlc2l1bS5UcmFuc2Zvcm1zLmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKG5ldyBDZXNpdW0uQ2FydGVzaWFuMygxLjAsIDEuMCwgMS4wKSk7CiAgICAgICAgICogY29uc3QgbTMgPSBDZXNpdW0uTWF0cml4NC5tdWx0aXBseVRyYW5zZm9ybWF0aW9uKG0xLCBtMiwgbmV3IENlc2l1bS5NYXRyaXg0KCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseVRyYW5zZm9ybWF0aW9uKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGxlZnQwID0gbGVmdFswXTsKICAgICAgICAgIGNvbnN0IGxlZnQxID0gbGVmdFsxXTsKICAgICAgICAgIGNvbnN0IGxlZnQyID0gbGVmdFsyXTsKICAgICAgICAgIGNvbnN0IGxlZnQ0ID0gbGVmdFs0XTsKICAgICAgICAgIGNvbnN0IGxlZnQ1ID0gbGVmdFs1XTsKICAgICAgICAgIGNvbnN0IGxlZnQ2ID0gbGVmdFs2XTsKICAgICAgICAgIGNvbnN0IGxlZnQ4ID0gbGVmdFs4XTsKICAgICAgICAgIGNvbnN0IGxlZnQ5ID0gbGVmdFs5XTsKICAgICAgICAgIGNvbnN0IGxlZnQxMCA9IGxlZnRbMTBdOwogICAgICAgICAgY29uc3QgbGVmdDEyID0gbGVmdFsxMl07CiAgICAgICAgICBjb25zdCBsZWZ0MTMgPSBsZWZ0WzEzXTsKICAgICAgICAgIGNvbnN0IGxlZnQxNCA9IGxlZnRbMTRdOwogICAgICAgICAgY29uc3QgcmlnaHQwID0gcmlnaHRbMF07CiAgICAgICAgICBjb25zdCByaWdodDEgPSByaWdodFsxXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MiA9IHJpZ2h0WzJdOwogICAgICAgICAgY29uc3QgcmlnaHQ0ID0gcmlnaHRbNF07CiAgICAgICAgICBjb25zdCByaWdodDUgPSByaWdodFs1XTsKICAgICAgICAgIGNvbnN0IHJpZ2h0NiA9IHJpZ2h0WzZdOwogICAgICAgICAgY29uc3QgcmlnaHQ4ID0gcmlnaHRbOF07CiAgICAgICAgICBjb25zdCByaWdodDkgPSByaWdodFs5XTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MTAgPSByaWdodFsxMF07CiAgICAgICAgICBjb25zdCByaWdodDEyID0gcmlnaHRbMTJdOwogICAgICAgICAgY29uc3QgcmlnaHQxMyA9IHJpZ2h0WzEzXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MTQgPSByaWdodFsxNF07CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MCA9IGxlZnQwICogcmlnaHQwICsgbGVmdDQgKiByaWdodDEgKyBsZWZ0OCAqIHJpZ2h0MjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cxID0gbGVmdDEgKiByaWdodDAgKyBsZWZ0NSAqIHJpZ2h0MSArIGxlZnQ5ICogcmlnaHQyOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzIgPSBsZWZ0MiAqIHJpZ2h0MCArIGxlZnQ2ICogcmlnaHQxICsgbGVmdDEwICogcmlnaHQyOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzAgPSBsZWZ0MCAqIHJpZ2h0NCArIGxlZnQ0ICogcmlnaHQ1ICsgbGVmdDggKiByaWdodDY7CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MSA9IGxlZnQxICogcmlnaHQ0ICsgbGVmdDUgKiByaWdodDUgKyBsZWZ0OSAqIHJpZ2h0NjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cyID0gbGVmdDIgKiByaWdodDQgKyBsZWZ0NiAqIHJpZ2h0NSArIGxlZnQxMCAqIHJpZ2h0NjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cwID0gbGVmdDAgKiByaWdodDggKyBsZWZ0NCAqIHJpZ2h0OSArIGxlZnQ4ICogcmlnaHQxMDsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cxID0gbGVmdDEgKiByaWdodDggKyBsZWZ0NSAqIHJpZ2h0OSArIGxlZnQ5ICogcmlnaHQxMDsKICAgICAgICAgIGNvbnN0IGNvbHVtbjJSb3cyID0gbGVmdDIgKiByaWdodDggKyBsZWZ0NiAqIHJpZ2h0OSArIGxlZnQxMCAqIHJpZ2h0MTA7CiAgICAgICAgICBjb25zdCBjb2x1bW4zUm93MCA9IGxlZnQwICogcmlnaHQxMiArIGxlZnQ0ICogcmlnaHQxMyArIGxlZnQ4ICogcmlnaHQxNCArIGxlZnQxMjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjNSb3cxID0gbGVmdDEgKiByaWdodDEyICsgbGVmdDUgKiByaWdodDEzICsgbGVmdDkgKiByaWdodDE0ICsgbGVmdDEzOwogICAgICAgICAgY29uc3QgY29sdW1uM1JvdzIgPSBsZWZ0MiAqIHJpZ2h0MTIgKyBsZWZ0NiAqIHJpZ2h0MTMgKyBsZWZ0MTAgKiByaWdodDE0ICsgbGVmdDE0OwogICAgICAgICAgcmVzdWx0WzBdID0gY29sdW1uMFJvdzA7CiAgICAgICAgICByZXN1bHRbMV0gPSBjb2x1bW4wUm93MTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGNvbHVtbjBSb3cyOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IGNvbHVtbjFSb3cwOwogICAgICAgICAgcmVzdWx0WzVdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXN1bHRbNl0gPSBjb2x1bW4xUm93MjsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSBjb2x1bW4yUm93MDsKICAgICAgICAgIHJlc3VsdFs5XSA9IGNvbHVtbjJSb3cxOwogICAgICAgICAgcmVzdWx0WzEwXSA9IGNvbHVtbjJSb3cyOwogICAgICAgICAgcmVzdWx0WzExXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTJdID0gY29sdW1uM1JvdzA7CiAgICAgICAgICByZXN1bHRbMTNdID0gY29sdW1uM1JvdzE7CiAgICAgICAgICByZXN1bHRbMTRdID0gY29sdW1uM1JvdzI7CiAgICAgICAgICByZXN1bHRbMTVdID0gMTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgYSB0cmFuc2Zvcm1hdGlvbiBtYXRyaXggKHdpdGggYSBib3R0b20gcm93IG9mIDxjb2RlPlswLjAsIDAuMCwgMC4wLCAxLjBdPC9jb2RlPikKICAgICAgICAgKiBieSBhIDN4MyByb3RhdGlvbiBtYXRyaXguICBUaGlzIGlzIGFuIG9wdGltaXphdGlvbgogICAgICAgICAqIGZvciA8Y29kZT5NYXRyaXg0Lm11bHRpcGx5KG0sIE1hdHJpeDQuZnJvbVJvdGF0aW9uVHJhbnNsYXRpb24ocm90YXRpb24pLCBtKTs8L2NvZGU+IHdpdGggbGVzcyBhbGxvY2F0aW9ucyBhbmQgYXJpdGhtZXRpYyBvcGVyYXRpb25zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCBvbiB0aGUgbGVmdC1oYW5kIHNpZGUuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByb3RhdGlvbiBUaGUgM3gzIHJvdGF0aW9uIG1hdHJpeCBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gSW5zdGVhZCBvZiBDZXNpdW0uTWF0cml4NC5tdWx0aXBseShtLCBDZXNpdW0uTWF0cml4NC5mcm9tUm90YXRpb25UcmFuc2xhdGlvbihyb3RhdGlvbiksIG0pOwogICAgICAgICAqIENlc2l1bS5NYXRyaXg0Lm11bHRpcGx5QnlNYXRyaXgzKG0sIHJvdGF0aW9uLCBtKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeU1hdHJpeDMobWF0cml4LCByb3RhdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJvdGF0aW9uIiwgcm90YXRpb24pOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgbGVmdDAgPSBtYXRyaXhbMF07CiAgICAgICAgICBjb25zdCBsZWZ0MSA9IG1hdHJpeFsxXTsKICAgICAgICAgIGNvbnN0IGxlZnQyID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgbGVmdDQgPSBtYXRyaXhbNF07CiAgICAgICAgICBjb25zdCBsZWZ0NSA9IG1hdHJpeFs1XTsKICAgICAgICAgIGNvbnN0IGxlZnQ2ID0gbWF0cml4WzZdOwogICAgICAgICAgY29uc3QgbGVmdDggPSBtYXRyaXhbOF07CiAgICAgICAgICBjb25zdCBsZWZ0OSA9IG1hdHJpeFs5XTsKICAgICAgICAgIGNvbnN0IGxlZnQxMCA9IG1hdHJpeFsxMF07CiAgICAgICAgICBjb25zdCByaWdodDAgPSByb3RhdGlvblswXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0MSA9IHJvdGF0aW9uWzFdOwogICAgICAgICAgY29uc3QgcmlnaHQyID0gcm90YXRpb25bMl07CiAgICAgICAgICBjb25zdCByaWdodDQgPSByb3RhdGlvblszXTsKICAgICAgICAgIGNvbnN0IHJpZ2h0NSA9IHJvdGF0aW9uWzRdOwogICAgICAgICAgY29uc3QgcmlnaHQ2ID0gcm90YXRpb25bNV07CiAgICAgICAgICBjb25zdCByaWdodDggPSByb3RhdGlvbls2XTsKICAgICAgICAgIGNvbnN0IHJpZ2h0OSA9IHJvdGF0aW9uWzddOwogICAgICAgICAgY29uc3QgcmlnaHQxMCA9IHJvdGF0aW9uWzhdOwogICAgICAgICAgY29uc3QgY29sdW1uMFJvdzAgPSBsZWZ0MCAqIHJpZ2h0MCArIGxlZnQ0ICogcmlnaHQxICsgbGVmdDggKiByaWdodDI7CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MSA9IGxlZnQxICogcmlnaHQwICsgbGVmdDUgKiByaWdodDEgKyBsZWZ0OSAqIHJpZ2h0MjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cyID0gbGVmdDIgKiByaWdodDAgKyBsZWZ0NiAqIHJpZ2h0MSArIGxlZnQxMCAqIHJpZ2h0MjsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cwID0gbGVmdDAgKiByaWdodDQgKyBsZWZ0NCAqIHJpZ2h0NSArIGxlZnQ4ICogcmlnaHQ2OwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzEgPSBsZWZ0MSAqIHJpZ2h0NCArIGxlZnQ1ICogcmlnaHQ1ICsgbGVmdDkgKiByaWdodDY7CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MiA9IGxlZnQyICogcmlnaHQ0ICsgbGVmdDYgKiByaWdodDUgKyBsZWZ0MTAgKiByaWdodDY7CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MCA9IGxlZnQwICogcmlnaHQ4ICsgbGVmdDQgKiByaWdodDkgKyBsZWZ0OCAqIHJpZ2h0MTA7CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MSA9IGxlZnQxICogcmlnaHQ4ICsgbGVmdDUgKiByaWdodDkgKyBsZWZ0OSAqIHJpZ2h0MTA7CiAgICAgICAgICBjb25zdCBjb2x1bW4yUm93MiA9IGxlZnQyICogcmlnaHQ4ICsgbGVmdDYgKiByaWdodDkgKyBsZWZ0MTAgKiByaWdodDEwOwogICAgICAgICAgcmVzdWx0WzBdID0gY29sdW1uMFJvdzA7CiAgICAgICAgICByZXN1bHRbMV0gPSBjb2x1bW4wUm93MTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGNvbHVtbjBSb3cyOwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IGNvbHVtbjFSb3cwOwogICAgICAgICAgcmVzdWx0WzVdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXN1bHRbNl0gPSBjb2x1bW4xUm93MjsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSBjb2x1bW4yUm93MDsKICAgICAgICAgIHJlc3VsdFs5XSA9IGNvbHVtbjJSb3cxOwogICAgICAgICAgcmVzdWx0WzEwXSA9IGNvbHVtbjJSb3cyOwogICAgICAgICAgcmVzdWx0WzExXSA9IDA7CiAgICAgICAgICByZXN1bHRbMTJdID0gbWF0cml4WzEyXTsKICAgICAgICAgIHJlc3VsdFsxM10gPSBtYXRyaXhbMTNdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IG1hdHJpeFsxNF07CiAgICAgICAgICByZXN1bHRbMTVdID0gbWF0cml4WzE1XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgYSB0cmFuc2Zvcm1hdGlvbiBtYXRyaXggKHdpdGggYSBib3R0b20gcm93IG9mIDxjb2RlPlswLjAsIDAuMCwgMC4wLCAxLjBdPC9jb2RlPikKICAgICAgICAgKiBieSBhbiBpbXBsaWNpdCB0cmFuc2xhdGlvbiBtYXRyaXggZGVmaW5lZCBieSBhIHtAbGluayBDYXJ0ZXNpYW4zfS4gIFRoaXMgaXMgYW4gb3B0aW1pemF0aW9uCiAgICAgICAgICogZm9yIDxjb2RlPk1hdHJpeDQubXVsdGlwbHkobSwgTWF0cml4NC5mcm9tVHJhbnNsYXRpb24ocG9zaXRpb24pLCBtKTs8L2NvZGU+IHdpdGggbGVzcyBhbGxvY2F0aW9ucyBhbmQgYXJpdGhtZXRpYyBvcGVyYXRpb25zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCBvbiB0aGUgbGVmdC1oYW5kIHNpZGUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSB0cmFuc2xhdGlvbiBUaGUgdHJhbnNsYXRpb24gb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIEluc3RlYWQgb2YgQ2VzaXVtLk1hdHJpeDQubXVsdGlwbHkobSwgQ2VzaXVtLk1hdHJpeDQuZnJvbVRyYW5zbGF0aW9uKHBvc2l0aW9uKSwgbSk7CiAgICAgICAgICogQ2VzaXVtLk1hdHJpeDQubXVsdGlwbHlCeVRyYW5zbGF0aW9uKG0sIHBvc2l0aW9uLCBtKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVRyYW5zbGF0aW9uKG1hdHJpeCwgdHJhbnNsYXRpb24yLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidHJhbnNsYXRpb24iLCB0cmFuc2xhdGlvbjIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgeDIgPSB0cmFuc2xhdGlvbjIueDsKICAgICAgICAgIGNvbnN0IHkyID0gdHJhbnNsYXRpb24yLnk7CiAgICAgICAgICBjb25zdCB6MiA9IHRyYW5zbGF0aW9uMi56OwogICAgICAgICAgY29uc3QgdHggPSB4MiAqIG1hdHJpeFswXSArIHkyICogbWF0cml4WzRdICsgejIgKiBtYXRyaXhbOF0gKyBtYXRyaXhbMTJdOwogICAgICAgICAgY29uc3QgdHkgPSB4MiAqIG1hdHJpeFsxXSArIHkyICogbWF0cml4WzVdICsgejIgKiBtYXRyaXhbOV0gKyBtYXRyaXhbMTNdOwogICAgICAgICAgY29uc3QgdHogPSB4MiAqIG1hdHJpeFsyXSArIHkyICogbWF0cml4WzZdICsgejIgKiBtYXRyaXhbMTBdICsgbWF0cml4WzE0XTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IG1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IG1hdHJpeFs4XTsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeFs5XTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtYXRyaXhbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IG1hdHJpeFsxMV07CiAgICAgICAgICByZXN1bHRbMTJdID0gdHg7CiAgICAgICAgICByZXN1bHRbMTNdID0gdHk7CiAgICAgICAgICByZXN1bHRbMTRdID0gdHo7CiAgICAgICAgICByZXN1bHRbMTVdID0gbWF0cml4WzE1XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIE11bHRpcGxpZXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCAod2l0aCBhIGJvdHRvbSByb3cgb2YgPGNvZGU+WzAuMCwgMC4wLCAwLjAsIDEuMF08L2NvZGU+KQogICAgICAgICAqIGJ5IGFuIGltcGxpY2l0IG5vbi11bmlmb3JtIHNjYWxlIG1hdHJpeC4gVGhpcyBpcyBhbiBvcHRpbWl6YXRpb24KICAgICAgICAgKiBmb3IgPGNvZGU+TWF0cml4NC5tdWx0aXBseShtLCBNYXRyaXg0LmZyb21Vbmlmb3JtU2NhbGUoc2NhbGUpLCBtKTs8L2NvZGU+LCB3aGVyZQogICAgICAgICAqIDxjb2RlPm08L2NvZGU+IG11c3QgYmUgYW4gYWZmaW5lIG1hdHJpeC4KICAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIHBlcmZvcm1zIGZld2VyIGFsbG9jYXRpb25zIGFuZCBhcml0aG1ldGljIG9wZXJhdGlvbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgYWZmaW5lIG1hdHJpeCBvbiB0aGUgbGVmdC1oYW5kIHNpZGUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBzY2FsZSBUaGUgbm9uLXVuaWZvcm0gc2NhbGUgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gSW5zdGVhZCBvZiBDZXNpdW0uTWF0cml4NC5tdWx0aXBseShtLCBDZXNpdW0uTWF0cml4NC5mcm9tU2NhbGUoc2NhbGUpLCBtKTsKICAgICAgICAgKiBDZXNpdW0uTWF0cml4NC5tdWx0aXBseUJ5U2NhbGUobSwgc2NhbGUsIG0pOwogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXg0Lm11bHRpcGx5QnlVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZnJvbVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmZyb21Vbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuc2V0U2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuc2V0VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXg0LmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5QnlTY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBzY2FsZVggPSBzY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVZID0gc2NhbGUueTsKICAgICAgICAgIGNvbnN0IHNjYWxlWiA9IHNjYWxlLno7CiAgICAgICAgICBpZiAoc2NhbGVYID09PSAxICYmIHNjYWxlWSA9PT0gMSAmJiBzY2FsZVogPT09IDEpIHsKICAgICAgICAgICAgcmV0dXJuIF9NYXRyaXg0LmNsb25lKG1hdHJpeCwgcmVzdWx0KTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IHNjYWxlWCAqIG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IHNjYWxlWCAqIG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IHNjYWxlWCAqIG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IHNjYWxlWSAqIG1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IHNjYWxlWSAqIG1hdHJpeFs1XTsKICAgICAgICAgIHJlc3VsdFs2XSA9IHNjYWxlWSAqIG1hdHJpeFs2XTsKICAgICAgICAgIHJlc3VsdFs3XSA9IG1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IHNjYWxlWiAqIG1hdHJpeFs4XTsKICAgICAgICAgIHJlc3VsdFs5XSA9IHNjYWxlWiAqIG1hdHJpeFs5XTsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBzY2FsZVogKiBtYXRyaXhbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IG1hdHJpeFsxMV07CiAgICAgICAgICByZXN1bHRbMTJdID0gbWF0cml4WzEyXTsKICAgICAgICAgIHJlc3VsdFsxM10gPSBtYXRyaXhbMTNdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IG1hdHJpeFsxNF07CiAgICAgICAgICByZXN1bHRbMTVdID0gbWF0cml4WzE1XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIGEgbWF0cml4IHRpbWVzIGEgdW5pZm9ybSBzY2FsZSwgYXMgaWYgdGhlIHNjYWxlIHdlcmUgYSBzY2FsZSBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IG9uIHRoZSBsZWZ0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgVGhlIHVuaWZvcm0gc2NhbGUgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIEluc3RlYWQgb2YgQ2VzaXVtLk1hdHJpeDQubXVsdGlwbHkobSwgQ2VzaXVtLk1hdHJpeDQuZnJvbVVuaWZvcm1TY2FsZShzY2FsZSksIG0pOwogICAgICAgICAqIENlc2l1bS5NYXRyaXg0Lm11bHRpcGx5QnlVbmlmb3JtU2NhbGUobSwgc2NhbGUsIG0pOwogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXg0Lm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5mcm9tU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZnJvbVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5zZXRTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4NC5zZXRVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDQuZ2V0U2NhbGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVVuaWZvcm1TY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGU7CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM107CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNF0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFs1XSA9IG1hdHJpeFs1XSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4WzZdICogc2NhbGU7CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbN107CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbOF0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeFs5XSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzEwXSA9IG1hdHJpeFsxMF0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBtYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IG1hdHJpeFsxMl07CiAgICAgICAgICByZXN1bHRbMTNdID0gbWF0cml4WzEzXTsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBtYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IG1hdHJpeFsxNV07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCBhbmQgYSBjb2x1bW4gdmVjdG9yLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjR9IGNhcnRlc2lhbiBUaGUgdmVjdG9yLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuNH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW40fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVZlY3RvcihtYXRyaXgsIGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgdlggPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgY29uc3QgdlkgPSBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgY29uc3QgdlogPSBjYXJ0ZXNpYW4xMS56OwogICAgICAgICAgY29uc3QgdlcgPSBjYXJ0ZXNpYW4xMS53OwogICAgICAgICAgY29uc3QgeDIgPSBtYXRyaXhbMF0gKiB2WCArIG1hdHJpeFs0XSAqIHZZICsgbWF0cml4WzhdICogdlogKyBtYXRyaXhbMTJdICogdlc7CiAgICAgICAgICBjb25zdCB5MiA9IG1hdHJpeFsxXSAqIHZYICsgbWF0cml4WzVdICogdlkgKyBtYXRyaXhbOV0gKiB2WiArIG1hdHJpeFsxM10gKiB2VzsKICAgICAgICAgIGNvbnN0IHoyID0gbWF0cml4WzJdICogdlggKyBtYXRyaXhbNl0gKiB2WSArIG1hdHJpeFsxMF0gKiB2WiArIG1hdHJpeFsxNF0gKiB2VzsKICAgICAgICAgIGNvbnN0IHcyID0gbWF0cml4WzNdICogdlggKyBtYXRyaXhbN10gKiB2WSArIG1hdHJpeFsxMV0gKiB2WiArIG1hdHJpeFsxNV0gKiB2VzsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJlc3VsdC53ID0gdzI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCBhbmQgYSB7QGxpbmsgQ2FydGVzaWFuM30uICBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gY2FsbGluZyB7QGxpbmsgTWF0cml4NC5tdWx0aXBseUJ5VmVjdG9yfQogICAgICAgICAqIHdpdGggYSB7QGxpbmsgQ2FydGVzaWFuNH0gd2l0aCBhIDxjb2RlPnc8L2NvZGU+IGNvbXBvbmVudCBvZiB6ZXJvLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgcG9pbnQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiBjb25zdCBwID0gbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKDEuMCwgMi4wLCAzLjApOwogICAgICAgICAqIGNvbnN0IHJlc3VsdCA9IENlc2l1bS5NYXRyaXg0Lm11bHRpcGx5QnlQb2ludEFzVmVjdG9yKG1hdHJpeCwgcCwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKCkpOwogICAgICAgICAqIC8vIEEgc2hvcnRjdXQgZm9yCiAgICAgICAgICogLy8gICBDYXJ0ZXNpYW4zIHAgPSAuLi4KICAgICAgICAgKiAvLyAgIENlc2l1bS5NYXRyaXg0Lm11bHRpcGx5QnlWZWN0b3IobWF0cml4LCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjQocC54LCBwLnksIHAueiwgMC4wKSwgcmVzdWx0KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVBvaW50QXNWZWN0b3IobWF0cml4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHZYID0gY2FydGVzaWFuMTEueDsKICAgICAgICAgIGNvbnN0IHZZID0gY2FydGVzaWFuMTEueTsKICAgICAgICAgIGNvbnN0IHZaID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4WzBdICogdlggKyBtYXRyaXhbNF0gKiB2WSArIG1hdHJpeFs4XSAqIHZaOwogICAgICAgICAgY29uc3QgeTIgPSBtYXRyaXhbMV0gKiB2WCArIG1hdHJpeFs1XSAqIHZZICsgbWF0cml4WzldICogdlo7CiAgICAgICAgICBjb25zdCB6MiA9IG1hdHJpeFsyXSAqIHZYICsgbWF0cml4WzZdICogdlkgKyBtYXRyaXhbMTBdICogdlo7CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJlc3VsdC56ID0gejI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCBhbmQgYSB7QGxpbmsgQ2FydGVzaWFuM30uIFRoaXMgaXMgZXF1aXZhbGVudCB0byBjYWxsaW5nIHtAbGluayBNYXRyaXg0Lm11bHRpcGx5QnlWZWN0b3J9CiAgICAgICAgICogd2l0aCBhIHtAbGluayBDYXJ0ZXNpYW40fSB3aXRoIGEgPGNvZGU+dzwvY29kZT4gY29tcG9uZW50IG9mIDEsIGJ1dCByZXR1cm5zIGEge0BsaW5rIENhcnRlc2lhbjN9IGluc3RlYWQgb2YgYSB7QGxpbmsgQ2FydGVzaWFuNH0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBwb2ludC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IHAgPSBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMS4wLCAyLjAsIDMuMCk7CiAgICAgICAgICogY29uc3QgcmVzdWx0ID0gQ2VzaXVtLk1hdHJpeDQubXVsdGlwbHlCeVBvaW50KG1hdHJpeCwgcCwgbmV3IENlc2l1bS5DYXJ0ZXNpYW4zKCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5UG9pbnQobWF0cml4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHZYID0gY2FydGVzaWFuMTEueDsKICAgICAgICAgIGNvbnN0IHZZID0gY2FydGVzaWFuMTEueTsKICAgICAgICAgIGNvbnN0IHZaID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4WzBdICogdlggKyBtYXRyaXhbNF0gKiB2WSArIG1hdHJpeFs4XSAqIHZaICsgbWF0cml4WzEyXTsKICAgICAgICAgIGNvbnN0IHkyID0gbWF0cml4WzFdICogdlggKyBtYXRyaXhbNV0gKiB2WSArIG1hdHJpeFs5XSAqIHZaICsgbWF0cml4WzEzXTsKICAgICAgICAgIGNvbnN0IHoyID0gbWF0cml4WzJdICogdlggKyBtYXRyaXhbNl0gKiB2WSArIG1hdHJpeFsxMF0gKiB2WiArIG1hdHJpeFsxNF07CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJlc3VsdC56ID0gejI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCBhbmQgYSBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXIgVGhlIG51bWJlciB0byBtdWx0aXBseSBieS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vY3JlYXRlIGEgTWF0cml4NCBpbnN0YW5jZSB3aGljaCBpcyBhIHNjYWxlZCB2ZXJzaW9uIG9mIHRoZSBzdXBwbGllZCBNYXRyaXg0CiAgICAgICAgICogLy8gbSA9IFsxMC4wLCAxMS4wLCAxMi4wLCAxMy4wXQogICAgICAgICAqIC8vICAgICBbMTQuMCwgMTUuMCwgMTYuMCwgMTcuMF0KICAgICAgICAgKiAvLyAgICAgWzE4LjAsIDE5LjAsIDIwLjAsIDIxLjBdCiAgICAgICAgICogLy8gICAgIFsyMi4wLCAyMy4wLCAyNC4wLCAyNS4wXQogICAgICAgICAqCiAgICAgICAgICogY29uc3QgYSA9IENlc2l1bS5NYXRyaXg0Lm11bHRpcGx5QnlTY2FsYXIobSwgLTIsIG5ldyBDZXNpdW0uTWF0cml4NCgpKTsKICAgICAgICAgKgogICAgICAgICAqIC8vIG0gcmVtYWlucyB0aGUgc2FtZQogICAgICAgICAqIC8vIGEgPSBbLTIwLjAsIC0yMi4wLCAtMjQuMCwgLTI2LjBdCiAgICAgICAgICogLy8gICAgIFstMjguMCwgLTMwLjAsIC0zMi4wLCAtMzQuMF0KICAgICAgICAgKiAvLyAgICAgWy0zNi4wLCAtMzguMCwgLTQwLjAsIC00Mi4wXQogICAgICAgICAqIC8vICAgICBbLTQ0LjAsIC00Ni4wLCAtNDguMCwgLTUwLjBdCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5QnlTY2FsYXIobWF0cml4LCBzY2FsYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJzY2FsYXIiLCBzY2FsYXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzRdID0gbWF0cml4WzRdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzVdID0gbWF0cml4WzVdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4WzZdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzddID0gbWF0cml4WzddICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzhdID0gbWF0cml4WzhdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzldID0gbWF0cml4WzldICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzEwXSA9IG1hdHJpeFsxMF0gKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHRbMTFdID0gbWF0cml4WzExXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsxMl0gPSBtYXRyaXhbMTJdICogc2NhbGFyOwogICAgICAgICAgcmVzdWx0WzEzXSA9IG1hdHJpeFsxM10gKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHRbMTRdID0gbWF0cml4WzE0XSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBtYXRyaXhbMTVdICogc2NhbGFyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBuZWdhdGVkIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4IFRoZSBtYXRyaXggdG8gbmVnYXRlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy9jcmVhdGUgYSBuZXcgTWF0cml4NCBpbnN0YW5jZSB3aGljaCBpcyBhIG5lZ2F0aW9uIG9mIGEgTWF0cml4NAogICAgICAgICAqIC8vIG0gPSBbMTAuMCwgMTEuMCwgMTIuMCwgMTMuMF0KICAgICAgICAgKiAvLyAgICAgWzE0LjAsIDE1LjAsIDE2LjAsIDE3LjBdCiAgICAgICAgICogLy8gICAgIFsxOC4wLCAxOS4wLCAyMC4wLCAyMS4wXQogICAgICAgICAqIC8vICAgICBbMjIuMCwgMjMuMCwgMjQuMCwgMjUuMF0KICAgICAgICAgKgogICAgICAgICAqIGNvbnN0IGEgPSBDZXNpdW0uTWF0cml4NC5uZWdhdGUobSwgbmV3IENlc2l1bS5NYXRyaXg0KCkpOwogICAgICAgICAqCiAgICAgICAgICogLy8gbSByZW1haW5zIHRoZSBzYW1lCiAgICAgICAgICogLy8gYSA9IFstMTAuMCwgLTExLjAsIC0xMi4wLCAtMTMuMF0KICAgICAgICAgKiAvLyAgICAgWy0xNC4wLCAtMTUuMCwgLTE2LjAsIC0xNy4wXQogICAgICAgICAqIC8vICAgICBbLTE4LjAsIC0xOS4wLCAtMjAuMCwgLTIxLjBdCiAgICAgICAgICogLy8gICAgIFstMjIuMCwgLTIzLjAsIC0yNC4wLCAtMjUuMF0KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbmVnYXRlKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSAtbWF0cml4WzBdOwogICAgICAgICAgcmVzdWx0WzFdID0gLW1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IC1tYXRyaXhbMl07CiAgICAgICAgICByZXN1bHRbM10gPSAtbWF0cml4WzNdOwogICAgICAgICAgcmVzdWx0WzRdID0gLW1hdHJpeFs0XTsKICAgICAgICAgIHJlc3VsdFs1XSA9IC1tYXRyaXhbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSAtbWF0cml4WzZdOwogICAgICAgICAgcmVzdWx0WzddID0gLW1hdHJpeFs3XTsKICAgICAgICAgIHJlc3VsdFs4XSA9IC1tYXRyaXhbOF07CiAgICAgICAgICByZXN1bHRbOV0gPSAtbWF0cml4WzldOwogICAgICAgICAgcmVzdWx0WzEwXSA9IC1tYXRyaXhbMTBdOwogICAgICAgICAgcmVzdWx0WzExXSA9IC1tYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IC1tYXRyaXhbMTJdOwogICAgICAgICAgcmVzdWx0WzEzXSA9IC1tYXRyaXhbMTNdOwogICAgICAgICAgcmVzdWx0WzE0XSA9IC1tYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzE1XSA9IC1tYXRyaXhbMTVdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHRyYW5zcG9zZSBvZiB0aGUgcHJvdmlkZWQgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byB0cmFuc3Bvc2UuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL3JldHVybnMgdHJhbnNwb3NlIG9mIGEgTWF0cml4NAogICAgICAgICAqIC8vIG0gPSBbMTAuMCwgMTEuMCwgMTIuMCwgMTMuMF0KICAgICAgICAgKiAvLyAgICAgWzE0LjAsIDE1LjAsIDE2LjAsIDE3LjBdCiAgICAgICAgICogLy8gICAgIFsxOC4wLCAxOS4wLCAyMC4wLCAyMS4wXQogICAgICAgICAqIC8vICAgICBbMjIuMCwgMjMuMCwgMjQuMCwgMjUuMF0KICAgICAgICAgKgogICAgICAgICAqIGNvbnN0IGEgPSBDZXNpdW0uTWF0cml4NC50cmFuc3Bvc2UobSwgbmV3IENlc2l1bS5NYXRyaXg0KCkpOwogICAgICAgICAqCiAgICAgICAgICogLy8gbSByZW1haW5zIHRoZSBzYW1lCiAgICAgICAgICogLy8gYSA9IFsxMC4wLCAxNC4wLCAxOC4wLCAyMi4wXQogICAgICAgICAqIC8vICAgICBbMTEuMCwgMTUuMCwgMTkuMCwgMjMuMF0KICAgICAgICAgKiAvLyAgICAgWzEyLjAsIDE2LjAsIDIwLjAsIDI0LjBdCiAgICAgICAgICogLy8gICAgIFsxMy4wLCAxNy4wLCAyMS4wLCAyNS4wXQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0cmFuc3Bvc2UobWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IG1hdHJpeDEgPSBtYXRyaXhbMV07CiAgICAgICAgICBjb25zdCBtYXRyaXgyID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgbWF0cml4MyA9IG1hdHJpeFszXTsKICAgICAgICAgIGNvbnN0IG1hdHJpeDYgPSBtYXRyaXhbNl07CiAgICAgICAgICBjb25zdCBtYXRyaXg3ID0gbWF0cml4WzddOwogICAgICAgICAgY29uc3QgbWF0cml4MTEgPSBtYXRyaXhbMTFdOwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzRdOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzhdOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzEyXTsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeDE7CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNV07CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbOV07CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbMTNdOwogICAgICAgICAgcmVzdWx0WzhdID0gbWF0cml4MjsKICAgICAgICAgIHJlc3VsdFs5XSA9IG1hdHJpeDY7CiAgICAgICAgICByZXN1bHRbMTBdID0gbWF0cml4WzEwXTsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBtYXRyaXhbMTRdOwogICAgICAgICAgcmVzdWx0WzEyXSA9IG1hdHJpeDM7CiAgICAgICAgICByZXN1bHRbMTNdID0gbWF0cml4NzsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBtYXRyaXgxMTsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBtYXRyaXhbMTVdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBtYXRyaXgsIHdoaWNoIGNvbnRhaW5zIHRoZSBhYnNvbHV0ZSAodW5zaWduZWQpIHZhbHVlcyBvZiB0aGUgcHJvdmlkZWQgbWF0cml4J3MgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHdpdGggc2lnbmVkIGVsZW1lbnRzLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWJzKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBNYXRoLmFicyhtYXRyaXhbMF0pOwogICAgICAgICAgcmVzdWx0WzFdID0gTWF0aC5hYnMobWF0cml4WzFdKTsKICAgICAgICAgIHJlc3VsdFsyXSA9IE1hdGguYWJzKG1hdHJpeFsyXSk7CiAgICAgICAgICByZXN1bHRbM10gPSBNYXRoLmFicyhtYXRyaXhbM10pOwogICAgICAgICAgcmVzdWx0WzRdID0gTWF0aC5hYnMobWF0cml4WzRdKTsKICAgICAgICAgIHJlc3VsdFs1XSA9IE1hdGguYWJzKG1hdHJpeFs1XSk7CiAgICAgICAgICByZXN1bHRbNl0gPSBNYXRoLmFicyhtYXRyaXhbNl0pOwogICAgICAgICAgcmVzdWx0WzddID0gTWF0aC5hYnMobWF0cml4WzddKTsKICAgICAgICAgIHJlc3VsdFs4XSA9IE1hdGguYWJzKG1hdHJpeFs4XSk7CiAgICAgICAgICByZXN1bHRbOV0gPSBNYXRoLmFicyhtYXRyaXhbOV0pOwogICAgICAgICAgcmVzdWx0WzEwXSA9IE1hdGguYWJzKG1hdHJpeFsxMF0pOwogICAgICAgICAgcmVzdWx0WzExXSA9IE1hdGguYWJzKG1hdHJpeFsxMV0pOwogICAgICAgICAgcmVzdWx0WzEyXSA9IE1hdGguYWJzKG1hdHJpeFsxMl0pOwogICAgICAgICAgcmVzdWx0WzEzXSA9IE1hdGguYWJzKG1hdHJpeFsxM10pOwogICAgICAgICAgcmVzdWx0WzE0XSA9IE1hdGguYWJzKG1hdHJpeFsxNF0pOwogICAgICAgICAgcmVzdWx0WzE1XSA9IE1hdGguYWJzKG1hdHJpeFsxNV0pOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIG1hdHJpY2VzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW2xlZnRdIFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmlnaHRdIFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vY29tcGFyZXMgdHdvIE1hdHJpeDQgaW5zdGFuY2VzCiAgICAgICAgICoKICAgICAgICAgKiAvLyBhID0gWzEwLjAsIDE0LjAsIDE4LjAsIDIyLjBdCiAgICAgICAgICogLy8gICAgIFsxMS4wLCAxNS4wLCAxOS4wLCAyMy4wXQogICAgICAgICAqIC8vICAgICBbMTIuMCwgMTYuMCwgMjAuMCwgMjQuMF0KICAgICAgICAgKiAvLyAgICAgWzEzLjAsIDE3LjAsIDIxLjAsIDI1LjBdCiAgICAgICAgICoKICAgICAgICAgKiAvLyBiID0gWzEwLjAsIDE0LjAsIDE4LjAsIDIyLjBdCiAgICAgICAgICogLy8gICAgIFsxMS4wLCAxNS4wLCAxOS4wLCAyMy4wXQogICAgICAgICAqIC8vICAgICBbMTIuMCwgMTYuMCwgMjAuMCwgMjQuMF0KICAgICAgICAgKiAvLyAgICAgWzEzLjAsIDE3LjAsIDIxLjAsIDI1LjBdCiAgICAgICAgICoKICAgICAgICAgKiBpZihDZXNpdW0uTWF0cml4NC5lcXVhbHMoYSxiKSkgewogICAgICAgICAqICAgICAgY29uc29sZS5sb2coIkJvdGggbWF0cmljZXMgYXJlIGVxdWFsIik7CiAgICAgICAgICogfSBlbHNlIHsKICAgICAgICAgKiAgICAgIGNvbnNvbGUubG9nKCJUaGV5IGFyZSBub3QgZXF1YWwiKTsKICAgICAgICAgKiB9CiAgICAgICAgICoKICAgICAgICAgKiAvL1ByaW50cyAiQm90aCBtYXRyaWNlcyBhcmUgZXF1YWwiIG9uIHRoZSBjb25zb2xlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFscyhsZWZ0LCByaWdodCkgewogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIC8vIFRyYW5zbGF0aW9uCiAgICAgICAgICBsZWZ0WzEyXSA9PT0gcmlnaHRbMTJdICYmIGxlZnRbMTNdID09PSByaWdodFsxM10gJiYgbGVmdFsxNF0gPT09IHJpZ2h0WzE0XSAmJiAvLyBSb3RhdGlvbi9zY2FsZQogICAgICAgICAgbGVmdFswXSA9PT0gcmlnaHRbMF0gJiYgbGVmdFsxXSA9PT0gcmlnaHRbMV0gJiYgbGVmdFsyXSA9PT0gcmlnaHRbMl0gJiYgbGVmdFs0XSA9PT0gcmlnaHRbNF0gJiYgbGVmdFs1XSA9PT0gcmlnaHRbNV0gJiYgbGVmdFs2XSA9PT0gcmlnaHRbNl0gJiYgbGVmdFs4XSA9PT0gcmlnaHRbOF0gJiYgbGVmdFs5XSA9PT0gcmlnaHRbOV0gJiYgbGVmdFsxMF0gPT09IHJpZ2h0WzEwXSAmJiAvLyBCb3R0b20gcm93CiAgICAgICAgICBsZWZ0WzNdID09PSByaWdodFszXSAmJiBsZWZ0WzddID09PSByaWdodFs3XSAmJiBsZWZ0WzExXSA9PT0gcmlnaHRbMTFdICYmIGxlZnRbMTVdID09PSByaWdodFsxNV07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBtYXRyaWNlcyBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IFtsZWZ0XSBUaGUgZmlyc3QgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3JpZ2h0XSBUaGUgc2Vjb25kIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MF0gVGhlIGVwc2lsb24gdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL2NvbXBhcmVzIHR3byBNYXRyaXg0IGluc3RhbmNlcwogICAgICAgICAqCiAgICAgICAgICogLy8gYSA9IFsxMC41LCAxNC41LCAxOC41LCAyMi41XQogICAgICAgICAqIC8vICAgICBbMTEuNSwgMTUuNSwgMTkuNSwgMjMuNV0KICAgICAgICAgKiAvLyAgICAgWzEyLjUsIDE2LjUsIDIwLjUsIDI0LjVdCiAgICAgICAgICogLy8gICAgIFsxMy41LCAxNy41LCAyMS41LCAyNS41XQogICAgICAgICAqCiAgICAgICAgICogLy8gYiA9IFsxMC4wLCAxNC4wLCAxOC4wLCAyMi4wXQogICAgICAgICAqIC8vICAgICBbMTEuMCwgMTUuMCwgMTkuMCwgMjMuMF0KICAgICAgICAgKiAvLyAgICAgWzEyLjAsIDE2LjAsIDIwLjAsIDI0LjBdCiAgICAgICAgICogLy8gICAgIFsxMy4wLCAxNy4wLCAyMS4wLCAyNS4wXQogICAgICAgICAqCiAgICAgICAgICogaWYoQ2VzaXVtLk1hdHJpeDQuZXF1YWxzRXBzaWxvbihhLGIsMC4xKSl7CiAgICAgICAgICogICAgICBjb25zb2xlLmxvZygiRGlmZmVyZW5jZSBiZXR3ZWVuIGJvdGggdGhlIG1hdHJpY2VzIGlzIGxlc3MgdGhhbiAwLjEiKTsKICAgICAgICAgKiB9IGVsc2UgewogICAgICAgICAqICAgICAgY29uc29sZS5sb2coIkRpZmZlcmVuY2UgYmV0d2VlbiBib3RoIHRoZSBtYXRyaWNlcyBpcyBub3QgbGVzcyB0aGFuIDAuMSIpOwogICAgICAgICAqIH0KICAgICAgICAgKgogICAgICAgICAqIC8vUHJpbnRzICJEaWZmZXJlbmNlIGJldHdlZW4gYm90aCB0aGUgbWF0cmljZXMgaXMgbm90IGxlc3MgdGhhbiAwLjEiIG9uIHRoZSBjb25zb2xlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0Vwc2lsb24obGVmdCwgcmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIGVwc2lsb24gPSBlcHNpbG9uID8/IDA7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgTWF0aC5hYnMobGVmdFswXSAtIHJpZ2h0WzBdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMV0gLSByaWdodFsxXSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzJdIC0gcmlnaHRbMl0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFszXSAtIHJpZ2h0WzNdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbNF0gLSByaWdodFs0XSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzVdIC0gcmlnaHRbNV0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFs2XSAtIHJpZ2h0WzZdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbN10gLSByaWdodFs3XSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzhdIC0gcmlnaHRbOF0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFs5XSAtIHJpZ2h0WzldKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTBdIC0gcmlnaHRbMTBdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTFdIC0gcmlnaHRbMTFdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTJdIC0gcmlnaHRbMTJdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTNdIC0gcmlnaHRbMTNdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTRdIC0gcmlnaHRbMTRdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMTVdIC0gcmlnaHRbMTVdKSA8PSBlcHNpbG9uOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSB0cmFuc2xhdGlvbiBwb3J0aW9uIG9mIHRoZSBwcm92aWRlZCBtYXRyaXgsIGFzc3VtaW5nIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0VHJhbnNsYXRpb24obWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC54ID0gbWF0cml4WzEyXTsKICAgICAgICAgIHJlc3VsdC55ID0gbWF0cml4WzEzXTsKICAgICAgICAgIHJlc3VsdC56ID0gbWF0cml4WzE0XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHVwcGVyIGxlZnQgM3gzIG1hdHJpeCBvZiB0aGUgcHJvdmlkZWQgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgzfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyByZXR1cm5zIGEgTWF0cml4MyBpbnN0YW5jZSBmcm9tIGEgTWF0cml4NCBpbnN0YW5jZQogICAgICAgICAqCiAgICAgICAgICogLy8gbSA9IFsxMC4wLCAxNC4wLCAxOC4wLCAyMi4wXQogICAgICAgICAqIC8vICAgICBbMTEuMCwgMTUuMCwgMTkuMCwgMjMuMF0KICAgICAgICAgKiAvLyAgICAgWzEyLjAsIDE2LjAsIDIwLjAsIDI0LjBdCiAgICAgICAgICogLy8gICAgIFsxMy4wLCAxNy4wLCAyMS4wLCAyNS4wXQogICAgICAgICAqCiAgICAgICAgICogY29uc3QgYiA9IG5ldyBDZXNpdW0uTWF0cml4MygpOwogICAgICAgICAqIENlc2l1bS5NYXRyaXg0LmdldE1hdHJpeDMobSxiKTsKICAgICAgICAgKgogICAgICAgICAqIC8vIGIgPSBbMTAuMCwgMTQuMCwgMTguMF0KICAgICAgICAgKiAvLyAgICAgWzExLjAsIDE1LjAsIDE5LjBdCiAgICAgICAgICogLy8gICAgIFsxMi4wLCAxNi4wLCAyMC4wXQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRNYXRyaXgzKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF07CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl07CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbNF07CiAgICAgICAgICByZXN1bHRbNF0gPSBtYXRyaXhbNV07CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXhbNl07CiAgICAgICAgICByZXN1bHRbNl0gPSBtYXRyaXhbOF07CiAgICAgICAgICByZXN1bHRbN10gPSBtYXRyaXhbOV07CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXhbMTBdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGludmVyc2Ugb2YgdGhlIHByb3ZpZGVkIG1hdHJpeCB1c2luZyBDcmFtZXJzIFJ1bGUuCiAgICAgICAgICogSWYgdGhlIGRldGVybWluYW50IGlzIHplcm8sIHRoZSBtYXRyaXggY2FuIG5vdCBiZSBpbnZlcnRlZCwgYW5kIGFuIGV4Y2VwdGlvbiBpcyB0aHJvd24uCiAgICAgICAgICogSWYgdGhlIG1hdHJpeCBpcyBhIHByb3BlciByaWdpZCB0cmFuc2Zvcm1hdGlvbiwgaXQgaXMgbW9yZSBlZmZpY2llbnQKICAgICAgICAgKiB0byBpbnZlcnQgaXQgd2l0aCB7QGxpbmsgTWF0cml4NC5pbnZlcnNlVHJhbnNmb3JtYXRpb259LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBtYXRyaXggVGhlIG1hdHJpeCB0byBpbnZlcnQuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4Y2VwdGlvbiB7UnVudGltZUVycm9yfSBtYXRyaXggaXMgbm90IGludmVydGlibGUgYmVjYXVzZSBpdHMgZGV0ZXJtaW5hdGUgaXMgemVyby4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgaW52ZXJzZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3Qgc3JjMCA9IG1hdHJpeFswXTsKICAgICAgICAgIGNvbnN0IHNyYzEgPSBtYXRyaXhbNF07CiAgICAgICAgICBjb25zdCBzcmMyID0gbWF0cml4WzhdOwogICAgICAgICAgY29uc3Qgc3JjMyA9IG1hdHJpeFsxMl07CiAgICAgICAgICBjb25zdCBzcmM0ID0gbWF0cml4WzFdOwogICAgICAgICAgY29uc3Qgc3JjNSA9IG1hdHJpeFs1XTsKICAgICAgICAgIGNvbnN0IHNyYzYgPSBtYXRyaXhbOV07CiAgICAgICAgICBjb25zdCBzcmM3ID0gbWF0cml4WzEzXTsKICAgICAgICAgIGNvbnN0IHNyYzggPSBtYXRyaXhbMl07CiAgICAgICAgICBjb25zdCBzcmM5ID0gbWF0cml4WzZdOwogICAgICAgICAgY29uc3Qgc3JjMTAgPSBtYXRyaXhbMTBdOwogICAgICAgICAgY29uc3Qgc3JjMTEgPSBtYXRyaXhbMTRdOwogICAgICAgICAgY29uc3Qgc3JjMTIgPSBtYXRyaXhbM107CiAgICAgICAgICBjb25zdCBzcmMxMyA9IG1hdHJpeFs3XTsKICAgICAgICAgIGNvbnN0IHNyYzE0ID0gbWF0cml4WzExXTsKICAgICAgICAgIGNvbnN0IHNyYzE1ID0gbWF0cml4WzE1XTsKICAgICAgICAgIGxldCB0bXAwID0gc3JjMTAgKiBzcmMxNTsKICAgICAgICAgIGxldCB0bXAxID0gc3JjMTEgKiBzcmMxNDsKICAgICAgICAgIGxldCB0bXAyID0gc3JjOSAqIHNyYzE1OwogICAgICAgICAgbGV0IHRtcDMgPSBzcmMxMSAqIHNyYzEzOwogICAgICAgICAgbGV0IHRtcDQgPSBzcmM5ICogc3JjMTQ7CiAgICAgICAgICBsZXQgdG1wNSA9IHNyYzEwICogc3JjMTM7CiAgICAgICAgICBsZXQgdG1wNiA9IHNyYzggKiBzcmMxNTsKICAgICAgICAgIGxldCB0bXA3ID0gc3JjMTEgKiBzcmMxMjsKICAgICAgICAgIGxldCB0bXA4ID0gc3JjOCAqIHNyYzE0OwogICAgICAgICAgbGV0IHRtcDkgPSBzcmMxMCAqIHNyYzEyOwogICAgICAgICAgbGV0IHRtcDEwID0gc3JjOCAqIHNyYzEzOwogICAgICAgICAgbGV0IHRtcDExID0gc3JjOSAqIHNyYzEyOwogICAgICAgICAgY29uc3QgZHN0MCA9IHRtcDAgKiBzcmM1ICsgdG1wMyAqIHNyYzYgKyB0bXA0ICogc3JjNyAtICh0bXAxICogc3JjNSArIHRtcDIgKiBzcmM2ICsgdG1wNSAqIHNyYzcpOwogICAgICAgICAgY29uc3QgZHN0MSA9IHRtcDEgKiBzcmM0ICsgdG1wNiAqIHNyYzYgKyB0bXA5ICogc3JjNyAtICh0bXAwICogc3JjNCArIHRtcDcgKiBzcmM2ICsgdG1wOCAqIHNyYzcpOwogICAgICAgICAgY29uc3QgZHN0MiA9IHRtcDIgKiBzcmM0ICsgdG1wNyAqIHNyYzUgKyB0bXAxMCAqIHNyYzcgLSAodG1wMyAqIHNyYzQgKyB0bXA2ICogc3JjNSArIHRtcDExICogc3JjNyk7CiAgICAgICAgICBjb25zdCBkc3QzID0gdG1wNSAqIHNyYzQgKyB0bXA4ICogc3JjNSArIHRtcDExICogc3JjNiAtICh0bXA0ICogc3JjNCArIHRtcDkgKiBzcmM1ICsgdG1wMTAgKiBzcmM2KTsKICAgICAgICAgIGNvbnN0IGRzdDQgPSB0bXAxICogc3JjMSArIHRtcDIgKiBzcmMyICsgdG1wNSAqIHNyYzMgLSAodG1wMCAqIHNyYzEgKyB0bXAzICogc3JjMiArIHRtcDQgKiBzcmMzKTsKICAgICAgICAgIGNvbnN0IGRzdDUgPSB0bXAwICogc3JjMCArIHRtcDcgKiBzcmMyICsgdG1wOCAqIHNyYzMgLSAodG1wMSAqIHNyYzAgKyB0bXA2ICogc3JjMiArIHRtcDkgKiBzcmMzKTsKICAgICAgICAgIGNvbnN0IGRzdDYgPSB0bXAzICogc3JjMCArIHRtcDYgKiBzcmMxICsgdG1wMTEgKiBzcmMzIC0gKHRtcDIgKiBzcmMwICsgdG1wNyAqIHNyYzEgKyB0bXAxMCAqIHNyYzMpOwogICAgICAgICAgY29uc3QgZHN0NyA9IHRtcDQgKiBzcmMwICsgdG1wOSAqIHNyYzEgKyB0bXAxMCAqIHNyYzIgLSAodG1wNSAqIHNyYzAgKyB0bXA4ICogc3JjMSArIHRtcDExICogc3JjMik7CiAgICAgICAgICB0bXAwID0gc3JjMiAqIHNyYzc7CiAgICAgICAgICB0bXAxID0gc3JjMyAqIHNyYzY7CiAgICAgICAgICB0bXAyID0gc3JjMSAqIHNyYzc7CiAgICAgICAgICB0bXAzID0gc3JjMyAqIHNyYzU7CiAgICAgICAgICB0bXA0ID0gc3JjMSAqIHNyYzY7CiAgICAgICAgICB0bXA1ID0gc3JjMiAqIHNyYzU7CiAgICAgICAgICB0bXA2ID0gc3JjMCAqIHNyYzc7CiAgICAgICAgICB0bXA3ID0gc3JjMyAqIHNyYzQ7CiAgICAgICAgICB0bXA4ID0gc3JjMCAqIHNyYzY7CiAgICAgICAgICB0bXA5ID0gc3JjMiAqIHNyYzQ7CiAgICAgICAgICB0bXAxMCA9IHNyYzAgKiBzcmM1OwogICAgICAgICAgdG1wMTEgPSBzcmMxICogc3JjNDsKICAgICAgICAgIGNvbnN0IGRzdDggPSB0bXAwICogc3JjMTMgKyB0bXAzICogc3JjMTQgKyB0bXA0ICogc3JjMTUgLSAodG1wMSAqIHNyYzEzICsgdG1wMiAqIHNyYzE0ICsgdG1wNSAqIHNyYzE1KTsKICAgICAgICAgIGNvbnN0IGRzdDkgPSB0bXAxICogc3JjMTIgKyB0bXA2ICogc3JjMTQgKyB0bXA5ICogc3JjMTUgLSAodG1wMCAqIHNyYzEyICsgdG1wNyAqIHNyYzE0ICsgdG1wOCAqIHNyYzE1KTsKICAgICAgICAgIGNvbnN0IGRzdDEwID0gdG1wMiAqIHNyYzEyICsgdG1wNyAqIHNyYzEzICsgdG1wMTAgKiBzcmMxNSAtICh0bXAzICogc3JjMTIgKyB0bXA2ICogc3JjMTMgKyB0bXAxMSAqIHNyYzE1KTsKICAgICAgICAgIGNvbnN0IGRzdDExID0gdG1wNSAqIHNyYzEyICsgdG1wOCAqIHNyYzEzICsgdG1wMTEgKiBzcmMxNCAtICh0bXA0ICogc3JjMTIgKyB0bXA5ICogc3JjMTMgKyB0bXAxMCAqIHNyYzE0KTsKICAgICAgICAgIGNvbnN0IGRzdDEyID0gdG1wMiAqIHNyYzEwICsgdG1wNSAqIHNyYzExICsgdG1wMSAqIHNyYzkgLSAodG1wNCAqIHNyYzExICsgdG1wMCAqIHNyYzkgKyB0bXAzICogc3JjMTApOwogICAgICAgICAgY29uc3QgZHN0MTMgPSB0bXA4ICogc3JjMTEgKyB0bXAwICogc3JjOCArIHRtcDcgKiBzcmMxMCAtICh0bXA2ICogc3JjMTAgKyB0bXA5ICogc3JjMTEgKyB0bXAxICogc3JjOCk7CiAgICAgICAgICBjb25zdCBkc3QxNCA9IHRtcDYgKiBzcmM5ICsgdG1wMTEgKiBzcmMxMSArIHRtcDMgKiBzcmM4IC0gKHRtcDEwICogc3JjMTEgKyB0bXAyICogc3JjOCArIHRtcDcgKiBzcmM5KTsKICAgICAgICAgIGNvbnN0IGRzdDE1ID0gdG1wMTAgKiBzcmMxMCArIHRtcDQgKiBzcmM4ICsgdG1wOSAqIHNyYzkgLSAodG1wOCAqIHNyYzkgKyB0bXAxMSAqIHNyYzEwICsgdG1wNSAqIHNyYzgpOwogICAgICAgICAgbGV0IGRldCA9IHNyYzAgKiBkc3QwICsgc3JjMSAqIGRzdDEgKyBzcmMyICogZHN0MiArIHNyYzMgKiBkc3QzOwogICAgICAgICAgaWYgKE1hdGguYWJzKGRldCkgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjIxKSB7CiAgICAgICAgICAgIGlmIChNYXRyaXgzX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgICAgICBfTWF0cml4NC5nZXRNYXRyaXgzKG1hdHJpeCwgc2NyYXRjaEludmVyc2VSb3RhdGlvbiksCiAgICAgICAgICAgICAgc2NyYXRjaE1hdHJpeDNaZXJvLAogICAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9ONwogICAgICAgICAgICApICYmIENhcnRlc2lhbjRfZGVmYXVsdC5lcXVhbHMoCiAgICAgICAgICAgICAgX01hdHJpeDQuZ2V0Um93KG1hdHJpeCwgMywgc2NyYXRjaEJvdHRvbVJvdyksCiAgICAgICAgICAgICAgc2NyYXRjaEV4cGVjdGVkQm90dG9tUm93CiAgICAgICAgICAgICkpIHsKICAgICAgICAgICAgICByZXN1bHRbMF0gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFsxXSA9IDA7CiAgICAgICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgICAgICByZXN1bHRbM10gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFs0XSA9IDA7CiAgICAgICAgICAgICAgcmVzdWx0WzVdID0gMDsKICAgICAgICAgICAgICByZXN1bHRbNl0gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICAgICAgcmVzdWx0WzhdID0gMDsKICAgICAgICAgICAgICByZXN1bHRbOV0gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFsxMF0gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFsxMV0gPSAwOwogICAgICAgICAgICAgIHJlc3VsdFsxMl0gPSAtbWF0cml4WzEyXTsKICAgICAgICAgICAgICByZXN1bHRbMTNdID0gLW1hdHJpeFsxM107CiAgICAgICAgICAgICAgcmVzdWx0WzE0XSA9IC1tYXRyaXhbMTRdOwogICAgICAgICAgICAgIHJlc3VsdFsxNV0gPSAxOwogICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJtYXRyaXggaXMgbm90IGludmVydGlibGUgYmVjYXVzZSBpdHMgZGV0ZXJtaW5hdGUgaXMgemVyby4iCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBkZXQgPSAxIC8gZGV0OwogICAgICAgICAgcmVzdWx0WzBdID0gZHN0MCAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxXSA9IGRzdDEgKiBkZXQ7CiAgICAgICAgICByZXN1bHRbMl0gPSBkc3QyICogZGV0OwogICAgICAgICAgcmVzdWx0WzNdID0gZHN0MyAqIGRldDsKICAgICAgICAgIHJlc3VsdFs0XSA9IGRzdDQgKiBkZXQ7CiAgICAgICAgICByZXN1bHRbNV0gPSBkc3Q1ICogZGV0OwogICAgICAgICAgcmVzdWx0WzZdID0gZHN0NiAqIGRldDsKICAgICAgICAgIHJlc3VsdFs3XSA9IGRzdDcgKiBkZXQ7CiAgICAgICAgICByZXN1bHRbOF0gPSBkc3Q4ICogZGV0OwogICAgICAgICAgcmVzdWx0WzldID0gZHN0OSAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBkc3QxMCAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxMV0gPSBkc3QxMSAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxMl0gPSBkc3QxMiAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxM10gPSBkc3QxMyAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxNF0gPSBkc3QxNCAqIGRldDsKICAgICAgICAgIHJlc3VsdFsxNV0gPSBkc3QxNSAqIGRldDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBpbnZlcnNlIG9mIHRoZSBwcm92aWRlZCBtYXRyaXggYXNzdW1pbmcgaXQgaXMgYSBwcm9wZXIgcmlnaWQgbWF0cml4LAogICAgICAgICAqIHdoZXJlIHRoZSB1cHBlciBsZWZ0IDN4MyBlbGVtZW50cyBhcmUgYSByb3RhdGlvbiBtYXRyaXgsCiAgICAgICAgICogYW5kIHRoZSB1cHBlciB0aHJlZSBlbGVtZW50cyBpbiB0aGUgZm91cnRoIGNvbHVtbiBhcmUgdGhlIHRyYW5zbGF0aW9uLgogICAgICAgICAqIFRoZSBib3R0b20gcm93IGlzIGFzc3VtZWQgdG8gYmUgWzAsIDAsIDAsIDFdLgogICAgICAgICAqIFRoZSBtYXRyaXggaXMgbm90IHZlcmlmaWVkIHRvIGJlIGluIHRoZSBwcm9wZXIgZm9ybS4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBpcyBmYXN0ZXIgdGhhbiBjb21wdXRpbmcgdGhlIGludmVyc2UgZm9yIGEgZ2VuZXJhbCA0eDQKICAgICAgICAgKiBtYXRyaXggdXNpbmcge0BsaW5rIE1hdHJpeDQuaW52ZXJzZX0uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIGludmVydC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGludmVyc2VUcmFuc2Zvcm1hdGlvbihtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3QgbWF0cml4MCA9IG1hdHJpeFswXTsKICAgICAgICAgIGNvbnN0IG1hdHJpeDEgPSBtYXRyaXhbMV07CiAgICAgICAgICBjb25zdCBtYXRyaXgyID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgbWF0cml4NCA9IG1hdHJpeFs0XTsKICAgICAgICAgIGNvbnN0IG1hdHJpeDUgPSBtYXRyaXhbNV07CiAgICAgICAgICBjb25zdCBtYXRyaXg2ID0gbWF0cml4WzZdOwogICAgICAgICAgY29uc3QgbWF0cml4OCA9IG1hdHJpeFs4XTsKICAgICAgICAgIGNvbnN0IG1hdHJpeDkgPSBtYXRyaXhbOV07CiAgICAgICAgICBjb25zdCBtYXRyaXgxMCA9IG1hdHJpeFsxMF07CiAgICAgICAgICBjb25zdCB2WCA9IG1hdHJpeFsxMl07CiAgICAgICAgICBjb25zdCB2WSA9IG1hdHJpeFsxM107CiAgICAgICAgICBjb25zdCB2WiA9IG1hdHJpeFsxNF07CiAgICAgICAgICBjb25zdCB4MiA9IC1tYXRyaXgwICogdlggLSBtYXRyaXgxICogdlkgLSBtYXRyaXgyICogdlo7CiAgICAgICAgICBjb25zdCB5MiA9IC1tYXRyaXg0ICogdlggLSBtYXRyaXg1ICogdlkgLSBtYXRyaXg2ICogdlo7CiAgICAgICAgICBjb25zdCB6MiA9IC1tYXRyaXg4ICogdlggLSBtYXRyaXg5ICogdlkgLSBtYXRyaXgxMCAqIHZaOwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4MDsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeDQ7CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXg4OwogICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgIHJlc3VsdFs0XSA9IG1hdHJpeDE7CiAgICAgICAgICByZXN1bHRbNV0gPSBtYXRyaXg1OwogICAgICAgICAgcmVzdWx0WzZdID0gbWF0cml4OTsKICAgICAgICAgIHJlc3VsdFs3XSA9IDA7CiAgICAgICAgICByZXN1bHRbOF0gPSBtYXRyaXgyOwogICAgICAgICAgcmVzdWx0WzldID0gbWF0cml4NjsKICAgICAgICAgIHJlc3VsdFsxMF0gPSBtYXRyaXgxMDsKICAgICAgICAgIHJlc3VsdFsxMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzEyXSA9IHgyOwogICAgICAgICAgcmVzdWx0WzEzXSA9IHkyOwogICAgICAgICAgcmVzdWx0WzE0XSA9IHoyOwogICAgICAgICAgcmVzdWx0WzE1XSA9IDE7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgaW52ZXJzZSB0cmFuc3Bvc2Ugb2YgYSBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHRyYW5zcG9zZSBhbmQgaW52ZXJ0LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXg0fSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgaW52ZXJzZVRyYW5zcG9zZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmV0dXJuIF9NYXRyaXg0LmludmVyc2UoCiAgICAgICAgICAgIF9NYXRyaXg0LnRyYW5zcG9zZShtYXRyaXgsIHNjcmF0Y2hUcmFuc3Bvc2VNYXRyaXgyKSwKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBudW1iZXIgb2YgaXRlbXMgaW4gdGhlIGNvbGxlY3Rpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqLwogICAgICAgIGdldCBsZW5ndGgoKSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDQucGFja2VkTGVuZ3RoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIHRoZSBwcm92aWRlZCBNYXRyaXg0IGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4NH0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgTWF0cml4NCBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfTWF0cml4NC5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGlzIG1hdHJpeCB0byB0aGUgcHJvdmlkZWQgbWF0cml4IGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gW3JpZ2h0XSBUaGUgcmlnaHQgaGFuZCBzaWRlIG1hdHJpeC4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzKHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDQuZXF1YWxzKHRoaXMsIHJpZ2h0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgcHJvdmlkZWQgbWF0cml4IGFuZCBhcnJheSwgc3RhcnRpbmcgZnJvbSBhIGdpdmVuIGFycmF5IG9mZnNldC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gbWF0cml4CiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gb2Zmc2V0CiAgICAgICAgICogQGlnbm9yZQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHNBcnJheShtYXRyaXgsIGFycmF5LCBvZmZzZXQpIHsKICAgICAgICAgIHJldHVybiBtYXRyaXhbMF0gPT09IGFycmF5W29mZnNldF0gJiYgbWF0cml4WzFdID09PSBhcnJheVtvZmZzZXQgKyAxXSAmJiBtYXRyaXhbMl0gPT09IGFycmF5W29mZnNldCArIDJdICYmIG1hdHJpeFszXSA9PT0gYXJyYXlbb2Zmc2V0ICsgM10gJiYgbWF0cml4WzRdID09PSBhcnJheVtvZmZzZXQgKyA0XSAmJiBtYXRyaXhbNV0gPT09IGFycmF5W29mZnNldCArIDVdICYmIG1hdHJpeFs2XSA9PT0gYXJyYXlbb2Zmc2V0ICsgNl0gJiYgbWF0cml4WzddID09PSBhcnJheVtvZmZzZXQgKyA3XSAmJiBtYXRyaXhbOF0gPT09IGFycmF5W29mZnNldCArIDhdICYmIG1hdHJpeFs5XSA9PT0gYXJyYXlbb2Zmc2V0ICsgOV0gJiYgbWF0cml4WzEwXSA9PT0gYXJyYXlbb2Zmc2V0ICsgMTBdICYmIG1hdHJpeFsxMV0gPT09IGFycmF5W29mZnNldCArIDExXSAmJiBtYXRyaXhbMTJdID09PSBhcnJheVtvZmZzZXQgKyAxMl0gJiYgbWF0cml4WzEzXSA9PT0gYXJyYXlbb2Zmc2V0ICsgMTNdICYmIG1hdHJpeFsxNF0gPT09IGFycmF5W29mZnNldCArIDE0XSAmJiBtYXRyaXhbMTVdID09PSBhcnJheVtvZmZzZXQgKyAxNV07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgbWF0cml4IHRvIHRoZSBwcm92aWRlZCBtYXRyaXggY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwKICAgICAgICAgKiA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSBbcmlnaHRdIFRoZSByaWdodCBoYW5kIHNpZGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZXBzaWxvbj0wXSBUaGUgZXBzaWxvbiB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHNFcHNpbG9uKHJpZ2h0LCBlcHNpbG9uKSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDQuZXF1YWxzRXBzaWxvbih0aGlzLCByaWdodCwgZXBzaWxvbik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIE1hdHJpeCB3aXRoIGVhY2ggcm93IGJlaW5nCiAgICAgICAgICogb24gYSBzZXBhcmF0ZSBsaW5lIGFuZCBpbiB0aGUgZm9ybWF0ICcoY29sdW1uMCwgY29sdW1uMSwgY29sdW1uMiwgY29sdW1uMyknLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge3N0cmluZ30gQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBwcm92aWRlZCBNYXRyaXggd2l0aCBlYWNoIHJvdyBiZWluZyBvbiBhIHNlcGFyYXRlIGxpbmUgYW5kIGluIHRoZSBmb3JtYXQgJyhjb2x1bW4wLCBjb2x1bW4xLCBjb2x1bW4yLCBjb2x1bW4zKScuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICByZXR1cm4gYCgke3RoaXNbMF19LCAke3RoaXNbNF19LCAke3RoaXNbOF19LCAke3RoaXNbMTJdfSkKKCR7dGhpc1sxXX0sICR7dGhpc1s1XX0sICR7dGhpc1s5XX0sICR7dGhpc1sxM119KQooJHt0aGlzWzJdfSwgJHt0aGlzWzZdfSwgJHt0aGlzWzEwXX0sICR7dGhpc1sxNF19KQooJHt0aGlzWzNdfSwgJHt0aGlzWzddfSwgJHt0aGlzWzExXX0sICR7dGhpc1sxNV19KWA7CiAgICAgICAgfQogICAgICB9OwogICAgICBNYXRyaXg0LnBhY2tlZExlbmd0aCA9IDE2OwogICAgICBNYXRyaXg0LmZyb21BcnJheSA9IE1hdHJpeDQudW5wYWNrOwogICAgICBNYXRyaXg0LklERU5USVRZID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgTWF0cml4NCgKICAgICAgICAgIDEsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMSwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAxLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDEKICAgICAgICApCiAgICAgICk7CiAgICAgIE1hdHJpeDQuWkVSTyA9IE9iamVjdC5mcmVlemUoCiAgICAgICAgbmV3IE1hdHJpeDQoCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwCiAgICAgICAgKQogICAgICApOwogICAgICBNYXRyaXg0LkNPTFVNTjBST1cwID0gMDsKICAgICAgTWF0cml4NC5DT0xVTU4wUk9XMSA9IDE7CiAgICAgIE1hdHJpeDQuQ09MVU1OMFJPVzIgPSAyOwogICAgICBNYXRyaXg0LkNPTFVNTjBST1czID0gMzsKICAgICAgTWF0cml4NC5DT0xVTU4xUk9XMCA9IDQ7CiAgICAgIE1hdHJpeDQuQ09MVU1OMVJPVzEgPSA1OwogICAgICBNYXRyaXg0LkNPTFVNTjFST1cyID0gNjsKICAgICAgTWF0cml4NC5DT0xVTU4xUk9XMyA9IDc7CiAgICAgIE1hdHJpeDQuQ09MVU1OMlJPVzAgPSA4OwogICAgICBNYXRyaXg0LkNPTFVNTjJST1cxID0gOTsKICAgICAgTWF0cml4NC5DT0xVTU4yUk9XMiA9IDEwOwogICAgICBNYXRyaXg0LkNPTFVNTjJST1czID0gMTE7CiAgICAgIE1hdHJpeDQuQ09MVU1OM1JPVzAgPSAxMjsKICAgICAgTWF0cml4NC5DT0xVTU4zUk9XMSA9IDEzOwogICAgICBNYXRyaXg0LkNPTFVNTjNST1cyID0gMTQ7CiAgICAgIE1hdHJpeDQuQ09MVU1OM1JPVzMgPSAxNTsKICAgICAgZnJvbUNhbWVyYUYgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZyb21DYW1lcmFSID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tQ2FtZXJhVSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoMTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlU2NyYXRjaDIyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ29sdW1uMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoMzIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlU2NyYXRjaDQyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY2FsZVNjcmF0Y2g1MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEludmVyc2VSb3RhdGlvbiA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1hdHJpeDNaZXJvID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQm90dG9tUm93ID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRXhwZWN0ZWRCb3R0b21Sb3cgPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KDAsIDAsIDAsIDEpOwogICAgICBzY3JhdGNoVHJhbnNwb3NlTWF0cml4MiA9IG5ldyBNYXRyaXg0KCk7CiAgICAgIE1hdHJpeDRfZGVmYXVsdCA9IE1hdHJpeDQ7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9iaW5hcnlTZWFyY2guanMKICBmdW5jdGlvbiBiaW5hcnlTZWFyY2goYXJyYXksIGl0ZW1Ub0ZpbmQsIGNvbXBhcmF0b3IpIHsKICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIml0ZW1Ub0ZpbmQiLCBpdGVtVG9GaW5kKTsKICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY29tcGFyYXRvciIsIGNvbXBhcmF0b3IpOwogICAgbGV0IGxvdyA9IDA7CiAgICBsZXQgaGlnaCA9IGFycmF5Lmxlbmd0aCAtIDE7CiAgICBsZXQgaTI7CiAgICBsZXQgY29tcGFyaXNvbjsKICAgIHdoaWxlIChsb3cgPD0gaGlnaCkgewogICAgICBpMiA9IH5+KChsb3cgKyBoaWdoKSAvIDIpOwogICAgICBjb21wYXJpc29uID0gY29tcGFyYXRvcihhcnJheVtpMl0sIGl0ZW1Ub0ZpbmQpOwogICAgICBpZiAoY29tcGFyaXNvbiA8IDApIHsKICAgICAgICBsb3cgPSBpMiArIDE7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgaWYgKGNvbXBhcmlzb24gPiAwKSB7CiAgICAgICAgaGlnaCA9IGkyIC0gMTsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICByZXR1cm4gaTI7CiAgICB9CiAgICByZXR1cm4gfihoaWdoICsgMSk7CiAgfQogIHZhciBiaW5hcnlTZWFyY2hfZGVmYXVsdDsKICB2YXIgaW5pdF9iaW5hcnlTZWFyY2ggPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2JpbmFyeVNlYXJjaC5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgYmluYXJ5U2VhcmNoX2RlZmF1bHQgPSBiaW5hcnlTZWFyY2g7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVyc1NhbXBsZS5qcwogIGZ1bmN0aW9uIEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzU2FtcGxlKHhQb2xlV2FuZGVyLCB5UG9sZVdhbmRlciwgeFBvbGVPZmZzZXQsIHlQb2xlT2Zmc2V0LCB1dDFNaW51c1V0YykgewogICAgdGhpcy54UG9sZVdhbmRlciA9IHhQb2xlV2FuZGVyOwogICAgdGhpcy55UG9sZVdhbmRlciA9IHlQb2xlV2FuZGVyOwogICAgdGhpcy54UG9sZU9mZnNldCA9IHhQb2xlT2Zmc2V0OwogICAgdGhpcy55UG9sZU9mZnNldCA9IHlQb2xlT2Zmc2V0OwogICAgdGhpcy51dDFNaW51c1V0YyA9IHV0MU1pbnVzVXRjOwogIH0KICB2YXIgRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNTYW1wbGVfZGVmYXVsdDsKICB2YXIgaW5pdF9FYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVyc1NhbXBsZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNTYW1wbGUuanMiKCkgewogICAgICBFYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVyc1NhbXBsZV9kZWZhdWx0ID0gRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNTYW1wbGU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9pc0xlYXBZZWFyLmpzCiAgZnVuY3Rpb24gaXNMZWFwWWVhcih5ZWFyKSB7CiAgICBpZiAoeWVhciA9PT0gbnVsbCB8fCBpc05hTih5ZWFyKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieWVhciBpcyByZXF1aXJlZCBhbmQgbXVzdCBiZSBhIG51bWJlci4iKTsKICAgIH0KICAgIHJldHVybiB5ZWFyICUgNCA9PT0gMCAmJiB5ZWFyICUgMTAwICE9PSAwIHx8IHllYXIgJSA0MDAgPT09IDA7CiAgfQogIHZhciBpc0xlYXBZZWFyX2RlZmF1bHQ7CiAgdmFyIGluaXRfaXNMZWFwWWVhciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvaXNMZWFwWWVhci5qcyIoKSB7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaXNMZWFwWWVhcl9kZWZhdWx0ID0gaXNMZWFwWWVhcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0dyZWdvcmlhbkRhdGUuanMKICBmdW5jdGlvbiBHcmVnb3JpYW5EYXRlKHllYXIsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaXNlY29uZCwgaXNMZWFwU2Vjb25kKSB7CiAgICBjb25zdCBtaW5pbXVtWWVhciA9IDE7CiAgICBjb25zdCBtaW5pbXVtTW9udGggPSAxOwogICAgY29uc3QgbWluaW11bURheSA9IDE7CiAgICBjb25zdCBtaW5pbXVtSG91ciA9IDA7CiAgICBjb25zdCBtaW5pbXVtTWludXRlID0gMDsKICAgIGNvbnN0IG1pbmltdW1TZWNvbmQgPSAwOwogICAgY29uc3QgbWluaW11bU1pbGxpc2Vjb25kID0gMDsKICAgIHllYXIgPSB5ZWFyID8/IG1pbmltdW1ZZWFyOwogICAgbW9udGggPSBtb250aCA/PyBtaW5pbXVtTW9udGg7CiAgICBkYXkgPSBkYXkgPz8gbWluaW11bURheTsKICAgIGhvdXIgPSBob3VyID8/IG1pbmltdW1Ib3VyOwogICAgbWludXRlID0gbWludXRlID8/IG1pbmltdW1NaW51dGU7CiAgICBzZWNvbmQgPSBzZWNvbmQgPz8gbWluaW11bVNlY29uZDsKICAgIG1pbGxpc2Vjb25kID0gbWlsbGlzZWNvbmQgPz8gbWluaW11bU1pbGxpc2Vjb25kOwogICAgaXNMZWFwU2Vjb25kID0gaXNMZWFwU2Vjb25kID8/IGZhbHNlOwogICAgdmFsaWRhdGVSYW5nZSgpOwogICAgdmFsaWRhdGVEYXRlKCk7CiAgICB0aGlzLnllYXIgPSB5ZWFyOwogICAgdGhpcy5tb250aCA9IG1vbnRoOwogICAgdGhpcy5kYXkgPSBkYXk7CiAgICB0aGlzLmhvdXIgPSBob3VyOwogICAgdGhpcy5taW51dGUgPSBtaW51dGU7CiAgICB0aGlzLnNlY29uZCA9IHNlY29uZDsKICAgIHRoaXMubWlsbGlzZWNvbmQgPSBtaWxsaXNlY29uZDsKICAgIHRoaXMuaXNMZWFwU2Vjb25kID0gaXNMZWFwU2Vjb25kOwogICAgZnVuY3Rpb24gdmFsaWRhdGVSYW5nZSgpIHsKICAgICAgY29uc3QgbWF4aW11bVllYXIgPSA5OTk5OwogICAgICBjb25zdCBtYXhpbXVtTW9udGggPSAxMjsKICAgICAgY29uc3QgbWF4aW11bURheSA9IDMxOwogICAgICBjb25zdCBtYXhpbXVtSG91ciA9IDIzOwogICAgICBjb25zdCBtYXhpbXVtTWludXRlID0gNTk7CiAgICAgIGNvbnN0IG1heGltdW1TZWNvbmQgPSA1OTsKICAgICAgY29uc3QgZXhjbHVkZWRNYXhpbXVtTWlsaXNlY29uZCA9IDFlMzsKICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIlllYXIiLCB5ZWFyLCBtaW5pbXVtWWVhcik7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJZZWFyIiwgeWVhciwgbWF4aW11bVllYXIpOwogICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiTW9udGgiLCBtb250aCwgbWluaW11bU1vbnRoKTsKICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoIk1vbnRoIiwgbW9udGgsIG1heGltdW1Nb250aCk7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJEYXkiLCBkYXksIG1pbmltdW1EYXkpOwogICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiRGF5IiwgZGF5LCBtYXhpbXVtRGF5KTsKICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIkhvdXIiLCBob3VyLCBtaW5pbXVtSG91cik7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJIb3VyIiwgaG91ciwgbWF4aW11bUhvdXIpOwogICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiTWludXRlIiwgbWludXRlLCBtaW5pbXVtTWludXRlKTsKICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoIk1pbnV0ZSIsIG1pbnV0ZSwgbWF4aW11bU1pbnV0ZSk7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLmJvb2woIklzTGVhcFNlY29uZCIsIGlzTGVhcFNlY29uZCk7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJTZWNvbmQiLCBzZWNvbmQsIG1pbmltdW1TZWNvbmQpOwogICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygKICAgICAgICAiU2Vjb25kIiwKICAgICAgICBzZWNvbmQsCiAgICAgICAgaXNMZWFwU2Vjb25kID8gbWF4aW11bVNlY29uZCArIDEgOiBtYXhpbXVtU2Vjb25kCiAgICAgICk7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKAogICAgICAgICJNaWxsaXNlY29uZCIsCiAgICAgICAgbWlsbGlzZWNvbmQsCiAgICAgICAgbWluaW11bU1pbGxpc2Vjb25kCiAgICAgICk7CiAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbigKICAgICAgICAiTWlsbGlzZWNvbmQiLAogICAgICAgIG1pbGxpc2Vjb25kLAogICAgICAgIGV4Y2x1ZGVkTWF4aW11bU1pbGlzZWNvbmQKICAgICAgKTsKICAgIH0KICAgIGZ1bmN0aW9uIHZhbGlkYXRlRGF0ZSgpIHsKICAgICAgY29uc3QgZGF5c0luTW9udGgyID0gbW9udGggPT09IDIgJiYgaXNMZWFwWWVhcl9kZWZhdWx0KHllYXIpID8gZGF5c0luWWVhclttb250aCAtIDFdICsgMSA6IGRheXNJblllYXJbbW9udGggLSAxXTsKICAgICAgaWYgKGRheSA+IGRheXNJbk1vbnRoMikgewogICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJNb250aCBhbmQgRGF5IHJlcHJlc2VudHMgaW52YWxpZCBkYXRlIik7CiAgICAgIH0KICAgIH0KICB9CiAgdmFyIGRheXNJblllYXIsIEdyZWdvcmlhbkRhdGVfZGVmYXVsdDsKICB2YXIgaW5pdF9HcmVnb3JpYW5EYXRlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HcmVnb3JpYW5EYXRlLmpzIigpIHsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfaXNMZWFwWWVhcigpOwogICAgICBkYXlzSW5ZZWFyID0gWzMxLCAyOCwgMzEsIDMwLCAzMSwgMzAsIDMxLCAzMSwgMzAsIDMxLCAzMCwgMzFdOwogICAgICBHcmVnb3JpYW5EYXRlX2RlZmF1bHQgPSBHcmVnb3JpYW5EYXRlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvTGVhcFNlY29uZC5qcwogIGZ1bmN0aW9uIExlYXBTZWNvbmQoZGF0ZSwgb2Zmc2V0KSB7CiAgICB0aGlzLmp1bGlhbkRhdGUgPSBkYXRlOwogICAgdGhpcy5vZmZzZXQgPSBvZmZzZXQ7CiAgfQogIHZhciBMZWFwU2Vjb25kX2RlZmF1bHQ7CiAgdmFyIGluaXRfTGVhcFNlY29uZCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvTGVhcFNlY29uZC5qcyIoKSB7CiAgICAgIExlYXBTZWNvbmRfZGVmYXVsdCA9IExlYXBTZWNvbmQ7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9UaW1lQ29uc3RhbnRzLmpzCiAgdmFyIFRpbWVDb25zdGFudHMsIFRpbWVDb25zdGFudHNfZGVmYXVsdDsKICB2YXIgaW5pdF9UaW1lQ29uc3RhbnRzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9UaW1lQ29uc3RhbnRzLmpzIigpIHsKICAgICAgVGltZUNvbnN0YW50cyA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgbnVtYmVyIG9mIHNlY29uZHMgaW4gb25lIG1pbGxpc2Vjb25kOiA8Y29kZT4wLjAwMTwvY29kZT4KICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFNFQ09ORFNfUEVSX01JTExJU0VDT05EOiAxZS0zLAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBudW1iZXIgb2Ygc2Vjb25kcyBpbiBvbmUgbWludXRlOiA8Y29kZT42MDwvY29kZT4uCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBTRUNPTkRTX1BFUl9NSU5VVEU6IDYwLAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBudW1iZXIgb2YgbWludXRlcyBpbiBvbmUgaG91cjogPGNvZGU+NjA8L2NvZGU+LgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgTUlOVVRFU19QRVJfSE9VUjogNjAsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG51bWJlciBvZiBob3VycyBpbiBvbmUgZGF5OiA8Y29kZT4yNDwvY29kZT4uCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBIT1VSU19QRVJfREFZOiAyNCwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgbnVtYmVyIG9mIHNlY29uZHMgaW4gb25lIGhvdXI6IDxjb2RlPjM2MDA8L2NvZGU+LgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgU0VDT05EU19QRVJfSE9VUjogMzYwMCwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgbnVtYmVyIG9mIG1pbnV0ZXMgaW4gb25lIGRheTogPGNvZGU+MTQ0MDwvY29kZT4uCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBNSU5VVEVTX1BFUl9EQVk6IDE0NDAsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG51bWJlciBvZiBzZWNvbmRzIGluIG9uZSBkYXksIGlnbm9yaW5nIGxlYXAgc2Vjb25kczogPGNvZGU+ODY0MDA8L2NvZGU+LgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgU0VDT05EU19QRVJfREFZOiA4NjQwMCwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgbnVtYmVyIG9mIGRheXMgaW4gb25lIEp1bGlhbiBjZW50dXJ5OiA8Y29kZT4zNjUyNTwvY29kZT4uCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBEQVlTX1BFUl9KVUxJQU5fQ0VOVFVSWTogMzY1MjUsCiAgICAgICAgLyoqCiAgICAgICAgICogT25lIHRyaWxsaW9udGggb2YgYSBzZWNvbmQuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBQSUNPU0VDT05EOiAxZS05LAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBudW1iZXIgb2YgZGF5cyB0byBzdWJ0cmFjdCBmcm9tIGEgSnVsaWFuIGRhdGUgdG8gZGV0ZXJtaW5lIHRoZQogICAgICAgICAqIG1vZGlmaWVkIEp1bGlhbiBkYXRlLCB3aGljaCBnaXZlcyB0aGUgbnVtYmVyIG9mIGRheXMgc2luY2UgbWlkbmlnaHQKICAgICAgICAgKiBvbiBOb3ZlbWJlciAxNywgMTg1OC4KICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIE1PRElGSUVEX0pVTElBTl9EQVRFX0RJRkZFUkVOQ0U6IDI0MDAwMDA1ZS0xCiAgICAgIH07CiAgICAgIE9iamVjdC5mcmVlemUoVGltZUNvbnN0YW50cyk7CiAgICAgIFRpbWVDb25zdGFudHNfZGVmYXVsdCA9IFRpbWVDb25zdGFudHM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9UaW1lU3RhbmRhcmQuanMKICB2YXIgVGltZVN0YW5kYXJkLCBUaW1lU3RhbmRhcmRfZGVmYXVsdDsKICB2YXIgaW5pdF9UaW1lU3RhbmRhcmQgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RpbWVTdGFuZGFyZC5qcyIoKSB7CiAgICAgIFRpbWVTdGFuZGFyZCA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBSZXByZXNlbnRzIHRoZSBjb29yZGluYXRlZCBVbml2ZXJzYWwgVGltZSAoVVRDKSB0aW1lIHN0YW5kYXJkLgogICAgICAgICAqCiAgICAgICAgICogVVRDIGlzIHJlbGF0ZWQgdG8gVEFJIGFjY29yZGluZyB0byB0aGUgcmVsYXRpb25zaGlwCiAgICAgICAgICogPGNvZGU+VVRDID0gVEFJIC0gZGVsdGFUPC9jb2RlPiB3aGVyZSA8Y29kZT5kZWx0YVQ8L2NvZGU+IGlzIHRoZSBudW1iZXIgb2YgbGVhcAogICAgICAgICAqIHNlY29uZHMgd2hpY2ggaGF2ZSBiZWVuIGludHJvZHVjZWQgYXMgb2YgdGhlIHRpbWUgaW4gVEFJLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBVVEM6IDAsCiAgICAgICAgLyoqCiAgICAgICAgICogUmVwcmVzZW50cyB0aGUgSW50ZXJuYXRpb25hbCBBdG9taWMgVGltZSAoVEFJKSB0aW1lIHN0YW5kYXJkLgogICAgICAgICAqIFRBSSBpcyB0aGUgcHJpbmNpcGFsIHRpbWUgc3RhbmRhcmQgdG8gd2hpY2ggdGhlIG90aGVyIHRpbWUgc3RhbmRhcmRzIGFyZSByZWxhdGVkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBUQUk6IDEKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShUaW1lU3RhbmRhcmQpOwogICAgICBUaW1lU3RhbmRhcmRfZGVmYXVsdCA9IFRpbWVTdGFuZGFyZDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0p1bGlhbkRhdGUuanMKICBmdW5jdGlvbiBjb21wYXJlTGVhcFNlY29uZERhdGVzKGxlYXBTZWNvbmQsIGRhdGVUb0ZpbmQpIHsKICAgIHJldHVybiBKdWxpYW5EYXRlLmNvbXBhcmUobGVhcFNlY29uZC5qdWxpYW5EYXRlLCBkYXRlVG9GaW5kLmp1bGlhbkRhdGUpOwogIH0KICBmdW5jdGlvbiBjb252ZXJ0VXRjVG9UYWkoanVsaWFuRGF0ZSkgewogICAgYmluYXJ5U2VhcmNoU2NyYXRjaExlYXBTZWNvbmQuanVsaWFuRGF0ZSA9IGp1bGlhbkRhdGU7CiAgICBjb25zdCBsZWFwU2Vjb25kcyA9IEp1bGlhbkRhdGUubGVhcFNlY29uZHM7CiAgICBsZXQgaW5kZXggPSBiaW5hcnlTZWFyY2hfZGVmYXVsdCgKICAgICAgbGVhcFNlY29uZHMsCiAgICAgIGJpbmFyeVNlYXJjaFNjcmF0Y2hMZWFwU2Vjb25kLAogICAgICBjb21wYXJlTGVhcFNlY29uZERhdGVzCiAgICApOwogICAgaWYgKGluZGV4IDwgMCkgewogICAgICBpbmRleCA9IH5pbmRleDsKICAgIH0KICAgIGlmIChpbmRleCA+PSBsZWFwU2Vjb25kcy5sZW5ndGgpIHsKICAgICAgaW5kZXggPSBsZWFwU2Vjb25kcy5sZW5ndGggLSAxOwogICAgfQogICAgbGV0IG9mZnNldCA9IGxlYXBTZWNvbmRzW2luZGV4XS5vZmZzZXQ7CiAgICBpZiAoaW5kZXggPiAwKSB7CiAgICAgIGNvbnN0IGRpZmZlcmVuY2UgPSBKdWxpYW5EYXRlLnNlY29uZHNEaWZmZXJlbmNlKAogICAgICAgIGxlYXBTZWNvbmRzW2luZGV4XS5qdWxpYW5EYXRlLAogICAgICAgIGp1bGlhbkRhdGUKICAgICAgKTsKICAgICAgaWYgKGRpZmZlcmVuY2UgPiBvZmZzZXQpIHsKICAgICAgICBpbmRleC0tOwogICAgICAgIG9mZnNldCA9IGxlYXBTZWNvbmRzW2luZGV4XS5vZmZzZXQ7CiAgICAgIH0KICAgIH0KICAgIEp1bGlhbkRhdGUuYWRkU2Vjb25kcyhqdWxpYW5EYXRlLCBvZmZzZXQsIGp1bGlhbkRhdGUpOwogIH0KICBmdW5jdGlvbiBjb252ZXJ0VGFpVG9VdGMoanVsaWFuRGF0ZSwgcmVzdWx0KSB7CiAgICBiaW5hcnlTZWFyY2hTY3JhdGNoTGVhcFNlY29uZC5qdWxpYW5EYXRlID0ganVsaWFuRGF0ZTsKICAgIGNvbnN0IGxlYXBTZWNvbmRzID0gSnVsaWFuRGF0ZS5sZWFwU2Vjb25kczsKICAgIGxldCBpbmRleCA9IGJpbmFyeVNlYXJjaF9kZWZhdWx0KAogICAgICBsZWFwU2Vjb25kcywKICAgICAgYmluYXJ5U2VhcmNoU2NyYXRjaExlYXBTZWNvbmQsCiAgICAgIGNvbXBhcmVMZWFwU2Vjb25kRGF0ZXMKICAgICk7CiAgICBpZiAoaW5kZXggPCAwKSB7CiAgICAgIGluZGV4ID0gfmluZGV4OwogICAgfQogICAgaWYgKGluZGV4ID09PSAwKSB7CiAgICAgIHJldHVybiBKdWxpYW5EYXRlLmFkZFNlY29uZHMoanVsaWFuRGF0ZSwgLWxlYXBTZWNvbmRzWzBdLm9mZnNldCwgcmVzdWx0KTsKICAgIH0KICAgIGlmIChpbmRleCA+PSBsZWFwU2Vjb25kcy5sZW5ndGgpIHsKICAgICAgcmV0dXJuIEp1bGlhbkRhdGUuYWRkU2Vjb25kcygKICAgICAgICBqdWxpYW5EYXRlLAogICAgICAgIC1sZWFwU2Vjb25kc1tpbmRleCAtIDFdLm9mZnNldCwKICAgICAgICByZXN1bHQKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IGRpZmZlcmVuY2UgPSBKdWxpYW5EYXRlLnNlY29uZHNEaWZmZXJlbmNlKAogICAgICBsZWFwU2Vjb25kc1tpbmRleF0uanVsaWFuRGF0ZSwKICAgICAganVsaWFuRGF0ZQogICAgKTsKICAgIGlmIChkaWZmZXJlbmNlID09PSAwKSB7CiAgICAgIHJldHVybiBKdWxpYW5EYXRlLmFkZFNlY29uZHMoCiAgICAgICAganVsaWFuRGF0ZSwKICAgICAgICAtbGVhcFNlY29uZHNbaW5kZXhdLm9mZnNldCwKICAgICAgICByZXN1bHQKICAgICAgKTsKICAgIH0KICAgIGlmIChkaWZmZXJlbmNlIDw9IDEpIHsKICAgICAgcmV0dXJuIHZvaWQgMDsKICAgIH0KICAgIHJldHVybiBKdWxpYW5EYXRlLmFkZFNlY29uZHMoCiAgICAgIGp1bGlhbkRhdGUsCiAgICAgIC1sZWFwU2Vjb25kc1tpbmRleCAtIDFdLm9mZnNldCwKICAgICAgcmVzdWx0CiAgICApOwogIH0KICBmdW5jdGlvbiBzZXRDb21wb25lbnRzKHdob2xlRGF5cywgc2Vjb25kc09mRGF5LCBqdWxpYW5EYXRlKSB7CiAgICBjb25zdCBleHRyYURheXMgPSBzZWNvbmRzT2ZEYXkgLyBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZIHwgMDsKICAgIHdob2xlRGF5cyArPSBleHRyYURheXM7CiAgICBzZWNvbmRzT2ZEYXkgLT0gVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0RBWSAqIGV4dHJhRGF5czsKICAgIGlmIChzZWNvbmRzT2ZEYXkgPCAwKSB7CiAgICAgIHdob2xlRGF5cy0tOwogICAgICBzZWNvbmRzT2ZEYXkgKz0gVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0RBWTsKICAgIH0KICAgIGp1bGlhbkRhdGUuZGF5TnVtYmVyID0gd2hvbGVEYXlzOwogICAganVsaWFuRGF0ZS5zZWNvbmRzT2ZEYXkgPSBzZWNvbmRzT2ZEYXk7CiAgICByZXR1cm4ganVsaWFuRGF0ZTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUp1bGlhbkRhdGVDb21wb25lbnRzKHllYXIsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtaWxsaXNlY29uZCkgewogICAgY29uc3QgYTQgPSAobW9udGggLSAxNCkgLyAxMiB8IDA7CiAgICBjb25zdCBiMiA9IHllYXIgKyA0ODAwICsgYTQ7CiAgICBsZXQgZGF5TnVtYmVyID0gKDE0NjEgKiBiMiAvIDQgfCAwKSArICgzNjcgKiAobW9udGggLSAyIC0gMTIgKiBhNCkgLyAxMiB8IDApIC0gKDMgKiAoKGIyICsgMTAwKSAvIDEwMCB8IDApIC8gNCB8IDApICsgZGF5IC0gMzIwNzU7CiAgICBob3VyID0gaG91ciAtIDEyOwogICAgaWYgKGhvdXIgPCAwKSB7CiAgICAgIGhvdXIgKz0gMjQ7CiAgICB9CiAgICBjb25zdCBzZWNvbmRzT2ZEYXkgPSBzZWNvbmQgKyAoaG91ciAqIFRpbWVDb25zdGFudHNfZGVmYXVsdC5TRUNPTkRTX1BFUl9IT1VSICsgbWludXRlICogVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX01JTlVURSArIG1pbGxpc2Vjb25kICogVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX01JTExJU0VDT05EKTsKICAgIGlmIChzZWNvbmRzT2ZEYXkgPj0gNDMyMDApIHsKICAgICAgZGF5TnVtYmVyIC09IDE7CiAgICB9CiAgICByZXR1cm4gW2RheU51bWJlciwgc2Vjb25kc09mRGF5XTsKICB9CiAgdmFyIGdyZWdvcmlhbkRhdGVTY3JhdGNoLCBkYXlzSW5Nb250aCwgZGF5c0luTGVhcEZlYnJ1YXJ5LCBiaW5hcnlTZWFyY2hTY3JhdGNoTGVhcFNlY29uZCwgbWF0Y2hDYWxlbmRhclllYXIsIG1hdGNoQ2FsZW5kYXJNb250aCwgbWF0Y2hPcmRpbmFsRGF0ZSwgbWF0Y2hXZWVrRGF0ZSwgbWF0Y2hDYWxlbmRhckRhdGUsIHV0Y09mZnNldCwgbWF0Y2hIb3VycywgbWF0Y2hIb3Vyc01pbnV0ZXMsIG1hdGNoSG91cnNNaW51dGVzU2Vjb25kcywgaXNvODYwMUVycm9yTWVzc2FnZSwgSnVsaWFuRGF0ZSwgdG9HcmVnb3JpYW5EYXRlU2NyYXRjaCwgSnVsaWFuRGF0ZV9kZWZhdWx0OwogIHZhciBpbml0X0p1bGlhbkRhdGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0p1bGlhbkRhdGUuanMiKCkgewogICAgICBpbml0X2JpbmFyeVNlYXJjaCgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0dyZWdvcmlhbkRhdGUoKTsKICAgICAgaW5pdF9pc0xlYXBZZWFyKCk7CiAgICAgIGluaXRfTGVhcFNlY29uZCgpOwogICAgICBpbml0X1RpbWVDb25zdGFudHMoKTsKICAgICAgaW5pdF9UaW1lU3RhbmRhcmQoKTsKICAgICAgZ3JlZ29yaWFuRGF0ZVNjcmF0Y2ggPSBuZXcgR3JlZ29yaWFuRGF0ZV9kZWZhdWx0KCk7CiAgICAgIGRheXNJbk1vbnRoID0gWzMxLCAyOCwgMzEsIDMwLCAzMSwgMzAsIDMxLCAzMSwgMzAsIDMxLCAzMCwgMzFdOwogICAgICBkYXlzSW5MZWFwRmVicnVhcnkgPSAyOTsKICAgICAgYmluYXJ5U2VhcmNoU2NyYXRjaExlYXBTZWNvbmQgPSBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KCk7CiAgICAgIG1hdGNoQ2FsZW5kYXJZZWFyID0gL14oXGR7NH0pJC87CiAgICAgIG1hdGNoQ2FsZW5kYXJNb250aCA9IC9eKFxkezR9KS0oXGR7Mn0pJC87CiAgICAgIG1hdGNoT3JkaW5hbERhdGUgPSAvXihcZHs0fSktPyhcZHszfSkkLzsKICAgICAgbWF0Y2hXZWVrRGF0ZSA9IC9eKFxkezR9KS0/VyhcZHsyfSktPyhcZHsxfSk/JC87CiAgICAgIG1hdGNoQ2FsZW5kYXJEYXRlID0gL14oXGR7NH0pLT8oXGR7Mn0pLT8oXGR7Mn0pJC87CiAgICAgIHV0Y09mZnNldCA9IC8oW1orXC1dKT8oXGR7Mn0pPzo/KFxkezJ9KT8kLzsKICAgICAgbWF0Y2hIb3VycyA9IC9eKFxkezJ9KShcLlxkKyk/Ly5zb3VyY2UgKyB1dGNPZmZzZXQuc291cmNlOwogICAgICBtYXRjaEhvdXJzTWludXRlcyA9IC9eKFxkezJ9KTo/KFxkezJ9KShcLlxkKyk/Ly5zb3VyY2UgKyB1dGNPZmZzZXQuc291cmNlOwogICAgICBtYXRjaEhvdXJzTWludXRlc1NlY29uZHMgPSAvXihcZHsyfSk6PyhcZHsyfSk6PyhcZHsyfSkoXC5cZCspPy8uc291cmNlICsgdXRjT2Zmc2V0LnNvdXJjZTsKICAgICAgaXNvODYwMUVycm9yTWVzc2FnZSA9ICJJbnZhbGlkIElTTyA4NjAxIGRhdGUuIjsKICAgICAgSnVsaWFuRGF0ZSA9IGNsYXNzIF9KdWxpYW5EYXRlIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2p1bGlhbkRheU51bWJlcj0wLjBdIFRoZSBKdWxpYW4gRGF5IE51bWJlciByZXByZXNlbnRpbmcgdGhlIG51bWJlciBvZiB3aG9sZSBkYXlzLiAgRnJhY3Rpb25hbCBkYXlzIHdpbGwgYWxzbyBiZSBoYW5kbGVkIGNvcnJlY3RseS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3NlY29uZHNPZkRheT0wLjBdIFRoZSBudW1iZXIgb2Ygc2Vjb25kcyBpbnRvIHRoZSBjdXJyZW50IEp1bGlhbiBEYXkgTnVtYmVyLiAgRnJhY3Rpb25hbCBzZWNvbmRzLCBuZWdhdGl2ZSBzZWNvbmRzIGFuZCBzZWNvbmRzIGdyZWF0ZXIgdGhhbiBhIGRheSB3aWxsIGJlIGhhbmRsZWQgY29ycmVjdGx5LgogICAgICAgICAqIEBwYXJhbSB7VGltZVN0YW5kYXJkfSBbdGltZVN0YW5kYXJkPVRpbWVTdGFuZGFyZC5VVENdIFRoZSB0aW1lIHN0YW5kYXJkIGluIHdoaWNoIHRoZSBmaXJzdCB0d28gcGFyYW1ldGVycyBhcmUgZGVmaW5lZC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihqdWxpYW5EYXlOdW1iZXIsIHNlY29uZHNPZkRheSwgdGltZVN0YW5kYXJkKSB7CiAgICAgICAgICB0aGlzLmRheU51bWJlciA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMuc2Vjb25kc09mRGF5ID0gdm9pZCAwOwogICAgICAgICAganVsaWFuRGF5TnVtYmVyID0ganVsaWFuRGF5TnVtYmVyID8/IDA7CiAgICAgICAgICBzZWNvbmRzT2ZEYXkgPSBzZWNvbmRzT2ZEYXkgPz8gMDsKICAgICAgICAgIHRpbWVTdGFuZGFyZCA9IHRpbWVTdGFuZGFyZCA/PyBUaW1lU3RhbmRhcmRfZGVmYXVsdC5VVEM7CiAgICAgICAgICBjb25zdCB3aG9sZURheXMgPSBqdWxpYW5EYXlOdW1iZXIgfCAwOwogICAgICAgICAgc2Vjb25kc09mRGF5ID0gc2Vjb25kc09mRGF5ICsgKGp1bGlhbkRheU51bWJlciAtIHdob2xlRGF5cykgKiBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZOwogICAgICAgICAgc2V0Q29tcG9uZW50cyh3aG9sZURheXMsIHNlY29uZHNPZkRheSwgdGhpcyk7CiAgICAgICAgICBpZiAodGltZVN0YW5kYXJkID09PSBUaW1lU3RhbmRhcmRfZGVmYXVsdC5VVEMpIHsKICAgICAgICAgICAgY29udmVydFV0Y1RvVGFpKHRoaXMpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIGZyb20gYSBHcmVnb3JpYW5EYXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtHcmVnb3JpYW5EYXRlfSBkYXRlIEEgR3JlZ29yaWFuRGF0ZS4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyZXN1bHRdIEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gZGF0ZSBtdXN0IGJlIGEgdmFsaWQgR3JlZ29yaWFuRGF0ZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUdyZWdvcmlhbkRhdGUoZGF0ZSwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIShkYXRlIGluc3RhbmNlb2YgR3JlZ29yaWFuRGF0ZV9kZWZhdWx0KSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGF0ZSBtdXN0IGJlIGEgdmFsaWQgR3JlZ29yaWFuRGF0ZS4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGNvbXBvbmVudHMgPSBjb21wdXRlSnVsaWFuRGF0ZUNvbXBvbmVudHMoCiAgICAgICAgICAgIGRhdGUueWVhciwKICAgICAgICAgICAgZGF0ZS5tb250aCwKICAgICAgICAgICAgZGF0ZS5kYXksCiAgICAgICAgICAgIGRhdGUuaG91ciwKICAgICAgICAgICAgZGF0ZS5taW51dGUsCiAgICAgICAgICAgIGRhdGUuc2Vjb25kLAogICAgICAgICAgICBkYXRlLm1pbGxpc2Vjb25kCiAgICAgICAgICApOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9KdWxpYW5EYXRlKGNvbXBvbmVudHNbMF0sIGNvbXBvbmVudHNbMV0sIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlVUQyk7CiAgICAgICAgICB9CiAgICAgICAgICBzZXRDb21wb25lbnRzKGNvbXBvbmVudHNbMF0sIGNvbXBvbmVudHNbMV0sIHJlc3VsdCk7CiAgICAgICAgICBjb252ZXJ0VXRjVG9UYWkocmVzdWx0KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgaW5zdGFuY2UgZnJvbSBhIEphdmFTY3JpcHQgRGF0ZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7RGF0ZX0gZGF0ZSBBIEphdmFTY3JpcHQgRGF0ZS4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyZXN1bHRdIEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gZGF0ZSBtdXN0IGJlIGEgdmFsaWQgSmF2YVNjcmlwdCBEYXRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tRGF0ZShkYXRlLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghKGRhdGUgaW5zdGFuY2VvZiBEYXRlKSB8fCBpc05hTihkYXRlLmdldFRpbWUoKSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRhdGUgbXVzdCBiZSBhIHZhbGlkIEphdmFTY3JpcHQgRGF0ZS4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGNvbXBvbmVudHMgPSBjb21wdXRlSnVsaWFuRGF0ZUNvbXBvbmVudHMoCiAgICAgICAgICAgIGRhdGUuZ2V0VVRDRnVsbFllYXIoKSwKICAgICAgICAgICAgZGF0ZS5nZXRVVENNb250aCgpICsgMSwKICAgICAgICAgICAgZGF0ZS5nZXRVVENEYXRlKCksCiAgICAgICAgICAgIGRhdGUuZ2V0VVRDSG91cnMoKSwKICAgICAgICAgICAgZGF0ZS5nZXRVVENNaW51dGVzKCksCiAgICAgICAgICAgIGRhdGUuZ2V0VVRDU2Vjb25kcygpLAogICAgICAgICAgICBkYXRlLmdldFVUQ01pbGxpc2Vjb25kcygpCiAgICAgICAgICApOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9KdWxpYW5EYXRlKGNvbXBvbmVudHNbMF0sIGNvbXBvbmVudHNbMV0sIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlVUQyk7CiAgICAgICAgICB9CiAgICAgICAgICBzZXRDb21wb25lbnRzKGNvbXBvbmVudHNbMF0sIGNvbXBvbmVudHNbMV0sIHJlc3VsdCk7CiAgICAgICAgICBjb252ZXJ0VXRjVG9UYWkocmVzdWx0KTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgaW5zdGFuY2UgZnJvbSBhIGZyb20gYW4ge0BsaW5rIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvSVNPXzg2MDF8SVNPIDg2MDF9IGRhdGUuCiAgICAgICAgICogVGhpcyBtZXRob2QgaXMgc3VwZXJpb3IgdG8gPGNvZGU+RGF0ZS5wYXJzZTwvY29kZT4gYmVjYXVzZSBpdCB3aWxsIGhhbmRsZSBhbGwgdmFsaWQgZm9ybWF0cyBkZWZpbmVkIGJ5IHRoZSBJU08gODYwMQogICAgICAgICAqIHNwZWNpZmljYXRpb24sIGluY2x1ZGluZyBsZWFwIHNlY29uZHMgYW5kIHN1Yi1taWxsaXNlY29uZCB0aW1lcywgd2hpY2ggZGlzY2FyZGVkIGJ5IG1vc3QgSmF2YVNjcmlwdCBpbXBsZW1lbnRhdGlvbnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gaXNvODYwMVN0cmluZyBBbiBJU08gODYwMSBkYXRlLgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gW3Jlc3VsdF0gQW4gZXhpc3RpbmcgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtKdWxpYW5EYXRlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBJbnZhbGlkIElTTyA4NjAxIGRhdGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Jc284NjAxKGlzbzg2MDFTdHJpbmcsIHJlc3VsdCkgewogICAgICAgICAgaWYgKHR5cGVvZiBpc284NjAxU3RyaW5nICE9PSAic3RyaW5nIikgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdChpc284NjAxRXJyb3JNZXNzYWdlKTsKICAgICAgICAgIH0KICAgICAgICAgIGlzbzg2MDFTdHJpbmcgPSBpc284NjAxU3RyaW5nLnJlcGxhY2UoIiwiLCAiLiIpOwogICAgICAgICAgbGV0IHRva2VucyA9IGlzbzg2MDFTdHJpbmcuc3BsaXQoIlQiKTsKICAgICAgICAgIGxldCB5ZWFyOwogICAgICAgICAgbGV0IG1vbnRoID0gMTsKICAgICAgICAgIGxldCBkYXkgPSAxOwogICAgICAgICAgbGV0IGhvdXIgPSAwOwogICAgICAgICAgbGV0IG1pbnV0ZSA9IDA7CiAgICAgICAgICBsZXQgc2Vjb25kID0gMDsKICAgICAgICAgIGxldCBtaWxsaXNlY29uZCA9IDA7CiAgICAgICAgICBjb25zdCBkYXRlID0gdG9rZW5zWzBdOwogICAgICAgICAgY29uc3QgdGltZSA9IHRva2Vuc1sxXTsKICAgICAgICAgIGxldCB0bXAyOwogICAgICAgICAgbGV0IGluTGVhcFllYXI7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkYXRlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdChpc284NjAxRXJyb3JNZXNzYWdlKTsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBkYXNoQ291bnQ7CiAgICAgICAgICB0b2tlbnMgPSBkYXRlLm1hdGNoKG1hdGNoQ2FsZW5kYXJEYXRlKTsKICAgICAgICAgIGlmICh0b2tlbnMgIT09IG51bGwpIHsKICAgICAgICAgICAgZGFzaENvdW50ID0gZGF0ZS5zcGxpdCgiLSIpLmxlbmd0aCAtIDE7CiAgICAgICAgICAgIGlmIChkYXNoQ291bnQgPiAwICYmIGRhc2hDb3VudCAhPT0gMikgewogICAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KGlzbzg2MDFFcnJvck1lc3NhZ2UpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHllYXIgPSArdG9rZW5zWzFdOwogICAgICAgICAgICBtb250aCA9ICt0b2tlbnNbMl07CiAgICAgICAgICAgIGRheSA9ICt0b2tlbnNbM107CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0b2tlbnMgPSBkYXRlLm1hdGNoKG1hdGNoQ2FsZW5kYXJNb250aCk7CiAgICAgICAgICAgIGlmICh0b2tlbnMgIT09IG51bGwpIHsKICAgICAgICAgICAgICB5ZWFyID0gK3Rva2Vuc1sxXTsKICAgICAgICAgICAgICBtb250aCA9ICt0b2tlbnNbMl07CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdG9rZW5zID0gZGF0ZS5tYXRjaChtYXRjaENhbGVuZGFyWWVhcik7CiAgICAgICAgICAgICAgaWYgKHRva2VucyAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgeWVhciA9ICt0b2tlbnNbMV07CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGxldCBkYXlPZlllYXI7CiAgICAgICAgICAgICAgICB0b2tlbnMgPSBkYXRlLm1hdGNoKG1hdGNoT3JkaW5hbERhdGUpOwogICAgICAgICAgICAgICAgaWYgKHRva2VucyAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgICB5ZWFyID0gK3Rva2Vuc1sxXTsKICAgICAgICAgICAgICAgICAgZGF5T2ZZZWFyID0gK3Rva2Vuc1syXTsKICAgICAgICAgICAgICAgICAgaW5MZWFwWWVhciA9IGlzTGVhcFllYXJfZGVmYXVsdCh5ZWFyKTsKICAgICAgICAgICAgICAgICAgaWYgKGRheU9mWWVhciA8IDEgfHwgaW5MZWFwWWVhciAmJiBkYXlPZlllYXIgPiAzNjYgfHwgIWluTGVhcFllYXIgJiYgZGF5T2ZZZWFyID4gMzY1KSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoaXNvODYwMUVycm9yTWVzc2FnZSk7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIHRva2VucyA9IGRhdGUubWF0Y2gobWF0Y2hXZWVrRGF0ZSk7CiAgICAgICAgICAgICAgICAgIGlmICh0b2tlbnMgIT09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICB5ZWFyID0gK3Rva2Vuc1sxXTsKICAgICAgICAgICAgICAgICAgICBjb25zdCB3ZWVrTnVtYmVyID0gK3Rva2Vuc1syXTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBkYXlPZldlZWsgPSArdG9rZW5zWzNdIHx8IDA7CiAgICAgICAgICAgICAgICAgICAgZGFzaENvdW50ID0gZGF0ZS5zcGxpdCgiLSIpLmxlbmd0aCAtIDE7CiAgICAgICAgICAgICAgICAgICAgaWYgKGRhc2hDb3VudCA+IDAgJiYgKCFkZWZpbmVkX2RlZmF1bHQodG9rZW5zWzNdKSAmJiBkYXNoQ291bnQgIT09IDEgfHwgZGVmaW5lZF9kZWZhdWx0KHRva2Vuc1szXSkgJiYgZGFzaENvdW50ICE9PSAyKSkgewogICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoaXNvODYwMUVycm9yTWVzc2FnZSk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGNvbnN0IGphbnVhcnk0ID0gbmV3IERhdGUoRGF0ZS5VVEMoeWVhciwgMCwgNCkpOwogICAgICAgICAgICAgICAgICAgIGRheU9mWWVhciA9IHdlZWtOdW1iZXIgKiA3ICsgZGF5T2ZXZWVrIC0gamFudWFyeTQuZ2V0VVRDRGF5KCkgLSAzOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KGlzbzg2MDFFcnJvck1lc3NhZ2UpOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB0bXAyID0gbmV3IERhdGUoRGF0ZS5VVEMoeWVhciwgMCwgMSkpOwogICAgICAgICAgICAgICAgdG1wMi5zZXRVVENEYXRlKGRheU9mWWVhcik7CiAgICAgICAgICAgICAgICBtb250aCA9IHRtcDIuZ2V0VVRDTW9udGgoKSArIDE7CiAgICAgICAgICAgICAgICBkYXkgPSB0bXAyLmdldFVUQ0RhdGUoKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGluTGVhcFllYXIgPSBpc0xlYXBZZWFyX2RlZmF1bHQoeWVhcik7CiAgICAgICAgICBpZiAobW9udGggPCAxIHx8IG1vbnRoID4gMTIgfHwgZGF5IDwgMSB8fCAobW9udGggIT09IDIgfHwgIWluTGVhcFllYXIpICYmIGRheSA+IGRheXNJbk1vbnRoW21vbnRoIC0gMV0gfHwgaW5MZWFwWWVhciAmJiBtb250aCA9PT0gMiAmJiBkYXkgPiBkYXlzSW5MZWFwRmVicnVhcnkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoaXNvODYwMUVycm9yTWVzc2FnZSk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgb2Zmc2V0SW5kZXg7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRpbWUpKSB7CiAgICAgICAgICAgIHRva2VucyA9IHRpbWUubWF0Y2gobWF0Y2hIb3Vyc01pbnV0ZXNTZWNvbmRzKTsKICAgICAgICAgICAgaWYgKHRva2VucyAhPT0gbnVsbCkgewogICAgICAgICAgICAgIGRhc2hDb3VudCA9IHRpbWUuc3BsaXQoIjoiKS5sZW5ndGggLSAxOwogICAgICAgICAgICAgIGlmIChkYXNoQ291bnQgPiAwICYmIGRhc2hDb3VudCAhPT0gMiAmJiBkYXNoQ291bnQgIT09IDMpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KGlzbzg2MDFFcnJvck1lc3NhZ2UpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBob3VyID0gK3Rva2Vuc1sxXTsKICAgICAgICAgICAgICBtaW51dGUgPSArdG9rZW5zWzJdOwogICAgICAgICAgICAgIHNlY29uZCA9ICt0b2tlbnNbM107CiAgICAgICAgICAgICAgbWlsbGlzZWNvbmQgPSArKHRva2Vuc1s0XSB8fCAwKSAqIDFlMzsKICAgICAgICAgICAgICBvZmZzZXRJbmRleCA9IDU7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdG9rZW5zID0gdGltZS5tYXRjaChtYXRjaEhvdXJzTWludXRlcyk7CiAgICAgICAgICAgICAgaWYgKHRva2VucyAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgZGFzaENvdW50ID0gdGltZS5zcGxpdCgiOiIpLmxlbmd0aCAtIDE7CiAgICAgICAgICAgICAgICBpZiAoZGFzaENvdW50ID4gMikgewogICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdChpc284NjAxRXJyb3JNZXNzYWdlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGhvdXIgPSArdG9rZW5zWzFdOwogICAgICAgICAgICAgICAgbWludXRlID0gK3Rva2Vuc1syXTsKICAgICAgICAgICAgICAgIHNlY29uZCA9ICsodG9rZW5zWzNdIHx8IDApICogNjA7CiAgICAgICAgICAgICAgICBvZmZzZXRJbmRleCA9IDQ7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHRva2VucyA9IHRpbWUubWF0Y2gobWF0Y2hIb3Vycyk7CiAgICAgICAgICAgICAgICBpZiAodG9rZW5zICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICAgIGhvdXIgPSArdG9rZW5zWzFdOwogICAgICAgICAgICAgICAgICBtaW51dGUgPSArKHRva2Vuc1syXSB8fCAwKSAqIDYwOwogICAgICAgICAgICAgICAgICBvZmZzZXRJbmRleCA9IDM7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdChpc284NjAxRXJyb3JNZXNzYWdlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKG1pbnV0ZSA+PSA2MCB8fCBzZWNvbmQgPj0gNjEgfHwgaG91ciA+IDI0IHx8IGhvdXIgPT09IDI0ICYmIChtaW51dGUgPiAwIHx8IHNlY29uZCA+IDAgfHwgbWlsbGlzZWNvbmQgPiAwKSkgewogICAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KGlzbzg2MDFFcnJvck1lc3NhZ2UpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IHRva2Vuc1tvZmZzZXRJbmRleF07CiAgICAgICAgICAgIGNvbnN0IG9mZnNldEhvdXJzID0gK3Rva2Vuc1tvZmZzZXRJbmRleCArIDFdOwogICAgICAgICAgICBjb25zdCBvZmZzZXRNaW51dGVzID0gKyh0b2tlbnNbb2Zmc2V0SW5kZXggKyAyXSB8fCAwKTsKICAgICAgICAgICAgc3dpdGNoIChvZmZzZXQpIHsKICAgICAgICAgICAgICBjYXNlICIrIjoKICAgICAgICAgICAgICAgIGhvdXIgPSBob3VyIC0gb2Zmc2V0SG91cnM7CiAgICAgICAgICAgICAgICBtaW51dGUgPSBtaW51dGUgLSBvZmZzZXRNaW51dGVzOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgY2FzZSAiLSI6CiAgICAgICAgICAgICAgICBob3VyID0gaG91ciArIG9mZnNldEhvdXJzOwogICAgICAgICAgICAgICAgbWludXRlID0gbWludXRlICsgb2Zmc2V0TWludXRlczsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIGNhc2UgIloiOgogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgIG1pbnV0ZSA9IG1pbnV0ZSArIG5ldyBEYXRlKAogICAgICAgICAgICAgICAgICBEYXRlLlVUQyh5ZWFyLCBtb250aCAtIDEsIGRheSwgaG91ciwgbWludXRlKQogICAgICAgICAgICAgICAgKS5nZXRUaW1lem9uZU9mZnNldCgpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGlzTGVhcFNlY29uZCA9IHNlY29uZCA9PT0gNjA7CiAgICAgICAgICBpZiAoaXNMZWFwU2Vjb25kKSB7CiAgICAgICAgICAgIHNlY29uZC0tOwogICAgICAgICAgfQogICAgICAgICAgd2hpbGUgKG1pbnV0ZSA+PSA2MCkgewogICAgICAgICAgICBtaW51dGUgLT0gNjA7CiAgICAgICAgICAgIGhvdXIrKzsKICAgICAgICAgIH0KICAgICAgICAgIHdoaWxlIChob3VyID49IDI0KSB7CiAgICAgICAgICAgIGhvdXIgLT0gMjQ7CiAgICAgICAgICAgIGRheSsrOwogICAgICAgICAgfQogICAgICAgICAgdG1wMiA9IGluTGVhcFllYXIgJiYgbW9udGggPT09IDIgPyBkYXlzSW5MZWFwRmVicnVhcnkgOiBkYXlzSW5Nb250aFttb250aCAtIDFdOwogICAgICAgICAgd2hpbGUgKGRheSA+IHRtcDIpIHsKICAgICAgICAgICAgZGF5IC09IHRtcDI7CiAgICAgICAgICAgIG1vbnRoKys7CiAgICAgICAgICAgIGlmIChtb250aCA+IDEyKSB7CiAgICAgICAgICAgICAgbW9udGggLT0gMTI7CiAgICAgICAgICAgICAgeWVhcisrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRtcDIgPSBpbkxlYXBZZWFyICYmIG1vbnRoID09PSAyID8gZGF5c0luTGVhcEZlYnJ1YXJ5IDogZGF5c0luTW9udGhbbW9udGggLSAxXTsKICAgICAgICAgIH0KICAgICAgICAgIHdoaWxlIChtaW51dGUgPCAwKSB7CiAgICAgICAgICAgIG1pbnV0ZSArPSA2MDsKICAgICAgICAgICAgaG91ci0tOwogICAgICAgICAgfQogICAgICAgICAgd2hpbGUgKGhvdXIgPCAwKSB7CiAgICAgICAgICAgIGhvdXIgKz0gMjQ7CiAgICAgICAgICAgIGRheS0tOwogICAgICAgICAgfQogICAgICAgICAgd2hpbGUgKGRheSA8IDEpIHsKICAgICAgICAgICAgbW9udGgtLTsKICAgICAgICAgICAgaWYgKG1vbnRoIDwgMSkgewogICAgICAgICAgICAgIG1vbnRoICs9IDEyOwogICAgICAgICAgICAgIHllYXItLTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0bXAyID0gaW5MZWFwWWVhciAmJiBtb250aCA9PT0gMiA/IGRheXNJbkxlYXBGZWJydWFyeSA6IGRheXNJbk1vbnRoW21vbnRoIC0gMV07CiAgICAgICAgICAgIGRheSArPSB0bXAyOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgY29tcG9uZW50cyA9IGNvbXB1dGVKdWxpYW5EYXRlQ29tcG9uZW50cygKICAgICAgICAgICAgeWVhciwKICAgICAgICAgICAgbW9udGgsCiAgICAgICAgICAgIGRheSwKICAgICAgICAgICAgaG91ciwKICAgICAgICAgICAgbWludXRlLAogICAgICAgICAgICBzZWNvbmQsCiAgICAgICAgICAgIG1pbGxpc2Vjb25kCiAgICAgICAgICApOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0p1bGlhbkRhdGUoY29tcG9uZW50c1swXSwgY29tcG9uZW50c1sxXSwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVVRDKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHNldENvbXBvbmVudHMoY29tcG9uZW50c1swXSwgY29tcG9uZW50c1sxXSwgcmVzdWx0KTsKICAgICAgICAgICAgY29udmVydFV0Y1RvVGFpKHJlc3VsdCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoaXNMZWFwU2Vjb25kKSB7CiAgICAgICAgICAgIF9KdWxpYW5EYXRlLmFkZFNlY29uZHMocmVzdWx0LCAxLCByZXN1bHQpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSB0aGF0IHJlcHJlc2VudHMgdGhlIGN1cnJlbnQgc3lzdGVtIHRpbWUuCiAgICAgICAgICogVGhpcyBpcyBlcXVpdmFsZW50IHRvIGNhbGxpbmcgPGNvZGU+SnVsaWFuRGF0ZS5mcm9tRGF0ZShuZXcgRGF0ZSgpKTs8L2NvZGU+LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBbcmVzdWx0XSBBbiBleGlzdGluZyBpbnN0YW5jZSB0byB1c2UgZm9yIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0p1bGlhbkRhdGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBub3cocmVzdWx0KSB7CiAgICAgICAgICByZXR1cm4gX0p1bGlhbkRhdGUuZnJvbURhdGUoLyogQF9fUFVSRV9fICovIG5ldyBEYXRlKCksIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSB7QGxpbmsgR3JlZ29yaWFuRGF0ZX0gZnJvbSB0aGUgcHJvdmlkZWQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGp1bGlhbkRhdGUgVGhlIGRhdGUgdG8gYmUgY29udmVydGVkLgogICAgICAgICAqIEBwYXJhbSB7R3JlZ29yaWFuRGF0ZX0gW3Jlc3VsdF0gQW4gZXhpc3RpbmcgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtHcmVnb3JpYW5EYXRlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdG9HcmVnb3JpYW5EYXRlKGp1bGlhbkRhdGUsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoanVsaWFuRGF0ZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImp1bGlhbkRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgaXNMZWFwU2Vjb25kID0gZmFsc2U7CiAgICAgICAgICBsZXQgdGhpc1V0YyA9IGNvbnZlcnRUYWlUb1V0YyhqdWxpYW5EYXRlLCB0b0dyZWdvcmlhbkRhdGVTY3JhdGNoKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXNVdGMpKSB7CiAgICAgICAgICAgIF9KdWxpYW5EYXRlLmFkZFNlY29uZHMoanVsaWFuRGF0ZSwgLTEsIHRvR3JlZ29yaWFuRGF0ZVNjcmF0Y2gpOwogICAgICAgICAgICB0aGlzVXRjID0gY29udmVydFRhaVRvVXRjKHRvR3JlZ29yaWFuRGF0ZVNjcmF0Y2gsIHRvR3JlZ29yaWFuRGF0ZVNjcmF0Y2gpOwogICAgICAgICAgICBpc0xlYXBTZWNvbmQgPSB0cnVlOwogICAgICAgICAgfQogICAgICAgICAgbGV0IGp1bGlhbkRheU51bWJlciA9IHRoaXNVdGMuZGF5TnVtYmVyOwogICAgICAgICAgY29uc3Qgc2Vjb25kc09mRGF5ID0gdGhpc1V0Yy5zZWNvbmRzT2ZEYXk7CiAgICAgICAgICBpZiAoc2Vjb25kc09mRGF5ID49IDQzMjAwKSB7CiAgICAgICAgICAgIGp1bGlhbkRheU51bWJlciArPSAxOwogICAgICAgICAgfQogICAgICAgICAgbGV0IEwyID0ganVsaWFuRGF5TnVtYmVyICsgNjg1NjkgfCAwOwogICAgICAgICAgY29uc3QgTjIgPSA0ICogTDIgLyAxNDYwOTcgfCAwOwogICAgICAgICAgTDIgPSBMMiAtICgoMTQ2MDk3ICogTjIgKyAzKSAvIDQgfCAwKSB8IDA7CiAgICAgICAgICBjb25zdCBJMiA9IDRlMyAqIChMMiArIDEpIC8gMTQ2MTAwMSB8IDA7CiAgICAgICAgICBMMiA9IEwyIC0gKDE0NjEgKiBJMiAvIDQgfCAwKSArIDMxIHwgMDsKICAgICAgICAgIGNvbnN0IEoyID0gODAgKiBMMiAvIDI0NDcgfCAwOwogICAgICAgICAgY29uc3QgZGF5ID0gTDIgLSAoMjQ0NyAqIEoyIC8gODAgfCAwKSB8IDA7CiAgICAgICAgICBMMiA9IEoyIC8gMTEgfCAwOwogICAgICAgICAgY29uc3QgbW9udGggPSBKMiArIDIgLSAxMiAqIEwyIHwgMDsKICAgICAgICAgIGNvbnN0IHllYXIgPSAxMDAgKiAoTjIgLSA0OSkgKyBJMiArIEwyIHwgMDsKICAgICAgICAgIGxldCBob3VyID0gc2Vjb25kc09mRGF5IC8gVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0hPVVIgfCAwOwogICAgICAgICAgbGV0IHJlbWFpbmluZ1NlY29uZHMgPSBzZWNvbmRzT2ZEYXkgLSBob3VyICogVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0hPVVI7CiAgICAgICAgICBjb25zdCBtaW51dGUgPSByZW1haW5pbmdTZWNvbmRzIC8gVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX01JTlVURSB8IDA7CiAgICAgICAgICByZW1haW5pbmdTZWNvbmRzID0gcmVtYWluaW5nU2Vjb25kcyAtIG1pbnV0ZSAqIFRpbWVDb25zdGFudHNfZGVmYXVsdC5TRUNPTkRTX1BFUl9NSU5VVEU7CiAgICAgICAgICBsZXQgc2Vjb25kID0gcmVtYWluaW5nU2Vjb25kcyB8IDA7CiAgICAgICAgICBjb25zdCBtaWxsaXNlY29uZCA9IChyZW1haW5pbmdTZWNvbmRzIC0gc2Vjb25kKSAvIFRpbWVDb25zdGFudHNfZGVmYXVsdC5TRUNPTkRTX1BFUl9NSUxMSVNFQ09ORDsKICAgICAgICAgIGhvdXIgKz0gMTI7CiAgICAgICAgICBpZiAoaG91ciA+IDIzKSB7CiAgICAgICAgICAgIGhvdXIgLT0gMjQ7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoaXNMZWFwU2Vjb25kKSB7CiAgICAgICAgICAgIHNlY29uZCArPSAxOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IEdyZWdvcmlhbkRhdGVfZGVmYXVsdCgKICAgICAgICAgICAgICB5ZWFyLAogICAgICAgICAgICAgIG1vbnRoLAogICAgICAgICAgICAgIGRheSwKICAgICAgICAgICAgICBob3VyLAogICAgICAgICAgICAgIG1pbnV0ZSwKICAgICAgICAgICAgICBzZWNvbmQsCiAgICAgICAgICAgICAgbWlsbGlzZWNvbmQsCiAgICAgICAgICAgICAgaXNMZWFwU2Vjb25kCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueWVhciA9IHllYXI7CiAgICAgICAgICByZXN1bHQubW9udGggPSBtb250aDsKICAgICAgICAgIHJlc3VsdC5kYXkgPSBkYXk7CiAgICAgICAgICByZXN1bHQuaG91ciA9IGhvdXI7CiAgICAgICAgICByZXN1bHQubWludXRlID0gbWludXRlOwogICAgICAgICAgcmVzdWx0LnNlY29uZCA9IHNlY29uZDsKICAgICAgICAgIHJlc3VsdC5taWxsaXNlY29uZCA9IG1pbGxpc2Vjb25kOwogICAgICAgICAgcmVzdWx0LmlzTGVhcFNlY29uZCA9IGlzTGVhcFNlY29uZDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBKYXZhU2NyaXB0IERhdGUgZnJvbSB0aGUgcHJvdmlkZWQgaW5zdGFuY2UuCiAgICAgICAgICogU2luY2UgSmF2YVNjcmlwdCBkYXRlcyBhcmUgb25seSBhY2N1cmF0ZSB0byB0aGUgbmVhcmVzdCBtaWxsaXNlY29uZCBhbmQKICAgICAgICAgKiBjYW5ub3QgcmVwcmVzZW50IGEgbGVhcCBzZWNvbmQsIGNvbnNpZGVyIHVzaW5nIHtAbGluayBKdWxpYW5EYXRlLnRvR3JlZ29yaWFuRGF0ZX0gaW5zdGVhZC4KICAgICAgICAgKiBJZiB0aGUgcHJvdmlkZWQgSnVsaWFuRGF0ZSBpcyBkdXJpbmcgYSBsZWFwIHNlY29uZCwgdGhlIHByZXZpb3VzIHNlY29uZCBpcyB1c2VkLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBqdWxpYW5EYXRlIFRoZSBkYXRlIHRvIGJlIGNvbnZlcnRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7RGF0ZX0gQSBuZXcgaW5zdGFuY2UgcmVwcmVzZW50aW5nIHRoZSBwcm92aWRlZCBkYXRlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0b0RhdGUoanVsaWFuRGF0ZSkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoanVsaWFuRGF0ZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImp1bGlhbkRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBnRGF0ZSA9IF9KdWxpYW5EYXRlLnRvR3JlZ29yaWFuRGF0ZShqdWxpYW5EYXRlLCBncmVnb3JpYW5EYXRlU2NyYXRjaCk7CiAgICAgICAgICBsZXQgc2Vjb25kID0gZ0RhdGUuc2Vjb25kOwogICAgICAgICAgaWYgKGdEYXRlLmlzTGVhcFNlY29uZCkgewogICAgICAgICAgICBzZWNvbmQgLT0gMTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBuZXcgRGF0ZSgKICAgICAgICAgICAgRGF0ZS5VVEMoCiAgICAgICAgICAgICAgZ0RhdGUueWVhciwKICAgICAgICAgICAgICBnRGF0ZS5tb250aCAtIDEsCiAgICAgICAgICAgICAgZ0RhdGUuZGF5LAogICAgICAgICAgICAgIGdEYXRlLmhvdXIsCiAgICAgICAgICAgICAgZ0RhdGUubWludXRlLAogICAgICAgICAgICAgIHNlY29uZCwKICAgICAgICAgICAgICBnRGF0ZS5taWxsaXNlY29uZAogICAgICAgICAgICApCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuIElTTzg2MDEgcmVwcmVzZW50YXRpb24gb2YgdGhlIHByb3ZpZGVkIGRhdGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGp1bGlhbkRhdGUgVGhlIGRhdGUgdG8gYmUgY29udmVydGVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbcHJlY2lzaW9uXSBUaGUgbnVtYmVyIG9mIGZyYWN0aW9uYWwgZGlnaXRzIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBzZWNvbmRzIGNvbXBvbmVudC4gIEJ5IGRlZmF1bHQsIHRoZSBtb3N0IHByZWNpc2UgcmVwcmVzZW50YXRpb24gaXMgdXNlZC4KICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSVNPODYwMSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcHJvdmlkZWQgZGF0ZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdG9Jc284NjAxKGp1bGlhbkRhdGUsIHByZWNpc2lvbikgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoanVsaWFuRGF0ZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImp1bGlhbkRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBnRGF0ZSA9IF9KdWxpYW5EYXRlLnRvR3JlZ29yaWFuRGF0ZShqdWxpYW5EYXRlLCBncmVnb3JpYW5EYXRlU2NyYXRjaCk7CiAgICAgICAgICBsZXQgeWVhciA9IGdEYXRlLnllYXI7CiAgICAgICAgICBsZXQgbW9udGggPSBnRGF0ZS5tb250aDsKICAgICAgICAgIGxldCBkYXkgPSBnRGF0ZS5kYXk7CiAgICAgICAgICBsZXQgaG91ciA9IGdEYXRlLmhvdXI7CiAgICAgICAgICBjb25zdCBtaW51dGUgPSBnRGF0ZS5taW51dGU7CiAgICAgICAgICBjb25zdCBzZWNvbmQgPSBnRGF0ZS5zZWNvbmQ7CiAgICAgICAgICBjb25zdCBtaWxsaXNlY29uZCA9IGdEYXRlLm1pbGxpc2Vjb25kOwogICAgICAgICAgaWYgKHllYXIgPT09IDFlNCAmJiBtb250aCA9PT0gMSAmJiBkYXkgPT09IDEgJiYgaG91ciA9PT0gMCAmJiBtaW51dGUgPT09IDAgJiYgc2Vjb25kID09PSAwICYmIG1pbGxpc2Vjb25kID09PSAwKSB7CiAgICAgICAgICAgIHllYXIgPSA5OTk5OwogICAgICAgICAgICBtb250aCA9IDEyOwogICAgICAgICAgICBkYXkgPSAzMTsKICAgICAgICAgICAgaG91ciA9IDI0OwogICAgICAgICAgfQogICAgICAgICAgbGV0IG1pbGxpc2Vjb25kU3RyOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocHJlY2lzaW9uKSAmJiBtaWxsaXNlY29uZCAhPT0gMCkgewogICAgICAgICAgICBjb25zdCBtaWxsaXNlY29uZEh1bmRyZWRzID0gbWlsbGlzZWNvbmQgKiAwLjAxOwogICAgICAgICAgICBtaWxsaXNlY29uZFN0ciA9IG1pbGxpc2Vjb25kSHVuZHJlZHMgPCAxZS02ID8gbWlsbGlzZWNvbmRIdW5kcmVkcy50b0ZpeGVkKDIwKS5yZXBsYWNlKCIuIiwgIiIpLnJlcGxhY2UoLzArJC8sICIiKSA6IG1pbGxpc2Vjb25kSHVuZHJlZHMudG9TdHJpbmcoKS5yZXBsYWNlKCIuIiwgIiIpOwogICAgICAgICAgICByZXR1cm4gYCR7eWVhci50b1N0cmluZygpLnBhZFN0YXJ0KDQsICIwIil9LSR7bW9udGgudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAiMCIpfS0ke2RheS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICIwIil9VCR7aG91ci50b1N0cmluZygpLnBhZFN0YXJ0KDIsICIwIil9OiR7bWludXRlLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgIjAiKX06JHtzZWNvbmQudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAiMCIpfS4ke21pbGxpc2Vjb25kU3RyfVpgOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocHJlY2lzaW9uKSB8fCBwcmVjaXNpb24gPT09IDApIHsKICAgICAgICAgICAgcmV0dXJuIGAke3llYXIudG9TdHJpbmcoKS5wYWRTdGFydCg0LCAiMCIpfS0ke21vbnRoLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgIjAiKX0tJHtkYXkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAiMCIpfVQke2hvdXIudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAiMCIpfToke21pbnV0ZS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICIwIil9OiR7c2Vjb25kLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgIjAiKX1aYDsKICAgICAgICAgIH0KICAgICAgICAgIG1pbGxpc2Vjb25kU3RyID0gKG1pbGxpc2Vjb25kICogMC4wMSkudG9GaXhlZChwcmVjaXNpb24pLnJlcGxhY2UoIi4iLCAiIikuc2xpY2UoMCwgcHJlY2lzaW9uKTsKICAgICAgICAgIHJldHVybiBgJHt5ZWFyLnRvU3RyaW5nKCkucGFkU3RhcnQoNCwgIjAiKX0tJHttb250aC50b1N0cmluZygpLnBhZFN0YXJ0KDIsICIwIil9LSR7ZGF5LnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgIjAiKX1UJHtob3VyLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgIjAiKX06JHttaW51dGUudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAiMCIpfToke3NlY29uZC50b1N0cmluZygpLnBhZFN0YXJ0KDIsICIwIil9LiR7bWlsbGlzZWNvbmRTdHJ9WmA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIER1cGxpY2F0ZXMgYSBKdWxpYW5EYXRlIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBqdWxpYW5EYXRlIFRoZSBkYXRlIHRvIGR1cGxpY2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyZXN1bHRdIEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuIFJldHVybnMgdW5kZWZpbmVkIGlmIGp1bGlhbkRhdGUgaXMgdW5kZWZpbmVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjbG9uZShqdWxpYW5EYXRlLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGp1bGlhbkRhdGUpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0p1bGlhbkRhdGUoCiAgICAgICAgICAgICAganVsaWFuRGF0ZS5kYXlOdW1iZXIsCiAgICAgICAgICAgICAganVsaWFuRGF0ZS5zZWNvbmRzT2ZEYXksCiAgICAgICAgICAgICAgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQuZGF5TnVtYmVyID0ganVsaWFuRGF0ZS5kYXlOdW1iZXI7CiAgICAgICAgICByZXN1bHQuc2Vjb25kc09mRGF5ID0ganVsaWFuRGF0ZS5zZWNvbmRzT2ZEYXk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0d28gaW5zdGFuY2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBsZWZ0IFRoZSBmaXJzdCBpbnN0YW5jZS4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IHJpZ2h0IFRoZSBzZWNvbmQgaW5zdGFuY2UuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gQSBuZWdhdGl2ZSB2YWx1ZSBpZiBsZWZ0IGlzIGxlc3MgdGhhbiByaWdodCwgYSBwb3NpdGl2ZSB2YWx1ZSBpZiBsZWZ0IGlzIGdyZWF0ZXIgdGhhbiByaWdodCwgb3IgemVybyBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbXBhcmUobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxlZnQpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJsZWZ0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmlnaHQpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyaWdodCBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGp1bGlhbkRheU51bWJlckRpZmZlcmVuY2UgPSBsZWZ0LmRheU51bWJlciAtIHJpZ2h0LmRheU51bWJlcjsKICAgICAgICAgIGlmIChqdWxpYW5EYXlOdW1iZXJEaWZmZXJlbmNlICE9PSAwKSB7CiAgICAgICAgICAgIHJldHVybiBqdWxpYW5EYXlOdW1iZXJEaWZmZXJlbmNlOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGxlZnQuc2Vjb25kc09mRGF5IC0gcmlnaHQuc2Vjb25kc09mRGF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0d28gaW5zdGFuY2VzIGFuZCByZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBbbGVmdF0gVGhlIGZpcnN0IGluc3RhbmNlLgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gW3JpZ2h0XSBUaGUgc2Vjb25kIGluc3RhbmNlLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgZGF0ZXMgYXJlIGVxdWFsOyBvdGhlcndpc2UsIDxjb2RlPmZhbHNlPC9jb2RlPi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgbGVmdC5kYXlOdW1iZXIgPT09IHJpZ2h0LmRheU51bWJlciAmJiBsZWZ0LnNlY29uZHNPZkRheSA9PT0gcmlnaHQuc2Vjb25kc09mRGF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0d28gaW5zdGFuY2VzIGFuZCByZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiA8Y29kZT5lcHNpbG9uPC9jb2RlPiBzZWNvbmRzIG9mCiAgICAgICAgICogZWFjaCBvdGhlci4gIFRoYXQgaXMsIGluIG9yZGVyIGZvciB0aGUgZGF0ZXMgdG8gYmUgY29uc2lkZXJlZCBlcXVhbCAoYW5kIGZvcgogICAgICAgICAqIHRoaXMgZnVuY3Rpb24gdG8gcmV0dXJuIDxjb2RlPnRydWU8L2NvZGU+KSwgdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlbSwgaW4KICAgICAgICAgKiBzZWNvbmRzLCBtdXN0IGJlIGxlc3MgdGhhbiA8Y29kZT5lcHNpbG9uPC9jb2RlPi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gW2xlZnRdIFRoZSBmaXJzdCBpbnN0YW5jZS4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyaWdodF0gVGhlIHNlY29uZCBpbnN0YW5jZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHNlY29uZHMgdGhhdCBzaG91bGQgc2VwYXJhdGUgdGhlIHR3byBpbnN0YW5jZXMuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSB0d28gZGF0ZXMgYXJlIHdpdGhpbiA8Y29kZT5lcHNpbG9uPC9jb2RlPiBzZWNvbmRzIG9mIGVhY2ggb3RoZXI7IG90aGVyd2lzZSA8Y29kZT5mYWxzZTwvY29kZT4uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0Vwc2lsb24obGVmdCwgcmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIGVwc2lsb24gPSBlcHNpbG9uID8/IDA7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgTWF0aC5hYnMoX0p1bGlhbkRhdGUuc2Vjb25kc0RpZmZlcmVuY2UobGVmdCwgcmlnaHQpKSA8PSBlcHNpbG9uOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgdG90YWwgbnVtYmVyIG9mIHdob2xlIGFuZCBmcmFjdGlvbmFsIGRheXMgcmVwcmVzZW50ZWQgYnkgdGhlIHByb3ZpZGVkIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBqdWxpYW5EYXRlIFRoZSBkYXRlLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBKdWxpYW4gZGF0ZSBhcyBzaW5nbGUgZmxvYXRpbmcgcG9pbnQgbnVtYmVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0b3RhbERheXMoanVsaWFuRGF0ZSkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoanVsaWFuRGF0ZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImp1bGlhbkRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4ganVsaWFuRGF0ZS5kYXlOdW1iZXIgKyBqdWxpYW5EYXRlLnNlY29uZHNPZkRheSAvIFRpbWVDb25zdGFudHNfZGVmYXVsdC5TRUNPTkRTX1BFUl9EQVk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBkaWZmZXJlbmNlIGluIHNlY29uZHMgYmV0d2VlbiB0aGUgcHJvdmlkZWQgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGxlZnQgVGhlIGZpcnN0IGluc3RhbmNlLgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gcmlnaHQgVGhlIHNlY29uZCBpbnN0YW5jZS4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZGlmZmVyZW5jZSwgaW4gc2Vjb25kcywgd2hlbiBzdWJ0cmFjdGluZyA8Y29kZT5yaWdodDwvY29kZT4gZnJvbSA8Y29kZT5sZWZ0PC9jb2RlPi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2Vjb25kc0RpZmZlcmVuY2UobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxlZnQpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJsZWZ0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmlnaHQpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyaWdodCBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGRheURpZmZlcmVuY2UgPSAobGVmdC5kYXlOdW1iZXIgLSByaWdodC5kYXlOdW1iZXIpICogVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0RBWTsKICAgICAgICAgIHJldHVybiBkYXlEaWZmZXJlbmNlICsgKGxlZnQuc2Vjb25kc09mRGF5IC0gcmlnaHQuc2Vjb25kc09mRGF5KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGRpZmZlcmVuY2UgaW4gZGF5cyBiZXR3ZWVuIHRoZSBwcm92aWRlZCBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gbGVmdCBUaGUgZmlyc3QgaW5zdGFuY2UuCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSByaWdodCBUaGUgc2Vjb25kIGluc3RhbmNlLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBkaWZmZXJlbmNlLCBpbiBkYXlzLCB3aGVuIHN1YnRyYWN0aW5nIDxjb2RlPnJpZ2h0PC9jb2RlPiBmcm9tIDxjb2RlPmxlZnQ8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkYXlzRGlmZmVyZW5jZShsZWZ0LCByaWdodCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobGVmdCkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImxlZnQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyaWdodCkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJpZ2h0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgZGF5RGlmZmVyZW5jZSA9IGxlZnQuZGF5TnVtYmVyIC0gcmlnaHQuZGF5TnVtYmVyOwogICAgICAgICAgY29uc3Qgc2Vjb25kRGlmZmVyZW5jZSA9IChsZWZ0LnNlY29uZHNPZkRheSAtIHJpZ2h0LnNlY29uZHNPZkRheSkgLyBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZOwogICAgICAgICAgcmV0dXJuIGRheURpZmZlcmVuY2UgKyBzZWNvbmREaWZmZXJlbmNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgbnVtYmVyIG9mIHNlY29uZHMgdGhlIHByb3ZpZGVkIGluc3RhbmNlIGlzIGFoZWFkIG9mIFVUQy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0ganVsaWFuRGF0ZSBUaGUgZGF0ZS4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbnVtYmVyIG9mIHNlY29uZHMgdGhlIHByb3ZpZGVkIGluc3RhbmNlIGlzIGFoZWFkIG9mIFVUQwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjb21wdXRlVGFpTWludXNVdGMoanVsaWFuRGF0ZSkgewogICAgICAgICAgYmluYXJ5U2VhcmNoU2NyYXRjaExlYXBTZWNvbmQuanVsaWFuRGF0ZSA9IGp1bGlhbkRhdGU7CiAgICAgICAgICBjb25zdCBsZWFwU2Vjb25kcyA9IF9KdWxpYW5EYXRlLmxlYXBTZWNvbmRzOwogICAgICAgICAgbGV0IGluZGV4ID0gYmluYXJ5U2VhcmNoX2RlZmF1bHQoCiAgICAgICAgICAgIGxlYXBTZWNvbmRzLAogICAgICAgICAgICBiaW5hcnlTZWFyY2hTY3JhdGNoTGVhcFNlY29uZCwKICAgICAgICAgICAgY29tcGFyZUxlYXBTZWNvbmREYXRlcwogICAgICAgICAgKTsKICAgICAgICAgIGlmIChpbmRleCA8IDApIHsKICAgICAgICAgICAgaW5kZXggPSB+aW5kZXg7CiAgICAgICAgICAgIC0taW5kZXg7CiAgICAgICAgICAgIGlmIChpbmRleCA8IDApIHsKICAgICAgICAgICAgICBpbmRleCA9IDA7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBsZWFwU2Vjb25kc1tpbmRleF0ub2Zmc2V0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIHRoZSBwcm92aWRlZCBudW1iZXIgb2Ygc2Vjb25kcyB0byB0aGUgcHJvdmlkZWQgZGF0ZSBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0ganVsaWFuRGF0ZSBUaGUgZGF0ZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2Vjb25kcyBUaGUgbnVtYmVyIG9mIHNlY29uZHMgdG8gYWRkIG9yIHN1YnRyYWN0LgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gcmVzdWx0IEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGFkZFNlY29uZHMoanVsaWFuRGF0ZSwgc2Vjb25kcywgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChqdWxpYW5EYXRlKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgianVsaWFuRGF0ZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHNlY29uZHMpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzZWNvbmRzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmVzdWx0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHNldENvbXBvbmVudHMoCiAgICAgICAgICAgIGp1bGlhbkRhdGUuZGF5TnVtYmVyLAogICAgICAgICAgICBqdWxpYW5EYXRlLnNlY29uZHNPZkRheSArIHNlY29uZHMsCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQWRkcyB0aGUgcHJvdmlkZWQgbnVtYmVyIG9mIG1pbnV0ZXMgdG8gdGhlIHByb3ZpZGVkIGRhdGUgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGp1bGlhbkRhdGUgVGhlIGRhdGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG1pbnV0ZXMgVGhlIG51bWJlciBvZiBtaW51dGVzIHRvIGFkZCBvciBzdWJ0cmFjdC4KICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IHJlc3VsdCBBbiBleGlzdGluZyBpbnN0YW5jZSB0byB1c2UgZm9yIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0p1bGlhbkRhdGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhZGRNaW51dGVzKGp1bGlhbkRhdGUsIG1pbnV0ZXMsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoanVsaWFuRGF0ZSkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImp1bGlhbkRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtaW51dGVzKSkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibWludXRlcyBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJlc3VsdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IG5ld1NlY29uZHNPZkRheSA9IGp1bGlhbkRhdGUuc2Vjb25kc09mRGF5ICsgbWludXRlcyAqIFRpbWVDb25zdGFudHNfZGVmYXVsdC5TRUNPTkRTX1BFUl9NSU5VVEU7CiAgICAgICAgICByZXR1cm4gc2V0Q29tcG9uZW50cyhqdWxpYW5EYXRlLmRheU51bWJlciwgbmV3U2Vjb25kc09mRGF5LCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIHRoZSBwcm92aWRlZCBudW1iZXIgb2YgaG91cnMgdG8gdGhlIHByb3ZpZGVkIGRhdGUgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGp1bGlhbkRhdGUgVGhlIGRhdGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGhvdXJzIFRoZSBudW1iZXIgb2YgaG91cnMgdG8gYWRkIG9yIHN1YnRyYWN0LgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gcmVzdWx0IEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGFkZEhvdXJzKGp1bGlhbkRhdGUsIGhvdXJzLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGp1bGlhbkRhdGUpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJqdWxpYW5EYXRlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaG91cnMpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJob3VycyBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJlc3VsdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IG5ld1NlY29uZHNPZkRheSA9IGp1bGlhbkRhdGUuc2Vjb25kc09mRGF5ICsgaG91cnMgKiBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfSE9VUjsKICAgICAgICAgIHJldHVybiBzZXRDb21wb25lbnRzKGp1bGlhbkRhdGUuZGF5TnVtYmVyLCBuZXdTZWNvbmRzT2ZEYXksIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFkZHMgdGhlIHByb3ZpZGVkIG51bWJlciBvZiBkYXlzIHRvIHRoZSBwcm92aWRlZCBkYXRlIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBqdWxpYW5EYXRlIFRoZSBkYXRlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBkYXlzIFRoZSBudW1iZXIgb2YgZGF5cyB0byBhZGQgb3Igc3VidHJhY3QuCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSByZXN1bHQgQW4gZXhpc3RpbmcgaW5zdGFuY2UgdG8gdXNlIGZvciB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtKdWxpYW5EYXRlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWRkRGF5cyhqdWxpYW5EYXRlLCBkYXlzLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGp1bGlhbkRhdGUpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJqdWxpYW5EYXRlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZGF5cykpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRheXMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyZXN1bHQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBuZXdKdWxpYW5EYXlOdW1iZXIgPSBqdWxpYW5EYXRlLmRheU51bWJlciArIGRheXM7CiAgICAgICAgICByZXR1cm4gc2V0Q29tcG9uZW50cyhuZXdKdWxpYW5EYXlOdW1iZXIsIGp1bGlhbkRhdGUuc2Vjb25kc09mRGF5LCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2VzIGFuZCByZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIDxjb2RlPmxlZnQ8L2NvZGU+IGlzIGVhcmxpZXIgdGhhbiA8Y29kZT5yaWdodDwvY29kZT4sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGxlZnQgVGhlIGZpcnN0IGluc3RhbmNlLgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gcmlnaHQgVGhlIHNlY29uZCBpbnN0YW5jZS4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgPGNvZGU+bGVmdDwvY29kZT4gaXMgZWFybGllciB0aGFuIDxjb2RlPnJpZ2h0PC9jb2RlPiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbGVzc1RoYW4obGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBfSnVsaWFuRGF0ZS5jb21wYXJlKGxlZnQsIHJpZ2h0KSA8IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBpbnN0YW5jZXMgYW5kIHJldHVybnMgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgPGNvZGU+bGVmdDwvY29kZT4gaXMgZWFybGllciB0aGFuIG9yIGVxdWFsIHRvIDxjb2RlPnJpZ2h0PC9jb2RlPiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gbGVmdCBUaGUgZmlyc3QgaW5zdGFuY2UuCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSByaWdodCBUaGUgc2Vjb25kIGluc3RhbmNlLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiA8Y29kZT5sZWZ0PC9jb2RlPiBpcyBlYXJsaWVyIHRoYW4gb3IgZXF1YWwgdG8gPGNvZGU+cmlnaHQ8L2NvZGU+LCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBsZXNzVGhhbk9yRXF1YWxzKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gX0p1bGlhbkRhdGUuY29tcGFyZShsZWZ0LCByaWdodCkgPD0gMDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIGluc3RhbmNlcyBhbmQgcmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiA8Y29kZT5sZWZ0PC9jb2RlPiBpcyBsYXRlciB0aGFuIDxjb2RlPnJpZ2h0PC9jb2RlPiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gbGVmdCBUaGUgZmlyc3QgaW5zdGFuY2UuCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSByaWdodCBUaGUgc2Vjb25kIGluc3RhbmNlLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiA8Y29kZT5sZWZ0PC9jb2RlPiBpcyBsYXRlciB0aGFuIDxjb2RlPnJpZ2h0PC9jb2RlPiwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ3JlYXRlclRoYW4obGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBfSnVsaWFuRGF0ZS5jb21wYXJlKGxlZnQsIHJpZ2h0KSA+IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBpbnN0YW5jZXMgYW5kIHJldHVybnMgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgPGNvZGU+bGVmdDwvY29kZT4gaXMgbGF0ZXIgdGhhbiBvciBlcXVhbCB0byA8Y29kZT5yaWdodDwvY29kZT4sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IGxlZnQgVGhlIGZpcnN0IGluc3RhbmNlLgogICAgICAgICAqIEBwYXJhbSB7SnVsaWFuRGF0ZX0gcmlnaHQgVGhlIHNlY29uZCBpbnN0YW5jZS4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgPGNvZGU+bGVmdDwvY29kZT4gaXMgbGF0ZXIgdGhhbiBvciBlcXVhbCB0byA8Y29kZT5yaWdodDwvY29kZT4sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdyZWF0ZXJUaGFuT3JFcXVhbHMobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBfSnVsaWFuRGF0ZS5jb21wYXJlKGxlZnQsIHJpZ2h0KSA+PSAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIHRoaXMgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyZXN1bHRdIEFuIGV4aXN0aW5nIGluc3RhbmNlIHRvIHVzZSBmb3IgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7SnVsaWFuRGF0ZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgY2xvbmUocmVzdWx0KSB7CiAgICAgICAgICByZXR1cm4gX0p1bGlhbkRhdGUuY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhpcyBhbmQgdGhlIHByb3ZpZGVkIGluc3RhbmNlIGFuZCByZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtKdWxpYW5EYXRlfSBbcmlnaHRdIFRoZSBzZWNvbmQgaW5zdGFuY2UuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBkYXRlcyBhcmUgZXF1YWw7IG90aGVyd2lzZSwgPGNvZGU+ZmFsc2U8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhyaWdodCkgewogICAgICAgICAgcmV0dXJuIF9KdWxpYW5EYXRlLmVxdWFscyh0aGlzLCByaWdodCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgYW5kIHRoZSBwcm92aWRlZCBpbnN0YW5jZSBhbmQgcmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSB3aXRoaW4gPGNvZGU+ZXBzaWxvbjwvY29kZT4gc2Vjb25kcyBvZgogICAgICAgICAqIGVhY2ggb3RoZXIuICBUaGF0IGlzLCBpbiBvcmRlciBmb3IgdGhlIGRhdGVzIHRvIGJlIGNvbnNpZGVyZWQgZXF1YWwgKGFuZCBmb3IKICAgICAgICAgKiB0aGlzIGZ1bmN0aW9uIHRvIHJldHVybiA8Y29kZT50cnVlPC9jb2RlPiksIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZW0sIGluCiAgICAgICAgICogc2Vjb25kcywgbXVzdCBiZSBsZXNzIHRoYW4gPGNvZGU+ZXBzaWxvbjwvY29kZT4uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0p1bGlhbkRhdGV9IFtyaWdodF0gVGhlIHNlY29uZCBpbnN0YW5jZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHNlY29uZHMgdGhhdCBzaG91bGQgc2VwYXJhdGUgdGhlIHR3byBpbnN0YW5jZXMuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSB0d28gZGF0ZXMgYXJlIHdpdGhpbiA8Y29kZT5lcHNpbG9uPC9jb2RlPiBzZWNvbmRzIG9mIGVhY2ggb3RoZXI7IG90aGVyd2lzZSA8Y29kZT5mYWxzZTwvY29kZT4uCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzRXBzaWxvbihyaWdodCwgZXBzaWxvbikgewogICAgICAgICAgcmV0dXJuIF9KdWxpYW5EYXRlLmVxdWFsc0Vwc2lsb24odGhpcywgcmlnaHQsIGVwc2lsb24pOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIGRhdGUgaW4gSVNPODYwMSBmb3JtYXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBkYXRlIGluIElTTzg2MDEgZm9ybWF0LgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIF9KdWxpYW5EYXRlLnRvSXNvODYwMSh0aGlzKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIHRvR3JlZ29yaWFuRGF0ZVNjcmF0Y2ggPSBuZXcgSnVsaWFuRGF0ZSgwLCAwLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpOwogICAgICBKdWxpYW5EYXRlLmxlYXBTZWNvbmRzID0gWwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0MTMxNywgNDMyMTAsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDEwKSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDE5NzIgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQxNDk5LCA0MzIxMSwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMTEpLAogICAgICAgIC8vIEp1bHkgMSwgMTk3MiAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDE2ODMsIDQzMjEyLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAxMiksCiAgICAgICAgLy8gSmFudWFyeSAxLCAxOTczIDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0MjA0OCwgNDMyMTMsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDEzKSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDE5NzQgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQyNDEzLCA0MzIxNCwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMTQpLAogICAgICAgIC8vIEphbnVhcnkgMSwgMTk3NSAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDI3NzgsIDQzMjE1LCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAxNSksCiAgICAgICAgLy8gSmFudWFyeSAxLCAxOTc2IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0MzE0NCwgNDMyMTYsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDE2KSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDE5NzcgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQzNTA5LCA0MzIxNywgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMTcpLAogICAgICAgIC8vIEphbnVhcnkgMSwgMTk3OCAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDM4NzQsIDQzMjE4LCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAxOCksCiAgICAgICAgLy8gSmFudWFyeSAxLCAxOTc5IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0NDIzOSwgNDMyMTksIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDE5KSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDE5ODAgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQ0Nzg2LCA0MzIyMCwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMjApLAogICAgICAgIC8vIEp1bHkgMSwgMTk4MSAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDUxNTEsIDQzMjIxLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAyMSksCiAgICAgICAgLy8gSnVseSAxLCAxOTgyIDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0NTUxNiwgNDMyMjIsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDIyKSwKICAgICAgICAvLyBKdWx5IDEsIDE5ODMgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQ2MjQ3LCA0MzIyMywgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMjMpLAogICAgICAgIC8vIEp1bHkgMSwgMTk4NSAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDcxNjEsIDQzMjI0LCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAyNCksCiAgICAgICAgLy8gSmFudWFyeSAxLCAxOTg4IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0Nzg5MiwgNDMyMjUsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDI1KSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDE5OTAgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQ4MjU3LCA0MzIyNiwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMjYpLAogICAgICAgIC8vIEphbnVhcnkgMSwgMTk5MSAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NDg4MDQsIDQzMjI3LCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAyNyksCiAgICAgICAgLy8gSnVseSAxLCAxOTkyIDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ0OTE2OSwgNDMyMjgsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDI4KSwKICAgICAgICAvLyBKdWx5IDEsIDE5OTMgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDQ5NTM0LCA0MzIyOSwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMjkpLAogICAgICAgIC8vIEp1bHkgMSwgMTk5NCAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NTAwODMsIDQzMjMwLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAzMCksCiAgICAgICAgLy8gSmFudWFyeSAxLCAxOTk2IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ1MDYzMCwgNDMyMzEsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDMxKSwKICAgICAgICAvLyBKdWx5IDEsIDE5OTcgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDUxMTc5LCA0MzIzMiwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMzIpLAogICAgICAgIC8vIEphbnVhcnkgMSwgMTk5OSAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NTM3MzYsIDQzMjMzLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAzMyksCiAgICAgICAgLy8gSmFudWFyeSAxLCAyMDA2IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ1NDgzMiwgNDMyMzQsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDM0KSwKICAgICAgICAvLyBKYW51YXJ5IDEsIDIwMDkgMDA6MDA6MDAgVVRDCiAgICAgICAgbmV3IExlYXBTZWNvbmRfZGVmYXVsdChuZXcgSnVsaWFuRGF0ZSgyNDU2MTA5LCA0MzIzNSwgVGltZVN0YW5kYXJkX2RlZmF1bHQuVEFJKSwgMzUpLAogICAgICAgIC8vIEp1bHkgMSwgMjAxMiAwMDowMDowMCBVVEMKICAgICAgICBuZXcgTGVhcFNlY29uZF9kZWZhdWx0KG5ldyBKdWxpYW5EYXRlKDI0NTcyMDQsIDQzMjM2LCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpLCAzNiksCiAgICAgICAgLy8gSnVseSAxLCAyMDE1IDAwOjAwOjAwIFVUQwogICAgICAgIG5ldyBMZWFwU2Vjb25kX2RlZmF1bHQobmV3IEp1bGlhbkRhdGUoMjQ1Nzc1NCwgNDMyMzcsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSksIDM3KQogICAgICAgIC8vIEphbnVhcnkgMSwgMjAxNyAwMDowMDowMCBVVEMKICAgICAgXTsKICAgICAgSnVsaWFuRGF0ZV9kZWZhdWx0ID0gSnVsaWFuRGF0ZTsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL3VyaWpzL3NyYy9wdW55Y29kZS5qcwogIHZhciByZXF1aXJlX3B1bnljb2RlID0gX19jb21tb25KUyh7CiAgICAibm9kZV9tb2R1bGVzL3VyaWpzL3NyYy9wdW55Y29kZS5qcyIoZXhwb3J0czIsIG1vZHVsZSkgewogICAgICAvKiEgaHR0cHM6Ly9tdGhzLmJlL3B1bnljb2RlIHYxLjQuMCBieSBAbWF0aGlhcyAqLwogICAgICAoZnVuY3Rpb24ocm9vdCkgewogICAgICAgIHZhciBmcmVlRXhwb3J0cyA9IHR5cGVvZiBleHBvcnRzMiA9PSAib2JqZWN0IiAmJiBleHBvcnRzMiAmJiAhZXhwb3J0czIubm9kZVR5cGUgJiYgZXhwb3J0czI7CiAgICAgICAgdmFyIGZyZWVNb2R1bGUgPSB0eXBlb2YgbW9kdWxlID09ICJvYmplY3QiICYmIG1vZHVsZSAmJiAhbW9kdWxlLm5vZGVUeXBlICYmIG1vZHVsZTsKICAgICAgICB2YXIgZnJlZUdsb2JhbCA9IHR5cGVvZiBnbG9iYWwgPT0gIm9iamVjdCIgJiYgZ2xvYmFsOwogICAgICAgIGlmIChmcmVlR2xvYmFsLmdsb2JhbCA9PT0gZnJlZUdsb2JhbCB8fCBmcmVlR2xvYmFsLndpbmRvdyA9PT0gZnJlZUdsb2JhbCB8fCBmcmVlR2xvYmFsLnNlbGYgPT09IGZyZWVHbG9iYWwpIHsKICAgICAgICAgIHJvb3QgPSBmcmVlR2xvYmFsOwogICAgICAgIH0KICAgICAgICB2YXIgcHVueWNvZGUsIG1heEludCA9IDIxNDc0ODM2NDcsIGJhc2UgPSAzNiwgdE1pbiA9IDEsIHRNYXggPSAyNiwgc2tldyA9IDM4LCBkYW1wID0gNzAwLCBpbml0aWFsQmlhcyA9IDcyLCBpbml0aWFsTiA9IDEyOCwgZGVsaW1pdGVyID0gIi0iLCByZWdleFB1bnljb2RlID0gL154bi0tLywgcmVnZXhOb25BU0NJSSA9IC9bXlx4MjAtXHg3RV0vLCByZWdleFNlcGFyYXRvcnMgPSAvW1x4MkVcdTMwMDJcdUZGMEVcdUZGNjFdL2csIGVycm9ycyA9IHsKICAgICAgICAgICJvdmVyZmxvdyI6ICJPdmVyZmxvdzogaW5wdXQgbmVlZHMgd2lkZXIgaW50ZWdlcnMgdG8gcHJvY2VzcyIsCiAgICAgICAgICAibm90LWJhc2ljIjogIklsbGVnYWwgaW5wdXQgPj0gMHg4MCAobm90IGEgYmFzaWMgY29kZSBwb2ludCkiLAogICAgICAgICAgImludmFsaWQtaW5wdXQiOiAiSW52YWxpZCBpbnB1dCIKICAgICAgICB9LCBiYXNlTWludXNUTWluID0gYmFzZSAtIHRNaW4sIGZsb29yID0gTWF0aC5mbG9vciwgc3RyaW5nRnJvbUNoYXJDb2RlID0gU3RyaW5nLmZyb21DaGFyQ29kZSwga2V5OwogICAgICAgIGZ1bmN0aW9uIGVycm9yKHR5cGUpIHsKICAgICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKGVycm9yc1t0eXBlXSk7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIG1hcChhcnJheSwgZm4pIHsKICAgICAgICAgIHZhciBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICB2YXIgcmVzdWx0ID0gW107CiAgICAgICAgICB3aGlsZSAobGVuZ3RoLS0pIHsKICAgICAgICAgICAgcmVzdWx0W2xlbmd0aF0gPSBmbihhcnJheVtsZW5ndGhdKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIG1hcERvbWFpbihzdHJpbmcsIGZuKSB7CiAgICAgICAgICB2YXIgcGFydHMgPSBzdHJpbmcuc3BsaXQoIkAiKTsKICAgICAgICAgIHZhciByZXN1bHQgPSAiIjsKICAgICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IHBhcnRzWzBdICsgIkAiOwogICAgICAgICAgICBzdHJpbmcgPSBwYXJ0c1sxXTsKICAgICAgICAgIH0KICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5yZXBsYWNlKHJlZ2V4U2VwYXJhdG9ycywgIi4iKTsKICAgICAgICAgIHZhciBsYWJlbHMgPSBzdHJpbmcuc3BsaXQoIi4iKTsKICAgICAgICAgIHZhciBlbmNvZGVkID0gbWFwKGxhYmVscywgZm4pLmpvaW4oIi4iKTsKICAgICAgICAgIHJldHVybiByZXN1bHQgKyBlbmNvZGVkOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiB1Y3MyZGVjb2RlKHN0cmluZykgewogICAgICAgICAgdmFyIG91dHB1dCA9IFtdLCBjb3VudGVyID0gMCwgbGVuZ3RoID0gc3RyaW5nLmxlbmd0aCwgdmFsdWUsIGV4dHJhOwogICAgICAgICAgd2hpbGUgKGNvdW50ZXIgPCBsZW5ndGgpIHsKICAgICAgICAgICAgdmFsdWUgPSBzdHJpbmcuY2hhckNvZGVBdChjb3VudGVyKyspOwogICAgICAgICAgICBpZiAodmFsdWUgPj0gNTUyOTYgJiYgdmFsdWUgPD0gNTYzMTkgJiYgY291bnRlciA8IGxlbmd0aCkgewogICAgICAgICAgICAgIGV4dHJhID0gc3RyaW5nLmNoYXJDb2RlQXQoY291bnRlcisrKTsKICAgICAgICAgICAgICBpZiAoKGV4dHJhICYgNjQ1MTIpID09IDU2MzIwKSB7CiAgICAgICAgICAgICAgICBvdXRwdXQucHVzaCgoKHZhbHVlICYgMTAyMykgPDwgMTApICsgKGV4dHJhICYgMTAyMykgKyA2NTUzNik7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG91dHB1dC5wdXNoKHZhbHVlKTsKICAgICAgICAgICAgICAgIGNvdW50ZXItLTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgb3V0cHV0LnB1c2godmFsdWUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gb3V0cHV0OwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiB1Y3MyZW5jb2RlKGFycmF5KSB7CiAgICAgICAgICByZXR1cm4gbWFwKGFycmF5LCBmdW5jdGlvbih2YWx1ZSkgewogICAgICAgICAgICB2YXIgb3V0cHV0ID0gIiI7CiAgICAgICAgICAgIGlmICh2YWx1ZSA+IDY1NTM1KSB7CiAgICAgICAgICAgICAgdmFsdWUgLT0gNjU1MzY7CiAgICAgICAgICAgICAgb3V0cHV0ICs9IHN0cmluZ0Zyb21DaGFyQ29kZSh2YWx1ZSA+Pj4gMTAgJiAxMDIzIHwgNTUyOTYpOwogICAgICAgICAgICAgIHZhbHVlID0gNTYzMjAgfCB2YWx1ZSAmIDEwMjM7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgb3V0cHV0ICs9IHN0cmluZ0Zyb21DaGFyQ29kZSh2YWx1ZSk7CiAgICAgICAgICAgIHJldHVybiBvdXRwdXQ7CiAgICAgICAgICB9KS5qb2luKCIiKTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gYmFzaWNUb0RpZ2l0KGNvZGVQb2ludCkgewogICAgICAgICAgaWYgKGNvZGVQb2ludCAtIDQ4IDwgMTApIHsKICAgICAgICAgICAgcmV0dXJuIGNvZGVQb2ludCAtIDIyOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGNvZGVQb2ludCAtIDY1IDwgMjYpIHsKICAgICAgICAgICAgcmV0dXJuIGNvZGVQb2ludCAtIDY1OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGNvZGVQb2ludCAtIDk3IDwgMjYpIHsKICAgICAgICAgICAgcmV0dXJuIGNvZGVQb2ludCAtIDk3OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGJhc2U7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGRpZ2l0VG9CYXNpYyhkaWdpdCwgZmxhZykgewogICAgICAgICAgcmV0dXJuIGRpZ2l0ICsgMjIgKyA3NSAqIChkaWdpdCA8IDI2KSAtICgoZmxhZyAhPSAwKSA8PCA1KTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gYWRhcHQoZGVsdGEsIG51bVBvaW50cywgZmlyc3RUaW1lKSB7CiAgICAgICAgICB2YXIgazIgPSAwOwogICAgICAgICAgZGVsdGEgPSBmaXJzdFRpbWUgPyBmbG9vcihkZWx0YSAvIGRhbXApIDogZGVsdGEgPj4gMTsKICAgICAgICAgIGRlbHRhICs9IGZsb29yKGRlbHRhIC8gbnVtUG9pbnRzKTsKICAgICAgICAgIGZvciAoOyBkZWx0YSA+IGJhc2VNaW51c1RNaW4gKiB0TWF4ID4+IDE7IGsyICs9IGJhc2UpIHsKICAgICAgICAgICAgZGVsdGEgPSBmbG9vcihkZWx0YSAvIGJhc2VNaW51c1RNaW4pOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGZsb29yKGsyICsgKGJhc2VNaW51c1RNaW4gKyAxKSAqIGRlbHRhIC8gKGRlbHRhICsgc2tldykpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBkZWNvZGUzKGlucHV0KSB7CiAgICAgICAgICB2YXIgb3V0cHV0ID0gW10sIGlucHV0TGVuZ3RoID0gaW5wdXQubGVuZ3RoLCBvdXQsIGkyID0gMCwgbjIgPSBpbml0aWFsTiwgYmlhcyA9IGluaXRpYWxCaWFzLCBiYXNpYywgajIsIGluZGV4LCBvbGRpLCB3MiwgazIsIGRpZ2l0LCB0MiwgYmFzZU1pbnVzVDsKICAgICAgICAgIGJhc2ljID0gaW5wdXQubGFzdEluZGV4T2YoZGVsaW1pdGVyKTsKICAgICAgICAgIGlmIChiYXNpYyA8IDApIHsKICAgICAgICAgICAgYmFzaWMgPSAwOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgYmFzaWM7ICsrajIpIHsKICAgICAgICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQoajIpID49IDEyOCkgewogICAgICAgICAgICAgIGVycm9yKCJub3QtYmFzaWMiKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBvdXRwdXQucHVzaChpbnB1dC5jaGFyQ29kZUF0KGoyKSk7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGluZGV4ID0gYmFzaWMgPiAwID8gYmFzaWMgKyAxIDogMDsgaW5kZXggPCBpbnB1dExlbmd0aDsgKSB7CiAgICAgICAgICAgIGZvciAob2xkaSA9IGkyLCB3MiA9IDEsIGsyID0gYmFzZTsgOyBrMiArPSBiYXNlKSB7CiAgICAgICAgICAgICAgaWYgKGluZGV4ID49IGlucHV0TGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBlcnJvcigiaW52YWxpZC1pbnB1dCIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBkaWdpdCA9IGJhc2ljVG9EaWdpdChpbnB1dC5jaGFyQ29kZUF0KGluZGV4KyspKTsKICAgICAgICAgICAgICBpZiAoZGlnaXQgPj0gYmFzZSB8fCBkaWdpdCA+IGZsb29yKChtYXhJbnQgLSBpMikgLyB3MikpIHsKICAgICAgICAgICAgICAgIGVycm9yKCJvdmVyZmxvdyIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpMiArPSBkaWdpdCAqIHcyOwogICAgICAgICAgICAgIHQyID0gazIgPD0gYmlhcyA/IHRNaW4gOiBrMiA+PSBiaWFzICsgdE1heCA/IHRNYXggOiBrMiAtIGJpYXM7CiAgICAgICAgICAgICAgaWYgKGRpZ2l0IDwgdDIpIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBiYXNlTWludXNUID0gYmFzZSAtIHQyOwogICAgICAgICAgICAgIGlmICh3MiA+IGZsb29yKG1heEludCAvIGJhc2VNaW51c1QpKSB7CiAgICAgICAgICAgICAgICBlcnJvcigib3ZlcmZsb3ciKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdzIgKj0gYmFzZU1pbnVzVDsKICAgICAgICAgICAgfQogICAgICAgICAgICBvdXQgPSBvdXRwdXQubGVuZ3RoICsgMTsKICAgICAgICAgICAgYmlhcyA9IGFkYXB0KGkyIC0gb2xkaSwgb3V0LCBvbGRpID09IDApOwogICAgICAgICAgICBpZiAoZmxvb3IoaTIgLyBvdXQpID4gbWF4SW50IC0gbjIpIHsKICAgICAgICAgICAgICBlcnJvcigib3ZlcmZsb3ciKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBuMiArPSBmbG9vcihpMiAvIG91dCk7CiAgICAgICAgICAgIGkyICU9IG91dDsKICAgICAgICAgICAgb3V0cHV0LnNwbGljZShpMisrLCAwLCBuMik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdWNzMmVuY29kZShvdXRwdXQpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBlbmNvZGUoaW5wdXQpIHsKICAgICAgICAgIHZhciBuMiwgZGVsdGEsIGhhbmRsZWRDUENvdW50LCBiYXNpY0xlbmd0aCwgYmlhcywgajIsIG0yLCBxMywgazIsIHQyLCBjdXJyZW50VmFsdWUsIG91dHB1dCA9IFtdLCBpbnB1dExlbmd0aCwgaGFuZGxlZENQQ291bnRQbHVzT25lLCBiYXNlTWludXNULCBxTWludXNUOwogICAgICAgICAgaW5wdXQgPSB1Y3MyZGVjb2RlKGlucHV0KTsKICAgICAgICAgIGlucHV0TGVuZ3RoID0gaW5wdXQubGVuZ3RoOwogICAgICAgICAgbjIgPSBpbml0aWFsTjsKICAgICAgICAgIGRlbHRhID0gMDsKICAgICAgICAgIGJpYXMgPSBpbml0aWFsQmlhczsKICAgICAgICAgIGZvciAoajIgPSAwOyBqMiA8IGlucHV0TGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICAgIGN1cnJlbnRWYWx1ZSA9IGlucHV0W2oyXTsKICAgICAgICAgICAgaWYgKGN1cnJlbnRWYWx1ZSA8IDEyOCkgewogICAgICAgICAgICAgIG91dHB1dC5wdXNoKHN0cmluZ0Zyb21DaGFyQ29kZShjdXJyZW50VmFsdWUpKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaGFuZGxlZENQQ291bnQgPSBiYXNpY0xlbmd0aCA9IG91dHB1dC5sZW5ndGg7CiAgICAgICAgICBpZiAoYmFzaWNMZW5ndGgpIHsKICAgICAgICAgICAgb3V0cHV0LnB1c2goZGVsaW1pdGVyKTsKICAgICAgICAgIH0KICAgICAgICAgIHdoaWxlIChoYW5kbGVkQ1BDb3VudCA8IGlucHV0TGVuZ3RoKSB7CiAgICAgICAgICAgIGZvciAobTIgPSBtYXhJbnQsIGoyID0gMDsgajIgPCBpbnB1dExlbmd0aDsgKytqMikgewogICAgICAgICAgICAgIGN1cnJlbnRWYWx1ZSA9IGlucHV0W2oyXTsKICAgICAgICAgICAgICBpZiAoY3VycmVudFZhbHVlID49IG4yICYmIGN1cnJlbnRWYWx1ZSA8IG0yKSB7CiAgICAgICAgICAgICAgICBtMiA9IGN1cnJlbnRWYWx1ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaGFuZGxlZENQQ291bnRQbHVzT25lID0gaGFuZGxlZENQQ291bnQgKyAxOwogICAgICAgICAgICBpZiAobTIgLSBuMiA+IGZsb29yKChtYXhJbnQgLSBkZWx0YSkgLyBoYW5kbGVkQ1BDb3VudFBsdXNPbmUpKSB7CiAgICAgICAgICAgICAgZXJyb3IoIm92ZXJmbG93Iik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGVsdGEgKz0gKG0yIC0gbjIpICogaGFuZGxlZENQQ291bnRQbHVzT25lOwogICAgICAgICAgICBuMiA9IG0yOwogICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBpbnB1dExlbmd0aDsgKytqMikgewogICAgICAgICAgICAgIGN1cnJlbnRWYWx1ZSA9IGlucHV0W2oyXTsKICAgICAgICAgICAgICBpZiAoY3VycmVudFZhbHVlIDwgbjIgJiYgKytkZWx0YSA+IG1heEludCkgewogICAgICAgICAgICAgICAgZXJyb3IoIm92ZXJmbG93Iik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChjdXJyZW50VmFsdWUgPT0gbjIpIHsKICAgICAgICAgICAgICAgIGZvciAocTMgPSBkZWx0YSwgazIgPSBiYXNlOyA7IGsyICs9IGJhc2UpIHsKICAgICAgICAgICAgICAgICAgdDIgPSBrMiA8PSBiaWFzID8gdE1pbiA6IGsyID49IGJpYXMgKyB0TWF4ID8gdE1heCA6IGsyIC0gYmlhczsKICAgICAgICAgICAgICAgICAgaWYgKHEzIDwgdDIpIHsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBxTWludXNUID0gcTMgLSB0MjsKICAgICAgICAgICAgICAgICAgYmFzZU1pbnVzVCA9IGJhc2UgLSB0MjsKICAgICAgICAgICAgICAgICAgb3V0cHV0LnB1c2goCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nRnJvbUNoYXJDb2RlKGRpZ2l0VG9CYXNpYyh0MiArIHFNaW51c1QgJSBiYXNlTWludXNULCAwKSkKICAgICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgICAgcTMgPSBmbG9vcihxTWludXNUIC8gYmFzZU1pbnVzVCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBvdXRwdXQucHVzaChzdHJpbmdGcm9tQ2hhckNvZGUoZGlnaXRUb0Jhc2ljKHEzLCAwKSkpOwogICAgICAgICAgICAgICAgYmlhcyA9IGFkYXB0KGRlbHRhLCBoYW5kbGVkQ1BDb3VudFBsdXNPbmUsIGhhbmRsZWRDUENvdW50ID09IGJhc2ljTGVuZ3RoKTsKICAgICAgICAgICAgICAgIGRlbHRhID0gMDsKICAgICAgICAgICAgICAgICsraGFuZGxlZENQQ291bnQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgICsrZGVsdGE7CiAgICAgICAgICAgICsrbjI7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gb3V0cHV0LmpvaW4oIiIpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiB0b1VuaWNvZGUoaW5wdXQpIHsKICAgICAgICAgIHJldHVybiBtYXBEb21haW4oaW5wdXQsIGZ1bmN0aW9uKHN0cmluZykgewogICAgICAgICAgICByZXR1cm4gcmVnZXhQdW55Y29kZS50ZXN0KHN0cmluZykgPyBkZWNvZGUzKHN0cmluZy5zbGljZSg0KS50b0xvd2VyQ2FzZSgpKSA6IHN0cmluZzsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiB0b0FTQ0lJKGlucHV0KSB7CiAgICAgICAgICByZXR1cm4gbWFwRG9tYWluKGlucHV0LCBmdW5jdGlvbihzdHJpbmcpIHsKICAgICAgICAgICAgcmV0dXJuIHJlZ2V4Tm9uQVNDSUkudGVzdChzdHJpbmcpID8gInhuLS0iICsgZW5jb2RlKHN0cmluZykgOiBzdHJpbmc7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcHVueWNvZGUgPSB7CiAgICAgICAgICAvKioKICAgICAgICAgICAqIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY3VycmVudCBQdW55Y29kZS5qcyB2ZXJzaW9uIG51bWJlci4KICAgICAgICAgICAqIEBtZW1iZXJPZiBwdW55Y29kZQogICAgICAgICAgICogQHR5cGUgU3RyaW5nCiAgICAgICAgICAgKi8KICAgICAgICAgICJ2ZXJzaW9uIjogIjEuMy4yIiwKICAgICAgICAgIC8qKgogICAgICAgICAgICogQW4gb2JqZWN0IG9mIG1ldGhvZHMgdG8gY29udmVydCBmcm9tIEphdmFTY3JpcHQncyBpbnRlcm5hbCBjaGFyYWN0ZXIKICAgICAgICAgICAqIHJlcHJlc2VudGF0aW9uIChVQ1MtMikgdG8gVW5pY29kZSBjb2RlIHBvaW50cywgYW5kIGJhY2suCiAgICAgICAgICAgKiBAc2VlIDxodHRwczovL21hdGhpYXNieW5lbnMuYmUvbm90ZXMvamF2YXNjcmlwdC1lbmNvZGluZz4KICAgICAgICAgICAqIEBtZW1iZXJPZiBwdW55Y29kZQogICAgICAgICAgICogQHR5cGUgT2JqZWN0CiAgICAgICAgICAgKi8KICAgICAgICAgICJ1Y3MyIjogewogICAgICAgICAgICAiZGVjb2RlIjogdWNzMmRlY29kZSwKICAgICAgICAgICAgImVuY29kZSI6IHVjczJlbmNvZGUKICAgICAgICAgIH0sCiAgICAgICAgICAiZGVjb2RlIjogZGVjb2RlMywKICAgICAgICAgICJlbmNvZGUiOiBlbmNvZGUsCiAgICAgICAgICAidG9BU0NJSSI6IHRvQVNDSUksCiAgICAgICAgICAidG9Vbmljb2RlIjogdG9Vbmljb2RlCiAgICAgICAgfTsKICAgICAgICBpZiAodHlwZW9mIGRlZmluZSA9PSAiZnVuY3Rpb24iICYmIHR5cGVvZiBkZWZpbmUuYW1kID09ICJvYmplY3QiICYmIGRlZmluZS5hbWQpIHsKICAgICAgICAgIGRlZmluZSgicHVueWNvZGUiLCBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHB1bnljb2RlOwogICAgICAgICAgfSk7CiAgICAgICAgfSBlbHNlIGlmIChmcmVlRXhwb3J0cyAmJiBmcmVlTW9kdWxlKSB7CiAgICAgICAgICBpZiAobW9kdWxlLmV4cG9ydHMgPT0gZnJlZUV4cG9ydHMpIHsKICAgICAgICAgICAgZnJlZU1vZHVsZS5leHBvcnRzID0gcHVueWNvZGU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBmb3IgKGtleSBpbiBwdW55Y29kZSkgewogICAgICAgICAgICAgIHB1bnljb2RlLmhhc093blByb3BlcnR5KGtleSkgJiYgKGZyZWVFeHBvcnRzW2tleV0gPSBwdW55Y29kZVtrZXldKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByb290LnB1bnljb2RlID0gcHVueWNvZGU7CiAgICAgICAgfQogICAgICB9KShleHBvcnRzMik7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy91cmlqcy9zcmMvSVB2Ni5qcwogIHZhciByZXF1aXJlX0lQdjYgPSBfX2NvbW1vbkpTKHsKICAgICJub2RlX21vZHVsZXMvdXJpanMvc3JjL0lQdjYuanMiKGV4cG9ydHMyLCBtb2R1bGUpIHsKICAgICAgLyohCiAgICAgICAqIFVSSS5qcyAtIE11dGF0aW5nIFVSTHMKICAgICAgICogSVB2NiBTdXBwb3J0CiAgICAgICAqCiAgICAgICAqIFZlcnNpb246IDEuMTkuMTEKICAgICAgICoKICAgICAgICogQXV0aG9yOiBSb2RuZXkgUmVobQogICAgICAgKiBXZWI6IGh0dHA6Ly9tZWRpYWxpemUuZ2l0aHViLmlvL1VSSS5qcy8KICAgICAgICoKICAgICAgICogTGljZW5zZWQgdW5kZXIKICAgICAgICogICBNSVQgTGljZW5zZSBodHRwOi8vd3d3Lm9wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNlbnNlCiAgICAgICAqCiAgICAgICAqLwogICAgICAoZnVuY3Rpb24ocm9vdCwgZmFjdG9yeSkgewogICAgICAgICJ1c2Ugc3RyaWN0IjsKICAgICAgICBpZiAodHlwZW9mIG1vZHVsZSA9PT0gIm9iamVjdCIgJiYgbW9kdWxlLmV4cG9ydHMpIHsKICAgICAgICAgIG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeSgpOwogICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gImZ1bmN0aW9uIiAmJiBkZWZpbmUuYW1kKSB7CiAgICAgICAgICBkZWZpbmUoZmFjdG9yeSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJvb3QuSVB2NiA9IGZhY3Rvcnkocm9vdCk7CiAgICAgICAgfQogICAgICB9KShleHBvcnRzMiwgZnVuY3Rpb24ocm9vdCkgewogICAgICAgICJ1c2Ugc3RyaWN0IjsKICAgICAgICB2YXIgX0lQdjYgPSByb290ICYmIHJvb3QuSVB2NjsKICAgICAgICBmdW5jdGlvbiBiZXN0UHJlc2VudGF0aW9uKGFkZHJlc3MpIHsKICAgICAgICAgIHZhciBfYWRkcmVzcyA9IGFkZHJlc3MudG9Mb3dlckNhc2UoKTsKICAgICAgICAgIHZhciBzZWdtZW50cyA9IF9hZGRyZXNzLnNwbGl0KCI6Iik7CiAgICAgICAgICB2YXIgbGVuZ3RoID0gc2VnbWVudHMubGVuZ3RoOwogICAgICAgICAgdmFyIHRvdGFsID0gODsKICAgICAgICAgIGlmIChzZWdtZW50c1swXSA9PT0gIiIgJiYgc2VnbWVudHNbMV0gPT09ICIiICYmIHNlZ21lbnRzWzJdID09PSAiIikgewogICAgICAgICAgICBzZWdtZW50cy5zaGlmdCgpOwogICAgICAgICAgICBzZWdtZW50cy5zaGlmdCgpOwogICAgICAgICAgfSBlbHNlIGlmIChzZWdtZW50c1swXSA9PT0gIiIgJiYgc2VnbWVudHNbMV0gPT09ICIiKSB7CiAgICAgICAgICAgIHNlZ21lbnRzLnNoaWZ0KCk7CiAgICAgICAgICB9IGVsc2UgaWYgKHNlZ21lbnRzW2xlbmd0aCAtIDFdID09PSAiIiAmJiBzZWdtZW50c1tsZW5ndGggLSAyXSA9PT0gIiIpIHsKICAgICAgICAgICAgc2VnbWVudHMucG9wKCk7CiAgICAgICAgICB9CiAgICAgICAgICBsZW5ndGggPSBzZWdtZW50cy5sZW5ndGg7CiAgICAgICAgICBpZiAoc2VnbWVudHNbbGVuZ3RoIC0gMV0uaW5kZXhPZigiLiIpICE9PSAtMSkgewogICAgICAgICAgICB0b3RhbCA9IDc7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgcG9zOwogICAgICAgICAgZm9yIChwb3MgPSAwOyBwb3MgPCBsZW5ndGg7IHBvcysrKSB7CiAgICAgICAgICAgIGlmIChzZWdtZW50c1twb3NdID09PSAiIikgewogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocG9zIDwgdG90YWwpIHsKICAgICAgICAgICAgc2VnbWVudHMuc3BsaWNlKHBvcywgMSwgIjAwMDAiKTsKICAgICAgICAgICAgd2hpbGUgKHNlZ21lbnRzLmxlbmd0aCA8IHRvdGFsKSB7CiAgICAgICAgICAgICAgc2VnbWVudHMuc3BsaWNlKHBvcywgMCwgIjAwMDAiKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdmFyIF9zZWdtZW50czsKICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCB0b3RhbDsgaTIrKykgewogICAgICAgICAgICBfc2VnbWVudHMgPSBzZWdtZW50c1tpMl0uc3BsaXQoIiIpOwogICAgICAgICAgICBmb3IgKHZhciBqMiA9IDA7IGoyIDwgMzsgajIrKykgewogICAgICAgICAgICAgIGlmIChfc2VnbWVudHNbMF0gPT09ICIwIiAmJiBfc2VnbWVudHMubGVuZ3RoID4gMSkgewogICAgICAgICAgICAgICAgX3NlZ21lbnRzLnNwbGljZSgwLCAxKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHNlZ21lbnRzW2kyXSA9IF9zZWdtZW50cy5qb2luKCIiKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBiZXN0ID0gLTE7CiAgICAgICAgICB2YXIgX2Jlc3QgPSAwOwogICAgICAgICAgdmFyIF9jdXJyZW50ID0gMDsKICAgICAgICAgIHZhciBjdXJyZW50ID0gLTE7CiAgICAgICAgICB2YXIgaW56ZXJvZXMgPSBmYWxzZTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHRvdGFsOyBpMisrKSB7CiAgICAgICAgICAgIGlmIChpbnplcm9lcykgewogICAgICAgICAgICAgIGlmIChzZWdtZW50c1tpMl0gPT09ICIwIikgewogICAgICAgICAgICAgICAgX2N1cnJlbnQgKz0gMTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgaW56ZXJvZXMgPSBmYWxzZTsKICAgICAgICAgICAgICAgIGlmIChfY3VycmVudCA+IF9iZXN0KSB7CiAgICAgICAgICAgICAgICAgIGJlc3QgPSBjdXJyZW50OwogICAgICAgICAgICAgICAgICBfYmVzdCA9IF9jdXJyZW50OwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBpZiAoc2VnbWVudHNbaTJdID09PSAiMCIpIHsKICAgICAgICAgICAgICAgIGluemVyb2VzID0gdHJ1ZTsKICAgICAgICAgICAgICAgIGN1cnJlbnQgPSBpMjsKICAgICAgICAgICAgICAgIF9jdXJyZW50ID0gMTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChfY3VycmVudCA+IF9iZXN0KSB7CiAgICAgICAgICAgIGJlc3QgPSBjdXJyZW50OwogICAgICAgICAgICBfYmVzdCA9IF9jdXJyZW50OwogICAgICAgICAgfQogICAgICAgICAgaWYgKF9iZXN0ID4gMSkgewogICAgICAgICAgICBzZWdtZW50cy5zcGxpY2UoYmVzdCwgX2Jlc3QsICIiKTsKICAgICAgICAgIH0KICAgICAgICAgIGxlbmd0aCA9IHNlZ21lbnRzLmxlbmd0aDsKICAgICAgICAgIHZhciByZXN1bHQgPSAiIjsKICAgICAgICAgIGlmIChzZWdtZW50c1swXSA9PT0gIiIpIHsKICAgICAgICAgICAgcmVzdWx0ID0gIjoiOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIHJlc3VsdCArPSBzZWdtZW50c1tpMl07CiAgICAgICAgICAgIGlmIChpMiA9PT0gbGVuZ3RoIC0gMSkgewogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJlc3VsdCArPSAiOiI7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoc2VnbWVudHNbbGVuZ3RoIC0gMV0gPT09ICIiKSB7CiAgICAgICAgICAgIHJlc3VsdCArPSAiOiI7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBub0NvbmZsaWN0KCkgewogICAgICAgICAgaWYgKHJvb3QuSVB2NiA9PT0gdGhpcykgewogICAgICAgICAgICByb290LklQdjYgPSBfSVB2NjsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgYmVzdDogYmVzdFByZXNlbnRhdGlvbiwKICAgICAgICAgIG5vQ29uZmxpY3QKICAgICAgICB9OwogICAgICB9KTsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL3VyaWpzL3NyYy9TZWNvbmRMZXZlbERvbWFpbnMuanMKICB2YXIgcmVxdWlyZV9TZWNvbmRMZXZlbERvbWFpbnMgPSBfX2NvbW1vbkpTKHsKICAgICJub2RlX21vZHVsZXMvdXJpanMvc3JjL1NlY29uZExldmVsRG9tYWlucy5qcyIoZXhwb3J0czIsIG1vZHVsZSkgewogICAgICAvKiEKICAgICAgICogVVJJLmpzIC0gTXV0YXRpbmcgVVJMcwogICAgICAgKiBTZWNvbmQgTGV2ZWwgRG9tYWluIChTTEQpIFN1cHBvcnQKICAgICAgICoKICAgICAgICogVmVyc2lvbjogMS4xOS4xMQogICAgICAgKgogICAgICAgKiBBdXRob3I6IFJvZG5leSBSZWhtCiAgICAgICAqIFdlYjogaHR0cDovL21lZGlhbGl6ZS5naXRodWIuaW8vVVJJLmpzLwogICAgICAgKgogICAgICAgKiBMaWNlbnNlZCB1bmRlcgogICAgICAgKiAgIE1JVCBMaWNlbnNlIGh0dHA6Ly93d3cub3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvbWl0LWxpY2Vuc2UKICAgICAgICoKICAgICAgICovCiAgICAgIChmdW5jdGlvbihyb290LCBmYWN0b3J5KSB7CiAgICAgICAgInVzZSBzdHJpY3QiOwogICAgICAgIGlmICh0eXBlb2YgbW9kdWxlID09PSAib2JqZWN0IiAmJiBtb2R1bGUuZXhwb3J0cykgewogICAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KCk7CiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSAiZnVuY3Rpb24iICYmIGRlZmluZS5hbWQpIHsKICAgICAgICAgIGRlZmluZShmYWN0b3J5KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcm9vdC5TZWNvbmRMZXZlbERvbWFpbnMgPSBmYWN0b3J5KHJvb3QpOwogICAgICAgIH0KICAgICAgfSkoZXhwb3J0czIsIGZ1bmN0aW9uKHJvb3QpIHsKICAgICAgICAidXNlIHN0cmljdCI7CiAgICAgICAgdmFyIF9TZWNvbmRMZXZlbERvbWFpbnMgPSByb290ICYmIHJvb3QuU2Vjb25kTGV2ZWxEb21haW5zOwogICAgICAgIHZhciBTTEQgPSB7CiAgICAgICAgICAvLyBsaXN0IG9mIGtub3duIFNlY29uZCBMZXZlbCBEb21haW5zCiAgICAgICAgICAvLyBjb252ZXJ0ZWQgbGlzdCBvZiBTTERzIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2dhdmluZ21pbGxlci9zZWNvbmQtbGV2ZWwtZG9tYWlucwogICAgICAgICAgLy8gLS0tLQogICAgICAgICAgLy8gcHVibGljc3VmZml4Lm9yZyBpcyBtb3JlIGN1cnJlbnQgYW5kIGFjdHVhbGx5IHVzZWQgYnkgYSBjb3VwbGUgb2YgYnJvd3NlcnMgaW50ZXJuYWxseS4KICAgICAgICAgIC8vIGRvd25zaWRlIGlzIGl0IGFsc28gY29udGFpbnMgZG9tYWlucyBsaWtlICJkeW5kbnMub3JnIiAtIHdoaWNoIGlzIGZpbmUgZm9yIHRoZSBzZWN1cml0eQogICAgICAgICAgLy8gaXNzdWVzIGJyb3dzZXIgaGF2ZSB0byBkZWFsIHdpdGggKFNPUCBmb3IgY29va2llcywgZXRjKSAtIGJ1dCBpcyB3YXkgb3ZlcmJvYXJkIGZvciBVUkkuanMKICAgICAgICAgIC8vIC0tLS0KICAgICAgICAgIGxpc3Q6IHsKICAgICAgICAgICAgImFjIjogIiBjb20gZ292IG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJhZSI6ICIgYWMgY28gZ292IG1pbCBuYW1lIG5ldCBvcmcgcHJvIHNjaCAiLAogICAgICAgICAgICAiYWYiOiAiIGNvbSBlZHUgZ292IG5ldCBvcmcgIiwKICAgICAgICAgICAgImFsIjogIiBjb20gZWR1IGdvdiBtaWwgbmV0IG9yZyAiLAogICAgICAgICAgICAiYW8iOiAiIGNvIGVkIGd2IGl0IG9nIHBiICIsCiAgICAgICAgICAgICJhciI6ICIgY29tIGVkdSBnb2IgZ292IGludCBtaWwgbmV0IG9yZyB0dXIgIiwKICAgICAgICAgICAgImF0IjogIiBhYyBjbyBndiBvciAiLAogICAgICAgICAgICAiYXUiOiAiIGFzbiBjb20gY3Npcm8gZWR1IGdvdiBpZCBuZXQgb3JnICIsCiAgICAgICAgICAgICJiYSI6ICIgY28gY29tIGVkdSBnb3YgbWlsIG5ldCBvcmcgcnMgdW5iaSB1bm1vIHVuc2EgdW50eiB1bnplICIsCiAgICAgICAgICAgICJiYiI6ICIgYml6IGNvIGNvbSBlZHUgZ292IGluZm8gbmV0IG9yZyBzdG9yZSB0diAiLAogICAgICAgICAgICAiYmgiOiAiIGJpeiBjYyBjb20gZWR1IGdvdiBpbmZvIG5ldCBvcmcgIiwKICAgICAgICAgICAgImJuIjogIiBjb20gZWR1IGdvdiBuZXQgb3JnICIsCiAgICAgICAgICAgICJibyI6ICIgY29tIGVkdSBnb2IgZ292IGludCBtaWwgbmV0IG9yZyB0diAiLAogICAgICAgICAgICAiYnIiOiAiIGFkbSBhZHYgYWdyIGFtIGFycSBhcnQgYXRvIGIgYmlvIGJsb2cgYm1kIGNpbSBjbmcgY250IGNvbSBjb29wIGVjbiBlZHUgZW5nIGVzcCBldGMgZXRpIGZhciBmbG9nIGZtIGZuZCBmb3QgZnN0IGcxMiBnZ2YgZ292IGltYiBpbmQgaW5mIGpvciBqdXMgbGVsIG1hdCBtZWQgbWlsIG11cyBuZXQgbm9tIG5vdCBudHIgb2RvIG9yZyBwcGcgcHJvIHBzYyBwc2kgcXNsIHJlYyBzbGcgc3J2IHRtcCB0cmQgdHVyIHR2IHZldCB2bG9nIHdpa2kgemxnICIsCiAgICAgICAgICAgICJicyI6ICIgY29tIGVkdSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAiYnoiOiAiIGR1IGV0IG9tIG92IHJnICIsCiAgICAgICAgICAgICJjYSI6ICIgYWIgYmMgbWIgbmIgbmYgbmwgbnMgbnQgbnUgb24gcGUgcWMgc2sgeWsgIiwKICAgICAgICAgICAgImNrIjogIiBiaXogY28gZWR1IGdlbiBnb3YgaW5mbyBuZXQgb3JnICIsCiAgICAgICAgICAgICJjbiI6ICIgYWMgYWggYmogY29tIGNxIGVkdSBmaiBnZCBnb3YgZ3MgZ3ggZ3ogaGEgaGIgaGUgaGkgaGwgaG4gamwganMganggbG4gbWlsIG5ldCBubSBueCBvcmcgcWggc2Mgc2Qgc2ggc24gc3ggdGogdHcgeGogeHogeW4gemogIiwKICAgICAgICAgICAgImNvIjogIiBjb20gZWR1IGdvdiBtaWwgbmV0IG5vbSBvcmcgIiwKICAgICAgICAgICAgImNyIjogIiBhYyBjIGNvIGVkIGZpIGdvIG9yIHNhICIsCiAgICAgICAgICAgICJjeSI6ICIgYWMgYml6IGNvbSBla2xvZ2VzIGdvdiBsdGQgbmFtZSBuZXQgb3JnIHBhcmxpYW1lbnQgcHJlc3MgcHJvIHRtICIsCiAgICAgICAgICAgICJkbyI6ICIgYXJ0IGNvbSBlZHUgZ29iIGdvdiBtaWwgbmV0IG9yZyBzbGQgd2ViICIsCiAgICAgICAgICAgICJkeiI6ICIgYXJ0IGFzc28gY29tIGVkdSBnb3YgbmV0IG9yZyBwb2wgIiwKICAgICAgICAgICAgImVjIjogIiBjb20gZWR1IGZpbiBnb3YgaW5mbyBtZWQgbWlsIG5ldCBvcmcgcHJvICIsCiAgICAgICAgICAgICJlZyI6ICIgY29tIGVkdSBldW4gZ292IG1pbCBuYW1lIG5ldCBvcmcgc2NpICIsCiAgICAgICAgICAgICJlciI6ICIgY29tIGVkdSBnb3YgaW5kIG1pbCBuZXQgb3JnIHJvY2hlc3QgdyAiLAogICAgICAgICAgICAiZXMiOiAiIGNvbSBlZHUgZ29iIG5vbSBvcmcgIiwKICAgICAgICAgICAgImV0IjogIiBiaXogY29tIGVkdSBnb3YgaW5mbyBuYW1lIG5ldCBvcmcgIiwKICAgICAgICAgICAgImZqIjogIiBhYyBiaXogY29tIGluZm8gbWlsIG5hbWUgbmV0IG9yZyBwcm8gIiwKICAgICAgICAgICAgImZrIjogIiBhYyBjbyBnb3YgbmV0IG5vbSBvcmcgIiwKICAgICAgICAgICAgImZyIjogIiBhc3NvIGNvbSBmIGdvdXYgbm9tIHByZCBwcmVzc2UgdG0gIiwKICAgICAgICAgICAgImdnIjogIiBjbyBuZXQgb3JnICIsCiAgICAgICAgICAgICJnaCI6ICIgY29tIGVkdSBnb3YgbWlsIG9yZyAiLAogICAgICAgICAgICAiZ24iOiAiIGFjIGNvbSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAiZ3IiOiAiIGNvbSBlZHUgZ292IG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJndCI6ICIgY29tIGVkdSBnb2IgaW5kIG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJndSI6ICIgY29tIGVkdSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAiaGsiOiAiIGNvbSBlZHUgZ292IGlkdiBuZXQgb3JnICIsCiAgICAgICAgICAgICJodSI6ICIgMjAwMCBhZ3JhciBib2x0IGNhc2lubyBjaXR5IGNvIGVyb3RpY2EgZXJvdGlrYSBmaWxtIGZvcnVtIGdhbWVzIGhvdGVsIGluZm8gaW5nYXRsYW4gam9nYXN6IGtvbnl2ZWxvIGxha2FzIG1lZGlhIG5ld3Mgb3JnIHByaXYgcmVrbGFtIHNleCBzaG9wIHNwb3J0IHN1bGkgc3pleCB0bSB0b3pzZGUgdXRhemFzIHZpZGVvICIsCiAgICAgICAgICAgICJpZCI6ICIgYWMgY28gZ28gbWlsIG5ldCBvciBzY2ggd2ViICIsCiAgICAgICAgICAgICJpbCI6ICIgYWMgY28gZ292IGlkZiBrMTIgbXVuaSBuZXQgb3JnICIsCiAgICAgICAgICAgICJpbiI6ICIgYWMgY28gZWR1IGVybmV0IGZpcm0gZ2VuIGdvdiBpIGluZCBtaWwgbmV0IG5pYyBvcmcgcmVzICIsCiAgICAgICAgICAgICJpcSI6ICIgY29tIGVkdSBnb3YgaSBtaWwgbmV0IG9yZyAiLAogICAgICAgICAgICAiaXIiOiAiIGFjIGNvIGRuc3NlYyBnb3YgaSBpZCBuZXQgb3JnIHNjaCAiLAogICAgICAgICAgICAiaXQiOiAiIGVkdSBnb3YgIiwKICAgICAgICAgICAgImplIjogIiBjbyBuZXQgb3JnICIsCiAgICAgICAgICAgICJqbyI6ICIgY29tIGVkdSBnb3YgbWlsIG5hbWUgbmV0IG9yZyBzY2ggIiwKICAgICAgICAgICAgImpwIjogIiBhYyBhZCBjbyBlZCBnbyBnciBsZyBuZSBvciAiLAogICAgICAgICAgICAia2UiOiAiIGFjIGNvIGdvIGluZm8gbWUgbW9iaSBuZSBvciBzYyAiLAogICAgICAgICAgICAia2giOiAiIGNvbSBlZHUgZ292IG1pbCBuZXQgb3JnIHBlciAiLAogICAgICAgICAgICAia2kiOiAiIGJpeiBjb20gZGUgZWR1IGdvdiBpbmZvIG1vYiBuZXQgb3JnIHRlbCAiLAogICAgICAgICAgICAia20iOiAiIGFzc28gY29tIGNvb3AgZWR1IGdvdXYgayBtZWRlY2luIG1pbCBub20gbm90YWlyZXMgcGhhcm1hY2llbnMgcHJlc3NlIHRtIHZldGVyaW5haXJlICIsCiAgICAgICAgICAgICJrbiI6ICIgZWR1IGdvdiBuZXQgb3JnICIsCiAgICAgICAgICAgICJrciI6ICIgYWMgYnVzYW4gY2h1bmdidWsgY2h1bmduYW0gY28gZGFlZ3UgZGFlamVvbiBlcyBnYW5nd29uIGdvIGd3YW5nanUgZ3llb25nYnVrIGd5ZW9uZ2dpIGd5ZW9uZ25hbSBocyBpbmNoZW9uIGplanUgamVvbmJ1ayBqZW9ubmFtIGsga2cgbWlsIG1zIG5lIG9yIHBlIHJlIHNjIHNlb3VsIHVsc2FuICIsCiAgICAgICAgICAgICJrdyI6ICIgY29tIGVkdSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAia3kiOiAiIGNvbSBlZHUgZ292IG5ldCBvcmcgIiwKICAgICAgICAgICAgImt6IjogIiBjb20gZWR1IGdvdiBtaWwgbmV0IG9yZyAiLAogICAgICAgICAgICAibGIiOiAiIGNvbSBlZHUgZ292IG5ldCBvcmcgIiwKICAgICAgICAgICAgImxrIjogIiBhc3NuIGNvbSBlZHUgZ292IGdycCBob3RlbCBpbnQgbHRkIG5ldCBuZ28gb3JnIHNjaCBzb2Mgd2ViICIsCiAgICAgICAgICAgICJsciI6ICIgY29tIGVkdSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAibHYiOiAiIGFzbiBjb20gY29uZiBlZHUgZ292IGlkIG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJseSI6ICIgY29tIGVkdSBnb3YgaWQgbWVkIG5ldCBvcmcgcGxjIHNjaCAiLAogICAgICAgICAgICAibWEiOiAiIGFjIGNvIGdvdiBtIG5ldCBvcmcgcHJlc3MgIiwKICAgICAgICAgICAgIm1jIjogIiBhc3NvIHRtICIsCiAgICAgICAgICAgICJtZSI6ICIgYWMgY28gZWR1IGdvdiBpdHMgbmV0IG9yZyBwcml2ICIsCiAgICAgICAgICAgICJtZyI6ICIgY29tIGVkdSBnb3YgbWlsIG5vbSBvcmcgcHJkIHRtICIsCiAgICAgICAgICAgICJtayI6ICIgY29tIGVkdSBnb3YgaW5mIG5hbWUgbmV0IG9yZyBwcm8gIiwKICAgICAgICAgICAgIm1sIjogIiBjb20gZWR1IGdvdiBuZXQgb3JnIHByZXNzZSAiLAogICAgICAgICAgICAibW4iOiAiIGVkdSBnb3Ygb3JnICIsCiAgICAgICAgICAgICJtbyI6ICIgY29tIGVkdSBnb3YgbmV0IG9yZyAiLAogICAgICAgICAgICAibXQiOiAiIGNvbSBlZHUgZ292IG5ldCBvcmcgIiwKICAgICAgICAgICAgIm12IjogIiBhZXJvIGJpeiBjb20gY29vcCBlZHUgZ292IGluZm8gaW50IG1pbCBtdXNldW0gbmFtZSBuZXQgb3JnIHBybyAiLAogICAgICAgICAgICAibXciOiAiIGFjIGNvIGNvbSBjb29wIGVkdSBnb3YgaW50IG11c2V1bSBuZXQgb3JnICIsCiAgICAgICAgICAgICJteCI6ICIgY29tIGVkdSBnb2IgbmV0IG9yZyAiLAogICAgICAgICAgICAibXkiOiAiIGNvbSBlZHUgZ292IG1pbCBuYW1lIG5ldCBvcmcgc2NoICIsCiAgICAgICAgICAgICJuZiI6ICIgYXJ0cyBjb20gZmlybSBpbmZvIG5ldCBvdGhlciBwZXIgcmVjIHN0b3JlIHdlYiAiLAogICAgICAgICAgICAibmciOiAiIGJpeiBjb20gZWR1IGdvdiBtaWwgbW9iaSBuYW1lIG5ldCBvcmcgc2NoICIsCiAgICAgICAgICAgICJuaSI6ICIgYWMgY28gY29tIGVkdSBnb2IgbWlsIG5ldCBub20gb3JnICIsCiAgICAgICAgICAgICJucCI6ICIgY29tIGVkdSBnb3YgbWlsIG5ldCBvcmcgIiwKICAgICAgICAgICAgIm5yIjogIiBiaXogY29tIGVkdSBnb3YgaW5mbyBuZXQgb3JnICIsCiAgICAgICAgICAgICJvbSI6ICIgYWMgYml6IGNvIGNvbSBlZHUgZ292IG1lZCBtaWwgbXVzZXVtIG5ldCBvcmcgcHJvIHNjaCAiLAogICAgICAgICAgICAicGUiOiAiIGNvbSBlZHUgZ29iIG1pbCBuZXQgbm9tIG9yZyBzbGQgIiwKICAgICAgICAgICAgInBoIjogIiBjb20gZWR1IGdvdiBpIG1pbCBuZXQgbmdvIG9yZyAiLAogICAgICAgICAgICAicGsiOiAiIGJpeiBjb20gZWR1IGZhbSBnb2IgZ29rIGdvbiBnb3AgZ29zIGdvdiBuZXQgb3JnIHdlYiAiLAogICAgICAgICAgICAicGwiOiAiIGFydCBiaWFseXN0b2sgYml6IGNvbSBlZHUgZ2RhIGdkYW5zayBnb3J6b3cgZ292IGluZm8ga2F0b3dpY2Uga3Jha293IGxvZHogbHVibGluIG1pbCBuZXQgbmdvIG9sc3p0eW4gb3JnIHBvem5hbiBwd3IgcmFkb20gc2x1cHNrIHN6Y3plY2luIHRvcnVuIHdhcnN6YXdhIHdhdyB3cm9jIHdyb2NsYXcgemdvcmEgIiwKICAgICAgICAgICAgInByIjogIiBhYyBiaXogY29tIGVkdSBlc3QgZ292IGluZm8gaXNsYSBuYW1lIG5ldCBvcmcgcHJvIHByb2YgIiwKICAgICAgICAgICAgInBzIjogIiBjb20gZWR1IGdvdiBuZXQgb3JnIHBsbyBzZWMgIiwKICAgICAgICAgICAgInB3IjogIiBiZWxhdSBjbyBlZCBnbyBuZSBvciAiLAogICAgICAgICAgICAicm8iOiAiIGFydHMgY29tIGZpcm0gaW5mbyBub20gbnQgb3JnIHJlYyBzdG9yZSB0bSB3d3cgIiwKICAgICAgICAgICAgInJzIjogIiBhYyBjbyBlZHUgZ292IGluIG9yZyAiLAogICAgICAgICAgICAic2IiOiAiIGNvbSBlZHUgZ292IG5ldCBvcmcgIiwKICAgICAgICAgICAgInNjIjogIiBjb20gZWR1IGdvdiBuZXQgb3JnICIsCiAgICAgICAgICAgICJzaCI6ICIgY28gY29tIGVkdSBnb3YgbmV0IG5vbSBvcmcgIiwKICAgICAgICAgICAgInNsIjogIiBjb20gZWR1IGdvdiBuZXQgb3JnICIsCiAgICAgICAgICAgICJzdCI6ICIgY28gY29tIGNvbnN1bGFkbyBlZHUgZW1iYWl4YWRhIGdvdiBtaWwgbmV0IG9yZyBwcmluY2lwZSBzYW90b21lIHN0b3JlICIsCiAgICAgICAgICAgICJzdiI6ICIgY29tIGVkdSBnb2Igb3JnIHJlZCAiLAogICAgICAgICAgICAic3oiOiAiIGFjIGNvIG9yZyAiLAogICAgICAgICAgICAidHIiOiAiIGF2IGJicyBiZWwgYml6IGNvbSBkciBlZHUgZ2VuIGdvdiBpbmZvIGsxMiBuYW1lIG5ldCBvcmcgcG9sIHRlbCB0c2sgdHYgd2ViICIsCiAgICAgICAgICAgICJ0dCI6ICIgYWVybyBiaXogY2F0IGNvIGNvbSBjb29wIGVkdSBnb3YgaW5mbyBpbnQgam9icyBtaWwgbW9iaSBtdXNldW0gbmFtZSBuZXQgb3JnIHBybyB0ZWwgdHJhdmVsICIsCiAgICAgICAgICAgICJ0dyI6ICIgY2x1YiBjb20gZWJpeiBlZHUgZ2FtZSBnb3YgaWR2IG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJtdSI6ICIgYWMgY28gY29tIGdvdiBuZXQgb3Igb3JnICIsCiAgICAgICAgICAgICJteiI6ICIgYWMgY28gZWR1IGdvdiBvcmcgIiwKICAgICAgICAgICAgIm5hIjogIiBjbyBjb20gIiwKICAgICAgICAgICAgIm56IjogIiBhYyBjbyBjcmkgZ2VlayBnZW4gZ292dCBoZWFsdGggaXdpIG1hb3JpIG1pbCBuZXQgb3JnIHBhcmxpYW1lbnQgc2Nob29sICIsCiAgICAgICAgICAgICJwYSI6ICIgYWJvIGFjIGNvbSBlZHUgZ29iIGluZyBtZWQgbmV0IG5vbSBvcmcgc2xkICIsCiAgICAgICAgICAgICJwdCI6ICIgY29tIGVkdSBnb3YgaW50IG5ldCBub21lIG9yZyBwdWJsICIsCiAgICAgICAgICAgICJweSI6ICIgY29tIGVkdSBnb3YgbWlsIG5ldCBvcmcgIiwKICAgICAgICAgICAgInFhIjogIiBjb20gZWR1IGdvdiBtaWwgbmV0IG9yZyAiLAogICAgICAgICAgICAicmUiOiAiIGFzc28gY29tIG5vbSAiLAogICAgICAgICAgICAicnUiOiAiIGFjIGFkeWdleWEgYWx0YWkgYW11ciBhcmtoYW5nZWxzayBhc3RyYWtoYW4gYmFzaGtpcmlhIGJlbGdvcm9kIGJpciBicnlhbnNrIGJ1cnlhdGlhIGNiZyBjaGVsIGNoZWx5YWJpbnNrIGNoaXRhIGNodWtvdGthIGNodXZhc2hpYSBjb20gZGFnZXN0YW4gZS1idXJnIGVkdSBnb3YgZ3Jvem55IGludCBpcmt1dHNrIGl2YW5vdm8gaXpoZXZzayBqYXIgam9zaGthci1vbGEga2FsbXlraWEga2FsdWdhIGthbWNoYXRrYSBrYXJlbGlhIGthemFuIGtjaHIga2VtZXJvdm8ga2hhYmFyb3ZzayBraGFrYXNzaWEga2h2IGtpcm92IGtvZW5pZyBrb21pIGtvc3Ryb21hIGtyYW5veWFyc2sga3ViYW4ga3VyZ2FuIGt1cnNrIGxpcGV0c2sgbWFnYWRhbiBtYXJpIG1hcmktZWwgbWFyaW5lIG1pbCBtb3Jkb3ZpYSBtb3NyZWcgbXNrIG11cm1hbnNrIG5hbGNoaWsgbmV0IG5ub3Ygbm92IG5vdm9zaWJpcnNrIG5zayBvbXNrIG9yZW5idXJnIG9yZyBvcnlvbCBwZW56YSBwZXJtIHBwIHBza292IHB0eiBybmQgcnlhemFuIHNha2hhbGluIHNhbWFyYSBzYXJhdG92IHNpbWJpcnNrIHNtb2xlbnNrIHNwYiBzdGF2cm9wb2wgc3R2IHN1cmd1dCB0YW1ib3YgdGF0YXJzdGFuIHRvbSB0b21zayB0c2FyaXRzeW4gdHNrIHR1bGEgdHV2YSB0dmVyIHR5dW1lbiB1ZG0gdWRtdXJ0aWEgdWxhbi11ZGUgdmxhZGlrYXZrYXogdmxhZGltaXIgdmxhZGl2b3N0b2sgdm9sZ29ncmFkIHZvbG9nZGEgdm9yb25lemggdnJuIHZ5YXRrYSB5YWt1dGlhIHlhbWFsIHlla2F0ZXJpbmJ1cmcgeXV6aG5vLXNha2hhbGluc2sgIiwKICAgICAgICAgICAgInJ3IjogIiBhYyBjbyBjb20gZWR1IGdvdXYgZ292IGludCBtaWwgbmV0ICIsCiAgICAgICAgICAgICJzYSI6ICIgY29tIGVkdSBnb3YgbWVkIG5ldCBvcmcgcHViIHNjaCAiLAogICAgICAgICAgICAic2QiOiAiIGNvbSBlZHUgZ292IGluZm8gbWVkIG5ldCBvcmcgdHYgIiwKICAgICAgICAgICAgInNlIjogIiBhIGFjIGIgYmQgYyBkIGUgZiBnIGggaSBrIGwgbSBuIG8gb3JnIHAgcGFydGkgcHAgcHJlc3MgciBzIHQgdG0gdSB3IHggeSB6ICIsCiAgICAgICAgICAgICJzZyI6ICIgY29tIGVkdSBnb3YgaWRuIG5ldCBvcmcgcGVyICIsCiAgICAgICAgICAgICJzbiI6ICIgYXJ0IGNvbSBlZHUgZ291diBvcmcgcGVyc28gdW5pdiAiLAogICAgICAgICAgICAic3kiOiAiIGNvbSBlZHUgZ292IG1pbCBuZXQgbmV3cyBvcmcgIiwKICAgICAgICAgICAgInRoIjogIiBhYyBjbyBnbyBpbiBtaSBuZXQgb3IgIiwKICAgICAgICAgICAgInRqIjogIiBhYyBiaXogY28gY29tIGVkdSBnbyBnb3YgaW5mbyBpbnQgbWlsIG5hbWUgbmV0IG5pYyBvcmcgdGVzdCB3ZWIgIiwKICAgICAgICAgICAgInRuIjogIiBhZ3JpbmV0IGNvbSBkZWZlbnNlIGVkdW5ldCBlbnMgZmluIGdvdiBpbmQgaW5mbyBpbnRsIG1pbmNvbSBuYXQgbmV0IG9yZyBwZXJzbyBybnJ0IHJucyBybnUgdG91cmlzbSAiLAogICAgICAgICAgICAidHoiOiAiIGFjIGNvIGdvIG5lIG9yICIsCiAgICAgICAgICAgICJ1YSI6ICIgYml6IGNoZXJrYXNzeSBjaGVybmlnb3YgY2hlcm5vdnRzeSBjayBjbiBjbyBjb20gY3JpbWVhIGN2IGRuIGRuZXByb3BldHJvdnNrIGRvbmV0c2sgZHAgZWR1IGdvdiBpZiBpbiBpdmFuby1mcmFua2l2c2sga2gga2hhcmtvdiBraGVyc29uIGtobWVsbml0c2tpeSBraWV2IGtpcm92b2dyYWQga20ga3Iga3Mga3YgbGcgbHVnYW5zayBsdXRzayBsdml2IG1lIG1rIG5ldCBuaWtvbGFldiBvZCBvZGVzc2Egb3JnIHBsIHBvbHRhdmEgcHAgcm92bm8gcnYgc2ViYXN0b3BvbCBzdW15IHRlIHRlcm5vcGlsIHV6aGdvcm9kIHZpbm5pY2Egdm4gemFwb3Jpemh6aGUgemhpdG9taXIgenAgenQgIiwKICAgICAgICAgICAgInVnIjogIiBhYyBjbyBnbyBuZSBvciBvcmcgc2MgIiwKICAgICAgICAgICAgInVrIjogIiBhYyBibCBicml0aXNoLWxpYnJhcnkgY28gY3ltIGdvdiBnb3Z0IGljbmV0IGpldCBsZWEgbHRkIG1lIG1pbCBtb2QgbmF0aW9uYWwtbGlicmFyeS1zY290bGFuZCBuZWwgbmV0IG5ocyBuaWMgbmxzIG9yZyBvcmduIHBhcmxpYW1lbnQgcGxjIHBvbGljZSBzY2ggc2NvdCBzb2MgIiwKICAgICAgICAgICAgInVzIjogIiBkbmkgZmVkIGlzYSBraWRzIG5zbiAiLAogICAgICAgICAgICAidXkiOiAiIGNvbSBlZHUgZ3ViIG1pbCBuZXQgb3JnICIsCiAgICAgICAgICAgICJ2ZSI6ICIgY28gY29tIGVkdSBnb2IgaW5mbyBtaWwgbmV0IG9yZyB3ZWIgIiwKICAgICAgICAgICAgInZpIjogIiBjbyBjb20gazEyIG5ldCBvcmcgIiwKICAgICAgICAgICAgInZuIjogIiBhYyBiaXogY29tIGVkdSBnb3YgaGVhbHRoIGluZm8gaW50IG5hbWUgbmV0IG9yZyBwcm8gIiwKICAgICAgICAgICAgInllIjogIiBjbyBjb20gZ292IGx0ZCBtZSBuZXQgb3JnIHBsYyAiLAogICAgICAgICAgICAieXUiOiAiIGFjIGNvIGVkdSBnb3Ygb3JnICIsCiAgICAgICAgICAgICJ6YSI6ICIgYWMgYWdyaWMgYWx0IGJvdXJzZSBjaXR5IGNvIGN5YmVybmV0IGRiIGVkdSBnb3YgZ3JvbmRhciBpYWNjZXNzIGltdCBpbmNhIGxhbmRlc2lnbiBsYXcgbWlsIG5ldCBuZ28gbmlzIG5vbSBvbGl2ZXR0aSBvcmcgcGl4IHNjaG9vbCB0bSB3ZWIgIiwKICAgICAgICAgICAgInptIjogIiBhYyBjbyBjb20gZWR1IGdvdiBuZXQgb3JnIHNjaCAiLAogICAgICAgICAgICAvLyBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DZW50cmFsTmljI1NlY29uZC1sZXZlbF9kb21haW5zCiAgICAgICAgICAgICJjb20iOiAiYXIgYnIgY24gZGUgZXUgZ2IgZ3IgaHUganBuIGtyIG5vIHFjIHJ1IHNhIHNlIHVrIHVzIHV5IHphICIsCiAgICAgICAgICAgICJuZXQiOiAiZ2IganAgc2UgdWsgIiwKICAgICAgICAgICAgIm9yZyI6ICJhZSIsCiAgICAgICAgICAgICJkZSI6ICJjb20gIgogICAgICAgICAgfSwKICAgICAgICAgIC8vIGdvcmhpbGwgMjAxMy0xMC0yNTogVXNpbmcgaW5kZXhPZigpIGluc3RlYWQgUmVnZXhwKCkuIFNpZ25pZmljYW50IGJvb3N0CiAgICAgICAgICAvLyBpbiBib3RoIHBlcmZvcm1hbmNlIGFuZCBtZW1vcnkgZm9vdHByaW50LiBObyBpbml0aWFsaXphdGlvbiByZXF1aXJlZC4KICAgICAgICAgIC8vIGh0dHA6Ly9qc3BlcmYuY29tL3VyaS1qcy1zbGQtcmVnZXgtdnMtYmluYXJ5LXNlYXJjaC80CiAgICAgICAgICAvLyBGb2xsb3dpbmcgbWV0aG9kcyB1c2UgbGFzdEluZGV4T2YoKSByYXRoZXIgdGhhbiBhcnJheS5zcGxpdCgpIGluIG9yZGVyCiAgICAgICAgICAvLyB0byBhdm9pZCBhbnkgbWVtb3J5IGFsbG9jYXRpb25zLgogICAgICAgICAgaGFzOiBmdW5jdGlvbihkb21haW4pIHsKICAgICAgICAgICAgdmFyIHRsZE9mZnNldCA9IGRvbWFpbi5sYXN0SW5kZXhPZigiLiIpOwogICAgICAgICAgICBpZiAodGxkT2Zmc2V0IDw9IDAgfHwgdGxkT2Zmc2V0ID49IGRvbWFpbi5sZW5ndGggLSAxKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzbGRPZmZzZXQgPSBkb21haW4ubGFzdEluZGV4T2YoIi4iLCB0bGRPZmZzZXQgLSAxKTsKICAgICAgICAgICAgaWYgKHNsZE9mZnNldCA8PSAwIHx8IHNsZE9mZnNldCA+PSB0bGRPZmZzZXQgLSAxKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzbGRMaXN0ID0gU0xELmxpc3RbZG9tYWluLnNsaWNlKHRsZE9mZnNldCArIDEpXTsKICAgICAgICAgICAgaWYgKCFzbGRMaXN0KSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBzbGRMaXN0LmluZGV4T2YoIiAiICsgZG9tYWluLnNsaWNlKHNsZE9mZnNldCArIDEsIHRsZE9mZnNldCkgKyAiICIpID49IDA7CiAgICAgICAgICB9LAogICAgICAgICAgaXM6IGZ1bmN0aW9uKGRvbWFpbikgewogICAgICAgICAgICB2YXIgdGxkT2Zmc2V0ID0gZG9tYWluLmxhc3RJbmRleE9mKCIuIik7CiAgICAgICAgICAgIGlmICh0bGRPZmZzZXQgPD0gMCB8fCB0bGRPZmZzZXQgPj0gZG9tYWluLmxlbmd0aCAtIDEpIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHNsZE9mZnNldCA9IGRvbWFpbi5sYXN0SW5kZXhPZigiLiIsIHRsZE9mZnNldCAtIDEpOwogICAgICAgICAgICBpZiAoc2xkT2Zmc2V0ID49IDApIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHNsZExpc3QgPSBTTEQubGlzdFtkb21haW4uc2xpY2UodGxkT2Zmc2V0ICsgMSldOwogICAgICAgICAgICBpZiAoIXNsZExpc3QpIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHNsZExpc3QuaW5kZXhPZigiICIgKyBkb21haW4uc2xpY2UoMCwgdGxkT2Zmc2V0KSArICIgIikgPj0gMDsKICAgICAgICAgIH0sCiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKGRvbWFpbikgewogICAgICAgICAgICB2YXIgdGxkT2Zmc2V0ID0gZG9tYWluLmxhc3RJbmRleE9mKCIuIik7CiAgICAgICAgICAgIGlmICh0bGRPZmZzZXQgPD0gMCB8fCB0bGRPZmZzZXQgPj0gZG9tYWluLmxlbmd0aCAtIDEpIHsKICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgc2xkT2Zmc2V0ID0gZG9tYWluLmxhc3RJbmRleE9mKCIuIiwgdGxkT2Zmc2V0IC0gMSk7CiAgICAgICAgICAgIGlmIChzbGRPZmZzZXQgPD0gMCB8fCBzbGRPZmZzZXQgPj0gdGxkT2Zmc2V0IC0gMSkgewogICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzbGRMaXN0ID0gU0xELmxpc3RbZG9tYWluLnNsaWNlKHRsZE9mZnNldCArIDEpXTsKICAgICAgICAgICAgaWYgKCFzbGRMaXN0KSB7CiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHNsZExpc3QuaW5kZXhPZigiICIgKyBkb21haW4uc2xpY2Uoc2xkT2Zmc2V0ICsgMSwgdGxkT2Zmc2V0KSArICIgIikgPCAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGRvbWFpbi5zbGljZShzbGRPZmZzZXQgKyAxKTsKICAgICAgICAgIH0sCiAgICAgICAgICBub0NvbmZsaWN0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgaWYgKHJvb3QuU2Vjb25kTGV2ZWxEb21haW5zID09PSB0aGlzKSB7CiAgICAgICAgICAgICAgcm9vdC5TZWNvbmRMZXZlbERvbWFpbnMgPSBfU2Vjb25kTGV2ZWxEb21haW5zOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgcmV0dXJuIFNMRDsKICAgICAgfSk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy91cmlqcy9zcmMvVVJJLmpzCiAgdmFyIHJlcXVpcmVfVVJJID0gX19jb21tb25KUyh7CiAgICAibm9kZV9tb2R1bGVzL3VyaWpzL3NyYy9VUkkuanMiKGV4cG9ydHMyLCBtb2R1bGUpIHsKICAgICAgLyohCiAgICAgICAqIFVSSS5qcyAtIE11dGF0aW5nIFVSTHMKICAgICAgICoKICAgICAgICogVmVyc2lvbjogMS4xOS4xMQogICAgICAgKgogICAgICAgKiBBdXRob3I6IFJvZG5leSBSZWhtCiAgICAgICAqIFdlYjogaHR0cDovL21lZGlhbGl6ZS5naXRodWIuaW8vVVJJLmpzLwogICAgICAgKgogICAgICAgKiBMaWNlbnNlZCB1bmRlcgogICAgICAgKiAgIE1JVCBMaWNlbnNlIGh0dHA6Ly93d3cub3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvbWl0LWxpY2Vuc2UKICAgICAgICoKICAgICAgICovCiAgICAgIChmdW5jdGlvbihyb290LCBmYWN0b3J5KSB7CiAgICAgICAgInVzZSBzdHJpY3QiOwogICAgICAgIGlmICh0eXBlb2YgbW9kdWxlID09PSAib2JqZWN0IiAmJiBtb2R1bGUuZXhwb3J0cykgewogICAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KHJlcXVpcmVfcHVueWNvZGUoKSwgcmVxdWlyZV9JUHY2KCksIHJlcXVpcmVfU2Vjb25kTGV2ZWxEb21haW5zKCkpOwogICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gImZ1bmN0aW9uIiAmJiBkZWZpbmUuYW1kKSB7CiAgICAgICAgICBkZWZpbmUoWyIuL3B1bnljb2RlIiwgIi4vSVB2NiIsICIuL1NlY29uZExldmVsRG9tYWlucyJdLCBmYWN0b3J5KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcm9vdC5VUkkgPSBmYWN0b3J5KHJvb3QucHVueWNvZGUsIHJvb3QuSVB2Niwgcm9vdC5TZWNvbmRMZXZlbERvbWFpbnMsIHJvb3QpOwogICAgICAgIH0KICAgICAgfSkoZXhwb3J0czIsIGZ1bmN0aW9uKHB1bnljb2RlLCBJUHY2LCBTTEQsIHJvb3QpIHsKICAgICAgICAidXNlIHN0cmljdCI7CiAgICAgICAgdmFyIF9VUkkgPSByb290ICYmIHJvb3QuVVJJOwogICAgICAgIGZ1bmN0aW9uIFVSSSh1cmwsIGJhc2UpIHsKICAgICAgICAgIHZhciBfdXJsU3VwcGxpZWQgPSBhcmd1bWVudHMubGVuZ3RoID49IDE7CiAgICAgICAgICB2YXIgX2Jhc2VTdXBwbGllZCA9IGFyZ3VtZW50cy5sZW5ndGggPj0gMjsKICAgICAgICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBVUkkpKSB7CiAgICAgICAgICAgIGlmIChfdXJsU3VwcGxpZWQpIHsKICAgICAgICAgICAgICBpZiAoX2Jhc2VTdXBwbGllZCkgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBVUkkodXJsLCBiYXNlKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIG5ldyBVUkkodXJsKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbmV3IFVSSSgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHVybCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIGlmIChfdXJsU3VwcGxpZWQpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJ1bmRlZmluZWQgaXMgbm90IGEgdmFsaWQgYXJndW1lbnQgZm9yIFVSSSIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh0eXBlb2YgbG9jYXRpb24gIT09ICJ1bmRlZmluZWQiKSB7CiAgICAgICAgICAgICAgdXJsID0gbG9jYXRpb24uaHJlZiArICIiOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHVybCA9ICIiOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodXJsID09PSBudWxsKSB7CiAgICAgICAgICAgIGlmIChfdXJsU3VwcGxpZWQpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJudWxsIGlzIG5vdCBhIHZhbGlkIGFyZ3VtZW50IGZvciBVUkkiKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdGhpcy5ocmVmKHVybCk7CiAgICAgICAgICBpZiAoYmFzZSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLmFic29sdXRlVG8oYmFzZSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gaXNJbnRlZ2VyKHZhbHVlKSB7CiAgICAgICAgICByZXR1cm4gL15bMC05XSskLy50ZXN0KHZhbHVlKTsKICAgICAgICB9CiAgICAgICAgVVJJLnZlcnNpb24gPSAiMS4xOS4xMSI7CiAgICAgICAgdmFyIHAyID0gVVJJLnByb3RvdHlwZTsKICAgICAgICB2YXIgaGFzT3duID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTsKICAgICAgICBmdW5jdGlvbiBlc2NhcGVSZWdFeChzdHJpbmcpIHsKICAgICAgICAgIHJldHVybiBzdHJpbmcucmVwbGFjZSgvKFsuKis/Xj0hOiR7fSgpfFtcXVwvXFxdKS9nLCAiXFwkMSIpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBnZXRUeXBlKHZhbHVlKSB7CiAgICAgICAgICBpZiAodmFsdWUgPT09IHZvaWQgMCkgewogICAgICAgICAgICByZXR1cm4gIlVuZGVmaW5lZCI7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gU3RyaW5nKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSkpLnNsaWNlKDgsIC0xKTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gaXNBcnJheShvYmopIHsKICAgICAgICAgIHJldHVybiBnZXRUeXBlKG9iaikgPT09ICJBcnJheSI7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGZpbHRlckFycmF5VmFsdWVzKGRhdGEsIHZhbHVlKSB7CiAgICAgICAgICB2YXIgbG9va3VwID0ge307CiAgICAgICAgICB2YXIgaTIsIGxlbmd0aDsKICAgICAgICAgIGlmIChnZXRUeXBlKHZhbHVlKSA9PT0gIlJlZ0V4cCIpIHsKICAgICAgICAgICAgbG9va3VwID0gbnVsbDsKICAgICAgICAgIH0gZWxzZSBpZiAoaXNBcnJheSh2YWx1ZSkpIHsKICAgICAgICAgICAgZm9yIChpMiA9IDAsIGxlbmd0aCA9IHZhbHVlLmxlbmd0aDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgICBsb29rdXBbdmFsdWVbaTJdXSA9IHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGxvb2t1cFt2YWx1ZV0gPSB0cnVlOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChpMiA9IDAsIGxlbmd0aCA9IGRhdGEubGVuZ3RoOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICB2YXIgX21hdGNoID0gbG9va3VwICYmIGxvb2t1cFtkYXRhW2kyXV0gIT09IHZvaWQgMCB8fCAhbG9va3VwICYmIHZhbHVlLnRlc3QoZGF0YVtpMl0pOwogICAgICAgICAgICBpZiAoX21hdGNoKSB7CiAgICAgICAgICAgICAgZGF0YS5zcGxpY2UoaTIsIDEpOwogICAgICAgICAgICAgIGxlbmd0aC0tOwogICAgICAgICAgICAgIGkyLS07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBkYXRhOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBhcnJheUNvbnRhaW5zKGxpc3QsIHZhbHVlKSB7CiAgICAgICAgICB2YXIgaTIsIGxlbmd0aDsKICAgICAgICAgIGlmIChpc0FycmF5KHZhbHVlKSkgewogICAgICAgICAgICBmb3IgKGkyID0gMCwgbGVuZ3RoID0gdmFsdWUubGVuZ3RoOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICAgIGlmICghYXJyYXlDb250YWlucyhsaXN0LCB2YWx1ZVtpMl0pKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgfQogICAgICAgICAgdmFyIF90eXBlID0gZ2V0VHlwZSh2YWx1ZSk7CiAgICAgICAgICBmb3IgKGkyID0gMCwgbGVuZ3RoID0gbGlzdC5sZW5ndGg7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIGlmIChfdHlwZSA9PT0gIlJlZ0V4cCIpIHsKICAgICAgICAgICAgICBpZiAodHlwZW9mIGxpc3RbaTJdID09PSAic3RyaW5nIiAmJiBsaXN0W2kyXS5tYXRjaCh2YWx1ZSkpIHsKICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmIChsaXN0W2kyXSA9PT0gdmFsdWUpIHsKICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBhcnJheXNFcXVhbChvbmUsIHR3bykgewogICAgICAgICAgaWYgKCFpc0FycmF5KG9uZSkgfHwgIWlzQXJyYXkodHdvKSkgewogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAob25lLmxlbmd0aCAhPT0gdHdvLmxlbmd0aCkgewogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICB9CiAgICAgICAgICBvbmUuc29ydCgpOwogICAgICAgICAgdHdvLnNvcnQoKTsKICAgICAgICAgIGZvciAodmFyIGkyID0gMCwgbDIgPSBvbmUubGVuZ3RoOyBpMiA8IGwyOyBpMisrKSB7CiAgICAgICAgICAgIGlmIChvbmVbaTJdICE9PSB0d29baTJdKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gdHJpbVNsYXNoZXModGV4dCkgewogICAgICAgICAgdmFyIHRyaW1fZXhwcmVzc2lvbiA9IC9eXC8rfFwvKyQvZzsKICAgICAgICAgIHJldHVybiB0ZXh0LnJlcGxhY2UodHJpbV9leHByZXNzaW9uLCAiIik7CiAgICAgICAgfQogICAgICAgIFVSSS5fcGFydHMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIHByb3RvY29sOiBudWxsLAogICAgICAgICAgICB1c2VybmFtZTogbnVsbCwKICAgICAgICAgICAgcGFzc3dvcmQ6IG51bGwsCiAgICAgICAgICAgIGhvc3RuYW1lOiBudWxsLAogICAgICAgICAgICB1cm46IG51bGwsCiAgICAgICAgICAgIHBvcnQ6IG51bGwsCiAgICAgICAgICAgIHBhdGg6IG51bGwsCiAgICAgICAgICAgIHF1ZXJ5OiBudWxsLAogICAgICAgICAgICBmcmFnbWVudDogbnVsbCwKICAgICAgICAgICAgLy8gc3RhdGUKICAgICAgICAgICAgcHJldmVudEludmFsaWRIb3N0bmFtZTogVVJJLnByZXZlbnRJbnZhbGlkSG9zdG5hbWUsCiAgICAgICAgICAgIGR1cGxpY2F0ZVF1ZXJ5UGFyYW1ldGVyczogVVJJLmR1cGxpY2F0ZVF1ZXJ5UGFyYW1ldGVycywKICAgICAgICAgICAgZXNjYXBlUXVlcnlTcGFjZTogVVJJLmVzY2FwZVF1ZXJ5U3BhY2UKICAgICAgICAgIH07CiAgICAgICAgfTsKICAgICAgICBVUkkucHJldmVudEludmFsaWRIb3N0bmFtZSA9IGZhbHNlOwogICAgICAgIFVSSS5kdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMgPSBmYWxzZTsKICAgICAgICBVUkkuZXNjYXBlUXVlcnlTcGFjZSA9IHRydWU7CiAgICAgICAgVVJJLnByb3RvY29sX2V4cHJlc3Npb24gPSAvXlthLXpdW2EtejAtOS4rLV0qJC9pOwogICAgICAgIFVSSS5pZG5fZXhwcmVzc2lvbiA9IC9bXmEtejAtOVwuXy1dL2k7CiAgICAgICAgVVJJLnB1bnljb2RlX2V4cHJlc3Npb24gPSAvKHhuLS0pL2k7CiAgICAgICAgVVJJLmlwNF9leHByZXNzaW9uID0gL15cZHsxLDN9XC5cZHsxLDN9XC5cZHsxLDN9XC5cZHsxLDN9JC87CiAgICAgICAgVVJJLmlwNl9leHByZXNzaW9uID0gL15ccyooKChbMC05QS1GYS1mXXsxLDR9Oil7N30oWzAtOUEtRmEtZl17MSw0fXw6KSl8KChbMC05QS1GYS1mXXsxLDR9Oil7Nn0oOlswLTlBLUZhLWZdezEsNH18KCgyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKShcLigyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKSl7M30pfDopKXwoKFswLTlBLUZhLWZdezEsNH06KXs1fSgoKDpbMC05QS1GYS1mXXsxLDR9KXsxLDJ9KXw6KCgyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKShcLigyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKSl7M30pfDopKXwoKFswLTlBLUZhLWZdezEsNH06KXs0fSgoKDpbMC05QS1GYS1mXXsxLDR9KXsxLDN9KXwoKDpbMC05QS1GYS1mXXsxLDR9KT86KCgyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKShcLigyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKSl7M30pKXw6KSl8KChbMC05QS1GYS1mXXsxLDR9Oil7M30oKCg6WzAtOUEtRmEtZl17MSw0fSl7MSw0fSl8KCg6WzAtOUEtRmEtZl17MSw0fSl7MCwyfTooKDI1WzAtNV18MlswLTRdXGR8MVxkXGR8WzEtOV0/XGQpKFwuKDI1WzAtNV18MlswLTRdXGR8MVxkXGR8WzEtOV0/XGQpKXszfSkpfDopKXwoKFswLTlBLUZhLWZdezEsNH06KXsyfSgoKDpbMC05QS1GYS1mXXsxLDR9KXsxLDV9KXwoKDpbMC05QS1GYS1mXXsxLDR9KXswLDN9OigoMjVbMC01XXwyWzAtNF1cZHwxXGRcZHxbMS05XT9cZCkoXC4oMjVbMC01XXwyWzAtNF1cZHwxXGRcZHxbMS05XT9cZCkpezN9KSl8OikpfCgoWzAtOUEtRmEtZl17MSw0fTopezF9KCgoOlswLTlBLUZhLWZdezEsNH0pezEsNn0pfCgoOlswLTlBLUZhLWZdezEsNH0pezAsNH06KCgyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKShcLigyNVswLTVdfDJbMC00XVxkfDFcZFxkfFsxLTldP1xkKSl7M30pKXw6KSl8KDooKCg6WzAtOUEtRmEtZl17MSw0fSl7MSw3fSl8KCg6WzAtOUEtRmEtZl17MSw0fSl7MCw1fTooKDI1WzAtNV18MlswLTRdXGR8MVxkXGR8WzEtOV0/XGQpKFwuKDI1WzAtNV18MlswLTRdXGR8MVxkXGR8WzEtOV0/XGQpKXszfSkpfDopKSkoJS4rKT9ccyokLzsKICAgICAgICBVUkkuZmluZF91cmlfZXhwcmVzc2lvbiA9IC9cYigoPzpbYS16XVtcdy1dKzooPzpcL3sxLDN9fFthLXowLTklXSl8d3d3XGR7MCwzfVsuXXxbYS16MC05LlwtXStbLl1bYS16XXsyLDR9XC8pKD86W15ccygpPD5dK3xcKChbXlxzKCk8Pl0rfChcKFteXHMoKTw+XStcKSkpKlwpKSsoPzpcKChbXlxzKCk8Pl0rfChcKFteXHMoKTw+XStcKSkpKlwpfFteXHNgISgpXFtcXXt9OzonIi4sPD4/wqvCu+KAnOKAneKAmOKAmV0pKS9pZzsKICAgICAgICBVUkkuZmluZFVyaSA9IHsKICAgICAgICAgIC8vIHZhbGlkICJzY2hlbWU6Ly8iIG9yICJ3d3cuIgogICAgICAgICAgc3RhcnQ6IC9cYig/OihbYS16XVthLXowLTkuKy1dKjpcL1wvKXx3d3dcLikvZ2ksCiAgICAgICAgICAvLyBldmVyeXRoaW5nIHVwIHRvIHRoZSBuZXh0IHdoaXRlc3BhY2UKICAgICAgICAgIGVuZDogL1tcc1xyXG5dfCQvLAogICAgICAgICAgLy8gdHJpbSB0cmFpbGluZyBwdW5jdHVhdGlvbiBjYXB0dXJlZCBieSBlbmQgUmVnRXhwCiAgICAgICAgICB0cmltOiAvW2AhKClcW1xde307OiciLiw8Pj/Cq8K74oCc4oCd4oCe4oCY4oCZXSskLywKICAgICAgICAgIC8vIGJhbGFuY2VkIHBhcmVucyBpbmNsdXNpb24gKCksIFtdLCB7fSwgPD4KICAgICAgICAgIHBhcmVuczogLyhcKFteXCldKlwpfFxbW15cXV0qXF18XHtbXn1dKlx9fDxbXj5dKj4pL2cKICAgICAgICB9OwogICAgICAgIFVSSS5sZWFkaW5nX3doaXRlc3BhY2VfZXhwcmVzc2lvbiA9IC9eW1x4MDAtXHgyMFx1MDBhMFx1MTY4MFx1MjAwMC1cdTIwMGFcdTIwMjhcdTIwMjlcdTIwMmZcdTIwNWZcdTMwMDBcdWZlZmZdKy87CiAgICAgICAgVVJJLmFzY2lpX3RhYl93aGl0ZXNwYWNlID0gL1tcdTAwMDlcdTAwMEFcdTAwMERdKy9nOwogICAgICAgIFVSSS5kZWZhdWx0UG9ydHMgPSB7CiAgICAgICAgICBodHRwOiAiODAiLAogICAgICAgICAgaHR0cHM6ICI0NDMiLAogICAgICAgICAgZnRwOiAiMjEiLAogICAgICAgICAgZ29waGVyOiAiNzAiLAogICAgICAgICAgd3M6ICI4MCIsCiAgICAgICAgICB3c3M6ICI0NDMiCiAgICAgICAgfTsKICAgICAgICBVUkkuaG9zdFByb3RvY29scyA9IFsKICAgICAgICAgICJodHRwIiwKICAgICAgICAgICJodHRwcyIKICAgICAgICBdOwogICAgICAgIFVSSS5pbnZhbGlkX2hvc3RuYW1lX2NoYXJhY3RlcnMgPSAvW15hLXpBLVowLTlcLlwtOl9dLzsKICAgICAgICBVUkkuZG9tQXR0cmlidXRlcyA9IHsKICAgICAgICAgICJhIjogImhyZWYiLAogICAgICAgICAgImJsb2NrcXVvdGUiOiAiY2l0ZSIsCiAgICAgICAgICAibGluayI6ICJocmVmIiwKICAgICAgICAgICJiYXNlIjogImhyZWYiLAogICAgICAgICAgInNjcmlwdCI6ICJzcmMiLAogICAgICAgICAgImZvcm0iOiAiYWN0aW9uIiwKICAgICAgICAgICJpbWciOiAic3JjIiwKICAgICAgICAgICJhcmVhIjogImhyZWYiLAogICAgICAgICAgImlmcmFtZSI6ICJzcmMiLAogICAgICAgICAgImVtYmVkIjogInNyYyIsCiAgICAgICAgICAic291cmNlIjogInNyYyIsCiAgICAgICAgICAidHJhY2siOiAic3JjIiwKICAgICAgICAgICJpbnB1dCI6ICJzcmMiLAogICAgICAgICAgLy8gYnV0IG9ubHkgaWYgdHlwZT0iaW1hZ2UiCiAgICAgICAgICAiYXVkaW8iOiAic3JjIiwKICAgICAgICAgICJ2aWRlbyI6ICJzcmMiCiAgICAgICAgfTsKICAgICAgICBVUkkuZ2V0RG9tQXR0cmlidXRlID0gZnVuY3Rpb24obm9kZSkgewogICAgICAgICAgaWYgKCFub2RlIHx8ICFub2RlLm5vZGVOYW1lKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgbm9kZU5hbWUgPSBub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7CiAgICAgICAgICBpZiAobm9kZU5hbWUgPT09ICJpbnB1dCIgJiYgbm9kZS50eXBlICE9PSAiaW1hZ2UiKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gVVJJLmRvbUF0dHJpYnV0ZXNbbm9kZU5hbWVdOwogICAgICAgIH07CiAgICAgICAgZnVuY3Rpb24gZXNjYXBlRm9yRHVtYkZpcmVmb3gzNih2YWx1ZSkgewogICAgICAgICAgcmV0dXJuIGVzY2FwZSh2YWx1ZSk7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHN0cmljdEVuY29kZVVSSUNvbXBvbmVudChzdHJpbmcpIHsKICAgICAgICAgIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQoc3RyaW5nKS5yZXBsYWNlKC9bIScoKSpdL2csIGVzY2FwZUZvckR1bWJGaXJlZm94MzYpLnJlcGxhY2UoL1wqL2csICIlMkEiKTsKICAgICAgICB9CiAgICAgICAgVVJJLmVuY29kZSA9IHN0cmljdEVuY29kZVVSSUNvbXBvbmVudDsKICAgICAgICBVUkkuZGVjb2RlID0gZGVjb2RlVVJJQ29tcG9uZW50OwogICAgICAgIFVSSS5pc284ODU5ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICBVUkkuZW5jb2RlID0gZXNjYXBlOwogICAgICAgICAgVVJJLmRlY29kZSA9IHVuZXNjYXBlOwogICAgICAgIH07CiAgICAgICAgVVJJLnVuaWNvZGUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgIFVSSS5lbmNvZGUgPSBzdHJpY3RFbmNvZGVVUklDb21wb25lbnQ7CiAgICAgICAgICBVUkkuZGVjb2RlID0gZGVjb2RlVVJJQ29tcG9uZW50OwogICAgICAgIH07CiAgICAgICAgVVJJLmNoYXJhY3RlcnMgPSB7CiAgICAgICAgICBwYXRobmFtZTogewogICAgICAgICAgICBlbmNvZGU6IHsKICAgICAgICAgICAgICAvLyBSRkMzOTg2IDIuMTogRm9yIGNvbnNpc3RlbmN5LCBVUkkgcHJvZHVjZXJzIGFuZCBub3JtYWxpemVycyBzaG91bGQKICAgICAgICAgICAgICAvLyB1c2UgdXBwZXJjYXNlIGhleGFkZWNpbWFsIGRpZ2l0cyBmb3IgYWxsIHBlcmNlbnQtZW5jb2RpbmdzLgogICAgICAgICAgICAgIGV4cHJlc3Npb246IC8lKDI0fDI2fDJCfDJDfDNCfDNEfDNBfDQwKS9pZywKICAgICAgICAgICAgICBtYXA6IHsKICAgICAgICAgICAgICAgIC8vIC0uX34hJygpKgogICAgICAgICAgICAgICAgIiUyNCI6ICIkIiwKICAgICAgICAgICAgICAgICIlMjYiOiAiJiIsCiAgICAgICAgICAgICAgICAiJTJCIjogIisiLAogICAgICAgICAgICAgICAgIiUyQyI6ICIsIiwKICAgICAgICAgICAgICAgICIlM0IiOiAiOyIsCiAgICAgICAgICAgICAgICAiJTNEIjogIj0iLAogICAgICAgICAgICAgICAgIiUzQSI6ICI6IiwKICAgICAgICAgICAgICAgICIlNDAiOiAiQCIKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGRlY29kZTogewogICAgICAgICAgICAgIGV4cHJlc3Npb246IC9bXC9cPyNdL2csCiAgICAgICAgICAgICAgbWFwOiB7CiAgICAgICAgICAgICAgICAiLyI6ICIlMkYiLAogICAgICAgICAgICAgICAgIj8iOiAiJTNGIiwKICAgICAgICAgICAgICAgICIjIjogIiUyMyIKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0sCiAgICAgICAgICByZXNlcnZlZDogewogICAgICAgICAgICBlbmNvZGU6IHsKICAgICAgICAgICAgICAvLyBSRkMzOTg2IDIuMTogRm9yIGNvbnNpc3RlbmN5LCBVUkkgcHJvZHVjZXJzIGFuZCBub3JtYWxpemVycyBzaG91bGQKICAgICAgICAgICAgICAvLyB1c2UgdXBwZXJjYXNlIGhleGFkZWNpbWFsIGRpZ2l0cyBmb3IgYWxsIHBlcmNlbnQtZW5jb2RpbmdzLgogICAgICAgICAgICAgIGV4cHJlc3Npb246IC8lKDIxfDIzfDI0fDI2fDI3fDI4fDI5fDJBfDJCfDJDfDJGfDNBfDNCfDNEfDNGfDQwfDVCfDVEKS9pZywKICAgICAgICAgICAgICBtYXA6IHsKICAgICAgICAgICAgICAgIC8vIGdlbi1kZWxpbXMKICAgICAgICAgICAgICAgICIlM0EiOiAiOiIsCiAgICAgICAgICAgICAgICAiJTJGIjogIi8iLAogICAgICAgICAgICAgICAgIiUzRiI6ICI/IiwKICAgICAgICAgICAgICAgICIlMjMiOiAiIyIsCiAgICAgICAgICAgICAgICAiJTVCIjogIlsiLAogICAgICAgICAgICAgICAgIiU1RCI6ICJdIiwKICAgICAgICAgICAgICAgICIlNDAiOiAiQCIsCiAgICAgICAgICAgICAgICAvLyBzdWItZGVsaW1zCiAgICAgICAgICAgICAgICAiJTIxIjogIiEiLAogICAgICAgICAgICAgICAgIiUyNCI6ICIkIiwKICAgICAgICAgICAgICAgICIlMjYiOiAiJiIsCiAgICAgICAgICAgICAgICAiJTI3IjogIiciLAogICAgICAgICAgICAgICAgIiUyOCI6ICIoIiwKICAgICAgICAgICAgICAgICIlMjkiOiAiKSIsCiAgICAgICAgICAgICAgICAiJTJBIjogIioiLAogICAgICAgICAgICAgICAgIiUyQiI6ICIrIiwKICAgICAgICAgICAgICAgICIlMkMiOiAiLCIsCiAgICAgICAgICAgICAgICAiJTNCIjogIjsiLAogICAgICAgICAgICAgICAgIiUzRCI6ICI9IgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIHVybnBhdGg6IHsKICAgICAgICAgICAgLy8gVGhlIGNoYXJhY3RlcnMgdW5kZXIgYGVuY29kZWAgYXJlIHRoZSBjaGFyYWN0ZXJzIGNhbGxlZCBvdXQgYnkgUkZDIDIxNDEgYXMgYmVpbmcgYWNjZXB0YWJsZQogICAgICAgICAgICAvLyBmb3IgdXNhZ2UgaW4gYSBVUk4uIFJGQzIxNDEgYWxzbyBjYWxscyBvdXQgIi0iLCAiLiIsIGFuZCAiXyIgYXMgYWNjZXB0YWJsZSBjaGFyYWN0ZXJzLCBidXQKICAgICAgICAgICAgLy8gdGhlc2UgYXJlbid0IGVuY29kZWQgYnkgZW5jb2RlVVJJQ29tcG9uZW50LCBzbyB3ZSBkb24ndCBoYXZlIHRvIGNhbGwgdGhlbSBvdXQgaGVyZS4gQWxzbwogICAgICAgICAgICAvLyBub3RlIHRoYXQgdGhlIGNvbG9uIGNoYXJhY3RlciBpcyBub3QgZmVhdHVyZWQgaW4gdGhlIGVuY29kaW5nIG1hcDsgdGhpcyBpcyBiZWNhdXNlIFVSSS5qcwogICAgICAgICAgICAvLyBnaXZlcyB0aGUgY29sb25zIGluIFVSTnMgc2VtYW50aWMgbWVhbmluZyBhcyB0aGUgZGVsaW1pdGVycyBvZiBwYXRoIHNlZ2VtZW50cywgYW5kIHNvIGl0CiAgICAgICAgICAgIC8vIHNob3VsZCBub3QgYXBwZWFyIHVuZW5jb2RlZCBpbiBhIHNlZ21lbnQgaXRzZWxmLgogICAgICAgICAgICAvLyBTZWUgYWxzbyB0aGUgbm90ZSBhYm92ZSBhYm91dCBSRkMzOTg2IGFuZCBjYXBpdGFsYWxpemVkIGhleCBkaWdpdHMuCiAgICAgICAgICAgIGVuY29kZTogewogICAgICAgICAgICAgIGV4cHJlc3Npb246IC8lKDIxfDI0fDI3fDI4fDI5fDJBfDJCfDJDfDNCfDNEfDQwKS9pZywKICAgICAgICAgICAgICBtYXA6IHsKICAgICAgICAgICAgICAgICIlMjEiOiAiISIsCiAgICAgICAgICAgICAgICAiJTI0IjogIiQiLAogICAgICAgICAgICAgICAgIiUyNyI6ICInIiwKICAgICAgICAgICAgICAgICIlMjgiOiAiKCIsCiAgICAgICAgICAgICAgICAiJTI5IjogIikiLAogICAgICAgICAgICAgICAgIiUyQSI6ICIqIiwKICAgICAgICAgICAgICAgICIlMkIiOiAiKyIsCiAgICAgICAgICAgICAgICAiJTJDIjogIiwiLAogICAgICAgICAgICAgICAgIiUzQiI6ICI7IiwKICAgICAgICAgICAgICAgICIlM0QiOiAiPSIsCiAgICAgICAgICAgICAgICAiJTQwIjogIkAiCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAvLyBUaGVzZSBjaGFyYWN0ZXJzIGFyZSB0aGUgY2hhcmFjdGVycyBjYWxsZWQgb3V0IGJ5IFJGQzIxNDEgYXMgInJlc2VydmVkIiBjaGFyYWN0ZXJzIHRoYXQKICAgICAgICAgICAgLy8gc2hvdWxkIG5ldmVyIGFwcGVhciBpbiBhIFVSTiwgcGx1cyB0aGUgY29sb24gY2hhcmFjdGVyIChzZWUgbm90ZSBhYm92ZSkuCiAgICAgICAgICAgIGRlY29kZTogewogICAgICAgICAgICAgIGV4cHJlc3Npb246IC9bXC9cPyM6XS9nLAogICAgICAgICAgICAgIG1hcDogewogICAgICAgICAgICAgICAgIi8iOiAiJTJGIiwKICAgICAgICAgICAgICAgICI/IjogIiUzRiIsCiAgICAgICAgICAgICAgICAiIyI6ICIlMjMiLAogICAgICAgICAgICAgICAgIjoiOiAiJTNBIgogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgVVJJLmVuY29kZVF1ZXJ5ID0gZnVuY3Rpb24oc3RyaW5nLCBlc2NhcGVRdWVyeVNwYWNlKSB7CiAgICAgICAgICB2YXIgZXNjYXBlZCA9IFVSSS5lbmNvZGUoc3RyaW5nICsgIiIpOwogICAgICAgICAgaWYgKGVzY2FwZVF1ZXJ5U3BhY2UgPT09IHZvaWQgMCkgewogICAgICAgICAgICBlc2NhcGVRdWVyeVNwYWNlID0gVVJJLmVzY2FwZVF1ZXJ5U3BhY2U7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZXNjYXBlUXVlcnlTcGFjZSA/IGVzY2FwZWQucmVwbGFjZSgvJTIwL2csICIrIikgOiBlc2NhcGVkOwogICAgICAgIH07CiAgICAgICAgVVJJLmRlY29kZVF1ZXJ5ID0gZnVuY3Rpb24oc3RyaW5nLCBlc2NhcGVRdWVyeVNwYWNlKSB7CiAgICAgICAgICBzdHJpbmcgKz0gIiI7CiAgICAgICAgICBpZiAoZXNjYXBlUXVlcnlTcGFjZSA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIGVzY2FwZVF1ZXJ5U3BhY2UgPSBVUkkuZXNjYXBlUXVlcnlTcGFjZTsKICAgICAgICAgIH0KICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgIHJldHVybiBVUkkuZGVjb2RlKGVzY2FwZVF1ZXJ5U3BhY2UgPyBzdHJpbmcucmVwbGFjZSgvXCsvZywgIiUyMCIpIDogc3RyaW5nKTsKICAgICAgICAgIH0gY2F0Y2ggKGUyKSB7CiAgICAgICAgICAgIHJldHVybiBzdHJpbmc7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICB2YXIgX3BhcnRzID0geyAiZW5jb2RlIjogImVuY29kZSIsICJkZWNvZGUiOiAiZGVjb2RlIiB9OwogICAgICAgIHZhciBfcGFydDsKICAgICAgICB2YXIgZ2VuZXJhdGVBY2Nlc3NvciA9IGZ1bmN0aW9uKF9ncm91cCwgX3BhcnQyKSB7CiAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oc3RyaW5nKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmV0dXJuIFVSSVtfcGFydDJdKHN0cmluZyArICIiKS5yZXBsYWNlKFVSSS5jaGFyYWN0ZXJzW19ncm91cF1bX3BhcnQyXS5leHByZXNzaW9uLCBmdW5jdGlvbihjMikgewogICAgICAgICAgICAgICAgcmV0dXJuIFVSSS5jaGFyYWN0ZXJzW19ncm91cF1bX3BhcnQyXS5tYXBbYzJdOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9IGNhdGNoIChlMikgewogICAgICAgICAgICAgIHJldHVybiBzdHJpbmc7CiAgICAgICAgICAgIH0KICAgICAgICAgIH07CiAgICAgICAgfTsKICAgICAgICBmb3IgKF9wYXJ0IGluIF9wYXJ0cykgewogICAgICAgICAgVVJJW19wYXJ0ICsgIlBhdGhTZWdtZW50Il0gPSBnZW5lcmF0ZUFjY2Vzc29yKCJwYXRobmFtZSIsIF9wYXJ0c1tfcGFydF0pOwogICAgICAgICAgVVJJW19wYXJ0ICsgIlVyblBhdGhTZWdtZW50Il0gPSBnZW5lcmF0ZUFjY2Vzc29yKCJ1cm5wYXRoIiwgX3BhcnRzW19wYXJ0XSk7CiAgICAgICAgfQogICAgICAgIHZhciBnZW5lcmF0ZVNlZ21lbnRlZFBhdGhGdW5jdGlvbiA9IGZ1bmN0aW9uKF9zZXAsIF9jb2RpbmdGdW5jTmFtZSwgX2lubmVyQ29kaW5nRnVuY05hbWUpIHsKICAgICAgICAgIHJldHVybiBmdW5jdGlvbihzdHJpbmcpIHsKICAgICAgICAgICAgdmFyIGFjdHVhbENvZGluZ0Z1bmM7CiAgICAgICAgICAgIGlmICghX2lubmVyQ29kaW5nRnVuY05hbWUpIHsKICAgICAgICAgICAgICBhY3R1YWxDb2RpbmdGdW5jID0gVVJJW19jb2RpbmdGdW5jTmFtZV07CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgYWN0dWFsQ29kaW5nRnVuYyA9IGZ1bmN0aW9uKHN0cmluZzIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBVUklbX2NvZGluZ0Z1bmNOYW1lXShVUklbX2lubmVyQ29kaW5nRnVuY05hbWVdKHN0cmluZzIpKTsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzZWdtZW50cyA9IChzdHJpbmcgKyAiIikuc3BsaXQoX3NlcCk7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMCwgbGVuZ3RoID0gc2VnbWVudHMubGVuZ3RoOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICAgIHNlZ21lbnRzW2kyXSA9IGFjdHVhbENvZGluZ0Z1bmMoc2VnbWVudHNbaTJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gc2VnbWVudHMuam9pbihfc2VwKTsKICAgICAgICAgIH07CiAgICAgICAgfTsKICAgICAgICBVUkkuZGVjb2RlUGF0aCA9IGdlbmVyYXRlU2VnbWVudGVkUGF0aEZ1bmN0aW9uKCIvIiwgImRlY29kZVBhdGhTZWdtZW50Iik7CiAgICAgICAgVVJJLmRlY29kZVVyblBhdGggPSBnZW5lcmF0ZVNlZ21lbnRlZFBhdGhGdW5jdGlvbigiOiIsICJkZWNvZGVVcm5QYXRoU2VnbWVudCIpOwogICAgICAgIFVSSS5yZWNvZGVQYXRoID0gZ2VuZXJhdGVTZWdtZW50ZWRQYXRoRnVuY3Rpb24oIi8iLCAiZW5jb2RlUGF0aFNlZ21lbnQiLCAiZGVjb2RlIik7CiAgICAgICAgVVJJLnJlY29kZVVyblBhdGggPSBnZW5lcmF0ZVNlZ21lbnRlZFBhdGhGdW5jdGlvbigiOiIsICJlbmNvZGVVcm5QYXRoU2VnbWVudCIsICJkZWNvZGUiKTsKICAgICAgICBVUkkuZW5jb2RlUmVzZXJ2ZWQgPSBnZW5lcmF0ZUFjY2Vzc29yKCJyZXNlcnZlZCIsICJlbmNvZGUiKTsKICAgICAgICBVUkkucGFyc2UgPSBmdW5jdGlvbihzdHJpbmcsIHBhcnRzKSB7CiAgICAgICAgICB2YXIgcG9zOwogICAgICAgICAgaWYgKCFwYXJ0cykgewogICAgICAgICAgICBwYXJ0cyA9IHsKICAgICAgICAgICAgICBwcmV2ZW50SW52YWxpZEhvc3RuYW1lOiBVUkkucHJldmVudEludmFsaWRIb3N0bmFtZQogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgICAgc3RyaW5nID0gc3RyaW5nLnJlcGxhY2UoVVJJLmxlYWRpbmdfd2hpdGVzcGFjZV9leHByZXNzaW9uLCAiIik7CiAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZShVUkkuYXNjaWlfdGFiX3doaXRlc3BhY2UsICIiKTsKICAgICAgICAgIHBvcyA9IHN0cmluZy5pbmRleE9mKCIjIik7CiAgICAgICAgICBpZiAocG9zID4gLTEpIHsKICAgICAgICAgICAgcGFydHMuZnJhZ21lbnQgPSBzdHJpbmcuc3Vic3RyaW5nKHBvcyArIDEpIHx8IG51bGw7CiAgICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5zdWJzdHJpbmcoMCwgcG9zKTsKICAgICAgICAgIH0KICAgICAgICAgIHBvcyA9IHN0cmluZy5pbmRleE9mKCI/Iik7CiAgICAgICAgICBpZiAocG9zID4gLTEpIHsKICAgICAgICAgICAgcGFydHMucXVlcnkgPSBzdHJpbmcuc3Vic3RyaW5nKHBvcyArIDEpIHx8IG51bGw7CiAgICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5zdWJzdHJpbmcoMCwgcG9zKTsKICAgICAgICAgIH0KICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5yZXBsYWNlKC9eKGh0dHBzP3xmdHB8d3NzPyk/OitbL1xcXSovaSwgIiQxOi8vIik7CiAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvXlsvXFxdezIsfS9pLCAiLy8iKTsKICAgICAgICAgIGlmIChzdHJpbmcuc3Vic3RyaW5nKDAsIDIpID09PSAiLy8iKSB7CiAgICAgICAgICAgIHBhcnRzLnByb3RvY29sID0gbnVsbDsKICAgICAgICAgICAgc3RyaW5nID0gc3RyaW5nLnN1YnN0cmluZygyKTsKICAgICAgICAgICAgc3RyaW5nID0gVVJJLnBhcnNlQXV0aG9yaXR5KHN0cmluZywgcGFydHMpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcG9zID0gc3RyaW5nLmluZGV4T2YoIjoiKTsKICAgICAgICAgICAgaWYgKHBvcyA+IC0xKSB7CiAgICAgICAgICAgICAgcGFydHMucHJvdG9jb2wgPSBzdHJpbmcuc3Vic3RyaW5nKDAsIHBvcykgfHwgbnVsbDsKICAgICAgICAgICAgICBpZiAocGFydHMucHJvdG9jb2wgJiYgIXBhcnRzLnByb3RvY29sLm1hdGNoKFVSSS5wcm90b2NvbF9leHByZXNzaW9uKSkgewogICAgICAgICAgICAgICAgcGFydHMucHJvdG9jb2wgPSB2b2lkIDA7CiAgICAgICAgICAgICAgfSBlbHNlIGlmIChzdHJpbmcuc3Vic3RyaW5nKHBvcyArIDEsIHBvcyArIDMpLnJlcGxhY2UoL1xcL2csICIvIikgPT09ICIvLyIpIHsKICAgICAgICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5zdWJzdHJpbmcocG9zICsgMyk7CiAgICAgICAgICAgICAgICBzdHJpbmcgPSBVUkkucGFyc2VBdXRob3JpdHkoc3RyaW5nLCBwYXJ0cyk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5zdWJzdHJpbmcocG9zICsgMSk7CiAgICAgICAgICAgICAgICBwYXJ0cy51cm4gPSB0cnVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcGFydHMucGF0aCA9IHN0cmluZzsKICAgICAgICAgIHJldHVybiBwYXJ0czsKICAgICAgICB9OwogICAgICAgIFVSSS5wYXJzZUhvc3QgPSBmdW5jdGlvbihzdHJpbmcsIHBhcnRzKSB7CiAgICAgICAgICBpZiAoIXN0cmluZykgewogICAgICAgICAgICBzdHJpbmcgPSAiIjsKICAgICAgICAgIH0KICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5yZXBsYWNlKC9cXC9nLCAiLyIpOwogICAgICAgICAgdmFyIHBvcyA9IHN0cmluZy5pbmRleE9mKCIvIik7CiAgICAgICAgICB2YXIgYnJhY2tldFBvczsKICAgICAgICAgIHZhciB0MjsKICAgICAgICAgIGlmIChwb3MgPT09IC0xKSB7CiAgICAgICAgICAgIHBvcyA9IHN0cmluZy5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoc3RyaW5nLmNoYXJBdCgwKSA9PT0gIlsiKSB7CiAgICAgICAgICAgIGJyYWNrZXRQb3MgPSBzdHJpbmcuaW5kZXhPZigiXSIpOwogICAgICAgICAgICBwYXJ0cy5ob3N0bmFtZSA9IHN0cmluZy5zdWJzdHJpbmcoMSwgYnJhY2tldFBvcykgfHwgbnVsbDsKICAgICAgICAgICAgcGFydHMucG9ydCA9IHN0cmluZy5zdWJzdHJpbmcoYnJhY2tldFBvcyArIDIsIHBvcykgfHwgbnVsbDsKICAgICAgICAgICAgaWYgKHBhcnRzLnBvcnQgPT09ICIvIikgewogICAgICAgICAgICAgIHBhcnRzLnBvcnQgPSBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB2YXIgZmlyc3RDb2xvbiA9IHN0cmluZy5pbmRleE9mKCI6Iik7CiAgICAgICAgICAgIHZhciBmaXJzdFNsYXNoID0gc3RyaW5nLmluZGV4T2YoIi8iKTsKICAgICAgICAgICAgdmFyIG5leHRDb2xvbiA9IHN0cmluZy5pbmRleE9mKCI6IiwgZmlyc3RDb2xvbiArIDEpOwogICAgICAgICAgICBpZiAobmV4dENvbG9uICE9PSAtMSAmJiAoZmlyc3RTbGFzaCA9PT0gLTEgfHwgbmV4dENvbG9uIDwgZmlyc3RTbGFzaCkpIHsKICAgICAgICAgICAgICBwYXJ0cy5ob3N0bmFtZSA9IHN0cmluZy5zdWJzdHJpbmcoMCwgcG9zKSB8fCBudWxsOwogICAgICAgICAgICAgIHBhcnRzLnBvcnQgPSBudWxsOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHQyID0gc3RyaW5nLnN1YnN0cmluZygwLCBwb3MpLnNwbGl0KCI6Iik7CiAgICAgICAgICAgICAgcGFydHMuaG9zdG5hbWUgPSB0MlswXSB8fCBudWxsOwogICAgICAgICAgICAgIHBhcnRzLnBvcnQgPSB0MlsxXSB8fCBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocGFydHMuaG9zdG5hbWUgJiYgc3RyaW5nLnN1YnN0cmluZyhwb3MpLmNoYXJBdCgwKSAhPT0gIi8iKSB7CiAgICAgICAgICAgIHBvcysrOwogICAgICAgICAgICBzdHJpbmcgPSAiLyIgKyBzdHJpbmc7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocGFydHMucHJldmVudEludmFsaWRIb3N0bmFtZSkgewogICAgICAgICAgICBVUkkuZW5zdXJlVmFsaWRIb3N0bmFtZShwYXJ0cy5ob3N0bmFtZSwgcGFydHMucHJvdG9jb2wpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHBhcnRzLnBvcnQpIHsKICAgICAgICAgICAgVVJJLmVuc3VyZVZhbGlkUG9ydChwYXJ0cy5wb3J0KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBzdHJpbmcuc3Vic3RyaW5nKHBvcykgfHwgIi8iOwogICAgICAgIH07CiAgICAgICAgVVJJLnBhcnNlQXV0aG9yaXR5ID0gZnVuY3Rpb24oc3RyaW5nLCBwYXJ0cykgewogICAgICAgICAgc3RyaW5nID0gVVJJLnBhcnNlVXNlcmluZm8oc3RyaW5nLCBwYXJ0cyk7CiAgICAgICAgICByZXR1cm4gVVJJLnBhcnNlSG9zdChzdHJpbmcsIHBhcnRzKTsKICAgICAgICB9OwogICAgICAgIFVSSS5wYXJzZVVzZXJpbmZvID0gZnVuY3Rpb24oc3RyaW5nLCBwYXJ0cykgewogICAgICAgICAgdmFyIF9zdHJpbmcgPSBzdHJpbmc7CiAgICAgICAgICB2YXIgZmlyc3RCYWNrU2xhc2ggPSBzdHJpbmcuaW5kZXhPZigiXFwiKTsKICAgICAgICAgIGlmIChmaXJzdEJhY2tTbGFzaCAhPT0gLTEpIHsKICAgICAgICAgICAgc3RyaW5nID0gc3RyaW5nLnJlcGxhY2UoL1xcL2csICIvIik7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgZmlyc3RTbGFzaCA9IHN0cmluZy5pbmRleE9mKCIvIik7CiAgICAgICAgICB2YXIgcG9zID0gc3RyaW5nLmxhc3RJbmRleE9mKCJAIiwgZmlyc3RTbGFzaCA+IC0xID8gZmlyc3RTbGFzaCA6IHN0cmluZy5sZW5ndGggLSAxKTsKICAgICAgICAgIHZhciB0MjsKICAgICAgICAgIGlmIChwb3MgPiAtMSAmJiAoZmlyc3RTbGFzaCA9PT0gLTEgfHwgcG9zIDwgZmlyc3RTbGFzaCkpIHsKICAgICAgICAgICAgdDIgPSBzdHJpbmcuc3Vic3RyaW5nKDAsIHBvcykuc3BsaXQoIjoiKTsKICAgICAgICAgICAgcGFydHMudXNlcm5hbWUgPSB0MlswXSA/IFVSSS5kZWNvZGUodDJbMF0pIDogbnVsbDsKICAgICAgICAgICAgdDIuc2hpZnQoKTsKICAgICAgICAgICAgcGFydHMucGFzc3dvcmQgPSB0MlswXSA/IFVSSS5kZWNvZGUodDIuam9pbigiOiIpKSA6IG51bGw7CiAgICAgICAgICAgIHN0cmluZyA9IF9zdHJpbmcuc3Vic3RyaW5nKHBvcyArIDEpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcGFydHMudXNlcm5hbWUgPSBudWxsOwogICAgICAgICAgICBwYXJ0cy5wYXNzd29yZCA9IG51bGw7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gc3RyaW5nOwogICAgICAgIH07CiAgICAgICAgVVJJLnBhcnNlUXVlcnkgPSBmdW5jdGlvbihzdHJpbmcsIGVzY2FwZVF1ZXJ5U3BhY2UpIHsKICAgICAgICAgIGlmICghc3RyaW5nKSB7CiAgICAgICAgICAgIHJldHVybiB7fTsKICAgICAgICAgIH0KICAgICAgICAgIHN0cmluZyA9IHN0cmluZy5yZXBsYWNlKC8mKy9nLCAiJiIpLnJlcGxhY2UoL15cPyomKnwmKyQvZywgIiIpOwogICAgICAgICAgaWYgKCFzdHJpbmcpIHsKICAgICAgICAgICAgcmV0dXJuIHt9OwogICAgICAgICAgfQogICAgICAgICAgdmFyIGl0ZW1zID0ge307CiAgICAgICAgICB2YXIgc3BsaXRzID0gc3RyaW5nLnNwbGl0KCImIik7CiAgICAgICAgICB2YXIgbGVuZ3RoID0gc3BsaXRzLmxlbmd0aDsKICAgICAgICAgIHZhciB2NCwgbmFtZSwgdmFsdWU7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIHY0ID0gc3BsaXRzW2kyXS5zcGxpdCgiPSIpOwogICAgICAgICAgICBuYW1lID0gVVJJLmRlY29kZVF1ZXJ5KHY0LnNoaWZ0KCksIGVzY2FwZVF1ZXJ5U3BhY2UpOwogICAgICAgICAgICB2YWx1ZSA9IHY0Lmxlbmd0aCA/IFVSSS5kZWNvZGVRdWVyeSh2NC5qb2luKCI9IiksIGVzY2FwZVF1ZXJ5U3BhY2UpIDogbnVsbDsKICAgICAgICAgICAgaWYgKG5hbWUgPT09ICJfX3Byb3RvX18iKSB7CiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoaGFzT3duLmNhbGwoaXRlbXMsIG5hbWUpKSB7CiAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtc1tuYW1lXSA9PT0gInN0cmluZyIgfHwgaXRlbXNbbmFtZV0gPT09IG51bGwpIHsKICAgICAgICAgICAgICAgIGl0ZW1zW25hbWVdID0gW2l0ZW1zW25hbWVdXTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaXRlbXNbbmFtZV0ucHVzaCh2YWx1ZSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgaXRlbXNbbmFtZV0gPSB2YWx1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGl0ZW1zOwogICAgICAgIH07CiAgICAgICAgVVJJLmJ1aWxkID0gZnVuY3Rpb24ocGFydHMpIHsKICAgICAgICAgIHZhciB0MiA9ICIiOwogICAgICAgICAgdmFyIHJlcXVpcmVBYnNvbHV0ZVBhdGggPSBmYWxzZTsKICAgICAgICAgIGlmIChwYXJ0cy5wcm90b2NvbCkgewogICAgICAgICAgICB0MiArPSBwYXJ0cy5wcm90b2NvbCArICI6IjsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghcGFydHMudXJuICYmICh0MiB8fCBwYXJ0cy5ob3N0bmFtZSkpIHsKICAgICAgICAgICAgdDIgKz0gIi8vIjsKICAgICAgICAgICAgcmVxdWlyZUFic29sdXRlUGF0aCA9IHRydWU7CiAgICAgICAgICB9CiAgICAgICAgICB0MiArPSBVUkkuYnVpbGRBdXRob3JpdHkocGFydHMpIHx8ICIiOwogICAgICAgICAgaWYgKHR5cGVvZiBwYXJ0cy5wYXRoID09PSAic3RyaW5nIikgewogICAgICAgICAgICBpZiAocGFydHMucGF0aC5jaGFyQXQoMCkgIT09ICIvIiAmJiByZXF1aXJlQWJzb2x1dGVQYXRoKSB7CiAgICAgICAgICAgICAgdDIgKz0gIi8iOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHQyICs9IHBhcnRzLnBhdGg7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodHlwZW9mIHBhcnRzLnF1ZXJ5ID09PSAic3RyaW5nIiAmJiBwYXJ0cy5xdWVyeSkgewogICAgICAgICAgICB0MiArPSAiPyIgKyBwYXJ0cy5xdWVyeTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh0eXBlb2YgcGFydHMuZnJhZ21lbnQgPT09ICJzdHJpbmciICYmIHBhcnRzLmZyYWdtZW50KSB7CiAgICAgICAgICAgIHQyICs9ICIjIiArIHBhcnRzLmZyYWdtZW50OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHQyOwogICAgICAgIH07CiAgICAgICAgVVJJLmJ1aWxkSG9zdCA9IGZ1bmN0aW9uKHBhcnRzKSB7CiAgICAgICAgICB2YXIgdDIgPSAiIjsKICAgICAgICAgIGlmICghcGFydHMuaG9zdG5hbWUpIHsKICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgfSBlbHNlIGlmIChVUkkuaXA2X2V4cHJlc3Npb24udGVzdChwYXJ0cy5ob3N0bmFtZSkpIHsKICAgICAgICAgICAgdDIgKz0gIlsiICsgcGFydHMuaG9zdG5hbWUgKyAiXSI7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0MiArPSBwYXJ0cy5ob3N0bmFtZTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChwYXJ0cy5wb3J0KSB7CiAgICAgICAgICAgIHQyICs9ICI6IiArIHBhcnRzLnBvcnQ7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdDI7CiAgICAgICAgfTsKICAgICAgICBVUkkuYnVpbGRBdXRob3JpdHkgPSBmdW5jdGlvbihwYXJ0cykgewogICAgICAgICAgcmV0dXJuIFVSSS5idWlsZFVzZXJpbmZvKHBhcnRzKSArIFVSSS5idWlsZEhvc3QocGFydHMpOwogICAgICAgIH07CiAgICAgICAgVVJJLmJ1aWxkVXNlcmluZm8gPSBmdW5jdGlvbihwYXJ0cykgewogICAgICAgICAgdmFyIHQyID0gIiI7CiAgICAgICAgICBpZiAocGFydHMudXNlcm5hbWUpIHsKICAgICAgICAgICAgdDIgKz0gVVJJLmVuY29kZShwYXJ0cy51c2VybmFtZSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocGFydHMucGFzc3dvcmQpIHsKICAgICAgICAgICAgdDIgKz0gIjoiICsgVVJJLmVuY29kZShwYXJ0cy5wYXNzd29yZCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodDIpIHsKICAgICAgICAgICAgdDIgKz0gIkAiOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHQyOwogICAgICAgIH07CiAgICAgICAgVVJJLmJ1aWxkUXVlcnkgPSBmdW5jdGlvbihkYXRhLCBkdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMsIGVzY2FwZVF1ZXJ5U3BhY2UpIHsKICAgICAgICAgIHZhciB0MiA9ICIiOwogICAgICAgICAgdmFyIHVuaXF1ZSwga2V5LCBpMiwgbGVuZ3RoOwogICAgICAgICAgZm9yIChrZXkgaW4gZGF0YSkgewogICAgICAgICAgICBpZiAoa2V5ID09PSAiX19wcm90b19fIikgewogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9IGVsc2UgaWYgKGhhc093bi5jYWxsKGRhdGEsIGtleSkpIHsKICAgICAgICAgICAgICBpZiAoaXNBcnJheShkYXRhW2tleV0pKSB7CiAgICAgICAgICAgICAgICB1bmlxdWUgPSB7fTsKICAgICAgICAgICAgICAgIGZvciAoaTIgPSAwLCBsZW5ndGggPSBkYXRhW2tleV0ubGVuZ3RoOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICAgICAgICBpZiAoZGF0YVtrZXldW2kyXSAhPT0gdm9pZCAwICYmIHVuaXF1ZVtkYXRhW2tleV1baTJdICsgIiJdID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICAgICAgICB0MiArPSAiJiIgKyBVUkkuYnVpbGRRdWVyeVBhcmFtZXRlcihrZXksIGRhdGFba2V5XVtpMl0sIGVzY2FwZVF1ZXJ5U3BhY2UpOwogICAgICAgICAgICAgICAgICAgIGlmIChkdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMgIT09IHRydWUpIHsKICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZVtkYXRhW2tleV1baTJdICsgIiJdID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgaWYgKGRhdGFba2V5XSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgICAgICB0MiArPSAiJiIgKyBVUkkuYnVpbGRRdWVyeVBhcmFtZXRlcihrZXksIGRhdGFba2V5XSwgZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdDIuc3Vic3RyaW5nKDEpOwogICAgICAgIH07CiAgICAgICAgVVJJLmJ1aWxkUXVlcnlQYXJhbWV0ZXIgPSBmdW5jdGlvbihuYW1lLCB2YWx1ZSwgZXNjYXBlUXVlcnlTcGFjZSkgewogICAgICAgICAgcmV0dXJuIFVSSS5lbmNvZGVRdWVyeShuYW1lLCBlc2NhcGVRdWVyeVNwYWNlKSArICh2YWx1ZSAhPT0gbnVsbCA/ICI9IiArIFVSSS5lbmNvZGVRdWVyeSh2YWx1ZSwgZXNjYXBlUXVlcnlTcGFjZSkgOiAiIik7CiAgICAgICAgfTsKICAgICAgICBVUkkuYWRkUXVlcnkgPSBmdW5jdGlvbihkYXRhLCBuYW1lLCB2YWx1ZSkgewogICAgICAgICAgaWYgKHR5cGVvZiBuYW1lID09PSAib2JqZWN0IikgewogICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gbmFtZSkgewogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChuYW1lLCBrZXkpKSB7CiAgICAgICAgICAgICAgICBVUkkuYWRkUXVlcnkoZGF0YSwga2V5LCBuYW1lW2tleV0pOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmFtZSA9PT0gInN0cmluZyIpIHsKICAgICAgICAgICAgaWYgKGRhdGFbbmFtZV0gPT09IHZvaWQgMCkgewogICAgICAgICAgICAgIGRhdGFbbmFtZV0gPSB2YWx1ZTsKICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRhdGFbbmFtZV0gPT09ICJzdHJpbmciKSB7CiAgICAgICAgICAgICAgZGF0YVtuYW1lXSA9IFtkYXRhW25hbWVdXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWlzQXJyYXkodmFsdWUpKSB7CiAgICAgICAgICAgICAgdmFsdWUgPSBbdmFsdWVdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGRhdGFbbmFtZV0gPSAoZGF0YVtuYW1lXSB8fCBbXSkuY29uY2F0KHZhbHVlKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIlVSSS5hZGRRdWVyeSgpIGFjY2VwdHMgYW4gb2JqZWN0LCBzdHJpbmcgYXMgdGhlIG5hbWUgcGFyYW1ldGVyIik7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBVUkkuc2V0UXVlcnkgPSBmdW5jdGlvbihkYXRhLCBuYW1lLCB2YWx1ZSkgewogICAgICAgICAgaWYgKHR5cGVvZiBuYW1lID09PSAib2JqZWN0IikgewogICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gbmFtZSkgewogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChuYW1lLCBrZXkpKSB7CiAgICAgICAgICAgICAgICBVUkkuc2V0UXVlcnkoZGF0YSwga2V5LCBuYW1lW2tleV0pOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmFtZSA9PT0gInN0cmluZyIpIHsKICAgICAgICAgICAgZGF0YVtuYW1lXSA9IHZhbHVlID09PSB2b2lkIDAgPyBudWxsIDogdmFsdWU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVUkkuc2V0UXVlcnkoKSBhY2NlcHRzIGFuIG9iamVjdCwgc3RyaW5nIGFzIHRoZSBuYW1lIHBhcmFtZXRlciIpOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgVVJJLnJlbW92ZVF1ZXJ5ID0gZnVuY3Rpb24oZGF0YSwgbmFtZSwgdmFsdWUpIHsKICAgICAgICAgIHZhciBpMiwgbGVuZ3RoLCBrZXk7CiAgICAgICAgICBpZiAoaXNBcnJheShuYW1lKSkgewogICAgICAgICAgICBmb3IgKGkyID0gMCwgbGVuZ3RoID0gbmFtZS5sZW5ndGg7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgICAgZGF0YVtuYW1lW2kyXV0gPSB2b2lkIDA7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAoZ2V0VHlwZShuYW1lKSA9PT0gIlJlZ0V4cCIpIHsKICAgICAgICAgICAgZm9yIChrZXkgaW4gZGF0YSkgewogICAgICAgICAgICAgIGlmIChuYW1lLnRlc3Qoa2V5KSkgewogICAgICAgICAgICAgICAgZGF0YVtrZXldID0gdm9pZCAwOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmFtZSA9PT0gIm9iamVjdCIpIHsKICAgICAgICAgICAgZm9yIChrZXkgaW4gbmFtZSkgewogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChuYW1lLCBrZXkpKSB7CiAgICAgICAgICAgICAgICBVUkkucmVtb3ZlUXVlcnkoZGF0YSwga2V5LCBuYW1lW2tleV0pOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmFtZSA9PT0gInN0cmluZyIpIHsKICAgICAgICAgICAgaWYgKHZhbHVlICE9PSB2b2lkIDApIHsKICAgICAgICAgICAgICBpZiAoZ2V0VHlwZSh2YWx1ZSkgPT09ICJSZWdFeHAiKSB7CiAgICAgICAgICAgICAgICBpZiAoIWlzQXJyYXkoZGF0YVtuYW1lXSkgJiYgdmFsdWUudGVzdChkYXRhW25hbWVdKSkgewogICAgICAgICAgICAgICAgICBkYXRhW25hbWVdID0gdm9pZCAwOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgZGF0YVtuYW1lXSA9IGZpbHRlckFycmF5VmFsdWVzKGRhdGFbbmFtZV0sIHZhbHVlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgaWYgKGRhdGFbbmFtZV0gPT09IFN0cmluZyh2YWx1ZSkgJiYgKCFpc0FycmF5KHZhbHVlKSB8fCB2YWx1ZS5sZW5ndGggPT09IDEpKSB7CiAgICAgICAgICAgICAgICBkYXRhW25hbWVdID0gdm9pZCAwOwogICAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNBcnJheShkYXRhW25hbWVdKSkgewogICAgICAgICAgICAgICAgZGF0YVtuYW1lXSA9IGZpbHRlckFycmF5VmFsdWVzKGRhdGFbbmFtZV0sIHZhbHVlKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZGF0YVtuYW1lXSA9IHZvaWQgMDsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigiVVJJLnJlbW92ZVF1ZXJ5KCkgYWNjZXB0cyBhbiBvYmplY3QsIHN0cmluZywgUmVnRXhwIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXIiKTsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIFVSSS5oYXNRdWVyeSA9IGZ1bmN0aW9uKGRhdGEsIG5hbWUsIHZhbHVlLCB3aXRoaW5BcnJheSkgewogICAgICAgICAgc3dpdGNoIChnZXRUeXBlKG5hbWUpKSB7CiAgICAgICAgICAgIGNhc2UgIlN0cmluZyI6CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgIlJlZ0V4cCI6CiAgICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIGRhdGEpIHsKICAgICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChkYXRhLCBrZXkpKSB7CiAgICAgICAgICAgICAgICAgIGlmIChuYW1lLnRlc3Qoa2V5KSAmJiAodmFsdWUgPT09IHZvaWQgMCB8fCBVUkkuaGFzUXVlcnkoZGF0YSwga2V5LCB2YWx1ZSkpKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICBjYXNlICJPYmplY3QiOgogICAgICAgICAgICAgIGZvciAodmFyIF9rZXkgaW4gbmFtZSkgewogICAgICAgICAgICAgICAgaWYgKGhhc093bi5jYWxsKG5hbWUsIF9rZXkpKSB7CiAgICAgICAgICAgICAgICAgIGlmICghVVJJLmhhc1F1ZXJ5KGRhdGEsIF9rZXksIG5hbWVbX2tleV0pKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIlVSSS5oYXNRdWVyeSgpIGFjY2VwdHMgYSBzdHJpbmcsIHJlZ3VsYXIgZXhwcmVzc2lvbiBvciBvYmplY3QgYXMgdGhlIG5hbWUgcGFyYW1ldGVyIik7CiAgICAgICAgICB9CiAgICAgICAgICBzd2l0Y2ggKGdldFR5cGUodmFsdWUpKSB7CiAgICAgICAgICAgIGNhc2UgIlVuZGVmaW5lZCI6CiAgICAgICAgICAgICAgcmV0dXJuIG5hbWUgaW4gZGF0YTsKICAgICAgICAgICAgLy8gZGF0YVtuYW1lXSAhPT0gdW5kZWZpbmVkOwogICAgICAgICAgICBjYXNlICJCb29sZWFuIjoKICAgICAgICAgICAgICB2YXIgX2Jvb2x5ID0gQm9vbGVhbihpc0FycmF5KGRhdGFbbmFtZV0pID8gZGF0YVtuYW1lXS5sZW5ndGggOiBkYXRhW25hbWVdKTsKICAgICAgICAgICAgICByZXR1cm4gdmFsdWUgPT09IF9ib29seTsKICAgICAgICAgICAgY2FzZSAiRnVuY3Rpb24iOgogICAgICAgICAgICAgIHJldHVybiAhIXZhbHVlKGRhdGFbbmFtZV0sIG5hbWUsIGRhdGEpOwogICAgICAgICAgICBjYXNlICJBcnJheSI6CiAgICAgICAgICAgICAgaWYgKCFpc0FycmF5KGRhdGFbbmFtZV0pKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBvcCA9IHdpdGhpbkFycmF5ID8gYXJyYXlDb250YWlucyA6IGFycmF5c0VxdWFsOwogICAgICAgICAgICAgIHJldHVybiBvcChkYXRhW25hbWVdLCB2YWx1ZSk7CiAgICAgICAgICAgIGNhc2UgIlJlZ0V4cCI6CiAgICAgICAgICAgICAgaWYgKCFpc0FycmF5KGRhdGFbbmFtZV0pKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gQm9vbGVhbihkYXRhW25hbWVdICYmIGRhdGFbbmFtZV0ubWF0Y2godmFsdWUpKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKCF3aXRoaW5BcnJheSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gYXJyYXlDb250YWlucyhkYXRhW25hbWVdLCB2YWx1ZSk7CiAgICAgICAgICAgIGNhc2UgIk51bWJlciI6CiAgICAgICAgICAgICAgdmFsdWUgPSBTdHJpbmcodmFsdWUpOwogICAgICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovCiAgICAgICAgICAgIGNhc2UgIlN0cmluZyI6CiAgICAgICAgICAgICAgaWYgKCFpc0FycmF5KGRhdGFbbmFtZV0pKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZGF0YVtuYW1lXSA9PT0gdmFsdWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmICghd2l0aGluQXJyYXkpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGFycmF5Q29udGFpbnMoZGF0YVtuYW1lXSwgdmFsdWUpOwogICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIlVSSS5oYXNRdWVyeSgpIGFjY2VwdHMgdW5kZWZpbmVkLCBib29sZWFuLCBzdHJpbmcsIG51bWJlciwgUmVnRXhwLCBGdW5jdGlvbiBhcyB0aGUgdmFsdWUgcGFyYW1ldGVyIik7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBVUkkuam9pblBhdGhzID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICB2YXIgaW5wdXQgPSBbXTsKICAgICAgICAgIHZhciBzZWdtZW50cyA9IFtdOwogICAgICAgICAgdmFyIG5vbkVtcHR5U2VnbWVudHMgPSAwOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGFyZ3VtZW50cy5sZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgdmFyIHVybCA9IG5ldyBVUkkoYXJndW1lbnRzW2kyXSk7CiAgICAgICAgICAgIGlucHV0LnB1c2godXJsKTsKICAgICAgICAgICAgdmFyIF9zZWdtZW50cyA9IHVybC5zZWdtZW50KCk7CiAgICAgICAgICAgIGZvciAodmFyIHMyID0gMDsgczIgPCBfc2VnbWVudHMubGVuZ3RoOyBzMisrKSB7CiAgICAgICAgICAgICAgaWYgKHR5cGVvZiBfc2VnbWVudHNbczJdID09PSAic3RyaW5nIikgewogICAgICAgICAgICAgICAgc2VnbWVudHMucHVzaChfc2VnbWVudHNbczJdKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKF9zZWdtZW50c1tzMl0pIHsKICAgICAgICAgICAgICAgIG5vbkVtcHR5U2VnbWVudHMrKzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmICghc2VnbWVudHMubGVuZ3RoIHx8ICFub25FbXB0eVNlZ21lbnRzKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVVJJKCIiKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB1cmkgPSBuZXcgVVJJKCIiKS5zZWdtZW50KHNlZ21lbnRzKTsKICAgICAgICAgIGlmIChpbnB1dFswXS5wYXRoKCkgPT09ICIiIHx8IGlucHV0WzBdLnBhdGgoKS5zbGljZSgwLCAxKSA9PT0gIi8iKSB7CiAgICAgICAgICAgIHVyaS5wYXRoKCIvIiArIHVyaS5wYXRoKCkpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHVyaS5ub3JtYWxpemUoKTsKICAgICAgICB9OwogICAgICAgIFVSSS5jb21tb25QYXRoID0gZnVuY3Rpb24ob25lLCB0d28pIHsKICAgICAgICAgIHZhciBsZW5ndGggPSBNYXRoLm1pbihvbmUubGVuZ3RoLCB0d28ubGVuZ3RoKTsKICAgICAgICAgIHZhciBwb3M7CiAgICAgICAgICBmb3IgKHBvcyA9IDA7IHBvcyA8IGxlbmd0aDsgcG9zKyspIHsKICAgICAgICAgICAgaWYgKG9uZS5jaGFyQXQocG9zKSAhPT0gdHdvLmNoYXJBdChwb3MpKSB7CiAgICAgICAgICAgICAgcG9zLS07CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChwb3MgPCAxKSB7CiAgICAgICAgICAgIHJldHVybiBvbmUuY2hhckF0KDApID09PSB0d28uY2hhckF0KDApICYmIG9uZS5jaGFyQXQoMCkgPT09ICIvIiA/ICIvIiA6ICIiOwogICAgICAgICAgfQogICAgICAgICAgaWYgKG9uZS5jaGFyQXQocG9zKSAhPT0gIi8iIHx8IHR3by5jaGFyQXQocG9zKSAhPT0gIi8iKSB7CiAgICAgICAgICAgIHBvcyA9IG9uZS5zdWJzdHJpbmcoMCwgcG9zKS5sYXN0SW5kZXhPZigiLyIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIG9uZS5zdWJzdHJpbmcoMCwgcG9zICsgMSk7CiAgICAgICAgfTsKICAgICAgICBVUkkud2l0aGluU3RyaW5nID0gZnVuY3Rpb24oc3RyaW5nLCBjYWxsYmFjaywgb3B0aW9ucykgewogICAgICAgICAgb3B0aW9ucyB8fCAob3B0aW9ucyA9IHt9KTsKICAgICAgICAgIHZhciBfc3RhcnQgPSBvcHRpb25zLnN0YXJ0IHx8IFVSSS5maW5kVXJpLnN0YXJ0OwogICAgICAgICAgdmFyIF9lbmQgPSBvcHRpb25zLmVuZCB8fCBVUkkuZmluZFVyaS5lbmQ7CiAgICAgICAgICB2YXIgX3RyaW0gPSBvcHRpb25zLnRyaW0gfHwgVVJJLmZpbmRVcmkudHJpbTsKICAgICAgICAgIHZhciBfcGFyZW5zID0gb3B0aW9ucy5wYXJlbnMgfHwgVVJJLmZpbmRVcmkucGFyZW5zOwogICAgICAgICAgdmFyIF9hdHRyaWJ1dGVPcGVuID0gL1thLXowLTktXT1bIiddPyQvaTsKICAgICAgICAgIF9zdGFydC5sYXN0SW5kZXggPSAwOwogICAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgICAgdmFyIG1hdGNoID0gX3N0YXJ0LmV4ZWMoc3RyaW5nKTsKICAgICAgICAgICAgaWYgKCFtYXRjaCkgewogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzdGFydCA9IG1hdGNoLmluZGV4OwogICAgICAgICAgICBpZiAob3B0aW9ucy5pZ25vcmVIdG1sKSB7CiAgICAgICAgICAgICAgdmFyIGF0dHJpYnV0ZU9wZW4gPSBzdHJpbmcuc2xpY2UoTWF0aC5tYXgoc3RhcnQgLSAzLCAwKSwgc3RhcnQpOwogICAgICAgICAgICAgIGlmIChhdHRyaWJ1dGVPcGVuICYmIF9hdHRyaWJ1dGVPcGVuLnRlc3QoYXR0cmlidXRlT3BlbikpIHsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgZW5kID0gc3RhcnQgKyBzdHJpbmcuc2xpY2Uoc3RhcnQpLnNlYXJjaChfZW5kKTsKICAgICAgICAgICAgdmFyIHNsaWNlID0gc3RyaW5nLnNsaWNlKHN0YXJ0LCBlbmQpOwogICAgICAgICAgICB2YXIgcGFyZW5zRW5kID0gLTE7CiAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7CiAgICAgICAgICAgICAgdmFyIHBhcmVuc01hdGNoID0gX3BhcmVucy5leGVjKHNsaWNlKTsKICAgICAgICAgICAgICBpZiAoIXBhcmVuc01hdGNoKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIHBhcmVuc01hdGNoRW5kID0gcGFyZW5zTWF0Y2guaW5kZXggKyBwYXJlbnNNYXRjaFswXS5sZW5ndGg7CiAgICAgICAgICAgICAgcGFyZW5zRW5kID0gTWF0aC5tYXgocGFyZW5zRW5kLCBwYXJlbnNNYXRjaEVuZCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHBhcmVuc0VuZCA+IC0xKSB7CiAgICAgICAgICAgICAgc2xpY2UgPSBzbGljZS5zbGljZSgwLCBwYXJlbnNFbmQpICsgc2xpY2Uuc2xpY2UocGFyZW5zRW5kKS5yZXBsYWNlKF90cmltLCAiIik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgc2xpY2UgPSBzbGljZS5yZXBsYWNlKF90cmltLCAiIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHNsaWNlLmxlbmd0aCA8PSBtYXRjaFswXS5sZW5ndGgpIHsKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAob3B0aW9ucy5pZ25vcmUgJiYgb3B0aW9ucy5pZ25vcmUudGVzdChzbGljZSkpIHsKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbmQgPSBzdGFydCArIHNsaWNlLmxlbmd0aDsKICAgICAgICAgICAgdmFyIHJlc3VsdCA9IGNhbGxiYWNrKHNsaWNlLCBzdGFydCwgZW5kLCBzdHJpbmcpOwogICAgICAgICAgICBpZiAocmVzdWx0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICBfc3RhcnQubGFzdEluZGV4ID0gZW5kOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJlc3VsdCA9IFN0cmluZyhyZXN1bHQpOwogICAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcuc2xpY2UoMCwgc3RhcnQpICsgcmVzdWx0ICsgc3RyaW5nLnNsaWNlKGVuZCk7CiAgICAgICAgICAgIF9zdGFydC5sYXN0SW5kZXggPSBzdGFydCArIHJlc3VsdC5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgICBfc3RhcnQubGFzdEluZGV4ID0gMDsKICAgICAgICAgIHJldHVybiBzdHJpbmc7CiAgICAgICAgfTsKICAgICAgICBVUkkuZW5zdXJlVmFsaWRIb3N0bmFtZSA9IGZ1bmN0aW9uKHY0LCBwcm90b2NvbCkgewogICAgICAgICAgdmFyIGhhc0hvc3RuYW1lID0gISF2NDsKICAgICAgICAgIHZhciBoYXNQcm90b2NvbCA9ICEhcHJvdG9jb2w7CiAgICAgICAgICB2YXIgcmVqZWN0RW1wdHlIb3N0bmFtZSA9IGZhbHNlOwogICAgICAgICAgaWYgKGhhc1Byb3RvY29sKSB7CiAgICAgICAgICAgIHJlamVjdEVtcHR5SG9zdG5hbWUgPSBhcnJheUNvbnRhaW5zKFVSSS5ob3N0UHJvdG9jb2xzLCBwcm90b2NvbCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocmVqZWN0RW1wdHlIb3N0bmFtZSAmJiAhaGFzSG9zdG5hbWUpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigiSG9zdG5hbWUgY2Fubm90IGJlIGVtcHR5LCBpZiBwcm90b2NvbCBpcyAiICsgcHJvdG9jb2wpOwogICAgICAgICAgfSBlbHNlIGlmICh2NCAmJiB2NC5tYXRjaChVUkkuaW52YWxpZF9ob3N0bmFtZV9jaGFyYWN0ZXJzKSkgewogICAgICAgICAgICBpZiAoIXB1bnljb2RlKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSG9zdG5hbWUgIicgKyB2NCArICciIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05Li06X10gYW5kIFB1bnljb2RlLmpzIGlzIG5vdCBhdmFpbGFibGUnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocHVueWNvZGUudG9BU0NJSSh2NCkubWF0Y2goVVJJLmludmFsaWRfaG9zdG5hbWVfY2hhcmFjdGVycykpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdIb3N0bmFtZSAiJyArIHY0ICsgJyIgY29udGFpbnMgY2hhcmFjdGVycyBvdGhlciB0aGFuIFtBLVowLTkuLTpfXScpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBVUkkuZW5zdXJlVmFsaWRQb3J0ID0gZnVuY3Rpb24odjQpIHsKICAgICAgICAgIGlmICghdjQpIHsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgfQogICAgICAgICAgdmFyIHBvcnQgPSBOdW1iZXIodjQpOwogICAgICAgICAgaWYgKGlzSW50ZWdlcihwb3J0KSAmJiBwb3J0ID4gMCAmJiBwb3J0IDwgNjU1MzYpIHsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgfQogICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignUG9ydCAiJyArIHY0ICsgJyIgaXMgbm90IGEgdmFsaWQgcG9ydCcpOwogICAgICAgIH07CiAgICAgICAgVVJJLm5vQ29uZmxpY3QgPSBmdW5jdGlvbihyZW1vdmVBbGwpIHsKICAgICAgICAgIGlmIChyZW1vdmVBbGwpIHsKICAgICAgICAgICAgdmFyIHVuY29uZmxpY3RlZCA9IHsKICAgICAgICAgICAgICBVUkk6IHRoaXMubm9Db25mbGljdCgpCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGlmIChyb290LlVSSVRlbXBsYXRlICYmIHR5cGVvZiByb290LlVSSVRlbXBsYXRlLm5vQ29uZmxpY3QgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICB1bmNvbmZsaWN0ZWQuVVJJVGVtcGxhdGUgPSByb290LlVSSVRlbXBsYXRlLm5vQ29uZmxpY3QoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocm9vdC5JUHY2ICYmIHR5cGVvZiByb290LklQdjYubm9Db25mbGljdCA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICAgIHVuY29uZmxpY3RlZC5JUHY2ID0gcm9vdC5JUHY2Lm5vQ29uZmxpY3QoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocm9vdC5TZWNvbmRMZXZlbERvbWFpbnMgJiYgdHlwZW9mIHJvb3QuU2Vjb25kTGV2ZWxEb21haW5zLm5vQ29uZmxpY3QgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICB1bmNvbmZsaWN0ZWQuU2Vjb25kTGV2ZWxEb21haW5zID0gcm9vdC5TZWNvbmRMZXZlbERvbWFpbnMubm9Db25mbGljdCgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB1bmNvbmZsaWN0ZWQ7CiAgICAgICAgICB9IGVsc2UgaWYgKHJvb3QuVVJJID09PSB0aGlzKSB7CiAgICAgICAgICAgIHJvb3QuVVJJID0gX1VSSTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH07CiAgICAgICAgcDIuYnVpbGQgPSBmdW5jdGlvbihkZWZlckJ1aWxkKSB7CiAgICAgICAgICBpZiAoZGVmZXJCdWlsZCA9PT0gdHJ1ZSkgewogICAgICAgICAgICB0aGlzLl9kZWZlcnJlZF9idWlsZCA9IHRydWU7CiAgICAgICAgICB9IGVsc2UgaWYgKGRlZmVyQnVpbGQgPT09IHZvaWQgMCB8fCB0aGlzLl9kZWZlcnJlZF9idWlsZCkgewogICAgICAgICAgICB0aGlzLl9zdHJpbmcgPSBVUkkuYnVpbGQodGhpcy5fcGFydHMpOwogICAgICAgICAgICB0aGlzLl9kZWZlcnJlZF9idWlsZCA9IGZhbHNlOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICBwMi5jbG9uZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgcmV0dXJuIG5ldyBVUkkodGhpcyk7CiAgICAgICAgfTsKICAgICAgICBwMi52YWx1ZU9mID0gcDIudG9TdHJpbmcgPSBmdW5jdGlvbigpIHsKICAgICAgICAgIHJldHVybiB0aGlzLmJ1aWxkKGZhbHNlKS5fc3RyaW5nOwogICAgICAgIH07CiAgICAgICAgZnVuY3Rpb24gZ2VuZXJhdGVTaW1wbGVBY2Nlc3NvcihfcGFydDIpIHsKICAgICAgICAgIHJldHVybiBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgICAgaWYgKHY0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcGFydHNbX3BhcnQyXSB8fCAiIjsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB0aGlzLl9wYXJ0c1tfcGFydDJdID0gdjQgfHwgbnVsbDsKICAgICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICAgIH0KICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGdlbmVyYXRlUHJlZml4QWNjZXNzb3IoX3BhcnQyLCBfa2V5KSB7CiAgICAgICAgICByZXR1cm4gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnRzW19wYXJ0Ml0gfHwgIiI7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgaWYgKHY0ICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICB2NCA9IHY0ICsgIiI7CiAgICAgICAgICAgICAgICBpZiAodjQuY2hhckF0KDApID09PSBfa2V5KSB7CiAgICAgICAgICAgICAgICAgIHY0ID0gdjQuc3Vic3RyaW5nKDEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB0aGlzLl9wYXJ0c1tfcGFydDJdID0gdjQ7CiAgICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgICB9CiAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBwMi5wcm90b2NvbCA9IGdlbmVyYXRlU2ltcGxlQWNjZXNzb3IoInByb3RvY29sIik7CiAgICAgICAgcDIudXNlcm5hbWUgPSBnZW5lcmF0ZVNpbXBsZUFjY2Vzc29yKCJ1c2VybmFtZSIpOwogICAgICAgIHAyLnBhc3N3b3JkID0gZ2VuZXJhdGVTaW1wbGVBY2Nlc3NvcigicGFzc3dvcmQiKTsKICAgICAgICBwMi5ob3N0bmFtZSA9IGdlbmVyYXRlU2ltcGxlQWNjZXNzb3IoImhvc3RuYW1lIik7CiAgICAgICAgcDIucG9ydCA9IGdlbmVyYXRlU2ltcGxlQWNjZXNzb3IoInBvcnQiKTsKICAgICAgICBwMi5xdWVyeSA9IGdlbmVyYXRlUHJlZml4QWNjZXNzb3IoInF1ZXJ5IiwgIj8iKTsKICAgICAgICBwMi5mcmFnbWVudCA9IGdlbmVyYXRlUHJlZml4QWNjZXNzb3IoImZyYWdtZW50IiwgIiMiKTsKICAgICAgICBwMi5zZWFyY2ggPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIHZhciB0MiA9IHRoaXMucXVlcnkodjQsIGJ1aWxkKTsKICAgICAgICAgIHJldHVybiB0eXBlb2YgdDIgPT09ICJzdHJpbmciICYmIHQyLmxlbmd0aCA/ICI/IiArIHQyIDogdDI7CiAgICAgICAgfTsKICAgICAgICBwMi5oYXNoID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICB2YXIgdDIgPSB0aGlzLmZyYWdtZW50KHY0LCBidWlsZCk7CiAgICAgICAgICByZXR1cm4gdHlwZW9mIHQyID09PSAic3RyaW5nIiAmJiB0Mi5sZW5ndGggPyAiIyIgKyB0MiA6IHQyOwogICAgICAgIH07CiAgICAgICAgcDIucGF0aG5hbWUgPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwIHx8IHY0ID09PSB0cnVlKSB7CiAgICAgICAgICAgIHZhciByZXMgPSB0aGlzLl9wYXJ0cy5wYXRoIHx8ICh0aGlzLl9wYXJ0cy5ob3N0bmFtZSA/ICIvIiA6ICIiKTsKICAgICAgICAgICAgcmV0dXJuIHY0ID8gKHRoaXMuX3BhcnRzLnVybiA/IFVSSS5kZWNvZGVVcm5QYXRoIDogVVJJLmRlY29kZVBhdGgpKHJlcykgOiByZXM7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgICAgdGhpcy5fcGFydHMucGF0aCA9IHY0ID8gVVJJLnJlY29kZVVyblBhdGgodjQpIDogIiI7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdGhpcy5fcGFydHMucGF0aCA9IHY0ID8gVVJJLnJlY29kZVBhdGgodjQpIDogIi8iOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBwMi5wYXRoID0gcDIucGF0aG5hbWU7CiAgICAgICAgcDIuaHJlZiA9IGZ1bmN0aW9uKGhyZWYsIGJ1aWxkKSB7CiAgICAgICAgICB2YXIga2V5OwogICAgICAgICAgaWYgKGhyZWYgPT09IHZvaWQgMCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy50b1N0cmluZygpOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5fc3RyaW5nID0gIiI7CiAgICAgICAgICB0aGlzLl9wYXJ0cyA9IFVSSS5fcGFydHMoKTsKICAgICAgICAgIHZhciBfVVJJMiA9IGhyZWYgaW5zdGFuY2VvZiBVUkk7CiAgICAgICAgICB2YXIgX29iamVjdCA9IHR5cGVvZiBocmVmID09PSAib2JqZWN0IiAmJiAoaHJlZi5ob3N0bmFtZSB8fCBocmVmLnBhdGggfHwgaHJlZi5wYXRobmFtZSk7CiAgICAgICAgICBpZiAoaHJlZi5ub2RlTmFtZSkgewogICAgICAgICAgICB2YXIgYXR0cmlidXRlID0gVVJJLmdldERvbUF0dHJpYnV0ZShocmVmKTsKICAgICAgICAgICAgaHJlZiA9IGhyZWZbYXR0cmlidXRlXSB8fCAiIjsKICAgICAgICAgICAgX29iamVjdCA9IGZhbHNlOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFfVVJJMiAmJiBfb2JqZWN0ICYmIGhyZWYucGF0aG5hbWUgIT09IHZvaWQgMCkgewogICAgICAgICAgICBocmVmID0gaHJlZi50b1N0cmluZygpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHR5cGVvZiBocmVmID09PSAic3RyaW5nIiB8fCBocmVmIGluc3RhbmNlb2YgU3RyaW5nKSB7CiAgICAgICAgICAgIHRoaXMuX3BhcnRzID0gVVJJLnBhcnNlKFN0cmluZyhocmVmKSwgdGhpcy5fcGFydHMpOwogICAgICAgICAgfSBlbHNlIGlmIChfVVJJMiB8fCBfb2JqZWN0KSB7CiAgICAgICAgICAgIHZhciBzcmMgPSBfVVJJMiA/IGhyZWYuX3BhcnRzIDogaHJlZjsKICAgICAgICAgICAgZm9yIChrZXkgaW4gc3JjKSB7CiAgICAgICAgICAgICAgaWYgKGtleSA9PT0gInF1ZXJ5IikgewogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbCh0aGlzLl9wYXJ0cywga2V5KSkgewogICAgICAgICAgICAgICAgdGhpcy5fcGFydHNba2V5XSA9IHNyY1trZXldOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoc3JjLnF1ZXJ5KSB7CiAgICAgICAgICAgICAgdGhpcy5xdWVyeShzcmMucXVlcnksIGZhbHNlKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigiaW52YWxpZCBpbnB1dCIpOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICBwMi5pcyA9IGZ1bmN0aW9uKHdoYXQpIHsKICAgICAgICAgIHZhciBpcCA9IGZhbHNlOwogICAgICAgICAgdmFyIGlwNCA9IGZhbHNlOwogICAgICAgICAgdmFyIGlwNiA9IGZhbHNlOwogICAgICAgICAgdmFyIG5hbWUgPSBmYWxzZTsKICAgICAgICAgIHZhciBzbGQgPSBmYWxzZTsKICAgICAgICAgIHZhciBpZG4gPSBmYWxzZTsKICAgICAgICAgIHZhciBwdW55Y29kZTIgPSBmYWxzZTsKICAgICAgICAgIHZhciByZWxhdGl2ZSA9ICF0aGlzLl9wYXJ0cy51cm47CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMuaG9zdG5hbWUpIHsKICAgICAgICAgICAgcmVsYXRpdmUgPSBmYWxzZTsKICAgICAgICAgICAgaXA0ID0gVVJJLmlwNF9leHByZXNzaW9uLnRlc3QodGhpcy5fcGFydHMuaG9zdG5hbWUpOwogICAgICAgICAgICBpcDYgPSBVUkkuaXA2X2V4cHJlc3Npb24udGVzdCh0aGlzLl9wYXJ0cy5ob3N0bmFtZSk7CiAgICAgICAgICAgIGlwID0gaXA0IHx8IGlwNjsKICAgICAgICAgICAgbmFtZSA9ICFpcDsKICAgICAgICAgICAgc2xkID0gbmFtZSAmJiBTTEQgJiYgU0xELmhhcyh0aGlzLl9wYXJ0cy5ob3N0bmFtZSk7CiAgICAgICAgICAgIGlkbiA9IG5hbWUgJiYgVVJJLmlkbl9leHByZXNzaW9uLnRlc3QodGhpcy5fcGFydHMuaG9zdG5hbWUpOwogICAgICAgICAgICBwdW55Y29kZTIgPSBuYW1lICYmIFVSSS5wdW55Y29kZV9leHByZXNzaW9uLnRlc3QodGhpcy5fcGFydHMuaG9zdG5hbWUpOwogICAgICAgICAgfQogICAgICAgICAgc3dpdGNoICh3aGF0LnRvTG93ZXJDYXNlKCkpIHsKICAgICAgICAgICAgY2FzZSAicmVsYXRpdmUiOgogICAgICAgICAgICAgIHJldHVybiByZWxhdGl2ZTsKICAgICAgICAgICAgY2FzZSAiYWJzb2x1dGUiOgogICAgICAgICAgICAgIHJldHVybiAhcmVsYXRpdmU7CiAgICAgICAgICAgIC8vIGhvc3RuYW1lIGlkZW50aWZpY2F0aW9uCiAgICAgICAgICAgIGNhc2UgImRvbWFpbiI6CiAgICAgICAgICAgIGNhc2UgIm5hbWUiOgogICAgICAgICAgICAgIHJldHVybiBuYW1lOwogICAgICAgICAgICBjYXNlICJzbGQiOgogICAgICAgICAgICAgIHJldHVybiBzbGQ7CiAgICAgICAgICAgIGNhc2UgImlwIjoKICAgICAgICAgICAgICByZXR1cm4gaXA7CiAgICAgICAgICAgIGNhc2UgImlwNCI6CiAgICAgICAgICAgIGNhc2UgImlwdjQiOgogICAgICAgICAgICBjYXNlICJpbmV0NCI6CiAgICAgICAgICAgICAgcmV0dXJuIGlwNDsKICAgICAgICAgICAgY2FzZSAiaXA2IjoKICAgICAgICAgICAgY2FzZSAiaXB2NiI6CiAgICAgICAgICAgIGNhc2UgImluZXQ2IjoKICAgICAgICAgICAgICByZXR1cm4gaXA2OwogICAgICAgICAgICBjYXNlICJpZG4iOgogICAgICAgICAgICAgIHJldHVybiBpZG47CiAgICAgICAgICAgIGNhc2UgInVybCI6CiAgICAgICAgICAgICAgcmV0dXJuICF0aGlzLl9wYXJ0cy51cm47CiAgICAgICAgICAgIGNhc2UgInVybiI6CiAgICAgICAgICAgICAgcmV0dXJuICEhdGhpcy5fcGFydHMudXJuOwogICAgICAgICAgICBjYXNlICJwdW55Y29kZSI6CiAgICAgICAgICAgICAgcmV0dXJuIHB1bnljb2RlMjsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgIH07CiAgICAgICAgdmFyIF9wcm90b2NvbCA9IHAyLnByb3RvY29sOwogICAgICAgIHZhciBfcG9ydCA9IHAyLnBvcnQ7CiAgICAgICAgdmFyIF9ob3N0bmFtZSA9IHAyLmhvc3RuYW1lOwogICAgICAgIHAyLnByb3RvY29sID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICBpZiAodjQpIHsKICAgICAgICAgICAgdjQgPSB2NC5yZXBsYWNlKC86KFwvXC8pPyQvLCAiIik7CiAgICAgICAgICAgIGlmICghdjQubWF0Y2goVVJJLnByb3RvY29sX2V4cHJlc3Npb24pKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignUHJvdG9jb2wgIicgKyB2NCArIGAiIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05ListXSBvciBkb2Vzbid0IHN0YXJ0IHdpdGggW0EtWl1gKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIF9wcm90b2NvbC5jYWxsKHRoaXMsIHY0LCBidWlsZCk7CiAgICAgICAgfTsKICAgICAgICBwMi5zY2hlbWUgPSBwMi5wcm90b2NvbDsKICAgICAgICBwMi5wb3J0ID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgIHJldHVybiB2NCA9PT0gdm9pZCAwID8gIiIgOiB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHY0ICE9PSB2b2lkIDApIHsKICAgICAgICAgICAgaWYgKHY0ID09PSAwKSB7CiAgICAgICAgICAgICAgdjQgPSBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2NCkgewogICAgICAgICAgICAgIHY0ICs9ICIiOwogICAgICAgICAgICAgIGlmICh2NC5jaGFyQXQoMCkgPT09ICI6IikgewogICAgICAgICAgICAgICAgdjQgPSB2NC5zdWJzdHJpbmcoMSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIFVSSS5lbnN1cmVWYWxpZFBvcnQodjQpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gX3BvcnQuY2FsbCh0aGlzLCB2NCwgYnVpbGQpOwogICAgICAgIH07CiAgICAgICAgcDIuaG9zdG5hbWUgPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIGlmICh0aGlzLl9wYXJ0cy51cm4pIHsKICAgICAgICAgICAgcmV0dXJuIHY0ID09PSB2b2lkIDAgPyAiIiA6IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodjQgIT09IHZvaWQgMCkgewogICAgICAgICAgICB2YXIgeDIgPSB7IHByZXZlbnRJbnZhbGlkSG9zdG5hbWU6IHRoaXMuX3BhcnRzLnByZXZlbnRJbnZhbGlkSG9zdG5hbWUgfTsKICAgICAgICAgICAgdmFyIHJlcyA9IFVSSS5wYXJzZUhvc3QodjQsIHgyKTsKICAgICAgICAgICAgaWYgKHJlcyAhPT0gIi8iKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSG9zdG5hbWUgIicgKyB2NCArICciIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05Li1dJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdjQgPSB4Mi5ob3N0bmFtZTsKICAgICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnByZXZlbnRJbnZhbGlkSG9zdG5hbWUpIHsKICAgICAgICAgICAgICBVUkkuZW5zdXJlVmFsaWRIb3N0bmFtZSh2NCwgdGhpcy5fcGFydHMucHJvdG9jb2wpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gX2hvc3RuYW1lLmNhbGwodGhpcywgdjQsIGJ1aWxkKTsKICAgICAgICB9OwogICAgICAgIHAyLm9yaWdpbiA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdjQgPT09IHZvaWQgMCA/ICIiIDogdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIHZhciBwcm90b2NvbCA9IHRoaXMucHJvdG9jb2woKTsKICAgICAgICAgICAgdmFyIGF1dGhvcml0eSA9IHRoaXMuYXV0aG9yaXR5KCk7CiAgICAgICAgICAgIGlmICghYXV0aG9yaXR5KSB7CiAgICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiAocHJvdG9jb2wgPyBwcm90b2NvbCArICI6Ly8iIDogIiIpICsgdGhpcy5hdXRob3JpdHkoKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBvcmlnaW4gPSBVUkkodjQpOwogICAgICAgICAgICB0aGlzLnByb3RvY29sKG9yaWdpbi5wcm90b2NvbCgpKS5hdXRob3JpdHkob3JpZ2luLmF1dGhvcml0eSgpKS5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLmhvc3QgPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIGlmICh0aGlzLl9wYXJ0cy51cm4pIHsKICAgICAgICAgICAgcmV0dXJuIHY0ID09PSB2b2lkIDAgPyAiIiA6IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodjQgPT09IHZvaWQgMCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fcGFydHMuaG9zdG5hbWUgPyBVUkkuYnVpbGRIb3N0KHRoaXMuX3BhcnRzKSA6ICIiOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdmFyIHJlcyA9IFVSSS5wYXJzZUhvc3QodjQsIHRoaXMuX3BhcnRzKTsKICAgICAgICAgICAgaWYgKHJlcyAhPT0gIi8iKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSG9zdG5hbWUgIicgKyB2NCArICciIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05Li1dJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLmF1dGhvcml0eSA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdjQgPT09IHZvaWQgMCA/ICIiIDogdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9wYXJ0cy5ob3N0bmFtZSA/IFVSSS5idWlsZEF1dGhvcml0eSh0aGlzLl9wYXJ0cykgOiAiIjsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciByZXMgPSBVUkkucGFyc2VBdXRob3JpdHkodjQsIHRoaXMuX3BhcnRzKTsKICAgICAgICAgICAgaWYgKHJlcyAhPT0gIi8iKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignSG9zdG5hbWUgIicgKyB2NCArICciIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05Li1dJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLnVzZXJpbmZvID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgIHJldHVybiB2NCA9PT0gdm9pZCAwID8gIiIgOiB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHY0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgdmFyIHQyID0gVVJJLmJ1aWxkVXNlcmluZm8odGhpcy5fcGFydHMpOwogICAgICAgICAgICByZXR1cm4gdDIgPyB0Mi5zdWJzdHJpbmcoMCwgdDIubGVuZ3RoIC0gMSkgOiB0MjsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmICh2NFt2NC5sZW5ndGggLSAxXSAhPT0gIkAiKSB7CiAgICAgICAgICAgICAgdjQgKz0gIkAiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIFVSSS5wYXJzZVVzZXJpbmZvKHY0LCB0aGlzLl9wYXJ0cyk7CiAgICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBwMi5yZXNvdXJjZSA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgdmFyIHBhcnRzOwogICAgICAgICAgaWYgKHY0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucGF0aCgpICsgdGhpcy5zZWFyY2goKSArIHRoaXMuaGFzaCgpOwogICAgICAgICAgfQogICAgICAgICAgcGFydHMgPSBVUkkucGFyc2UodjQpOwogICAgICAgICAgdGhpcy5fcGFydHMucGF0aCA9IHBhcnRzLnBhdGg7CiAgICAgICAgICB0aGlzLl9wYXJ0cy5xdWVyeSA9IHBhcnRzLnF1ZXJ5OwogICAgICAgICAgdGhpcy5fcGFydHMuZnJhZ21lbnQgPSBwYXJ0cy5mcmFnbWVudDsKICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH07CiAgICAgICAgcDIuc3ViZG9tYWluID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgIHJldHVybiB2NCA9PT0gdm9pZCAwID8gIiIgOiB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHY0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgaWYgKCF0aGlzLl9wYXJ0cy5ob3N0bmFtZSB8fCB0aGlzLmlzKCJJUCIpKSB7CiAgICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBlbmQgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5sZW5ndGggLSB0aGlzLmRvbWFpbigpLmxlbmd0aCAtIDE7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5zdWJzdHJpbmcoMCwgZW5kKSB8fCAiIjsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBlMiA9IHRoaXMuX3BhcnRzLmhvc3RuYW1lLmxlbmd0aCAtIHRoaXMuZG9tYWluKCkubGVuZ3RoOwogICAgICAgICAgICB2YXIgc3ViID0gdGhpcy5fcGFydHMuaG9zdG5hbWUuc3Vic3RyaW5nKDAsIGUyKTsKICAgICAgICAgICAgdmFyIHJlcGxhY2UgPSBuZXcgUmVnRXhwKCJeIiArIGVzY2FwZVJlZ0V4KHN1YikpOwogICAgICAgICAgICBpZiAodjQgJiYgdjQuY2hhckF0KHY0Lmxlbmd0aCAtIDEpICE9PSAiLiIpIHsKICAgICAgICAgICAgICB2NCArPSAiLiI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHY0LmluZGV4T2YoIjoiKSAhPT0gLTEpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJEb21haW5zIGNhbm5vdCBjb250YWluIGNvbG9ucyIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2NCkgewogICAgICAgICAgICAgIFVSSS5lbnN1cmVWYWxpZEhvc3RuYW1lKHY0LCB0aGlzLl9wYXJ0cy5wcm90b2NvbCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5fcGFydHMuaG9zdG5hbWUgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5yZXBsYWNlKHJlcGxhY2UsIHY0KTsKICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLmRvbWFpbiA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdjQgPT09IHZvaWQgMCA/ICIiIDogdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh0eXBlb2YgdjQgPT09ICJib29sZWFuIikgewogICAgICAgICAgICBidWlsZCA9IHY0OwogICAgICAgICAgICB2NCA9IHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIGlmICghdGhpcy5fcGFydHMuaG9zdG5hbWUgfHwgdGhpcy5pcygiSVAiKSkgewogICAgICAgICAgICAgIHJldHVybiAiIjsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgdDIgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5tYXRjaCgvXC4vZyk7CiAgICAgICAgICAgIGlmICh0MiAmJiB0Mi5sZW5ndGggPCAyKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3BhcnRzLmhvc3RuYW1lOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBlbmQgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5sZW5ndGggLSB0aGlzLnRsZChidWlsZCkubGVuZ3RoIC0gMTsKICAgICAgICAgICAgZW5kID0gdGhpcy5fcGFydHMuaG9zdG5hbWUubGFzdEluZGV4T2YoIi4iLCBlbmQgLSAxKSArIDE7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5zdWJzdHJpbmcoZW5kKSB8fCAiIjsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmICghdjQpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJjYW5ub3Qgc2V0IGRvbWFpbiBlbXB0eSIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2NC5pbmRleE9mKCI6IikgIT09IC0xKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigiRG9tYWlucyBjYW5ub3QgY29udGFpbiBjb2xvbnMiKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBVUkkuZW5zdXJlVmFsaWRIb3N0bmFtZSh2NCwgdGhpcy5fcGFydHMucHJvdG9jb2wpOwogICAgICAgICAgICBpZiAoIXRoaXMuX3BhcnRzLmhvc3RuYW1lIHx8IHRoaXMuaXMoIklQIikpIHsKICAgICAgICAgICAgICB0aGlzLl9wYXJ0cy5ob3N0bmFtZSA9IHY0OwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHZhciByZXBsYWNlID0gbmV3IFJlZ0V4cChlc2NhcGVSZWdFeCh0aGlzLmRvbWFpbigpKSArICIkIik7CiAgICAgICAgICAgICAgdGhpcy5fcGFydHMuaG9zdG5hbWUgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5yZXBsYWNlKHJlcGxhY2UsIHY0KTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgcDIudGxkID0gZnVuY3Rpb24odjQsIGJ1aWxkKSB7CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgIHJldHVybiB2NCA9PT0gdm9pZCAwID8gIiIgOiB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHR5cGVvZiB2NCA9PT0gImJvb2xlYW4iKSB7CiAgICAgICAgICAgIGJ1aWxkID0gdjQ7CiAgICAgICAgICAgIHY0ID0gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHY0ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgaWYgKCF0aGlzLl9wYXJ0cy5ob3N0bmFtZSB8fCB0aGlzLmlzKCJJUCIpKSB7CiAgICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBwb3MgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS5sYXN0SW5kZXhPZigiLiIpOwogICAgICAgICAgICB2YXIgdGxkID0gdGhpcy5fcGFydHMuaG9zdG5hbWUuc3Vic3RyaW5nKHBvcyArIDEpOwogICAgICAgICAgICBpZiAoYnVpbGQgIT09IHRydWUgJiYgU0xEICYmIFNMRC5saXN0W3RsZC50b0xvd2VyQ2FzZSgpXSkgewogICAgICAgICAgICAgIHJldHVybiBTTEQuZ2V0KHRoaXMuX3BhcnRzLmhvc3RuYW1lKSB8fCB0bGQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRsZDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciByZXBsYWNlOwogICAgICAgICAgICBpZiAoIXY0KSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigiY2Fubm90IHNldCBUTEQgZW1wdHkiKTsKICAgICAgICAgICAgfSBlbHNlIGlmICh2NC5tYXRjaCgvW15hLXpBLVowLTktXS8pKSB7CiAgICAgICAgICAgICAgaWYgKFNMRCAmJiBTTEQuaXModjQpKSB7CiAgICAgICAgICAgICAgICByZXBsYWNlID0gbmV3IFJlZ0V4cChlc2NhcGVSZWdFeCh0aGlzLnRsZCgpKSArICIkIik7CiAgICAgICAgICAgICAgICB0aGlzLl9wYXJ0cy5ob3N0bmFtZSA9IHRoaXMuX3BhcnRzLmhvc3RuYW1lLnJlcGxhY2UocmVwbGFjZSwgdjQpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUTEQgIicgKyB2NCArICciIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBbQS1aMC05XScpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmICghdGhpcy5fcGFydHMuaG9zdG5hbWUgfHwgdGhpcy5pcygiSVAiKSkgewogICAgICAgICAgICAgIHRocm93IG5ldyBSZWZlcmVuY2VFcnJvcigiY2Fubm90IHNldCBUTEQgb24gbm9uLWRvbWFpbiBob3N0Iik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmVwbGFjZSA9IG5ldyBSZWdFeHAoZXNjYXBlUmVnRXgodGhpcy50bGQoKSkgKyAiJCIpOwogICAgICAgICAgICAgIHRoaXMuX3BhcnRzLmhvc3RuYW1lID0gdGhpcy5fcGFydHMuaG9zdG5hbWUucmVwbGFjZShyZXBsYWNlLCB2NCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLmRpcmVjdG9yeSA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdjQgPT09IHZvaWQgMCA/ICIiIDogdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwIHx8IHY0ID09PSB0cnVlKSB7CiAgICAgICAgICAgIGlmICghdGhpcy5fcGFydHMucGF0aCAmJiAhdGhpcy5fcGFydHMuaG9zdG5hbWUpIHsKICAgICAgICAgICAgICByZXR1cm4gIiI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnBhdGggPT09ICIvIikgewogICAgICAgICAgICAgIHJldHVybiAiLyI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGVuZCA9IHRoaXMuX3BhcnRzLnBhdGgubGVuZ3RoIC0gdGhpcy5maWxlbmFtZSgpLmxlbmd0aCAtIDE7CiAgICAgICAgICAgIHZhciByZXMgPSB0aGlzLl9wYXJ0cy5wYXRoLnN1YnN0cmluZygwLCBlbmQpIHx8ICh0aGlzLl9wYXJ0cy5ob3N0bmFtZSA/ICIvIiA6ICIiKTsKICAgICAgICAgICAgcmV0dXJuIHY0ID8gVVJJLmRlY29kZVBhdGgocmVzKSA6IHJlczsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciBlMiA9IHRoaXMuX3BhcnRzLnBhdGgubGVuZ3RoIC0gdGhpcy5maWxlbmFtZSgpLmxlbmd0aDsKICAgICAgICAgICAgdmFyIGRpcmVjdG9yeSA9IHRoaXMuX3BhcnRzLnBhdGguc3Vic3RyaW5nKDAsIGUyKTsKICAgICAgICAgICAgdmFyIHJlcGxhY2UgPSBuZXcgUmVnRXhwKCJeIiArIGVzY2FwZVJlZ0V4KGRpcmVjdG9yeSkpOwogICAgICAgICAgICBpZiAoIXRoaXMuaXMoInJlbGF0aXZlIikpIHsKICAgICAgICAgICAgICBpZiAoIXY0KSB7CiAgICAgICAgICAgICAgICB2NCA9ICIvIjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHY0LmNoYXJBdCgwKSAhPT0gIi8iKSB7CiAgICAgICAgICAgICAgICB2NCA9ICIvIiArIHY0OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodjQgJiYgdjQuY2hhckF0KHY0Lmxlbmd0aCAtIDEpICE9PSAiLyIpIHsKICAgICAgICAgICAgICB2NCArPSAiLyI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdjQgPSBVUkkucmVjb2RlUGF0aCh2NCk7CiAgICAgICAgICAgIHRoaXMuX3BhcnRzLnBhdGggPSB0aGlzLl9wYXJ0cy5wYXRoLnJlcGxhY2UocmVwbGFjZSwgdjQpOwogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgcDIuZmlsZW5hbWUgPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIGlmICh0aGlzLl9wYXJ0cy51cm4pIHsKICAgICAgICAgICAgcmV0dXJuIHY0ID09PSB2b2lkIDAgPyAiIiA6IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodHlwZW9mIHY0ICE9PSAic3RyaW5nIikgewogICAgICAgICAgICBpZiAoIXRoaXMuX3BhcnRzLnBhdGggfHwgdGhpcy5fcGFydHMucGF0aCA9PT0gIi8iKSB7CiAgICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBwb3MgPSB0aGlzLl9wYXJ0cy5wYXRoLmxhc3RJbmRleE9mKCIvIik7CiAgICAgICAgICAgIHZhciByZXMgPSB0aGlzLl9wYXJ0cy5wYXRoLnN1YnN0cmluZyhwb3MgKyAxKTsKICAgICAgICAgICAgcmV0dXJuIHY0ID8gVVJJLmRlY29kZVBhdGhTZWdtZW50KHJlcykgOiByZXM7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB2YXIgbXV0YXRlZERpcmVjdG9yeSA9IGZhbHNlOwogICAgICAgICAgICBpZiAodjQuY2hhckF0KDApID09PSAiLyIpIHsKICAgICAgICAgICAgICB2NCA9IHY0LnN1YnN0cmluZygxKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodjQubWF0Y2goL1wuP1wvLykpIHsKICAgICAgICAgICAgICBtdXRhdGVkRGlyZWN0b3J5ID0gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgcmVwbGFjZSA9IG5ldyBSZWdFeHAoZXNjYXBlUmVnRXgodGhpcy5maWxlbmFtZSgpKSArICIkIik7CiAgICAgICAgICAgIHY0ID0gVVJJLnJlY29kZVBhdGgodjQpOwogICAgICAgICAgICB0aGlzLl9wYXJ0cy5wYXRoID0gdGhpcy5fcGFydHMucGF0aC5yZXBsYWNlKHJlcGxhY2UsIHY0KTsKICAgICAgICAgICAgaWYgKG11dGF0ZWREaXJlY3RvcnkpIHsKICAgICAgICAgICAgICB0aGlzLm5vcm1hbGl6ZVBhdGgoYnVpbGQpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHAyLnN1ZmZpeCA9IGZ1bmN0aW9uKHY0LCBidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdjQgPT09IHZvaWQgMCA/ICIiIDogdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwIHx8IHY0ID09PSB0cnVlKSB7CiAgICAgICAgICAgIGlmICghdGhpcy5fcGFydHMucGF0aCB8fCB0aGlzLl9wYXJ0cy5wYXRoID09PSAiLyIpIHsKICAgICAgICAgICAgICByZXR1cm4gIiI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGZpbGVuYW1lID0gdGhpcy5maWxlbmFtZSgpOwogICAgICAgICAgICB2YXIgcG9zID0gZmlsZW5hbWUubGFzdEluZGV4T2YoIi4iKTsKICAgICAgICAgICAgdmFyIHMyLCByZXM7CiAgICAgICAgICAgIGlmIChwb3MgPT09IC0xKSB7CiAgICAgICAgICAgICAgcmV0dXJuICIiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHMyID0gZmlsZW5hbWUuc3Vic3RyaW5nKHBvcyArIDEpOwogICAgICAgICAgICByZXMgPSAvXlthLXowLTklXSskL2kudGVzdChzMikgPyBzMiA6ICIiOwogICAgICAgICAgICByZXR1cm4gdjQgPyBVUkkuZGVjb2RlUGF0aFNlZ21lbnQocmVzKSA6IHJlczsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmICh2NC5jaGFyQXQoMCkgPT09ICIuIikgewogICAgICAgICAgICAgIHY0ID0gdjQuc3Vic3RyaW5nKDEpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBzdWZmaXggPSB0aGlzLnN1ZmZpeCgpOwogICAgICAgICAgICB2YXIgcmVwbGFjZTsKICAgICAgICAgICAgaWYgKCFzdWZmaXgpIHsKICAgICAgICAgICAgICBpZiAoIXY0KSB7CiAgICAgICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdGhpcy5fcGFydHMucGF0aCArPSAiLiIgKyBVUkkucmVjb2RlUGF0aCh2NCk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoIXY0KSB7CiAgICAgICAgICAgICAgcmVwbGFjZSA9IG5ldyBSZWdFeHAoZXNjYXBlUmVnRXgoIi4iICsgc3VmZml4KSArICIkIik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmVwbGFjZSA9IG5ldyBSZWdFeHAoZXNjYXBlUmVnRXgoc3VmZml4KSArICIkIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHJlcGxhY2UpIHsKICAgICAgICAgICAgICB2NCA9IFVSSS5yZWNvZGVQYXRoKHY0KTsKICAgICAgICAgICAgICB0aGlzLl9wYXJ0cy5wYXRoID0gdGhpcy5fcGFydHMucGF0aC5yZXBsYWNlKHJlcGxhY2UsIHY0KTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgcDIuc2VnbWVudCA9IGZ1bmN0aW9uKHNlZ21lbnQsIHY0LCBidWlsZCkgewogICAgICAgICAgdmFyIHNlcGFyYXRvciA9IHRoaXMuX3BhcnRzLnVybiA/ICI6IiA6ICIvIjsKICAgICAgICAgIHZhciBwYXRoID0gdGhpcy5wYXRoKCk7CiAgICAgICAgICB2YXIgYWJzb2x1dGUgPSBwYXRoLnN1YnN0cmluZygwLCAxKSA9PT0gIi8iOwogICAgICAgICAgdmFyIHNlZ21lbnRzID0gcGF0aC5zcGxpdChzZXBhcmF0b3IpOwogICAgICAgICAgaWYgKHNlZ21lbnQgIT09IHZvaWQgMCAmJiB0eXBlb2Ygc2VnbWVudCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgICAgYnVpbGQgPSB2NDsKICAgICAgICAgICAgdjQgPSBzZWdtZW50OwogICAgICAgICAgICBzZWdtZW50ID0gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHNlZ21lbnQgIT09IHZvaWQgMCAmJiB0eXBlb2Ygc2VnbWVudCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdCYWQgc2VnbWVudCAiJyArIHNlZ21lbnQgKyAnIiwgbXVzdCBiZSAwLWJhc2VkIGludGVnZXInKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChhYnNvbHV0ZSkgewogICAgICAgICAgICBzZWdtZW50cy5zaGlmdCgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHNlZ21lbnQgPCAwKSB7CiAgICAgICAgICAgIHNlZ21lbnQgPSBNYXRoLm1heChzZWdtZW50cy5sZW5ndGggKyBzZWdtZW50LCAwKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2NCA9PT0gdm9pZCAwKSB7CiAgICAgICAgICAgIHJldHVybiBzZWdtZW50ID09PSB2b2lkIDAgPyBzZWdtZW50cyA6IHNlZ21lbnRzW3NlZ21lbnRdOwogICAgICAgICAgfSBlbHNlIGlmIChzZWdtZW50ID09PSBudWxsIHx8IHNlZ21lbnRzW3NlZ21lbnRdID09PSB2b2lkIDApIHsKICAgICAgICAgICAgaWYgKGlzQXJyYXkodjQpKSB7CiAgICAgICAgICAgICAgc2VnbWVudHMgPSBbXTsKICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDAsIGwyID0gdjQubGVuZ3RoOyBpMiA8IGwyOyBpMisrKSB7CiAgICAgICAgICAgICAgICBpZiAoIXY0W2kyXS5sZW5ndGggJiYgKCFzZWdtZW50cy5sZW5ndGggfHwgIXNlZ21lbnRzW3NlZ21lbnRzLmxlbmd0aCAtIDFdLmxlbmd0aCkpIHsKICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoc2VnbWVudHMubGVuZ3RoICYmICFzZWdtZW50c1tzZWdtZW50cy5sZW5ndGggLSAxXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgc2VnbWVudHMucG9wKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzZWdtZW50cy5wdXNoKHRyaW1TbGFzaGVzKHY0W2kyXSkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmICh2NCB8fCB0eXBlb2YgdjQgPT09ICJzdHJpbmciKSB7CiAgICAgICAgICAgICAgdjQgPSB0cmltU2xhc2hlcyh2NCk7CiAgICAgICAgICAgICAgaWYgKHNlZ21lbnRzW3NlZ21lbnRzLmxlbmd0aCAtIDFdID09PSAiIikgewogICAgICAgICAgICAgICAgc2VnbWVudHNbc2VnbWVudHMubGVuZ3RoIC0gMV0gPSB2NDsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgc2VnbWVudHMucHVzaCh2NCk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpZiAodjQpIHsKICAgICAgICAgICAgICBzZWdtZW50c1tzZWdtZW50XSA9IHRyaW1TbGFzaGVzKHY0KTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBzZWdtZW50cy5zcGxpY2Uoc2VnbWVudCwgMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChhYnNvbHV0ZSkgewogICAgICAgICAgICBzZWdtZW50cy51bnNoaWZ0KCIiKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzLnBhdGgoc2VnbWVudHMuam9pbihzZXBhcmF0b3IpLCBidWlsZCk7CiAgICAgICAgfTsKICAgICAgICBwMi5zZWdtZW50Q29kZWQgPSBmdW5jdGlvbihzZWdtZW50LCB2NCwgYnVpbGQpIHsKICAgICAgICAgIHZhciBzZWdtZW50cywgaTIsIGwyOwogICAgICAgICAgaWYgKHR5cGVvZiBzZWdtZW50ICE9PSAibnVtYmVyIikgewogICAgICAgICAgICBidWlsZCA9IHY0OwogICAgICAgICAgICB2NCA9IHNlZ21lbnQ7CiAgICAgICAgICAgIHNlZ21lbnQgPSB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodjQgPT09IHZvaWQgMCkgewogICAgICAgICAgICBzZWdtZW50cyA9IHRoaXMuc2VnbWVudChzZWdtZW50LCB2NCwgYnVpbGQpOwogICAgICAgICAgICBpZiAoIWlzQXJyYXkoc2VnbWVudHMpKSB7CiAgICAgICAgICAgICAgc2VnbWVudHMgPSBzZWdtZW50cyAhPT0gdm9pZCAwID8gVVJJLmRlY29kZShzZWdtZW50cykgOiB2b2lkIDA7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZm9yIChpMiA9IDAsIGwyID0gc2VnbWVudHMubGVuZ3RoOyBpMiA8IGwyOyBpMisrKSB7CiAgICAgICAgICAgICAgICBzZWdtZW50c1tpMl0gPSBVUkkuZGVjb2RlKHNlZ21lbnRzW2kyXSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBzZWdtZW50czsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghaXNBcnJheSh2NCkpIHsKICAgICAgICAgICAgdjQgPSB0eXBlb2YgdjQgPT09ICJzdHJpbmciIHx8IHY0IGluc3RhbmNlb2YgU3RyaW5nID8gVVJJLmVuY29kZSh2NCkgOiB2NDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGZvciAoaTIgPSAwLCBsMiA9IHY0Lmxlbmd0aDsgaTIgPCBsMjsgaTIrKykgewogICAgICAgICAgICAgIHY0W2kyXSA9IFVSSS5lbmNvZGUodjRbaTJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRoaXMuc2VnbWVudChzZWdtZW50LCB2NCwgYnVpbGQpOwogICAgICAgIH07CiAgICAgICAgdmFyIHEzID0gcDIucXVlcnk7CiAgICAgICAgcDIucXVlcnkgPSBmdW5jdGlvbih2NCwgYnVpbGQpIHsKICAgICAgICAgIGlmICh2NCA9PT0gdHJ1ZSkgewogICAgICAgICAgICByZXR1cm4gVVJJLnBhcnNlUXVlcnkodGhpcy5fcGFydHMucXVlcnksIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpOwogICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdjQgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgdmFyIGRhdGEgPSBVUkkucGFyc2VRdWVyeSh0aGlzLl9wYXJ0cy5xdWVyeSwgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICAgIHZhciByZXN1bHQgPSB2NC5jYWxsKHRoaXMsIGRhdGEpOwogICAgICAgICAgICB0aGlzLl9wYXJ0cy5xdWVyeSA9IFVSSS5idWlsZFF1ZXJ5KHJlc3VsdCB8fCBkYXRhLCB0aGlzLl9wYXJ0cy5kdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMsIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpOwogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfSBlbHNlIGlmICh2NCAhPT0gdm9pZCAwICYmIHR5cGVvZiB2NCAhPT0gInN0cmluZyIpIHsKICAgICAgICAgICAgdGhpcy5fcGFydHMucXVlcnkgPSBVUkkuYnVpbGRRdWVyeSh2NCwgdGhpcy5fcGFydHMuZHVwbGljYXRlUXVlcnlQYXJhbWV0ZXJzLCB0aGlzLl9wYXJ0cy5lc2NhcGVRdWVyeVNwYWNlKTsKICAgICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiBxMy5jYWxsKHRoaXMsIHY0LCBidWlsZCk7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBwMi5zZXRRdWVyeSA9IGZ1bmN0aW9uKG5hbWUsIHZhbHVlLCBidWlsZCkgewogICAgICAgICAgdmFyIGRhdGEgPSBVUkkucGFyc2VRdWVyeSh0aGlzLl9wYXJ0cy5xdWVyeSwgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICBpZiAodHlwZW9mIG5hbWUgPT09ICJzdHJpbmciIHx8IG5hbWUgaW5zdGFuY2VvZiBTdHJpbmcpIHsKICAgICAgICAgICAgZGF0YVtuYW1lXSA9IHZhbHVlICE9PSB2b2lkIDAgPyB2YWx1ZSA6IG51bGw7CiAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBuYW1lID09PSAib2JqZWN0IikgewogICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gbmFtZSkgewogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChuYW1lLCBrZXkpKSB7CiAgICAgICAgICAgICAgICBkYXRhW2tleV0gPSBuYW1lW2tleV07CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVUkkuYWRkUXVlcnkoKSBhY2NlcHRzIGFuIG9iamVjdCwgc3RyaW5nIGFzIHRoZSBuYW1lIHBhcmFtZXRlciIpOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5fcGFydHMucXVlcnkgPSBVUkkuYnVpbGRRdWVyeShkYXRhLCB0aGlzLl9wYXJ0cy5kdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMsIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpOwogICAgICAgICAgaWYgKHR5cGVvZiBuYW1lICE9PSAic3RyaW5nIikgewogICAgICAgICAgICBidWlsZCA9IHZhbHVlOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5idWlsZCghYnVpbGQpOwogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICBwMi5hZGRRdWVyeSA9IGZ1bmN0aW9uKG5hbWUsIHZhbHVlLCBidWlsZCkgewogICAgICAgICAgdmFyIGRhdGEgPSBVUkkucGFyc2VRdWVyeSh0aGlzLl9wYXJ0cy5xdWVyeSwgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICBVUkkuYWRkUXVlcnkoZGF0YSwgbmFtZSwgdmFsdWUgPT09IHZvaWQgMCA/IG51bGwgOiB2YWx1ZSk7CiAgICAgICAgICB0aGlzLl9wYXJ0cy5xdWVyeSA9IFVSSS5idWlsZFF1ZXJ5KGRhdGEsIHRoaXMuX3BhcnRzLmR1cGxpY2F0ZVF1ZXJ5UGFyYW1ldGVycywgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICBpZiAodHlwZW9mIG5hbWUgIT09ICJzdHJpbmciKSB7CiAgICAgICAgICAgIGJ1aWxkID0gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLnJlbW92ZVF1ZXJ5ID0gZnVuY3Rpb24obmFtZSwgdmFsdWUsIGJ1aWxkKSB7CiAgICAgICAgICB2YXIgZGF0YSA9IFVSSS5wYXJzZVF1ZXJ5KHRoaXMuX3BhcnRzLnF1ZXJ5LCB0aGlzLl9wYXJ0cy5lc2NhcGVRdWVyeVNwYWNlKTsKICAgICAgICAgIFVSSS5yZW1vdmVRdWVyeShkYXRhLCBuYW1lLCB2YWx1ZSk7CiAgICAgICAgICB0aGlzLl9wYXJ0cy5xdWVyeSA9IFVSSS5idWlsZFF1ZXJ5KGRhdGEsIHRoaXMuX3BhcnRzLmR1cGxpY2F0ZVF1ZXJ5UGFyYW1ldGVycywgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICBpZiAodHlwZW9mIG5hbWUgIT09ICJzdHJpbmciKSB7CiAgICAgICAgICAgIGJ1aWxkID0gdmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLmhhc1F1ZXJ5ID0gZnVuY3Rpb24obmFtZSwgdmFsdWUsIHdpdGhpbkFycmF5KSB7CiAgICAgICAgICB2YXIgZGF0YSA9IFVSSS5wYXJzZVF1ZXJ5KHRoaXMuX3BhcnRzLnF1ZXJ5LCB0aGlzLl9wYXJ0cy5lc2NhcGVRdWVyeVNwYWNlKTsKICAgICAgICAgIHJldHVybiBVUkkuaGFzUXVlcnkoZGF0YSwgbmFtZSwgdmFsdWUsIHdpdGhpbkFycmF5KTsKICAgICAgICB9OwogICAgICAgIHAyLnNldFNlYXJjaCA9IHAyLnNldFF1ZXJ5OwogICAgICAgIHAyLmFkZFNlYXJjaCA9IHAyLmFkZFF1ZXJ5OwogICAgICAgIHAyLnJlbW92ZVNlYXJjaCA9IHAyLnJlbW92ZVF1ZXJ5OwogICAgICAgIHAyLmhhc1NlYXJjaCA9IHAyLmhhc1F1ZXJ5OwogICAgICAgIHAyLm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnVybikgewogICAgICAgICAgICByZXR1cm4gdGhpcy5ub3JtYWxpemVQcm90b2NvbChmYWxzZSkubm9ybWFsaXplUGF0aChmYWxzZSkubm9ybWFsaXplUXVlcnkoZmFsc2UpLm5vcm1hbGl6ZUZyYWdtZW50KGZhbHNlKS5idWlsZCgpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRoaXMubm9ybWFsaXplUHJvdG9jb2woZmFsc2UpLm5vcm1hbGl6ZUhvc3RuYW1lKGZhbHNlKS5ub3JtYWxpemVQb3J0KGZhbHNlKS5ub3JtYWxpemVQYXRoKGZhbHNlKS5ub3JtYWxpemVRdWVyeShmYWxzZSkubm9ybWFsaXplRnJhZ21lbnQoZmFsc2UpLmJ1aWxkKCk7CiAgICAgICAgfTsKICAgICAgICBwMi5ub3JtYWxpemVQcm90b2NvbCA9IGZ1bmN0aW9uKGJ1aWxkKSB7CiAgICAgICAgICBpZiAodHlwZW9mIHRoaXMuX3BhcnRzLnByb3RvY29sID09PSAic3RyaW5nIikgewogICAgICAgICAgICB0aGlzLl9wYXJ0cy5wcm90b2NvbCA9IHRoaXMuX3BhcnRzLnByb3RvY29sLnRvTG93ZXJDYXNlKCk7CiAgICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH07CiAgICAgICAgcDIubm9ybWFsaXplSG9zdG5hbWUgPSBmdW5jdGlvbihidWlsZCkgewogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLmhvc3RuYW1lKSB7CiAgICAgICAgICAgIGlmICh0aGlzLmlzKCJJRE4iKSAmJiBwdW55Y29kZSkgewogICAgICAgICAgICAgIHRoaXMuX3BhcnRzLmhvc3RuYW1lID0gcHVueWNvZGUudG9BU0NJSSh0aGlzLl9wYXJ0cy5ob3N0bmFtZSk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5pcygiSVB2NiIpICYmIElQdjYpIHsKICAgICAgICAgICAgICB0aGlzLl9wYXJ0cy5ob3N0bmFtZSA9IElQdjYuYmVzdCh0aGlzLl9wYXJ0cy5ob3N0bmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5fcGFydHMuaG9zdG5hbWUgPSB0aGlzLl9wYXJ0cy5ob3N0bmFtZS50b0xvd2VyQ2FzZSgpOwogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLm5vcm1hbGl6ZVBvcnQgPSBmdW5jdGlvbihidWlsZCkgewogICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLl9wYXJ0cy5wcm90b2NvbCA9PT0gInN0cmluZyIgJiYgdGhpcy5fcGFydHMucG9ydCA9PT0gVVJJLmRlZmF1bHRQb3J0c1t0aGlzLl9wYXJ0cy5wcm90b2NvbF0pIHsKICAgICAgICAgICAgdGhpcy5fcGFydHMucG9ydCA9IG51bGw7CiAgICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH07CiAgICAgICAgcDIubm9ybWFsaXplUGF0aCA9IGZ1bmN0aW9uKGJ1aWxkKSB7CiAgICAgICAgICB2YXIgX3BhdGggPSB0aGlzLl9wYXJ0cy5wYXRoOwogICAgICAgICAgaWYgKCFfcGF0aCkgewogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh0aGlzLl9wYXJ0cy51cm4pIHsKICAgICAgICAgICAgdGhpcy5fcGFydHMucGF0aCA9IFVSSS5yZWNvZGVVcm5QYXRoKHRoaXMuX3BhcnRzLnBhdGgpOwogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHRoaXMuX3BhcnRzLnBhdGggPT09ICIvIikgewogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIF9wYXRoID0gVVJJLnJlY29kZVBhdGgoX3BhdGgpOwogICAgICAgICAgdmFyIF93YXNfcmVsYXRpdmU7CiAgICAgICAgICB2YXIgX2xlYWRpbmdQYXJlbnRzID0gIiI7CiAgICAgICAgICB2YXIgX3BhcmVudCwgX3BvczsKICAgICAgICAgIGlmIChfcGF0aC5jaGFyQXQoMCkgIT09ICIvIikgewogICAgICAgICAgICBfd2FzX3JlbGF0aXZlID0gdHJ1ZTsKICAgICAgICAgICAgX3BhdGggPSAiLyIgKyBfcGF0aDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChfcGF0aC5zbGljZSgtMykgPT09ICIvLi4iIHx8IF9wYXRoLnNsaWNlKC0yKSA9PT0gIi8uIikgewogICAgICAgICAgICBfcGF0aCArPSAiLyI7CiAgICAgICAgICB9CiAgICAgICAgICBfcGF0aCA9IF9wYXRoLnJlcGxhY2UoLyhcLyhcLlwvKSspfChcL1wuJCkvZywgIi8iKS5yZXBsYWNlKC9cL3syLH0vZywgIi8iKTsKICAgICAgICAgIGlmIChfd2FzX3JlbGF0aXZlKSB7CiAgICAgICAgICAgIF9sZWFkaW5nUGFyZW50cyA9IF9wYXRoLnN1YnN0cmluZygxKS5tYXRjaCgvXihcLlwuXC8pKy8pIHx8ICIiOwogICAgICAgICAgICBpZiAoX2xlYWRpbmdQYXJlbnRzKSB7CiAgICAgICAgICAgICAgX2xlYWRpbmdQYXJlbnRzID0gX2xlYWRpbmdQYXJlbnRzWzBdOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICB3aGlsZSAodHJ1ZSkgewogICAgICAgICAgICBfcGFyZW50ID0gX3BhdGguc2VhcmNoKC9cL1wuXC4oXC98JCkvKTsKICAgICAgICAgICAgaWYgKF9wYXJlbnQgPT09IC0xKSB7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoX3BhcmVudCA9PT0gMCkgewogICAgICAgICAgICAgIF9wYXRoID0gX3BhdGguc3Vic3RyaW5nKDMpOwogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIF9wb3MgPSBfcGF0aC5zdWJzdHJpbmcoMCwgX3BhcmVudCkubGFzdEluZGV4T2YoIi8iKTsKICAgICAgICAgICAgaWYgKF9wb3MgPT09IC0xKSB7CiAgICAgICAgICAgICAgX3BvcyA9IF9wYXJlbnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgX3BhdGggPSBfcGF0aC5zdWJzdHJpbmcoMCwgX3BvcykgKyBfcGF0aC5zdWJzdHJpbmcoX3BhcmVudCArIDMpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKF93YXNfcmVsYXRpdmUgJiYgdGhpcy5pcygicmVsYXRpdmUiKSkgewogICAgICAgICAgICBfcGF0aCA9IF9sZWFkaW5nUGFyZW50cyArIF9wYXRoLnN1YnN0cmluZygxKTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuX3BhcnRzLnBhdGggPSBfcGF0aDsKICAgICAgICAgIHRoaXMuYnVpbGQoIWJ1aWxkKTsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH07CiAgICAgICAgcDIubm9ybWFsaXplUGF0aG5hbWUgPSBwMi5ub3JtYWxpemVQYXRoOwogICAgICAgIHAyLm5vcm1hbGl6ZVF1ZXJ5ID0gZnVuY3Rpb24oYnVpbGQpIHsKICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5fcGFydHMucXVlcnkgPT09ICJzdHJpbmciKSB7CiAgICAgICAgICAgIGlmICghdGhpcy5fcGFydHMucXVlcnkubGVuZ3RoKSB7CiAgICAgICAgICAgICAgdGhpcy5fcGFydHMucXVlcnkgPSBudWxsOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRoaXMucXVlcnkoVVJJLnBhcnNlUXVlcnkodGhpcy5fcGFydHMucXVlcnksIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLm5vcm1hbGl6ZUZyYWdtZW50ID0gZnVuY3Rpb24oYnVpbGQpIHsKICAgICAgICAgIGlmICghdGhpcy5fcGFydHMuZnJhZ21lbnQpIHsKICAgICAgICAgICAgdGhpcy5fcGFydHMuZnJhZ21lbnQgPSBudWxsOwogICAgICAgICAgICB0aGlzLmJ1aWxkKCFidWlsZCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLm5vcm1hbGl6ZVNlYXJjaCA9IHAyLm5vcm1hbGl6ZVF1ZXJ5OwogICAgICAgIHAyLm5vcm1hbGl6ZUhhc2ggPSBwMi5ub3JtYWxpemVGcmFnbWVudDsKICAgICAgICBwMi5pc284ODU5ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICB2YXIgZTIgPSBVUkkuZW5jb2RlOwogICAgICAgICAgdmFyIGQyID0gVVJJLmRlY29kZTsKICAgICAgICAgIFVSSS5lbmNvZGUgPSBlc2NhcGU7CiAgICAgICAgICBVUkkuZGVjb2RlID0gZGVjb2RlVVJJQ29tcG9uZW50OwogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgdGhpcy5ub3JtYWxpemUoKTsKICAgICAgICAgIH0gZmluYWxseSB7CiAgICAgICAgICAgIFVSSS5lbmNvZGUgPSBlMjsKICAgICAgICAgICAgVVJJLmRlY29kZSA9IGQyOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICBwMi51bmljb2RlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICB2YXIgZTIgPSBVUkkuZW5jb2RlOwogICAgICAgICAgdmFyIGQyID0gVVJJLmRlY29kZTsKICAgICAgICAgIFVSSS5lbmNvZGUgPSBzdHJpY3RFbmNvZGVVUklDb21wb25lbnQ7CiAgICAgICAgICBVUkkuZGVjb2RlID0gdW5lc2NhcGU7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICB0aGlzLm5vcm1hbGl6ZSgpOwogICAgICAgICAgfSBmaW5hbGx5IHsKICAgICAgICAgICAgVVJJLmVuY29kZSA9IGUyOwogICAgICAgICAgICBVUkkuZGVjb2RlID0gZDI7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLnJlYWRhYmxlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICB2YXIgdXJpID0gdGhpcy5jbG9uZSgpOwogICAgICAgICAgdXJpLnVzZXJuYW1lKCIiKS5wYXNzd29yZCgiIikubm9ybWFsaXplKCk7CiAgICAgICAgICB2YXIgdDIgPSAiIjsKICAgICAgICAgIGlmICh1cmkuX3BhcnRzLnByb3RvY29sKSB7CiAgICAgICAgICAgIHQyICs9IHVyaS5fcGFydHMucHJvdG9jb2wgKyAiOi8vIjsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh1cmkuX3BhcnRzLmhvc3RuYW1lKSB7CiAgICAgICAgICAgIGlmICh1cmkuaXMoInB1bnljb2RlIikgJiYgcHVueWNvZGUpIHsKICAgICAgICAgICAgICB0MiArPSBwdW55Y29kZS50b1VuaWNvZGUodXJpLl9wYXJ0cy5ob3N0bmFtZSk7CiAgICAgICAgICAgICAgaWYgKHVyaS5fcGFydHMucG9ydCkgewogICAgICAgICAgICAgICAgdDIgKz0gIjoiICsgdXJpLl9wYXJ0cy5wb3J0OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB0MiArPSB1cmkuaG9zdCgpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodXJpLl9wYXJ0cy5ob3N0bmFtZSAmJiB1cmkuX3BhcnRzLnBhdGggJiYgdXJpLl9wYXJ0cy5wYXRoLmNoYXJBdCgwKSAhPT0gIi8iKSB7CiAgICAgICAgICAgIHQyICs9ICIvIjsKICAgICAgICAgIH0KICAgICAgICAgIHQyICs9IHVyaS5wYXRoKHRydWUpOwogICAgICAgICAgaWYgKHVyaS5fcGFydHMucXVlcnkpIHsKICAgICAgICAgICAgdmFyIHE0ID0gIiI7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMCwgcXAgPSB1cmkuX3BhcnRzLnF1ZXJ5LnNwbGl0KCImIiksIGwyID0gcXAubGVuZ3RoOyBpMiA8IGwyOyBpMisrKSB7CiAgICAgICAgICAgICAgdmFyIGt2ID0gKHFwW2kyXSB8fCAiIikuc3BsaXQoIj0iKTsKICAgICAgICAgICAgICBxNCArPSAiJiIgKyBVUkkuZGVjb2RlUXVlcnkoa3ZbMF0sIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpLnJlcGxhY2UoLyYvZywgIiUyNiIpOwogICAgICAgICAgICAgIGlmIChrdlsxXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgICAgICBxNCArPSAiPSIgKyBVUkkuZGVjb2RlUXVlcnkoa3ZbMV0sIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UpLnJlcGxhY2UoLyYvZywgIiUyNiIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICB0MiArPSAiPyIgKyBxNC5zdWJzdHJpbmcoMSk7CiAgICAgICAgICB9CiAgICAgICAgICB0MiArPSBVUkkuZGVjb2RlUXVlcnkodXJpLmhhc2goKSwgdHJ1ZSk7CiAgICAgICAgICByZXR1cm4gdDI7CiAgICAgICAgfTsKICAgICAgICBwMi5hYnNvbHV0ZVRvID0gZnVuY3Rpb24oYmFzZSkgewogICAgICAgICAgdmFyIHJlc29sdmVkID0gdGhpcy5jbG9uZSgpOwogICAgICAgICAgdmFyIHByb3BlcnRpZXMgPSBbInByb3RvY29sIiwgInVzZXJuYW1lIiwgInBhc3N3b3JkIiwgImhvc3RuYW1lIiwgInBvcnQiXTsKICAgICAgICAgIHZhciBiYXNlZGlyLCBpMiwgcDM7CiAgICAgICAgICBpZiAodGhpcy5fcGFydHMudXJuKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiVVJOcyBkbyBub3QgaGF2ZSBhbnkgZ2VuZXJhbGx5IGRlZmluZWQgaGllcmFyY2hpY2FsIGNvbXBvbmVudHMiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghKGJhc2UgaW5zdGFuY2VvZiBVUkkpKSB7CiAgICAgICAgICAgIGJhc2UgPSBuZXcgVVJJKGJhc2UpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJlc29sdmVkLl9wYXJ0cy5wcm90b2NvbCkgewogICAgICAgICAgICByZXR1cm4gcmVzb2x2ZWQ7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICByZXNvbHZlZC5fcGFydHMucHJvdG9jb2wgPSBiYXNlLl9wYXJ0cy5wcm90b2NvbDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh0aGlzLl9wYXJ0cy5ob3N0bmFtZSkgewogICAgICAgICAgICByZXR1cm4gcmVzb2x2ZWQ7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGkyID0gMDsgcDMgPSBwcm9wZXJ0aWVzW2kyXTsgaTIrKykgewogICAgICAgICAgICByZXNvbHZlZC5fcGFydHNbcDNdID0gYmFzZS5fcGFydHNbcDNdOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFyZXNvbHZlZC5fcGFydHMucGF0aCkgewogICAgICAgICAgICByZXNvbHZlZC5fcGFydHMucGF0aCA9IGJhc2UuX3BhcnRzLnBhdGg7CiAgICAgICAgICAgIGlmICghcmVzb2x2ZWQuX3BhcnRzLnF1ZXJ5KSB7CiAgICAgICAgICAgICAgcmVzb2x2ZWQuX3BhcnRzLnF1ZXJ5ID0gYmFzZS5fcGFydHMucXVlcnk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGlmIChyZXNvbHZlZC5fcGFydHMucGF0aC5zdWJzdHJpbmcoLTIpID09PSAiLi4iKSB7CiAgICAgICAgICAgICAgcmVzb2x2ZWQuX3BhcnRzLnBhdGggKz0gIi8iOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChyZXNvbHZlZC5wYXRoKCkuY2hhckF0KDApICE9PSAiLyIpIHsKICAgICAgICAgICAgICBiYXNlZGlyID0gYmFzZS5kaXJlY3RvcnkoKTsKICAgICAgICAgICAgICBiYXNlZGlyID0gYmFzZWRpciA/IGJhc2VkaXIgOiBiYXNlLnBhdGgoKS5pbmRleE9mKCIvIikgPT09IDAgPyAiLyIgOiAiIjsKICAgICAgICAgICAgICByZXNvbHZlZC5fcGFydHMucGF0aCA9IChiYXNlZGlyID8gYmFzZWRpciArICIvIiA6ICIiKSArIHJlc29sdmVkLl9wYXJ0cy5wYXRoOwogICAgICAgICAgICAgIHJlc29sdmVkLm5vcm1hbGl6ZVBhdGgoKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmVzb2x2ZWQuYnVpbGQoKTsKICAgICAgICAgIHJldHVybiByZXNvbHZlZDsKICAgICAgICB9OwogICAgICAgIHAyLnJlbGF0aXZlVG8gPSBmdW5jdGlvbihiYXNlKSB7CiAgICAgICAgICB2YXIgcmVsYXRpdmUgPSB0aGlzLmNsb25lKCkubm9ybWFsaXplKCk7CiAgICAgICAgICB2YXIgcmVsYXRpdmVQYXJ0cywgYmFzZVBhcnRzLCBjb21tb24sIHJlbGF0aXZlUGF0aCwgYmFzZVBhdGg7CiAgICAgICAgICBpZiAocmVsYXRpdmUuX3BhcnRzLnVybikgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIlVSTnMgZG8gbm90IGhhdmUgYW55IGdlbmVyYWxseSBkZWZpbmVkIGhpZXJhcmNoaWNhbCBjb21wb25lbnRzIik7CiAgICAgICAgICB9CiAgICAgICAgICBiYXNlID0gbmV3IFVSSShiYXNlKS5ub3JtYWxpemUoKTsKICAgICAgICAgIHJlbGF0aXZlUGFydHMgPSByZWxhdGl2ZS5fcGFydHM7CiAgICAgICAgICBiYXNlUGFydHMgPSBiYXNlLl9wYXJ0czsKICAgICAgICAgIHJlbGF0aXZlUGF0aCA9IHJlbGF0aXZlLnBhdGgoKTsKICAgICAgICAgIGJhc2VQYXRoID0gYmFzZS5wYXRoKCk7CiAgICAgICAgICBpZiAocmVsYXRpdmVQYXRoLmNoYXJBdCgwKSAhPT0gIi8iKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiVVJJIGlzIGFscmVhZHkgcmVsYXRpdmUiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChiYXNlUGF0aC5jaGFyQXQoMCkgIT09ICIvIikgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBjYWxjdWxhdGUgYSBVUkkgcmVsYXRpdmUgdG8gYW5vdGhlciByZWxhdGl2ZSBVUkkiKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWxhdGl2ZVBhcnRzLnByb3RvY29sID09PSBiYXNlUGFydHMucHJvdG9jb2wpIHsKICAgICAgICAgICAgcmVsYXRpdmVQYXJ0cy5wcm90b2NvbCA9IG51bGw7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocmVsYXRpdmVQYXJ0cy51c2VybmFtZSAhPT0gYmFzZVBhcnRzLnVzZXJuYW1lIHx8IHJlbGF0aXZlUGFydHMucGFzc3dvcmQgIT09IGJhc2VQYXJ0cy5wYXNzd29yZCkgewogICAgICAgICAgICByZXR1cm4gcmVsYXRpdmUuYnVpbGQoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWxhdGl2ZVBhcnRzLnByb3RvY29sICE9PSBudWxsIHx8IHJlbGF0aXZlUGFydHMudXNlcm5hbWUgIT09IG51bGwgfHwgcmVsYXRpdmVQYXJ0cy5wYXNzd29yZCAhPT0gbnVsbCkgewogICAgICAgICAgICByZXR1cm4gcmVsYXRpdmUuYnVpbGQoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWxhdGl2ZVBhcnRzLmhvc3RuYW1lID09PSBiYXNlUGFydHMuaG9zdG5hbWUgJiYgcmVsYXRpdmVQYXJ0cy5wb3J0ID09PSBiYXNlUGFydHMucG9ydCkgewogICAgICAgICAgICByZWxhdGl2ZVBhcnRzLmhvc3RuYW1lID0gbnVsbDsKICAgICAgICAgICAgcmVsYXRpdmVQYXJ0cy5wb3J0ID0gbnVsbDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiByZWxhdGl2ZS5idWlsZCgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJlbGF0aXZlUGF0aCA9PT0gYmFzZVBhdGgpIHsKICAgICAgICAgICAgcmVsYXRpdmVQYXJ0cy5wYXRoID0gIiI7CiAgICAgICAgICAgIHJldHVybiByZWxhdGl2ZS5idWlsZCgpOwogICAgICAgICAgfQogICAgICAgICAgY29tbW9uID0gVVJJLmNvbW1vblBhdGgocmVsYXRpdmVQYXRoLCBiYXNlUGF0aCk7CiAgICAgICAgICBpZiAoIWNvbW1vbikgewogICAgICAgICAgICByZXR1cm4gcmVsYXRpdmUuYnVpbGQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBwYXJlbnRzID0gYmFzZVBhcnRzLnBhdGguc3Vic3RyaW5nKGNvbW1vbi5sZW5ndGgpLnJlcGxhY2UoL1teXC9dKiQvLCAiIikucmVwbGFjZSgvLio/XC8vZywgIi4uLyIpOwogICAgICAgICAgcmVsYXRpdmVQYXJ0cy5wYXRoID0gcGFyZW50cyArIHJlbGF0aXZlUGFydHMucGF0aC5zdWJzdHJpbmcoY29tbW9uLmxlbmd0aCkgfHwgIi4vIjsKICAgICAgICAgIHJldHVybiByZWxhdGl2ZS5idWlsZCgpOwogICAgICAgIH07CiAgICAgICAgcDIuZXF1YWxzID0gZnVuY3Rpb24odXJpKSB7CiAgICAgICAgICB2YXIgb25lID0gdGhpcy5jbG9uZSgpOwogICAgICAgICAgdmFyIHR3byA9IG5ldyBVUkkodXJpKTsKICAgICAgICAgIHZhciBvbmVfbWFwID0ge307CiAgICAgICAgICB2YXIgdHdvX21hcCA9IHt9OwogICAgICAgICAgdmFyIGNoZWNrZWQgPSB7fTsKICAgICAgICAgIHZhciBvbmVfcXVlcnksIHR3b19xdWVyeSwga2V5OwogICAgICAgICAgb25lLm5vcm1hbGl6ZSgpOwogICAgICAgICAgdHdvLm5vcm1hbGl6ZSgpOwogICAgICAgICAgaWYgKG9uZS50b1N0cmluZygpID09PSB0d28udG9TdHJpbmcoKSkgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgIH0KICAgICAgICAgIG9uZV9xdWVyeSA9IG9uZS5xdWVyeSgpOwogICAgICAgICAgdHdvX3F1ZXJ5ID0gdHdvLnF1ZXJ5KCk7CiAgICAgICAgICBvbmUucXVlcnkoIiIpOwogICAgICAgICAgdHdvLnF1ZXJ5KCIiKTsKICAgICAgICAgIGlmIChvbmUudG9TdHJpbmcoKSAhPT0gdHdvLnRvU3RyaW5nKCkpIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgfQogICAgICAgICAgaWYgKG9uZV9xdWVyeS5sZW5ndGggIT09IHR3b19xdWVyeS5sZW5ndGgpIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgfQogICAgICAgICAgb25lX21hcCA9IFVSSS5wYXJzZVF1ZXJ5KG9uZV9xdWVyeSwgdGhpcy5fcGFydHMuZXNjYXBlUXVlcnlTcGFjZSk7CiAgICAgICAgICB0d29fbWFwID0gVVJJLnBhcnNlUXVlcnkodHdvX3F1ZXJ5LCB0aGlzLl9wYXJ0cy5lc2NhcGVRdWVyeVNwYWNlKTsKICAgICAgICAgIGZvciAoa2V5IGluIG9uZV9tYXApIHsKICAgICAgICAgICAgaWYgKGhhc093bi5jYWxsKG9uZV9tYXAsIGtleSkpIHsKICAgICAgICAgICAgICBpZiAoIWlzQXJyYXkob25lX21hcFtrZXldKSkgewogICAgICAgICAgICAgICAgaWYgKG9uZV9tYXBba2V5XSAhPT0gdHdvX21hcFtrZXldKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFhcnJheXNFcXVhbChvbmVfbWFwW2tleV0sIHR3b19tYXBba2V5XSkpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgY2hlY2tlZFtrZXldID0gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZm9yIChrZXkgaW4gdHdvX21hcCkgewogICAgICAgICAgICBpZiAoaGFzT3duLmNhbGwodHdvX21hcCwga2V5KSkgewogICAgICAgICAgICAgIGlmICghY2hlY2tlZFtrZXldKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9OwogICAgICAgIHAyLnByZXZlbnRJbnZhbGlkSG9zdG5hbWUgPSBmdW5jdGlvbih2NCkgewogICAgICAgICAgdGhpcy5fcGFydHMucHJldmVudEludmFsaWRIb3N0bmFtZSA9ICEhdjQ7CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICAgIHAyLmR1cGxpY2F0ZVF1ZXJ5UGFyYW1ldGVycyA9IGZ1bmN0aW9uKHY0KSB7CiAgICAgICAgICB0aGlzLl9wYXJ0cy5kdXBsaWNhdGVRdWVyeVBhcmFtZXRlcnMgPSAhIXY0OwogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICBwMi5lc2NhcGVRdWVyeVNwYWNlID0gZnVuY3Rpb24odjQpIHsKICAgICAgICAgIHRoaXMuX3BhcnRzLmVzY2FwZVF1ZXJ5U3BhY2UgPSAhIXY0OwogICAgICAgICAgcmV0dXJuIHRoaXM7CiAgICAgICAgfTsKICAgICAgICByZXR1cm4gVVJJOwogICAgICB9KTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2FwcGVuZEZvcndhcmRTbGFzaC5qcwogIGZ1bmN0aW9uIGFwcGVuZEZvcndhcmRTbGFzaCh1cmwpIHsKICAgIGlmICh1cmwubGVuZ3RoID09PSAwIHx8IHVybFt1cmwubGVuZ3RoIC0gMV0gIT09ICIvIikgewogICAgICB1cmwgPSBgJHt1cmx9L2A7CiAgICB9CiAgICByZXR1cm4gdXJsOwogIH0KICB2YXIgYXBwZW5kRm9yd2FyZFNsYXNoX2RlZmF1bHQ7CiAgdmFyIGluaXRfYXBwZW5kRm9yd2FyZFNsYXNoID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9hcHBlbmRGb3J3YXJkU2xhc2guanMiKCkgewogICAgICBhcHBlbmRGb3J3YXJkU2xhc2hfZGVmYXVsdCA9IGFwcGVuZEZvcndhcmRTbGFzaDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2Nsb25lLmpzCiAgZnVuY3Rpb24gY2xvbmUob2JqZWN0LCBkZWVwKSB7CiAgICBpZiAob2JqZWN0ID09PSBudWxsIHx8IHR5cGVvZiBvYmplY3QgIT09ICJvYmplY3QiKSB7CiAgICAgIHJldHVybiBvYmplY3Q7CiAgICB9CiAgICBkZWVwID0gZGVlcCA/PyBmYWxzZTsKICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBvYmplY3QuY29uc3RydWN0b3IoKTsKICAgIGZvciAoY29uc3QgcHJvcGVydHlOYW1lIGluIG9iamVjdCkgewogICAgICBpZiAob2JqZWN0Lmhhc093blByb3BlcnR5KHByb3BlcnR5TmFtZSkpIHsKICAgICAgICBsZXQgdmFsdWUgPSBvYmplY3RbcHJvcGVydHlOYW1lXTsKICAgICAgICBpZiAoZGVlcCkgewogICAgICAgICAgdmFsdWUgPSBjbG9uZSh2YWx1ZSwgZGVlcCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdFtwcm9wZXJ0eU5hbWVdID0gdmFsdWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBjbG9uZV9kZWZhdWx0OwogIHZhciBpbml0X2Nsb25lID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9jbG9uZS5qcyIoKSB7CiAgICAgIGNsb25lX2RlZmF1bHQgPSBjbG9uZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2NvbWJpbmUuanMKICBmdW5jdGlvbiBjb21iaW5lKG9iamVjdDEsIG9iamVjdDIsIGRlZXApIHsKICAgIGRlZXAgPSBkZWVwID8/IGZhbHNlOwogICAgY29uc3QgcmVzdWx0ID0ge307CiAgICBjb25zdCBvYmplY3QxRGVmaW5lZCA9IGRlZmluZWRfZGVmYXVsdChvYmplY3QxKTsKICAgIGNvbnN0IG9iamVjdDJEZWZpbmVkID0gZGVmaW5lZF9kZWZhdWx0KG9iamVjdDIpOwogICAgbGV0IHByb3BlcnR5OwogICAgbGV0IG9iamVjdDFWYWx1ZTsKICAgIGxldCBvYmplY3QyVmFsdWU7CiAgICBpZiAob2JqZWN0MURlZmluZWQpIHsKICAgICAgZm9yIChwcm9wZXJ0eSBpbiBvYmplY3QxKSB7CiAgICAgICAgaWYgKG9iamVjdDEuaGFzT3duUHJvcGVydHkocHJvcGVydHkpKSB7CiAgICAgICAgICBvYmplY3QxVmFsdWUgPSBvYmplY3QxW3Byb3BlcnR5XTsKICAgICAgICAgIGlmIChvYmplY3QyRGVmaW5lZCAmJiBkZWVwICYmIHR5cGVvZiBvYmplY3QxVmFsdWUgPT09ICJvYmplY3QiICYmIG9iamVjdDIuaGFzT3duUHJvcGVydHkocHJvcGVydHkpKSB7CiAgICAgICAgICAgIG9iamVjdDJWYWx1ZSA9IG9iamVjdDJbcHJvcGVydHldOwogICAgICAgICAgICBpZiAodHlwZW9mIG9iamVjdDJWYWx1ZSA9PT0gIm9iamVjdCIpIHsKICAgICAgICAgICAgICByZXN1bHRbcHJvcGVydHldID0gY29tYmluZShvYmplY3QxVmFsdWUsIG9iamVjdDJWYWx1ZSwgZGVlcCk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmVzdWx0W3Byb3BlcnR5XSA9IG9iamVjdDFWYWx1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmVzdWx0W3Byb3BlcnR5XSA9IG9iamVjdDFWYWx1ZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmIChvYmplY3QyRGVmaW5lZCkgewogICAgICBmb3IgKHByb3BlcnR5IGluIG9iamVjdDIpIHsKICAgICAgICBpZiAob2JqZWN0Mi5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSkgJiYgIXJlc3VsdC5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSkpIHsKICAgICAgICAgIG9iamVjdDJWYWx1ZSA9IG9iamVjdDJbcHJvcGVydHldOwogICAgICAgICAgcmVzdWx0W3Byb3BlcnR5XSA9IG9iamVjdDJWYWx1ZTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBjb21iaW5lX2RlZmF1bHQ7CiAgdmFyIGluaXRfY29tYmluZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvY29tYmluZS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBjb21iaW5lX2RlZmF1bHQgPSBjb21iaW5lOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZGVmZXIuanMKICBmdW5jdGlvbiBkZWZlcigpIHsKICAgIGxldCByZXNvbHZlOwogICAgbGV0IHJlamVjdDsKICAgIGNvbnN0IHByb21pc2UgPSBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXMsIHJlaikgewogICAgICByZXNvbHZlID0gcmVzOwogICAgICByZWplY3QgPSByZWo7CiAgICB9KTsKICAgIHJldHVybiB7CiAgICAgIHJlc29sdmUsCiAgICAgIHJlamVjdCwKICAgICAgcHJvbWlzZQogICAgfTsKICB9CiAgdmFyIGRlZmVyX2RlZmF1bHQ7CiAgdmFyIGluaXRfZGVmZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2RlZmVyLmpzIigpIHsKICAgICAgZGVmZXJfZGVmYXVsdCA9IGRlZmVyOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0QWJzb2x1dGVVcmkuanMKICBmdW5jdGlvbiBnZXRBYnNvbHV0ZVVyaShyZWxhdGl2ZSwgYmFzZSkgewogICAgbGV0IGRvY3VtZW50T2JqZWN0OwogICAgaWYgKHR5cGVvZiBkb2N1bWVudCAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgZG9jdW1lbnRPYmplY3QgPSBkb2N1bWVudDsKICAgIH0KICAgIHJldHVybiBnZXRBYnNvbHV0ZVVyaS5faW1wbGVtZW50YXRpb24ocmVsYXRpdmUsIGJhc2UsIGRvY3VtZW50T2JqZWN0KTsKICB9CiAgdmFyIGltcG9ydF91cmlqcywgZ2V0QWJzb2x1dGVVcmlfZGVmYXVsdDsKICB2YXIgaW5pdF9nZXRBYnNvbHV0ZVVyaSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0QWJzb2x1dGVVcmkuanMiKCkgewogICAgICBpbXBvcnRfdXJpanMgPSBfX3RvRVNNKHJlcXVpcmVfVVJJKCksIDEpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBnZXRBYnNvbHV0ZVVyaS5faW1wbGVtZW50YXRpb24gPSBmdW5jdGlvbihyZWxhdGl2ZSwgYmFzZSwgZG9jdW1lbnRPYmplY3QpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWxhdGl2ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyZWxhdGl2ZSB1cmkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJhc2UpKSB7CiAgICAgICAgICBpZiAodHlwZW9mIGRvY3VtZW50T2JqZWN0ID09PSAidW5kZWZpbmVkIikgewogICAgICAgICAgICByZXR1cm4gcmVsYXRpdmU7CiAgICAgICAgICB9CiAgICAgICAgICBiYXNlID0gZG9jdW1lbnRPYmplY3QuYmFzZVVSSSA/PyBkb2N1bWVudE9iamVjdC5sb2NhdGlvbi5ocmVmOwogICAgICAgIH0KICAgICAgICBjb25zdCByZWxhdGl2ZVVyaSA9IG5ldyBpbXBvcnRfdXJpanMuZGVmYXVsdChyZWxhdGl2ZSk7CiAgICAgICAgaWYgKHJlbGF0aXZlVXJpLnNjaGVtZSgpICE9PSAiIikgewogICAgICAgICAgcmV0dXJuIHJlbGF0aXZlVXJpLnRvU3RyaW5nKCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZWxhdGl2ZVVyaS5hYnNvbHV0ZVRvKGJhc2UpLnRvU3RyaW5nKCk7CiAgICAgIH07CiAgICAgIGdldEFic29sdXRlVXJpX2RlZmF1bHQgPSBnZXRBYnNvbHV0ZVVyaTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2dldEJhc2VVcmkuanMKICBmdW5jdGlvbiBnZXRCYXNlVXJpKHVyaSwgaW5jbHVkZVF1ZXJ5KSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1cmkpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ1cmkgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBsZXQgYmFzZVBhdGggPSAiIjsKICAgIGNvbnN0IGkyID0gdXJpLmxhc3RJbmRleE9mKCIvIik7CiAgICBpZiAoaTIgIT09IC0xKSB7CiAgICAgIGJhc2VQYXRoID0gdXJpLnN1YnN0cmluZygwLCBpMiArIDEpOwogICAgfQogICAgaWYgKCFpbmNsdWRlUXVlcnkpIHsKICAgICAgcmV0dXJuIGJhc2VQYXRoOwogICAgfQogICAgdXJpID0gbmV3IGltcG9ydF91cmlqczIuZGVmYXVsdCh1cmkpOwogICAgaWYgKHVyaS5xdWVyeSgpLmxlbmd0aCAhPT0gMCkgewogICAgICBiYXNlUGF0aCArPSBgPyR7dXJpLnF1ZXJ5KCl9YDsKICAgIH0KICAgIGlmICh1cmkuZnJhZ21lbnQoKS5sZW5ndGggIT09IDApIHsKICAgICAgYmFzZVBhdGggKz0gYCMke3VyaS5mcmFnbWVudCgpfWA7CiAgICB9CiAgICByZXR1cm4gYmFzZVBhdGg7CiAgfQogIHZhciBpbXBvcnRfdXJpanMyLCBnZXRCYXNlVXJpX2RlZmF1bHQ7CiAgdmFyIGluaXRfZ2V0QmFzZVVyaSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0QmFzZVVyaS5qcyIoKSB7CiAgICAgIGltcG9ydF91cmlqczIgPSBfX3RvRVNNKHJlcXVpcmVfVVJJKCksIDEpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBnZXRCYXNlVXJpX2RlZmF1bHQgPSBnZXRCYXNlVXJpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0RXh0ZW5zaW9uRnJvbVVyaS5qcwogIGZ1bmN0aW9uIGdldEV4dGVuc2lvbkZyb21VcmkodXJpKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1cmkpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ1cmkgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBjb25zdCB1cmlPYmplY3QgPSBuZXcgaW1wb3J0X3VyaWpzMy5kZWZhdWx0KHVyaSk7CiAgICB1cmlPYmplY3Qubm9ybWFsaXplKCk7CiAgICBsZXQgcGF0aCA9IHVyaU9iamVjdC5wYXRoKCk7CiAgICBsZXQgaW5kZXggPSBwYXRoLmxhc3RJbmRleE9mKCIvIik7CiAgICBpZiAoaW5kZXggIT09IC0xKSB7CiAgICAgIHBhdGggPSBwYXRoLnN1YnN0cihpbmRleCArIDEpOwogICAgfQogICAgaW5kZXggPSBwYXRoLmxhc3RJbmRleE9mKCIuIik7CiAgICBpZiAoaW5kZXggPT09IC0xKSB7CiAgICAgIHBhdGggPSAiIjsKICAgIH0gZWxzZSB7CiAgICAgIHBhdGggPSBwYXRoLnN1YnN0cihpbmRleCArIDEpOwogICAgfQogICAgcmV0dXJuIHBhdGg7CiAgfQogIHZhciBpbXBvcnRfdXJpanMzLCBnZXRFeHRlbnNpb25Gcm9tVXJpX2RlZmF1bHQ7CiAgdmFyIGluaXRfZ2V0RXh0ZW5zaW9uRnJvbVVyaSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0RXh0ZW5zaW9uRnJvbVVyaS5qcyIoKSB7CiAgICAgIGltcG9ydF91cmlqczMgPSBfX3RvRVNNKHJlcXVpcmVfVVJJKCksIDEpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBnZXRFeHRlbnNpb25Gcm9tVXJpX2RlZmF1bHQgPSBnZXRFeHRlbnNpb25Gcm9tVXJpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZ2V0SW1hZ2VQaXhlbHMuanMKICBmdW5jdGlvbiBnZXRJbWFnZVBpeGVscyhpbWFnZSwgd2lkdGgsIGhlaWdodCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQod2lkdGgpKSB7CiAgICAgIHdpZHRoID0gaW1hZ2Uud2lkdGg7CiAgICB9CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChoZWlnaHQpKSB7CiAgICAgIGhlaWdodCA9IGltYWdlLmhlaWdodDsKICAgIH0KICAgIGxldCBjb250ZXh0MkRzQnlIZWlnaHQgPSBjb250ZXh0MkRzQnlXaWR0aEFuZEhlaWdodFt3aWR0aF07CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb250ZXh0MkRzQnlIZWlnaHQpKSB7CiAgICAgIGNvbnRleHQyRHNCeUhlaWdodCA9IHt9OwogICAgICBjb250ZXh0MkRzQnlXaWR0aEFuZEhlaWdodFt3aWR0aF0gPSBjb250ZXh0MkRzQnlIZWlnaHQ7CiAgICB9CiAgICBsZXQgY29udGV4dDJkID0gY29udGV4dDJEc0J5SGVpZ2h0W2hlaWdodF07CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb250ZXh0MmQpKSB7CiAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpOwogICAgICBjYW52YXMud2lkdGggPSB3aWR0aDsKICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDsKICAgICAgY29udGV4dDJkID0gY2FudmFzLmdldENvbnRleHQoIjJkIiwgeyB3aWxsUmVhZEZyZXF1ZW50bHk6IHRydWUgfSk7CiAgICAgIGNvbnRleHQyZC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAiY29weSI7CiAgICAgIGNvbnRleHQyRHNCeUhlaWdodFtoZWlnaHRdID0gY29udGV4dDJkOwogICAgfQogICAgY29udGV4dDJkLmRyYXdJbWFnZShpbWFnZSwgMCwgMCwgd2lkdGgsIGhlaWdodCk7CiAgICByZXR1cm4gY29udGV4dDJkLmdldEltYWdlRGF0YSgwLCAwLCB3aWR0aCwgaGVpZ2h0KS5kYXRhOwogIH0KICB2YXIgY29udGV4dDJEc0J5V2lkdGhBbmRIZWlnaHQsIGdldEltYWdlUGl4ZWxzX2RlZmF1bHQ7CiAgdmFyIGluaXRfZ2V0SW1hZ2VQaXhlbHMgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2dldEltYWdlUGl4ZWxzLmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGNvbnRleHQyRHNCeVdpZHRoQW5kSGVpZ2h0ID0ge307CiAgICAgIGdldEltYWdlUGl4ZWxzX2RlZmF1bHQgPSBnZXRJbWFnZVBpeGVsczsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2lzQmxvYlVyaS5qcwogIGZ1bmN0aW9uIGlzQmxvYlVyaSh1cmkpIHsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLnN0cmluZygidXJpIiwgdXJpKTsKICAgIHJldHVybiBibG9iVXJpUmVnZXgudGVzdCh1cmkpOwogIH0KICB2YXIgYmxvYlVyaVJlZ2V4LCBpc0Jsb2JVcmlfZGVmYXVsdDsKICB2YXIgaW5pdF9pc0Jsb2JVcmkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2lzQmxvYlVyaS5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgYmxvYlVyaVJlZ2V4ID0gL15ibG9iOi9pOwogICAgICBpc0Jsb2JVcmlfZGVmYXVsdCA9IGlzQmxvYlVyaTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2lzQ3Jvc3NPcmlnaW5VcmwuanMKICBmdW5jdGlvbiBpc0Nyb3NzT3JpZ2luVXJsKHVybCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYSkpIHsKICAgICAgYSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKTsKICAgIH0KICAgIGEuaHJlZiA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmOwogICAgY29uc3QgaG9zdCA9IGEuaG9zdDsKICAgIGNvbnN0IHByb3RvY29sID0gYS5wcm90b2NvbDsKICAgIGEuaHJlZiA9IHVybDsKICAgIGEuaHJlZiA9IGEuaHJlZjsKICAgIHJldHVybiBwcm90b2NvbCAhPT0gYS5wcm90b2NvbCB8fCBob3N0ICE9PSBhLmhvc3Q7CiAgfQogIHZhciBhLCBpc0Nyb3NzT3JpZ2luVXJsX2RlZmF1bHQ7CiAgdmFyIGluaXRfaXNDcm9zc09yaWdpblVybCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvaXNDcm9zc09yaWdpblVybC5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpc0Nyb3NzT3JpZ2luVXJsX2RlZmF1bHQgPSBpc0Nyb3NzT3JpZ2luVXJsOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvaXNEYXRhVXJpLmpzCiAgZnVuY3Rpb24gaXNEYXRhVXJpKHVyaSkgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yuc3RyaW5nKCJ1cmkiLCB1cmkpOwogICAgcmV0dXJuIGRhdGFVcmlSZWdleC50ZXN0KHVyaSk7CiAgfQogIHZhciBkYXRhVXJpUmVnZXgsIGlzRGF0YVVyaV9kZWZhdWx0OwogIHZhciBpbml0X2lzRGF0YVVyaSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvaXNEYXRhVXJpLmpzIigpIHsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBkYXRhVXJpUmVnZXggPSAvXmRhdGE6L2k7CiAgICAgIGlzRGF0YVVyaV9kZWZhdWx0ID0gaXNEYXRhVXJpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvbG9hZEFuZEV4ZWN1dGVTY3JpcHQuanMKICBmdW5jdGlvbiBsb2FkQW5kRXhlY3V0ZVNjcmlwdCh1cmwpIHsKICAgIGNvbnN0IHNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpOwogICAgc2NyaXB0LmFzeW5jID0gdHJ1ZTsKICAgIHNjcmlwdC5zcmMgPSB1cmw7CiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gewogICAgICBpZiAod2luZG93LmNyb3NzT3JpZ2luSXNvbGF0ZWQpIHsKICAgICAgICBzY3JpcHQuc2V0QXR0cmlidXRlKCJjcm9zc29yaWdpbiIsICJhbm9ueW1vdXMiKTsKICAgICAgfQogICAgICBjb25zdCBoZWFkID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImhlYWQiKVswXTsKICAgICAgc2NyaXB0Lm9ubG9hZCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHNjcmlwdC5vbmxvYWQgPSB2b2lkIDA7CiAgICAgICAgaGVhZC5yZW1vdmVDaGlsZChzY3JpcHQpOwogICAgICAgIHJlc29sdmUoKTsKICAgICAgfTsKICAgICAgc2NyaXB0Lm9uZXJyb3IgPSBmdW5jdGlvbihlMikgewogICAgICAgIHJlamVjdChlMik7CiAgICAgIH07CiAgICAgIGhlYWQuYXBwZW5kQ2hpbGQoc2NyaXB0KTsKICAgIH0pOwogIH0KICB2YXIgbG9hZEFuZEV4ZWN1dGVTY3JpcHRfZGVmYXVsdDsKICB2YXIgaW5pdF9sb2FkQW5kRXhlY3V0ZVNjcmlwdCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvbG9hZEFuZEV4ZWN1dGVTY3JpcHQuanMiKCkgewogICAgICBsb2FkQW5kRXhlY3V0ZVNjcmlwdF9kZWZhdWx0ID0gbG9hZEFuZEV4ZWN1dGVTY3JpcHQ7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9vYmplY3RUb1F1ZXJ5LmpzCiAgZnVuY3Rpb24gb2JqZWN0VG9RdWVyeShvYmopIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9iaikpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9iaiBpcyByZXF1aXJlZC4iKTsKICAgIH0KICAgIGxldCByZXN1bHQgPSAiIjsKICAgIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gb2JqKSB7CiAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7CiAgICAgICAgY29uc3QgdmFsdWUgPSBvYmpbcHJvcE5hbWVdOwogICAgICAgIGNvbnN0IHBhcnQgPSBgJHtlbmNvZGVVUklDb21wb25lbnQocHJvcE5hbWUpfT1gOwogICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgewogICAgICAgICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSB2YWx1ZS5sZW5ndGg7IGkyIDwgbGVuOyArK2kyKSB7CiAgICAgICAgICAgIHJlc3VsdCArPSBgJHtwYXJ0ICsgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlW2kyXSl9JmA7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlc3VsdCArPSBgJHtwYXJ0ICsgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKX0mYDsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJlc3VsdCA9IHJlc3VsdC5zbGljZSgwLCAtMSk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICB2YXIgb2JqZWN0VG9RdWVyeV9kZWZhdWx0OwogIHZhciBpbml0X29iamVjdFRvUXVlcnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL29iamVjdFRvUXVlcnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBvYmplY3RUb1F1ZXJ5X2RlZmF1bHQgPSBvYmplY3RUb1F1ZXJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvcXVlcnlUb09iamVjdC5qcwogIGZ1bmN0aW9uIHF1ZXJ5VG9PYmplY3QocXVlcnlTdHJpbmcpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHF1ZXJ5U3RyaW5nKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicXVlcnlTdHJpbmcgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBjb25zdCByZXN1bHQgPSB7fTsKICAgIGlmIChxdWVyeVN0cmluZyA9PT0gIiIpIHsKICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KICAgIGNvbnN0IHBhcnRzID0gcXVlcnlTdHJpbmcucmVwbGFjZSgvXCsvZywgIiUyMCIpLnNwbGl0KC9bJjtdLyk7CiAgICBmb3IgKGxldCBpMiA9IDAsIGxlbiA9IHBhcnRzLmxlbmd0aDsgaTIgPCBsZW47ICsraTIpIHsKICAgICAgY29uc3Qgc3VicGFydHMgPSBwYXJ0c1tpMl0uc3BsaXQoIj0iKTsKICAgICAgY29uc3QgbmFtZSA9IGRlY29kZVVSSUNvbXBvbmVudChzdWJwYXJ0c1swXSk7CiAgICAgIGxldCB2YWx1ZSA9IHN1YnBhcnRzWzFdOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgIHZhbHVlID0gZGVjb2RlVVJJQ29tcG9uZW50KHZhbHVlKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB2YWx1ZSA9ICIiOwogICAgICB9CiAgICAgIGNvbnN0IHJlc3VsdFZhbHVlID0gcmVzdWx0W25hbWVdOwogICAgICBpZiAodHlwZW9mIHJlc3VsdFZhbHVlID09PSAic3RyaW5nIikgewogICAgICAgIHJlc3VsdFtuYW1lXSA9IFtyZXN1bHRWYWx1ZSwgdmFsdWVdOwogICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0VmFsdWUpKSB7CiAgICAgICAgcmVzdWx0VmFsdWUucHVzaCh2YWx1ZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmVzdWx0W25hbWVdID0gdmFsdWU7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBxdWVyeVRvT2JqZWN0X2RlZmF1bHQ7CiAgdmFyIGluaXRfcXVlcnlUb09iamVjdCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvcXVlcnlUb09iamVjdC5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIHF1ZXJ5VG9PYmplY3RfZGVmYXVsdCA9IHF1ZXJ5VG9PYmplY3Q7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZXF1ZXN0U3RhdGUuanMKICB2YXIgUmVxdWVzdFN0YXRlLCBSZXF1ZXN0U3RhdGVfZGVmYXVsdDsKICB2YXIgaW5pdF9SZXF1ZXN0U3RhdGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JlcXVlc3RTdGF0ZS5qcyIoKSB7CiAgICAgIFJlcXVlc3RTdGF0ZSA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBJbml0aWFsIHVuaXNzdWVkIHN0YXRlLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBVTklTU1VFRDogMCwKICAgICAgICAvKioKICAgICAgICAgKiBJc3N1ZWQgYnV0IG5vdCB5ZXQgYWN0aXZlLiBXaWxsIGJlY29tZSBhY3RpdmUgd2hlbiBvcGVuIHNsb3RzIGFyZSBhdmFpbGFibGUuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIElTU1VFRDogMSwKICAgICAgICAvKioKICAgICAgICAgKiBBY3R1YWwgaHR0cCByZXF1ZXN0IGhhcyBiZWVuIHNlbnQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIEFDVElWRTogMiwKICAgICAgICAvKioKICAgICAgICAgKiBSZXF1ZXN0IGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJFQ0VJVkVEOiAzLAogICAgICAgIC8qKgogICAgICAgICAqIFJlcXVlc3Qgd2FzIGNhbmNlbGxlZCwgZWl0aGVyIGV4cGxpY2l0bHkgb3IgYXV0b21hdGljYWxseSBiZWNhdXNlIG9mIGxvdyBwcmlvcml0eS4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgQ0FOQ0VMTEVEOiA0LAogICAgICAgIC8qKgogICAgICAgICAqIFJlcXVlc3QgZmFpbGVkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBGQUlMRUQ6IDUKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShSZXF1ZXN0U3RhdGUpOwogICAgICBSZXF1ZXN0U3RhdGVfZGVmYXVsdCA9IFJlcXVlc3RTdGF0ZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JlcXVlc3RUeXBlLmpzCiAgdmFyIFJlcXVlc3RUeXBlLCBSZXF1ZXN0VHlwZV9kZWZhdWx0OwogIHZhciBpbml0X1JlcXVlc3RUeXBlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZXF1ZXN0VHlwZS5qcyIoKSB7CiAgICAgIFJlcXVlc3RUeXBlID0gewogICAgICAgIC8qKgogICAgICAgICAqIFRlcnJhaW4gcmVxdWVzdC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgVEVSUkFJTjogMCwKICAgICAgICAvKioKICAgICAgICAgKiBJbWFnZXJ5IHJlcXVlc3QuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIElNQUdFUlk6IDEsCiAgICAgICAgLyoqCiAgICAgICAgICogM0QgVGlsZXMgcmVxdWVzdC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgVElMRVMzRDogMiwKICAgICAgICAvKioKICAgICAgICAgKiBPdGhlciByZXF1ZXN0LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBPVEhFUjogMwogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKFJlcXVlc3RUeXBlKTsKICAgICAgUmVxdWVzdFR5cGVfZGVmYXVsdCA9IFJlcXVlc3RUeXBlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVxdWVzdC5qcwogIGZ1bmN0aW9uIFJlcXVlc3QyKG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IHRocm90dGxlQnlTZXJ2ZXIgPSBvcHRpb25zLnRocm90dGxlQnlTZXJ2ZXIgPz8gZmFsc2U7CiAgICBjb25zdCB0aHJvdHRsZSA9IG9wdGlvbnMudGhyb3R0bGUgPz8gZmFsc2U7CiAgICB0aGlzLnVybCA9IG9wdGlvbnMudXJsOwogICAgdGhpcy5yZXF1ZXN0RnVuY3Rpb24gPSBvcHRpb25zLnJlcXVlc3RGdW5jdGlvbjsKICAgIHRoaXMuY2FuY2VsRnVuY3Rpb24gPSBvcHRpb25zLmNhbmNlbEZ1bmN0aW9uOwogICAgdGhpcy5wcmlvcml0eUZ1bmN0aW9uID0gb3B0aW9ucy5wcmlvcml0eUZ1bmN0aW9uOwogICAgdGhpcy5wcmlvcml0eSA9IG9wdGlvbnMucHJpb3JpdHkgPz8gMDsKICAgIHRoaXMudGhyb3R0bGUgPSB0aHJvdHRsZTsKICAgIHRoaXMudGhyb3R0bGVCeVNlcnZlciA9IHRocm90dGxlQnlTZXJ2ZXI7CiAgICB0aGlzLnR5cGUgPSBvcHRpb25zLnR5cGUgPz8gUmVxdWVzdFR5cGVfZGVmYXVsdC5PVEhFUjsKICAgIHRoaXMuc2VydmVyS2V5ID0gb3B0aW9ucy5zZXJ2ZXJLZXk7CiAgICB0aGlzLnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuVU5JU1NVRUQ7CiAgICB0aGlzLmRlZmVycmVkID0gdm9pZCAwOwogICAgdGhpcy5jYW5jZWxsZWQgPSBmYWxzZTsKICB9CiAgdmFyIFJlcXVlc3RfZGVmYXVsdDsKICB2YXIgaW5pdF9SZXF1ZXN0ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZXF1ZXN0LmpzIigpIHsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfUmVxdWVzdFN0YXRlKCk7CiAgICAgIGluaXRfUmVxdWVzdFR5cGUoKTsKICAgICAgUmVxdWVzdDIucHJvdG90eXBlLmNhbmNlbCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRoaXMuY2FuY2VsbGVkID0gdHJ1ZTsKICAgICAgfTsKICAgICAgUmVxdWVzdDIucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBSZXF1ZXN0Mih0aGlzKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnVybCA9IHRoaXMudXJsOwogICAgICAgIHJlc3VsdC5yZXF1ZXN0RnVuY3Rpb24gPSB0aGlzLnJlcXVlc3RGdW5jdGlvbjsKICAgICAgICByZXN1bHQuY2FuY2VsRnVuY3Rpb24gPSB0aGlzLmNhbmNlbEZ1bmN0aW9uOwogICAgICAgIHJlc3VsdC5wcmlvcml0eUZ1bmN0aW9uID0gdGhpcy5wcmlvcml0eUZ1bmN0aW9uOwogICAgICAgIHJlc3VsdC5wcmlvcml0eSA9IHRoaXMucHJpb3JpdHk7CiAgICAgICAgcmVzdWx0LnRocm90dGxlID0gdGhpcy50aHJvdHRsZTsKICAgICAgICByZXN1bHQudGhyb3R0bGVCeVNlcnZlciA9IHRoaXMudGhyb3R0bGVCeVNlcnZlcjsKICAgICAgICByZXN1bHQudHlwZSA9IHRoaXMudHlwZTsKICAgICAgICByZXN1bHQuc2VydmVyS2V5ID0gdGhpcy5zZXJ2ZXJLZXk7CiAgICAgICAgcmVzdWx0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuVU5JU1NVRUQ7CiAgICAgICAgcmVzdWx0LmRlZmVycmVkID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5jYW5jZWxsZWQgPSBmYWxzZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBSZXF1ZXN0X2RlZmF1bHQgPSBSZXF1ZXN0MjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL3BhcnNlUmVzcG9uc2VIZWFkZXJzLmpzCiAgZnVuY3Rpb24gcGFyc2VSZXNwb25zZUhlYWRlcnMoaGVhZGVyU3RyaW5nKSB7CiAgICBjb25zdCBoZWFkZXJzID0ge307CiAgICBpZiAoIWhlYWRlclN0cmluZykgewogICAgICByZXR1cm4gaGVhZGVyczsKICAgIH0KICAgIGNvbnN0IGhlYWRlclBhaXJzID0gaGVhZGVyU3RyaW5nLnNwbGl0KCJcclxuIik7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgaGVhZGVyUGFpcnMubGVuZ3RoOyArK2kyKSB7CiAgICAgIGNvbnN0IGhlYWRlclBhaXIgPSBoZWFkZXJQYWlyc1tpMl07CiAgICAgIGNvbnN0IGluZGV4ID0gaGVhZGVyUGFpci5pbmRleE9mKCI6ICIpOwogICAgICBpZiAoaW5kZXggPiAwKSB7CiAgICAgICAgY29uc3Qga2V5ID0gaGVhZGVyUGFpci5zdWJzdHJpbmcoMCwgaW5kZXgpOwogICAgICAgIGNvbnN0IHZhbCA9IGhlYWRlclBhaXIuc3Vic3RyaW5nKGluZGV4ICsgMik7CiAgICAgICAgaGVhZGVyc1trZXldID0gdmFsOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gaGVhZGVyczsKICB9CiAgdmFyIHBhcnNlUmVzcG9uc2VIZWFkZXJzX2RlZmF1bHQ7CiAgdmFyIGluaXRfcGFyc2VSZXNwb25zZUhlYWRlcnMgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL3BhcnNlUmVzcG9uc2VIZWFkZXJzLmpzIigpIHsKICAgICAgcGFyc2VSZXNwb25zZUhlYWRlcnNfZGVmYXVsdCA9IHBhcnNlUmVzcG9uc2VIZWFkZXJzOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVxdWVzdEVycm9yRXZlbnQuanMKICBmdW5jdGlvbiBSZXF1ZXN0RXJyb3JFdmVudChzdGF0dXNDb2RlLCByZXNwb25zZSwgcmVzcG9uc2VIZWFkZXJzKSB7CiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlOwogICAgdGhpcy5yZXNwb25zZSA9IHJlc3BvbnNlOwogICAgdGhpcy5yZXNwb25zZUhlYWRlcnMgPSByZXNwb25zZUhlYWRlcnM7CiAgICBpZiAodHlwZW9mIHRoaXMucmVzcG9uc2VIZWFkZXJzID09PSAic3RyaW5nIikgewogICAgICB0aGlzLnJlc3BvbnNlSGVhZGVycyA9IHBhcnNlUmVzcG9uc2VIZWFkZXJzX2RlZmF1bHQodGhpcy5yZXNwb25zZUhlYWRlcnMpOwogICAgfQogIH0KICB2YXIgUmVxdWVzdEVycm9yRXZlbnRfZGVmYXVsdDsKICB2YXIgaW5pdF9SZXF1ZXN0RXJyb3JFdmVudCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVxdWVzdEVycm9yRXZlbnQuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9wYXJzZVJlc3BvbnNlSGVhZGVycygpOwogICAgICBSZXF1ZXN0RXJyb3JFdmVudC5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbigpIHsKICAgICAgICBsZXQgc3RyID0gIlJlcXVlc3QgaGFzIGZhaWxlZC4iOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGhpcy5zdGF0dXNDb2RlKSkgewogICAgICAgICAgc3RyICs9IGAgU3RhdHVzIENvZGU6ICR7dGhpcy5zdGF0dXNDb2RlfWA7CiAgICAgICAgfQogICAgICAgIHJldHVybiBzdHI7CiAgICAgIH07CiAgICAgIFJlcXVlc3RFcnJvckV2ZW50X2RlZmF1bHQgPSBSZXF1ZXN0RXJyb3JFdmVudDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0V2ZW50LmpzCiAgZnVuY3Rpb24gRXZlbnQoKSB7CiAgICB0aGlzLl9saXN0ZW5lcnMgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogICAgdGhpcy5fdG9SZW1vdmUgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogICAgdGhpcy5fdG9BZGQgPSAvKiBAX19QVVJFX18gKi8gbmV3IE1hcCgpOwogICAgdGhpcy5faW52b2tpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgIHRoaXMuX2xpc3RlbmVyQ291bnQgPSAwOwogIH0KICBmdW5jdGlvbiBhZGRFdmVudExpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lck1hcCwgbGlzdGVuZXIsIHNjb3BlKSB7CiAgICBpZiAoIWxpc3RlbmVyTWFwLmhhcyhsaXN0ZW5lcikpIHsKICAgICAgbGlzdGVuZXJNYXAuc2V0KGxpc3RlbmVyLCAvKiBAX19QVVJFX18gKi8gbmV3IFNldCgpKTsKICAgIH0KICAgIGNvbnN0IHNjb3BlcyA9IGxpc3RlbmVyTWFwLmdldChsaXN0ZW5lcik7CiAgICBpZiAoIXNjb3Blcy5oYXMoc2NvcGUpKSB7CiAgICAgIHNjb3Blcy5hZGQoc2NvcGUpOwogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CiAgZnVuY3Rpb24gcmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgbGlzdGVuZXJNYXAsIGxpc3RlbmVyLCBzY29wZSkgewogICAgY29uc3Qgc2NvcGVzID0gbGlzdGVuZXJNYXAuZ2V0KGxpc3RlbmVyKTsKICAgIGlmICghc2NvcGVzIHx8ICFzY29wZXMuaGFzKHNjb3BlKSkgewogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICBpZiAoZXZlbnQuX2ludm9raW5nTGlzdGVuZXJzKSB7CiAgICAgIGlmICghYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgZXZlbnQuX3RvUmVtb3ZlLCBsaXN0ZW5lciwgc2NvcGUpKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9CiAgICB9IGVsc2UgewogICAgICBzY29wZXMuZGVsZXRlKHNjb3BlKTsKICAgICAgaWYgKHNjb3Blcy5zaXplID09PSAwKSB7CiAgICAgICAgbGlzdGVuZXJNYXAuZGVsZXRlKGxpc3RlbmVyKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQogIHZhciBFdmVudF9kZWZhdWx0OwogIHZhciBpbml0X0V2ZW50ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FdmVudC5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEV2ZW50LnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBudW1iZXIgb2YgbGlzdGVuZXJzIGN1cnJlbnRseSBzdWJzY3JpYmVkIHRvIHRoZSBldmVudC4KICAgICAgICAgKiBAbWVtYmVyb2YgRXZlbnQucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBudW1iZXJPZkxpc3RlbmVyczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xpc3RlbmVyQ291bnQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgRXZlbnQucHJvdG90eXBlLmFkZEV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbihsaXN0ZW5lciwgc2NvcGUpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5mdW5jKCJsaXN0ZW5lciIsIGxpc3RlbmVyKTsKICAgICAgICBjb25zdCBldmVudCA9IHRoaXM7CiAgICAgICAgY29uc3QgbGlzdGVuZXJNYXAgPSBldmVudC5faW52b2tpbmdMaXN0ZW5lcnMgPyBldmVudC5fdG9BZGQgOiBldmVudC5fbGlzdGVuZXJzOwogICAgICAgIGNvbnN0IGFkZGVkID0gYWRkRXZlbnRMaXN0ZW5lcih0aGlzLCBsaXN0ZW5lck1hcCwgbGlzdGVuZXIsIHNjb3BlKTsKICAgICAgICBpZiAoYWRkZWQpIHsKICAgICAgICAgIGV2ZW50Ll9saXN0ZW5lckNvdW50Kys7CiAgICAgICAgfQogICAgICAgIHJldHVybiBmdW5jdGlvbigpIHsKICAgICAgICAgIGV2ZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIobGlzdGVuZXIsIHNjb3BlKTsKICAgICAgICB9OwogICAgICB9OwogICAgICBFdmVudC5wcm90b3R5cGUucmVtb3ZlRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGxpc3RlbmVyLCBzY29wZSkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLmZ1bmMoImxpc3RlbmVyIiwgbGlzdGVuZXIpOwogICAgICAgIGNvbnN0IHJlbW92ZWRGcm9tTGlzdGVuZXJzID0gcmVtb3ZlRXZlbnRMaXN0ZW5lcigKICAgICAgICAgIHRoaXMsCiAgICAgICAgICB0aGlzLl9saXN0ZW5lcnMsCiAgICAgICAgICBsaXN0ZW5lciwKICAgICAgICAgIHNjb3BlCiAgICAgICAgKTsKICAgICAgICBjb25zdCByZW1vdmVkRnJvbVRvQWRkID0gcmVtb3ZlRXZlbnRMaXN0ZW5lcigKICAgICAgICAgIHRoaXMsCiAgICAgICAgICB0aGlzLl90b0FkZCwKICAgICAgICAgIGxpc3RlbmVyLAogICAgICAgICAgc2NvcGUKICAgICAgICApOwogICAgICAgIGNvbnN0IHJlbW92ZWQgPSByZW1vdmVkRnJvbUxpc3RlbmVycyB8fCByZW1vdmVkRnJvbVRvQWRkOwogICAgICAgIGlmIChyZW1vdmVkKSB7CiAgICAgICAgICB0aGlzLl9saXN0ZW5lckNvdW50LS07CiAgICAgICAgfQogICAgICAgIHJldHVybiByZW1vdmVkOwogICAgICB9OwogICAgICBFdmVudC5wcm90b3R5cGUucmFpc2VFdmVudCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRoaXMuX2ludm9raW5nTGlzdGVuZXJzID0gdHJ1ZTsKICAgICAgICBmb3IgKGNvbnN0IFtsaXN0ZW5lciwgc2NvcGVzXSBvZiB0aGlzLl9saXN0ZW5lcnMuZW50cmllcygpKSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChsaXN0ZW5lcikpIHsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGNvbnN0IHNjb3BlIG9mIHNjb3BlcykgewogICAgICAgICAgICBsaXN0ZW5lci5hcHBseShzY29wZSwgYXJndW1lbnRzKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgdGhpcy5faW52b2tpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgICAgICBmb3IgKGNvbnN0IFtsaXN0ZW5lciwgc2NvcGVzXSBvZiB0aGlzLl90b0FkZC5lbnRyaWVzKCkpIHsKICAgICAgICAgIGZvciAoY29uc3Qgc2NvcGUgb2Ygc2NvcGVzKSB7CiAgICAgICAgICAgIGFkZEV2ZW50TGlzdGVuZXIodGhpcywgdGhpcy5fbGlzdGVuZXJzLCBsaXN0ZW5lciwgc2NvcGUpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB0aGlzLl90b0FkZC5jbGVhcigpOwogICAgICAgIGZvciAoY29uc3QgW2xpc3RlbmVyLCBzY29wZXNdIG9mIHRoaXMuX3RvUmVtb3ZlLmVudHJpZXMoKSkgewogICAgICAgICAgZm9yIChjb25zdCBzY29wZSBvZiBzY29wZXMpIHsKICAgICAgICAgICAgcmVtb3ZlRXZlbnRMaXN0ZW5lcih0aGlzLCB0aGlzLl9saXN0ZW5lcnMsIGxpc3RlbmVyLCBzY29wZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHRoaXMuX3RvUmVtb3ZlLmNsZWFyKCk7CiAgICAgIH07CiAgICAgIEV2ZW50X2RlZmF1bHQgPSBFdmVudDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0hlYXAuanMKICBmdW5jdGlvbiBIZWFwKG9wdGlvbnMpIHsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucyIsIG9wdGlvbnMpOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLmNvbXBhcmF0b3IiLCBvcHRpb25zLmNvbXBhcmF0b3IpOwogICAgdGhpcy5fY29tcGFyYXRvciA9IG9wdGlvbnMuY29tcGFyYXRvcjsKICAgIHRoaXMuX2FycmF5ID0gW107CiAgICB0aGlzLl9sZW5ndGggPSAwOwogICAgdGhpcy5fbWF4aW11bUxlbmd0aCA9IHZvaWQgMDsKICB9CiAgZnVuY3Rpb24gc3dhcChhcnJheSwgYTQsIGIyKSB7CiAgICBjb25zdCB0ZW1wID0gYXJyYXlbYTRdOwogICAgYXJyYXlbYTRdID0gYXJyYXlbYjJdOwogICAgYXJyYXlbYjJdID0gdGVtcDsKICB9CiAgdmFyIEhlYXBfZGVmYXVsdDsKICB2YXIgaW5pdF9IZWFwID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9IZWFwLmpzIigpIHsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoSGVhcC5wcm90b3R5cGUsIHsKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBsZW5ndGggb2YgdGhlIGhlYXAuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgSGVhcC5wcm90b3R5cGUKICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgbGVuZ3RoOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fbGVuZ3RoOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgaW50ZXJuYWwgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgSGVhcC5wcm90b3R5cGUKICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtBcnJheX0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBpbnRlcm5hbEFycmF5OiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fYXJyYXk7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIGFuZCBzZXRzIHRoZSBtYXhpbXVtIGxlbmd0aCBvZiB0aGUgaGVhcC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBIZWFwLnByb3RvdHlwZQogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKi8KICAgICAgICBtYXhpbXVtTGVuZ3RoOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fbWF4aW11bUxlbmd0aDsKICAgICAgICAgIH0sCiAgICAgICAgICBzZXQ6IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJtYXhpbXVtTGVuZ3RoIiwgdmFsdWUsIDApOwogICAgICAgICAgICBjb25zdCBvcmlnaW5hbExlbmd0aCA9IHRoaXMuX2xlbmd0aDsKICAgICAgICAgICAgaWYgKHZhbHVlIDwgb3JpZ2luYWxMZW5ndGgpIHsKICAgICAgICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuX2FycmF5OwogICAgICAgICAgICAgIGZvciAobGV0IGkyID0gdmFsdWU7IGkyIDwgb3JpZ2luYWxMZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgICAgIGFycmF5W2kyXSA9IHZvaWQgMDsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdGhpcy5fbGVuZ3RoID0gdmFsdWU7CiAgICAgICAgICAgICAgYXJyYXkubGVuZ3RoID0gdmFsdWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy5fbWF4aW11bUxlbmd0aCA9IHZhbHVlOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGNvbXBhcmF0b3IgdG8gdXNlIGZvciB0aGUgaGVhcC4gSWYgY29tcGFyYXRvcihhLCBiKSBpcyBsZXNzIHRoYW4gMCwgc29ydCBhIHRvIGEgbG93ZXIgaW5kZXggdGhhbiBiLCBvdGhlcndpc2Ugc29ydCB0byBhIGhpZ2hlciBpbmRleC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBIZWFwLnByb3RvdHlwZQogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge0hlYXAuQ29tcGFyYXRvckNhbGxiYWNrfQogICAgICAgICAqLwogICAgICAgIGNvbXBhcmF0b3I6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9jb21wYXJhdG9yOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIEhlYXAucHJvdG90eXBlLnJlc2VydmUgPSBmdW5jdGlvbihsZW5ndGgpIHsKICAgICAgICBsZW5ndGggPSBsZW5ndGggPz8gdGhpcy5fbGVuZ3RoOwogICAgICAgIHRoaXMuX2FycmF5Lmxlbmd0aCA9IGxlbmd0aDsKICAgICAgfTsKICAgICAgSGVhcC5wcm90b3R5cGUuaGVhcGlmeSA9IGZ1bmN0aW9uKGluZGV4KSB7CiAgICAgICAgaW5kZXggPSBpbmRleCA/PyAwOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IHRoaXMuX2xlbmd0aDsKICAgICAgICBjb25zdCBjb21wYXJhdG9yID0gdGhpcy5fY29tcGFyYXRvcjsKICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuX2FycmF5OwogICAgICAgIGxldCBjYW5kaWRhdGU7CiAgICAgICAgbGV0IGluc2VydGluZyA9IHRydWU7CiAgICAgICAgd2hpbGUgKGluc2VydGluZykgewogICAgICAgICAgY29uc3QgcmlnaHQgPSAyICogKGluZGV4ICsgMSk7CiAgICAgICAgICBjb25zdCBsZWZ0ID0gcmlnaHQgLSAxOwogICAgICAgICAgaWYgKGxlZnQgPCBsZW5ndGggJiYgY29tcGFyYXRvcihhcnJheVtsZWZ0XSwgYXJyYXlbaW5kZXhdKSA8IDApIHsKICAgICAgICAgICAgY2FuZGlkYXRlID0gbGVmdDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGNhbmRpZGF0ZSA9IGluZGV4OwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJpZ2h0IDwgbGVuZ3RoICYmIGNvbXBhcmF0b3IoYXJyYXlbcmlnaHRdLCBhcnJheVtjYW5kaWRhdGVdKSA8IDApIHsKICAgICAgICAgICAgY2FuZGlkYXRlID0gcmlnaHQ7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoY2FuZGlkYXRlICE9PSBpbmRleCkgewogICAgICAgICAgICBzd2FwKGFycmF5LCBjYW5kaWRhdGUsIGluZGV4KTsKICAgICAgICAgICAgaW5kZXggPSBjYW5kaWRhdGU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpbnNlcnRpbmcgPSBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH07CiAgICAgIEhlYXAucHJvdG90eXBlLnJlc29ydCA9IGZ1bmN0aW9uKCkgewogICAgICAgIGNvbnN0IGxlbmd0aCA9IHRoaXMuX2xlbmd0aDsKICAgICAgICBmb3IgKGxldCBpMiA9IE1hdGguY2VpbChsZW5ndGggLyAyKTsgaTIgPj0gMDsgLS1pMikgewogICAgICAgICAgdGhpcy5oZWFwaWZ5KGkyKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIEhlYXAucHJvdG90eXBlLmluc2VydCA9IGZ1bmN0aW9uKGVsZW1lbnQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImVsZW1lbnQiLCBlbGVtZW50KTsKICAgICAgICBjb25zdCBhcnJheSA9IHRoaXMuX2FycmF5OwogICAgICAgIGNvbnN0IGNvbXBhcmF0b3IgPSB0aGlzLl9jb21wYXJhdG9yOwogICAgICAgIGNvbnN0IG1heGltdW1MZW5ndGggPSB0aGlzLl9tYXhpbXVtTGVuZ3RoOwogICAgICAgIGxldCBpbmRleCA9IHRoaXMuX2xlbmd0aCsrOwogICAgICAgIGlmIChpbmRleCA8IGFycmF5Lmxlbmd0aCkgewogICAgICAgICAgYXJyYXlbaW5kZXhdID0gZWxlbWVudDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgYXJyYXkucHVzaChlbGVtZW50KTsKICAgICAgICB9CiAgICAgICAgd2hpbGUgKGluZGV4ICE9PSAwKSB7CiAgICAgICAgICBjb25zdCBwYXJlbnQgPSBNYXRoLmZsb29yKChpbmRleCAtIDEpIC8gMik7CiAgICAgICAgICBpZiAoY29tcGFyYXRvcihhcnJheVtpbmRleF0sIGFycmF5W3BhcmVudF0pIDwgMCkgewogICAgICAgICAgICBzd2FwKGFycmF5LCBpbmRleCwgcGFyZW50KTsKICAgICAgICAgICAgaW5kZXggPSBwYXJlbnQ7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbGV0IHJlbW92ZWRFbGVtZW50OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWF4aW11bUxlbmd0aCkgJiYgdGhpcy5fbGVuZ3RoID4gbWF4aW11bUxlbmd0aCkgewogICAgICAgICAgcmVtb3ZlZEVsZW1lbnQgPSBhcnJheVttYXhpbXVtTGVuZ3RoXTsKICAgICAgICAgIHRoaXMuX2xlbmd0aCA9IG1heGltdW1MZW5ndGg7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZW1vdmVkRWxlbWVudDsKICAgICAgfTsKICAgICAgSGVhcC5wcm90b3R5cGUucG9wID0gZnVuY3Rpb24oaW5kZXgpIHsKICAgICAgICBpbmRleCA9IGluZGV4ID8/IDA7CiAgICAgICAgaWYgKHRoaXMuX2xlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuKCJpbmRleCIsIGluZGV4LCB0aGlzLl9sZW5ndGgpOwogICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5fYXJyYXk7CiAgICAgICAgY29uc3Qgcm9vdCA9IGFycmF5W2luZGV4XTsKICAgICAgICBzd2FwKGFycmF5LCBpbmRleCwgLS10aGlzLl9sZW5ndGgpOwogICAgICAgIHRoaXMuaGVhcGlmeShpbmRleCk7CiAgICAgICAgYXJyYXlbdGhpcy5fbGVuZ3RoXSA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gcm9vdDsKICAgICAgfTsKICAgICAgSGVhcF9kZWZhdWx0ID0gSGVhcDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JlcXVlc3RTY2hlZHVsZXIuanMKICBmdW5jdGlvbiBzb3J0UmVxdWVzdHMoYTQsIGIyKSB7CiAgICByZXR1cm4gYTQucHJpb3JpdHkgLSBiMi5wcmlvcml0eTsKICB9CiAgZnVuY3Rpb24gUmVxdWVzdFNjaGVkdWxlcigpIHsKICB9CiAgZnVuY3Rpb24gdXBkYXRlUHJpb3JpdHkocmVxdWVzdCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZXF1ZXN0LnByaW9yaXR5RnVuY3Rpb24pKSB7CiAgICAgIHJlcXVlc3QucHJpb3JpdHkgPSByZXF1ZXN0LnByaW9yaXR5RnVuY3Rpb24oKTsKICAgIH0KICB9CiAgZnVuY3Rpb24gaXNzdWVSZXF1ZXN0KHJlcXVlc3QpIHsKICAgIGlmIChyZXF1ZXN0LnN0YXRlID09PSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5VTklTU1VFRCkgewogICAgICByZXF1ZXN0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuSVNTVUVEOwogICAgICByZXF1ZXN0LmRlZmVycmVkID0gZGVmZXJfZGVmYXVsdCgpOwogICAgfQogICAgcmV0dXJuIHJlcXVlc3QuZGVmZXJyZWQucHJvbWlzZTsKICB9CiAgZnVuY3Rpb24gZ2V0UmVxdWVzdFJlY2VpdmVkRnVuY3Rpb24ocmVxdWVzdCkgewogICAgcmV0dXJuIGZ1bmN0aW9uKHJlc3VsdHMpIHsKICAgICAgaWYgKHJlcXVlc3Quc3RhdGUgPT09IFJlcXVlc3RTdGF0ZV9kZWZhdWx0LkNBTkNFTExFRCkgewogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICBjb25zdCBkZWZlcnJlZCA9IHJlcXVlc3QuZGVmZXJyZWQ7CiAgICAgIC0tc3RhdGlzdGljcy5udW1iZXJPZkFjdGl2ZVJlcXVlc3RzOwogICAgICAtLW51bWJlck9mQWN0aXZlUmVxdWVzdHNCeVNlcnZlcltyZXF1ZXN0LnNlcnZlcktleV07CiAgICAgIHJlcXVlc3RDb21wbGV0ZWRFdmVudC5yYWlzZUV2ZW50KCk7CiAgICAgIHJlcXVlc3Quc3RhdGUgPSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5SRUNFSVZFRDsKICAgICAgcmVxdWVzdC5kZWZlcnJlZCA9IHZvaWQgMDsKICAgICAgZGVmZXJyZWQucmVzb2x2ZShyZXN1bHRzKTsKICAgIH07CiAgfQogIGZ1bmN0aW9uIGdldFJlcXVlc3RGYWlsZWRGdW5jdGlvbihyZXF1ZXN0KSB7CiAgICByZXR1cm4gZnVuY3Rpb24oZXJyb3IpIHsKICAgICAgaWYgKHJlcXVlc3Quc3RhdGUgPT09IFJlcXVlc3RTdGF0ZV9kZWZhdWx0LkNBTkNFTExFRCkgewogICAgICAgIHJldHVybjsKICAgICAgfQogICAgICArK3N0YXRpc3RpY3MubnVtYmVyT2ZGYWlsZWRSZXF1ZXN0czsKICAgICAgLS1zdGF0aXN0aWNzLm51bWJlck9mQWN0aXZlUmVxdWVzdHM7CiAgICAgIC0tbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyW3JlcXVlc3Quc2VydmVyS2V5XTsKICAgICAgcmVxdWVzdENvbXBsZXRlZEV2ZW50LnJhaXNlRXZlbnQoZXJyb3IpOwogICAgICByZXF1ZXN0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuRkFJTEVEOwogICAgICByZXF1ZXN0LmRlZmVycmVkLnJlamVjdChlcnJvcik7CiAgICB9OwogIH0KICBmdW5jdGlvbiBzdGFydFJlcXVlc3QocmVxdWVzdCkgewogICAgY29uc3QgcHJvbWlzZSA9IGlzc3VlUmVxdWVzdChyZXF1ZXN0KTsKICAgIHJlcXVlc3Quc3RhdGUgPSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5BQ1RJVkU7CiAgICBhY3RpdmVSZXF1ZXN0cy5wdXNoKHJlcXVlc3QpOwogICAgKytzdGF0aXN0aWNzLm51bWJlck9mQWN0aXZlUmVxdWVzdHM7CiAgICArK3N0YXRpc3RpY3MubnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0V2ZXI7CiAgICArK251bWJlck9mQWN0aXZlUmVxdWVzdHNCeVNlcnZlcltyZXF1ZXN0LnNlcnZlcktleV07CiAgICByZXF1ZXN0LnJlcXVlc3RGdW5jdGlvbigpLnRoZW4oZ2V0UmVxdWVzdFJlY2VpdmVkRnVuY3Rpb24ocmVxdWVzdCkpLmNhdGNoKGdldFJlcXVlc3RGYWlsZWRGdW5jdGlvbihyZXF1ZXN0KSk7CiAgICByZXR1cm4gcHJvbWlzZTsKICB9CiAgZnVuY3Rpb24gY2FuY2VsUmVxdWVzdChyZXF1ZXN0KSB7CiAgICBjb25zdCBhY3RpdmUgPSByZXF1ZXN0LnN0YXRlID09PSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5BQ1RJVkU7CiAgICByZXF1ZXN0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuQ0FOQ0VMTEVEOwogICAgKytzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkUmVxdWVzdHM7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlcXVlc3QuZGVmZXJyZWQpKSB7CiAgICAgIGNvbnN0IGRlZmVycmVkID0gcmVxdWVzdC5kZWZlcnJlZDsKICAgICAgZGVmZXJyZWQucHJvbWlzZS5jYXRjaCgoKSA9PiB7CiAgICAgIH0pOwogICAgICByZXF1ZXN0LmRlZmVycmVkID0gdm9pZCAwOwogICAgICBkZWZlcnJlZC5yZWplY3QobmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KGBSZXF1ZXN0IGNhbmNlbGxlZDogIiR7cmVxdWVzdC51cmx9ImApKTsKICAgIH0KICAgIGlmIChhY3RpdmUpIHsKICAgICAgLS1zdGF0aXN0aWNzLm51bWJlck9mQWN0aXZlUmVxdWVzdHM7CiAgICAgIC0tbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyW3JlcXVlc3Quc2VydmVyS2V5XTsKICAgICAgKytzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkQWN0aXZlUmVxdWVzdHM7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlcXVlc3QuY2FuY2VsRnVuY3Rpb24pKSB7CiAgICAgIHJlcXVlc3QuY2FuY2VsRnVuY3Rpb24oKTsKICAgIH0KICB9CiAgZnVuY3Rpb24gdXBkYXRlU3RhdGlzdGljcygpIHsKICAgIGlmICghUmVxdWVzdFNjaGVkdWxlci5kZWJ1Z1Nob3dTdGF0aXN0aWNzKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGlmIChzdGF0aXN0aWNzLm51bWJlck9mQWN0aXZlUmVxdWVzdHMgPT09IDAgJiYgc3RhdGlzdGljcy5sYXN0TnVtYmVyT2ZBY3RpdmVSZXF1ZXN0cyA+IDApIHsKICAgICAgaWYgKHN0YXRpc3RpY3MubnVtYmVyT2ZBdHRlbXB0ZWRSZXF1ZXN0cyA+IDApIHsKICAgICAgICBjb25zb2xlLmxvZygKICAgICAgICAgIGBOdW1iZXIgb2YgYXR0ZW1wdGVkIHJlcXVlc3RzOiAke3N0YXRpc3RpY3MubnVtYmVyT2ZBdHRlbXB0ZWRSZXF1ZXN0c31gCiAgICAgICAgKTsKICAgICAgICBzdGF0aXN0aWNzLm51bWJlck9mQXR0ZW1wdGVkUmVxdWVzdHMgPSAwOwogICAgICB9CiAgICAgIGlmIChzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkUmVxdWVzdHMgPiAwKSB7CiAgICAgICAgY29uc29sZS5sb2coCiAgICAgICAgICBgTnVtYmVyIG9mIGNhbmNlbGxlZCByZXF1ZXN0czogJHtzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkUmVxdWVzdHN9YAogICAgICAgICk7CiAgICAgICAgc3RhdGlzdGljcy5udW1iZXJPZkNhbmNlbGxlZFJlcXVlc3RzID0gMDsKICAgICAgfQogICAgICBpZiAoc3RhdGlzdGljcy5udW1iZXJPZkNhbmNlbGxlZEFjdGl2ZVJlcXVlc3RzID4gMCkgewogICAgICAgIGNvbnNvbGUubG9nKAogICAgICAgICAgYE51bWJlciBvZiBjYW5jZWxsZWQgYWN0aXZlIHJlcXVlc3RzOiAke3N0YXRpc3RpY3MubnVtYmVyT2ZDYW5jZWxsZWRBY3RpdmVSZXF1ZXN0c31gCiAgICAgICAgKTsKICAgICAgICBzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkQWN0aXZlUmVxdWVzdHMgPSAwOwogICAgICB9CiAgICAgIGlmIChzdGF0aXN0aWNzLm51bWJlck9mRmFpbGVkUmVxdWVzdHMgPiAwKSB7CiAgICAgICAgY29uc29sZS5sb2coCiAgICAgICAgICBgTnVtYmVyIG9mIGZhaWxlZCByZXF1ZXN0czogJHtzdGF0aXN0aWNzLm51bWJlck9mRmFpbGVkUmVxdWVzdHN9YAogICAgICAgICk7CiAgICAgICAgc3RhdGlzdGljcy5udW1iZXJPZkZhaWxlZFJlcXVlc3RzID0gMDsKICAgICAgfQogICAgfQogICAgc3RhdGlzdGljcy5sYXN0TnVtYmVyT2ZBY3RpdmVSZXF1ZXN0cyA9IHN0YXRpc3RpY3MubnVtYmVyT2ZBY3RpdmVSZXF1ZXN0czsKICB9CiAgdmFyIGltcG9ydF91cmlqczQsIHN0YXRpc3RpY3MsIHByaW9yaXR5SGVhcExlbmd0aCwgcmVxdWVzdEhlYXAsIGFjdGl2ZVJlcXVlc3RzLCBudW1iZXJPZkFjdGl2ZVJlcXVlc3RzQnlTZXJ2ZXIsIHBhZ2VVcmksIHJlcXVlc3RDb21wbGV0ZWRFdmVudCwgUmVxdWVzdFNjaGVkdWxlcl9kZWZhdWx0OwogIHZhciBpbml0X1JlcXVlc3RTY2hlZHVsZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JlcXVlc3RTY2hlZHVsZXIuanMiKCkgewogICAgICBpbXBvcnRfdXJpanM0ID0gX190b0VTTShyZXF1aXJlX1VSSSgpLCAxKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmVyKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0V2ZW50KCk7CiAgICAgIGluaXRfSGVhcCgpOwogICAgICBpbml0X2lzQmxvYlVyaSgpOwogICAgICBpbml0X2lzRGF0YVVyaSgpOwogICAgICBpbml0X1JlcXVlc3RTdGF0ZSgpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBzdGF0aXN0aWNzID0gewogICAgICAgIG51bWJlck9mQXR0ZW1wdGVkUmVxdWVzdHM6IDAsCiAgICAgICAgbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0czogMCwKICAgICAgICBudW1iZXJPZkNhbmNlbGxlZFJlcXVlc3RzOiAwLAogICAgICAgIG51bWJlck9mQ2FuY2VsbGVkQWN0aXZlUmVxdWVzdHM6IDAsCiAgICAgICAgbnVtYmVyT2ZGYWlsZWRSZXF1ZXN0czogMCwKICAgICAgICBudW1iZXJPZkFjdGl2ZVJlcXVlc3RzRXZlcjogMCwKICAgICAgICBsYXN0TnVtYmVyT2ZBY3RpdmVSZXF1ZXN0czogMAogICAgICB9OwogICAgICBwcmlvcml0eUhlYXBMZW5ndGggPSAyMDsKICAgICAgcmVxdWVzdEhlYXAgPSBuZXcgSGVhcF9kZWZhdWx0KHsKICAgICAgICBjb21wYXJhdG9yOiBzb3J0UmVxdWVzdHMKICAgICAgfSk7CiAgICAgIHJlcXVlc3RIZWFwLm1heGltdW1MZW5ndGggPSBwcmlvcml0eUhlYXBMZW5ndGg7CiAgICAgIHJlcXVlc3RIZWFwLnJlc2VydmUocHJpb3JpdHlIZWFwTGVuZ3RoKTsKICAgICAgYWN0aXZlUmVxdWVzdHMgPSBbXTsKICAgICAgbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyID0ge307CiAgICAgIHBhZ2VVcmkgPSB0eXBlb2YgZG9jdW1lbnQgIT09ICJ1bmRlZmluZWQiID8gbmV3IGltcG9ydF91cmlqczQuZGVmYXVsdChkb2N1bWVudC5sb2NhdGlvbi5ocmVmKSA6IG5ldyBpbXBvcnRfdXJpanM0LmRlZmF1bHQoKTsKICAgICAgcmVxdWVzdENvbXBsZXRlZEV2ZW50ID0gbmV3IEV2ZW50X2RlZmF1bHQoKTsKICAgICAgUmVxdWVzdFNjaGVkdWxlci5tYXhpbXVtUmVxdWVzdHMgPSA1MDsKICAgICAgUmVxdWVzdFNjaGVkdWxlci5tYXhpbXVtUmVxdWVzdHNQZXJTZXJ2ZXIgPSAxODsKICAgICAgUmVxdWVzdFNjaGVkdWxlci5yZXF1ZXN0c0J5U2VydmVyID0ge307CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIudGhyb3R0bGVSZXF1ZXN0cyA9IHRydWU7CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIuZGVidWdTaG93U3RhdGlzdGljcyA9IGZhbHNlOwogICAgICBSZXF1ZXN0U2NoZWR1bGVyLnJlcXVlc3RDb21wbGV0ZWRFdmVudCA9IHJlcXVlc3RDb21wbGV0ZWRFdmVudDsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoUmVxdWVzdFNjaGVkdWxlciwgewogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdGhlIHN0YXRpc3RpY3MgdXNlZCBieSB0aGUgcmVxdWVzdCBzY2hlZHVsZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgUmVxdWVzdFNjaGVkdWxlcgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge29iamVjdH0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIHN0YXRpc3RpY3M6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBzdGF0aXN0aWNzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG1heGltdW0gc2l6ZSBvZiB0aGUgcHJpb3JpdHkgaGVhcC4gVGhpcyBsaW1pdHMgdGhlIG51bWJlciBvZiByZXF1ZXN0cyB0aGF0IGFyZSBzb3J0ZWQgYnkgcHJpb3JpdHkuIE9ubHkgYXBwbGllcyB0byByZXF1ZXN0cyB0aGF0IGFyZSBub3QgeWV0IGFjdGl2ZS4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBSZXF1ZXN0U2NoZWR1bGVyCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBkZWZhdWx0IDIwCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBwcmlvcml0eUhlYXBMZW5ndGg6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBwcmlvcml0eUhlYXBMZW5ndGg7CiAgICAgICAgICB9LAogICAgICAgICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkgewogICAgICAgICAgICBpZiAodmFsdWUgPCBwcmlvcml0eUhlYXBMZW5ndGgpIHsKICAgICAgICAgICAgICB3aGlsZSAocmVxdWVzdEhlYXAubGVuZ3RoID4gdmFsdWUpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJlcXVlc3QgPSByZXF1ZXN0SGVhcC5wb3AoKTsKICAgICAgICAgICAgICAgIGNhbmNlbFJlcXVlc3QocmVxdWVzdCk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHByaW9yaXR5SGVhcExlbmd0aCA9IHZhbHVlOwogICAgICAgICAgICByZXF1ZXN0SGVhcC5tYXhpbXVtTGVuZ3RoID0gdmFsdWU7CiAgICAgICAgICAgIHJlcXVlc3RIZWFwLnJlc2VydmUodmFsdWUpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIuc2VydmVySGFzT3BlblNsb3RzID0gZnVuY3Rpb24oc2VydmVyS2V5LCBkZXNpcmVkUmVxdWVzdHMpIHsKICAgICAgICBkZXNpcmVkUmVxdWVzdHMgPSBkZXNpcmVkUmVxdWVzdHMgPz8gMTsKICAgICAgICBjb25zdCBtYXhSZXF1ZXN0cyA9IFJlcXVlc3RTY2hlZHVsZXIucmVxdWVzdHNCeVNlcnZlcltzZXJ2ZXJLZXldID8/IFJlcXVlc3RTY2hlZHVsZXIubWF4aW11bVJlcXVlc3RzUGVyU2VydmVyOwogICAgICAgIGNvbnN0IGhhc09wZW5TbG90c1NlcnZlciA9IG51bWJlck9mQWN0aXZlUmVxdWVzdHNCeVNlcnZlcltzZXJ2ZXJLZXldICsgZGVzaXJlZFJlcXVlc3RzIDw9IG1heFJlcXVlc3RzOwogICAgICAgIHJldHVybiBoYXNPcGVuU2xvdHNTZXJ2ZXI7CiAgICAgIH07CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIuaGVhcEhhc09wZW5TbG90cyA9IGZ1bmN0aW9uKGRlc2lyZWRSZXF1ZXN0cykgewogICAgICAgIGNvbnN0IGhhc09wZW5TbG90c0hlYXAgPSByZXF1ZXN0SGVhcC5sZW5ndGggKyBkZXNpcmVkUmVxdWVzdHMgPD0gcHJpb3JpdHlIZWFwTGVuZ3RoOwogICAgICAgIHJldHVybiBoYXNPcGVuU2xvdHNIZWFwOwogICAgICB9OwogICAgICBSZXF1ZXN0U2NoZWR1bGVyLnVwZGF0ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgcmVxdWVzdDsKICAgICAgICBsZXQgcmVtb3ZlQ291bnQgPSAwOwogICAgICAgIGNvbnN0IGFjdGl2ZUxlbmd0aCA9IGFjdGl2ZVJlcXVlc3RzLmxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBhY3RpdmVMZW5ndGg7ICsraTIpIHsKICAgICAgICAgIHJlcXVlc3QgPSBhY3RpdmVSZXF1ZXN0c1tpMl07CiAgICAgICAgICBpZiAocmVxdWVzdC5jYW5jZWxsZWQpIHsKICAgICAgICAgICAgY2FuY2VsUmVxdWVzdChyZXF1ZXN0KTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZXF1ZXN0LnN0YXRlICE9PSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5BQ1RJVkUpIHsKICAgICAgICAgICAgKytyZW1vdmVDb3VudDsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocmVtb3ZlQ291bnQgPiAwKSB7CiAgICAgICAgICAgIGFjdGl2ZVJlcXVlc3RzW2kyIC0gcmVtb3ZlQ291bnRdID0gcmVxdWVzdDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgYWN0aXZlUmVxdWVzdHMubGVuZ3RoIC09IHJlbW92ZUNvdW50OwogICAgICAgIGNvbnN0IGlzc3VlZFJlcXVlc3RzID0gcmVxdWVzdEhlYXAuaW50ZXJuYWxBcnJheTsKICAgICAgICBjb25zdCBpc3N1ZWRMZW5ndGggPSByZXF1ZXN0SGVhcC5sZW5ndGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgaXNzdWVkTGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICB1cGRhdGVQcmlvcml0eShpc3N1ZWRSZXF1ZXN0c1tpMl0pOwogICAgICAgIH0KICAgICAgICByZXF1ZXN0SGVhcC5yZXNvcnQoKTsKICAgICAgICBjb25zdCBvcGVuU2xvdHMgPSBNYXRoLm1heCgKICAgICAgICAgIFJlcXVlc3RTY2hlZHVsZXIubWF4aW11bVJlcXVlc3RzIC0gYWN0aXZlUmVxdWVzdHMubGVuZ3RoLAogICAgICAgICAgMAogICAgICAgICk7CiAgICAgICAgbGV0IGZpbGxlZFNsb3RzID0gMDsKICAgICAgICB3aGlsZSAoZmlsbGVkU2xvdHMgPCBvcGVuU2xvdHMgJiYgcmVxdWVzdEhlYXAubGVuZ3RoID4gMCkgewogICAgICAgICAgcmVxdWVzdCA9IHJlcXVlc3RIZWFwLnBvcCgpOwogICAgICAgICAgaWYgKHJlcXVlc3QuY2FuY2VsbGVkKSB7CiAgICAgICAgICAgIGNhbmNlbFJlcXVlc3QocmVxdWVzdCk7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJlcXVlc3QudGhyb3R0bGVCeVNlcnZlciAmJiAhUmVxdWVzdFNjaGVkdWxlci5zZXJ2ZXJIYXNPcGVuU2xvdHMocmVxdWVzdC5zZXJ2ZXJLZXkpKSB7CiAgICAgICAgICAgIGNhbmNlbFJlcXVlc3QocmVxdWVzdCk7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgc3RhcnRSZXF1ZXN0KHJlcXVlc3QpOwogICAgICAgICAgKytmaWxsZWRTbG90czsKICAgICAgICB9CiAgICAgICAgdXBkYXRlU3RhdGlzdGljcygpOwogICAgICB9OwogICAgICBSZXF1ZXN0U2NoZWR1bGVyLmdldFNlcnZlcktleSA9IGZ1bmN0aW9uKHVybCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLnN0cmluZygidXJsIiwgdXJsKTsKICAgICAgICBsZXQgdXJpID0gbmV3IGltcG9ydF91cmlqczQuZGVmYXVsdCh1cmwpOwogICAgICAgIGlmICh1cmkuc2NoZW1lKCkgPT09ICIiKSB7CiAgICAgICAgICB1cmkgPSB1cmkuYWJzb2x1dGVUbyhwYWdlVXJpKTsKICAgICAgICAgIHVyaS5ub3JtYWxpemUoKTsKICAgICAgICB9CiAgICAgICAgbGV0IHNlcnZlcktleSA9IHVyaS5hdXRob3JpdHkoKTsKICAgICAgICBpZiAoIS86Ly50ZXN0KHNlcnZlcktleSkpIHsKICAgICAgICAgIHNlcnZlcktleSA9IGAke3NlcnZlcktleX06JHt1cmkuc2NoZW1lKCkgPT09ICJodHRwcyIgPyAiNDQzIiA6ICI4MCJ9YDsKICAgICAgICB9CiAgICAgICAgY29uc3QgbGVuZ3RoID0gbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyW3NlcnZlcktleV07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobGVuZ3RoKSkgewogICAgICAgICAgbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyW3NlcnZlcktleV0gPSAwOwogICAgICAgIH0KICAgICAgICByZXR1cm4gc2VydmVyS2V5OwogICAgICB9OwogICAgICBSZXF1ZXN0U2NoZWR1bGVyLnJlcXVlc3QgPSBmdW5jdGlvbihyZXF1ZXN0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXF1ZXN0IiwgcmVxdWVzdCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yuc3RyaW5nKCJyZXF1ZXN0LnVybCIsIHJlcXVlc3QudXJsKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5mdW5jKCJyZXF1ZXN0LnJlcXVlc3RGdW5jdGlvbiIsIHJlcXVlc3QucmVxdWVzdEZ1bmN0aW9uKTsKICAgICAgICBpZiAoaXNEYXRhVXJpX2RlZmF1bHQocmVxdWVzdC51cmwpIHx8IGlzQmxvYlVyaV9kZWZhdWx0KHJlcXVlc3QudXJsKSkgewogICAgICAgICAgcmVxdWVzdENvbXBsZXRlZEV2ZW50LnJhaXNlRXZlbnQoKTsKICAgICAgICAgIHJlcXVlc3Quc3RhdGUgPSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5SRUNFSVZFRDsKICAgICAgICAgIHJldHVybiByZXF1ZXN0LnJlcXVlc3RGdW5jdGlvbigpOwogICAgICAgIH0KICAgICAgICArK3N0YXRpc3RpY3MubnVtYmVyT2ZBdHRlbXB0ZWRSZXF1ZXN0czsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXF1ZXN0LnNlcnZlcktleSkpIHsKICAgICAgICAgIHJlcXVlc3Quc2VydmVyS2V5ID0gUmVxdWVzdFNjaGVkdWxlci5nZXRTZXJ2ZXJLZXkocmVxdWVzdC51cmwpOwogICAgICAgIH0KICAgICAgICBpZiAoUmVxdWVzdFNjaGVkdWxlci50aHJvdHRsZVJlcXVlc3RzICYmIHJlcXVlc3QudGhyb3R0bGVCeVNlcnZlciAmJiAhUmVxdWVzdFNjaGVkdWxlci5zZXJ2ZXJIYXNPcGVuU2xvdHMocmVxdWVzdC5zZXJ2ZXJLZXkpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoIVJlcXVlc3RTY2hlZHVsZXIudGhyb3R0bGVSZXF1ZXN0cyB8fCAhcmVxdWVzdC50aHJvdHRsZSkgewogICAgICAgICAgcmV0dXJuIHN0YXJ0UmVxdWVzdChyZXF1ZXN0KTsKICAgICAgICB9CiAgICAgICAgaWYgKGFjdGl2ZVJlcXVlc3RzLmxlbmd0aCA+PSBSZXF1ZXN0U2NoZWR1bGVyLm1heGltdW1SZXF1ZXN0cykgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgdXBkYXRlUHJpb3JpdHkocmVxdWVzdCk7CiAgICAgICAgY29uc3QgcmVtb3ZlZFJlcXVlc3QgPSByZXF1ZXN0SGVhcC5pbnNlcnQocmVxdWVzdCk7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZW1vdmVkUmVxdWVzdCkpIHsKICAgICAgICAgIGlmIChyZW1vdmVkUmVxdWVzdCA9PT0gcmVxdWVzdCkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgY2FuY2VsUmVxdWVzdChyZW1vdmVkUmVxdWVzdCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBpc3N1ZVJlcXVlc3QocmVxdWVzdCk7CiAgICAgIH07CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIuY2xlYXJGb3JTcGVjcyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHdoaWxlIChyZXF1ZXN0SGVhcC5sZW5ndGggPiAwKSB7CiAgICAgICAgICBjb25zdCByZXF1ZXN0ID0gcmVxdWVzdEhlYXAucG9wKCk7CiAgICAgICAgICBjYW5jZWxSZXF1ZXN0KHJlcXVlc3QpOwogICAgICAgIH0KICAgICAgICBjb25zdCBsZW5ndGggPSBhY3RpdmVSZXF1ZXN0cy5sZW5ndGg7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY2FuY2VsUmVxdWVzdChhY3RpdmVSZXF1ZXN0c1tpMl0pOwogICAgICAgIH0KICAgICAgICBhY3RpdmVSZXF1ZXN0cy5sZW5ndGggPSAwOwogICAgICAgIG51bWJlck9mQWN0aXZlUmVxdWVzdHNCeVNlcnZlciA9IHt9OwogICAgICAgIHN0YXRpc3RpY3MubnVtYmVyT2ZBdHRlbXB0ZWRSZXF1ZXN0cyA9IDA7CiAgICAgICAgc3RhdGlzdGljcy5udW1iZXJPZkFjdGl2ZVJlcXVlc3RzID0gMDsKICAgICAgICBzdGF0aXN0aWNzLm51bWJlck9mQ2FuY2VsbGVkUmVxdWVzdHMgPSAwOwogICAgICAgIHN0YXRpc3RpY3MubnVtYmVyT2ZDYW5jZWxsZWRBY3RpdmVSZXF1ZXN0cyA9IDA7CiAgICAgICAgc3RhdGlzdGljcy5udW1iZXJPZkZhaWxlZFJlcXVlc3RzID0gMDsKICAgICAgICBzdGF0aXN0aWNzLm51bWJlck9mQWN0aXZlUmVxdWVzdHNFdmVyID0gMDsKICAgICAgICBzdGF0aXN0aWNzLmxhc3ROdW1iZXJPZkFjdGl2ZVJlcXVlc3RzID0gMDsKICAgICAgfTsKICAgICAgUmVxdWVzdFNjaGVkdWxlci5udW1iZXJPZkFjdGl2ZVJlcXVlc3RzQnlTZXJ2ZXIgPSBmdW5jdGlvbihzZXJ2ZXJLZXkpIHsKICAgICAgICByZXR1cm4gbnVtYmVyT2ZBY3RpdmVSZXF1ZXN0c0J5U2VydmVyW3NlcnZlcktleV07CiAgICAgIH07CiAgICAgIFJlcXVlc3RTY2hlZHVsZXIucmVxdWVzdEhlYXAgPSByZXF1ZXN0SGVhcDsKICAgICAgUmVxdWVzdFNjaGVkdWxlcl9kZWZhdWx0ID0gUmVxdWVzdFNjaGVkdWxlcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RydXN0ZWRTZXJ2ZXJzLmpzCiAgZnVuY3Rpb24gZ2V0QXV0aG9yaXR5KHVybCkgewogICAgY29uc3QgdXJpID0gbmV3IGltcG9ydF91cmlqczUuZGVmYXVsdCh1cmwpOwogICAgdXJpLm5vcm1hbGl6ZSgpOwogICAgbGV0IGF1dGhvcml0eSA9IHVyaS5hdXRob3JpdHkoKTsKICAgIGlmIChhdXRob3JpdHkubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybiB2b2lkIDA7CiAgICB9CiAgICB1cmkuYXV0aG9yaXR5KGF1dGhvcml0eSk7CiAgICBpZiAoYXV0aG9yaXR5LmluZGV4T2YoIkAiKSAhPT0gLTEpIHsKICAgICAgY29uc3QgcGFydHMgPSBhdXRob3JpdHkuc3BsaXQoIkAiKTsKICAgICAgYXV0aG9yaXR5ID0gcGFydHNbMV07CiAgICB9CiAgICBpZiAoYXV0aG9yaXR5LmluZGV4T2YoIjoiKSA9PT0gLTEpIHsKICAgICAgbGV0IHNjaGVtZSA9IHVyaS5zY2hlbWUoKTsKICAgICAgaWYgKHNjaGVtZS5sZW5ndGggPT09IDApIHsKICAgICAgICBzY2hlbWUgPSB3aW5kb3cubG9jYXRpb24ucHJvdG9jb2w7CiAgICAgICAgc2NoZW1lID0gc2NoZW1lLnN1YnN0cmluZygwLCBzY2hlbWUubGVuZ3RoIC0gMSk7CiAgICAgIH0KICAgICAgaWYgKHNjaGVtZSA9PT0gImh0dHAiKSB7CiAgICAgICAgYXV0aG9yaXR5ICs9ICI6ODAiOwogICAgICB9IGVsc2UgaWYgKHNjaGVtZSA9PT0gImh0dHBzIikgewogICAgICAgIGF1dGhvcml0eSArPSAiOjQ0MyI7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGF1dGhvcml0eTsKICB9CiAgdmFyIGltcG9ydF91cmlqczUsIFRydXN0ZWRTZXJ2ZXJzLCBfc2VydmVycywgVHJ1c3RlZFNlcnZlcnNfZGVmYXVsdDsKICB2YXIgaW5pdF9UcnVzdGVkU2VydmVycyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVHJ1c3RlZFNlcnZlcnMuanMiKCkgewogICAgICBpbXBvcnRfdXJpanM1ID0gX190b0VTTShyZXF1aXJlX1VSSSgpLCAxKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgVHJ1c3RlZFNlcnZlcnMgPSB7fTsKICAgICAgX3NlcnZlcnMgPSB7fTsKICAgICAgVHJ1c3RlZFNlcnZlcnMuYWRkID0gZnVuY3Rpb24oaG9zdCwgcG9ydCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGhvc3QpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiaG9zdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9ydCkgfHwgcG9ydCA8PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicG9ydCBpcyByZXF1aXJlZCB0byBiZSBncmVhdGVyIHRoYW4gMC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXV0aG9yaXR5ID0gYCR7aG9zdC50b0xvd2VyQ2FzZSgpfToke3BvcnR9YDsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChfc2VydmVyc1thdXRob3JpdHldKSkgewogICAgICAgICAgX3NlcnZlcnNbYXV0aG9yaXR5XSA9IHRydWU7CiAgICAgICAgfQogICAgICB9OwogICAgICBUcnVzdGVkU2VydmVycy5yZW1vdmUgPSBmdW5jdGlvbihob3N0LCBwb3J0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaG9zdCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJob3N0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3J0KSB8fCBwb3J0IDw9IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwb3J0IGlzIHJlcXVpcmVkIHRvIGJlIGdyZWF0ZXIgdGhhbiAwLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdXRob3JpdHkgPSBgJHtob3N0LnRvTG93ZXJDYXNlKCl9OiR7cG9ydH1gOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoX3NlcnZlcnNbYXV0aG9yaXR5XSkpIHsKICAgICAgICAgIGRlbGV0ZSBfc2VydmVyc1thdXRob3JpdHldOwogICAgICAgIH0KICAgICAgfTsKICAgICAgVHJ1c3RlZFNlcnZlcnMuY29udGFpbnMgPSBmdW5jdGlvbih1cmwpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1cmwpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidXJsIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdXRob3JpdHkgPSBnZXRBdXRob3JpdHkodXJsKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGF1dGhvcml0eSkgJiYgZGVmaW5lZF9kZWZhdWx0KF9zZXJ2ZXJzW2F1dGhvcml0eV0pKSB7CiAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9OwogICAgICBUcnVzdGVkU2VydmVycy5jbGVhciA9IGZ1bmN0aW9uKCkgewogICAgICAgIF9zZXJ2ZXJzID0ge307CiAgICAgIH07CiAgICAgIFRydXN0ZWRTZXJ2ZXJzX2RlZmF1bHQgPSBUcnVzdGVkU2VydmVyczsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1Jlc291cmNlLmpzCiAgZnVuY3Rpb24gUmVzb3VyY2Uob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAic3RyaW5nIikgewogICAgICBvcHRpb25zID0gewogICAgICAgIHVybDogb3B0aW9ucwogICAgICB9OwogICAgfQogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yuc3RyaW5nKCJvcHRpb25zLnVybCIsIG9wdGlvbnMudXJsKTsKICAgIHRoaXMuX3VybCA9IHZvaWQgMDsKICAgIHRoaXMuX3RlbXBsYXRlVmFsdWVzID0gZGVmYXVsdENsb25lKG9wdGlvbnMudGVtcGxhdGVWYWx1ZXMsIHt9KTsKICAgIHRoaXMuX3F1ZXJ5UGFyYW1ldGVycyA9IGRlZmF1bHRDbG9uZShvcHRpb25zLnF1ZXJ5UGFyYW1ldGVycywge30pOwogICAgdGhpcy5oZWFkZXJzID0gZGVmYXVsdENsb25lKG9wdGlvbnMuaGVhZGVycywge30pOwogICAgdGhpcy5yZXF1ZXN0ID0gb3B0aW9ucy5yZXF1ZXN0ID8/IG5ldyBSZXF1ZXN0X2RlZmF1bHQoKTsKICAgIHRoaXMucHJveHkgPSBvcHRpb25zLnByb3h5OwogICAgdGhpcy5yZXRyeUNhbGxiYWNrID0gb3B0aW9ucy5yZXRyeUNhbGxiYWNrOwogICAgdGhpcy5yZXRyeUF0dGVtcHRzID0gb3B0aW9ucy5yZXRyeUF0dGVtcHRzID8/IDA7CiAgICB0aGlzLl9yZXRyeUNvdW50ID0gMDsKICAgIGNvbnN0IHBhcnNlVXJsID0gb3B0aW9ucy5wYXJzZVVybCA/PyB0cnVlOwogICAgaWYgKHBhcnNlVXJsKSB7CiAgICAgIHRoaXMucGFyc2VVcmwob3B0aW9ucy51cmwsIHRydWUsIHRydWUpOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fdXJsID0gb3B0aW9ucy51cmw7CiAgICB9CiAgICB0aGlzLl9jcmVkaXRzID0gb3B0aW9ucy5jcmVkaXRzOwogIH0KICBmdW5jdGlvbiBkZWZhdWx0Q2xvbmUodmFsdWUsIGRlZmF1bHRWYWx1ZSkgewogICAgcmV0dXJuIGRlZmluZWRfZGVmYXVsdCh2YWx1ZSkgPyBjbG9uZV9kZWZhdWx0KHZhbHVlKSA6IGRlZmF1bHRWYWx1ZTsKICB9CiAgZnVuY3Rpb24gcGFyc2VRdWVyeVN0cmluZyhxdWVyeVN0cmluZykgewogICAgaWYgKHF1ZXJ5U3RyaW5nLmxlbmd0aCA9PT0gMCkgewogICAgICByZXR1cm4ge307CiAgICB9CiAgICBpZiAocXVlcnlTdHJpbmcuaW5kZXhPZigiPSIpID09PSAtMSkgewogICAgICByZXR1cm4geyBbcXVlcnlTdHJpbmddOiB2b2lkIDAgfTsKICAgIH0KICAgIHJldHVybiBxdWVyeVRvT2JqZWN0X2RlZmF1bHQocXVlcnlTdHJpbmcpOwogIH0KICBmdW5jdGlvbiBjb21iaW5lUXVlcnlQYXJhbWV0ZXJzKHExMiwgcTIyLCBwcmVzZXJ2ZVF1ZXJ5UGFyYW1ldGVycykgewogICAgaWYgKCFwcmVzZXJ2ZVF1ZXJ5UGFyYW1ldGVycykgewogICAgICByZXR1cm4gY29tYmluZV9kZWZhdWx0KHExMiwgcTIyKTsKICAgIH0KICAgIGNvbnN0IHJlc3VsdCA9IGNsb25lX2RlZmF1bHQocTEyLCB0cnVlKTsKICAgIGZvciAoY29uc3QgcGFyYW0gaW4gcTIyKSB7CiAgICAgIGlmIChxMjIuaGFzT3duUHJvcGVydHkocGFyYW0pKSB7CiAgICAgICAgbGV0IHZhbHVlID0gcmVzdWx0W3BhcmFtXTsKICAgICAgICBjb25zdCBxMlZhbHVlID0gcTIyW3BhcmFtXTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgewogICAgICAgICAgICB2YWx1ZSA9IHJlc3VsdFtwYXJhbV0gPSBbdmFsdWVdOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0W3BhcmFtXSA9IHZhbHVlLmNvbmNhdChxMlZhbHVlKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmVzdWx0W3BhcmFtXSA9IEFycmF5LmlzQXJyYXkocTJWYWx1ZSkgPyBxMlZhbHVlLnNsaWNlKCkgOiBxMlZhbHVlOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgZnVuY3Rpb24gc3RyaW5naWZ5UXVlcnkocXVlcnlPYmplY3QpIHsKICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhxdWVyeU9iamVjdCk7CiAgICBpZiAoa2V5cy5sZW5ndGggPT09IDApIHsKICAgICAgcmV0dXJuICIiOwogICAgfQogICAgaWYgKGtleXMubGVuZ3RoID09PSAxICYmICFkZWZpbmVkX2RlZmF1bHQocXVlcnlPYmplY3Rba2V5c1swXV0pKSB7CiAgICAgIHJldHVybiBgPyR7a2V5c1swXX1gOwogICAgfQogICAgcmV0dXJuIGA/JHtvYmplY3RUb1F1ZXJ5X2RlZmF1bHQocXVlcnlPYmplY3QpfWA7CiAgfQogIGZ1bmN0aW9uIGZldGNoSnNvbnAocmVzb3VyY2UsIGNhbGxiYWNrUGFyYW1ldGVyTmFtZSwgZnVuY3Rpb25OYW1lKSB7CiAgICBjb25zdCBjYWxsYmFja1F1ZXJ5ID0ge307CiAgICBjYWxsYmFja1F1ZXJ5W2NhbGxiYWNrUGFyYW1ldGVyTmFtZV0gPSBmdW5jdGlvbk5hbWU7CiAgICByZXNvdXJjZS5zZXRRdWVyeVBhcmFtZXRlcnMoY2FsbGJhY2tRdWVyeSk7CiAgICBjb25zdCByZXF1ZXN0ID0gcmVzb3VyY2UucmVxdWVzdDsKICAgIGNvbnN0IHVybCA9IHJlc291cmNlLnVybDsKICAgIHJlcXVlc3QudXJsID0gdXJsOwogICAgcmVxdWVzdC5yZXF1ZXN0RnVuY3Rpb24gPSBmdW5jdGlvbigpIHsKICAgICAgY29uc3QgZGVmZXJyZWQgPSBkZWZlcl9kZWZhdWx0KCk7CiAgICAgIHdpbmRvd1tmdW5jdGlvbk5hbWVdID0gZnVuY3Rpb24oZGF0YSkgewogICAgICAgIGRlZmVycmVkLnJlc29sdmUoZGF0YSk7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGRlbGV0ZSB3aW5kb3dbZnVuY3Rpb25OYW1lXTsKICAgICAgICB9IGNhdGNoIChlMikgewogICAgICAgICAgd2luZG93W2Z1bmN0aW9uTmFtZV0gPSB2b2lkIDA7CiAgICAgICAgfQogICAgICB9OwogICAgICBSZXNvdXJjZS5fSW1wbGVtZW50YXRpb25zLmxvYWRBbmRFeGVjdXRlU2NyaXB0KHVybCwgZnVuY3Rpb25OYW1lLCBkZWZlcnJlZCk7CiAgICAgIHJldHVybiBkZWZlcnJlZC5wcm9taXNlOwogICAgfTsKICAgIGNvbnN0IHByb21pc2UgPSBSZXF1ZXN0U2NoZWR1bGVyX2RlZmF1bHQucmVxdWVzdChyZXF1ZXN0KTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHByb21pc2UpKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIHJldHVybiBwcm9taXNlLmNhdGNoKGZ1bmN0aW9uKGUyKSB7CiAgICAgIGlmIChyZXF1ZXN0LnN0YXRlICE9PSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5GQUlMRUQpIHsKICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZTIpOwogICAgICB9CiAgICAgIHJldHVybiByZXNvdXJjZS5yZXRyeU9uRXJyb3IoZTIpLnRoZW4oZnVuY3Rpb24ocmV0cnkpIHsKICAgICAgICBpZiAocmV0cnkpIHsKICAgICAgICAgIHJlcXVlc3Quc3RhdGUgPSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5VTklTU1VFRDsKICAgICAgICAgIHJlcXVlc3QuZGVmZXJyZWQgPSB2b2lkIDA7CiAgICAgICAgICByZXR1cm4gZmV0Y2hKc29ucChyZXNvdXJjZSwgY2FsbGJhY2tQYXJhbWV0ZXJOYW1lLCBmdW5jdGlvbk5hbWUpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZTIpOwogICAgICB9KTsKICAgIH0pOwogIH0KICBmdW5jdGlvbiBjaGVja0FuZFJlc2V0UmVxdWVzdChyZXF1ZXN0KSB7CiAgICBpZiAocmVxdWVzdC5zdGF0ZSA9PT0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuSVNTVUVEIHx8IHJlcXVlc3Quc3RhdGUgPT09IFJlcXVlc3RTdGF0ZV9kZWZhdWx0LkFDVElWRSkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIlRoZSBSZXNvdXJjZSBpcyBhbHJlYWR5IGJlaW5nIGZldGNoZWQuIik7CiAgICB9CiAgICByZXF1ZXN0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuVU5JU1NVRUQ7CiAgICByZXF1ZXN0LmRlZmVycmVkID0gdm9pZCAwOwogIH0KICBmdW5jdGlvbiBkZWNvZGVEYXRhVXJpVGV4dChpc0Jhc2U2NCwgZGF0YSkgewogICAgY29uc3QgcmVzdWx0ID0gZGVjb2RlVVJJQ29tcG9uZW50KGRhdGEpOwogICAgaWYgKGlzQmFzZTY0KSB7CiAgICAgIHJldHVybiBhdG9iKHJlc3VsdCk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBkZWNvZGVEYXRhVXJpQXJyYXlCdWZmZXIoaXNCYXNlNjQsIGRhdGEpIHsKICAgIGNvbnN0IGJ5dGVTdHJpbmcgPSBkZWNvZGVEYXRhVXJpVGV4dChpc0Jhc2U2NCwgZGF0YSk7CiAgICBjb25zdCBidWZmZXIgPSBuZXcgQXJyYXlCdWZmZXIoYnl0ZVN0cmluZy5sZW5ndGgpOwogICAgY29uc3QgdmlldyA9IG5ldyBVaW50OEFycmF5KGJ1ZmZlcik7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgYnl0ZVN0cmluZy5sZW5ndGg7IGkyKyspIHsKICAgICAgdmlld1tpMl0gPSBieXRlU3RyaW5nLmNoYXJDb2RlQXQoaTIpOwogICAgfQogICAgcmV0dXJuIGJ1ZmZlcjsKICB9CiAgZnVuY3Rpb24gZGVjb2RlRGF0YVVyaShkYXRhVXJpUmVnZXhSZXN1bHQsIHJlc3BvbnNlVHlwZSkgewogICAgcmVzcG9uc2VUeXBlID0gcmVzcG9uc2VUeXBlID8/ICIiOwogICAgY29uc3QgbWltZVR5cGUgPSBkYXRhVXJpUmVnZXhSZXN1bHRbMV07CiAgICBjb25zdCBpc0Jhc2U2NCA9ICEhZGF0YVVyaVJlZ2V4UmVzdWx0WzJdOwogICAgY29uc3QgZGF0YSA9IGRhdGFVcmlSZWdleFJlc3VsdFszXTsKICAgIGxldCBidWZmZXI7CiAgICBsZXQgcGFyc2VyOwogICAgc3dpdGNoIChyZXNwb25zZVR5cGUpIHsKICAgICAgY2FzZSAiIjoKICAgICAgY2FzZSAidGV4dCI6CiAgICAgICAgcmV0dXJuIGRlY29kZURhdGFVcmlUZXh0KGlzQmFzZTY0LCBkYXRhKTsKICAgICAgY2FzZSAiYXJyYXlidWZmZXIiOgogICAgICAgIHJldHVybiBkZWNvZGVEYXRhVXJpQXJyYXlCdWZmZXIoaXNCYXNlNjQsIGRhdGEpOwogICAgICBjYXNlICJibG9iIjoKICAgICAgICBidWZmZXIgPSBkZWNvZGVEYXRhVXJpQXJyYXlCdWZmZXIoaXNCYXNlNjQsIGRhdGEpOwogICAgICAgIHJldHVybiBuZXcgQmxvYihbYnVmZmVyXSwgewogICAgICAgICAgdHlwZTogbWltZVR5cGUKICAgICAgICB9KTsKICAgICAgY2FzZSAiZG9jdW1lbnQiOgogICAgICAgIHBhcnNlciA9IG5ldyBET01QYXJzZXIoKTsKICAgICAgICByZXR1cm4gcGFyc2VyLnBhcnNlRnJvbVN0cmluZygKICAgICAgICAgIGRlY29kZURhdGFVcmlUZXh0KGlzQmFzZTY0LCBkYXRhKSwKICAgICAgICAgIG1pbWVUeXBlCiAgICAgICAgKTsKICAgICAgY2FzZSAianNvbiI6CiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlRGF0YVVyaVRleHQoaXNCYXNlNjQsIGRhdGEpKTsKICAgICAgZGVmYXVsdDoKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdChgVW5oYW5kbGVkIHJlc3BvbnNlVHlwZTogJHtyZXNwb25zZVR5cGV9YCk7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGxvYWRXaXRoSHR0cFJlcXVlc3QodXJsLCByZXNwb25zZVR5cGUsIG1ldGhvZCwgZGF0YSwgaGVhZGVycywgZGVmZXJyZWQsIG92ZXJyaWRlTWltZVR5cGUpIHsKICAgIGZldGNoKHVybCwgewogICAgICBtZXRob2QsCiAgICAgIGhlYWRlcnMKICAgIH0pLnRoZW4oYXN5bmMgKHJlc3BvbnNlKSA9PiB7CiAgICAgIGlmICghcmVzcG9uc2Uub2spIHsKICAgICAgICBjb25zdCByZXNwb25zZUhlYWRlcnMgPSB7fTsKICAgICAgICByZXNwb25zZS5oZWFkZXJzLmZvckVhY2goKHZhbHVlLCBrZXkpID0+IHsKICAgICAgICAgIHJlc3BvbnNlSGVhZGVyc1trZXldID0gdmFsdWU7CiAgICAgICAgfSk7CiAgICAgICAgZGVmZXJyZWQucmVqZWN0KAogICAgICAgICAgbmV3IFJlcXVlc3RFcnJvckV2ZW50X2RlZmF1bHQocmVzcG9uc2Uuc3RhdHVzLCByZXNwb25zZSwgcmVzcG9uc2VIZWFkZXJzKQogICAgICAgICk7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIHN3aXRjaCAocmVzcG9uc2VUeXBlKSB7CiAgICAgICAgY2FzZSAidGV4dCI6CiAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKHJlc3BvbnNlLnRleHQoKSk7CiAgICAgICAgICBicmVhazsKICAgICAgICBjYXNlICJqc29uIjoKICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUocmVzcG9uc2UuanNvbigpKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKG5ldyBVaW50OEFycmF5KGF3YWl0IHJlc3BvbnNlLmFycmF5QnVmZmVyKCkpLmJ1ZmZlcik7CiAgICAgICAgICBicmVhazsKICAgICAgfQogICAgfSkuY2F0Y2goKCkgPT4gewogICAgICBkZWZlcnJlZC5yZWplY3QobmV3IFJlcXVlc3RFcnJvckV2ZW50X2RlZmF1bHQoKSk7CiAgICB9KTsKICB9CiAgdmFyIGltcG9ydF91cmlqczYsIHhockJsb2JTdXBwb3J0ZWQsIHN1cHBvcnRzSW1hZ2VCaXRtYXBPcHRpb25zUHJvbWlzZSwgZGF0YVVyaVJlZ2V4Miwgbm9YTUxIdHRwUmVxdWVzdCwgUmVzb3VyY2VfZGVmYXVsdDsKICB2YXIgaW5pdF9SZXNvdXJjZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVzb3VyY2UuanMiKCkgewogICAgICBpbXBvcnRfdXJpanM2ID0gX190b0VTTShyZXF1aXJlX1VSSSgpLCAxKTsKICAgICAgaW5pdF9hcHBlbmRGb3J3YXJkU2xhc2goKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2Nsb25lKCk7CiAgICAgIGluaXRfY29tYmluZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmVyKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfZ2V0QWJzb2x1dGVVcmkoKTsKICAgICAgaW5pdF9nZXRCYXNlVXJpKCk7CiAgICAgIGluaXRfZ2V0RXh0ZW5zaW9uRnJvbVVyaSgpOwogICAgICBpbml0X2dldEltYWdlUGl4ZWxzKCk7CiAgICAgIGluaXRfaXNCbG9iVXJpKCk7CiAgICAgIGluaXRfaXNDcm9zc09yaWdpblVybCgpOwogICAgICBpbml0X2lzRGF0YVVyaSgpOwogICAgICBpbml0X2xvYWRBbmRFeGVjdXRlU2NyaXB0KCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X29iamVjdFRvUXVlcnkoKTsKICAgICAgaW5pdF9xdWVyeVRvT2JqZWN0KCk7CiAgICAgIGluaXRfUmVxdWVzdCgpOwogICAgICBpbml0X1JlcXVlc3RFcnJvckV2ZW50KCk7CiAgICAgIGluaXRfUmVxdWVzdFNjaGVkdWxlcigpOwogICAgICBpbml0X1JlcXVlc3RTdGF0ZSgpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBpbml0X1RydXN0ZWRTZXJ2ZXJzKCk7CiAgICAgIHhockJsb2JTdXBwb3J0ZWQgPSAoZnVuY3Rpb24oKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIGNvbnN0IHhociA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgICAgeGhyLm9wZW4oIkdFVCIsICIjIiwgdHJ1ZSk7CiAgICAgICAgICB4aHIucmVzcG9uc2VUeXBlID0gImJsb2IiOwogICAgICAgICAgcmV0dXJuIHhoci5yZXNwb25zZVR5cGUgPT09ICJibG9iIjsKICAgICAgICB9IGNhdGNoIChlMikgewogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgfSkoKTsKICAgICAgUmVzb3VyY2UuY3JlYXRlSWZOZWVkZWQgPSBmdW5jdGlvbihyZXNvdXJjZSkgewogICAgICAgIGlmIChyZXNvdXJjZSBpbnN0YW5jZW9mIFJlc291cmNlKSB7CiAgICAgICAgICByZXR1cm4gcmVzb3VyY2UuZ2V0RGVyaXZlZFJlc291cmNlKHsKICAgICAgICAgICAgcmVxdWVzdDogcmVzb3VyY2UucmVxdWVzdAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgcmVzb3VyY2UgIT09ICJzdHJpbmciKSB7CiAgICAgICAgICByZXR1cm4gcmVzb3VyY2U7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgUmVzb3VyY2UoewogICAgICAgICAgdXJsOiByZXNvdXJjZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZXNvdXJjZS5zdXBwb3J0c0ltYWdlQml0bWFwT3B0aW9ucyA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoc3VwcG9ydHNJbWFnZUJpdG1hcE9wdGlvbnNQcm9taXNlKSkgewogICAgICAgICAgcmV0dXJuIHN1cHBvcnRzSW1hZ2VCaXRtYXBPcHRpb25zUHJvbWlzZTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBjcmVhdGVJbWFnZUJpdG1hcCAhPT0gImZ1bmN0aW9uIikgewogICAgICAgICAgc3VwcG9ydHNJbWFnZUJpdG1hcE9wdGlvbnNQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTsKICAgICAgICAgIHJldHVybiBzdXBwb3J0c0ltYWdlQml0bWFwT3B0aW9uc1Byb21pc2U7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGltYWdlRGF0YVVyaSA9ICJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUFFQUFBQUJDQUlBQUFDUWQxUGVBQUFBQkdkQlRVRUFBRTRnM3JFaURnQUFBQ0JqU0ZKTkFBQjZKZ0FBZ0lRQUFQb0FBQUNBNkFBQWRUQUFBT3BnQUFBNm1BQUFGM0NjdWxFOEFBQUFERWxFUVZRSTEyTmc2R0FBQUFFVUFJbmdFM1ppQUFBQUFFbEZUa1N1UW1DQyI7CiAgICAgICAgc3VwcG9ydHNJbWFnZUJpdG1hcE9wdGlvbnNQcm9taXNlID0gUmVzb3VyY2UuZmV0Y2hCbG9iKHsKICAgICAgICAgIHVybDogaW1hZ2VEYXRhVXJpCiAgICAgICAgfSkudGhlbihmdW5jdGlvbihibG9iKSB7CiAgICAgICAgICBjb25zdCBpbWFnZUJpdG1hcE9wdGlvbnMgPSB7CiAgICAgICAgICAgIC8vICdmcm9tLWltYWdlJyBpcyBkZXByZWNhdGVkLCBuZXcgb3B0aW9uIGlzICdub25lJy4gSG93ZXZlciwgd2Ugc3RpbGwgbmVlZCB0byBzdXBwb3J0IG9sZGVyIGJyb3dzZXJzLAogICAgICAgICAgICAvLyBhbmQgdGhlcmUncyBubyBnb29kIHdheSB0byBkZXRlY3Qgc3VwcG9ydCBmb3IgdGhlc2Ugb3B0aW9ucy4gRm9yIG5vdywgY29udGludWUgdG8gdXNlICdmcm9tLWltYWdlJy4gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vQ2VzaXVtR1MvY2VzaXVtL2lzc3Vlcy8xMjg0NgogICAgICAgICAgICBpbWFnZU9yaWVudGF0aW9uOiAiZmxpcFkiLAogICAgICAgICAgICAvLyBkZWZhdWx0IGlzICJmcm9tLWltYWdlIgogICAgICAgICAgICBwcmVtdWx0aXBseUFscGhhOiAibm9uZSIsCiAgICAgICAgICAgIC8vIGRlZmF1bHQgaXMgImRlZmF1bHQiCiAgICAgICAgICAgIGNvbG9yU3BhY2VDb252ZXJzaW9uOiAibm9uZSIKICAgICAgICAgICAgLy8gZGVmYXVsdCBpcyAiZGVmYXVsdCIKICAgICAgICAgIH07CiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoWwogICAgICAgICAgICBjcmVhdGVJbWFnZUJpdG1hcChibG9iLCBpbWFnZUJpdG1hcE9wdGlvbnMpLAogICAgICAgICAgICBjcmVhdGVJbWFnZUJpdG1hcChibG9iKQogICAgICAgICAgXSk7CiAgICAgICAgfSkudGhlbihmdW5jdGlvbihpbWFnZUJpdG1hcHMpIHsKICAgICAgICAgIGNvbnN0IGNvbG9yV2l0aE9wdGlvbnMgPSBnZXRJbWFnZVBpeGVsc19kZWZhdWx0KGltYWdlQml0bWFwc1swXSk7CiAgICAgICAgICBjb25zdCBjb2xvcldpdGhEZWZhdWx0cyA9IGdldEltYWdlUGl4ZWxzX2RlZmF1bHQoaW1hZ2VCaXRtYXBzWzFdKTsKICAgICAgICAgIHJldHVybiBjb2xvcldpdGhPcHRpb25zWzFdICE9PSBjb2xvcldpdGhEZWZhdWx0c1sxXTsKICAgICAgICB9KS5jYXRjaChmdW5jdGlvbigpIHsKICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gc3VwcG9ydHNJbWFnZUJpdG1hcE9wdGlvbnNQcm9taXNlOwogICAgICB9OwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhSZXNvdXJjZSwgewogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiBibG9icyBhcmUgc3VwcG9ydGVkLgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlcm9mIFJlc291cmNlCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICoKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBpc0Jsb2JTdXBwb3J0ZWQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB4aHJCbG9iU3VwcG9ydGVkOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFJlc291cmNlLnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIFF1ZXJ5IHBhcmFtZXRlcnMgYXBwZW5kZWQgdG8gdGhlIHVybC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBSZXNvdXJjZS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fQogICAgICAgICAqCiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fcXVlcnlQYXJhbWV0ZXJzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGtleS92YWx1ZSBwYWlycyB1c2VkIHRvIHJlcGxhY2UgdGVtcGxhdGUgcGFyYW1ldGVycyBpbiB0aGUgdXJsLgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlcm9mIFJlc291cmNlLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtvYmplY3R9CiAgICAgICAgICoKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICB0ZW1wbGF0ZVZhbHVlczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3RlbXBsYXRlVmFsdWVzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHVybCB0byB0aGUgcmVzb3VyY2Ugd2l0aCB0ZW1wbGF0ZSB2YWx1ZXMgcmVwbGFjZWQsIHF1ZXJ5IHN0cmluZyBhcHBlbmRlZCBhbmQgZW5jb2RlZCBieSBwcm94eSBpZiBvbmUgd2FzIHNldC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBSZXNvdXJjZS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICAgICAqLwogICAgICAgIHVybDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0VXJsQ29tcG9uZW50KHRydWUsIHRydWUpOwogICAgICAgICAgfSwKICAgICAgICAgIHNldDogZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgICAgdGhpcy5wYXJzZVVybCh2YWx1ZSwgZmFsc2UsIGZhbHNlKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBmaWxlIGV4dGVuc2lvbiBvZiB0aGUgcmVzb3VyY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgUmVzb3VyY2UucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge3N0cmluZ30KICAgICAgICAgKgogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGV4dGVuc2lvbjogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGdldEV4dGVuc2lvbkZyb21VcmlfZGVmYXVsdCh0aGlzLl91cmwpOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVHJ1ZSBpZiB0aGUgUmVzb3VyY2UgcmVmZXJzIHRvIGEgZGF0YSBVUkkuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgUmVzb3VyY2UucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICovCiAgICAgICAgaXNEYXRhVXJpOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gaXNEYXRhVXJpX2RlZmF1bHQodGhpcy5fdXJsKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIFRydWUgaWYgdGhlIFJlc291cmNlIHJlZmVycyB0byBhIGJsb2IgVVJJLgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlcm9mIFJlc291cmNlLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICAgICAqLwogICAgICAgIGlzQmxvYlVyaTogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGlzQmxvYlVyaV9kZWZhdWx0KHRoaXMuX3VybCk7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBUcnVlIGlmIHRoZSBSZXNvdXJjZSByZWZlcnMgdG8gYSBjcm9zcyBvcmlnaW4gVVJMLgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlcm9mIFJlc291cmNlLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICAgICAqLwogICAgICAgIGlzQ3Jvc3NPcmlnaW5Vcmw6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBpc0Nyb3NzT3JpZ2luVXJsX2RlZmF1bHQodGhpcy5fdXJsKTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIFRydWUgaWYgdGhlIFJlc291cmNlIGhhcyByZXF1ZXN0IGhlYWRlcnMuIFRoaXMgaXMgZXF1aXZhbGVudCB0byBjaGVja2luZyBpZiB0aGUgaGVhZGVycyBwcm9wZXJ0eSBoYXMgYW55IGtleXMuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgUmVzb3VyY2UucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICovCiAgICAgICAgaGFzSGVhZGVyczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuaGVhZGVycykubGVuZ3RoID4gMDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGNyZWRpdHMgcmVxdWlyZWQgZm9yIGF0dHJpYnV0aW9uIG9mIGFuIGFzc2V0LgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgY3JlZGl0czogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NyZWRpdHM7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0VXJsQ29tcG9uZW50KHRydWUsIHRydWUpOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUucGFyc2VVcmwgPSBmdW5jdGlvbih1cmwsIG1lcmdlLCBwcmVzZXJ2ZVF1ZXJ5LCBiYXNlVXJsKSB7CiAgICAgICAgbGV0IHVyaSA9IG5ldyBpbXBvcnRfdXJpanM2LmRlZmF1bHQodXJsKTsKICAgICAgICBjb25zdCBxdWVyeSA9IHBhcnNlUXVlcnlTdHJpbmcodXJpLnF1ZXJ5KCkpOwogICAgICAgIHRoaXMuX3F1ZXJ5UGFyYW1ldGVycyA9IG1lcmdlID8gY29tYmluZVF1ZXJ5UGFyYW1ldGVycyhxdWVyeSwgdGhpcy5xdWVyeVBhcmFtZXRlcnMsIHByZXNlcnZlUXVlcnkpIDogcXVlcnk7CiAgICAgICAgdXJpLnNlYXJjaCgiIik7CiAgICAgICAgdXJpLmZyYWdtZW50KCIiKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGJhc2VVcmwpICYmIHVyaS5zY2hlbWUoKSA9PT0gIiIpIHsKICAgICAgICAgIHVyaSA9IHVyaS5hYnNvbHV0ZVRvKGdldEFic29sdXRlVXJpX2RlZmF1bHQoYmFzZVVybCkpOwogICAgICAgIH0KICAgICAgICB0aGlzLl91cmwgPSB1cmkudG9TdHJpbmcoKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmdldFVybENvbXBvbmVudCA9IGZ1bmN0aW9uKHF1ZXJ5LCBwcm94eSkgewogICAgICAgIGlmICh0aGlzLmlzRGF0YVVyaSkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX3VybDsKICAgICAgICB9CiAgICAgICAgbGV0IHVybCA9IHRoaXMuX3VybDsKICAgICAgICBpZiAocXVlcnkpIHsKICAgICAgICAgIHVybCA9IGAke3VybH0ke3N0cmluZ2lmeVF1ZXJ5KHRoaXMucXVlcnlQYXJhbWV0ZXJzKX1gOwogICAgICAgIH0KICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvJTdCL2csICJ7IikucmVwbGFjZSgvJTdEL2csICJ9Iik7CiAgICAgICAgY29uc3QgdGVtcGxhdGVWYWx1ZXMgPSB0aGlzLl90ZW1wbGF0ZVZhbHVlczsKICAgICAgICBpZiAoT2JqZWN0LmtleXModGVtcGxhdGVWYWx1ZXMpLmxlbmd0aCA+IDApIHsKICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC97KC4qPyl9L2csIGZ1bmN0aW9uKG1hdGNoLCBrZXkpIHsKICAgICAgICAgICAgY29uc3QgcmVwbGFjZW1lbnQgPSB0ZW1wbGF0ZVZhbHVlc1trZXldOwogICAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlcGxhY2VtZW50KSkgewogICAgICAgICAgICAgIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQocmVwbGFjZW1lbnQpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBtYXRjaDsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBpZiAocHJveHkgJiYgZGVmaW5lZF9kZWZhdWx0KHRoaXMucHJveHkpKSB7CiAgICAgICAgICB1cmwgPSB0aGlzLnByb3h5LmdldFVSTCh1cmwpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdXJsOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuc2V0UXVlcnlQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFyYW1zLCB1c2VBc0RlZmF1bHQpIHsKICAgICAgICBpZiAodXNlQXNEZWZhdWx0KSB7CiAgICAgICAgICB0aGlzLl9xdWVyeVBhcmFtZXRlcnMgPSBjb21iaW5lUXVlcnlQYXJhbWV0ZXJzKAogICAgICAgICAgICB0aGlzLl9xdWVyeVBhcmFtZXRlcnMsCiAgICAgICAgICAgIHBhcmFtcywKICAgICAgICAgICAgZmFsc2UKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRoaXMuX3F1ZXJ5UGFyYW1ldGVycyA9IGNvbWJpbmVRdWVyeVBhcmFtZXRlcnMoCiAgICAgICAgICAgIHBhcmFtcywKICAgICAgICAgICAgdGhpcy5fcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgICAgICBmYWxzZQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5hcHBlbmRRdWVyeVBhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMpIHsKICAgICAgICB0aGlzLl9xdWVyeVBhcmFtZXRlcnMgPSBjb21iaW5lUXVlcnlQYXJhbWV0ZXJzKAogICAgICAgICAgcGFyYW1zLAogICAgICAgICAgdGhpcy5fcXVlcnlQYXJhbWV0ZXJzLAogICAgICAgICAgdHJ1ZQogICAgICAgICk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5zZXRUZW1wbGF0ZVZhbHVlcyA9IGZ1bmN0aW9uKHRlbXBsYXRlLCB1c2VBc0RlZmF1bHQpIHsKICAgICAgICBpZiAodXNlQXNEZWZhdWx0KSB7CiAgICAgICAgICB0aGlzLl90ZW1wbGF0ZVZhbHVlcyA9IGNvbWJpbmVfZGVmYXVsdCh0aGlzLl90ZW1wbGF0ZVZhbHVlcywgdGVtcGxhdGUpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLl90ZW1wbGF0ZVZhbHVlcyA9IGNvbWJpbmVfZGVmYXVsdCh0ZW1wbGF0ZSwgdGhpcy5fdGVtcGxhdGVWYWx1ZXMpOwogICAgICAgIH0KICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmdldERlcml2ZWRSZXNvdXJjZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IHRoaXMuY2xvbmUoKTsKICAgICAgICByZXNvdXJjZS5fcmV0cnlDb3VudCA9IDA7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChvcHRpb25zLnVybCkpIHsKICAgICAgICAgIGNvbnN0IHByZXNlcnZlUXVlcnkgPSBvcHRpb25zLnByZXNlcnZlUXVlcnlQYXJhbWV0ZXJzID8/IGZhbHNlOwogICAgICAgICAgcmVzb3VyY2UucGFyc2VVcmwob3B0aW9ucy51cmwsIHRydWUsIHByZXNlcnZlUXVlcnksIHRoaXMuX3VybCk7CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5xdWVyeVBhcmFtZXRlcnMpKSB7CiAgICAgICAgICByZXNvdXJjZS5fcXVlcnlQYXJhbWV0ZXJzID0gY29tYmluZV9kZWZhdWx0KAogICAgICAgICAgICBvcHRpb25zLnF1ZXJ5UGFyYW1ldGVycywKICAgICAgICAgICAgcmVzb3VyY2UucXVlcnlQYXJhbWV0ZXJzCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMudGVtcGxhdGVWYWx1ZXMpKSB7CiAgICAgICAgICByZXNvdXJjZS5fdGVtcGxhdGVWYWx1ZXMgPSBjb21iaW5lX2RlZmF1bHQoCiAgICAgICAgICAgIG9wdGlvbnMudGVtcGxhdGVWYWx1ZXMsCiAgICAgICAgICAgIHJlc291cmNlLnRlbXBsYXRlVmFsdWVzCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuaGVhZGVycykpIHsKICAgICAgICAgIHJlc291cmNlLmhlYWRlcnMgPSBjb21iaW5lX2RlZmF1bHQob3B0aW9ucy5oZWFkZXJzLCByZXNvdXJjZS5oZWFkZXJzKTsKICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChvcHRpb25zLnByb3h5KSkgewogICAgICAgICAgcmVzb3VyY2UucHJveHkgPSBvcHRpb25zLnByb3h5OwogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMucmVxdWVzdCkpIHsKICAgICAgICAgIHJlc291cmNlLnJlcXVlc3QgPSBvcHRpb25zLnJlcXVlc3Q7CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5yZXRyeUNhbGxiYWNrKSkgewogICAgICAgICAgcmVzb3VyY2UucmV0cnlDYWxsYmFjayA9IG9wdGlvbnMucmV0cnlDYWxsYmFjazsKICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChvcHRpb25zLnJldHJ5QXR0ZW1wdHMpKSB7CiAgICAgICAgICByZXNvdXJjZS5yZXRyeUF0dGVtcHRzID0gb3B0aW9ucy5yZXRyeUF0dGVtcHRzOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzb3VyY2U7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5yZXRyeU9uRXJyb3IgPSBmdW5jdGlvbihlcnJvcikgewogICAgICAgIGNvbnN0IHJldHJ5Q2FsbGJhY2sgPSB0aGlzLnJldHJ5Q2FsbGJhY2s7CiAgICAgICAgaWYgKHR5cGVvZiByZXRyeUNhbGxiYWNrICE9PSAiZnVuY3Rpb24iIHx8IHRoaXMuX3JldHJ5Q291bnQgPj0gdGhpcy5yZXRyeUF0dGVtcHRzKSB7CiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdGhhdCA9IHRoaXM7CiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXRyeUNhbGxiYWNrKHRoaXMsIGVycm9yKSkudGhlbihmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICAgICsrdGhhdC5fcmV0cnlDb3VudDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uKHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJldHVybiBuZXcgUmVzb3VyY2UoewogICAgICAgICAgICB1cmw6IHRoaXMuX3VybCwKICAgICAgICAgICAgcXVlcnlQYXJhbWV0ZXJzOiB0aGlzLnF1ZXJ5UGFyYW1ldGVycywKICAgICAgICAgICAgdGVtcGxhdGVWYWx1ZXM6IHRoaXMudGVtcGxhdGVWYWx1ZXMsCiAgICAgICAgICAgIGhlYWRlcnM6IHRoaXMuaGVhZGVycywKICAgICAgICAgICAgcHJveHk6IHRoaXMucHJveHksCiAgICAgICAgICAgIHJldHJ5Q2FsbGJhY2s6IHRoaXMucmV0cnlDYWxsYmFjaywKICAgICAgICAgICAgcmV0cnlBdHRlbXB0czogdGhpcy5yZXRyeUF0dGVtcHRzLAogICAgICAgICAgICByZXF1ZXN0OiB0aGlzLnJlcXVlc3QuY2xvbmUoKSwKICAgICAgICAgICAgcGFyc2VVcmw6IGZhbHNlLAogICAgICAgICAgICBjcmVkaXRzOiBkZWZpbmVkX2RlZmF1bHQodGhpcy5jcmVkaXRzKSA/IHRoaXMuY3JlZGl0cy5zbGljZSgpIDogdm9pZCAwCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll91cmwgPSB0aGlzLl91cmw7CiAgICAgICAgcmVzdWx0Ll9xdWVyeVBhcmFtZXRlcnMgPSBjbG9uZV9kZWZhdWx0KHRoaXMuX3F1ZXJ5UGFyYW1ldGVycyk7CiAgICAgICAgcmVzdWx0Ll90ZW1wbGF0ZVZhbHVlcyA9IGNsb25lX2RlZmF1bHQodGhpcy5fdGVtcGxhdGVWYWx1ZXMpOwogICAgICAgIHJlc3VsdC5oZWFkZXJzID0gY2xvbmVfZGVmYXVsdCh0aGlzLmhlYWRlcnMpOwogICAgICAgIHJlc3VsdC5wcm94eSA9IHRoaXMucHJveHk7CiAgICAgICAgcmVzdWx0LnJldHJ5Q2FsbGJhY2sgPSB0aGlzLnJldHJ5Q2FsbGJhY2s7CiAgICAgICAgcmVzdWx0LnJldHJ5QXR0ZW1wdHMgPSB0aGlzLnJldHJ5QXR0ZW1wdHM7CiAgICAgICAgcmVzdWx0Ll9yZXRyeUNvdW50ID0gMDsKICAgICAgICByZXN1bHQucmVxdWVzdCA9IHRoaXMucmVxdWVzdC5jbG9uZSgpOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5nZXRCYXNlVXJpID0gZnVuY3Rpb24oaW5jbHVkZVF1ZXJ5KSB7CiAgICAgICAgcmV0dXJuIGdldEJhc2VVcmlfZGVmYXVsdCh0aGlzLmdldFVybENvbXBvbmVudChpbmNsdWRlUXVlcnkpLCBpbmNsdWRlUXVlcnkpOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuYXBwZW5kRm9yd2FyZFNsYXNoID0gZnVuY3Rpb24oKSB7CiAgICAgICAgdGhpcy5fdXJsID0gYXBwZW5kRm9yd2FyZFNsYXNoX2RlZmF1bHQodGhpcy5fdXJsKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmZldGNoQXJyYXlCdWZmZXIgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gdGhpcy5mZXRjaCh7CiAgICAgICAgICByZXNwb25zZVR5cGU6ICJhcnJheWJ1ZmZlciIKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuZmV0Y2hBcnJheUJ1ZmZlciA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UuZmV0Y2hBcnJheUJ1ZmZlcigpOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuZmV0Y2hCbG9iID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZmV0Y2goewogICAgICAgICAgcmVzcG9uc2VUeXBlOiAiYmxvYiIKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuZmV0Y2hCbG9iID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIGNvbnN0IHJlc291cmNlID0gbmV3IFJlc291cmNlKG9wdGlvbnMpOwogICAgICAgIHJldHVybiByZXNvdXJjZS5mZXRjaEJsb2IoKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmZldGNoSW1hZ2UgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHByZWZlckltYWdlQml0bWFwID0gb3B0aW9ucy5wcmVmZXJJbWFnZUJpdG1hcCA/PyBmYWxzZTsKICAgICAgICBjb25zdCBwcmVmZXJCbG9iID0gb3B0aW9ucy5wcmVmZXJCbG9iID8/IGZhbHNlOwogICAgICAgIGNvbnN0IGZsaXBZID0gb3B0aW9ucy5mbGlwWSA/PyBmYWxzZTsKICAgICAgICBjb25zdCBza2lwQ29sb3JTcGFjZUNvbnZlcnNpb24gPSBvcHRpb25zLnNraXBDb2xvclNwYWNlQ29udmVyc2lvbiA/PyBmYWxzZTsKICAgICAgICBjaGVja0FuZFJlc2V0UmVxdWVzdCh0aGlzLnJlcXVlc3QpOwogICAgICAgIGlmICgheGhyQmxvYlN1cHBvcnRlZCB8fCB0aGlzLmlzRGF0YVVyaSB8fCB0aGlzLmlzQmxvYlVyaSB8fCAhdGhpcy5oYXNIZWFkZXJzICYmICFwcmVmZXJCbG9iKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fZmV0Y2hJbWFnZSh7CiAgICAgICAgICAgIHJlc291cmNlOiB0aGlzLAogICAgICAgICAgICBmbGlwWSwKICAgICAgICAgICAgc2tpcENvbG9yU3BhY2VDb252ZXJzaW9uLAogICAgICAgICAgICBwcmVmZXJJbWFnZUJpdG1hcAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGJsb2JQcm9taXNlID0gdGhpcy5mZXRjaEJsb2IoKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChibG9iUHJvbWlzZSkpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgbGV0IHN1cHBvcnRzSW1hZ2VCaXRtYXA7CiAgICAgICAgbGV0IHVzZUltYWdlQml0bWFwOwogICAgICAgIGxldCBnZW5lcmF0ZWRCbG9iUmVzb3VyY2U7CiAgICAgICAgbGV0IGdlbmVyYXRlZEJsb2I7CiAgICAgICAgcmV0dXJuIFJlc291cmNlLnN1cHBvcnRzSW1hZ2VCaXRtYXBPcHRpb25zKCkudGhlbihmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICAgIHN1cHBvcnRzSW1hZ2VCaXRtYXAgPSByZXN1bHQ7CiAgICAgICAgICB1c2VJbWFnZUJpdG1hcCA9IHN1cHBvcnRzSW1hZ2VCaXRtYXAgJiYgcHJlZmVySW1hZ2VCaXRtYXA7CiAgICAgICAgICByZXR1cm4gYmxvYlByb21pc2U7CiAgICAgICAgfSkudGhlbihmdW5jdGlvbihibG9iKSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChibG9iKSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICBnZW5lcmF0ZWRCbG9iID0gYmxvYjsKICAgICAgICAgIGlmICh1c2VJbWFnZUJpdG1hcCkgewogICAgICAgICAgICByZXR1cm4gUmVzb3VyY2UuY3JlYXRlSW1hZ2VCaXRtYXBGcm9tQmxvYihibG9iLCB7CiAgICAgICAgICAgICAgZmxpcFksCiAgICAgICAgICAgICAgcHJlbXVsdGlwbHlBbHBoYTogZmFsc2UsCiAgICAgICAgICAgICAgc2tpcENvbG9yU3BhY2VDb252ZXJzaW9uCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgYmxvYlVybCA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpOwogICAgICAgICAgZ2VuZXJhdGVkQmxvYlJlc291cmNlID0gbmV3IFJlc291cmNlKHsKICAgICAgICAgICAgdXJsOiBibG9iVXJsCiAgICAgICAgICB9KTsKICAgICAgICAgIHJldHVybiBnZW5lcmF0ZWRCbG9iUmVzb3VyY2UuX2ZldGNoSW1hZ2UoewogICAgICAgICAgICBmbGlwWSwKICAgICAgICAgICAgc2tpcENvbG9yU3BhY2VDb252ZXJzaW9uLAogICAgICAgICAgICBwcmVmZXJJbWFnZUJpdG1hcDogZmFsc2UKICAgICAgICAgIH0pOwogICAgICAgIH0pLnRoZW4oZnVuY3Rpb24oaW1hZ2UpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGltYWdlKSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICBpbWFnZS5ibG9iID0gZ2VuZXJhdGVkQmxvYjsKICAgICAgICAgIGlmICh1c2VJbWFnZUJpdG1hcCkgewogICAgICAgICAgICByZXR1cm4gaW1hZ2U7CiAgICAgICAgICB9CiAgICAgICAgICB3aW5kb3cuVVJMLnJldm9rZU9iamVjdFVSTChnZW5lcmF0ZWRCbG9iUmVzb3VyY2UudXJsKTsKICAgICAgICAgIHJldHVybiBpbWFnZTsKICAgICAgICB9KS5jYXRjaChmdW5jdGlvbihlcnJvcikgewogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChnZW5lcmF0ZWRCbG9iUmVzb3VyY2UpKSB7CiAgICAgICAgICAgIHdpbmRvdy5VUkwucmV2b2tlT2JqZWN0VVJMKGdlbmVyYXRlZEJsb2JSZXNvdXJjZS51cmwpOwogICAgICAgICAgfQogICAgICAgICAgZXJyb3IuYmxvYiA9IGdlbmVyYXRlZEJsb2I7CiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyb3IpOwogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuX2ZldGNoSW1hZ2UgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSB0aGlzOwogICAgICAgIGNvbnN0IGZsaXBZID0gb3B0aW9ucy5mbGlwWTsKICAgICAgICBjb25zdCBza2lwQ29sb3JTcGFjZUNvbnZlcnNpb24gPSBvcHRpb25zLnNraXBDb2xvclNwYWNlQ29udmVyc2lvbjsKICAgICAgICBjb25zdCBwcmVmZXJJbWFnZUJpdG1hcCA9IG9wdGlvbnMucHJlZmVySW1hZ2VCaXRtYXA7CiAgICAgICAgY29uc3QgcmVxdWVzdCA9IHJlc291cmNlLnJlcXVlc3Q7CiAgICAgICAgcmVxdWVzdC51cmwgPSByZXNvdXJjZS51cmw7CiAgICAgICAgcmVxdWVzdC5yZXF1ZXN0RnVuY3Rpb24gPSBmdW5jdGlvbigpIHsKICAgICAgICAgIGxldCBjcm9zc09yaWdpbiA9IGZhbHNlOwogICAgICAgICAgaWYgKCFyZXNvdXJjZS5pc0RhdGFVcmkgJiYgIXJlc291cmNlLmlzQmxvYlVyaSkgewogICAgICAgICAgICBjcm9zc09yaWdpbiA9IHJlc291cmNlLmlzQ3Jvc3NPcmlnaW5Vcmw7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBkZWZlcnJlZCA9IGRlZmVyX2RlZmF1bHQoKTsKICAgICAgICAgIFJlc291cmNlLl9JbXBsZW1lbnRhdGlvbnMuY3JlYXRlSW1hZ2UoCiAgICAgICAgICAgIHJlcXVlc3QsCiAgICAgICAgICAgIGNyb3NzT3JpZ2luLAogICAgICAgICAgICBkZWZlcnJlZCwKICAgICAgICAgICAgZmxpcFksCiAgICAgICAgICAgIHNraXBDb2xvclNwYWNlQ29udmVyc2lvbiwKICAgICAgICAgICAgcHJlZmVySW1hZ2VCaXRtYXAKICAgICAgICAgICk7CiAgICAgICAgICByZXR1cm4gZGVmZXJyZWQucHJvbWlzZTsKICAgICAgICB9OwogICAgICAgIGNvbnN0IHByb21pc2UgPSBSZXF1ZXN0U2NoZWR1bGVyX2RlZmF1bHQucmVxdWVzdChyZXF1ZXN0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwcm9taXNlKSkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcHJvbWlzZS5jYXRjaChmdW5jdGlvbihlMikgewogICAgICAgICAgaWYgKHJlcXVlc3Quc3RhdGUgIT09IFJlcXVlc3RTdGF0ZV9kZWZhdWx0LkZBSUxFRCkgewogICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZTIpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc291cmNlLnJldHJ5T25FcnJvcihlMikudGhlbihmdW5jdGlvbihyZXRyeSkgewogICAgICAgICAgICBpZiAocmV0cnkpIHsKICAgICAgICAgICAgICByZXF1ZXN0LnN0YXRlID0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuVU5JU1NVRUQ7CiAgICAgICAgICAgICAgcmVxdWVzdC5kZWZlcnJlZCA9IHZvaWQgMDsKICAgICAgICAgICAgICByZXR1cm4gcmVzb3VyY2UuX2ZldGNoSW1hZ2UoewogICAgICAgICAgICAgICAgZmxpcFksCiAgICAgICAgICAgICAgICBza2lwQ29sb3JTcGFjZUNvbnZlcnNpb24sCiAgICAgICAgICAgICAgICBwcmVmZXJJbWFnZUJpdG1hcAogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlMik7CiAgICAgICAgICB9KTsKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuZmV0Y2hJbWFnZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UuZmV0Y2hJbWFnZSh7CiAgICAgICAgICBmbGlwWTogb3B0aW9ucy5mbGlwWSwKICAgICAgICAgIHNraXBDb2xvclNwYWNlQ29udmVyc2lvbjogb3B0aW9ucy5za2lwQ29sb3JTcGFjZUNvbnZlcnNpb24sCiAgICAgICAgICBwcmVmZXJCbG9iOiBvcHRpb25zLnByZWZlckJsb2IsCiAgICAgICAgICBwcmVmZXJJbWFnZUJpdG1hcDogb3B0aW9ucy5wcmVmZXJJbWFnZUJpdG1hcAogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuZmV0Y2hUZXh0ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHRoaXMuZmV0Y2goewogICAgICAgICAgcmVzcG9uc2VUeXBlOiAidGV4dCIKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuZmV0Y2hUZXh0ID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIGNvbnN0IHJlc291cmNlID0gbmV3IFJlc291cmNlKG9wdGlvbnMpOwogICAgICAgIHJldHVybiByZXNvdXJjZS5mZXRjaFRleHQoKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmZldGNoSnNvbiA9IGZ1bmN0aW9uKCkgewogICAgICAgIGNvbnN0IHByb21pc2UgPSB0aGlzLmZldGNoKHsKICAgICAgICAgIHJlc3BvbnNlVHlwZTogInRleHQiLAogICAgICAgICAgaGVhZGVyczogewogICAgICAgICAgICBBY2NlcHQ6ICJhcHBsaWNhdGlvbi9qc29uLCovKjtxPTAuMDEiCiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocHJvbWlzZSkpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIHJldHVybiBwcm9taXNlLnRoZW4oZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZSh2YWx1ZSk7CiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLmZldGNoSnNvbiA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UuZmV0Y2hKc29uKCk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5mZXRjaFhNTCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0aGlzLmZldGNoKHsKICAgICAgICAgIHJlc3BvbnNlVHlwZTogImRvY3VtZW50IiwKICAgICAgICAgIG92ZXJyaWRlTWltZVR5cGU6ICJ0ZXh0L3htbCIKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuZmV0Y2hYTUwgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgUmVzb3VyY2Uob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuIHJlc291cmNlLmZldGNoWE1MKCk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5mZXRjaEpzb25wID0gZnVuY3Rpb24oY2FsbGJhY2tQYXJhbWV0ZXJOYW1lKSB7CiAgICAgICAgY2FsbGJhY2tQYXJhbWV0ZXJOYW1lID0gY2FsbGJhY2tQYXJhbWV0ZXJOYW1lID8/ICJjYWxsYmFjayI7CiAgICAgICAgY2hlY2tBbmRSZXNldFJlcXVlc3QodGhpcy5yZXF1ZXN0KTsKICAgICAgICBsZXQgZnVuY3Rpb25OYW1lOwogICAgICAgIGRvIHsKICAgICAgICAgIGZ1bmN0aW9uTmFtZSA9IGBsb2FkSnNvbnAke01hdGhfZGVmYXVsdC5uZXh0UmFuZG9tTnVtYmVyKCkudG9TdHJpbmcoKS5zdWJzdHJpbmcoMiwgOCl9YDsKICAgICAgICB9IHdoaWxlIChkZWZpbmVkX2RlZmF1bHQod2luZG93W2Z1bmN0aW9uTmFtZV0pKTsKICAgICAgICByZXR1cm4gZmV0Y2hKc29ucCh0aGlzLCBjYWxsYmFja1BhcmFtZXRlck5hbWUsIGZ1bmN0aW9uTmFtZSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLmZldGNoSnNvbnAgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgUmVzb3VyY2Uob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuIHJlc291cmNlLmZldGNoSnNvbnAob3B0aW9ucy5jYWxsYmFja1BhcmFtZXRlck5hbWUpOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuX21ha2VSZXF1ZXN0ID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIGNvbnN0IHJlc291cmNlID0gdGhpczsKICAgICAgICBjaGVja0FuZFJlc2V0UmVxdWVzdChyZXNvdXJjZS5yZXF1ZXN0KTsKICAgICAgICBjb25zdCByZXF1ZXN0ID0gcmVzb3VyY2UucmVxdWVzdDsKICAgICAgICBjb25zdCB1cmwgPSByZXNvdXJjZS51cmw7CiAgICAgICAgcmVxdWVzdC51cmwgPSB1cmw7CiAgICAgICAgcmVxdWVzdC5yZXF1ZXN0RnVuY3Rpb24gPSBmdW5jdGlvbigpIHsKICAgICAgICAgIGNvbnN0IHJlc3BvbnNlVHlwZSA9IG9wdGlvbnMucmVzcG9uc2VUeXBlOwogICAgICAgICAgY29uc3QgaGVhZGVycyA9IGNvbWJpbmVfZGVmYXVsdChvcHRpb25zLmhlYWRlcnMsIHJlc291cmNlLmhlYWRlcnMpOwogICAgICAgICAgY29uc3Qgb3ZlcnJpZGVNaW1lVHlwZSA9IG9wdGlvbnMub3ZlcnJpZGVNaW1lVHlwZTsKICAgICAgICAgIGNvbnN0IG1ldGhvZCA9IG9wdGlvbnMubWV0aG9kOwogICAgICAgICAgY29uc3QgZGF0YSA9IG9wdGlvbnMuZGF0YTsKICAgICAgICAgIGNvbnN0IGRlZmVycmVkID0gZGVmZXJfZGVmYXVsdCgpOwogICAgICAgICAgY29uc3QgeGhyID0gUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucy5sb2FkV2l0aFhocigKICAgICAgICAgICAgdXJsLAogICAgICAgICAgICByZXNwb25zZVR5cGUsCiAgICAgICAgICAgIG1ldGhvZCwKICAgICAgICAgICAgZGF0YSwKICAgICAgICAgICAgaGVhZGVycywKICAgICAgICAgICAgZGVmZXJyZWQsCiAgICAgICAgICAgIG92ZXJyaWRlTWltZVR5cGUKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHhocikgJiYgZGVmaW5lZF9kZWZhdWx0KHhoci5hYm9ydCkpIHsKICAgICAgICAgICAgcmVxdWVzdC5jYW5jZWxGdW5jdGlvbiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHhoci5hYm9ydCgpOwogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGRlZmVycmVkLnByb21pc2U7CiAgICAgICAgfTsKICAgICAgICBjb25zdCBwcm9taXNlID0gUmVxdWVzdFNjaGVkdWxlcl9kZWZhdWx0LnJlcXVlc3QocmVxdWVzdCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocHJvbWlzZSkpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHByb21pc2UudGhlbihmdW5jdGlvbihkYXRhKSB7CiAgICAgICAgICByZXF1ZXN0LmNhbmNlbEZ1bmN0aW9uID0gdm9pZCAwOwogICAgICAgICAgcmV0dXJuIGRhdGE7CiAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24oZTIpIHsKICAgICAgICAgIHJlcXVlc3QuY2FuY2VsRnVuY3Rpb24gPSB2b2lkIDA7CiAgICAgICAgICBpZiAocmVxdWVzdC5zdGF0ZSAhPT0gUmVxdWVzdFN0YXRlX2RlZmF1bHQuRkFJTEVEKSB7CiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChlMik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzb3VyY2UucmV0cnlPbkVycm9yKGUyKS50aGVuKGZ1bmN0aW9uKHJldHJ5KSB7CiAgICAgICAgICAgIGlmIChyZXRyeSkgewogICAgICAgICAgICAgIHJlcXVlc3Quc3RhdGUgPSBSZXF1ZXN0U3RhdGVfZGVmYXVsdC5VTklTU1VFRDsKICAgICAgICAgICAgICByZXF1ZXN0LmRlZmVycmVkID0gdm9pZCAwOwogICAgICAgICAgICAgIHJldHVybiByZXNvdXJjZS5mZXRjaChvcHRpb25zKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZTIpOwogICAgICAgICAgfSk7CiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIGRhdGFVcmlSZWdleDIgPSAvXmRhdGE6KC4qPykoO2Jhc2U2NCk/LCguKikkLzsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLmZldGNoID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIG9wdGlvbnMgPSBkZWZhdWx0Q2xvbmUob3B0aW9ucywge30pOwogICAgICAgIG9wdGlvbnMubWV0aG9kID0gIkdFVCI7CiAgICAgICAgcmV0dXJuIHRoaXMuX21ha2VSZXF1ZXN0KG9wdGlvbnMpOwogICAgICB9OwogICAgICBSZXNvdXJjZS5mZXRjaCA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UuZmV0Y2goewogICAgICAgICAgLy8gTWFrZSBjb3B5IG9mIGp1c3QgdGhlIG5lZWRlZCBmaWVsZHMgYmVjYXVzZSBoZWFkZXJzIGNhbiBiZSBwYXNzZWQgdG8gYm90aCB0aGUgY29uc3RydWN0b3IgYW5kIHRvIGZldGNoCiAgICAgICAgICByZXNwb25zZVR5cGU6IG9wdGlvbnMucmVzcG9uc2VUeXBlLAogICAgICAgICAgb3ZlcnJpZGVNaW1lVHlwZTogb3B0aW9ucy5vdmVycmlkZU1pbWVUeXBlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5kZWxldGUgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IGRlZmF1bHRDbG9uZShvcHRpb25zLCB7fSk7CiAgICAgICAgb3B0aW9ucy5tZXRob2QgPSAiREVMRVRFIjsKICAgICAgICByZXR1cm4gdGhpcy5fbWFrZVJlcXVlc3Qob3B0aW9ucyk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLmRlbGV0ZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UuZGVsZXRlKHsKICAgICAgICAgIC8vIE1ha2UgY29weSBvZiBqdXN0IHRoZSBuZWVkZWQgZmllbGRzIGJlY2F1c2UgaGVhZGVycyBjYW4gYmUgcGFzc2VkIHRvIGJvdGggdGhlIGNvbnN0cnVjdG9yIGFuZCB0byBmZXRjaAogICAgICAgICAgcmVzcG9uc2VUeXBlOiBvcHRpb25zLnJlc3BvbnNlVHlwZSwKICAgICAgICAgIG92ZXJyaWRlTWltZVR5cGU6IG9wdGlvbnMub3ZlcnJpZGVNaW1lVHlwZSwKICAgICAgICAgIGRhdGE6IG9wdGlvbnMuZGF0YQogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUuaGVhZCA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gZGVmYXVsdENsb25lKG9wdGlvbnMsIHt9KTsKICAgICAgICBvcHRpb25zLm1ldGhvZCA9ICJIRUFEIjsKICAgICAgICByZXR1cm4gdGhpcy5fbWFrZVJlcXVlc3Qob3B0aW9ucyk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLmhlYWQgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgUmVzb3VyY2Uob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuIHJlc291cmNlLmhlYWQoewogICAgICAgICAgLy8gTWFrZSBjb3B5IG9mIGp1c3QgdGhlIG5lZWRlZCBmaWVsZHMgYmVjYXVzZSBoZWFkZXJzIGNhbiBiZSBwYXNzZWQgdG8gYm90aCB0aGUgY29uc3RydWN0b3IgYW5kIHRvIGZldGNoCiAgICAgICAgICByZXNwb25zZVR5cGU6IG9wdGlvbnMucmVzcG9uc2VUeXBlLAogICAgICAgICAgb3ZlcnJpZGVNaW1lVHlwZTogb3B0aW9ucy5vdmVycmlkZU1pbWVUeXBlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnByb3RvdHlwZS5vcHRpb25zID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIG9wdGlvbnMgPSBkZWZhdWx0Q2xvbmUob3B0aW9ucywge30pOwogICAgICAgIG9wdGlvbnMubWV0aG9kID0gIk9QVElPTlMiOwogICAgICAgIHJldHVybiB0aGlzLl9tYWtlUmVxdWVzdChvcHRpb25zKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2Uub3B0aW9ucyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2Uub3B0aW9ucyh7CiAgICAgICAgICAvLyBNYWtlIGNvcHkgb2YganVzdCB0aGUgbmVlZGVkIGZpZWxkcyBiZWNhdXNlIGhlYWRlcnMgY2FuIGJlIHBhc3NlZCB0byBib3RoIHRoZSBjb25zdHJ1Y3RvciBhbmQgdG8gZmV0Y2gKICAgICAgICAgIHJlc3BvbnNlVHlwZTogb3B0aW9ucy5yZXNwb25zZVR5cGUsCiAgICAgICAgICBvdmVycmlkZU1pbWVUeXBlOiBvcHRpb25zLm92ZXJyaWRlTWltZVR5cGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLnBvc3QgPSBmdW5jdGlvbihkYXRhLCBvcHRpb25zKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJkYXRhIiwgZGF0YSk7CiAgICAgICAgb3B0aW9ucyA9IGRlZmF1bHRDbG9uZShvcHRpb25zLCB7fSk7CiAgICAgICAgb3B0aW9ucy5tZXRob2QgPSAiUE9TVCI7CiAgICAgICAgb3B0aW9ucy5kYXRhID0gZGF0YTsKICAgICAgICByZXR1cm4gdGhpcy5fbWFrZVJlcXVlc3Qob3B0aW9ucyk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnBvc3QgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgUmVzb3VyY2Uob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuIHJlc291cmNlLnBvc3Qob3B0aW9ucy5kYXRhLCB7CiAgICAgICAgICAvLyBNYWtlIGNvcHkgb2YganVzdCB0aGUgbmVlZGVkIGZpZWxkcyBiZWNhdXNlIGhlYWRlcnMgY2FuIGJlIHBhc3NlZCB0byBib3RoIHRoZSBjb25zdHJ1Y3RvciBhbmQgdG8gcG9zdAogICAgICAgICAgcmVzcG9uc2VUeXBlOiBvcHRpb25zLnJlc3BvbnNlVHlwZSwKICAgICAgICAgIG92ZXJyaWRlTWltZVR5cGU6IG9wdGlvbnMub3ZlcnJpZGVNaW1lVHlwZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZXNvdXJjZS5wcm90b3R5cGUucHV0ID0gZnVuY3Rpb24oZGF0YSwgb3B0aW9ucykgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZGF0YSIsIGRhdGEpOwogICAgICAgIG9wdGlvbnMgPSBkZWZhdWx0Q2xvbmUob3B0aW9ucywge30pOwogICAgICAgIG9wdGlvbnMubWV0aG9kID0gIlBVVCI7CiAgICAgICAgb3B0aW9ucy5kYXRhID0gZGF0YTsKICAgICAgICByZXR1cm4gdGhpcy5fbWFrZVJlcXVlc3Qob3B0aW9ucyk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLnB1dCA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCByZXNvdXJjZSA9IG5ldyBSZXNvdXJjZShvcHRpb25zKTsKICAgICAgICByZXR1cm4gcmVzb3VyY2UucHV0KG9wdGlvbnMuZGF0YSwgewogICAgICAgICAgLy8gTWFrZSBjb3B5IG9mIGp1c3QgdGhlIG5lZWRlZCBmaWVsZHMgYmVjYXVzZSBoZWFkZXJzIGNhbiBiZSBwYXNzZWQgdG8gYm90aCB0aGUgY29uc3RydWN0b3IgYW5kIHRvIHBvc3QKICAgICAgICAgIHJlc3BvbnNlVHlwZTogb3B0aW9ucy5yZXNwb25zZVR5cGUsCiAgICAgICAgICBvdmVycmlkZU1pbWVUeXBlOiBvcHRpb25zLm92ZXJyaWRlTWltZVR5cGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucHJvdG90eXBlLnBhdGNoID0gZnVuY3Rpb24oZGF0YSwgb3B0aW9ucykgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZGF0YSIsIGRhdGEpOwogICAgICAgIG9wdGlvbnMgPSBkZWZhdWx0Q2xvbmUob3B0aW9ucywge30pOwogICAgICAgIG9wdGlvbnMubWV0aG9kID0gIlBBVENIIjsKICAgICAgICBvcHRpb25zLmRhdGEgPSBkYXRhOwogICAgICAgIHJldHVybiB0aGlzLl9tYWtlUmVxdWVzdChvcHRpb25zKTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UucGF0Y2ggPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBuZXcgUmVzb3VyY2Uob3B0aW9ucyk7CiAgICAgICAgcmV0dXJuIHJlc291cmNlLnBhdGNoKG9wdGlvbnMuZGF0YSwgewogICAgICAgICAgLy8gTWFrZSBjb3B5IG9mIGp1c3QgdGhlIG5lZWRlZCBmaWVsZHMgYmVjYXVzZSBoZWFkZXJzIGNhbiBiZSBwYXNzZWQgdG8gYm90aCB0aGUgY29uc3RydWN0b3IgYW5kIHRvIHBvc3QKICAgICAgICAgIHJlc3BvbnNlVHlwZTogb3B0aW9ucy5yZXNwb25zZVR5cGUsCiAgICAgICAgICBvdmVycmlkZU1pbWVUeXBlOiBvcHRpb25zLm92ZXJyaWRlTWltZVR5cGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucyA9IHt9OwogICAgICBSZXNvdXJjZS5fSW1wbGVtZW50YXRpb25zLmxvYWRJbWFnZUVsZW1lbnQgPSBmdW5jdGlvbih1cmwsIGNyb3NzT3JpZ2luLCBkZWZlcnJlZCkgewogICAgICAgIGNvbnN0IGltYWdlID0gbmV3IEltYWdlKCk7CiAgICAgICAgaW1hZ2Uub25sb2FkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICBpZiAoaW1hZ2UubmF0dXJhbFdpZHRoID09PSAwICYmIGltYWdlLm5hdHVyYWxIZWlnaHQgPT09IDAgJiYgaW1hZ2Uud2lkdGggPT09IDAgJiYgaW1hZ2UuaGVpZ2h0ID09PSAwKSB7CiAgICAgICAgICAgIGltYWdlLndpZHRoID0gMzAwOwogICAgICAgICAgICBpbWFnZS5oZWlnaHQgPSAxNTA7CiAgICAgICAgICB9CiAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKGltYWdlKTsKICAgICAgICB9OwogICAgICAgIGltYWdlLm9uZXJyb3IgPSBmdW5jdGlvbihlMikgewogICAgICAgICAgZGVmZXJyZWQucmVqZWN0KGUyKTsKICAgICAgICB9OwogICAgICAgIGlmIChjcm9zc09yaWdpbikgewogICAgICAgICAgaWYgKFRydXN0ZWRTZXJ2ZXJzX2RlZmF1bHQuY29udGFpbnModXJsKSkgewogICAgICAgICAgICBpbWFnZS5jcm9zc09yaWdpbiA9ICJ1c2UtY3JlZGVudGlhbHMiOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgaW1hZ2UuY3Jvc3NPcmlnaW4gPSAiIjsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaW1hZ2Uuc3JjID0gdXJsOwogICAgICB9OwogICAgICBSZXNvdXJjZS5fSW1wbGVtZW50YXRpb25zLmNyZWF0ZUltYWdlID0gZnVuY3Rpb24ocmVxdWVzdCwgY3Jvc3NPcmlnaW4sIGRlZmVycmVkLCBmbGlwWSwgc2tpcENvbG9yU3BhY2VDb252ZXJzaW9uLCBwcmVmZXJJbWFnZUJpdG1hcCwgaGVhZGVycykgewogICAgICAgIGNvbnN0IHVybCA9IHJlcXVlc3QudXJsOwogICAgICAgIFJlc291cmNlLnN1cHBvcnRzSW1hZ2VCaXRtYXBPcHRpb25zKCkudGhlbihmdW5jdGlvbihzdXBwb3J0c0ltYWdlQml0bWFwKSB7CiAgICAgICAgICBpZiAoIShzdXBwb3J0c0ltYWdlQml0bWFwICYmIHByZWZlckltYWdlQml0bWFwKSkgewogICAgICAgICAgICBSZXNvdXJjZS5fSW1wbGVtZW50YXRpb25zLmxvYWRJbWFnZUVsZW1lbnQodXJsLCBjcm9zc09yaWdpbiwgZGVmZXJyZWQpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByZXNwb25zZVR5cGUgPSAiYmxvYiI7CiAgICAgICAgICBjb25zdCBtZXRob2QgPSAiR0VUIjsKICAgICAgICAgIGNvbnN0IHhockRlZmVycmVkID0gZGVmZXJfZGVmYXVsdCgpOwogICAgICAgICAgY29uc3QgeGhyID0gUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucy5sb2FkV2l0aFhocigKICAgICAgICAgICAgdXJsLAogICAgICAgICAgICByZXNwb25zZVR5cGUsCiAgICAgICAgICAgIG1ldGhvZCwKICAgICAgICAgICAgdm9pZCAwLAogICAgICAgICAgICBoZWFkZXJzLAogICAgICAgICAgICB4aHJEZWZlcnJlZCwKICAgICAgICAgICAgdm9pZCAwLAogICAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICAgIHZvaWQgMAogICAgICAgICAgKTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoeGhyKSAmJiBkZWZpbmVkX2RlZmF1bHQoeGhyLmFib3J0KSkgewogICAgICAgICAgICByZXF1ZXN0LmNhbmNlbEZ1bmN0aW9uID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgeGhyLmFib3J0KCk7CiAgICAgICAgICAgIH07CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4geGhyRGVmZXJyZWQucHJvbWlzZS50aGVuKGZ1bmN0aW9uKGJsb2IpIHsKICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYmxvYikpIHsKICAgICAgICAgICAgICBkZWZlcnJlZC5yZWplY3QoCiAgICAgICAgICAgICAgICBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgICAgIGBTdWNjZXNzZnVsbHkgcmV0cmlldmVkICR7dXJsfSBidXQgaXQgY29udGFpbmVkIG5vIGNvbnRlbnQuYAogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBSZXNvdXJjZS5jcmVhdGVJbWFnZUJpdG1hcEZyb21CbG9iKGJsb2IsIHsKICAgICAgICAgICAgICBmbGlwWSwKICAgICAgICAgICAgICBwcmVtdWx0aXBseUFscGhhOiBmYWxzZSwKICAgICAgICAgICAgICBza2lwQ29sb3JTcGFjZUNvbnZlcnNpb24KICAgICAgICAgICAgfSk7CiAgICAgICAgICB9KS50aGVuKGZ1bmN0aW9uKGltYWdlKSB7CiAgICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUoaW1hZ2UpOwogICAgICAgICAgfSk7CiAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24oZTIpIHsKICAgICAgICAgIGRlZmVycmVkLnJlamVjdChlMik7CiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlc291cmNlLmNyZWF0ZUltYWdlQml0bWFwRnJvbUJsb2IgPSBmdW5jdGlvbihibG9iLCBvcHRpb25zKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zIiwgb3B0aW9ucyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuYm9vbCgib3B0aW9ucy5mbGlwWSIsIG9wdGlvbnMuZmxpcFkpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLmJvb2woIm9wdGlvbnMucHJlbXVsdGlwbHlBbHBoYSIsIG9wdGlvbnMucHJlbXVsdGlwbHlBbHBoYSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuYm9vbCgKICAgICAgICAgICJvcHRpb25zLnNraXBDb2xvclNwYWNlQ29udmVyc2lvbiIsCiAgICAgICAgICBvcHRpb25zLnNraXBDb2xvclNwYWNlQ29udmVyc2lvbgogICAgICAgICk7CiAgICAgICAgcmV0dXJuIGNyZWF0ZUltYWdlQml0bWFwKGJsb2IsIHsKICAgICAgICAgIC8vICdmcm9tLWltYWdlJyBpcyBkZXByZWNhdGVkLCBuZXcgb3B0aW9uIGlzICdub25lJy4gSG93ZXZlciwgd2Ugc3RpbGwgbmVlZCB0byBzdXBwb3J0IG9sZGVyIGJyb3dzZXJzLAogICAgICAgICAgLy8gYW5kIHRoZXJlJ3Mgbm8gZ29vZCB3YXkgdG8gZGV0ZWN0IHN1cHBvcnQgZm9yIHRoZXNlIG9wdGlvbnMuIEZvciBub3csIGNvbnRpbnVlIHRvIHVzZSAnZnJvbS1pbWFnZScuIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL0Nlc2l1bUdTL2Nlc2l1bS9pc3N1ZXMvMTI4NDYKICAgICAgICAgIGltYWdlT3JpZW50YXRpb246IG9wdGlvbnMuZmxpcFkgPyAiZmxpcFkiIDogIm5vbmUiLAogICAgICAgICAgcHJlbXVsdGlwbHlBbHBoYTogb3B0aW9ucy5wcmVtdWx0aXBseUFscGhhID8gInByZW11bHRpcGx5IiA6ICJub25lIiwKICAgICAgICAgIGNvbG9yU3BhY2VDb252ZXJzaW9uOiBvcHRpb25zLnNraXBDb2xvclNwYWNlQ29udmVyc2lvbiA/ICJub25lIiA6ICJkZWZhdWx0IgogICAgICAgIH0pOwogICAgICB9OwogICAgICBub1hNTEh0dHBSZXF1ZXN0ID0gdHlwZW9mIFhNTEh0dHBSZXF1ZXN0ID09PSAidW5kZWZpbmVkIjsKICAgICAgUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucy5sb2FkV2l0aFhociA9IGZ1bmN0aW9uKHVybCwgcmVzcG9uc2VUeXBlLCBtZXRob2QsIGRhdGEsIGhlYWRlcnMsIGRlZmVycmVkLCBvdmVycmlkZU1pbWVUeXBlKSB7CiAgICAgICAgY29uc3QgZGF0YVVyaVJlZ2V4UmVzdWx0ID0gZGF0YVVyaVJlZ2V4Mi5leGVjKHVybCk7CiAgICAgICAgaWYgKGRhdGFVcmlSZWdleFJlc3VsdCAhPT0gbnVsbCkgewogICAgICAgICAgZGVmZXJyZWQucmVzb2x2ZShkZWNvZGVEYXRhVXJpKGRhdGFVcmlSZWdleFJlc3VsdCwgcmVzcG9uc2VUeXBlKSk7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGlmIChub1hNTEh0dHBSZXF1ZXN0KSB7CiAgICAgICAgICBsb2FkV2l0aEh0dHBSZXF1ZXN0KAogICAgICAgICAgICB1cmwsCiAgICAgICAgICAgIHJlc3BvbnNlVHlwZSwKICAgICAgICAgICAgbWV0aG9kLAogICAgICAgICAgICBkYXRhLAogICAgICAgICAgICBoZWFkZXJzLAogICAgICAgICAgICBkZWZlcnJlZCwKICAgICAgICAgICAgb3ZlcnJpZGVNaW1lVHlwZQogICAgICAgICAgKTsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgeGhyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7CiAgICAgICAgaWYgKFRydXN0ZWRTZXJ2ZXJzX2RlZmF1bHQuY29udGFpbnModXJsKSkgewogICAgICAgICAgeGhyLndpdGhDcmVkZW50aWFscyA9IHRydWU7CiAgICAgICAgfQogICAgICAgIHhoci5vcGVuKG1ldGhvZCwgdXJsLCB0cnVlKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG92ZXJyaWRlTWltZVR5cGUpICYmIGRlZmluZWRfZGVmYXVsdCh4aHIub3ZlcnJpZGVNaW1lVHlwZSkpIHsKICAgICAgICAgIHhoci5vdmVycmlkZU1pbWVUeXBlKG92ZXJyaWRlTWltZVR5cGUpOwogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGhlYWRlcnMpKSB7CiAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBoZWFkZXJzKSB7CiAgICAgICAgICAgIGlmIChoZWFkZXJzLmhhc093blByb3BlcnR5KGtleSkpIHsKICAgICAgICAgICAgICB4aHIuc2V0UmVxdWVzdEhlYWRlcihrZXksIGhlYWRlcnNba2V5XSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZXNwb25zZVR5cGUpKSB7CiAgICAgICAgICB4aHIucmVzcG9uc2VUeXBlID0gcmVzcG9uc2VUeXBlOwogICAgICAgIH0KICAgICAgICBsZXQgbG9jYWxGaWxlID0gZmFsc2U7CiAgICAgICAgaWYgKHR5cGVvZiB1cmwgPT09ICJzdHJpbmciKSB7CiAgICAgICAgICBsb2NhbEZpbGUgPSB1cmwuaW5kZXhPZigiZmlsZTovLyIpID09PSAwIHx8IHR5cGVvZiB3aW5kb3cgIT09ICJ1bmRlZmluZWQiICYmIHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gPT09ICJmaWxlOi8vIjsKICAgICAgICB9CiAgICAgICAgeGhyLm9ubG9hZCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgaWYgKCh4aHIuc3RhdHVzIDwgMjAwIHx8IHhoci5zdGF0dXMgPj0gMzAwKSAmJiAhKGxvY2FsRmlsZSAmJiB4aHIuc3RhdHVzID09PSAwKSkgewogICAgICAgICAgICBkZWZlcnJlZC5yZWplY3QoCiAgICAgICAgICAgICAgbmV3IFJlcXVlc3RFcnJvckV2ZW50X2RlZmF1bHQoCiAgICAgICAgICAgICAgICB4aHIuc3RhdHVzLAogICAgICAgICAgICAgICAgeGhyLnJlc3BvbnNlLAogICAgICAgICAgICAgICAgeGhyLmdldEFsbFJlc3BvbnNlSGVhZGVycygpCiAgICAgICAgICAgICAgKQogICAgICAgICAgICApOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByZXNwb25zZSA9IHhoci5yZXNwb25zZTsKICAgICAgICAgIGNvbnN0IGJyb3dzZXJSZXNwb25zZVR5cGUgPSB4aHIucmVzcG9uc2VUeXBlOwogICAgICAgICAgaWYgKG1ldGhvZCA9PT0gIkhFQUQiIHx8IG1ldGhvZCA9PT0gIk9QVElPTlMiKSB7CiAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlSGVhZGVyU3RyaW5nID0geGhyLmdldEFsbFJlc3BvbnNlSGVhZGVycygpOwogICAgICAgICAgICBjb25zdCBzcGxpdEhlYWRlcnMgPSByZXNwb25zZUhlYWRlclN0cmluZy50cmltKCkuc3BsaXQoL1tcclxuXSsvKTsKICAgICAgICAgICAgY29uc3QgcmVzcG9uc2VIZWFkZXJzID0ge307CiAgICAgICAgICAgIHNwbGl0SGVhZGVycy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHsKICAgICAgICAgICAgICBjb25zdCBwYXJ0cyA9IGxpbmUuc3BsaXQoIjogIik7CiAgICAgICAgICAgICAgY29uc3QgaGVhZGVyID0gcGFydHMuc2hpZnQoKTsKICAgICAgICAgICAgICByZXNwb25zZUhlYWRlcnNbaGVhZGVyXSA9IHBhcnRzLmpvaW4oIjogIik7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKHJlc3BvbnNlSGVhZGVycyk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh4aHIuc3RhdHVzID09PSAyMDQpIHsKICAgICAgICAgICAgZGVmZXJyZWQucmVzb2x2ZSh2b2lkIDApOwogICAgICAgICAgfSBlbHNlIGlmIChkZWZpbmVkX2RlZmF1bHQocmVzcG9uc2UpICYmICghZGVmaW5lZF9kZWZhdWx0KHJlc3BvbnNlVHlwZSkgfHwgYnJvd3NlclJlc3BvbnNlVHlwZSA9PT0gcmVzcG9uc2VUeXBlKSkgewogICAgICAgICAgICBkZWZlcnJlZC5yZXNvbHZlKHJlc3BvbnNlKTsKICAgICAgICAgIH0gZWxzZSBpZiAocmVzcG9uc2VUeXBlID09PSAianNvbiIgJiYgdHlwZW9mIHJlc3BvbnNlID09PSAic3RyaW5nIikgewogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgIGRlZmVycmVkLnJlc29sdmUoSlNPTi5wYXJzZShyZXNwb25zZSkpOwogICAgICAgICAgICB9IGNhdGNoIChlMikgewogICAgICAgICAgICAgIGRlZmVycmVkLnJlamVjdChlMik7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAoKGJyb3dzZXJSZXNwb25zZVR5cGUgPT09ICIiIHx8IGJyb3dzZXJSZXNwb25zZVR5cGUgPT09ICJkb2N1bWVudCIpICYmIGRlZmluZWRfZGVmYXVsdCh4aHIucmVzcG9uc2VYTUwpICYmIHhoci5yZXNwb25zZVhNTC5oYXNDaGlsZE5vZGVzKCkpIHsKICAgICAgICAgICAgZGVmZXJyZWQucmVzb2x2ZSh4aHIucmVzcG9uc2VYTUwpOwogICAgICAgICAgfSBlbHNlIGlmICgoYnJvd3NlclJlc3BvbnNlVHlwZSA9PT0gIiIgfHwgYnJvd3NlclJlc3BvbnNlVHlwZSA9PT0gInRleHQiKSAmJiBkZWZpbmVkX2RlZmF1bHQoeGhyLnJlc3BvbnNlVGV4dCkpIHsKICAgICAgICAgICAgZGVmZXJyZWQucmVzb2x2ZSh4aHIucmVzcG9uc2VUZXh0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGRlZmVycmVkLnJlamVjdCgKICAgICAgICAgICAgICBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkludmFsaWQgWE1MSHR0cFJlcXVlc3QgcmVzcG9uc2UgdHlwZS4iKQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgICAgeGhyLm9uZXJyb3IgPSBmdW5jdGlvbihlMikgewogICAgICAgICAgZGVmZXJyZWQucmVqZWN0KG5ldyBSZXF1ZXN0RXJyb3JFdmVudF9kZWZhdWx0KCkpOwogICAgICAgIH07CiAgICAgICAgeGhyLnNlbmQoZGF0YSk7CiAgICAgICAgcmV0dXJuIHhocjsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucy5sb2FkQW5kRXhlY3V0ZVNjcmlwdCA9IGZ1bmN0aW9uKHVybCwgZnVuY3Rpb25OYW1lLCBkZWZlcnJlZCkgewogICAgICAgIHJldHVybiBsb2FkQW5kRXhlY3V0ZVNjcmlwdF9kZWZhdWx0KHVybCwgZnVuY3Rpb25OYW1lKS5jYXRjaChmdW5jdGlvbihlMikgewogICAgICAgICAgZGVmZXJyZWQucmVqZWN0KGUyKTsKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUmVzb3VyY2UuX0RlZmF1bHRJbXBsZW1lbnRhdGlvbnMgPSB7fTsKICAgICAgUmVzb3VyY2UuX0RlZmF1bHRJbXBsZW1lbnRhdGlvbnMuY3JlYXRlSW1hZ2UgPSBSZXNvdXJjZS5fSW1wbGVtZW50YXRpb25zLmNyZWF0ZUltYWdlOwogICAgICBSZXNvdXJjZS5fRGVmYXVsdEltcGxlbWVudGF0aW9ucy5sb2FkV2l0aFhociA9IFJlc291cmNlLl9JbXBsZW1lbnRhdGlvbnMubG9hZFdpdGhYaHI7CiAgICAgIFJlc291cmNlLl9EZWZhdWx0SW1wbGVtZW50YXRpb25zLmxvYWRBbmRFeGVjdXRlU2NyaXB0ID0gUmVzb3VyY2UuX0ltcGxlbWVudGF0aW9ucy5sb2FkQW5kRXhlY3V0ZVNjcmlwdDsKICAgICAgUmVzb3VyY2UuREVGQVVMVCA9IE9iamVjdC5mcmVlemUoCiAgICAgICAgbmV3IFJlc291cmNlKHsKICAgICAgICAgIHVybDogdHlwZW9mIGRvY3VtZW50ID09PSAidW5kZWZpbmVkIiA/ICIiIDogZG9jdW1lbnQubG9jYXRpb24uaHJlZi5zcGxpdCgiPyIpWzBdCiAgICAgICAgfSkKICAgICAgKTsKICAgICAgUmVzb3VyY2VfZGVmYXVsdCA9IFJlc291cmNlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnMuanMKICBmdW5jdGlvbiBFYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVycyhvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICB0aGlzLl9kYXRlcyA9IHZvaWQgMDsKICAgIHRoaXMuX3NhbXBsZXMgPSB2b2lkIDA7CiAgICB0aGlzLl9kYXRlQ29sdW1uID0gLTE7CiAgICB0aGlzLl94UG9sZVdhbmRlclJhZGlhbnNDb2x1bW4gPSAtMTsKICAgIHRoaXMuX3lQb2xlV2FuZGVyUmFkaWFuc0NvbHVtbiA9IC0xOwogICAgdGhpcy5fdXQxTWludXNVdGNTZWNvbmRzQ29sdW1uID0gLTE7CiAgICB0aGlzLl94Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW4gPSAtMTsKICAgIHRoaXMuX3lDZWxlc3RpYWxQb2xlT2Zmc2V0UmFkaWFuc0NvbHVtbiA9IC0xOwogICAgdGhpcy5fdGFpTWludXNVdGNTZWNvbmRzQ29sdW1uID0gLTE7CiAgICB0aGlzLl9jb2x1bW5Db3VudCA9IDA7CiAgICB0aGlzLl9sYXN0SW5kZXggPSAtMTsKICAgIHRoaXMuX2FkZE5ld0xlYXBTZWNvbmRzID0gb3B0aW9ucy5hZGROZXdMZWFwU2Vjb25kcyA/PyB0cnVlOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvcHRpb25zLmRhdGEpKSB7CiAgICAgIG9uRGF0YVJlYWR5KHRoaXMsIG9wdGlvbnMuZGF0YSk7CiAgICB9IGVsc2UgewogICAgICBvbkRhdGFSZWFkeSh0aGlzLCB7CiAgICAgICAgY29sdW1uTmFtZXM6IFsKICAgICAgICAgICJkYXRlSXNvODYwMSIsCiAgICAgICAgICAibW9kaWZpZWRKdWxpYW5EYXRlVXRjIiwKICAgICAgICAgICJ4UG9sZVdhbmRlclJhZGlhbnMiLAogICAgICAgICAgInlQb2xlV2FuZGVyUmFkaWFucyIsCiAgICAgICAgICAidXQxTWludXNVdGNTZWNvbmRzIiwKICAgICAgICAgICJsZW5ndGhPZkRheUNvcnJlY3Rpb25TZWNvbmRzIiwKICAgICAgICAgICJ4Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnMiLAogICAgICAgICAgInlDZWxlc3RpYWxQb2xlT2Zmc2V0UmFkaWFucyIsCiAgICAgICAgICAidGFpTWludXNVdGNTZWNvbmRzIgogICAgICAgIF0sCiAgICAgICAgc2FtcGxlczogW10KICAgICAgfSk7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGNvbXBhcmVMZWFwU2Vjb25kRGF0ZXMyKGxlYXBTZWNvbmQsIGRhdGVUb0ZpbmQpIHsKICAgIHJldHVybiBKdWxpYW5EYXRlX2RlZmF1bHQuY29tcGFyZShsZWFwU2Vjb25kLmp1bGlhbkRhdGUsIGRhdGVUb0ZpbmQpOwogIH0KICBmdW5jdGlvbiBvbkRhdGFSZWFkeShlb3AsIGVvcERhdGEpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVvcERhdGEuY29sdW1uTmFtZXMpKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgKICAgICAgICAiRXJyb3IgaW4gbG9hZGVkIEVPUCBkYXRhOiBUaGUgY29sdW1uTmFtZXMgcHJvcGVydHkgaXMgcmVxdWlyZWQuIgogICAgICApOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZW9wRGF0YS5zYW1wbGVzKSkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoCiAgICAgICAgIkVycm9yIGluIGxvYWRlZCBFT1AgZGF0YTogVGhlIHNhbXBsZXMgcHJvcGVydHkgaXMgcmVxdWlyZWQuIgogICAgICApOwogICAgfQogICAgY29uc3QgZGF0ZUNvbHVtbiA9IGVvcERhdGEuY29sdW1uTmFtZXMuaW5kZXhPZigibW9kaWZpZWRKdWxpYW5EYXRlVXRjIik7CiAgICBjb25zdCB4UG9sZVdhbmRlclJhZGlhbnNDb2x1bW4gPSBlb3BEYXRhLmNvbHVtbk5hbWVzLmluZGV4T2YoInhQb2xlV2FuZGVyUmFkaWFucyIpOwogICAgY29uc3QgeVBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uID0gZW9wRGF0YS5jb2x1bW5OYW1lcy5pbmRleE9mKCJ5UG9sZVdhbmRlclJhZGlhbnMiKTsKICAgIGNvbnN0IHV0MU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA9IGVvcERhdGEuY29sdW1uTmFtZXMuaW5kZXhPZigidXQxTWludXNVdGNTZWNvbmRzIik7CiAgICBjb25zdCB4Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW4gPSBlb3BEYXRhLmNvbHVtbk5hbWVzLmluZGV4T2YoCiAgICAgICJ4Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnMiCiAgICApOwogICAgY29uc3QgeUNlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zQ29sdW1uID0gZW9wRGF0YS5jb2x1bW5OYW1lcy5pbmRleE9mKAogICAgICAieUNlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zIgogICAgKTsKICAgIGNvbnN0IHRhaU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA9IGVvcERhdGEuY29sdW1uTmFtZXMuaW5kZXhPZigidGFpTWludXNVdGNTZWNvbmRzIik7CiAgICBpZiAoZGF0ZUNvbHVtbiA8IDAgfHwgeFBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uIDwgMCB8fCB5UG9sZVdhbmRlclJhZGlhbnNDb2x1bW4gPCAwIHx8IHV0MU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA8IDAgfHwgeENlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zQ29sdW1uIDwgMCB8fCB5Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW4gPCAwIHx8IHRhaU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA8IDApIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KAogICAgICAgICJFcnJvciBpbiBsb2FkZWQgRU9QIGRhdGE6IFRoZSBjb2x1bW5OYW1lcyBwcm9wZXJ0eSBtdXN0IGluY2x1ZGUgbW9kaWZpZWRKdWxpYW5EYXRlVXRjLCB4UG9sZVdhbmRlclJhZGlhbnMsIHlQb2xlV2FuZGVyUmFkaWFucywgdXQxTWludXNVdGNTZWNvbmRzLCB4Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnMsIHlDZWxlc3RpYWxQb2xlT2Zmc2V0UmFkaWFucywgYW5kIHRhaU1pbnVzVXRjU2Vjb25kcyBjb2x1bW5zIgogICAgICApOwogICAgfQogICAgY29uc3Qgc2FtcGxlcyA9IGVvcC5fc2FtcGxlcyA9IGVvcERhdGEuc2FtcGxlczsKICAgIGNvbnN0IGRhdGVzID0gZW9wLl9kYXRlcyA9IFtdOwogICAgZW9wLl9kYXRlQ29sdW1uID0gZGF0ZUNvbHVtbjsKICAgIGVvcC5feFBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uID0geFBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uOwogICAgZW9wLl95UG9sZVdhbmRlclJhZGlhbnNDb2x1bW4gPSB5UG9sZVdhbmRlclJhZGlhbnNDb2x1bW47CiAgICBlb3AuX3V0MU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA9IHV0MU1pbnVzVXRjU2Vjb25kc0NvbHVtbjsKICAgIGVvcC5feENlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zQ29sdW1uID0geENlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zQ29sdW1uOwogICAgZW9wLl95Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW4gPSB5Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW47CiAgICBlb3AuX3RhaU1pbnVzVXRjU2Vjb25kc0NvbHVtbiA9IHRhaU1pbnVzVXRjU2Vjb25kc0NvbHVtbjsKICAgIGVvcC5fY29sdW1uQ291bnQgPSBlb3BEYXRhLmNvbHVtbk5hbWVzLmxlbmd0aDsKICAgIGVvcC5fbGFzdEluZGV4ID0gdm9pZCAwOwogICAgbGV0IGxhc3RUYWlNaW51c1V0YzsKICAgIGNvbnN0IGFkZE5ld0xlYXBTZWNvbmRzID0gZW9wLl9hZGROZXdMZWFwU2Vjb25kczsKICAgIGZvciAobGV0IGkyID0gMCwgbGVuID0gc2FtcGxlcy5sZW5ndGg7IGkyIDwgbGVuOyBpMiArPSBlb3AuX2NvbHVtbkNvdW50KSB7CiAgICAgIGNvbnN0IG1qZCA9IHNhbXBsZXNbaTIgKyBkYXRlQ29sdW1uXTsKICAgICAgY29uc3QgdGFpTWludXNVdGMgPSBzYW1wbGVzW2kyICsgdGFpTWludXNVdGNTZWNvbmRzQ29sdW1uXTsKICAgICAgY29uc3QgZGF5ID0gbWpkICsgVGltZUNvbnN0YW50c19kZWZhdWx0Lk1PRElGSUVEX0pVTElBTl9EQVRFX0RJRkZFUkVOQ0U7CiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgSnVsaWFuRGF0ZV9kZWZhdWx0KGRheSwgdGFpTWludXNVdGMsIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSSk7CiAgICAgIGRhdGVzLnB1c2goZGF0ZSk7CiAgICAgIGlmIChhZGROZXdMZWFwU2Vjb25kcykgewogICAgICAgIGlmICh0YWlNaW51c1V0YyAhPT0gbGFzdFRhaU1pbnVzVXRjICYmIGRlZmluZWRfZGVmYXVsdChsYXN0VGFpTWludXNVdGMpKSB7CiAgICAgICAgICBjb25zdCBsZWFwU2Vjb25kcyA9IEp1bGlhbkRhdGVfZGVmYXVsdC5sZWFwU2Vjb25kczsKICAgICAgICAgIGNvbnN0IGxlYXBTZWNvbmRJbmRleCA9IGJpbmFyeVNlYXJjaF9kZWZhdWx0KAogICAgICAgICAgICBsZWFwU2Vjb25kcywKICAgICAgICAgICAgZGF0ZSwKICAgICAgICAgICAgY29tcGFyZUxlYXBTZWNvbmREYXRlczIKICAgICAgICAgICk7CiAgICAgICAgICBpZiAobGVhcFNlY29uZEluZGV4IDwgMCkgewogICAgICAgICAgICBjb25zdCBsZWFwU2Vjb25kID0gbmV3IExlYXBTZWNvbmRfZGVmYXVsdChkYXRlLCB0YWlNaW51c1V0Yyk7CiAgICAgICAgICAgIGxlYXBTZWNvbmRzLnNwbGljZSh+bGVhcFNlY29uZEluZGV4LCAwLCBsZWFwU2Vjb25kKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbGFzdFRhaU1pbnVzVXRjID0gdGFpTWludXNVdGM7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gZmlsbFJlc3VsdEZyb21JbmRleChlb3AsIHNhbXBsZXMsIGluZGV4LCBjb2x1bW5Db3VudCwgcmVzdWx0KSB7CiAgICBjb25zdCBzdGFydCA9IGluZGV4ICogY29sdW1uQ291bnQ7CiAgICByZXN1bHQueFBvbGVXYW5kZXIgPSBzYW1wbGVzW3N0YXJ0ICsgZW9wLl94UG9sZVdhbmRlclJhZGlhbnNDb2x1bW5dOwogICAgcmVzdWx0LnlQb2xlV2FuZGVyID0gc2FtcGxlc1tzdGFydCArIGVvcC5feVBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uXTsKICAgIHJlc3VsdC54UG9sZU9mZnNldCA9IHNhbXBsZXNbc3RhcnQgKyBlb3AuX3hDZWxlc3RpYWxQb2xlT2Zmc2V0UmFkaWFuc0NvbHVtbl07CiAgICByZXN1bHQueVBvbGVPZmZzZXQgPSBzYW1wbGVzW3N0YXJ0ICsgZW9wLl95Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW5dOwogICAgcmVzdWx0LnV0MU1pbnVzVXRjID0gc2FtcGxlc1tzdGFydCArIGVvcC5fdXQxTWludXNVdGNTZWNvbmRzQ29sdW1uXTsKICB9CiAgZnVuY3Rpb24gbGluZWFySW50ZXJwKGR4LCB5MSwgeTIpIHsKICAgIHJldHVybiB5MSArIGR4ICogKHkyIC0geTEpOwogIH0KICBmdW5jdGlvbiBpbnRlcnBvbGF0ZShlb3AsIGRhdGVzLCBzYW1wbGVzLCBkYXRlLCBiZWZvcmUsIGFmdGVyLCByZXN1bHQpIHsKICAgIGNvbnN0IGNvbHVtbkNvdW50ID0gZW9wLl9jb2x1bW5Db3VudDsKICAgIGlmIChhZnRlciA+IGRhdGVzLmxlbmd0aCAtIDEpIHsKICAgICAgcmVzdWx0LnhQb2xlV2FuZGVyID0gMDsKICAgICAgcmVzdWx0LnlQb2xlV2FuZGVyID0gMDsKICAgICAgcmVzdWx0LnhQb2xlT2Zmc2V0ID0gMDsKICAgICAgcmVzdWx0LnlQb2xlT2Zmc2V0ID0gMDsKICAgICAgcmVzdWx0LnV0MU1pbnVzVXRjID0gMDsKICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KICAgIGNvbnN0IGJlZm9yZURhdGUgPSBkYXRlc1tiZWZvcmVdOwogICAgY29uc3QgYWZ0ZXJEYXRlID0gZGF0ZXNbYWZ0ZXJdOwogICAgaWYgKGJlZm9yZURhdGUuZXF1YWxzKGFmdGVyRGF0ZSkgfHwgZGF0ZS5lcXVhbHMoYmVmb3JlRGF0ZSkpIHsKICAgICAgZmlsbFJlc3VsdEZyb21JbmRleChlb3AsIHNhbXBsZXMsIGJlZm9yZSwgY29sdW1uQ291bnQsIHJlc3VsdCk7CiAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9IGVsc2UgaWYgKGRhdGUuZXF1YWxzKGFmdGVyRGF0ZSkpIHsKICAgICAgZmlsbFJlc3VsdEZyb21JbmRleChlb3AsIHNhbXBsZXMsIGFmdGVyLCBjb2x1bW5Db3VudCwgcmVzdWx0KTsKICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KICAgIGNvbnN0IGZhY3RvciA9IEp1bGlhbkRhdGVfZGVmYXVsdC5zZWNvbmRzRGlmZmVyZW5jZShkYXRlLCBiZWZvcmVEYXRlKSAvIEp1bGlhbkRhdGVfZGVmYXVsdC5zZWNvbmRzRGlmZmVyZW5jZShhZnRlckRhdGUsIGJlZm9yZURhdGUpOwogICAgY29uc3Qgc3RhcnRCZWZvcmUgPSBiZWZvcmUgKiBjb2x1bW5Db3VudDsKICAgIGNvbnN0IHN0YXJ0QWZ0ZXIgPSBhZnRlciAqIGNvbHVtbkNvdW50OwogICAgbGV0IGJlZm9yZVV0MU1pbnVzVXRjID0gc2FtcGxlc1tzdGFydEJlZm9yZSArIGVvcC5fdXQxTWludXNVdGNTZWNvbmRzQ29sdW1uXTsKICAgIGxldCBhZnRlclV0MU1pbnVzVXRjID0gc2FtcGxlc1tzdGFydEFmdGVyICsgZW9wLl91dDFNaW51c1V0Y1NlY29uZHNDb2x1bW5dOwogICAgY29uc3Qgb2Zmc2V0RGlmZmVyZW5jZSA9IGFmdGVyVXQxTWludXNVdGMgLSBiZWZvcmVVdDFNaW51c1V0YzsKICAgIGlmIChvZmZzZXREaWZmZXJlbmNlID4gMC41IHx8IG9mZnNldERpZmZlcmVuY2UgPCAtMC41KSB7CiAgICAgIGNvbnN0IGJlZm9yZVRhaU1pbnVzVXRjID0gc2FtcGxlc1tzdGFydEJlZm9yZSArIGVvcC5fdGFpTWludXNVdGNTZWNvbmRzQ29sdW1uXTsKICAgICAgY29uc3QgYWZ0ZXJUYWlNaW51c1V0YyA9IHNhbXBsZXNbc3RhcnRBZnRlciArIGVvcC5fdGFpTWludXNVdGNTZWNvbmRzQ29sdW1uXTsKICAgICAgaWYgKGJlZm9yZVRhaU1pbnVzVXRjICE9PSBhZnRlclRhaU1pbnVzVXRjKSB7CiAgICAgICAgaWYgKGFmdGVyRGF0ZS5lcXVhbHMoZGF0ZSkpIHsKICAgICAgICAgIGJlZm9yZVV0MU1pbnVzVXRjID0gYWZ0ZXJVdDFNaW51c1V0YzsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgYWZ0ZXJVdDFNaW51c1V0YyAtPSBhZnRlclRhaU1pbnVzVXRjIC0gYmVmb3JlVGFpTWludXNVdGM7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXN1bHQueFBvbGVXYW5kZXIgPSBsaW5lYXJJbnRlcnAoCiAgICAgIGZhY3RvciwKICAgICAgc2FtcGxlc1tzdGFydEJlZm9yZSArIGVvcC5feFBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uXSwKICAgICAgc2FtcGxlc1tzdGFydEFmdGVyICsgZW9wLl94UG9sZVdhbmRlclJhZGlhbnNDb2x1bW5dCiAgICApOwogICAgcmVzdWx0LnlQb2xlV2FuZGVyID0gbGluZWFySW50ZXJwKAogICAgICBmYWN0b3IsCiAgICAgIHNhbXBsZXNbc3RhcnRCZWZvcmUgKyBlb3AuX3lQb2xlV2FuZGVyUmFkaWFuc0NvbHVtbl0sCiAgICAgIHNhbXBsZXNbc3RhcnRBZnRlciArIGVvcC5feVBvbGVXYW5kZXJSYWRpYW5zQ29sdW1uXQogICAgKTsKICAgIHJlc3VsdC54UG9sZU9mZnNldCA9IGxpbmVhckludGVycCgKICAgICAgZmFjdG9yLAogICAgICBzYW1wbGVzW3N0YXJ0QmVmb3JlICsgZW9wLl94Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW5dLAogICAgICBzYW1wbGVzW3N0YXJ0QWZ0ZXIgKyBlb3AuX3hDZWxlc3RpYWxQb2xlT2Zmc2V0UmFkaWFuc0NvbHVtbl0KICAgICk7CiAgICByZXN1bHQueVBvbGVPZmZzZXQgPSBsaW5lYXJJbnRlcnAoCiAgICAgIGZhY3RvciwKICAgICAgc2FtcGxlc1tzdGFydEJlZm9yZSArIGVvcC5feUNlbGVzdGlhbFBvbGVPZmZzZXRSYWRpYW5zQ29sdW1uXSwKICAgICAgc2FtcGxlc1tzdGFydEFmdGVyICsgZW9wLl95Q2VsZXN0aWFsUG9sZU9mZnNldFJhZGlhbnNDb2x1bW5dCiAgICApOwogICAgcmVzdWx0LnV0MU1pbnVzVXRjID0gbGluZWFySW50ZXJwKAogICAgICBmYWN0b3IsCiAgICAgIGJlZm9yZVV0MU1pbnVzVXRjLAogICAgICBhZnRlclV0MU1pbnVzVXRjCiAgICApOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgdmFyIEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzX2RlZmF1bHQ7CiAgdmFyIGluaXRfRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnMgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0VhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzLmpzIigpIHsKICAgICAgaW5pdF9iaW5hcnlTZWFyY2goKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVyc1NhbXBsZSgpOwogICAgICBpbml0X0p1bGlhbkRhdGUoKTsKICAgICAgaW5pdF9MZWFwU2Vjb25kKCk7CiAgICAgIGluaXRfUmVzb3VyY2UoKTsKICAgICAgaW5pdF9SdW50aW1lRXJyb3IoKTsKICAgICAgaW5pdF9UaW1lQ29uc3RhbnRzKCk7CiAgICAgIGluaXRfVGltZVN0YW5kYXJkKCk7CiAgICAgIEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzLmZyb21VcmwgPSBhc3luYyBmdW5jdGlvbih1cmwsIG9wdGlvbnMpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInVybCIsIHVybCk7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHJlc291cmNlID0gUmVzb3VyY2VfZGVmYXVsdC5jcmVhdGVJZk5lZWRlZCh1cmwpOwogICAgICAgIGxldCBlb3BEYXRhOwogICAgICAgIHRyeSB7CiAgICAgICAgICBlb3BEYXRhID0gYXdhaXQgcmVzb3VyY2UuZmV0Y2hKc29uKCk7CiAgICAgICAgfSBjYXRjaCAoZTIpIHsKICAgICAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgYEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIHJldHJpZXZpbmcgdGhlIEVPUCBkYXRhIGZyb20gdGhlIFVSTCAke3Jlc291cmNlLnVybH0uYAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBFYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVycyh7CiAgICAgICAgICBhZGROZXdMZWFwU2Vjb25kczogb3B0aW9ucy5hZGROZXdMZWFwU2Vjb25kcywKICAgICAgICAgIGRhdGE6IGVvcERhdGEKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnMuTk9ORSA9IE9iamVjdC5mcmVlemUoewogICAgICAgIGNvbXB1dGU6IGZ1bmN0aW9uKGRhdGUsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNTYW1wbGVfZGVmYXVsdCgwLCAwLCAwLCAwLCAwKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC54UG9sZVdhbmRlciA9IDA7CiAgICAgICAgICAgIHJlc3VsdC55UG9sZVdhbmRlciA9IDA7CiAgICAgICAgICAgIHJlc3VsdC54UG9sZU9mZnNldCA9IDA7CiAgICAgICAgICAgIHJlc3VsdC55UG9sZU9mZnNldCA9IDA7CiAgICAgICAgICAgIHJlc3VsdC51dDFNaW51c1V0YyA9IDA7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgfSk7CiAgICAgIEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzLnByb3RvdHlwZS5jb21wdXRlID0gZnVuY3Rpb24oZGF0ZSwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodGhpcy5fc2FtcGxlcykpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBFYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVyc1NhbXBsZV9kZWZhdWx0KDAsIDAsIDAsIDAsIDApOwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5fc2FtcGxlcy5sZW5ndGggPT09IDApIHsKICAgICAgICAgIHJlc3VsdC54UG9sZVdhbmRlciA9IDA7CiAgICAgICAgICByZXN1bHQueVBvbGVXYW5kZXIgPSAwOwogICAgICAgICAgcmVzdWx0LnhQb2xlT2Zmc2V0ID0gMDsKICAgICAgICAgIHJlc3VsdC55UG9sZU9mZnNldCA9IDA7CiAgICAgICAgICByZXN1bHQudXQxTWludXNVdGMgPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgY29uc3QgZGF0ZXMgPSB0aGlzLl9kYXRlczsKICAgICAgICBjb25zdCBsYXN0SW5kZXggPSB0aGlzLl9sYXN0SW5kZXg7CiAgICAgICAgbGV0IGJlZm9yZTsKICAgICAgICBsZXQgYWZ0ZXI7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChsYXN0SW5kZXgpKSB7CiAgICAgICAgICBjb25zdCBwcmV2aW91c0luZGV4RGF0ZSA9IGRhdGVzW2xhc3RJbmRleF07CiAgICAgICAgICBjb25zdCBuZXh0SW5kZXhEYXRlID0gZGF0ZXNbbGFzdEluZGV4ICsgMV07CiAgICAgICAgICBjb25zdCBpc0FmdGVyUHJldmlvdXMgPSBKdWxpYW5EYXRlX2RlZmF1bHQubGVzc1RoYW5PckVxdWFscygKICAgICAgICAgICAgcHJldmlvdXNJbmRleERhdGUsCiAgICAgICAgICAgIGRhdGUKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBpc0FmdGVyTGFzdFNhbXBsZSA9ICFkZWZpbmVkX2RlZmF1bHQobmV4dEluZGV4RGF0ZSk7CiAgICAgICAgICBjb25zdCBpc0JlZm9yZU5leHQgPSBpc0FmdGVyTGFzdFNhbXBsZSB8fCBKdWxpYW5EYXRlX2RlZmF1bHQuZ3JlYXRlclRoYW5PckVxdWFscyhuZXh0SW5kZXhEYXRlLCBkYXRlKTsKICAgICAgICAgIGlmIChpc0FmdGVyUHJldmlvdXMgJiYgaXNCZWZvcmVOZXh0KSB7CiAgICAgICAgICAgIGJlZm9yZSA9IGxhc3RJbmRleDsKICAgICAgICAgICAgaWYgKCFpc0FmdGVyTGFzdFNhbXBsZSAmJiBuZXh0SW5kZXhEYXRlLmVxdWFscyhkYXRlKSkgewogICAgICAgICAgICAgICsrYmVmb3JlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGFmdGVyID0gYmVmb3JlICsgMTsKICAgICAgICAgICAgaW50ZXJwb2xhdGUodGhpcywgZGF0ZXMsIHRoaXMuX3NhbXBsZXMsIGRhdGUsIGJlZm9yZSwgYWZ0ZXIsIHJlc3VsdCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGxldCBpbmRleCA9IGJpbmFyeVNlYXJjaF9kZWZhdWx0KGRhdGVzLCBkYXRlLCBKdWxpYW5EYXRlX2RlZmF1bHQuY29tcGFyZSwgdGhpcy5fZGF0ZUNvbHVtbik7CiAgICAgICAgaWYgKGluZGV4ID49IDApIHsKICAgICAgICAgIGlmIChpbmRleCA8IGRhdGVzLmxlbmd0aCAtIDEgJiYgZGF0ZXNbaW5kZXggKyAxXS5lcXVhbHMoZGF0ZSkpIHsKICAgICAgICAgICAgKytpbmRleDsKICAgICAgICAgIH0KICAgICAgICAgIGJlZm9yZSA9IGluZGV4OwogICAgICAgICAgYWZ0ZXIgPSBpbmRleDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgYWZ0ZXIgPSB+aW5kZXg7CiAgICAgICAgICBiZWZvcmUgPSBhZnRlciAtIDE7CiAgICAgICAgICBpZiAoYmVmb3JlIDwgMCkgewogICAgICAgICAgICBiZWZvcmUgPSAwOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB0aGlzLl9sYXN0SW5kZXggPSBiZWZvcmU7CiAgICAgICAgaW50ZXJwb2xhdGUodGhpcywgZGF0ZXMsIHRoaXMuX3NhbXBsZXMsIGRhdGUsIGJlZm9yZSwgYWZ0ZXIsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNfZGVmYXVsdCA9IEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSGVhZGluZ1BpdGNoUm9sbC5qcwogIGZ1bmN0aW9uIEhlYWRpbmdQaXRjaFJvbGwoaGVhZGluZywgcGl0Y2gsIHJvbGwpIHsKICAgIHRoaXMuaGVhZGluZyA9IGhlYWRpbmcgPz8gMDsKICAgIHRoaXMucGl0Y2ggPSBwaXRjaCA/PyAwOwogICAgdGhpcy5yb2xsID0gcm9sbCA/PyAwOwogIH0KICB2YXIgSGVhZGluZ1BpdGNoUm9sbF9kZWZhdWx0OwogIHZhciBpbml0X0hlYWRpbmdQaXRjaFJvbGwgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0hlYWRpbmdQaXRjaFJvbGwuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbC5mcm9tUXVhdGVybmlvbiA9IGZ1bmN0aW9uKHF1YXRlcm5pb24sIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHF1YXRlcm5pb24pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicXVhdGVybmlvbiBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgSGVhZGluZ1BpdGNoUm9sbCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCB0ZXN0ID0gMiAqIChxdWF0ZXJuaW9uLncgKiBxdWF0ZXJuaW9uLnkgLSBxdWF0ZXJuaW9uLnogKiBxdWF0ZXJuaW9uLngpOwogICAgICAgIGNvbnN0IGRlbm9taW5hdG9yUm9sbCA9IDEgLSAyICogKHF1YXRlcm5pb24ueCAqIHF1YXRlcm5pb24ueCArIHF1YXRlcm5pb24ueSAqIHF1YXRlcm5pb24ueSk7CiAgICAgICAgY29uc3QgbnVtZXJhdG9yUm9sbCA9IDIgKiAocXVhdGVybmlvbi53ICogcXVhdGVybmlvbi54ICsgcXVhdGVybmlvbi55ICogcXVhdGVybmlvbi56KTsKICAgICAgICBjb25zdCBkZW5vbWluYXRvckhlYWRpbmcgPSAxIC0gMiAqIChxdWF0ZXJuaW9uLnkgKiBxdWF0ZXJuaW9uLnkgKyBxdWF0ZXJuaW9uLnogKiBxdWF0ZXJuaW9uLnopOwogICAgICAgIGNvbnN0IG51bWVyYXRvckhlYWRpbmcgPSAyICogKHF1YXRlcm5pb24udyAqIHF1YXRlcm5pb24ueiArIHF1YXRlcm5pb24ueCAqIHF1YXRlcm5pb24ueSk7CiAgICAgICAgcmVzdWx0LmhlYWRpbmcgPSAtTWF0aC5hdGFuMihudW1lcmF0b3JIZWFkaW5nLCBkZW5vbWluYXRvckhlYWRpbmcpOwogICAgICAgIHJlc3VsdC5yb2xsID0gTWF0aC5hdGFuMihudW1lcmF0b3JSb2xsLCBkZW5vbWluYXRvclJvbGwpOwogICAgICAgIHJlc3VsdC5waXRjaCA9IC1NYXRoX2RlZmF1bHQuYXNpbkNsYW1wZWQodGVzdCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbC5mcm9tRGVncmVlcyA9IGZ1bmN0aW9uKGhlYWRpbmcsIHBpdGNoLCByb2xsLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChoZWFkaW5nKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImhlYWRpbmcgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocGl0Y2gpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicGl0Y2ggaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocm9sbCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyb2xsIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBIZWFkaW5nUGl0Y2hSb2xsKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5oZWFkaW5nID0gaGVhZGluZyAqIE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICAgICAgcmVzdWx0LnBpdGNoID0gcGl0Y2ggKiBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgICAgIHJlc3VsdC5yb2xsID0gcm9sbCAqIE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbC5jbG9uZSA9IGZ1bmN0aW9uKGhlYWRpbmdQaXRjaFJvbGwsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGhlYWRpbmdQaXRjaFJvbGwpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IEhlYWRpbmdQaXRjaFJvbGwoCiAgICAgICAgICAgIGhlYWRpbmdQaXRjaFJvbGwuaGVhZGluZywKICAgICAgICAgICAgaGVhZGluZ1BpdGNoUm9sbC5waXRjaCwKICAgICAgICAgICAgaGVhZGluZ1BpdGNoUm9sbC5yb2xsCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXN1bHQuaGVhZGluZyA9IGhlYWRpbmdQaXRjaFJvbGwuaGVhZGluZzsKICAgICAgICByZXN1bHQucGl0Y2ggPSBoZWFkaW5nUGl0Y2hSb2xsLnBpdGNoOwogICAgICAgIHJlc3VsdC5yb2xsID0gaGVhZGluZ1BpdGNoUm9sbC5yb2xsOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEhlYWRpbmdQaXRjaFJvbGwuZXF1YWxzID0gZnVuY3Rpb24obGVmdCwgcmlnaHQpIHsKICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgbGVmdC5oZWFkaW5nID09PSByaWdodC5oZWFkaW5nICYmIGxlZnQucGl0Y2ggPT09IHJpZ2h0LnBpdGNoICYmIGxlZnQucm9sbCA9PT0gcmlnaHQucm9sbDsKICAgICAgfTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbC5lcXVhbHNFcHNpbG9uID0gZnVuY3Rpb24obGVmdCwgcmlnaHQsIHJlbGF0aXZlRXBzaWxvbiwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgbGVmdC5oZWFkaW5nLAogICAgICAgICAgcmlnaHQuaGVhZGluZywKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBsZWZ0LnBpdGNoLAogICAgICAgICAgcmlnaHQucGl0Y2gsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgbGVmdC5yb2xsLAogICAgICAgICAgcmlnaHQucm9sbCwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICk7CiAgICAgIH07CiAgICAgIEhlYWRpbmdQaXRjaFJvbGwucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIEhlYWRpbmdQaXRjaFJvbGwuY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgfTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbC5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24ocmlnaHQpIHsKICAgICAgICByZXR1cm4gSGVhZGluZ1BpdGNoUm9sbC5lcXVhbHModGhpcywgcmlnaHQpOwogICAgICB9OwogICAgICBIZWFkaW5nUGl0Y2hSb2xsLnByb3RvdHlwZS5lcXVhbHNFcHNpbG9uID0gZnVuY3Rpb24ocmlnaHQsIHJlbGF0aXZlRXBzaWxvbiwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgcmV0dXJuIEhlYWRpbmdQaXRjaFJvbGwuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMsCiAgICAgICAgICByaWdodCwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICk7CiAgICAgIH07CiAgICAgIEhlYWRpbmdQaXRjaFJvbGwucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIGAoJHt0aGlzLmhlYWRpbmd9LCAke3RoaXMucGl0Y2h9LCAke3RoaXMucm9sbH0pYDsKICAgICAgfTsKICAgICAgSGVhZGluZ1BpdGNoUm9sbF9kZWZhdWx0ID0gSGVhZGluZ1BpdGNoUm9sbDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2J1aWxkTW9kdWxlVXJsLmpzCiAgZnVuY3Rpb24gZ2V0QmFzZVVybEZyb21DZXNpdW1TY3JpcHQoKSB7CiAgICBjb25zdCBzY3JpcHRzID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoInNjcmlwdCIpOwogICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSBzY3JpcHRzLmxlbmd0aDsgaTIgPCBsZW47ICsraTIpIHsKICAgICAgY29uc3Qgc3JjID0gc2NyaXB0c1tpMl0uZ2V0QXR0cmlidXRlKCJzcmMiKTsKICAgICAgY29uc3QgcmVzdWx0ID0gY2VzaXVtU2NyaXB0UmVnZXguZXhlYyhzcmMpOwogICAgICBpZiAocmVzdWx0ICE9PSBudWxsKSB7CiAgICAgICAgcmV0dXJuIHJlc3VsdFsxXTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHZvaWQgMDsKICB9CiAgZnVuY3Rpb24gdHJ5TWFrZUFic29sdXRlKHVybCkgewogICAgaWYgKHR5cGVvZiBkb2N1bWVudCA9PT0gInVuZGVmaW5lZCIpIHsKICAgICAgcmV0dXJuIHVybDsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGEyKSkgewogICAgICBhMiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKTsKICAgIH0KICAgIGEyLmhyZWYgPSB1cmw7CiAgICByZXR1cm4gYTIuaHJlZjsKICB9CiAgZnVuY3Rpb24gZ2V0Q2VzaXVtQmFzZVVybCgpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoYmFzZVJlc291cmNlKSkgewogICAgICByZXR1cm4gYmFzZVJlc291cmNlOwogICAgfQogICAgbGV0IGJhc2VVcmxTdHJpbmc7CiAgICBpZiAodHlwZW9mIENFU0lVTV9CQVNFX1VSTCAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgYmFzZVVybFN0cmluZyA9IENFU0lVTV9CQVNFX1VSTDsKICAgIH0gZWxzZSBpZiAoZGVmaW5lZF9kZWZhdWx0KGltcG9ydF9tZXRhPy51cmwpKSB7CiAgICAgIGJhc2VVcmxTdHJpbmcgPSBnZXRBYnNvbHV0ZVVyaV9kZWZhdWx0KCIuIiwgaW1wb3J0X21ldGEudXJsKTsKICAgIH0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gIm9iamVjdCIgJiYgZGVmaW5lZF9kZWZhdWx0KGRlZmluZS5hbWQpICYmICFkZWZpbmUuYW1kLnRvVXJsVW5kZWZpbmVkICYmIGRlZmluZWRfZGVmYXVsdChfX3JlcXVpcmUudG9VcmwpKSB7CiAgICAgIGJhc2VVcmxTdHJpbmcgPSBnZXRBYnNvbHV0ZVVyaV9kZWZhdWx0KAogICAgICAgICIuLiIsCiAgICAgICAgYnVpbGRNb2R1bGVVcmwoIkNvcmUvYnVpbGRNb2R1bGVVcmwuanMiKQogICAgICApOwogICAgfSBlbHNlIHsKICAgICAgYmFzZVVybFN0cmluZyA9IGdldEJhc2VVcmxGcm9tQ2VzaXVtU2NyaXB0KCk7CiAgICB9CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChiYXNlVXJsU3RyaW5nKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiVW5hYmxlIHRvIGRldGVybWluZSBDZXNpdW0gYmFzZSBVUkwgYXV0b21hdGljYWxseSwgdHJ5IGRlZmluaW5nIGEgZ2xvYmFsIHZhcmlhYmxlIGNhbGxlZCBDRVNJVU1fQkFTRV9VUkwuIgogICAgICApOwogICAgfQogICAgYmFzZVJlc291cmNlID0gbmV3IFJlc291cmNlX2RlZmF1bHQoewogICAgICB1cmw6IHRyeU1ha2VBYnNvbHV0ZShiYXNlVXJsU3RyaW5nKQogICAgfSk7CiAgICBiYXNlUmVzb3VyY2UuYXBwZW5kRm9yd2FyZFNsYXNoKCk7CiAgICByZXR1cm4gYmFzZVJlc291cmNlOwogIH0KICBmdW5jdGlvbiBidWlsZE1vZHVsZVVybEZyb21SZXF1aXJlVG9VcmwobW9kdWxlSUQpIHsKICAgIHJldHVybiB0cnlNYWtlQWJzb2x1dGUoX19yZXF1aXJlLnRvVXJsKGAuLi8ke21vZHVsZUlEfWApKTsKICB9CiAgZnVuY3Rpb24gYnVpbGRNb2R1bGVVcmxGcm9tQmFzZVVybChtb2R1bGVJRCkgewogICAgY29uc3QgcmVzb3VyY2UgPSBnZXRDZXNpdW1CYXNlVXJsKCkuZ2V0RGVyaXZlZFJlc291cmNlKHsKICAgICAgdXJsOiBtb2R1bGVJRAogICAgfSk7CiAgICByZXR1cm4gcmVzb3VyY2UudXJsOwogIH0KICBmdW5jdGlvbiBidWlsZE1vZHVsZVVybChyZWxhdGl2ZVVybCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW1wbGVtZW50YXRpb24pKSB7CiAgICAgIGlmICh0eXBlb2YgZGVmaW5lID09PSAib2JqZWN0IiAmJiBkZWZpbmVkX2RlZmF1bHQoZGVmaW5lLmFtZCkgJiYgIWRlZmluZS5hbWQudG9VcmxVbmRlZmluZWQgJiYgZGVmaW5lZF9kZWZhdWx0KF9fcmVxdWlyZS50b1VybCkpIHsKICAgICAgICBpbXBsZW1lbnRhdGlvbiA9IGJ1aWxkTW9kdWxlVXJsRnJvbVJlcXVpcmVUb1VybDsKICAgICAgfSBlbHNlIHsKICAgICAgICBpbXBsZW1lbnRhdGlvbiA9IGJ1aWxkTW9kdWxlVXJsRnJvbUJhc2VVcmw7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IHVybCA9IGltcGxlbWVudGF0aW9uKHJlbGF0aXZlVXJsKTsKICAgIHJldHVybiB1cmw7CiAgfQogIHZhciBpbXBvcnRfbWV0YSwgY2VzaXVtU2NyaXB0UmVnZXgsIGEyLCBiYXNlUmVzb3VyY2UsIGltcGxlbWVudGF0aW9uLCBidWlsZE1vZHVsZVVybF9kZWZhdWx0OwogIHZhciBpbml0X2J1aWxkTW9kdWxlVXJsID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9idWlsZE1vZHVsZVVybC5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfZ2V0QWJzb2x1dGVVcmkoKTsKICAgICAgaW5pdF9SZXNvdXJjZSgpOwogICAgICBpbXBvcnRfbWV0YSA9IHt9OwogICAgICBjZXNpdW1TY3JpcHRSZWdleCA9IC8oKD86LipcLyl8XilDZXNpdW1cLmpzKD86XD98XCN8JCkvOwogICAgICBidWlsZE1vZHVsZVVybC5fY2VzaXVtU2NyaXB0UmVnZXggPSBjZXNpdW1TY3JpcHRSZWdleDsKICAgICAgYnVpbGRNb2R1bGVVcmwuX2J1aWxkTW9kdWxlVXJsRnJvbUJhc2VVcmwgPSBidWlsZE1vZHVsZVVybEZyb21CYXNlVXJsOwogICAgICBidWlsZE1vZHVsZVVybC5fY2xlYXJCYXNlUmVzb3VyY2UgPSBmdW5jdGlvbigpIHsKICAgICAgICBiYXNlUmVzb3VyY2UgPSB2b2lkIDA7CiAgICAgIH07CiAgICAgIGJ1aWxkTW9kdWxlVXJsLnNldEJhc2VVcmwgPSBmdW5jdGlvbih2YWx1ZSkgewogICAgICAgIGJhc2VSZXNvdXJjZSA9IFJlc291cmNlX2RlZmF1bHQuREVGQVVMVC5nZXREZXJpdmVkUmVzb3VyY2UoewogICAgICAgICAgdXJsOiB2YWx1ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBidWlsZE1vZHVsZVVybC5nZXRDZXNpdW1CYXNlVXJsID0gZ2V0Q2VzaXVtQmFzZVVybDsKICAgICAgYnVpbGRNb2R1bGVVcmxfZGVmYXVsdCA9IGJ1aWxkTW9kdWxlVXJsOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSWF1MjAwNlh5c1NhbXBsZS5qcwogIGZ1bmN0aW9uIElhdTIwMDZYeXNTYW1wbGUoeDIsIHkyLCBzMikgewogICAgdGhpcy54ID0geDI7CiAgICB0aGlzLnkgPSB5MjsKICAgIHRoaXMucyA9IHMyOwogIH0KICB2YXIgSWF1MjAwNlh5c1NhbXBsZV9kZWZhdWx0OwogIHZhciBpbml0X0lhdTIwMDZYeXNTYW1wbGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0lhdTIwMDZYeXNTYW1wbGUuanMiKCkgewogICAgICBJYXUyMDA2WHlzU2FtcGxlX2RlZmF1bHQgPSBJYXUyMDA2WHlzU2FtcGxlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSWF1MjAwNlh5c0RhdGEuanMKICBmdW5jdGlvbiBJYXUyMDA2WHlzRGF0YShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICB0aGlzLl94eXNGaWxlVXJsVGVtcGxhdGUgPSBSZXNvdXJjZV9kZWZhdWx0LmNyZWF0ZUlmTmVlZGVkKAogICAgICBvcHRpb25zLnh5c0ZpbGVVcmxUZW1wbGF0ZQogICAgKTsKICAgIHRoaXMuX2ludGVycG9sYXRpb25PcmRlciA9IG9wdGlvbnMuaW50ZXJwb2xhdGlvbk9yZGVyID8/IDk7CiAgICB0aGlzLl9zYW1wbGVaZXJvSnVsaWFuRXBoZW1lcmlzRGF0ZSA9IG9wdGlvbnMuc2FtcGxlWmVyb0p1bGlhbkVwaGVtZXJpc0RhdGUgPz8gMjQ0MjM5NjVlLTE7CiAgICB0aGlzLl9zYW1wbGVaZXJvRGF0ZVRUID0gbmV3IEp1bGlhbkRhdGVfZGVmYXVsdCgKICAgICAgdGhpcy5fc2FtcGxlWmVyb0p1bGlhbkVwaGVtZXJpc0RhdGUsCiAgICAgIDAsCiAgICAgIFRpbWVTdGFuZGFyZF9kZWZhdWx0LlRBSQogICAgKTsKICAgIHRoaXMuX3N0ZXBTaXplRGF5cyA9IG9wdGlvbnMuc3RlcFNpemVEYXlzID8/IDE7CiAgICB0aGlzLl9zYW1wbGVzUGVyWHlzRmlsZSA9IG9wdGlvbnMuc2FtcGxlc1Blclh5c0ZpbGUgPz8gMWUzOwogICAgdGhpcy5fdG90YWxTYW1wbGVzID0gb3B0aW9ucy50b3RhbFNhbXBsZXMgPz8gMjc0MjY7CiAgICB0aGlzLl9zYW1wbGVzID0gbmV3IEFycmF5KHRoaXMuX3RvdGFsU2FtcGxlcyAqIDMpOwogICAgdGhpcy5fY2h1bmtEb3dubG9hZHNJblByb2dyZXNzID0gW107CiAgICBjb25zdCBvcmRlciA9IHRoaXMuX2ludGVycG9sYXRpb25PcmRlcjsKICAgIGNvbnN0IGRlbm9tID0gdGhpcy5fZGVub21pbmF0b3JzID0gbmV3IEFycmF5KG9yZGVyICsgMSk7CiAgICBjb25zdCB4VGFibGUgPSB0aGlzLl94VGFibGUgPSBuZXcgQXJyYXkob3JkZXIgKyAxKTsKICAgIGNvbnN0IHN0ZXBOID0gTWF0aC5wb3codGhpcy5fc3RlcFNpemVEYXlzLCBvcmRlcik7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDw9IG9yZGVyOyArK2kyKSB7CiAgICAgIGRlbm9tW2kyXSA9IHN0ZXBOOwogICAgICB4VGFibGVbaTJdID0gaTIgKiB0aGlzLl9zdGVwU2l6ZURheXM7CiAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPD0gb3JkZXI7ICsrajIpIHsKICAgICAgICBpZiAoajIgIT09IGkyKSB7CiAgICAgICAgICBkZW5vbVtpMl0gKj0gaTIgLSBqMjsKICAgICAgICB9CiAgICAgIH0KICAgICAgZGVub21baTJdID0gMSAvIGRlbm9tW2kyXTsKICAgIH0KICAgIHRoaXMuX3dvcmsgPSBuZXcgQXJyYXkob3JkZXIgKyAxKTsKICAgIHRoaXMuX2NvZWYgPSBuZXcgQXJyYXkob3JkZXIgKyAxKTsKICB9CiAgZnVuY3Rpb24gZ2V0RGF5c1NpbmNlRXBvY2goeHlzLCBkYXlUVCwgc2Vjb25kVFQpIHsKICAgIGNvbnN0IGRhdGVUVCA9IGp1bGlhbkRhdGVTY3JhdGNoOwogICAgZGF0ZVRULmRheU51bWJlciA9IGRheVRUOwogICAgZGF0ZVRULnNlY29uZHNPZkRheSA9IHNlY29uZFRUOwogICAgcmV0dXJuIEp1bGlhbkRhdGVfZGVmYXVsdC5kYXlzRGlmZmVyZW5jZShkYXRlVFQsIHh5cy5fc2FtcGxlWmVyb0RhdGVUVCk7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RYeXNDaHVua0pzb24ocmVzb3VyY2UsIGluZGV4LCB4eXNEYXRhKSB7CiAgICB0cnkgewogICAgICBjb25zdCBjaHVuayA9IGF3YWl0IHJlc291cmNlLmZldGNoSnNvbigpOwogICAgICB4eXNEYXRhLl91cGRhdGVDaHVua0RhdGEoaW5kZXgsIGNodW5rKTsKICAgIH0gY2F0Y2ggKGUyKSB7CiAgICB9CiAgfQogIGZ1bmN0aW9uIHJlcXVlc3RYeXNDaHVuayh4eXNEYXRhLCBjaHVua0luZGV4KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHh5c0RhdGEuX2NodW5rRG93bmxvYWRzSW5Qcm9ncmVzc1tjaHVua0luZGV4XSkpIHsKICAgICAgcmV0dXJuIHh5c0RhdGEuX2NodW5rRG93bmxvYWRzSW5Qcm9ncmVzc1tjaHVua0luZGV4XTsKICAgIH0KICAgIGxldCBjaHVua1VybDsKICAgIGNvbnN0IHh5c0ZpbGVVcmxUZW1wbGF0ZSA9IHh5c0RhdGEuX3h5c0ZpbGVVcmxUZW1wbGF0ZTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoeHlzRmlsZVVybFRlbXBsYXRlKSkgewogICAgICBjaHVua1VybCA9IHh5c0ZpbGVVcmxUZW1wbGF0ZS5nZXREZXJpdmVkUmVzb3VyY2UoewogICAgICAgIHRlbXBsYXRlVmFsdWVzOiB7CiAgICAgICAgICAwOiBjaHVua0luZGV4CiAgICAgICAgfQogICAgICB9KTsKICAgIH0gZWxzZSB7CiAgICAgIGNodW5rVXJsID0gbmV3IFJlc291cmNlX2RlZmF1bHQoewogICAgICAgIHVybDogYnVpbGRNb2R1bGVVcmxfZGVmYXVsdChgQXNzZXRzL0lBVTIwMDZfWFlTL0lBVTIwMDZfWFlTXyR7Y2h1bmtJbmRleH0uanNvbmApCiAgICAgIH0pOwogICAgfQogICAgY29uc3QgcHJvbWlzZSA9IHJlcXVlc3RYeXNDaHVua0pzb24oY2h1bmtVcmwsIGNodW5rSW5kZXgsIHh5c0RhdGEpOwogICAgeHlzRGF0YS5fY2h1bmtEb3dubG9hZHNJblByb2dyZXNzW2NodW5rSW5kZXhdID0gcHJvbWlzZTsKICAgIHJldHVybiBwcm9taXNlOwogIH0KICB2YXIganVsaWFuRGF0ZVNjcmF0Y2gsIElhdTIwMDZYeXNEYXRhX2RlZmF1bHQ7CiAgdmFyIGluaXRfSWF1MjAwNlh5c0RhdGEgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0lhdTIwMDZYeXNEYXRhLmpzIigpIHsKICAgICAgaW5pdF9idWlsZE1vZHVsZVVybCgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9JYXUyMDA2WHlzU2FtcGxlKCk7CiAgICAgIGluaXRfSnVsaWFuRGF0ZSgpOwogICAgICBpbml0X1Jlc291cmNlKCk7CiAgICAgIGluaXRfVGltZVN0YW5kYXJkKCk7CiAgICAgIGp1bGlhbkRhdGVTY3JhdGNoID0gbmV3IEp1bGlhbkRhdGVfZGVmYXVsdCgwLCAwLCBUaW1lU3RhbmRhcmRfZGVmYXVsdC5UQUkpOwogICAgICBJYXUyMDA2WHlzRGF0YS5wcm90b3R5cGUucHJlbG9hZCA9IGZ1bmN0aW9uKHN0YXJ0RGF5VFQsIHN0YXJ0U2Vjb25kVFQsIHN0b3BEYXlUVCwgc3RvcFNlY29uZFRUKSB7CiAgICAgICAgY29uc3Qgc3RhcnREYXlzU2luY2VFcG9jaCA9IGdldERheXNTaW5jZUVwb2NoKAogICAgICAgICAgdGhpcywKICAgICAgICAgIHN0YXJ0RGF5VFQsCiAgICAgICAgICBzdGFydFNlY29uZFRUCiAgICAgICAgKTsKICAgICAgICBjb25zdCBzdG9wRGF5c1NpbmNlRXBvY2ggPSBnZXREYXlzU2luY2VFcG9jaCh0aGlzLCBzdG9wRGF5VFQsIHN0b3BTZWNvbmRUVCk7CiAgICAgICAgbGV0IHN0YXJ0SW5kZXggPSBzdGFydERheXNTaW5jZUVwb2NoIC8gdGhpcy5fc3RlcFNpemVEYXlzIC0gdGhpcy5faW50ZXJwb2xhdGlvbk9yZGVyIC8gMiB8IDA7CiAgICAgICAgaWYgKHN0YXJ0SW5kZXggPCAwKSB7CiAgICAgICAgICBzdGFydEluZGV4ID0gMDsKICAgICAgICB9CiAgICAgICAgbGV0IHN0b3BJbmRleCA9IHN0b3BEYXlzU2luY2VFcG9jaCAvIHRoaXMuX3N0ZXBTaXplRGF5cyAtIHRoaXMuX2ludGVycG9sYXRpb25PcmRlciAvIDIgfCAwICsgdGhpcy5faW50ZXJwb2xhdGlvbk9yZGVyOwogICAgICAgIGlmIChzdG9wSW5kZXggPj0gdGhpcy5fdG90YWxTYW1wbGVzKSB7CiAgICAgICAgICBzdG9wSW5kZXggPSB0aGlzLl90b3RhbFNhbXBsZXMgLSAxOwogICAgICAgIH0KICAgICAgICBjb25zdCBzdGFydENodW5rID0gc3RhcnRJbmRleCAvIHRoaXMuX3NhbXBsZXNQZXJYeXNGaWxlIHwgMDsKICAgICAgICBjb25zdCBzdG9wQ2h1bmsgPSBzdG9wSW5kZXggLyB0aGlzLl9zYW1wbGVzUGVyWHlzRmlsZSB8IDA7CiAgICAgICAgY29uc3QgcHJvbWlzZXMgPSBbXTsKICAgICAgICBmb3IgKGxldCBpMiA9IHN0YXJ0Q2h1bms7IGkyIDw9IHN0b3BDaHVuazsgKytpMikgewogICAgICAgICAgcHJvbWlzZXMucHVzaChyZXF1ZXN0WHlzQ2h1bmsodGhpcywgaTIpKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHByb21pc2VzKTsKICAgICAgfTsKICAgICAgSWF1MjAwNlh5c0RhdGEucHJvdG90eXBlLmNvbXB1dGVYeXNSYWRpYW5zID0gZnVuY3Rpb24oZGF5VFQsIHNlY29uZFRULCByZXN1bHQpIHsKICAgICAgICBjb25zdCBkYXlzU2luY2VFcG9jaCA9IGdldERheXNTaW5jZUVwb2NoKHRoaXMsIGRheVRULCBzZWNvbmRUVCk7CiAgICAgICAgaWYgKGRheXNTaW5jZUVwb2NoIDwgMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgY2VudGVySW5kZXggPSBkYXlzU2luY2VFcG9jaCAvIHRoaXMuX3N0ZXBTaXplRGF5cyB8IDA7CiAgICAgICAgaWYgKGNlbnRlckluZGV4ID49IHRoaXMuX3RvdGFsU2FtcGxlcykgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgZGVncmVlID0gdGhpcy5faW50ZXJwb2xhdGlvbk9yZGVyOwogICAgICAgIGxldCBmaXJzdEluZGV4ID0gY2VudGVySW5kZXggLSAoZGVncmVlIC8gMiB8IDApOwogICAgICAgIGlmIChmaXJzdEluZGV4IDwgMCkgewogICAgICAgICAgZmlyc3RJbmRleCA9IDA7CiAgICAgICAgfQogICAgICAgIGxldCBsYXN0SW5kZXggPSBmaXJzdEluZGV4ICsgZGVncmVlOwogICAgICAgIGlmIChsYXN0SW5kZXggPj0gdGhpcy5fdG90YWxTYW1wbGVzKSB7CiAgICAgICAgICBsYXN0SW5kZXggPSB0aGlzLl90b3RhbFNhbXBsZXMgLSAxOwogICAgICAgICAgZmlyc3RJbmRleCA9IGxhc3RJbmRleCAtIGRlZ3JlZTsKICAgICAgICAgIGlmIChmaXJzdEluZGV4IDwgMCkgewogICAgICAgICAgICBmaXJzdEluZGV4ID0gMDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbGV0IGlzRGF0YU1pc3NpbmcgPSBmYWxzZTsKICAgICAgICBjb25zdCBzYW1wbGVzID0gdGhpcy5fc2FtcGxlczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzYW1wbGVzW2ZpcnN0SW5kZXggKiAzXSkpIHsKICAgICAgICAgIHJlcXVlc3RYeXNDaHVuayh0aGlzLCBmaXJzdEluZGV4IC8gdGhpcy5fc2FtcGxlc1Blclh5c0ZpbGUgfCAwKTsKICAgICAgICAgIGlzRGF0YU1pc3NpbmcgPSB0cnVlOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzYW1wbGVzW2xhc3RJbmRleCAqIDNdKSkgewogICAgICAgICAgcmVxdWVzdFh5c0NodW5rKHRoaXMsIGxhc3RJbmRleCAvIHRoaXMuX3NhbXBsZXNQZXJYeXNGaWxlIHwgMCk7CiAgICAgICAgICBpc0RhdGFNaXNzaW5nID0gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgaWYgKGlzRGF0YU1pc3NpbmcpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBJYXUyMDA2WHlzU2FtcGxlX2RlZmF1bHQoMCwgMCwgMCk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlc3VsdC54ID0gMDsKICAgICAgICAgIHJlc3VsdC55ID0gMDsKICAgICAgICAgIHJlc3VsdC5zID0gMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgeDIgPSBkYXlzU2luY2VFcG9jaCAtIGZpcnN0SW5kZXggKiB0aGlzLl9zdGVwU2l6ZURheXM7CiAgICAgICAgY29uc3Qgd29yayA9IHRoaXMuX3dvcms7CiAgICAgICAgY29uc3QgZGVub20gPSB0aGlzLl9kZW5vbWluYXRvcnM7CiAgICAgICAgY29uc3QgY29lZiA9IHRoaXMuX2NvZWY7CiAgICAgICAgY29uc3QgeFRhYmxlID0gdGhpcy5feFRhYmxlOwogICAgICAgIGxldCBpMiwgajI7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDw9IGRlZ3JlZTsgKytpMikgewogICAgICAgICAgd29ya1tpMl0gPSB4MiAtIHhUYWJsZVtpMl07CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8PSBkZWdyZWU7ICsraTIpIHsKICAgICAgICAgIGNvZWZbaTJdID0gMTsKICAgICAgICAgIGZvciAoajIgPSAwOyBqMiA8PSBkZWdyZWU7ICsrajIpIHsKICAgICAgICAgICAgaWYgKGoyICE9PSBpMikgewogICAgICAgICAgICAgIGNvZWZbaTJdICo9IHdvcmtbajJdOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBjb2VmW2kyXSAqPSBkZW5vbVtpMl07CiAgICAgICAgICBsZXQgc2FtcGxlSW5kZXggPSAoZmlyc3RJbmRleCArIGkyKSAqIDM7CiAgICAgICAgICByZXN1bHQueCArPSBjb2VmW2kyXSAqIHNhbXBsZXNbc2FtcGxlSW5kZXgrK107CiAgICAgICAgICByZXN1bHQueSArPSBjb2VmW2kyXSAqIHNhbXBsZXNbc2FtcGxlSW5kZXgrK107CiAgICAgICAgICByZXN1bHQucyArPSBjb2VmW2kyXSAqIHNhbXBsZXNbc2FtcGxlSW5kZXhdOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBJYXUyMDA2WHlzRGF0YS5wcm90b3R5cGUuX3VwZGF0ZUNodW5rRGF0YSA9IGZ1bmN0aW9uKGluZGV4LCB7IHNhbXBsZXMgfSkgewogICAgICAgIHRoaXMuX2NodW5rRG93bmxvYWRzSW5Qcm9ncmVzc1tpbmRleF0gPSB2b2lkIDA7CiAgICAgICAgY29uc3Qgc2FtcGxlc1BlckZpbGUgPSB0aGlzLl9zYW1wbGVzUGVyWHlzRmlsZTsKICAgICAgICBjb25zdCBzdGFydEluZGV4ID0gaW5kZXggKiBzYW1wbGVzUGVyRmlsZSAqIDM7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHNhbXBsZXMubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICB0aGlzLl9zYW1wbGVzW3N0YXJ0SW5kZXggKyBpMl0gPSBzYW1wbGVzW2kyXTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIElhdTIwMDZYeXNEYXRhX2RlZmF1bHQgPSBJYXUyMDA2WHlzRGF0YTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0Z1bGxzY3JlZW4uanMKICB2YXIgX3N1cHBvcnRzRnVsbHNjcmVlbiwgX25hbWVzLCBGdWxsc2NyZWVuLCBGdWxsc2NyZWVuX2RlZmF1bHQ7CiAgdmFyIGluaXRfRnVsbHNjcmVlbiA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRnVsbHNjcmVlbi5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBfbmFtZXMgPSB7CiAgICAgICAgcmVxdWVzdEZ1bGxzY3JlZW46IHZvaWQgMCwKICAgICAgICBleGl0RnVsbHNjcmVlbjogdm9pZCAwLAogICAgICAgIGZ1bGxzY3JlZW5FbmFibGVkOiB2b2lkIDAsCiAgICAgICAgZnVsbHNjcmVlbkVsZW1lbnQ6IHZvaWQgMCwKICAgICAgICBmdWxsc2NyZWVuY2hhbmdlOiB2b2lkIDAsCiAgICAgICAgZnVsbHNjcmVlbmVycm9yOiB2b2lkIDAKICAgICAgfTsKICAgICAgRnVsbHNjcmVlbiA9IHt9OwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhGdWxsc2NyZWVuLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGVsZW1lbnQgdGhhdCBpcyBjdXJyZW50bHkgZnVsbHNjcmVlbiwgaWYgYW55LiAgVG8gc2ltcGx5IGNoZWNrIGlmIHRoZQogICAgICAgICAqIGJyb3dzZXIgaXMgaW4gZnVsbHNjcmVlbiBtb2RlIG9yIG5vdCwgdXNlIHtAbGluayBGdWxsc2NyZWVuI2Z1bGxzY3JlZW59LgogICAgICAgICAqIEBtZW1iZXJvZiBGdWxsc2NyZWVuCiAgICAgICAgICogQHR5cGUge29iamVjdH0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBlbGVtZW50OiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoIUZ1bGxzY3JlZW4uc3VwcG9ydHNGdWxsc2NyZWVuKCkpIHsKICAgICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBkb2N1bWVudFtfbmFtZXMuZnVsbHNjcmVlbkVsZW1lbnRdOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG5hbWUgb2YgdGhlIGV2ZW50IG9uIHRoZSBkb2N1bWVudCB0aGF0IGlzIGZpcmVkIHdoZW4gZnVsbHNjcmVlbiBpcwogICAgICAgICAqIGVudGVyZWQgb3IgZXhpdGVkLiAgVGhpcyBldmVudCBuYW1lIGlzIGludGVuZGVkIGZvciB1c2Ugd2l0aCBhZGRFdmVudExpc3RlbmVyLgogICAgICAgICAqIEluIHlvdXIgZXZlbnQgaGFuZGxlciwgdG8gZGV0ZXJtaW5lIGlmIHRoZSBicm93c2VyIGlzIGluIGZ1bGxzY3JlZW4gbW9kZSBvciBub3QsCiAgICAgICAgICogdXNlIHtAbGluayBGdWxsc2NyZWVuI2Z1bGxzY3JlZW59LgogICAgICAgICAqIEBtZW1iZXJvZiBGdWxsc2NyZWVuCiAgICAgICAgICogQHR5cGUge3N0cmluZ30KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBjaGFuZ2VFdmVudE5hbWU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGlmICghRnVsbHNjcmVlbi5zdXBwb3J0c0Z1bGxzY3JlZW4oKSkgewogICAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIF9uYW1lcy5mdWxsc2NyZWVuY2hhbmdlOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG5hbWUgb2YgdGhlIGV2ZW50IHRoYXQgaXMgZmlyZWQgd2hlbiBhIGZ1bGxzY3JlZW4gZXJyb3IKICAgICAgICAgKiBvY2N1cnMuICBUaGlzIGV2ZW50IG5hbWUgaXMgaW50ZW5kZWQgZm9yIHVzZSB3aXRoIGFkZEV2ZW50TGlzdGVuZXIuCiAgICAgICAgICogQG1lbWJlcm9mIEZ1bGxzY3JlZW4KICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGVycm9yRXZlbnROYW1lOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoIUZ1bGxzY3JlZW4uc3VwcG9ydHNGdWxsc2NyZWVuKCkpIHsKICAgICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBfbmFtZXMuZnVsbHNjcmVlbmVycm9yOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGJyb3dzZXIgd2lsbCBhbGxvdyBhbiBlbGVtZW50IHRvIGJlIG1hZGUgZnVsbHNjcmVlbiwgb3Igbm90LgogICAgICAgICAqIEZvciBleGFtcGxlLCBieSBkZWZhdWx0LCBpZnJhbWVzIGNhbm5vdCBnbyBmdWxsc2NyZWVuIHVubGVzcyB0aGUgY29udGFpbmluZyBwYWdlCiAgICAgICAgICogYWRkcyBhbiAiYWxsb3dmdWxsc2NyZWVuIiBhdHRyaWJ1dGUgKG9yIHByZWZpeGVkIGVxdWl2YWxlbnQpLgogICAgICAgICAqIEBtZW1iZXJvZiBGdWxsc2NyZWVuCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgZW5hYmxlZDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgaWYgKCFGdWxsc2NyZWVuLnN1cHBvcnRzRnVsbHNjcmVlbigpKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZG9jdW1lbnRbX25hbWVzLmZ1bGxzY3JlZW5FbmFibGVkXTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIERldGVybWluZXMgaWYgdGhlIGJyb3dzZXIgaXMgY3VycmVudGx5IGluIGZ1bGxzY3JlZW4gbW9kZS4KICAgICAgICAgKiBAbWVtYmVyb2YgRnVsbHNjcmVlbgogICAgICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGZ1bGxzY3JlZW46IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGlmICghRnVsbHNjcmVlbi5zdXBwb3J0c0Z1bGxzY3JlZW4oKSkgewogICAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIEZ1bGxzY3JlZW4uZWxlbWVudCAhPT0gbnVsbDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBGdWxsc2NyZWVuLnN1cHBvcnRzRnVsbHNjcmVlbiA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoX3N1cHBvcnRzRnVsbHNjcmVlbikpIHsKICAgICAgICAgIHJldHVybiBfc3VwcG9ydHNGdWxsc2NyZWVuOwogICAgICAgIH0KICAgICAgICBfc3VwcG9ydHNGdWxsc2NyZWVuID0gZmFsc2U7CiAgICAgICAgY29uc3QgYm9keSA9IGRvY3VtZW50LmJvZHk7CiAgICAgICAgaWYgKHR5cGVvZiBib2R5LnJlcXVlc3RGdWxsc2NyZWVuID09PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgICBfbmFtZXMucmVxdWVzdEZ1bGxzY3JlZW4gPSAicmVxdWVzdEZ1bGxzY3JlZW4iOwogICAgICAgICAgX25hbWVzLmV4aXRGdWxsc2NyZWVuID0gImV4aXRGdWxsc2NyZWVuIjsKICAgICAgICAgIF9uYW1lcy5mdWxsc2NyZWVuRW5hYmxlZCA9ICJmdWxsc2NyZWVuRW5hYmxlZCI7CiAgICAgICAgICBfbmFtZXMuZnVsbHNjcmVlbkVsZW1lbnQgPSAiZnVsbHNjcmVlbkVsZW1lbnQiOwogICAgICAgICAgX25hbWVzLmZ1bGxzY3JlZW5jaGFuZ2UgPSAiZnVsbHNjcmVlbmNoYW5nZSI7CiAgICAgICAgICBfbmFtZXMuZnVsbHNjcmVlbmVycm9yID0gImZ1bGxzY3JlZW5lcnJvciI7CiAgICAgICAgICBfc3VwcG9ydHNGdWxsc2NyZWVuID0gdHJ1ZTsKICAgICAgICAgIHJldHVybiBfc3VwcG9ydHNGdWxsc2NyZWVuOwogICAgICAgIH0KICAgICAgICBjb25zdCBwcmVmaXhlcyA9IFsid2Via2l0IiwgIm1veiIsICJvIiwgIm1zIiwgImtodG1sIl07CiAgICAgICAgbGV0IG5hbWU7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSBwcmVmaXhlcy5sZW5ndGg7IGkyIDwgbGVuOyArK2kyKSB7CiAgICAgICAgICBjb25zdCBwcmVmaXggPSBwcmVmaXhlc1tpMl07CiAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fVJlcXVlc3RGdWxsc2NyZWVuYDsKICAgICAgICAgIGlmICh0eXBlb2YgYm9keVtuYW1lXSA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICBfbmFtZXMucmVxdWVzdEZ1bGxzY3JlZW4gPSBuYW1lOwogICAgICAgICAgICBfc3VwcG9ydHNGdWxsc2NyZWVuID0gdHJ1ZTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG5hbWUgPSBgJHtwcmVmaXh9UmVxdWVzdEZ1bGxTY3JlZW5gOwogICAgICAgICAgICBpZiAodHlwZW9mIGJvZHlbbmFtZV0gPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICBfbmFtZXMucmVxdWVzdEZ1bGxzY3JlZW4gPSBuYW1lOwogICAgICAgICAgICAgIF9zdXBwb3J0c0Z1bGxzY3JlZW4gPSB0cnVlOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fUV4aXRGdWxsc2NyZWVuYDsKICAgICAgICAgIGlmICh0eXBlb2YgZG9jdW1lbnRbbmFtZV0gPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgX25hbWVzLmV4aXRGdWxsc2NyZWVuID0gbmFtZTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG5hbWUgPSBgJHtwcmVmaXh9Q2FuY2VsRnVsbFNjcmVlbmA7CiAgICAgICAgICAgIGlmICh0eXBlb2YgZG9jdW1lbnRbbmFtZV0gPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICBfbmFtZXMuZXhpdEZ1bGxzY3JlZW4gPSBuYW1lOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fUZ1bGxzY3JlZW5FbmFibGVkYDsKICAgICAgICAgIGlmIChkb2N1bWVudFtuYW1lXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgIF9uYW1lcy5mdWxsc2NyZWVuRW5hYmxlZCA9IG5hbWU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fUZ1bGxTY3JlZW5FbmFibGVkYDsKICAgICAgICAgICAgaWYgKGRvY3VtZW50W25hbWVdICE9PSB2b2lkIDApIHsKICAgICAgICAgICAgICBfbmFtZXMuZnVsbHNjcmVlbkVuYWJsZWQgPSBuYW1lOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fUZ1bGxzY3JlZW5FbGVtZW50YDsKICAgICAgICAgIGlmIChkb2N1bWVudFtuYW1lXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgIF9uYW1lcy5mdWxsc2NyZWVuRWxlbWVudCA9IG5hbWU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fUZ1bGxTY3JlZW5FbGVtZW50YDsKICAgICAgICAgICAgaWYgKGRvY3VtZW50W25hbWVdICE9PSB2b2lkIDApIHsKICAgICAgICAgICAgICBfbmFtZXMuZnVsbHNjcmVlbkVsZW1lbnQgPSBuYW1lOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBuYW1lID0gYCR7cHJlZml4fWZ1bGxzY3JlZW5jaGFuZ2VgOwogICAgICAgICAgaWYgKGRvY3VtZW50W2BvbiR7bmFtZX1gXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgIGlmIChwcmVmaXggPT09ICJtcyIpIHsKICAgICAgICAgICAgICBuYW1lID0gIk1TRnVsbHNjcmVlbkNoYW5nZSI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgX25hbWVzLmZ1bGxzY3JlZW5jaGFuZ2UgPSBuYW1lOwogICAgICAgICAgfQogICAgICAgICAgbmFtZSA9IGAke3ByZWZpeH1mdWxsc2NyZWVuZXJyb3JgOwogICAgICAgICAgaWYgKGRvY3VtZW50W2BvbiR7bmFtZX1gXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgIGlmIChwcmVmaXggPT09ICJtcyIpIHsKICAgICAgICAgICAgICBuYW1lID0gIk1TRnVsbHNjcmVlbkVycm9yIjsKICAgICAgICAgICAgfQogICAgICAgICAgICBfbmFtZXMuZnVsbHNjcmVlbmVycm9yID0gbmFtZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIF9zdXBwb3J0c0Z1bGxzY3JlZW47CiAgICAgIH07CiAgICAgIEZ1bGxzY3JlZW4ucmVxdWVzdEZ1bGxzY3JlZW4gPSBmdW5jdGlvbihlbGVtZW50LCB2ckRldmljZSkgewogICAgICAgIGlmICghRnVsbHNjcmVlbi5zdXBwb3J0c0Z1bGxzY3JlZW4oKSkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBlbGVtZW50W19uYW1lcy5yZXF1ZXN0RnVsbHNjcmVlbl0oeyB2ckRpc3BsYXk6IHZyRGV2aWNlIH0pOwogICAgICB9OwogICAgICBGdWxsc2NyZWVuLmV4aXRGdWxsc2NyZWVuID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKCFGdWxsc2NyZWVuLnN1cHBvcnRzRnVsbHNjcmVlbigpKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGRvY3VtZW50W19uYW1lcy5leGl0RnVsbHNjcmVlbl0oKTsKICAgICAgfTsKICAgICAgRnVsbHNjcmVlbi5fbmFtZXMgPSBfbmFtZXM7CiAgICAgIEZ1bGxzY3JlZW5fZGVmYXVsdCA9IEZ1bGxzY3JlZW47CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9GZWF0dXJlRGV0ZWN0aW9uLmpzCiAgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24odmVyc2lvblN0cmluZykgewogICAgY29uc3QgcGFydHMgPSB2ZXJzaW9uU3RyaW5nLnNwbGl0KCIuIik7CiAgICBmb3IgKGxldCBpMiA9IDAsIGxlbiA9IHBhcnRzLmxlbmd0aDsgaTIgPCBsZW47ICsraTIpIHsKICAgICAgcGFydHNbaTJdID0gcGFyc2VJbnQocGFydHNbaTJdLCAxMCk7CiAgICB9CiAgICByZXR1cm4gcGFydHM7CiAgfQogIGZ1bmN0aW9uIGlzQ2hyb21lKCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaXNDaHJvbWVSZXN1bHQpKSB7CiAgICAgIGlzQ2hyb21lUmVzdWx0ID0gZmFsc2U7CiAgICAgIGlmICghaXNFZGdlKCkpIHsKICAgICAgICBjb25zdCBmaWVsZHMgPSAvIENocm9tZVwvKFtcLjAtOV0rKS8uZXhlYyh0aGVOYXZpZ2F0b3IudXNlckFnZW50KTsKICAgICAgICBpZiAoZmllbGRzICE9PSBudWxsKSB7CiAgICAgICAgICBpc0Nocm9tZVJlc3VsdCA9IHRydWU7CiAgICAgICAgICBjaHJvbWVWZXJzaW9uUmVzdWx0ID0gZXh0cmFjdFZlcnNpb24oZmllbGRzWzFdKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBpc0Nocm9tZVJlc3VsdDsKICB9CiAgZnVuY3Rpb24gY2hyb21lVmVyc2lvbigpIHsKICAgIHJldHVybiBpc0Nocm9tZSgpICYmIGNocm9tZVZlcnNpb25SZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGlzU2FmYXJpKCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaXNTYWZhcmlSZXN1bHQpKSB7CiAgICAgIGlzU2FmYXJpUmVzdWx0ID0gZmFsc2U7CiAgICAgIGlmICghaXNDaHJvbWUoKSAmJiAhaXNFZGdlKCkgJiYgLyBTYWZhcmlcL1tcLjAtOV0rLy50ZXN0KHRoZU5hdmlnYXRvci51c2VyQWdlbnQpKSB7CiAgICAgICAgY29uc3QgZmllbGRzID0gLyBWZXJzaW9uXC8oW1wuMC05XSspLy5leGVjKHRoZU5hdmlnYXRvci51c2VyQWdlbnQpOwogICAgICAgIGlmIChmaWVsZHMgIT09IG51bGwpIHsKICAgICAgICAgIGlzU2FmYXJpUmVzdWx0ID0gdHJ1ZTsKICAgICAgICAgIHNhZmFyaVZlcnNpb25SZXN1bHQgPSBleHRyYWN0VmVyc2lvbihmaWVsZHNbMV0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIGlzU2FmYXJpUmVzdWx0OwogIH0KICBmdW5jdGlvbiBzYWZhcmlWZXJzaW9uKCkgewogICAgcmV0dXJuIGlzU2FmYXJpKCkgJiYgc2FmYXJpVmVyc2lvblJlc3VsdDsKICB9CiAgZnVuY3Rpb24gaXNXZWJraXQoKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpc1dlYmtpdFJlc3VsdCkpIHsKICAgICAgaXNXZWJraXRSZXN1bHQgPSBmYWxzZTsKICAgICAgY29uc3QgZmllbGRzID0gLyBBcHBsZVdlYktpdFwvKFtcLjAtOV0rKShcKz8pLy5leGVjKHRoZU5hdmlnYXRvci51c2VyQWdlbnQpOwogICAgICBpZiAoZmllbGRzICE9PSBudWxsKSB7CiAgICAgICAgaXNXZWJraXRSZXN1bHQgPSB0cnVlOwogICAgICAgIHdlYmtpdFZlcnNpb25SZXN1bHQgPSBleHRyYWN0VmVyc2lvbihmaWVsZHNbMV0pOwogICAgICAgIHdlYmtpdFZlcnNpb25SZXN1bHQuaXNOaWdodGx5ID0gISFmaWVsZHNbMl07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBpc1dlYmtpdFJlc3VsdDsKICB9CiAgZnVuY3Rpb24gd2Via2l0VmVyc2lvbigpIHsKICAgIHJldHVybiBpc1dlYmtpdCgpICYmIHdlYmtpdFZlcnNpb25SZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGlzRWRnZSgpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGlzRWRnZVJlc3VsdCkpIHsKICAgICAgaXNFZGdlUmVzdWx0ID0gZmFsc2U7CiAgICAgIGNvbnN0IGZpZWxkcyA9IC8gRWRnXC8oW1wuMC05XSspLy5leGVjKHRoZU5hdmlnYXRvci51c2VyQWdlbnQpOwogICAgICBpZiAoZmllbGRzICE9PSBudWxsKSB7CiAgICAgICAgaXNFZGdlUmVzdWx0ID0gdHJ1ZTsKICAgICAgICBlZGdlVmVyc2lvblJlc3VsdCA9IGV4dHJhY3RWZXJzaW9uKGZpZWxkc1sxXSk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBpc0VkZ2VSZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGVkZ2VWZXJzaW9uKCkgewogICAgcmV0dXJuIGlzRWRnZSgpICYmIGVkZ2VWZXJzaW9uUmVzdWx0OwogIH0KICBmdW5jdGlvbiBpc0ZpcmVmb3goKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpc0ZpcmVmb3hSZXN1bHQpKSB7CiAgICAgIGlzRmlyZWZveFJlc3VsdCA9IGZhbHNlOwogICAgICBjb25zdCBmaWVsZHMgPSAvRmlyZWZveFwvKFtcLjAtOV0rKS8uZXhlYyh0aGVOYXZpZ2F0b3IudXNlckFnZW50KTsKICAgICAgaWYgKGZpZWxkcyAhPT0gbnVsbCkgewogICAgICAgIGlzRmlyZWZveFJlc3VsdCA9IHRydWU7CiAgICAgICAgZmlyZWZveFZlcnNpb25SZXN1bHQgPSBleHRyYWN0VmVyc2lvbihmaWVsZHNbMV0pOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gaXNGaXJlZm94UmVzdWx0OwogIH0KICBmdW5jdGlvbiBpc1dpbmRvd3MoKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpc1dpbmRvd3NSZXN1bHQpKSB7CiAgICAgIGlzV2luZG93c1Jlc3VsdCA9IC9XaW5kb3dzL2kudGVzdCh0aGVOYXZpZ2F0b3IuYXBwVmVyc2lvbik7CiAgICB9CiAgICByZXR1cm4gaXNXaW5kb3dzUmVzdWx0OwogIH0KICBmdW5jdGlvbiBpc0lQYWRPcklPUygpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGlzSVBhZE9ySU9TUmVzdWx0KSkgewogICAgICBpc0lQYWRPcklPU1Jlc3VsdCA9IG5hdmlnYXRvci5wbGF0Zm9ybSA9PT0gImlQaG9uZSIgfHwgbmF2aWdhdG9yLnBsYXRmb3JtID09PSAiaVBvZCIgfHwgbmF2aWdhdG9yLnBsYXRmb3JtID09PSAiaVBhZCI7CiAgICB9CiAgICByZXR1cm4gaXNJUGFkT3JJT1NSZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGZpcmVmb3hWZXJzaW9uKCkgewogICAgcmV0dXJuIGlzRmlyZWZveCgpICYmIGZpcmVmb3hWZXJzaW9uUmVzdWx0OwogIH0KICBmdW5jdGlvbiBzdXBwb3J0c1BvaW50ZXJFdmVudHMoKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChoYXNQb2ludGVyRXZlbnRzKSkgewogICAgICBoYXNQb2ludGVyRXZlbnRzID0gIWlzRmlyZWZveCgpICYmIHR5cGVvZiBQb2ludGVyRXZlbnQgIT09ICJ1bmRlZmluZWQiICYmICghZGVmaW5lZF9kZWZhdWx0KHRoZU5hdmlnYXRvci5wb2ludGVyRW5hYmxlZCkgfHwgdGhlTmF2aWdhdG9yLnBvaW50ZXJFbmFibGVkKTsKICAgIH0KICAgIHJldHVybiBoYXNQb2ludGVyRXZlbnRzOwogIH0KICBmdW5jdGlvbiBzdXBwb3J0c0ltYWdlUmVuZGVyaW5nUGl4ZWxhdGVkKCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoc3VwcG9ydHNJbWFnZVJlbmRlcmluZ1BpeGVsYXRlZFJlc3VsdCkpIHsKICAgICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiY2FudmFzIik7CiAgICAgIGNhbnZhcy5zZXRBdHRyaWJ1dGUoCiAgICAgICAgInN0eWxlIiwKICAgICAgICAiaW1hZ2UtcmVuZGVyaW5nOiAtbW96LWNyaXNwLWVkZ2VzO2ltYWdlLXJlbmRlcmluZzogcGl4ZWxhdGVkOyIKICAgICAgKTsKICAgICAgY29uc3QgdG1wMiA9IGNhbnZhcy5zdHlsZS5pbWFnZVJlbmRlcmluZzsKICAgICAgc3VwcG9ydHNJbWFnZVJlbmRlcmluZ1BpeGVsYXRlZFJlc3VsdCA9IGRlZmluZWRfZGVmYXVsdCh0bXAyKSAmJiB0bXAyICE9PSAiIjsKICAgICAgaWYgKHN1cHBvcnRzSW1hZ2VSZW5kZXJpbmdQaXhlbGF0ZWRSZXN1bHQpIHsKICAgICAgICBpbWFnZVJlbmRlcmluZ1ZhbHVlUmVzdWx0ID0gdG1wMjsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHN1cHBvcnRzSW1hZ2VSZW5kZXJpbmdQaXhlbGF0ZWRSZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGltYWdlUmVuZGVyaW5nVmFsdWUoKSB7CiAgICByZXR1cm4gc3VwcG9ydHNJbWFnZVJlbmRlcmluZ1BpeGVsYXRlZCgpID8gaW1hZ2VSZW5kZXJpbmdWYWx1ZVJlc3VsdCA6IHZvaWQgMDsKICB9CiAgZnVuY3Rpb24gc3VwcG9ydHNXZWJQKCkgewogICAgaWYgKCFzdXBwb3J0c1dlYlAuaW5pdGlhbGl6ZWQpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIllvdSBtdXN0IGNhbGwgRmVhdHVyZURldGVjdGlvbi5zdXBwb3J0c1dlYlAuaW5pdGlhbGl6ZSBhbmQgd2FpdCBmb3IgdGhlIHByb21pc2UgdG8gcmVzb2x2ZSBiZWZvcmUgY2FsbGluZyBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzV2ViUCIKICAgICAgKTsKICAgIH0KICAgIHJldHVybiBzdXBwb3J0c1dlYlAuX3Jlc3VsdDsKICB9CiAgdmFyIHRoZU5hdmlnYXRvciwgaXNDaHJvbWVSZXN1bHQsIGNocm9tZVZlcnNpb25SZXN1bHQsIGlzU2FmYXJpUmVzdWx0LCBzYWZhcmlWZXJzaW9uUmVzdWx0LCBpc1dlYmtpdFJlc3VsdCwgd2Via2l0VmVyc2lvblJlc3VsdCwgaXNFZGdlUmVzdWx0LCBlZGdlVmVyc2lvblJlc3VsdCwgaXNGaXJlZm94UmVzdWx0LCBmaXJlZm94VmVyc2lvblJlc3VsdCwgaXNXaW5kb3dzUmVzdWx0LCBpc0lQYWRPcklPU1Jlc3VsdCwgaGFzUG9pbnRlckV2ZW50cywgaW1hZ2VSZW5kZXJpbmdWYWx1ZVJlc3VsdCwgc3VwcG9ydHNJbWFnZVJlbmRlcmluZ1BpeGVsYXRlZFJlc3VsdCwgdHlwZWRBcnJheVR5cGVzLCBGZWF0dXJlRGV0ZWN0aW9uLCBGZWF0dXJlRGV0ZWN0aW9uX2RlZmF1bHQ7CiAgdmFyIGluaXRfRmVhdHVyZURldGVjdGlvbiA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRmVhdHVyZURldGVjdGlvbi5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9GdWxsc2NyZWVuKCk7CiAgICAgIGlmICh0eXBlb2YgbmF2aWdhdG9yICE9PSAidW5kZWZpbmVkIikgewogICAgICAgIHRoZU5hdmlnYXRvciA9IG5hdmlnYXRvcjsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aGVOYXZpZ2F0b3IgPSB7fTsKICAgICAgfQogICAgICBzdXBwb3J0c1dlYlAuX3Byb21pc2UgPSB2b2lkIDA7CiAgICAgIHN1cHBvcnRzV2ViUC5fcmVzdWx0ID0gdm9pZCAwOwogICAgICBzdXBwb3J0c1dlYlAuaW5pdGlhbGl6ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoc3VwcG9ydHNXZWJQLl9wcm9taXNlKSkgewogICAgICAgICAgcmV0dXJuIHN1cHBvcnRzV2ViUC5fcHJvbWlzZTsKICAgICAgICB9CiAgICAgICAgc3VwcG9ydHNXZWJQLl9wcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHsKICAgICAgICAgIGNvbnN0IGltYWdlID0gbmV3IEltYWdlKCk7CiAgICAgICAgICBpbWFnZS5vbmxvYWQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgc3VwcG9ydHNXZWJQLl9yZXN1bHQgPSBpbWFnZS53aWR0aCA+IDAgJiYgaW1hZ2UuaGVpZ2h0ID4gMDsKICAgICAgICAgICAgcmVzb2x2ZShzdXBwb3J0c1dlYlAuX3Jlc3VsdCk7CiAgICAgICAgICB9OwogICAgICAgICAgaW1hZ2Uub25lcnJvciA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBzdXBwb3J0c1dlYlAuX3Jlc3VsdCA9IGZhbHNlOwogICAgICAgICAgICByZXNvbHZlKHN1cHBvcnRzV2ViUC5fcmVzdWx0KTsKICAgICAgICAgIH07CiAgICAgICAgICBpbWFnZS5zcmMgPSAiZGF0YTppbWFnZS93ZWJwO2Jhc2U2NCxVa2xHUmlJQUFBQlhSVUpRVmxBNElCWUFBQUF3QVFDZEFTb0JBQUVBRHNEK0phUUFBM0FBQUFBQSI7CiAgICAgICAgfSk7CiAgICAgICAgcmV0dXJuIHN1cHBvcnRzV2ViUC5fcHJvbWlzZTsKICAgICAgfTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoc3VwcG9ydHNXZWJQLCB7CiAgICAgICAgaW5pdGlhbGl6ZWQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBkZWZpbmVkX2RlZmF1bHQoc3VwcG9ydHNXZWJQLl9yZXN1bHQpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIHR5cGVkQXJyYXlUeXBlcyA9IFtdOwogICAgICBpZiAodHlwZW9mIEFycmF5QnVmZmVyICE9PSAidW5kZWZpbmVkIikgewogICAgICAgIHR5cGVkQXJyYXlUeXBlcy5wdXNoKAogICAgICAgICAgSW50OEFycmF5LAogICAgICAgICAgVWludDhBcnJheSwKICAgICAgICAgIEludDE2QXJyYXksCiAgICAgICAgICBVaW50MTZBcnJheSwKICAgICAgICAgIEludDMyQXJyYXksCiAgICAgICAgICBVaW50MzJBcnJheSwKICAgICAgICAgIEZsb2F0MzJBcnJheSwKICAgICAgICAgIEZsb2F0NjRBcnJheQogICAgICAgICk7CiAgICAgICAgaWYgKHR5cGVvZiBVaW50OENsYW1wZWRBcnJheSAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgICAgIHR5cGVkQXJyYXlUeXBlcy5wdXNoKFVpbnQ4Q2xhbXBlZEFycmF5KTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBVaW50OENsYW1wZWRBcnJheSAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgICAgIHR5cGVkQXJyYXlUeXBlcy5wdXNoKFVpbnQ4Q2xhbXBlZEFycmF5KTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBCaWdJbnQ2NEFycmF5ICE9PSAidW5kZWZpbmVkIikgewogICAgICAgICAgdHlwZWRBcnJheVR5cGVzLnB1c2goQmlnSW50NjRBcnJheSk7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgQmlnVWludDY0QXJyYXkgIT09ICJ1bmRlZmluZWQiKSB7CiAgICAgICAgICB0eXBlZEFycmF5VHlwZXMucHVzaChCaWdVaW50NjRBcnJheSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIEZlYXR1cmVEZXRlY3Rpb24gPSB7CiAgICAgICAgaXNDaHJvbWUsCiAgICAgICAgY2hyb21lVmVyc2lvbiwKICAgICAgICBpc1NhZmFyaSwKICAgICAgICBzYWZhcmlWZXJzaW9uLAogICAgICAgIGlzV2Via2l0LAogICAgICAgIHdlYmtpdFZlcnNpb24sCiAgICAgICAgaXNFZGdlLAogICAgICAgIGVkZ2VWZXJzaW9uLAogICAgICAgIGlzRmlyZWZveCwKICAgICAgICBmaXJlZm94VmVyc2lvbiwKICAgICAgICBpc1dpbmRvd3MsCiAgICAgICAgaXNJUGFkT3JJT1MsCiAgICAgICAgaGFyZHdhcmVDb25jdXJyZW5jeTogdGhlTmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3kgPz8gMywKICAgICAgICBzdXBwb3J0c1BvaW50ZXJFdmVudHMsCiAgICAgICAgc3VwcG9ydHNJbWFnZVJlbmRlcmluZ1BpeGVsYXRlZCwKICAgICAgICBzdXBwb3J0c1dlYlAsCiAgICAgICAgaW1hZ2VSZW5kZXJpbmdWYWx1ZSwKICAgICAgICB0eXBlZEFycmF5VHlwZXMKICAgICAgfTsKICAgICAgRmVhdHVyZURldGVjdGlvbi5zdXBwb3J0c0Jhc2lzID0gZnVuY3Rpb24oc2NlbmUpIHsKICAgICAgICByZXR1cm4gRmVhdHVyZURldGVjdGlvbi5zdXBwb3J0c1dlYkFzc2VtYmx5KCkgJiYgc2NlbmUuY29udGV4dC5zdXBwb3J0c0Jhc2lzOwogICAgICB9OwogICAgICBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzRnVsbHNjcmVlbiA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBGdWxsc2NyZWVuX2RlZmF1bHQuc3VwcG9ydHNGdWxsc2NyZWVuKCk7CiAgICAgIH07CiAgICAgIEZlYXR1cmVEZXRlY3Rpb24uc3VwcG9ydHNUeXBlZEFycmF5cyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICJ1bmRlZmluZWQiOwogICAgICB9OwogICAgICBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzQmlnSW50NjRBcnJheSA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0eXBlb2YgQmlnSW50NjRBcnJheSAhPT0gInVuZGVmaW5lZCI7CiAgICAgIH07CiAgICAgIEZlYXR1cmVEZXRlY3Rpb24uc3VwcG9ydHNCaWdVaW50NjRBcnJheSA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0eXBlb2YgQmlnVWludDY0QXJyYXkgIT09ICJ1bmRlZmluZWQiOwogICAgICB9OwogICAgICBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzQmlnSW50ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHR5cGVvZiBCaWdJbnQgIT09ICJ1bmRlZmluZWQiOwogICAgICB9OwogICAgICBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzV2ViV29ya2VycyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiB0eXBlb2YgV29ya2VyICE9PSAidW5kZWZpbmVkIjsKICAgICAgfTsKICAgICAgRmVhdHVyZURldGVjdGlvbi5zdXBwb3J0c1dlYkFzc2VtYmx5ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIHR5cGVvZiBXZWJBc3NlbWJseSAhPT0gInVuZGVmaW5lZCI7CiAgICAgIH07CiAgICAgIEZlYXR1cmVEZXRlY3Rpb24uc3VwcG9ydHNXZWJnbDIgPSBmdW5jdGlvbihzY2VuZSkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgic2NlbmUiLCBzY2VuZSk7CiAgICAgICAgcmV0dXJuIHNjZW5lLmNvbnRleHQud2ViZ2wyOwogICAgICB9OwogICAgICBGZWF0dXJlRGV0ZWN0aW9uLnN1cHBvcnRzRXNtV2ViV29ya2VycyA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiAhaXNGaXJlZm94KCkgfHwgcGFyc2VJbnQoZmlyZWZveFZlcnNpb25SZXN1bHQpID49IDExNDsKICAgICAgfTsKICAgICAgRmVhdHVyZURldGVjdGlvbl9kZWZhdWx0ID0gRmVhdHVyZURldGVjdGlvbjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1F1YXRlcm5pb24uanMKICBmdW5jdGlvbiBRdWF0ZXJuaW9uKHgyLCB5MiwgejIsIHcyKSB7CiAgICB0aGlzLnggPSB4MiA/PyAwOwogICAgdGhpcy55ID0geTIgPz8gMDsKICAgIHRoaXMueiA9IHoyID8/IDA7CiAgICB0aGlzLncgPSB3MiA/PyAwOwogIH0KICB2YXIgZnJvbUF4aXNBbmdsZVNjcmF0Y2gsIGZyb21Sb3RhdGlvbk1hdHJpeE5leHQsIGZyb21Sb3RhdGlvbk1hdHJpeFF1YXQsIHNjcmF0Y2hIUFJRdWF0ZXJuaW9uLCBzY3JhdGNoSGVhZGluZ1F1YXRlcm5pb24sIHNjcmF0Y2hQaXRjaFF1YXRlcm5pb24sIHNjcmF0Y2hSb2xsUXVhdGVybmlvbiwgc2FtcGxlZFF1YXRlcm5pb25BeGlzLCBzYW1wbGVkUXVhdGVybmlvblJvdGF0aW9uLCBzYW1wbGVkUXVhdGVybmlvblRlbXBRdWF0ZXJuaW9uLCBzYW1wbGVkUXVhdGVybmlvblF1YXRlcm5pb24wLCBzYW1wbGVkUXVhdGVybmlvblF1YXRlcm5pb24wQ29uanVnYXRlLCBsZXJwU2NyYXRjaDQsIHNsZXJwRW5kTmVnYXRlZCwgc2xlcnBTY2FsZWRQLCBzbGVycFNjYWxlZFIsIHNxdWFkU2NyYXRjaENhcnRlc2lhbjAsIHNxdWFkU2NyYXRjaENhcnRlc2lhbjEsIHNxdWFkU2NyYXRjaFF1YXRlcm5pb24wLCBzcXVhZFNjcmF0Y2hRdWF0ZXJuaW9uMSwgZmFzdFNsZXJwU2NyYXRjaFF1YXRlcm5pb24sIG9wbXUsIHUsIHYsIGJULCBiRCwgUXVhdGVybmlvbl9kZWZhdWx0OwogIHZhciBpbml0X1F1YXRlcm5pb24gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1F1YXRlcm5pb24uanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9GZWF0dXJlRGV0ZWN0aW9uKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgZnJvbUF4aXNBbmdsZVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFF1YXRlcm5pb24uZnJvbUF4aXNBbmdsZSA9IGZ1bmN0aW9uKGF4aXMsIGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImF4aXMiLCBheGlzKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImFuZ2xlIiwgYW5nbGUpOwogICAgICAgIGNvbnN0IGhhbGZBbmdsZSA9IGFuZ2xlIC8gMjsKICAgICAgICBjb25zdCBzMiA9IE1hdGguc2luKGhhbGZBbmdsZSk7CiAgICAgICAgZnJvbUF4aXNBbmdsZVNjcmF0Y2ggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGF4aXMsIGZyb21BeGlzQW5nbGVTY3JhdGNoKTsKICAgICAgICBjb25zdCB4MiA9IGZyb21BeGlzQW5nbGVTY3JhdGNoLnggKiBzMjsKICAgICAgICBjb25zdCB5MiA9IGZyb21BeGlzQW5nbGVTY3JhdGNoLnkgKiBzMjsKICAgICAgICBjb25zdCB6MiA9IGZyb21BeGlzQW5nbGVTY3JhdGNoLnogKiBzMjsKICAgICAgICBjb25zdCB3MiA9IE1hdGguY29zKGhhbGZBbmdsZSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBRdWF0ZXJuaW9uKHgyLCB5MiwgejIsIHcyKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgIHJlc3VsdC56ID0gejI7CiAgICAgICAgcmVzdWx0LncgPSB3MjsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBmcm9tUm90YXRpb25NYXRyaXhOZXh0ID0gWzEsIDIsIDBdOwogICAgICBmcm9tUm90YXRpb25NYXRyaXhRdWF0ID0gbmV3IEFycmF5KDMpOwogICAgICBRdWF0ZXJuaW9uLmZyb21Sb3RhdGlvbk1hdHJpeCA9IGZ1bmN0aW9uKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgIGxldCByb290OwogICAgICAgIGxldCB4MjsKICAgICAgICBsZXQgeTI7CiAgICAgICAgbGV0IHoyOwogICAgICAgIGxldCB3MjsKICAgICAgICBjb25zdCBtMDAgPSBtYXRyaXhbTWF0cml4M19kZWZhdWx0LkNPTFVNTjBST1cwXTsKICAgICAgICBjb25zdCBtMTEgPSBtYXRyaXhbTWF0cml4M19kZWZhdWx0LkNPTFVNTjFST1cxXTsKICAgICAgICBjb25zdCBtMjIgPSBtYXRyaXhbTWF0cml4M19kZWZhdWx0LkNPTFVNTjJST1cyXTsKICAgICAgICBjb25zdCB0cmFjZSA9IG0wMCArIG0xMSArIG0yMjsKICAgICAgICBpZiAodHJhY2UgPiAwKSB7CiAgICAgICAgICByb290ID0gTWF0aC5zcXJ0KHRyYWNlICsgMSk7CiAgICAgICAgICB3MiA9IDAuNSAqIHJvb3Q7CiAgICAgICAgICByb290ID0gMC41IC8gcm9vdDsKICAgICAgICAgIHgyID0gKG1hdHJpeFtNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMVJPVzJdIC0gbWF0cml4W01hdHJpeDNfZGVmYXVsdC5DT0xVTU4yUk9XMV0pICogcm9vdDsKICAgICAgICAgIHkyID0gKG1hdHJpeFtNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMlJPVzBdIC0gbWF0cml4W01hdHJpeDNfZGVmYXVsdC5DT0xVTU4wUk9XMl0pICogcm9vdDsKICAgICAgICAgIHoyID0gKG1hdHJpeFtNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMFJPVzFdIC0gbWF0cml4W01hdHJpeDNfZGVmYXVsdC5DT0xVTU4xUk9XMF0pICogcm9vdDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3QgbmV4dCA9IGZyb21Sb3RhdGlvbk1hdHJpeE5leHQ7CiAgICAgICAgICBsZXQgaTIgPSAwOwogICAgICAgICAgaWYgKG0xMSA+IG0wMCkgewogICAgICAgICAgICBpMiA9IDE7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobTIyID4gbTAwICYmIG0yMiA+IG0xMSkgewogICAgICAgICAgICBpMiA9IDI7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBqMiA9IG5leHRbaTJdOwogICAgICAgICAgY29uc3QgazIgPSBuZXh0W2oyXTsKICAgICAgICAgIHJvb3QgPSBNYXRoLnNxcnQoCiAgICAgICAgICAgIG1hdHJpeFtNYXRyaXgzX2RlZmF1bHQuZ2V0RWxlbWVudEluZGV4KGkyLCBpMildIC0gbWF0cml4W01hdHJpeDNfZGVmYXVsdC5nZXRFbGVtZW50SW5kZXgoajIsIGoyKV0gLSBtYXRyaXhbTWF0cml4M19kZWZhdWx0LmdldEVsZW1lbnRJbmRleChrMiwgazIpXSArIDEKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBxdWF0ID0gZnJvbVJvdGF0aW9uTWF0cml4UXVhdDsKICAgICAgICAgIHF1YXRbaTJdID0gMC41ICogcm9vdDsKICAgICAgICAgIHJvb3QgPSAwLjUgLyByb290OwogICAgICAgICAgdzIgPSAobWF0cml4W01hdHJpeDNfZGVmYXVsdC5nZXRFbGVtZW50SW5kZXgoazIsIGoyKV0gLSBtYXRyaXhbTWF0cml4M19kZWZhdWx0LmdldEVsZW1lbnRJbmRleChqMiwgazIpXSkgKiByb290OwogICAgICAgICAgcXVhdFtqMl0gPSAobWF0cml4W01hdHJpeDNfZGVmYXVsdC5nZXRFbGVtZW50SW5kZXgoajIsIGkyKV0gKyBtYXRyaXhbTWF0cml4M19kZWZhdWx0LmdldEVsZW1lbnRJbmRleChpMiwgajIpXSkgKiByb290OwogICAgICAgICAgcXVhdFtrMl0gPSAobWF0cml4W01hdHJpeDNfZGVmYXVsdC5nZXRFbGVtZW50SW5kZXgoazIsIGkyKV0gKyBtYXRyaXhbTWF0cml4M19kZWZhdWx0LmdldEVsZW1lbnRJbmRleChpMiwgazIpXSkgKiByb290OwogICAgICAgICAgeDIgPSAtcXVhdFswXTsKICAgICAgICAgIHkyID0gLXF1YXRbMV07CiAgICAgICAgICB6MiA9IC1xdWF0WzJdOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IFF1YXRlcm5pb24oeDIsIHkyLCB6MiwgdzIpOwogICAgICAgIH0KICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICByZXN1bHQudyA9IHcyOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hIUFJRdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgc2NyYXRjaEhlYWRpbmdRdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgc2NyYXRjaFBpdGNoUXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIHNjcmF0Y2hSb2xsUXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIFF1YXRlcm5pb24uZnJvbUhlYWRpbmdQaXRjaFJvbGwgPSBmdW5jdGlvbihoZWFkaW5nUGl0Y2hSb2xsLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImhlYWRpbmdQaXRjaFJvbGwiLCBoZWFkaW5nUGl0Y2hSb2xsKTsKICAgICAgICBzY3JhdGNoUm9sbFF1YXRlcm5pb24gPSBRdWF0ZXJuaW9uLmZyb21BeGlzQW5nbGUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9YLAogICAgICAgICAgaGVhZGluZ1BpdGNoUm9sbC5yb2xsLAogICAgICAgICAgc2NyYXRjaEhQUlF1YXRlcm5pb24KICAgICAgICApOwogICAgICAgIHNjcmF0Y2hQaXRjaFF1YXRlcm5pb24gPSBRdWF0ZXJuaW9uLmZyb21BeGlzQW5nbGUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZLAogICAgICAgICAgLWhlYWRpbmdQaXRjaFJvbGwucGl0Y2gsCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICAgIHJlc3VsdCA9IFF1YXRlcm5pb24ubXVsdGlwbHkoCiAgICAgICAgICBzY3JhdGNoUGl0Y2hRdWF0ZXJuaW9uLAogICAgICAgICAgc2NyYXRjaFJvbGxRdWF0ZXJuaW9uLAogICAgICAgICAgc2NyYXRjaFBpdGNoUXVhdGVybmlvbgogICAgICAgICk7CiAgICAgICAgc2NyYXRjaEhlYWRpbmdRdWF0ZXJuaW9uID0gUXVhdGVybmlvbi5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwKICAgICAgICAgIC1oZWFkaW5nUGl0Y2hSb2xsLmhlYWRpbmcsCiAgICAgICAgICBzY3JhdGNoSFBSUXVhdGVybmlvbgogICAgICAgICk7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24ubXVsdGlwbHkoc2NyYXRjaEhlYWRpbmdRdWF0ZXJuaW9uLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uQXhpcyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2FtcGxlZFF1YXRlcm5pb25Sb3RhdGlvbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2FtcGxlZFF1YXRlcm5pb25UZW1wUXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uUXVhdGVybmlvbjAgPSBuZXcgUXVhdGVybmlvbigpOwogICAgICBzYW1wbGVkUXVhdGVybmlvblF1YXRlcm5pb24wQ29uanVnYXRlID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgUXVhdGVybmlvbi5wYWNrZWRMZW5ndGggPSA0OwogICAgICBRdWF0ZXJuaW9uLnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUueDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUueTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuejsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLnc7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnggPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICByZXN1bHQueSA9IGFycmF5W3N0YXJ0aW5nSW5kZXggKyAxXTsKICAgICAgICByZXN1bHQueiA9IGFycmF5W3N0YXJ0aW5nSW5kZXggKyAyXTsKICAgICAgICByZXN1bHQudyA9IGFycmF5W3N0YXJ0aW5nSW5kZXggKyAzXTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLnBhY2tlZEludGVycG9sYXRpb25MZW5ndGggPSAzOwogICAgICBRdWF0ZXJuaW9uLmNvbnZlcnRQYWNrZWRBcnJheUZvckludGVycG9sYXRpb24gPSBmdW5jdGlvbihwYWNrZWRBcnJheSwgc3RhcnRpbmdJbmRleCwgbGFzdEluZGV4LCByZXN1bHQpIHsKICAgICAgICBRdWF0ZXJuaW9uLnVucGFjaygKICAgICAgICAgIHBhY2tlZEFycmF5LAogICAgICAgICAgbGFzdEluZGV4ICogNCwKICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uUXVhdGVybmlvbjBDb25qdWdhdGUKICAgICAgICApOwogICAgICAgIFF1YXRlcm5pb24uY29uanVnYXRlKAogICAgICAgICAgc2FtcGxlZFF1YXRlcm5pb25RdWF0ZXJuaW9uMENvbmp1Z2F0ZSwKICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uUXVhdGVybmlvbjBDb25qdWdhdGUKICAgICAgICApOwogICAgICAgIGZvciAobGV0IGkyID0gMCwgbGVuID0gbGFzdEluZGV4IC0gc3RhcnRpbmdJbmRleCArIDE7IGkyIDwgbGVuOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBvZmZzZXQgPSBpMiAqIDM7CiAgICAgICAgICBRdWF0ZXJuaW9uLnVucGFjaygKICAgICAgICAgICAgcGFja2VkQXJyYXksCiAgICAgICAgICAgIChzdGFydGluZ0luZGV4ICsgaTIpICogNCwKICAgICAgICAgICAgc2FtcGxlZFF1YXRlcm5pb25UZW1wUXVhdGVybmlvbgogICAgICAgICAgKTsKICAgICAgICAgIFF1YXRlcm5pb24ubXVsdGlwbHkoCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uVGVtcFF1YXRlcm5pb24sCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uUXVhdGVybmlvbjBDb25qdWdhdGUsCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uVGVtcFF1YXRlcm5pb24KICAgICAgICAgICk7CiAgICAgICAgICBpZiAoc2FtcGxlZFF1YXRlcm5pb25UZW1wUXVhdGVybmlvbi53IDwgMCkgewogICAgICAgICAgICBRdWF0ZXJuaW9uLm5lZ2F0ZSgKICAgICAgICAgICAgICBzYW1wbGVkUXVhdGVybmlvblRlbXBRdWF0ZXJuaW9uLAogICAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uVGVtcFF1YXRlcm5pb24KICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIFF1YXRlcm5pb24uY29tcHV0ZUF4aXMoCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uVGVtcFF1YXRlcm5pb24sCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uQXhpcwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IGFuZ2xlID0gUXVhdGVybmlvbi5jb21wdXRlQW5nbGUoc2FtcGxlZFF1YXRlcm5pb25UZW1wUXVhdGVybmlvbik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IFtdOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0W29mZnNldF0gPSBzYW1wbGVkUXVhdGVybmlvbkF4aXMueCAqIGFuZ2xlOwogICAgICAgICAgcmVzdWx0W29mZnNldCArIDFdID0gc2FtcGxlZFF1YXRlcm5pb25BeGlzLnkgKiBhbmdsZTsKICAgICAgICAgIHJlc3VsdFtvZmZzZXQgKyAyXSA9IHNhbXBsZWRRdWF0ZXJuaW9uQXhpcy56ICogYW5nbGU7CiAgICAgICAgfQogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLnVucGFja0ludGVycG9sYXRpb25SZXN1bHQgPSBmdW5jdGlvbihhcnJheSwgc291cmNlQXJyYXksIGZpcnN0SW5kZXgsIGxhc3RJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShhcnJheSwgMCwgc2FtcGxlZFF1YXRlcm5pb25Sb3RhdGlvbik7CiAgICAgICAgY29uc3QgbWFnbml0dWRlID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShzYW1wbGVkUXVhdGVybmlvblJvdGF0aW9uKTsKICAgICAgICBRdWF0ZXJuaW9uLnVucGFjayhzb3VyY2VBcnJheSwgbGFzdEluZGV4ICogNCwgc2FtcGxlZFF1YXRlcm5pb25RdWF0ZXJuaW9uMCk7CiAgICAgICAgaWYgKG1hZ25pdHVkZSA9PT0gMCkgewogICAgICAgICAgUXVhdGVybmlvbi5jbG9uZShRdWF0ZXJuaW9uLklERU5USVRZLCBzYW1wbGVkUXVhdGVybmlvblRlbXBRdWF0ZXJuaW9uKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgUXVhdGVybmlvbi5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgICBzYW1wbGVkUXVhdGVybmlvblJvdGF0aW9uLAogICAgICAgICAgICBtYWduaXR1ZGUsCiAgICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uVGVtcFF1YXRlcm5pb24KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBRdWF0ZXJuaW9uLm11bHRpcGx5KAogICAgICAgICAgc2FtcGxlZFF1YXRlcm5pb25UZW1wUXVhdGVybmlvbiwKICAgICAgICAgIHNhbXBsZWRRdWF0ZXJuaW9uUXVhdGVybmlvbjAsCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmNsb25lID0gZnVuY3Rpb24ocXVhdGVybmlvbiwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocXVhdGVybmlvbikpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJldHVybiBuZXcgUXVhdGVybmlvbigKICAgICAgICAgICAgcXVhdGVybmlvbi54LAogICAgICAgICAgICBxdWF0ZXJuaW9uLnksCiAgICAgICAgICAgIHF1YXRlcm5pb24ueiwKICAgICAgICAgICAgcXVhdGVybmlvbi53CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXN1bHQueCA9IHF1YXRlcm5pb24ueDsKICAgICAgICByZXN1bHQueSA9IHF1YXRlcm5pb24ueTsKICAgICAgICByZXN1bHQueiA9IHF1YXRlcm5pb24uejsKICAgICAgICByZXN1bHQudyA9IHF1YXRlcm5pb24udzsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmNvbmp1Z2F0ZSA9IGZ1bmN0aW9uKHF1YXRlcm5pb24sIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicXVhdGVybmlvbiIsIHF1YXRlcm5pb24pOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICByZXN1bHQueCA9IC1xdWF0ZXJuaW9uLng7CiAgICAgICAgcmVzdWx0LnkgPSAtcXVhdGVybmlvbi55OwogICAgICAgIHJlc3VsdC56ID0gLXF1YXRlcm5pb24uejsKICAgICAgICByZXN1bHQudyA9IHF1YXRlcm5pb24udzsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLm1hZ25pdHVkZVNxdWFyZWQgPSBmdW5jdGlvbihxdWF0ZXJuaW9uKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxdWF0ZXJuaW9uIiwgcXVhdGVybmlvbik7CiAgICAgICAgcmV0dXJuIHF1YXRlcm5pb24ueCAqIHF1YXRlcm5pb24ueCArIHF1YXRlcm5pb24ueSAqIHF1YXRlcm5pb24ueSArIHF1YXRlcm5pb24ueiAqIHF1YXRlcm5pb24ueiArIHF1YXRlcm5pb24udyAqIHF1YXRlcm5pb24udzsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5tYWduaXR1ZGUgPSBmdW5jdGlvbihxdWF0ZXJuaW9uKSB7CiAgICAgICAgcmV0dXJuIE1hdGguc3FydChRdWF0ZXJuaW9uLm1hZ25pdHVkZVNxdWFyZWQocXVhdGVybmlvbikpOwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKHF1YXRlcm5pb24sIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCBpbnZlcnNlTWFnbml0dWRlID0gMSAvIFF1YXRlcm5pb24ubWFnbml0dWRlKHF1YXRlcm5pb24pOwogICAgICAgIGNvbnN0IHgyID0gcXVhdGVybmlvbi54ICogaW52ZXJzZU1hZ25pdHVkZTsKICAgICAgICBjb25zdCB5MiA9IHF1YXRlcm5pb24ueSAqIGludmVyc2VNYWduaXR1ZGU7CiAgICAgICAgY29uc3QgejIgPSBxdWF0ZXJuaW9uLnogKiBpbnZlcnNlTWFnbml0dWRlOwogICAgICAgIGNvbnN0IHcyID0gcXVhdGVybmlvbi53ICogaW52ZXJzZU1hZ25pdHVkZTsKICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICByZXN1bHQudyA9IHcyOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24uaW52ZXJzZSA9IGZ1bmN0aW9uKHF1YXRlcm5pb24sIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCBtYWduaXR1ZGVTcXVhcmVkID0gUXVhdGVybmlvbi5tYWduaXR1ZGVTcXVhcmVkKHF1YXRlcm5pb24pOwogICAgICAgIHJlc3VsdCA9IFF1YXRlcm5pb24uY29uanVnYXRlKHF1YXRlcm5pb24sIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24ubXVsdGlwbHlCeVNjYWxhcihyZXN1bHQsIDEgLyBtYWduaXR1ZGVTcXVhcmVkLCByZXN1bHQpOwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmFkZCA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICByZXN1bHQueCA9IGxlZnQueCArIHJpZ2h0Lng7CiAgICAgICAgcmVzdWx0LnkgPSBsZWZ0LnkgKyByaWdodC55OwogICAgICAgIHJlc3VsdC56ID0gbGVmdC56ICsgcmlnaHQuejsKICAgICAgICByZXN1bHQudyA9IGxlZnQudyArIHJpZ2h0Lnc7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5zdWJ0cmFjdCA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICByZXN1bHQueCA9IGxlZnQueCAtIHJpZ2h0Lng7CiAgICAgICAgcmVzdWx0LnkgPSBsZWZ0LnkgLSByaWdodC55OwogICAgICAgIHJlc3VsdC56ID0gbGVmdC56IC0gcmlnaHQuejsKICAgICAgICByZXN1bHQudyA9IGxlZnQudyAtIHJpZ2h0Lnc7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5uZWdhdGUgPSBmdW5jdGlvbihxdWF0ZXJuaW9uLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInF1YXRlcm5pb24iLCBxdWF0ZXJuaW9uKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgcmVzdWx0LnggPSAtcXVhdGVybmlvbi54OwogICAgICAgIHJlc3VsdC55ID0gLXF1YXRlcm5pb24ueTsKICAgICAgICByZXN1bHQueiA9IC1xdWF0ZXJuaW9uLno7CiAgICAgICAgcmVzdWx0LncgPSAtcXVhdGVybmlvbi53OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24uZG90ID0gZnVuY3Rpb24obGVmdCwgcmlnaHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImxlZnQiLCBsZWZ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgIHJldHVybiBsZWZ0LnggKiByaWdodC54ICsgbGVmdC55ICogcmlnaHQueSArIGxlZnQueiAqIHJpZ2h0LnogKyBsZWZ0LncgKiByaWdodC53OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLm11bHRpcGx5ID0gZnVuY3Rpb24obGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGNvbnN0IGxlZnRYID0gbGVmdC54OwogICAgICAgIGNvbnN0IGxlZnRZID0gbGVmdC55OwogICAgICAgIGNvbnN0IGxlZnRaID0gbGVmdC56OwogICAgICAgIGNvbnN0IGxlZnRXID0gbGVmdC53OwogICAgICAgIGNvbnN0IHJpZ2h0WCA9IHJpZ2h0Lng7CiAgICAgICAgY29uc3QgcmlnaHRZID0gcmlnaHQueTsKICAgICAgICBjb25zdCByaWdodFogPSByaWdodC56OwogICAgICAgIGNvbnN0IHJpZ2h0VyA9IHJpZ2h0Lnc7CiAgICAgICAgY29uc3QgeDIgPSBsZWZ0VyAqIHJpZ2h0WCArIGxlZnRYICogcmlnaHRXICsgbGVmdFkgKiByaWdodFogLSBsZWZ0WiAqIHJpZ2h0WTsKICAgICAgICBjb25zdCB5MiA9IGxlZnRXICogcmlnaHRZIC0gbGVmdFggKiByaWdodFogKyBsZWZ0WSAqIHJpZ2h0VyArIGxlZnRaICogcmlnaHRYOwogICAgICAgIGNvbnN0IHoyID0gbGVmdFcgKiByaWdodFogKyBsZWZ0WCAqIHJpZ2h0WSAtIGxlZnRZICogcmlnaHRYICsgbGVmdFogKiByaWdodFc7CiAgICAgICAgY29uc3QgdzIgPSBsZWZ0VyAqIHJpZ2h0VyAtIGxlZnRYICogcmlnaHRYIC0gbGVmdFkgKiByaWdodFkgLSBsZWZ0WiAqIHJpZ2h0WjsKICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICByZXN1bHQudyA9IHcyOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24ubXVsdGlwbHlCeVNjYWxhciA9IGZ1bmN0aW9uKHF1YXRlcm5pb24sIHNjYWxhciwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxdWF0ZXJuaW9uIiwgcXVhdGVybmlvbik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJzY2FsYXIiLCBzY2FsYXIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICByZXN1bHQueCA9IHF1YXRlcm5pb24ueCAqIHNjYWxhcjsKICAgICAgICByZXN1bHQueSA9IHF1YXRlcm5pb24ueSAqIHNjYWxhcjsKICAgICAgICByZXN1bHQueiA9IHF1YXRlcm5pb24ueiAqIHNjYWxhcjsKICAgICAgICByZXN1bHQudyA9IHF1YXRlcm5pb24udyAqIHNjYWxhcjsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmRpdmlkZUJ5U2NhbGFyID0gZnVuY3Rpb24ocXVhdGVybmlvbiwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInF1YXRlcm5pb24iLCBxdWF0ZXJuaW9uKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxhciIsIHNjYWxhcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIHJlc3VsdC54ID0gcXVhdGVybmlvbi54IC8gc2NhbGFyOwogICAgICAgIHJlc3VsdC55ID0gcXVhdGVybmlvbi55IC8gc2NhbGFyOwogICAgICAgIHJlc3VsdC56ID0gcXVhdGVybmlvbi56IC8gc2NhbGFyOwogICAgICAgIHJlc3VsdC53ID0gcXVhdGVybmlvbi53IC8gc2NhbGFyOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24uY29tcHV0ZUF4aXMgPSBmdW5jdGlvbihxdWF0ZXJuaW9uLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInF1YXRlcm5pb24iLCBxdWF0ZXJuaW9uKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgY29uc3QgdzIgPSBxdWF0ZXJuaW9uLnc7CiAgICAgICAgaWYgKE1hdGguYWJzKHcyIC0gMSkgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjYgfHwgTWF0aC5hYnModzIgKyAxKSA8IE1hdGhfZGVmYXVsdC5FUFNJTE9ONikgewogICAgICAgICAgcmVzdWx0LnggPSAxOwogICAgICAgICAgcmVzdWx0LnkgPSByZXN1bHQueiA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBjb25zdCBzY2FsYXIgPSAxIC8gTWF0aC5zcXJ0KDEgLSB3MiAqIHcyKTsKICAgICAgICByZXN1bHQueCA9IHF1YXRlcm5pb24ueCAqIHNjYWxhcjsKICAgICAgICByZXN1bHQueSA9IHF1YXRlcm5pb24ueSAqIHNjYWxhcjsKICAgICAgICByZXN1bHQueiA9IHF1YXRlcm5pb24ueiAqIHNjYWxhcjsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmNvbXB1dGVBbmdsZSA9IGZ1bmN0aW9uKHF1YXRlcm5pb24pIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInF1YXRlcm5pb24iLCBxdWF0ZXJuaW9uKTsKICAgICAgICBpZiAoTWF0aC5hYnMocXVhdGVybmlvbi53IC0gMSkgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjYpIHsKICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH0KICAgICAgICByZXR1cm4gMiAqIE1hdGguYWNvcyhxdWF0ZXJuaW9uLncpOwogICAgICB9OwogICAgICBsZXJwU2NyYXRjaDQgPSBuZXcgUXVhdGVybmlvbigpOwogICAgICBRdWF0ZXJuaW9uLmxlcnAgPSBmdW5jdGlvbihzdGFydCwgZW5kLCB0MiwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzdGFydCIsIHN0YXJ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImVuZCIsIGVuZCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ0IiwgdDIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBsZXJwU2NyYXRjaDQgPSBRdWF0ZXJuaW9uLm11bHRpcGx5QnlTY2FsYXIoZW5kLCB0MiwgbGVycFNjcmF0Y2g0KTsKICAgICAgICByZXN1bHQgPSBRdWF0ZXJuaW9uLm11bHRpcGx5QnlTY2FsYXIoc3RhcnQsIDEgLSB0MiwgcmVzdWx0KTsKICAgICAgICByZXR1cm4gUXVhdGVybmlvbi5hZGQobGVycFNjcmF0Y2g0LCByZXN1bHQsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNsZXJwRW5kTmVnYXRlZCA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIHNsZXJwU2NhbGVkUCA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIHNsZXJwU2NhbGVkUiA9IG5ldyBRdWF0ZXJuaW9uKCk7CiAgICAgIFF1YXRlcm5pb24uc2xlcnAgPSBmdW5jdGlvbihzdGFydCwgZW5kLCB0MiwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzdGFydCIsIHN0YXJ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImVuZCIsIGVuZCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ0IiwgdDIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBsZXQgZG90ID0gUXVhdGVybmlvbi5kb3Qoc3RhcnQsIGVuZCk7CiAgICAgICAgbGV0IHIyID0gZW5kOwogICAgICAgIGlmIChkb3QgPCAwKSB7CiAgICAgICAgICBkb3QgPSAtZG90OwogICAgICAgICAgcjIgPSBzbGVycEVuZE5lZ2F0ZWQgPSBRdWF0ZXJuaW9uLm5lZ2F0ZShlbmQsIHNsZXJwRW5kTmVnYXRlZCk7CiAgICAgICAgfQogICAgICAgIGlmICgxIC0gZG90IDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgICAgICByZXR1cm4gUXVhdGVybmlvbi5sZXJwKHN0YXJ0LCByMiwgdDIsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHRoZXRhID0gTWF0aC5hY29zKGRvdCk7CiAgICAgICAgc2xlcnBTY2FsZWRQID0gUXVhdGVybmlvbi5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgc3RhcnQsCiAgICAgICAgICBNYXRoLnNpbigoMSAtIHQyKSAqIHRoZXRhKSwKICAgICAgICAgIHNsZXJwU2NhbGVkUAogICAgICAgICk7CiAgICAgICAgc2xlcnBTY2FsZWRSID0gUXVhdGVybmlvbi5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgcjIsCiAgICAgICAgICBNYXRoLnNpbih0MiAqIHRoZXRhKSwKICAgICAgICAgIHNsZXJwU2NhbGVkUgogICAgICAgICk7CiAgICAgICAgcmVzdWx0ID0gUXVhdGVybmlvbi5hZGQoc2xlcnBTY2FsZWRQLCBzbGVycFNjYWxlZFIsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24ubXVsdGlwbHlCeVNjYWxhcihyZXN1bHQsIDEgLyBNYXRoLnNpbih0aGV0YSksIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24ubG9nID0gZnVuY3Rpb24ocXVhdGVybmlvbiwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxdWF0ZXJuaW9uIiwgcXVhdGVybmlvbik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGNvbnN0IHRoZXRhID0gTWF0aF9kZWZhdWx0LmFjb3NDbGFtcGVkKHF1YXRlcm5pb24udyk7CiAgICAgICAgbGV0IHRoZXRhT3ZlclNpblRoZXRhID0gMDsKICAgICAgICBpZiAodGhldGEgIT09IDApIHsKICAgICAgICAgIHRoZXRhT3ZlclNpblRoZXRhID0gdGhldGEgLyBNYXRoLnNpbih0aGV0YSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihxdWF0ZXJuaW9uLCB0aGV0YU92ZXJTaW5UaGV0YSwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5leHAgPSBmdW5jdGlvbihjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGNvbnN0IHRoZXRhID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShjYXJ0ZXNpYW4xMSk7CiAgICAgICAgbGV0IHNpblRoZXRhT3ZlclRoZXRhID0gMDsKICAgICAgICBpZiAodGhldGEgIT09IDApIHsKICAgICAgICAgIHNpblRoZXRhT3ZlclRoZXRhID0gTWF0aC5zaW4odGhldGEpIC8gdGhldGE7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gY2FydGVzaWFuMTEueCAqIHNpblRoZXRhT3ZlclRoZXRhOwogICAgICAgIHJlc3VsdC55ID0gY2FydGVzaWFuMTEueSAqIHNpblRoZXRhT3ZlclRoZXRhOwogICAgICAgIHJlc3VsdC56ID0gY2FydGVzaWFuMTEueiAqIHNpblRoZXRhT3ZlclRoZXRhOwogICAgICAgIHJlc3VsdC53ID0gTWF0aC5jb3ModGhldGEpOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIHNxdWFkU2NyYXRjaENhcnRlc2lhbjAgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNxdWFkU2NyYXRjaENhcnRlc2lhbjEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNxdWFkU2NyYXRjaFF1YXRlcm5pb24wID0gbmV3IFF1YXRlcm5pb24oKTsKICAgICAgc3F1YWRTY3JhdGNoUXVhdGVybmlvbjEgPSBuZXcgUXVhdGVybmlvbigpOwogICAgICBRdWF0ZXJuaW9uLmNvbXB1dGVJbm5lclF1YWRyYW5nbGUgPSBmdW5jdGlvbihxMCwgcTEyLCBxMjIsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicTAiLCBxMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxMSIsIHExMik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxMiIsIHEyMik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGNvbnN0IHFJbnYgPSBRdWF0ZXJuaW9uLmNvbmp1Z2F0ZShxMTIsIHNxdWFkU2NyYXRjaFF1YXRlcm5pb24wKTsKICAgICAgICBRdWF0ZXJuaW9uLm11bHRpcGx5KHFJbnYsIHEyMiwgc3F1YWRTY3JhdGNoUXVhdGVybmlvbjEpOwogICAgICAgIGNvbnN0IGNhcnQwID0gUXVhdGVybmlvbi5sb2coc3F1YWRTY3JhdGNoUXVhdGVybmlvbjEsIHNxdWFkU2NyYXRjaENhcnRlc2lhbjApOwogICAgICAgIFF1YXRlcm5pb24ubXVsdGlwbHkocUludiwgcTAsIHNxdWFkU2NyYXRjaFF1YXRlcm5pb24xKTsKICAgICAgICBjb25zdCBjYXJ0MSA9IFF1YXRlcm5pb24ubG9nKHNxdWFkU2NyYXRjaFF1YXRlcm5pb24xLCBzcXVhZFNjcmF0Y2hDYXJ0ZXNpYW4xKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNhcnQwLCBjYXJ0MSwgY2FydDApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGNhcnQwLCAwLjI1LCBjYXJ0MCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShjYXJ0MCwgY2FydDApOwogICAgICAgIFF1YXRlcm5pb24uZXhwKGNhcnQwLCBzcXVhZFNjcmF0Y2hRdWF0ZXJuaW9uMCk7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24ubXVsdGlwbHkocTEyLCBzcXVhZFNjcmF0Y2hRdWF0ZXJuaW9uMCwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5zcXVhZCA9IGZ1bmN0aW9uKHEwLCBxMTIsIHMwLCBzMSwgdDIsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicTAiLCBxMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxMSIsIHExMik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzMCIsIHMwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInMxIiwgczEpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigidCIsIHQyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgY29uc3Qgc2xlcnAwID0gUXVhdGVybmlvbi5zbGVycChxMCwgcTEyLCB0Miwgc3F1YWRTY3JhdGNoUXVhdGVybmlvbjApOwogICAgICAgIGNvbnN0IHNsZXJwMSA9IFF1YXRlcm5pb24uc2xlcnAoczAsIHMxLCB0Miwgc3F1YWRTY3JhdGNoUXVhdGVybmlvbjEpOwogICAgICAgIHJldHVybiBRdWF0ZXJuaW9uLnNsZXJwKHNsZXJwMCwgc2xlcnAxLCAyICogdDIgKiAoMSAtIHQyKSwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgZmFzdFNsZXJwU2NyYXRjaFF1YXRlcm5pb24gPSBuZXcgUXVhdGVybmlvbigpOwogICAgICBvcG11ID0gMS45MDExMDc0NTM1MTczMDAzOwogICAgICB1ID0gRmVhdHVyZURldGVjdGlvbl9kZWZhdWx0LnN1cHBvcnRzVHlwZWRBcnJheXMoKSA/IG5ldyBGbG9hdDMyQXJyYXkoOCkgOiBbXTsKICAgICAgdiA9IEZlYXR1cmVEZXRlY3Rpb25fZGVmYXVsdC5zdXBwb3J0c1R5cGVkQXJyYXlzKCkgPyBuZXcgRmxvYXQzMkFycmF5KDgpIDogW107CiAgICAgIGJUID0gRmVhdHVyZURldGVjdGlvbl9kZWZhdWx0LnN1cHBvcnRzVHlwZWRBcnJheXMoKSA/IG5ldyBGbG9hdDMyQXJyYXkoOCkgOiBbXTsKICAgICAgYkQgPSBGZWF0dXJlRGV0ZWN0aW9uX2RlZmF1bHQuc3VwcG9ydHNUeXBlZEFycmF5cygpID8gbmV3IEZsb2F0MzJBcnJheSg4KSA6IFtdOwogICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgNzsgKytpMikgewogICAgICAgIGNvbnN0IHMyID0gaTIgKyAxOwogICAgICAgIGNvbnN0IHQyID0gMiAqIHMyICsgMTsKICAgICAgICB1W2kyXSA9IDEgLyAoczIgKiB0Mik7CiAgICAgICAgdltpMl0gPSBzMiAvIHQyOwogICAgICB9CiAgICAgIHVbN10gPSBvcG11IC8gKDggKiAxNyk7CiAgICAgIHZbN10gPSBvcG11ICogOCAvIDE3OwogICAgICBRdWF0ZXJuaW9uLmZhc3RTbGVycCA9IGZ1bmN0aW9uKHN0YXJ0LCBlbmQsIHQyLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInN0YXJ0Iiwgc3RhcnQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZW5kIiwgZW5kKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInQiLCB0Mik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGxldCB4MiA9IFF1YXRlcm5pb24uZG90KHN0YXJ0LCBlbmQpOwogICAgICAgIGxldCBzaWduMzsKICAgICAgICBpZiAoeDIgPj0gMCkgewogICAgICAgICAgc2lnbjMgPSAxOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBzaWduMyA9IC0xOwogICAgICAgICAgeDIgPSAteDI7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHhtMSA9IHgyIC0gMTsKICAgICAgICBjb25zdCBkMiA9IDEgLSB0MjsKICAgICAgICBjb25zdCBzcXJUID0gdDIgKiB0MjsKICAgICAgICBjb25zdCBzcXJEID0gZDIgKiBkMjsKICAgICAgICBmb3IgKGxldCBpMiA9IDc7IGkyID49IDA7IC0taTIpIHsKICAgICAgICAgIGJUW2kyXSA9ICh1W2kyXSAqIHNxclQgLSB2W2kyXSkgKiB4bTE7CiAgICAgICAgICBiRFtpMl0gPSAodVtpMl0gKiBzcXJEIC0gdltpMl0pICogeG0xOwogICAgICAgIH0KICAgICAgICBjb25zdCBjVCA9IHNpZ24zICogdDIgKiAoMSArIGJUWzBdICogKDEgKyBiVFsxXSAqICgxICsgYlRbMl0gKiAoMSArIGJUWzNdICogKDEgKyBiVFs0XSAqICgxICsgYlRbNV0gKiAoMSArIGJUWzZdICogKDEgKyBiVFs3XSkpKSkpKSkpOwogICAgICAgIGNvbnN0IGNEID0gZDIgKiAoMSArIGJEWzBdICogKDEgKyBiRFsxXSAqICgxICsgYkRbMl0gKiAoMSArIGJEWzNdICogKDEgKyBiRFs0XSAqICgxICsgYkRbNV0gKiAoMSArIGJEWzZdICogKDEgKyBiRFs3XSkpKSkpKSkpOwogICAgICAgIGNvbnN0IHRlbXAgPSBRdWF0ZXJuaW9uLm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICBzdGFydCwKICAgICAgICAgIGNELAogICAgICAgICAgZmFzdFNsZXJwU2NyYXRjaFF1YXRlcm5pb24KICAgICAgICApOwogICAgICAgIFF1YXRlcm5pb24ubXVsdGlwbHlCeVNjYWxhcihlbmQsIGNULCByZXN1bHQpOwogICAgICAgIHJldHVybiBRdWF0ZXJuaW9uLmFkZCh0ZW1wLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24uZmFzdFNxdWFkID0gZnVuY3Rpb24ocTAsIHExMiwgczAsIHMxLCB0MiwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJxMCIsIHEwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInExIiwgcTEyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInMwIiwgczApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiczEiLCBzMSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ0IiwgdDIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCBzbGVycDAgPSBRdWF0ZXJuaW9uLmZhc3RTbGVycChxMCwgcTEyLCB0Miwgc3F1YWRTY3JhdGNoUXVhdGVybmlvbjApOwogICAgICAgIGNvbnN0IHNsZXJwMSA9IFF1YXRlcm5pb24uZmFzdFNsZXJwKHMwLCBzMSwgdDIsIHNxdWFkU2NyYXRjaFF1YXRlcm5pb24xKTsKICAgICAgICByZXR1cm4gUXVhdGVybmlvbi5mYXN0U2xlcnAoc2xlcnAwLCBzbGVycDEsIDIgKiB0MiAqICgxIC0gdDIpLCByZXN1bHQpOwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLmVxdWFscyA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIGxlZnQueCA9PT0gcmlnaHQueCAmJiBsZWZ0LnkgPT09IHJpZ2h0LnkgJiYgbGVmdC56ID09PSByaWdodC56ICYmIGxlZnQudyA9PT0gcmlnaHQudzsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5lcXVhbHNFcHNpbG9uID0gZnVuY3Rpb24obGVmdCwgcmlnaHQsIGVwc2lsb24pIHsKICAgICAgICBlcHNpbG9uID0gZXBzaWxvbiA/PyAwOwogICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBNYXRoLmFicyhsZWZ0LnggLSByaWdodC54KSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnQueSAtIHJpZ2h0LnkpIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdC56IC0gcmlnaHQueikgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0LncgLSByaWdodC53KSA8PSBlcHNpbG9uOwogICAgICB9OwogICAgICBRdWF0ZXJuaW9uLlpFUk8gPSBPYmplY3QuZnJlZXplKG5ldyBRdWF0ZXJuaW9uKDAsIDAsIDAsIDApKTsKICAgICAgUXVhdGVybmlvbi5JREVOVElUWSA9IE9iamVjdC5mcmVlemUobmV3IFF1YXRlcm5pb24oMCwgMCwgMCwgMSkpOwogICAgICBRdWF0ZXJuaW9uLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uKHJlc3VsdCkgewogICAgICAgIHJldHVybiBRdWF0ZXJuaW9uLmNsb25lKHRoaXMsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24ucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uKHJpZ2h0KSB7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24uZXF1YWxzKHRoaXMsIHJpZ2h0KTsKICAgICAgfTsKICAgICAgUXVhdGVybmlvbi5wcm90b3R5cGUuZXF1YWxzRXBzaWxvbiA9IGZ1bmN0aW9uKHJpZ2h0LCBlcHNpbG9uKSB7CiAgICAgICAgcmV0dXJuIFF1YXRlcm5pb24uZXF1YWxzRXBzaWxvbih0aGlzLCByaWdodCwgZXBzaWxvbik7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb24ucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIGAoJHt0aGlzLnh9LCAke3RoaXMueX0sICR7dGhpcy56fSwgJHt0aGlzLnd9KWA7CiAgICAgIH07CiAgICAgIFF1YXRlcm5pb25fZGVmYXVsdCA9IFF1YXRlcm5pb247CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9UcmFuc2Zvcm1zLmpzCiAgdmFyIFRyYW5zZm9ybXMsIHZlY3RvclByb2R1Y3RMb2NhbEZyYW1lLCBkZWdlbmVyYXRlUG9zaXRpb25Mb2NhbEZyYW1lLCBsb2NhbEZyYW1lVG9GaXhlZEZyYW1lQ2FjaGUsIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4sIHNjcmF0Y2hGaXJzdENhcnRlc2lhbiwgc2NyYXRjaFNlY29uZENhcnRlc2lhbiwgc2NyYXRjaFRoaXJkQ2FydGVzaWFuLCBzY3JhdGNoSFBSUXVhdGVybmlvbjIsIHNjcmF0Y2hTY2FsZSwgc2NyYXRjaEhQUk1hdHJpeDQsIHNjcmF0Y2hFTlVNYXRyaXg0LCBzY3JhdGNoSFBSTWF0cml4Mywgbm9TY2FsZSwgaHByQ2VudGVyU2NyYXRjaCwgZmZTY3JhdGNoLCBocHJUcmFuc2Zvcm1TY3JhdGNoLCBocHJSb3RhdGlvblNjcmF0Y2gsIGhwclF1YXRlcm5pb25TY3JhdGNoLCBnbXN0Q29uc3RhbnQwLCBnbXN0Q29uc3RhbnQxLCBnbXN0Q29uc3RhbnQyLCBnbXN0Q29uc3RhbnQzLCByYXRlQ29lZiwgd2dzODRXUlByZWNlc3NpbmcsIHR3b1BpT3ZlclNlY29uZHNJbkRheSwgZGF0ZUluVXRjLCB0dE1pbnVzVGFpLCBqMjAwMHR0RGF5cywgVGR0TWludXNUYWksIEoyMDAwZCwgc2NyYXRjaEhwciwgc2NyYXRjaFJvdGF0aW9uTWF0cml4LCBkYXRlU2NyYXRjaCwgeHlzU2NyYXRjaCwgZW9wU2NyYXRjaCwgcm90YXRpb24xU2NyYXRjaCwgcm90YXRpb24yU2NyYXRjaCwgcG9pbnRUb1dpbmRvd0Nvb3JkaW5hdGVzVGVtcCwgbm9ybWFsU2NyYXRjaCwgcmlnaHRTY3JhdGNoLCB1cFNjcmF0Y2gsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMsIHNjcmF0Y2hDYXJ0ZXNpYW4zUHJvamVjdGlvbiwgc2NyYXRjaENlbnRlciwgc2NyYXRjaFJvdGF0aW9uLCBzY3JhdGNoRnJvbUVOVSwgc2NyYXRjaFRvRU5VLCBUcmFuc2Zvcm1zX2RlZmF1bHQ7CiAgdmFyIGluaXRfVHJhbnNmb3JtcyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVHJhbnNmb3Jtcy5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW40KCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVycygpOwogICAgICBpbml0X0VhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzU2FtcGxlKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfSGVhZGluZ1BpdGNoUm9sbCgpOwogICAgICBpbml0X0lhdTIwMDZYeXNEYXRhKCk7CiAgICAgIGluaXRfSWF1MjAwNlh5c1NhbXBsZSgpOwogICAgICBpbml0X0p1bGlhbkRhdGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9RdWF0ZXJuaW9uKCk7CiAgICAgIGluaXRfVGltZUNvbnN0YW50cygpOwogICAgICBUcmFuc2Zvcm1zID0ge307CiAgICAgIHZlY3RvclByb2R1Y3RMb2NhbEZyYW1lID0gewogICAgICAgIHVwOiB7CiAgICAgICAgICBzb3V0aDogImVhc3QiLAogICAgICAgICAgbm9ydGg6ICJ3ZXN0IiwKICAgICAgICAgIHdlc3Q6ICJzb3V0aCIsCiAgICAgICAgICBlYXN0OiAibm9ydGgiCiAgICAgICAgfSwKICAgICAgICBkb3duOiB7CiAgICAgICAgICBzb3V0aDogIndlc3QiLAogICAgICAgICAgbm9ydGg6ICJlYXN0IiwKICAgICAgICAgIHdlc3Q6ICJub3J0aCIsCiAgICAgICAgICBlYXN0OiAic291dGgiCiAgICAgICAgfSwKICAgICAgICBzb3V0aDogewogICAgICAgICAgdXA6ICJ3ZXN0IiwKICAgICAgICAgIGRvd246ICJlYXN0IiwKICAgICAgICAgIHdlc3Q6ICJkb3duIiwKICAgICAgICAgIGVhc3Q6ICJ1cCIKICAgICAgICB9LAogICAgICAgIG5vcnRoOiB7CiAgICAgICAgICB1cDogImVhc3QiLAogICAgICAgICAgZG93bjogIndlc3QiLAogICAgICAgICAgd2VzdDogInVwIiwKICAgICAgICAgIGVhc3Q6ICJkb3duIgogICAgICAgIH0sCiAgICAgICAgd2VzdDogewogICAgICAgICAgdXA6ICJub3J0aCIsCiAgICAgICAgICBkb3duOiAic291dGgiLAogICAgICAgICAgbm9ydGg6ICJkb3duIiwKICAgICAgICAgIHNvdXRoOiAidXAiCiAgICAgICAgfSwKICAgICAgICBlYXN0OiB7CiAgICAgICAgICB1cDogInNvdXRoIiwKICAgICAgICAgIGRvd246ICJub3J0aCIsCiAgICAgICAgICBub3J0aDogInVwIiwKICAgICAgICAgIHNvdXRoOiAiZG93biIKICAgICAgICB9CiAgICAgIH07CiAgICAgIGRlZ2VuZXJhdGVQb3NpdGlvbkxvY2FsRnJhbWUgPSB7CiAgICAgICAgbm9ydGg6IFstMSwgMCwgMF0sCiAgICAgICAgZWFzdDogWzAsIDEsIDBdLAogICAgICAgIHVwOiBbMCwgMCwgMV0sCiAgICAgICAgc291dGg6IFsxLCAwLCAwXSwKICAgICAgICB3ZXN0OiBbMCwgLTEsIDBdLAogICAgICAgIGRvd246IFswLCAwLCAtMV0KICAgICAgfTsKICAgICAgbG9jYWxGcmFtZVRvRml4ZWRGcmFtZUNhY2hlID0ge307CiAgICAgIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4gPSB7CiAgICAgICAgZWFzdDogbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5vcnRoOiBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgdXA6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICB3ZXN0OiBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgc291dGg6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBkb3duOiBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkKICAgICAgfTsKICAgICAgc2NyYXRjaEZpcnN0Q2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoU2Vjb25kQ2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVGhpcmRDYXJ0ZXNpYW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFRyYW5zZm9ybXMubG9jYWxGcmFtZVRvRml4ZWRGcmFtZUdlbmVyYXRvciA9IGZ1bmN0aW9uKGZpcnN0QXhpcywgc2Vjb25kQXhpcykgewogICAgICAgIGlmICghdmVjdG9yUHJvZHVjdExvY2FsRnJhbWUuaGFzT3duUHJvcGVydHkoZmlyc3RBeGlzKSB8fCAhdmVjdG9yUHJvZHVjdExvY2FsRnJhbWVbZmlyc3RBeGlzXS5oYXNPd25Qcm9wZXJ0eShzZWNvbmRBeGlzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJmaXJzdEF4aXMgYW5kIHNlY29uZEF4aXMgbXVzdCBiZSBlYXN0LCBub3J0aCwgdXAsIHdlc3QsIHNvdXRoIG9yIGRvd24uIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdGhpcmRBeGlzID0gdmVjdG9yUHJvZHVjdExvY2FsRnJhbWVbZmlyc3RBeGlzXVtzZWNvbmRBeGlzXTsKICAgICAgICBsZXQgcmVzdWx0YXQ7CiAgICAgICAgY29uc3QgaGFzaEF4aXMgPSBmaXJzdEF4aXMgKyBzZWNvbmRBeGlzOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobG9jYWxGcmFtZVRvRml4ZWRGcmFtZUNhY2hlW2hhc2hBeGlzXSkpIHsKICAgICAgICAgIHJlc3VsdGF0ID0gbG9jYWxGcmFtZVRvRml4ZWRGcmFtZUNhY2hlW2hhc2hBeGlzXTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmVzdWx0YXQgPSBmdW5jdGlvbihvcmlnaW4sIGVsbGlwc29pZCwgcmVzdWx0KSB7CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9yaWdpbikpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3JpZ2luIGlzIHJlcXVpcmVkLiIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChpc05hTihvcmlnaW4ueCkgfHwgaXNOYU4ob3JpZ2luLnkpIHx8IGlzTmFOKG9yaWdpbi56KSkgewogICAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcmlnaW4gaGFzIGEgTmFOIGNvbXBvbmVudCIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgICByZXN1bHQgPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKG9yaWdpbiwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTQpKSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgICAgIGRlZ2VuZXJhdGVQb3NpdGlvbkxvY2FsRnJhbWVbZmlyc3RBeGlzXSwKICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICBzY3JhdGNoRmlyc3RDYXJ0ZXNpYW4KICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgICAgICBkZWdlbmVyYXRlUG9zaXRpb25Mb2NhbEZyYW1lW3NlY29uZEF4aXNdLAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIHNjcmF0Y2hTZWNvbmRDYXJ0ZXNpYW4KICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgICAgICBkZWdlbmVyYXRlUG9zaXRpb25Mb2NhbEZyYW1lW3RoaXJkQXhpc10sCiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgc2NyYXRjaFRoaXJkQ2FydGVzaWFuCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihvcmlnaW4ueCwgMCwgTWF0aF9kZWZhdWx0LkVQU0lMT04xNCkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24ob3JpZ2luLnksIDAsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTQpKSB7CiAgICAgICAgICAgICAgY29uc3Qgc2lnbjMgPSBNYXRoX2RlZmF1bHQuc2lnbihvcmlnaW4ueik7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgICAgIGRlZ2VuZXJhdGVQb3NpdGlvbkxvY2FsRnJhbWVbZmlyc3RBeGlzXSwKICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICBzY3JhdGNoRmlyc3RDYXJ0ZXNpYW4KICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmIChmaXJzdEF4aXMgIT09ICJlYXN0IiAmJiBmaXJzdEF4aXMgIT09ICJ3ZXN0IikgewogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICAgICAgICAgIHNjcmF0Y2hGaXJzdENhcnRlc2lhbiwKICAgICAgICAgICAgICAgICAgc2lnbjMsCiAgICAgICAgICAgICAgICAgIHNjcmF0Y2hGaXJzdENhcnRlc2lhbgogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgICAgIGRlZ2VuZXJhdGVQb3NpdGlvbkxvY2FsRnJhbWVbc2Vjb25kQXhpc10sCiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgc2NyYXRjaFNlY29uZENhcnRlc2lhbgogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgaWYgKHNlY29uZEF4aXMgIT09ICJlYXN0IiAmJiBzZWNvbmRBeGlzICE9PSAid2VzdCIpIHsKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICAgICAgICBzY3JhdGNoU2Vjb25kQ2FydGVzaWFuLAogICAgICAgICAgICAgICAgICBzaWduMywKICAgICAgICAgICAgICAgICAgc2NyYXRjaFNlY29uZENhcnRlc2lhbgogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgICAgIGRlZ2VuZXJhdGVQb3NpdGlvbkxvY2FsRnJhbWVbdGhpcmRBeGlzXSwKICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICBzY3JhdGNoVGhpcmRDYXJ0ZXNpYW4KICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmICh0aGlyZEF4aXMgIT09ICJlYXN0IiAmJiB0aGlyZEF4aXMgIT09ICJ3ZXN0IikgewogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICAgICAgICAgIHNjcmF0Y2hUaGlyZENhcnRlc2lhbiwKICAgICAgICAgICAgICAgICAgc2lnbjMsCiAgICAgICAgICAgICAgICAgIHNjcmF0Y2hUaGlyZENhcnRlc2lhbgogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZWxsaXBzb2lkID0gZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICAgICAgICAgICAgZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChvcmlnaW4sIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4udXApOwogICAgICAgICAgICAgIGNvbnN0IHVwID0gc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi51cDsKICAgICAgICAgICAgICBjb25zdCBlYXN0ID0gc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi5lYXN0OwogICAgICAgICAgICAgIGVhc3QueCA9IC1vcmlnaW4ueTsKICAgICAgICAgICAgICBlYXN0LnkgPSBvcmlnaW4ueDsKICAgICAgICAgICAgICBlYXN0LnogPSAwOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoZWFzdCwgc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi5lYXN0KTsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModXAsIGVhc3QsIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4ubm9ydGgpOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICAgICAgc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi51cCwKICAgICAgICAgICAgICAgIC0xLAogICAgICAgICAgICAgICAgc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi5kb3duCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4uZWFzdCwKICAgICAgICAgICAgICAgIC0xLAogICAgICAgICAgICAgICAgc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbi53ZXN0CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4ubm9ydGgsCiAgICAgICAgICAgICAgICAtMSwKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW4uc291dGgKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIHNjcmF0Y2hGaXJzdENhcnRlc2lhbiA9IHNjcmF0Y2hDYWxjdWxhdGVDYXJ0ZXNpYW5bZmlyc3RBeGlzXTsKICAgICAgICAgICAgICBzY3JhdGNoU2Vjb25kQ2FydGVzaWFuID0gc2NyYXRjaENhbGN1bGF0ZUNhcnRlc2lhbltzZWNvbmRBeGlzXTsKICAgICAgICAgICAgICBzY3JhdGNoVGhpcmRDYXJ0ZXNpYW4gPSBzY3JhdGNoQ2FsY3VsYXRlQ2FydGVzaWFuW3RoaXJkQXhpc107CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmVzdWx0WzBdID0gc2NyYXRjaEZpcnN0Q2FydGVzaWFuLng7CiAgICAgICAgICAgIHJlc3VsdFsxXSA9IHNjcmF0Y2hGaXJzdENhcnRlc2lhbi55OwogICAgICAgICAgICByZXN1bHRbMl0gPSBzY3JhdGNoRmlyc3RDYXJ0ZXNpYW4uejsKICAgICAgICAgICAgcmVzdWx0WzNdID0gMDsKICAgICAgICAgICAgcmVzdWx0WzRdID0gc2NyYXRjaFNlY29uZENhcnRlc2lhbi54OwogICAgICAgICAgICByZXN1bHRbNV0gPSBzY3JhdGNoU2Vjb25kQ2FydGVzaWFuLnk7CiAgICAgICAgICAgIHJlc3VsdFs2XSA9IHNjcmF0Y2hTZWNvbmRDYXJ0ZXNpYW4uejsKICAgICAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICAgICAgcmVzdWx0WzhdID0gc2NyYXRjaFRoaXJkQ2FydGVzaWFuLng7CiAgICAgICAgICAgIHJlc3VsdFs5XSA9IHNjcmF0Y2hUaGlyZENhcnRlc2lhbi55OwogICAgICAgICAgICByZXN1bHRbMTBdID0gc2NyYXRjaFRoaXJkQ2FydGVzaWFuLno7CiAgICAgICAgICAgIHJlc3VsdFsxMV0gPSAwOwogICAgICAgICAgICByZXN1bHRbMTJdID0gb3JpZ2luLng7CiAgICAgICAgICAgIHJlc3VsdFsxM10gPSBvcmlnaW4ueTsKICAgICAgICAgICAgcmVzdWx0WzE0XSA9IG9yaWdpbi56OwogICAgICAgICAgICByZXN1bHRbMTVdID0gMTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH07CiAgICAgICAgICBsb2NhbEZyYW1lVG9GaXhlZEZyYW1lQ2FjaGVbaGFzaEF4aXNdID0gcmVzdWx0YXQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXN1bHRhdDsKICAgICAgfTsKICAgICAgVHJhbnNmb3Jtcy5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZSA9IFRyYW5zZm9ybXMubG9jYWxGcmFtZVRvRml4ZWRGcmFtZUdlbmVyYXRvcigKICAgICAgICAiZWFzdCIsCiAgICAgICAgIm5vcnRoIgogICAgICApOwogICAgICBUcmFuc2Zvcm1zLm5vcnRoRWFzdERvd25Ub0ZpeGVkRnJhbWUgPSBUcmFuc2Zvcm1zLmxvY2FsRnJhbWVUb0ZpeGVkRnJhbWVHZW5lcmF0b3IoIm5vcnRoIiwgImVhc3QiKTsKICAgICAgVHJhbnNmb3Jtcy5ub3J0aFVwRWFzdFRvRml4ZWRGcmFtZSA9IFRyYW5zZm9ybXMubG9jYWxGcmFtZVRvRml4ZWRGcmFtZUdlbmVyYXRvcigKICAgICAgICAibm9ydGgiLAogICAgICAgICJ1cCIKICAgICAgKTsKICAgICAgVHJhbnNmb3Jtcy5ub3J0aFdlc3RVcFRvRml4ZWRGcmFtZSA9IFRyYW5zZm9ybXMubG9jYWxGcmFtZVRvRml4ZWRGcmFtZUdlbmVyYXRvcigKICAgICAgICAibm9ydGgiLAogICAgICAgICJ3ZXN0IgogICAgICApOwogICAgICBzY3JhdGNoSFBSUXVhdGVybmlvbjIgPSBuZXcgUXVhdGVybmlvbl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hTY2FsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoMSwgMSwgMSk7CiAgICAgIHNjcmF0Y2hIUFJNYXRyaXg0ID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBUcmFuc2Zvcm1zLmhlYWRpbmdQaXRjaFJvbGxUb0ZpeGVkRnJhbWUgPSBmdW5jdGlvbihvcmlnaW4sIGhlYWRpbmdQaXRjaFJvbGwsIGVsbGlwc29pZCwgZml4ZWRGcmFtZVRyYW5zZm9ybSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJIZWFkaW5nUGl0Y2hSb2xsIiwgaGVhZGluZ1BpdGNoUm9sbCk7CiAgICAgICAgZml4ZWRGcmFtZVRyYW5zZm9ybSA9IGZpeGVkRnJhbWVUcmFuc2Zvcm0gPz8gVHJhbnNmb3Jtcy5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZTsKICAgICAgICBjb25zdCBocHJRdWF0ZXJuaW9uID0gUXVhdGVybmlvbl9kZWZhdWx0LmZyb21IZWFkaW5nUGl0Y2hSb2xsKAogICAgICAgICAgaGVhZGluZ1BpdGNoUm9sbCwKICAgICAgICAgIHNjcmF0Y2hIUFJRdWF0ZXJuaW9uMgogICAgICAgICk7CiAgICAgICAgY29uc3QgaHByTWF0cml4ID0gTWF0cml4NF9kZWZhdWx0LmZyb21UcmFuc2xhdGlvblF1YXRlcm5pb25Sb3RhdGlvblNjYWxlKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sCiAgICAgICAgICBocHJRdWF0ZXJuaW9uLAogICAgICAgICAgc2NyYXRjaFNjYWxlLAogICAgICAgICAgc2NyYXRjaEhQUk1hdHJpeDQKICAgICAgICApOwogICAgICAgIHJlc3VsdCA9IGZpeGVkRnJhbWVUcmFuc2Zvcm0ob3JpZ2luLCBlbGxpcHNvaWQsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseShyZXN1bHQsIGhwck1hdHJpeCwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVOVU1hdHJpeDQgPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hIUFJNYXRyaXgzID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBUcmFuc2Zvcm1zLmhlYWRpbmdQaXRjaFJvbGxRdWF0ZXJuaW9uID0gZnVuY3Rpb24ob3JpZ2luLCBoZWFkaW5nUGl0Y2hSb2xsLCBlbGxpcHNvaWQsIGZpeGVkRnJhbWVUcmFuc2Zvcm0sIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiSGVhZGluZ1BpdGNoUm9sbCIsIGhlYWRpbmdQaXRjaFJvbGwpOwogICAgICAgIGNvbnN0IHRyYW5zZm9ybTIgPSBUcmFuc2Zvcm1zLmhlYWRpbmdQaXRjaFJvbGxUb0ZpeGVkRnJhbWUoCiAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICBoZWFkaW5nUGl0Y2hSb2xsLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZml4ZWRGcmFtZVRyYW5zZm9ybSwKICAgICAgICAgIHNjcmF0Y2hFTlVNYXRyaXg0CiAgICAgICAgKTsKICAgICAgICBjb25zdCByb3RhdGlvbiA9IE1hdHJpeDRfZGVmYXVsdC5nZXRNYXRyaXgzKHRyYW5zZm9ybTIsIHNjcmF0Y2hIUFJNYXRyaXgzKTsKICAgICAgICByZXR1cm4gUXVhdGVybmlvbl9kZWZhdWx0LmZyb21Sb3RhdGlvbk1hdHJpeChyb3RhdGlvbiwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgbm9TY2FsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoMSwgMSwgMSk7CiAgICAgIGhwckNlbnRlclNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZmU2NyYXRjaCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgaHByVHJhbnNmb3JtU2NyYXRjaCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgaHByUm90YXRpb25TY3JhdGNoID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBocHJRdWF0ZXJuaW9uU2NyYXRjaCA9IG5ldyBRdWF0ZXJuaW9uX2RlZmF1bHQoKTsKICAgICAgVHJhbnNmb3Jtcy5maXhlZEZyYW1lVG9IZWFkaW5nUGl0Y2hSb2xsID0gZnVuY3Rpb24odHJhbnNmb3JtMiwgZWxsaXBzb2lkLCBmaXhlZEZyYW1lVHJhbnNmb3JtLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInRyYW5zZm9ybSIsIHRyYW5zZm9ybTIpOwogICAgICAgIGVsbGlwc29pZCA9IGVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgIGZpeGVkRnJhbWVUcmFuc2Zvcm0gPSBmaXhlZEZyYW1lVHJhbnNmb3JtID8/IFRyYW5zZm9ybXMuZWFzdE5vcnRoVXBUb0ZpeGVkRnJhbWU7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEhlYWRpbmdQaXRjaFJvbGxfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBjZW50ZXIgPSBNYXRyaXg0X2RlZmF1bHQuZ2V0VHJhbnNsYXRpb24odHJhbnNmb3JtMiwgaHByQ2VudGVyU2NyYXRjaCk7CiAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMoY2VudGVyLCBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTykpIHsKICAgICAgICAgIHJlc3VsdC5oZWFkaW5nID0gMDsKICAgICAgICAgIHJlc3VsdC5waXRjaCA9IDA7CiAgICAgICAgICByZXN1bHQucm9sbCA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBsZXQgdG9GaXhlZEZyYW1lID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2VUcmFuc2Zvcm1hdGlvbigKICAgICAgICAgIGZpeGVkRnJhbWVUcmFuc2Zvcm0oY2VudGVyLCBlbGxpcHNvaWQsIGZmU2NyYXRjaCksCiAgICAgICAgICBmZlNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGxldCB0cmFuc2Zvcm1Db3B5ID0gTWF0cml4NF9kZWZhdWx0LnNldFNjYWxlKHRyYW5zZm9ybTIsIG5vU2NhbGUsIGhwclRyYW5zZm9ybVNjcmF0Y2gpOwogICAgICAgIHRyYW5zZm9ybUNvcHkgPSBNYXRyaXg0X2RlZmF1bHQuc2V0VHJhbnNsYXRpb24oCiAgICAgICAgICB0cmFuc2Zvcm1Db3B5LAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sCiAgICAgICAgICB0cmFuc2Zvcm1Db3B5CiAgICAgICAgKTsKICAgICAgICB0b0ZpeGVkRnJhbWUgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkodG9GaXhlZEZyYW1lLCB0cmFuc2Zvcm1Db3B5LCB0b0ZpeGVkRnJhbWUpOwogICAgICAgIGxldCBxdWF0ZXJuaW9uUm90YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuZnJvbVJvdGF0aW9uTWF0cml4KAogICAgICAgICAgTWF0cml4NF9kZWZhdWx0LmdldE1hdHJpeDModG9GaXhlZEZyYW1lLCBocHJSb3RhdGlvblNjcmF0Y2gpLAogICAgICAgICAgaHByUXVhdGVybmlvblNjcmF0Y2gKICAgICAgICApOwogICAgICAgIHF1YXRlcm5pb25Sb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICBxdWF0ZXJuaW9uUm90YXRpb24sCiAgICAgICAgICBxdWF0ZXJuaW9uUm90YXRpb24KICAgICAgICApOwogICAgICAgIHJldHVybiBIZWFkaW5nUGl0Y2hSb2xsX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24ocXVhdGVybmlvblJvdGF0aW9uLCByZXN1bHQpOwogICAgICB9OwogICAgICBnbXN0Q29uc3RhbnQwID0gNiAqIDM2MDAgKyA0MSAqIDYwICsgNTAuNTQ4NDE7CiAgICAgIGdtc3RDb25zdGFudDEgPSA4NjQwMTg0ODEyODY2ZS02OwogICAgICBnbXN0Q29uc3RhbnQyID0gMC4wOTMxMDQ7CiAgICAgIGdtc3RDb25zdGFudDMgPSAtNjJlLTc7CiAgICAgIHJhdGVDb2VmID0gMTE3NzI3NTgzODQ2NjhlLTMyOwogICAgICB3Z3M4NFdSUHJlY2Vzc2luZyA9IDcyOTIxMTU4NTUzZS0xNTsKICAgICAgdHdvUGlPdmVyU2Vjb25kc0luRGF5ID0gTWF0aF9kZWZhdWx0LlRXT19QSSAvIDg2NDAwOwogICAgICBkYXRlSW5VdGMgPSBuZXcgSnVsaWFuRGF0ZV9kZWZhdWx0KCk7CiAgICAgIFRyYW5zZm9ybXMuY29tcHV0ZUljcmZUb0NlbnRyYWxCb2R5Rml4ZWRNYXRyaXggPSBmdW5jdGlvbihkYXRlLCByZXN1bHQpIHsKICAgICAgICBsZXQgdHJhbnNmb3JtTWF0cml4ID0gVHJhbnNmb3Jtcy5jb21wdXRlSWNyZlRvRml4ZWRNYXRyaXgoZGF0ZSwgcmVzdWx0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0cmFuc2Zvcm1NYXRyaXgpKSB7CiAgICAgICAgICB0cmFuc2Zvcm1NYXRyaXggPSBUcmFuc2Zvcm1zLmNvbXB1dGVUZW1lVG9Qc2V1ZG9GaXhlZE1hdHJpeChkYXRlLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdHJhbnNmb3JtTWF0cml4OwogICAgICB9OwogICAgICBUcmFuc2Zvcm1zLmNvbXB1dGVUZW1lVG9Qc2V1ZG9GaXhlZE1hdHJpeCA9IGZ1bmN0aW9uKGRhdGUsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRhdGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGF0ZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgZGF0ZUluVXRjID0gSnVsaWFuRGF0ZV9kZWZhdWx0LmFkZFNlY29uZHMoCiAgICAgICAgICBkYXRlLAogICAgICAgICAgLUp1bGlhbkRhdGVfZGVmYXVsdC5jb21wdXRlVGFpTWludXNVdGMoZGF0ZSksCiAgICAgICAgICBkYXRlSW5VdGMKICAgICAgICApOwogICAgICAgIGNvbnN0IHV0Y0RheU51bWJlciA9IGRhdGVJblV0Yy5kYXlOdW1iZXI7CiAgICAgICAgY29uc3QgdXRjU2Vjb25kc0ludG9EYXkgPSBkYXRlSW5VdGMuc2Vjb25kc09mRGF5OwogICAgICAgIGxldCB0MjsKICAgICAgICBjb25zdCBkaWZmRGF5cyA9IHV0Y0RheU51bWJlciAtIDI0NTE1NDU7CiAgICAgICAgaWYgKHV0Y1NlY29uZHNJbnRvRGF5ID49IDQzMjAwKSB7CiAgICAgICAgICB0MiA9IChkaWZmRGF5cyArIDAuNSkgLyBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuREFZU19QRVJfSlVMSUFOX0NFTlRVUlk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHQyID0gKGRpZmZEYXlzIC0gMC41KSAvIFRpbWVDb25zdGFudHNfZGVmYXVsdC5EQVlTX1BFUl9KVUxJQU5fQ0VOVFVSWTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZ21zdDAgPSBnbXN0Q29uc3RhbnQwICsgdDIgKiAoZ21zdENvbnN0YW50MSArIHQyICogKGdtc3RDb25zdGFudDIgKyB0MiAqIGdtc3RDb25zdGFudDMpKTsKICAgICAgICBjb25zdCBhbmdsZSA9IGdtc3QwICogdHdvUGlPdmVyU2Vjb25kc0luRGF5ICUgTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICBjb25zdCByYXRpbyA9IHdnczg0V1JQcmVjZXNzaW5nICsgcmF0ZUNvZWYgKiAodXRjRGF5TnVtYmVyIC0gMjQ1MTU0NTVlLTEpOwogICAgICAgIGNvbnN0IHNlY29uZHNTaW5jZU1pZG5pZ2h0ID0gKHV0Y1NlY29uZHNJbnRvRGF5ICsgVGltZUNvbnN0YW50c19kZWZhdWx0LlNFQ09ORFNfUEVSX0RBWSAqIDAuNSkgJSBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZOwogICAgICAgIGNvbnN0IGdoYSA9IGFuZ2xlICsgcmF0aW8gKiBzZWNvbmRzU2luY2VNaWRuaWdodDsKICAgICAgICBjb25zdCBjb3NHaGEgPSBNYXRoLmNvcyhnaGEpOwogICAgICAgIGNvbnN0IHNpbkdoYSA9IE1hdGguc2luKGdoYSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBNYXRyaXgzX2RlZmF1bHQoCiAgICAgICAgICAgIGNvc0doYSwKICAgICAgICAgICAgc2luR2hhLAogICAgICAgICAgICAwLAogICAgICAgICAgICAtc2luR2hhLAogICAgICAgICAgICBjb3NHaGEsCiAgICAgICAgICAgIDAsCiAgICAgICAgICAgIDAsCiAgICAgICAgICAgIDAsCiAgICAgICAgICAgIDEKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdFswXSA9IGNvc0doYTsKICAgICAgICByZXN1bHRbMV0gPSAtc2luR2hhOwogICAgICAgIHJlc3VsdFsyXSA9IDA7CiAgICAgICAgcmVzdWx0WzNdID0gc2luR2hhOwogICAgICAgIHJlc3VsdFs0XSA9IGNvc0doYTsKICAgICAgICByZXN1bHRbNV0gPSAwOwogICAgICAgIHJlc3VsdFs2XSA9IDA7CiAgICAgICAgcmVzdWx0WzddID0gMDsKICAgICAgICByZXN1bHRbOF0gPSAxOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFRyYW5zZm9ybXMuaWF1MjAwNlh5c0RhdGEgPSBuZXcgSWF1MjAwNlh5c0RhdGFfZGVmYXVsdCgpOwogICAgICBUcmFuc2Zvcm1zLmVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzID0gRWFydGhPcmllbnRhdGlvblBhcmFtZXRlcnNfZGVmYXVsdC5OT05FOwogICAgICB0dE1pbnVzVGFpID0gMzIuMTg0OwogICAgICBqMjAwMHR0RGF5cyA9IDI0NTE1NDU7CiAgICAgIFRyYW5zZm9ybXMucHJlbG9hZEljcmZGaXhlZCA9IGZ1bmN0aW9uKHRpbWVJbnRlcnZhbCkgewogICAgICAgIGNvbnN0IHN0YXJ0RGF5VFQgPSB0aW1lSW50ZXJ2YWwuc3RhcnQuZGF5TnVtYmVyOwogICAgICAgIGNvbnN0IHN0YXJ0U2Vjb25kVFQgPSB0aW1lSW50ZXJ2YWwuc3RhcnQuc2Vjb25kc09mRGF5ICsgdHRNaW51c1RhaTsKICAgICAgICBjb25zdCBzdG9wRGF5VFQgPSB0aW1lSW50ZXJ2YWwuc3RvcC5kYXlOdW1iZXI7CiAgICAgICAgY29uc3Qgc3RvcFNlY29uZFRUID0gdGltZUludGVydmFsLnN0b3Auc2Vjb25kc09mRGF5ICsgdHRNaW51c1RhaTsKICAgICAgICByZXR1cm4gVHJhbnNmb3Jtcy5pYXUyMDA2WHlzRGF0YS5wcmVsb2FkKAogICAgICAgICAgc3RhcnREYXlUVCwKICAgICAgICAgIHN0YXJ0U2Vjb25kVFQsCiAgICAgICAgICBzdG9wRGF5VFQsCiAgICAgICAgICBzdG9wU2Vjb25kVFQKICAgICAgICApOwogICAgICB9OwogICAgICBUcmFuc2Zvcm1zLmNvbXB1dGVJY3JmVG9GaXhlZE1hdHJpeCA9IGZ1bmN0aW9uKGRhdGUsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRhdGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGF0ZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBmaXhlZFRvSWNyZk10eCA9IFRyYW5zZm9ybXMuY29tcHV0ZUZpeGVkVG9JY3JmTWF0cml4KGRhdGUsIHJlc3VsdCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZml4ZWRUb0ljcmZNdHgpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICByZXR1cm4gTWF0cml4M19kZWZhdWx0LnRyYW5zcG9zZShmaXhlZFRvSWNyZk10eCwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgVGR0TWludXNUYWkgPSAzMi4xODQ7CiAgICAgIEoyMDAwZCA9IDI0NTE1NDU7CiAgICAgIHNjcmF0Y2hIcHIgPSBuZXcgSGVhZGluZ1BpdGNoUm9sbF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hSb3RhdGlvbk1hdHJpeCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgZGF0ZVNjcmF0Y2ggPSBuZXcgSnVsaWFuRGF0ZV9kZWZhdWx0KCk7CiAgICAgIFRyYW5zZm9ybXMuY29tcHV0ZU1vb25GaXhlZFRvSWNyZk1hdHJpeCA9IGZ1bmN0aW9uKGRhdGUsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRhdGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGF0ZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBzZWNvbmRzVFQgPSBKdWxpYW5EYXRlX2RlZmF1bHQuYWRkU2Vjb25kcyhkYXRlLCBUZHRNaW51c1RhaSwgZGF0ZVNjcmF0Y2gpOwogICAgICAgIGNvbnN0IGQyID0gSnVsaWFuRGF0ZV9kZWZhdWx0LnRvdGFsRGF5cyhzZWNvbmRzVFQpIC0gSjIwMDBkOwogICAgICAgIGNvbnN0IGUxID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucygxMi4xMTIpIC0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucygwLjA1Mjk5MikgKiBkMjsKICAgICAgICBjb25zdCBlMiA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMjQuMjI0KSAtIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMC4xMDU5ODQpICogZDI7CiAgICAgICAgY29uc3QgZTMgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDIyNy42NDUpICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucygxMy4wMTIpICogZDI7CiAgICAgICAgY29uc3QgZTQgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDI2MS4xMDUpICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucygxMy4zNDA3MTYpICogZDI7CiAgICAgICAgY29uc3QgZTUgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDM1OCkgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDAuOTg1NikgKiBkMjsKICAgICAgICBzY3JhdGNoSHByLnBpdGNoID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucygyNzAgLSA5MCkgLSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDMuODc4KSAqIE1hdGguc2luKGUxKSAtIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMC4xMikgKiBNYXRoLnNpbihlMikgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDAuMDcpICogTWF0aC5zaW4oZTMpIC0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucygwLjAxNykgKiBNYXRoLnNpbihlNCk7CiAgICAgICAgc2NyYXRjaEhwci5yb2xsID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyg2Ni41MyAtIDkwKSArIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMS41NDMpICogTWF0aC5jb3MoZTEpICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucygwLjI0KSAqIE1hdGguY29zKGUyKSAtIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMC4wMjgpICogTWF0aC5jb3MoZTMpICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucyg3ZS0zKSAqIE1hdGguY29zKGU0KTsKICAgICAgICBzY3JhdGNoSHByLmhlYWRpbmcgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDI0NC4zNzUgLSA5MCkgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDEzLjE3NjM1ODMxKSAqIGQyICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucygzLjU1OCkgKiBNYXRoLnNpbihlMSkgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDAuMTIxKSAqIE1hdGguc2luKGUyKSAtIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMC4wNjQpICogTWF0aC5zaW4oZTMpICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucygwLjAxNikgKiBNYXRoLnNpbihlNCkgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKDAuMDI1KSAqIE1hdGguc2luKGU1KTsKICAgICAgICByZXR1cm4gTWF0cml4M19kZWZhdWx0LmZyb21IZWFkaW5nUGl0Y2hSb2xsKAogICAgICAgICAgc2NyYXRjaEhwciwKICAgICAgICAgIHNjcmF0Y2hSb3RhdGlvbk1hdHJpeCwKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgIH07CiAgICAgIFRyYW5zZm9ybXMuY29tcHV0ZUljcmZUb01vb25GaXhlZE1hdHJpeCA9IGZ1bmN0aW9uKGRhdGUsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRhdGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGF0ZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBmaXhlZFRvSWNyZk10eCA9IFRyYW5zZm9ybXMuY29tcHV0ZU1vb25GaXhlZFRvSWNyZk1hdHJpeChkYXRlLCByZXN1bHQpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGZpeGVkVG9JY3JmTXR4KSkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIE1hdHJpeDNfZGVmYXVsdC50cmFuc3Bvc2UoZml4ZWRUb0ljcmZNdHgsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHh5c1NjcmF0Y2ggPSBuZXcgSWF1MjAwNlh5c1NhbXBsZV9kZWZhdWx0KDAsIDAsIDApOwogICAgICBlb3BTY3JhdGNoID0gbmV3IEVhcnRoT3JpZW50YXRpb25QYXJhbWV0ZXJzU2FtcGxlX2RlZmF1bHQoCiAgICAgICAgMCwKICAgICAgICAwLAogICAgICAgIDAsCiAgICAgICAgMCwKICAgICAgICAwLAogICAgICAgIDAKICAgICAgKTsKICAgICAgcm90YXRpb24xU2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgcm90YXRpb24yU2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgVHJhbnNmb3Jtcy5jb21wdXRlRml4ZWRUb0ljcmZNYXRyaXggPSBmdW5jdGlvbihkYXRlLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkYXRlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRhdGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZW9wID0gVHJhbnNmb3Jtcy5lYXJ0aE9yaWVudGF0aW9uUGFyYW1ldGVycy5jb21wdXRlKGRhdGUsIGVvcFNjcmF0Y2gpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVvcCkpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGRheVRUID0gZGF0ZS5kYXlOdW1iZXI7CiAgICAgICAgY29uc3Qgc2Vjb25kVFQgPSBkYXRlLnNlY29uZHNPZkRheSArIHR0TWludXNUYWk7CiAgICAgICAgY29uc3QgeHlzID0gVHJhbnNmb3Jtcy5pYXUyMDA2WHlzRGF0YS5jb21wdXRlWHlzUmFkaWFucygKICAgICAgICAgIGRheVRULAogICAgICAgICAgc2Vjb25kVFQsCiAgICAgICAgICB4eXNTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh4eXMpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBjb25zdCB4MiA9IHh5cy54ICsgZW9wLnhQb2xlT2Zmc2V0OwogICAgICAgIGNvbnN0IHkyID0geHlzLnkgKyBlb3AueVBvbGVPZmZzZXQ7CiAgICAgICAgY29uc3QgYTQgPSAxIC8gKDEgKyBNYXRoLnNxcnQoMSAtIHgyICogeDIgLSB5MiAqIHkyKSk7CiAgICAgICAgY29uc3Qgcm90YXRpb24xID0gcm90YXRpb24xU2NyYXRjaDsKICAgICAgICByb3RhdGlvbjFbMF0gPSAxIC0gYTQgKiB4MiAqIHgyOwogICAgICAgIHJvdGF0aW9uMVszXSA9IC1hNCAqIHgyICogeTI7CiAgICAgICAgcm90YXRpb24xWzZdID0geDI7CiAgICAgICAgcm90YXRpb24xWzFdID0gLWE0ICogeDIgKiB5MjsKICAgICAgICByb3RhdGlvbjFbNF0gPSAxIC0gYTQgKiB5MiAqIHkyOwogICAgICAgIHJvdGF0aW9uMVs3XSA9IHkyOwogICAgICAgIHJvdGF0aW9uMVsyXSA9IC14MjsKICAgICAgICByb3RhdGlvbjFbNV0gPSAteTI7CiAgICAgICAgcm90YXRpb24xWzhdID0gMSAtIGE0ICogKHgyICogeDIgKyB5MiAqIHkyKTsKICAgICAgICBjb25zdCByb3RhdGlvbjIgPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVJvdGF0aW9uWigteHlzLnMsIHJvdGF0aW9uMlNjcmF0Y2gpOwogICAgICAgIGNvbnN0IG1hdHJpeFEgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHkocm90YXRpb24xLCByb3RhdGlvbjIsIHJvdGF0aW9uMVNjcmF0Y2gpOwogICAgICAgIGNvbnN0IGRhdGVVdDFkYXkgPSBkYXRlLmRheU51bWJlcjsKICAgICAgICBjb25zdCBkYXRlVXQxc2VjID0gZGF0ZS5zZWNvbmRzT2ZEYXkgLSBKdWxpYW5EYXRlX2RlZmF1bHQuY29tcHV0ZVRhaU1pbnVzVXRjKGRhdGUpICsgZW9wLnV0MU1pbnVzVXRjOwogICAgICAgIGNvbnN0IGRheXNTaW5jZUoyMDAwID0gZGF0ZVV0MWRheSAtIDI0NTE1NDU7CiAgICAgICAgY29uc3QgZnJhY3Rpb25PZkRheSA9IGRhdGVVdDFzZWMgLyBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZOwogICAgICAgIGxldCBlcmEgPSAwLjc3OTA1NzI3MzI2NCArIGZyYWN0aW9uT2ZEYXkgKyAwLjAwMjczNzgxMTkxMTM1NDQ4ICogKGRheXNTaW5jZUoyMDAwICsgZnJhY3Rpb25PZkRheSk7CiAgICAgICAgZXJhID0gZXJhICUgMSAqIE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgY29uc3QgZWFydGhSb3RhdGlvbiA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tUm90YXRpb25aKGVyYSwgcm90YXRpb24yU2NyYXRjaCk7CiAgICAgICAgY29uc3QgcGZUb0ljcmYgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHkobWF0cml4USwgZWFydGhSb3RhdGlvbiwgcm90YXRpb24xU2NyYXRjaCk7CiAgICAgICAgY29uc3QgY29zeHAgPSBNYXRoLmNvcyhlb3AueFBvbGVXYW5kZXIpOwogICAgICAgIGNvbnN0IGNvc3lwID0gTWF0aC5jb3MoZW9wLnlQb2xlV2FuZGVyKTsKICAgICAgICBjb25zdCBzaW54cCA9IE1hdGguc2luKGVvcC54UG9sZVdhbmRlcik7CiAgICAgICAgY29uc3Qgc2lueXAgPSBNYXRoLnNpbihlb3AueVBvbGVXYW5kZXIpOwogICAgICAgIGxldCB0dHQgPSBkYXlUVCAtIGoyMDAwdHREYXlzICsgc2Vjb25kVFQgLyBUaW1lQ29uc3RhbnRzX2RlZmF1bHQuU0VDT05EU19QRVJfREFZOwogICAgICAgIHR0dCAvPSAzNjUyNTsKICAgICAgICBjb25zdCBzcCA9IC00N2UtNiAqIHR0dCAqIE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUUgLyAzNjAwOwogICAgICAgIGNvbnN0IGNvc3NwID0gTWF0aC5jb3Moc3ApOwogICAgICAgIGNvbnN0IHNpbnNwID0gTWF0aC5zaW4oc3ApOwogICAgICAgIGNvbnN0IGZUb1BmTXR4ID0gcm90YXRpb24yU2NyYXRjaDsKICAgICAgICBmVG9QZk10eFswXSA9IGNvc3hwICogY29zc3A7CiAgICAgICAgZlRvUGZNdHhbMV0gPSBjb3N4cCAqIHNpbnNwOwogICAgICAgIGZUb1BmTXR4WzJdID0gc2lueHA7CiAgICAgICAgZlRvUGZNdHhbM10gPSAtY29zeXAgKiBzaW5zcCArIHNpbnlwICogc2lueHAgKiBjb3NzcDsKICAgICAgICBmVG9QZk10eFs0XSA9IGNvc3lwICogY29zc3AgKyBzaW55cCAqIHNpbnhwICogc2luc3A7CiAgICAgICAgZlRvUGZNdHhbNV0gPSAtc2lueXAgKiBjb3N4cDsKICAgICAgICBmVG9QZk10eFs2XSA9IC1zaW55cCAqIHNpbnNwIC0gY29zeXAgKiBzaW54cCAqIGNvc3NwOwogICAgICAgIGZUb1BmTXR4WzddID0gc2lueXAgKiBjb3NzcCAtIGNvc3lwICogc2lueHAgKiBzaW5zcDsKICAgICAgICBmVG9QZk10eFs4XSA9IGNvc3lwICogY29zeHA7CiAgICAgICAgcmV0dXJuIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseShwZlRvSWNyZiwgZlRvUGZNdHgsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHBvaW50VG9XaW5kb3dDb29yZGluYXRlc1RlbXAgPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KCk7CiAgICAgIFRyYW5zZm9ybXMucG9pbnRUb1dpbmRvd0Nvb3JkaW5hdGVzID0gZnVuY3Rpb24obW9kZWxWaWV3UHJvamVjdGlvbk1hdHJpeCwgdmlld3BvcnRUcmFuc2Zvcm1hdGlvbiwgcG9pbnQsIHJlc3VsdCkgewogICAgICAgIHJlc3VsdCA9IFRyYW5zZm9ybXMucG9pbnRUb0dMV2luZG93Q29vcmRpbmF0ZXMoCiAgICAgICAgICBtb2RlbFZpZXdQcm9qZWN0aW9uTWF0cml4LAogICAgICAgICAgdmlld3BvcnRUcmFuc2Zvcm1hdGlvbiwKICAgICAgICAgIHBvaW50LAogICAgICAgICAgcmVzdWx0CiAgICAgICAgKTsKICAgICAgICByZXN1bHQueSA9IDIgKiB2aWV3cG9ydFRyYW5zZm9ybWF0aW9uWzVdIC0gcmVzdWx0Lnk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgVHJhbnNmb3Jtcy5wb2ludFRvR0xXaW5kb3dDb29yZGluYXRlcyA9IGZ1bmN0aW9uKG1vZGVsVmlld1Byb2plY3Rpb25NYXRyaXgsIHZpZXdwb3J0VHJhbnNmb3JtYXRpb24sIHBvaW50LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtb2RlbFZpZXdQcm9qZWN0aW9uTWF0cml4KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm1vZGVsVmlld1Byb2plY3Rpb25NYXRyaXggaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZpZXdwb3J0VHJhbnNmb3JtYXRpb24pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmlld3BvcnRUcmFuc2Zvcm1hdGlvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9pbnQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicG9pbnQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdG1wMiA9IHBvaW50VG9XaW5kb3dDb29yZGluYXRlc1RlbXA7CiAgICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IoCiAgICAgICAgICBtb2RlbFZpZXdQcm9qZWN0aW9uTWF0cml4LAogICAgICAgICAgQ2FydGVzaWFuNF9kZWZhdWx0LmZyb21FbGVtZW50cyhwb2ludC54LCBwb2ludC55LCBwb2ludC56LCAxLCB0bXAyKSwKICAgICAgICAgIHRtcDIKICAgICAgICApOwogICAgICAgIENhcnRlc2lhbjRfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHRtcDIsIDEgLyB0bXAyLncsIHRtcDIpOwogICAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKHZpZXdwb3J0VHJhbnNmb3JtYXRpb24sIHRtcDIsIHRtcDIpOwogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUNhcnRlc2lhbjQodG1wMiwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgbm9ybWFsU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcmlnaHRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB1cFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFRyYW5zZm9ybXMucm90YXRpb25NYXRyaXhGcm9tUG9zaXRpb25WZWxvY2l0eSA9IGZ1bmN0aW9uKHBvc2l0aW9uLCB2ZWxvY2l0eSwgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwb3NpdGlvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmVsb2NpdHkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmVsb2NpdHkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG5vcm1hbDIgPSAoZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQpLmdlb2RldGljU3VyZmFjZU5vcm1hbCgKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgbm9ybWFsU2NyYXRjaAogICAgICAgICk7CiAgICAgICAgbGV0IHJpZ2h0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHZlbG9jaXR5LCBub3JtYWwyLCByaWdodFNjcmF0Y2gpOwogICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihyaWdodCwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIE1hdGhfZGVmYXVsdC5FUFNJTE9ONikpIHsKICAgICAgICAgIHJpZ2h0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1gsIHJpZ2h0KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdXAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MocmlnaHQsIHZlbG9jaXR5LCB1cFNjcmF0Y2gpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUodXAsIHVwKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModmVsb2NpdHksIHVwLCByaWdodCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShyaWdodCwgcmlnaHQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmlnaHQsIHJpZ2h0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdFswXSA9IHZlbG9jaXR5Lng7CiAgICAgICAgcmVzdWx0WzFdID0gdmVsb2NpdHkueTsKICAgICAgICByZXN1bHRbMl0gPSB2ZWxvY2l0eS56OwogICAgICAgIHJlc3VsdFszXSA9IHJpZ2h0Lng7CiAgICAgICAgcmVzdWx0WzRdID0gcmlnaHQueTsKICAgICAgICByZXN1bHRbNV0gPSByaWdodC56OwogICAgICAgIHJlc3VsdFs2XSA9IHVwLng7CiAgICAgICAgcmVzdWx0WzddID0gdXAueTsKICAgICAgICByZXN1bHRbOF0gPSB1cC56OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFRyYW5zZm9ybXMuU1dJWlpMRV8zRF9UT18yRF9NQVRSSVggPSBPYmplY3QuZnJlZXplKAogICAgICAgIG5ldyBNYXRyaXg0X2RlZmF1bHQoCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDEsCiAgICAgICAgICAwLAogICAgICAgICAgMSwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAxLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAxCiAgICAgICAgKQogICAgICApOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUHJvamVjdGlvbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENlbnRlciA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFJvdGF0aW9uID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRnJvbUVOVSA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRvRU5VID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBUcmFuc2Zvcm1zLmJhc2lzVG8yRCA9IGZ1bmN0aW9uKHByb2plY3Rpb24sIG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocHJvamVjdGlvbikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwcm9qZWN0aW9uIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtYXRyaXgpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibWF0cml4IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmVzdWx0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBydGNDZW50ZXIgPSBNYXRyaXg0X2RlZmF1bHQuZ2V0VHJhbnNsYXRpb24obWF0cml4LCBzY3JhdGNoQ2VudGVyKTsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBwcm9qZWN0aW9uLmVsbGlwc29pZDsKICAgICAgICBsZXQgcHJvamVjdGVkUG9zaXRpb247CiAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMocnRjQ2VudGVyLCBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTykpIHsKICAgICAgICAgIHByb2plY3RlZFBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTywKICAgICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjNQcm9qZWN0aW9uCiAgICAgICAgICApOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjb25zdCBjYXJ0b2dyYXBoaWMyID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgICBydGNDZW50ZXIsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWMKICAgICAgICAgICk7CiAgICAgICAgICBwcm9qZWN0ZWRQb3NpdGlvbiA9IHByb2plY3Rpb24ucHJvamVjdCgKICAgICAgICAgICAgY2FydG9ncmFwaGljMiwKICAgICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjNQcm9qZWN0aW9uCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygKICAgICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24ueiwKICAgICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24ueCwKICAgICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24ueSwKICAgICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGZyb21FTlUgPSBUcmFuc2Zvcm1zLmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKAogICAgICAgICAgcnRjQ2VudGVyLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc2NyYXRjaEZyb21FTlUKICAgICAgICApOwogICAgICAgIGNvbnN0IHRvRU5VID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2VUcmFuc2Zvcm1hdGlvbihmcm9tRU5VLCBzY3JhdGNoVG9FTlUpOwogICAgICAgIGNvbnN0IHJvdGF0aW9uID0gTWF0cml4NF9kZWZhdWx0LmdldE1hdHJpeDMobWF0cml4LCBzY3JhdGNoUm90YXRpb24pOwogICAgICAgIGNvbnN0IGxvY2FsID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlNYXRyaXgzKHRvRU5VLCByb3RhdGlvbiwgcmVzdWx0KTsKICAgICAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkoVHJhbnNmb3Jtcy5TV0laWkxFXzNEX1RPXzJEX01BVFJJWCwgbG9jYWwsIHJlc3VsdCk7CiAgICAgICAgTWF0cml4NF9kZWZhdWx0LnNldFRyYW5zbGF0aW9uKHJlc3VsdCwgcHJvamVjdGVkUG9zaXRpb24sIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgVHJhbnNmb3Jtcy5lbGxpcHNvaWRUbzJETW9kZWxNYXRyaXggPSBmdW5jdGlvbihwcm9qZWN0aW9uLCBjZW50ZXIsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHByb2plY3Rpb24pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicHJvamVjdGlvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2VudGVyKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNlbnRlciBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJlc3VsdCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gcHJvamVjdGlvbi5lbGxpcHNvaWQ7CiAgICAgICAgY29uc3QgZnJvbUVOVSA9IFRyYW5zZm9ybXMuZWFzdE5vcnRoVXBUb0ZpeGVkRnJhbWUoCiAgICAgICAgICBjZW50ZXIsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoRnJvbUVOVQogICAgICAgICk7CiAgICAgICAgY29uc3QgdG9FTlUgPSBNYXRyaXg0X2RlZmF1bHQuaW52ZXJzZVRyYW5zZm9ybWF0aW9uKGZyb21FTlUsIHNjcmF0Y2hUb0VOVSk7CiAgICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICAgIGNlbnRlciwKICAgICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWMKICAgICAgICApOwogICAgICAgIGNvbnN0IHByb2plY3RlZFBvc2l0aW9uID0gcHJvamVjdGlvbi5wcm9qZWN0KAogICAgICAgICAgY2FydG9ncmFwaGljMiwKICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUHJvamVjdGlvbgogICAgICAgICk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygKICAgICAgICAgIHByb2plY3RlZFBvc2l0aW9uLnosCiAgICAgICAgICBwcm9qZWN0ZWRQb3NpdGlvbi54LAogICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24ueSwKICAgICAgICAgIHByb2plY3RlZFBvc2l0aW9uCiAgICAgICAgKTsKICAgICAgICBjb25zdCB0cmFuc2xhdGlvbjIgPSBNYXRyaXg0X2RlZmF1bHQuZnJvbVRyYW5zbGF0aW9uKAogICAgICAgICAgcHJvamVjdGVkUG9zaXRpb24sCiAgICAgICAgICBzY3JhdGNoRnJvbUVOVQogICAgICAgICk7CiAgICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5KFRyYW5zZm9ybXMuU1dJWlpMRV8zRF9UT18yRF9NQVRSSVgsIHRvRU5VLCByZXN1bHQpOwogICAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseSh0cmFuc2xhdGlvbjIsIHJlc3VsdCwgcmVzdWx0KTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBUcmFuc2Zvcm1zX2RlZmF1bHQgPSBUcmFuc2Zvcm1zOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVjdGFuZ2xlLmpzCiAgdmFyIFJlY3RhbmdsZSwgZnJvbUJvdW5kaW5nU3BoZXJlTWF0cml4U2NyYXRjaCwgZnJvbUJvdW5kaW5nU3BoZXJlRWFzdFNjcmF0Y2gsIGZyb21Cb3VuZGluZ1NwaGVyZU5vcnRoU2NyYXRjaCwgZnJvbUJvdW5kaW5nU3BoZXJlV2VzdFNjcmF0Y2gsIGZyb21Cb3VuZGluZ1NwaGVyZVNvdXRoU2NyYXRjaCwgZnJvbUJvdW5kaW5nU3BoZXJlUG9zaXRpb25zU2NyYXRjaCwgc3Vic2FtcGxlTGxhU2NyYXRjaCwgUmVjdGFuZ2xlX2RlZmF1bHQ7CiAgdmFyIGluaXRfUmVjdGFuZ2xlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZWN0YW5nbGUuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfVHJhbnNmb3JtcygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgUmVjdGFuZ2xlID0gY2xhc3MgX1JlY3RhbmdsZSB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt3ZXN0PTAuMF0gVGhlIHdlc3Rlcm5tb3N0IGxvbmdpdHVkZSwgaW4gcmFkaWFucywgaW4gdGhlIHJhbmdlIFstUGksIFBpXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3NvdXRoPTAuMF0gVGhlIHNvdXRoZXJubW9zdCBsYXRpdHVkZSwgaW4gcmFkaWFucywgaW4gdGhlIHJhbmdlIFstUGkvMiwgUGkvMl0uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtlYXN0PTAuMF0gVGhlIGVhc3Rlcm5tb3N0IGxvbmdpdHVkZSwgaW4gcmFkaWFucywgaW4gdGhlIHJhbmdlIFstUGksIFBpXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW25vcnRoPTAuMF0gVGhlIG5vcnRoZXJubW9zdCBsYXRpdHVkZSwgaW4gcmFkaWFucywgaW4gdGhlIHJhbmdlIFstUGkvMiwgUGkvMl0uCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3Iod2VzdCwgc291dGgsIGVhc3QsIG5vcnRoKSB7CiAgICAgICAgICB0aGlzLndlc3QgPSB3ZXN0ID8/IDA7CiAgICAgICAgICB0aGlzLnNvdXRoID0gc291dGggPz8gMDsKICAgICAgICAgIHRoaXMuZWFzdCA9IGVhc3QgPz8gMDsKICAgICAgICAgIHRoaXMubm9ydGggPSBub3J0aCA/PyAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSB3aWR0aCBvZiB0aGUgcmVjdGFuZ2xlIGluIHJhZGlhbnMuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBnZXQgd2lkdGgoKSB7CiAgICAgICAgICByZXR1cm4gX1JlY3RhbmdsZS5jb21wdXRlV2lkdGgodGhpcyk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGhlaWdodCBvZiB0aGUgcmVjdGFuZ2xlIGluIHJhZGlhbnMuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBnZXQgaGVpZ2h0KCkgewogICAgICAgICAgcmV0dXJuIF9SZWN0YW5nbGUuY29tcHV0ZUhlaWdodCh0aGlzKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU3RvcmVzIHRoZSBwcm92aWRlZCBpbnN0YW5jZSBpbnRvIHRoZSBwcm92aWRlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcGFjay4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheSBUaGUgYXJyYXkgdG8gcGFjayBpbnRvLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRpbmdJbmRleD0wXSBUaGUgaW5kZXggaW50byB0aGUgYXJyYXkgYXQgd2hpY2ggdG8gc3RhcnQgcGFja2luZyB0aGUgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBhcnJheSB0aGF0IHdhcyBwYWNrZWQgaW50bwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwYWNrKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLndlc3Q7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuc291dGg7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuZWFzdDsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWUubm9ydGg7CiAgICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhbiBpbnN0YW5jZSBmcm9tIGEgcGFja2VkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIHN0YXJ0aW5nIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIGJlIHVucGFja2VkLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IGludG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7UmVjdGFuZ2xlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBSZWN0YW5nbGUgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9SZWN0YW5nbGUoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC53ZXN0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHQubm9ydGggPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSB3aWR0aCBvZiBhIHJlY3RhbmdsZSBpbiByYWRpYW5zLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgVGhlIHJlY3RhbmdsZSB0byBjb21wdXRlIHRoZSB3aWR0aCBvZi4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgd2lkdGguCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbXB1dGVXaWR0aChyZWN0YW5nbGUpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIGxldCBlYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgICBjb25zdCB3ZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICBpZiAoZWFzdCA8IHdlc3QpIHsKICAgICAgICAgICAgZWFzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIGVhc3QgLSB3ZXN0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgaGVpZ2h0IG9mIGEgcmVjdGFuZ2xlIGluIHJhZGlhbnMuCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBUaGUgcmVjdGFuZ2xlIHRvIGNvbXB1dGUgdGhlIGhlaWdodCBvZi4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgaGVpZ2h0LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjb21wdXRlSGVpZ2h0KHJlY3RhbmdsZSkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgcmV0dXJuIHJlY3RhbmdsZS5ub3J0aCAtIHJlY3RhbmdsZS5zb3V0aDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJlY3RhbmdsZSBnaXZlbiB0aGUgYm91bmRhcnkgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZSBpbiBkZWdyZWVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFt3ZXN0PTAuMF0gVGhlIHdlc3Rlcm5tb3N0IGxvbmdpdHVkZSBpbiBkZWdyZWVzIGluIHRoZSByYW5nZSBbLTE4MC4wLCAxODAuMF0uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzb3V0aD0wLjBdIFRoZSBzb3V0aGVybm1vc3QgbGF0aXR1ZGUgaW4gZGVncmVlcyBpbiB0aGUgcmFuZ2UgWy05MC4wLCA5MC4wXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vhc3Q9MC4wXSBUaGUgZWFzdGVybm1vc3QgbG9uZ2l0dWRlIGluIGRlZ3JlZXMgaW4gdGhlIHJhbmdlIFstMTgwLjAsIDE4MC4wXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW25vcnRoPTAuMF0gVGhlIG5vcnRoZXJubW9zdCBsYXRpdHVkZSBpbiBkZWdyZWVzIGluIHRoZSByYW5nZSBbLTkwLjAsIDkwLjBdLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEgbmV3IGluc3RhbmNlIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IFJlY3RhbmdsZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgcmVjdGFuZ2xlID0gQ2VzaXVtLlJlY3RhbmdsZS5mcm9tRGVncmVlcygwLjAsIDIwLjAsIDEwLjAsIDMwLjApOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tRGVncmVlcyh3ZXN0LCBzb3V0aCwgZWFzdCwgbm9ydGgsIHJlc3VsdCkgewogICAgICAgICAgd2VzdCA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMod2VzdCA/PyAwKTsKICAgICAgICAgIHNvdXRoID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhzb3V0aCA/PyAwKTsKICAgICAgICAgIGVhc3QgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKGVhc3QgPz8gMCk7CiAgICAgICAgICBub3J0aCA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMobm9ydGggPz8gMCk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JlY3RhbmdsZSh3ZXN0LCBzb3V0aCwgZWFzdCwgbm9ydGgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0Lndlc3QgPSB3ZXN0OwogICAgICAgICAgcmVzdWx0LnNvdXRoID0gc291dGg7CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGVhc3Q7CiAgICAgICAgICByZXN1bHQubm9ydGggPSBub3J0aDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSByZWN0YW5nbGUgZ2l2ZW4gdGhlIGJvdW5kYXJ5IGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgaW4gcmFkaWFucy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbd2VzdD0wLjBdIFRoZSB3ZXN0ZXJubW9zdCBsb25naXR1ZGUgaW4gcmFkaWFucyBpbiB0aGUgcmFuZ2UgWy1NYXRoLlBJLCBNYXRoLlBJXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3NvdXRoPTAuMF0gVGhlIHNvdXRoZXJubW9zdCBsYXRpdHVkZSBpbiByYWRpYW5zIGluIHRoZSByYW5nZSBbLU1hdGguUEkvMiwgTWF0aC5QSS8yXS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vhc3Q9MC4wXSBUaGUgZWFzdGVybm1vc3QgbG9uZ2l0dWRlIGluIHJhZGlhbnMgaW4gdGhlIHJhbmdlIFstTWF0aC5QSSwgTWF0aC5QSV0uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtub3J0aD0wLjBdIFRoZSBub3J0aGVybm1vc3QgbGF0aXR1ZGUgaW4gcmFkaWFucyBpbiB0aGUgcmFuZ2UgWy1NYXRoLlBJLzIsIE1hdGguUEkvMl0uCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYSBuZXcgaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiBjb25zdCByZWN0YW5nbGUgPSBDZXNpdW0uUmVjdGFuZ2xlLmZyb21SYWRpYW5zKDAuMCwgTWF0aC5QSS80LCBNYXRoLlBJLzgsIDMqTWF0aC5QSS80KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVJhZGlhbnMod2VzdCwgc291dGgsIGVhc3QsIG5vcnRoLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfUmVjdGFuZ2xlKHdlc3QsIHNvdXRoLCBlYXN0LCBub3J0aCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQud2VzdCA9IHdlc3QgPz8gMDsKICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IHNvdXRoID8/IDA7CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGVhc3QgPz8gMDsKICAgICAgICAgIHJlc3VsdC5ub3J0aCA9IG5vcnRoID8/IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIHRoZSBzbWFsbGVzdCBwb3NzaWJsZSBSZWN0YW5nbGUgdGhhdCBlbmNsb3NlcyBhbGwgcG9zaXRpb25zIGluIHRoZSBwcm92aWRlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljW119IGNhcnRvZ3JhcGhpY3MgVGhlIGxpc3Qgb2YgQ2FydG9ncmFwaGljIGluc3RhbmNlcy4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQsIG9yIHVuZGVmaW5lZCBpZiBhIG5ldyBpbnN0YW5jZSBzaG91bGQgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7UmVjdGFuZ2xlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBSZWN0YW5nbGUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21DYXJ0b2dyYXBoaWNBcnJheShjYXJ0b2dyYXBoaWNzLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydG9ncmFwaGljcyIsIGNhcnRvZ3JhcGhpY3MpOwogICAgICAgICAgbGV0IHdlc3QgPSBOdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgICAgbGV0IGVhc3QgPSAtTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICAgIGxldCB3ZXN0T3ZlcklETCA9IE51bWJlci5NQVhfVkFMVUU7CiAgICAgICAgICBsZXQgZWFzdE92ZXJJREwgPSAtTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICAgIGxldCBzb3V0aCA9IE51bWJlci5NQVhfVkFMVUU7CiAgICAgICAgICBsZXQgbm9ydGggPSAtTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICAgIGZvciAobGV0IGkyID0gMCwgbGVuID0gY2FydG9ncmFwaGljcy5sZW5ndGg7IGkyIDwgbGVuOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gY2FydG9ncmFwaGljc1tpMl07CiAgICAgICAgICAgIHdlc3QgPSBNYXRoLm1pbih3ZXN0LCBwb3NpdGlvbi5sb25naXR1ZGUpOwogICAgICAgICAgICBlYXN0ID0gTWF0aC5tYXgoZWFzdCwgcG9zaXRpb24ubG9uZ2l0dWRlKTsKICAgICAgICAgICAgc291dGggPSBNYXRoLm1pbihzb3V0aCwgcG9zaXRpb24ubGF0aXR1ZGUpOwogICAgICAgICAgICBub3J0aCA9IE1hdGgubWF4KG5vcnRoLCBwb3NpdGlvbi5sYXRpdHVkZSk7CiAgICAgICAgICAgIGNvbnN0IGxvbkFkanVzdGVkID0gcG9zaXRpb24ubG9uZ2l0dWRlID49IDAgPyBwb3NpdGlvbi5sb25naXR1ZGUgOiBwb3NpdGlvbi5sb25naXR1ZGUgKyBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgICB3ZXN0T3ZlcklETCA9IE1hdGgubWluKHdlc3RPdmVySURMLCBsb25BZGp1c3RlZCk7CiAgICAgICAgICAgIGVhc3RPdmVySURMID0gTWF0aC5tYXgoZWFzdE92ZXJJREwsIGxvbkFkanVzdGVkKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChlYXN0IC0gd2VzdCA+IGVhc3RPdmVySURMIC0gd2VzdE92ZXJJREwpIHsKICAgICAgICAgICAgd2VzdCA9IHdlc3RPdmVySURMOwogICAgICAgICAgICBlYXN0ID0gZWFzdE92ZXJJREw7CiAgICAgICAgICAgIGlmIChlYXN0ID4gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICAgICAgZWFzdCA9IGVhc3QgLSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh3ZXN0ID4gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICAgICAgd2VzdCA9IHdlc3QgLSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JlY3RhbmdsZSh3ZXN0LCBzb3V0aCwgZWFzdCwgbm9ydGgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0Lndlc3QgPSB3ZXN0OwogICAgICAgICAgcmVzdWx0LnNvdXRoID0gc291dGg7CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGVhc3Q7CiAgICAgICAgICByZXN1bHQubm9ydGggPSBub3J0aDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgdGhlIHNtYWxsZXN0IHBvc3NpYmxlIFJlY3RhbmdsZSB0aGF0IGVuY2xvc2VzIGFsbCBwb3NpdGlvbnMgaW4gdGhlIHByb3ZpZGVkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zW119IGNhcnRlc2lhbnMgVGhlIGxpc3Qgb2YgQ2FydGVzaWFuIGluc3RhbmNlcy4KICAgICAgICAgKiBAcGFyYW0ge0VsbGlwc29pZH0gW2VsbGlwc29pZD1FbGxpcHNvaWQuZGVmYXVsdF0gVGhlIGVsbGlwc29pZCB0aGUgY2FydGVzaWFucyBhcmUgb24uCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYSBuZXcgaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tQ2FydGVzaWFuQXJyYXkoY2FydGVzaWFucywgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydGVzaWFucyIsIGNhcnRlc2lhbnMpOwogICAgICAgICAgZWxsaXBzb2lkID0gZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICAgICAgICBsZXQgd2VzdCA9IE51bWJlci5NQVhfVkFMVUU7CiAgICAgICAgICBsZXQgZWFzdCA9IC1OdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgICAgbGV0IHdlc3RPdmVySURMID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICAgIGxldCBlYXN0T3ZlcklETCA9IC1OdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgICAgbGV0IHNvdXRoID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICAgIGxldCBub3J0aCA9IC1OdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSBjYXJ0ZXNpYW5zLmxlbmd0aDsgaTIgPCBsZW47IGkyKyspIHsKICAgICAgICAgICAgY29uc3QgcG9zaXRpb24gPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoY2FydGVzaWFuc1tpMl0pOwogICAgICAgICAgICB3ZXN0ID0gTWF0aC5taW4od2VzdCwgcG9zaXRpb24ubG9uZ2l0dWRlKTsKICAgICAgICAgICAgZWFzdCA9IE1hdGgubWF4KGVhc3QsIHBvc2l0aW9uLmxvbmdpdHVkZSk7CiAgICAgICAgICAgIHNvdXRoID0gTWF0aC5taW4oc291dGgsIHBvc2l0aW9uLmxhdGl0dWRlKTsKICAgICAgICAgICAgbm9ydGggPSBNYXRoLm1heChub3J0aCwgcG9zaXRpb24ubGF0aXR1ZGUpOwogICAgICAgICAgICBjb25zdCBsb25BZGp1c3RlZCA9IHBvc2l0aW9uLmxvbmdpdHVkZSA+PSAwID8gcG9zaXRpb24ubG9uZ2l0dWRlIDogcG9zaXRpb24ubG9uZ2l0dWRlICsgTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgICAgd2VzdE92ZXJJREwgPSBNYXRoLm1pbih3ZXN0T3ZlcklETCwgbG9uQWRqdXN0ZWQpOwogICAgICAgICAgICBlYXN0T3ZlcklETCA9IE1hdGgubWF4KGVhc3RPdmVySURMLCBsb25BZGp1c3RlZCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoZWFzdCAtIHdlc3QgPiBlYXN0T3ZlcklETCAtIHdlc3RPdmVySURMKSB7CiAgICAgICAgICAgIHdlc3QgPSB3ZXN0T3ZlcklETDsKICAgICAgICAgICAgZWFzdCA9IGVhc3RPdmVySURMOwogICAgICAgICAgICBpZiAoZWFzdCA+IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICAgICAgICAgIGVhc3QgPSBlYXN0IC0gTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAod2VzdCA+IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICAgICAgICAgIHdlc3QgPSB3ZXN0IC0gTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9SZWN0YW5nbGUod2VzdCwgc291dGgsIGVhc3QsIG5vcnRoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC53ZXN0ID0gd2VzdDsKICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IHNvdXRoOwogICAgICAgICAgcmVzdWx0LmVhc3QgPSBlYXN0OwogICAgICAgICAgcmVzdWx0Lm5vcnRoID0gbm9ydGg7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGUgYSByZWN0YW5nbGUgZnJvbSBhIGJvdW5kaW5nIHNwaGVyZSwgaWdub3JpbmcgaGVpZ2h0LgogICAgICAgICAqCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBib3VuZGluZ1NwaGVyZSBUaGUgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqIEBwYXJhbSB7RWxsaXBzb2lkfSBbZWxsaXBzb2lkPUVsbGlwc29pZC5kZWZhdWx0XSBUaGUgZWxsaXBzb2lkLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEgbmV3IGluc3RhbmNlIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IFJlY3RhbmdsZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUJvdW5kaW5nU3BoZXJlKGJvdW5kaW5nU3BoZXJlLCBlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJib3VuZGluZ1NwaGVyZSIsIGJvdW5kaW5nU3BoZXJlKTsKICAgICAgICAgIGNvbnN0IGNlbnRlciA9IGJvdW5kaW5nU3BoZXJlLmNlbnRlcjsKICAgICAgICAgIGNvbnN0IHJhZGl1cyA9IGJvdW5kaW5nU3BoZXJlLnJhZGl1czsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVsbGlwc29pZCkpIHsKICAgICAgICAgICAgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9SZWN0YW5nbGUoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGNlbnRlciwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pKSB7CiAgICAgICAgICAgIF9SZWN0YW5nbGUuY2xvbmUoX1JlY3RhbmdsZS5NQVhfVkFMVUUsIHJlc3VsdCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBmcm9tRU5VID0gVHJhbnNmb3Jtc19kZWZhdWx0LmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKAogICAgICAgICAgICBjZW50ZXIsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgZnJvbUJvdW5kaW5nU3BoZXJlTWF0cml4U2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IGVhc3QgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50QXNWZWN0b3IoCiAgICAgICAgICAgIGZyb21FTlUsCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1gsCiAgICAgICAgICAgIGZyb21Cb3VuZGluZ1NwaGVyZUVhc3RTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShlYXN0LCBlYXN0KTsKICAgICAgICAgIGNvbnN0IG5vcnRoID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludEFzVmVjdG9yKAogICAgICAgICAgICBmcm9tRU5VLAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZLAogICAgICAgICAgICBmcm9tQm91bmRpbmdTcGhlcmVOb3J0aFNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG5vcnRoLCBub3J0aCk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihub3J0aCwgcmFkaXVzLCBub3J0aCk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihlYXN0LCByYWRpdXMsIGVhc3QpOwogICAgICAgICAgY29uc3Qgc291dGggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKG5vcnRoLCBmcm9tQm91bmRpbmdTcGhlcmVTb3V0aFNjcmF0Y2gpOwogICAgICAgICAgY29uc3Qgd2VzdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoZWFzdCwgZnJvbUJvdW5kaW5nU3BoZXJlV2VzdFNjcmF0Y2gpOwogICAgICAgICAgY29uc3QgcG9zaXRpb25zID0gZnJvbUJvdW5kaW5nU3BoZXJlUG9zaXRpb25zU2NyYXRjaDsKICAgICAgICAgIGxldCBjb3JuZXIgPSBwb3NpdGlvbnNbMF07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNlbnRlciwgbm9ydGgsIGNvcm5lcik7CiAgICAgICAgICBjb3JuZXIgPSBwb3NpdGlvbnNbMV07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNlbnRlciwgd2VzdCwgY29ybmVyKTsKICAgICAgICAgIGNvcm5lciA9IHBvc2l0aW9uc1syXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCBzb3V0aCwgY29ybmVyKTsKICAgICAgICAgIGNvcm5lciA9IHBvc2l0aW9uc1szXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCBlYXN0LCBjb3JuZXIpOwogICAgICAgICAgcG9zaXRpb25zWzRdID0gY2VudGVyOwogICAgICAgICAgcmV0dXJuIF9SZWN0YW5nbGUuZnJvbUNhcnRlc2lhbkFycmF5KHBvc2l0aW9ucywgZWxsaXBzb2lkLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIGEgUmVjdGFuZ2xlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBUaGUgcmVjdGFuZ2xlIHRvIGNsb25lLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEgbmV3IGluc3RhbmNlIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IFJlY3RhbmdsZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4gKFJldHVybnMgdW5kZWZpbmVkIGlmIHJlY3RhbmdsZSBpcyB1bmRlZmluZWQpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsb25lKHJlY3RhbmdsZSwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JlY3RhbmdsZSgKICAgICAgICAgICAgICByZWN0YW5nbGUud2VzdCwKICAgICAgICAgICAgICByZWN0YW5nbGUuc291dGgsCiAgICAgICAgICAgICAgcmVjdGFuZ2xlLmVhc3QsCiAgICAgICAgICAgICAgcmVjdGFuZ2xlLm5vcnRoCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQud2VzdCA9IHJlY3RhbmdsZS53ZXN0OwogICAgICAgICAgcmVzdWx0LnNvdXRoID0gcmVjdGFuZ2xlLnNvdXRoOwogICAgICAgICAgcmVzdWx0LmVhc3QgPSByZWN0YW5nbGUuZWFzdDsKICAgICAgICAgIHJlc3VsdC5ub3J0aCA9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoZSBwcm92aWRlZCBSZWN0YW5nbGVzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IHBhc3MgYW4gYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG9sZXJhbmNlIHRlc3QsCiAgICAgICAgICogPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbbGVmdF0gVGhlIGZpcnN0IFJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3JpZ2h0XSBUaGUgc2Vjb25kIFJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Fic29sdXRlRXBzaWxvbj0wXSBUaGUgYWJzb2x1dGUgZXBzaWxvbiB0b2xlcmFuY2UgdG8gdXNlIGZvciBlcXVhbGl0eSB0ZXN0aW5nLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHNFcHNpbG9uKGxlZnQsIHJpZ2h0LCBhYnNvbHV0ZUVwc2lsb24pIHsKICAgICAgICAgIGFic29sdXRlRXBzaWxvbiA9IGFic29sdXRlRXBzaWxvbiA/PyAwOwogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIE1hdGguYWJzKGxlZnQud2VzdCAtIHJpZ2h0Lndlc3QpIDw9IGFic29sdXRlRXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0LnNvdXRoIC0gcmlnaHQuc291dGgpIDw9IGFic29sdXRlRXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0LmVhc3QgLSByaWdodC5lYXN0KSA8PSBhYnNvbHV0ZUVwc2lsb24gJiYgTWF0aC5hYnMobGVmdC5ub3J0aCAtIHJpZ2h0Lm5vcnRoKSA8PSBhYnNvbHV0ZUVwc2lsb247CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIER1cGxpY2F0ZXMgdGhpcyBSZWN0YW5nbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIGNsb25lKHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIF9SZWN0YW5nbGUuY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIFJlY3RhbmdsZSB3aXRoIHRoaXMgUmVjdGFuZ2xlIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbb3RoZXJdIFRoZSBSZWN0YW5nbGUgdG8gY29tcGFyZS4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIFJlY3RhbmdsZXMgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhvdGhlcikgewogICAgICAgICAgcmV0dXJuIF9SZWN0YW5nbGUuZXF1YWxzKHRoaXMsIG90aGVyKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIHJlY3RhbmdsZXMgYW5kIHJldHVybnMgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsCiAgICAgICAgICogPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbbGVmdF0gVGhlIGZpcnN0IFJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3JpZ2h0XSBUaGUgc2Vjb25kIFJlY3RhbmdsZS4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgbGVmdCBhbmQgcmlnaHQgYXJlIGVxdWFsOyBvdGhlcndpc2UgPGNvZGU+ZmFsc2U8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBlcXVhbHMobGVmdCwgcmlnaHQpIHsKICAgICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBsZWZ0Lndlc3QgPT09IHJpZ2h0Lndlc3QgJiYgbGVmdC5zb3V0aCA9PT0gcmlnaHQuc291dGggJiYgbGVmdC5lYXN0ID09PSByaWdodC5lYXN0ICYmIGxlZnQubm9ydGggPT09IHJpZ2h0Lm5vcnRoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgUmVjdGFuZ2xlIHdpdGggdGhpcyBSZWN0YW5nbGUgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIHdpdGhpbiB0aGUgcHJvdmlkZWQgZXBzaWxvbiwKICAgICAgICAgKiA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtvdGhlcl0gVGhlIFJlY3RhbmdsZSB0byBjb21wYXJlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZXBzaWxvbj0wXSBUaGUgZXBzaWxvbiB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBSZWN0YW5nbGVzIGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzRXBzaWxvbihvdGhlciwgZXBzaWxvbikgewogICAgICAgICAgcmV0dXJuIF9SZWN0YW5nbGUuZXF1YWxzRXBzaWxvbih0aGlzLCBvdGhlciwgZXBzaWxvbik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENoZWNrcyBhIFJlY3RhbmdsZSdzIHByb3BlcnRpZXMgYW5kIHRocm93cyBpZiB0aGV5IGFyZSBub3QgaW4gdmFsaWQgcmFuZ2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBUaGUgcmVjdGFuZ2xlIHRvIHZhbGlkYXRlCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gPGNvZGU+bm9ydGg8L2NvZGU+IG11c3QgYmUgaW4gdGhlIGludGVydmFsIFs8Y29kZT4tUGkvMjwvY29kZT4sIDxjb2RlPlBpLzI8L2NvZGU+XS4KICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gPGNvZGU+c291dGg8L2NvZGU+IG11c3QgYmUgaW4gdGhlIGludGVydmFsIFs8Y29kZT4tUGkvMjwvY29kZT4sIDxjb2RlPlBpLzI8L2NvZGU+XS4KICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gPGNvZGU+ZWFzdDwvY29kZT4gbXVzdCBiZSBpbiB0aGUgaW50ZXJ2YWwgWzxjb2RlPi1QaTwvY29kZT4sIDxjb2RlPlBpPC9jb2RlPl0uCiAgICAgICAgICogQGV4Y2VwdGlvbiB7RGV2ZWxvcGVyRXJyb3J9IDxjb2RlPndlc3Q8L2NvZGU+IG11c3QgYmUgaW4gdGhlIGludGVydmFsIFs8Y29kZT4tUGk8L2NvZGU+LCA8Y29kZT5QaTwvY29kZT5dLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIF92YWxpZGF0ZShyZWN0YW5nbGUpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IG5vcnRoID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoCiAgICAgICAgICAgICJub3J0aCIsCiAgICAgICAgICAgIG5vcnRoLAogICAgICAgICAgICAtTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPCiAgICAgICAgICApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoCiAgICAgICAgICAgICJub3J0aCIsCiAgICAgICAgICAgIG5vcnRoLAogICAgICAgICAgICBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08KICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBzb3V0aCA9IHJlY3RhbmdsZS5zb3V0aDsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKAogICAgICAgICAgICAic291dGgiLAogICAgICAgICAgICBzb3V0aCwKICAgICAgICAgICAgLU1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTwogICAgICAgICAgKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKAogICAgICAgICAgICAic291dGgiLAogICAgICAgICAgICBzb3V0aCwKICAgICAgICAgICAgTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPCiAgICAgICAgICApOwogICAgICAgICAgY29uc3Qgd2VzdCA9IHJlY3RhbmdsZS53ZXN0OwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIndlc3QiLCB3ZXN0LCAtTWF0aC5QSSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygid2VzdCIsIHdlc3QsIE1hdGguUEkpOwogICAgICAgICAgY29uc3QgZWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImVhc3QiLCBlYXN0LCAtTWF0aC5QSSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiZWFzdCIsIGVhc3QsIE1hdGguUEkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgc291dGh3ZXN0IGNvcm5lciBvZiBhIHJlY3RhbmdsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgVGhlIHJlY3RhbmdsZSBmb3Igd2hpY2ggdG8gZmluZCB0aGUgY29ybmVyCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc291dGh3ZXN0KHJlY3RhbmdsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlY3RhbmdsZSIsIHJlY3RhbmdsZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQocmVjdGFuZ2xlLndlc3QsIHJlY3RhbmdsZS5zb3V0aCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICByZXN1bHQubGF0aXR1ZGUgPSByZWN0YW5nbGUuc291dGg7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gMDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBub3J0aHdlc3QgY29ybmVyIG9mIGEgcmVjdGFuZ2xlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBUaGUgcmVjdGFuZ2xlIGZvciB3aGljaCB0byBmaW5kIHRoZSBjb3JuZXIKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRvZ3JhcGhpY30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ2FydG9ncmFwaGljIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBub3J0aHdlc3QocmVjdGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdChyZWN0YW5nbGUud2VzdCwgcmVjdGFuZ2xlLm5vcnRoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC5sb25naXR1ZGUgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICAgIHJlc3VsdC5oZWlnaHQgPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIG5vcnRoZWFzdCBjb3JuZXIgb2YgYSByZWN0YW5nbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gcmVjdGFuZ2xlIFRoZSByZWN0YW5nbGUgZm9yIHdoaWNoIHRvIGZpbmQgdGhlIGNvcm5lcgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydG9ncmFwaGljfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0b2dyYXBoaWMgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5vcnRoZWFzdChyZWN0YW5nbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KHJlY3RhbmdsZS5lYXN0LCByZWN0YW5nbGUubm9ydGgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgcmVzdWx0LmxhdGl0dWRlID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgc291dGhlYXN0IGNvcm5lciBvZiBhIHJlY3RhbmdsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgVGhlIHJlY3RhbmdsZSBmb3Igd2hpY2ggdG8gZmluZCB0aGUgY29ybmVyCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENhcnRvZ3JhcGhpYyBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc291dGhlYXN0KHJlY3RhbmdsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlY3RhbmdsZSIsIHJlY3RhbmdsZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQocmVjdGFuZ2xlLmVhc3QsIHJlY3RhbmdsZS5zb3V0aCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgICByZXN1bHQubGF0aXR1ZGUgPSByZWN0YW5nbGUuc291dGg7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gMDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjZW50ZXIgb2YgYSByZWN0YW5nbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gcmVjdGFuZ2xlIFRoZSByZWN0YW5nbGUgZm9yIHdoaWNoIHRvIGZpbmQgdGhlIGNlbnRlcgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydG9ncmFwaGljfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDYXJ0b2dyYXBoaWMgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNlbnRlcihyZWN0YW5nbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgbGV0IGVhc3QgPSByZWN0YW5nbGUuZWFzdDsKICAgICAgICAgIGNvbnN0IHdlc3QgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGlmIChlYXN0IDwgd2VzdCkgewogICAgICAgICAgICBlYXN0ICs9IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBsb25naXR1ZGUgPSBNYXRoX2RlZmF1bHQubmVnYXRpdmVQaVRvUGkoKHdlc3QgKyBlYXN0KSAqIDAuNSk7CiAgICAgICAgICBjb25zdCBsYXRpdHVkZSA9IChyZWN0YW5nbGUuc291dGggKyByZWN0YW5nbGUubm9ydGgpICogMC41OwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KGxvbmdpdHVkZSwgbGF0aXR1ZGUpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGxvbmdpdHVkZTsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IGxhdGl0dWRlOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHR3byByZWN0YW5nbGVzLiAgVGhpcyBmdW5jdGlvbiBhc3N1bWVzIHRoYXQgdGhlIHJlY3RhbmdsZSdzIGNvb3JkaW5hdGVzIGFyZQogICAgICAgICAqIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgaW4gcmFkaWFucyBhbmQgcHJvZHVjZXMgYSBjb3JyZWN0IGludGVyc2VjdGlvbiwgdGFraW5nIGludG8gYWNjb3VudCB0aGUgZmFjdCB0aGF0CiAgICAgICAgICogdGhlIHNhbWUgYW5nbGUgY2FuIGJlIHJlcHJlc2VudGVkIHdpdGggbXVsdGlwbGUgdmFsdWVzIGFzIHdlbGwgYXMgdGhlIHdyYXBwaW5nIG9mIGxvbmdpdHVkZSBhdCB0aGUKICAgICAgICAgKiBhbnRpLW1lcmlkaWFuLiAgRm9yIGEgc2ltcGxlIGludGVyc2VjdGlvbiB0aGF0IGlnbm9yZXMgdGhlc2UgZmFjdG9ycyBhbmQgY2FuIGJlIHVzZWQgd2l0aCBwcm9qZWN0ZWQKICAgICAgICAgKiBjb29yZGluYXRlcywgc2VlIHtAbGluayBSZWN0YW5nbGUuc2ltcGxlSW50ZXJzZWN0aW9ufS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgT24gcmVjdGFuZ2xlIHRvIGZpbmQgYW4gaW50ZXJzZWN0aW9uCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IG90aGVyUmVjdGFuZ2xlIEFub3RoZXIgcmVjdGFuZ2xlIHRvIGZpbmQgYW4gaW50ZXJzZWN0aW9uCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV8dW5kZWZpbmVkfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkIG9yIHVuZGVmaW5lZCBpZiB0aGVyZSBpcyBubyBpbnRlcnNlY3Rpb24uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGludGVyc2VjdGlvbihyZWN0YW5nbGUsIG90aGVyUmVjdGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3RoZXJSZWN0YW5nbGUiLCBvdGhlclJlY3RhbmdsZSk7CiAgICAgICAgICBsZXQgcmVjdGFuZ2xlRWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgbGV0IHJlY3RhbmdsZVdlc3QgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGxldCBvdGhlclJlY3RhbmdsZUVhc3QgPSBvdGhlclJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgbGV0IG90aGVyUmVjdGFuZ2xlV2VzdCA9IG90aGVyUmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICBpZiAocmVjdGFuZ2xlRWFzdCA8IHJlY3RhbmdsZVdlc3QgJiYgb3RoZXJSZWN0YW5nbGVFYXN0ID4gMCkgewogICAgICAgICAgICByZWN0YW5nbGVFYXN0ICs9IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICB9IGVsc2UgaWYgKG90aGVyUmVjdGFuZ2xlRWFzdCA8IG90aGVyUmVjdGFuZ2xlV2VzdCAmJiByZWN0YW5nbGVFYXN0ID4gMCkgewogICAgICAgICAgICBvdGhlclJlY3RhbmdsZUVhc3QgKz0gTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWN0YW5nbGVFYXN0IDwgcmVjdGFuZ2xlV2VzdCAmJiBvdGhlclJlY3RhbmdsZVdlc3QgPCAwKSB7CiAgICAgICAgICAgIG90aGVyUmVjdGFuZ2xlV2VzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfSBlbHNlIGlmIChvdGhlclJlY3RhbmdsZUVhc3QgPCBvdGhlclJlY3RhbmdsZVdlc3QgJiYgcmVjdGFuZ2xlV2VzdCA8IDApIHsKICAgICAgICAgICAgcmVjdGFuZ2xlV2VzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgbGV0IHdlc3QgPSBNYXRoX2RlZmF1bHQubmVnYXRpdmVQaVRvUGkoCiAgICAgICAgICAgIE1hdGgubWF4KHJlY3RhbmdsZVdlc3QsIG90aGVyUmVjdGFuZ2xlV2VzdCkKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBlYXN0ID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKAogICAgICAgICAgICBNYXRoLm1pbihyZWN0YW5nbGVFYXN0LCBvdGhlclJlY3RhbmdsZUVhc3QpCiAgICAgICAgICApOwogICAgICAgICAgaWYgKHdlc3QgPT09IE1hdGhfZGVmYXVsdC5QSSAmJiBlYXN0IDwgTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICAgIHdlc3QgPSAtTWF0aF9kZWZhdWx0LlBJOwogICAgICAgICAgfQogICAgICAgICAgaWYgKChyZWN0YW5nbGUud2VzdCA8IHJlY3RhbmdsZS5lYXN0IHx8IG90aGVyUmVjdGFuZ2xlLndlc3QgPCBvdGhlclJlY3RhbmdsZS5lYXN0KSAmJiBlYXN0IDw9IHdlc3QpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHNvdXRoID0gTWF0aC5tYXgocmVjdGFuZ2xlLnNvdXRoLCBvdGhlclJlY3RhbmdsZS5zb3V0aCk7CiAgICAgICAgICBjb25zdCBub3J0aCA9IE1hdGgubWluKHJlY3RhbmdsZS5ub3J0aCwgb3RoZXJSZWN0YW5nbGUubm9ydGgpOwogICAgICAgICAgaWYgKHNvdXRoID49IG5vcnRoKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JlY3RhbmdsZSh3ZXN0LCBzb3V0aCwgZWFzdCwgbm9ydGgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0Lndlc3QgPSB3ZXN0OwogICAgICAgICAgcmVzdWx0LnNvdXRoID0gc291dGg7CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGVhc3Q7CiAgICAgICAgICByZXN1bHQubm9ydGggPSBub3J0aDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgc2ltcGxlIGludGVyc2VjdGlvbiBvZiB0d28gcmVjdGFuZ2xlcy4gIFVubGlrZSB7QGxpbmsgUmVjdGFuZ2xlLmludGVyc2VjdGlvbn0sIHRoaXMgZnVuY3Rpb24KICAgICAgICAgKiBkb2VzIG5vdCBhdHRlbXB0IHRvIHB1dCB0aGUgYW5ndWxhciBjb29yZGluYXRlcyBpbnRvIGEgY29uc2lzdGVudCByYW5nZSBvciB0byBhY2NvdW50IGZvciBjcm9zc2luZyB0aGUKICAgICAgICAgKiBhbnRpLW1lcmlkaWFuLiAgQXMgc3VjaCwgaXQgY2FuIGJlIHVzZWQgZm9yIHJlY3RhbmdsZXMgd2hlcmUgdGhlIGNvb3JkaW5hdGVzIGFyZSBub3Qgc2ltcGx5IGxhdGl0dWRlCiAgICAgICAgICogYW5kIGxvbmdpdHVkZSAoaS5lLiBwcm9qZWN0ZWQgY29vcmRpbmF0ZXMpLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBPbiByZWN0YW5nbGUgdG8gZmluZCBhbiBpbnRlcnNlY3Rpb24KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gb3RoZXJSZWN0YW5nbGUgQW5vdGhlciByZWN0YW5nbGUgdG8gZmluZCBhbiBpbnRlcnNlY3Rpb24KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZXx1bmRlZmluZWR9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBhIG5ldyBSZWN0YW5nbGUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQgb3IgdW5kZWZpbmVkIGlmIHRoZXJlIGlzIG5vIGludGVyc2VjdGlvbi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2ltcGxlSW50ZXJzZWN0aW9uKHJlY3RhbmdsZSwgb3RoZXJSZWN0YW5nbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvdGhlclJlY3RhbmdsZSIsIG90aGVyUmVjdGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHdlc3QgPSBNYXRoLm1heChyZWN0YW5nbGUud2VzdCwgb3RoZXJSZWN0YW5nbGUud2VzdCk7CiAgICAgICAgICBjb25zdCBzb3V0aCA9IE1hdGgubWF4KHJlY3RhbmdsZS5zb3V0aCwgb3RoZXJSZWN0YW5nbGUuc291dGgpOwogICAgICAgICAgY29uc3QgZWFzdCA9IE1hdGgubWluKHJlY3RhbmdsZS5lYXN0LCBvdGhlclJlY3RhbmdsZS5lYXN0KTsKICAgICAgICAgIGNvbnN0IG5vcnRoID0gTWF0aC5taW4ocmVjdGFuZ2xlLm5vcnRoLCBvdGhlclJlY3RhbmdsZS5ub3J0aCk7CiAgICAgICAgICBpZiAoc291dGggPj0gbm9ydGggfHwgd2VzdCA+PSBlYXN0KSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JlY3RhbmdsZSh3ZXN0LCBzb3V0aCwgZWFzdCwgbm9ydGgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0Lndlc3QgPSB3ZXN0OwogICAgICAgICAgcmVzdWx0LnNvdXRoID0gc291dGg7CiAgICAgICAgICByZXN1bHQuZWFzdCA9IGVhc3Q7CiAgICAgICAgICByZXN1bHQubm9ydGggPSBub3J0aDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgcmVjdGFuZ2xlIHRoYXQgaXMgdGhlIHVuaW9uIG9mIHR3byByZWN0YW5nbGVzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IHJlY3RhbmdsZSBBIHJlY3RhbmdsZSB0byBlbmNsb3NlIGluIHJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gb3RoZXJSZWN0YW5nbGUgQSByZWN0YW5nbGUgdG8gZW5jbG9zZSBpbiBhIHJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bmlvbihyZWN0YW5nbGUsIG90aGVyUmVjdGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3RoZXJSZWN0YW5nbGUiLCBvdGhlclJlY3RhbmdsZSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfUmVjdGFuZ2xlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgcmVjdGFuZ2xlRWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgbGV0IHJlY3RhbmdsZVdlc3QgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGxldCBvdGhlclJlY3RhbmdsZUVhc3QgPSBvdGhlclJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgbGV0IG90aGVyUmVjdGFuZ2xlV2VzdCA9IG90aGVyUmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICBpZiAocmVjdGFuZ2xlRWFzdCA8IHJlY3RhbmdsZVdlc3QgJiYgb3RoZXJSZWN0YW5nbGVFYXN0ID4gMCkgewogICAgICAgICAgICByZWN0YW5nbGVFYXN0ICs9IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICB9IGVsc2UgaWYgKG90aGVyUmVjdGFuZ2xlRWFzdCA8IG90aGVyUmVjdGFuZ2xlV2VzdCAmJiByZWN0YW5nbGVFYXN0ID4gMCkgewogICAgICAgICAgICBvdGhlclJlY3RhbmdsZUVhc3QgKz0gTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWN0YW5nbGVFYXN0IDwgcmVjdGFuZ2xlV2VzdCAmJiBvdGhlclJlY3RhbmdsZVdlc3QgPCAwKSB7CiAgICAgICAgICAgIG90aGVyUmVjdGFuZ2xlV2VzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfSBlbHNlIGlmIChvdGhlclJlY3RhbmdsZUVhc3QgPCBvdGhlclJlY3RhbmdsZVdlc3QgJiYgcmVjdGFuZ2xlV2VzdCA8IDApIHsKICAgICAgICAgICAgcmVjdGFuZ2xlV2VzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgd2VzdCA9IE1hdGhfZGVmYXVsdC5uZWdhdGl2ZVBpVG9QaSgKICAgICAgICAgICAgTWF0aC5taW4ocmVjdGFuZ2xlV2VzdCwgb3RoZXJSZWN0YW5nbGVXZXN0KQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IGVhc3QgPSBNYXRoX2RlZmF1bHQubmVnYXRpdmVQaVRvUGkoCiAgICAgICAgICAgIE1hdGgubWF4KHJlY3RhbmdsZUVhc3QsIG90aGVyUmVjdGFuZ2xlRWFzdCkKICAgICAgICAgICk7CiAgICAgICAgICByZXN1bHQud2VzdCA9IHdlc3Q7CiAgICAgICAgICByZXN1bHQuc291dGggPSBNYXRoLm1pbihyZWN0YW5nbGUuc291dGgsIG90aGVyUmVjdGFuZ2xlLnNvdXRoKTsKICAgICAgICAgIHJlc3VsdC5lYXN0ID0gZWFzdDsKICAgICAgICAgIHJlc3VsdC5ub3J0aCA9IE1hdGgubWF4KHJlY3RhbmdsZS5ub3J0aCwgb3RoZXJSZWN0YW5nbGUubm9ydGgpOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSByZWN0YW5nbGUgYnkgZW5sYXJnaW5nIHRoZSBwcm92aWRlZCByZWN0YW5nbGUgdW50aWwgaXQgY29udGFpbnMgdGhlIHByb3ZpZGVkIGNhcnRvZ3JhcGhpYy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgQSByZWN0YW5nbGUgdG8gZXhwYW5kLgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBjYXJ0b2dyYXBoaWMgQSBjYXJ0b2dyYXBoaWMgdG8gZW5jbG9zZSBpbiBhIHJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgUmVjdGFuZ2xlIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBleHBhbmQocmVjdGFuZ2xlLCBjYXJ0b2dyYXBoaWMyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydG9ncmFwaGljIiwgY2FydG9ncmFwaGljMik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfUmVjdGFuZ2xlKCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQud2VzdCA9IE1hdGgubWluKHJlY3RhbmdsZS53ZXN0LCBjYXJ0b2dyYXBoaWMyLmxvbmdpdHVkZSk7CiAgICAgICAgICByZXN1bHQuc291dGggPSBNYXRoLm1pbihyZWN0YW5nbGUuc291dGgsIGNhcnRvZ3JhcGhpYzIubGF0aXR1ZGUpOwogICAgICAgICAgcmVzdWx0LmVhc3QgPSBNYXRoLm1heChyZWN0YW5nbGUuZWFzdCwgY2FydG9ncmFwaGljMi5sb25naXR1ZGUpOwogICAgICAgICAgcmVzdWx0Lm5vcnRoID0gTWF0aC5tYXgocmVjdGFuZ2xlLm5vcnRoLCBjYXJ0b2dyYXBoaWMyLmxhdGl0dWRlKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgY2FydG9ncmFwaGljIGlzIG9uIG9yIGluc2lkZSB0aGUgcmVjdGFuZ2xlLCBmYWxzZSBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gcmVjdGFuZ2xlIFRoZSByZWN0YW5nbGUKICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gY2FydG9ncmFwaGljIFRoZSBjYXJ0b2dyYXBoaWMgdG8gdGVzdC4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgcHJvdmlkZWQgY2FydG9ncmFwaGljIGlzIGluc2lkZSB0aGUgcmVjdGFuZ2xlLCBmYWxzZSBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbnRhaW5zKHJlY3RhbmdsZSwgY2FydG9ncmFwaGljMikgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0b2dyYXBoaWMiLCBjYXJ0b2dyYXBoaWMyKTsKICAgICAgICAgIGxldCBsb25naXR1ZGUgPSBjYXJ0b2dyYXBoaWMyLmxvbmdpdHVkZTsKICAgICAgICAgIGNvbnN0IGxhdGl0dWRlID0gY2FydG9ncmFwaGljMi5sYXRpdHVkZTsKICAgICAgICAgIGNvbnN0IHdlc3QgPSByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGxldCBlYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgICBpZiAoZWFzdCA8IHdlc3QpIHsKICAgICAgICAgICAgZWFzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgICBpZiAobG9uZ2l0dWRlIDwgMCkgewogICAgICAgICAgICAgIGxvbmdpdHVkZSArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gKGxvbmdpdHVkZSA+IHdlc3QgfHwgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24obG9uZ2l0dWRlLCB3ZXN0LCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgJiYgKGxvbmdpdHVkZSA8IGVhc3QgfHwgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24obG9uZ2l0dWRlLCBlYXN0LCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgJiYgbGF0aXR1ZGUgPj0gcmVjdGFuZ2xlLnNvdXRoICYmIGxhdGl0dWRlIDw9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2FtcGxlcyBhIHJlY3RhbmdsZSBzbyB0aGF0IGl0IGluY2x1ZGVzIGEgbGlzdCBvZiBDYXJ0ZXNpYW4gcG9pbnRzIHN1aXRhYmxlIGZvciBwYXNzaW5nIHRvCiAgICAgICAgICoge0BsaW5rIEJvdW5kaW5nU3BoZXJlI2Zyb21Qb2ludHN9LiAgU2FtcGxpbmcgaXMgbmVjZXNzYXJ5IHRvIGFjY291bnQKICAgICAgICAgKiBmb3IgcmVjdGFuZ2xlcyB0aGF0IGNvdmVyIHRoZSBwb2xlcyBvciBjcm9zcyB0aGUgZXF1YXRvci4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgVGhlIHJlY3RhbmdsZSB0byBzdWJzYW1wbGUuCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3VyZmFjZUhlaWdodD0wLjBdIFRoZSBoZWlnaHQgb2YgdGhlIHJlY3RhbmdsZSBhYm92ZSB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM1tdfSBbcmVzdWx0XSBUaGUgYXJyYXkgb2YgQ2FydGVzaWFucyBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjNbXX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQXJyYXkgb2YgQ2FydGVzaWFucyBpbnN0YW5jZXMgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHN1YnNhbXBsZShyZWN0YW5nbGUsIGVsbGlwc29pZCwgc3VyZmFjZUhlaWdodCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlY3RhbmdsZSIsIHJlY3RhbmdsZSk7CiAgICAgICAgICBlbGxpcHNvaWQgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICAgIHN1cmZhY2VIZWlnaHQgPSBzdXJmYWNlSGVpZ2h0ID8/IDA7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IFtdOwogICAgICAgICAgfQogICAgICAgICAgbGV0IGxlbmd0aCA9IDA7CiAgICAgICAgICBjb25zdCBub3J0aCA9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICAgIGNvbnN0IHNvdXRoID0gcmVjdGFuZ2xlLnNvdXRoOwogICAgICAgICAgY29uc3QgZWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgY29uc3Qgd2VzdCA9IHJlY3RhbmdsZS53ZXN0OwogICAgICAgICAgY29uc3QgbGxhID0gc3Vic2FtcGxlTGxhU2NyYXRjaDsKICAgICAgICAgIGxsYS5oZWlnaHQgPSBzdXJmYWNlSGVpZ2h0OwogICAgICAgICAgbGxhLmxvbmdpdHVkZSA9IHdlc3Q7CiAgICAgICAgICBsbGEubGF0aXR1ZGUgPSBub3J0aDsKICAgICAgICAgIHJlc3VsdFtsZW5ndGhdID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGxsYSwgcmVzdWx0W2xlbmd0aF0pOwogICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICBsbGEubG9uZ2l0dWRlID0gZWFzdDsKICAgICAgICAgIHJlc3VsdFtsZW5ndGhdID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGxsYSwgcmVzdWx0W2xlbmd0aF0pOwogICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICBsbGEubGF0aXR1ZGUgPSBzb3V0aDsKICAgICAgICAgIHJlc3VsdFtsZW5ndGhdID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGxsYSwgcmVzdWx0W2xlbmd0aF0pOwogICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICBsbGEubG9uZ2l0dWRlID0gd2VzdDsKICAgICAgICAgIHJlc3VsdFtsZW5ndGhdID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGxsYSwgcmVzdWx0W2xlbmd0aF0pOwogICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICBpZiAobm9ydGggPCAwKSB7CiAgICAgICAgICAgIGxsYS5sYXRpdHVkZSA9IG5vcnRoOwogICAgICAgICAgfSBlbHNlIGlmIChzb3V0aCA+IDApIHsKICAgICAgICAgICAgbGxhLmxhdGl0dWRlID0gc291dGg7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBsbGEubGF0aXR1ZGUgPSAwOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IDg7ICsraTIpIHsKICAgICAgICAgICAgbGxhLmxvbmdpdHVkZSA9IC1NYXRoLlBJICsgaTIgKiBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV087CiAgICAgICAgICAgIGlmIChfUmVjdGFuZ2xlLmNvbnRhaW5zKHJlY3RhbmdsZSwgbGxhKSkgewogICAgICAgICAgICAgIHJlc3VsdFtsZW5ndGhdID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGxsYSwgcmVzdWx0W2xlbmd0aF0pOwogICAgICAgICAgICAgIGxlbmd0aCsrOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobGxhLmxhdGl0dWRlID09PSAwKSB7CiAgICAgICAgICAgIGxsYS5sb25naXR1ZGUgPSB3ZXN0OwogICAgICAgICAgICByZXN1bHRbbGVuZ3RoXSA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihsbGEsIHJlc3VsdFtsZW5ndGhdKTsKICAgICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICAgIGxsYS5sb25naXR1ZGUgPSBlYXN0OwogICAgICAgICAgICByZXN1bHRbbGVuZ3RoXSA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihsbGEsIHJlc3VsdFtsZW5ndGhdKTsKICAgICAgICAgICAgbGVuZ3RoKys7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBzdWJzZWN0aW9uIG9mIGEgcmVjdGFuZ2xlIGZyb20gbm9ybWFsaXplZCBjb29yZGluYXRlcyBpbiB0aGUgcmFuZ2UgWzAuMCwgMS4wXS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSByZWN0YW5nbGUgVGhlIHJlY3RhbmdsZSB0byBzdWJzZWN0aW9uLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3ZXN0TGVycCBUaGUgd2VzdCBpbnRlcnBvbGF0aW9uIGZhY3RvciBpbiB0aGUgcmFuZ2UgWzAuMCwgMS4wXS4gTXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gZWFzdExlcnAuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNvdXRoTGVycCBUaGUgc291dGggaW50ZXJwb2xhdGlvbiBmYWN0b3IgaW4gdGhlIHJhbmdlIFswLjAsIDEuMF0uIE11c3QgYmUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIG5vcnRoTGVycC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gZWFzdExlcnAgVGhlIGVhc3QgaW50ZXJwb2xhdGlvbiBmYWN0b3IgaW4gdGhlIHJhbmdlIFswLjAsIDEuMF0uIE11c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHdlc3RMZXJwLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBub3J0aExlcnAgVGhlIG5vcnRoIGludGVycG9sYXRpb24gZmFjdG9yIGluIHRoZSByYW5nZSBbMC4wLCAxLjBdLiBNdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byBzb3V0aExlcnAuCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IFJlY3RhbmdsZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc3Vic2VjdGlvbihyZWN0YW5nbGUsIHdlc3RMZXJwLCBzb3V0aExlcnAsIGVhc3RMZXJwLCBub3J0aExlcnAsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIndlc3RMZXJwIiwgd2VzdExlcnAsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoIndlc3RMZXJwIiwgd2VzdExlcnAsIDEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoInNvdXRoTGVycCIsIHNvdXRoTGVycCwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygic291dGhMZXJwIiwgc291dGhMZXJwLCAxKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJlYXN0TGVycCIsIGVhc3RMZXJwLCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJlYXN0TGVycCIsIGVhc3RMZXJwLCAxKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJub3J0aExlcnAiLCBub3J0aExlcnAsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoIm5vcnRoTGVycCIsIG5vcnRoTGVycCwgMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygid2VzdExlcnAiLCB3ZXN0TGVycCwgZWFzdExlcnApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoInNvdXRoTGVycCIsIHNvdXRoTGVycCwgbm9ydGhMZXJwKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9SZWN0YW5nbGUoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChyZWN0YW5nbGUud2VzdCA8PSByZWN0YW5nbGUuZWFzdCkgewogICAgICAgICAgICBjb25zdCB3aWR0aCA9IHJlY3RhbmdsZS5lYXN0IC0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICAgIHJlc3VsdC53ZXN0ID0gcmVjdGFuZ2xlLndlc3QgKyB3ZXN0TGVycCAqIHdpZHRoOwogICAgICAgICAgICByZXN1bHQuZWFzdCA9IHJlY3RhbmdsZS53ZXN0ICsgZWFzdExlcnAgKiB3aWR0aDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGNvbnN0IHdpZHRoID0gTWF0aF9kZWZhdWx0LlRXT19QSSArIHJlY3RhbmdsZS5lYXN0IC0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICAgIHJlc3VsdC53ZXN0ID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKAogICAgICAgICAgICAgIHJlY3RhbmdsZS53ZXN0ICsgd2VzdExlcnAgKiB3aWR0aAogICAgICAgICAgICApOwogICAgICAgICAgICByZXN1bHQuZWFzdCA9IE1hdGhfZGVmYXVsdC5uZWdhdGl2ZVBpVG9QaSgKICAgICAgICAgICAgICByZWN0YW5nbGUud2VzdCArIGVhc3RMZXJwICogd2lkdGgKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhlaWdodCA9IHJlY3RhbmdsZS5ub3J0aCAtIHJlY3RhbmdsZS5zb3V0aDsKICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IHJlY3RhbmdsZS5zb3V0aCArIHNvdXRoTGVycCAqIGhlaWdodDsKICAgICAgICAgIHJlc3VsdC5ub3J0aCA9IHJlY3RhbmdsZS5zb3V0aCArIG5vcnRoTGVycCAqIGhlaWdodDsKICAgICAgICAgIGlmICh3ZXN0TGVycCA9PT0gMSkgewogICAgICAgICAgICByZXN1bHQud2VzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgfQogICAgICAgICAgaWYgKGVhc3RMZXJwID09PSAxKSB7CiAgICAgICAgICAgIHJlc3VsdC5lYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoc291dGhMZXJwID09PSAxKSB7CiAgICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChub3J0aExlcnAgPT09IDEpIHsKICAgICAgICAgICAgcmVzdWx0Lm5vcnRoID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFJlY3RhbmdsZS5wYWNrZWRMZW5ndGggPSA0OwogICAgICBmcm9tQm91bmRpbmdTcGhlcmVNYXRyaXhTY3JhdGNoID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBmcm9tQm91bmRpbmdTcGhlcmVFYXN0U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbUJvdW5kaW5nU3BoZXJlTm9ydGhTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tQm91bmRpbmdTcGhlcmVXZXN0U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbUJvdW5kaW5nU3BoZXJlU291dGhTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tQm91bmRpbmdTcGhlcmVQb3NpdGlvbnNTY3JhdGNoID0gbmV3IEFycmF5KDUpOwogICAgICBmb3IgKGxldCBuMiA9IDA7IG4yIDwgZnJvbUJvdW5kaW5nU3BoZXJlUG9zaXRpb25zU2NyYXRjaC5sZW5ndGg7ICsrbjIpIHsKICAgICAgICBmcm9tQm91bmRpbmdTcGhlcmVQb3NpdGlvbnNTY3JhdGNoW24yXSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgfQogICAgICBzdWJzYW1wbGVMbGFTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIFJlY3RhbmdsZS5NQVhfVkFMVUUgPSBPYmplY3QuZnJlZXplKAogICAgICAgIG5ldyBSZWN0YW5nbGUoCiAgICAgICAgICAtTWF0aC5QSSwKICAgICAgICAgIC1NYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08sCiAgICAgICAgICBNYXRoLlBJLAogICAgICAgICAgTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPCiAgICAgICAgKQogICAgICApOwogICAgICBSZWN0YW5nbGVfZGVmYXVsdCA9IFJlY3RhbmdsZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0JvdW5kaW5nU3BoZXJlLmpzCiAgdmFyIEJvdW5kaW5nU3BoZXJlLCBmcm9tUG9pbnRzWE1pbiwgZnJvbVBvaW50c1lNaW4sIGZyb21Qb2ludHNaTWluLCBmcm9tUG9pbnRzWE1heCwgZnJvbVBvaW50c1lNYXgsIGZyb21Qb2ludHNaTWF4LCBmcm9tUG9pbnRzQ3VycmVudFBvcywgZnJvbVBvaW50c1NjcmF0Y2gsIGZyb21Qb2ludHNSaXR0ZXJDZW50ZXIsIGZyb21Qb2ludHNNaW5Cb3hQdCwgZnJvbVBvaW50c01heEJveFB0LCBmcm9tUG9pbnRzTmFpdmVDZW50ZXJTY3JhdGNoLCB2b2x1bWVDb25zdGFudCwgZGVmYXVsdFByb2plY3Rpb24sIGZyb21SZWN0YW5nbGUyRExvd2VyTGVmdCwgZnJvbVJlY3RhbmdsZTJEVXBwZXJSaWdodCwgZnJvbVJlY3RhbmdsZTJEU291dGh3ZXN0LCBmcm9tUmVjdGFuZ2xlMkROb3J0aGVhc3QsIGZyb21SZWN0YW5nbGUzRFNjcmF0Y2gsIGZyb21PcmllbnRlZEJvdW5kaW5nQm94U2NyYXRjaFUsIGZyb21PcmllbnRlZEJvdW5kaW5nQm94U2NyYXRjaFYsIGZyb21PcmllbnRlZEJvdW5kaW5nQm94U2NyYXRjaFcsIHNjcmF0Y2hGcm9tVHJhbnNmb3JtYXRpb25DZW50ZXIsIHNjcmF0Y2hGcm9tVHJhbnNmb3JtYXRpb25TY2FsZSwgdW5pb25TY3JhdGNoLCB1bmlvblNjcmF0Y2hDZW50ZXIsIGV4cGFuZFNjcmF0Y2gsIGRpc3RhbmNlU3F1YXJlZFRvU2NyYXRjaCwgc2NyYXRjaENhcnRlc2lhbjMsIHByb2plY3RUbzJETm9ybWFsU2NyYXRjaCwgcHJvamVjdFRvMkRFYXN0U2NyYXRjaCwgcHJvamVjdFRvMkROb3J0aFNjcmF0Y2gsIHByb2plY3RUbzJEV2VzdFNjcmF0Y2gsIHByb2plY3RUbzJEU291dGhTY3JhdGNoLCBwcm9qZWN0VG8yRENhcnRvZ3JhcGhpY1NjcmF0Y2gsIHByb2plY3RUbzJEUG9zaXRpb25zU2NyYXRjaCwgcHJvamVjdFRvMkRQcm9qZWN0aW9uLCBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0OwogIHZhciBpbml0X0JvdW5kaW5nU3BoZXJlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Cb3VuZGluZ1NwaGVyZS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb2dyYXBoaWNQcm9qZWN0aW9uKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0KCk7CiAgICAgIGluaXRfSW50ZXJ2YWwoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgQm91bmRpbmdTcGhlcmUgPSBjbGFzcyBfQm91bmRpbmdTcGhlcmUgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW2NlbnRlcj1DYXJ0ZXNpYW4zLlpFUk9dIFRoZSBjZW50ZXIgb2YgdGhlIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3JhZGl1cz0wLjBdIFRoZSByYWRpdXMgb2YgdGhlIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihjZW50ZXIsIHJhZGl1cykgewogICAgICAgICAgdGhpcy5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyID8/IENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKTsKICAgICAgICAgIHRoaXMucmFkaXVzID0gcmFkaXVzID8/IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgdGlnaHQtZml0dGluZyBib3VuZGluZyBzcGhlcmUgZW5jbG9zaW5nIGEgbGlzdCBvZiAzRCBDYXJ0ZXNpYW4gcG9pbnRzLgogICAgICAgICAqIFRoZSBib3VuZGluZyBzcGhlcmUgaXMgY29tcHV0ZWQgYnkgcnVubmluZyB0d28gYWxnb3JpdGhtcywgYSBuYWl2ZSBhbGdvcml0aG0gYW5kCiAgICAgICAgICogUml0dGVyJ3MgYWxnb3JpdGhtLiBUaGUgc21hbGxlciBvZiB0aGUgdHdvIHNwaGVyZXMgaXMgdXNlZCB0byBlbnN1cmUgYSB0aWdodCBmaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjNbXX0gW3Bvc2l0aW9uc10gQW4gYXJyYXkgb2YgcG9pbnRzIHRoYXQgdGhlIGJvdW5kaW5nIHNwaGVyZSB3aWxsIGVuY2xvc2UuICBFYWNoIHBvaW50IG11c3QgaGF2ZSA8Y29kZT54PC9jb2RlPiwgPGNvZGU+eTwvY29kZT4sIGFuZCA8Y29kZT56PC9jb2RlPiBwcm9wZXJ0aWVzLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwOi8vaGVscC5hZ2kuY29tL0FHSUNvbXBvbmVudHMvaHRtbC9CbG9nQm91bmRpbmdTcGhlcmUuaHRtfEJvdW5kaW5nIFNwaGVyZSBjb21wdXRhdGlvbiBhcnRpY2xlfQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUG9pbnRzKHBvc2l0aW9ucywgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykgfHwgcG9zaXRpb25zLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCByZXN1bHQuY2VudGVyKTsKICAgICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IDA7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBjdXJyZW50UG9zID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHBvc2l0aW9uc1swXSwgZnJvbVBvaW50c0N1cnJlbnRQb3MpOwogICAgICAgICAgY29uc3QgeE1pbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWE1pbik7CiAgICAgICAgICBjb25zdCB5TWluID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNZTWluKTsKICAgICAgICAgIGNvbnN0IHpNaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1pNaW4pOwogICAgICAgICAgY29uc3QgeE1heCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWE1heCk7CiAgICAgICAgICBjb25zdCB5TWF4ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNZTWF4KTsKICAgICAgICAgIGNvbnN0IHpNYXggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1pNYXgpOwogICAgICAgICAgY29uc3QgbnVtUG9zaXRpb25zID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgIGxldCBpMjsKICAgICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IG51bVBvc2l0aW9uczsgaTIrKykgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb25zW2kyXSwgY3VycmVudFBvcyk7CiAgICAgICAgICAgIGNvbnN0IHgyID0gY3VycmVudFBvcy54OwogICAgICAgICAgICBjb25zdCB5MiA9IGN1cnJlbnRQb3MueTsKICAgICAgICAgICAgY29uc3QgejIgPSBjdXJyZW50UG9zLno7CiAgICAgICAgICAgIGlmICh4MiA8IHhNaW4ueCkgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB4TWluKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoeDIgPiB4TWF4LngpIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgeE1heCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHkyIDwgeU1pbi55KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHlNaW4pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh5MiA+IHlNYXgueSkgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB5TWF4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoejIgPCB6TWluLnopIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgek1pbik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHoyID4gek1heC56KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHpNYXgpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCB4U3BhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGVTcXVhcmVkKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoeE1heCwgeE1pbiwgZnJvbVBvaW50c1NjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgeVNwYW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHlNYXgsIHlNaW4sIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHpTcGFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh6TWF4LCB6TWluLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgZGlhbWV0ZXIxID0geE1pbjsKICAgICAgICAgIGxldCBkaWFtZXRlcjIgPSB4TWF4OwogICAgICAgICAgbGV0IG1heFNwYW4gPSB4U3BhbjsKICAgICAgICAgIGlmICh5U3BhbiA+IG1heFNwYW4pIHsKICAgICAgICAgICAgbWF4U3BhbiA9IHlTcGFuOwogICAgICAgICAgICBkaWFtZXRlcjEgPSB5TWluOwogICAgICAgICAgICBkaWFtZXRlcjIgPSB5TWF4OwogICAgICAgICAgfQogICAgICAgICAgaWYgKHpTcGFuID4gbWF4U3BhbikgewogICAgICAgICAgICBkaWFtZXRlcjEgPSB6TWluOwogICAgICAgICAgICBkaWFtZXRlcjIgPSB6TWF4OwogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgcml0dGVyQ2VudGVyID0gZnJvbVBvaW50c1JpdHRlckNlbnRlcjsKICAgICAgICAgIHJpdHRlckNlbnRlci54ID0gKGRpYW1ldGVyMS54ICsgZGlhbWV0ZXIyLngpICogMC41OwogICAgICAgICAgcml0dGVyQ2VudGVyLnkgPSAoZGlhbWV0ZXIxLnkgKyBkaWFtZXRlcjIueSkgKiAwLjU7CiAgICAgICAgICByaXR0ZXJDZW50ZXIueiA9IChkaWFtZXRlcjEueiArIGRpYW1ldGVyMi56KSAqIDAuNTsKICAgICAgICAgIGxldCByYWRpdXNTcXVhcmVkID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChkaWFtZXRlcjIsIHJpdHRlckNlbnRlciwgZnJvbVBvaW50c1NjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgbGV0IHJpdHRlclJhZGl1cyA9IE1hdGguc3FydChyYWRpdXNTcXVhcmVkKTsKICAgICAgICAgIGNvbnN0IG1pbkJveFB0ID0gZnJvbVBvaW50c01pbkJveFB0OwogICAgICAgICAgbWluQm94UHQueCA9IHhNaW4ueDsKICAgICAgICAgIG1pbkJveFB0LnkgPSB5TWluLnk7CiAgICAgICAgICBtaW5Cb3hQdC56ID0gek1pbi56OwogICAgICAgICAgY29uc3QgbWF4Qm94UHQgPSBmcm9tUG9pbnRzTWF4Qm94UHQ7CiAgICAgICAgICBtYXhCb3hQdC54ID0geE1heC54OwogICAgICAgICAgbWF4Qm94UHQueSA9IHlNYXgueTsKICAgICAgICAgIG1heEJveFB0LnogPSB6TWF4Lno7CiAgICAgICAgICBjb25zdCBuYWl2ZUNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5taWRwb2ludCgKICAgICAgICAgICAgbWluQm94UHQsCiAgICAgICAgICAgIG1heEJveFB0LAogICAgICAgICAgICBmcm9tUG9pbnRzTmFpdmVDZW50ZXJTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgbGV0IG5haXZlUmFkaXVzID0gMDsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bVBvc2l0aW9uczsgaTIrKykgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb25zW2kyXSwgY3VycmVudFBvcyk7CiAgICAgICAgICAgIGNvbnN0IHIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgbmFpdmVDZW50ZXIsIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAocjIgPiBuYWl2ZVJhZGl1cykgewogICAgICAgICAgICAgIG5haXZlUmFkaXVzID0gcjI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgb2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgcml0dGVyQ2VudGVyLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICAgKTsKICAgICAgICAgICAgaWYgKG9sZENlbnRlclRvUG9pbnRTcXVhcmVkID4gcmFkaXVzU3F1YXJlZCkgewogICAgICAgICAgICAgIGNvbnN0IG9sZENlbnRlclRvUG9pbnQgPSBNYXRoLnNxcnQob2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQpOwogICAgICAgICAgICAgIHJpdHRlclJhZGl1cyA9IChyaXR0ZXJSYWRpdXMgKyBvbGRDZW50ZXJUb1BvaW50KSAqIDAuNTsKICAgICAgICAgICAgICByYWRpdXNTcXVhcmVkID0gcml0dGVyUmFkaXVzICogcml0dGVyUmFkaXVzOwogICAgICAgICAgICAgIGNvbnN0IG9sZFRvTmV3ID0gb2xkQ2VudGVyVG9Qb2ludCAtIHJpdHRlclJhZGl1czsKICAgICAgICAgICAgICByaXR0ZXJDZW50ZXIueCA9IChyaXR0ZXJSYWRpdXMgKiByaXR0ZXJDZW50ZXIueCArIG9sZFRvTmV3ICogY3VycmVudFBvcy54KSAvIG9sZENlbnRlclRvUG9pbnQ7CiAgICAgICAgICAgICAgcml0dGVyQ2VudGVyLnkgPSAocml0dGVyUmFkaXVzICogcml0dGVyQ2VudGVyLnkgKyBvbGRUb05ldyAqIGN1cnJlbnRQb3MueSkgLyBvbGRDZW50ZXJUb1BvaW50OwogICAgICAgICAgICAgIHJpdHRlckNlbnRlci56ID0gKHJpdHRlclJhZGl1cyAqIHJpdHRlckNlbnRlci56ICsgb2xkVG9OZXcgKiBjdXJyZW50UG9zLnopIC8gb2xkQ2VudGVyVG9Qb2ludDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHJpdHRlclJhZGl1cyA8IG5haXZlUmFkaXVzKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyaXR0ZXJDZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gcml0dGVyUmFkaXVzOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG5haXZlQ2VudGVyLCByZXN1bHQuY2VudGVyKTsKICAgICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IG5haXZlUmFkaXVzOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBib3VuZGluZyBzcGhlcmUgZnJvbSBhIHJlY3RhbmdsZSBwcm9qZWN0ZWQgaW4gMkQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3JlY3RhbmdsZV0gVGhlIHJlY3RhbmdsZSBhcm91bmQgd2hpY2ggdG8gY3JlYXRlIGEgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqIEBwYXJhbSB7TWFwUHJvamVjdGlvbn0gW3Byb2plY3Rpb249R2VvZ3JhcGhpY1Byb2plY3Rpb25dIFRoZSBwcm9qZWN0aW9uIHVzZWQgdG8gcHJvamVjdCB0aGUgcmVjdGFuZ2xlIGludG8gMkQuCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVJlY3RhbmdsZTJEKHJlY3RhbmdsZSwgcHJvamVjdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgICByZXR1cm4gX0JvdW5kaW5nU3BoZXJlLmZyb21SZWN0YW5nbGVXaXRoSGVpZ2h0czJEKAogICAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICAgIHByb2plY3Rpb24sCiAgICAgICAgICAgIDAsCiAgICAgICAgICAgIDAsCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBib3VuZGluZyBzcGhlcmUgZnJvbSBhIHJlY3RhbmdsZSBwcm9qZWN0ZWQgaW4gMkQuICBUaGUgYm91bmRpbmcgc3BoZXJlIGFjY291bnRzIGZvciB0aGUKICAgICAgICAgKiBvYmplY3QncyBtaW5pbXVtIGFuZCBtYXhpbXVtIGhlaWdodHMgb3ZlciB0aGUgcmVjdGFuZ2xlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZWN0YW5nbGVdIFRoZSByZWN0YW5nbGUgYXJvdW5kIHdoaWNoIHRvIGNyZWF0ZSBhIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKiBAcGFyYW0ge01hcFByb2plY3Rpb259IFtwcm9qZWN0aW9uPUdlb2dyYXBoaWNQcm9qZWN0aW9uXSBUaGUgcHJvamVjdGlvbiB1c2VkIHRvIHByb2plY3QgdGhlIHJlY3RhbmdsZSBpbnRvIDJELgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbWluaW11bUhlaWdodD0wLjBdIFRoZSBtaW5pbXVtIGhlaWdodCBvdmVyIHRoZSByZWN0YW5nbGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhpbXVtSGVpZ2h0PTAuMF0gVGhlIG1heGltdW0gaGVpZ2h0IG92ZXIgdGhlIHJlY3RhbmdsZS4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUmVjdGFuZ2xlV2l0aEhlaWdodHMyRChyZWN0YW5nbGUsIHByb2plY3Rpb24sIG1pbmltdW1IZWlnaHQsIG1heGltdW1IZWlnaHQsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gMDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGRlZmF1bHRQcm9qZWN0aW9uLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgICAgcHJvamVjdGlvbiA9IHByb2plY3Rpb24gPz8gZGVmYXVsdFByb2plY3Rpb247CiAgICAgICAgICBSZWN0YW5nbGVfZGVmYXVsdC5zb3V0aHdlc3QocmVjdGFuZ2xlLCBmcm9tUmVjdGFuZ2xlMkRTb3V0aHdlc3QpOwogICAgICAgICAgZnJvbVJlY3RhbmdsZTJEU291dGh3ZXN0LmhlaWdodCA9IG1pbmltdW1IZWlnaHQ7CiAgICAgICAgICBSZWN0YW5nbGVfZGVmYXVsdC5ub3J0aGVhc3QocmVjdGFuZ2xlLCBmcm9tUmVjdGFuZ2xlMkROb3J0aGVhc3QpOwogICAgICAgICAgZnJvbVJlY3RhbmdsZTJETm9ydGhlYXN0LmhlaWdodCA9IG1heGltdW1IZWlnaHQ7CiAgICAgICAgICBjb25zdCBsb3dlckxlZnQgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgICAgICAgIGZyb21SZWN0YW5nbGUyRFNvdXRod2VzdCwKICAgICAgICAgICAgZnJvbVJlY3RhbmdsZTJETG93ZXJMZWZ0CiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgdXBwZXJSaWdodCA9IHByb2plY3Rpb24ucHJvamVjdCgKICAgICAgICAgICAgZnJvbVJlY3RhbmdsZTJETm9ydGhlYXN0LAogICAgICAgICAgICBmcm9tUmVjdGFuZ2xlMkRVcHBlclJpZ2h0CiAgICAgICAgICApOwogICAgICAgICAgY29uc3Qgd2lkdGggPSB1cHBlclJpZ2h0LnggLSBsb3dlckxlZnQueDsKICAgICAgICAgIGNvbnN0IGhlaWdodCA9IHVwcGVyUmlnaHQueSAtIGxvd2VyTGVmdC55OwogICAgICAgICAgY29uc3QgZWxldmF0aW9uID0gdXBwZXJSaWdodC56IC0gbG93ZXJMZWZ0Lno7CiAgICAgICAgICByZXN1bHQucmFkaXVzID0gTWF0aC5zcXJ0KHdpZHRoICogd2lkdGggKyBoZWlnaHQgKiBoZWlnaHQgKyBlbGV2YXRpb24gKiBlbGV2YXRpb24pICogMC41OwogICAgICAgICAgY29uc3QgY2VudGVyID0gcmVzdWx0LmNlbnRlcjsKICAgICAgICAgIGNlbnRlci54ID0gbG93ZXJMZWZ0LnggKyB3aWR0aCAqIDAuNTsKICAgICAgICAgIGNlbnRlci55ID0gbG93ZXJMZWZ0LnkgKyBoZWlnaHQgKiAwLjU7CiAgICAgICAgICBjZW50ZXIueiA9IGxvd2VyTGVmdC56ICsgZWxldmF0aW9uICogMC41OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBib3VuZGluZyBzcGhlcmUgZnJvbSBhIHJlY3RhbmdsZSBpbiAzRC4gVGhlIGJvdW5kaW5nIHNwaGVyZSBpcyBjcmVhdGVkIHVzaW5nIGEgc3Vic2FtcGxlIG9mIHBvaW50cwogICAgICAgICAqIG9uIHRoZSBlbGxpcHNvaWQgYW5kIGNvbnRhaW5lZCBpbiB0aGUgcmVjdGFuZ2xlLiBJdCBtYXkgbm90IGJlIGFjY3VyYXRlIGZvciBhbGwgcmVjdGFuZ2xlcyBvbiBhbGwgdHlwZXMgb2YgZWxsaXBzb2lkcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVjdGFuZ2xlXSBUaGUgdmFsaWQgcmVjdGFuZ2xlIHVzZWQgdG8gY3JlYXRlIGEgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqIEBwYXJhbSB7RWxsaXBzb2lkfSBbZWxsaXBzb2lkPUVsbGlwc29pZC5kZWZhdWx0XSBUaGUgZWxsaXBzb2lkIHVzZWQgdG8gZGV0ZXJtaW5lIHBvc2l0aW9ucyBvZiB0aGUgcmVjdGFuZ2xlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3VyZmFjZUhlaWdodD0wLjBdIFRoZSBoZWlnaHQgYWJvdmUgdGhlIHN1cmZhY2Ugb2YgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUmVjdGFuZ2xlM0QocmVjdGFuZ2xlLCBlbGxpcHNvaWQsIHN1cmZhY2VIZWlnaHQsIHJlc3VsdCkgewogICAgICAgICAgZWxsaXBzb2lkID0gZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICAgICAgICBzdXJmYWNlSGVpZ2h0ID0gc3VyZmFjZUhlaWdodCA/PyAwOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gMDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IFJlY3RhbmdsZV9kZWZhdWx0LnN1YnNhbXBsZSgKICAgICAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHN1cmZhY2VIZWlnaHQsCiAgICAgICAgICAgIGZyb21SZWN0YW5nbGUzRFNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICByZXR1cm4gX0JvdW5kaW5nU3BoZXJlLmZyb21Qb2ludHMocG9zaXRpb25zLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIHRpZ2h0LWZpdHRpbmcgYm91bmRpbmcgc3BoZXJlIGVuY2xvc2luZyBhIGxpc3Qgb2YgM0QgcG9pbnRzLCB3aGVyZSB0aGUgcG9pbnRzIGFyZQogICAgICAgICAqIHN0b3JlZCBpbiBhIGZsYXQgYXJyYXkgaW4gWCwgWSwgWiwgb3JkZXIuICBUaGUgYm91bmRpbmcgc3BoZXJlIGlzIGNvbXB1dGVkIGJ5IHJ1bm5pbmcgdHdvCiAgICAgICAgICogYWxnb3JpdGhtcywgYSBuYWl2ZSBhbGdvcml0aG0gYW5kIFJpdHRlcidzIGFsZ29yaXRobS4gVGhlIHNtYWxsZXIgb2YgdGhlIHR3byBzcGhlcmVzIGlzIHVzZWQgdG8KICAgICAgICAgKiBlbnN1cmUgYSB0aWdodCBmaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfFR5cGVkQXJyYXl9IFtwb3NpdGlvbnNdIEFuIGFycmF5IG9mIHBvaW50cyB0aGF0IHRoZSBib3VuZGluZyBzcGhlcmUgd2lsbCBlbmNsb3NlLiAgRWFjaCBwb2ludAogICAgICAgICAqICAgICAgICBpcyBmb3JtZWQgZnJvbSB0aHJlZSBlbGVtZW50cyBpbiB0aGUgYXJyYXkgaW4gdGhlIG9yZGVyIFgsIFksIFouCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbY2VudGVyPUNhcnRlc2lhbjMuWkVST10gVGhlIHBvc2l0aW9uIHRvIHdoaWNoIHRoZSBwb3NpdGlvbnMgYXJlIHJlbGF0aXZlLCB3aGljaCBuZWVkIG5vdCBiZSB0aGUKICAgICAgICAgKiAgICAgICAgb3JpZ2luIG9mIHRoZSBjb29yZGluYXRlIHN5c3RlbS4gIFRoaXMgaXMgdXNlZnVsIHdoZW4gdGhlIHBvc2l0aW9ucyBhcmUgdG8gYmUgdXNlZCBmb3IKICAgICAgICAgKiAgICAgICAgcmVsYXRpdmUtdG8tY2VudGVyIChSVEMpIHJlbmRlcmluZy4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0cmlkZT0zXSBUaGUgbnVtYmVyIG9mIGFycmF5IGVsZW1lbnRzIHBlciB2ZXJ0ZXguICBJdCBtdXN0IGJlIGF0IGxlYXN0IDMsIGJ1dCBpdCBtYXkKICAgICAgICAgKiAgICAgICAgYmUgaGlnaGVyLiAgUmVnYXJkbGVzcyBvZiB0aGUgdmFsdWUgb2YgdGhpcyBwYXJhbWV0ZXIsIHRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIGZpcnN0IHBvc2l0aW9uCiAgICAgICAgICogICAgICAgIGlzIGF0IGFycmF5IGluZGV4IDAsIHRoZSBZIGNvb3JkaW5hdGUgaXMgYXQgYXJyYXkgaW5kZXggMSwgYW5kIHRoZSBaIGNvb3JkaW5hdGUgaXMgYXQgYXJyYXkgaW5kZXgKICAgICAgICAgKiAgICAgICAgMi4gIFdoZW4gc3RyaWRlIGlzIDMsIHRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIG5leHQgcG9zaXRpb24gdGhlbiBiZWdpbnMgYXQgYXJyYXkgaW5kZXggMy4gIElmCiAgICAgICAgICogICAgICAgIHRoZSBzdHJpZGUgaXMgNSwgaG93ZXZlciwgdHdvIGFycmF5IGVsZW1lbnRzIGFyZSBza2lwcGVkIGFuZCB0aGUgbmV4dCBwb3NpdGlvbiBiZWdpbnMgYXQgYXJyYXkKICAgICAgICAgKiAgICAgICAgaW5kZXggNS4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBDb21wdXRlIHRoZSBib3VuZGluZyBzcGhlcmUgZnJvbSAzIHBvc2l0aW9ucywgZWFjaCBzcGVjaWZpZWQgcmVsYXRpdmUgdG8gYSBjZW50ZXIuCiAgICAgICAgICogLy8gSW4gYWRkaXRpb24gdG8gdGhlIFgsIFksIGFuZCBaIGNvb3JkaW5hdGVzLCB0aGUgcG9pbnRzIGFycmF5IGNvbnRhaW5zIHR3byBhZGRpdGlvbmFsCiAgICAgICAgICogLy8gZWxlbWVudHMgcGVyIHBvaW50IHdoaWNoIGFyZSBpZ25vcmVkIGZvciB0aGUgcHVycG9zZSBvZiBjb21wdXRpbmcgdGhlIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKiBjb25zdCBjZW50ZXIgPSBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMS4wLCAyLjAsIDMuMCk7CiAgICAgICAgICogY29uc3QgcG9pbnRzID0gWzEuMCwgMi4wLCAzLjAsIDAuMSwgMC4yLAogICAgICAgICAqICAgICAgICAgICAgICAgNC4wLCA1LjAsIDYuMCwgMC4xLCAwLjIsCiAgICAgICAgICogICAgICAgICAgICAgICA3LjAsIDguMCwgOS4wLCAwLjEsIDAuMl07CiAgICAgICAgICogY29uc3Qgc3BoZXJlID0gQ2VzaXVtLkJvdW5kaW5nU3BoZXJlLmZyb21WZXJ0aWNlcyhwb2ludHMsIGNlbnRlciwgNSk7CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwOi8vYmxvZ3MuYWdpLmNvbS9pbnNpZ2h0M2QvaW5kZXgucGhwLzIwMDgvMDIvMDQvYS1ib3VuZGluZy98Qm91bmRpbmcgU3BoZXJlIGNvbXB1dGF0aW9uIGFydGljbGV9CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21WZXJ0aWNlcyhwb3NpdGlvbnMsIGNlbnRlciwgc3RyaWRlLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSB8fCBwb3NpdGlvbnMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gMDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGNlbnRlciA9IGNlbnRlciA/PyBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTzsKICAgICAgICAgIHN0cmlkZSA9IHN0cmlkZSA/PyAzOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoInN0cmlkZSIsIHN0cmlkZSwgMyk7CiAgICAgICAgICBjb25zdCBjdXJyZW50UG9zID0gZnJvbVBvaW50c0N1cnJlbnRQb3M7CiAgICAgICAgICBjdXJyZW50UG9zLnggPSBwb3NpdGlvbnNbMF0gKyBjZW50ZXIueDsKICAgICAgICAgIGN1cnJlbnRQb3MueSA9IHBvc2l0aW9uc1sxXSArIGNlbnRlci55OwogICAgICAgICAgY3VycmVudFBvcy56ID0gcG9zaXRpb25zWzJdICsgY2VudGVyLno7CiAgICAgICAgICBjb25zdCB4TWluID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNYTWluKTsKICAgICAgICAgIGNvbnN0IHlNaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1lNaW4pOwogICAgICAgICAgY29uc3Qgek1pbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWk1pbik7CiAgICAgICAgICBjb25zdCB4TWF4ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNYTWF4KTsKICAgICAgICAgIGNvbnN0IHlNYXggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1lNYXgpOwogICAgICAgICAgY29uc3Qgek1heCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWk1heCk7CiAgICAgICAgICBjb25zdCBudW1FbGVtZW50cyA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICBsZXQgaTI7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1FbGVtZW50czsgaTIgKz0gc3RyaWRlKSB7CiAgICAgICAgICAgIGNvbnN0IHgyID0gcG9zaXRpb25zW2kyXSArIGNlbnRlci54OwogICAgICAgICAgICBjb25zdCB5MiA9IHBvc2l0aW9uc1tpMiArIDFdICsgY2VudGVyLnk7CiAgICAgICAgICAgIGNvbnN0IHoyID0gcG9zaXRpb25zW2kyICsgMl0gKyBjZW50ZXIuejsKICAgICAgICAgICAgY3VycmVudFBvcy54ID0geDI7CiAgICAgICAgICAgIGN1cnJlbnRQb3MueSA9IHkyOwogICAgICAgICAgICBjdXJyZW50UG9zLnogPSB6MjsKICAgICAgICAgICAgaWYgKHgyIDwgeE1pbi54KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHhNaW4pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh4MiA+IHhNYXgueCkgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB4TWF4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoeTIgPCB5TWluLnkpIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgeU1pbik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHkyID4geU1heC55KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHlNYXgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh6MiA8IHpNaW4ueikgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB6TWluKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoejIgPiB6TWF4LnopIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgek1heCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHhTcGFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh4TWF4LCB4TWluLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCB5U3BhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGVTcXVhcmVkKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoeU1heCwgeU1pbiwgZnJvbVBvaW50c1NjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgelNwYW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHpNYXgsIHpNaW4sIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgKTsKICAgICAgICAgIGxldCBkaWFtZXRlcjEgPSB4TWluOwogICAgICAgICAgbGV0IGRpYW1ldGVyMiA9IHhNYXg7CiAgICAgICAgICBsZXQgbWF4U3BhbiA9IHhTcGFuOwogICAgICAgICAgaWYgKHlTcGFuID4gbWF4U3BhbikgewogICAgICAgICAgICBtYXhTcGFuID0geVNwYW47CiAgICAgICAgICAgIGRpYW1ldGVyMSA9IHlNaW47CiAgICAgICAgICAgIGRpYW1ldGVyMiA9IHlNYXg7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoelNwYW4gPiBtYXhTcGFuKSB7CiAgICAgICAgICAgIGRpYW1ldGVyMSA9IHpNaW47CiAgICAgICAgICAgIGRpYW1ldGVyMiA9IHpNYXg7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByaXR0ZXJDZW50ZXIgPSBmcm9tUG9pbnRzUml0dGVyQ2VudGVyOwogICAgICAgICAgcml0dGVyQ2VudGVyLnggPSAoZGlhbWV0ZXIxLnggKyBkaWFtZXRlcjIueCkgKiAwLjU7CiAgICAgICAgICByaXR0ZXJDZW50ZXIueSA9IChkaWFtZXRlcjEueSArIGRpYW1ldGVyMi55KSAqIDAuNTsKICAgICAgICAgIHJpdHRlckNlbnRlci56ID0gKGRpYW1ldGVyMS56ICsgZGlhbWV0ZXIyLnopICogMC41OwogICAgICAgICAgbGV0IHJhZGl1c1NxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGRpYW1ldGVyMiwgcml0dGVyQ2VudGVyLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgcml0dGVyUmFkaXVzID0gTWF0aC5zcXJ0KHJhZGl1c1NxdWFyZWQpOwogICAgICAgICAgY29uc3QgbWluQm94UHQgPSBmcm9tUG9pbnRzTWluQm94UHQ7CiAgICAgICAgICBtaW5Cb3hQdC54ID0geE1pbi54OwogICAgICAgICAgbWluQm94UHQueSA9IHlNaW4ueTsKICAgICAgICAgIG1pbkJveFB0LnogPSB6TWluLno7CiAgICAgICAgICBjb25zdCBtYXhCb3hQdCA9IGZyb21Qb2ludHNNYXhCb3hQdDsKICAgICAgICAgIG1heEJveFB0LnggPSB4TWF4Lng7CiAgICAgICAgICBtYXhCb3hQdC55ID0geU1heC55OwogICAgICAgICAgbWF4Qm94UHQueiA9IHpNYXguejsKICAgICAgICAgIGNvbnN0IG5haXZlQ2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1pZHBvaW50KAogICAgICAgICAgICBtaW5Cb3hQdCwKICAgICAgICAgICAgbWF4Qm94UHQsCiAgICAgICAgICAgIGZyb21Qb2ludHNOYWl2ZUNlbnRlclNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgbmFpdmVSYWRpdXMgPSAwOwogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtRWxlbWVudHM7IGkyICs9IHN0cmlkZSkgewogICAgICAgICAgICBjdXJyZW50UG9zLnggPSBwb3NpdGlvbnNbaTJdICsgY2VudGVyLng7CiAgICAgICAgICAgIGN1cnJlbnRQb3MueSA9IHBvc2l0aW9uc1tpMiArIDFdICsgY2VudGVyLnk7CiAgICAgICAgICAgIGN1cnJlbnRQb3MueiA9IHBvc2l0aW9uc1tpMiArIDJdICsgY2VudGVyLno7CiAgICAgICAgICAgIGNvbnN0IHIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgbmFpdmVDZW50ZXIsIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAocjIgPiBuYWl2ZVJhZGl1cykgewogICAgICAgICAgICAgIG5haXZlUmFkaXVzID0gcjI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgb2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgcml0dGVyQ2VudGVyLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICAgKTsKICAgICAgICAgICAgaWYgKG9sZENlbnRlclRvUG9pbnRTcXVhcmVkID4gcmFkaXVzU3F1YXJlZCkgewogICAgICAgICAgICAgIGNvbnN0IG9sZENlbnRlclRvUG9pbnQgPSBNYXRoLnNxcnQob2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQpOwogICAgICAgICAgICAgIHJpdHRlclJhZGl1cyA9IChyaXR0ZXJSYWRpdXMgKyBvbGRDZW50ZXJUb1BvaW50KSAqIDAuNTsKICAgICAgICAgICAgICByYWRpdXNTcXVhcmVkID0gcml0dGVyUmFkaXVzICogcml0dGVyUmFkaXVzOwogICAgICAgICAgICAgIGNvbnN0IG9sZFRvTmV3ID0gb2xkQ2VudGVyVG9Qb2ludCAtIHJpdHRlclJhZGl1czsKICAgICAgICAgICAgICByaXR0ZXJDZW50ZXIueCA9IChyaXR0ZXJSYWRpdXMgKiByaXR0ZXJDZW50ZXIueCArIG9sZFRvTmV3ICogY3VycmVudFBvcy54KSAvIG9sZENlbnRlclRvUG9pbnQ7CiAgICAgICAgICAgICAgcml0dGVyQ2VudGVyLnkgPSAocml0dGVyUmFkaXVzICogcml0dGVyQ2VudGVyLnkgKyBvbGRUb05ldyAqIGN1cnJlbnRQb3MueSkgLyBvbGRDZW50ZXJUb1BvaW50OwogICAgICAgICAgICAgIHJpdHRlckNlbnRlci56ID0gKHJpdHRlclJhZGl1cyAqIHJpdHRlckNlbnRlci56ICsgb2xkVG9OZXcgKiBjdXJyZW50UG9zLnopIC8gb2xkQ2VudGVyVG9Qb2ludDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHJpdHRlclJhZGl1cyA8IG5haXZlUmFkaXVzKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyaXR0ZXJDZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gcml0dGVyUmFkaXVzOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG5haXZlQ2VudGVyLCByZXN1bHQuY2VudGVyKTsKICAgICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IG5haXZlUmFkaXVzOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSB0aWdodC1maXR0aW5nIGJvdW5kaW5nIHNwaGVyZSBlbmNsb3NpbmcgYSBsaXN0IG9mIEVuY29kZWRDYXJ0ZXNpYW4zcywgd2hlcmUgdGhlIHBvaW50cyBhcmUKICAgICAgICAgKiBzdG9yZWQgaW4gcGFyYWxsZWwgZmxhdCBhcnJheXMgaW4gWCwgWSwgWiwgb3JkZXIuICBUaGUgYm91bmRpbmcgc3BoZXJlIGlzIGNvbXB1dGVkIGJ5IHJ1bm5pbmcgdHdvCiAgICAgICAgICogYWxnb3JpdGhtcywgYSBuYWl2ZSBhbGdvcml0aG0gYW5kIFJpdHRlcidzIGFsZ29yaXRobS4gVGhlIHNtYWxsZXIgb2YgdGhlIHR3byBzcGhlcmVzIGlzIHVzZWQgdG8KICAgICAgICAgKiBlbnN1cmUgYSB0aWdodCBmaXQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBbcG9zaXRpb25zSGlnaF0gQW4gYXJyYXkgb2YgaGlnaCBiaXRzIG9mIHRoZSBlbmNvZGVkIGNhcnRlc2lhbnMgdGhhdCB0aGUgYm91bmRpbmcgc3BoZXJlIHdpbGwgZW5jbG9zZS4gIEVhY2ggcG9pbnQKICAgICAgICAgKiAgICAgICAgaXMgZm9ybWVkIGZyb20gdGhyZWUgZWxlbWVudHMgaW4gdGhlIGFycmF5IGluIHRoZSBvcmRlciBYLCBZLCBaLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtwb3NpdGlvbnNMb3ddIEFuIGFycmF5IG9mIGxvdyBiaXRzIG9mIHRoZSBlbmNvZGVkIGNhcnRlc2lhbnMgdGhhdCB0aGUgYm91bmRpbmcgc3BoZXJlIHdpbGwgZW5jbG9zZS4gIEVhY2ggcG9pbnQKICAgICAgICAgKiAgICAgICAgaXMgZm9ybWVkIGZyb20gdGhyZWUgZWxlbWVudHMgaW4gdGhlIGFycmF5IGluIHRoZSBvcmRlciBYLCBZLCBaLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwOi8vYmxvZ3MuYWdpLmNvbS9pbnNpZ2h0M2QvaW5kZXgucGhwLzIwMDgvMDIvMDQvYS1ib3VuZGluZy98Qm91bmRpbmcgU3BoZXJlIGNvbXB1dGF0aW9uIGFydGljbGV9CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21FbmNvZGVkQ2FydGVzaWFuVmVydGljZXMocG9zaXRpb25zSGlnaCwgcG9zaXRpb25zTG93LCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zSGlnaCkgfHwgIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnNMb3cpIHx8IHBvc2l0aW9uc0hpZ2gubGVuZ3RoICE9PSBwb3NpdGlvbnNMb3cubGVuZ3RoIHx8IHBvc2l0aW9uc0hpZ2gubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gMDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGN1cnJlbnRQb3MgPSBmcm9tUG9pbnRzQ3VycmVudFBvczsKICAgICAgICAgIGN1cnJlbnRQb3MueCA9IHBvc2l0aW9uc0hpZ2hbMF0gKyBwb3NpdGlvbnNMb3dbMF07CiAgICAgICAgICBjdXJyZW50UG9zLnkgPSBwb3NpdGlvbnNIaWdoWzFdICsgcG9zaXRpb25zTG93WzFdOwogICAgICAgICAgY3VycmVudFBvcy56ID0gcG9zaXRpb25zSGlnaFsyXSArIHBvc2l0aW9uc0xvd1syXTsKICAgICAgICAgIGNvbnN0IHhNaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1hNaW4pOwogICAgICAgICAgY29uc3QgeU1pbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWU1pbik7CiAgICAgICAgICBjb25zdCB6TWluID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNaTWluKTsKICAgICAgICAgIGNvbnN0IHhNYXggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgZnJvbVBvaW50c1hNYXgpOwogICAgICAgICAgY29uc3QgeU1heCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCBmcm9tUG9pbnRzWU1heCk7CiAgICAgICAgICBjb25zdCB6TWF4ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIGZyb21Qb2ludHNaTWF4KTsKICAgICAgICAgIGNvbnN0IG51bUVsZW1lbnRzID0gcG9zaXRpb25zSGlnaC5sZW5ndGg7CiAgICAgICAgICBsZXQgaTI7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1FbGVtZW50czsgaTIgKz0gMykgewogICAgICAgICAgICBjb25zdCB4MiA9IHBvc2l0aW9uc0hpZ2hbaTJdICsgcG9zaXRpb25zTG93W2kyXTsKICAgICAgICAgICAgY29uc3QgeTIgPSBwb3NpdGlvbnNIaWdoW2kyICsgMV0gKyBwb3NpdGlvbnNMb3dbaTIgKyAxXTsKICAgICAgICAgICAgY29uc3QgejIgPSBwb3NpdGlvbnNIaWdoW2kyICsgMl0gKyBwb3NpdGlvbnNMb3dbaTIgKyAyXTsKICAgICAgICAgICAgY3VycmVudFBvcy54ID0geDI7CiAgICAgICAgICAgIGN1cnJlbnRQb3MueSA9IHkyOwogICAgICAgICAgICBjdXJyZW50UG9zLnogPSB6MjsKICAgICAgICAgICAgaWYgKHgyIDwgeE1pbi54KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHhNaW4pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh4MiA+IHhNYXgueCkgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB4TWF4KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoeTIgPCB5TWluLnkpIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgeU1pbik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHkyID4geU1heC55KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJlbnRQb3MsIHlNYXgpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh6MiA8IHpNaW4ueikgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjdXJyZW50UG9zLCB6TWluKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoejIgPiB6TWF4LnopIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY3VycmVudFBvcywgek1heCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHhTcGFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh4TWF4LCB4TWluLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCB5U3BhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGVTcXVhcmVkKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoeU1heCwgeU1pbiwgZnJvbVBvaW50c1NjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgelNwYW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHpNYXgsIHpNaW4sIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgKTsKICAgICAgICAgIGxldCBkaWFtZXRlcjEgPSB4TWluOwogICAgICAgICAgbGV0IGRpYW1ldGVyMiA9IHhNYXg7CiAgICAgICAgICBsZXQgbWF4U3BhbiA9IHhTcGFuOwogICAgICAgICAgaWYgKHlTcGFuID4gbWF4U3BhbikgewogICAgICAgICAgICBtYXhTcGFuID0geVNwYW47CiAgICAgICAgICAgIGRpYW1ldGVyMSA9IHlNaW47CiAgICAgICAgICAgIGRpYW1ldGVyMiA9IHlNYXg7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoelNwYW4gPiBtYXhTcGFuKSB7CiAgICAgICAgICAgIGRpYW1ldGVyMSA9IHpNaW47CiAgICAgICAgICAgIGRpYW1ldGVyMiA9IHpNYXg7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByaXR0ZXJDZW50ZXIgPSBmcm9tUG9pbnRzUml0dGVyQ2VudGVyOwogICAgICAgICAgcml0dGVyQ2VudGVyLnggPSAoZGlhbWV0ZXIxLnggKyBkaWFtZXRlcjIueCkgKiAwLjU7CiAgICAgICAgICByaXR0ZXJDZW50ZXIueSA9IChkaWFtZXRlcjEueSArIGRpYW1ldGVyMi55KSAqIDAuNTsKICAgICAgICAgIHJpdHRlckNlbnRlci56ID0gKGRpYW1ldGVyMS56ICsgZGlhbWV0ZXIyLnopICogMC41OwogICAgICAgICAgbGV0IHJhZGl1c1NxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGRpYW1ldGVyMiwgcml0dGVyQ2VudGVyLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgcml0dGVyUmFkaXVzID0gTWF0aC5zcXJ0KHJhZGl1c1NxdWFyZWQpOwogICAgICAgICAgY29uc3QgbWluQm94UHQgPSBmcm9tUG9pbnRzTWluQm94UHQ7CiAgICAgICAgICBtaW5Cb3hQdC54ID0geE1pbi54OwogICAgICAgICAgbWluQm94UHQueSA9IHlNaW4ueTsKICAgICAgICAgIG1pbkJveFB0LnogPSB6TWluLno7CiAgICAgICAgICBjb25zdCBtYXhCb3hQdCA9IGZyb21Qb2ludHNNYXhCb3hQdDsKICAgICAgICAgIG1heEJveFB0LnggPSB4TWF4Lng7CiAgICAgICAgICBtYXhCb3hQdC55ID0geU1heC55OwogICAgICAgICAgbWF4Qm94UHQueiA9IHpNYXguejsKICAgICAgICAgIGNvbnN0IG5haXZlQ2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1pZHBvaW50KAogICAgICAgICAgICBtaW5Cb3hQdCwKICAgICAgICAgICAgbWF4Qm94UHQsCiAgICAgICAgICAgIGZyb21Qb2ludHNOYWl2ZUNlbnRlclNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgbmFpdmVSYWRpdXMgPSAwOwogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtRWxlbWVudHM7IGkyICs9IDMpIHsKICAgICAgICAgICAgY3VycmVudFBvcy54ID0gcG9zaXRpb25zSGlnaFtpMl0gKyBwb3NpdGlvbnNMb3dbaTJdOwogICAgICAgICAgICBjdXJyZW50UG9zLnkgPSBwb3NpdGlvbnNIaWdoW2kyICsgMV0gKyBwb3NpdGlvbnNMb3dbaTIgKyAxXTsKICAgICAgICAgICAgY3VycmVudFBvcy56ID0gcG9zaXRpb25zSGlnaFtpMiArIDJdICsgcG9zaXRpb25zTG93W2kyICsgMl07CiAgICAgICAgICAgIGNvbnN0IHIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgbmFpdmVDZW50ZXIsIGZyb21Qb2ludHNTY3JhdGNoKQogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAocjIgPiBuYWl2ZVJhZGl1cykgewogICAgICAgICAgICAgIG5haXZlUmFkaXVzID0gcjI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3Qgb2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY3VycmVudFBvcywgcml0dGVyQ2VudGVyLCBmcm9tUG9pbnRzU2NyYXRjaCkKICAgICAgICAgICAgKTsKICAgICAgICAgICAgaWYgKG9sZENlbnRlclRvUG9pbnRTcXVhcmVkID4gcmFkaXVzU3F1YXJlZCkgewogICAgICAgICAgICAgIGNvbnN0IG9sZENlbnRlclRvUG9pbnQgPSBNYXRoLnNxcnQob2xkQ2VudGVyVG9Qb2ludFNxdWFyZWQpOwogICAgICAgICAgICAgIHJpdHRlclJhZGl1cyA9IChyaXR0ZXJSYWRpdXMgKyBvbGRDZW50ZXJUb1BvaW50KSAqIDAuNTsKICAgICAgICAgICAgICByYWRpdXNTcXVhcmVkID0gcml0dGVyUmFkaXVzICogcml0dGVyUmFkaXVzOwogICAgICAgICAgICAgIGNvbnN0IG9sZFRvTmV3ID0gb2xkQ2VudGVyVG9Qb2ludCAtIHJpdHRlclJhZGl1czsKICAgICAgICAgICAgICByaXR0ZXJDZW50ZXIueCA9IChyaXR0ZXJSYWRpdXMgKiByaXR0ZXJDZW50ZXIueCArIG9sZFRvTmV3ICogY3VycmVudFBvcy54KSAvIG9sZENlbnRlclRvUG9pbnQ7CiAgICAgICAgICAgICAgcml0dGVyQ2VudGVyLnkgPSAocml0dGVyUmFkaXVzICogcml0dGVyQ2VudGVyLnkgKyBvbGRUb05ldyAqIGN1cnJlbnRQb3MueSkgLyBvbGRDZW50ZXJUb1BvaW50OwogICAgICAgICAgICAgIHJpdHRlckNlbnRlci56ID0gKHJpdHRlclJhZGl1cyAqIHJpdHRlckNlbnRlci56ICsgb2xkVG9OZXcgKiBjdXJyZW50UG9zLnopIC8gb2xkQ2VudGVyVG9Qb2ludDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHJpdHRlclJhZGl1cyA8IG5haXZlUmFkaXVzKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyaXR0ZXJDZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gcml0dGVyUmFkaXVzOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG5haXZlQ2VudGVyLCByZXN1bHQuY2VudGVyKTsKICAgICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IG5haXZlUmFkaXVzOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBib3VuZGluZyBzcGhlcmUgZnJvbSB0aGUgY29ybmVyIHBvaW50cyBvZiBhbiBheGlzLWFsaWduZWQgYm91bmRpbmcgYm94LiAgVGhlIHNwaGVyZQogICAgICAgICAqIHRpZ2h0bHkgYW5kIGZ1bGx5IGVuY29tcGFzc2VzIHRoZSBib3guCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtjb3JuZXJdIFRoZSBtaW5pbXVtIGhlaWdodCBvdmVyIHRoZSByZWN0YW5nbGUuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbb3Bwb3NpdGVDb3JuZXJdIFRoZSBtYXhpbXVtIGhlaWdodCBvdmVyIHRoZSByZWN0YW5nbGUuCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gQ3JlYXRlIGEgYm91bmRpbmcgc3BoZXJlIGFyb3VuZCB0aGUgdW5pdCBjdWJlCiAgICAgICAgICogY29uc3Qgc3BoZXJlID0gQ2VzaXVtLkJvdW5kaW5nU3BoZXJlLmZyb21Db3JuZXJQb2ludHMobmV3IENlc2l1bS5DYXJ0ZXNpYW4zKC0wLjUsIC0wLjUsIC0wLjUpLCBuZXcgQ2VzaXVtLkNhcnRlc2lhbjMoMC41LCAwLjUsIDAuNSkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tQ29ybmVyUG9pbnRzKGNvcm5lciwgb3Bwb3NpdGVDb3JuZXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjb3JuZXIiLCBjb3JuZXIpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHBvc2l0ZUNvcm5lciIsIG9wcG9zaXRlQ29ybmVyKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1pZHBvaW50KGNvcm5lciwgb3Bwb3NpdGVDb3JuZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IENhcnRlc2lhbjNfZGVmYXVsdC5kaXN0YW5jZShjZW50ZXIsIG9wcG9zaXRlQ29ybmVyKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBib3VuZGluZyBzcGhlcmUgZW5jb21wYXNzaW5nIGFuIGVsbGlwc29pZC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7RWxsaXBzb2lkfSBlbGxpcHNvaWQgVGhlIGVsbGlwc29pZCBhcm91bmQgd2hpY2ggdG8gY3JlYXRlIGEgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IGJvdW5kaW5nU3BoZXJlID0gQ2VzaXVtLkJvdW5kaW5nU3BoZXJlLmZyb21FbGxpcHNvaWQoZWxsaXBzb2lkKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUVsbGlwc29pZChlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJlbGxpcHNvaWQiLCBlbGxpcHNvaWQpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSB0aWdodC1maXR0aW5nIGJvdW5kaW5nIHNwaGVyZSBlbmNsb3NpbmcgdGhlIHByb3ZpZGVkIGFycmF5IG9mIGJvdW5kaW5nIHNwaGVyZXMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlW119IFtib3VuZGluZ1NwaGVyZXNdIFRoZSBhcnJheSBvZiBib3VuZGluZyBzcGhlcmVzLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Cb3VuZGluZ1NwaGVyZXMoYm91bmRpbmdTcGhlcmVzLCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm91bmRpbmdTcGhlcmVzKSB8fCBib3VuZGluZ1NwaGVyZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgICByZXN1bHQucmFkaXVzID0gMDsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGJvdW5kaW5nU3BoZXJlcy5sZW5ndGg7CiAgICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7CiAgICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuY2xvbmUoYm91bmRpbmdTcGhlcmVzWzBdLCByZXN1bHQpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGxlbmd0aCA9PT0gMikgewogICAgICAgICAgICByZXR1cm4gX0JvdW5kaW5nU3BoZXJlLnVuaW9uKAogICAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlc1swXSwKICAgICAgICAgICAgICBib3VuZGluZ1NwaGVyZXNbMV0sCiAgICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBbXTsKICAgICAgICAgIGxldCBpMjsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICBwb3NpdGlvbnMucHVzaChib3VuZGluZ1NwaGVyZXNbaTJdLmNlbnRlcik7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQgPSBfQm91bmRpbmdTcGhlcmUuZnJvbVBvaW50cyhwb3NpdGlvbnMsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBjZW50ZXIgPSByZXN1bHQuY2VudGVyOwogICAgICAgICAgbGV0IHJhZGl1cyA9IHJlc3VsdC5yYWRpdXM7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgY29uc3QgdG1wMiA9IGJvdW5kaW5nU3BoZXJlc1tpMl07CiAgICAgICAgICAgIHJhZGl1cyA9IE1hdGgubWF4KAogICAgICAgICAgICAgIHJhZGl1cywKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZGlzdGFuY2UoY2VudGVyLCB0bXAyLmNlbnRlcikgKyB0bXAyLnJhZGl1cwogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IHJhZGl1czsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgdGlnaHQtZml0dGluZyBib3VuZGluZyBzcGhlcmUgZW5jbG9zaW5nIHRoZSBwcm92aWRlZCBvcmllbnRlZCBib3VuZGluZyBib3guCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge09yaWVudGVkQm91bmRpbmdCb3h9IG9yaWVudGVkQm91bmRpbmdCb3ggVGhlIG9yaWVudGVkIGJvdW5kaW5nIGJveC4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tT3JpZW50ZWRCb3VuZGluZ0JveChvcmllbnRlZEJvdW5kaW5nQm94LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgib3JpZW50ZWRCb3VuZGluZ0JveCIsIG9yaWVudGVkQm91bmRpbmdCb3gpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBoYWxmQXhlcyA9IG9yaWVudGVkQm91bmRpbmdCb3guaGFsZkF4ZXM7CiAgICAgICAgICBjb25zdCB1NCA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDAsIGZyb21PcmllbnRlZEJvdW5kaW5nQm94U2NyYXRjaFUpOwogICAgICAgICAgY29uc3QgdjQgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKGhhbGZBeGVzLCAxLCBmcm9tT3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2hWKTsKICAgICAgICAgIGNvbnN0IHcyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihoYWxmQXhlcywgMiwgZnJvbU9yaWVudGVkQm91bmRpbmdCb3hTY3JhdGNoVyk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHU0LCB2NCwgdTQpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZCh1NCwgdzIsIHU0KTsKICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUob3JpZW50ZWRCb3VuZGluZ0JveC5jZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUodTQpOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSB0aWdodC1maXR0aW5nIGJvdW5kaW5nIHNwaGVyZSBlbmNsb3NpbmcgdGhlIHByb3ZpZGVkIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4NH0gdHJhbnNmb3JtYXRpb24gVGhlIGFmZmluZSB0cmFuc2Zvcm1hdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tVHJhbnNmb3JtYXRpb24odHJhbnNmb3JtYXRpb24sIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ0cmFuc2Zvcm1hdGlvbiIsIHRyYW5zZm9ybWF0aW9uKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgY2VudGVyID0gTWF0cml4NF9kZWZhdWx0LmdldFRyYW5zbGF0aW9uKAogICAgICAgICAgICB0cmFuc2Zvcm1hdGlvbiwKICAgICAgICAgICAgc2NyYXRjaEZyb21UcmFuc2Zvcm1hdGlvbkNlbnRlcgogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHNjYWxlID0gTWF0cml4NF9kZWZhdWx0LmdldFNjYWxlKAogICAgICAgICAgICB0cmFuc2Zvcm1hdGlvbiwKICAgICAgICAgICAgc2NyYXRjaEZyb21UcmFuc2Zvcm1hdGlvblNjYWxlCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcmFkaXVzID0gMC41ICogQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShzY2FsZSk7CiAgICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlciwgcmVzdWx0LmNlbnRlcik7CiAgICAgICAgICByZXN1bHQucmFkaXVzID0gcmFkaXVzOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhIEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gc3BoZXJlIFRoZSBib3VuZGluZyBzcGhlcmUgdG8gZHVwbGljYXRlLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuIChSZXR1cm5zIHVuZGVmaW5lZCBpZiBzcGhlcmUgaXMgdW5kZWZpbmVkKQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjbG9uZShzcGhlcmUsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoc3BoZXJlKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9Cb3VuZGluZ1NwaGVyZShzcGhlcmUuY2VudGVyLCBzcGhlcmUucmFkaXVzKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoc3BoZXJlLmNlbnRlciwgcmVzdWx0LmNlbnRlcik7CiAgICAgICAgICByZXN1bHQucmFkaXVzID0gc3BoZXJlLnJhZGl1czsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2UgaW50byB0aGUgcHJvdmlkZWQgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcGFjay4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheSBUaGUgYXJyYXkgdG8gcGFjayBpbnRvLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRpbmdJbmRleD0wXSBUaGUgaW5kZXggaW50byB0aGUgYXJyYXkgYXQgd2hpY2ggdG8gc3RhcnQgcGFja2luZyB0aGUgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBhcnJheSB0aGF0IHdhcyBwYWNrZWQgaW50bwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwYWNrKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgICAgY29uc3QgY2VudGVyID0gdmFsdWUuY2VudGVyOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGNlbnRlci54OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGNlbnRlci55OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGNlbnRlci56OwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5yYWRpdXM7CiAgICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhbiBpbnN0YW5jZSBmcm9tIGEgcGFja2VkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gYXJyYXkgVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIHN0YXJ0aW5nIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIGJlIHVucGFja2VkLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgY2VudGVyID0gcmVzdWx0LmNlbnRlcjsKICAgICAgICAgIGNlbnRlci54ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIGNlbnRlci55ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIGNlbnRlci56ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdC5yYWRpdXMgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgYm91bmRpbmcgc3BoZXJlIHRoYXQgY29udGFpbnMgYm90aCB0aGUgbGVmdCBhbmQgcmlnaHQgYm91bmRpbmcgc3BoZXJlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IGxlZnQgQSBzcGhlcmUgdG8gZW5jbG9zZSBpbiBhIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSByaWdodCBBIHNwaGVyZSB0byBlbmNsb3NlIGluIGEgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtCb3VuZGluZ1NwaGVyZX0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQm91bmRpbmdTcGhlcmUgaW5zdGFuY2UgaWYgbm9uZSB3YXMgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVuaW9uKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbGVmdENlbnRlciA9IGxlZnQuY2VudGVyOwogICAgICAgICAgY29uc3QgbGVmdFJhZGl1cyA9IGxlZnQucmFkaXVzOwogICAgICAgICAgY29uc3QgcmlnaHRDZW50ZXIgPSByaWdodC5jZW50ZXI7CiAgICAgICAgICBjb25zdCByaWdodFJhZGl1cyA9IHJpZ2h0LnJhZGl1czsKICAgICAgICAgIGNvbnN0IHRvUmlnaHRDZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICAgIHJpZ2h0Q2VudGVyLAogICAgICAgICAgICBsZWZ0Q2VudGVyLAogICAgICAgICAgICB1bmlvblNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBjZW50ZXJTZXBhcmF0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSh0b1JpZ2h0Q2VudGVyKTsKICAgICAgICAgIGlmIChsZWZ0UmFkaXVzID49IGNlbnRlclNlcGFyYXRpb24gKyByaWdodFJhZGl1cykgewogICAgICAgICAgICBsZWZ0LmNsb25lKHJlc3VsdCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAocmlnaHRSYWRpdXMgPj0gY2VudGVyU2VwYXJhdGlvbiArIGxlZnRSYWRpdXMpIHsKICAgICAgICAgICAgcmlnaHQuY2xvbmUocmVzdWx0KTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhhbGZEaXN0YW5jZUJldHdlZW5UYW5nZW50UG9pbnRzID0gKGxlZnRSYWRpdXMgKyBjZW50ZXJTZXBhcmF0aW9uICsgcmlnaHRSYWRpdXMpICogMC41OwogICAgICAgICAgY29uc3QgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICAgIHRvUmlnaHRDZW50ZXIsCiAgICAgICAgICAgICgtbGVmdFJhZGl1cyArIGhhbGZEaXN0YW5jZUJldHdlZW5UYW5nZW50UG9pbnRzKSAvIGNlbnRlclNlcGFyYXRpb24sCiAgICAgICAgICAgIHVuaW9uU2NyYXRjaENlbnRlcgogICAgICAgICAgKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCBsZWZ0Q2VudGVyLCBjZW50ZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlciwgcmVzdWx0LmNlbnRlcik7CiAgICAgICAgICByZXN1bHQucmFkaXVzID0gaGFsZkRpc3RhbmNlQmV0d2VlblRhbmdlbnRQb2ludHM7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIGJvdW5kaW5nIHNwaGVyZSBieSBlbmxhcmdpbmcgdGhlIHByb3ZpZGVkIHNwaGVyZSB0byBjb250YWluIHRoZSBwcm92aWRlZCBwb2ludC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IHNwaGVyZSBBIHNwaGVyZSB0byBleHBhbmQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBwb2ludCBBIHBvaW50IHRvIGVuY2xvc2UgaW4gYSBib3VuZGluZyBzcGhlcmUuCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXhwYW5kKHNwaGVyZSwgcG9pbnQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzcGhlcmUiLCBzcGhlcmUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwb2ludCIsIHBvaW50KTsKICAgICAgICAgIHJlc3VsdCA9IF9Cb3VuZGluZ1NwaGVyZS5jbG9uZShzcGhlcmUsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCByYWRpdXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocG9pbnQsIHJlc3VsdC5jZW50ZXIsIGV4cGFuZFNjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgaWYgKHJhZGl1cyA+IHJlc3VsdC5yYWRpdXMpIHsKICAgICAgICAgICAgcmVzdWx0LnJhZGl1cyA9IHJhZGl1czsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERldGVybWluZXMgd2hpY2ggc2lkZSBvZiBhIHBsYW5lIGEgc3BoZXJlIGlzIGxvY2F0ZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBzcGhlcmUgVGhlIGJvdW5kaW5nIHNwaGVyZSB0byB0ZXN0LgogICAgICAgICAqIEBwYXJhbSB7UGxhbmV9IHBsYW5lIFRoZSBwbGFuZSB0byB0ZXN0IGFnYWluc3QuCiAgICAgICAgICogQHJldHVybnMge0ludGVyc2VjdH0ge0BsaW5rIEludGVyc2VjdC5JTlNJREV9IGlmIHRoZSBlbnRpcmUgc3BoZXJlIGlzIG9uIHRoZSBzaWRlIG9mIHRoZSBwbGFuZQogICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgIHRoZSBub3JtYWwgaXMgcG9pbnRpbmcsIHtAbGluayBJbnRlcnNlY3QuT1VUU0lERX0gaWYgdGhlIGVudGlyZSBzcGhlcmUgaXMKICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICBvbiB0aGUgb3Bwb3NpdGUgc2lkZSwgYW5kIHtAbGluayBJbnRlcnNlY3QuSU5URVJTRUNUSU5HfSBpZiB0aGUgc3BoZXJlCiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgaW50ZXJzZWN0cyB0aGUgcGxhbmUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGludGVyc2VjdFBsYW5lKHNwaGVyZSwgcGxhbmUpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic3BoZXJlIiwgc3BoZXJlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicGxhbmUiLCBwbGFuZSk7CiAgICAgICAgICBjb25zdCBjZW50ZXIgPSBzcGhlcmUuY2VudGVyOwogICAgICAgICAgY29uc3QgcmFkaXVzID0gc3BoZXJlLnJhZGl1czsKICAgICAgICAgIGNvbnN0IG5vcm1hbDIgPSBwbGFuZS5ub3JtYWw7CiAgICAgICAgICBjb25zdCBkaXN0YW5jZVRvUGxhbmUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG5vcm1hbDIsIGNlbnRlcikgKyBwbGFuZS5kaXN0YW5jZTsKICAgICAgICAgIGlmIChkaXN0YW5jZVRvUGxhbmUgPCAtcmFkaXVzKSB7CiAgICAgICAgICAgIHJldHVybiBJbnRlcnNlY3RfZGVmYXVsdC5PVVRTSURFOwogICAgICAgICAgfSBlbHNlIGlmIChkaXN0YW5jZVRvUGxhbmUgPCByYWRpdXMpIHsKICAgICAgICAgICAgcmV0dXJuIEludGVyc2VjdF9kZWZhdWx0LklOVEVSU0VDVElORzsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBJbnRlcnNlY3RfZGVmYXVsdC5JTlNJREU7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEFwcGxpZXMgYSA0eDQgYWZmaW5lIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCB0byBhIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IHNwaGVyZSBUaGUgYm91bmRpbmcgc3BoZXJlIHRvIGFwcGx5IHRoZSB0cmFuc2Zvcm1hdGlvbiB0by4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHRyYW5zZm9ybSBUaGUgdHJhbnNmb3JtYXRpb24gbWF0cml4IHRvIGFwcGx5IHRvIHRoZSBib3VuZGluZyBzcGhlcmUuCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdHJhbnNmb3JtKHNwaGVyZSwgdHJhbnNmb3JtMiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNwaGVyZSIsIHNwaGVyZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zZm9ybSIsIHRyYW5zZm9ybTIpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQuY2VudGVyID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCgKICAgICAgICAgICAgdHJhbnNmb3JtMiwKICAgICAgICAgICAgc3BoZXJlLmNlbnRlciwKICAgICAgICAgICAgcmVzdWx0LmNlbnRlcgogICAgICAgICAgKTsKICAgICAgICAgIHJlc3VsdC5yYWRpdXMgPSBNYXRyaXg0X2RlZmF1bHQuZ2V0TWF4aW11bVNjYWxlKHRyYW5zZm9ybTIpICogc3BoZXJlLnJhZGl1czsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBlc3RpbWF0ZWQgZGlzdGFuY2Ugc3F1YXJlZCBmcm9tIHRoZSBjbG9zZXN0IHBvaW50IG9uIGEgYm91bmRpbmcgc3BoZXJlIHRvIGEgcG9pbnQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBzcGhlcmUgVGhlIHNwaGVyZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IGNhcnRlc2lhbiBUaGUgcG9pbnQKICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZGlzdGFuY2Ugc3F1YXJlZCBmcm9tIHRoZSBib3VuZGluZyBzcGhlcmUgdG8gdGhlIHBvaW50LiBSZXR1cm5zIDAgaWYgdGhlIHBvaW50IGlzIGluc2lkZSB0aGUgc3BoZXJlLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBTb3J0IGJvdW5kaW5nIHNwaGVyZXMgZnJvbSBiYWNrIHRvIGZyb250CiAgICAgICAgICogc3BoZXJlcy5zb3J0KGZ1bmN0aW9uKGEsIGIpIHsKICAgICAgICAgKiAgICAgcmV0dXJuIENlc2l1bS5Cb3VuZGluZ1NwaGVyZS5kaXN0YW5jZVNxdWFyZWRUbyhiLCBjYW1lcmEucG9zaXRpb25XQykgLSBDZXNpdW0uQm91bmRpbmdTcGhlcmUuZGlzdGFuY2VTcXVhcmVkVG8oYSwgY2FtZXJhLnBvc2l0aW9uV0MpOwogICAgICAgICAqIH0pOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXN0YW5jZVNxdWFyZWRUbyhzcGhlcmUsIGNhcnRlc2lhbjExKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNwaGVyZSIsIHNwaGVyZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIGNvbnN0IGRpZmYgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICAgIHNwaGVyZS5jZW50ZXIsCiAgICAgICAgICAgIGNhcnRlc2lhbjExLAogICAgICAgICAgICBkaXN0YW5jZVNxdWFyZWRUb1NjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBkaXN0YW5jZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoZGlmZikgLSBzcGhlcmUucmFkaXVzOwogICAgICAgICAgaWYgKGRpc3RhbmNlIDw9IDApIHsKICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gZGlzdGFuY2UgKiBkaXN0YW5jZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQXBwbGllcyBhIDR4NCBhZmZpbmUgdHJhbnNmb3JtYXRpb24gbWF0cml4IHRvIGEgYm91bmRpbmcgc3BoZXJlIHdoZXJlIHRoZXJlIGlzIG5vIHNjYWxlCiAgICAgICAgICogVGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBpcyBub3QgdmVyaWZpZWQgdG8gaGF2ZSBhIHVuaWZvcm0gc2NhbGUgb2YgMS4KICAgICAgICAgKiBUaGlzIG1ldGhvZCBpcyBmYXN0ZXIgdGhhbiBjb21wdXRpbmcgdGhlIGdlbmVyYWwgYm91bmRpbmcgc3BoZXJlIHRyYW5zZm9ybSB1c2luZyB7QGxpbmsgQm91bmRpbmdTcGhlcmUudHJhbnNmb3JtfS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IHNwaGVyZSBUaGUgYm91bmRpbmcgc3BoZXJlIHRvIGFwcGx5IHRoZSB0cmFuc2Zvcm1hdGlvbiB0by4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDR9IHRyYW5zZm9ybSBUaGUgdHJhbnNmb3JtYXRpb24gbWF0cml4IHRvIGFwcGx5IHRvIHRoZSBib3VuZGluZyBzcGhlcmUuCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgbW9kZWxNYXRyaXggPSBDZXNpdW0uVHJhbnNmb3Jtcy5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZShwb3NpdGlvbk9uRWxsaXBzb2lkKTsKICAgICAgICAgKiBjb25zdCBib3VuZGluZ1NwaGVyZSA9IG5ldyBDZXNpdW0uQm91bmRpbmdTcGhlcmUoKTsKICAgICAgICAgKiBjb25zdCBuZXdCb3VuZGluZ1NwaGVyZSA9IENlc2l1bS5Cb3VuZGluZ1NwaGVyZS50cmFuc2Zvcm1XaXRob3V0U2NhbGUoYm91bmRpbmdTcGhlcmUsIG1vZGVsTWF0cml4KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdHJhbnNmb3JtV2l0aG91dFNjYWxlKHNwaGVyZSwgdHJhbnNmb3JtMiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNwaGVyZSIsIHNwaGVyZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zZm9ybSIsIHRyYW5zZm9ybTIpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgX0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQuY2VudGVyID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCgKICAgICAgICAgICAgdHJhbnNmb3JtMiwKICAgICAgICAgICAgc3BoZXJlLmNlbnRlciwKICAgICAgICAgICAgcmVzdWx0LmNlbnRlcgogICAgICAgICAgKTsKICAgICAgICAgIHJlc3VsdC5yYWRpdXMgPSBzcGhlcmUucmFkaXVzOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGRpc3RhbmNlcyBjYWxjdWxhdGVkIGJ5IHRoZSB2ZWN0b3IgZnJvbSB0aGUgY2VudGVyIG9mIHRoZSBib3VuZGluZyBzcGhlcmUgdG8gcG9zaXRpb24gcHJvamVjdGVkIG9udG8gZGlyZWN0aW9uCiAgICAgICAgICogcGx1cy9taW51cyB0aGUgcmFkaXVzIG9mIHRoZSBib3VuZGluZyBzcGhlcmUuCiAgICAgICAgICogPGJyPgogICAgICAgICAqIElmIHlvdSBpbWFnaW5lIHRoZSBpbmZpbml0ZSBudW1iZXIgb2YgcGxhbmVzIHdpdGggbm9ybWFsIGRpcmVjdGlvbiwgdGhpcyBjb21wdXRlcyB0aGUgc21hbGxlc3QgZGlzdGFuY2UgdG8gdGhlCiAgICAgICAgICogY2xvc2VzdCBhbmQgZmFydGhlc3QgcGxhbmVzIGZyb20gcG9zaXRpb24gdGhhdCBpbnRlcnNlY3QgdGhlIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IHNwaGVyZSBUaGUgYm91bmRpbmcgc3BoZXJlIHRvIGNhbGN1bGF0ZSB0aGUgZGlzdGFuY2UgdG8uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBwb3NpdGlvbiBUaGUgcG9zaXRpb24gdG8gY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBmcm9tLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gZGlyZWN0aW9uIFRoZSBkaXJlY3Rpb24gZnJvbSBwb3NpdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0ludGVydmFsfSBbcmVzdWx0XSBBIEludGVydmFsIHRvIHN0b3JlIHRoZSBuZWFyZXN0IGFuZCBmYXJ0aGVzdCBkaXN0YW5jZXMuCiAgICAgICAgICogQHJldHVybnMge0ludGVydmFsfSBUaGUgbmVhcmVzdCBhbmQgZmFydGhlc3QgZGlzdGFuY2VzIG9uIHRoZSBib3VuZGluZyBzcGhlcmUgZnJvbSBwb3NpdGlvbiBpbiBkaXJlY3Rpb24uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNvbXB1dGVQbGFuZURpc3RhbmNlcyhzcGhlcmUsIHBvc2l0aW9uLCBkaXJlY3Rpb24yLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic3BoZXJlIiwgc3BoZXJlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicG9zaXRpb24iLCBwb3NpdGlvbik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImRpcmVjdGlvbiIsIGRpcmVjdGlvbjIpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXN1bHQgPSBuZXcgSW50ZXJ2YWxfZGVmYXVsdCgpOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgdG9DZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICAgIHNwaGVyZS5jZW50ZXIsCiAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IG1hZyA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZGlyZWN0aW9uMiwgdG9DZW50ZXIpOwogICAgICAgICAgcmVzdWx0LnN0YXJ0ID0gbWFnIC0gc3BoZXJlLnJhZGl1czsKICAgICAgICAgIHJlc3VsdC5zdG9wID0gbWFnICsgc3BoZXJlLnJhZGl1czsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBib3VuZGluZyBzcGhlcmUgaW4gMkQgZnJvbSBhIGJvdW5kaW5nIHNwaGVyZSBpbiAzRCB3b3JsZCBjb29yZGluYXRlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Qm91bmRpbmdTcGhlcmV9IHNwaGVyZSBUaGUgYm91bmRpbmcgc3BoZXJlIHRvIHRyYW5zZm9ybSB0byAyRC4KICAgICAgICAgKiBAcGFyYW0ge01hcFByb2plY3Rpb259IFtwcm9qZWN0aW9uPUdlb2dyYXBoaWNQcm9qZWN0aW9uXSBUaGUgcHJvamVjdGlvbiB0byAyRC4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Qm91bmRpbmdTcGhlcmV9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwcm9qZWN0VG8yRChzcGhlcmUsIHByb2plY3Rpb24sIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzcGhlcmUiLCBzcGhlcmUpOwogICAgICAgICAgcHJvamVjdFRvMkRQcm9qZWN0aW9uLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgICAgcHJvamVjdGlvbiA9IHByb2plY3Rpb24gPz8gcHJvamVjdFRvMkRQcm9qZWN0aW9uOwogICAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gcHJvamVjdGlvbi5lbGxpcHNvaWQ7CiAgICAgICAgICBsZXQgY2VudGVyID0gc3BoZXJlLmNlbnRlcjsKICAgICAgICAgIGNvbnN0IHJhZGl1cyA9IHNwaGVyZS5yYWRpdXM7CiAgICAgICAgICBsZXQgbm9ybWFsMjsKICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGNlbnRlciwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pKSB7CiAgICAgICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgcHJvamVjdFRvMkROb3JtYWxTY3JhdGNoKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgICAgIGNlbnRlciwKICAgICAgICAgICAgICBwcm9qZWN0VG8yRE5vcm1hbFNjcmF0Y2gKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGVhc3QgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1osCiAgICAgICAgICAgIG5vcm1hbDIsCiAgICAgICAgICAgIHByb2plY3RUbzJERWFzdFNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGVhc3QsIGVhc3QpOwogICAgICAgICAgY29uc3Qgbm9ydGggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Mobm9ybWFsMiwgZWFzdCwgcHJvamVjdFRvMkROb3J0aFNjcmF0Y2gpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShub3J0aCwgbm9ydGgpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobm9ybWFsMiwgcmFkaXVzLCBub3JtYWwyKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG5vcnRoLCByYWRpdXMsIG5vcnRoKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGVhc3QsIHJhZGl1cywgZWFzdCk7CiAgICAgICAgICBjb25zdCBzb3V0aCA9IENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUobm9ydGgsIHByb2plY3RUbzJEU291dGhTY3JhdGNoKTsKICAgICAgICAgIGNvbnN0IHdlc3QgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGVhc3QsIHByb2plY3RUbzJEV2VzdFNjcmF0Y2gpOwogICAgICAgICAgY29uc3QgcG9zaXRpb25zID0gcHJvamVjdFRvMkRQb3NpdGlvbnNTY3JhdGNoOwogICAgICAgICAgbGV0IGNvcm5lciA9IHBvc2l0aW9uc1swXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobm9ybWFsMiwgbm9ydGgsIGNvcm5lcik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgZWFzdCwgY29ybmVyKTsKICAgICAgICAgIGNvcm5lciA9IHBvc2l0aW9uc1sxXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobm9ybWFsMiwgbm9ydGgsIGNvcm5lcik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgd2VzdCwgY29ybmVyKTsKICAgICAgICAgIGNvcm5lciA9IHBvc2l0aW9uc1syXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobm9ybWFsMiwgc291dGgsIGNvcm5lcik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgd2VzdCwgY29ybmVyKTsKICAgICAgICAgIGNvcm5lciA9IHBvc2l0aW9uc1szXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobm9ybWFsMiwgc291dGgsIGNvcm5lcik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgZWFzdCwgY29ybmVyKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUobm9ybWFsMiwgbm9ybWFsMik7CiAgICAgICAgICBjb3JuZXIgPSBwb3NpdGlvbnNbNF07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5vcm1hbDIsIG5vcnRoLCBjb3JuZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIGVhc3QsIGNvcm5lcik7CiAgICAgICAgICBjb3JuZXIgPSBwb3NpdGlvbnNbNV07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5vcm1hbDIsIG5vcnRoLCBjb3JuZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHdlc3QsIGNvcm5lcik7CiAgICAgICAgICBjb3JuZXIgPSBwb3NpdGlvbnNbNl07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5vcm1hbDIsIHNvdXRoLCBjb3JuZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHdlc3QsIGNvcm5lcik7CiAgICAgICAgICBjb3JuZXIgPSBwb3NpdGlvbnNbN107CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5vcm1hbDIsIHNvdXRoLCBjb3JuZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIGVhc3QsIGNvcm5lcik7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBjb25zdCBwb3NpdGlvbiA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCBwb3NpdGlvbiwgcG9zaXRpb24pOwogICAgICAgICAgICBjb25zdCBjYXJ0b2dyYXBoaWMyID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgIHByb2plY3RUbzJEQ2FydG9ncmFwaGljU2NyYXRjaAogICAgICAgICAgICApOwogICAgICAgICAgICBwcm9qZWN0aW9uLnByb2plY3QoY2FydG9ncmFwaGljMiwgcG9zaXRpb24pOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0ID0gX0JvdW5kaW5nU3BoZXJlLmZyb21Qb2ludHMocG9zaXRpb25zLCByZXN1bHQpOwogICAgICAgICAgY2VudGVyID0gcmVzdWx0LmNlbnRlcjsKICAgICAgICAgIGNvbnN0IHgyID0gY2VudGVyLng7CiAgICAgICAgICBjb25zdCB5MiA9IGNlbnRlci55OwogICAgICAgICAgY29uc3QgejIgPSBjZW50ZXIuejsKICAgICAgICAgIGNlbnRlci54ID0gejI7CiAgICAgICAgICBjZW50ZXIueSA9IHgyOwogICAgICAgICAgY2VudGVyLnogPSB5MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIERldGVybWluZXMgd2hldGhlciBvciBub3QgYSBzcGhlcmUgaXMgaGlkZGVuIGZyb20gdmlldyBieSB0aGUgb2NjbHVkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBzcGhlcmUgVGhlIGJvdW5kaW5nIHNwaGVyZSBzdXJyb3VuZGluZyB0aGUgb2NjbHVkZWQgb2JqZWN0LgogICAgICAgICAqIEBwYXJhbSB7T2NjbHVkZXJ9IG9jY2x1ZGVyIFRoZSBvY2NsdWRlci4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIHNwaGVyZSBpcyBub3QgdmlzaWJsZTsgb3RoZXJ3aXNlIDxjb2RlPmZhbHNlPC9jb2RlPi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgaXNPY2NsdWRlZChzcGhlcmUsIG9jY2x1ZGVyKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInNwaGVyZSIsIHNwaGVyZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9jY2x1ZGVyIiwgb2NjbHVkZXIpOwogICAgICAgICAgcmV0dXJuICFvY2NsdWRlci5pc0JvdW5kaW5nU3BoZXJlVmlzaWJsZShzcGhlcmUpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGUgcHJvdmlkZWQgQm91bmRpbmdTcGhlcmUgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW2xlZnRdIFRoZSBmaXJzdCBCb3VuZGluZ1NwaGVyZS4KICAgICAgICAgKiBAcGFyYW0ge0JvdW5kaW5nU3BoZXJlfSBbcmlnaHRdIFRoZSBzZWNvbmQgQm91bmRpbmdTcGhlcmUuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIGxlZnQgYW5kIHJpZ2h0IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhsZWZ0LmNlbnRlciwgcmlnaHQuY2VudGVyKSAmJiBsZWZ0LnJhZGl1cyA9PT0gcmlnaHQucmFkaXVzOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZXRlcm1pbmVzIHdoaWNoIHNpZGUgb2YgYSBwbGFuZSB0aGUgc3BoZXJlIGlzIGxvY2F0ZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1BsYW5lfSBwbGFuZSBUaGUgcGxhbmUgdG8gdGVzdCBhZ2FpbnN0LgogICAgICAgICAqIEByZXR1cm5zIHtJbnRlcnNlY3R9IHtAbGluayBJbnRlcnNlY3QuSU5TSURFfSBpZiB0aGUgZW50aXJlIHNwaGVyZSBpcyBvbiB0aGUgc2lkZSBvZiB0aGUgcGxhbmUKICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICB0aGUgbm9ybWFsIGlzIHBvaW50aW5nLCB7QGxpbmsgSW50ZXJzZWN0Lk9VVFNJREV9IGlmIHRoZSBlbnRpcmUgc3BoZXJlIGlzCiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgb24gdGhlIG9wcG9zaXRlIHNpZGUsIGFuZCB7QGxpbmsgSW50ZXJzZWN0LklOVEVSU0VDVElOR30gaWYgdGhlIHNwaGVyZQogICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgIGludGVyc2VjdHMgdGhlIHBsYW5lLgogICAgICAgICAqLwogICAgICAgIGludGVyc2VjdFBsYW5lKHBsYW5lKSB7CiAgICAgICAgICByZXR1cm4gX0JvdW5kaW5nU3BoZXJlLmludGVyc2VjdFBsYW5lKHRoaXMsIHBsYW5lKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGVzdGltYXRlZCBkaXN0YW5jZSBzcXVhcmVkIGZyb20gdGhlIGNsb3Nlc3QgcG9pbnQgb24gYSBib3VuZGluZyBzcGhlcmUgdG8gYSBwb2ludC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSBwb2ludAogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBlc3RpbWF0ZWQgZGlzdGFuY2Ugc3F1YXJlZCBmcm9tIHRoZSBib3VuZGluZyBzcGhlcmUgdG8gdGhlIHBvaW50LgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBTb3J0IGJvdW5kaW5nIHNwaGVyZXMgZnJvbSBiYWNrIHRvIGZyb250CiAgICAgICAgICogc3BoZXJlcy5zb3J0KGZ1bmN0aW9uKGEsIGIpIHsKICAgICAgICAgKiAgICAgcmV0dXJuIGIuZGlzdGFuY2VTcXVhcmVkVG8oY2FtZXJhLnBvc2l0aW9uV0MpIC0gYS5kaXN0YW5jZVNxdWFyZWRUbyhjYW1lcmEucG9zaXRpb25XQyk7CiAgICAgICAgICogfSk7CiAgICAgICAgICovCiAgICAgICAgZGlzdGFuY2VTcXVhcmVkVG8oY2FydGVzaWFuMTEpIHsKICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuZGlzdGFuY2VTcXVhcmVkVG8odGhpcywgY2FydGVzaWFuMTEpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZGlzdGFuY2VzIGNhbGN1bGF0ZWQgYnkgdGhlIHZlY3RvciBmcm9tIHRoZSBjZW50ZXIgb2YgdGhlIGJvdW5kaW5nIHNwaGVyZSB0byBwb3NpdGlvbiBwcm9qZWN0ZWQgb250byBkaXJlY3Rpb24KICAgICAgICAgKiBwbHVzL21pbnVzIHRoZSByYWRpdXMgb2YgdGhlIGJvdW5kaW5nIHNwaGVyZS4KICAgICAgICAgKiA8YnI+CiAgICAgICAgICogSWYgeW91IGltYWdpbmUgdGhlIGluZmluaXRlIG51bWJlciBvZiBwbGFuZXMgd2l0aCBub3JtYWwgZGlyZWN0aW9uLCB0aGlzIGNvbXB1dGVzIHRoZSBzbWFsbGVzdCBkaXN0YW5jZSB0byB0aGUKICAgICAgICAgKiBjbG9zZXN0IGFuZCBmYXJ0aGVzdCBwbGFuZXMgZnJvbSBwb3NpdGlvbiB0aGF0IGludGVyc2VjdCB0aGUgYm91bmRpbmcgc3BoZXJlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBwb3NpdGlvbiBUaGUgcG9zaXRpb24gdG8gY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBmcm9tLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gZGlyZWN0aW9uIFRoZSBkaXJlY3Rpb24gZnJvbSBwb3NpdGlvbi4KICAgICAgICAgKiBAcGFyYW0ge0ludGVydmFsfSBbcmVzdWx0XSBBIEludGVydmFsIHRvIHN0b3JlIHRoZSBuZWFyZXN0IGFuZCBmYXJ0aGVzdCBkaXN0YW5jZXMuCiAgICAgICAgICogQHJldHVybnMge0ludGVydmFsfSBUaGUgbmVhcmVzdCBhbmQgZmFydGhlc3QgZGlzdGFuY2VzIG9uIHRoZSBib3VuZGluZyBzcGhlcmUgZnJvbSBwb3NpdGlvbiBpbiBkaXJlY3Rpb24uCiAgICAgICAgICovCiAgICAgICAgY29tcHV0ZVBsYW5lRGlzdGFuY2VzKHBvc2l0aW9uLCBkaXJlY3Rpb24yLCByZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuY29tcHV0ZVBsYW5lRGlzdGFuY2VzKAogICAgICAgICAgICB0aGlzLAogICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgZGlyZWN0aW9uMiwKICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgb3Igbm90IGEgc3BoZXJlIGlzIGhpZGRlbiBmcm9tIHZpZXcgYnkgdGhlIG9jY2x1ZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtPY2NsdWRlcn0gb2NjbHVkZXIgVGhlIG9jY2x1ZGVyLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgc3BoZXJlIGlzIG5vdCB2aXNpYmxlOyBvdGhlcndpc2UgPGNvZGU+ZmFsc2U8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIGlzT2NjbHVkZWQob2NjbHVkZXIpIHsKICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuaXNPY2NsdWRlZCh0aGlzLCBvY2NsdWRlcik7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXBhcmVzIHRoaXMgQm91bmRpbmdTcGhlcmUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgQm91bmRpbmdTcGhlcmUgY29tcG9uZW50d2lzZSBhbmQgcmV0dXJucwogICAgICAgICAqIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZXkgYXJlIGVxdWFsLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3JpZ2h0XSBUaGUgcmlnaHQgaGFuZCBzaWRlIEJvdW5kaW5nU3BoZXJlLgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKi8KICAgICAgICBlcXVhbHMocmlnaHQpIHsKICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuZXF1YWxzKHRoaXMsIHJpZ2h0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyB0aGlzIEJvdW5kaW5nU3BoZXJlIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtCb3VuZGluZ1NwaGVyZX0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0JvdW5kaW5nU3BoZXJlfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBCb3VuZGluZ1NwaGVyZSBpbnN0YW5jZSBpZiBub25lIHdhcyBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfQm91bmRpbmdTcGhlcmUuY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHJhZGl1cyBvZiB0aGUgQm91bmRpbmdTcGhlcmUuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIHJhZGl1cyBvZiB0aGUgQm91bmRpbmdTcGhlcmUuCiAgICAgICAgICovCiAgICAgICAgdm9sdW1lKCkgewogICAgICAgICAgY29uc3QgcmFkaXVzID0gdGhpcy5yYWRpdXM7CiAgICAgICAgICByZXR1cm4gdm9sdW1lQ29uc3RhbnQgKiByYWRpdXMgKiByYWRpdXMgKiByYWRpdXM7CiAgICAgICAgfQogICAgICB9OwogICAgICBCb3VuZGluZ1NwaGVyZS5wYWNrZWRMZW5ndGggPSA0OwogICAgICBmcm9tUG9pbnRzWE1pbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVBvaW50c1lNaW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZyb21Qb2ludHNaTWluID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tUG9pbnRzWE1heCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVBvaW50c1lNYXggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZyb21Qb2ludHNaTWF4ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tUG9pbnRzQ3VycmVudFBvcyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVBvaW50c1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZyb21Qb2ludHNSaXR0ZXJDZW50ZXIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZyb21Qb2ludHNNaW5Cb3hQdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVBvaW50c01heEJveFB0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tUG9pbnRzTmFpdmVDZW50ZXJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB2b2x1bWVDb25zdGFudCA9IDQgLyAzICogTWF0aF9kZWZhdWx0LlBJOwogICAgICBkZWZhdWx0UHJvamVjdGlvbiA9IG5ldyBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0KCk7CiAgICAgIGZyb21SZWN0YW5nbGUyRExvd2VyTGVmdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVJlY3RhbmdsZTJEVXBwZXJSaWdodCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJvbVJlY3RhbmdsZTJEU291dGh3ZXN0ID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIGZyb21SZWN0YW5nbGUyRE5vcnRoZWFzdCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBmcm9tUmVjdGFuZ2xlM0RTY3JhdGNoID0gLyoqIEB0eXBlIHtDYXJ0ZXNpYW4zW119ICovCiAgICAgIFtdOwogICAgICBmcm9tT3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2hVID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tT3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2hWID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmcm9tT3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2hXID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRnJvbVRyYW5zZm9ybWF0aW9uQ2VudGVyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRnJvbVRyYW5zZm9ybWF0aW9uU2NhbGUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHVuaW9uU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdW5pb25TY3JhdGNoQ2VudGVyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBleHBhbmRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBkaXN0YW5jZVNxdWFyZWRUb1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwcm9qZWN0VG8yRE5vcm1hbFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHByb2plY3RUbzJERWFzdFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHByb2plY3RUbzJETm9ydGhTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwcm9qZWN0VG8yRFdlc3RTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwcm9qZWN0VG8yRFNvdXRoU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcHJvamVjdFRvMkRDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHByb2plY3RUbzJEUG9zaXRpb25zU2NyYXRjaCA9IG5ldyBBcnJheSg4KTsKICAgICAgZm9yIChsZXQgbjIgPSAwOyBuMiA8IDg7ICsrbjIpIHsKICAgICAgICBwcm9qZWN0VG8yRFBvc2l0aW9uc1NjcmF0Y2hbbjJdID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB9CiAgICAgIHByb2plY3RUbzJEUHJvamVjdGlvbiA9IG5ldyBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0KCk7CiAgICAgIEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQgPSBCb3VuZGluZ1NwaGVyZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1dlYkdMQ29uc3RhbnRzLmpzCiAgdmFyIFdlYkdMQ29uc3RhbnRzLCBXZWJHTENvbnN0YW50c19kZWZhdWx0OwogIHZhciBpbml0X1dlYkdMQ29uc3RhbnRzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9XZWJHTENvbnN0YW50cy5qcyIoKSB7CiAgICAgIFdlYkdMQ29uc3RhbnRzID0gewogICAgICAgIERFUFRIX0JVRkZFUl9CSVQ6IDI1NiwKICAgICAgICBTVEVOQ0lMX0JVRkZFUl9CSVQ6IDEwMjQsCiAgICAgICAgQ09MT1JfQlVGRkVSX0JJVDogMTYzODQsCiAgICAgICAgUE9JTlRTOiAwLAogICAgICAgIExJTkVTOiAxLAogICAgICAgIExJTkVfTE9PUDogMiwKICAgICAgICBMSU5FX1NUUklQOiAzLAogICAgICAgIFRSSUFOR0xFUzogNCwKICAgICAgICBUUklBTkdMRV9TVFJJUDogNSwKICAgICAgICBUUklBTkdMRV9GQU46IDYsCiAgICAgICAgWkVSTzogMCwKICAgICAgICBPTkU6IDEsCiAgICAgICAgU1JDX0NPTE9SOiA3NjgsCiAgICAgICAgT05FX01JTlVTX1NSQ19DT0xPUjogNzY5LAogICAgICAgIFNSQ19BTFBIQTogNzcwLAogICAgICAgIE9ORV9NSU5VU19TUkNfQUxQSEE6IDc3MSwKICAgICAgICBEU1RfQUxQSEE6IDc3MiwKICAgICAgICBPTkVfTUlOVVNfRFNUX0FMUEhBOiA3NzMsCiAgICAgICAgRFNUX0NPTE9SOiA3NzQsCiAgICAgICAgT05FX01JTlVTX0RTVF9DT0xPUjogNzc1LAogICAgICAgIFNSQ19BTFBIQV9TQVRVUkFURTogNzc2LAogICAgICAgIEZVTkNfQUREOiAzMjc3NCwKICAgICAgICBCTEVORF9FUVVBVElPTjogMzI3NzcsCiAgICAgICAgQkxFTkRfRVFVQVRJT05fUkdCOiAzMjc3NywKICAgICAgICAvLyBzYW1lIGFzIEJMRU5EX0VRVUFUSU9OCiAgICAgICAgQkxFTkRfRVFVQVRJT05fQUxQSEE6IDM0ODc3LAogICAgICAgIEZVTkNfU1VCVFJBQ1Q6IDMyNzc4LAogICAgICAgIEZVTkNfUkVWRVJTRV9TVUJUUkFDVDogMzI3NzksCiAgICAgICAgQkxFTkRfRFNUX1JHQjogMzI5NjgsCiAgICAgICAgQkxFTkRfU1JDX1JHQjogMzI5NjksCiAgICAgICAgQkxFTkRfRFNUX0FMUEhBOiAzMjk3MCwKICAgICAgICBCTEVORF9TUkNfQUxQSEE6IDMyOTcxLAogICAgICAgIENPTlNUQU5UX0NPTE9SOiAzMjc2OSwKICAgICAgICBPTkVfTUlOVVNfQ09OU1RBTlRfQ09MT1I6IDMyNzcwLAogICAgICAgIENPTlNUQU5UX0FMUEhBOiAzMjc3MSwKICAgICAgICBPTkVfTUlOVVNfQ09OU1RBTlRfQUxQSEE6IDMyNzcyLAogICAgICAgIEJMRU5EX0NPTE9SOiAzMjc3MywKICAgICAgICBBUlJBWV9CVUZGRVI6IDM0OTYyLAogICAgICAgIEVMRU1FTlRfQVJSQVlfQlVGRkVSOiAzNDk2MywKICAgICAgICBBUlJBWV9CVUZGRVJfQklORElORzogMzQ5NjQsCiAgICAgICAgRUxFTUVOVF9BUlJBWV9CVUZGRVJfQklORElORzogMzQ5NjUsCiAgICAgICAgU1RSRUFNX0RSQVc6IDM1MDQwLAogICAgICAgIFNUQVRJQ19EUkFXOiAzNTA0NCwKICAgICAgICBEWU5BTUlDX0RSQVc6IDM1MDQ4LAogICAgICAgIEJVRkZFUl9TSVpFOiAzNDY2MCwKICAgICAgICBCVUZGRVJfVVNBR0U6IDM0NjYxLAogICAgICAgIENVUlJFTlRfVkVSVEVYX0FUVFJJQjogMzQzNDIsCiAgICAgICAgRlJPTlQ6IDEwMjgsCiAgICAgICAgQkFDSzogMTAyOSwKICAgICAgICBGUk9OVF9BTkRfQkFDSzogMTAzMiwKICAgICAgICBDVUxMX0ZBQ0U6IDI4ODQsCiAgICAgICAgQkxFTkQ6IDMwNDIsCiAgICAgICAgRElUSEVSOiAzMDI0LAogICAgICAgIFNURU5DSUxfVEVTVDogMjk2MCwKICAgICAgICBERVBUSF9URVNUOiAyOTI5LAogICAgICAgIFNDSVNTT1JfVEVTVDogMzA4OSwKICAgICAgICBQT0xZR09OX09GRlNFVF9GSUxMOiAzMjgyMywKICAgICAgICBTQU1QTEVfQUxQSEFfVE9fQ09WRVJBR0U6IDMyOTI2LAogICAgICAgIFNBTVBMRV9DT1ZFUkFHRTogMzI5MjgsCiAgICAgICAgTk9fRVJST1I6IDAsCiAgICAgICAgSU5WQUxJRF9FTlVNOiAxMjgwLAogICAgICAgIElOVkFMSURfVkFMVUU6IDEyODEsCiAgICAgICAgSU5WQUxJRF9PUEVSQVRJT046IDEyODIsCiAgICAgICAgT1VUX09GX01FTU9SWTogMTI4NSwKICAgICAgICBDVzogMjMwNCwKICAgICAgICBDQ1c6IDIzMDUsCiAgICAgICAgTElORV9XSURUSDogMjg0OSwKICAgICAgICBBTElBU0VEX1BPSU5UX1NJWkVfUkFOR0U6IDMzOTAxLAogICAgICAgIEFMSUFTRURfTElORV9XSURUSF9SQU5HRTogMzM5MDIsCiAgICAgICAgQ1VMTF9GQUNFX01PREU6IDI4ODUsCiAgICAgICAgRlJPTlRfRkFDRTogMjg4NiwKICAgICAgICBERVBUSF9SQU5HRTogMjkyOCwKICAgICAgICBERVBUSF9XUklURU1BU0s6IDI5MzAsCiAgICAgICAgREVQVEhfQ0xFQVJfVkFMVUU6IDI5MzEsCiAgICAgICAgREVQVEhfRlVOQzogMjkzMiwKICAgICAgICBTVEVOQ0lMX0NMRUFSX1ZBTFVFOiAyOTYxLAogICAgICAgIFNURU5DSUxfRlVOQzogMjk2MiwKICAgICAgICBTVEVOQ0lMX0ZBSUw6IDI5NjQsCiAgICAgICAgU1RFTkNJTF9QQVNTX0RFUFRIX0ZBSUw6IDI5NjUsCiAgICAgICAgU1RFTkNJTF9QQVNTX0RFUFRIX1BBU1M6IDI5NjYsCiAgICAgICAgU1RFTkNJTF9SRUY6IDI5NjcsCiAgICAgICAgU1RFTkNJTF9WQUxVRV9NQVNLOiAyOTYzLAogICAgICAgIFNURU5DSUxfV1JJVEVNQVNLOiAyOTY4LAogICAgICAgIFNURU5DSUxfQkFDS19GVU5DOiAzNDgxNiwKICAgICAgICBTVEVOQ0lMX0JBQ0tfRkFJTDogMzQ4MTcsCiAgICAgICAgU1RFTkNJTF9CQUNLX1BBU1NfREVQVEhfRkFJTDogMzQ4MTgsCiAgICAgICAgU1RFTkNJTF9CQUNLX1BBU1NfREVQVEhfUEFTUzogMzQ4MTksCiAgICAgICAgU1RFTkNJTF9CQUNLX1JFRjogMzYwMDMsCiAgICAgICAgU1RFTkNJTF9CQUNLX1ZBTFVFX01BU0s6IDM2MDA0LAogICAgICAgIFNURU5DSUxfQkFDS19XUklURU1BU0s6IDM2MDA1LAogICAgICAgIFZJRVdQT1JUOiAyOTc4LAogICAgICAgIFNDSVNTT1JfQk9YOiAzMDg4LAogICAgICAgIENPTE9SX0NMRUFSX1ZBTFVFOiAzMTA2LAogICAgICAgIENPTE9SX1dSSVRFTUFTSzogMzEwNywKICAgICAgICBVTlBBQ0tfQUxJR05NRU5UOiAzMzE3LAogICAgICAgIFBBQ0tfQUxJR05NRU5UOiAzMzMzLAogICAgICAgIE1BWF9URVhUVVJFX1NJWkU6IDMzNzksCiAgICAgICAgTUFYX1ZJRVdQT1JUX0RJTVM6IDMzODYsCiAgICAgICAgU1VCUElYRUxfQklUUzogMzQwOCwKICAgICAgICBSRURfQklUUzogMzQxMCwKICAgICAgICBHUkVFTl9CSVRTOiAzNDExLAogICAgICAgIEJMVUVfQklUUzogMzQxMiwKICAgICAgICBBTFBIQV9CSVRTOiAzNDEzLAogICAgICAgIERFUFRIX0JJVFM6IDM0MTQsCiAgICAgICAgU1RFTkNJTF9CSVRTOiAzNDE1LAogICAgICAgIFBPTFlHT05fT0ZGU0VUX1VOSVRTOiAxMDc1MiwKICAgICAgICBQT0xZR09OX09GRlNFVF9GQUNUT1I6IDMyODI0LAogICAgICAgIFRFWFRVUkVfQklORElOR18yRDogMzI4NzMsCiAgICAgICAgU0FNUExFX0JVRkZFUlM6IDMyOTM2LAogICAgICAgIFNBTVBMRVM6IDMyOTM3LAogICAgICAgIFNBTVBMRV9DT1ZFUkFHRV9WQUxVRTogMzI5MzgsCiAgICAgICAgU0FNUExFX0NPVkVSQUdFX0lOVkVSVDogMzI5MzksCiAgICAgICAgQ09NUFJFU1NFRF9URVhUVVJFX0ZPUk1BVFM6IDM0NDY3LAogICAgICAgIERPTlRfQ0FSRTogNDM1MiwKICAgICAgICBGQVNURVNUOiA0MzUzLAogICAgICAgIE5JQ0VTVDogNDM1NCwKICAgICAgICBHRU5FUkFURV9NSVBNQVBfSElOVDogMzMxNzAsCiAgICAgICAgQllURTogNTEyMCwKICAgICAgICBVTlNJR05FRF9CWVRFOiA1MTIxLAogICAgICAgIFNIT1JUOiA1MTIyLAogICAgICAgIFVOU0lHTkVEX1NIT1JUOiA1MTIzLAogICAgICAgIElOVDogNTEyNCwKICAgICAgICBVTlNJR05FRF9JTlQ6IDUxMjUsCiAgICAgICAgRkxPQVQ6IDUxMjYsCiAgICAgICAgREVQVEhfQ09NUE9ORU5UOiA2NDAyLAogICAgICAgIEFMUEhBOiA2NDA2LAogICAgICAgIFJHQjogNjQwNywKICAgICAgICBSR0JBOiA2NDA4LAogICAgICAgIExVTUlOQU5DRTogNjQwOSwKICAgICAgICBMVU1JTkFOQ0VfQUxQSEE6IDY0MTAsCiAgICAgICAgVU5TSUdORURfU0hPUlRfNF80XzRfNDogMzI4MTksCiAgICAgICAgVU5TSUdORURfU0hPUlRfNV81XzVfMTogMzI4MjAsCiAgICAgICAgVU5TSUdORURfU0hPUlRfNV82XzU6IDMzNjM1LAogICAgICAgIEZSQUdNRU5UX1NIQURFUjogMzU2MzIsCiAgICAgICAgVkVSVEVYX1NIQURFUjogMzU2MzMsCiAgICAgICAgTUFYX1ZFUlRFWF9BVFRSSUJTOiAzNDkyMSwKICAgICAgICBNQVhfVkVSVEVYX1VOSUZPUk1fVkVDVE9SUzogMzYzNDcsCiAgICAgICAgTUFYX1ZBUllJTkdfVkVDVE9SUzogMzYzNDgsCiAgICAgICAgTUFYX0NPTUJJTkVEX1RFWFRVUkVfSU1BR0VfVU5JVFM6IDM1NjYxLAogICAgICAgIE1BWF9WRVJURVhfVEVYVFVSRV9JTUFHRV9VTklUUzogMzU2NjAsCiAgICAgICAgTUFYX1RFWFRVUkVfSU1BR0VfVU5JVFM6IDM0OTMwLAogICAgICAgIE1BWF9GUkFHTUVOVF9VTklGT1JNX1ZFQ1RPUlM6IDM2MzQ5LAogICAgICAgIFNIQURFUl9UWVBFOiAzNTY2MywKICAgICAgICBERUxFVEVfU1RBVFVTOiAzNTcxMiwKICAgICAgICBMSU5LX1NUQVRVUzogMzU3MTQsCiAgICAgICAgVkFMSURBVEVfU1RBVFVTOiAzNTcxNSwKICAgICAgICBBVFRBQ0hFRF9TSEFERVJTOiAzNTcxNywKICAgICAgICBBQ1RJVkVfVU5JRk9STVM6IDM1NzE4LAogICAgICAgIEFDVElWRV9BVFRSSUJVVEVTOiAzNTcyMSwKICAgICAgICBTSEFESU5HX0xBTkdVQUdFX1ZFUlNJT046IDM1NzI0LAogICAgICAgIENVUlJFTlRfUFJPR1JBTTogMzU3MjUsCiAgICAgICAgTkVWRVI6IDUxMiwKICAgICAgICBMRVNTOiA1MTMsCiAgICAgICAgRVFVQUw6IDUxNCwKICAgICAgICBMRVFVQUw6IDUxNSwKICAgICAgICBHUkVBVEVSOiA1MTYsCiAgICAgICAgTk9URVFVQUw6IDUxNywKICAgICAgICBHRVFVQUw6IDUxOCwKICAgICAgICBBTFdBWVM6IDUxOSwKICAgICAgICBLRUVQOiA3NjgwLAogICAgICAgIFJFUExBQ0U6IDc2ODEsCiAgICAgICAgSU5DUjogNzY4MiwKICAgICAgICBERUNSOiA3NjgzLAogICAgICAgIElOVkVSVDogNTM4NiwKICAgICAgICBJTkNSX1dSQVA6IDM0MDU1LAogICAgICAgIERFQ1JfV1JBUDogMzQwNTYsCiAgICAgICAgVkVORE9SOiA3OTM2LAogICAgICAgIFJFTkRFUkVSOiA3OTM3LAogICAgICAgIFZFUlNJT046IDc5MzgsCiAgICAgICAgTkVBUkVTVDogOTcyOCwKICAgICAgICBMSU5FQVI6IDk3MjksCiAgICAgICAgTkVBUkVTVF9NSVBNQVBfTkVBUkVTVDogOTk4NCwKICAgICAgICBMSU5FQVJfTUlQTUFQX05FQVJFU1Q6IDk5ODUsCiAgICAgICAgTkVBUkVTVF9NSVBNQVBfTElORUFSOiA5OTg2LAogICAgICAgIExJTkVBUl9NSVBNQVBfTElORUFSOiA5OTg3LAogICAgICAgIFRFWFRVUkVfTUFHX0ZJTFRFUjogMTAyNDAsCiAgICAgICAgVEVYVFVSRV9NSU5fRklMVEVSOiAxMDI0MSwKICAgICAgICBURVhUVVJFX1dSQVBfUzogMTAyNDIsCiAgICAgICAgVEVYVFVSRV9XUkFQX1Q6IDEwMjQzLAogICAgICAgIFRFWFRVUkVfMkQ6IDM1NTMsCiAgICAgICAgVEVYVFVSRTogNTg5MCwKICAgICAgICBURVhUVVJFX0NVQkVfTUFQOiAzNDA2NywKICAgICAgICBURVhUVVJFX0JJTkRJTkdfQ1VCRV9NQVA6IDM0MDY4LAogICAgICAgIFRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWDogMzQwNjksCiAgICAgICAgVEVYVFVSRV9DVUJFX01BUF9ORUdBVElWRV9YOiAzNDA3MCwKICAgICAgICBURVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1k6IDM0MDcxLAogICAgICAgIFRFWFRVUkVfQ1VCRV9NQVBfTkVHQVRJVkVfWTogMzQwNzIsCiAgICAgICAgVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9aOiAzNDA3MywKICAgICAgICBURVhUVVJFX0NVQkVfTUFQX05FR0FUSVZFX1o6IDM0MDc0LAogICAgICAgIE1BWF9DVUJFX01BUF9URVhUVVJFX1NJWkU6IDM0MDc2LAogICAgICAgIFRFWFRVUkUwOiAzMzk4NCwKICAgICAgICBURVhUVVJFMTogMzM5ODUsCiAgICAgICAgVEVYVFVSRTI6IDMzOTg2LAogICAgICAgIFRFWFRVUkUzOiAzMzk4NywKICAgICAgICBURVhUVVJFNDogMzM5ODgsCiAgICAgICAgVEVYVFVSRTU6IDMzOTg5LAogICAgICAgIFRFWFRVUkU2OiAzMzk5MCwKICAgICAgICBURVhUVVJFNzogMzM5OTEsCiAgICAgICAgVEVYVFVSRTg6IDMzOTkyLAogICAgICAgIFRFWFRVUkU5OiAzMzk5MywKICAgICAgICBURVhUVVJFMTA6IDMzOTk0LAogICAgICAgIFRFWFRVUkUxMTogMzM5OTUsCiAgICAgICAgVEVYVFVSRTEyOiAzMzk5NiwKICAgICAgICBURVhUVVJFMTM6IDMzOTk3LAogICAgICAgIFRFWFRVUkUxNDogMzM5OTgsCiAgICAgICAgVEVYVFVSRTE1OiAzMzk5OSwKICAgICAgICBURVhUVVJFMTY6IDM0ZTMsCiAgICAgICAgVEVYVFVSRTE3OiAzNDAwMSwKICAgICAgICBURVhUVVJFMTg6IDM0MDAyLAogICAgICAgIFRFWFRVUkUxOTogMzQwMDMsCiAgICAgICAgVEVYVFVSRTIwOiAzNDAwNCwKICAgICAgICBURVhUVVJFMjE6IDM0MDA1LAogICAgICAgIFRFWFRVUkUyMjogMzQwMDYsCiAgICAgICAgVEVYVFVSRTIzOiAzNDAwNywKICAgICAgICBURVhUVVJFMjQ6IDM0MDA4LAogICAgICAgIFRFWFRVUkUyNTogMzQwMDksCiAgICAgICAgVEVYVFVSRTI2OiAzNDAxMCwKICAgICAgICBURVhUVVJFMjc6IDM0MDExLAogICAgICAgIFRFWFRVUkUyODogMzQwMTIsCiAgICAgICAgVEVYVFVSRTI5OiAzNDAxMywKICAgICAgICBURVhUVVJFMzA6IDM0MDE0LAogICAgICAgIFRFWFRVUkUzMTogMzQwMTUsCiAgICAgICAgQUNUSVZFX1RFWFRVUkU6IDM0MDE2LAogICAgICAgIFJFUEVBVDogMTA0OTcsCiAgICAgICAgQ0xBTVBfVE9fRURHRTogMzMwNzEsCiAgICAgICAgTUlSUk9SRURfUkVQRUFUOiAzMzY0OCwKICAgICAgICBGTE9BVF9WRUMyOiAzNTY2NCwKICAgICAgICBGTE9BVF9WRUMzOiAzNTY2NSwKICAgICAgICBGTE9BVF9WRUM0OiAzNTY2NiwKICAgICAgICBJTlRfVkVDMjogMzU2NjcsCiAgICAgICAgSU5UX1ZFQzM6IDM1NjY4LAogICAgICAgIElOVF9WRUM0OiAzNTY2OSwKICAgICAgICBCT09MOiAzNTY3MCwKICAgICAgICBCT09MX1ZFQzI6IDM1NjcxLAogICAgICAgIEJPT0xfVkVDMzogMzU2NzIsCiAgICAgICAgQk9PTF9WRUM0OiAzNTY3MywKICAgICAgICBGTE9BVF9NQVQyOiAzNTY3NCwKICAgICAgICBGTE9BVF9NQVQzOiAzNTY3NSwKICAgICAgICBGTE9BVF9NQVQ0OiAzNTY3NiwKICAgICAgICBTQU1QTEVSXzJEOiAzNTY3OCwKICAgICAgICBTQU1QTEVSX0NVQkU6IDM1NjgwLAogICAgICAgIFZFUlRFWF9BVFRSSUJfQVJSQVlfRU5BQkxFRDogMzQzMzgsCiAgICAgICAgVkVSVEVYX0FUVFJJQl9BUlJBWV9TSVpFOiAzNDMzOSwKICAgICAgICBWRVJURVhfQVRUUklCX0FSUkFZX1NUUklERTogMzQzNDAsCiAgICAgICAgVkVSVEVYX0FUVFJJQl9BUlJBWV9UWVBFOiAzNDM0MSwKICAgICAgICBWRVJURVhfQVRUUklCX0FSUkFZX05PUk1BTElaRUQ6IDM0OTIyLAogICAgICAgIFZFUlRFWF9BVFRSSUJfQVJSQVlfUE9JTlRFUjogMzQzNzMsCiAgICAgICAgVkVSVEVYX0FUVFJJQl9BUlJBWV9CVUZGRVJfQklORElORzogMzQ5NzUsCiAgICAgICAgSU1QTEVNRU5UQVRJT05fQ09MT1JfUkVBRF9UWVBFOiAzNTczOCwKICAgICAgICBJTVBMRU1FTlRBVElPTl9DT0xPUl9SRUFEX0ZPUk1BVDogMzU3MzksCiAgICAgICAgQ09NUElMRV9TVEFUVVM6IDM1NzEzLAogICAgICAgIExPV19GTE9BVDogMzYzMzYsCiAgICAgICAgTUVESVVNX0ZMT0FUOiAzNjMzNywKICAgICAgICBISUdIX0ZMT0FUOiAzNjMzOCwKICAgICAgICBMT1dfSU5UOiAzNjMzOSwKICAgICAgICBNRURJVU1fSU5UOiAzNjM0MCwKICAgICAgICBISUdIX0lOVDogMzYzNDEsCiAgICAgICAgRlJBTUVCVUZGRVI6IDM2MTYwLAogICAgICAgIFJFTkRFUkJVRkZFUjogMzYxNjEsCiAgICAgICAgUkdCQTQ6IDMyODU0LAogICAgICAgIFJHQjVfQTE6IDMyODU1LAogICAgICAgIFJHQjU2NTogMzYxOTQsCiAgICAgICAgREVQVEhfQ09NUE9ORU5UMTY6IDMzMTg5LAogICAgICAgIFNURU5DSUxfSU5ERVg6IDY0MDEsCiAgICAgICAgU1RFTkNJTF9JTkRFWDg6IDM2MTY4LAogICAgICAgIERFUFRIX1NURU5DSUw6IDM0MDQxLAogICAgICAgIFJFTkRFUkJVRkZFUl9XSURUSDogMzYxNjIsCiAgICAgICAgUkVOREVSQlVGRkVSX0hFSUdIVDogMzYxNjMsCiAgICAgICAgUkVOREVSQlVGRkVSX0lOVEVSTkFMX0ZPUk1BVDogMzYxNjQsCiAgICAgICAgUkVOREVSQlVGRkVSX1JFRF9TSVpFOiAzNjE3NiwKICAgICAgICBSRU5ERVJCVUZGRVJfR1JFRU5fU0laRTogMzYxNzcsCiAgICAgICAgUkVOREVSQlVGRkVSX0JMVUVfU0laRTogMzYxNzgsCiAgICAgICAgUkVOREVSQlVGRkVSX0FMUEhBX1NJWkU6IDM2MTc5LAogICAgICAgIFJFTkRFUkJVRkZFUl9ERVBUSF9TSVpFOiAzNjE4MCwKICAgICAgICBSRU5ERVJCVUZGRVJfU1RFTkNJTF9TSVpFOiAzNjE4MSwKICAgICAgICBGUkFNRUJVRkZFUl9BVFRBQ0hNRU5UX09CSkVDVF9UWVBFOiAzNjA0OCwKICAgICAgICBGUkFNRUJVRkZFUl9BVFRBQ0hNRU5UX09CSkVDVF9OQU1FOiAzNjA0OSwKICAgICAgICBGUkFNRUJVRkZFUl9BVFRBQ0hNRU5UX1RFWFRVUkVfTEVWRUw6IDM2MDUwLAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfVEVYVFVSRV9DVUJFX01BUF9GQUNFOiAzNjA1MSwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UMDogMzYwNjQsCiAgICAgICAgREVQVEhfQVRUQUNITUVOVDogMzYwOTYsCiAgICAgICAgU1RFTkNJTF9BVFRBQ0hNRU5UOiAzNjEyOCwKICAgICAgICBERVBUSF9TVEVOQ0lMX0FUVEFDSE1FTlQ6IDMzMzA2LAogICAgICAgIE5PTkU6IDAsCiAgICAgICAgRlJBTUVCVUZGRVJfQ09NUExFVEU6IDM2MDUzLAogICAgICAgIEZSQU1FQlVGRkVSX0lOQ09NUExFVEVfQVRUQUNITUVOVDogMzYwNTQsCiAgICAgICAgRlJBTUVCVUZGRVJfSU5DT01QTEVURV9NSVNTSU5HX0FUVEFDSE1FTlQ6IDM2MDU1LAogICAgICAgIEZSQU1FQlVGRkVSX0lOQ09NUExFVEVfRElNRU5TSU9OUzogMzYwNTcsCiAgICAgICAgRlJBTUVCVUZGRVJfVU5TVVBQT1JURUQ6IDM2MDYxLAogICAgICAgIEZSQU1FQlVGRkVSX0JJTkRJTkc6IDM2MDA2LAogICAgICAgIFJFTkRFUkJVRkZFUl9CSU5ESU5HOiAzNjAwNywKICAgICAgICBNQVhfUkVOREVSQlVGRkVSX1NJWkU6IDM0MDI0LAogICAgICAgIElOVkFMSURfRlJBTUVCVUZGRVJfT1BFUkFUSU9OOiAxMjg2LAogICAgICAgIFVOUEFDS19GTElQX1lfV0VCR0w6IDM3NDQwLAogICAgICAgIFVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTDogMzc0NDEsCiAgICAgICAgQ09OVEVYVF9MT1NUX1dFQkdMOiAzNzQ0MiwKICAgICAgICBVTlBBQ0tfQ09MT1JTUEFDRV9DT05WRVJTSU9OX1dFQkdMOiAzNzQ0MywKICAgICAgICBCUk9XU0VSX0RFRkFVTFRfV0VCR0w6IDM3NDQ0LAogICAgICAgIC8vIFdFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjCiAgICAgICAgQ09NUFJFU1NFRF9SR0JfUzNUQ19EWFQxX0VYVDogMzM3NzYsCiAgICAgICAgQ09NUFJFU1NFRF9SR0JBX1MzVENfRFhUMV9FWFQ6IDMzNzc3LAogICAgICAgIENPTVBSRVNTRURfUkdCQV9TM1RDX0RYVDNfRVhUOiAzMzc3OCwKICAgICAgICBDT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQ1X0VYVDogMzM3NzksCiAgICAgICAgLy8gV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjCiAgICAgICAgQ09NUFJFU1NFRF9SR0JfUFZSVENfNEJQUFYxX0lNRzogMzU4NDAsCiAgICAgICAgQ09NUFJFU1NFRF9SR0JfUFZSVENfMkJQUFYxX0lNRzogMzU4NDEsCiAgICAgICAgQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUc6IDM1ODQyLAogICAgICAgIENPTVBSRVNTRURfUkdCQV9QVlJUQ18yQlBQVjFfSU1HOiAzNTg0MywKICAgICAgICAvLyBXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfYXN0YwogICAgICAgIENPTVBSRVNTRURfUkdCQV9BU1RDXzR4NF9XRUJHTDogMzc4MDgsCiAgICAgICAgLy8gV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YzEKICAgICAgICBDT01QUkVTU0VEX1JHQl9FVEMxX1dFQkdMOiAzNjE5NiwKICAgICAgICAvLyBFWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9icHRjCiAgICAgICAgQ09NUFJFU1NFRF9SR0JBX0JQVENfVU5PUk06IDM2NDkyLAogICAgICAgIC8vIEVYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdAogICAgICAgIEhBTEZfRkxPQVRfT0VTOiAzNjE5MywKICAgICAgICAvLyBEZXNrdG9wIE9wZW5HTAogICAgICAgIERPVUJMRTogNTEzMCwKICAgICAgICAvLyBXZWJHTCAyCiAgICAgICAgUkVBRF9CVUZGRVI6IDMwNzQsCiAgICAgICAgVU5QQUNLX1JPV19MRU5HVEg6IDMzMTQsCiAgICAgICAgVU5QQUNLX1NLSVBfUk9XUzogMzMxNSwKICAgICAgICBVTlBBQ0tfU0tJUF9QSVhFTFM6IDMzMTYsCiAgICAgICAgUEFDS19ST1dfTEVOR1RIOiAzMzMwLAogICAgICAgIFBBQ0tfU0tJUF9ST1dTOiAzMzMxLAogICAgICAgIFBBQ0tfU0tJUF9QSVhFTFM6IDMzMzIsCiAgICAgICAgQ09MT1I6IDYxNDQsCiAgICAgICAgREVQVEg6IDYxNDUsCiAgICAgICAgU1RFTkNJTDogNjE0NiwKICAgICAgICBSRUQ6IDY0MDMsCiAgICAgICAgUkdCODogMzI4NDksCiAgICAgICAgUkdCQTg6IDMyODU2LAogICAgICAgIFJHQjEwX0EyOiAzMjg1NywKICAgICAgICBURVhUVVJFX0JJTkRJTkdfM0Q6IDMyODc0LAogICAgICAgIFVOUEFDS19TS0lQX0lNQUdFUzogMzI4NzcsCiAgICAgICAgVU5QQUNLX0lNQUdFX0hFSUdIVDogMzI4NzgsCiAgICAgICAgVEVYVFVSRV8zRDogMzI4NzksCiAgICAgICAgVEVYVFVSRV9XUkFQX1I6IDMyODgyLAogICAgICAgIE1BWF8zRF9URVhUVVJFX1NJWkU6IDMyODgzLAogICAgICAgIFVOU0lHTkVEX0lOVF8yXzEwXzEwXzEwX1JFVjogMzM2NDAsCiAgICAgICAgTUFYX0VMRU1FTlRTX1ZFUlRJQ0VTOiAzM2UzLAogICAgICAgIE1BWF9FTEVNRU5UU19JTkRJQ0VTOiAzMzAwMSwKICAgICAgICBURVhUVVJFX01JTl9MT0Q6IDMzMDgyLAogICAgICAgIFRFWFRVUkVfTUFYX0xPRDogMzMwODMsCiAgICAgICAgVEVYVFVSRV9CQVNFX0xFVkVMOiAzMzA4NCwKICAgICAgICBURVhUVVJFX01BWF9MRVZFTDogMzMwODUsCiAgICAgICAgTUlOOiAzMjc3NSwKICAgICAgICBNQVg6IDMyNzc2LAogICAgICAgIERFUFRIX0NPTVBPTkVOVDI0OiAzMzE5MCwKICAgICAgICBNQVhfVEVYVFVSRV9MT0RfQklBUzogMzQwNDUsCiAgICAgICAgVEVYVFVSRV9DT01QQVJFX01PREU6IDM0ODkyLAogICAgICAgIFRFWFRVUkVfQ09NUEFSRV9GVU5DOiAzNDg5MywKICAgICAgICBDVVJSRU5UX1FVRVJZOiAzNDkxNywKICAgICAgICBRVUVSWV9SRVNVTFQ6IDM0OTE4LAogICAgICAgIFFVRVJZX1JFU1VMVF9BVkFJTEFCTEU6IDM0OTE5LAogICAgICAgIFNUUkVBTV9SRUFEOiAzNTA0MSwKICAgICAgICBTVFJFQU1fQ09QWTogMzUwNDIsCiAgICAgICAgU1RBVElDX1JFQUQ6IDM1MDQ1LAogICAgICAgIFNUQVRJQ19DT1BZOiAzNTA0NiwKICAgICAgICBEWU5BTUlDX1JFQUQ6IDM1MDQ5LAogICAgICAgIERZTkFNSUNfQ09QWTogMzUwNTAsCiAgICAgICAgTUFYX0RSQVdfQlVGRkVSUzogMzQ4NTIsCiAgICAgICAgRFJBV19CVUZGRVIwOiAzNDg1MywKICAgICAgICBEUkFXX0JVRkZFUjE6IDM0ODU0LAogICAgICAgIERSQVdfQlVGRkVSMjogMzQ4NTUsCiAgICAgICAgRFJBV19CVUZGRVIzOiAzNDg1NiwKICAgICAgICBEUkFXX0JVRkZFUjQ6IDM0ODU3LAogICAgICAgIERSQVdfQlVGRkVSNTogMzQ4NTgsCiAgICAgICAgRFJBV19CVUZGRVI2OiAzNDg1OSwKICAgICAgICBEUkFXX0JVRkZFUjc6IDM0ODYwLAogICAgICAgIERSQVdfQlVGRkVSODogMzQ4NjEsCiAgICAgICAgRFJBV19CVUZGRVI5OiAzNDg2MiwKICAgICAgICBEUkFXX0JVRkZFUjEwOiAzNDg2MywKICAgICAgICBEUkFXX0JVRkZFUjExOiAzNDg2NCwKICAgICAgICBEUkFXX0JVRkZFUjEyOiAzNDg2NSwKICAgICAgICBEUkFXX0JVRkZFUjEzOiAzNDg2NiwKICAgICAgICBEUkFXX0JVRkZFUjE0OiAzNDg2NywKICAgICAgICBEUkFXX0JVRkZFUjE1OiAzNDg2OCwKICAgICAgICBNQVhfRlJBR01FTlRfVU5JRk9STV9DT01QT05FTlRTOiAzNTY1NywKICAgICAgICBNQVhfVkVSVEVYX1VOSUZPUk1fQ09NUE9ORU5UUzogMzU2NTgsCiAgICAgICAgU0FNUExFUl8zRDogMzU2NzksCiAgICAgICAgU0FNUExFUl8yRF9TSEFET1c6IDM1NjgyLAogICAgICAgIEZSQUdNRU5UX1NIQURFUl9ERVJJVkFUSVZFX0hJTlQ6IDM1NzIzLAogICAgICAgIFBJWEVMX1BBQ0tfQlVGRkVSOiAzNTA1MSwKICAgICAgICBQSVhFTF9VTlBBQ0tfQlVGRkVSOiAzNTA1MiwKICAgICAgICBQSVhFTF9QQUNLX0JVRkZFUl9CSU5ESU5HOiAzNTA1MywKICAgICAgICBQSVhFTF9VTlBBQ0tfQlVGRkVSX0JJTkRJTkc6IDM1MDU1LAogICAgICAgIEZMT0FUX01BVDJ4MzogMzU2ODUsCiAgICAgICAgRkxPQVRfTUFUMng0OiAzNTY4NiwKICAgICAgICBGTE9BVF9NQVQzeDI6IDM1Njg3LAogICAgICAgIEZMT0FUX01BVDN4NDogMzU2ODgsCiAgICAgICAgRkxPQVRfTUFUNHgyOiAzNTY4OSwKICAgICAgICBGTE9BVF9NQVQ0eDM6IDM1NjkwLAogICAgICAgIFNSR0I6IDM1OTA0LAogICAgICAgIFNSR0I4OiAzNTkwNSwKICAgICAgICBTUkdCOF9BTFBIQTg6IDM1OTA3LAogICAgICAgIENPTVBBUkVfUkVGX1RPX1RFWFRVUkU6IDM0ODk0LAogICAgICAgIFJHQkEzMkY6IDM0ODM2LAogICAgICAgIFJHQjMyRjogMzQ4MzcsCiAgICAgICAgUkdCQTE2RjogMzQ4NDIsCiAgICAgICAgUkdCMTZGOiAzNDg0MywKICAgICAgICBWRVJURVhfQVRUUklCX0FSUkFZX0lOVEVHRVI6IDM1MDY5LAogICAgICAgIE1BWF9BUlJBWV9URVhUVVJFX0xBWUVSUzogMzUwNzEsCiAgICAgICAgTUlOX1BST0dSQU1fVEVYRUxfT0ZGU0VUOiAzNTA3NiwKICAgICAgICBNQVhfUFJPR1JBTV9URVhFTF9PRkZTRVQ6IDM1MDc3LAogICAgICAgIE1BWF9WQVJZSU5HX0NPTVBPTkVOVFM6IDM1NjU5LAogICAgICAgIFRFWFRVUkVfMkRfQVJSQVk6IDM1ODY2LAogICAgICAgIFRFWFRVUkVfQklORElOR18yRF9BUlJBWTogMzU4NjksCiAgICAgICAgUjExRl9HMTFGX0IxMEY6IDM1ODk4LAogICAgICAgIFVOU0lHTkVEX0lOVF8xMEZfMTFGXzExRl9SRVY6IDM1ODk5LAogICAgICAgIFJHQjlfRTU6IDM1OTAxLAogICAgICAgIFVOU0lHTkVEX0lOVF81XzlfOV85X1JFVjogMzU5MDIsCiAgICAgICAgVFJBTlNGT1JNX0ZFRURCQUNLX0JVRkZFUl9NT0RFOiAzNTk2NywKICAgICAgICBNQVhfVFJBTlNGT1JNX0ZFRURCQUNLX1NFUEFSQVRFX0NPTVBPTkVOVFM6IDM1OTY4LAogICAgICAgIFRSQU5TRk9STV9GRUVEQkFDS19WQVJZSU5HUzogMzU5NzEsCiAgICAgICAgVFJBTlNGT1JNX0ZFRURCQUNLX0JVRkZFUl9TVEFSVDogMzU5NzIsCiAgICAgICAgVFJBTlNGT1JNX0ZFRURCQUNLX0JVRkZFUl9TSVpFOiAzNTk3MywKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfUFJJTUlUSVZFU19XUklUVEVOOiAzNTk3NiwKICAgICAgICBSQVNURVJJWkVSX0RJU0NBUkQ6IDM1OTc3LAogICAgICAgIE1BWF9UUkFOU0ZPUk1fRkVFREJBQ0tfSU5URVJMRUFWRURfQ09NUE9ORU5UUzogMzU5NzgsCiAgICAgICAgTUFYX1RSQU5TRk9STV9GRUVEQkFDS19TRVBBUkFURV9BVFRSSUJTOiAzNTk3OSwKICAgICAgICBJTlRFUkxFQVZFRF9BVFRSSUJTOiAzNTk4MCwKICAgICAgICBTRVBBUkFURV9BVFRSSUJTOiAzNTk4MSwKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfQlVGRkVSOiAzNTk4MiwKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfQlVGRkVSX0JJTkRJTkc6IDM1OTgzLAogICAgICAgIFJHQkEzMlVJOiAzNjIwOCwKICAgICAgICBSR0IzMlVJOiAzNjIwOSwKICAgICAgICBSR0JBMTZVSTogMzYyMTQsCiAgICAgICAgUkdCMTZVSTogMzYyMTUsCiAgICAgICAgUkdCQThVSTogMzYyMjAsCiAgICAgICAgUkdCOFVJOiAzNjIyMSwKICAgICAgICBSR0JBMzJJOiAzNjIyNiwKICAgICAgICBSR0IzMkk6IDM2MjI3LAogICAgICAgIFJHQkExNkk6IDM2MjMyLAogICAgICAgIFJHQjE2STogMzYyMzMsCiAgICAgICAgUkdCQThJOiAzNjIzOCwKICAgICAgICBSR0I4STogMzYyMzksCiAgICAgICAgUkVEX0lOVEVHRVI6IDM2MjQ0LAogICAgICAgIFJHQl9JTlRFR0VSOiAzNjI0OCwKICAgICAgICBSR0JBX0lOVEVHRVI6IDM2MjQ5LAogICAgICAgIFNBTVBMRVJfMkRfQVJSQVk6IDM2Mjg5LAogICAgICAgIFNBTVBMRVJfMkRfQVJSQVlfU0hBRE9XOiAzNjI5MiwKICAgICAgICBTQU1QTEVSX0NVQkVfU0hBRE9XOiAzNjI5MywKICAgICAgICBVTlNJR05FRF9JTlRfVkVDMjogMzYyOTQsCiAgICAgICAgVU5TSUdORURfSU5UX1ZFQzM6IDM2Mjk1LAogICAgICAgIFVOU0lHTkVEX0lOVF9WRUM0OiAzNjI5NiwKICAgICAgICBJTlRfU0FNUExFUl8yRDogMzYyOTgsCiAgICAgICAgSU5UX1NBTVBMRVJfM0Q6IDM2Mjk5LAogICAgICAgIElOVF9TQU1QTEVSX0NVQkU6IDM2MzAwLAogICAgICAgIElOVF9TQU1QTEVSXzJEX0FSUkFZOiAzNjMwMywKICAgICAgICBVTlNJR05FRF9JTlRfU0FNUExFUl8yRDogMzYzMDYsCiAgICAgICAgVU5TSUdORURfSU5UX1NBTVBMRVJfM0Q6IDM2MzA3LAogICAgICAgIFVOU0lHTkVEX0lOVF9TQU1QTEVSX0NVQkU6IDM2MzA4LAogICAgICAgIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEX0FSUkFZOiAzNjMxMSwKICAgICAgICBERVBUSF9DT01QT05FTlQzMkY6IDM2MDEyLAogICAgICAgIERFUFRIMzJGX1NURU5DSUw4OiAzNjAxMywKICAgICAgICBGTE9BVF8zMl9VTlNJR05FRF9JTlRfMjRfOF9SRVY6IDM2MjY5LAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfQ09MT1JfRU5DT0RJTkc6IDMzMjk2LAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfQ09NUE9ORU5UX1RZUEU6IDMzMjk3LAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfUkVEX1NJWkU6IDMzMjk4LAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfR1JFRU5fU0laRTogMzMyOTksCiAgICAgICAgRlJBTUVCVUZGRVJfQVRUQUNITUVOVF9CTFVFX1NJWkU6IDMzMzAwLAogICAgICAgIEZSQU1FQlVGRkVSX0FUVEFDSE1FTlRfQUxQSEFfU0laRTogMzMzMDEsCiAgICAgICAgRlJBTUVCVUZGRVJfQVRUQUNITUVOVF9ERVBUSF9TSVpFOiAzMzMwMiwKICAgICAgICBGUkFNRUJVRkZFUl9BVFRBQ0hNRU5UX1NURU5DSUxfU0laRTogMzMzMDMsCiAgICAgICAgRlJBTUVCVUZGRVJfREVGQVVMVDogMzMzMDQsCiAgICAgICAgVU5TSUdORURfSU5UXzI0Xzg6IDM0MDQyLAogICAgICAgIERFUFRIMjRfU1RFTkNJTDg6IDM1MDU2LAogICAgICAgIFVOU0lHTkVEX05PUk1BTElaRUQ6IDM1ODYzLAogICAgICAgIERSQVdfRlJBTUVCVUZGRVJfQklORElORzogMzYwMDYsCiAgICAgICAgLy8gU2FtZSBhcyBGUkFNRUJVRkZFUl9CSU5ESU5HCiAgICAgICAgUkVBRF9GUkFNRUJVRkZFUjogMzYwMDgsCiAgICAgICAgRFJBV19GUkFNRUJVRkZFUjogMzYwMDksCiAgICAgICAgUkVBRF9GUkFNRUJVRkZFUl9CSU5ESU5HOiAzNjAxMCwKICAgICAgICBSRU5ERVJCVUZGRVJfU0FNUExFUzogMzYwMTEsCiAgICAgICAgRlJBTUVCVUZGRVJfQVRUQUNITUVOVF9URVhUVVJFX0xBWUVSOiAzNjA1MiwKICAgICAgICBNQVhfQ09MT1JfQVRUQUNITUVOVFM6IDM2MDYzLAogICAgICAgIENPTE9SX0FUVEFDSE1FTlQxOiAzNjA2NSwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UMjogMzYwNjYsCiAgICAgICAgQ09MT1JfQVRUQUNITUVOVDM6IDM2MDY3LAogICAgICAgIENPTE9SX0FUVEFDSE1FTlQ0OiAzNjA2OCwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UNTogMzYwNjksCiAgICAgICAgQ09MT1JfQVRUQUNITUVOVDY6IDM2MDcwLAogICAgICAgIENPTE9SX0FUVEFDSE1FTlQ3OiAzNjA3MSwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UODogMzYwNzIsCiAgICAgICAgQ09MT1JfQVRUQUNITUVOVDk6IDM2MDczLAogICAgICAgIENPTE9SX0FUVEFDSE1FTlQxMDogMzYwNzQsCiAgICAgICAgQ09MT1JfQVRUQUNITUVOVDExOiAzNjA3NSwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UMTI6IDM2MDc2LAogICAgICAgIENPTE9SX0FUVEFDSE1FTlQxMzogMzYwNzcsCiAgICAgICAgQ09MT1JfQVRUQUNITUVOVDE0OiAzNjA3OCwKICAgICAgICBDT0xPUl9BVFRBQ0hNRU5UMTU6IDM2MDc5LAogICAgICAgIEZSQU1FQlVGRkVSX0lOQ09NUExFVEVfTVVMVElTQU1QTEU6IDM2MTgyLAogICAgICAgIE1BWF9TQU1QTEVTOiAzNjE4MywKICAgICAgICBIQUxGX0ZMT0FUOiA1MTMxLAogICAgICAgIFJHOiAzMzMxOSwKICAgICAgICBSR19JTlRFR0VSOiAzMzMyMCwKICAgICAgICBSODogMzMzMjEsCiAgICAgICAgUkc4OiAzMzMyMywKICAgICAgICBSMTZGOiAzMzMyNSwKICAgICAgICBSMzJGOiAzMzMyNiwKICAgICAgICBSRzE2RjogMzMzMjcsCiAgICAgICAgUkczMkY6IDMzMzI4LAogICAgICAgIFI4STogMzMzMjksCiAgICAgICAgUjhVSTogMzMzMzAsCiAgICAgICAgUjE2STogMzMzMzEsCiAgICAgICAgUjE2VUk6IDMzMzMyLAogICAgICAgIFIzMkk6IDMzMzMzLAogICAgICAgIFIzMlVJOiAzMzMzNCwKICAgICAgICBSRzhJOiAzMzMzNSwKICAgICAgICBSRzhVSTogMzMzMzYsCiAgICAgICAgUkcxNkk6IDMzMzM3LAogICAgICAgIFJHMTZVSTogMzMzMzgsCiAgICAgICAgUkczMkk6IDMzMzM5LAogICAgICAgIFJHMzJVSTogMzMzNDAsCiAgICAgICAgVkVSVEVYX0FSUkFZX0JJTkRJTkc6IDM0MjI5LAogICAgICAgIFI4X1NOT1JNOiAzNjc1NiwKICAgICAgICBSRzhfU05PUk06IDM2NzU3LAogICAgICAgIFJHQjhfU05PUk06IDM2NzU4LAogICAgICAgIFJHQkE4X1NOT1JNOiAzNjc1OSwKICAgICAgICBTSUdORURfTk9STUFMSVpFRDogMzY3NjQsCiAgICAgICAgQ09QWV9SRUFEX0JVRkZFUjogMzY2NjIsCiAgICAgICAgQ09QWV9XUklURV9CVUZGRVI6IDM2NjYzLAogICAgICAgIENPUFlfUkVBRF9CVUZGRVJfQklORElORzogMzY2NjIsCiAgICAgICAgLy8gU2FtZSBhcyBDT1BZX1JFQURfQlVGRkVSCiAgICAgICAgQ09QWV9XUklURV9CVUZGRVJfQklORElORzogMzY2NjMsCiAgICAgICAgLy8gU2FtZSBhcyBDT1BZX1dSSVRFX0JVRkZFUgogICAgICAgIFVOSUZPUk1fQlVGRkVSOiAzNTM0NSwKICAgICAgICBVTklGT1JNX0JVRkZFUl9CSU5ESU5HOiAzNTM2OCwKICAgICAgICBVTklGT1JNX0JVRkZFUl9TVEFSVDogMzUzNjksCiAgICAgICAgVU5JRk9STV9CVUZGRVJfU0laRTogMzUzNzAsCiAgICAgICAgTUFYX1ZFUlRFWF9VTklGT1JNX0JMT0NLUzogMzUzNzEsCiAgICAgICAgTUFYX0ZSQUdNRU5UX1VOSUZPUk1fQkxPQ0tTOiAzNTM3MywKICAgICAgICBNQVhfQ09NQklORURfVU5JRk9STV9CTE9DS1M6IDM1Mzc0LAogICAgICAgIE1BWF9VTklGT1JNX0JVRkZFUl9CSU5ESU5HUzogMzUzNzUsCiAgICAgICAgTUFYX1VOSUZPUk1fQkxPQ0tfU0laRTogMzUzNzYsCiAgICAgICAgTUFYX0NPTUJJTkVEX1ZFUlRFWF9VTklGT1JNX0NPTVBPTkVOVFM6IDM1Mzc3LAogICAgICAgIE1BWF9DT01CSU5FRF9GUkFHTUVOVF9VTklGT1JNX0NPTVBPTkVOVFM6IDM1Mzc5LAogICAgICAgIFVOSUZPUk1fQlVGRkVSX09GRlNFVF9BTElHTk1FTlQ6IDM1MzgwLAogICAgICAgIEFDVElWRV9VTklGT1JNX0JMT0NLUzogMzUzODIsCiAgICAgICAgVU5JRk9STV9UWVBFOiAzNTM4MywKICAgICAgICBVTklGT1JNX1NJWkU6IDM1Mzg0LAogICAgICAgIFVOSUZPUk1fQkxPQ0tfSU5ERVg6IDM1Mzg2LAogICAgICAgIFVOSUZPUk1fT0ZGU0VUOiAzNTM4NywKICAgICAgICBVTklGT1JNX0FSUkFZX1NUUklERTogMzUzODgsCiAgICAgICAgVU5JRk9STV9NQVRSSVhfU1RSSURFOiAzNTM4OSwKICAgICAgICBVTklGT1JNX0lTX1JPV19NQUpPUjogMzUzOTAsCiAgICAgICAgVU5JRk9STV9CTE9DS19CSU5ESU5HOiAzNTM5MSwKICAgICAgICBVTklGT1JNX0JMT0NLX0RBVEFfU0laRTogMzUzOTIsCiAgICAgICAgVU5JRk9STV9CTE9DS19BQ1RJVkVfVU5JRk9STVM6IDM1Mzk0LAogICAgICAgIFVOSUZPUk1fQkxPQ0tfQUNUSVZFX1VOSUZPUk1fSU5ESUNFUzogMzUzOTUsCiAgICAgICAgVU5JRk9STV9CTE9DS19SRUZFUkVOQ0VEX0JZX1ZFUlRFWF9TSEFERVI6IDM1Mzk2LAogICAgICAgIFVOSUZPUk1fQkxPQ0tfUkVGRVJFTkNFRF9CWV9GUkFHTUVOVF9TSEFERVI6IDM1Mzk4LAogICAgICAgIElOVkFMSURfSU5ERVg6IDQyOTQ5NjcyOTUsCiAgICAgICAgTUFYX1ZFUlRFWF9PVVRQVVRfQ09NUE9ORU5UUzogMzcxNTQsCiAgICAgICAgTUFYX0ZSQUdNRU5UX0lOUFVUX0NPTVBPTkVOVFM6IDM3MTU3LAogICAgICAgIE1BWF9TRVJWRVJfV0FJVF9USU1FT1VUOiAzNzEzNywKICAgICAgICBPQkpFQ1RfVFlQRTogMzcxMzgsCiAgICAgICAgU1lOQ19DT05ESVRJT046IDM3MTM5LAogICAgICAgIFNZTkNfU1RBVFVTOiAzNzE0MCwKICAgICAgICBTWU5DX0ZMQUdTOiAzNzE0MSwKICAgICAgICBTWU5DX0ZFTkNFOiAzNzE0MiwKICAgICAgICBTWU5DX0dQVV9DT01NQU5EU19DT01QTEVURTogMzcxNDMsCiAgICAgICAgVU5TSUdOQUxFRDogMzcxNDQsCiAgICAgICAgU0lHTkFMRUQ6IDM3MTQ1LAogICAgICAgIEFMUkVBRFlfU0lHTkFMRUQ6IDM3MTQ2LAogICAgICAgIFRJTUVPVVRfRVhQSVJFRDogMzcxNDcsCiAgICAgICAgQ09ORElUSU9OX1NBVElTRklFRDogMzcxNDgsCiAgICAgICAgV0FJVF9GQUlMRUQ6IDM3MTQ5LAogICAgICAgIFNZTkNfRkxVU0hfQ09NTUFORFNfQklUOiAxLAogICAgICAgIFZFUlRFWF9BVFRSSUJfQVJSQVlfRElWSVNPUjogMzUwNzAsCiAgICAgICAgQU5ZX1NBTVBMRVNfUEFTU0VEOiAzNTg4NywKICAgICAgICBBTllfU0FNUExFU19QQVNTRURfQ09OU0VSVkFUSVZFOiAzNjIwMiwKICAgICAgICBTQU1QTEVSX0JJTkRJTkc6IDM1MDk3LAogICAgICAgIFJHQjEwX0EyVUk6IDM2OTc1LAogICAgICAgIElOVF8yXzEwXzEwXzEwX1JFVjogMzYyNTUsCiAgICAgICAgVFJBTlNGT1JNX0ZFRURCQUNLOiAzNjM4NiwKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfUEFVU0VEOiAzNjM4NywKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfQUNUSVZFOiAzNjM4OCwKICAgICAgICBUUkFOU0ZPUk1fRkVFREJBQ0tfQklORElORzogMzYzODksCiAgICAgICAgQ09NUFJFU1NFRF9SMTFfRUFDOiAzNzQ4OCwKICAgICAgICBDT01QUkVTU0VEX1NJR05FRF9SMTFfRUFDOiAzNzQ4OSwKICAgICAgICBDT01QUkVTU0VEX1JHMTFfRUFDOiAzNzQ5MCwKICAgICAgICBDT01QUkVTU0VEX1NJR05FRF9SRzExX0VBQzogMzc0OTEsCiAgICAgICAgQ09NUFJFU1NFRF9SR0I4X0VUQzI6IDM3NDkyLAogICAgICAgIENPTVBSRVNTRURfU1JHQjhfRVRDMjogMzc0OTMsCiAgICAgICAgQ09NUFJFU1NFRF9SR0I4X1BVTkNIVEhST1VHSF9BTFBIQTFfRVRDMjogMzc0OTQsCiAgICAgICAgQ09NUFJFU1NFRF9TUkdCOF9QVU5DSFRIUk9VR0hfQUxQSEExX0VUQzI6IDM3NDk1LAogICAgICAgIENPTVBSRVNTRURfUkdCQThfRVRDMl9FQUM6IDM3NDk2LAogICAgICAgIENPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0VUQzJfRUFDOiAzNzQ5NywKICAgICAgICBURVhUVVJFX0lNTVVUQUJMRV9GT1JNQVQ6IDM3MTY3LAogICAgICAgIE1BWF9FTEVNRU5UX0lOREVYOiAzNjIwMywKICAgICAgICBURVhUVVJFX0lNTVVUQUJMRV9MRVZFTFM6IDMzNTAzLAogICAgICAgIC8vIEV4dGVuc2lvbnMKICAgICAgICBNQVhfVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQ6IDM0MDQ3CiAgICAgIH07CiAgICAgIE9iamVjdC5mcmVlemUoV2ViR0xDb25zdGFudHMpOwogICAgICBXZWJHTENvbnN0YW50c19kZWZhdWx0ID0gV2ViR0xDb25zdGFudHM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Db21wb25lbnREYXRhdHlwZS5qcwogIHZhciBDb21wb25lbnREYXRhdHlwZSwgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdDsKICB2YXIgaW5pdF9Db21wb25lbnREYXRhdHlwZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29tcG9uZW50RGF0YXR5cGUuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X1dlYkdMQ29uc3RhbnRzKCk7CiAgICAgIENvbXBvbmVudERhdGF0eXBlID0gewogICAgICAgIC8qKgogICAgICAgICAqIDgtYml0IHNpZ25lZCBieXRlIGNvcnJlc3BvbmRpbmcgdG8gPGNvZGU+Z2wuQllURTwvY29kZT4gYW5kIHRoZSB0eXBlCiAgICAgICAgICogb2YgYW4gZWxlbWVudCBpbiA8Y29kZT5JbnQ4QXJyYXk8L2NvZGU+LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBCWVRFOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkJZVEUsCiAgICAgICAgLyoqCiAgICAgICAgICogOC1iaXQgdW5zaWduZWQgYnl0ZSBjb3JyZXNwb25kaW5nIHRvIDxjb2RlPlVOU0lHTkVEX0JZVEU8L2NvZGU+IGFuZCB0aGUgdHlwZQogICAgICAgICAqIG9mIGFuIGVsZW1lbnQgaW4gPGNvZGU+VWludDhBcnJheTwvY29kZT4uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFVOU0lHTkVEX0JZVEU6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICAvKioKICAgICAgICAgKiAxNi1iaXQgc2lnbmVkIHNob3J0IGNvcnJlc3BvbmRpbmcgdG8gPGNvZGU+U0hPUlQ8L2NvZGU+IGFuZCB0aGUgdHlwZQogICAgICAgICAqIG9mIGFuIGVsZW1lbnQgaW4gPGNvZGU+SW50MTZBcnJheTwvY29kZT4uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFNIT1JUOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlNIT1JULAogICAgICAgIC8qKgogICAgICAgICAqIDE2LWJpdCB1bnNpZ25lZCBzaG9ydCBjb3JyZXNwb25kaW5nIHRvIDxjb2RlPlVOU0lHTkVEX1NIT1JUPC9jb2RlPiBhbmQgdGhlIHR5cGUKICAgICAgICAgKiBvZiBhbiBlbGVtZW50IGluIDxjb2RlPlVpbnQxNkFycmF5PC9jb2RlPi4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgVU5TSUdORURfU0hPUlQ6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfU0hPUlQsCiAgICAgICAgLyoqCiAgICAgICAgICogMzItYml0IHNpZ25lZCBpbnQgY29ycmVzcG9uZGluZyB0byA8Y29kZT5JTlQ8L2NvZGU+IGFuZCB0aGUgdHlwZQogICAgICAgICAqIG9mIGFuIGVsZW1lbnQgaW4gPGNvZGU+SW50MzJBcnJheTwvY29kZT4uCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyT2YgQ29tcG9uZW50RGF0YXR5cGUKICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgSU5UOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LklOVCwKICAgICAgICAvKioKICAgICAgICAgKiAzMi1iaXQgdW5zaWduZWQgaW50IGNvcnJlc3BvbmRpbmcgdG8gPGNvZGU+VU5TSUdORURfSU5UPC9jb2RlPiBhbmQgdGhlIHR5cGUKICAgICAgICAgKiBvZiBhbiBlbGVtZW50IGluIDxjb2RlPlVpbnQzMkFycmF5PC9jb2RlPi4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJPZiBDb21wb25lbnREYXRhdHlwZQogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBVTlNJR05FRF9JTlQ6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfSU5ULAogICAgICAgIC8qKgogICAgICAgICAqIDMyLWJpdCBmbG9hdGluZy1wb2ludCBjb3JyZXNwb25kaW5nIHRvIDxjb2RlPkZMT0FUPC9jb2RlPiBhbmQgdGhlIHR5cGUKICAgICAgICAgKiBvZiBhbiBlbGVtZW50IGluIDxjb2RlPkZsb2F0MzJBcnJheTwvY29kZT4uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIEZMT0FUOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkZMT0FULAogICAgICAgIC8qKgogICAgICAgICAqIDY0LWJpdCBmbG9hdGluZy1wb2ludCBjb3JyZXNwb25kaW5nIHRvIDxjb2RlPmdsLkRPVUJMRTwvY29kZT4gKGluIERlc2t0b3AgT3BlbkdMOwogICAgICAgICAqIHRoaXMgaXMgbm90IHN1cHBvcnRlZCBpbiBXZWJHTCwgYW5kIGlzIGVtdWxhdGVkIGluIENlc2l1bSB2aWEge0BsaW5rIEdlb21ldHJ5UGlwZWxpbmUuZW5jb2RlQXR0cmlidXRlfSkKICAgICAgICAgKiBhbmQgdGhlIHR5cGUgb2YgYW4gZWxlbWVudCBpbiA8Y29kZT5GbG9hdDY0QXJyYXk8L2NvZGU+LgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlck9mIENvbXBvbmVudERhdGF0eXBlCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqIEBkZWZhdWx0IDB4MTQwQQogICAgICAgICAqLwogICAgICAgIERPVUJMRTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5ET1VCTEUKICAgICAgfTsKICAgICAgQ29tcG9uZW50RGF0YXR5cGUuZ2V0U2l6ZUluQnl0ZXMgPSBmdW5jdGlvbihjb21wb25lbnREYXRhdHlwZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNvbXBvbmVudERhdGF0eXBlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBzd2l0Y2ggKGNvbXBvbmVudERhdGF0eXBlKSB7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLkJZVEU6CiAgICAgICAgICAgIHJldHVybiBJbnQ4QXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0JZVEU6CiAgICAgICAgICAgIHJldHVybiBVaW50OEFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5TSE9SVDoKICAgICAgICAgICAgcmV0dXJuIEludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOgogICAgICAgICAgICByZXR1cm4gVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLklOVDoKICAgICAgICAgICAgcmV0dXJuIEludDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0lOVDoKICAgICAgICAgICAgcmV0dXJuIFVpbnQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5GTE9BVDoKICAgICAgICAgICAgcmV0dXJuIEZsb2F0MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVDsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuRE9VQkxFOgogICAgICAgICAgICByZXR1cm4gRmxvYXQ2NEFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICAgICAgLy8+PmluY2x1ZGVTdGFydCgnZGVidWcnLCBwcmFnbWFzLmRlYnVnKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJjb21wb25lbnREYXRhdHlwZSBpcyBub3QgYSB2YWxpZCB2YWx1ZS4iKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIENvbXBvbmVudERhdGF0eXBlLmZyb21UeXBlZEFycmF5ID0gZnVuY3Rpb24oYXJyYXkpIHsKICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBJbnQ4QXJyYXkpIHsKICAgICAgICAgIHJldHVybiBDb21wb25lbnREYXRhdHlwZS5CWVRFOwogICAgICAgIH0KICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7CiAgICAgICAgICByZXR1cm4gQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfQllURTsKICAgICAgICB9CiAgICAgICAgaWYgKGFycmF5IGluc3RhbmNlb2YgSW50MTZBcnJheSkgewogICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLlNIT1JUOwogICAgICAgIH0KICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBVaW50MTZBcnJheSkgewogICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOwogICAgICAgIH0KICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBJbnQzMkFycmF5KSB7CiAgICAgICAgICByZXR1cm4gQ29tcG9uZW50RGF0YXR5cGUuSU5UOwogICAgICAgIH0KICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBVaW50MzJBcnJheSkgewogICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0lOVDsKICAgICAgICB9CiAgICAgICAgaWYgKGFycmF5IGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KSB7CiAgICAgICAgICByZXR1cm4gQ29tcG9uZW50RGF0YXR5cGUuRkxPQVQ7CiAgICAgICAgfQogICAgICAgIGlmIChhcnJheSBpbnN0YW5jZW9mIEZsb2F0NjRBcnJheSkgewogICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLkRPVUJMRTsKICAgICAgICB9CiAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAiYXJyYXkgbXVzdCBiZSBhbiBJbnQ4QXJyYXksIFVpbnQ4QXJyYXksIEludDE2QXJyYXksIFVpbnQxNkFycmF5LCBJbnQzMkFycmF5LCBVaW50MzJBcnJheSwgRmxvYXQzMkFycmF5LCBvciBGbG9hdDY0QXJyYXkuIgogICAgICAgICk7CiAgICAgIH07CiAgICAgIENvbXBvbmVudERhdGF0eXBlLnZhbGlkYXRlID0gZnVuY3Rpb24oY29tcG9uZW50RGF0YXR5cGUpIHsKICAgICAgICByZXR1cm4gZGVmaW5lZF9kZWZhdWx0KGNvbXBvbmVudERhdGF0eXBlKSAmJiAoY29tcG9uZW50RGF0YXR5cGUgPT09IENvbXBvbmVudERhdGF0eXBlLkJZVEUgfHwgY29tcG9uZW50RGF0YXR5cGUgPT09IENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0JZVEUgfHwgY29tcG9uZW50RGF0YXR5cGUgPT09IENvbXBvbmVudERhdGF0eXBlLlNIT1JUIHx8IGNvbXBvbmVudERhdGF0eXBlID09PSBDb21wb25lbnREYXRhdHlwZS5VTlNJR05FRF9TSE9SVCB8fCBjb21wb25lbnREYXRhdHlwZSA9PT0gQ29tcG9uZW50RGF0YXR5cGUuSU5UIHx8IGNvbXBvbmVudERhdGF0eXBlID09PSBDb21wb25lbnREYXRhdHlwZS5VTlNJR05FRF9JTlQgfHwgY29tcG9uZW50RGF0YXR5cGUgPT09IENvbXBvbmVudERhdGF0eXBlLkZMT0FUIHx8IGNvbXBvbmVudERhdGF0eXBlID09PSBDb21wb25lbnREYXRhdHlwZS5ET1VCTEUpOwogICAgICB9OwogICAgICBDb21wb25lbnREYXRhdHlwZS5jcmVhdGVUeXBlZEFycmF5ID0gZnVuY3Rpb24oY29tcG9uZW50RGF0YXR5cGUsIHZhbHVlc09yTGVuZ3RoKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY29tcG9uZW50RGF0YXR5cGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiY29tcG9uZW50RGF0YXR5cGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlc09yTGVuZ3RoKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlc09yTGVuZ3RoIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBzd2l0Y2ggKGNvbXBvbmVudERhdGF0eXBlKSB7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLkJZVEU6CiAgICAgICAgICAgIHJldHVybiBuZXcgSW50OEFycmF5KHZhbHVlc09yTGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfQllURToKICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHZhbHVlc09yTGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuU0hPUlQ6CiAgICAgICAgICAgIHJldHVybiBuZXcgSW50MTZBcnJheSh2YWx1ZXNPckxlbmd0aCk7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOgogICAgICAgICAgICByZXR1cm4gbmV3IFVpbnQxNkFycmF5KHZhbHVlc09yTGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuSU5UOgogICAgICAgICAgICByZXR1cm4gbmV3IEludDMyQXJyYXkodmFsdWVzT3JMZW5ndGgpOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5VTlNJR05FRF9JTlQ6CiAgICAgICAgICAgIHJldHVybiBuZXcgVWludDMyQXJyYXkodmFsdWVzT3JMZW5ndGgpOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5GTE9BVDoKICAgICAgICAgICAgcmV0dXJuIG5ldyBGbG9hdDMyQXJyYXkodmFsdWVzT3JMZW5ndGgpOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5ET1VCTEU6CiAgICAgICAgICAgIHJldHVybiBuZXcgRmxvYXQ2NEFycmF5KHZhbHVlc09yTGVuZ3RoKTsKICAgICAgICAgIC8vPj5pbmNsdWRlU3RhcnQoJ2RlYnVnJywgcHJhZ21hcy5kZWJ1Zyk7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiY29tcG9uZW50RGF0YXR5cGUgaXMgbm90IGEgdmFsaWQgdmFsdWUuIik7CiAgICAgICAgfQogICAgICB9OwogICAgICBDb21wb25lbnREYXRhdHlwZS5jcmVhdGVBcnJheUJ1ZmZlclZpZXcgPSBmdW5jdGlvbihjb21wb25lbnREYXRhdHlwZSwgYnVmZmVyLCBieXRlT2Zmc2V0LCBsZW5ndGgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb21wb25lbnREYXRhdHlwZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJjb21wb25lbnREYXRhdHlwZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYnVmZmVyKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImJ1ZmZlciBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgYnl0ZU9mZnNldCA9IGJ5dGVPZmZzZXQgPz8gMDsKICAgICAgICBsZW5ndGggPSBsZW5ndGggPz8gKGJ1ZmZlci5ieXRlTGVuZ3RoIC0gYnl0ZU9mZnNldCkgLyBDb21wb25lbnREYXRhdHlwZS5nZXRTaXplSW5CeXRlcyhjb21wb25lbnREYXRhdHlwZSk7CiAgICAgICAgc3dpdGNoIChjb21wb25lbnREYXRhdHlwZSkgewogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5CWVRFOgogICAgICAgICAgICByZXR1cm4gbmV3IEludDhBcnJheShidWZmZXIsIGJ5dGVPZmZzZXQsIGxlbmd0aCk7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0JZVEU6CiAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShidWZmZXIsIGJ5dGVPZmZzZXQsIGxlbmd0aCk7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLlNIT1JUOgogICAgICAgICAgICByZXR1cm4gbmV3IEludDE2QXJyYXkoYnVmZmVyLCBieXRlT2Zmc2V0LCBsZW5ndGgpOwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5VTlNJR05FRF9TSE9SVDoKICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50MTZBcnJheShidWZmZXIsIGJ5dGVPZmZzZXQsIGxlbmd0aCk7CiAgICAgICAgICBjYXNlIENvbXBvbmVudERhdGF0eXBlLklOVDoKICAgICAgICAgICAgcmV0dXJuIG5ldyBJbnQzMkFycmF5KGJ1ZmZlciwgYnl0ZU9mZnNldCwgbGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfSU5UOgogICAgICAgICAgICByZXR1cm4gbmV3IFVpbnQzMkFycmF5KGJ1ZmZlciwgYnl0ZU9mZnNldCwgbGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuRkxPQVQ6CiAgICAgICAgICAgIHJldHVybiBuZXcgRmxvYXQzMkFycmF5KGJ1ZmZlciwgYnl0ZU9mZnNldCwgbGVuZ3RoKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuRE9VQkxFOgogICAgICAgICAgICByZXR1cm4gbmV3IEZsb2F0NjRBcnJheShidWZmZXIsIGJ5dGVPZmZzZXQsIGxlbmd0aCk7CiAgICAgICAgICAvLz4+aW5jbHVkZVN0YXJ0KCdkZWJ1ZycsIHByYWdtYXMuZGVidWcpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNvbXBvbmVudERhdGF0eXBlIGlzIG5vdCBhIHZhbGlkIHZhbHVlLiIpOwogICAgICAgIH0KICAgICAgfTsKICAgICAgQ29tcG9uZW50RGF0YXR5cGUuZnJvbU5hbWUgPSBmdW5jdGlvbihuYW1lKSB7CiAgICAgICAgc3dpdGNoIChuYW1lKSB7CiAgICAgICAgICBjYXNlICJCWVRFIjoKICAgICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLkJZVEU7CiAgICAgICAgICBjYXNlICJVTlNJR05FRF9CWVRFIjoKICAgICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX0JZVEU7CiAgICAgICAgICBjYXNlICJTSE9SVCI6CiAgICAgICAgICAgIHJldHVybiBDb21wb25lbnREYXRhdHlwZS5TSE9SVDsKICAgICAgICAgIGNhc2UgIlVOU0lHTkVEX1NIT1JUIjoKICAgICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOwogICAgICAgICAgY2FzZSAiSU5UIjoKICAgICAgICAgICAgcmV0dXJuIENvbXBvbmVudERhdGF0eXBlLklOVDsKICAgICAgICAgIGNhc2UgIlVOU0lHTkVEX0lOVCI6CiAgICAgICAgICAgIHJldHVybiBDb21wb25lbnREYXRhdHlwZS5VTlNJR05FRF9JTlQ7CiAgICAgICAgICBjYXNlICJGTE9BVCI6CiAgICAgICAgICAgIHJldHVybiBDb21wb25lbnREYXRhdHlwZS5GTE9BVDsKICAgICAgICAgIGNhc2UgIkRPVUJMRSI6CiAgICAgICAgICAgIHJldHVybiBDb21wb25lbnREYXRhdHlwZS5ET1VCTEU7CiAgICAgICAgICAvLz4+aW5jbHVkZVN0YXJ0KCdkZWJ1ZycsIHByYWdtYXMuZGVidWcpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm5hbWUgaXMgbm90IGEgdmFsaWQgdmFsdWUuIik7CiAgICAgICAgfQogICAgICB9OwogICAgICBDb21wb25lbnREYXRhdHlwZS5kZXF1YW50aXplID0gZnVuY3Rpb24odmFsdWUsIGNvbXBvbmVudERhdGF0eXBlKSB7CiAgICAgICAgc3dpdGNoIChjb21wb25lbnREYXRhdHlwZSkgewogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5CWVRFOgogICAgICAgICAgICByZXR1cm4gTWF0aC5tYXgodmFsdWUgLyAxMjcsIC0xKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfQllURToKICAgICAgICAgICAgcmV0dXJuIHZhbHVlIC8gMjU1OwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5TSE9SVDoKICAgICAgICAgICAgcmV0dXJuIE1hdGgubWF4KHZhbHVlIC8gMzI3NjcsIC0xKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfU0hPUlQ6CiAgICAgICAgICAgIHJldHVybiB2YWx1ZSAvIDY1NTM1OwogICAgICAgICAgY2FzZSBDb21wb25lbnREYXRhdHlwZS5JTlQ6CiAgICAgICAgICAgIHJldHVybiBNYXRoLm1heCh2YWx1ZSAvIDIxNDc0ODM2NDcsIC0xKTsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGUuVU5TSUdORURfSU5UOgogICAgICAgICAgICByZXR1cm4gdmFsdWUgLyA0Mjk0OTY3Mjk1OwogICAgICAgICAgLy8+PmluY2x1ZGVTdGFydCgnZGVidWcnLCBwcmFnbWFzLmRlYnVnKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJjb21wb25lbnREYXRhdHlwZSBpcyBub3QgYSB2YWxpZCBpbnRlZ2VyIHR5cGUgZm9yIGRlcXVhbnRpemF0aW9uLiIKICAgICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIE9iamVjdC5mcmVlemUoQ29tcG9uZW50RGF0YXR5cGUpOwogICAgICBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0ID0gQ29tcG9uZW50RGF0YXR5cGU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9tZXRyeVR5cGUuanMKICB2YXIgR2VvbWV0cnlUeXBlLCBHZW9tZXRyeVR5cGVfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeVR5cGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0dlb21ldHJ5VHlwZS5qcyIoKSB7CiAgICAgIEdlb21ldHJ5VHlwZSA9IHsKICAgICAgICBOT05FOiAwLAogICAgICAgIFRSSUFOR0xFUzogMSwKICAgICAgICBMSU5FUzogMiwKICAgICAgICBQT0xZTElORVM6IDMKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShHZW9tZXRyeVR5cGUpOwogICAgICBHZW9tZXRyeVR5cGVfZGVmYXVsdCA9IEdlb21ldHJ5VHlwZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL01hdHJpeDIuanMKICB2YXIgTWF0cml4Miwgc2NhbGVTY3JhdGNoMTMsIHNjYWxlU2NyYXRjaDIzLCBzY3JhdGNoQ29sdW1uMywgc2NhbGVTY3JhdGNoMzMsIHNjYWxlU2NyYXRjaDQzLCBzY2FsZVNjcmF0Y2g1MywgTWF0cml4Ml9kZWZhdWx0OwogIHZhciBpbml0X01hdHJpeDIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL01hdHJpeDIuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBNYXRyaXgyID0gY2xhc3MgX01hdHJpeDIgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMFJvdzA9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAwLCByb3cgMC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbHVtbjFSb3cwPTAuMF0gVGhlIHZhbHVlIGZvciBjb2x1bW4gMSwgcm93IDAuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtjb2x1bW4wUm93MT0wLjBdIFRoZSB2YWx1ZSBmb3IgY29sdW1uIDAsIHJvdyAxLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbY29sdW1uMVJvdzE9MC4wXSBUaGUgdmFsdWUgZm9yIGNvbHVtbiAxLCByb3cgMS4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3Rvcihjb2x1bW4wUm93MCwgY29sdW1uMVJvdzAsIGNvbHVtbjBSb3cxLCBjb2x1bW4xUm93MSkgewogICAgICAgICAgdGhpc1swXSA9IGNvbHVtbjBSb3cwID8/IDA7CiAgICAgICAgICB0aGlzWzFdID0gY29sdW1uMFJvdzEgPz8gMDsKICAgICAgICAgIHRoaXNbMl0gPSBjb2x1bW4xUm93MCA/PyAwOwogICAgICAgICAgdGhpc1szXSA9IGNvbHVtbjFSb3cxID8/IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgaW5zdGFuY2UgaW50byB0aGUgcHJvdmlkZWQgYXJyYXkuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHZhbHVlIFRoZSB2YWx1ZSB0byBwYWNrLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSB0byBwYWNrIGludG8uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBpbmRleCBpbnRvIHRoZSBhcnJheSBhdCB3aGljaCB0byBzdGFydCBwYWNraW5nIHRoZSBlbGVtZW50cy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJbXX0gVGhlIGFycmF5IHRoYXQgd2FzIHBhY2tlZCBpbnRvCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2sodmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMF07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMV07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWVbMl07CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlWzNdOwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBwYWNrZWQgYXJyYXkuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtzdGFydGluZ0luZGV4PTBdIFRoZSBzdGFydGluZyBpbmRleCBvZiB0aGUgZWxlbWVudCB0byBiZSB1bnBhY2tlZC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBNYXRyaXgyIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB1bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfTWF0cml4MigpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHRbMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0WzNdID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBGbGF0dGVucyBhbiBhcnJheSBvZiBNYXRyaXgycyBpbnRvIGFuIGFycmF5IG9mIGNvbXBvbmVudHMuIFRoZSBjb21wb25lbnRzCiAgICAgICAgICogYXJlIHN0b3JlZCBpbiBjb2x1bW4tbWFqb3Igb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJbXX0gYXJyYXkgVGhlIGFycmF5IG9mIG1hdHJpY2VzIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXX0gW3Jlc3VsdF0gVGhlIGFycmF5IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4gSWYgdGhpcyBpcyBhIHR5cGVkIGFycmF5LCBpdCBtdXN0IGhhdmUgYXJyYXkubGVuZ3RoICogNCBjb21wb25lbnRzLCBlbHNlIGEge0BsaW5rIERldmVsb3BlckVycm9yfSB3aWxsIGJlIHRocm93bi4gSWYgaXQgaXMgYSByZWd1bGFyIGFycmF5LCBpdCB3aWxsIGJlIHJlc2l6ZWQgdG8gaGF2ZSAoYXJyYXkubGVuZ3RoICogNCkgZWxlbWVudHMuCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgcGFja2VkIGFycmF5LgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBwYWNrQXJyYXkoYXJyYXksIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGFycmF5Lmxlbmd0aDsKICAgICAgICAgIGNvbnN0IHJlc3VsdExlbmd0aCA9IGxlbmd0aCAqIDQ7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShyZXN1bHRMZW5ndGgpOwogICAgICAgICAgfSBlbHNlIGlmICghQXJyYXkuaXNBcnJheShyZXN1bHQpICYmIHJlc3VsdC5sZW5ndGggIT09IHJlc3VsdExlbmd0aCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgICAiSWYgcmVzdWx0IGlzIGEgdHlwZWQgYXJyYXksIGl0IG11c3QgaGF2ZSBleGFjdGx5IGFycmF5Lmxlbmd0aCAqIDQgZWxlbWVudHMiCiAgICAgICAgICAgICk7CiAgICAgICAgICB9IGVsc2UgaWYgKHJlc3VsdC5sZW5ndGggIT09IHJlc3VsdExlbmd0aCkgewogICAgICAgICAgICByZXN1bHQubGVuZ3RoID0gcmVzdWx0TGVuZ3RoOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBfTWF0cml4Mi5wYWNrKGFycmF5W2kyXSwgcmVzdWx0LCBpMiAqIDQpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogVW5wYWNrcyBhbiBhcnJheSBvZiBjb2x1bW4tbWFqb3IgbWF0cml4IGNvbXBvbmVudHMgaW50byBhbiBhcnJheSBvZiBNYXRyaXgycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IGFycmF5IFRoZSBhcnJheSBvZiBjb21wb25lbnRzIHRvIHVucGFjay4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJbXX0gW3Jlc3VsdF0gVGhlIGFycmF5IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4MltdfSBUaGUgdW5wYWNrZWQgYXJyYXkuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFja0FycmF5KGFycmF5LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiYXJyYXkubGVuZ3RoIiwgYXJyYXkubGVuZ3RoLCA0KTsKICAgICAgICAgIGlmIChhcnJheS5sZW5ndGggJSA0ICE9PSAwKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBsZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQuIik7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheS5sZW5ndGg7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShsZW5ndGggLyA0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSBsZW5ndGggLyA0OwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gNCkgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IGkyIC8gNDsKICAgICAgICAgICAgcmVzdWx0W2luZGV4XSA9IF9NYXRyaXgyLnVucGFjayhhcnJheSwgaTIsIHJlc3VsdFtpbmRleF0pOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhIE1hdHJpeDIgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IHRvIGR1cGxpY2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBNYXRyaXgyIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLiAoUmV0dXJucyB1bmRlZmluZWQgaWYgbWF0cml4IGlzIHVuZGVmaW5lZCkKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgY2xvbmUobWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG1hdHJpeCkpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4MihtYXRyaXhbMF0sIG1hdHJpeFsyXSwgbWF0cml4WzFdLCBtYXRyaXhbM10pOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdOwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIE1hdHJpeDIgaW5zdGFuY2UgZnJvbSBhIGNvbHVtbi1tYWpvciBvcmRlciBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IHZhbHVlcyBUaGUgY29sdW1uLW1ham9yIG9yZGVyIGFycmF5LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4MiBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUNvbHVtbk1ham9yQXJyYXkodmFsdWVzLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidmFsdWVzIiwgdmFsdWVzKTsKICAgICAgICAgIHJldHVybiBfTWF0cml4Mi5jbG9uZSh2YWx1ZXMsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBNYXRyaXgyIGluc3RhbmNlIGZyb20gYSByb3ctbWFqb3Igb3JkZXIgYXJyYXkuCiAgICAgICAgICogVGhlIHJlc3VsdGluZyBtYXRyaXggd2lsbCBiZSBpbiBjb2x1bW4tbWFqb3Igb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSB2YWx1ZXMgVGhlIHJvdy1tYWpvciBvcmRlciBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDIgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21Sb3dNYWpvckFycmF5KHZhbHVlcywgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlcyIsIHZhbHVlcyk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX01hdHJpeDIodmFsdWVzWzBdLCB2YWx1ZXNbMV0sIHZhbHVlc1syXSwgdmFsdWVzWzNdKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IHZhbHVlc1swXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IHZhbHVlc1syXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IHZhbHVlc1sxXTsKICAgICAgICAgIHJlc3VsdFszXSA9IHZhbHVlc1szXTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgTWF0cml4MiBpbnN0YW5jZSByZXByZXNlbnRpbmcgYSBub24tdW5pZm9ybSBzY2FsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gc2NhbGUgVGhlIHggYW5kIHkgc2NhbGUgZmFjdG9ycy4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZCwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IE1hdHJpeDIgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIC8vIENyZWF0ZXMKICAgICAgICAgKiAvLyAgIFs3LjAsIDAuMF0KICAgICAgICAgKiAvLyAgIFswLjAsIDguMF0KICAgICAgICAgKiBjb25zdCBtID0gQ2VzaXVtLk1hdHJpeDIuZnJvbVNjYWxlKG5ldyBDZXNpdW0uQ2FydGVzaWFuMig3LjAsIDguMCkpOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tU2NhbGUoc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfTWF0cml4MihzY2FsZS54LCAwLCAwLCBzY2FsZS55KTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IHNjYWxlLng7CiAgICAgICAgICByZXN1bHRbMV0gPSAwOwogICAgICAgICAgcmVzdWx0WzJdID0gMDsKICAgICAgICAgIHJlc3VsdFszXSA9IHNjYWxlLnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIE1hdHJpeDIgaW5zdGFuY2UgcmVwcmVzZW50aW5nIGEgdW5pZm9ybSBzY2FsZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsZSBUaGUgdW5pZm9ybSBzY2FsZSBmYWN0b3IuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBbcmVzdWx0XSBUaGUgb2JqZWN0IGluIHdoaWNoIHRoZSByZXN1bHQgd2lsbCBiZSBzdG9yZWQsIGlmIHVuZGVmaW5lZCBhIG5ldyBpbnN0YW5jZSB3aWxsIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLCBvciBhIG5ldyBNYXRyaXgyIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBDcmVhdGVzCiAgICAgICAgICogLy8gICBbMi4wLCAwLjBdCiAgICAgICAgICogLy8gICBbMC4wLCAyLjBdCiAgICAgICAgICogY29uc3QgbSA9IENlc2l1bS5NYXRyaXgyLmZyb21Vbmlmb3JtU2NhbGUoMi4wKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVVuaWZvcm1TY2FsZShzY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxlIiwgc2NhbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgyKHNjYWxlLCAwLCAwLCBzY2FsZSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBzY2FsZTsKICAgICAgICAgIHJlc3VsdFsxXSA9IDA7CiAgICAgICAgICByZXN1bHRbMl0gPSAwOwogICAgICAgICAgcmVzdWx0WzNdID0gc2NhbGU7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgcm90YXRpb24gbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGFuZ2xlIFRoZSBhbmdsZSwgaW4gcmFkaWFucywgb2YgdGhlIHJvdGF0aW9uLiAgUG9zaXRpdmUgYW5nbGVzIGFyZSBjb3VudGVyY2xvY2t3aXNlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gW3Jlc3VsdF0gVGhlIG9iamVjdCBpbiB3aGljaCB0aGUgcmVzdWx0IHdpbGwgYmUgc3RvcmVkLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciwgb3IgYSBuZXcgTWF0cml4MiBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy8gUm90YXRlIGEgcG9pbnQgNDUgZGVncmVlcyBjb3VudGVyY2xvY2t3aXNlLgogICAgICAgICAqIGNvbnN0IHAgPSBuZXcgQ2VzaXVtLkNhcnRlc2lhbjIoNSwgNik7CiAgICAgICAgICogY29uc3QgbSA9IENlc2l1bS5NYXRyaXgyLmZyb21Sb3RhdGlvbihDZXNpdW0uTWF0aC50b1JhZGlhbnMoNDUuMCkpOwogICAgICAgICAqIGNvbnN0IHJvdGF0ZWQgPSBDZXNpdW0uTWF0cml4Mi5tdWx0aXBseUJ5VmVjdG9yKG0sIHAsIG5ldyBDZXNpdW0uQ2FydGVzaWFuMigpKTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbVJvdGF0aW9uKGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYW5nbGUiLCBhbmdsZSk7CiAgICAgICAgICBjb25zdCBjb3NBbmdsZSA9IE1hdGguY29zKGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHNpbkFuZ2xlID0gTWF0aC5zaW4oYW5nbGUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9NYXRyaXgyKGNvc0FuZ2xlLCAtc2luQW5nbGUsIHNpbkFuZ2xlLCBjb3NBbmdsZSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSBjb3NBbmdsZTsKICAgICAgICAgIHJlc3VsdFsxXSA9IHNpbkFuZ2xlOwogICAgICAgICAgcmVzdWx0WzJdID0gLXNpbkFuZ2xlOwogICAgICAgICAgcmVzdWx0WzNdID0gY29zQW5nbGU7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGFuIEFycmF5IGZyb20gdGhlIHByb3ZpZGVkIE1hdHJpeDIgaW5zdGFuY2UuCiAgICAgICAgICogVGhlIGFycmF5IHdpbGwgYmUgaW4gY29sdW1uLW1ham9yIG9yZGVyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW119IFtyZXN1bHRdIFRoZSBBcnJheSBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge251bWJlcltdfSBUaGUgbW9kaWZpZWQgQXJyYXkgcGFyYW1ldGVyIG9yIGEgbmV3IEFycmF5IGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyB0b0FycmF5KG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBbbWF0cml4WzBdLCBtYXRyaXhbMV0sIG1hdHJpeFsyXSwgbWF0cml4WzNdXTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBhcnJheSBpbmRleCBvZiB0aGUgZWxlbWVudCBhdCB0aGUgcHJvdmlkZWQgcm93IGFuZCBjb2x1bW4uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gcm93IFRoZSB6ZXJvLWJhc2VkIGluZGV4IG9mIHRoZSByb3cuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbiBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBpbmRleCBvZiB0aGUgZWxlbWVudCBhdCB0aGUgcHJvdmlkZWQgcm93IGFuZCBjb2x1bW4uCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gcm93IG11c3QgYmUgMCBvciAxLgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBjb2x1bW4gbXVzdCBiZSAwIG9yIDEuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IG15TWF0cml4ID0gbmV3IENlc2l1bS5NYXRyaXgyKCk7CiAgICAgICAgICogY29uc3QgY29sdW1uMVJvdzBJbmRleCA9IENlc2l1bS5NYXRyaXgyLmdldEVsZW1lbnRJbmRleCgxLCAwKTsKICAgICAgICAgKiBjb25zdCBjb2x1bW4xUm93MCA9IG15TWF0cml4W2NvbHVtbjFSb3cwSW5kZXhdCiAgICAgICAgICogbXlNYXRyaXhbY29sdW1uMVJvdzBJbmRleF0gPSAxMC4wOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBnZXRFbGVtZW50SW5kZXgoY29sdW1uLCByb3cpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJyb3ciLCByb3csIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoInJvdyIsIHJvdywgMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiY29sdW1uIiwgY29sdW1uLCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJjb2x1bW4iLCBjb2x1bW4sIDEpOwogICAgICAgICAgcmV0dXJuIGNvbHVtbiAqIDIgKyByb3c7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHJpZXZlcyBhIGNvcHkgb2YgdGhlIG1hdHJpeCBjb2x1bW4gYXQgdGhlIHByb3ZpZGVkIGluZGV4IGFzIGEgQ2FydGVzaWFuMiBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgY29sdW1uIHRvIHJldHJpZXZlLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAgb3IgMS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0Q29sdW1uKG1hdHJpeCwgaW5kZXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoImluZGV4IiwgaW5kZXgsIDEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3Qgc3RhcnRJbmRleCA9IGluZGV4ICogMjsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4W3N0YXJ0SW5kZXhdOwogICAgICAgICAgY29uc3QgeTIgPSBtYXRyaXhbc3RhcnRJbmRleCArIDFdOwogICAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICAgIHJlc3VsdC55ID0geTI7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIG5ldyBtYXRyaXggdGhhdCByZXBsYWNlcyB0aGUgc3BlY2lmaWVkIGNvbHVtbiBpbiB0aGUgcHJvdmlkZWQgbWF0cml4IHdpdGggdGhlIHByb3ZpZGVkIENhcnRlc2lhbjIgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIGNvbHVtbiB0byBzZXQuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBjYXJ0ZXNpYW4gVGhlIENhcnRlc2lhbiB3aG9zZSB2YWx1ZXMgd2lsbCBiZSBhc3NpZ25lZCB0byB0aGUgc3BlY2lmaWVkIGNvbHVtbi4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gaW5kZXggbXVzdCBiZSAwIG9yIDEuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldENvbHVtbihtYXRyaXgsIGluZGV4LCBjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygiaW5kZXgiLCBpbmRleCwgMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdCA9IF9NYXRyaXgyLmNsb25lKG1hdHJpeCwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHN0YXJ0SW5kZXggPSBpbmRleCAqIDI7CiAgICAgICAgICByZXN1bHRbc3RhcnRJbmRleF0gPSBjYXJ0ZXNpYW4xMS54OwogICAgICAgICAgcmVzdWx0W3N0YXJ0SW5kZXggKyAxXSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBtYXRyaXggcm93IGF0IHRoZSBwcm92aWRlZCBpbmRleCBhcyBhIENhcnRlc2lhbjIgaW5zdGFuY2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IHRvIHVzZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggVGhlIHplcm8tYmFzZWQgaW5kZXggb2YgdGhlIHJvdyB0byByZXRyaWV2ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gaW5kZXggbXVzdCBiZSAwIG9yIDEuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldFJvdyhtYXRyaXgsIGluZGV4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAxKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHgyID0gbWF0cml4W2luZGV4XTsKICAgICAgICAgIGNvbnN0IHkyID0gbWF0cml4W2luZGV4ICsgMl07CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIGEgbmV3IG1hdHJpeCB0aGF0IHJlcGxhY2VzIHRoZSBzcGVjaWZpZWQgcm93IGluIHRoZSBwcm92aWRlZCBtYXRyaXggd2l0aCB0aGUgcHJvdmlkZWQgQ2FydGVzaWFuMiBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gbWF0cml4IFRoZSBtYXRyaXggdG8gdXNlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgemVyby1iYXNlZCBpbmRleCBvZiB0aGUgcm93IHRvIHNldC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IGNhcnRlc2lhbiBUaGUgQ2FydGVzaWFuIHdob3NlIHZhbHVlcyB3aWxsIGJlIGFzc2lnbmVkIHRvIHRoZSBzcGVjaWZpZWQgcm93LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBpbmRleCBtdXN0IGJlIDAgb3IgMS4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgc2V0Um93KG1hdHJpeCwgaW5kZXgsIGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAxKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0ID0gX01hdHJpeDIuY2xvbmUobWF0cml4LCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0W2luZGV4XSA9IGNhcnRlc2lhbjExLng7CiAgICAgICAgICByZXN1bHRbaW5kZXggKyAyXSA9IGNhcnRlc2lhbjExLnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyBhIG5ldyBtYXRyaXggdGhhdCByZXBsYWNlcyB0aGUgc2NhbGUgd2l0aCB0aGUgcHJvdmlkZWQgc2NhbGUuCiAgICAgICAgICogVGhpcyBhc3N1bWVzIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSBzY2FsZSBUaGUgc2NhbGUgdGhhdCByZXBsYWNlcyB0aGUgc2NhbGUgb2YgdGhlIHByb3ZpZGVkIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuc2V0VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFNjYWxlKG1hdHJpeCwgc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGV4aXN0aW5nU2NhbGUgPSBfTWF0cml4Mi5nZXRTY2FsZShtYXRyaXgsIHNjYWxlU2NyYXRjaDEzKTsKICAgICAgICAgIGNvbnN0IHNjYWxlUmF0aW9YID0gc2NhbGUueCAvIGV4aXN0aW5nU2NhbGUueDsKICAgICAgICAgIGNvbnN0IHNjYWxlUmF0aW9ZID0gc2NhbGUueSAvIGV4aXN0aW5nU2NhbGUueTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBuZXcgbWF0cml4IHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIHdpdGggdGhlIHByb3ZpZGVkIHVuaWZvcm0gc2NhbGUuCiAgICAgICAgICogVGhpcyBhc3N1bWVzIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeCB0byB1c2UuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlIFRoZSB1bmlmb3JtIHNjYWxlIHRoYXQgcmVwbGFjZXMgdGhlIHNjYWxlIG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQHNlZSBNYXRyaXgyLnNldFNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmZyb21TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5mcm9tVW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLm11bHRpcGx5QnlTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFVuaWZvcm1TY2FsZShtYXRyaXgsIHNjYWxlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGUiLCBzY2FsZSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBleGlzdGluZ1NjYWxlID0gX01hdHJpeDIuZ2V0U2NhbGUobWF0cml4LCBzY2FsZVNjcmF0Y2gyMyk7CiAgICAgICAgICBjb25zdCBzY2FsZVJhdGlvWCA9IHNjYWxlIC8gZXhpc3RpbmdTY2FsZS54OwogICAgICAgICAgY29uc3Qgc2NhbGVSYXRpb1kgPSBzY2FsZSAvIGV4aXN0aW5nU2NhbGUueTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxlUmF0aW9YOwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdICogc2NhbGVSYXRpb1g7CiAgICAgICAgICByZXN1bHRbMl0gPSBtYXRyaXhbMl0gKiBzY2FsZVJhdGlvWTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxlUmF0aW9ZOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRXh0cmFjdHMgdGhlIG5vbi11bmlmb3JtIHNjYWxlIGFzc3VtaW5nIHRoZSBtYXRyaXggaXMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuMn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDIubXVsdGlwbHlCeVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLm11bHRpcGx5QnlVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuZnJvbVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmZyb21Vbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuc2V0U2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuc2V0VW5pZm9ybVNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldFNjYWxlKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQueCA9IENhcnRlc2lhbjJfZGVmYXVsdC5tYWduaXR1ZGUoCiAgICAgICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMobWF0cml4WzBdLCBtYXRyaXhbMV0sIHNjcmF0Y2hDb2x1bW4zKQogICAgICAgICAgKTsKICAgICAgICAgIHJlc3VsdC55ID0gQ2FydGVzaWFuMl9kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21FbGVtZW50cyhtYXRyaXhbMl0sIG1hdHJpeFszXSwgc2NyYXRjaENvbHVtbjMpCiAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIG1heGltdW0gc2NhbGUgYXNzdW1pbmcgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICogVGhlIG1heGltdW0gc2NhbGUgaXMgdGhlIG1heGltdW0gbGVuZ3RoIG9mIHRoZSBjb2x1bW4gdmVjdG9ycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gbWF0cml4IFRoZSBtYXRyaXguCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIG1heGltdW0gc2NhbGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdldE1heGltdW1TY2FsZShtYXRyaXgpIHsKICAgICAgICAgIF9NYXRyaXgyLmdldFNjYWxlKG1hdHJpeCwgc2NhbGVTY3JhdGNoMzMpOwogICAgICAgICAgcmV0dXJuIENhcnRlc2lhbjJfZGVmYXVsdC5tYXhpbXVtQ29tcG9uZW50KHNjYWxlU2NyYXRjaDMzKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogU2V0cyB0aGUgcm90YXRpb24gYXNzdW1pbmcgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcm90YXRpb24gVGhlIHJvdGF0aW9uIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuZnJvbVJvdGF0aW9uCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmdldFJvdGF0aW9uCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHNldFJvdGF0aW9uKG1hdHJpeCwgcm90YXRpb24sIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgY29uc3Qgc2NhbGUgPSBfTWF0cml4Mi5nZXRTY2FsZShtYXRyaXgsIHNjYWxlU2NyYXRjaDQzKTsKICAgICAgICAgIHJlc3VsdFswXSA9IHJvdGF0aW9uWzBdICogc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFsxXSA9IHJvdGF0aW9uWzFdICogc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFsyXSA9IHJvdGF0aW9uWzJdICogc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFszXSA9IHJvdGF0aW9uWzNdICogc2NhbGUueTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEV4dHJhY3RzIHRoZSByb3RhdGlvbiBtYXRyaXggYXNzdW1pbmcgdGhlIG1hdHJpeCBpcyBhbiBhZmZpbmUgdHJhbnNmb3JtYXRpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBzZWUgTWF0cml4Mi5zZXRSb3RhdGlvbgogICAgICAgICAqIEBzZWUgTWF0cml4Mi5mcm9tUm90YXRpb24KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0Um90YXRpb24obWF0cml4LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IHNjYWxlID0gX01hdHJpeDIuZ2V0U2NhbGUobWF0cml4LCBzY2FsZVNjcmF0Y2g1Myk7CiAgICAgICAgICByZXN1bHRbMF0gPSBtYXRyaXhbMF0gLyBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzFdID0gbWF0cml4WzFdIC8gc2NhbGUueDsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAvIHNjYWxlLnk7CiAgICAgICAgICByZXN1bHRbM10gPSBtYXRyaXhbM10gLyBzY2FsZS55OwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHByb2R1Y3Qgb2YgdHdvIG1hdHJpY2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBsZWZ0IFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByaWdodCBUaGUgc2Vjb25kIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5KGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cwID0gbGVmdFswXSAqIHJpZ2h0WzBdICsgbGVmdFsyXSAqIHJpZ2h0WzFdOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzAgPSBsZWZ0WzBdICogcmlnaHRbMl0gKyBsZWZ0WzJdICogcmlnaHRbM107CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MSA9IGxlZnRbMV0gKiByaWdodFswXSArIGxlZnRbM10gKiByaWdodFsxXTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjFSb3cxID0gbGVmdFsxXSAqIHJpZ2h0WzJdICsgbGVmdFszXSAqIHJpZ2h0WzNdOwogICAgICAgICAgcmVzdWx0WzBdID0gY29sdW1uMFJvdzA7CiAgICAgICAgICByZXN1bHRbMV0gPSBjb2x1bW4wUm93MTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGNvbHVtbjFSb3cwOwogICAgICAgICAgcmVzdWx0WzNdID0gY29sdW1uMVJvdzE7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgc3VtIG9mIHR3byBtYXRyaWNlcy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gbGVmdCBUaGUgZmlyc3QgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmlnaHQgVGhlIHNlY29uZCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBhZGQobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gbGVmdFswXSArIHJpZ2h0WzBdOwogICAgICAgICAgcmVzdWx0WzFdID0gbGVmdFsxXSArIHJpZ2h0WzFdOwogICAgICAgICAgcmVzdWx0WzJdID0gbGVmdFsyXSArIHJpZ2h0WzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gbGVmdFszXSArIHJpZ2h0WzNdOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGRpZmZlcmVuY2Ugb2YgdHdvIG1hdHJpY2VzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBsZWZ0IFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByaWdodCBUaGUgc2Vjb25kIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHN1YnRyYWN0KGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IGxlZnRbMF0gLSByaWdodFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IGxlZnRbMV0gLSByaWdodFsxXTsKICAgICAgICAgIHJlc3VsdFsyXSA9IGxlZnRbMl0gLSByaWdodFsyXTsKICAgICAgICAgIHJlc3VsdFszXSA9IGxlZnRbM10gLSByaWdodFszXTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIGEgbWF0cml4IGFuZCBhIGNvbHVtbiB2ZWN0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gY2FydGVzaWFuIFRoZSBjb2x1bW4uCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5VmVjdG9yKG1hdHJpeCwgY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCB4MiA9IG1hdHJpeFswXSAqIGNhcnRlc2lhbjExLnggKyBtYXRyaXhbMl0gKiBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgY29uc3QgeTIgPSBtYXRyaXhbMV0gKiBjYXJ0ZXNpYW4xMS54ICsgbWF0cml4WzNdICogY2FydGVzaWFuMTEueTsKICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHByb2R1Y3Qgb2YgYSBtYXRyaXggYW5kIGEgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGFyIFRoZSBudW1iZXIgdG8gbXVsdGlwbHkgYnkuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKG1hdHJpeCwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibWF0cml4IiwgbWF0cml4KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGFyIiwgc2NhbGFyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsxXSA9IG1hdHJpeFsxXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxhcjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBwcm9kdWN0IG9mIGEgbWF0cml4IHRpbWVzIGEgKG5vbi11bmlmb3JtKSBzY2FsZSwgYXMgaWYgdGhlIHNjYWxlIHdlcmUgYSBzY2FsZSBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IG9uIHRoZSBsZWZ0LWhhbmQgc2lkZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjJ9IHNjYWxlIFRoZSBub24tdW5pZm9ybSBzY2FsZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBJbnN0ZWFkIG9mIENlc2l1bS5NYXRyaXgyLm11bHRpcGx5KG0sIENlc2l1bS5NYXRyaXgyLmZyb21TY2FsZShzY2FsZSksIG0pOwogICAgICAgICAqIENlc2l1bS5NYXRyaXgyLm11bHRpcGx5QnlTY2FsZShtLCBzY2FsZSwgbSk7CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIE1hdHJpeDIubXVsdGlwbHlCeVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5mcm9tU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuZnJvbVVuaWZvcm1TY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5zZXRTY2FsZQogICAgICAgICAqIEBzZWUgTWF0cml4Mi5zZXRVbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuZ2V0U2NhbGUKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbXVsdGlwbHlCeVNjYWxlKG1hdHJpeCwgc2NhbGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJzY2FsZSIsIHNjYWxlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdFswXSA9IG1hdHJpeFswXSAqIHNjYWxlLng7CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV0gKiBzY2FsZS54OwogICAgICAgICAgcmVzdWx0WzJdID0gbWF0cml4WzJdICogc2NhbGUueTsKICAgICAgICAgIHJlc3VsdFszXSA9IG1hdHJpeFszXSAqIHNjYWxlLnk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhIG1hdHJpeCB0aW1lcyBhIHVuaWZvcm0gc2NhbGUsIGFzIGlmIHRoZSBzY2FsZSB3ZXJlIGEgc2NhbGUgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXggVGhlIG1hdHJpeCBvbiB0aGUgbGVmdC1oYW5kIHNpZGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlIFRoZSB1bmlmb3JtIHNjYWxlIG9uIHRoZSByaWdodC1oYW5kIHNpZGUuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge01hdHJpeDJ9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvLyBJbnN0ZWFkIG9mIENlc2l1bS5NYXRyaXgyLm11bHRpcGx5KG0sIENlc2l1bS5NYXRyaXgyLmZyb21Vbmlmb3JtU2NhbGUoc2NhbGUpLCBtKTsKICAgICAgICAgKiBDZXNpdW0uTWF0cml4Mi5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlKG0sIHNjYWxlLCBtKTsKICAgICAgICAgKgogICAgICAgICAqIEBzZWUgTWF0cml4Mi5tdWx0aXBseUJ5U2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuZnJvbVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmZyb21Vbmlmb3JtU2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuc2V0U2NhbGUKICAgICAgICAgKiBAc2VlIE1hdHJpeDIuc2V0VW5pZm9ybVNjYWxlCiAgICAgICAgICogQHNlZSBNYXRyaXgyLmdldFNjYWxlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5QnlVbmlmb3JtU2NhbGUobWF0cml4LCBzY2FsZSwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxlIiwgc2NhbGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gbWF0cml4WzBdICogc2NhbGU7CiAgICAgICAgICByZXN1bHRbMV0gPSBtYXRyaXhbMV0gKiBzY2FsZTsKICAgICAgICAgIHJlc3VsdFsyXSA9IG1hdHJpeFsyXSAqIHNjYWxlOwogICAgICAgICAgcmVzdWx0WzNdID0gbWF0cml4WzNdICogc2NhbGU7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgbmVnYXRlZCBjb3B5IG9mIHRoZSBwcm92aWRlZCBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IHRvIG5lZ2F0ZS4KICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG5lZ2F0ZShtYXRyaXgsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXRyaXgiLCBtYXRyaXgpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0WzBdID0gLW1hdHJpeFswXTsKICAgICAgICAgIHJlc3VsdFsxXSA9IC1tYXRyaXhbMV07CiAgICAgICAgICByZXN1bHRbMl0gPSAtbWF0cml4WzJdOwogICAgICAgICAgcmVzdWx0WzNdID0gLW1hdHJpeFszXTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSB0cmFuc3Bvc2Ugb2YgdGhlIHByb3ZpZGVkIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gbWF0cml4IFRoZSBtYXRyaXggdG8gdHJhbnNwb3NlLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgdHJhbnNwb3NlKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBjb25zdCBjb2x1bW4wUm93MCA9IG1hdHJpeFswXTsKICAgICAgICAgIGNvbnN0IGNvbHVtbjBSb3cxID0gbWF0cml4WzJdOwogICAgICAgICAgY29uc3QgY29sdW1uMVJvdzAgPSBtYXRyaXhbMV07CiAgICAgICAgICBjb25zdCBjb2x1bW4xUm93MSA9IG1hdHJpeFszXTsKICAgICAgICAgIHJlc3VsdFswXSA9IGNvbHVtbjBSb3cwOwogICAgICAgICAgcmVzdWx0WzFdID0gY29sdW1uMFJvdzE7CiAgICAgICAgICByZXN1bHRbMl0gPSBjb2x1bW4xUm93MDsKICAgICAgICAgIHJlc3VsdFszXSA9IGNvbHVtbjFSb3cxOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgYSBtYXRyaXgsIHdoaWNoIGNvbnRhaW5zIHRoZSBhYnNvbHV0ZSAodW5zaWduZWQpIHZhbHVlcyBvZiB0aGUgcHJvdmlkZWQgbWF0cml4J3MgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IG1hdHJpeCBUaGUgbWF0cml4IHdpdGggc2lnbmVkIGVsZW1lbnRzLgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtNYXRyaXgyfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWJzKG1hdHJpeCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1hdHJpeCIsIG1hdHJpeCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHRbMF0gPSBNYXRoLmFicyhtYXRyaXhbMF0pOwogICAgICAgICAgcmVzdWx0WzFdID0gTWF0aC5hYnMobWF0cml4WzFdKTsKICAgICAgICAgIHJlc3VsdFsyXSA9IE1hdGguYWJzKG1hdHJpeFsyXSk7CiAgICAgICAgICByZXN1bHRbM10gPSBNYXRoLmFicyhtYXRyaXhbM10pOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIG1hdHJpY2VzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gW2xlZnRdIFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBbcmlnaHRdIFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8Y29kZT50cnVlPC9jb2RlPiBpZiBsZWZ0IGFuZCByaWdodCBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFscyhsZWZ0LCByaWdodCkgewogICAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIGxlZnRbMF0gPT09IHJpZ2h0WzBdICYmIGxlZnRbMV0gPT09IHJpZ2h0WzFdICYmIGxlZnRbMl0gPT09IHJpZ2h0WzJdICYmIGxlZnRbM10gPT09IHJpZ2h0WzNdOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyBwcm92aWRlZCBtYXRyaXggYW5kIGFycmF5LCBzdGFydGluZyBmcm9tIGEgZ2l2ZW4gYXJyYXkgb2Zmc2V0LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBtYXRyaXgKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBhcnJheQogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQKICAgICAgICAgKiBAaWdub3JlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0FycmF5KG1hdHJpeCwgYXJyYXksIG9mZnNldCkgewogICAgICAgICAgcmV0dXJuIG1hdHJpeFswXSA9PT0gYXJyYXlbb2Zmc2V0XSAmJiBtYXRyaXhbMV0gPT09IGFycmF5W29mZnNldCArIDFdICYmIG1hdHJpeFsyXSA9PT0gYXJyYXlbb2Zmc2V0ICsgMl0gJiYgbWF0cml4WzNdID09PSBhcnJheVtvZmZzZXQgKyAzXTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhlIHByb3ZpZGVkIG1hdHJpY2VzIGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sCiAgICAgICAgICogPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gW2xlZnRdIFRoZSBmaXJzdCBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBbcmlnaHRdIFRoZSBzZWNvbmQgbWF0cml4LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZXBzaWxvbj0wXSBUaGUgZXBzaWxvbiB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIGxlZnQgYW5kIHJpZ2h0IGFyZSB3aXRoaW4gdGhlIHByb3ZpZGVkIGVwc2lsb24sIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0Vwc2lsb24obGVmdCwgcmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIGVwc2lsb24gPSBlcHNpbG9uID8/IDA7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgTWF0aC5hYnMobGVmdFswXSAtIHJpZ2h0WzBdKSA8PSBlcHNpbG9uICYmIE1hdGguYWJzKGxlZnRbMV0gLSByaWdodFsxXSkgPD0gZXBzaWxvbiAmJiBNYXRoLmFicyhsZWZ0WzJdIC0gcmlnaHRbMl0pIDw9IGVwc2lsb24gJiYgTWF0aC5hYnMobGVmdFszXSAtIHJpZ2h0WzNdKSA8PSBlcHNpbG9uOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBudW1iZXIgb2YgaXRlbXMgaW4gdGhlIGNvbGxlY3Rpb24uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqLwogICAgICAgIGdldCBsZW5ndGgoKSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDIucGFja2VkTGVuZ3RoOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIHRoZSBwcm92aWRlZCBNYXRyaXgyIGluc3RhbmNlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXgyfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7TWF0cml4Mn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgTWF0cml4MiBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBjbG9uZShyZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBfTWF0cml4Mi5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb21wYXJlcyB0aGlzIG1hdHJpeCB0byB0aGUgcHJvdmlkZWQgbWF0cml4IGNvbXBvbmVudHdpc2UgYW5kIHJldHVybnMKICAgICAgICAgKiA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGV5IGFyZSBlcXVhbCwgPGNvZGU+ZmFsc2U8L2NvZGU+IG90aGVyd2lzZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7TWF0cml4Mn0gW3JpZ2h0XSBUaGUgcmlnaHQgaGFuZCBzaWRlIG1hdHJpeC4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgZXF1YWwsIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICovCiAgICAgICAgZXF1YWxzKHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gX01hdHJpeDIuZXF1YWxzKHRoaXMsIHJpZ2h0KTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcGFyZXMgdGhpcyBtYXRyaXggdG8gdGhlIHByb3ZpZGVkIG1hdHJpeCBjb21wb25lbnR3aXNlIGFuZCByZXR1cm5zCiAgICAgICAgICogPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLAogICAgICAgICAqIDxjb2RlPmZhbHNlPC9jb2RlPiBvdGhlcndpc2UuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge01hdHJpeDJ9IFtyaWdodF0gVGhlIHJpZ2h0IGhhbmQgc2lkZSBtYXRyaXguCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtlcHNpbG9uPTBdIFRoZSBlcHNpbG9uIHRvIHVzZSBmb3IgZXF1YWxpdHkgdGVzdGluZy4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhleSBhcmUgd2l0aGluIHRoZSBwcm92aWRlZCBlcHNpbG9uLCA8Y29kZT5mYWxzZTwvY29kZT4gb3RoZXJ3aXNlLgogICAgICAgICAqLwogICAgICAgIGVxdWFsc0Vwc2lsb24ocmlnaHQsIGVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiBfTWF0cml4Mi5lcXVhbHNFcHNpbG9uKHRoaXMsIHJpZ2h0LCBlcHNpbG9uKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhpcyBNYXRyaXggd2l0aCBlYWNoIHJvdyBiZWluZwogICAgICAgICAqIG9uIGEgc2VwYXJhdGUgbGluZSBhbmQgaW4gdGhlIGZvcm1hdCAnKGNvbHVtbjAsIGNvbHVtbjEpJy4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgcHJvdmlkZWQgTWF0cml4IHdpdGggZWFjaCByb3cgYmVpbmcgb24gYSBzZXBhcmF0ZSBsaW5lIGFuZCBpbiB0aGUgZm9ybWF0ICcoY29sdW1uMCwgY29sdW1uMSknLgogICAgICAgICAqLwogICAgICAgIHRvU3RyaW5nKCkgewogICAgICAgICAgcmV0dXJuIGAoJHt0aGlzWzBdfSwgJHt0aGlzWzJdfSkKKCR7dGhpc1sxXX0sICR7dGhpc1szXX0pYDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIE1hdHJpeDIucGFja2VkTGVuZ3RoID0gNDsKICAgICAgTWF0cml4Mi5mcm9tQXJyYXkgPSBNYXRyaXgyLnVucGFjazsKICAgICAgTWF0cml4Mi5JREVOVElUWSA9IE9iamVjdC5mcmVlemUobmV3IE1hdHJpeDIoMSwgMCwgMCwgMSkpOwogICAgICBNYXRyaXgyLlpFUk8gPSBPYmplY3QuZnJlZXplKG5ldyBNYXRyaXgyKDAsIDAsIDAsIDApKTsKICAgICAgTWF0cml4Mi5DT0xVTU4wUk9XMCA9IDA7CiAgICAgIE1hdHJpeDIuQ09MVU1OMFJPVzEgPSAxOwogICAgICBNYXRyaXgyLkNPTFVNTjFST1cwID0gMjsKICAgICAgTWF0cml4Mi5DT0xVTU4xUk9XMSA9IDM7CiAgICAgIHNjYWxlU2NyYXRjaDEzID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY2FsZVNjcmF0Y2gyMyA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENvbHVtbjMgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjYWxlU2NyYXRjaDMzID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY2FsZVNjcmF0Y2g0MyA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NhbGVTY3JhdGNoNTMgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIE1hdHJpeDJfZGVmYXVsdCA9IE1hdHJpeDI7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QcmltaXRpdmVUeXBlLmpzCiAgdmFyIFByaW1pdGl2ZVR5cGUsIFByaW1pdGl2ZVR5cGVfZGVmYXVsdDsKICB2YXIgaW5pdF9QcmltaXRpdmVUeXBlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QcmltaXRpdmVUeXBlLmpzIigpIHsKICAgICAgaW5pdF9XZWJHTENvbnN0YW50cygpOwogICAgICBQcmltaXRpdmVUeXBlID0gewogICAgICAgIC8qKgogICAgICAgICAqIFBvaW50cyBwcmltaXRpdmUgd2hlcmUgZWFjaCB2ZXJ0ZXggKG9yIGluZGV4KSBpcyBhIHNlcGFyYXRlIHBvaW50LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBQT0lOVFM6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUE9JTlRTLAogICAgICAgIC8qKgogICAgICAgICAqIExpbmVzIHByaW1pdGl2ZSB3aGVyZSBlYWNoIHR3byB2ZXJ0aWNlcyAob3IgaW5kaWNlcykgaXMgYSBsaW5lIHNlZ21lbnQuICBMaW5lIHNlZ21lbnRzIGFyZSBub3QgbmVjZXNzYXJpbHkgY29ubmVjdGVkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBMSU5FUzogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5MSU5FUywKICAgICAgICAvKioKICAgICAgICAgKiBMaW5lIGxvb3AgcHJpbWl0aXZlIHdoZXJlIGVhY2ggdmVydGV4IChvciBpbmRleCkgYWZ0ZXIgdGhlIGZpcnN0IGNvbm5lY3RzIGEgbGluZSB0bwogICAgICAgICAqIHRoZSBwcmV2aW91cyB2ZXJ0ZXgsIGFuZCB0aGUgbGFzdCB2ZXJ0ZXggaW1wbGljaXRseSBjb25uZWN0cyB0byB0aGUgZmlyc3QuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIExJTkVfTE9PUDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5MSU5FX0xPT1AsCiAgICAgICAgLyoqCiAgICAgICAgICogTGluZSBzdHJpcCBwcmltaXRpdmUgd2hlcmUgZWFjaCB2ZXJ0ZXggKG9yIGluZGV4KSBhZnRlciB0aGUgZmlyc3QgY29ubmVjdHMgYSBsaW5lIHRvIHRoZSBwcmV2aW91cyB2ZXJ0ZXguCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIExJTkVfU1RSSVA6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuTElORV9TVFJJUCwKICAgICAgICAvKioKICAgICAgICAgKiBUcmlhbmdsZXMgcHJpbWl0aXZlIHdoZXJlIGVhY2ggdGhyZWUgdmVydGljZXMgKG9yIGluZGljZXMpIGlzIGEgdHJpYW5nbGUuICBUcmlhbmdsZXMgZG8gbm90IG5lY2Vzc2FyaWx5IHNoYXJlIGVkZ2VzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBUUklBTkdMRVM6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVFJJQU5HTEVTLAogICAgICAgIC8qKgogICAgICAgICAqIFRyaWFuZ2xlIHN0cmlwIHByaW1pdGl2ZSB3aGVyZSBlYWNoIHZlcnRleCAob3IgaW5kZXgpIGFmdGVyIHRoZSBmaXJzdCB0d28gY29ubmVjdCB0bwogICAgICAgICAqIHRoZSBwcmV2aW91cyB0d28gdmVydGljZXMgZm9ybWluZyBhIHRyaWFuZ2xlLiAgRm9yIGV4YW1wbGUsIHRoaXMgY2FuIGJlIHVzZWQgdG8gbW9kZWwgYSB3YWxsLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBUUklBTkdMRV9TVFJJUDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5UUklBTkdMRV9TVFJJUCwKICAgICAgICAvKioKICAgICAgICAgKiBUcmlhbmdsZSBmYW4gcHJpbWl0aXZlIHdoZXJlIGVhY2ggdmVydGV4IChvciBpbmRleCkgYWZ0ZXIgdGhlIGZpcnN0IHR3byBjb25uZWN0IHRvCiAgICAgICAgICogdGhlIHByZXZpb3VzIHZlcnRleCBhbmQgdGhlIGZpcnN0IHZlcnRleCBmb3JtaW5nIGEgdHJpYW5nbGUuICBGb3IgZXhhbXBsZSwgdGhpcyBjYW4gYmUgdXNlZAogICAgICAgICAqIHRvIG1vZGVsIGEgY29uZSBvciBjaXJjbGUuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFRSSUFOR0xFX0ZBTjogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5UUklBTkdMRV9GQU4KICAgICAgfTsKICAgICAgUHJpbWl0aXZlVHlwZS5pc0xpbmVzID0gZnVuY3Rpb24ocHJpbWl0aXZlVHlwZSkgewogICAgICAgIHJldHVybiBwcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlLkxJTkVTIHx8IHByaW1pdGl2ZVR5cGUgPT09IFByaW1pdGl2ZVR5cGUuTElORV9MT09QIHx8IHByaW1pdGl2ZVR5cGUgPT09IFByaW1pdGl2ZVR5cGUuTElORV9TVFJJUDsKICAgICAgfTsKICAgICAgUHJpbWl0aXZlVHlwZS5pc1RyaWFuZ2xlcyA9IGZ1bmN0aW9uKHByaW1pdGl2ZVR5cGUpIHsKICAgICAgICByZXR1cm4gcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5UUklBTkdMRVMgfHwgcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5UUklBTkdMRV9TVFJJUCB8fCBwcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlLlRSSUFOR0xFX0ZBTjsKICAgICAgfTsKICAgICAgUHJpbWl0aXZlVHlwZS52YWxpZGF0ZSA9IGZ1bmN0aW9uKHByaW1pdGl2ZVR5cGUpIHsKICAgICAgICByZXR1cm4gcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5QT0lOVFMgfHwgcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5MSU5FUyB8fCBwcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlLkxJTkVfTE9PUCB8fCBwcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlLkxJTkVfU1RSSVAgfHwgcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5UUklBTkdMRVMgfHwgcHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZS5UUklBTkdMRV9TVFJJUCB8fCBwcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlLlRSSUFOR0xFX0ZBTjsKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShQcmltaXRpdmVUeXBlKTsKICAgICAgUHJpbWl0aXZlVHlwZV9kZWZhdWx0ID0gUHJpbWl0aXZlVHlwZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0dlb21ldHJ5LmpzCiAgZnVuY3Rpb24gR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zLmF0dHJpYnV0ZXMiLCBvcHRpb25zLmF0dHJpYnV0ZXMpOwogICAgdGhpcy5hdHRyaWJ1dGVzID0gb3B0aW9ucy5hdHRyaWJ1dGVzOwogICAgdGhpcy5pbmRpY2VzID0gb3B0aW9ucy5pbmRpY2VzOwogICAgdGhpcy5wcmltaXRpdmVUeXBlID0gb3B0aW9ucy5wcmltaXRpdmVUeXBlID8/IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVM7CiAgICB0aGlzLmJvdW5kaW5nU3BoZXJlID0gb3B0aW9ucy5ib3VuZGluZ1NwaGVyZTsKICAgIHRoaXMuZ2VvbWV0cnlUeXBlID0gb3B0aW9ucy5nZW9tZXRyeVR5cGUgPz8gR2VvbWV0cnlUeXBlX2RlZmF1bHQuTk9ORTsKICAgIHRoaXMuYm91bmRpbmdTcGhlcmVDViA9IG9wdGlvbnMuYm91bmRpbmdTcGhlcmVDVjsKICAgIHRoaXMub2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgfQogIHZhciByZWN0YW5nbGVDZW50ZXJTY3JhdGNoLCBlbnVDZW50ZXJTY3JhdGNoLCBmaXhlZEZyYW1lVG9FbnVTY3JhdGNoLCBib3VuZGluZ1JlY3RhbmdsZVBvaW50c0NhcnRvZ3JhcGhpY1NjcmF0Y2gsIGJvdW5kaW5nUmVjdGFuZ2xlUG9pbnRzRW51U2NyYXRjaCwgcG9pbnRzMkRTY3JhdGNoLCBwb2ludEVudVNjcmF0Y2gsIGVudVJvdGF0aW9uU2NyYXRjaCwgZW51Um90YXRpb25NYXRyaXhTY3JhdGNoLCByb3RhdGlvbjJEU2NyYXRjaCwgR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9HZW9tZXRyeVR5cGUoKTsKICAgICAgaW5pdF9NYXRyaXgyKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1RyYW5zZm9ybXMoKTsKICAgICAgR2VvbWV0cnkuY29tcHV0ZU51bWJlck9mVmVydGljZXMgPSBmdW5jdGlvbihnZW9tZXRyeSkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZ2VvbWV0cnkiLCBnZW9tZXRyeSk7CiAgICAgICAgbGV0IG51bWJlck9mVmVydGljZXMgPSAtMTsKICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5IGluIGdlb21ldHJ5LmF0dHJpYnV0ZXMpIHsKICAgICAgICAgIGlmIChnZW9tZXRyeS5hdHRyaWJ1dGVzLmhhc093blByb3BlcnR5KHByb3BlcnR5KSAmJiBkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkuYXR0cmlidXRlc1twcm9wZXJ0eV0pICYmIGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5hdHRyaWJ1dGVzW3Byb3BlcnR5XS52YWx1ZXMpKSB7CiAgICAgICAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IGdlb21ldHJ5LmF0dHJpYnV0ZXNbcHJvcGVydHldOwogICAgICAgICAgICBjb25zdCBudW0gPSBhdHRyaWJ1dGUudmFsdWVzLmxlbmd0aCAvIGF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlOwogICAgICAgICAgICBpZiAobnVtYmVyT2ZWZXJ0aWNlcyAhPT0gbnVtICYmIG51bWJlck9mVmVydGljZXMgIT09IC0xKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgICAiQWxsIGF0dHJpYnV0ZSBsaXN0cyBtdXN0IGhhdmUgdGhlIHNhbWUgbnVtYmVyIG9mIGF0dHJpYnV0ZXMuIgogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbnVtYmVyT2ZWZXJ0aWNlcyA9IG51bTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG51bWJlck9mVmVydGljZXM7CiAgICAgIH07CiAgICAgIHJlY3RhbmdsZUNlbnRlclNjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgZW51Q2VudGVyU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZml4ZWRGcmFtZVRvRW51U2NyYXRjaCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgYm91bmRpbmdSZWN0YW5nbGVQb2ludHNDYXJ0b2dyYXBoaWNTY3JhdGNoID0gWwogICAgICAgIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpCiAgICAgIF07CiAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlUG9pbnRzRW51U2NyYXRjaCA9IFsKICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKQogICAgICBdOwogICAgICBwb2ludHMyRFNjcmF0Y2ggPSBbbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLCBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKV07CiAgICAgIHBvaW50RW51U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZW51Um90YXRpb25TY3JhdGNoID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBlbnVSb3RhdGlvbk1hdHJpeFNjcmF0Y2ggPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIHJvdGF0aW9uMkRTY3JhdGNoID0gbmV3IE1hdHJpeDJfZGVmYXVsdCgpOwogICAgICBHZW9tZXRyeS5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cyA9IGZ1bmN0aW9uKHBvc2l0aW9ucywgc3RSb3RhdGlvbiwgZWxsaXBzb2lkLCBib3VuZGluZ1JlY3RhbmdsZSkgewogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCByZWN0YW5nbGVDZW50ZXIgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgICAgICBib3VuZGluZ1JlY3RhbmdsZSwKICAgICAgICAgIHJlY3RhbmdsZUNlbnRlclNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IGVudUNlbnRlciA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LnRvQ2FydGVzaWFuKAogICAgICAgICAgcmVjdGFuZ2xlQ2VudGVyLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZW51Q2VudGVyU2NyYXRjaAogICAgICAgICk7CiAgICAgICAgY29uc3QgZW51VG9GaXhlZEZyYW1lID0gVHJhbnNmb3Jtc19kZWZhdWx0LmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKAogICAgICAgICAgZW51Q2VudGVyLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZml4ZWRGcmFtZVRvRW51U2NyYXRjaAogICAgICAgICk7CiAgICAgICAgY29uc3QgZml4ZWRGcmFtZVRvRW51ID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2UoCiAgICAgICAgICBlbnVUb0ZpeGVkRnJhbWUsCiAgICAgICAgICBmaXhlZEZyYW1lVG9FbnVTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBib3VuZGluZ1BvaW50c0VudSA9IGJvdW5kaW5nUmVjdGFuZ2xlUG9pbnRzRW51U2NyYXRjaDsKICAgICAgICBjb25zdCBib3VuZGluZ1BvaW50c0NhcnRvID0gYm91bmRpbmdSZWN0YW5nbGVQb2ludHNDYXJ0b2dyYXBoaWNTY3JhdGNoOwogICAgICAgIGJvdW5kaW5nUG9pbnRzQ2FydG9bMF0ubG9uZ2l0dWRlID0gYm91bmRpbmdSZWN0YW5nbGUud2VzdDsKICAgICAgICBib3VuZGluZ1BvaW50c0NhcnRvWzBdLmxhdGl0dWRlID0gYm91bmRpbmdSZWN0YW5nbGUuc291dGg7CiAgICAgICAgYm91bmRpbmdQb2ludHNDYXJ0b1sxXS5sb25naXR1ZGUgPSBib3VuZGluZ1JlY3RhbmdsZS53ZXN0OwogICAgICAgIGJvdW5kaW5nUG9pbnRzQ2FydG9bMV0ubGF0aXR1ZGUgPSBib3VuZGluZ1JlY3RhbmdsZS5ub3J0aDsKICAgICAgICBib3VuZGluZ1BvaW50c0NhcnRvWzJdLmxvbmdpdHVkZSA9IGJvdW5kaW5nUmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgYm91bmRpbmdQb2ludHNDYXJ0b1syXS5sYXRpdHVkZSA9IGJvdW5kaW5nUmVjdGFuZ2xlLnNvdXRoOwogICAgICAgIGxldCBwb3NFbnUgPSBwb2ludEVudVNjcmF0Y2g7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgMzsgaTIrKykgewogICAgICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQudG9DYXJ0ZXNpYW4oYm91bmRpbmdQb2ludHNDYXJ0b1tpMl0sIGVsbGlwc29pZCwgcG9zRW51KTsKICAgICAgICAgIHBvc0VudSA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnRBc1ZlY3RvcihmaXhlZEZyYW1lVG9FbnUsIHBvc0VudSwgcG9zRW51KTsKICAgICAgICAgIGJvdW5kaW5nUG9pbnRzRW51W2kyXS54ID0gcG9zRW51Lng7CiAgICAgICAgICBib3VuZGluZ1BvaW50c0VudVtpMl0ueSA9IHBvc0VudS55OwogICAgICAgIH0KICAgICAgICBjb25zdCByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwKICAgICAgICAgIC1zdFJvdGF0aW9uLAogICAgICAgICAgZW51Um90YXRpb25TY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCB0ZXh0dXJlTWF0cml4ID0gTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKAogICAgICAgICAgcm90YXRpb24sCiAgICAgICAgICBlbnVSb3RhdGlvbk1hdHJpeFNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgbGV0IGVudU1pblggPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IGVudU1pblkgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IGVudU1heFggPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IGVudU1heFkgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgcG9zaXRpb25zTGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBwb3NFbnUgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50QXNWZWN0b3IoCiAgICAgICAgICAgIGZpeGVkRnJhbWVUb0VudSwKICAgICAgICAgICAgcG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgcG9zRW51CiAgICAgICAgICApOwogICAgICAgICAgcG9zRW51ID0gTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IodGV4dHVyZU1hdHJpeCwgcG9zRW51LCBwb3NFbnUpOwogICAgICAgICAgZW51TWluWCA9IE1hdGgubWluKGVudU1pblgsIHBvc0VudS54KTsKICAgICAgICAgIGVudU1pblkgPSBNYXRoLm1pbihlbnVNaW5ZLCBwb3NFbnUueSk7CiAgICAgICAgICBlbnVNYXhYID0gTWF0aC5tYXgoZW51TWF4WCwgcG9zRW51LngpOwogICAgICAgICAgZW51TWF4WSA9IE1hdGgubWF4KGVudU1heFksIHBvc0VudS55KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdG9EZXNpcmVkSW5Db21wdXRlZCA9IE1hdHJpeDJfZGVmYXVsdC5mcm9tUm90YXRpb24oCiAgICAgICAgICBzdFJvdGF0aW9uLAogICAgICAgICAgcm90YXRpb24yRFNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IHBvaW50czJEID0gcG9pbnRzMkRTY3JhdGNoOwogICAgICAgIHBvaW50czJEWzBdLnggPSBlbnVNaW5YOwogICAgICAgIHBvaW50czJEWzBdLnkgPSBlbnVNaW5ZOwogICAgICAgIHBvaW50czJEWzFdLnggPSBlbnVNaW5YOwogICAgICAgIHBvaW50czJEWzFdLnkgPSBlbnVNYXhZOwogICAgICAgIHBvaW50czJEWzJdLnggPSBlbnVNYXhYOwogICAgICAgIHBvaW50czJEWzJdLnkgPSBlbnVNaW5ZOwogICAgICAgIGNvbnN0IGJvdW5kaW5nRW51TWluID0gYm91bmRpbmdQb2ludHNFbnVbMF07CiAgICAgICAgY29uc3QgYm91bmRpbmdQb2ludHNXaWR0aCA9IGJvdW5kaW5nUG9pbnRzRW51WzJdLnggLSBib3VuZGluZ0VudU1pbi54OwogICAgICAgIGNvbnN0IGJvdW5kaW5nUG9pbnRzSGVpZ2h0ID0gYm91bmRpbmdQb2ludHNFbnVbMV0ueSAtIGJvdW5kaW5nRW51TWluLnk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgMzsgaTIrKykgewogICAgICAgICAgY29uc3QgcG9pbnQyRCA9IHBvaW50czJEW2kyXTsKICAgICAgICAgIE1hdHJpeDJfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKHRvRGVzaXJlZEluQ29tcHV0ZWQsIHBvaW50MkQsIHBvaW50MkQpOwogICAgICAgICAgcG9pbnQyRC54ID0gKHBvaW50MkQueCAtIGJvdW5kaW5nRW51TWluLngpIC8gYm91bmRpbmdQb2ludHNXaWR0aDsKICAgICAgICAgIHBvaW50MkQueSA9IChwb2ludDJELnkgLSBib3VuZGluZ0VudU1pbi55KSAvIGJvdW5kaW5nUG9pbnRzSGVpZ2h0OwogICAgICAgIH0KICAgICAgICBjb25zdCBtaW5YWUNvcm5lciA9IHBvaW50czJEWzBdOwogICAgICAgIGNvbnN0IG1heFlDb3JuZXIgPSBwb2ludHMyRFsxXTsKICAgICAgICBjb25zdCBtYXhYQ29ybmVyID0gcG9pbnRzMkRbMl07CiAgICAgICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5KDYpOwogICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5wYWNrKG1pblhZQ29ybmVyLCByZXN1bHQpOwogICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5wYWNrKG1heFlDb3JuZXIsIHJlc3VsdCwgMik7CiAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2sobWF4WENvcm5lciwgcmVzdWx0LCA0KTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBHZW9tZXRyeV9kZWZhdWx0ID0gR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9tZXRyeUF0dHJpYnV0ZS5qcwogIGZ1bmN0aW9uIEdlb21ldHJ5QXR0cmlidXRlKG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuY29tcG9uZW50RGF0YXR5cGUpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcHRpb25zLmNvbXBvbmVudERhdGF0eXBlIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5jb21wb25lbnRzUGVyQXR0cmlidXRlKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy5jb21wb25lbnRzUGVyQXR0cmlidXRlIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKG9wdGlvbnMuY29tcG9uZW50c1BlckF0dHJpYnV0ZSA8IDEgfHwgb3B0aW9ucy5jb21wb25lbnRzUGVyQXR0cmlidXRlID4gNCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAib3B0aW9ucy5jb21wb25lbnRzUGVyQXR0cmlidXRlIG11c3QgYmUgYmV0d2VlbiAxIGFuZCA0LiIKICAgICAgKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMudmFsdWVzKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy52YWx1ZXMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICB0aGlzLmNvbXBvbmVudERhdGF0eXBlID0gb3B0aW9ucy5jb21wb25lbnREYXRhdHlwZTsKICAgIHRoaXMuY29tcG9uZW50c1BlckF0dHJpYnV0ZSA9IG9wdGlvbnMuY29tcG9uZW50c1BlckF0dHJpYnV0ZTsKICAgIHRoaXMubm9ybWFsaXplID0gb3B0aW9ucy5ub3JtYWxpemUgPz8gZmFsc2U7CiAgICB0aGlzLnZhbHVlcyA9IG9wdGlvbnMudmFsdWVzOwogIH0KICB2YXIgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnlBdHRyaWJ1dGUuanMiKCkgewogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0ID0gR2VvbWV0cnlBdHRyaWJ1dGU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9tZXRyeUF0dHJpYnV0ZXMuanMKICBmdW5jdGlvbiBHZW9tZXRyeUF0dHJpYnV0ZXMob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgdGhpcy5wb3NpdGlvbiA9IG9wdGlvbnMucG9zaXRpb247CiAgICB0aGlzLm5vcm1hbCA9IG9wdGlvbnMubm9ybWFsOwogICAgdGhpcy5zdCA9IG9wdGlvbnMuc3Q7CiAgICB0aGlzLmJpdGFuZ2VudCA9IG9wdGlvbnMuYml0YW5nZW50OwogICAgdGhpcy50YW5nZW50ID0gb3B0aW9ucy50YW5nZW50OwogICAgdGhpcy5jb2xvciA9IG9wdGlvbnMuY29sb3I7CiAgfQogIHZhciBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0dlb21ldHJ5QXR0cmlidXRlcy5qcyIoKSB7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0ID0gR2VvbWV0cnlBdHRyaWJ1dGVzOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1NjZW5lL0F0dHJpYnV0ZVR5cGUuanMKICB2YXIgQXR0cmlidXRlVHlwZSwgQXR0cmlidXRlVHlwZV9kZWZhdWx0OwogIHZhciBpbml0X0F0dHJpYnV0ZVR5cGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9TY2VuZS9BdHRyaWJ1dGVUeXBlLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRlc2lhbjQoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0cml4MigpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIEF0dHJpYnV0ZVR5cGUgPSB7CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGF0dHJpYnV0ZSBpcyBhIHNpbmdsZSBjb21wb25lbnQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFNDQUxBUjogIlNDQUxBUiIsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGF0dHJpYnV0ZSBpcyBhIHR3by1jb21wb25lbnQgdmVjdG9yLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge3N0cmluZ30KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBWRUMyOiAiVkVDMiIsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGF0dHJpYnV0ZSBpcyBhIHRocmVlLWNvbXBvbmVudCB2ZWN0b3IuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFZFQzM6ICJWRUMzIiwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgYXR0cmlidXRlIGlzIGEgZm91ci1jb21wb25lbnQgdmVjdG9yLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge3N0cmluZ30KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBWRUM0OiAiVkVDNCIsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGF0dHJpYnV0ZSBpcyBhIDJ4MiBtYXRyaXguCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIE1BVDI6ICJNQVQyIiwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgYXR0cmlidXRlIGlzIGEgM3gzIG1hdHJpeC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtzdHJpbmd9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgTUFUMzogIk1BVDMiLAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBhdHRyaWJ1dGUgaXMgYSA0eDQgbWF0cml4LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge3N0cmluZ30KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBNQVQ0OiAiTUFUNCIKICAgICAgfTsKICAgICAgQXR0cmlidXRlVHlwZS5nZXRNYXRoVHlwZSA9IGZ1bmN0aW9uKGF0dHJpYnV0ZVR5cGUpIHsKICAgICAgICBzd2l0Y2ggKGF0dHJpYnV0ZVR5cGUpIHsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5TQ0FMQVI6CiAgICAgICAgICAgIHJldHVybiBOdW1iZXI7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuVkVDMjoKICAgICAgICAgICAgcmV0dXJuIENhcnRlc2lhbjJfZGVmYXVsdDsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5WRUMzOgogICAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0OwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzQ6CiAgICAgICAgICAgIHJldHVybiBDYXJ0ZXNpYW40X2RlZmF1bHQ7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMjoKICAgICAgICAgICAgcmV0dXJuIE1hdHJpeDJfZGVmYXVsdDsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5NQVQzOgogICAgICAgICAgICByZXR1cm4gTWF0cml4M19kZWZhdWx0OwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLk1BVDQ6CiAgICAgICAgICAgIHJldHVybiBNYXRyaXg0X2RlZmF1bHQ7CiAgICAgICAgICAvLz4+aW5jbHVkZVN0YXJ0KCdkZWJ1ZycsIHByYWdtYXMuZGVidWcpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZVR5cGUgaXMgbm90IGEgdmFsaWQgdmFsdWUuIik7CiAgICAgICAgfQogICAgICB9OwogICAgICBBdHRyaWJ1dGVUeXBlLmdldE51bWJlck9mQ29tcG9uZW50cyA9IGZ1bmN0aW9uKGF0dHJpYnV0ZVR5cGUpIHsKICAgICAgICBzd2l0Y2ggKGF0dHJpYnV0ZVR5cGUpIHsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5TQ0FMQVI6CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzI6CiAgICAgICAgICAgIHJldHVybiAyOwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzM6CiAgICAgICAgICAgIHJldHVybiAzOwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzQ6CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMjoKICAgICAgICAgICAgcmV0dXJuIDQ7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMzoKICAgICAgICAgICAgcmV0dXJuIDk7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUNDoKICAgICAgICAgICAgcmV0dXJuIDE2OwogICAgICAgICAgLy8+PmluY2x1ZGVTdGFydCgnZGVidWcnLCBwcmFnbWFzLmRlYnVnKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhdHRyaWJ1dGVUeXBlIGlzIG5vdCBhIHZhbGlkIHZhbHVlLiIpOwogICAgICAgIH0KICAgICAgfTsKICAgICAgQXR0cmlidXRlVHlwZS5nZXRBdHRyaWJ1dGVMb2NhdGlvbkNvdW50ID0gZnVuY3Rpb24oYXR0cmlidXRlVHlwZSkgewogICAgICAgIHN3aXRjaCAoYXR0cmlidXRlVHlwZSkgewogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlNDQUxBUjoKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5WRUMyOgogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzM6CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuVkVDNDoKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMjoKICAgICAgICAgICAgcmV0dXJuIDI7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMzoKICAgICAgICAgICAgcmV0dXJuIDM7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUNDoKICAgICAgICAgICAgcmV0dXJuIDQ7CiAgICAgICAgICAvLz4+aW5jbHVkZVN0YXJ0KCdkZWJ1ZycsIHByYWdtYXMuZGVidWcpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZVR5cGUgaXMgbm90IGEgdmFsaWQgdmFsdWUuIik7CiAgICAgICAgfQogICAgICB9OwogICAgICBBdHRyaWJ1dGVUeXBlLmdldEdsc2xUeXBlID0gZnVuY3Rpb24oYXR0cmlidXRlVHlwZSkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLnN0cmluZygiYXR0cmlidXRlVHlwZSIsIGF0dHJpYnV0ZVR5cGUpOwogICAgICAgIHN3aXRjaCAoYXR0cmlidXRlVHlwZSkgewogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlNDQUxBUjoKICAgICAgICAgICAgcmV0dXJuICJmbG9hdCI7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuVkVDMjoKICAgICAgICAgICAgcmV0dXJuICJ2ZWMyIjsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5WRUMzOgogICAgICAgICAgICByZXR1cm4gInZlYzMiOwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLlZFQzQ6CiAgICAgICAgICAgIHJldHVybiAidmVjNCI7CiAgICAgICAgICBjYXNlIEF0dHJpYnV0ZVR5cGUuTUFUMjoKICAgICAgICAgICAgcmV0dXJuICJtYXQyIjsKICAgICAgICAgIGNhc2UgQXR0cmlidXRlVHlwZS5NQVQzOgogICAgICAgICAgICByZXR1cm4gIm1hdDMiOwogICAgICAgICAgY2FzZSBBdHRyaWJ1dGVUeXBlLk1BVDQ6CiAgICAgICAgICAgIHJldHVybiAibWF0NCI7CiAgICAgICAgICAvLz4+aW5jbHVkZVN0YXJ0KCdkZWJ1ZycsIHByYWdtYXMuZGVidWcpOwogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZVR5cGUgaXMgbm90IGEgdmFsaWQgdmFsdWUuIik7CiAgICAgICAgfQogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKEF0dHJpYnV0ZVR5cGUpOwogICAgICBBdHRyaWJ1dGVUeXBlX2RlZmF1bHQgPSBBdHRyaWJ1dGVUeXBlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQXR0cmlidXRlQ29tcHJlc3Npb24uanMKICBmdW5jdGlvbiBmb3JjZVVpbnQ4KHZhbHVlKSB7CiAgICB1aW50OEZvcmNlQXJyYXlbMF0gPSB2YWx1ZTsKICAgIHJldHVybiB1aW50OEZvcmNlQXJyYXlbMF07CiAgfQogIGZ1bmN0aW9uIHppZ1phZ0RlY29kZSh2YWx1ZSkgewogICAgcmV0dXJuIHZhbHVlID4+IDEgXiAtKHZhbHVlICYgMSk7CiAgfQogIHZhciBSSUdIVF9TSElGVDgsIExFRlRfU0hJRlQxNiwgTEVGVF9TSElGVDgsIEF0dHJpYnV0ZUNvbXByZXNzaW9uLCBvY3RFbmNvZGVTY3JhdGNoLCB1aW50OEZvcmNlQXJyYXksIHNjcmF0Y2hFbmNvZGVDYXJ0MiwgQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdDsKICB2YXIgaW5pdF9BdHRyaWJ1dGVDb21wcmVzc2lvbiA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQXR0cmlidXRlQ29tcHJlc3Npb24uanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9BdHRyaWJ1dGVUeXBlKCk7CiAgICAgIFJJR0hUX1NISUZUOCA9IDEgLyAyNTY7CiAgICAgIExFRlRfU0hJRlQxNiA9IDY1NTM2OwogICAgICBMRUZUX1NISUZUOCA9IDI1NjsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24gPSB7fTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RW5jb2RlSW5SYW5nZSA9IGZ1bmN0aW9uKHZlY3RvciwgcmFuZ2VNYXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidmVjdG9yIiwgdmVjdG9yKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgY29uc3QgbWFnU3F1YXJlZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGVTcXVhcmVkKHZlY3Rvcik7CiAgICAgICAgaWYgKE1hdGguYWJzKG1hZ1NxdWFyZWQgLSAxKSA+IE1hdGhfZGVmYXVsdC5FUFNJTE9ONikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZlY3RvciBtdXN0IGJlIG5vcm1hbGl6ZWQuIik7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gdmVjdG9yLnggLyAoTWF0aC5hYnModmVjdG9yLngpICsgTWF0aC5hYnModmVjdG9yLnkpICsgTWF0aC5hYnModmVjdG9yLnopKTsKICAgICAgICByZXN1bHQueSA9IHZlY3Rvci55IC8gKE1hdGguYWJzKHZlY3Rvci54KSArIE1hdGguYWJzKHZlY3Rvci55KSArIE1hdGguYWJzKHZlY3Rvci56KSk7CiAgICAgICAgaWYgKHZlY3Rvci56IDwgMCkgewogICAgICAgICAgY29uc3QgeDIgPSByZXN1bHQueDsKICAgICAgICAgIGNvbnN0IHkyID0gcmVzdWx0Lnk7CiAgICAgICAgICByZXN1bHQueCA9ICgxIC0gTWF0aC5hYnMoeTIpKSAqIE1hdGhfZGVmYXVsdC5zaWduTm90WmVybyh4Mik7CiAgICAgICAgICByZXN1bHQueSA9ICgxIC0gTWF0aC5hYnMoeDIpKSAqIE1hdGhfZGVmYXVsdC5zaWduTm90WmVybyh5Mik7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gTWF0aF9kZWZhdWx0LnRvU05vcm0ocmVzdWx0LngsIHJhbmdlTWF4KTsKICAgICAgICByZXN1bHQueSA9IE1hdGhfZGVmYXVsdC50b1NOb3JtKHJlc3VsdC55LCByYW5nZU1heCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RW5jb2RlID0gZnVuY3Rpb24odmVjdG9yLCByZXN1bHQpIHsKICAgICAgICByZXR1cm4gQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RW5jb2RlSW5SYW5nZSh2ZWN0b3IsIDI1NSwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgb2N0RW5jb2RlU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgdWludDhGb3JjZUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoMSk7CiAgICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdEVuY29kZVRvQ2FydGVzaWFuNCA9IGZ1bmN0aW9uKHZlY3RvciwgcmVzdWx0KSB7CiAgICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RW5jb2RlSW5SYW5nZSh2ZWN0b3IsIDY1NTM1LCBvY3RFbmNvZGVTY3JhdGNoKTsKICAgICAgICByZXN1bHQueCA9IGZvcmNlVWludDgob2N0RW5jb2RlU2NyYXRjaC54ICogUklHSFRfU0hJRlQ4KTsKICAgICAgICByZXN1bHQueSA9IGZvcmNlVWludDgob2N0RW5jb2RlU2NyYXRjaC54KTsKICAgICAgICByZXN1bHQueiA9IGZvcmNlVWludDgob2N0RW5jb2RlU2NyYXRjaC55ICogUklHSFRfU0hJRlQ4KTsKICAgICAgICByZXN1bHQudyA9IGZvcmNlVWludDgob2N0RW5jb2RlU2NyYXRjaC55KTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGVJblJhbmdlID0gZnVuY3Rpb24oeDIsIHkyLCByYW5nZU1heCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGlmICh4MiA8IDAgfHwgeDIgPiByYW5nZU1heCB8fCB5MiA8IDAgfHwgeTIgPiByYW5nZU1heCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGB4IGFuZCB5IG11c3QgYmUgdW5zaWduZWQgbm9ybWFsaXplZCBpbnRlZ2VycyBiZXR3ZWVuIDAgYW5kICR7cmFuZ2VNYXh9YAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnggPSBNYXRoX2RlZmF1bHQuZnJvbVNOb3JtKHgyLCByYW5nZU1heCk7CiAgICAgICAgcmVzdWx0LnkgPSBNYXRoX2RlZmF1bHQuZnJvbVNOb3JtKHkyLCByYW5nZU1heCk7CiAgICAgICAgcmVzdWx0LnogPSAxIC0gKE1hdGguYWJzKHJlc3VsdC54KSArIE1hdGguYWJzKHJlc3VsdC55KSk7CiAgICAgICAgaWYgKHJlc3VsdC56IDwgMCkgewogICAgICAgICAgY29uc3Qgb2xkVlggPSByZXN1bHQueDsKICAgICAgICAgIHJlc3VsdC54ID0gKDEgLSBNYXRoLmFicyhyZXN1bHQueSkpICogTWF0aF9kZWZhdWx0LnNpZ25Ob3RaZXJvKG9sZFZYKTsKICAgICAgICAgIHJlc3VsdC55ID0gKDEgLSBNYXRoLmFicyhvbGRWWCkpICogTWF0aF9kZWZhdWx0LnNpZ25Ob3RaZXJvKHJlc3VsdC55KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmVzdWx0LCByZXN1bHQpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGUgPSBmdW5jdGlvbih4MiwgeTIsIHJlc3VsdCkgewogICAgICAgIHJldHVybiBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGVJblJhbmdlKHgyLCB5MiwgMjU1LCByZXN1bHQpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGVGcm9tQ2FydGVzaWFuNCA9IGZ1bmN0aW9uKGVuY29kZWQsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZW5jb2RlZCIsIGVuY29kZWQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCB4MiA9IGVuY29kZWQueDsKICAgICAgICBjb25zdCB5MiA9IGVuY29kZWQueTsKICAgICAgICBjb25zdCB6MiA9IGVuY29kZWQuejsKICAgICAgICBjb25zdCB3MiA9IGVuY29kZWQudzsKICAgICAgICBpZiAoeDIgPCAwIHx8IHgyID4gMjU1IHx8IHkyIDwgMCB8fCB5MiA+IDI1NSB8fCB6MiA8IDAgfHwgejIgPiAyNTUgfHwgdzIgPCAwIHx8IHcyID4gMjU1KSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgIngsIHksIHosIGFuZCB3IG11c3QgYmUgdW5zaWduZWQgbm9ybWFsaXplZCBpbnRlZ2VycyBiZXR3ZWVuIDAgYW5kIDI1NSIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHhPY3QxNiA9IHgyICogTEVGVF9TSElGVDggKyB5MjsKICAgICAgICBjb25zdCB5T2N0MTYgPSB6MiAqIExFRlRfU0hJRlQ4ICsgdzI7CiAgICAgICAgcmV0dXJuIEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdERlY29kZUluUmFuZ2UoeE9jdDE2LCB5T2N0MTYsIDY1NTM1LCByZXN1bHQpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3RQYWNrRmxvYXQgPSBmdW5jdGlvbihlbmNvZGVkKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJlbmNvZGVkIiwgZW5jb2RlZCk7CiAgICAgICAgcmV0dXJuIDI1NiAqIGVuY29kZWQueCArIGVuY29kZWQueTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVuY29kZUNhcnQyID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3RFbmNvZGVGbG9hdCA9IGZ1bmN0aW9uKHZlY3RvcikgewogICAgICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdEVuY29kZSh2ZWN0b3IsIHNjcmF0Y2hFbmNvZGVDYXJ0Mik7CiAgICAgICAgcmV0dXJuIEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdFBhY2tGbG9hdChzY3JhdGNoRW5jb2RlQ2FydDIpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGVGbG9hdCA9IGZ1bmN0aW9uKHZhbHVlLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIGNvbnN0IHRlbXAgPSB2YWx1ZSAvIDI1NjsKICAgICAgICBjb25zdCB4MiA9IE1hdGguZmxvb3IodGVtcCk7CiAgICAgICAgY29uc3QgeTIgPSAodGVtcCAtIHgyKSAqIDI1NjsKICAgICAgICByZXR1cm4gQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RGVjb2RlKHgyLCB5MiwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0UGFjayA9IGZ1bmN0aW9uKHYxMiwgdjIyLCB2MzIsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjEiLCB2MTIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjIiLCB2MjIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjMiLCB2MzIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCBlbmNvZGVkMSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdEVuY29kZUZsb2F0KHYxMik7CiAgICAgICAgY29uc3QgZW5jb2RlZDIgPSBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3RFbmNvZGVGbG9hdCh2MjIpOwogICAgICAgIGNvbnN0IGVuY29kZWQzID0gQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RW5jb2RlKHYzMiwgc2NyYXRjaEVuY29kZUNhcnQyKTsKICAgICAgICByZXN1bHQueCA9IDY1NTM2ICogZW5jb2RlZDMueCArIGVuY29kZWQxOwogICAgICAgIHJlc3VsdC55ID0gNjU1MzYgKiBlbmNvZGVkMy55ICsgZW5jb2RlZDI7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0VW5wYWNrID0gZnVuY3Rpb24ocGFja2VkLCB2MTIsIHYyMiwgdjMyKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJwYWNrZWQiLCBwYWNrZWQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjEiLCB2MTIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjIiLCB2MjIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidjMiLCB2MzIpOwogICAgICAgIGxldCB0ZW1wID0gcGFja2VkLnggLyA2NTUzNjsKICAgICAgICBjb25zdCB4MiA9IE1hdGguZmxvb3IodGVtcCk7CiAgICAgICAgY29uc3QgZW5jb2RlZEZsb2F0MSA9ICh0ZW1wIC0geDIpICogNjU1MzY7CiAgICAgICAgdGVtcCA9IHBhY2tlZC55IC8gNjU1MzY7CiAgICAgICAgY29uc3QgeTIgPSBNYXRoLmZsb29yKHRlbXApOwogICAgICAgIGNvbnN0IGVuY29kZWRGbG9hdDIgPSAodGVtcCAtIHkyKSAqIDY1NTM2OwogICAgICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uLm9jdERlY29kZUZsb2F0KGVuY29kZWRGbG9hdDEsIHYxMik7CiAgICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24ub2N0RGVjb2RlRmxvYXQoZW5jb2RlZEZsb2F0MiwgdjIyKTsKICAgICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5vY3REZWNvZGUoeDIsIHkyLCB2MzIpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5jb21wcmVzc1RleHR1cmVDb29yZGluYXRlcyA9IGZ1bmN0aW9uKHRleHR1cmVDb29yZGluYXRlcykgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidGV4dHVyZUNvb3JkaW5hdGVzIiwgdGV4dHVyZUNvb3JkaW5hdGVzKTsKICAgICAgICBjb25zdCB4MiA9IHRleHR1cmVDb29yZGluYXRlcy54ICogNDA5NSB8IDA7CiAgICAgICAgY29uc3QgeTIgPSB0ZXh0dXJlQ29vcmRpbmF0ZXMueSAqIDQwOTUgfCAwOwogICAgICAgIHJldHVybiA0MDk2ICogeDIgKyB5MjsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24uZGVjb21wcmVzc1RleHR1cmVDb29yZGluYXRlcyA9IGZ1bmN0aW9uKGNvbXByZXNzZWQsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY29tcHJlc3NlZCIsIGNvbXByZXNzZWQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICBjb25zdCB0ZW1wID0gY29tcHJlc3NlZCAvIDQwOTY7CiAgICAgICAgY29uc3QgeFplcm9UbzQwOTUgPSBNYXRoLmZsb29yKHRlbXApOwogICAgICAgIHJlc3VsdC54ID0geFplcm9UbzQwOTUgLyA0MDk1OwogICAgICAgIHJlc3VsdC55ID0gKGNvbXByZXNzZWQgLSB4WmVyb1RvNDA5NSAqIDQwOTYpIC8gNDA5NTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi56aWdaYWdEZWx0YURlY29kZSA9IGZ1bmN0aW9uKHVCdWZmZXIsIHZCdWZmZXIsIGhlaWdodEJ1ZmZlcikgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidUJ1ZmZlciIsIHVCdWZmZXIpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgidkJ1ZmZlciIsIHZCdWZmZXIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5lcXVhbHMoCiAgICAgICAgICAidUJ1ZmZlci5sZW5ndGgiLAogICAgICAgICAgInZCdWZmZXIubGVuZ3RoIiwKICAgICAgICAgIHVCdWZmZXIubGVuZ3RoLAogICAgICAgICAgdkJ1ZmZlci5sZW5ndGgKICAgICAgICApOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaGVpZ2h0QnVmZmVyKSkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmVxdWFscygKICAgICAgICAgICAgInVCdWZmZXIubGVuZ3RoIiwKICAgICAgICAgICAgImhlaWdodEJ1ZmZlci5sZW5ndGgiLAogICAgICAgICAgICB1QnVmZmVyLmxlbmd0aCwKICAgICAgICAgICAgaGVpZ2h0QnVmZmVyLmxlbmd0aAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY291bnQgPSB1QnVmZmVyLmxlbmd0aDsKICAgICAgICBsZXQgdTQgPSAwOwogICAgICAgIGxldCB2NCA9IDA7CiAgICAgICAgbGV0IGhlaWdodCA9IDA7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGNvdW50OyArK2kyKSB7CiAgICAgICAgICB1NCArPSB6aWdaYWdEZWNvZGUodUJ1ZmZlcltpMl0pOwogICAgICAgICAgdjQgKz0gemlnWmFnRGVjb2RlKHZCdWZmZXJbaTJdKTsKICAgICAgICAgIHVCdWZmZXJbaTJdID0gdTQ7CiAgICAgICAgICB2QnVmZmVyW2kyXSA9IHY0OwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChoZWlnaHRCdWZmZXIpKSB7CiAgICAgICAgICAgIGhlaWdodCArPSB6aWdaYWdEZWNvZGUoaGVpZ2h0QnVmZmVyW2kyXSk7CiAgICAgICAgICAgIGhlaWdodEJ1ZmZlcltpMl0gPSBoZWlnaHQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5kZXF1YW50aXplID0gZnVuY3Rpb24odHlwZWRBcnJheSwgY29tcG9uZW50RGF0YXR5cGUsIHR5cGUsIGNvdW50KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ0eXBlZEFycmF5IiwgdHlwZWRBcnJheSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjb21wb25lbnREYXRhdHlwZSIsIGNvbXBvbmVudERhdGF0eXBlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInR5cGUiLCB0eXBlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImNvdW50IiwgY291bnQpOwogICAgICAgIGNvbnN0IGNvbXBvbmVudHNQZXJBdHRyaWJ1dGUgPSBBdHRyaWJ1dGVUeXBlX2RlZmF1bHQuZ2V0TnVtYmVyT2ZDb21wb25lbnRzKHR5cGUpOwogICAgICAgIGxldCBkaXZpc29yOwogICAgICAgIHN3aXRjaCAoY29tcG9uZW50RGF0YXR5cGUpIHsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5CWVRFOgogICAgICAgICAgICBkaXZpc29yID0gMTI3OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFOgogICAgICAgICAgICBkaXZpc29yID0gMjU1OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5TSE9SVDoKICAgICAgICAgICAgZGl2aXNvciA9IDMyNzY3OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9TSE9SVDoKICAgICAgICAgICAgZGl2aXNvciA9IDY1NTM1OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5JTlQ6CiAgICAgICAgICAgIGRpdmlzb3IgPSAyMTQ3NDgzNjQ3OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9JTlQ6CiAgICAgICAgICAgIGRpdmlzb3IgPSA0Mjk0OTY3Mjk1OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIC8vPj5pbmNsdWRlU3RhcnQoJ2RlYnVnJywgcHJhZ21hcy5kZWJ1Zyk7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgICBgQ2Fubm90IGRlcXVhbnRpemUgY29tcG9uZW50IGRhdGF0eXBlOiAke2NvbXBvbmVudERhdGF0eXBlfWAKICAgICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZGVxdWFudGl6ZWRUeXBlZEFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSgKICAgICAgICAgIGNvdW50ICogY29tcG9uZW50c1BlckF0dHJpYnV0ZQogICAgICAgICk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGNvdW50OyBpMisrKSB7CiAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgY29tcG9uZW50c1BlckF0dHJpYnV0ZTsgajIrKykgewogICAgICAgICAgICBjb25zdCBpbmRleCA9IGkyICogY29tcG9uZW50c1BlckF0dHJpYnV0ZSArIGoyOwogICAgICAgICAgICBkZXF1YW50aXplZFR5cGVkQXJyYXlbaW5kZXhdID0gTWF0aC5tYXgoCiAgICAgICAgICAgICAgdHlwZWRBcnJheVtpbmRleF0gLyBkaXZpc29yLAogICAgICAgICAgICAgIC0xCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBkZXF1YW50aXplZFR5cGVkQXJyYXk7CiAgICAgIH07CiAgICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uLmVuY29kZVJHQjggPSBmdW5jdGlvbihjb2xvcikgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY29sb3IiLCBjb2xvcik7CiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQoTWF0aF9kZWZhdWx0LmNsYW1wKGNvbG9yLnJlZCAqIDI1NSwgMCwgMjU1KSkgKiBMRUZUX1NISUZUMTYgKyBNYXRoLnJvdW5kKE1hdGhfZGVmYXVsdC5jbGFtcChjb2xvci5ncmVlbiAqIDI1NSwgMCwgMjU1KSkgKiBMRUZUX1NISUZUOCArIE1hdGgucm91bmQoTWF0aF9kZWZhdWx0LmNsYW1wKGNvbG9yLmJsdWUgKiAyNTUsIDAsIDI1NSkpOwogICAgICB9OwogICAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbi5kZWNvZGVSR0I4ID0gZnVuY3Rpb24oZW5jb2RlZCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJlbmNvZGVkIiwgZW5jb2RlZCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGVuY29kZWQgPSBNYXRoLmZsb29yKGVuY29kZWQpOwogICAgICAgIHJlc3VsdC5yZWQgPSAoZW5jb2RlZCA+PiAxNiAmIDI1NSkgLyAyNTU7CiAgICAgICAgcmVzdWx0LmdyZWVuID0gKGVuY29kZWQgPj4gOCAmIDI1NSkgLyAyNTU7CiAgICAgICAgcmVzdWx0LmJsdWUgPSAoZW5jb2RlZCAmIDI1NSkgLyAyNTU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb24uZGVjb2RlUkdCNTY1ID0gZnVuY3Rpb24odHlwZWRBcnJheSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ0eXBlZEFycmF5IiwgdHlwZWRBcnJheSk7CiAgICAgICAgY29uc3QgZXhwZWN0ZWRMZW5ndGggPSB0eXBlZEFycmF5Lmxlbmd0aCAqIDM7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZXF1YWxzKAogICAgICAgICAgICAicmVzdWx0Lmxlbmd0aCIsCiAgICAgICAgICAgICJ0eXBlZEFycmF5Lmxlbmd0aCAqIDMiLAogICAgICAgICAgICByZXN1bHQubGVuZ3RoLAogICAgICAgICAgICBleHBlY3RlZExlbmd0aAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY291bnQgPSB0eXBlZEFycmF5Lmxlbmd0aDsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgRmxvYXQzMkFycmF5KGNvdW50ICogMyk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG1hc2s1ID0gKDEgPDwgNSkgLSAxOwogICAgICAgIGNvbnN0IG1hc2s2ID0gKDEgPDwgNikgLSAxOwogICAgICAgIGNvbnN0IG5vcm1hbGl6ZTUgPSAxIC8gMzE7CiAgICAgICAgY29uc3Qgbm9ybWFsaXplNiA9IDEgLyA2MzsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgY291bnQ7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHZhbHVlID0gdHlwZWRBcnJheVtpMl07CiAgICAgICAgICBjb25zdCByZWQgPSB2YWx1ZSA+PiAxMTsKICAgICAgICAgIGNvbnN0IGdyZWVuID0gdmFsdWUgPj4gNSAmIG1hc2s2OwogICAgICAgICAgY29uc3QgYmx1ZSA9IHZhbHVlICYgbWFzazU7CiAgICAgICAgICBjb25zdCBvZmZzZXQgPSAzICogaTI7CiAgICAgICAgICByZXN1bHRbb2Zmc2V0XSA9IHJlZCAqIG5vcm1hbGl6ZTU7CiAgICAgICAgICByZXN1bHRbb2Zmc2V0ICsgMV0gPSBncmVlbiAqIG5vcm1hbGl6ZTY7CiAgICAgICAgICByZXN1bHRbb2Zmc2V0ICsgMl0gPSBibHVlICogbm9ybWFsaXplNTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdCA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvYmFyeWNlbnRyaWNDb29yZGluYXRlcy5qcwogIGZ1bmN0aW9uIGJhcnljZW50cmljQ29vcmRpbmF0ZXMocG9pbnQsIHAwLCBwMSwgcDIsIHJlc3VsdCkgewogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJwb2ludCIsIHBvaW50KTsKICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicDAiLCBwMCk7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInAxIiwgcDEpOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJwMiIsIHAyKTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgfQogICAgbGV0IHYwMjsKICAgIGxldCB2MTI7CiAgICBsZXQgdjIyOwogICAgbGV0IGRvdDAwOwogICAgbGV0IGRvdDAxOwogICAgbGV0IGRvdDAyOwogICAgbGV0IGRvdDExOwogICAgbGV0IGRvdDEyOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDAueikpIHsKICAgICAgaWYgKENhcnRlc2lhbjJfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKHBvaW50LCBwMCwgTWF0aF9kZWZhdWx0LkVQU0lMT04xNCkpIHsKICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1gsIHJlc3VsdCk7CiAgICAgIH0KICAgICAgaWYgKENhcnRlc2lhbjJfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKHBvaW50LCBwMSwgTWF0aF9kZWZhdWx0LkVQU0lMT04xNCkpIHsKICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1ksIHJlc3VsdCk7CiAgICAgIH0KICAgICAgaWYgKENhcnRlc2lhbjJfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKHBvaW50LCBwMiwgTWF0aF9kZWZhdWx0LkVQU0lMT04xNCkpIHsKICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1osIHJlc3VsdCk7CiAgICAgIH0KICAgICAgdjAyID0gQ2FydGVzaWFuMl9kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMCwgc2NyYXRjaENhcnRlc2lhbjEpOwogICAgICB2MTIgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuc3VidHJhY3QocDIsIHAwLCBzY3JhdGNoQ2FydGVzaWFuMik7CiAgICAgIHYyMiA9IENhcnRlc2lhbjJfZGVmYXVsdC5zdWJ0cmFjdChwb2ludCwgcDAsIHNjcmF0Y2hDYXJ0ZXNpYW4zMik7CiAgICAgIGRvdDAwID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRvdCh2MDIsIHYwMik7CiAgICAgIGRvdDAxID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRvdCh2MDIsIHYxMik7CiAgICAgIGRvdDAyID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRvdCh2MDIsIHYyMik7CiAgICAgIGRvdDExID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRvdCh2MTIsIHYxMik7CiAgICAgIGRvdDEyID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRvdCh2MTIsIHYyMik7CiAgICB9IGVsc2UgewogICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24ocG9pbnQsIHAwLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgewogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgcmVzdWx0KTsKICAgICAgfQogICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24ocG9pbnQsIHAxLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgewogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWSwgcmVzdWx0KTsKICAgICAgfQogICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24ocG9pbnQsIHAyLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSkgewogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwgcmVzdWx0KTsKICAgICAgfQogICAgICB2MDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocDEsIHAwLCBzY3JhdGNoQ2FydGVzaWFuMSk7CiAgICAgIHYxMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwMiwgcDAsIHNjcmF0Y2hDYXJ0ZXNpYW4yKTsKICAgICAgdjIyID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHBvaW50LCBwMCwgc2NyYXRjaENhcnRlc2lhbjMyKTsKICAgICAgZG90MDAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYwMiwgdjAyKTsKICAgICAgZG90MDEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYwMiwgdjEyKTsKICAgICAgZG90MDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYwMiwgdjIyKTsKICAgICAgZG90MTEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYxMiwgdjEyKTsKICAgICAgZG90MTIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYxMiwgdjIyKTsKICAgIH0KICAgIHJlc3VsdC55ID0gZG90MTEgKiBkb3QwMiAtIGRvdDAxICogZG90MTI7CiAgICByZXN1bHQueiA9IGRvdDAwICogZG90MTIgLSBkb3QwMSAqIGRvdDAyOwogICAgY29uc3QgcTMgPSBkb3QwMCAqIGRvdDExIC0gZG90MDEgKiBkb3QwMTsKICAgIGlmIChxMyA9PT0gMCkgewogICAgICByZXR1cm4gdm9pZCAwOwogICAgfQogICAgcmVzdWx0LnkgLz0gcTM7CiAgICByZXN1bHQueiAvPSBxMzsKICAgIHJlc3VsdC54ID0gMSAtIHJlc3VsdC55IC0gcmVzdWx0Lno7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICB2YXIgc2NyYXRjaENhcnRlc2lhbjEsIHNjcmF0Y2hDYXJ0ZXNpYW4yLCBzY3JhdGNoQ2FydGVzaWFuMzIsIGJhcnljZW50cmljQ29vcmRpbmF0ZXNfZGVmYXVsdDsKICB2YXIgaW5pdF9iYXJ5Y2VudHJpY0Nvb3JkaW5hdGVzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9iYXJ5Y2VudHJpY0Nvb3JkaW5hdGVzLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMzIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGJhcnljZW50cmljQ29vcmRpbmF0ZXNfZGVmYXVsdCA9IGJhcnljZW50cmljQ29vcmRpbmF0ZXM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbmNvZGVkQ2FydGVzaWFuMy5qcwogIGZ1bmN0aW9uIEVuY29kZWRDYXJ0ZXNpYW4zKCkgewogICAgdGhpcy5oaWdoID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKTsKICAgIHRoaXMubG93ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKTsKICB9CiAgdmFyIHNjcmF0Y2hFbmNvZGUsIGVuY29kZWRQLCBFbmNvZGVkQ2FydGVzaWFuM19kZWZhdWx0OwogIHZhciBpbml0X0VuY29kZWRDYXJ0ZXNpYW4zID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbmNvZGVkQ2FydGVzaWFuMy5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBFbmNvZGVkQ2FydGVzaWFuMy5lbmNvZGUgPSBmdW5jdGlvbih2YWx1ZSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSB7CiAgICAgICAgICAgIGhpZ2g6IDAsCiAgICAgICAgICAgIGxvdzogMAogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgbGV0IGRvdWJsZUhpZ2g7CiAgICAgICAgaWYgKHZhbHVlID49IDApIHsKICAgICAgICAgIGRvdWJsZUhpZ2ggPSBNYXRoLmZsb29yKHZhbHVlIC8gNjU1MzYpICogNjU1MzY7CiAgICAgICAgICByZXN1bHQuaGlnaCA9IGRvdWJsZUhpZ2g7CiAgICAgICAgICByZXN1bHQubG93ID0gdmFsdWUgLSBkb3VibGVIaWdoOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBkb3VibGVIaWdoID0gTWF0aC5mbG9vcigtdmFsdWUgLyA2NTUzNikgKiA2NTUzNjsKICAgICAgICAgIHJlc3VsdC5oaWdoID0gLWRvdWJsZUhpZ2g7CiAgICAgICAgICByZXN1bHQubG93ID0gdmFsdWUgKyBkb3VibGVIaWdoOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoRW5jb2RlID0gewogICAgICAgIGhpZ2g6IDAsCiAgICAgICAgbG93OiAwCiAgICAgIH07CiAgICAgIEVuY29kZWRDYXJ0ZXNpYW4zLmZyb21DYXJ0ZXNpYW4gPSBmdW5jdGlvbihjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEVuY29kZWRDYXJ0ZXNpYW4zKCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGhpZ2ggPSByZXN1bHQuaGlnaDsKICAgICAgICBjb25zdCBsb3cgPSByZXN1bHQubG93OwogICAgICAgIEVuY29kZWRDYXJ0ZXNpYW4zLmVuY29kZShjYXJ0ZXNpYW4xMS54LCBzY3JhdGNoRW5jb2RlKTsKICAgICAgICBoaWdoLnggPSBzY3JhdGNoRW5jb2RlLmhpZ2g7CiAgICAgICAgbG93LnggPSBzY3JhdGNoRW5jb2RlLmxvdzsKICAgICAgICBFbmNvZGVkQ2FydGVzaWFuMy5lbmNvZGUoY2FydGVzaWFuMTEueSwgc2NyYXRjaEVuY29kZSk7CiAgICAgICAgaGlnaC55ID0gc2NyYXRjaEVuY29kZS5oaWdoOwogICAgICAgIGxvdy55ID0gc2NyYXRjaEVuY29kZS5sb3c7CiAgICAgICAgRW5jb2RlZENhcnRlc2lhbjMuZW5jb2RlKGNhcnRlc2lhbjExLnosIHNjcmF0Y2hFbmNvZGUpOwogICAgICAgIGhpZ2gueiA9IHNjcmF0Y2hFbmNvZGUuaGlnaDsKICAgICAgICBsb3cueiA9IHNjcmF0Y2hFbmNvZGUubG93OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIGVuY29kZWRQID0gbmV3IEVuY29kZWRDYXJ0ZXNpYW4zKCk7CiAgICAgIEVuY29kZWRDYXJ0ZXNpYW4zLndyaXRlRWxlbWVudHMgPSBmdW5jdGlvbihjYXJ0ZXNpYW4xMSwgY2FydGVzaWFuQXJyYXksIGluZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjYXJ0ZXNpYW5BcnJheSIsIGNhcnRlc2lhbkFycmF5KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImluZGV4IiwgaW5kZXgpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJpbmRleCIsIGluZGV4LCAwKTsKICAgICAgICBFbmNvZGVkQ2FydGVzaWFuMy5mcm9tQ2FydGVzaWFuKGNhcnRlc2lhbjExLCBlbmNvZGVkUCk7CiAgICAgICAgY29uc3QgaGlnaCA9IGVuY29kZWRQLmhpZ2g7CiAgICAgICAgY29uc3QgbG93ID0gZW5jb2RlZFAubG93OwogICAgICAgIGNhcnRlc2lhbkFycmF5W2luZGV4XSA9IGhpZ2gueDsKICAgICAgICBjYXJ0ZXNpYW5BcnJheVtpbmRleCArIDFdID0gaGlnaC55OwogICAgICAgIGNhcnRlc2lhbkFycmF5W2luZGV4ICsgMl0gPSBoaWdoLno7CiAgICAgICAgY2FydGVzaWFuQXJyYXlbaW5kZXggKyAzXSA9IGxvdy54OwogICAgICAgIGNhcnRlc2lhbkFycmF5W2luZGV4ICsgNF0gPSBsb3cueTsKICAgICAgICBjYXJ0ZXNpYW5BcnJheVtpbmRleCArIDVdID0gbG93Lno7CiAgICAgIH07CiAgICAgIEVuY29kZWRDYXJ0ZXNpYW4zX2RlZmF1bHQgPSBFbmNvZGVkQ2FydGVzaWFuMzsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0luZGV4RGF0YXR5cGUuanMKICB2YXIgSW5kZXhEYXRhdHlwZSwgSW5kZXhEYXRhdHlwZV9kZWZhdWx0OwogIHZhciBpbml0X0luZGV4RGF0YXR5cGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0luZGV4RGF0YXR5cGUuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9XZWJHTENvbnN0YW50cygpOwogICAgICBJbmRleERhdGF0eXBlID0gewogICAgICAgIC8qKgogICAgICAgICAqIDgtYml0IHVuc2lnbmVkIGJ5dGUgY29ycmVzcG9uZGluZyB0byA8Y29kZT5VTlNJR05FRF9CWVRFPC9jb2RlPiBhbmQgdGhlIHR5cGUKICAgICAgICAgKiBvZiBhbiBlbGVtZW50IGluIDxjb2RlPlVpbnQ4QXJyYXk8L2NvZGU+LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBVTlNJR05FRF9CWVRFOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgLyoqCiAgICAgICAgICogMTYtYml0IHVuc2lnbmVkIHNob3J0IGNvcnJlc3BvbmRpbmcgdG8gPGNvZGU+VU5TSUdORURfU0hPUlQ8L2NvZGU+IGFuZCB0aGUgdHlwZQogICAgICAgICAqIG9mIGFuIGVsZW1lbnQgaW4gPGNvZGU+VWludDE2QXJyYXk8L2NvZGU+LgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBVTlNJR05FRF9TSE9SVDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVCwKICAgICAgICAvKioKICAgICAgICAgKiAzMi1iaXQgdW5zaWduZWQgaW50IGNvcnJlc3BvbmRpbmcgdG8gPGNvZGU+VU5TSUdORURfSU5UPC9jb2RlPiBhbmQgdGhlIHR5cGUKICAgICAgICAgKiBvZiBhbiBlbGVtZW50IGluIDxjb2RlPlVpbnQzMkFycmF5PC9jb2RlPi4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgVU5TSUdORURfSU5UOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlVOU0lHTkVEX0lOVAogICAgICB9OwogICAgICBJbmRleERhdGF0eXBlLmdldFNpemVJbkJ5dGVzID0gZnVuY3Rpb24oaW5kZXhEYXRhdHlwZSkgewogICAgICAgIHN3aXRjaCAoaW5kZXhEYXRhdHlwZSkgewogICAgICAgICAgY2FzZSBJbmRleERhdGF0eXBlLlVOU0lHTkVEX0JZVEU6CiAgICAgICAgICAgIHJldHVybiBVaW50OEFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICAgICAgY2FzZSBJbmRleERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOgogICAgICAgICAgICByZXR1cm4gVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgICBjYXNlIEluZGV4RGF0YXR5cGUuVU5TSUdORURfSU5UOgogICAgICAgICAgICByZXR1cm4gVWludDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgICAgfQogICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgImluZGV4RGF0YXR5cGUgaXMgcmVxdWlyZWQgYW5kIG11c3QgYmUgYSB2YWxpZCBJbmRleERhdGF0eXBlIGNvbnN0YW50LiIKICAgICAgICApOwogICAgICB9OwogICAgICBJbmRleERhdGF0eXBlLmZyb21TaXplSW5CeXRlcyA9IGZ1bmN0aW9uKHNpemVJbkJ5dGVzKSB7CiAgICAgICAgc3dpdGNoIChzaXplSW5CeXRlcykgewogICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICByZXR1cm4gSW5kZXhEYXRhdHlwZS5VTlNJR05FRF9TSE9SVDsKICAgICAgICAgIGNhc2UgNDoKICAgICAgICAgICAgcmV0dXJuIEluZGV4RGF0YXR5cGUuVU5TSUdORURfSU5UOwogICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICByZXR1cm4gSW5kZXhEYXRhdHlwZS5VTlNJR05FRF9CWVRFOwogICAgICAgICAgLy8+PmluY2x1ZGVTdGFydCgnZGVidWcnLCBwcmFnbWFzLmRlYnVnKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJTaXplIGluIGJ5dGVzIGNhbm5vdCBiZSBtYXBwZWQgdG8gYW4gSW5kZXhEYXRhdHlwZSIKICAgICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIEluZGV4RGF0YXR5cGUudmFsaWRhdGUgPSBmdW5jdGlvbihpbmRleERhdGF0eXBlKSB7CiAgICAgICAgcmV0dXJuIGRlZmluZWRfZGVmYXVsdChpbmRleERhdGF0eXBlKSAmJiAoaW5kZXhEYXRhdHlwZSA9PT0gSW5kZXhEYXRhdHlwZS5VTlNJR05FRF9CWVRFIHx8IGluZGV4RGF0YXR5cGUgPT09IEluZGV4RGF0YXR5cGUuVU5TSUdORURfU0hPUlQgfHwgaW5kZXhEYXRhdHlwZSA9PT0gSW5kZXhEYXRhdHlwZS5VTlNJR05FRF9JTlQpOwogICAgICB9OwogICAgICBJbmRleERhdGF0eXBlLmNyZWF0ZVR5cGVkQXJyYXkgPSBmdW5jdGlvbihudW1iZXJPZlZlcnRpY2VzLCBpbmRpY2VzTGVuZ3RoT3JBcnJheSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG51bWJlck9mVmVydGljZXMpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibnVtYmVyT2ZWZXJ0aWNlcyBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKG51bWJlck9mVmVydGljZXMgPj0gTWF0aF9kZWZhdWx0LlNJWFRZX0ZPVVJfS0lMT0JZVEVTKSB7CiAgICAgICAgICByZXR1cm4gbmV3IFVpbnQzMkFycmF5KGluZGljZXNMZW5ndGhPckFycmF5KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBVaW50MTZBcnJheShpbmRpY2VzTGVuZ3RoT3JBcnJheSk7CiAgICAgIH07CiAgICAgIEluZGV4RGF0YXR5cGUuY3JlYXRlVHlwZWRBcnJheUZyb21BcnJheUJ1ZmZlciA9IGZ1bmN0aW9uKG51bWJlck9mVmVydGljZXMsIHNvdXJjZUFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChudW1iZXJPZlZlcnRpY2VzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm51bWJlck9mVmVydGljZXMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHNvdXJjZUFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInNvdXJjZUFycmF5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChieXRlT2Zmc2V0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImJ5dGVPZmZzZXQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChudW1iZXJPZlZlcnRpY2VzID49IE1hdGhfZGVmYXVsdC5TSVhUWV9GT1VSX0tJTE9CWVRFUykgewogICAgICAgICAgcmV0dXJuIG5ldyBVaW50MzJBcnJheShzb3VyY2VBcnJheSwgYnl0ZU9mZnNldCwgbGVuZ3RoKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBVaW50MTZBcnJheShzb3VyY2VBcnJheSwgYnl0ZU9mZnNldCwgbGVuZ3RoKTsKICAgICAgfTsKICAgICAgSW5kZXhEYXRhdHlwZS5mcm9tVHlwZWRBcnJheSA9IGZ1bmN0aW9uKGFycmF5KSB7CiAgICAgICAgaWYgKGFycmF5IGluc3RhbmNlb2YgVWludDhBcnJheSkgewogICAgICAgICAgcmV0dXJuIEluZGV4RGF0YXR5cGUuVU5TSUdORURfQllURTsKICAgICAgICB9CiAgICAgICAgaWYgKGFycmF5IGluc3RhbmNlb2YgVWludDE2QXJyYXkpIHsKICAgICAgICAgIHJldHVybiBJbmRleERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOwogICAgICAgIH0KICAgICAgICBpZiAoYXJyYXkgaW5zdGFuY2VvZiBVaW50MzJBcnJheSkgewogICAgICAgICAgcmV0dXJuIEluZGV4RGF0YXR5cGUuVU5TSUdORURfSU5UOwogICAgICAgIH0KICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICJhcnJheSBtdXN0IGJlIGEgVWludDhBcnJheSwgVWludDE2QXJyYXksIG9yIFVpbnQzMkFycmF5LiIKICAgICAgICApOwogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKEluZGV4RGF0YXR5cGUpOwogICAgICBJbmRleERhdGF0eXBlX2RlZmF1bHQgPSBJbmRleERhdGF0eXBlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUXVhZHJhdGljUmVhbFBvbHlub21pYWwuanMKICBmdW5jdGlvbiBhZGRXaXRoQ2FuY2VsbGF0aW9uQ2hlY2sobGVmdCwgcmlnaHQsIHRvbGVyYW5jZSkgewogICAgY29uc3QgZGlmZmVyZW5jZSA9IGxlZnQgKyByaWdodDsKICAgIGlmIChNYXRoX2RlZmF1bHQuc2lnbihsZWZ0KSAhPT0gTWF0aF9kZWZhdWx0LnNpZ24ocmlnaHQpICYmIE1hdGguYWJzKGRpZmZlcmVuY2UgLyBNYXRoLm1heChNYXRoLmFicyhsZWZ0KSwgTWF0aC5hYnMocmlnaHQpKSkgPCB0b2xlcmFuY2UpIHsKICAgICAgcmV0dXJuIDA7CiAgICB9CiAgICByZXR1cm4gZGlmZmVyZW5jZTsKICB9CiAgdmFyIFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsLCBRdWFkcmF0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0OwogIHZhciBpbml0X1F1YWRyYXRpY1JlYWxQb2x5bm9taWFsID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9RdWFkcmF0aWNSZWFsUG9seW5vbWlhbC5qcyIoKSB7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsID0ge307CiAgICAgIFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsLmNvbXB1dGVEaXNjcmltaW5hbnQgPSBmdW5jdGlvbihhNCwgYjIsIGMyKSB7CiAgICAgICAgaWYgKHR5cGVvZiBhNCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGIyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImIgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgYzIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYyBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZGlzY3JpbWluYW50ID0gYjIgKiBiMiAtIDQgKiBhNCAqIGMyOwogICAgICAgIHJldHVybiBkaXNjcmltaW5hbnQ7CiAgICAgIH07CiAgICAgIFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsLmNvbXB1dGVSZWFsUm9vdHMgPSBmdW5jdGlvbihhNCwgYjIsIGMyKSB7CiAgICAgICAgaWYgKHR5cGVvZiBhNCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGIyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImIgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgYzIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYyBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgbGV0IHJhdGlvOwogICAgICAgIGlmIChhNCA9PT0gMCkgewogICAgICAgICAgaWYgKGIyID09PSAwKSB7CiAgICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBbLWMyIC8gYjJdOwogICAgICAgIH0gZWxzZSBpZiAoYjIgPT09IDApIHsKICAgICAgICAgIGlmIChjMiA9PT0gMCkgewogICAgICAgICAgICByZXR1cm4gWzAsIDBdOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgY01hZ25pdHVkZSA9IE1hdGguYWJzKGMyKTsKICAgICAgICAgIGNvbnN0IGFNYWduaXR1ZGUgPSBNYXRoLmFicyhhNCk7CiAgICAgICAgICBpZiAoY01hZ25pdHVkZSA8IGFNYWduaXR1ZGUgJiYgY01hZ25pdHVkZSAvIGFNYWduaXR1ZGUgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0KSB7CiAgICAgICAgICAgIHJldHVybiBbMCwgMF07CiAgICAgICAgICB9IGVsc2UgaWYgKGNNYWduaXR1ZGUgPiBhTWFnbml0dWRlICYmIGFNYWduaXR1ZGUgLyBjTWFnbml0dWRlIDwgTWF0aF9kZWZhdWx0LkVQU0lMT04xNCkgewogICAgICAgICAgICByZXR1cm4gW107CiAgICAgICAgICB9CiAgICAgICAgICByYXRpbyA9IC1jMiAvIGE0OwogICAgICAgICAgaWYgKHJhdGlvIDwgMCkgewogICAgICAgICAgICByZXR1cm4gW107CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByb290ID0gTWF0aC5zcXJ0KHJhdGlvKTsKICAgICAgICAgIHJldHVybiBbLXJvb3QsIHJvb3RdOwogICAgICAgIH0gZWxzZSBpZiAoYzIgPT09IDApIHsKICAgICAgICAgIHJhdGlvID0gLWIyIC8gYTQ7CiAgICAgICAgICBpZiAocmF0aW8gPCAwKSB7CiAgICAgICAgICAgIHJldHVybiBbcmF0aW8sIDBdOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIFswLCByYXRpb107CiAgICAgICAgfQogICAgICAgIGNvbnN0IGIyMiA9IGIyICogYjI7CiAgICAgICAgY29uc3QgZm91cl9hYyA9IDQgKiBhNCAqIGMyOwogICAgICAgIGNvbnN0IHJhZGljYW5kID0gYWRkV2l0aENhbmNlbGxhdGlvbkNoZWNrKGIyMiwgLWZvdXJfYWMsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTQpOwogICAgICAgIGlmIChyYWRpY2FuZCA8IDApIHsKICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcTMgPSAtMC41ICogYWRkV2l0aENhbmNlbGxhdGlvbkNoZWNrKAogICAgICAgICAgYjIsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuc2lnbihiMikgKiBNYXRoLnNxcnQocmFkaWNhbmQpLAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xNAogICAgICAgICk7CiAgICAgICAgaWYgKGIyID4gMCkgewogICAgICAgICAgcmV0dXJuIFtxMyAvIGE0LCBjMiAvIHEzXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIFtjMiAvIHEzLCBxMyAvIGE0XTsKICAgICAgfTsKICAgICAgUXVhZHJhdGljUmVhbFBvbHlub21pYWxfZGVmYXVsdCA9IFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ3ViaWNSZWFsUG9seW5vbWlhbC5qcwogIGZ1bmN0aW9uIGNvbXB1dGVSZWFsUm9vdHMoYTQsIGIyLCBjMiwgZDIpIHsKICAgIGNvbnN0IEEyID0gYTQ7CiAgICBjb25zdCBCMiA9IGIyIC8gMzsKICAgIGNvbnN0IEMyID0gYzIgLyAzOwogICAgY29uc3QgRDIgPSBkMjsKICAgIGNvbnN0IEFDID0gQTIgKiBDMjsKICAgIGNvbnN0IEJEID0gQjIgKiBEMjsKICAgIGNvbnN0IEIyMiA9IEIyICogQjI7CiAgICBjb25zdCBDMjIgPSBDMiAqIEMyOwogICAgY29uc3QgZGVsdGExID0gQTIgKiBDMiAtIEIyMjsKICAgIGNvbnN0IGRlbHRhMiA9IEEyICogRDIgLSBCMiAqIEMyOwogICAgY29uc3QgZGVsdGEzID0gQjIgKiBEMiAtIEMyMjsKICAgIGNvbnN0IGRpc2NyaW1pbmFudCA9IDQgKiBkZWx0YTEgKiBkZWx0YTMgLSBkZWx0YTIgKiBkZWx0YTI7CiAgICBsZXQgdGVtcDsKICAgIGxldCB0ZW1wMTsKICAgIGlmIChkaXNjcmltaW5hbnQgPCAwKSB7CiAgICAgIGxldCBBQmFyOwogICAgICBsZXQgQ0JhcjsKICAgICAgbGV0IERCYXI7CiAgICAgIGlmIChCMjIgKiBCRCA+PSBBQyAqIEMyMikgewogICAgICAgIEFCYXIgPSBBMjsKICAgICAgICBDQmFyID0gZGVsdGExOwogICAgICAgIERCYXIgPSAtMiAqIEIyICogZGVsdGExICsgQTIgKiBkZWx0YTI7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgQUJhciA9IEQyOwogICAgICAgIENCYXIgPSBkZWx0YTM7CiAgICAgICAgREJhciA9IC1EMiAqIGRlbHRhMiArIDIgKiBDMiAqIGRlbHRhMzsKICAgICAgfQogICAgICBjb25zdCBzMiA9IERCYXIgPCAwID8gLTEgOiAxOwogICAgICBjb25zdCB0ZW1wMCA9IC1zMiAqIE1hdGguYWJzKEFCYXIpICogTWF0aC5zcXJ0KC1kaXNjcmltaW5hbnQpOwogICAgICB0ZW1wMSA9IC1EQmFyICsgdGVtcDA7CiAgICAgIGNvbnN0IHgyID0gdGVtcDEgLyAyOwogICAgICBjb25zdCBwMiA9IHgyIDwgMCA/IC1NYXRoLnBvdygteDIsIDEgLyAzKSA6IE1hdGgucG93KHgyLCAxIC8gMyk7CiAgICAgIGNvbnN0IHEzID0gdGVtcDEgPT09IHRlbXAwID8gLXAyIDogLUNCYXIgLyBwMjsKICAgICAgdGVtcCA9IENCYXIgPD0gMCA/IHAyICsgcTMgOiAtREJhciAvIChwMiAqIHAyICsgcTMgKiBxMyArIENCYXIpOwogICAgICBpZiAoQjIyICogQkQgPj0gQUMgKiBDMjIpIHsKICAgICAgICByZXR1cm4gWyh0ZW1wIC0gQjIpIC8gQTJdOwogICAgICB9CiAgICAgIHJldHVybiBbLUQyIC8gKHRlbXAgKyBDMildOwogICAgfQogICAgY29uc3QgQ0JhckEgPSBkZWx0YTE7CiAgICBjb25zdCBEQmFyQSA9IC0yICogQjIgKiBkZWx0YTEgKyBBMiAqIGRlbHRhMjsKICAgIGNvbnN0IENCYXJEID0gZGVsdGEzOwogICAgY29uc3QgREJhckQgPSAtRDIgKiBkZWx0YTIgKyAyICogQzIgKiBkZWx0YTM7CiAgICBjb25zdCBzcXVhcmVSb290T2ZEaXNjcmltaW5hbnQgPSBNYXRoLnNxcnQoZGlzY3JpbWluYW50KTsKICAgIGNvbnN0IGhhbGZTcXVhcmVSb290T2YzID0gTWF0aC5zcXJ0KDMpIC8gMjsKICAgIGxldCB0aGV0YSA9IE1hdGguYWJzKE1hdGguYXRhbjIoQTIgKiBzcXVhcmVSb290T2ZEaXNjcmltaW5hbnQsIC1EQmFyQSkgLyAzKTsKICAgIHRlbXAgPSAyICogTWF0aC5zcXJ0KC1DQmFyQSk7CiAgICBsZXQgY29zaW5lID0gTWF0aC5jb3ModGhldGEpOwogICAgdGVtcDEgPSB0ZW1wICogY29zaW5lOwogICAgbGV0IHRlbXAzID0gdGVtcCAqICgtY29zaW5lIC8gMiAtIGhhbGZTcXVhcmVSb290T2YzICogTWF0aC5zaW4odGhldGEpKTsKICAgIGNvbnN0IG51bWVyYXRvckxhcmdlID0gdGVtcDEgKyB0ZW1wMyA+IDIgKiBCMiA/IHRlbXAxIC0gQjIgOiB0ZW1wMyAtIEIyOwogICAgY29uc3QgZGVub21pbmF0b3JMYXJnZSA9IEEyOwogICAgY29uc3Qgcm9vdDEgPSBudW1lcmF0b3JMYXJnZSAvIGRlbm9taW5hdG9yTGFyZ2U7CiAgICB0aGV0YSA9IE1hdGguYWJzKE1hdGguYXRhbjIoRDIgKiBzcXVhcmVSb290T2ZEaXNjcmltaW5hbnQsIC1EQmFyRCkgLyAzKTsKICAgIHRlbXAgPSAyICogTWF0aC5zcXJ0KC1DQmFyRCk7CiAgICBjb3NpbmUgPSBNYXRoLmNvcyh0aGV0YSk7CiAgICB0ZW1wMSA9IHRlbXAgKiBjb3NpbmU7CiAgICB0ZW1wMyA9IHRlbXAgKiAoLWNvc2luZSAvIDIgLSBoYWxmU3F1YXJlUm9vdE9mMyAqIE1hdGguc2luKHRoZXRhKSk7CiAgICBjb25zdCBudW1lcmF0b3JTbWFsbCA9IC1EMjsKICAgIGNvbnN0IGRlbm9taW5hdG9yU21hbGwgPSB0ZW1wMSArIHRlbXAzIDwgMiAqIEMyID8gdGVtcDEgKyBDMiA6IHRlbXAzICsgQzI7CiAgICBjb25zdCByb290MyA9IG51bWVyYXRvclNtYWxsIC8gZGVub21pbmF0b3JTbWFsbDsKICAgIGNvbnN0IEUyID0gZGVub21pbmF0b3JMYXJnZSAqIGRlbm9taW5hdG9yU21hbGw7CiAgICBjb25zdCBGMiA9IC1udW1lcmF0b3JMYXJnZSAqIGRlbm9taW5hdG9yU21hbGwgLSBkZW5vbWluYXRvckxhcmdlICogbnVtZXJhdG9yU21hbGw7CiAgICBjb25zdCBHMiA9IG51bWVyYXRvckxhcmdlICogbnVtZXJhdG9yU21hbGw7CiAgICBjb25zdCByb290MiA9IChDMiAqIEYyIC0gQjIgKiBHMikgLyAoLUIyICogRjIgKyBDMiAqIEUyKTsKICAgIGlmIChyb290MSA8PSByb290MikgewogICAgICBpZiAocm9vdDEgPD0gcm9vdDMpIHsKICAgICAgICBpZiAocm9vdDIgPD0gcm9vdDMpIHsKICAgICAgICAgIHJldHVybiBbcm9vdDEsIHJvb3QyLCByb290M107CiAgICAgICAgfQogICAgICAgIHJldHVybiBbcm9vdDEsIHJvb3QzLCByb290Ml07CiAgICAgIH0KICAgICAgcmV0dXJuIFtyb290Mywgcm9vdDEsIHJvb3QyXTsKICAgIH0KICAgIGlmIChyb290MSA8PSByb290MykgewogICAgICByZXR1cm4gW3Jvb3QyLCByb290MSwgcm9vdDNdOwogICAgfQogICAgaWYgKHJvb3QyIDw9IHJvb3QzKSB7CiAgICAgIHJldHVybiBbcm9vdDIsIHJvb3QzLCByb290MV07CiAgICB9CiAgICByZXR1cm4gW3Jvb3QzLCByb290Miwgcm9vdDFdOwogIH0KICB2YXIgQ3ViaWNSZWFsUG9seW5vbWlhbCwgQ3ViaWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0OwogIHZhciBpbml0X0N1YmljUmVhbFBvbHlub21pYWwgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0N1YmljUmVhbFBvbHlub21pYWwuanMiKCkgewogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfUXVhZHJhdGljUmVhbFBvbHlub21pYWwoKTsKICAgICAgQ3ViaWNSZWFsUG9seW5vbWlhbCA9IHt9OwogICAgICBDdWJpY1JlYWxQb2x5bm9taWFsLmNvbXB1dGVEaXNjcmltaW5hbnQgPSBmdW5jdGlvbihhNCwgYjIsIGMyLCBkMikgewogICAgICAgIGlmICh0eXBlb2YgYTQgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYSBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBiMiAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJiIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGMyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImMgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgZDIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZCBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYTIyID0gYTQgKiBhNDsKICAgICAgICBjb25zdCBiMjIgPSBiMiAqIGIyOwogICAgICAgIGNvbnN0IGMyMiA9IGMyICogYzI7CiAgICAgICAgY29uc3QgZDIyID0gZDIgKiBkMjsKICAgICAgICBjb25zdCBkaXNjcmltaW5hbnQgPSAxOCAqIGE0ICogYjIgKiBjMiAqIGQyICsgYjIyICogYzIyIC0gMjcgKiBhMjIgKiBkMjIgLSA0ICogKGE0ICogYzIyICogYzIgKyBiMjIgKiBiMiAqIGQyKTsKICAgICAgICByZXR1cm4gZGlzY3JpbWluYW50OwogICAgICB9OwogICAgICBDdWJpY1JlYWxQb2x5bm9taWFsLmNvbXB1dGVSZWFsUm9vdHMgPSBmdW5jdGlvbihhNCwgYjIsIGMyLCBkMikgewogICAgICAgIGlmICh0eXBlb2YgYTQgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYSBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBiMiAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJiIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGMyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImMgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgZDIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZCBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgbGV0IHJvb3RzOwogICAgICAgIGxldCByYXRpbzsKICAgICAgICBpZiAoYTQgPT09IDApIHsKICAgICAgICAgIHJldHVybiBRdWFkcmF0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0LmNvbXB1dGVSZWFsUm9vdHMoYjIsIGMyLCBkMik7CiAgICAgICAgfSBlbHNlIGlmIChiMiA9PT0gMCkgewogICAgICAgICAgaWYgKGMyID09PSAwKSB7CiAgICAgICAgICAgIGlmIChkMiA9PT0gMCkgewogICAgICAgICAgICAgIHJldHVybiBbMCwgMCwgMF07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmF0aW8gPSAtZDIgLyBhNDsKICAgICAgICAgICAgY29uc3Qgcm9vdCA9IHJhdGlvIDwgMCA/IC1NYXRoLnBvdygtcmF0aW8sIDEgLyAzKSA6IE1hdGgucG93KHJhdGlvLCAxIC8gMyk7CiAgICAgICAgICAgIHJldHVybiBbcm9vdCwgcm9vdCwgcm9vdF07CiAgICAgICAgICB9IGVsc2UgaWYgKGQyID09PSAwKSB7CiAgICAgICAgICAgIHJvb3RzID0gUXVhZHJhdGljUmVhbFBvbHlub21pYWxfZGVmYXVsdC5jb21wdXRlUmVhbFJvb3RzKGE0LCAwLCBjMik7CiAgICAgICAgICAgIGlmIChyb290cy5MZW5ndGggPT09IDApIHsKICAgICAgICAgICAgICByZXR1cm4gWzBdOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcm9vdHNbMF0sIDAsIHJvb3RzWzFdXTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBjb21wdXRlUmVhbFJvb3RzKGE0LCAwLCBjMiwgZDIpOwogICAgICAgIH0gZWxzZSBpZiAoYzIgPT09IDApIHsKICAgICAgICAgIGlmIChkMiA9PT0gMCkgewogICAgICAgICAgICByYXRpbyA9IC1iMiAvIGE0OwogICAgICAgICAgICBpZiAocmF0aW8gPCAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtyYXRpbywgMCwgMF07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIFswLCAwLCByYXRpb107CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gY29tcHV0ZVJlYWxSb290cyhhNCwgYjIsIDAsIGQyKTsKICAgICAgICB9IGVsc2UgaWYgKGQyID09PSAwKSB7CiAgICAgICAgICByb290cyA9IFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsX2RlZmF1bHQuY29tcHV0ZVJlYWxSb290cyhhNCwgYjIsIGMyKTsKICAgICAgICAgIGlmIChyb290cy5sZW5ndGggPT09IDApIHsKICAgICAgICAgICAgcmV0dXJuIFswXTsKICAgICAgICAgIH0gZWxzZSBpZiAocm9vdHNbMV0gPD0gMCkgewogICAgICAgICAgICByZXR1cm4gW3Jvb3RzWzBdLCByb290c1sxXSwgMF07CiAgICAgICAgICB9IGVsc2UgaWYgKHJvb3RzWzBdID49IDApIHsKICAgICAgICAgICAgcmV0dXJuIFswLCByb290c1swXSwgcm9vdHNbMV1dOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIFtyb290c1swXSwgMCwgcm9vdHNbMV1dOwogICAgICAgIH0KICAgICAgICByZXR1cm4gY29tcHV0ZVJlYWxSb290cyhhNCwgYjIsIGMyLCBkMik7CiAgICAgIH07CiAgICAgIEN1YmljUmVhbFBvbHlub21pYWxfZGVmYXVsdCA9IEN1YmljUmVhbFBvbHlub21pYWw7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9RdWFydGljUmVhbFBvbHlub21pYWwuanMKICBmdW5jdGlvbiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKSB7CiAgICBjb25zdCBhM1NxdWFyZWQgPSBhMzIgKiBhMzI7CiAgICBjb25zdCBwMiA9IGEyMiAtIDMgKiBhM1NxdWFyZWQgLyA4OwogICAgY29uc3QgcTMgPSBhMSAtIGEyMiAqIGEzMiAvIDIgKyBhM1NxdWFyZWQgKiBhMzIgLyA4OwogICAgY29uc3QgcjIgPSBhMCAtIGExICogYTMyIC8gNCArIGEyMiAqIGEzU3F1YXJlZCAvIDE2IC0gMyAqIGEzU3F1YXJlZCAqIGEzU3F1YXJlZCAvIDI1NjsKICAgIGNvbnN0IGN1YmljUm9vdHMgPSBDdWJpY1JlYWxQb2x5bm9taWFsX2RlZmF1bHQuY29tcHV0ZVJlYWxSb290cygKICAgICAgMSwKICAgICAgMiAqIHAyLAogICAgICBwMiAqIHAyIC0gNCAqIHIyLAogICAgICAtcTMgKiBxMwogICAgKTsKICAgIGlmIChjdWJpY1Jvb3RzLmxlbmd0aCA+IDApIHsKICAgICAgY29uc3QgdGVtcCA9IC1hMzIgLyA0OwogICAgICBjb25zdCBoU3F1YXJlZCA9IGN1YmljUm9vdHNbY3ViaWNSb290cy5sZW5ndGggLSAxXTsKICAgICAgaWYgKE1hdGguYWJzKGhTcXVhcmVkKSA8IE1hdGhfZGVmYXVsdC5FUFNJTE9OMTQpIHsKICAgICAgICBjb25zdCByb290cyA9IFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsX2RlZmF1bHQuY29tcHV0ZVJlYWxSb290cygxLCBwMiwgcjIpOwogICAgICAgIGlmIChyb290cy5sZW5ndGggPT09IDIpIHsKICAgICAgICAgIGNvbnN0IHJvb3QwID0gcm9vdHNbMF07CiAgICAgICAgICBjb25zdCByb290MSA9IHJvb3RzWzFdOwogICAgICAgICAgbGV0IHkyOwogICAgICAgICAgaWYgKHJvb3QwID49IDAgJiYgcm9vdDEgPj0gMCkgewogICAgICAgICAgICBjb25zdCB5MCA9IE1hdGguc3FydChyb290MCk7CiAgICAgICAgICAgIGNvbnN0IHkxID0gTWF0aC5zcXJ0KHJvb3QxKTsKICAgICAgICAgICAgcmV0dXJuIFt0ZW1wIC0geTEsIHRlbXAgLSB5MCwgdGVtcCArIHkwLCB0ZW1wICsgeTFdOwogICAgICAgICAgfSBlbHNlIGlmIChyb290MCA+PSAwICYmIHJvb3QxIDwgMCkgewogICAgICAgICAgICB5MiA9IE1hdGguc3FydChyb290MCk7CiAgICAgICAgICAgIHJldHVybiBbdGVtcCAtIHkyLCB0ZW1wICsgeTJdOwogICAgICAgICAgfSBlbHNlIGlmIChyb290MCA8IDAgJiYgcm9vdDEgPj0gMCkgewogICAgICAgICAgICB5MiA9IE1hdGguc3FydChyb290MSk7CiAgICAgICAgICAgIHJldHVybiBbdGVtcCAtIHkyLCB0ZW1wICsgeTJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gW107CiAgICAgIH0gZWxzZSBpZiAoaFNxdWFyZWQgPiAwKSB7CiAgICAgICAgY29uc3QgaDIgPSBNYXRoLnNxcnQoaFNxdWFyZWQpOwogICAgICAgIGNvbnN0IG0yID0gKHAyICsgaFNxdWFyZWQgLSBxMyAvIGgyKSAvIDI7CiAgICAgICAgY29uc3QgbjIgPSAocDIgKyBoU3F1YXJlZCArIHEzIC8gaDIpIC8gMjsKICAgICAgICBjb25zdCByb290czEgPSBRdWFkcmF0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0LmNvbXB1dGVSZWFsUm9vdHMoMSwgaDIsIG0yKTsKICAgICAgICBjb25zdCByb290czIgPSBRdWFkcmF0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0LmNvbXB1dGVSZWFsUm9vdHMoMSwgLWgyLCBuMik7CiAgICAgICAgaWYgKHJvb3RzMS5sZW5ndGggIT09IDApIHsKICAgICAgICAgIHJvb3RzMVswXSArPSB0ZW1wOwogICAgICAgICAgcm9vdHMxWzFdICs9IHRlbXA7CiAgICAgICAgICBpZiAocm9vdHMyLmxlbmd0aCAhPT0gMCkgewogICAgICAgICAgICByb290czJbMF0gKz0gdGVtcDsKICAgICAgICAgICAgcm9vdHMyWzFdICs9IHRlbXA7CiAgICAgICAgICAgIGlmIChyb290czFbMV0gPD0gcm9vdHMyWzBdKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtyb290czFbMF0sIHJvb3RzMVsxXSwgcm9vdHMyWzBdLCByb290czJbMV1dOwogICAgICAgICAgICB9IGVsc2UgaWYgKHJvb3RzMlsxXSA8PSByb290czFbMF0pIHsKICAgICAgICAgICAgICByZXR1cm4gW3Jvb3RzMlswXSwgcm9vdHMyWzFdLCByb290czFbMF0sIHJvb3RzMVsxXV07CiAgICAgICAgICAgIH0gZWxzZSBpZiAocm9vdHMxWzBdID49IHJvb3RzMlswXSAmJiByb290czFbMV0gPD0gcm9vdHMyWzFdKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtyb290czJbMF0sIHJvb3RzMVswXSwgcm9vdHMxWzFdLCByb290czJbMV1dOwogICAgICAgICAgICB9IGVsc2UgaWYgKHJvb3RzMlswXSA+PSByb290czFbMF0gJiYgcm9vdHMyWzFdIDw9IHJvb3RzMVsxXSkgewogICAgICAgICAgICAgIHJldHVybiBbcm9vdHMxWzBdLCByb290czJbMF0sIHJvb3RzMlsxXSwgcm9vdHMxWzFdXTsKICAgICAgICAgICAgfSBlbHNlIGlmIChyb290czFbMF0gPiByb290czJbMF0gJiYgcm9vdHMxWzBdIDwgcm9vdHMyWzFdKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFtyb290czJbMF0sIHJvb3RzMVswXSwgcm9vdHMyWzFdLCByb290czFbMV1dOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBbcm9vdHMxWzBdLCByb290czJbMF0sIHJvb3RzMVsxXSwgcm9vdHMyWzFdXTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByb290czE7CiAgICAgICAgfQogICAgICAgIGlmIChyb290czIubGVuZ3RoICE9PSAwKSB7CiAgICAgICAgICByb290czJbMF0gKz0gdGVtcDsKICAgICAgICAgIHJvb3RzMlsxXSArPSB0ZW1wOwogICAgICAgICAgcmV0dXJuIHJvb3RzMjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIFtdOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gW107CiAgfQogIGZ1bmN0aW9uIG5ldW1hcmsoYTMyLCBhMjIsIGExLCBhMCkgewogICAgY29uc3QgYTFTcXVhcmVkID0gYTEgKiBhMTsKICAgIGNvbnN0IGEyU3F1YXJlZCA9IGEyMiAqIGEyMjsKICAgIGNvbnN0IGEzU3F1YXJlZCA9IGEzMiAqIGEzMjsKICAgIGNvbnN0IHAyID0gLTIgKiBhMjI7CiAgICBjb25zdCBxMyA9IGExICogYTMyICsgYTJTcXVhcmVkIC0gNCAqIGEwOwogICAgY29uc3QgcjIgPSBhM1NxdWFyZWQgKiBhMCAtIGExICogYTIyICogYTMyICsgYTFTcXVhcmVkOwogICAgY29uc3QgY3ViaWNSb290cyA9IEN1YmljUmVhbFBvbHlub21pYWxfZGVmYXVsdC5jb21wdXRlUmVhbFJvb3RzKDEsIHAyLCBxMywgcjIpOwogICAgaWYgKGN1YmljUm9vdHMubGVuZ3RoID4gMCkgewogICAgICBjb25zdCB5MiA9IGN1YmljUm9vdHNbMF07CiAgICAgIGNvbnN0IHRlbXAgPSBhMjIgLSB5MjsKICAgICAgY29uc3QgdGVtcFNxdWFyZWQgPSB0ZW1wICogdGVtcDsKICAgICAgY29uc3QgZzEgPSBhMzIgLyAyOwogICAgICBjb25zdCBoMSA9IHRlbXAgLyAyOwogICAgICBjb25zdCBtMiA9IHRlbXBTcXVhcmVkIC0gNCAqIGEwOwogICAgICBjb25zdCBtRXJyb3IgPSB0ZW1wU3F1YXJlZCArIDQgKiBNYXRoLmFicyhhMCk7CiAgICAgIGNvbnN0IG4yID0gYTNTcXVhcmVkIC0gNCAqIHkyOwogICAgICBjb25zdCBuRXJyb3IgPSBhM1NxdWFyZWQgKyA0ICogTWF0aC5hYnMoeTIpOwogICAgICBsZXQgZzI7CiAgICAgIGxldCBoMjsKICAgICAgaWYgKHkyIDwgMCB8fCBtMiAqIG5FcnJvciA8IG4yICogbUVycm9yKSB7CiAgICAgICAgY29uc3Qgc3F1YXJlUm9vdE9mTiA9IE1hdGguc3FydChuMik7CiAgICAgICAgZzIgPSBzcXVhcmVSb290T2ZOIC8gMjsKICAgICAgICBoMiA9IHNxdWFyZVJvb3RPZk4gPT09IDAgPyAwIDogKGEzMiAqIGgxIC0gYTEpIC8gc3F1YXJlUm9vdE9mTjsKICAgICAgfSBlbHNlIHsKICAgICAgICBjb25zdCBzcXVhcmVSb290T2ZNID0gTWF0aC5zcXJ0KG0yKTsKICAgICAgICBnMiA9IHNxdWFyZVJvb3RPZk0gPT09IDAgPyAwIDogKGEzMiAqIGgxIC0gYTEpIC8gc3F1YXJlUm9vdE9mTTsKICAgICAgICBoMiA9IHNxdWFyZVJvb3RPZk0gLyAyOwogICAgICB9CiAgICAgIGxldCBHMjsKICAgICAgbGV0IGczOwogICAgICBpZiAoZzEgPT09IDAgJiYgZzIgPT09IDApIHsKICAgICAgICBHMiA9IDA7CiAgICAgICAgZzMgPSAwOwogICAgICB9IGVsc2UgaWYgKE1hdGhfZGVmYXVsdC5zaWduKGcxKSA9PT0gTWF0aF9kZWZhdWx0LnNpZ24oZzIpKSB7CiAgICAgICAgRzIgPSBnMSArIGcyOwogICAgICAgIGczID0geTIgLyBHMjsKICAgICAgfSBlbHNlIHsKICAgICAgICBnMyA9IGcxIC0gZzI7CiAgICAgICAgRzIgPSB5MiAvIGczOwogICAgICB9CiAgICAgIGxldCBIMjsKICAgICAgbGV0IGgzOwogICAgICBpZiAoaDEgPT09IDAgJiYgaDIgPT09IDApIHsKICAgICAgICBIMiA9IDA7CiAgICAgICAgaDMgPSAwOwogICAgICB9IGVsc2UgaWYgKE1hdGhfZGVmYXVsdC5zaWduKGgxKSA9PT0gTWF0aF9kZWZhdWx0LnNpZ24oaDIpKSB7CiAgICAgICAgSDIgPSBoMSArIGgyOwogICAgICAgIGgzID0gYTAgLyBIMjsKICAgICAgfSBlbHNlIHsKICAgICAgICBoMyA9IGgxIC0gaDI7CiAgICAgICAgSDIgPSBhMCAvIGgzOwogICAgICB9CiAgICAgIGNvbnN0IHJvb3RzMSA9IFF1YWRyYXRpY1JlYWxQb2x5bm9taWFsX2RlZmF1bHQuY29tcHV0ZVJlYWxSb290cygxLCBHMiwgSDIpOwogICAgICBjb25zdCByb290czIgPSBRdWFkcmF0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0LmNvbXB1dGVSZWFsUm9vdHMoMSwgZzMsIGgzKTsKICAgICAgaWYgKHJvb3RzMS5sZW5ndGggIT09IDApIHsKICAgICAgICBpZiAocm9vdHMyLmxlbmd0aCAhPT0gMCkgewogICAgICAgICAgaWYgKHJvb3RzMVsxXSA8PSByb290czJbMF0pIHsKICAgICAgICAgICAgcmV0dXJuIFtyb290czFbMF0sIHJvb3RzMVsxXSwgcm9vdHMyWzBdLCByb290czJbMV1dOwogICAgICAgICAgfSBlbHNlIGlmIChyb290czJbMV0gPD0gcm9vdHMxWzBdKSB7CiAgICAgICAgICAgIHJldHVybiBbcm9vdHMyWzBdLCByb290czJbMV0sIHJvb3RzMVswXSwgcm9vdHMxWzFdXTsKICAgICAgICAgIH0gZWxzZSBpZiAocm9vdHMxWzBdID49IHJvb3RzMlswXSAmJiByb290czFbMV0gPD0gcm9vdHMyWzFdKSB7CiAgICAgICAgICAgIHJldHVybiBbcm9vdHMyWzBdLCByb290czFbMF0sIHJvb3RzMVsxXSwgcm9vdHMyWzFdXTsKICAgICAgICAgIH0gZWxzZSBpZiAocm9vdHMyWzBdID49IHJvb3RzMVswXSAmJiByb290czJbMV0gPD0gcm9vdHMxWzFdKSB7CiAgICAgICAgICAgIHJldHVybiBbcm9vdHMxWzBdLCByb290czJbMF0sIHJvb3RzMlsxXSwgcm9vdHMxWzFdXTsKICAgICAgICAgIH0gZWxzZSBpZiAocm9vdHMxWzBdID4gcm9vdHMyWzBdICYmIHJvb3RzMVswXSA8IHJvb3RzMlsxXSkgewogICAgICAgICAgICByZXR1cm4gW3Jvb3RzMlswXSwgcm9vdHMxWzBdLCByb290czJbMV0sIHJvb3RzMVsxXV07CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gW3Jvb3RzMVswXSwgcm9vdHMyWzBdLCByb290czFbMV0sIHJvb3RzMlsxXV07CiAgICAgICAgfQogICAgICAgIHJldHVybiByb290czE7CiAgICAgIH0KICAgICAgaWYgKHJvb3RzMi5sZW5ndGggIT09IDApIHsKICAgICAgICByZXR1cm4gcm9vdHMyOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gW107CiAgfQogIHZhciBRdWFydGljUmVhbFBvbHlub21pYWwsIFF1YXJ0aWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0OwogIHZhciBpbml0X1F1YXJ0aWNSZWFsUG9seW5vbWlhbCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUXVhcnRpY1JlYWxQb2x5bm9taWFsLmpzIigpIHsKICAgICAgaW5pdF9DdWJpY1JlYWxQb2x5bm9taWFsKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUXVhZHJhdGljUmVhbFBvbHlub21pYWwoKTsKICAgICAgUXVhcnRpY1JlYWxQb2x5bm9taWFsID0ge307CiAgICAgIFF1YXJ0aWNSZWFsUG9seW5vbWlhbC5jb21wdXRlRGlzY3JpbWluYW50ID0gZnVuY3Rpb24oYTQsIGIyLCBjMiwgZDIsIGUyKSB7CiAgICAgICAgaWYgKHR5cGVvZiBhNCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGIyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImIgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgYzIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYyBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBkMiAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGUyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImUgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGEyMiA9IGE0ICogYTQ7CiAgICAgICAgY29uc3QgYTMyID0gYTIyICogYTQ7CiAgICAgICAgY29uc3QgYjIyID0gYjIgKiBiMjsKICAgICAgICBjb25zdCBiMyA9IGIyMiAqIGIyOwogICAgICAgIGNvbnN0IGMyMiA9IGMyICogYzI7CiAgICAgICAgY29uc3QgYzMyID0gYzIyICogYzI7CiAgICAgICAgY29uc3QgZDIyID0gZDIgKiBkMjsKICAgICAgICBjb25zdCBkMyA9IGQyMiAqIGQyOwogICAgICAgIGNvbnN0IGUyMiA9IGUyICogZTI7CiAgICAgICAgY29uc3QgZTMgPSBlMjIgKiBlMjsKICAgICAgICBjb25zdCBkaXNjcmltaW5hbnQgPSBiMjIgKiBjMjIgKiBkMjIgLSA0ICogYjMgKiBkMyAtIDQgKiBhNCAqIGMzMiAqIGQyMiArIDE4ICogYTQgKiBiMiAqIGMyICogZDMgLSAyNyAqIGEyMiAqIGQyMiAqIGQyMiArIDI1NiAqIGEzMiAqIGUzICsgZTIgKiAoMTggKiBiMyAqIGMyICogZDIgLSA0ICogYjIyICogYzMyICsgMTYgKiBhNCAqIGMyMiAqIGMyMiAtIDgwICogYTQgKiBiMiAqIGMyMiAqIGQyIC0gNiAqIGE0ICogYjIyICogZDIyICsgMTQ0ICogYTIyICogYzIgKiBkMjIpICsgZTIyICogKDE0NCAqIGE0ICogYjIyICogYzIgLSAyNyAqIGIyMiAqIGIyMiAtIDEyOCAqIGEyMiAqIGMyMiAtIDE5MiAqIGEyMiAqIGIyICogZDIpOwogICAgICAgIHJldHVybiBkaXNjcmltaW5hbnQ7CiAgICAgIH07CiAgICAgIFF1YXJ0aWNSZWFsUG9seW5vbWlhbC5jb21wdXRlUmVhbFJvb3RzID0gZnVuY3Rpb24oYTQsIGIyLCBjMiwgZDIsIGUyKSB7CiAgICAgICAgaWYgKHR5cGVvZiBhNCAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGIyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImIgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmICh0eXBlb2YgYzIgIT09ICJudW1iZXIiKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYyBpcyBhIHJlcXVpcmVkIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKHR5cGVvZiBkMiAhPT0gIm51bWJlciIpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkIGlzIGEgcmVxdWlyZWQgbnVtYmVyLiIpOwogICAgICAgIH0KICAgICAgICBpZiAodHlwZW9mIGUyICE9PSAibnVtYmVyIikgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImUgaXMgYSByZXF1aXJlZCBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIGlmIChNYXRoLmFicyhhNCkgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE1KSB7CiAgICAgICAgICByZXR1cm4gQ3ViaWNSZWFsUG9seW5vbWlhbF9kZWZhdWx0LmNvbXB1dGVSZWFsUm9vdHMoYjIsIGMyLCBkMiwgZTIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhMzIgPSBiMiAvIGE0OwogICAgICAgIGNvbnN0IGEyMiA9IGMyIC8gYTQ7CiAgICAgICAgY29uc3QgYTEgPSBkMiAvIGE0OwogICAgICAgIGNvbnN0IGEwID0gZTIgLyBhNDsKICAgICAgICBsZXQgazIgPSBhMzIgPCAwID8gMSA6IDA7CiAgICAgICAgazIgKz0gYTIyIDwgMCA/IGsyICsgMSA6IGsyOwogICAgICAgIGsyICs9IGExIDwgMCA/IGsyICsgMSA6IGsyOwogICAgICAgIGsyICs9IGEwIDwgMCA/IGsyICsgMSA6IGsyOwogICAgICAgIHN3aXRjaCAoazIpIHsKICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsKGEzMiwgYTIyLCBhMSwgYTApOwogICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICByZXR1cm4gbmV1bWFyayhhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgcmV0dXJuIG5ldW1hcmsoYTMyLCBhMjIsIGExLCBhMCk7CiAgICAgICAgICBjYXNlIDM6CiAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgNDoKICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsKGEzMiwgYTIyLCBhMSwgYTApOwogICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICByZXR1cm4gbmV1bWFyayhhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsKGEzMiwgYTIyLCBhMSwgYTApOwogICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwoYTMyLCBhMjIsIGExLCBhMCk7CiAgICAgICAgICBjYXNlIDg6CiAgICAgICAgICAgIHJldHVybiBuZXVtYXJrKGEzMiwgYTIyLCBhMSwgYTApOwogICAgICAgICAgY2FzZSA5OgogICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwoYTMyLCBhMjIsIGExLCBhMCk7CiAgICAgICAgICBjYXNlIDEwOgogICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwoYTMyLCBhMjIsIGExLCBhMCk7CiAgICAgICAgICBjYXNlIDExOgogICAgICAgICAgICByZXR1cm4gbmV1bWFyayhhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgMTI6CiAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgMTM6CiAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgMTQ6CiAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGNhc2UgMTU6CiAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbChhMzIsIGEyMiwgYTEsIGEwKTsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICB9OwogICAgICBRdWFydGljUmVhbFBvbHlub21pYWxfZGVmYXVsdCA9IFF1YXJ0aWNSZWFsUG9seW5vbWlhbDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JheS5qcwogIHZhciBSYXksIFJheV9kZWZhdWx0OwogIHZhciBpbml0X1JheSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmF5LmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIFJheSA9IGNsYXNzIF9SYXkgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gW29yaWdpbj1DYXJ0ZXNpYW4zLlpFUk9dIFRoZSBvcmlnaW4gb2YgdGhlIHJheS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtkaXJlY3Rpb249Q2FydGVzaWFuMy5aRVJPXSBUaGUgZGlyZWN0aW9uIG9mIHRoZSByYXkuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3Iob3JpZ2luLCBkaXJlY3Rpb24yKSB7CiAgICAgICAgICBkaXJlY3Rpb24yID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGRpcmVjdGlvbjIgPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pOwogICAgICAgICAgaWYgKCFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGRpcmVjdGlvbjIsIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKSkgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGRpcmVjdGlvbjIsIGRpcmVjdGlvbjIpOwogICAgICAgICAgfQogICAgICAgICAgdGhpcy5vcmlnaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUob3JpZ2luID8/IENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKTsKICAgICAgICAgIHRoaXMuZGlyZWN0aW9uID0gZGlyZWN0aW9uMjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRHVwbGljYXRlcyBhIFJheSBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmF5fSByYXkgVGhlIHJheSB0byBkdXBsaWNhdGUuCiAgICAgICAgICogQHBhcmFtIHtSYXl9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtSYXl9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IFJheSBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4gKFJldHVybnMgdW5kZWZpbmVkIGlmIHJheSBpcyB1bmRlZmluZWQpCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGNsb25lKHJheSwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyYXkpKSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX1JheShyYXkub3JpZ2luLCByYXkuZGlyZWN0aW9uKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC5vcmlnaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocmF5Lm9yaWdpbik7CiAgICAgICAgICByZXN1bHQuZGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHJheS5kaXJlY3Rpb24pOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIHBvaW50IGFsb25nIHRoZSByYXkgZ2l2ZW4gYnkgcih0KSA9IG8gKyB0KmQsCiAgICAgICAgICogd2hlcmUgbyBpcyB0aGUgb3JpZ2luIG9mIHRoZSByYXkgYW5kIGQgaXMgdGhlIGRpcmVjdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7UmF5fSByYXkgVGhlIHJheS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gdCBBIHNjYWxhciB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRlc2lhbjN9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW4gd2hpY2ggdGhlIHJlc3VsdCB3aWxsIGJlIHN0b3JlZC4KICAgICAgICAgKiBAcmV0dXJucyB7Q2FydGVzaWFuM30gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIsIG9yIGEgbmV3IGluc3RhbmNlIGlmIG5vbmUgd2FzIHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiAvL0dldCB0aGUgZmlyc3QgaW50ZXJzZWN0aW9uIHBvaW50IG9mIGEgcmF5IGFuZCBhbiBlbGxpcHNvaWQuCiAgICAgICAgICogY29uc3QgaW50ZXJzZWN0aW9uID0gQ2VzaXVtLkludGVyc2VjdGlvblRlc3RzLnJheUVsbGlwc29pZChyYXksIGVsbGlwc29pZCk7CiAgICAgICAgICogY29uc3QgcG9pbnQgPSBDZXNpdW0uUmF5LmdldFBvaW50KHJheSwgaW50ZXJzZWN0aW9uLnN0YXJ0KTsKICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZ2V0UG9pbnQocmF5LCB0MiwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJheSIsIHJheSk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInQiLCB0Mik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHJheS5kaXJlY3Rpb24sIHQyLCByZXN1bHQpOwogICAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmF5Lm9yaWdpbiwgcmVzdWx0LCByZXN1bHQpOwogICAgICAgIH0KICAgICAgfTsKICAgICAgUmF5X2RlZmF1bHQgPSBSYXk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9JbnRlcnNlY3Rpb25UZXN0cy5qcwogIGZ1bmN0aW9uIHNvbHZlUXVhZHJhdGljKGE0LCBiMiwgYzIsIHJlc3VsdCkgewogICAgY29uc3QgZGV0ID0gYjIgKiBiMiAtIDQgKiBhNCAqIGMyOwogICAgaWYgKGRldCA8IDApIHsKICAgICAgcmV0dXJuIHZvaWQgMDsKICAgIH0gZWxzZSBpZiAoZGV0ID4gMCkgewogICAgICBjb25zdCBkZW5vbSA9IDEgLyAoMiAqIGE0KTsKICAgICAgY29uc3QgZGlzYyA9IE1hdGguc3FydChkZXQpOwogICAgICBjb25zdCByb290MCA9ICgtYjIgKyBkaXNjKSAqIGRlbm9tOwogICAgICBjb25zdCByb290MSA9ICgtYjIgLSBkaXNjKSAqIGRlbm9tOwogICAgICBpZiAocm9vdDAgPCByb290MSkgewogICAgICAgIHJlc3VsdC5yb290MCA9IHJvb3QwOwogICAgICAgIHJlc3VsdC5yb290MSA9IHJvb3QxOwogICAgICB9IGVsc2UgewogICAgICAgIHJlc3VsdC5yb290MCA9IHJvb3QxOwogICAgICAgIHJlc3VsdC5yb290MSA9IHJvb3QwOwogICAgICB9CiAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9CiAgICBjb25zdCByb290ID0gLWIyIC8gKDIgKiBhNCk7CiAgICBpZiAocm9vdCA9PT0gMCkgewogICAgICByZXR1cm4gdm9pZCAwOwogICAgfQogICAgcmVzdWx0LnJvb3QwID0gcmVzdWx0LnJvb3QxID0gcm9vdDsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIHJheVNwaGVyZShyYXksIHNwaGVyZSwgcmVzdWx0KSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgIHJlc3VsdCA9IG5ldyBJbnRlcnZhbF9kZWZhdWx0KCk7CiAgICB9CiAgICBjb25zdCBvcmlnaW4gPSByYXkub3JpZ2luOwogICAgY29uc3QgZGlyZWN0aW9uMiA9IHJheS5kaXJlY3Rpb247CiAgICBjb25zdCBjZW50ZXIgPSBzcGhlcmUuY2VudGVyOwogICAgY29uc3QgcmFkaXVzU3F1YXJlZCA9IHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzOwogICAgY29uc3QgZGlmZiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChvcmlnaW4sIGNlbnRlciwgc2NyYXRjaFBWZWMpOwogICAgY29uc3QgYTQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIGRpcmVjdGlvbjIpOwogICAgY29uc3QgYjIgPSAyICogQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCBkaWZmKTsKICAgIGNvbnN0IGMyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoZGlmZikgLSByYWRpdXNTcXVhcmVkOwogICAgY29uc3Qgcm9vdHMgPSBzb2x2ZVF1YWRyYXRpYyhhNCwgYjIsIGMyLCByYXlTcGhlcmVSb290cyk7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyb290cykpIHsKICAgICAgcmV0dXJuIHZvaWQgMDsKICAgIH0KICAgIHJlc3VsdC5zdGFydCA9IHJvb3RzLnJvb3QwOwogICAgcmVzdWx0LnN0b3AgPSByb290cy5yb290MTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIHJheUludGVydmFsQWxvbmdBQUJCQXhpcyhvcmlnaW4sIGRpcmVjdGlvbjIsIG1pbjMsIG1heDMsIHJlc3VsdCkgewogICAgcmVzdWx0LnN0YXJ0ID0gKG1pbjMgLSBvcmlnaW4pIC8gZGlyZWN0aW9uMjsKICAgIHJlc3VsdC5zdG9wID0gKG1heDMgLSBvcmlnaW4pIC8gZGlyZWN0aW9uMjsKICAgIGlmIChyZXN1bHQuc3RvcCA8IHJlc3VsdC5zdGFydCkgewogICAgICBjb25zdCB0bXAyID0gcmVzdWx0LnN0b3A7CiAgICAgIHJlc3VsdC5zdG9wID0gcmVzdWx0LnN0YXJ0OwogICAgICByZXN1bHQuc3RhcnQgPSB0bXAyOwogICAgfQogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgZnVuY3Rpb24gYWRkV2l0aENhbmNlbGxhdGlvbkNoZWNrMihsZWZ0LCByaWdodCwgdG9sZXJhbmNlKSB7CiAgICBjb25zdCBkaWZmZXJlbmNlID0gbGVmdCArIHJpZ2h0OwogICAgaWYgKE1hdGhfZGVmYXVsdC5zaWduKGxlZnQpICE9PSBNYXRoX2RlZmF1bHQuc2lnbihyaWdodCkgJiYgTWF0aC5hYnMoZGlmZmVyZW5jZSAvIE1hdGgubWF4KE1hdGguYWJzKGxlZnQpLCBNYXRoLmFicyhyaWdodCkpKSA8IHRvbGVyYW5jZSkgewogICAgICByZXR1cm4gMDsKICAgIH0KICAgIHJldHVybiBkaWZmZXJlbmNlOwogIH0KICB2YXIgSW50ZXJzZWN0aW9uVGVzdHMsIHNjcmF0Y2hFZGdlMCwgc2NyYXRjaEVkZ2UxLCBzY3JhdGNoUFZlYywgc2NyYXRjaFRWZWMsIHNjcmF0Y2hRVmVjLCBzY3JhdGNoTGluZVNlZ21lbnRUcmlhbmdsZVJheSwgcmF5U3BoZXJlUm9vdHMsIHNjcmF0Y2hMaW5lU2VnbWVudFJheSwgc2NyYXRjaFEsIHNjcmF0Y2hXLCBzY3JhdGNoUmF5SW50ZXJ2YWxYLCBzY3JhdGNoUmF5SW50ZXJ2YWxZLCBzY3JhdGNoUmF5SW50ZXJ2YWxaLCBmaXJzdEF4aXNTY3JhdGNoLCBzZWNvbmRBeGlzU2NyYXRjaCwgdGhpcmRBeGlzU2NyYXRjaCwgcmVmZXJlbmNlU2NyYXRjaCwgYkNhcnQsIGJTY3JhdGNoLCBidFNjcmF0Y2gsIGRpU2NyYXRjaCwgZFNjcmF0Y2gsIGNTY3JhdGNoLCB0ZW1wTWF0cml4LCBhU2NyYXRjaCwgc1NjcmF0Y2gsIGNsb3Nlc3RTY3JhdGNoLCBzdXJmUG9pbnRTY3JhdGNoLCBsaW5lU2VnbWVudFBsYW5lRGlmZmVyZW5jZSwgSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdDsKICB2YXIgaW5pdF9JbnRlcnNlY3Rpb25UZXN0cyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSW50ZXJzZWN0aW9uVGVzdHMuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9JbnRlcnZhbCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfUXVhZHJhdGljUmVhbFBvbHlub21pYWwoKTsKICAgICAgaW5pdF9RdWFydGljUmVhbFBvbHlub21pYWwoKTsKICAgICAgaW5pdF9SYXkoKTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMgPSB7fTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMucmF5UGxhbmUgPSBmdW5jdGlvbihyYXksIHBsYW5lLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmF5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwbGFuZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBvcmlnaW4gPSByYXkub3JpZ2luOwogICAgICAgIGNvbnN0IGRpcmVjdGlvbjIgPSByYXkuZGlyZWN0aW9uOwogICAgICAgIGNvbnN0IG5vcm1hbDIgPSBwbGFuZS5ub3JtYWw7CiAgICAgICAgY29uc3QgZGVub21pbmF0b3IgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG5vcm1hbDIsIGRpcmVjdGlvbjIpOwogICAgICAgIGlmIChNYXRoLmFicyhkZW5vbWluYXRvcikgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjE1KSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBjb25zdCB0MiA9ICgtcGxhbmUuZGlzdGFuY2UgLSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG5vcm1hbDIsIG9yaWdpbikpIC8gZGVub21pbmF0b3I7CiAgICAgICAgaWYgKHQyIDwgMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZGlyZWN0aW9uMiwgdDIsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQob3JpZ2luLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFZGdlMCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVkZ2UxID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUFZlYyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRWZWMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hRVmVjID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBJbnRlcnNlY3Rpb25UZXN0cy5yYXlUcmlhbmdsZVBhcmFtZXRyaWMgPSBmdW5jdGlvbihyYXksIHAwLCBwMSwgcDIsIGN1bGxCYWNrRmFjZXMpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmF5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwMCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwMCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDEpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicDEgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHAyKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInAyIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjdWxsQmFja0ZhY2VzID0gY3VsbEJhY2tGYWNlcyA/PyBmYWxzZTsKICAgICAgICBjb25zdCBvcmlnaW4gPSByYXkub3JpZ2luOwogICAgICAgIGNvbnN0IGRpcmVjdGlvbjIgPSByYXkuZGlyZWN0aW9uOwogICAgICAgIGNvbnN0IGVkZ2UwID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMCwgc2NyYXRjaEVkZ2UwKTsKICAgICAgICBjb25zdCBlZGdlMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwMiwgcDAsIHNjcmF0Y2hFZGdlMSk7CiAgICAgICAgY29uc3QgcDMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoZGlyZWN0aW9uMiwgZWRnZTEsIHNjcmF0Y2hQVmVjKTsKICAgICAgICBjb25zdCBkZXQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGVkZ2UwLCBwMyk7CiAgICAgICAgbGV0IHR2ZWM7CiAgICAgICAgbGV0IHEzOwogICAgICAgIGxldCB1NDsKICAgICAgICBsZXQgdjQ7CiAgICAgICAgbGV0IHQyOwogICAgICAgIGlmIChjdWxsQmFja0ZhY2VzKSB7CiAgICAgICAgICBpZiAoZGV0IDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICB0dmVjID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KG9yaWdpbiwgcDAsIHNjcmF0Y2hUVmVjKTsKICAgICAgICAgIHU0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh0dmVjLCBwMyk7CiAgICAgICAgICBpZiAodTQgPCAwIHx8IHU0ID4gZGV0KSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBxMyA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyh0dmVjLCBlZGdlMCwgc2NyYXRjaFFWZWMpOwogICAgICAgICAgdjQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIHEzKTsKICAgICAgICAgIGlmICh2NCA8IDAgfHwgdTQgKyB2NCA+IGRldCkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgdDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGVkZ2UxLCBxMykgLyBkZXQ7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmIChNYXRoLmFicyhkZXQpIDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBpbnZEZXQgPSAxIC8gZGV0OwogICAgICAgICAgdHZlYyA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChvcmlnaW4sIHAwLCBzY3JhdGNoVFZlYyk7CiAgICAgICAgICB1NCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodHZlYywgcDMpICogaW52RGV0OwogICAgICAgICAgaWYgKHU0IDwgMCB8fCB1NCA+IDEpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIHEzID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHR2ZWMsIGVkZ2UwLCBzY3JhdGNoUVZlYyk7CiAgICAgICAgICB2NCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZGlyZWN0aW9uMiwgcTMpICogaW52RGV0OwogICAgICAgICAgaWYgKHY0IDwgMCB8fCB1NCArIHY0ID4gMSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgdDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGVkZ2UxLCBxMykgKiBpbnZEZXQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiB0MjsKICAgICAgfTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMucmF5VHJpYW5nbGUgPSBmdW5jdGlvbihyYXksIHAwLCBwMSwgcDIsIGN1bGxCYWNrRmFjZXMsIHJlc3VsdCkgewogICAgICAgIGNvbnN0IHQyID0gSW50ZXJzZWN0aW9uVGVzdHMucmF5VHJpYW5nbGVQYXJhbWV0cmljKAogICAgICAgICAgcmF5LAogICAgICAgICAgcDAsCiAgICAgICAgICBwMSwKICAgICAgICAgIHAyLAogICAgICAgICAgY3VsbEJhY2tGYWNlcwogICAgICAgICk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodDIpIHx8IHQyIDwgMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihyYXkuZGlyZWN0aW9uLCB0MiwgcmVzdWx0KTsKICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyYXkub3JpZ2luLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hMaW5lU2VnbWVudFRyaWFuZ2xlUmF5ID0gbmV3IFJheV9kZWZhdWx0KCk7CiAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50VHJpYW5nbGUgPSBmdW5jdGlvbih2MDIsIHYxMiwgcDAsIHAxLCBwMiwgY3VsbEJhY2tGYWNlcywgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodjAyKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInYwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2MTIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidjEgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHAwKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInAwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwMSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwMSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicDIgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHJheSA9IHNjcmF0Y2hMaW5lU2VnbWVudFRyaWFuZ2xlUmF5OwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSh2MDIsIHJheS5vcmlnaW4pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh2MTIsIHYwMiwgcmF5LmRpcmVjdGlvbik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShyYXkuZGlyZWN0aW9uLCByYXkuZGlyZWN0aW9uKTsKICAgICAgICBjb25zdCB0MiA9IEludGVyc2VjdGlvblRlc3RzLnJheVRyaWFuZ2xlUGFyYW1ldHJpYygKICAgICAgICAgIHJheSwKICAgICAgICAgIHAwLAogICAgICAgICAgcDEsCiAgICAgICAgICBwMiwKICAgICAgICAgIGN1bGxCYWNrRmFjZXMKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHQyKSB8fCB0MiA8IDAgfHwgdDIgPiBDYXJ0ZXNpYW4zX2RlZmF1bHQuZGlzdGFuY2UodjAyLCB2MTIpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHJheS5kaXJlY3Rpb24sIHQyLCByZXN1bHQpOwogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJheS5vcmlnaW4sIHJlc3VsdCwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgcmF5U3BoZXJlUm9vdHMgPSB7CiAgICAgICAgcm9vdDA6IDAsCiAgICAgICAgcm9vdDE6IDAKICAgICAgfTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMucmF5U3BoZXJlID0gZnVuY3Rpb24ocmF5LCBzcGhlcmUsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyYXkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHNwaGVyZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzcGhlcmUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIHJlc3VsdCA9IHJheVNwaGVyZShyYXksIHNwaGVyZSwgcmVzdWx0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpIHx8IHJlc3VsdC5zdG9wIDwgMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnN0YXJ0ID0gTWF0aC5tYXgocmVzdWx0LnN0YXJ0LCAwKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoTGluZVNlZ21lbnRSYXkgPSBuZXcgUmF5X2RlZmF1bHQoKTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMubGluZVNlZ21lbnRTcGhlcmUgPSBmdW5jdGlvbihwMCwgcDEsIHNwaGVyZSwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDApKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicDAgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHAxKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInAxIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzcGhlcmUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgic3BoZXJlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCByYXkgPSBzY3JhdGNoTGluZVNlZ21lbnRSYXk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHAwLCByYXkub3JpZ2luKTsKICAgICAgICBjb25zdCBkaXJlY3Rpb24yID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMCwgcmF5LmRpcmVjdGlvbik7CiAgICAgICAgY29uc3QgbWF4VCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoZGlyZWN0aW9uMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShkaXJlY3Rpb24yLCBkaXJlY3Rpb24yKTsKICAgICAgICByZXN1bHQgPSByYXlTcGhlcmUocmF5LCBzcGhlcmUsIHJlc3VsdCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSB8fCByZXN1bHQuc3RvcCA8IDAgfHwgcmVzdWx0LnN0YXJ0ID4gbWF4VCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnN0YXJ0ID0gTWF0aC5tYXgocmVzdWx0LnN0YXJ0LCAwKTsKICAgICAgICByZXN1bHQuc3RvcCA9IE1hdGgubWluKHJlc3VsdC5zdG9wLCBtYXhUKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoUSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEludGVyc2VjdGlvblRlc3RzLnJheUVsbGlwc29pZCA9IGZ1bmN0aW9uKHJheSwgZWxsaXBzb2lkKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJheSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImVsbGlwc29pZCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgaW52ZXJzZVJhZGlpID0gZWxsaXBzb2lkLm9uZU92ZXJSYWRpaTsKICAgICAgICBjb25zdCBxMyA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUNvbXBvbmVudHMoaW52ZXJzZVJhZGlpLCByYXkub3JpZ2luLCBzY3JhdGNoUSk7CiAgICAgICAgY29uc3QgdzIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlDb21wb25lbnRzKAogICAgICAgICAgaW52ZXJzZVJhZGlpLAogICAgICAgICAgcmF5LmRpcmVjdGlvbiwKICAgICAgICAgIHNjcmF0Y2hXCiAgICAgICAgKTsKICAgICAgICBjb25zdCBxMjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZChxMyk7CiAgICAgICAgY29uc3QgcXcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHEzLCB3Mik7CiAgICAgICAgbGV0IGRpZmZlcmVuY2UsIHcyMiwgcHJvZHVjdCwgZGlzY3JpbWluYW50LCB0ZW1wOwogICAgICAgIGlmIChxMjIgPiAxKSB7CiAgICAgICAgICBpZiAocXcgPj0gMCkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgcXcyID0gcXcgKiBxdzsKICAgICAgICAgIGRpZmZlcmVuY2UgPSBxMjIgLSAxOwogICAgICAgICAgdzIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQodzIpOwogICAgICAgICAgcHJvZHVjdCA9IHcyMiAqIGRpZmZlcmVuY2U7CiAgICAgICAgICBpZiAocXcyIDwgcHJvZHVjdCkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfSBlbHNlIGlmIChxdzIgPiBwcm9kdWN0KSB7CiAgICAgICAgICAgIGRpc2NyaW1pbmFudCA9IHF3ICogcXcgLSBwcm9kdWN0OwogICAgICAgICAgICB0ZW1wID0gLXF3ICsgTWF0aC5zcXJ0KGRpc2NyaW1pbmFudCk7CiAgICAgICAgICAgIGNvbnN0IHJvb3QwID0gdGVtcCAvIHcyMjsKICAgICAgICAgICAgY29uc3Qgcm9vdDEgPSBkaWZmZXJlbmNlIC8gdGVtcDsKICAgICAgICAgICAgaWYgKHJvb3QwIDwgcm9vdDEpIHsKICAgICAgICAgICAgICByZXR1cm4gbmV3IEludGVydmFsX2RlZmF1bHQocm9vdDAsIHJvb3QxKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgIHN0YXJ0OiByb290MSwKICAgICAgICAgICAgICBzdG9wOiByb290MAogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgcm9vdCA9IE1hdGguc3FydChkaWZmZXJlbmNlIC8gdzIyKTsKICAgICAgICAgIHJldHVybiBuZXcgSW50ZXJ2YWxfZGVmYXVsdChyb290LCByb290KTsKICAgICAgICB9IGVsc2UgaWYgKHEyMiA8IDEpIHsKICAgICAgICAgIGRpZmZlcmVuY2UgPSBxMjIgLSAxOwogICAgICAgICAgdzIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQodzIpOwogICAgICAgICAgcHJvZHVjdCA9IHcyMiAqIGRpZmZlcmVuY2U7CiAgICAgICAgICBkaXNjcmltaW5hbnQgPSBxdyAqIHF3IC0gcHJvZHVjdDsKICAgICAgICAgIHRlbXAgPSAtcXcgKyBNYXRoLnNxcnQoZGlzY3JpbWluYW50KTsKICAgICAgICAgIHJldHVybiBuZXcgSW50ZXJ2YWxfZGVmYXVsdCgwLCB0ZW1wIC8gdzIyKTsKICAgICAgICB9CiAgICAgICAgaWYgKHF3IDwgMCkgewogICAgICAgICAgdzIyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQodzIpOwogICAgICAgICAgcmV0dXJuIG5ldyBJbnRlcnZhbF9kZWZhdWx0KDAsIC1xdyAvIHcyMik7CiAgICAgICAgfQogICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hSYXlJbnRlcnZhbFggPSBuZXcgSW50ZXJ2YWxfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUmF5SW50ZXJ2YWxZID0gbmV3IEludGVydmFsX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFJheUludGVydmFsWiA9IG5ldyBJbnRlcnZhbF9kZWZhdWx0KCk7CiAgICAgIEludGVyc2VjdGlvblRlc3RzLnJheUF4aXNBbGlnbmVkQm91bmRpbmdCb3ggPSBmdW5jdGlvbihyYXksIGJveCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJheSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm94KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImJveCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEludGVydmFsX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdHggPSByYXlJbnRlcnZhbEFsb25nQUFCQkF4aXMoCiAgICAgICAgICByYXkub3JpZ2luLngsCiAgICAgICAgICByYXkuZGlyZWN0aW9uLngsCiAgICAgICAgICBib3gubWluaW11bS54LAogICAgICAgICAgYm94Lm1heGltdW0ueCwKICAgICAgICAgIHNjcmF0Y2hSYXlJbnRlcnZhbFgKICAgICAgICApOwogICAgICAgIGNvbnN0IHR5ID0gcmF5SW50ZXJ2YWxBbG9uZ0FBQkJBeGlzKAogICAgICAgICAgcmF5Lm9yaWdpbi55LAogICAgICAgICAgcmF5LmRpcmVjdGlvbi55LAogICAgICAgICAgYm94Lm1pbmltdW0ueSwKICAgICAgICAgIGJveC5tYXhpbXVtLnksCiAgICAgICAgICBzY3JhdGNoUmF5SW50ZXJ2YWxZCiAgICAgICAgKTsKICAgICAgICBjb25zdCB0eiA9IHJheUludGVydmFsQWxvbmdBQUJCQXhpcygKICAgICAgICAgIHJheS5vcmlnaW4ueiwKICAgICAgICAgIHJheS5kaXJlY3Rpb24ueiwKICAgICAgICAgIGJveC5taW5pbXVtLnosCiAgICAgICAgICBib3gubWF4aW11bS56LAogICAgICAgICAgc2NyYXRjaFJheUludGVydmFsWgogICAgICAgICk7CiAgICAgICAgcmVzdWx0LnN0YXJ0ID0gdHguc3RhcnQgPiB0eS5zdGFydCA/IHR4LnN0YXJ0IDogdHkuc3RhcnQ7CiAgICAgICAgcmVzdWx0LnN0b3AgPSB0eC5zdG9wIDwgdHkuc3RvcCA/IHR4LnN0b3AgOiB0eS5zdG9wOwogICAgICAgIGlmICh0eC5zdGFydCA+IHR5LnN0b3AgfHwgdHkuc3RhcnQgPiB0eC5zdG9wKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAocmVzdWx0LnN0YXJ0ID4gdHouc3RvcCB8fCB0ei5zdGFydCA+IHJlc3VsdC5zdG9wKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAodHouc3RhcnQgPiByZXN1bHQuc3RhcnQpIHsKICAgICAgICAgIHJlc3VsdC5zdGFydCA9IHR6LnN0YXJ0OwogICAgICAgIH0KICAgICAgICBpZiAodHouc3RvcCA8IHJlc3VsdC5zdG9wKSB7CiAgICAgICAgICByZXN1bHQuc3RvcCA9IHR6LnN0b3A7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEludGVyc2VjdGlvblRlc3RzLnF1YWRyYXRpY1ZlY3RvckV4cHJlc3Npb24gPSBmdW5jdGlvbihBMiwgYjIsIGMyLCB4MiwgdzIpIHsKICAgICAgICBjb25zdCB4U3F1YXJlZCA9IHgyICogeDI7CiAgICAgICAgY29uc3Qgd1NxdWFyZWQgPSB3MiAqIHcyOwogICAgICAgIGNvbnN0IGwyID0gKEEyW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4xUk9XMV0gLSBBMltNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMlJPVzJdKSAqIHdTcXVhcmVkOwogICAgICAgIGNvbnN0IGwxID0gdzIgKiAoeDIgKiBhZGRXaXRoQ2FuY2VsbGF0aW9uQ2hlY2syKAogICAgICAgICAgQTJbTWF0cml4M19kZWZhdWx0LkNPTFVNTjFST1cwXSwKICAgICAgICAgIEEyW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4wUk9XMV0sCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjE1CiAgICAgICAgKSArIGIyLnkpOwogICAgICAgIGNvbnN0IGwwID0gQTJbTWF0cml4M19kZWZhdWx0LkNPTFVNTjBST1cwXSAqIHhTcXVhcmVkICsgQTJbTWF0cml4M19kZWZhdWx0LkNPTFVNTjJST1cyXSAqIHdTcXVhcmVkICsgeDIgKiBiMi54ICsgYzI7CiAgICAgICAgY29uc3QgcjEgPSB3U3F1YXJlZCAqIGFkZFdpdGhDYW5jZWxsYXRpb25DaGVjazIoCiAgICAgICAgICBBMltNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMlJPVzFdLAogICAgICAgICAgQTJbTWF0cml4M19kZWZhdWx0LkNPTFVNTjFST1cyXSwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTUKICAgICAgICApOwogICAgICAgIGNvbnN0IHIwID0gdzIgKiAoeDIgKiBhZGRXaXRoQ2FuY2VsbGF0aW9uQ2hlY2syKEEyW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4yUk9XMF0sIEEyW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4wUk9XMl0pICsgYjIueik7CiAgICAgICAgbGV0IGNvc2luZXM7CiAgICAgICAgY29uc3Qgc29sdXRpb25zID0gW107CiAgICAgICAgaWYgKHIwID09PSAwICYmIHIxID09PSAwKSB7CiAgICAgICAgICBjb3NpbmVzID0gUXVhZHJhdGljUmVhbFBvbHlub21pYWxfZGVmYXVsdC5jb21wdXRlUmVhbFJvb3RzKGwyLCBsMSwgbDApOwogICAgICAgICAgaWYgKGNvc2luZXMubGVuZ3RoID09PSAwKSB7CiAgICAgICAgICAgIHJldHVybiBzb2x1dGlvbnM7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBjb3NpbmUwID0gY29zaW5lc1swXTsKICAgICAgICAgIGNvbnN0IHNpbmUwID0gTWF0aC5zcXJ0KE1hdGgubWF4KDEgLSBjb3NpbmUwICogY29zaW5lMCwgMCkpOwogICAgICAgICAgc29sdXRpb25zLnB1c2gobmV3IENhcnRlc2lhbjNfZGVmYXVsdCh4MiwgdzIgKiBjb3NpbmUwLCB3MiAqIC1zaW5lMCkpOwogICAgICAgICAgc29sdXRpb25zLnB1c2gobmV3IENhcnRlc2lhbjNfZGVmYXVsdCh4MiwgdzIgKiBjb3NpbmUwLCB3MiAqIHNpbmUwKSk7CiAgICAgICAgICBpZiAoY29zaW5lcy5sZW5ndGggPT09IDIpIHsKICAgICAgICAgICAgY29uc3QgY29zaW5lMSA9IGNvc2luZXNbMV07CiAgICAgICAgICAgIGNvbnN0IHNpbmUxID0gTWF0aC5zcXJ0KE1hdGgubWF4KDEgLSBjb3NpbmUxICogY29zaW5lMSwgMCkpOwogICAgICAgICAgICBzb2x1dGlvbnMucHVzaChuZXcgQ2FydGVzaWFuM19kZWZhdWx0KHgyLCB3MiAqIGNvc2luZTEsIHcyICogLXNpbmUxKSk7CiAgICAgICAgICAgIHNvbHV0aW9ucy5wdXNoKG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoeDIsIHcyICogY29zaW5lMSwgdzIgKiBzaW5lMSkpOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHNvbHV0aW9uczsKICAgICAgICB9CiAgICAgICAgY29uc3QgcjBTcXVhcmVkID0gcjAgKiByMDsKICAgICAgICBjb25zdCByMVNxdWFyZWQgPSByMSAqIHIxOwogICAgICAgIGNvbnN0IGwyU3F1YXJlZCA9IGwyICogbDI7CiAgICAgICAgY29uc3QgcjByMSA9IHIwICogcjE7CiAgICAgICAgY29uc3QgYzQgPSBsMlNxdWFyZWQgKyByMVNxdWFyZWQ7CiAgICAgICAgY29uc3QgYzMyID0gMiAqIChsMSAqIGwyICsgcjByMSk7CiAgICAgICAgY29uc3QgYzIyID0gMiAqIGwwICogbDIgKyBsMSAqIGwxIC0gcjFTcXVhcmVkICsgcjBTcXVhcmVkOwogICAgICAgIGNvbnN0IGMxID0gMiAqIChsMCAqIGwxIC0gcjByMSk7CiAgICAgICAgY29uc3QgYzAgPSBsMCAqIGwwIC0gcjBTcXVhcmVkOwogICAgICAgIGlmIChjNCA9PT0gMCAmJiBjMzIgPT09IDAgJiYgYzIyID09PSAwICYmIGMxID09PSAwKSB7CiAgICAgICAgICByZXR1cm4gc29sdXRpb25zOwogICAgICAgIH0KICAgICAgICBjb3NpbmVzID0gUXVhcnRpY1JlYWxQb2x5bm9taWFsX2RlZmF1bHQuY29tcHV0ZVJlYWxSb290cyhjNCwgYzMyLCBjMjIsIGMxLCBjMCk7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gY29zaW5lcy5sZW5ndGg7CiAgICAgICAgaWYgKGxlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmV0dXJuIHNvbHV0aW9uczsKICAgICAgICB9CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY29uc3QgY29zaW5lID0gY29zaW5lc1tpMl07CiAgICAgICAgICBjb25zdCBjb3NpbmVTcXVhcmVkID0gY29zaW5lICogY29zaW5lOwogICAgICAgICAgY29uc3Qgc2luZVNxdWFyZWQgPSBNYXRoLm1heCgxIC0gY29zaW5lU3F1YXJlZCwgMCk7CiAgICAgICAgICBjb25zdCBzaW5lID0gTWF0aC5zcXJ0KHNpbmVTcXVhcmVkKTsKICAgICAgICAgIGxldCBsZWZ0OwogICAgICAgICAgaWYgKE1hdGhfZGVmYXVsdC5zaWduKGwyKSA9PT0gTWF0aF9kZWZhdWx0LnNpZ24obDApKSB7CiAgICAgICAgICAgIGxlZnQgPSBhZGRXaXRoQ2FuY2VsbGF0aW9uQ2hlY2syKAogICAgICAgICAgICAgIGwyICogY29zaW5lU3F1YXJlZCArIGwwLAogICAgICAgICAgICAgIGwxICogY29zaW5lLAogICAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTIKICAgICAgICAgICAgKTsKICAgICAgICAgIH0gZWxzZSBpZiAoTWF0aF9kZWZhdWx0LnNpZ24obDApID09PSBNYXRoX2RlZmF1bHQuc2lnbihsMSAqIGNvc2luZSkpIHsKICAgICAgICAgICAgbGVmdCA9IGFkZFdpdGhDYW5jZWxsYXRpb25DaGVjazIoCiAgICAgICAgICAgICAgbDIgKiBjb3NpbmVTcXVhcmVkLAogICAgICAgICAgICAgIGwxICogY29zaW5lICsgbDAsCiAgICAgICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xMgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgbGVmdCA9IGFkZFdpdGhDYW5jZWxsYXRpb25DaGVjazIoCiAgICAgICAgICAgICAgbDIgKiBjb3NpbmVTcXVhcmVkICsgbDEgKiBjb3NpbmUsCiAgICAgICAgICAgICAgbDAsCiAgICAgICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xMgogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgcmlnaHQgPSBhZGRXaXRoQ2FuY2VsbGF0aW9uQ2hlY2syKAogICAgICAgICAgICByMSAqIGNvc2luZSwKICAgICAgICAgICAgcjAsCiAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTUKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwcm9kdWN0ID0gbGVmdCAqIHJpZ2h0OwogICAgICAgICAgaWYgKHByb2R1Y3QgPCAwKSB7CiAgICAgICAgICAgIHNvbHV0aW9ucy5wdXNoKG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoeDIsIHcyICogY29zaW5lLCB3MiAqIHNpbmUpKTsKICAgICAgICAgIH0gZWxzZSBpZiAocHJvZHVjdCA+IDApIHsKICAgICAgICAgICAgc29sdXRpb25zLnB1c2gobmV3IENhcnRlc2lhbjNfZGVmYXVsdCh4MiwgdzIgKiBjb3NpbmUsIHcyICogLXNpbmUpKTsKICAgICAgICAgIH0gZWxzZSBpZiAoc2luZSAhPT0gMCkgewogICAgICAgICAgICBzb2x1dGlvbnMucHVzaChuZXcgQ2FydGVzaWFuM19kZWZhdWx0KHgyLCB3MiAqIGNvc2luZSwgdzIgKiAtc2luZSkpOwogICAgICAgICAgICBzb2x1dGlvbnMucHVzaChuZXcgQ2FydGVzaWFuM19kZWZhdWx0KHgyLCB3MiAqIGNvc2luZSwgdzIgKiBzaW5lKSk7CiAgICAgICAgICAgICsraTI7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBzb2x1dGlvbnMucHVzaChuZXcgQ2FydGVzaWFuM19kZWZhdWx0KHgyLCB3MiAqIGNvc2luZSwgdzIgKiBzaW5lKSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBzb2x1dGlvbnM7CiAgICAgIH07CiAgICAgIGZpcnN0QXhpc1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNlY29uZEF4aXNTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0aGlyZEF4aXNTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICByZWZlcmVuY2VTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBiQ2FydCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYlNjcmF0Y2ggPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIGJ0U2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgZGlTY3JhdGNoID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBkU2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgY1NjcmF0Y2ggPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIHRlbXBNYXRyaXggPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIGFTY3JhdGNoID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBzU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2xvc2VzdFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN1cmZQb2ludFNjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMuZ3JhemluZ0FsdGl0dWRlTG9jYXRpb24gPSBmdW5jdGlvbihyYXksIGVsbGlwc29pZCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJyYXkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVsbGlwc29pZCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJlbGxpcHNvaWQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBvc2l0aW9uID0gcmF5Lm9yaWdpbjsKICAgICAgICBjb25zdCBkaXJlY3Rpb24yID0gcmF5LmRpcmVjdGlvbjsKICAgICAgICBpZiAoIUNhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMocG9zaXRpb24sIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKSkgewogICAgICAgICAgY29uc3Qgbm9ybWFsMiA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocG9zaXRpb24sIGZpcnN0QXhpc1NjcmF0Y2gpOwogICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZGlyZWN0aW9uMiwgbm9ybWFsMikgPj0gMCkgewogICAgICAgICAgICByZXR1cm4gcG9zaXRpb247CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGludGVyc2VjdHMyID0gZGVmaW5lZF9kZWZhdWx0KHRoaXMucmF5RWxsaXBzb2lkKHJheSwgZWxsaXBzb2lkKSk7CiAgICAgICAgY29uc3QgZjIgPSBlbGxpcHNvaWQudHJhbnNmb3JtUG9zaXRpb25Ub1NjYWxlZFNwYWNlKAogICAgICAgICAgZGlyZWN0aW9uMiwKICAgICAgICAgIGZpcnN0QXhpc1NjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IGZpcnN0QXhpcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoZjIsIGYyKTsKICAgICAgICBjb25zdCByZWZlcmVuY2UgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubW9zdE9ydGhvZ29uYWxBeGlzKGYyLCByZWZlcmVuY2VTY3JhdGNoKTsKICAgICAgICBjb25zdCBzZWNvbmRBeGlzID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhyZWZlcmVuY2UsIGZpcnN0QXhpcywgc2Vjb25kQXhpc1NjcmF0Y2gpLAogICAgICAgICAgc2Vjb25kQXhpc1NjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IHRoaXJkQXhpcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoZmlyc3RBeGlzLCBzZWNvbmRBeGlzLCB0aGlyZEF4aXNTY3JhdGNoKSwKICAgICAgICAgIHRoaXJkQXhpc1NjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IEIyID0gYlNjcmF0Y2g7CiAgICAgICAgQjJbMF0gPSBmaXJzdEF4aXMueDsKICAgICAgICBCMlsxXSA9IGZpcnN0QXhpcy55OwogICAgICAgIEIyWzJdID0gZmlyc3RBeGlzLno7CiAgICAgICAgQjJbM10gPSBzZWNvbmRBeGlzLng7CiAgICAgICAgQjJbNF0gPSBzZWNvbmRBeGlzLnk7CiAgICAgICAgQjJbNV0gPSBzZWNvbmRBeGlzLno7CiAgICAgICAgQjJbNl0gPSB0aGlyZEF4aXMueDsKICAgICAgICBCMls3XSA9IHRoaXJkQXhpcy55OwogICAgICAgIEIyWzhdID0gdGhpcmRBeGlzLno7CiAgICAgICAgY29uc3QgQl9UID0gTWF0cml4M19kZWZhdWx0LnRyYW5zcG9zZShCMiwgYnRTY3JhdGNoKTsKICAgICAgICBjb25zdCBEX0kgPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVNjYWxlKGVsbGlwc29pZC5yYWRpaSwgZGlTY3JhdGNoKTsKICAgICAgICBjb25zdCBEMiA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tU2NhbGUoZWxsaXBzb2lkLm9uZU92ZXJSYWRpaSwgZFNjcmF0Y2gpOwogICAgICAgIGNvbnN0IEMyID0gY1NjcmF0Y2g7CiAgICAgICAgQzJbMF0gPSAwOwogICAgICAgIEMyWzFdID0gLWRpcmVjdGlvbjIuejsKICAgICAgICBDMlsyXSA9IGRpcmVjdGlvbjIueTsKICAgICAgICBDMlszXSA9IGRpcmVjdGlvbjIuejsKICAgICAgICBDMls0XSA9IDA7CiAgICAgICAgQzJbNV0gPSAtZGlyZWN0aW9uMi54OwogICAgICAgIEMyWzZdID0gLWRpcmVjdGlvbjIueTsKICAgICAgICBDMls3XSA9IGRpcmVjdGlvbjIueDsKICAgICAgICBDMls4XSA9IDA7CiAgICAgICAgY29uc3QgdGVtcCA9IE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseSgKICAgICAgICAgIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseShCX1QsIEQyLCB0ZW1wTWF0cml4KSwKICAgICAgICAgIEMyLAogICAgICAgICAgdGVtcE1hdHJpeAogICAgICAgICk7CiAgICAgICAgY29uc3QgQTIgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHkoCiAgICAgICAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHkodGVtcCwgRF9JLCBhU2NyYXRjaCksCiAgICAgICAgICBCMiwKICAgICAgICAgIGFTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBiMiA9IE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKHRlbXAsIHBvc2l0aW9uLCBiQ2FydCk7CiAgICAgICAgY29uc3Qgc29sdXRpb25zID0gSW50ZXJzZWN0aW9uVGVzdHMucXVhZHJhdGljVmVjdG9yRXhwcmVzc2lvbigKICAgICAgICAgIEEyLAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShiMiwgZmlyc3RBeGlzU2NyYXRjaCksCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDEKICAgICAgICApOwogICAgICAgIGxldCBzMjsKICAgICAgICBsZXQgYWx0aXR1ZGU7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gc29sdXRpb25zLmxlbmd0aDsKICAgICAgICBpZiAobGVuZ3RoID4gMCkgewogICAgICAgICAgbGV0IGNsb3Nlc3QgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIGNsb3Nlc3RTY3JhdGNoKTsKICAgICAgICAgIGxldCBtYXhpbXVtVmFsdWUgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIHMyID0gTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IoCiAgICAgICAgICAgICAgRF9JLAogICAgICAgICAgICAgIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKEIyLCBzb2x1dGlvbnNbaTJdLCBzU2NyYXRjaCksCiAgICAgICAgICAgICAgc1NjcmF0Y2gKICAgICAgICAgICAgKTsKICAgICAgICAgICAgY29uc3QgdjQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChzMiwgcG9zaXRpb24sIHJlZmVyZW5jZVNjcmF0Y2gpLAogICAgICAgICAgICAgIHJlZmVyZW5jZVNjcmF0Y2gKICAgICAgICAgICAgKTsKICAgICAgICAgICAgY29uc3QgZG90UHJvZHVjdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodjQsIGRpcmVjdGlvbjIpOwogICAgICAgICAgICBpZiAoZG90UHJvZHVjdCA+IG1heGltdW1WYWx1ZSkgewogICAgICAgICAgICAgIG1heGltdW1WYWx1ZSA9IGRvdFByb2R1Y3Q7CiAgICAgICAgICAgICAgY2xvc2VzdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShzMiwgY2xvc2VzdCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHN1cmZhY2VQb2ludCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICAgICAgY2xvc2VzdCwKICAgICAgICAgICAgc3VyZlBvaW50U2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIG1heGltdW1WYWx1ZSA9IE1hdGhfZGVmYXVsdC5jbGFtcChtYXhpbXVtVmFsdWUsIDAsIDEpOwogICAgICAgICAgYWx0aXR1ZGUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY2xvc2VzdCwgcG9zaXRpb24sIHJlZmVyZW5jZVNjcmF0Y2gpCiAgICAgICAgICApICogTWF0aC5zcXJ0KDEgLSBtYXhpbXVtVmFsdWUgKiBtYXhpbXVtVmFsdWUpOwogICAgICAgICAgYWx0aXR1ZGUgPSBpbnRlcnNlY3RzMiA/IC1hbHRpdHVkZSA6IGFsdGl0dWRlOwogICAgICAgICAgc3VyZmFjZVBvaW50LmhlaWdodCA9IGFsdGl0dWRlOwogICAgICAgICAgcmV0dXJuIGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihzdXJmYWNlUG9pbnQsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgIH07CiAgICAgIGxpbmVTZWdtZW50UGxhbmVEaWZmZXJlbmNlID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lID0gZnVuY3Rpb24oZW5kUG9pbnQwLCBlbmRQb2ludDEsIHBsYW5lLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChlbmRQb2ludDApKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZW5kUG9pbnQwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChlbmRQb2ludDEpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZW5kUG9pbnQxIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwbGFuZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBkaWZmZXJlbmNlID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgZW5kUG9pbnQxLAogICAgICAgICAgZW5kUG9pbnQwLAogICAgICAgICAgbGluZVNlZ21lbnRQbGFuZURpZmZlcmVuY2UKICAgICAgICApOwogICAgICAgIGNvbnN0IG5vcm1hbDIgPSBwbGFuZS5ub3JtYWw7CiAgICAgICAgY29uc3QgbkRvdERpZmYgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG5vcm1hbDIsIGRpZmZlcmVuY2UpOwogICAgICAgIGlmIChNYXRoLmFicyhuRG90RGlmZikgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjYpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG5Eb3RQMCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgZW5kUG9pbnQwKTsKICAgICAgICBjb25zdCB0MiA9IC0ocGxhbmUuZGlzdGFuY2UgKyBuRG90UDApIC8gbkRvdERpZmY7CiAgICAgICAgaWYgKHQyIDwgMCB8fCB0MiA+IDEpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGRpZmZlcmVuY2UsIHQyLCByZXN1bHQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoZW5kUG9pbnQwLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHMudHJpYW5nbGVQbGFuZUludGVyc2VjdGlvbiA9IGZ1bmN0aW9uKHAwLCBwMSwgcDIsIHBsYW5lKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocDApIHx8ICFkZWZpbmVkX2RlZmF1bHQocDEpIHx8ICFkZWZpbmVkX2RlZmF1bHQocDIpIHx8ICFkZWZpbmVkX2RlZmF1bHQocGxhbmUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicDAsIHAxLCBwMiwgYW5kIHBsYW5lIGFyZSByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcGxhbmVOb3JtYWwgPSBwbGFuZS5ub3JtYWw7CiAgICAgICAgY29uc3QgcGxhbmVEID0gcGxhbmUuZGlzdGFuY2U7CiAgICAgICAgY29uc3QgcDBCZWhpbmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHBsYW5lTm9ybWFsLCBwMCkgKyBwbGFuZUQgPCAwOwogICAgICAgIGNvbnN0IHAxQmVoaW5kID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChwbGFuZU5vcm1hbCwgcDEpICsgcGxhbmVEIDwgMDsKICAgICAgICBjb25zdCBwMkJlaGluZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QocGxhbmVOb3JtYWwsIHAyKSArIHBsYW5lRCA8IDA7CiAgICAgICAgbGV0IG51bUJlaGluZCA9IDA7CiAgICAgICAgbnVtQmVoaW5kICs9IHAwQmVoaW5kID8gMSA6IDA7CiAgICAgICAgbnVtQmVoaW5kICs9IHAxQmVoaW5kID8gMSA6IDA7CiAgICAgICAgbnVtQmVoaW5kICs9IHAyQmVoaW5kID8gMSA6IDA7CiAgICAgICAgbGV0IHUxMiwgdTIyOwogICAgICAgIGlmIChudW1CZWhpbmQgPT09IDEgfHwgbnVtQmVoaW5kID09PSAyKSB7CiAgICAgICAgICB1MTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICB1MjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIGlmIChudW1CZWhpbmQgPT09IDEpIHsKICAgICAgICAgIGlmIChwMEJlaGluZCkgewogICAgICAgICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lKHAwLCBwMSwgcGxhbmUsIHUxMik7CiAgICAgICAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50UGxhbmUocDAsIHAyLCBwbGFuZSwgdTIyKTsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICBwb3NpdGlvbnM6IFtwMCwgcDEsIHAyLCB1MTIsIHUyMl0sCiAgICAgICAgICAgICAgaW5kaWNlczogWwogICAgICAgICAgICAgICAgLy8gQmVoaW5kCiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAvLyBJbiBmcm9udAogICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgIDIsCiAgICAgICAgICAgICAgICA0LAogICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAzCiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9OwogICAgICAgICAgfSBlbHNlIGlmIChwMUJlaGluZCkgewogICAgICAgICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lKHAxLCBwMiwgcGxhbmUsIHUxMik7CiAgICAgICAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50UGxhbmUocDEsIHAwLCBwbGFuZSwgdTIyKTsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICBwb3NpdGlvbnM6IFtwMCwgcDEsIHAyLCB1MTIsIHUyMl0sCiAgICAgICAgICAgICAgaW5kaWNlczogWwogICAgICAgICAgICAgICAgLy8gQmVoaW5kCiAgICAgICAgICAgICAgICAxLAogICAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAvLyBJbiBmcm9udAogICAgICAgICAgICAgICAgMiwKICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICA0LAogICAgICAgICAgICAgICAgMiwKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAzCiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9OwogICAgICAgICAgfSBlbHNlIGlmIChwMkJlaGluZCkgewogICAgICAgICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lKHAyLCBwMCwgcGxhbmUsIHUxMik7CiAgICAgICAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50UGxhbmUocDIsIHAxLCBwbGFuZSwgdTIyKTsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICBwb3NpdGlvbnM6IFtwMCwgcDEsIHAyLCB1MTIsIHUyMl0sCiAgICAgICAgICAgICAgaW5kaWNlczogWwogICAgICAgICAgICAgICAgLy8gQmVoaW5kCiAgICAgICAgICAgICAgICAyLAogICAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAvLyBJbiBmcm9udAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICA0LAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAzCiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSBpZiAobnVtQmVoaW5kID09PSAyKSB7CiAgICAgICAgICBpZiAoIXAwQmVoaW5kKSB7CiAgICAgICAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50UGxhbmUocDEsIHAwLCBwbGFuZSwgdTEyKTsKICAgICAgICAgICAgSW50ZXJzZWN0aW9uVGVzdHMubGluZVNlZ21lbnRQbGFuZShwMiwgcDAsIHBsYW5lLCB1MjIpOwogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgIHBvc2l0aW9uczogW3AwLCBwMSwgcDIsIHUxMiwgdTIyXSwKICAgICAgICAgICAgICBpbmRpY2VzOiBbCiAgICAgICAgICAgICAgICAvLyBCZWhpbmQKICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICAyLAogICAgICAgICAgICAgICAgNCwKICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICA0LAogICAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICAgIC8vIEluIGZyb250CiAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgMywKICAgICAgICAgICAgICAgIDQKICAgICAgICAgICAgICBdCiAgICAgICAgICAgIH07CiAgICAgICAgICB9IGVsc2UgaWYgKCFwMUJlaGluZCkgewogICAgICAgICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lKHAyLCBwMSwgcGxhbmUsIHUxMik7CiAgICAgICAgICAgIEludGVyc2VjdGlvblRlc3RzLmxpbmVTZWdtZW50UGxhbmUocDAsIHAxLCBwbGFuZSwgdTIyKTsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICBwb3NpdGlvbnM6IFtwMCwgcDEsIHAyLCB1MTIsIHUyMl0sCiAgICAgICAgICAgICAgaW5kaWNlczogWwogICAgICAgICAgICAgICAgLy8gQmVoaW5kCiAgICAgICAgICAgICAgICAyLAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAyLAogICAgICAgICAgICAgICAgNCwKICAgICAgICAgICAgICAgIDMsCiAgICAgICAgICAgICAgICAvLyBJbiBmcm9udAogICAgICAgICAgICAgICAgMSwKICAgICAgICAgICAgICAgIDMsCiAgICAgICAgICAgICAgICA0CiAgICAgICAgICAgICAgXQogICAgICAgICAgICB9OwogICAgICAgICAgfSBlbHNlIGlmICghcDJCZWhpbmQpIHsKICAgICAgICAgICAgSW50ZXJzZWN0aW9uVGVzdHMubGluZVNlZ21lbnRQbGFuZShwMCwgcDIsIHBsYW5lLCB1MTIpOwogICAgICAgICAgICBJbnRlcnNlY3Rpb25UZXN0cy5saW5lU2VnbWVudFBsYW5lKHAxLCBwMiwgcGxhbmUsIHUyMik7CiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgcG9zaXRpb25zOiBbcDAsIHAxLCBwMiwgdTEyLCB1MjJdLAogICAgICAgICAgICAgIGluZGljZXM6IFsKICAgICAgICAgICAgICAgIC8vIEJlaGluZAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgICA0LAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDQsCiAgICAgICAgICAgICAgICAzLAogICAgICAgICAgICAgICAgLy8gSW4gZnJvbnQKICAgICAgICAgICAgICAgIDIsCiAgICAgICAgICAgICAgICAzLAogICAgICAgICAgICAgICAgNAogICAgICAgICAgICAgIF0KICAgICAgICAgICAgfTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgfTsKICAgICAgSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdCA9IEludGVyc2VjdGlvblRlc3RzOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUGxhbmUuanMKICBmdW5jdGlvbiBQbGFuZShub3JtYWwyLCBkaXN0YW5jZSkgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJub3JtYWwiLCBub3JtYWwyKTsKICAgIGlmICghTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUobm9ybWFsMiksCiAgICAgIDEsCiAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9ONgogICAgKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibm9ybWFsIG11c3QgYmUgbm9ybWFsaXplZC4iKTsKICAgIH0KICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiZGlzdGFuY2UiLCBkaXN0YW5jZSk7CiAgICB0aGlzLm5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShub3JtYWwyKTsKICAgIHRoaXMuZGlzdGFuY2UgPSBkaXN0YW5jZTsKICB9CiAgdmFyIHNjcmF0Y2hOb3JtYWwsIHNjcmF0Y2hDYXJ0ZXNpYW4sIHNjcmF0Y2hJbnZlcnNlVHJhbnNwb3NlLCBzY3JhdGNoUGxhbmVDYXJ0ZXNpYW40LCBzY3JhdGNoVHJhbnNmb3JtTm9ybWFsLCBQbGFuZV9kZWZhdWx0OwogIHZhciBpbml0X1BsYW5lID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QbGFuZS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRlc2lhbjQoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIFBsYW5lLmZyb21Qb2ludE5vcm1hbCA9IGZ1bmN0aW9uKHBvaW50LCBub3JtYWwyLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInBvaW50IiwgcG9pbnQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibm9ybWFsIiwgbm9ybWFsMik7CiAgICAgICAgaWYgKCFNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUobm9ybWFsMiksCiAgICAgICAgICAxLAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT042CiAgICAgICAgKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm5vcm1hbCBtdXN0IGJlIG5vcm1hbGl6ZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGRpc3RhbmNlID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgcG9pbnQpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJldHVybiBuZXcgUGxhbmUobm9ybWFsMiwgZGlzdGFuY2UpOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUobm9ybWFsMiwgcmVzdWx0Lm5vcm1hbCk7CiAgICAgICAgcmVzdWx0LmRpc3RhbmNlID0gZGlzdGFuY2U7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgc2NyYXRjaE5vcm1hbCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgUGxhbmUuZnJvbUNhcnRlc2lhbjQgPSBmdW5jdGlvbihjb2VmZmljaWVudHMsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY29lZmZpY2llbnRzIiwgY29lZmZpY2llbnRzKTsKICAgICAgICBjb25zdCBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21DYXJ0ZXNpYW40KGNvZWZmaWNpZW50cywgc2NyYXRjaE5vcm1hbCk7CiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBjb2VmZmljaWVudHMudzsKICAgICAgICBpZiAoIU1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShub3JtYWwyKSwKICAgICAgICAgIDEsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjYKICAgICAgICApKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibm9ybWFsIG11c3QgYmUgbm9ybWFsaXplZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBQbGFuZShub3JtYWwyLCBkaXN0YW5jZSk7CiAgICAgICAgfQogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShub3JtYWwyLCByZXN1bHQubm9ybWFsKTsKICAgICAgICByZXN1bHQuZGlzdGFuY2UgPSBkaXN0YW5jZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQbGFuZS5nZXRQb2ludERpc3RhbmNlID0gZnVuY3Rpb24ocGxhbmUsIHBvaW50KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwbGFuZSIsIHBsYW5lKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInBvaW50IiwgcG9pbnQpOwogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHBsYW5lLm5vcm1hbCwgcG9pbnQpICsgcGxhbmUuZGlzdGFuY2U7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFBsYW5lLnByb2plY3RQb2ludE9udG9QbGFuZSA9IGZ1bmN0aW9uKHBsYW5lLCBwb2ludCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwbGFuZSIsIHBsYW5lKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInBvaW50IiwgcG9pbnQpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcG9pbnREaXN0YW5jZSA9IFBsYW5lLmdldFBvaW50RGlzdGFuY2UocGxhbmUsIHBvaW50KTsKICAgICAgICBjb25zdCBzY2FsZWROb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgIHBsYW5lLm5vcm1hbCwKICAgICAgICAgIHBvaW50RGlzdGFuY2UsCiAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuCiAgICAgICAgKTsKICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHBvaW50LCBzY2FsZWROb3JtYWwsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hJbnZlcnNlVHJhbnNwb3NlID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGxhbmVDYXJ0ZXNpYW40ID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVHJhbnNmb3JtTm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBQbGFuZS50cmFuc2Zvcm0gPSBmdW5jdGlvbihwbGFuZSwgdHJhbnNmb3JtMiwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwbGFuZSIsIHBsYW5lKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zZm9ybSIsIHRyYW5zZm9ybTIpOwogICAgICAgIGNvbnN0IG5vcm1hbDIgPSBwbGFuZS5ub3JtYWw7CiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBwbGFuZS5kaXN0YW5jZTsKICAgICAgICBjb25zdCBpbnZlcnNlVHJhbnNwb3NlMiA9IE1hdHJpeDRfZGVmYXVsdC5pbnZlcnNlVHJhbnNwb3NlKAogICAgICAgICAgdHJhbnNmb3JtMiwKICAgICAgICAgIHNjcmF0Y2hJbnZlcnNlVHJhbnNwb3NlCiAgICAgICAgKTsKICAgICAgICBsZXQgcGxhbmVBc0NhcnRlc2lhbjQgPSBDYXJ0ZXNpYW40X2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICAgICAgbm9ybWFsMi54LAogICAgICAgICAgbm9ybWFsMi55LAogICAgICAgICAgbm9ybWFsMi56LAogICAgICAgICAgZGlzdGFuY2UsCiAgICAgICAgICBzY3JhdGNoUGxhbmVDYXJ0ZXNpYW40CiAgICAgICAgKTsKICAgICAgICBwbGFuZUFzQ2FydGVzaWFuNCA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKAogICAgICAgICAgaW52ZXJzZVRyYW5zcG9zZTIsCiAgICAgICAgICBwbGFuZUFzQ2FydGVzaWFuNCwKICAgICAgICAgIHBsYW5lQXNDYXJ0ZXNpYW40CiAgICAgICAgKTsKICAgICAgICBjb25zdCB0cmFuc2Zvcm1lZE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQ2FydGVzaWFuNCgKICAgICAgICAgIHBsYW5lQXNDYXJ0ZXNpYW40LAogICAgICAgICAgc2NyYXRjaFRyYW5zZm9ybU5vcm1hbAogICAgICAgICk7CiAgICAgICAgcGxhbmVBc0NhcnRlc2lhbjQgPSBDYXJ0ZXNpYW40X2RlZmF1bHQuZGl2aWRlQnlTY2FsYXIoCiAgICAgICAgICBwbGFuZUFzQ2FydGVzaWFuNCwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUodHJhbnNmb3JtZWROb3JtYWwpLAogICAgICAgICAgcGxhbmVBc0NhcnRlc2lhbjQKICAgICAgICApOwogICAgICAgIHJldHVybiBQbGFuZS5mcm9tQ2FydGVzaWFuNChwbGFuZUFzQ2FydGVzaWFuNCwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgUGxhbmUuY2xvbmUgPSBmdW5jdGlvbihwbGFuZSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJwbGFuZSIsIHBsYW5lKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IFBsYW5lKHBsYW5lLm5vcm1hbCwgcGxhbmUuZGlzdGFuY2UpOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocGxhbmUubm9ybWFsLCByZXN1bHQubm9ybWFsKTsKICAgICAgICByZXN1bHQuZGlzdGFuY2UgPSBwbGFuZS5kaXN0YW5jZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQbGFuZS5lcXVhbHMgPSBmdW5jdGlvbihsZWZ0LCByaWdodCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmlnaHQiLCByaWdodCk7CiAgICAgICAgcmV0dXJuIGxlZnQuZGlzdGFuY2UgPT09IHJpZ2h0LmRpc3RhbmNlICYmIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMobGVmdC5ub3JtYWwsIHJpZ2h0Lm5vcm1hbCk7CiAgICAgIH07CiAgICAgIFBsYW5lLk9SSUdJTl9YWV9QTEFORSA9IE9iamVjdC5mcmVlemUobmV3IFBsYW5lKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1osIDApKTsKICAgICAgUGxhbmUuT1JJR0lOX1laX1BMQU5FID0gT2JqZWN0LmZyZWV6ZShuZXcgUGxhbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgMCkpOwogICAgICBQbGFuZS5PUklHSU5fWlhfUExBTkUgPSBPYmplY3QuZnJlZXplKG5ldyBQbGFuZShDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZLCAwKSk7CiAgICAgIFBsYW5lX2RlZmF1bHQgPSBQbGFuZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RpcHNpZnkuanMKICB2YXIgVGlwc2lmeSwgVGlwc2lmeV9kZWZhdWx0OwogIHZhciBpbml0X1RpcHNpZnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RpcHNpZnkuanMiKCkgewogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBUaXBzaWZ5ID0ge307CiAgICAgIFRpcHNpZnkuY2FsY3VsYXRlQUNNUiA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgY29uc3QgaW5kaWNlcyA9IG9wdGlvbnMuaW5kaWNlczsKICAgICAgICBsZXQgbWF4aW11bUluZGV4ID0gb3B0aW9ucy5tYXhpbXVtSW5kZXg7CiAgICAgICAgY29uc3QgY2FjaGVTaXplID0gb3B0aW9ucy5jYWNoZVNpemUgPz8gMjQ7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5kaWNlcykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJpbmRpY2VzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBudW1JbmRpY2VzID0gaW5kaWNlcy5sZW5ndGg7CiAgICAgICAgaWYgKG51bUluZGljZXMgPCAzIHx8IG51bUluZGljZXMgJSAzICE9PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiaW5kaWNlcyBsZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIHRocmVlLiIpOwogICAgICAgIH0KICAgICAgICBpZiAobWF4aW11bUluZGV4IDw9IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJtYXhpbXVtSW5kZXggbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKGNhY2hlU2l6ZSA8IDMpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJjYWNoZVNpemUgbXVzdCBiZSBncmVhdGVyIHRoYW4gdHdvLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChtYXhpbXVtSW5kZXgpKSB7CiAgICAgICAgICBtYXhpbXVtSW5kZXggPSAwOwogICAgICAgICAgbGV0IGN1cnJlbnRJbmRleCA9IDA7CiAgICAgICAgICBsZXQgaW50b0luZGljZXMgPSBpbmRpY2VzW2N1cnJlbnRJbmRleF07CiAgICAgICAgICB3aGlsZSAoY3VycmVudEluZGV4IDwgbnVtSW5kaWNlcykgewogICAgICAgICAgICBpZiAoaW50b0luZGljZXMgPiBtYXhpbXVtSW5kZXgpIHsKICAgICAgICAgICAgICBtYXhpbXVtSW5kZXggPSBpbnRvSW5kaWNlczsKICAgICAgICAgICAgfQogICAgICAgICAgICArK2N1cnJlbnRJbmRleDsKICAgICAgICAgICAgaW50b0luZGljZXMgPSBpbmRpY2VzW2N1cnJlbnRJbmRleF07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IHZlcnRleFRpbWVTdGFtcHMgPSBbXTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbWF4aW11bUluZGV4ICsgMTsgaTIrKykgewogICAgICAgICAgdmVydGV4VGltZVN0YW1wc1tpMl0gPSAwOwogICAgICAgIH0KICAgICAgICBsZXQgczIgPSBjYWNoZVNpemUgKyAxOwogICAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCBudW1JbmRpY2VzOyArK2oyKSB7CiAgICAgICAgICBpZiAoczIgLSB2ZXJ0ZXhUaW1lU3RhbXBzW2luZGljZXNbajJdXSA+IGNhY2hlU2l6ZSkgewogICAgICAgICAgICB2ZXJ0ZXhUaW1lU3RhbXBzW2luZGljZXNbajJdXSA9IHMyOwogICAgICAgICAgICArK3MyOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gKHMyIC0gY2FjaGVTaXplICsgMSkgLyAobnVtSW5kaWNlcyAvIDMpOwogICAgICB9OwogICAgICBUaXBzaWZ5LnRpcHNpZnkgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBvcHRpb25zLmluZGljZXM7CiAgICAgICAgY29uc3QgbWF4aW11bUluZGV4ID0gb3B0aW9ucy5tYXhpbXVtSW5kZXg7CiAgICAgICAgY29uc3QgY2FjaGVTaXplID0gb3B0aW9ucy5jYWNoZVNpemUgPz8gMjQ7CiAgICAgICAgbGV0IGN1cnNvcjsKICAgICAgICBmdW5jdGlvbiBza2lwRGVhZEVuZCh2ZXJ0aWNlczIsIGRlYWRFbmQyLCBpbmRpY2VzMiwgbWF4aW11bUluZGV4UGx1c09uZTIpIHsKICAgICAgICAgIHdoaWxlIChkZWFkRW5kMi5sZW5ndGggPj0gMSkgewogICAgICAgICAgICBjb25zdCBkMiA9IGRlYWRFbmQyW2RlYWRFbmQyLmxlbmd0aCAtIDFdOwogICAgICAgICAgICBkZWFkRW5kMi5zcGxpY2UoZGVhZEVuZDIubGVuZ3RoIC0gMSwgMSk7CiAgICAgICAgICAgIGlmICh2ZXJ0aWNlczJbZDJdLm51bUxpdmVUcmlhbmdsZXMgPiAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGQyOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICB3aGlsZSAoY3Vyc29yIDwgbWF4aW11bUluZGV4UGx1c09uZTIpIHsKICAgICAgICAgICAgaWYgKHZlcnRpY2VzMltjdXJzb3JdLm51bUxpdmVUcmlhbmdsZXMgPiAwKSB7CiAgICAgICAgICAgICAgKytjdXJzb3I7CiAgICAgICAgICAgICAgcmV0dXJuIGN1cnNvciAtIDE7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgKytjdXJzb3I7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gLTE7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGdldE5leHRWZXJ0ZXgoaW5kaWNlczIsIGNhY2hlU2l6ZTIsIG9uZVJpbmcyLCB2ZXJ0aWNlczIsIHMzLCBkZWFkRW5kMiwgbWF4aW11bUluZGV4UGx1c09uZTIpIHsKICAgICAgICAgIGxldCBuMiA9IC0xOwogICAgICAgICAgbGV0IHAyOwogICAgICAgICAgbGV0IG0yID0gLTE7CiAgICAgICAgICBsZXQgaXRPbmVSaW5nID0gMDsKICAgICAgICAgIHdoaWxlIChpdE9uZVJpbmcgPCBvbmVSaW5nMi5sZW5ndGgpIHsKICAgICAgICAgICAgY29uc3QgaW5kZXgyID0gb25lUmluZzJbaXRPbmVSaW5nXTsKICAgICAgICAgICAgaWYgKHZlcnRpY2VzMltpbmRleDJdLm51bUxpdmVUcmlhbmdsZXMpIHsKICAgICAgICAgICAgICBwMiA9IDA7CiAgICAgICAgICAgICAgaWYgKHMzIC0gdmVydGljZXMyW2luZGV4Ml0udGltZVN0YW1wICsgMiAqIHZlcnRpY2VzMltpbmRleDJdLm51bUxpdmVUcmlhbmdsZXMgPD0gY2FjaGVTaXplMikgewogICAgICAgICAgICAgICAgcDIgPSBzMyAtIHZlcnRpY2VzMltpbmRleDJdLnRpbWVTdGFtcDsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHAyID4gbTIgfHwgbTIgPT09IC0xKSB7CiAgICAgICAgICAgICAgICBtMiA9IHAyOwogICAgICAgICAgICAgICAgbjIgPSBpbmRleDI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgICsraXRPbmVSaW5nOwogICAgICAgICAgfQogICAgICAgICAgaWYgKG4yID09PSAtMSkgewogICAgICAgICAgICByZXR1cm4gc2tpcERlYWRFbmQodmVydGljZXMyLCBkZWFkRW5kMiwgaW5kaWNlczIsIG1heGltdW1JbmRleFBsdXNPbmUyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBuMjsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5kaWNlcykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJpbmRpY2VzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBudW1JbmRpY2VzID0gaW5kaWNlcy5sZW5ndGg7CiAgICAgICAgaWYgKG51bUluZGljZXMgPCAzIHx8IG51bUluZGljZXMgJSAzICE9PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiaW5kaWNlcyBsZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIHRocmVlLiIpOwogICAgICAgIH0KICAgICAgICBpZiAobWF4aW11bUluZGV4IDw9IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJtYXhpbXVtSW5kZXggbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKGNhY2hlU2l6ZSA8IDMpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJjYWNoZVNpemUgbXVzdCBiZSBncmVhdGVyIHRoYW4gdHdvLiIpOwogICAgICAgIH0KICAgICAgICBsZXQgbWF4aW11bUluZGV4UGx1c09uZSA9IDA7CiAgICAgICAgbGV0IGN1cnJlbnRJbmRleCA9IDA7CiAgICAgICAgbGV0IGludG9JbmRpY2VzID0gaW5kaWNlc1tjdXJyZW50SW5kZXhdOwogICAgICAgIGNvbnN0IGVuZEluZGV4ID0gbnVtSW5kaWNlczsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1heGltdW1JbmRleCkpIHsKICAgICAgICAgIG1heGltdW1JbmRleFBsdXNPbmUgPSBtYXhpbXVtSW5kZXggKyAxOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB3aGlsZSAoY3VycmVudEluZGV4IDwgZW5kSW5kZXgpIHsKICAgICAgICAgICAgaWYgKGludG9JbmRpY2VzID4gbWF4aW11bUluZGV4UGx1c09uZSkgewogICAgICAgICAgICAgIG1heGltdW1JbmRleFBsdXNPbmUgPSBpbnRvSW5kaWNlczsKICAgICAgICAgICAgfQogICAgICAgICAgICArK2N1cnJlbnRJbmRleDsKICAgICAgICAgICAgaW50b0luZGljZXMgPSBpbmRpY2VzW2N1cnJlbnRJbmRleF07CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobWF4aW11bUluZGV4UGx1c09uZSA9PT0gLTEpIHsKICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICB9CiAgICAgICAgICArK21heGltdW1JbmRleFBsdXNPbmU7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHZlcnRpY2VzID0gW107CiAgICAgICAgbGV0IGkyOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG1heGltdW1JbmRleFBsdXNPbmU7IGkyKyspIHsKICAgICAgICAgIHZlcnRpY2VzW2kyXSA9IHsKICAgICAgICAgICAgbnVtTGl2ZVRyaWFuZ2xlczogMCwKICAgICAgICAgICAgdGltZVN0YW1wOiAwLAogICAgICAgICAgICB2ZXJ0ZXhUcmlhbmdsZXM6IFtdCiAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBjdXJyZW50SW5kZXggPSAwOwogICAgICAgIGxldCB0cmlhbmdsZSA9IDA7CiAgICAgICAgd2hpbGUgKGN1cnJlbnRJbmRleCA8IGVuZEluZGV4KSB7CiAgICAgICAgICB2ZXJ0aWNlc1tpbmRpY2VzW2N1cnJlbnRJbmRleF1dLnZlcnRleFRyaWFuZ2xlcy5wdXNoKHRyaWFuZ2xlKTsKICAgICAgICAgICsrdmVydGljZXNbaW5kaWNlc1tjdXJyZW50SW5kZXhdXS5udW1MaXZlVHJpYW5nbGVzOwogICAgICAgICAgdmVydGljZXNbaW5kaWNlc1tjdXJyZW50SW5kZXggKyAxXV0udmVydGV4VHJpYW5nbGVzLnB1c2godHJpYW5nbGUpOwogICAgICAgICAgKyt2ZXJ0aWNlc1tpbmRpY2VzW2N1cnJlbnRJbmRleCArIDFdXS5udW1MaXZlVHJpYW5nbGVzOwogICAgICAgICAgdmVydGljZXNbaW5kaWNlc1tjdXJyZW50SW5kZXggKyAyXV0udmVydGV4VHJpYW5nbGVzLnB1c2godHJpYW5nbGUpOwogICAgICAgICAgKyt2ZXJ0aWNlc1tpbmRpY2VzW2N1cnJlbnRJbmRleCArIDJdXS5udW1MaXZlVHJpYW5nbGVzOwogICAgICAgICAgKyt0cmlhbmdsZTsKICAgICAgICAgIGN1cnJlbnRJbmRleCArPSAzOwogICAgICAgIH0KICAgICAgICBsZXQgZjIgPSAwOwogICAgICAgIGxldCBzMiA9IGNhY2hlU2l6ZSArIDE7CiAgICAgICAgY3Vyc29yID0gMTsKICAgICAgICBsZXQgb25lUmluZzsKICAgICAgICBjb25zdCBkZWFkRW5kID0gW107CiAgICAgICAgbGV0IHZlcnRleDsKICAgICAgICBsZXQgaW50b1ZlcnRpY2VzOwogICAgICAgIGxldCBjdXJyZW50T3V0cHV0SW5kZXggPSAwOwogICAgICAgIGNvbnN0IG91dHB1dEluZGljZXMgPSBbXTsKICAgICAgICBjb25zdCBudW1UcmlhbmdsZXMgPSBudW1JbmRpY2VzIC8gMzsKICAgICAgICBjb25zdCB0cmlhbmdsZUVtaXR0ZWQgPSBbXTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1UcmlhbmdsZXM7IGkyKyspIHsKICAgICAgICAgIHRyaWFuZ2xlRW1pdHRlZFtpMl0gPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgbGV0IGluZGV4OwogICAgICAgIGxldCBsaW1pdDsKICAgICAgICB3aGlsZSAoZjIgIT09IC0xKSB7CiAgICAgICAgICBvbmVSaW5nID0gW107CiAgICAgICAgICBpbnRvVmVydGljZXMgPSB2ZXJ0aWNlc1tmMl07CiAgICAgICAgICBsaW1pdCA9IGludG9WZXJ0aWNlcy52ZXJ0ZXhUcmlhbmdsZXMubGVuZ3RoOwogICAgICAgICAgZm9yIChsZXQgazIgPSAwOyBrMiA8IGxpbWl0OyArK2syKSB7CiAgICAgICAgICAgIHRyaWFuZ2xlID0gaW50b1ZlcnRpY2VzLnZlcnRleFRyaWFuZ2xlc1trMl07CiAgICAgICAgICAgIGlmICghdHJpYW5nbGVFbWl0dGVkW3RyaWFuZ2xlXSkgewogICAgICAgICAgICAgIHRyaWFuZ2xlRW1pdHRlZFt0cmlhbmdsZV0gPSB0cnVlOwogICAgICAgICAgICAgIGN1cnJlbnRJbmRleCA9IHRyaWFuZ2xlICsgdHJpYW5nbGUgKyB0cmlhbmdsZTsKICAgICAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgMzsgKytqMikgewogICAgICAgICAgICAgICAgaW5kZXggPSBpbmRpY2VzW2N1cnJlbnRJbmRleF07CiAgICAgICAgICAgICAgICBvbmVSaW5nLnB1c2goaW5kZXgpOwogICAgICAgICAgICAgICAgZGVhZEVuZC5wdXNoKGluZGV4KTsKICAgICAgICAgICAgICAgIG91dHB1dEluZGljZXNbY3VycmVudE91dHB1dEluZGV4XSA9IGluZGV4OwogICAgICAgICAgICAgICAgKytjdXJyZW50T3V0cHV0SW5kZXg7CiAgICAgICAgICAgICAgICB2ZXJ0ZXggPSB2ZXJ0aWNlc1tpbmRleF07CiAgICAgICAgICAgICAgICAtLXZlcnRleC5udW1MaXZlVHJpYW5nbGVzOwogICAgICAgICAgICAgICAgaWYgKHMyIC0gdmVydGV4LnRpbWVTdGFtcCA+IGNhY2hlU2l6ZSkgewogICAgICAgICAgICAgICAgICB2ZXJ0ZXgudGltZVN0YW1wID0gczI7CiAgICAgICAgICAgICAgICAgICsrczI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICArK2N1cnJlbnRJbmRleDsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGYyID0gZ2V0TmV4dFZlcnRleCgKICAgICAgICAgICAgaW5kaWNlcywKICAgICAgICAgICAgY2FjaGVTaXplLAogICAgICAgICAgICBvbmVSaW5nLAogICAgICAgICAgICB2ZXJ0aWNlcywKICAgICAgICAgICAgczIsCiAgICAgICAgICAgIGRlYWRFbmQsCiAgICAgICAgICAgIG1heGltdW1JbmRleFBsdXNPbmUKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBvdXRwdXRJbmRpY2VzOwogICAgICB9OwogICAgICBUaXBzaWZ5X2RlZmF1bHQgPSBUaXBzaWZ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnlQaXBlbGluZS5qcwogIGZ1bmN0aW9uIGFkZFRyaWFuZ2xlKGxpbmVzLCBpbmRleCwgaTAsIGkxLCBpMikgewogICAgbGluZXNbaW5kZXgrK10gPSBpMDsKICAgIGxpbmVzW2luZGV4KytdID0gaTE7CiAgICBsaW5lc1tpbmRleCsrXSA9IGkxOwogICAgbGluZXNbaW5kZXgrK10gPSBpMjsKICAgIGxpbmVzW2luZGV4KytdID0gaTI7CiAgICBsaW5lc1tpbmRleF0gPSBpMDsKICB9CiAgZnVuY3Rpb24gdHJpYW5nbGVzVG9MaW5lcyh0cmlhbmdsZXMpIHsKICAgIGNvbnN0IGNvdW50ID0gdHJpYW5nbGVzLmxlbmd0aDsKICAgIGNvbnN0IHNpemUgPSBjb3VudCAvIDMgKiA2OwogICAgY29uc3QgbGluZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShjb3VudCwgc2l6ZSk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGNvdW50OyBpMiArPSAzLCBpbmRleCArPSA2KSB7CiAgICAgIGFkZFRyaWFuZ2xlKGxpbmVzLCBpbmRleCwgdHJpYW5nbGVzW2kyXSwgdHJpYW5nbGVzW2kyICsgMV0sIHRyaWFuZ2xlc1tpMiArIDJdKTsKICAgIH0KICAgIHJldHVybiBsaW5lczsKICB9CiAgZnVuY3Rpb24gdHJpYW5nbGVTdHJpcFRvTGluZXModHJpYW5nbGVzKSB7CiAgICBjb25zdCBjb3VudCA9IHRyaWFuZ2xlcy5sZW5ndGg7CiAgICBpZiAoY291bnQgPj0gMykgewogICAgICBjb25zdCBzaXplID0gKGNvdW50IC0gMikgKiA2OwogICAgICBjb25zdCBsaW5lcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KGNvdW50LCBzaXplKTsKICAgICAgYWRkVHJpYW5nbGUobGluZXMsIDAsIHRyaWFuZ2xlc1swXSwgdHJpYW5nbGVzWzFdLCB0cmlhbmdsZXNbMl0pOwogICAgICBsZXQgaW5kZXggPSA2OwogICAgICBmb3IgKGxldCBpMiA9IDM7IGkyIDwgY291bnQ7ICsraTIsIGluZGV4ICs9IDYpIHsKICAgICAgICBhZGRUcmlhbmdsZSgKICAgICAgICAgIGxpbmVzLAogICAgICAgICAgaW5kZXgsCiAgICAgICAgICB0cmlhbmdsZXNbaTIgLSAxXSwKICAgICAgICAgIHRyaWFuZ2xlc1tpMl0sCiAgICAgICAgICB0cmlhbmdsZXNbaTIgLSAyXQogICAgICAgICk7CiAgICAgIH0KICAgICAgcmV0dXJuIGxpbmVzOwogICAgfQogICAgcmV0dXJuIG5ldyBVaW50MTZBcnJheSgpOwogIH0KICBmdW5jdGlvbiB0cmlhbmdsZUZhblRvTGluZXModHJpYW5nbGVzKSB7CiAgICBpZiAodHJpYW5nbGVzLmxlbmd0aCA+IDApIHsKICAgICAgY29uc3QgY291bnQgPSB0cmlhbmdsZXMubGVuZ3RoIC0gMTsKICAgICAgY29uc3Qgc2l6ZSA9IChjb3VudCAtIDEpICogNjsKICAgICAgY29uc3QgbGluZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShjb3VudCwgc2l6ZSk7CiAgICAgIGNvbnN0IGJhc2UgPSB0cmlhbmdsZXNbMF07CiAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgIGZvciAobGV0IGkyID0gMTsgaTIgPCBjb3VudDsgKytpMiwgaW5kZXggKz0gNikgewogICAgICAgIGFkZFRyaWFuZ2xlKGxpbmVzLCBpbmRleCwgYmFzZSwgdHJpYW5nbGVzW2kyXSwgdHJpYW5nbGVzW2kyICsgMV0pOwogICAgICB9CiAgICAgIHJldHVybiBsaW5lczsKICAgIH0KICAgIHJldHVybiBuZXcgVWludDE2QXJyYXkoKTsKICB9CiAgZnVuY3Rpb24gY29weUF0dHJpYnV0ZXNEZXNjcmlwdGlvbnMoYXR0cmlidXRlcykgewogICAgY29uc3QgbmV3QXR0cmlidXRlcyA9IHt9OwogICAgZm9yIChjb25zdCBhdHRyaWJ1dGUgaW4gYXR0cmlidXRlcykgewogICAgICBpZiAoYXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShhdHRyaWJ1dGUpICYmIGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzW2F0dHJpYnV0ZV0pICYmIGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzW2F0dHJpYnV0ZV0udmFsdWVzKSkgewogICAgICAgIGNvbnN0IGF0dHIgPSBhdHRyaWJ1dGVzW2F0dHJpYnV0ZV07CiAgICAgICAgbmV3QXR0cmlidXRlc1thdHRyaWJ1dGVdID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IGF0dHIuY29tcG9uZW50RGF0YXR5cGUsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiBhdHRyLmNvbXBvbmVudHNQZXJBdHRyaWJ1dGUsCiAgICAgICAgICBub3JtYWxpemU6IGF0dHIubm9ybWFsaXplLAogICAgICAgICAgdmFsdWVzOiBbXQogICAgICAgIH0pOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gbmV3QXR0cmlidXRlczsKICB9CiAgZnVuY3Rpb24gY29weVZlcnRleChkZXN0aW5hdGlvbkF0dHJpYnV0ZXMsIHNvdXJjZUF0dHJpYnV0ZXMsIGluZGV4KSB7CiAgICBmb3IgKGNvbnN0IGF0dHJpYnV0ZSBpbiBzb3VyY2VBdHRyaWJ1dGVzKSB7CiAgICAgIGlmIChzb3VyY2VBdHRyaWJ1dGVzLmhhc093blByb3BlcnR5KGF0dHJpYnV0ZSkgJiYgZGVmaW5lZF9kZWZhdWx0KHNvdXJjZUF0dHJpYnV0ZXNbYXR0cmlidXRlXSkgJiYgZGVmaW5lZF9kZWZhdWx0KHNvdXJjZUF0dHJpYnV0ZXNbYXR0cmlidXRlXS52YWx1ZXMpKSB7CiAgICAgICAgY29uc3QgYXR0ciA9IHNvdXJjZUF0dHJpYnV0ZXNbYXR0cmlidXRlXTsKICAgICAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgYXR0ci5jb21wb25lbnRzUGVyQXR0cmlidXRlOyArK2syKSB7CiAgICAgICAgICBkZXN0aW5hdGlvbkF0dHJpYnV0ZXNbYXR0cmlidXRlXS52YWx1ZXMucHVzaCgKICAgICAgICAgICAgYXR0ci52YWx1ZXNbaW5kZXggKiBhdHRyLmNvbXBvbmVudHNQZXJBdHRyaWJ1dGUgKyBrMl0KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQogIGZ1bmN0aW9uIHRyYW5zZm9ybVBvaW50KG1hdHJpeCwgYXR0cmlidXRlKSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZSkpIHsKICAgICAgY29uc3QgdmFsdWVzID0gYXR0cmlidXRlLnZhbHVlczsKICAgICAgY29uc3QgbGVuZ3RoID0gdmFsdWVzLmxlbmd0aDsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2sodmFsdWVzLCBpMiwgc2NyYXRjaENhcnRlc2lhbjMzKTsKICAgICAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KG1hdHJpeCwgc2NyYXRjaENhcnRlc2lhbjMzLCBzY3JhdGNoQ2FydGVzaWFuMzMpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHNjcmF0Y2hDYXJ0ZXNpYW4zMywgdmFsdWVzLCBpMik7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gdHJhbnNmb3JtVmVjdG9yKG1hdHJpeCwgYXR0cmlidXRlKSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZSkpIHsKICAgICAgY29uc3QgdmFsdWVzID0gYXR0cmlidXRlLnZhbHVlczsKICAgICAgY29uc3QgbGVuZ3RoID0gdmFsdWVzLmxlbmd0aDsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2sodmFsdWVzLCBpMiwgc2NyYXRjaENhcnRlc2lhbjMzKTsKICAgICAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcihtYXRyaXgsIHNjcmF0Y2hDYXJ0ZXNpYW4zMywgc2NyYXRjaENhcnRlc2lhbjMzKTsKICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMzMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjMzLAogICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjMzCiAgICAgICAgKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhzY3JhdGNoQ2FydGVzaWFuMzMsIHZhbHVlcywgaTIpOwogICAgICB9CiAgICB9CiAgfQogIGZ1bmN0aW9uIGZpbmRBdHRyaWJ1dGVzSW5BbGxHZW9tZXRyaWVzKGluc3RhbmNlcywgcHJvcGVydHlOYW1lKSB7CiAgICBjb25zdCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgY29uc3QgYXR0cmlidXRlc0luQWxsR2VvbWV0cmllcyA9IHt9OwogICAgY29uc3QgYXR0cmlidXRlczAgPSBpbnN0YW5jZXNbMF1bcHJvcGVydHlOYW1lXS5hdHRyaWJ1dGVzOwogICAgbGV0IG5hbWU7CiAgICBmb3IgKG5hbWUgaW4gYXR0cmlidXRlczApIHsKICAgICAgaWYgKGF0dHJpYnV0ZXMwLmhhc093blByb3BlcnR5KG5hbWUpICYmIGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzMFtuYW1lXSkgJiYgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMwW25hbWVdLnZhbHVlcykpIHsKICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzMFtuYW1lXTsKICAgICAgICBsZXQgbnVtYmVyT2ZDb21wb25lbnRzID0gYXR0cmlidXRlLnZhbHVlcy5sZW5ndGg7CiAgICAgICAgbGV0IGluQWxsR2VvbWV0cmllcyA9IHRydWU7CiAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY29uc3Qgb3RoZXJBdHRyaWJ1dGUgPSBpbnN0YW5jZXNbaTJdW3Byb3BlcnR5TmFtZV0uYXR0cmlidXRlc1tuYW1lXTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG90aGVyQXR0cmlidXRlKSB8fCBhdHRyaWJ1dGUuY29tcG9uZW50RGF0YXR5cGUgIT09IG90aGVyQXR0cmlidXRlLmNvbXBvbmVudERhdGF0eXBlIHx8IGF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlICE9PSBvdGhlckF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlIHx8IGF0dHJpYnV0ZS5ub3JtYWxpemUgIT09IG90aGVyQXR0cmlidXRlLm5vcm1hbGl6ZSkgewogICAgICAgICAgICBpbkFsbEdlb21ldHJpZXMgPSBmYWxzZTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgICBudW1iZXJPZkNvbXBvbmVudHMgKz0gb3RoZXJBdHRyaWJ1dGUudmFsdWVzLmxlbmd0aDsKICAgICAgICB9CiAgICAgICAgaWYgKGluQWxsR2VvbWV0cmllcykgewogICAgICAgICAgYXR0cmlidXRlc0luQWxsR2VvbWV0cmllc1tuYW1lXSA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IGF0dHJpYnV0ZS5jb21wb25lbnREYXRhdHlwZSwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogYXR0cmlidXRlLmNvbXBvbmVudHNQZXJBdHRyaWJ1dGUsCiAgICAgICAgICAgIG5vcm1hbGl6ZTogYXR0cmlidXRlLm5vcm1hbGl6ZSwKICAgICAgICAgICAgdmFsdWVzOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgICAgICAgICAgYXR0cmlidXRlLmNvbXBvbmVudERhdGF0eXBlLAogICAgICAgICAgICAgIG51bWJlck9mQ29tcG9uZW50cwogICAgICAgICAgICApCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBhdHRyaWJ1dGVzSW5BbGxHZW9tZXRyaWVzOwogIH0KICBmdW5jdGlvbiBjb21iaW5lR2VvbWV0cmllcyhpbnN0YW5jZXMsIHByb3BlcnR5TmFtZSkgewogICAgY29uc3QgbGVuZ3RoID0gaW5zdGFuY2VzLmxlbmd0aDsKICAgIGxldCBuYW1lOwogICAgbGV0IGkyOwogICAgbGV0IGoyOwogICAgbGV0IGsyOwogICAgY29uc3QgbTIgPSBpbnN0YW5jZXNbMF0ubW9kZWxNYXRyaXg7CiAgICBjb25zdCBoYXZlSW5kaWNlcyA9IGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZXNbMF1bcHJvcGVydHlOYW1lXS5pbmRpY2VzKTsKICAgIGNvbnN0IHByaW1pdGl2ZVR5cGUgPSBpbnN0YW5jZXNbMF1bcHJvcGVydHlOYW1lXS5wcmltaXRpdmVUeXBlOwogICAgZm9yIChpMiA9IDE7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIGlmICghTWF0cml4NF9kZWZhdWx0LmVxdWFscyhpbnN0YW5jZXNbaTJdLm1vZGVsTWF0cml4LCBtMikpIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiQWxsIGluc3RhbmNlcyBtdXN0IGhhdmUgdGhlIHNhbWUgbW9kZWxNYXRyaXguIik7CiAgICAgIH0KICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZXNbaTJdW3Byb3BlcnR5TmFtZV0uaW5kaWNlcykgIT09IGhhdmVJbmRpY2VzKSB7CiAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAiQWxsIGluc3RhbmNlIGdlb21ldHJpZXMgbXVzdCBoYXZlIGFuIGluZGljZXMgb3Igbm90IGhhdmUgb25lLiIKICAgICAgICApOwogICAgICB9CiAgICAgIGlmIChpbnN0YW5jZXNbaTJdW3Byb3BlcnR5TmFtZV0ucHJpbWl0aXZlVHlwZSAhPT0gcHJpbWl0aXZlVHlwZSkgewogICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgIkFsbCBpbnN0YW5jZSBnZW9tZXRyaWVzIG11c3QgaGF2ZSB0aGUgc2FtZSBwcmltaXRpdmVUeXBlLiIKICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZmluZEF0dHJpYnV0ZXNJbkFsbEdlb21ldHJpZXMoaW5zdGFuY2VzLCBwcm9wZXJ0eU5hbWUpOwogICAgbGV0IHZhbHVlczsKICAgIGxldCBzb3VyY2VWYWx1ZXM7CiAgICBsZXQgc291cmNlVmFsdWVzTGVuZ3RoOwogICAgZm9yIChuYW1lIGluIGF0dHJpYnV0ZXMpIHsKICAgICAgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkobmFtZSkpIHsKICAgICAgICB2YWx1ZXMgPSBhdHRyaWJ1dGVzW25hbWVdLnZhbHVlczsKICAgICAgICBrMiA9IDA7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICBzb3VyY2VWYWx1ZXMgPSBpbnN0YW5jZXNbaTJdW3Byb3BlcnR5TmFtZV0uYXR0cmlidXRlc1tuYW1lXS52YWx1ZXM7CiAgICAgICAgICBzb3VyY2VWYWx1ZXNMZW5ndGggPSBzb3VyY2VWYWx1ZXMubGVuZ3RoOwogICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc291cmNlVmFsdWVzTGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICAgIHZhbHVlc1trMisrXSA9IHNvdXJjZVZhbHVlc1tqMl07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBsZXQgaW5kaWNlczsKICAgIGlmIChoYXZlSW5kaWNlcykgewogICAgICBsZXQgbnVtYmVyT2ZJbmRpY2VzID0gMDsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgbnVtYmVyT2ZJbmRpY2VzICs9IGluc3RhbmNlc1tpMl1bcHJvcGVydHlOYW1lXS5pbmRpY2VzLmxlbmd0aDsKICAgICAgfQogICAgICBjb25zdCBudW1iZXJPZlZlcnRpY2VzID0gR2VvbWV0cnlfZGVmYXVsdC5jb21wdXRlTnVtYmVyT2ZWZXJ0aWNlcygKICAgICAgICBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlBPSU5UUwogICAgICAgIH0pCiAgICAgICk7CiAgICAgIGNvbnN0IGRlc3RJbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgICAgbnVtYmVyT2ZWZXJ0aWNlcywKICAgICAgICBudW1iZXJPZkluZGljZXMKICAgICAgKTsKICAgICAgbGV0IGRlc3RPZmZzZXQgPSAwOwogICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgY29uc3Qgc291cmNlSW5kaWNlcyA9IGluc3RhbmNlc1tpMl1bcHJvcGVydHlOYW1lXS5pbmRpY2VzOwogICAgICAgIGNvbnN0IHNvdXJjZUluZGljZXNMZW4gPSBzb3VyY2VJbmRpY2VzLmxlbmd0aDsKICAgICAgICBmb3IgKGsyID0gMDsgazIgPCBzb3VyY2VJbmRpY2VzTGVuOyArK2syKSB7CiAgICAgICAgICBkZXN0SW5kaWNlc1tkZXN0T2Zmc2V0KytdID0gb2Zmc2V0ICsgc291cmNlSW5kaWNlc1trMl07CiAgICAgICAgfQogICAgICAgIG9mZnNldCArPSBHZW9tZXRyeV9kZWZhdWx0LmNvbXB1dGVOdW1iZXJPZlZlcnRpY2VzKGluc3RhbmNlc1tpMl1bcHJvcGVydHlOYW1lXSk7CiAgICAgIH0KICAgICAgaW5kaWNlcyA9IGRlc3RJbmRpY2VzOwogICAgfQogICAgbGV0IGNlbnRlciA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgIGxldCByYWRpdXMgPSAwOwogICAgbGV0IGJzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIGJzID0gaW5zdGFuY2VzW2kyXVtwcm9wZXJ0eU5hbWVdLmJvdW5kaW5nU3BoZXJlOwogICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChicykpIHsKICAgICAgICBjZW50ZXIgPSB2b2lkIDA7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChicy5jZW50ZXIsIGNlbnRlciwgY2VudGVyKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoY2VudGVyKSkgewogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZGl2aWRlQnlTY2FsYXIoY2VudGVyLCBsZW5ndGgsIGNlbnRlcik7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgIGJzID0gaW5zdGFuY2VzW2kyXVtwcm9wZXJ0eU5hbWVdLmJvdW5kaW5nU3BoZXJlOwogICAgICAgIGNvbnN0IHRlbXBSYWRpdXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGJzLmNlbnRlciwgY2VudGVyLCB0ZW1wU2NyYXRjaCkKICAgICAgICApICsgYnMucmFkaXVzOwogICAgICAgIGlmICh0ZW1wUmFkaXVzID4gcmFkaXVzKSB7CiAgICAgICAgICByYWRpdXMgPSB0ZW1wUmFkaXVzOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlcywKICAgICAgcHJpbWl0aXZlVHlwZSwKICAgICAgYm91bmRpbmdTcGhlcmU6IGRlZmluZWRfZGVmYXVsdChjZW50ZXIpID8gbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoY2VudGVyLCByYWRpdXMpIDogdm9pZCAwCiAgICB9KTsKICB9CiAgZnVuY3Rpb24gaW5kZXhUcmlhbmdsZXMoZ2VvbWV0cnkpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkuaW5kaWNlcykpIHsKICAgICAgcmV0dXJuIGdlb21ldHJ5OwogICAgfQogICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNlcyA9IEdlb21ldHJ5X2RlZmF1bHQuY29tcHV0ZU51bWJlck9mVmVydGljZXMoZ2VvbWV0cnkpOwogICAgaWYgKG51bWJlck9mVmVydGljZXMgPCAzKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJUaGUgbnVtYmVyIG9mIHZlcnRpY2VzIG11c3QgYmUgYXQgbGVhc3QgdGhyZWUuIik7CiAgICB9CiAgICBpZiAobnVtYmVyT2ZWZXJ0aWNlcyAlIDMgIT09IDApIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIlRoZSBudW1iZXIgb2YgdmVydGljZXMgbXVzdCBiZSBhIG11bHRpcGxlIG9mIHRocmVlLiIKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgbnVtYmVyT2ZWZXJ0aWNlcywKICAgICAgbnVtYmVyT2ZWZXJ0aWNlcwogICAgKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBudW1iZXJPZlZlcnRpY2VzOyArK2kyKSB7CiAgICAgIGluZGljZXNbaTJdID0gaTI7CiAgICB9CiAgICBnZW9tZXRyeS5pbmRpY2VzID0gaW5kaWNlczsKICAgIHJldHVybiBnZW9tZXRyeTsKICB9CiAgZnVuY3Rpb24gaW5kZXhUcmlhbmdsZUZhbihnZW9tZXRyeSkgewogICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNlcyA9IEdlb21ldHJ5X2RlZmF1bHQuY29tcHV0ZU51bWJlck9mVmVydGljZXMoZ2VvbWV0cnkpOwogICAgaWYgKG51bWJlck9mVmVydGljZXMgPCAzKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJUaGUgbnVtYmVyIG9mIHZlcnRpY2VzIG11c3QgYmUgYXQgbGVhc3QgdGhyZWUuIik7CiAgICB9CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIG51bWJlck9mVmVydGljZXMsCiAgICAgIChudW1iZXJPZlZlcnRpY2VzIC0gMikgKiAzCiAgICApOwogICAgaW5kaWNlc1swXSA9IDE7CiAgICBpbmRpY2VzWzFdID0gMDsKICAgIGluZGljZXNbMl0gPSAyOwogICAgbGV0IGluZGljZXNJbmRleCA9IDM7CiAgICBmb3IgKGxldCBpMiA9IDM7IGkyIDwgbnVtYmVyT2ZWZXJ0aWNlczsgKytpMikgewogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGkyIC0gMTsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSAwOwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGkyOwogICAgfQogICAgZ2VvbWV0cnkuaW5kaWNlcyA9IGluZGljZXM7CiAgICBnZW9tZXRyeS5wcmltaXRpdmVUeXBlID0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUzsKICAgIHJldHVybiBnZW9tZXRyeTsKICB9CiAgZnVuY3Rpb24gaW5kZXhUcmlhbmdsZVN0cmlwKGdlb21ldHJ5KSB7CiAgICBjb25zdCBudW1iZXJPZlZlcnRpY2VzID0gR2VvbWV0cnlfZGVmYXVsdC5jb21wdXRlTnVtYmVyT2ZWZXJ0aWNlcyhnZW9tZXRyeSk7CiAgICBpZiAobnVtYmVyT2ZWZXJ0aWNlcyA8IDMpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIlRoZSBudW1iZXIgb2YgdmVydGljZXMgbXVzdCBiZSBhdCBsZWFzdCAzLiIpOwogICAgfQogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBudW1iZXJPZlZlcnRpY2VzLAogICAgICAobnVtYmVyT2ZWZXJ0aWNlcyAtIDIpICogMwogICAgKTsKICAgIGluZGljZXNbMF0gPSAwOwogICAgaW5kaWNlc1sxXSA9IDE7CiAgICBpbmRpY2VzWzJdID0gMjsKICAgIGlmIChudW1iZXJPZlZlcnRpY2VzID4gMykgewogICAgICBpbmRpY2VzWzNdID0gMDsKICAgICAgaW5kaWNlc1s0XSA9IDI7CiAgICAgIGluZGljZXNbNV0gPSAzOwogICAgfQogICAgbGV0IGluZGljZXNJbmRleCA9IDY7CiAgICBmb3IgKGxldCBpMiA9IDM7IGkyIDwgbnVtYmVyT2ZWZXJ0aWNlcyAtIDE7IGkyICs9IDIpIHsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpMjsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpMiAtIDE7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTIgKyAxOwogICAgICBpZiAoaTIgKyAyIDwgbnVtYmVyT2ZWZXJ0aWNlcykgewogICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTI7CiAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpMiArIDE7CiAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpMiArIDI7CiAgICAgIH0KICAgIH0KICAgIGdlb21ldHJ5LmluZGljZXMgPSBpbmRpY2VzOwogICAgZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSA9IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVM7CiAgICByZXR1cm4gZ2VvbWV0cnk7CiAgfQogIGZ1bmN0aW9uIGluZGV4TGluZXMoZ2VvbWV0cnkpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkuaW5kaWNlcykpIHsKICAgICAgcmV0dXJuIGdlb21ldHJ5OwogICAgfQogICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNlcyA9IEdlb21ldHJ5X2RlZmF1bHQuY29tcHV0ZU51bWJlck9mVmVydGljZXMoZ2VvbWV0cnkpOwogICAgaWYgKG51bWJlck9mVmVydGljZXMgPCAyKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJUaGUgbnVtYmVyIG9mIHZlcnRpY2VzIG11c3QgYmUgYXQgbGVhc3QgdHdvLiIpOwogICAgfQogICAgaWYgKG51bWJlck9mVmVydGljZXMgJSAyICE9PSAwKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJUaGUgbnVtYmVyIG9mIHZlcnRpY2VzIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAyLiIpOwogICAgfQogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBudW1iZXJPZlZlcnRpY2VzLAogICAgICBudW1iZXJPZlZlcnRpY2VzCiAgICApOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG51bWJlck9mVmVydGljZXM7ICsraTIpIHsKICAgICAgaW5kaWNlc1tpMl0gPSBpMjsKICAgIH0KICAgIGdlb21ldHJ5LmluZGljZXMgPSBpbmRpY2VzOwogICAgcmV0dXJuIGdlb21ldHJ5OwogIH0KICBmdW5jdGlvbiBpbmRleExpbmVTdHJpcChnZW9tZXRyeSkgewogICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNlcyA9IEdlb21ldHJ5X2RlZmF1bHQuY29tcHV0ZU51bWJlck9mVmVydGljZXMoZ2VvbWV0cnkpOwogICAgaWYgKG51bWJlck9mVmVydGljZXMgPCAyKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJUaGUgbnVtYmVyIG9mIHZlcnRpY2VzIG11c3QgYmUgYXQgbGVhc3QgdHdvLiIpOwogICAgfQogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBudW1iZXJPZlZlcnRpY2VzLAogICAgICAobnVtYmVyT2ZWZXJ0aWNlcyAtIDEpICogMgogICAgKTsKICAgIGluZGljZXNbMF0gPSAwOwogICAgaW5kaWNlc1sxXSA9IDE7CiAgICBsZXQgaW5kaWNlc0luZGV4ID0gMjsKICAgIGZvciAobGV0IGkyID0gMjsgaTIgPCBudW1iZXJPZlZlcnRpY2VzOyArK2kyKSB7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTIgLSAxOwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGkyOwogICAgfQogICAgZ2VvbWV0cnkuaW5kaWNlcyA9IGluZGljZXM7CiAgICBnZW9tZXRyeS5wcmltaXRpdmVUeXBlID0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTOwogICAgcmV0dXJuIGdlb21ldHJ5OwogIH0KICBmdW5jdGlvbiBpbmRleExpbmVMb29wKGdlb21ldHJ5KSB7CiAgICBjb25zdCBudW1iZXJPZlZlcnRpY2VzID0gR2VvbWV0cnlfZGVmYXVsdC5jb21wdXRlTnVtYmVyT2ZWZXJ0aWNlcyhnZW9tZXRyeSk7CiAgICBpZiAobnVtYmVyT2ZWZXJ0aWNlcyA8IDIpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIlRoZSBudW1iZXIgb2YgdmVydGljZXMgbXVzdCBiZSBhdCBsZWFzdCB0d28uIik7CiAgICB9CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIG51bWJlck9mVmVydGljZXMsCiAgICAgIG51bWJlck9mVmVydGljZXMgKiAyCiAgICApOwogICAgaW5kaWNlc1swXSA9IDA7CiAgICBpbmRpY2VzWzFdID0gMTsKICAgIGxldCBpbmRpY2VzSW5kZXggPSAyOwogICAgZm9yIChsZXQgaTIgPSAyOyBpMiA8IG51bWJlck9mVmVydGljZXM7ICsraTIpIHsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpMiAtIDE7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTI7CiAgICB9CiAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IG51bWJlck9mVmVydGljZXMgLSAxOwogICAgaW5kaWNlc1tpbmRpY2VzSW5kZXhdID0gMDsKICAgIGdlb21ldHJ5LmluZGljZXMgPSBpbmRpY2VzOwogICAgZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSA9IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5MSU5FUzsKICAgIHJldHVybiBnZW9tZXRyeTsKICB9CiAgZnVuY3Rpb24gaW5kZXhQcmltaXRpdmUoZ2VvbWV0cnkpIHsKICAgIHN3aXRjaCAoZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSkgewogICAgICBjYXNlIFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRV9GQU46CiAgICAgICAgcmV0dXJuIGluZGV4VHJpYW5nbGVGYW4oZ2VvbWV0cnkpOwogICAgICBjYXNlIFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRV9TVFJJUDoKICAgICAgICByZXR1cm4gaW5kZXhUcmlhbmdsZVN0cmlwKGdlb21ldHJ5KTsKICAgICAgY2FzZSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTOgogICAgICAgIHJldHVybiBpbmRleFRyaWFuZ2xlcyhnZW9tZXRyeSk7CiAgICAgIGNhc2UgUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVfU1RSSVA6CiAgICAgICAgcmV0dXJuIGluZGV4TGluZVN0cmlwKGdlb21ldHJ5KTsKICAgICAgY2FzZSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORV9MT09QOgogICAgICAgIHJldHVybiBpbmRleExpbmVMb29wKGdlb21ldHJ5KTsKICAgICAgY2FzZSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVM6CiAgICAgICAgcmV0dXJuIGluZGV4TGluZXMoZ2VvbWV0cnkpOwogICAgfQogICAgcmV0dXJuIGdlb21ldHJ5OwogIH0KICBmdW5jdGlvbiBvZmZzZXRQb2ludEZyb21YWlBsYW5lKHAyLCBpc0JlaGluZCkgewogICAgaWYgKE1hdGguYWJzKHAyLnkpIDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgIGlmIChpc0JlaGluZCkgewogICAgICAgIHAyLnkgPSAtTWF0aF9kZWZhdWx0LkVQU0lMT042OwogICAgICB9IGVsc2UgewogICAgICAgIHAyLnkgPSBNYXRoX2RlZmF1bHQuRVBTSUxPTjY7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gb2Zmc2V0VHJpYW5nbGVGcm9tWFpQbGFuZShwMCwgcDEsIHAyKSB7CiAgICBpZiAocDAueSAhPT0gMCAmJiBwMS55ICE9PSAwICYmIHAyLnkgIT09IDApIHsKICAgICAgb2Zmc2V0UG9pbnRGcm9tWFpQbGFuZShwMCwgcDAueSA8IDApOwogICAgICBvZmZzZXRQb2ludEZyb21YWlBsYW5lKHAxLCBwMS55IDwgMCk7CiAgICAgIG9mZnNldFBvaW50RnJvbVhaUGxhbmUocDIsIHAyLnkgPCAwKTsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3QgcDB5ID0gTWF0aC5hYnMocDAueSk7CiAgICBjb25zdCBwMXkgPSBNYXRoLmFicyhwMS55KTsKICAgIGNvbnN0IHAyeSA9IE1hdGguYWJzKHAyLnkpOwogICAgbGV0IHNpZ24zOwogICAgaWYgKHAweSA+IHAxeSkgewogICAgICBpZiAocDB5ID4gcDJ5KSB7CiAgICAgICAgc2lnbjMgPSBNYXRoX2RlZmF1bHQuc2lnbihwMC55KTsKICAgICAgfSBlbHNlIHsKICAgICAgICBzaWduMyA9IE1hdGhfZGVmYXVsdC5zaWduKHAyLnkpOwogICAgICB9CiAgICB9IGVsc2UgaWYgKHAxeSA+IHAyeSkgewogICAgICBzaWduMyA9IE1hdGhfZGVmYXVsdC5zaWduKHAxLnkpOwogICAgfSBlbHNlIHsKICAgICAgc2lnbjMgPSBNYXRoX2RlZmF1bHQuc2lnbihwMi55KTsKICAgIH0KICAgIGNvbnN0IGlzQmVoaW5kID0gc2lnbjMgPCAwOwogICAgb2Zmc2V0UG9pbnRGcm9tWFpQbGFuZShwMCwgaXNCZWhpbmQpOwogICAgb2Zmc2V0UG9pbnRGcm9tWFpQbGFuZShwMSwgaXNCZWhpbmQpOwogICAgb2Zmc2V0UG9pbnRGcm9tWFpQbGFuZShwMiwgaXNCZWhpbmQpOwogIH0KICBmdW5jdGlvbiBnZXRYWkludGVyc2VjdGlvbk9mZnNldFBvaW50cyhwMiwgcDEsIHUxMiwgdjEyKSB7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICBwMiwKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMiwgYzMpLAogICAgICAgIHAyLnkgLyAocDIueSAtIHAxLnkpLAogICAgICAgIGMzCiAgICAgICksCiAgICAgIHUxMgogICAgKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSh1MTIsIHYxMik7CiAgICBvZmZzZXRQb2ludEZyb21YWlBsYW5lKHUxMiwgdHJ1ZSk7CiAgICBvZmZzZXRQb2ludEZyb21YWlBsYW5lKHYxMiwgZmFsc2UpOwogIH0KICBmdW5jdGlvbiBzcGxpdFRyaWFuZ2xlKHAwLCBwMSwgcDIpIHsKICAgIGlmIChwMC54ID49IDAgfHwgcDEueCA+PSAwIHx8IHAyLnggPj0gMCkgewogICAgICByZXR1cm4gdm9pZCAwOwogICAgfQogICAgb2Zmc2V0VHJpYW5nbGVGcm9tWFpQbGFuZShwMCwgcDEsIHAyKTsKICAgIGNvbnN0IHAwQmVoaW5kID0gcDAueSA8IDA7CiAgICBjb25zdCBwMUJlaGluZCA9IHAxLnkgPCAwOwogICAgY29uc3QgcDJCZWhpbmQgPSBwMi55IDwgMDsKICAgIGxldCBudW1CZWhpbmQgPSAwOwogICAgbnVtQmVoaW5kICs9IHAwQmVoaW5kID8gMSA6IDA7CiAgICBudW1CZWhpbmQgKz0gcDFCZWhpbmQgPyAxIDogMDsKICAgIG51bUJlaGluZCArPSBwMkJlaGluZCA/IDEgOiAwOwogICAgY29uc3QgaW5kaWNlcyA9IHNwbGl0VHJpYW5nbGVSZXN1bHQuaW5kaWNlczsKICAgIGlmIChudW1CZWhpbmQgPT09IDEpIHsKICAgICAgaW5kaWNlc1sxXSA9IDM7CiAgICAgIGluZGljZXNbMl0gPSA0OwogICAgICBpbmRpY2VzWzVdID0gNjsKICAgICAgaW5kaWNlc1s3XSA9IDY7CiAgICAgIGluZGljZXNbOF0gPSA1OwogICAgICBpZiAocDBCZWhpbmQpIHsKICAgICAgICBnZXRYWkludGVyc2VjdGlvbk9mZnNldFBvaW50cyhwMCwgcDEsIHUxLCBxMSk7CiAgICAgICAgZ2V0WFpJbnRlcnNlY3Rpb25PZmZzZXRQb2ludHMocDAsIHAyLCB1MiwgcTIpOwogICAgICAgIGluZGljZXNbMF0gPSAwOwogICAgICAgIGluZGljZXNbM10gPSAxOwogICAgICAgIGluZGljZXNbNF0gPSAyOwogICAgICAgIGluZGljZXNbNl0gPSAxOwogICAgICB9IGVsc2UgaWYgKHAxQmVoaW5kKSB7CiAgICAgICAgZ2V0WFpJbnRlcnNlY3Rpb25PZmZzZXRQb2ludHMocDEsIHAyLCB1MSwgcTEpOwogICAgICAgIGdldFhaSW50ZXJzZWN0aW9uT2Zmc2V0UG9pbnRzKHAxLCBwMCwgdTIsIHEyKTsKICAgICAgICBpbmRpY2VzWzBdID0gMTsKICAgICAgICBpbmRpY2VzWzNdID0gMjsKICAgICAgICBpbmRpY2VzWzRdID0gMDsKICAgICAgICBpbmRpY2VzWzZdID0gMjsKICAgICAgfSBlbHNlIGlmIChwMkJlaGluZCkgewogICAgICAgIGdldFhaSW50ZXJzZWN0aW9uT2Zmc2V0UG9pbnRzKHAyLCBwMCwgdTEsIHExKTsKICAgICAgICBnZXRYWkludGVyc2VjdGlvbk9mZnNldFBvaW50cyhwMiwgcDEsIHUyLCBxMik7CiAgICAgICAgaW5kaWNlc1swXSA9IDI7CiAgICAgICAgaW5kaWNlc1szXSA9IDA7CiAgICAgICAgaW5kaWNlc1s0XSA9IDE7CiAgICAgICAgaW5kaWNlc1s2XSA9IDA7CiAgICAgIH0KICAgIH0gZWxzZSBpZiAobnVtQmVoaW5kID09PSAyKSB7CiAgICAgIGluZGljZXNbMl0gPSA0OwogICAgICBpbmRpY2VzWzRdID0gNDsKICAgICAgaW5kaWNlc1s1XSA9IDM7CiAgICAgIGluZGljZXNbN10gPSA1OwogICAgICBpbmRpY2VzWzhdID0gNjsKICAgICAgaWYgKCFwMEJlaGluZCkgewogICAgICAgIGdldFhaSW50ZXJzZWN0aW9uT2Zmc2V0UG9pbnRzKHAwLCBwMSwgdTEsIHExKTsKICAgICAgICBnZXRYWkludGVyc2VjdGlvbk9mZnNldFBvaW50cyhwMCwgcDIsIHUyLCBxMik7CiAgICAgICAgaW5kaWNlc1swXSA9IDE7CiAgICAgICAgaW5kaWNlc1sxXSA9IDI7CiAgICAgICAgaW5kaWNlc1szXSA9IDE7CiAgICAgICAgaW5kaWNlc1s2XSA9IDA7CiAgICAgIH0gZWxzZSBpZiAoIXAxQmVoaW5kKSB7CiAgICAgICAgZ2V0WFpJbnRlcnNlY3Rpb25PZmZzZXRQb2ludHMocDEsIHAyLCB1MSwgcTEpOwogICAgICAgIGdldFhaSW50ZXJzZWN0aW9uT2Zmc2V0UG9pbnRzKHAxLCBwMCwgdTIsIHEyKTsKICAgICAgICBpbmRpY2VzWzBdID0gMjsKICAgICAgICBpbmRpY2VzWzFdID0gMDsKICAgICAgICBpbmRpY2VzWzNdID0gMjsKICAgICAgICBpbmRpY2VzWzZdID0gMTsKICAgICAgfSBlbHNlIGlmICghcDJCZWhpbmQpIHsKICAgICAgICBnZXRYWkludGVyc2VjdGlvbk9mZnNldFBvaW50cyhwMiwgcDAsIHUxLCBxMSk7CiAgICAgICAgZ2V0WFpJbnRlcnNlY3Rpb25PZmZzZXRQb2ludHMocDIsIHAxLCB1MiwgcTIpOwogICAgICAgIGluZGljZXNbMF0gPSAwOwogICAgICAgIGluZGljZXNbMV0gPSAxOwogICAgICAgIGluZGljZXNbM10gPSAwOwogICAgICAgIGluZGljZXNbNl0gPSAyOwogICAgICB9CiAgICB9CiAgICBjb25zdCBwb3NpdGlvbnMgPSBzcGxpdFRyaWFuZ2xlUmVzdWx0LnBvc2l0aW9uczsKICAgIHBvc2l0aW9uc1swXSA9IHAwOwogICAgcG9zaXRpb25zWzFdID0gcDE7CiAgICBwb3NpdGlvbnNbMl0gPSBwMjsKICAgIHBvc2l0aW9ucy5sZW5ndGggPSAzOwogICAgaWYgKG51bUJlaGluZCA9PT0gMSB8fCBudW1CZWhpbmQgPT09IDIpIHsKICAgICAgcG9zaXRpb25zWzNdID0gdTE7CiAgICAgIHBvc2l0aW9uc1s0XSA9IHUyOwogICAgICBwb3NpdGlvbnNbNV0gPSBxMTsKICAgICAgcG9zaXRpb25zWzZdID0gcTI7CiAgICAgIHBvc2l0aW9ucy5sZW5ndGggPSA3OwogICAgfQogICAgcmV0dXJuIHNwbGl0VHJpYW5nbGVSZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIHVwZGF0ZUdlb21ldHJ5QWZ0ZXJTcGxpdChnZW9tZXRyeSwgY29tcHV0ZUJvdW5kaW5nU3BoZXJlKSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGlmIChhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGggPT09IDApIHsKICAgICAgcmV0dXJuIHZvaWQgMDsKICAgIH0KICAgIGZvciAoY29uc3QgcHJvcGVydHkgaW4gYXR0cmlidXRlcykgewogICAgICBpZiAoYXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSkgJiYgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXNbcHJvcGVydHldKSAmJiBkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlc1twcm9wZXJ0eV0udmFsdWVzKSkgewogICAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbcHJvcGVydHldOwogICAgICAgIGF0dHJpYnV0ZS52YWx1ZXMgPSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgICAgICBhdHRyaWJ1dGUuY29tcG9uZW50RGF0YXR5cGUsCiAgICAgICAgICBhdHRyaWJ1dGUudmFsdWVzCiAgICAgICAgKTsKICAgICAgfQogICAgfQogICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNlcyA9IEdlb21ldHJ5X2RlZmF1bHQuY29tcHV0ZU51bWJlck9mVmVydGljZXMoZ2VvbWV0cnkpOwogICAgZ2VvbWV0cnkuaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBudW1iZXJPZlZlcnRpY2VzLAogICAgICBnZW9tZXRyeS5pbmRpY2VzCiAgICApOwogICAgaWYgKGNvbXB1dGVCb3VuZGluZ1NwaGVyZSkgewogICAgICBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzCiAgICAgICk7CiAgICB9CiAgICByZXR1cm4gZ2VvbWV0cnk7CiAgfQogIGZ1bmN0aW9uIGNvcHlHZW9tZXRyeUZvclNwbGl0KGdlb21ldHJ5KSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGNvbnN0IGNvcGllZEF0dHJpYnV0ZXMgPSB7fTsKICAgIGZvciAoY29uc3QgcHJvcGVydHkgaW4gYXR0cmlidXRlcykgewogICAgICBpZiAoYXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSkgJiYgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXNbcHJvcGVydHldKSAmJiBkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlc1twcm9wZXJ0eV0udmFsdWVzKSkgewogICAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbcHJvcGVydHldOwogICAgICAgIGNvcGllZEF0dHJpYnV0ZXNbcHJvcGVydHldID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IGF0dHJpYnV0ZS5jb21wb25lbnREYXRhdHlwZSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IGF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlLAogICAgICAgICAgbm9ybWFsaXplOiBhdHRyaWJ1dGUubm9ybWFsaXplLAogICAgICAgICAgdmFsdWVzOiBbXQogICAgICAgIH0pOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICBhdHRyaWJ1dGVzOiBjb3BpZWRBdHRyaWJ1dGVzLAogICAgICBpbmRpY2VzOiBbXSwKICAgICAgcHJpbWl0aXZlVHlwZTogZ2VvbWV0cnkucHJpbWl0aXZlVHlwZQogICAgfSk7CiAgfQogIGZ1bmN0aW9uIHVwZGF0ZUluc3RhbmNlQWZ0ZXJTcGxpdChpbnN0YW5jZSwgd2VzdEdlb21ldHJ5LCBlYXN0R2VvbWV0cnkpIHsKICAgIGNvbnN0IGNvbXB1dGVCb3VuZGluZ1NwaGVyZSA9IGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZS5nZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSk7CiAgICB3ZXN0R2VvbWV0cnkgPSB1cGRhdGVHZW9tZXRyeUFmdGVyU3BsaXQod2VzdEdlb21ldHJ5LCBjb21wdXRlQm91bmRpbmdTcGhlcmUpOwogICAgZWFzdEdlb21ldHJ5ID0gdXBkYXRlR2VvbWV0cnlBZnRlclNwbGl0KGVhc3RHZW9tZXRyeSwgY29tcHV0ZUJvdW5kaW5nU3BoZXJlKTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZWFzdEdlb21ldHJ5KSAmJiAhZGVmaW5lZF9kZWZhdWx0KHdlc3RHZW9tZXRyeSkpIHsKICAgICAgaW5zdGFuY2UuZ2VvbWV0cnkgPSBlYXN0R2VvbWV0cnk7CiAgICB9IGVsc2UgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZWFzdEdlb21ldHJ5KSAmJiBkZWZpbmVkX2RlZmF1bHQod2VzdEdlb21ldHJ5KSkgewogICAgICBpbnN0YW5jZS5nZW9tZXRyeSA9IHdlc3RHZW9tZXRyeTsKICAgIH0gZWxzZSB7CiAgICAgIGluc3RhbmNlLndlc3RIZW1pc3BoZXJlR2VvbWV0cnkgPSB3ZXN0R2VvbWV0cnk7CiAgICAgIGluc3RhbmNlLmVhc3RIZW1pc3BoZXJlR2VvbWV0cnkgPSBlYXN0R2VvbWV0cnk7CiAgICAgIGluc3RhbmNlLmdlb21ldHJ5ID0gdm9pZCAwOwogICAgfQogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZUJhcnljZW50cmljSW50ZXJwb2xhdGVGdW5jdGlvbihDYXJ0ZXNpYW5UeXBlLCBudW1iZXJPZkNvbXBvbmVudHMpIHsKICAgIGNvbnN0IHYwU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW5UeXBlKCk7CiAgICBjb25zdCB2MVNjcmF0Y2gyID0gbmV3IENhcnRlc2lhblR5cGUoKTsKICAgIGNvbnN0IHYyU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuVHlwZSgpOwogICAgcmV0dXJuIGZ1bmN0aW9uKGkwLCBpMSwgaTIsIGNvb3Jkcywgc291cmNlVmFsdWVzLCBjdXJyZW50VmFsdWVzLCBpbnNlcnRlZEluZGV4LCBub3JtYWxpemUpIHsKICAgICAgY29uc3QgdjAyID0gQ2FydGVzaWFuVHlwZS5mcm9tQXJyYXkoCiAgICAgICAgc291cmNlVmFsdWVzLAogICAgICAgIGkwICogbnVtYmVyT2ZDb21wb25lbnRzLAogICAgICAgIHYwU2NyYXRjaAogICAgICApOwogICAgICBjb25zdCB2MTIgPSBDYXJ0ZXNpYW5UeXBlLmZyb21BcnJheSgKICAgICAgICBzb3VyY2VWYWx1ZXMsCiAgICAgICAgaTEgKiBudW1iZXJPZkNvbXBvbmVudHMsCiAgICAgICAgdjFTY3JhdGNoMgogICAgICApOwogICAgICBjb25zdCB2MjIgPSBDYXJ0ZXNpYW5UeXBlLmZyb21BcnJheSgKICAgICAgICBzb3VyY2VWYWx1ZXMsCiAgICAgICAgaTIgKiBudW1iZXJPZkNvbXBvbmVudHMsCiAgICAgICAgdjJTY3JhdGNoMgogICAgICApOwogICAgICBDYXJ0ZXNpYW5UeXBlLm11bHRpcGx5QnlTY2FsYXIodjAyLCBjb29yZHMueCwgdjAyKTsKICAgICAgQ2FydGVzaWFuVHlwZS5tdWx0aXBseUJ5U2NhbGFyKHYxMiwgY29vcmRzLnksIHYxMik7CiAgICAgIENhcnRlc2lhblR5cGUubXVsdGlwbHlCeVNjYWxhcih2MjIsIGNvb3Jkcy56LCB2MjIpOwogICAgICBjb25zdCB2YWx1ZSA9IENhcnRlc2lhblR5cGUuYWRkKHYwMiwgdjEyLCB2MDIpOwogICAgICBDYXJ0ZXNpYW5UeXBlLmFkZCh2YWx1ZSwgdjIyLCB2YWx1ZSk7CiAgICAgIGlmIChub3JtYWxpemUpIHsKICAgICAgICBDYXJ0ZXNpYW5UeXBlLm5vcm1hbGl6ZSh2YWx1ZSwgdmFsdWUpOwogICAgICB9CiAgICAgIENhcnRlc2lhblR5cGUucGFjaygKICAgICAgICB2YWx1ZSwKICAgICAgICBjdXJyZW50VmFsdWVzLAogICAgICAgIGluc2VydGVkSW5kZXggKiBudW1iZXJPZkNvbXBvbmVudHMKICAgICAgKTsKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVUcmlhbmdsZUF0dHJpYnV0ZXMoaTAsIGkxLCBpMiwgcG9pbnQsIHBvc2l0aW9ucywgbm9ybWFscywgdGFuZ2VudHMsIGJpdGFuZ2VudHMsIHRleENvb3JkcywgZXh0cnVkZURpcmVjdGlvbnMsIGFwcGx5T2Zmc2V0LCBjdXJyZW50QXR0cmlidXRlcywgY3VzdG9tQXR0cmlidXRlTmFtZXMsIGN1c3RvbUF0dHJpYnV0ZXNMZW5ndGgsIGFsbEF0dHJpYnV0ZXMsIGluc2VydGVkSW5kZXgpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHMpICYmICFkZWZpbmVkX2RlZmF1bHQodGFuZ2VudHMpICYmICFkZWZpbmVkX2RlZmF1bHQoYml0YW5nZW50cykgJiYgIWRlZmluZWRfZGVmYXVsdCh0ZXhDb29yZHMpICYmICFkZWZpbmVkX2RlZmF1bHQoZXh0cnVkZURpcmVjdGlvbnMpICYmIGN1c3RvbUF0dHJpYnV0ZXNMZW5ndGggPT09IDApIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3QgcDAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTAgKiAzLCBwMFNjcmF0Y2gpOwogICAgY29uc3QgcDEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTEgKiAzLCBwMVNjcmF0Y2gpOwogICAgY29uc3QgcDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIgKiAzLCBwMlNjcmF0Y2gpOwogICAgY29uc3QgY29vcmRzID0gYmFyeWNlbnRyaWNDb29yZGluYXRlc19kZWZhdWx0KHBvaW50LCBwMCwgcDEsIHAyLCBiYXJ5Y2VudHJpY1NjcmF0Y2gpOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY29vcmRzKSkgewogICAgICByZXR1cm47CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHMpKSB7CiAgICAgIGludGVycG9sYXRlQW5kUGFja0NhcnRlc2lhbjMoCiAgICAgICAgaTAsCiAgICAgICAgaTEsCiAgICAgICAgaTIsCiAgICAgICAgY29vcmRzLAogICAgICAgIG5vcm1hbHMsCiAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMubm9ybWFsLnZhbHVlcywKICAgICAgICBpbnNlcnRlZEluZGV4LAogICAgICAgIHRydWUKICAgICAgKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZXh0cnVkZURpcmVjdGlvbnMpKSB7CiAgICAgIGNvbnN0IGQwID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShleHRydWRlRGlyZWN0aW9ucywgaTAgKiAzLCBwMFNjcmF0Y2gpOwogICAgICBjb25zdCBkMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoZXh0cnVkZURpcmVjdGlvbnMsIGkxICogMywgcDFTY3JhdGNoKTsKICAgICAgY29uc3QgZDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGV4dHJ1ZGVEaXJlY3Rpb25zLCBpMiAqIDMsIHAyU2NyYXRjaCk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGQwLCBjb29yZHMueCwgZDApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihkMSwgY29vcmRzLnksIGQxKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZDIsIGNvb3Jkcy56LCBkMik7CiAgICAgIGxldCBkaXJlY3Rpb24yOwogICAgICBpZiAoIUNhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMoZDAsIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPKSB8fCAhQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhkMSwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pIHx8ICFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGQyLCBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTykpIHsKICAgICAgICBkaXJlY3Rpb24yID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChkMCwgZDEsIGQwKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGRpcmVjdGlvbjIsIGQyLCBkaXJlY3Rpb24yKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGRpcmVjdGlvbjIsIGRpcmVjdGlvbjIpOwogICAgICB9IGVsc2UgewogICAgICAgIGRpcmVjdGlvbjIgPSBwMFNjcmF0Y2g7CiAgICAgICAgZGlyZWN0aW9uMi54ID0gMDsKICAgICAgICBkaXJlY3Rpb24yLnkgPSAwOwogICAgICAgIGRpcmVjdGlvbjIueiA9IDA7CiAgICAgIH0KICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soCiAgICAgICAgZGlyZWN0aW9uMiwKICAgICAgICBjdXJyZW50QXR0cmlidXRlcy5leHRydWRlRGlyZWN0aW9uLnZhbHVlcywKICAgICAgICBpbnNlcnRlZEluZGV4ICogMwogICAgICApOwogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChhcHBseU9mZnNldCkpIHsKICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQm9vbGVhbigKICAgICAgICBpMCwKICAgICAgICBpMSwKICAgICAgICBpMiwKICAgICAgICBjb29yZHMsCiAgICAgICAgYXBwbHlPZmZzZXQsCiAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQudmFsdWVzLAogICAgICAgIGluc2VydGVkSW5kZXgKICAgICAgKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGFuZ2VudHMpKSB7CiAgICAgIGludGVycG9sYXRlQW5kUGFja0NhcnRlc2lhbjMoCiAgICAgICAgaTAsCiAgICAgICAgaTEsCiAgICAgICAgaTIsCiAgICAgICAgY29vcmRzLAogICAgICAgIHRhbmdlbnRzLAogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnRhbmdlbnQudmFsdWVzLAogICAgICAgIGluc2VydGVkSW5kZXgsCiAgICAgICAgdHJ1ZQogICAgICApOwogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChiaXRhbmdlbnRzKSkgewogICAgICBpbnRlcnBvbGF0ZUFuZFBhY2tDYXJ0ZXNpYW4zKAogICAgICAgIGkwLAogICAgICAgIGkxLAogICAgICAgIGkyLAogICAgICAgIGNvb3JkcywKICAgICAgICBiaXRhbmdlbnRzLAogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLmJpdGFuZ2VudC52YWx1ZXMsCiAgICAgICAgaW5zZXJ0ZWRJbmRleCwKICAgICAgICB0cnVlCiAgICAgICk7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRleENvb3JkcykpIHsKICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuMigKICAgICAgICBpMCwKICAgICAgICBpMSwKICAgICAgICBpMiwKICAgICAgICBjb29yZHMsCiAgICAgICAgdGV4Q29vcmRzLAogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnN0LnZhbHVlcywKICAgICAgICBpbnNlcnRlZEluZGV4CiAgICAgICk7CiAgICB9CiAgICBpZiAoY3VzdG9tQXR0cmlidXRlc0xlbmd0aCA+IDApIHsKICAgICAgZm9yIChsZXQgaTMgPSAwOyBpMyA8IGN1c3RvbUF0dHJpYnV0ZXNMZW5ndGg7IGkzKyspIHsKICAgICAgICBjb25zdCBhdHRyaWJ1dGVOYW1lID0gY3VzdG9tQXR0cmlidXRlTmFtZXNbaTNdOwogICAgICAgIGdlbmVyaWNJbnRlcnBvbGF0ZSgKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBpMiwKICAgICAgICAgIGNvb3JkcywKICAgICAgICAgIGluc2VydGVkSW5kZXgsCiAgICAgICAgICBhbGxBdHRyaWJ1dGVzW2F0dHJpYnV0ZU5hbWVdLAogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0KICAgICAgICApOwogICAgICB9CiAgICB9CiAgfQogIGZ1bmN0aW9uIGdlbmVyaWNJbnRlcnBvbGF0ZShpMCwgaTEsIGkyLCBjb29yZHMsIGluc2VydGVkSW5kZXgsIHNvdXJjZUF0dHJpYnV0ZSwgY3VycmVudEF0dHJpYnV0ZSkgewogICAgY29uc3QgY29tcG9uZW50c1BlckF0dHJpYnV0ZSA9IHNvdXJjZUF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlOwogICAgY29uc3Qgc291cmNlVmFsdWVzID0gc291cmNlQXR0cmlidXRlLnZhbHVlczsKICAgIGNvbnN0IGN1cnJlbnRWYWx1ZXMgPSBjdXJyZW50QXR0cmlidXRlLnZhbHVlczsKICAgIHN3aXRjaCAoY29tcG9uZW50c1BlckF0dHJpYnV0ZSkgewogICAgICBjYXNlIDQ6CiAgICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuNCgKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBpMiwKICAgICAgICAgIGNvb3JkcywKICAgICAgICAgIHNvdXJjZVZhbHVlcywKICAgICAgICAgIGN1cnJlbnRWYWx1ZXMsCiAgICAgICAgICBpbnNlcnRlZEluZGV4LAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIDM6CiAgICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuMygKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBpMiwKICAgICAgICAgIGNvb3JkcywKICAgICAgICAgIHNvdXJjZVZhbHVlcywKICAgICAgICAgIGN1cnJlbnRWYWx1ZXMsCiAgICAgICAgICBpbnNlcnRlZEluZGV4LAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIDI6CiAgICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuMigKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBpMiwKICAgICAgICAgIGNvb3JkcywKICAgICAgICAgIHNvdXJjZVZhbHVlcywKICAgICAgICAgIGN1cnJlbnRWYWx1ZXMsCiAgICAgICAgICBpbnNlcnRlZEluZGV4LAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGJyZWFrOwogICAgICBkZWZhdWx0OgogICAgICAgIGN1cnJlbnRWYWx1ZXNbaW5zZXJ0ZWRJbmRleF0gPSBzb3VyY2VWYWx1ZXNbaTBdICogY29vcmRzLnggKyBzb3VyY2VWYWx1ZXNbaTFdICogY29vcmRzLnkgKyBzb3VyY2VWYWx1ZXNbaTJdICogY29vcmRzLno7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGluc2VydFNwbGl0UG9pbnQoY3VycmVudEF0dHJpYnV0ZXMsIGN1cnJlbnRJbmRpY2VzLCBjdXJyZW50SW5kZXhNYXAsIGluZGljZXMsIGN1cnJlbnRJbmRleCwgcG9pbnQpIHsKICAgIGNvbnN0IGluc2VydEluZGV4ID0gY3VycmVudEF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aCAvIDM7CiAgICBpZiAoY3VycmVudEluZGV4ICE9PSAtMSkgewogICAgICBjb25zdCBwcmV2SW5kZXggPSBpbmRpY2VzW2N1cnJlbnRJbmRleF07CiAgICAgIGNvbnN0IG5ld0luZGV4ID0gY3VycmVudEluZGV4TWFwW3ByZXZJbmRleF07CiAgICAgIGlmIChuZXdJbmRleCA9PT0gLTEpIHsKICAgICAgICBjdXJyZW50SW5kZXhNYXBbcHJldkluZGV4XSA9IGluc2VydEluZGV4OwogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKHBvaW50LngsIHBvaW50LnksIHBvaW50LnopOwogICAgICAgIGN1cnJlbnRJbmRpY2VzLnB1c2goaW5zZXJ0SW5kZXgpOwogICAgICAgIHJldHVybiBpbnNlcnRJbmRleDsKICAgICAgfQogICAgICBjdXJyZW50SW5kaWNlcy5wdXNoKG5ld0luZGV4KTsKICAgICAgcmV0dXJuIG5ld0luZGV4OwogICAgfQogICAgY3VycmVudEF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLnB1c2gocG9pbnQueCwgcG9pbnQueSwgcG9pbnQueik7CiAgICBjdXJyZW50SW5kaWNlcy5wdXNoKGluc2VydEluZGV4KTsKICAgIHJldHVybiBpbnNlcnRJbmRleDsKICB9CiAgZnVuY3Rpb24gc3BsaXRMb25naXR1ZGVUcmlhbmdsZXMoaW5zdGFuY2UpIHsKICAgIGNvbnN0IGdlb21ldHJ5ID0gaW5zdGFuY2UuZ2VvbWV0cnk7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgY29uc3Qgbm9ybWFscyA9IGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLm5vcm1hbCkgPyBhdHRyaWJ1dGVzLm5vcm1hbC52YWx1ZXMgOiB2b2lkIDA7CiAgICBjb25zdCBiaXRhbmdlbnRzID0gZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuYml0YW5nZW50KSA/IGF0dHJpYnV0ZXMuYml0YW5nZW50LnZhbHVlcyA6IHZvaWQgMDsKICAgIGNvbnN0IHRhbmdlbnRzID0gZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMudGFuZ2VudCkgPyBhdHRyaWJ1dGVzLnRhbmdlbnQudmFsdWVzIDogdm9pZCAwOwogICAgY29uc3QgdGV4Q29vcmRzID0gZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuc3QpID8gYXR0cmlidXRlcy5zdC52YWx1ZXMgOiB2b2lkIDA7CiAgICBjb25zdCBleHRydWRlRGlyZWN0aW9ucyA9IGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLmV4dHJ1ZGVEaXJlY3Rpb24pID8gYXR0cmlidXRlcy5leHRydWRlRGlyZWN0aW9uLnZhbHVlcyA6IHZvaWQgMDsKICAgIGNvbnN0IGFwcGx5T2Zmc2V0ID0gZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQpID8gYXR0cmlidXRlcy5hcHBseU9mZnNldC52YWx1ZXMgOiB2b2lkIDA7CiAgICBjb25zdCBpbmRpY2VzID0gZ2VvbWV0cnkuaW5kaWNlczsKICAgIGNvbnN0IGN1c3RvbUF0dHJpYnV0ZU5hbWVzID0gW107CiAgICBmb3IgKGNvbnN0IGF0dHJpYnV0ZU5hbWUgaW4gYXR0cmlidXRlcykgewogICAgICBpZiAoYXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShhdHRyaWJ1dGVOYW1lKSAmJiAhTkFNRURfQVRUUklCVVRFU1thdHRyaWJ1dGVOYW1lXSAmJiBkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlc1thdHRyaWJ1dGVOYW1lXSkpIHsKICAgICAgICBjdXN0b21BdHRyaWJ1dGVOYW1lcy5wdXNoKGF0dHJpYnV0ZU5hbWUpOwogICAgICB9CiAgICB9CiAgICBjb25zdCBjdXN0b21BdHRyaWJ1dGVzTGVuZ3RoID0gY3VzdG9tQXR0cmlidXRlTmFtZXMubGVuZ3RoOwogICAgY29uc3QgZWFzdEdlb21ldHJ5ID0gY29weUdlb21ldHJ5Rm9yU3BsaXQoZ2VvbWV0cnkpOwogICAgY29uc3Qgd2VzdEdlb21ldHJ5ID0gY29weUdlb21ldHJ5Rm9yU3BsaXQoZ2VvbWV0cnkpOwogICAgbGV0IGN1cnJlbnRBdHRyaWJ1dGVzOwogICAgbGV0IGN1cnJlbnRJbmRpY2VzOwogICAgbGV0IGN1cnJlbnRJbmRleE1hcDsKICAgIGxldCBpbnNlcnRlZEluZGV4OwogICAgbGV0IGkyOwogICAgY29uc3Qgd2VzdEdlb21ldHJ5SW5kZXhNYXAgPSBbXTsKICAgIHdlc3RHZW9tZXRyeUluZGV4TWFwLmxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3QgZWFzdEdlb21ldHJ5SW5kZXhNYXAgPSBbXTsKICAgIGVhc3RHZW9tZXRyeUluZGV4TWFwLmxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgd2VzdEdlb21ldHJ5SW5kZXhNYXAubGVuZ3RoOyArK2kyKSB7CiAgICAgIHdlc3RHZW9tZXRyeUluZGV4TWFwW2kyXSA9IC0xOwogICAgICBlYXN0R2VvbWV0cnlJbmRleE1hcFtpMl0gPSAtMTsKICAgIH0KICAgIGNvbnN0IGxlbiA9IGluZGljZXMubGVuZ3RoOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuOyBpMiArPSAzKSB7CiAgICAgIGNvbnN0IGkwID0gaW5kaWNlc1tpMl07CiAgICAgIGNvbnN0IGkxID0gaW5kaWNlc1tpMiArIDFdOwogICAgICBjb25zdCBpMjIgPSBpbmRpY2VzW2kyICsgMl07CiAgICAgIGxldCBwMCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBpMCAqIDMpOwogICAgICBsZXQgcDEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTEgKiAzKTsKICAgICAgbGV0IHAyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkyMiAqIDMpOwogICAgICBjb25zdCByZXN1bHQgPSBzcGxpdFRyaWFuZ2xlKHAwLCBwMSwgcDIpOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkgJiYgcmVzdWx0LnBvc2l0aW9ucy5sZW5ndGggPiAzKSB7CiAgICAgICAgY29uc3QgcmVzdWx0UG9zaXRpb25zID0gcmVzdWx0LnBvc2l0aW9uczsKICAgICAgICBjb25zdCByZXN1bHRJbmRpY2VzID0gcmVzdWx0LmluZGljZXM7CiAgICAgICAgY29uc3QgcmVzdWx0TGVuZ3RoID0gcmVzdWx0SW5kaWNlcy5sZW5ndGg7CiAgICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IHJlc3VsdExlbmd0aDsgKytqMikgewogICAgICAgICAgY29uc3QgcmVzdWx0SW5kZXggPSByZXN1bHRJbmRpY2VzW2oyXTsKICAgICAgICAgIGNvbnN0IHBvaW50ID0gcmVzdWx0UG9zaXRpb25zW3Jlc3VsdEluZGV4XTsKICAgICAgICAgIGlmIChwb2ludC55IDwgMCkgewogICAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcyA9IHdlc3RHZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgICAgICBjdXJyZW50SW5kaWNlcyA9IHdlc3RHZW9tZXRyeS5pbmRpY2VzOwogICAgICAgICAgICBjdXJyZW50SW5kZXhNYXAgPSB3ZXN0R2VvbWV0cnlJbmRleE1hcDsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzID0gZWFzdEdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgICAgICAgIGN1cnJlbnRJbmRpY2VzID0gZWFzdEdlb21ldHJ5LmluZGljZXM7CiAgICAgICAgICAgIGN1cnJlbnRJbmRleE1hcCA9IGVhc3RHZW9tZXRyeUluZGV4TWFwOwogICAgICAgICAgfQogICAgICAgICAgaW5zZXJ0ZWRJbmRleCA9IGluc2VydFNwbGl0UG9pbnQoCiAgICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgICBjdXJyZW50SW5kaWNlcywKICAgICAgICAgICAgY3VycmVudEluZGV4TWFwLAogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICByZXN1bHRJbmRleCA8IDMgPyBpMiArIHJlc3VsdEluZGV4IDogLTEsCiAgICAgICAgICAgIHBvaW50CiAgICAgICAgICApOwogICAgICAgICAgY29tcHV0ZVRyaWFuZ2xlQXR0cmlidXRlcygKICAgICAgICAgICAgaTAsCiAgICAgICAgICAgIGkxLAogICAgICAgICAgICBpMjIsCiAgICAgICAgICAgIHBvaW50LAogICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgIG5vcm1hbHMsCiAgICAgICAgICAgIHRhbmdlbnRzLAogICAgICAgICAgICBiaXRhbmdlbnRzLAogICAgICAgICAgICB0ZXhDb29yZHMsCiAgICAgICAgICAgIGV4dHJ1ZGVEaXJlY3Rpb25zLAogICAgICAgICAgICBhcHBseU9mZnNldCwKICAgICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMsCiAgICAgICAgICAgIGN1c3RvbUF0dHJpYnV0ZU5hbWVzLAogICAgICAgICAgICBjdXN0b21BdHRyaWJ1dGVzTGVuZ3RoLAogICAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgICBpbnNlcnRlZEluZGV4CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHAwID0gcmVzdWx0LnBvc2l0aW9uc1swXTsKICAgICAgICAgIHAxID0gcmVzdWx0LnBvc2l0aW9uc1sxXTsKICAgICAgICAgIHAyID0gcmVzdWx0LnBvc2l0aW9uc1syXTsKICAgICAgICB9CiAgICAgICAgaWYgKHAwLnkgPCAwKSB7CiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcyA9IHdlc3RHZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgICAgY3VycmVudEluZGljZXMgPSB3ZXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgICAgIGN1cnJlbnRJbmRleE1hcCA9IHdlc3RHZW9tZXRyeUluZGV4TWFwOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcyA9IGVhc3RHZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgICAgY3VycmVudEluZGljZXMgPSBlYXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgICAgIGN1cnJlbnRJbmRleE1hcCA9IGVhc3RHZW9tZXRyeUluZGV4TWFwOwogICAgICAgIH0KICAgICAgICBpbnNlcnRlZEluZGV4ID0gaW5zZXJ0U3BsaXRQb2ludCgKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgY3VycmVudEluZGljZXMsCiAgICAgICAgICBjdXJyZW50SW5kZXhNYXAsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgaTIsCiAgICAgICAgICBwMAogICAgICAgICk7CiAgICAgICAgY29tcHV0ZVRyaWFuZ2xlQXR0cmlidXRlcygKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBpMjIsCiAgICAgICAgICBwMCwKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIG5vcm1hbHMsCiAgICAgICAgICB0YW5nZW50cywKICAgICAgICAgIGJpdGFuZ2VudHMsCiAgICAgICAgICB0ZXhDb29yZHMsCiAgICAgICAgICBleHRydWRlRGlyZWN0aW9ucywKICAgICAgICAgIGFwcGx5T2Zmc2V0LAogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMsCiAgICAgICAgICBjdXN0b21BdHRyaWJ1dGVOYW1lcywKICAgICAgICAgIGN1c3RvbUF0dHJpYnV0ZXNMZW5ndGgsCiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5zZXJ0ZWRJbmRleAogICAgICAgICk7CiAgICAgICAgaW5zZXJ0ZWRJbmRleCA9IGluc2VydFNwbGl0UG9pbnQoCiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcywKICAgICAgICAgIGN1cnJlbnRJbmRpY2VzLAogICAgICAgICAgY3VycmVudEluZGV4TWFwLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIGkyICsgMSwKICAgICAgICAgIHAxCiAgICAgICAgKTsKICAgICAgICBjb21wdXRlVHJpYW5nbGVBdHRyaWJ1dGVzKAogICAgICAgICAgaTAsCiAgICAgICAgICBpMSwKICAgICAgICAgIGkyMiwKICAgICAgICAgIHAxLAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgbm9ybWFscywKICAgICAgICAgIHRhbmdlbnRzLAogICAgICAgICAgYml0YW5nZW50cywKICAgICAgICAgIHRleENvb3JkcywKICAgICAgICAgIGV4dHJ1ZGVEaXJlY3Rpb25zLAogICAgICAgICAgYXBwbHlPZmZzZXQsCiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcywKICAgICAgICAgIGN1c3RvbUF0dHJpYnV0ZU5hbWVzLAogICAgICAgICAgY3VzdG9tQXR0cmlidXRlc0xlbmd0aCwKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbnNlcnRlZEluZGV4CiAgICAgICAgKTsKICAgICAgICBpbnNlcnRlZEluZGV4ID0gaW5zZXJ0U3BsaXRQb2ludCgKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgY3VycmVudEluZGljZXMsCiAgICAgICAgICBjdXJyZW50SW5kZXhNYXAsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgaTIgKyAyLAogICAgICAgICAgcDIKICAgICAgICApOwogICAgICAgIGNvbXB1dGVUcmlhbmdsZUF0dHJpYnV0ZXMoCiAgICAgICAgICBpMCwKICAgICAgICAgIGkxLAogICAgICAgICAgaTIyLAogICAgICAgICAgcDIsCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBub3JtYWxzLAogICAgICAgICAgdGFuZ2VudHMsCiAgICAgICAgICBiaXRhbmdlbnRzLAogICAgICAgICAgdGV4Q29vcmRzLAogICAgICAgICAgZXh0cnVkZURpcmVjdGlvbnMsCiAgICAgICAgICBhcHBseU9mZnNldCwKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgY3VzdG9tQXR0cmlidXRlTmFtZXMsCiAgICAgICAgICBjdXN0b21BdHRyaWJ1dGVzTGVuZ3RoLAogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluc2VydGVkSW5kZXgKICAgICAgICApOwogICAgICB9CiAgICB9CiAgICB1cGRhdGVJbnN0YW5jZUFmdGVyU3BsaXQoaW5zdGFuY2UsIHdlc3RHZW9tZXRyeSwgZWFzdEdlb21ldHJ5KTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUxpbmVBdHRyaWJ1dGVzKGkwLCBpMSwgcG9pbnQsIHBvc2l0aW9ucywgaW5zZXJ0SW5kZXgsIGN1cnJlbnRBdHRyaWJ1dGVzLCBhcHBseU9mZnNldCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXBwbHlPZmZzZXQpKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNvbnN0IHAwID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkwICogMywgcDBTY3JhdGNoKTsKICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihwMCwgcG9pbnQsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0LnZhbHVlc1tpbnNlcnRJbmRleF0gPSBhcHBseU9mZnNldFtpMF07CiAgICB9IGVsc2UgewogICAgICBjdXJyZW50QXR0cmlidXRlcy5hcHBseU9mZnNldC52YWx1ZXNbaW5zZXJ0SW5kZXhdID0gYXBwbHlPZmZzZXRbaTFdOwogICAgfQogIH0KICBmdW5jdGlvbiBzcGxpdExvbmdpdHVkZUxpbmVzKGluc3RhbmNlKSB7CiAgICBjb25zdCBnZW9tZXRyeSA9IGluc3RhbmNlLmdlb21ldHJ5OwogICAgY29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgIGNvbnN0IGFwcGx5T2Zmc2V0ID0gZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQpID8gYXR0cmlidXRlcy5hcHBseU9mZnNldC52YWx1ZXMgOiB2b2lkIDA7CiAgICBjb25zdCBpbmRpY2VzID0gZ2VvbWV0cnkuaW5kaWNlczsKICAgIGNvbnN0IGVhc3RHZW9tZXRyeSA9IGNvcHlHZW9tZXRyeUZvclNwbGl0KGdlb21ldHJ5KTsKICAgIGNvbnN0IHdlc3RHZW9tZXRyeSA9IGNvcHlHZW9tZXRyeUZvclNwbGl0KGdlb21ldHJ5KTsKICAgIGxldCBpMjsKICAgIGNvbnN0IGxlbmd0aCA9IGluZGljZXMubGVuZ3RoOwogICAgY29uc3Qgd2VzdEdlb21ldHJ5SW5kZXhNYXAgPSBbXTsKICAgIHdlc3RHZW9tZXRyeUluZGV4TWFwLmxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3QgZWFzdEdlb21ldHJ5SW5kZXhNYXAgPSBbXTsKICAgIGVhc3RHZW9tZXRyeUluZGV4TWFwLmxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgd2VzdEdlb21ldHJ5SW5kZXhNYXAubGVuZ3RoOyArK2kyKSB7CiAgICAgIHdlc3RHZW9tZXRyeUluZGV4TWFwW2kyXSA9IC0xOwogICAgICBlYXN0R2VvbWV0cnlJbmRleE1hcFtpMl0gPSAtMTsKICAgIH0KICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMikgewogICAgICBjb25zdCBpMCA9IGluZGljZXNbaTJdOwogICAgICBjb25zdCBpMSA9IGluZGljZXNbaTIgKyAxXTsKICAgICAgY29uc3QgcDAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTAgKiAzLCBwMFNjcmF0Y2gpOwogICAgICBjb25zdCBwMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBpMSAqIDMsIHAxU2NyYXRjaCk7CiAgICAgIGxldCBpbnNlcnRJbmRleDsKICAgICAgaWYgKE1hdGguYWJzKHAwLnkpIDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgICAgaWYgKHAwLnkgPCAwKSB7CiAgICAgICAgICBwMC55ID0gLU1hdGhfZGVmYXVsdC5FUFNJTE9ONjsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcDAueSA9IE1hdGhfZGVmYXVsdC5FUFNJTE9ONjsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKE1hdGguYWJzKHAxLnkpIDwgTWF0aF9kZWZhdWx0LkVQU0lMT042KSB7CiAgICAgICAgaWYgKHAxLnkgPCAwKSB7CiAgICAgICAgICBwMS55ID0gLU1hdGhfZGVmYXVsdC5FUFNJTE9ONjsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcDEueSA9IE1hdGhfZGVmYXVsdC5FUFNJTE9ONjsKICAgICAgICB9CiAgICAgIH0KICAgICAgbGV0IHAwQXR0cmlidXRlcyA9IGVhc3RHZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICBsZXQgcDBJbmRpY2VzID0gZWFzdEdlb21ldHJ5LmluZGljZXM7CiAgICAgIGxldCBwMEluZGV4TWFwID0gZWFzdEdlb21ldHJ5SW5kZXhNYXA7CiAgICAgIGxldCBwMUF0dHJpYnV0ZXMgPSB3ZXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgbGV0IHAxSW5kaWNlcyA9IHdlc3RHZW9tZXRyeS5pbmRpY2VzOwogICAgICBsZXQgcDFJbmRleE1hcCA9IHdlc3RHZW9tZXRyeUluZGV4TWFwOwogICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LmxpbmVTZWdtZW50UGxhbmUoCiAgICAgICAgcDAsCiAgICAgICAgcDEsCiAgICAgICAgeHpQbGFuZSwKICAgICAgICBwMlNjcmF0Y2gKICAgICAgKTsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb24pKSB7CiAgICAgICAgY29uc3Qgb2Zmc2V0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZLAogICAgICAgICAgNSAqIE1hdGhfZGVmYXVsdC5FUFNJTE9OOSwKICAgICAgICAgIG9mZnNldFNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGlmIChwMC55IDwgMCkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShvZmZzZXQsIG9mZnNldCk7CiAgICAgICAgICBwMEF0dHJpYnV0ZXMgPSB3ZXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIHAwSW5kaWNlcyA9IHdlc3RHZW9tZXRyeS5pbmRpY2VzOwogICAgICAgICAgcDBJbmRleE1hcCA9IHdlc3RHZW9tZXRyeUluZGV4TWFwOwogICAgICAgICAgcDFBdHRyaWJ1dGVzID0gZWFzdEdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgICAgICBwMUluZGljZXMgPSBlYXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgICAgIHAxSW5kZXhNYXAgPSBlYXN0R2VvbWV0cnlJbmRleE1hcDsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb2Zmc2V0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgaW50ZXJzZWN0aW9uLAogICAgICAgICAgb2Zmc2V0LAogICAgICAgICAgb2Zmc2V0UG9pbnRTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBpbnNlcnRJbmRleCA9IGluc2VydFNwbGl0UG9pbnQoCiAgICAgICAgICBwMEF0dHJpYnV0ZXMsCiAgICAgICAgICBwMEluZGljZXMsCiAgICAgICAgICBwMEluZGV4TWFwLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIGkyLAogICAgICAgICAgcDAKICAgICAgICApOwogICAgICAgIGNvbXB1dGVMaW5lQXR0cmlidXRlcygKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBwMCwKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIGluc2VydEluZGV4LAogICAgICAgICAgcDBBdHRyaWJ1dGVzLAogICAgICAgICAgYXBwbHlPZmZzZXQKICAgICAgICApOwogICAgICAgIGluc2VydEluZGV4ID0gaW5zZXJ0U3BsaXRQb2ludCgKICAgICAgICAgIHAwQXR0cmlidXRlcywKICAgICAgICAgIHAwSW5kaWNlcywKICAgICAgICAgIHAwSW5kZXhNYXAsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgLTEsCiAgICAgICAgICBvZmZzZXRQb2ludAogICAgICAgICk7CiAgICAgICAgY29tcHV0ZUxpbmVBdHRyaWJ1dGVzKAogICAgICAgICAgaTAsCiAgICAgICAgICBpMSwKICAgICAgICAgIG9mZnNldFBvaW50LAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgaW5zZXJ0SW5kZXgsCiAgICAgICAgICBwMEF0dHJpYnV0ZXMsCiAgICAgICAgICBhcHBseU9mZnNldAogICAgICAgICk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShvZmZzZXQsIG9mZnNldCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChpbnRlcnNlY3Rpb24sIG9mZnNldCwgb2Zmc2V0UG9pbnQpOwogICAgICAgIGluc2VydEluZGV4ID0gaW5zZXJ0U3BsaXRQb2ludCgKICAgICAgICAgIHAxQXR0cmlidXRlcywKICAgICAgICAgIHAxSW5kaWNlcywKICAgICAgICAgIHAxSW5kZXhNYXAsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgLTEsCiAgICAgICAgICBvZmZzZXRQb2ludAogICAgICAgICk7CiAgICAgICAgY29tcHV0ZUxpbmVBdHRyaWJ1dGVzKAogICAgICAgICAgaTAsCiAgICAgICAgICBpMSwKICAgICAgICAgIG9mZnNldFBvaW50LAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgaW5zZXJ0SW5kZXgsCiAgICAgICAgICBwMUF0dHJpYnV0ZXMsCiAgICAgICAgICBhcHBseU9mZnNldAogICAgICAgICk7CiAgICAgICAgaW5zZXJ0SW5kZXggPSBpbnNlcnRTcGxpdFBvaW50KAogICAgICAgICAgcDFBdHRyaWJ1dGVzLAogICAgICAgICAgcDFJbmRpY2VzLAogICAgICAgICAgcDFJbmRleE1hcCwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBpMiArIDEsCiAgICAgICAgICBwMQogICAgICAgICk7CiAgICAgICAgY29tcHV0ZUxpbmVBdHRyaWJ1dGVzKAogICAgICAgICAgaTAsCiAgICAgICAgICBpMSwKICAgICAgICAgIHAxLAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgaW5zZXJ0SW5kZXgsCiAgICAgICAgICBwMUF0dHJpYnV0ZXMsCiAgICAgICAgICBhcHBseU9mZnNldAogICAgICAgICk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgbGV0IGN1cnJlbnRBdHRyaWJ1dGVzOwogICAgICAgIGxldCBjdXJyZW50SW5kaWNlczsKICAgICAgICBsZXQgY3VycmVudEluZGV4TWFwOwogICAgICAgIGlmIChwMC55IDwgMCkgewogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMgPSB3ZXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIGN1cnJlbnRJbmRpY2VzID0gd2VzdEdlb21ldHJ5LmluZGljZXM7CiAgICAgICAgICBjdXJyZW50SW5kZXhNYXAgPSB3ZXN0R2VvbWV0cnlJbmRleE1hcDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMgPSBlYXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIGN1cnJlbnRJbmRpY2VzID0gZWFzdEdlb21ldHJ5LmluZGljZXM7CiAgICAgICAgICBjdXJyZW50SW5kZXhNYXAgPSBlYXN0R2VvbWV0cnlJbmRleE1hcDsKICAgICAgICB9CiAgICAgICAgaW5zZXJ0SW5kZXggPSBpbnNlcnRTcGxpdFBvaW50KAogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMsCiAgICAgICAgICBjdXJyZW50SW5kaWNlcywKICAgICAgICAgIGN1cnJlbnRJbmRleE1hcCwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBpMiwKICAgICAgICAgIHAwCiAgICAgICAgKTsKICAgICAgICBjb21wdXRlTGluZUF0dHJpYnV0ZXMoCiAgICAgICAgICBpMCwKICAgICAgICAgIGkxLAogICAgICAgICAgcDAsCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBpbnNlcnRJbmRleCwKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgYXBwbHlPZmZzZXQKICAgICAgICApOwogICAgICAgIGluc2VydEluZGV4ID0gaW5zZXJ0U3BsaXRQb2ludCgKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLAogICAgICAgICAgY3VycmVudEluZGljZXMsCiAgICAgICAgICBjdXJyZW50SW5kZXhNYXAsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgaTIgKyAxLAogICAgICAgICAgcDEKICAgICAgICApOwogICAgICAgIGNvbXB1dGVMaW5lQXR0cmlidXRlcygKICAgICAgICAgIGkwLAogICAgICAgICAgaTEsCiAgICAgICAgICBwMSwKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIGluc2VydEluZGV4LAogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMsCiAgICAgICAgICBhcHBseU9mZnNldAogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIHVwZGF0ZUluc3RhbmNlQWZ0ZXJTcGxpdChpbnN0YW5jZSwgd2VzdEdlb21ldHJ5LCBlYXN0R2VvbWV0cnkpOwogIH0KICBmdW5jdGlvbiB1cGRhdGVBZGphY2VuY3lBZnRlclNwbGl0KGdlb21ldHJ5KSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgY29uc3QgcHJldlBvc2l0aW9ucyA9IGF0dHJpYnV0ZXMucHJldlBvc2l0aW9uLnZhbHVlczsKICAgIGNvbnN0IG5leHRQb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLm5leHRQb3NpdGlvbi52YWx1ZXM7CiAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGxlbmd0aDsgajIgKz0gMykgewogICAgICBjb25zdCBwb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socG9zaXRpb25zLCBqMiwgY2FydGVzaWFuM1NjcmF0Y2gwKTsKICAgICAgaWYgKHBvc2l0aW9uLnggPiAwKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgY29uc3QgcHJldlBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICBwcmV2UG9zaXRpb25zLAogICAgICAgIGoyLAogICAgICAgIGNhcnRlc2lhbjNTY3JhdGNoMgogICAgICApOwogICAgICBpZiAocG9zaXRpb24ueSA8IDAgJiYgcHJldlBvc2l0aW9uLnkgPiAwIHx8IHBvc2l0aW9uLnkgPiAwICYmIHByZXZQb3NpdGlvbi55IDwgMCkgewogICAgICAgIGlmIChqMiAtIDMgPiAwKSB7CiAgICAgICAgICBwcmV2UG9zaXRpb25zW2oyXSA9IHBvc2l0aW9uc1tqMiAtIDNdOwogICAgICAgICAgcHJldlBvc2l0aW9uc1tqMiArIDFdID0gcG9zaXRpb25zW2oyIC0gMl07CiAgICAgICAgICBwcmV2UG9zaXRpb25zW2oyICsgMl0gPSBwb3NpdGlvbnNbajIgLSAxXTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2socG9zaXRpb24sIHByZXZQb3NpdGlvbnMsIGoyKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgY29uc3QgbmV4dFBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICBuZXh0UG9zaXRpb25zLAogICAgICAgIGoyLAogICAgICAgIGNhcnRlc2lhbjNTY3JhdGNoMwogICAgICApOwogICAgICBpZiAocG9zaXRpb24ueSA8IDAgJiYgbmV4dFBvc2l0aW9uLnkgPiAwIHx8IHBvc2l0aW9uLnkgPiAwICYmIG5leHRQb3NpdGlvbi55IDwgMCkgewogICAgICAgIGlmIChqMiArIDMgPCBsZW5ndGgpIHsKICAgICAgICAgIG5leHRQb3NpdGlvbnNbajJdID0gcG9zaXRpb25zW2oyICsgM107CiAgICAgICAgICBuZXh0UG9zaXRpb25zW2oyICsgMV0gPSBwb3NpdGlvbnNbajIgKyA0XTsKICAgICAgICAgIG5leHRQb3NpdGlvbnNbajIgKyAyXSA9IHBvc2l0aW9uc1tqMiArIDVdOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhwb3NpdGlvbiwgbmV4dFBvc2l0aW9ucywgajIpOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KICBmdW5jdGlvbiBzcGxpdExvbmdpdHVkZVBvbHlsaW5lKGluc3RhbmNlKSB7CiAgICBjb25zdCBnZW9tZXRyeSA9IGluc3RhbmNlLmdlb21ldHJ5OwogICAgY29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgIGNvbnN0IHByZXZQb3NpdGlvbnMgPSBhdHRyaWJ1dGVzLnByZXZQb3NpdGlvbi52YWx1ZXM7CiAgICBjb25zdCBuZXh0UG9zaXRpb25zID0gYXR0cmlidXRlcy5uZXh0UG9zaXRpb24udmFsdWVzOwogICAgY29uc3QgZXhwYW5kQW5kV2lkdGhzID0gYXR0cmlidXRlcy5leHBhbmRBbmRXaWR0aC52YWx1ZXM7CiAgICBjb25zdCB0ZXhDb29yZHMgPSBkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlcy5zdCkgPyBhdHRyaWJ1dGVzLnN0LnZhbHVlcyA6IHZvaWQgMDsKICAgIGNvbnN0IGNvbG9ycyA9IGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLmNvbG9yKSA/IGF0dHJpYnV0ZXMuY29sb3IudmFsdWVzIDogdm9pZCAwOwogICAgY29uc3QgZWFzdEdlb21ldHJ5ID0gY29weUdlb21ldHJ5Rm9yU3BsaXQoZ2VvbWV0cnkpOwogICAgY29uc3Qgd2VzdEdlb21ldHJ5ID0gY29weUdlb21ldHJ5Rm9yU3BsaXQoZ2VvbWV0cnkpOwogICAgbGV0IGkyOwogICAgbGV0IGoyOwogICAgbGV0IGluZGV4OwogICAgbGV0IGludGVyc2VjdGlvbkZvdW5kID0gZmFsc2U7CiAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gNCkgewogICAgICBjb25zdCBpMCA9IGkyOwogICAgICBjb25zdCBpMjIgPSBpMiArIDI7CiAgICAgIGNvbnN0IHAwID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkwICogMywgY2FydGVzaWFuM1NjcmF0Y2gwKTsKICAgICAgY29uc3QgcDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIyICogMywgY2FydGVzaWFuM1NjcmF0Y2gyKTsKICAgICAgaWYgKE1hdGguYWJzKHAwLnkpIDwgY29wbGFuYXJPZmZzZXQpIHsKICAgICAgICBwMC55ID0gY29wbGFuYXJPZmZzZXQgKiAocDIueSA8IDAgPyAtMSA6IDEpOwogICAgICAgIHBvc2l0aW9uc1tpMiAqIDMgKyAxXSA9IHAwLnk7CiAgICAgICAgcG9zaXRpb25zWyhpMiArIDEpICogMyArIDFdID0gcDAueTsKICAgICAgICBmb3IgKGoyID0gaTAgKiAzOyBqMiA8IGkwICogMyArIDQgKiAzOyBqMiArPSAzKSB7CiAgICAgICAgICBwcmV2UG9zaXRpb25zW2oyXSA9IHBvc2l0aW9uc1tpMiAqIDNdOwogICAgICAgICAgcHJldlBvc2l0aW9uc1tqMiArIDFdID0gcG9zaXRpb25zW2kyICogMyArIDFdOwogICAgICAgICAgcHJldlBvc2l0aW9uc1tqMiArIDJdID0gcG9zaXRpb25zW2kyICogMyArIDJdOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoTWF0aC5hYnMocDIueSkgPCBjb3BsYW5hck9mZnNldCkgewogICAgICAgIHAyLnkgPSBjb3BsYW5hck9mZnNldCAqIChwMC55IDwgMCA/IC0xIDogMSk7CiAgICAgICAgcG9zaXRpb25zWyhpMiArIDIpICogMyArIDFdID0gcDIueTsKICAgICAgICBwb3NpdGlvbnNbKGkyICsgMykgKiAzICsgMV0gPSBwMi55OwogICAgICAgIGZvciAoajIgPSBpMCAqIDM7IGoyIDwgaTAgKiAzICsgNCAqIDM7IGoyICs9IDMpIHsKICAgICAgICAgIG5leHRQb3NpdGlvbnNbajJdID0gcG9zaXRpb25zWyhpMiArIDIpICogM107CiAgICAgICAgICBuZXh0UG9zaXRpb25zW2oyICsgMV0gPSBwb3NpdGlvbnNbKGkyICsgMikgKiAzICsgMV07CiAgICAgICAgICBuZXh0UG9zaXRpb25zW2oyICsgMl0gPSBwb3NpdGlvbnNbKGkyICsgMikgKiAzICsgMl07CiAgICAgICAgfQogICAgICB9CiAgICAgIGxldCBwMEF0dHJpYnV0ZXMgPSBlYXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgbGV0IHAwSW5kaWNlcyA9IGVhc3RHZW9tZXRyeS5pbmRpY2VzOwogICAgICBsZXQgcDJBdHRyaWJ1dGVzID0gd2VzdEdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgIGxldCBwMkluZGljZXMgPSB3ZXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgY29uc3QgaW50ZXJzZWN0aW9uID0gSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdC5saW5lU2VnbWVudFBsYW5lKAogICAgICAgIHAwLAogICAgICAgIHAyLAogICAgICAgIHh6UGxhbmUsCiAgICAgICAgY2FydGVzaWFuM1NjcmF0Y2g0CiAgICAgICk7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW50ZXJzZWN0aW9uKSkgewogICAgICAgIGludGVyc2VjdGlvbkZvdW5kID0gdHJ1ZTsKICAgICAgICBjb25zdCBvZmZzZXQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1ksCiAgICAgICAgICBvZmZzZXRTY2FsYXIsCiAgICAgICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDUKICAgICAgICApOwogICAgICAgIGlmIChwMC55IDwgMCkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShvZmZzZXQsIG9mZnNldCk7CiAgICAgICAgICBwMEF0dHJpYnV0ZXMgPSB3ZXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIHAwSW5kaWNlcyA9IHdlc3RHZW9tZXRyeS5pbmRpY2VzOwogICAgICAgICAgcDJBdHRyaWJ1dGVzID0gZWFzdEdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgICAgICBwMkluZGljZXMgPSBlYXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb2Zmc2V0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgaW50ZXJzZWN0aW9uLAogICAgICAgICAgb2Zmc2V0LAogICAgICAgICAgY2FydGVzaWFuM1NjcmF0Y2g2CiAgICAgICAgKTsKICAgICAgICBwMEF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLnB1c2gocDAueCwgcDAueSwgcDAueiwgcDAueCwgcDAueSwgcDAueik7CiAgICAgICAgcDBBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMEF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLnB1c2goCiAgICAgICAgICBvZmZzZXRQb2ludC54LAogICAgICAgICAgb2Zmc2V0UG9pbnQueSwKICAgICAgICAgIG9mZnNldFBvaW50LnoKICAgICAgICApOwogICAgICAgIHAwQXR0cmlidXRlcy5wcmV2UG9zaXRpb24udmFsdWVzLnB1c2goCiAgICAgICAgICBwcmV2UG9zaXRpb25zW2kwICogM10sCiAgICAgICAgICBwcmV2UG9zaXRpb25zW2kwICogMyArIDFdLAogICAgICAgICAgcHJldlBvc2l0aW9uc1tpMCAqIDMgKyAyXQogICAgICAgICk7CiAgICAgICAgcDBBdHRyaWJ1dGVzLnByZXZQb3NpdGlvbi52YWx1ZXMucHVzaCgKICAgICAgICAgIHByZXZQb3NpdGlvbnNbaTAgKiAzICsgM10sCiAgICAgICAgICBwcmV2UG9zaXRpb25zW2kwICogMyArIDRdLAogICAgICAgICAgcHJldlBvc2l0aW9uc1tpMCAqIDMgKyA1XQogICAgICAgICk7CiAgICAgICAgcDBBdHRyaWJ1dGVzLnByZXZQb3NpdGlvbi52YWx1ZXMucHVzaChwMC54LCBwMC55LCBwMC56LCBwMC54LCBwMC55LCBwMC56KTsKICAgICAgICBwMEF0dHJpYnV0ZXMubmV4dFBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMEF0dHJpYnV0ZXMubmV4dFBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMEF0dHJpYnV0ZXMubmV4dFBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMEF0dHJpYnV0ZXMubmV4dFBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKG9mZnNldCwgb2Zmc2V0KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGludGVyc2VjdGlvbiwgb2Zmc2V0LCBvZmZzZXRQb2ludCk7CiAgICAgICAgcDJBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMkF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLnB1c2goCiAgICAgICAgICBvZmZzZXRQb2ludC54LAogICAgICAgICAgb2Zmc2V0UG9pbnQueSwKICAgICAgICAgIG9mZnNldFBvaW50LnoKICAgICAgICApOwogICAgICAgIHAyQXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMucHVzaChwMi54LCBwMi55LCBwMi56LCBwMi54LCBwMi55LCBwMi56KTsKICAgICAgICBwMkF0dHJpYnV0ZXMucHJldlBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMkF0dHJpYnV0ZXMucHJldlBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMkF0dHJpYnV0ZXMucHJldlBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMkF0dHJpYnV0ZXMucHJldlBvc2l0aW9uLnZhbHVlcy5wdXNoKAogICAgICAgICAgb2Zmc2V0UG9pbnQueCwKICAgICAgICAgIG9mZnNldFBvaW50LnksCiAgICAgICAgICBvZmZzZXRQb2ludC56CiAgICAgICAgKTsKICAgICAgICBwMkF0dHJpYnV0ZXMubmV4dFBvc2l0aW9uLnZhbHVlcy5wdXNoKHAyLngsIHAyLnksIHAyLnosIHAyLngsIHAyLnksIHAyLnopOwogICAgICAgIHAyQXR0cmlidXRlcy5uZXh0UG9zaXRpb24udmFsdWVzLnB1c2goCiAgICAgICAgICBuZXh0UG9zaXRpb25zW2kyMiAqIDNdLAogICAgICAgICAgbmV4dFBvc2l0aW9uc1tpMjIgKiAzICsgMV0sCiAgICAgICAgICBuZXh0UG9zaXRpb25zW2kyMiAqIDMgKyAyXQogICAgICAgICk7CiAgICAgICAgcDJBdHRyaWJ1dGVzLm5leHRQb3NpdGlvbi52YWx1ZXMucHVzaCgKICAgICAgICAgIG5leHRQb3NpdGlvbnNbaTIyICogMyArIDNdLAogICAgICAgICAgbmV4dFBvc2l0aW9uc1tpMjIgKiAzICsgNF0sCiAgICAgICAgICBuZXh0UG9zaXRpb25zW2kyMiAqIDMgKyA1XQogICAgICAgICk7CiAgICAgICAgY29uc3QgZXcwID0gQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGV4cGFuZEFuZFdpZHRocywKICAgICAgICAgIGkwICogMiwKICAgICAgICAgIGNhcnRlc2lhbjJTY3JhdGNoMAogICAgICAgICk7CiAgICAgICAgY29uc3Qgd2lkdGggPSBNYXRoLmFicyhldzAueSk7CiAgICAgICAgcDBBdHRyaWJ1dGVzLmV4cGFuZEFuZFdpZHRoLnZhbHVlcy5wdXNoKC0xLCB3aWR0aCwgMSwgd2lkdGgpOwogICAgICAgIHAwQXR0cmlidXRlcy5leHBhbmRBbmRXaWR0aC52YWx1ZXMucHVzaCgtMSwgLXdpZHRoLCAxLCAtd2lkdGgpOwogICAgICAgIHAyQXR0cmlidXRlcy5leHBhbmRBbmRXaWR0aC52YWx1ZXMucHVzaCgtMSwgd2lkdGgsIDEsIHdpZHRoKTsKICAgICAgICBwMkF0dHJpYnV0ZXMuZXhwYW5kQW5kV2lkdGgudmFsdWVzLnB1c2goLTEsIC13aWR0aCwgMSwgLXdpZHRoKTsKICAgICAgICBsZXQgdDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChpbnRlcnNlY3Rpb24sIHAwLCBjYXJ0ZXNpYW4zU2NyYXRjaDMpCiAgICAgICAgKTsKICAgICAgICB0MiAvPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwMiwgcDAsIGNhcnRlc2lhbjNTY3JhdGNoMykKICAgICAgICApOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSkgewogICAgICAgICAgY29uc3QgYzAgPSBDYXJ0ZXNpYW40X2RlZmF1bHQuZnJvbUFycmF5KGNvbG9ycywgaTAgKiA0LCBjYXJ0ZXNpYW40U2NyYXRjaDApOwogICAgICAgICAgY29uc3QgYzIgPSBDYXJ0ZXNpYW40X2RlZmF1bHQuZnJvbUFycmF5KGNvbG9ycywgaTIyICogNCwgY2FydGVzaWFuNFNjcmF0Y2gwKTsKICAgICAgICAgIGNvbnN0IHIyID0gTWF0aF9kZWZhdWx0LmxlcnAoYzAueCwgYzIueCwgdDIpOwogICAgICAgICAgY29uc3QgZzIgPSBNYXRoX2RlZmF1bHQubGVycChjMC55LCBjMi55LCB0Mik7CiAgICAgICAgICBjb25zdCBiMiA9IE1hdGhfZGVmYXVsdC5sZXJwKGMwLnosIGMyLnosIHQyKTsKICAgICAgICAgIGNvbnN0IGE0ID0gTWF0aF9kZWZhdWx0LmxlcnAoYzAudywgYzIudywgdDIpOwogICAgICAgICAgZm9yIChqMiA9IGkwICogNDsgajIgPCBpMCAqIDQgKyAyICogNDsgKytqMikgewogICAgICAgICAgICBwMEF0dHJpYnV0ZXMuY29sb3IudmFsdWVzLnB1c2goY29sb3JzW2oyXSk7CiAgICAgICAgICB9CiAgICAgICAgICBwMEF0dHJpYnV0ZXMuY29sb3IudmFsdWVzLnB1c2gocjIsIGcyLCBiMiwgYTQpOwogICAgICAgICAgcDBBdHRyaWJ1dGVzLmNvbG9yLnZhbHVlcy5wdXNoKHIyLCBnMiwgYjIsIGE0KTsKICAgICAgICAgIHAyQXR0cmlidXRlcy5jb2xvci52YWx1ZXMucHVzaChyMiwgZzIsIGIyLCBhNCk7CiAgICAgICAgICBwMkF0dHJpYnV0ZXMuY29sb3IudmFsdWVzLnB1c2gocjIsIGcyLCBiMiwgYTQpOwogICAgICAgICAgZm9yIChqMiA9IGkyMiAqIDQ7IGoyIDwgaTIyICogNCArIDIgKiA0OyArK2oyKSB7CiAgICAgICAgICAgIHAyQXR0cmlidXRlcy5jb2xvci52YWx1ZXMucHVzaChjb2xvcnNbajJdKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh0ZXhDb29yZHMpKSB7CiAgICAgICAgICBjb25zdCBzMCA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tQXJyYXkodGV4Q29vcmRzLCBpMCAqIDIsIGNhcnRlc2lhbjJTY3JhdGNoMCk7CiAgICAgICAgICBjb25zdCBzMyA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHRleENvb3JkcywKICAgICAgICAgICAgKGkyICsgMykgKiAyLAogICAgICAgICAgICBjYXJ0ZXNpYW4yU2NyYXRjaDEKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBzeCA9IE1hdGhfZGVmYXVsdC5sZXJwKHMwLngsIHMzLngsIHQyKTsKICAgICAgICAgIGZvciAoajIgPSBpMCAqIDI7IGoyIDwgaTAgKiAyICsgMiAqIDI7ICsrajIpIHsKICAgICAgICAgICAgcDBBdHRyaWJ1dGVzLnN0LnZhbHVlcy5wdXNoKHRleENvb3Jkc1tqMl0pOwogICAgICAgICAgfQogICAgICAgICAgcDBBdHRyaWJ1dGVzLnN0LnZhbHVlcy5wdXNoKHN4LCBzMC55KTsKICAgICAgICAgIHAwQXR0cmlidXRlcy5zdC52YWx1ZXMucHVzaChzeCwgczMueSk7CiAgICAgICAgICBwMkF0dHJpYnV0ZXMuc3QudmFsdWVzLnB1c2goc3gsIHMwLnkpOwogICAgICAgICAgcDJBdHRyaWJ1dGVzLnN0LnZhbHVlcy5wdXNoKHN4LCBzMy55KTsKICAgICAgICAgIGZvciAoajIgPSBpMjIgKiAyOyBqMiA8IGkyMiAqIDIgKyAyICogMjsgKytqMikgewogICAgICAgICAgICBwMkF0dHJpYnV0ZXMuc3QudmFsdWVzLnB1c2godGV4Q29vcmRzW2oyXSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGluZGV4ID0gcDBBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGggLyAzIC0gNDsKICAgICAgICBwMEluZGljZXMucHVzaChpbmRleCwgaW5kZXggKyAyLCBpbmRleCArIDEpOwogICAgICAgIHAwSW5kaWNlcy5wdXNoKGluZGV4ICsgMSwgaW5kZXggKyAyLCBpbmRleCArIDMpOwogICAgICAgIGluZGV4ID0gcDJBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGggLyAzIC0gNDsKICAgICAgICBwMkluZGljZXMucHVzaChpbmRleCwgaW5kZXggKyAyLCBpbmRleCArIDEpOwogICAgICAgIHAySW5kaWNlcy5wdXNoKGluZGV4ICsgMSwgaW5kZXggKyAyLCBpbmRleCArIDMpOwogICAgICB9IGVsc2UgewogICAgICAgIGxldCBjdXJyZW50QXR0cmlidXRlczsKICAgICAgICBsZXQgY3VycmVudEluZGljZXM7CiAgICAgICAgaWYgKHAwLnkgPCAwKSB7CiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcyA9IHdlc3RHZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgICAgY3VycmVudEluZGljZXMgPSB3ZXN0R2VvbWV0cnkuaW5kaWNlczsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY3VycmVudEF0dHJpYnV0ZXMgPSBlYXN0R2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIGN1cnJlbnRJbmRpY2VzID0gZWFzdEdlb21ldHJ5LmluZGljZXM7CiAgICAgICAgfQogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKHAwLngsIHAwLnksIHAwLnopOwogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKHAwLngsIHAwLnksIHAwLnopOwogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKHAyLngsIHAyLnksIHAyLnopOwogICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5wdXNoKHAyLngsIHAyLnksIHAyLnopOwogICAgICAgIGZvciAoajIgPSBpMiAqIDM7IGoyIDwgaTIgKiAzICsgNCAqIDM7ICsrajIpIHsKICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLnByZXZQb3NpdGlvbi52YWx1ZXMucHVzaChwcmV2UG9zaXRpb25zW2oyXSk7CiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcy5uZXh0UG9zaXRpb24udmFsdWVzLnB1c2gobmV4dFBvc2l0aW9uc1tqMl0pOwogICAgICAgIH0KICAgICAgICBmb3IgKGoyID0gaTIgKiAyOyBqMiA8IGkyICogMiArIDQgKiAyOyArK2oyKSB7CiAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcy5leHBhbmRBbmRXaWR0aC52YWx1ZXMucHVzaChleHBhbmRBbmRXaWR0aHNbajJdKTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGV4Q29vcmRzKSkgewogICAgICAgICAgICBjdXJyZW50QXR0cmlidXRlcy5zdC52YWx1ZXMucHVzaCh0ZXhDb29yZHNbajJdKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjb2xvcnMpKSB7CiAgICAgICAgICBmb3IgKGoyID0gaTIgKiA0OyBqMiA8IGkyICogNCArIDQgKiA0OyArK2oyKSB7CiAgICAgICAgICAgIGN1cnJlbnRBdHRyaWJ1dGVzLmNvbG9yLnZhbHVlcy5wdXNoKGNvbG9yc1tqMl0pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpbmRleCA9IGN1cnJlbnRBdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGggLyAzIC0gNDsKICAgICAgICBjdXJyZW50SW5kaWNlcy5wdXNoKGluZGV4LCBpbmRleCArIDIsIGluZGV4ICsgMSk7CiAgICAgICAgY3VycmVudEluZGljZXMucHVzaChpbmRleCArIDEsIGluZGV4ICsgMiwgaW5kZXggKyAzKTsKICAgICAgfQogICAgfQogICAgaWYgKGludGVyc2VjdGlvbkZvdW5kKSB7CiAgICAgIHVwZGF0ZUFkamFjZW5jeUFmdGVyU3BsaXQod2VzdEdlb21ldHJ5KTsKICAgICAgdXBkYXRlQWRqYWNlbmN5QWZ0ZXJTcGxpdChlYXN0R2VvbWV0cnkpOwogICAgfQogICAgdXBkYXRlSW5zdGFuY2VBZnRlclNwbGl0KGluc3RhbmNlLCB3ZXN0R2VvbWV0cnksIGVhc3RHZW9tZXRyeSk7CiAgfQogIHZhciBHZW9tZXRyeVBpcGVsaW5lLCBzY3JhdGNoUHJvamVjdFRvMkRDYXJ0ZXNpYW4zLCBzY3JhdGNoUHJvamVjdFRvMkRDYXJ0b2dyYXBoaWMsIGVuY29kZWRSZXN1bHQsIHNjcmF0Y2hDYXJ0ZXNpYW4zMywgaW52ZXJzZVRyYW5zcG9zZSwgbm9ybWFsTWF0cml4LCB0ZW1wU2NyYXRjaCwgbm9ybWFsLCB2MCwgdjEsIHYyLCBub3JtYWxTY3JhdGNoMiwgbm9ybWFsU2NhbGUsIHRTY3JhdGNoLCBzY3JhdGNoQ2FydGVzaWFuMjIsIHRvRW5jb2RlMSwgdG9FbmNvZGUyLCB0b0VuY29kZTMsIGVuY29kZVJlc3VsdDIsIGMzLCB1MSwgdTIsIHExLCBxMiwgc3BsaXRUcmlhbmdsZVJlc3VsdCwgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuNCwgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuMywgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuMiwgaW50ZXJwb2xhdGVBbmRQYWNrQm9vbGVhbiwgcDBTY3JhdGNoLCBwMVNjcmF0Y2gsIHAyU2NyYXRjaCwgYmFyeWNlbnRyaWNTY3JhdGNoLCBOQU1FRF9BVFRSSUJVVEVTLCB4elBsYW5lLCBvZmZzZXRTY3JhdGNoLCBvZmZzZXRQb2ludFNjcmF0Y2gsIGNhcnRlc2lhbjJTY3JhdGNoMCwgY2FydGVzaWFuMlNjcmF0Y2gxLCBjYXJ0ZXNpYW4zU2NyYXRjaDAsIGNhcnRlc2lhbjNTY3JhdGNoMiwgY2FydGVzaWFuM1NjcmF0Y2gzLCBjYXJ0ZXNpYW4zU2NyYXRjaDQsIGNhcnRlc2lhbjNTY3JhdGNoNSwgY2FydGVzaWFuM1NjcmF0Y2g2LCBjYXJ0ZXNpYW40U2NyYXRjaDAsIG9mZnNldFNjYWxhciwgY29wbGFuYXJPZmZzZXQsIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeVBpcGVsaW5lID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9tZXRyeVBpcGVsaW5lLmpzIigpIHsKICAgICAgaW5pdF9BdHRyaWJ1dGVDb21wcmVzc2lvbigpOwogICAgICBpbml0X2JhcnljZW50cmljQ29vcmRpbmF0ZXMoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuNCgpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRW5jb2RlZENhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9HZW9ncmFwaGljUHJvamVjdGlvbigpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeVR5cGUoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0KCk7CiAgICAgIGluaXRfSW50ZXJzZWN0aW9uVGVzdHMoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9QbGFuZSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9UaXBzaWZ5KCk7CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUgPSB7fTsKICAgICAgR2VvbWV0cnlQaXBlbGluZS50b1dpcmVmcmFtZSA9IGZ1bmN0aW9uKGdlb21ldHJ5KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ2VvbWV0cnkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGluZGljZXMgPSBnZW9tZXRyeS5pbmRpY2VzOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5kaWNlcykpIHsKICAgICAgICAgIHN3aXRjaCAoZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSkgewogICAgICAgICAgICBjYXNlIFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVM6CiAgICAgICAgICAgICAgZ2VvbWV0cnkuaW5kaWNlcyA9IHRyaWFuZ2xlc1RvTGluZXMoaW5kaWNlcyk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFX1NUUklQOgogICAgICAgICAgICAgIGdlb21ldHJ5LmluZGljZXMgPSB0cmlhbmdsZVN0cmlwVG9MaW5lcyhpbmRpY2VzKTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVfRkFOOgogICAgICAgICAgICAgIGdlb21ldHJ5LmluZGljZXMgPSB0cmlhbmdsZUZhblRvTGluZXMoaW5kaWNlcyk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIC8vPj5pbmNsdWRlU3RhcnQoJ2RlYnVnJywgcHJhZ21hcy5kZWJ1Zyk7CiAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgICAiZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSBtdXN0IGJlIFRSSUFOR0xFUywgVFJJQU5HTEVfU1RSSVAsIG9yIFRSSUFOR0xFX0ZBTi4iCiAgICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUgPSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVM7CiAgICAgICAgfQogICAgICAgIHJldHVybiBnZW9tZXRyeTsKICAgICAgfTsKICAgICAgR2VvbWV0cnlQaXBlbGluZS5jcmVhdGVMaW5lU2VnbWVudHNGb3JWZWN0b3JzID0gZnVuY3Rpb24oZ2VvbWV0cnksIGF0dHJpYnV0ZU5hbWUsIGxlbmd0aCkgewogICAgICAgIGF0dHJpYnV0ZU5hbWUgPSBhdHRyaWJ1dGVOYW1lID8/ICJub3JtYWwiOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgYGdlb21ldHJ5LmF0dHJpYnV0ZXMgbXVzdCBoYXZlIGFuIGF0dHJpYnV0ZSB3aXRoIHRoZSBzYW1lIG5hbWUgYXMgdGhlIGF0dHJpYnV0ZU5hbWUgcGFyYW1ldGVyLCAke2F0dHJpYnV0ZU5hbWV9LmAKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGxlbmd0aCA9IGxlbmd0aCA/PyAxZTQ7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXM7CiAgICAgICAgY29uc3QgdmVjdG9ycyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0udmFsdWVzOwogICAgICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3QgbmV3UG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSgyICogcG9zaXRpb25zTGVuZ3RoKTsKICAgICAgICBsZXQgajIgPSAwOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7IGkyICs9IDMpIHsKICAgICAgICAgIG5ld1Bvc2l0aW9uc1tqMisrXSA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICBuZXdQb3NpdGlvbnNbajIrK10gPSBwb3NpdGlvbnNbaTIgKyAxXTsKICAgICAgICAgIG5ld1Bvc2l0aW9uc1tqMisrXSA9IHBvc2l0aW9uc1tpMiArIDJdOwogICAgICAgICAgbmV3UG9zaXRpb25zW2oyKytdID0gcG9zaXRpb25zW2kyXSArIHZlY3RvcnNbaTJdICogbGVuZ3RoOwogICAgICAgICAgbmV3UG9zaXRpb25zW2oyKytdID0gcG9zaXRpb25zW2kyICsgMV0gKyB2ZWN0b3JzW2kyICsgMV0gKiBsZW5ndGg7CiAgICAgICAgICBuZXdQb3NpdGlvbnNbajIrK10gPSBwb3NpdGlvbnNbaTIgKyAyXSArIHZlY3RvcnNbaTIgKyAyXSAqIGxlbmd0aDsKICAgICAgICB9CiAgICAgICAgbGV0IG5ld0JvdW5kaW5nU3BoZXJlOwogICAgICAgIGNvbnN0IGJzID0gZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmU7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChicykpIHsKICAgICAgICAgIG5ld0JvdW5kaW5nU3BoZXJlID0gbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoYnMuY2VudGVyLCBicy5yYWRpdXMgKyBsZW5ndGgpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlczogewogICAgICAgICAgICBwb3NpdGlvbjogbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICAgIHZhbHVlczogbmV3UG9zaXRpb25zCiAgICAgICAgICAgIH0pCiAgICAgICAgICB9LAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IG5ld0JvdW5kaW5nU3BoZXJlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUuY3JlYXRlQXR0cmlidXRlTG9jYXRpb25zID0gZnVuY3Rpb24oZ2VvbWV0cnkpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJnZW9tZXRyeSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3Qgc2VtYW50aWNzID0gWwogICAgICAgICAgInBvc2l0aW9uIiwKICAgICAgICAgICJwb3NpdGlvbkhpZ2giLAogICAgICAgICAgInBvc2l0aW9uTG93IiwKICAgICAgICAgIC8vIEZyb20gVmVydGV4Rm9ybWF0LnBvc2l0aW9uIC0gYWZ0ZXIgMkQgcHJvamVjdGlvbiBhbmQgaGlnaC1wcmVjaXNpb24gZW5jb2RpbmcKICAgICAgICAgICJwb3NpdGlvbjNESGlnaCIsCiAgICAgICAgICAicG9zaXRpb24zRExvdyIsCiAgICAgICAgICAicG9zaXRpb24yREhpZ2giLAogICAgICAgICAgInBvc2l0aW9uMkRMb3ciLAogICAgICAgICAgLy8gRnJvbSBQcmltaXRpdmUKICAgICAgICAgICJwaWNrQ29sb3IiLAogICAgICAgICAgLy8gRnJvbSBWZXJ0ZXhGb3JtYXQKICAgICAgICAgICJub3JtYWwiLAogICAgICAgICAgInN0IiwKICAgICAgICAgICJ0YW5nZW50IiwKICAgICAgICAgICJiaXRhbmdlbnQiLAogICAgICAgICAgLy8gRm9yIHNoYWRvdyB2b2x1bWVzCiAgICAgICAgICAiZXh0cnVkZURpcmVjdGlvbiIsCiAgICAgICAgICAvLyBGcm9tIGNvbXByZXNzaW5nIHRleHR1cmUgY29vcmRpbmF0ZXMgYW5kIG5vcm1hbHMKICAgICAgICAgICJjb21wcmVzc2VkQXR0cmlidXRlcyIKICAgICAgICBdOwogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgIGNvbnN0IGluZGljZXMgPSB7fTsKICAgICAgICBsZXQgajIgPSAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBsZW4gPSBzZW1hbnRpY3MubGVuZ3RoOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbjsgKytpMikgewogICAgICAgICAgY29uc3Qgc2VtYW50aWMgPSBzZW1hbnRpY3NbaTJdOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzW3NlbWFudGljXSkpIHsKICAgICAgICAgICAgaW5kaWNlc1tzZW1hbnRpY10gPSBqMisrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBmb3IgKGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcykgewogICAgICAgICAgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkobmFtZSkgJiYgIWRlZmluZWRfZGVmYXVsdChpbmRpY2VzW25hbWVdKSkgewogICAgICAgICAgICBpbmRpY2VzW25hbWVdID0gajIrKzsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGluZGljZXM7CiAgICAgIH07CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUucmVvcmRlckZvclByZVZlcnRleENhY2hlID0gZnVuY3Rpb24oZ2VvbWV0cnkpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJnZW9tZXRyeSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbnVtVmVydGljZXMgPSBHZW9tZXRyeV9kZWZhdWx0LmNvbXB1dGVOdW1iZXJPZlZlcnRpY2VzKGdlb21ldHJ5KTsKICAgICAgICBjb25zdCBpbmRpY2VzID0gZ2VvbWV0cnkuaW5kaWNlczsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluZGljZXMpKSB7CiAgICAgICAgICBjb25zdCBpbmRleENyb3NzUmVmZXJlbmNlT2xkVG9OZXcgPSBuZXcgSW50MzJBcnJheShudW1WZXJ0aWNlcyk7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtVmVydGljZXM7IGkyKyspIHsKICAgICAgICAgICAgaW5kZXhDcm9zc1JlZmVyZW5jZU9sZFRvTmV3W2kyXSA9IC0xOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgaW5kaWNlc0luID0gaW5kaWNlczsKICAgICAgICAgIGNvbnN0IG51bUluZGljZXMgPSBpbmRpY2VzSW4ubGVuZ3RoOwogICAgICAgICAgY29uc3QgaW5kaWNlc091dCA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KG51bVZlcnRpY2VzLCBudW1JbmRpY2VzKTsKICAgICAgICAgIGxldCBpbnRvSW5kaWNlc0luID0gMDsKICAgICAgICAgIGxldCBpbnRvSW5kaWNlc091dCA9IDA7CiAgICAgICAgICBsZXQgbmV4dEluZGV4ID0gMDsKICAgICAgICAgIGxldCB0ZW1wSW5kZXg7CiAgICAgICAgICB3aGlsZSAoaW50b0luZGljZXNJbiA8IG51bUluZGljZXMpIHsKICAgICAgICAgICAgdGVtcEluZGV4ID0gaW5kZXhDcm9zc1JlZmVyZW5jZU9sZFRvTmV3W2luZGljZXNJbltpbnRvSW5kaWNlc0luXV07CiAgICAgICAgICAgIGlmICh0ZW1wSW5kZXggIT09IC0xKSB7CiAgICAgICAgICAgICAgaW5kaWNlc091dFtpbnRvSW5kaWNlc091dF0gPSB0ZW1wSW5kZXg7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdGVtcEluZGV4ID0gaW5kaWNlc0luW2ludG9JbmRpY2VzSW5dOwogICAgICAgICAgICAgIGluZGV4Q3Jvc3NSZWZlcmVuY2VPbGRUb05ld1t0ZW1wSW5kZXhdID0gbmV4dEluZGV4OwogICAgICAgICAgICAgIGluZGljZXNPdXRbaW50b0luZGljZXNPdXRdID0gbmV4dEluZGV4OwogICAgICAgICAgICAgICsrbmV4dEluZGV4OwogICAgICAgICAgICB9CiAgICAgICAgICAgICsraW50b0luZGljZXNJbjsKICAgICAgICAgICAgKytpbnRvSW5kaWNlc091dDsKICAgICAgICAgIH0KICAgICAgICAgIGdlb21ldHJ5LmluZGljZXMgPSBpbmRpY2VzT3V0OwogICAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5IGluIGF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkocHJvcGVydHkpICYmIGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzW3Byb3BlcnR5XSkgJiYgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXNbcHJvcGVydHldLnZhbHVlcykpIHsKICAgICAgICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzW3Byb3BlcnR5XTsKICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c0luID0gYXR0cmlidXRlLnZhbHVlczsKICAgICAgICAgICAgICBsZXQgaW50b0VsZW1lbnRzSW4gPSAwOwogICAgICAgICAgICAgIGNvbnN0IG51bUNvbXBvbmVudHMgPSBhdHRyaWJ1dGUuY29tcG9uZW50c1BlckF0dHJpYnV0ZTsKICAgICAgICAgICAgICBjb25zdCBlbGVtZW50c091dCA9IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgICAgICAgIGF0dHJpYnV0ZS5jb21wb25lbnREYXRhdHlwZSwKICAgICAgICAgICAgICAgIG5leHRJbmRleCAqIG51bUNvbXBvbmVudHMKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIHdoaWxlIChpbnRvRWxlbWVudHNJbiA8IG51bVZlcnRpY2VzKSB7CiAgICAgICAgICAgICAgICBjb25zdCB0ZW1wID0gaW5kZXhDcm9zc1JlZmVyZW5jZU9sZFRvTmV3W2ludG9FbGVtZW50c0luXTsKICAgICAgICAgICAgICAgIGlmICh0ZW1wICE9PSAtMSkgewogICAgICAgICAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgbnVtQ29tcG9uZW50czsgajIrKykgewogICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzT3V0W251bUNvbXBvbmVudHMgKiB0ZW1wICsgajJdID0gZWxlbWVudHNJbltudW1Db21wb25lbnRzICogaW50b0VsZW1lbnRzSW4gKyBqMl07CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICsraW50b0VsZW1lbnRzSW47CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGF0dHJpYnV0ZS52YWx1ZXMgPSBlbGVtZW50c091dDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgIH07CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUucmVvcmRlckZvclBvc3RWZXJ0ZXhDYWNoZSA9IGZ1bmN0aW9uKGdlb21ldHJ5LCBjYWNoZUNhcGFjaXR5KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ2VvbWV0cnkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGluZGljZXMgPSBnZW9tZXRyeS5pbmRpY2VzOwogICAgICAgIGlmIChnZW9tZXRyeS5wcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTICYmIGRlZmluZWRfZGVmYXVsdChpbmRpY2VzKSkgewogICAgICAgICAgY29uc3QgbnVtSW5kaWNlcyA9IGluZGljZXMubGVuZ3RoOwogICAgICAgICAgbGV0IG1heGltdW1JbmRleCA9IDA7CiAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgbnVtSW5kaWNlczsgajIrKykgewogICAgICAgICAgICBpZiAoaW5kaWNlc1tqMl0gPiBtYXhpbXVtSW5kZXgpIHsKICAgICAgICAgICAgICBtYXhpbXVtSW5kZXggPSBpbmRpY2VzW2oyXTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZ2VvbWV0cnkuaW5kaWNlcyA9IFRpcHNpZnlfZGVmYXVsdC50aXBzaWZ5KHsKICAgICAgICAgICAgaW5kaWNlcywKICAgICAgICAgICAgbWF4aW11bUluZGV4LAogICAgICAgICAgICBjYWNoZVNpemU6IGNhY2hlQ2FwYWNpdHkKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgIH07CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUuZml0VG9VbnNpZ25lZFNob3J0SW5kaWNlcyA9IGZ1bmN0aW9uKGdlb21ldHJ5KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ2VvbWV0cnkgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkuaW5kaWNlcykgJiYgZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSAhPT0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUyAmJiBnZW9tZXRyeS5wcmltaXRpdmVUeXBlICE9PSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMgJiYgZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSAhPT0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlBPSU5UUykgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJnZW9tZXRyeS5wcmltaXRpdmVUeXBlIG11c3QgZXF1YWwgdG8gUHJpbWl0aXZlVHlwZS5UUklBTkdMRVMsIFByaW1pdGl2ZVR5cGUuTElORVMsIG9yIFByaW1pdGl2ZVR5cGUuUE9JTlRTLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJpZXMgPSBbXTsKICAgICAgICBjb25zdCBudW1iZXJPZlZlcnRpY2VzID0gR2VvbWV0cnlfZGVmYXVsdC5jb21wdXRlTnVtYmVyT2ZWZXJ0aWNlcyhnZW9tZXRyeSk7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5pbmRpY2VzKSAmJiBudW1iZXJPZlZlcnRpY2VzID49IE1hdGhfZGVmYXVsdC5TSVhUWV9GT1VSX0tJTE9CWVRFUykgewogICAgICAgICAgbGV0IG9sZFRvTmV3SW5kZXggPSBbXTsKICAgICAgICAgIGxldCBuZXdJbmRpY2VzID0gW107CiAgICAgICAgICBsZXQgY3VycmVudEluZGV4ID0gMDsKICAgICAgICAgIGxldCBuZXdBdHRyaWJ1dGVzID0gY29weUF0dHJpYnV0ZXNEZXNjcmlwdGlvbnMoZ2VvbWV0cnkuYXR0cmlidXRlcyk7CiAgICAgICAgICBjb25zdCBvcmlnaW5hbEluZGljZXMgPSBnZW9tZXRyeS5pbmRpY2VzOwogICAgICAgICAgY29uc3QgbnVtYmVyT2ZJbmRpY2VzID0gb3JpZ2luYWxJbmRpY2VzLmxlbmd0aDsKICAgICAgICAgIGxldCBpbmRpY2VzUGVyUHJpbWl0aXZlOwogICAgICAgICAgaWYgKGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUgPT09IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMpIHsKICAgICAgICAgICAgaW5kaWNlc1BlclByaW1pdGl2ZSA9IDM7CiAgICAgICAgICB9IGVsc2UgaWYgKGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUgPT09IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5MSU5FUykgewogICAgICAgICAgICBpbmRpY2VzUGVyUHJpbWl0aXZlID0gMjsKICAgICAgICAgIH0gZWxzZSBpZiAoZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSA9PT0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlBPSU5UUykgewogICAgICAgICAgICBpbmRpY2VzUGVyUHJpbWl0aXZlID0gMTsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCBudW1iZXJPZkluZGljZXM7IGoyICs9IGluZGljZXNQZXJQcmltaXRpdmUpIHsKICAgICAgICAgICAgZm9yIChsZXQgazIgPSAwOyBrMiA8IGluZGljZXNQZXJQcmltaXRpdmU7ICsrazIpIHsKICAgICAgICAgICAgICBjb25zdCB4MiA9IG9yaWdpbmFsSW5kaWNlc1tqMiArIGsyXTsKICAgICAgICAgICAgICBsZXQgaTIgPSBvbGRUb05ld0luZGV4W3gyXTsKICAgICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpMikpIHsKICAgICAgICAgICAgICAgIGkyID0gY3VycmVudEluZGV4Kys7CiAgICAgICAgICAgICAgICBvbGRUb05ld0luZGV4W3gyXSA9IGkyOwogICAgICAgICAgICAgICAgY29weVZlcnRleChuZXdBdHRyaWJ1dGVzLCBnZW9tZXRyeS5hdHRyaWJ1dGVzLCB4Mik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIG5ld0luZGljZXMucHVzaChpMik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGN1cnJlbnRJbmRleCArIGluZGljZXNQZXJQcmltaXRpdmUgPj0gTWF0aF9kZWZhdWx0LlNJWFRZX0ZPVVJfS0lMT0JZVEVTKSB7CiAgICAgICAgICAgICAgZ2VvbWV0cmllcy5wdXNoKAogICAgICAgICAgICAgICAgbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzOiBuZXdBdHRyaWJ1dGVzLAogICAgICAgICAgICAgICAgICBpbmRpY2VzOiBuZXdJbmRpY2VzLAogICAgICAgICAgICAgICAgICBwcmltaXRpdmVUeXBlOiBnZW9tZXRyeS5wcmltaXRpdmVUeXBlLAogICAgICAgICAgICAgICAgICBib3VuZGluZ1NwaGVyZTogZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUsCiAgICAgICAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlQ1Y6IGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlQ1YKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBvbGRUb05ld0luZGV4ID0gW107CiAgICAgICAgICAgICAgbmV3SW5kaWNlcyA9IFtdOwogICAgICAgICAgICAgIGN1cnJlbnRJbmRleCA9IDA7CiAgICAgICAgICAgICAgbmV3QXR0cmlidXRlcyA9IGNvcHlBdHRyaWJ1dGVzRGVzY3JpcHRpb25zKGdlb21ldHJ5LmF0dHJpYnV0ZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobmV3SW5kaWNlcy5sZW5ndGggIT09IDApIHsKICAgICAgICAgICAgZ2VvbWV0cmllcy5wdXNoKAogICAgICAgICAgICAgIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXM6IG5ld0F0dHJpYnV0ZXMsCiAgICAgICAgICAgICAgICBpbmRpY2VzOiBuZXdJbmRpY2VzLAogICAgICAgICAgICAgICAgcHJpbWl0aXZlVHlwZTogZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSwKICAgICAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlOiBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSwKICAgICAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlQ1Y6IGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlQ1YKICAgICAgICAgICAgICB9KQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBnZW9tZXRyaWVzLnB1c2goZ2VvbWV0cnkpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZ2VvbWV0cmllczsKICAgICAgfTsKICAgICAgc2NyYXRjaFByb2plY3RUbzJEQ2FydGVzaWFuMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFByb2plY3RUbzJEQ2FydG9ncmFwaGljID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUucHJvamVjdFRvMkQgPSBmdW5jdGlvbihnZW9tZXRyeSwgYXR0cmlidXRlTmFtZSwgYXR0cmlidXRlTmFtZTNELCBhdHRyaWJ1dGVOYW1lMkQsIHByb2plY3Rpb24pIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJnZW9tZXRyeSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlTmFtZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhdHRyaWJ1dGVOYW1lIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVOYW1lM0QpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXR0cmlidXRlTmFtZTNEIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVOYW1lMkQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXR0cmlidXRlTmFtZTJEIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5hdHRyaWJ1dGVzW2F0dHJpYnV0ZU5hbWVdKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgIGBnZW9tZXRyeSBtdXN0IGhhdmUgYXR0cmlidXRlIG1hdGNoaW5nIHRoZSBhdHRyaWJ1dGVOYW1lIGFyZ3VtZW50OiAke2F0dHJpYnV0ZU5hbWV9LmAKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGlmIChnZW9tZXRyeS5hdHRyaWJ1dGVzW2F0dHJpYnV0ZU5hbWVdLmNvbXBvbmVudERhdGF0eXBlICE9PSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJUaGUgYXR0cmlidXRlIGNvbXBvbmVudERhdGF0eXBlIG11c3QgYmUgQ29tcG9uZW50RGF0YXR5cGUuRE9VQkxFLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV07CiAgICAgICAgcHJvamVjdGlvbiA9IGRlZmluZWRfZGVmYXVsdChwcm9qZWN0aW9uKSA/IHByb2plY3Rpb24gOiBuZXcgR2VvZ3JhcGhpY1Byb2plY3Rpb25fZGVmYXVsdCgpOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHByb2plY3Rpb24uZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IHZhbHVlczNEID0gYXR0cmlidXRlLnZhbHVlczsKICAgICAgICBjb25zdCBwcm9qZWN0ZWRWYWx1ZXMgPSBuZXcgRmxvYXQ2NEFycmF5KHZhbHVlczNELmxlbmd0aCk7CiAgICAgICAgbGV0IGluZGV4ID0gMDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgdmFsdWVzM0QubGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgICAgICBjb25zdCB2YWx1ZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHZhbHVlczNELAogICAgICAgICAgICBpMiwKICAgICAgICAgICAgc2NyYXRjaFByb2plY3RUbzJEQ2FydGVzaWFuMwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IGxvbkxhdCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICAgICAgdmFsdWUsCiAgICAgICAgICAgIHNjcmF0Y2hQcm9qZWN0VG8yRENhcnRvZ3JhcGhpYwogICAgICAgICAgKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxvbkxhdCkpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICAgYENvdWxkIG5vdCBwcm9qZWN0IHBvaW50ICgke3ZhbHVlLnh9LCAke3ZhbHVlLnl9LCAke3ZhbHVlLnp9KSB0byAyRC5gCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBwcm9qZWN0ZWRMb25MYXQgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgICAgICAgIGxvbkxhdCwKICAgICAgICAgICAgc2NyYXRjaFByb2plY3RUbzJEQ2FydGVzaWFuMwogICAgICAgICAgKTsKICAgICAgICAgIHByb2plY3RlZFZhbHVlc1tpbmRleCsrXSA9IHByb2plY3RlZExvbkxhdC54OwogICAgICAgICAgcHJvamVjdGVkVmFsdWVzW2luZGV4KytdID0gcHJvamVjdGVkTG9uTGF0Lnk7CiAgICAgICAgICBwcm9qZWN0ZWRWYWx1ZXNbaW5kZXgrK10gPSBwcm9qZWN0ZWRMb25MYXQuejsKICAgICAgICB9CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlc1thdHRyaWJ1dGVOYW1lM0RdID0gYXR0cmlidXRlOwogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZTJEXSA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IHByb2plY3RlZFZhbHVlcwogICAgICAgIH0pOwogICAgICAgIGRlbGV0ZSBnZW9tZXRyeS5hdHRyaWJ1dGVzW2F0dHJpYnV0ZU5hbWVdOwogICAgICAgIHJldHVybiBnZW9tZXRyeTsKICAgICAgfTsKICAgICAgZW5jb2RlZFJlc3VsdCA9IHsKICAgICAgICBoaWdoOiAwLAogICAgICAgIGxvdzogMAogICAgICB9OwogICAgICBHZW9tZXRyeVBpcGVsaW5lLmVuY29kZUF0dHJpYnV0ZSA9IGZ1bmN0aW9uKGdlb21ldHJ5LCBhdHRyaWJ1dGVOYW1lLCBhdHRyaWJ1dGVIaWdoTmFtZSwgYXR0cmlidXRlTG93TmFtZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVOYW1lKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZU5hbWUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZUhpZ2hOYW1lKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZUhpZ2hOYW1lIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVMb3dOYW1lKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImF0dHJpYnV0ZUxvd05hbWUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgYGdlb21ldHJ5IG11c3QgaGF2ZSBhdHRyaWJ1dGUgbWF0Y2hpbmcgdGhlIGF0dHJpYnV0ZU5hbWUgYXJndW1lbnQ6ICR7YXR0cmlidXRlTmFtZX0uYAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgaWYgKGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV0uY29tcG9uZW50RGF0YXR5cGUgIT09IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgIlRoZSBhdHRyaWJ1dGUgY29tcG9uZW50RGF0YXR5cGUgbXVzdCBiZSBDb21wb25lbnREYXRhdHlwZS5ET1VCTEUuIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlc1thdHRyaWJ1dGVOYW1lXTsKICAgICAgICBjb25zdCB2YWx1ZXMgPSBhdHRyaWJ1dGUudmFsdWVzOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IHZhbHVlcy5sZW5ndGg7CiAgICAgICAgY29uc3QgaGlnaFZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKTsKICAgICAgICBjb25zdCBsb3dWYWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KGxlbmd0aCk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgRW5jb2RlZENhcnRlc2lhbjNfZGVmYXVsdC5lbmNvZGUodmFsdWVzW2kyXSwgZW5jb2RlZFJlc3VsdCk7CiAgICAgICAgICBoaWdoVmFsdWVzW2kyXSA9IGVuY29kZWRSZXN1bHQuaGlnaDsKICAgICAgICAgIGxvd1ZhbHVlc1tpMl0gPSBlbmNvZGVkUmVzdWx0LmxvdzsKICAgICAgICB9CiAgICAgICAgY29uc3QgY29tcG9uZW50c1BlckF0dHJpYnV0ZSA9IGF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlOwogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlSGlnaE5hbWVdID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlLAogICAgICAgICAgdmFsdWVzOiBoaWdoVmFsdWVzCiAgICAgICAgfSk7CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlc1thdHRyaWJ1dGVMb3dOYW1lXSA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZSwKICAgICAgICAgIHZhbHVlczogbG93VmFsdWVzCiAgICAgICAgfSk7CiAgICAgICAgZGVsZXRlIGdlb21ldHJ5LmF0dHJpYnV0ZXNbYXR0cmlidXRlTmFtZV07CiAgICAgICAgcmV0dXJuIGdlb21ldHJ5OwogICAgICB9OwogICAgICBzY3JhdGNoQ2FydGVzaWFuMzMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGludmVyc2VUcmFuc3Bvc2UgPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIG5vcm1hbE1hdHJpeCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgR2VvbWV0cnlQaXBlbGluZS50cmFuc2Zvcm1Ub1dvcmxkQ29vcmRpbmF0ZXMgPSBmdW5jdGlvbihpbnN0YW5jZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImluc3RhbmNlIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBtb2RlbE1hdHJpeCA9IGluc3RhbmNlLm1vZGVsTWF0cml4OwogICAgICAgIGlmIChNYXRyaXg0X2RlZmF1bHQuZXF1YWxzKG1vZGVsTWF0cml4LCBNYXRyaXg0X2RlZmF1bHQuSURFTlRJVFkpKSB7CiAgICAgICAgICByZXR1cm4gaW5zdGFuY2U7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBpbnN0YW5jZS5nZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICAgIHRyYW5zZm9ybVBvaW50KG1vZGVsTWF0cml4LCBhdHRyaWJ1dGVzLnBvc2l0aW9uKTsKICAgICAgICB0cmFuc2Zvcm1Qb2ludChtb2RlbE1hdHJpeCwgYXR0cmlidXRlcy5wcmV2UG9zaXRpb24pOwogICAgICAgIHRyYW5zZm9ybVBvaW50KG1vZGVsTWF0cml4LCBhdHRyaWJ1dGVzLm5leHRQb3NpdGlvbik7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLm5vcm1hbCkgfHwgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMudGFuZ2VudCkgfHwgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuYml0YW5nZW50KSkgewogICAgICAgICAgTWF0cml4NF9kZWZhdWx0LmludmVyc2UobW9kZWxNYXRyaXgsIGludmVyc2VUcmFuc3Bvc2UpOwogICAgICAgICAgTWF0cml4NF9kZWZhdWx0LnRyYW5zcG9zZShpbnZlcnNlVHJhbnNwb3NlLCBpbnZlcnNlVHJhbnNwb3NlKTsKICAgICAgICAgIE1hdHJpeDRfZGVmYXVsdC5nZXRNYXRyaXgzKGludmVyc2VUcmFuc3Bvc2UsIG5vcm1hbE1hdHJpeCk7CiAgICAgICAgICB0cmFuc2Zvcm1WZWN0b3Iobm9ybWFsTWF0cml4LCBhdHRyaWJ1dGVzLm5vcm1hbCk7CiAgICAgICAgICB0cmFuc2Zvcm1WZWN0b3Iobm9ybWFsTWF0cml4LCBhdHRyaWJ1dGVzLnRhbmdlbnQpOwogICAgICAgICAgdHJhbnNmb3JtVmVjdG9yKG5vcm1hbE1hdHJpeCwgYXR0cmlidXRlcy5iaXRhbmdlbnQpOwogICAgICAgIH0KICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IGluc3RhbmNlLmdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoYm91bmRpbmdTcGhlcmUpKSB7CiAgICAgICAgICBpbnN0YW5jZS5nZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQudHJhbnNmb3JtKAogICAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgICAgbW9kZWxNYXRyaXgsCiAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpbnN0YW5jZS5tb2RlbE1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC5jbG9uZShNYXRyaXg0X2RlZmF1bHQuSURFTlRJVFkpOwogICAgICAgIHJldHVybiBpbnN0YW5jZTsKICAgICAgfTsKICAgICAgdGVtcFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUuY29tYmluZUluc3RhbmNlcyA9IGZ1bmN0aW9uKGluc3RhbmNlcykgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlcykgfHwgaW5zdGFuY2VzLmxlbmd0aCA8IDEpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiaW5zdGFuY2VzIGlzIHJlcXVpcmVkIGFuZCBtdXN0IGhhdmUgbGVuZ3RoIGdyZWF0ZXIgdGhhbiB6ZXJvLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGluc3RhbmNlR2VvbWV0cnkgPSBbXTsKICAgICAgICBjb25zdCBpbnN0YW5jZVNwbGl0R2VvbWV0cnkgPSBbXTsKICAgICAgICBjb25zdCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgIGNvbnN0IGluc3RhbmNlID0gaW5zdGFuY2VzW2kyXTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2UuZ2VvbWV0cnkpKSB7CiAgICAgICAgICAgIGluc3RhbmNlR2VvbWV0cnkucHVzaChpbnN0YW5jZSk7CiAgICAgICAgICB9IGVsc2UgaWYgKGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZS53ZXN0SGVtaXNwaGVyZUdlb21ldHJ5KSAmJiBkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2UuZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSkpIHsKICAgICAgICAgICAgaW5zdGFuY2VTcGxpdEdlb21ldHJ5LnB1c2goaW5zdGFuY2UpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBnZW9tZXRyaWVzID0gW107CiAgICAgICAgaWYgKGluc3RhbmNlR2VvbWV0cnkubGVuZ3RoID4gMCkgewogICAgICAgICAgZ2VvbWV0cmllcy5wdXNoKGNvbWJpbmVHZW9tZXRyaWVzKGluc3RhbmNlR2VvbWV0cnksICJnZW9tZXRyeSIpKTsKICAgICAgICB9CiAgICAgICAgaWYgKGluc3RhbmNlU3BsaXRHZW9tZXRyeS5sZW5ndGggPiAwKSB7CiAgICAgICAgICBnZW9tZXRyaWVzLnB1c2goCiAgICAgICAgICAgIGNvbWJpbmVHZW9tZXRyaWVzKGluc3RhbmNlU3BsaXRHZW9tZXRyeSwgIndlc3RIZW1pc3BoZXJlR2VvbWV0cnkiKQogICAgICAgICAgKTsKICAgICAgICAgIGdlb21ldHJpZXMucHVzaCgKICAgICAgICAgICAgY29tYmluZUdlb21ldHJpZXMoaW5zdGFuY2VTcGxpdEdlb21ldHJ5LCAiZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSIpCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZ2VvbWV0cmllczsKICAgICAgfTsKICAgICAgbm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB2MCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdjEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHYyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBHZW9tZXRyeVBpcGVsaW5lLmNvbXB1dGVOb3JtYWwgPSBmdW5jdGlvbihnZW9tZXRyeSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyBpcyByZXF1aXJlZC4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5pbmRpY2VzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5LmluZGljZXMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChnZW9tZXRyeS5pbmRpY2VzLmxlbmd0aCA8IDIgfHwgZ2VvbWV0cnkuaW5kaWNlcy5sZW5ndGggJSAzICE9PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgImdlb21ldHJ5LmluZGljZXMgbGVuZ3RoIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAgYW5kIGJlIGEgbXVsdGlwbGUgb2YgMy4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSAhPT0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUykgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJnZW9tZXRyeS5wcmltaXRpdmVUeXBlIG11c3QgYmUgUHJpbWl0aXZlVHlwZS5UUklBTkdMRVMuIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgaW5kaWNlcyA9IGdlb21ldHJ5LmluZGljZXM7CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7CiAgICAgICAgY29uc3QgdmVydGljZXMgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgICAgICBjb25zdCBudW1WZXJ0aWNlcyA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aCAvIDM7CiAgICAgICAgY29uc3QgbnVtSW5kaWNlcyA9IGluZGljZXMubGVuZ3RoOwogICAgICAgIGNvbnN0IG5vcm1hbHNQZXJWZXJ0ZXggPSBuZXcgQXJyYXkobnVtVmVydGljZXMpOwogICAgICAgIGNvbnN0IG5vcm1hbHNQZXJUcmlhbmdsZSA9IG5ldyBBcnJheShudW1JbmRpY2VzIC8gMyk7CiAgICAgICAgY29uc3Qgbm9ybWFsSW5kaWNlcyA9IG5ldyBBcnJheShudW1JbmRpY2VzKTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtVmVydGljZXM7IGkyKyspIHsKICAgICAgICAgIG5vcm1hbHNQZXJWZXJ0ZXhbaTJdID0gewogICAgICAgICAgICBpbmRleE9mZnNldDogMCwKICAgICAgICAgICAgY291bnQ6IDAsCiAgICAgICAgICAgIGN1cnJlbnRDb3VudDogMAogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgbGV0IGoyID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1JbmRpY2VzOyBpMiArPSAzKSB7CiAgICAgICAgICBjb25zdCBpMCA9IGluZGljZXNbaTJdOwogICAgICAgICAgY29uc3QgaTEgPSBpbmRpY2VzW2kyICsgMV07CiAgICAgICAgICBjb25zdCBpMjIgPSBpbmRpY2VzW2kyICsgMl07CiAgICAgICAgICBjb25zdCBpMDMgPSBpMCAqIDM7CiAgICAgICAgICBjb25zdCBpMTMgPSBpMSAqIDM7CiAgICAgICAgICBjb25zdCBpMjMgPSBpMjIgKiAzOwogICAgICAgICAgdjAueCA9IHZlcnRpY2VzW2kwM107CiAgICAgICAgICB2MC55ID0gdmVydGljZXNbaTAzICsgMV07CiAgICAgICAgICB2MC56ID0gdmVydGljZXNbaTAzICsgMl07CiAgICAgICAgICB2MS54ID0gdmVydGljZXNbaTEzXTsKICAgICAgICAgIHYxLnkgPSB2ZXJ0aWNlc1tpMTMgKyAxXTsKICAgICAgICAgIHYxLnogPSB2ZXJ0aWNlc1tpMTMgKyAyXTsKICAgICAgICAgIHYyLnggPSB2ZXJ0aWNlc1tpMjNdOwogICAgICAgICAgdjIueSA9IHZlcnRpY2VzW2kyMyArIDFdOwogICAgICAgICAgdjIueiA9IHZlcnRpY2VzW2kyMyArIDJdOwogICAgICAgICAgbm9ybWFsc1BlclZlcnRleFtpMF0uY291bnQrKzsKICAgICAgICAgIG5vcm1hbHNQZXJWZXJ0ZXhbaTFdLmNvdW50Kys7CiAgICAgICAgICBub3JtYWxzUGVyVmVydGV4W2kyMl0uY291bnQrKzsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh2MSwgdjAsIHYxKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh2MiwgdjAsIHYyKTsKICAgICAgICAgIG5vcm1hbHNQZXJUcmlhbmdsZVtqMl0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModjEsIHYyLCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkpOwogICAgICAgICAgajIrKzsKICAgICAgICB9CiAgICAgICAgbGV0IGluZGV4T2Zmc2V0ID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlczsgaTIrKykgewogICAgICAgICAgbm9ybWFsc1BlclZlcnRleFtpMl0uaW5kZXhPZmZzZXQgKz0gaW5kZXhPZmZzZXQ7CiAgICAgICAgICBpbmRleE9mZnNldCArPSBub3JtYWxzUGVyVmVydGV4W2kyXS5jb3VudDsKICAgICAgICB9CiAgICAgICAgajIgPSAwOwogICAgICAgIGxldCB2ZXJ0ZXhOb3JtYWxEYXRhOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bUluZGljZXM7IGkyICs9IDMpIHsKICAgICAgICAgIHZlcnRleE5vcm1hbERhdGEgPSBub3JtYWxzUGVyVmVydGV4W2luZGljZXNbaTJdXTsKICAgICAgICAgIGxldCBpbmRleCA9IHZlcnRleE5vcm1hbERhdGEuaW5kZXhPZmZzZXQgKyB2ZXJ0ZXhOb3JtYWxEYXRhLmN1cnJlbnRDb3VudDsKICAgICAgICAgIG5vcm1hbEluZGljZXNbaW5kZXhdID0gajI7CiAgICAgICAgICB2ZXJ0ZXhOb3JtYWxEYXRhLmN1cnJlbnRDb3VudCsrOwogICAgICAgICAgdmVydGV4Tm9ybWFsRGF0YSA9IG5vcm1hbHNQZXJWZXJ0ZXhbaW5kaWNlc1tpMiArIDFdXTsKICAgICAgICAgIGluZGV4ID0gdmVydGV4Tm9ybWFsRGF0YS5pbmRleE9mZnNldCArIHZlcnRleE5vcm1hbERhdGEuY3VycmVudENvdW50OwogICAgICAgICAgbm9ybWFsSW5kaWNlc1tpbmRleF0gPSBqMjsKICAgICAgICAgIHZlcnRleE5vcm1hbERhdGEuY3VycmVudENvdW50Kys7CiAgICAgICAgICB2ZXJ0ZXhOb3JtYWxEYXRhID0gbm9ybWFsc1BlclZlcnRleFtpbmRpY2VzW2kyICsgMl1dOwogICAgICAgICAgaW5kZXggPSB2ZXJ0ZXhOb3JtYWxEYXRhLmluZGV4T2Zmc2V0ICsgdmVydGV4Tm9ybWFsRGF0YS5jdXJyZW50Q291bnQ7CiAgICAgICAgICBub3JtYWxJbmRpY2VzW2luZGV4XSA9IGoyOwogICAgICAgICAgdmVydGV4Tm9ybWFsRGF0YS5jdXJyZW50Q291bnQrKzsKICAgICAgICAgIGoyKys7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG5vcm1hbFZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkobnVtVmVydGljZXMgKiAzKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlczsgaTIrKykgewogICAgICAgICAgY29uc3QgaTMgPSBpMiAqIDM7CiAgICAgICAgICB2ZXJ0ZXhOb3JtYWxEYXRhID0gbm9ybWFsc1BlclZlcnRleFtpMl07CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIG5vcm1hbCk7CiAgICAgICAgICBpZiAodmVydGV4Tm9ybWFsRGF0YS5jb3VudCA+IDApIHsKICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgdmVydGV4Tm9ybWFsRGF0YS5jb3VudDsgajIrKykgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICBub3JtYWwsCiAgICAgICAgICAgICAgICBub3JtYWxzUGVyVHJpYW5nbGVbbm9ybWFsSW5kaWNlc1t2ZXJ0ZXhOb3JtYWxEYXRhLmluZGV4T2Zmc2V0ICsgajJdXSwKICAgICAgICAgICAgICAgIG5vcm1hbAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBub3JtYWwsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKAogICAgICAgICAgICAgICAgbm9ybWFsc1BlclRyaWFuZ2xlW25vcm1hbEluZGljZXNbdmVydGV4Tm9ybWFsRGF0YS5pbmRleE9mZnNldF1dLAogICAgICAgICAgICAgICAgbm9ybWFsCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBub3JtYWwsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgICAgICAgIG5vcm1hbC56ID0gMTsKICAgICAgICAgIH0KICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUobm9ybWFsLCBub3JtYWwpOwogICAgICAgICAgbm9ybWFsVmFsdWVzW2kzXSA9IG5vcm1hbC54OwogICAgICAgICAgbm9ybWFsVmFsdWVzW2kzICsgMV0gPSBub3JtYWwueTsKICAgICAgICAgIG5vcm1hbFZhbHVlc1tpMyArIDJdID0gbm9ybWFsLno7CiAgICAgICAgfQogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMubm9ybWFsID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgdmFsdWVzOiBub3JtYWxWYWx1ZXMKICAgICAgICB9KTsKICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgIH07CiAgICAgIG5vcm1hbFNjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBub3JtYWxTY2FsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEdlb21ldHJ5UGlwZWxpbmUuY29tcHV0ZVRhbmdlbnRBbmRCaXRhbmdlbnQgPSBmdW5jdGlvbihnZW9tZXRyeSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICBjb25zdCBpbmRpY2VzID0gZ2VvbWV0cnkuaW5kaWNlczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLnBvc2l0aW9uKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyBpcyByZXF1aXJlZC4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLm5vcm1hbCkgfHwgIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLm5vcm1hbC52YWx1ZXMpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ2VvbWV0cnkuYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzLnN0KSB8fCAhZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZXMuc3QudmFsdWVzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5LmF0dHJpYnV0ZXMuc3QudmFsdWVzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbmRpY2VzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5LmluZGljZXMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChpbmRpY2VzLmxlbmd0aCA8IDIgfHwgaW5kaWNlcy5sZW5ndGggJSAzICE9PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgImdlb21ldHJ5LmluZGljZXMgbGVuZ3RoIG11c3QgYmUgZ3JlYXRlciB0aGFuIDAgYW5kIGJlIGEgbXVsdGlwbGUgb2YgMy4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSAhPT0gUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUykgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJnZW9tZXRyeS5wcmltaXRpdmVUeXBlIG11c3QgYmUgUHJpbWl0aXZlVHlwZS5UUklBTkdMRVMuIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdmVydGljZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgICAgICBjb25zdCBub3JtYWxzID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzOwogICAgICAgIGNvbnN0IHN0MiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMuc3QudmFsdWVzOwogICAgICAgIGNvbnN0IG51bVZlcnRpY2VzID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoIC8gMzsKICAgICAgICBjb25zdCBudW1JbmRpY2VzID0gaW5kaWNlcy5sZW5ndGg7CiAgICAgICAgY29uc3QgdGFuMSA9IG5ldyBBcnJheShudW1WZXJ0aWNlcyAqIDMpOwogICAgICAgIGxldCBpMjsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCB0YW4xLmxlbmd0aDsgaTIrKykgewogICAgICAgICAgdGFuMVtpMl0gPSAwOwogICAgICAgIH0KICAgICAgICBsZXQgaTAzOwogICAgICAgIGxldCBpMTM7CiAgICAgICAgbGV0IGkyMzsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1JbmRpY2VzOyBpMiArPSAzKSB7CiAgICAgICAgICBjb25zdCBpMCA9IGluZGljZXNbaTJdOwogICAgICAgICAgY29uc3QgaTEgPSBpbmRpY2VzW2kyICsgMV07CiAgICAgICAgICBjb25zdCBpMjIgPSBpbmRpY2VzW2kyICsgMl07CiAgICAgICAgICBpMDMgPSBpMCAqIDM7CiAgICAgICAgICBpMTMgPSBpMSAqIDM7CiAgICAgICAgICBpMjMgPSBpMjIgKiAzOwogICAgICAgICAgY29uc3QgaTAyID0gaTAgKiAyOwogICAgICAgICAgY29uc3QgaTEyID0gaTEgKiAyOwogICAgICAgICAgY29uc3QgaTIyMiA9IGkyMiAqIDI7CiAgICAgICAgICBjb25zdCB1eCA9IHZlcnRpY2VzW2kwM107CiAgICAgICAgICBjb25zdCB1eSA9IHZlcnRpY2VzW2kwMyArIDFdOwogICAgICAgICAgY29uc3QgdXogPSB2ZXJ0aWNlc1tpMDMgKyAyXTsKICAgICAgICAgIGNvbnN0IHd4ID0gc3QyW2kwMl07CiAgICAgICAgICBjb25zdCB3eSA9IHN0MltpMDIgKyAxXTsKICAgICAgICAgIGNvbnN0IHQxID0gc3QyW2kxMiArIDFdIC0gd3k7CiAgICAgICAgICBjb25zdCB0MiA9IHN0MltpMjIyICsgMV0gLSB3eTsKICAgICAgICAgIGNvbnN0IHIyID0gMSAvICgoc3QyW2kxMl0gLSB3eCkgKiB0MiAtIChzdDJbaTIyMl0gLSB3eCkgKiB0MSk7CiAgICAgICAgICBjb25zdCBzZGlyeCA9ICh0MiAqICh2ZXJ0aWNlc1tpMTNdIC0gdXgpIC0gdDEgKiAodmVydGljZXNbaTIzXSAtIHV4KSkgKiByMjsKICAgICAgICAgIGNvbnN0IHNkaXJ5ID0gKHQyICogKHZlcnRpY2VzW2kxMyArIDFdIC0gdXkpIC0gdDEgKiAodmVydGljZXNbaTIzICsgMV0gLSB1eSkpICogcjI7CiAgICAgICAgICBjb25zdCBzZGlyeiA9ICh0MiAqICh2ZXJ0aWNlc1tpMTMgKyAyXSAtIHV6KSAtIHQxICogKHZlcnRpY2VzW2kyMyArIDJdIC0gdXopKSAqIHIyOwogICAgICAgICAgdGFuMVtpMDNdICs9IHNkaXJ4OwogICAgICAgICAgdGFuMVtpMDMgKyAxXSArPSBzZGlyeTsKICAgICAgICAgIHRhbjFbaTAzICsgMl0gKz0gc2Rpcno7CiAgICAgICAgICB0YW4xW2kxM10gKz0gc2Rpcng7CiAgICAgICAgICB0YW4xW2kxMyArIDFdICs9IHNkaXJ5OwogICAgICAgICAgdGFuMVtpMTMgKyAyXSArPSBzZGlyejsKICAgICAgICAgIHRhbjFbaTIzXSArPSBzZGlyeDsKICAgICAgICAgIHRhbjFbaTIzICsgMV0gKz0gc2Rpcnk7CiAgICAgICAgICB0YW4xW2kyMyArIDJdICs9IHNkaXJ6OwogICAgICAgIH0KICAgICAgICBjb25zdCB0YW5nZW50VmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheShudW1WZXJ0aWNlcyAqIDMpOwogICAgICAgIGNvbnN0IGJpdGFuZ2VudFZhbHVlcyA9IG5ldyBGbG9hdDMyQXJyYXkobnVtVmVydGljZXMgKiAzKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlczsgaTIrKykgewogICAgICAgICAgaTAzID0gaTIgKiAzOwogICAgICAgICAgaTEzID0gaTAzICsgMTsKICAgICAgICAgIGkyMyA9IGkwMyArIDI7CiAgICAgICAgICBjb25zdCBuMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobm9ybWFscywgaTAzLCBub3JtYWxTY3JhdGNoMik7CiAgICAgICAgICBjb25zdCB0MiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkodGFuMSwgaTAzLCB0U2NyYXRjaCk7CiAgICAgICAgICBjb25zdCBzY2FsYXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG4yLCB0Mik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihuMiwgc2NhbGFyLCBub3JtYWxTY2FsZSk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCh0Miwgbm9ybWFsU2NhbGUsIHQyKSwgdDIpOwogICAgICAgICAgdGFuZ2VudFZhbHVlc1tpMDNdID0gdDIueDsKICAgICAgICAgIHRhbmdlbnRWYWx1ZXNbaTEzXSA9IHQyLnk7CiAgICAgICAgICB0YW5nZW50VmFsdWVzW2kyM10gPSB0Mi56OwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MobjIsIHQyLCB0MiksIHQyKTsKICAgICAgICAgIGJpdGFuZ2VudFZhbHVlc1tpMDNdID0gdDIueDsKICAgICAgICAgIGJpdGFuZ2VudFZhbHVlc1tpMTNdID0gdDIueTsKICAgICAgICAgIGJpdGFuZ2VudFZhbHVlc1tpMjNdID0gdDIuejsKICAgICAgICB9CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy50YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgdmFsdWVzOiB0YW5nZW50VmFsdWVzCiAgICAgICAgfSk7CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5iaXRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IGJpdGFuZ2VudFZhbHVlcwogICAgICAgIH0pOwogICAgICAgIHJldHVybiBnZW9tZXRyeTsKICAgICAgfTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjIyID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICB0b0VuY29kZTEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHRvRW5jb2RlMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdG9FbmNvZGUzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBlbmNvZGVSZXN1bHQyID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBHZW9tZXRyeVBpcGVsaW5lLmNvbXByZXNzVmVydGljZXMgPSBmdW5jdGlvbihnZW9tZXRyeSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdlb21ldHJ5IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBleHRydWRlQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5leHRydWRlRGlyZWN0aW9uOwogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgbnVtVmVydGljZXM7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChleHRydWRlQXR0cmlidXRlKSkgewogICAgICAgICAgY29uc3QgZXh0cnVkZURpcmVjdGlvbnMgPSBleHRydWRlQXR0cmlidXRlLnZhbHVlczsKICAgICAgICAgIG51bVZlcnRpY2VzID0gZXh0cnVkZURpcmVjdGlvbnMubGVuZ3RoIC8gMzsKICAgICAgICAgIGNvbnN0IGNvbXByZXNzZWREaXJlY3Rpb25zID0gbmV3IEZsb2F0MzJBcnJheShudW1WZXJ0aWNlcyAqIDIpOwogICAgICAgICAgbGV0IGkyMiA9IDA7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlczsgKytpMikgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGV4dHJ1ZGVEaXJlY3Rpb25zLCBpMiAqIDMsIHRvRW5jb2RlMSk7CiAgICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKHRvRW5jb2RlMSwgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pKSB7CiAgICAgICAgICAgICAgaTIyICs9IDI7CiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZW5jb2RlUmVzdWx0MiA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQub2N0RW5jb2RlSW5SYW5nZSgKICAgICAgICAgICAgICB0b0VuY29kZTEsCiAgICAgICAgICAgICAgNjU1MzUsCiAgICAgICAgICAgICAgZW5jb2RlUmVzdWx0MgogICAgICAgICAgICApOwogICAgICAgICAgICBjb21wcmVzc2VkRGlyZWN0aW9uc1tpMjIrK10gPSBlbmNvZGVSZXN1bHQyLng7CiAgICAgICAgICAgIGNvbXByZXNzZWREaXJlY3Rpb25zW2kyMisrXSA9IGVuY29kZVJlc3VsdDIueTsKICAgICAgICAgIH0KICAgICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29tcHJlc3NlZEF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICB2YWx1ZXM6IGNvbXByZXNzZWREaXJlY3Rpb25zCiAgICAgICAgICB9KTsKICAgICAgICAgIGRlbGV0ZSBnZW9tZXRyeS5hdHRyaWJ1dGVzLmV4dHJ1ZGVEaXJlY3Rpb247CiAgICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG5vcm1hbEF0dHJpYnV0ZSA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMubm9ybWFsOwogICAgICAgIGNvbnN0IHN0QXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5zdDsKICAgICAgICBjb25zdCBoYXNOb3JtYWwgPSBkZWZpbmVkX2RlZmF1bHQobm9ybWFsQXR0cmlidXRlKTsKICAgICAgICBjb25zdCBoYXNTdCA9IGRlZmluZWRfZGVmYXVsdChzdEF0dHJpYnV0ZSk7CiAgICAgICAgaWYgKCFoYXNOb3JtYWwgJiYgIWhhc1N0KSB7CiAgICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHRhbmdlbnRBdHRyaWJ1dGUgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQ7CiAgICAgICAgY29uc3QgYml0YW5nZW50QXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5iaXRhbmdlbnQ7CiAgICAgICAgY29uc3QgaGFzVGFuZ2VudCA9IGRlZmluZWRfZGVmYXVsdCh0YW5nZW50QXR0cmlidXRlKTsKICAgICAgICBjb25zdCBoYXNCaXRhbmdlbnQgPSBkZWZpbmVkX2RlZmF1bHQoYml0YW5nZW50QXR0cmlidXRlKTsKICAgICAgICBsZXQgbm9ybWFsczsKICAgICAgICBsZXQgc3QyOwogICAgICAgIGxldCB0YW5nZW50czsKICAgICAgICBsZXQgYml0YW5nZW50czsKICAgICAgICBpZiAoaGFzTm9ybWFsKSB7CiAgICAgICAgICBub3JtYWxzID0gbm9ybWFsQXR0cmlidXRlLnZhbHVlczsKICAgICAgICB9CiAgICAgICAgaWYgKGhhc1N0KSB7CiAgICAgICAgICBzdDIgPSBzdEF0dHJpYnV0ZS52YWx1ZXM7CiAgICAgICAgfQogICAgICAgIGlmIChoYXNUYW5nZW50KSB7CiAgICAgICAgICB0YW5nZW50cyA9IHRhbmdlbnRBdHRyaWJ1dGUudmFsdWVzOwogICAgICAgIH0KICAgICAgICBpZiAoaGFzQml0YW5nZW50KSB7CiAgICAgICAgICBiaXRhbmdlbnRzID0gYml0YW5nZW50QXR0cmlidXRlLnZhbHVlczsKICAgICAgICB9CiAgICAgICAgY29uc3QgbGVuZ3RoID0gaGFzTm9ybWFsID8gbm9ybWFscy5sZW5ndGggOiBzdDIubGVuZ3RoOwogICAgICAgIGNvbnN0IG51bUNvbXBvbmVudHMgPSBoYXNOb3JtYWwgPyAzIDogMjsKICAgICAgICBudW1WZXJ0aWNlcyA9IGxlbmd0aCAvIG51bUNvbXBvbmVudHM7CiAgICAgICAgbGV0IGNvbXByZXNzZWRMZW5ndGggPSBudW1WZXJ0aWNlczsKICAgICAgICBsZXQgbnVtQ29tcHJlc3NlZENvbXBvbmVudHMgPSBoYXNTdCAmJiBoYXNOb3JtYWwgPyAyIDogMTsKICAgICAgICBudW1Db21wcmVzc2VkQ29tcG9uZW50cyArPSBoYXNUYW5nZW50IHx8IGhhc0JpdGFuZ2VudCA/IDEgOiAwOwogICAgICAgIGNvbXByZXNzZWRMZW5ndGggKj0gbnVtQ29tcHJlc3NlZENvbXBvbmVudHM7CiAgICAgICAgY29uc3QgY29tcHJlc3NlZEF0dHJpYnV0ZXMgPSBuZXcgRmxvYXQzMkFycmF5KGNvbXByZXNzZWRMZW5ndGgpOwogICAgICAgIGxldCBub3JtYWxJbmRleCA9IDA7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtVmVydGljZXM7ICsraTIpIHsKICAgICAgICAgIGlmIChoYXNTdCkgewogICAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUFycmF5KHN0MiwgaTIgKiAyLCBzY3JhdGNoQ2FydGVzaWFuMjIpOwogICAgICAgICAgICBjb21wcmVzc2VkQXR0cmlidXRlc1tub3JtYWxJbmRleCsrXSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuY29tcHJlc3NUZXh0dXJlQ29vcmRpbmF0ZXMoc2NyYXRjaENhcnRlc2lhbjIyKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGluZGV4ID0gaTIgKiAzOwogICAgICAgICAgaWYgKGhhc05vcm1hbCAmJiBkZWZpbmVkX2RlZmF1bHQodGFuZ2VudHMpICYmIGRlZmluZWRfZGVmYXVsdChiaXRhbmdlbnRzKSkgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KG5vcm1hbHMsIGluZGV4LCB0b0VuY29kZTEpOwogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHRhbmdlbnRzLCBpbmRleCwgdG9FbmNvZGUyKTsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShiaXRhbmdlbnRzLCBpbmRleCwgdG9FbmNvZGUzKTsKICAgICAgICAgICAgQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5vY3RQYWNrKAogICAgICAgICAgICAgIHRvRW5jb2RlMSwKICAgICAgICAgICAgICB0b0VuY29kZTIsCiAgICAgICAgICAgICAgdG9FbmNvZGUzLAogICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yMgogICAgICAgICAgICApOwogICAgICAgICAgICBjb21wcmVzc2VkQXR0cmlidXRlc1tub3JtYWxJbmRleCsrXSA9IHNjcmF0Y2hDYXJ0ZXNpYW4yMi54OwogICAgICAgICAgICBjb21wcmVzc2VkQXR0cmlidXRlc1tub3JtYWxJbmRleCsrXSA9IHNjcmF0Y2hDYXJ0ZXNpYW4yMi55OwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgaWYgKGhhc05vcm1hbCkgewogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobm9ybWFscywgaW5kZXgsIHRvRW5jb2RlMSk7CiAgICAgICAgICAgICAgY29tcHJlc3NlZEF0dHJpYnV0ZXNbbm9ybWFsSW5kZXgrK10gPSBBdHRyaWJ1dGVDb21wcmVzc2lvbl9kZWZhdWx0Lm9jdEVuY29kZUZsb2F0KHRvRW5jb2RlMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGhhc1RhbmdlbnQpIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHRhbmdlbnRzLCBpbmRleCwgdG9FbmNvZGUxKTsKICAgICAgICAgICAgICBjb21wcmVzc2VkQXR0cmlidXRlc1tub3JtYWxJbmRleCsrXSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQub2N0RW5jb2RlRmxvYXQodG9FbmNvZGUxKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoaGFzQml0YW5nZW50KSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShiaXRhbmdlbnRzLCBpbmRleCwgdG9FbmNvZGUxKTsKICAgICAgICAgICAgICBjb21wcmVzc2VkQXR0cmlidXRlc1tub3JtYWxJbmRleCsrXSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQub2N0RW5jb2RlRmxvYXQodG9FbmNvZGUxKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLmNvbXByZXNzZWRBdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiBudW1Db21wcmVzc2VkQ29tcG9uZW50cywKICAgICAgICAgIHZhbHVlczogY29tcHJlc3NlZEF0dHJpYnV0ZXMKICAgICAgICB9KTsKICAgICAgICBpZiAoaGFzTm9ybWFsKSB7CiAgICAgICAgICBkZWxldGUgZ2VvbWV0cnkuYXR0cmlidXRlcy5ub3JtYWw7CiAgICAgICAgfQogICAgICAgIGlmIChoYXNTdCkgewogICAgICAgICAgZGVsZXRlIGdlb21ldHJ5LmF0dHJpYnV0ZXMuc3Q7CiAgICAgICAgfQogICAgICAgIGlmIChoYXNCaXRhbmdlbnQpIHsKICAgICAgICAgIGRlbGV0ZSBnZW9tZXRyeS5hdHRyaWJ1dGVzLmJpdGFuZ2VudDsKICAgICAgICB9CiAgICAgICAgaWYgKGhhc1RhbmdlbnQpIHsKICAgICAgICAgIGRlbGV0ZSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBnZW9tZXRyeTsKICAgICAgfTsKICAgICAgYzMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHUxID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB1MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcTEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHEyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzcGxpdFRyaWFuZ2xlUmVzdWx0ID0gewogICAgICAgIHBvc2l0aW9uczogbmV3IEFycmF5KDcpLAogICAgICAgIGluZGljZXM6IG5ldyBBcnJheSgzICogMykKICAgICAgfTsKICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQ2FydGVzaWFuNCA9IGdlbmVyYXRlQmFyeWNlbnRyaWNJbnRlcnBvbGF0ZUZ1bmN0aW9uKAogICAgICAgIENhcnRlc2lhbjRfZGVmYXVsdCwKICAgICAgICA0CiAgICAgICk7CiAgICAgIGludGVycG9sYXRlQW5kUGFja0NhcnRlc2lhbjMgPSBnZW5lcmF0ZUJhcnljZW50cmljSW50ZXJwb2xhdGVGdW5jdGlvbigKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQsCiAgICAgICAgMwogICAgICApOwogICAgICBpbnRlcnBvbGF0ZUFuZFBhY2tDYXJ0ZXNpYW4yID0gZ2VuZXJhdGVCYXJ5Y2VudHJpY0ludGVycG9sYXRlRnVuY3Rpb24oCiAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LAogICAgICAgIDIKICAgICAgKTsKICAgICAgaW50ZXJwb2xhdGVBbmRQYWNrQm9vbGVhbiA9IGZ1bmN0aW9uKGkwLCBpMSwgaTIsIGNvb3Jkcywgc291cmNlVmFsdWVzLCBjdXJyZW50VmFsdWVzLCBpbnNlcnRlZEluZGV4KSB7CiAgICAgICAgY29uc3QgdjEyID0gc291cmNlVmFsdWVzW2kwXSAqIGNvb3Jkcy54OwogICAgICAgIGNvbnN0IHYyMiA9IHNvdXJjZVZhbHVlc1tpMV0gKiBjb29yZHMueTsKICAgICAgICBjb25zdCB2MzIgPSBzb3VyY2VWYWx1ZXNbaTJdICogY29vcmRzLno7CiAgICAgICAgY3VycmVudFZhbHVlc1tpbnNlcnRlZEluZGV4XSA9IHYxMiArIHYyMiArIHYzMiA+IE1hdGhfZGVmYXVsdC5FUFNJTE9ONiA/IDEgOiAwOwogICAgICB9OwogICAgICBwMFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHAxU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcDJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBiYXJ5Y2VudHJpY1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIE5BTUVEX0FUVFJJQlVURVMgPSB7CiAgICAgICAgcG9zaXRpb246IHRydWUsCiAgICAgICAgbm9ybWFsOiB0cnVlLAogICAgICAgIGJpdGFuZ2VudDogdHJ1ZSwKICAgICAgICB0YW5nZW50OiB0cnVlLAogICAgICAgIHN0OiB0cnVlLAogICAgICAgIGV4dHJ1ZGVEaXJlY3Rpb246IHRydWUsCiAgICAgICAgYXBwbHlPZmZzZXQ6IHRydWUKICAgICAgfTsKICAgICAgeHpQbGFuZSA9IFBsYW5lX2RlZmF1bHQuZnJvbVBvaW50Tm9ybWFsKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZKTsKICAgICAgb2Zmc2V0U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgb2Zmc2V0UG9pbnRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4yU2NyYXRjaDAgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjJTY3JhdGNoMSA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuM1NjcmF0Y2gwID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjNTY3JhdGNoMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuM1NjcmF0Y2g0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjNTY3JhdGNoNiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuNFNjcmF0Y2gwID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICBvZmZzZXRTY2FsYXIgPSA1ICogTWF0aF9kZWZhdWx0LkVQU0lMT045OwogICAgICBjb3BsYW5hck9mZnNldCA9IE1hdGhfZGVmYXVsdC5FUFNJTE9ONjsKICAgICAgR2VvbWV0cnlQaXBlbGluZS5zcGxpdExvbmdpdHVkZSA9IGZ1bmN0aW9uKGluc3RhbmNlKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2UpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiaW5zdGFuY2UgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJ5ID0gaW5zdGFuY2UuZ2VvbWV0cnk7CiAgICAgICAgY29uc3QgYm91bmRpbmdTcGhlcmUgPSBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGJvdW5kaW5nU3BoZXJlKSkgewogICAgICAgICAgY29uc3QgbWluWCA9IGJvdW5kaW5nU3BoZXJlLmNlbnRlci54IC0gYm91bmRpbmdTcGhlcmUucmFkaXVzOwogICAgICAgICAgaWYgKG1pblggPiAwIHx8IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuaW50ZXJzZWN0UGxhbmUoYm91bmRpbmdTcGhlcmUsIFBsYW5lX2RlZmF1bHQuT1JJR0lOX1pYX1BMQU5FKSAhPT0gSW50ZXJzZWN0X2RlZmF1bHQuSU5URVJTRUNUSU5HKSB7CiAgICAgICAgICAgIHJldHVybiBpbnN0YW5jZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGdlb21ldHJ5Lmdlb21ldHJ5VHlwZSAhPT0gR2VvbWV0cnlUeXBlX2RlZmF1bHQuTk9ORSkgewogICAgICAgICAgc3dpdGNoIChnZW9tZXRyeS5nZW9tZXRyeVR5cGUpIHsKICAgICAgICAgICAgY2FzZSBHZW9tZXRyeVR5cGVfZGVmYXVsdC5QT0xZTElORVM6CiAgICAgICAgICAgICAgc3BsaXRMb25naXR1ZGVQb2x5bGluZShpbnN0YW5jZSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgR2VvbWV0cnlUeXBlX2RlZmF1bHQuVFJJQU5HTEVTOgogICAgICAgICAgICAgIHNwbGl0TG9uZ2l0dWRlVHJpYW5nbGVzKGluc3RhbmNlKTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgY2FzZSBHZW9tZXRyeVR5cGVfZGVmYXVsdC5MSU5FUzoKICAgICAgICAgICAgICBzcGxpdExvbmdpdHVkZUxpbmVzKGluc3RhbmNlKTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgaW5kZXhQcmltaXRpdmUoZ2VvbWV0cnkpOwogICAgICAgICAgaWYgKGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUgPT09IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMpIHsKICAgICAgICAgICAgc3BsaXRMb25naXR1ZGVUcmlhbmdsZXMoaW5zdGFuY2UpOwogICAgICAgICAgfSBlbHNlIGlmIChnZW9tZXRyeS5wcmltaXRpdmVUeXBlID09PSBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMpIHsKICAgICAgICAgICAgc3BsaXRMb25naXR1ZGVMaW5lcyhpbnN0YW5jZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbnN0YW5jZTsKICAgICAgfTsKICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0ID0gR2VvbWV0cnlQaXBlbGluZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL09mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGUuanMKICBmdW5jdGlvbiBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlKHgyLCB5MiwgejIpIHsKICAgIHgyID0geDIgPz8gMDsKICAgIHkyID0geTIgPz8gMDsKICAgIHoyID0gejIgPz8gMDsKICAgIHRoaXMudmFsdWUgPSBuZXcgRmxvYXQzMkFycmF5KFt4MiwgeTIsIHoyXSk7CiAgfQogIHZhciBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlX2RlZmF1bHQ7CiAgdmFyIGluaXRfT2Zmc2V0R2VvbWV0cnlJbnN0YW5jZUF0dHJpYnV0ZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvT2Zmc2V0R2VvbWV0cnlJbnN0YW5jZUF0dHJpYnV0ZS5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoT2Zmc2V0R2VvbWV0cnlJbnN0YW5jZUF0dHJpYnV0ZS5wcm90b3R5cGUsIHsKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgZGF0YXR5cGUgb2YgZWFjaCBjb21wb25lbnQgaW4gdGhlIGF0dHJpYnV0ZSwgZS5nLiwgaW5kaXZpZHVhbCBlbGVtZW50cyBpbgogICAgICAgICAqIHtAbGluayBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlI3ZhbHVlfS4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlLnByb3RvdHlwZQogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge0NvbXBvbmVudERhdGF0eXBlfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqCiAgICAgICAgICogQGRlZmF1bHQge0BsaW5rIENvbXBvbmVudERhdGF0eXBlLkZMT0FUfQogICAgICAgICAqLwogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIFRoZSBudW1iZXIgb2YgY29tcG9uZW50cyBpbiB0aGUgYXR0cmlidXRlcywgaS5lLiwge0BsaW5rIE9mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGUjdmFsdWV9LgogICAgICAgICAqCiAgICAgICAgICogQG1lbWJlcm9mIE9mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGUucHJvdG90eXBlCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqCiAgICAgICAgICogQGRlZmF1bHQgMwogICAgICAgICAqLwogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogV2hlbiA8Y29kZT50cnVlPC9jb2RlPiBhbmQgPGNvZGU+Y29tcG9uZW50RGF0YXR5cGU8L2NvZGU+IGlzIGFuIGludGVnZXIgZm9ybWF0LAogICAgICAgICAqIGluZGljYXRlIHRoYXQgdGhlIGNvbXBvbmVudHMgc2hvdWxkIGJlIG1hcHBlZCB0byB0aGUgcmFuZ2UgWzAsIDFdICh1bnNpZ25lZCkKICAgICAgICAgKiBvciBbLTEsIDFdIChzaWduZWQpIHdoZW4gdGhleSBhcmUgYWNjZXNzZWQgYXMgZmxvYXRpbmctcG9pbnQgZm9yIHJlbmRlcmluZy4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlLnByb3RvdHlwZQogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICoKICAgICAgICAgKiBAZGVmYXVsdCBmYWxzZQogICAgICAgICAqLwogICAgICAgIG5vcm1hbGl6ZTogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIE9mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGUuZnJvbUNhcnRlc2lhbjMgPSBmdW5jdGlvbihvZmZzZXQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9mZnNldCIsIG9mZnNldCk7CiAgICAgICAgcmV0dXJuIG5ldyBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlKG9mZnNldC54LCBvZmZzZXQueSwgb2Zmc2V0LnopOwogICAgICB9OwogICAgICBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlLnRvVmFsdWUgPSBmdW5jdGlvbihvZmZzZXQsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgib2Zmc2V0Iiwgb2Zmc2V0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgRmxvYXQzMkFycmF5KFtvZmZzZXQueCwgb2Zmc2V0LnksIG9mZnNldC56XSk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdFswXSA9IG9mZnNldC54OwogICAgICAgIHJlc3VsdFsxXSA9IG9mZnNldC55OwogICAgICAgIHJlc3VsdFsyXSA9IG9mZnNldC56OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIE9mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGVfZGVmYXVsdCA9IE9mZnNldEdlb21ldHJ5SW5zdGFuY2VBdHRyaWJ1dGU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9XZWJNZXJjYXRvclByb2plY3Rpb24uanMKICB2YXIgV2ViTWVyY2F0b3JQcm9qZWN0aW9uLCBXZWJNZXJjYXRvclByb2plY3Rpb25fZGVmYXVsdDsKICB2YXIgaW5pdF9XZWJNZXJjYXRvclByb2plY3Rpb24gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1dlYk1lcmNhdG9yUHJvamVjdGlvbi5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgV2ViTWVyY2F0b3JQcm9qZWN0aW9uID0gY2xhc3MgX1dlYk1lcmNhdG9yUHJvamVjdGlvbiB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHBhcmFtIHtFbGxpcHNvaWR9IFtlbGxpcHNvaWQ9RWxsaXBzb2lkLldHUzg0XSBUaGUgZWxsaXBzb2lkLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKGVsbGlwc29pZCkgewogICAgICAgICAgdGhpcy5fZWxsaXBzb2lkID0gZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LldHUzg0OwogICAgICAgICAgdGhpcy5fc2VtaW1ham9yQXhpcyA9IHRoaXMuX2VsbGlwc29pZC5tYXhpbXVtUmFkaXVzOwogICAgICAgICAgdGhpcy5fb25lT3ZlclNlbWltYWpvckF4aXMgPSAxIC8gdGhpcy5fc2VtaW1ham9yQXhpczsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUge0BsaW5rIEVsbGlwc29pZH0uCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGdldCBlbGxpcHNvaWQoKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fZWxsaXBzb2lkOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBhIE1lcmNhdG9yIGFuZ2xlLCBpbiB0aGUgcmFuZ2UgLVBJIHRvIFBJLCB0byBhIGdlb2RldGljIGxhdGl0dWRlCiAgICAgICAgICogaW4gdGhlIHJhbmdlIC1QSS8yIHRvIFBJLzIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbWVyY2F0b3JBbmdsZSBUaGUgYW5nbGUgdG8gY29udmVydC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgZ2VvZGV0aWMgbGF0aXR1ZGUgaW4gcmFkaWFucy4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbWVyY2F0b3JBbmdsZVRvR2VvZGV0aWNMYXRpdHVkZShtZXJjYXRvckFuZ2xlKSB7CiAgICAgICAgICByZXR1cm4gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIC0gMiAqIE1hdGguYXRhbihNYXRoLmV4cCgtbWVyY2F0b3JBbmdsZSkpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBhIGdlb2RldGljIGxhdGl0dWRlIGluIHJhZGlhbnMsIGluIHRoZSByYW5nZSAtUEkvMiB0byBQSS8yLCB0byBhIE1lcmNhdG9yCiAgICAgICAgICogYW5nbGUgaW4gdGhlIHJhbmdlIC1QSSB0byBQSS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsYXRpdHVkZSBUaGUgZ2VvZGV0aWMgbGF0aXR1ZGUgaW4gcmFkaWFucy4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgTWVyY2F0b3IgYW5nbGUuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUobGF0aXR1ZGUpIHsKICAgICAgICAgIGlmIChsYXRpdHVkZSA+IF9XZWJNZXJjYXRvclByb2plY3Rpb24uTWF4aW11bUxhdGl0dWRlKSB7CiAgICAgICAgICAgIGxhdGl0dWRlID0gX1dlYk1lcmNhdG9yUHJvamVjdGlvbi5NYXhpbXVtTGF0aXR1ZGU7CiAgICAgICAgICB9IGVsc2UgaWYgKGxhdGl0dWRlIDwgLV9XZWJNZXJjYXRvclByb2plY3Rpb24uTWF4aW11bUxhdGl0dWRlKSB7CiAgICAgICAgICAgIGxhdGl0dWRlID0gLV9XZWJNZXJjYXRvclByb2plY3Rpb24uTWF4aW11bUxhdGl0dWRlOwogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgc2luTGF0aXR1ZGUgPSBNYXRoLnNpbihsYXRpdHVkZSk7CiAgICAgICAgICByZXR1cm4gMC41ICogTWF0aC5sb2coKDEgKyBzaW5MYXRpdHVkZSkgLyAoMSAtIHNpbkxhdGl0dWRlKSk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIGdlb2RldGljIGVsbGlwc29pZCBjb29yZGluYXRlcywgaW4gcmFkaWFucywgdG8gdGhlIGVxdWl2YWxlbnQgV2ViIE1lcmNhdG9yCiAgICAgICAgICogWCwgWSwgWiBjb29yZGluYXRlcyBleHByZXNzZWQgaW4gbWV0ZXJzIGFuZCByZXR1cm5lZCBpbiBhIHtAbGluayBDYXJ0ZXNpYW4zfS4gIFRoZSBoZWlnaHQKICAgICAgICAgKiBpcyBjb3BpZWQgdW5tb2RpZmllZCB0byB0aGUgWiBjb29yZGluYXRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0b2dyYXBoaWN9IGNhcnRvZ3JhcGhpYyBUaGUgY2FydG9ncmFwaGljIGNvb3JkaW5hdGVzIGluIHJhZGlhbnMuCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW4zfSBbcmVzdWx0XSBUaGUgaW5zdGFuY2UgdG8gd2hpY2ggdG8gY29weSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYQogICAgICAgICAqICAgICAgICBuZXcgaW5zdGFuY2Ugc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge0NhcnRlc2lhbjN9IFRoZSBlcXVpdmFsZW50IHdlYiBtZXJjYXRvciBYLCBZLCBaIGNvb3JkaW5hdGVzLCBpbiBtZXRlcnMuCiAgICAgICAgICovCiAgICAgICAgcHJvamVjdChjYXJ0b2dyYXBoaWMyLCByZXN1bHQpIHsKICAgICAgICAgIGNvbnN0IHNlbWltYWpvckF4aXMgPSB0aGlzLl9zZW1pbWFqb3JBeGlzOwogICAgICAgICAgY29uc3QgeDIgPSBjYXJ0b2dyYXBoaWMyLmxvbmdpdHVkZSAqIHNlbWltYWpvckF4aXM7CiAgICAgICAgICBjb25zdCB5MiA9IF9XZWJNZXJjYXRvclByb2plY3Rpb24uZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZSgKICAgICAgICAgICAgY2FydG9ncmFwaGljMi5sYXRpdHVkZQogICAgICAgICAgKSAqIHNlbWltYWpvckF4aXM7CiAgICAgICAgICBjb25zdCB6MiA9IGNhcnRvZ3JhcGhpYzIuaGVpZ2h0OwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCh4MiwgeTIsIHoyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0geDI7CiAgICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgICAgcmVzdWx0LnogPSB6MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIFdlYiBNZXJjYXRvciBYLCBZIGNvb3JkaW5hdGVzLCBleHByZXNzZWQgaW4gbWV0ZXJzLCB0byBhIHtAbGluayBDYXJ0b2dyYXBoaWN9CiAgICAgICAgICogY29udGFpbmluZyBnZW9kZXRpYyBlbGxpcHNvaWQgY29vcmRpbmF0ZXMuICBUaGUgWiBjb29yZGluYXRlIGlzIGNvcGllZCB1bm1vZGlmaWVkIHRvIHRoZQogICAgICAgICAqIGhlaWdodC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuM30gY2FydGVzaWFuIFRoZSB3ZWIgbWVyY2F0b3IgQ2FydGVzaWFuIHBvc2l0aW9uIHRvIHVucnByb2plY3Qgd2l0aCBoZWlnaHQgKHopIGluIG1ldGVycy4KICAgICAgICAgKiBAcGFyYW0ge0NhcnRvZ3JhcGhpY30gW3Jlc3VsdF0gVGhlIGluc3RhbmNlIHRvIHdoaWNoIHRvIGNvcHkgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEKICAgICAgICAgKiAgICAgICAgbmV3IGluc3RhbmNlIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0b2dyYXBoaWN9IFRoZSBlcXVpdmFsZW50IGNhcnRvZ3JhcGhpYyBjb29yZGluYXRlcy4KICAgICAgICAgKi8KICAgICAgICB1bnByb2plY3QoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2FydGVzaWFuMTEpKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJjYXJ0ZXNpYW4gaXMgcmVxdWlyZWQiKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IG9uZU92ZXJFYXJ0aFNlbWltYWpvckF4aXMgPSB0aGlzLl9vbmVPdmVyU2VtaW1ham9yQXhpczsKICAgICAgICAgIGNvbnN0IGxvbmdpdHVkZSA9IGNhcnRlc2lhbjExLnggKiBvbmVPdmVyRWFydGhTZW1pbWFqb3JBeGlzOwogICAgICAgICAgY29uc3QgbGF0aXR1ZGUgPSBfV2ViTWVyY2F0b3JQcm9qZWN0aW9uLm1lcmNhdG9yQW5nbGVUb0dlb2RldGljTGF0aXR1ZGUoCiAgICAgICAgICAgIGNhcnRlc2lhbjExLnkgKiBvbmVPdmVyRWFydGhTZW1pbWFqb3JBeGlzCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgaGVpZ2h0ID0gY2FydGVzaWFuMTEuejsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdChsb25naXR1ZGUsIGxhdGl0dWRlLCBoZWlnaHQpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGxvbmdpdHVkZTsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IGxhdGl0dWRlOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICB9OwogICAgICBXZWJNZXJjYXRvclByb2plY3Rpb24uTWF4aW11bUxhdGl0dWRlID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uLm1lcmNhdG9yQW5nbGVUb0dlb2RldGljTGF0aXR1ZGUoTWF0aC5QSSk7CiAgICAgIFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0ID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1NjZW5lL1ByaW1pdGl2ZVBpcGVsaW5lLmpzCiAgZnVuY3Rpb24gdHJhbnNmb3JtVG9Xb3JsZENvb3JkaW5hdGVzKGluc3RhbmNlcywgcHJpbWl0aXZlTW9kZWxNYXRyaXgsIHNjZW5lM0RPbmx5KSB7CiAgICBsZXQgdG9Xb3JsZCA9ICFzY2VuZTNET25seTsKICAgIGNvbnN0IGxlbmd0aCA9IGluc3RhbmNlcy5sZW5ndGg7CiAgICBsZXQgaTI7CiAgICBpZiAoIXRvV29ybGQgJiYgbGVuZ3RoID4gMSkgewogICAgICBjb25zdCBtb2RlbE1hdHJpeCA9IGluc3RhbmNlc1swXS5tb2RlbE1hdHJpeDsKICAgICAgZm9yIChpMiA9IDE7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgaWYgKCFNYXRyaXg0X2RlZmF1bHQuZXF1YWxzKG1vZGVsTWF0cml4LCBpbnN0YW5jZXNbaTJdLm1vZGVsTWF0cml4KSkgewogICAgICAgICAgdG9Xb3JsZCA9IHRydWU7CiAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmICh0b1dvcmxkKSB7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2VzW2kyXS5nZW9tZXRyeSkpIHsKICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC50cmFuc2Zvcm1Ub1dvcmxkQ29vcmRpbmF0ZXMoaW5zdGFuY2VzW2kyXSk7CiAgICAgICAgfQogICAgICB9CiAgICB9IGVsc2UgewogICAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlUcmFuc2Zvcm1hdGlvbigKICAgICAgICBwcmltaXRpdmVNb2RlbE1hdHJpeCwKICAgICAgICBpbnN0YW5jZXNbMF0ubW9kZWxNYXRyaXgsCiAgICAgICAgcHJpbWl0aXZlTW9kZWxNYXRyaXgKICAgICAgKTsKICAgIH0KICB9CiAgZnVuY3Rpb24gYWRkR2VvbWV0cnlCYXRjaElkKGdlb21ldHJ5LCBiYXRjaElkKSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGNvbnN0IHBvc2l0aW9uQXR0ciA9IGF0dHJpYnV0ZXMucG9zaXRpb247CiAgICBjb25zdCBudW1iZXJPZkNvbXBvbmVudHMgPSBwb3NpdGlvbkF0dHIudmFsdWVzLmxlbmd0aCAvIHBvc2l0aW9uQXR0ci5jb21wb25lbnRzUGVyQXR0cmlidXRlOwogICAgYXR0cmlidXRlcy5iYXRjaElkID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgdmFsdWVzOiBuZXcgRmxvYXQzMkFycmF5KG51bWJlck9mQ29tcG9uZW50cykKICAgIH0pOwogICAgY29uc3QgdmFsdWVzID0gYXR0cmlidXRlcy5iYXRjaElkLnZhbHVlczsKICAgIGZvciAobGV0IGoyID0gMDsgajIgPCBudW1iZXJPZkNvbXBvbmVudHM7ICsrajIpIHsKICAgICAgdmFsdWVzW2oyXSA9IGJhdGNoSWQ7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGFkZEJhdGNoSWRzKGluc3RhbmNlcykgewogICAgY29uc3QgbGVuZ3RoID0gaW5zdGFuY2VzLmxlbmd0aDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgY29uc3QgaW5zdGFuY2UgPSBpbnN0YW5jZXNbaTJdOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlLmdlb21ldHJ5KSkgewogICAgICAgIGFkZEdlb21ldHJ5QmF0Y2hJZChpbnN0YW5jZS5nZW9tZXRyeSwgaTIpOwogICAgICB9IGVsc2UgaWYgKGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZS53ZXN0SGVtaXNwaGVyZUdlb21ldHJ5KSAmJiBkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2UuZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSkpIHsKICAgICAgICBhZGRHZW9tZXRyeUJhdGNoSWQoaW5zdGFuY2Uud2VzdEhlbWlzcGhlcmVHZW9tZXRyeSwgaTIpOwogICAgICAgIGFkZEdlb21ldHJ5QmF0Y2hJZChpbnN0YW5jZS5lYXN0SGVtaXNwaGVyZUdlb21ldHJ5LCBpMik7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gZ2VvbWV0cnlQaXBlbGluZShwYXJhbWV0ZXJzKSB7CiAgICBjb25zdCBpbnN0YW5jZXMgPSBwYXJhbWV0ZXJzLmluc3RhbmNlczsKICAgIGNvbnN0IHByb2plY3Rpb24gPSBwYXJhbWV0ZXJzLnByb2plY3Rpb247CiAgICBjb25zdCB1aW50SW5kZXhTdXBwb3J0ID0gcGFyYW1ldGVycy5lbGVtZW50SW5kZXhVaW50U3VwcG9ydGVkOwogICAgY29uc3Qgc2NlbmUzRE9ubHkgPSBwYXJhbWV0ZXJzLnNjZW5lM0RPbmx5OwogICAgY29uc3QgdmVydGV4Q2FjaGVPcHRpbWl6ZSA9IHBhcmFtZXRlcnMudmVydGV4Q2FjaGVPcHRpbWl6ZTsKICAgIGNvbnN0IGNvbXByZXNzVmVydGljZXMgPSBwYXJhbWV0ZXJzLmNvbXByZXNzVmVydGljZXM7CiAgICBjb25zdCBtb2RlbE1hdHJpeCA9IHBhcmFtZXRlcnMubW9kZWxNYXRyaXg7CiAgICBsZXQgaTI7CiAgICBsZXQgZ2VvbWV0cnk7CiAgICBsZXQgcHJpbWl0aXZlVHlwZTsKICAgIGxldCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2VzW2kyXS5nZW9tZXRyeSkpIHsKICAgICAgICBwcmltaXRpdmVUeXBlID0gaW5zdGFuY2VzW2kyXS5nZW9tZXRyeS5wcmltaXRpdmVUeXBlOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBmb3IgKGkyID0gMTsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZXNbaTJdLmdlb21ldHJ5KSAmJiBpbnN0YW5jZXNbaTJdLmdlb21ldHJ5LnByaW1pdGl2ZVR5cGUgIT09IHByaW1pdGl2ZVR5cGUpIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICJBbGwgaW5zdGFuY2UgZ2VvbWV0cmllcyBtdXN0IGhhdmUgdGhlIHNhbWUgcHJpbWl0aXZlVHlwZS4iCiAgICAgICAgKTsKICAgICAgfQogICAgfQogICAgdHJhbnNmb3JtVG9Xb3JsZENvb3JkaW5hdGVzKGluc3RhbmNlcywgbW9kZWxNYXRyaXgsIHNjZW5lM0RPbmx5KTsKICAgIGlmICghc2NlbmUzRE9ubHkpIHsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZXNbaTJdLmdlb21ldHJ5KSkgewogICAgICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LnNwbGl0TG9uZ2l0dWRlKGluc3RhbmNlc1tpMl0pOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgYWRkQmF0Y2hJZHMoaW5zdGFuY2VzKTsKICAgIGlmICh2ZXJ0ZXhDYWNoZU9wdGltaXplKSB7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgIGNvbnN0IGluc3RhbmNlID0gaW5zdGFuY2VzW2kyXTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlLmdlb21ldHJ5KSkgewogICAgICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LnJlb3JkZXJGb3JQb3N0VmVydGV4Q2FjaGUoaW5zdGFuY2UuZ2VvbWV0cnkpOwogICAgICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LnJlb3JkZXJGb3JQcmVWZXJ0ZXhDYWNoZShpbnN0YW5jZS5nZW9tZXRyeSk7CiAgICAgICAgfSBlbHNlIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2Uud2VzdEhlbWlzcGhlcmVHZW9tZXRyeSkgJiYgZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlLmVhc3RIZW1pc3BoZXJlR2VvbWV0cnkpKSB7CiAgICAgICAgICBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQucmVvcmRlckZvclBvc3RWZXJ0ZXhDYWNoZSgKICAgICAgICAgICAgaW5zdGFuY2Uud2VzdEhlbWlzcGhlcmVHZW9tZXRyeQogICAgICAgICAgKTsKICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5yZW9yZGVyRm9yUHJlVmVydGV4Q2FjaGUoCiAgICAgICAgICAgIGluc3RhbmNlLndlc3RIZW1pc3BoZXJlR2VvbWV0cnkKICAgICAgICAgICk7CiAgICAgICAgICBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQucmVvcmRlckZvclBvc3RWZXJ0ZXhDYWNoZSgKICAgICAgICAgICAgaW5zdGFuY2UuZWFzdEhlbWlzcGhlcmVHZW9tZXRyeQogICAgICAgICAgKTsKICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5yZW9yZGVyRm9yUHJlVmVydGV4Q2FjaGUoCiAgICAgICAgICAgIGluc3RhbmNlLmVhc3RIZW1pc3BoZXJlR2VvbWV0cnkKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBsZXQgZ2VvbWV0cmllcyA9IEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5jb21iaW5lSW5zdGFuY2VzKGluc3RhbmNlcyk7CiAgICBsZW5ndGggPSBnZW9tZXRyaWVzLmxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBnZW9tZXRyeSA9IGdlb21ldHJpZXNbaTJdOwogICAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgaWYgKCFzY2VuZTNET25seSkgewogICAgICAgIGZvciAoY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzKSB7CiAgICAgICAgICBpZiAoYXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShuYW1lKSAmJiBhdHRyaWJ1dGVzW25hbWVdLmNvbXBvbmVudERhdGF0eXBlID09PSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSkgewogICAgICAgICAgICBjb25zdCBuYW1lM0QgPSBgJHtuYW1lfTNEYDsKICAgICAgICAgICAgY29uc3QgbmFtZTJEID0gYCR7bmFtZX0yRGA7CiAgICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5wcm9qZWN0VG8yRCgKICAgICAgICAgICAgICBnZW9tZXRyeSwKICAgICAgICAgICAgICBuYW1lLAogICAgICAgICAgICAgIG5hbWUzRCwKICAgICAgICAgICAgICBuYW1lMkQsCiAgICAgICAgICAgICAgcHJvamVjdGlvbgogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlKSAmJiBuYW1lID09PSAicG9zaXRpb24iKSB7CiAgICAgICAgICAgICAgZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmVDViA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjJELnZhbHVlcwogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmVuY29kZUF0dHJpYnV0ZSgKICAgICAgICAgICAgICBnZW9tZXRyeSwKICAgICAgICAgICAgICBuYW1lM0QsCiAgICAgICAgICAgICAgYCR7bmFtZTNEfUhpZ2hgLAogICAgICAgICAgICAgIGAke25hbWUzRH1Mb3dgCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5lbmNvZGVBdHRyaWJ1dGUoCiAgICAgICAgICAgICAgZ2VvbWV0cnksCiAgICAgICAgICAgICAgbmFtZTJELAogICAgICAgICAgICAgIGAke25hbWUyRH1IaWdoYCwKICAgICAgICAgICAgICBgJHtuYW1lMkR9TG93YAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBmb3IgKGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcykgewogICAgICAgICAgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkobmFtZSkgJiYgYXR0cmlidXRlc1tuYW1lXS5jb21wb25lbnREYXRhdHlwZSA9PT0gQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUpIHsKICAgICAgICAgICAgR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmVuY29kZUF0dHJpYnV0ZSgKICAgICAgICAgICAgICBnZW9tZXRyeSwKICAgICAgICAgICAgICBuYW1lLAogICAgICAgICAgICAgIGAke25hbWV9M0RIaWdoYCwKICAgICAgICAgICAgICBgJHtuYW1lfTNETG93YAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoY29tcHJlc3NWZXJ0aWNlcykgewogICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5jb21wcmVzc1ZlcnRpY2VzKGdlb21ldHJ5KTsKICAgICAgfQogICAgfQogICAgaWYgKCF1aW50SW5kZXhTdXBwb3J0KSB7CiAgICAgIGxldCBzcGxpdEdlb21ldHJpZXMgPSBbXTsKICAgICAgbGVuZ3RoID0gZ2VvbWV0cmllcy5sZW5ndGg7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgIGdlb21ldHJ5ID0gZ2VvbWV0cmllc1tpMl07CiAgICAgICAgc3BsaXRHZW9tZXRyaWVzID0gc3BsaXRHZW9tZXRyaWVzLmNvbmNhdCgKICAgICAgICAgIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5maXRUb1Vuc2lnbmVkU2hvcnRJbmRpY2VzKGdlb21ldHJ5KQogICAgICAgICk7CiAgICAgIH0KICAgICAgZ2VvbWV0cmllcyA9IHNwbGl0R2VvbWV0cmllczsKICAgIH0KICAgIHJldHVybiBnZW9tZXRyaWVzOwogIH0KICBmdW5jdGlvbiBjcmVhdGVQaWNrT2Zmc2V0cyhpbnN0YW5jZXMsIGdlb21ldHJ5TmFtZSwgZ2VvbWV0cmllcywgcGlja09mZnNldHMpIHsKICAgIGxldCBvZmZzZXQ7CiAgICBsZXQgaW5kZXhDb3VudDsKICAgIGxldCBnZW9tZXRyeUluZGV4OwogICAgY29uc3Qgb2Zmc2V0SW5kZXggPSBwaWNrT2Zmc2V0cy5sZW5ndGggLSAxOwogICAgaWYgKG9mZnNldEluZGV4ID49IDApIHsKICAgICAgY29uc3QgcGlja09mZnNldCA9IHBpY2tPZmZzZXRzW29mZnNldEluZGV4XTsKICAgICAgb2Zmc2V0ID0gcGlja09mZnNldC5vZmZzZXQgKyBwaWNrT2Zmc2V0LmNvdW50OwogICAgICBnZW9tZXRyeUluZGV4ID0gcGlja09mZnNldC5pbmRleDsKICAgICAgaW5kZXhDb3VudCA9IGdlb21ldHJpZXNbZ2VvbWV0cnlJbmRleF0uaW5kaWNlcy5sZW5ndGg7CiAgICB9IGVsc2UgewogICAgICBvZmZzZXQgPSAwOwogICAgICBnZW9tZXRyeUluZGV4ID0gMDsKICAgICAgaW5kZXhDb3VudCA9IGdlb21ldHJpZXNbZ2VvbWV0cnlJbmRleF0uaW5kaWNlcy5sZW5ndGg7CiAgICB9CiAgICBjb25zdCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBjb25zdCBpbnN0YW5jZSA9IGluc3RhbmNlc1tpMl07CiAgICAgIGNvbnN0IGdlb21ldHJ5ID0gaW5zdGFuY2VbZ2VvbWV0cnlOYW1lXTsKICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgY29uc3QgY291bnQgPSBnZW9tZXRyeS5pbmRpY2VzLmxlbmd0aDsKICAgICAgaWYgKG9mZnNldCArIGNvdW50ID4gaW5kZXhDb3VudCkgewogICAgICAgIG9mZnNldCA9IDA7CiAgICAgICAgaW5kZXhDb3VudCA9IGdlb21ldHJpZXNbKytnZW9tZXRyeUluZGV4XS5pbmRpY2VzLmxlbmd0aDsKICAgICAgfQogICAgICBwaWNrT2Zmc2V0cy5wdXNoKHsKICAgICAgICBpbmRleDogZ2VvbWV0cnlJbmRleCwKICAgICAgICBvZmZzZXQsCiAgICAgICAgY291bnQKICAgICAgfSk7CiAgICAgIG9mZnNldCArPSBjb3VudDsKICAgIH0KICB9CiAgZnVuY3Rpb24gY3JlYXRlSW5zdGFuY2VQaWNrT2Zmc2V0cyhpbnN0YW5jZXMsIGdlb21ldHJpZXMpIHsKICAgIGNvbnN0IHBpY2tPZmZzZXRzID0gW107CiAgICBjcmVhdGVQaWNrT2Zmc2V0cyhpbnN0YW5jZXMsICJnZW9tZXRyeSIsIGdlb21ldHJpZXMsIHBpY2tPZmZzZXRzKTsKICAgIGNyZWF0ZVBpY2tPZmZzZXRzKAogICAgICBpbnN0YW5jZXMsCiAgICAgICJ3ZXN0SGVtaXNwaGVyZUdlb21ldHJ5IiwKICAgICAgZ2VvbWV0cmllcywKICAgICAgcGlja09mZnNldHMKICAgICk7CiAgICBjcmVhdGVQaWNrT2Zmc2V0cygKICAgICAgaW5zdGFuY2VzLAogICAgICAiZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSIsCiAgICAgIGdlb21ldHJpZXMsCiAgICAgIHBpY2tPZmZzZXRzCiAgICApOwogICAgcmV0dXJuIHBpY2tPZmZzZXRzOwogIH0KICBmdW5jdGlvbiB0cmFuc2Zlckdlb21ldHJ5KGdlb21ldHJ5LCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgIGZvciAoY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzKSB7CiAgICAgIGlmIChhdHRyaWJ1dGVzLmhhc093blByb3BlcnR5KG5hbWUpKSB7CiAgICAgICAgY29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1tuYW1lXTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZSkgJiYgZGVmaW5lZF9kZWZhdWx0KGF0dHJpYnV0ZS52YWx1ZXMpKSB7CiAgICAgICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goYXR0cmlidXRlLnZhbHVlcy5idWZmZXIpOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5pbmRpY2VzKSkgewogICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goZ2VvbWV0cnkuaW5kaWNlcy5idWZmZXIpOwogICAgfQogIH0KICBmdW5jdGlvbiB0cmFuc2Zlckdlb21ldHJpZXMoZ2VvbWV0cmllcywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgbGVuZ3RoID0gZ2VvbWV0cmllcy5sZW5ndGg7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIHRyYW5zZmVyR2VvbWV0cnkoZ2VvbWV0cmllc1tpMl0sIHRyYW5zZmVyYWJsZU9iamVjdHMpOwogICAgfQogIH0KICBmdW5jdGlvbiBjb3VudENyZWF0ZUdlb21ldHJ5UmVzdWx0cyhpdGVtcykgewogICAgbGV0IGNvdW50ID0gMTsKICAgIGNvbnN0IGxlbmd0aCA9IGl0ZW1zLmxlbmd0aDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgZ2VvbWV0cnkgPSBpdGVtc1tpMl07CiAgICAgICsrY291bnQ7CiAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5KSkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzOwogICAgICBjb3VudCArPSA3ICsgMiAqIEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgKGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5pbmRpY2VzKSA/IGdlb21ldHJ5LmluZGljZXMubGVuZ3RoIDogMCk7CiAgICAgIGZvciAoY29uc3QgcHJvcGVydHkgaW4gYXR0cmlidXRlcykgewogICAgICAgIGlmIChhdHRyaWJ1dGVzLmhhc093blByb3BlcnR5KHByb3BlcnR5KSAmJiBkZWZpbmVkX2RlZmF1bHQoYXR0cmlidXRlc1twcm9wZXJ0eV0pKSB7CiAgICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzW3Byb3BlcnR5XTsKICAgICAgICAgIGNvdW50ICs9IDUgKyBhdHRyaWJ1dGUudmFsdWVzLmxlbmd0aDsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBjb3VudDsKICB9CiAgZnVuY3Rpb24gcGFja0luc3RhbmNlc0ZvckNvbWJpbmUoaW5zdGFuY2VzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgY29uc3QgcGFja2VkRGF0YSA9IG5ldyBGbG9hdDY0QXJyYXkoMSArIGxlbmd0aCAqIDE5KTsKICAgIGxldCBjb3VudCA9IDA7CiAgICBwYWNrZWREYXRhW2NvdW50KytdID0gbGVuZ3RoOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICBjb25zdCBpbnN0YW5jZSA9IGluc3RhbmNlc1tpMl07CiAgICAgIE1hdHJpeDRfZGVmYXVsdC5wYWNrKGluc3RhbmNlLm1vZGVsTWF0cml4LCBwYWNrZWREYXRhLCBjb3VudCk7CiAgICAgIGNvdW50ICs9IE1hdHJpeDRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2UuYXR0cmlidXRlcykgJiYgZGVmaW5lZF9kZWZhdWx0KGluc3RhbmNlLmF0dHJpYnV0ZXMub2Zmc2V0KSkgewogICAgICAgIGNvbnN0IHZhbHVlcyA9IGluc3RhbmNlLmF0dHJpYnV0ZXMub2Zmc2V0LnZhbHVlOwogICAgICAgIHBhY2tlZERhdGFbY291bnRdID0gdmFsdWVzWzBdOwogICAgICAgIHBhY2tlZERhdGFbY291bnQgKyAxXSA9IHZhbHVlc1sxXTsKICAgICAgICBwYWNrZWREYXRhW2NvdW50ICsgMl0gPSB2YWx1ZXNbMl07CiAgICAgIH0KICAgICAgY291bnQgKz0gMzsKICAgIH0KICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChwYWNrZWREYXRhLmJ1ZmZlcik7CiAgICByZXR1cm4gcGFja2VkRGF0YTsKICB9CiAgZnVuY3Rpb24gdW5wYWNrSW5zdGFuY2VzRm9yQ29tYmluZShkYXRhKSB7CiAgICBjb25zdCBwYWNrZWRJbnN0YW5jZXMgPSBkYXRhOwogICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5KHBhY2tlZEluc3RhbmNlc1swXSk7CiAgICBsZXQgY291bnQgPSAwOwogICAgbGV0IGkyID0gMTsKICAgIHdoaWxlIChpMiA8IHBhY2tlZEluc3RhbmNlcy5sZW5ndGgpIHsKICAgICAgY29uc3QgbW9kZWxNYXRyaXggPSBNYXRyaXg0X2RlZmF1bHQudW5wYWNrKHBhY2tlZEluc3RhbmNlcywgaTIpOwogICAgICBsZXQgYXR0cmlidXRlczsKICAgICAgaTIgKz0gTWF0cml4NF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChwYWNrZWRJbnN0YW5jZXNbaTJdKSkgewogICAgICAgIGF0dHJpYnV0ZXMgPSB7CiAgICAgICAgICBvZmZzZXQ6IG5ldyBPZmZzZXRHZW9tZXRyeUluc3RhbmNlQXR0cmlidXRlX2RlZmF1bHQoCiAgICAgICAgICAgIHBhY2tlZEluc3RhbmNlc1tpMl0sCiAgICAgICAgICAgIHBhY2tlZEluc3RhbmNlc1tpMiArIDFdLAogICAgICAgICAgICBwYWNrZWRJbnN0YW5jZXNbaTIgKyAyXQogICAgICAgICAgKQogICAgICAgIH07CiAgICAgIH0KICAgICAgaTIgKz0gMzsKICAgICAgcmVzdWx0W2NvdW50KytdID0gewogICAgICAgIG1vZGVsTWF0cml4LAogICAgICAgIGF0dHJpYnV0ZXMKICAgICAgfTsKICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIHBhY2tCb3VuZGluZ1NwaGVyZXMoYm91bmRpbmdTcGhlcmVzKSB7CiAgICBjb25zdCBsZW5ndGggPSBib3VuZGluZ1NwaGVyZXMubGVuZ3RoOwogICAgY29uc3QgYnVmZmVyTGVuZ3RoID0gMSArIChCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDEpICogbGVuZ3RoOwogICAgY29uc3QgYnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheShidWZmZXJMZW5ndGgpOwogICAgbGV0IGJ1ZmZlckluZGV4ID0gMDsKICAgIGJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IGxlbmd0aDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgY29uc3QgYnMgPSBib3VuZGluZ1NwaGVyZXNbaTJdOwogICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChicykpIHsKICAgICAgICBidWZmZXJbYnVmZmVySW5kZXgrK10gPSAwOwogICAgICB9IGVsc2UgewogICAgICAgIGJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IDE7CiAgICAgICAgQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5wYWNrKGJvdW5kaW5nU3BoZXJlc1tpMl0sIGJ1ZmZlciwgYnVmZmVySW5kZXgpOwogICAgICB9CiAgICAgIGJ1ZmZlckluZGV4ICs9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgfQogICAgcmV0dXJuIGJ1ZmZlcjsKICB9CiAgZnVuY3Rpb24gdW5wYWNrQm91bmRpbmdTcGhlcmVzKGJ1ZmZlcikgewogICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5KGJ1ZmZlclswXSk7CiAgICBsZXQgY291bnQgPSAwOwogICAgbGV0IGkyID0gMTsKICAgIHdoaWxlIChpMiA8IGJ1ZmZlci5sZW5ndGgpIHsKICAgICAgaWYgKGJ1ZmZlcltpMisrXSA9PT0gMSkgewogICAgICAgIHJlc3VsdFtjb3VudF0gPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnVucGFjayhidWZmZXIsIGkyKTsKICAgICAgfQogICAgICArK2NvdW50OwogICAgICBpMiArPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBQcmltaXRpdmVQaXBlbGluZSwgUHJpbWl0aXZlUGlwZWxpbmVfZGVmYXVsdDsKICB2YXIgaW5pdF9QcmltaXRpdmVQaXBlbGluZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1NjZW5lL1ByaW1pdGl2ZVBpcGVsaW5lLmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvZ3JhcGhpY1Byb2plY3Rpb24oKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfR2VvbWV0cnlQaXBlbGluZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfT2Zmc2V0R2VvbWV0cnlJbnN0YW5jZUF0dHJpYnV0ZSgpOwogICAgICBpbml0X1dlYk1lcmNhdG9yUHJvamVjdGlvbigpOwogICAgICBQcmltaXRpdmVQaXBlbGluZSA9IHt9OwogICAgICBQcmltaXRpdmVQaXBlbGluZS5jb21iaW5lR2VvbWV0cnkgPSBmdW5jdGlvbihwYXJhbWV0ZXJzKSB7CiAgICAgICAgbGV0IGdlb21ldHJpZXM7CiAgICAgICAgbGV0IGF0dHJpYnV0ZUxvY2F0aW9uczsKICAgICAgICBjb25zdCBpbnN0YW5jZXMgPSBwYXJhbWV0ZXJzLmluc3RhbmNlczsKICAgICAgICBjb25zdCBsZW5ndGggPSBpbnN0YW5jZXMubGVuZ3RoOwogICAgICAgIGxldCBwaWNrT2Zmc2V0czsKICAgICAgICBsZXQgb2Zmc2V0SW5zdGFuY2VFeHRlbmQ7CiAgICAgICAgbGV0IGhhc09mZnNldCA9IGZhbHNlOwogICAgICAgIGlmIChsZW5ndGggPiAwKSB7CiAgICAgICAgICBnZW9tZXRyaWVzID0gZ2VvbWV0cnlQaXBlbGluZShwYXJhbWV0ZXJzKTsKICAgICAgICAgIGlmIChnZW9tZXRyaWVzLmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgYXR0cmlidXRlTG9jYXRpb25zID0gR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmNyZWF0ZUF0dHJpYnV0ZUxvY2F0aW9ucygKICAgICAgICAgICAgICBnZW9tZXRyaWVzWzBdCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGlmIChwYXJhbWV0ZXJzLmNyZWF0ZVBpY2tPZmZzZXRzKSB7CiAgICAgICAgICAgICAgcGlja09mZnNldHMgPSBjcmVhdGVJbnN0YW5jZVBpY2tPZmZzZXRzKGluc3RhbmNlcywgZ2VvbWV0cmllcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW5zdGFuY2VzWzBdLmF0dHJpYnV0ZXMpICYmIGRlZmluZWRfZGVmYXVsdChpbnN0YW5jZXNbMF0uYXR0cmlidXRlcy5vZmZzZXQpKSB7CiAgICAgICAgICAgIG9mZnNldEluc3RhbmNlRXh0ZW5kID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgICAgIGhhc09mZnNldCA9IHRydWU7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGJvdW5kaW5nU3BoZXJlcyA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgIGNvbnN0IGJvdW5kaW5nU3BoZXJlc0NWID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY29uc3QgaW5zdGFuY2UgPSBpbnN0YW5jZXNbaTJdOwogICAgICAgICAgY29uc3QgZ2VvbWV0cnkgPSBpbnN0YW5jZS5nZW9tZXRyeTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpKSB7CiAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlc1tpMl0gPSBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZTsKICAgICAgICAgICAgYm91bmRpbmdTcGhlcmVzQ1ZbaTJdID0gZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmVDVjsKICAgICAgICAgICAgaWYgKGhhc09mZnNldCkgewogICAgICAgICAgICAgIG9mZnNldEluc3RhbmNlRXh0ZW5kW2kyXSA9IGluc3RhbmNlLmdlb21ldHJ5Lm9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgY29uc3QgZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSA9IGluc3RhbmNlLmVhc3RIZW1pc3BoZXJlR2VvbWV0cnk7CiAgICAgICAgICBjb25zdCB3ZXN0SGVtaXNwaGVyZUdlb21ldHJ5ID0gaW5zdGFuY2Uud2VzdEhlbWlzcGhlcmVHZW9tZXRyeTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZWFzdEhlbWlzcGhlcmVHZW9tZXRyeSkgJiYgZGVmaW5lZF9kZWZhdWx0KHdlc3RIZW1pc3BoZXJlR2VvbWV0cnkpKSB7CiAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZWFzdEhlbWlzcGhlcmVHZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSkgJiYgZGVmaW5lZF9kZWZhdWx0KHdlc3RIZW1pc3BoZXJlR2VvbWV0cnkuYm91bmRpbmdTcGhlcmUpKSB7CiAgICAgICAgICAgICAgYm91bmRpbmdTcGhlcmVzW2kyXSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQudW5pb24oCiAgICAgICAgICAgICAgICBlYXN0SGVtaXNwaGVyZUdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgICAgICAgd2VzdEhlbWlzcGhlcmVHZW9tZXRyeS5ib3VuZGluZ1NwaGVyZQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChlYXN0SGVtaXNwaGVyZUdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlQ1YpICYmIGRlZmluZWRfZGVmYXVsdCh3ZXN0SGVtaXNwaGVyZUdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlQ1YpKSB7CiAgICAgICAgICAgICAgYm91bmRpbmdTcGhlcmVzQ1ZbaTJdID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC51bmlvbigKICAgICAgICAgICAgICAgIGVhc3RIZW1pc3BoZXJlR2VvbWV0cnkuYm91bmRpbmdTcGhlcmVDViwKICAgICAgICAgICAgICAgIHdlc3RIZW1pc3BoZXJlR2VvbWV0cnkuYm91bmRpbmdTcGhlcmVDVgogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIGdlb21ldHJpZXMsCiAgICAgICAgICBtb2RlbE1hdHJpeDogcGFyYW1ldGVycy5tb2RlbE1hdHJpeCwKICAgICAgICAgIGF0dHJpYnV0ZUxvY2F0aW9ucywKICAgICAgICAgIHBpY2tPZmZzZXRzLAogICAgICAgICAgb2Zmc2V0SW5zdGFuY2VFeHRlbmQsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZXMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZXNDVgogICAgICAgIH07CiAgICAgIH07CiAgICAgIFByaW1pdGl2ZVBpcGVsaW5lLnBhY2tDcmVhdGVHZW9tZXRyeVJlc3VsdHMgPSBmdW5jdGlvbihpdGVtcywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgICAgIGNvbnN0IHBhY2tlZERhdGEgPSBuZXcgRmxvYXQ2NEFycmF5KGNvdW50Q3JlYXRlR2VvbWV0cnlSZXN1bHRzKGl0ZW1zKSk7CiAgICAgICAgY29uc3Qgc3RyaW5nVGFibGUgPSBbXTsKICAgICAgICBjb25zdCBzdHJpbmdIYXNoID0ge307CiAgICAgICAgY29uc3QgbGVuZ3RoID0gaXRlbXMubGVuZ3RoOwogICAgICAgIGxldCBjb3VudCA9IDA7CiAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IGxlbmd0aDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBnZW9tZXRyeSA9IGl0ZW1zW2kyXTsKICAgICAgICAgIGNvbnN0IHZhbGlkR2VvbWV0cnkgPSBkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpOwogICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IHZhbGlkR2VvbWV0cnkgPyAxIDogMDsKICAgICAgICAgIGlmICghdmFsaWRHZW9tZXRyeSkgewogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICAgIHBhY2tlZERhdGFbY291bnQrK10gPSBnZW9tZXRyeS5wcmltaXRpdmVUeXBlOwogICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IGdlb21ldHJ5Lmdlb21ldHJ5VHlwZTsKICAgICAgICAgIHBhY2tlZERhdGFbY291bnQrK10gPSBnZW9tZXRyeS5vZmZzZXRBdHRyaWJ1dGUgPz8gLTE7CiAgICAgICAgICBjb25zdCB2YWxpZEJvdW5kaW5nU3BoZXJlID0gZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlKSA/IDEgOiAwOwogICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IHZhbGlkQm91bmRpbmdTcGhlcmU7CiAgICAgICAgICBpZiAodmFsaWRCb3VuZGluZ1NwaGVyZSkgewogICAgICAgICAgICBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2soZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUsIHBhY2tlZERhdGEsIGNvdW50KTsKICAgICAgICAgIH0KICAgICAgICAgIGNvdW50ICs9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgICAgY29uc3QgdmFsaWRCb3VuZGluZ1NwaGVyZUNWID0gZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlQ1YpID8gMSA6IDA7CiAgICAgICAgICBwYWNrZWREYXRhW2NvdW50KytdID0gdmFsaWRCb3VuZGluZ1NwaGVyZUNWOwogICAgICAgICAgaWYgKHZhbGlkQm91bmRpbmdTcGhlcmVDVikgewogICAgICAgICAgICBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2soZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmVDViwgcGFja2VkRGF0YSwgY291bnQpOwogICAgICAgICAgfQogICAgICAgICAgY291bnQgKz0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICAgIGNvbnN0IGF0dHJpYnV0ZXNUb1dyaXRlID0gW107CiAgICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5IGluIGF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkocHJvcGVydHkpICYmIGRlZmluZWRfZGVmYXVsdChhdHRyaWJ1dGVzW3Byb3BlcnR5XSkpIHsKICAgICAgICAgICAgICBhdHRyaWJ1dGVzVG9Xcml0ZS5wdXNoKHByb3BlcnR5KTsKICAgICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzdHJpbmdIYXNoW3Byb3BlcnR5XSkpIHsKICAgICAgICAgICAgICAgIHN0cmluZ0hhc2hbcHJvcGVydHldID0gc3RyaW5nVGFibGUubGVuZ3RoOwogICAgICAgICAgICAgICAgc3RyaW5nVGFibGUucHVzaChwcm9wZXJ0eSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBwYWNrZWREYXRhW2NvdW50KytdID0gYXR0cmlidXRlc1RvV3JpdGUubGVuZ3RoOwogICAgICAgICAgZm9yIChsZXQgcTMgPSAwOyBxMyA8IGF0dHJpYnV0ZXNUb1dyaXRlLmxlbmd0aDsgcTMrKykgewogICAgICAgICAgICBjb25zdCBuYW1lID0gYXR0cmlidXRlc1RvV3JpdGVbcTNdOwogICAgICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzW25hbWVdOwogICAgICAgICAgICBwYWNrZWREYXRhW2NvdW50KytdID0gc3RyaW5nSGFzaFtuYW1lXTsKICAgICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IGF0dHJpYnV0ZS5jb21wb25lbnREYXRhdHlwZTsKICAgICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IGF0dHJpYnV0ZS5jb21wb25lbnRzUGVyQXR0cmlidXRlOwogICAgICAgICAgICBwYWNrZWREYXRhW2NvdW50KytdID0gYXR0cmlidXRlLm5vcm1hbGl6ZSA/IDEgOiAwOwogICAgICAgICAgICBwYWNrZWREYXRhW2NvdW50KytdID0gYXR0cmlidXRlLnZhbHVlcy5sZW5ndGg7CiAgICAgICAgICAgIHBhY2tlZERhdGEuc2V0KGF0dHJpYnV0ZS52YWx1ZXMsIGNvdW50KTsKICAgICAgICAgICAgY291bnQgKz0gYXR0cmlidXRlLnZhbHVlcy5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBpbmRpY2VzTGVuZ3RoID0gZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmluZGljZXMpID8gZ2VvbWV0cnkuaW5kaWNlcy5sZW5ndGggOiAwOwogICAgICAgICAgcGFja2VkRGF0YVtjb3VudCsrXSA9IGluZGljZXNMZW5ndGg7CiAgICAgICAgICBpZiAoaW5kaWNlc0xlbmd0aCA+IDApIHsKICAgICAgICAgICAgcGFja2VkRGF0YS5zZXQoZ2VvbWV0cnkuaW5kaWNlcywgY291bnQpOwogICAgICAgICAgICBjb3VudCArPSBpbmRpY2VzTGVuZ3RoOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2gocGFja2VkRGF0YS5idWZmZXIpOwogICAgICAgIHJldHVybiB7CiAgICAgICAgICBzdHJpbmdUYWJsZSwKICAgICAgICAgIHBhY2tlZERhdGEKICAgICAgICB9OwogICAgICB9OwogICAgICBQcmltaXRpdmVQaXBlbGluZS51bnBhY2tDcmVhdGVHZW9tZXRyeVJlc3VsdHMgPSBmdW5jdGlvbihjcmVhdGVHZW9tZXRyeVJlc3VsdCkgewogICAgICAgIGNvbnN0IHN0cmluZ1RhYmxlID0gY3JlYXRlR2VvbWV0cnlSZXN1bHQuc3RyaW5nVGFibGU7CiAgICAgICAgY29uc3QgcGFja2VkR2VvbWV0cnkgPSBjcmVhdGVHZW9tZXRyeVJlc3VsdC5wYWNrZWREYXRhOwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXkocGFja2VkR2VvbWV0cnlbMF0pOwogICAgICAgIGxldCByZXN1bHRJbmRleCA9IDA7CiAgICAgICAgbGV0IHBhY2tlZEdlb21ldHJ5SW5kZXggPSAxOwogICAgICAgIHdoaWxlIChwYWNrZWRHZW9tZXRyeUluZGV4IDwgcGFja2VkR2VvbWV0cnkubGVuZ3RoKSB7CiAgICAgICAgICBjb25zdCB2YWxpZCA9IHBhY2tlZEdlb21ldHJ5W3BhY2tlZEdlb21ldHJ5SW5kZXgrK10gPT09IDE7CiAgICAgICAgICBpZiAoIXZhbGlkKSB7CiAgICAgICAgICAgIHJlc3VsdFtyZXN1bHRJbmRleCsrXSA9IHZvaWQgMDsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBwcmltaXRpdmVUeXBlID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgIGNvbnN0IGdlb21ldHJ5VHlwZSA9IHBhY2tlZEdlb21ldHJ5W3BhY2tlZEdlb21ldHJ5SW5kZXgrK107CiAgICAgICAgICBsZXQgb2Zmc2V0QXR0cmlidXRlID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgIGlmIChvZmZzZXRBdHRyaWJ1dGUgPT09IC0xKSB7CiAgICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBib3VuZGluZ1NwaGVyZTsKICAgICAgICAgIGxldCBib3VuZGluZ1NwaGVyZUNWOwogICAgICAgICAgY29uc3QgdmFsaWRCb3VuZGluZ1NwaGVyZSA9IHBhY2tlZEdlb21ldHJ5W3BhY2tlZEdlb21ldHJ5SW5kZXgrK10gPT09IDE7CiAgICAgICAgICBpZiAodmFsaWRCb3VuZGluZ1NwaGVyZSkgewogICAgICAgICAgICBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgICAgIHBhY2tlZEdlb21ldHJ5LAogICAgICAgICAgICAgIHBhY2tlZEdlb21ldHJ5SW5kZXgKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHBhY2tlZEdlb21ldHJ5SW5kZXggKz0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgICBjb25zdCB2YWxpZEJvdW5kaW5nU3BoZXJlQ1YgPSBwYWNrZWRHZW9tZXRyeVtwYWNrZWRHZW9tZXRyeUluZGV4KytdID09PSAxOwogICAgICAgICAgaWYgKHZhbGlkQm91bmRpbmdTcGhlcmVDVikgewogICAgICAgICAgICBib3VuZGluZ1NwaGVyZUNWID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgICAgcGFja2VkR2VvbWV0cnksCiAgICAgICAgICAgICAgcGFja2VkR2VvbWV0cnlJbmRleAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgcGFja2VkR2VvbWV0cnlJbmRleCArPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICAgIGxldCBsZW5ndGg7CiAgICAgICAgICBsZXQgdmFsdWVzOwogICAgICAgICAgbGV0IGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU7CiAgICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICAgICAgICBjb25zdCBudW1BdHRyaWJ1dGVzID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bUF0dHJpYnV0ZXM7IGkyKyspIHsKICAgICAgICAgICAgY29uc3QgbmFtZSA9IHN0cmluZ1RhYmxlW3BhY2tlZEdlb21ldHJ5W3BhY2tlZEdlb21ldHJ5SW5kZXgrK11dOwogICAgICAgICAgICBjb25zdCBjb21wb25lbnREYXRhdHlwZSA9IHBhY2tlZEdlb21ldHJ5W3BhY2tlZEdlb21ldHJ5SW5kZXgrK107CiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGUgPSBwYWNrZWRHZW9tZXRyeVtwYWNrZWRHZW9tZXRyeUluZGV4KytdOwogICAgICAgICAgICBjb25zdCBub3JtYWxpemUgPSBwYWNrZWRHZW9tZXRyeVtwYWNrZWRHZW9tZXRyeUluZGV4KytdICE9PSAwOwogICAgICAgICAgICBsZW5ndGggPSBwYWNrZWRHZW9tZXRyeVtwYWNrZWRHZW9tZXRyeUluZGV4KytdOwogICAgICAgICAgICB2YWx1ZXMgPSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoY29tcG9uZW50RGF0YXR5cGUsIGxlbmd0aCk7CiAgICAgICAgICAgIGZvciAobGV0IHZhbHVlc0luZGV4ID0gMDsgdmFsdWVzSW5kZXggPCBsZW5ndGg7IHZhbHVlc0luZGV4KyspIHsKICAgICAgICAgICAgICB2YWx1ZXNbdmFsdWVzSW5kZXhdID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBhdHRyaWJ1dGVzW25hbWVdID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGUsCiAgICAgICAgICAgICAgbm9ybWFsaXplLAogICAgICAgICAgICAgIHZhbHVlcwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBpbmRpY2VzOwogICAgICAgICAgbGVuZ3RoID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgIGlmIChsZW5ndGggPiAwKSB7CiAgICAgICAgICAgIGNvbnN0IG51bWJlck9mVmVydGljZXMgPSB2YWx1ZXMubGVuZ3RoIC8gY29tcG9uZW50c1BlckF0dHJpYnV0ZTsKICAgICAgICAgICAgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KG51bWJlck9mVmVydGljZXMsIGxlbmd0aCk7CiAgICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgICAgIGluZGljZXNbaTJdID0gcGFja2VkR2VvbWV0cnlbcGFja2VkR2VvbWV0cnlJbmRleCsrXTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0W3Jlc3VsdEluZGV4KytdID0gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgICBwcmltaXRpdmVUeXBlLAogICAgICAgICAgICBnZW9tZXRyeVR5cGUsCiAgICAgICAgICAgIGJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgICBib3VuZGluZ1NwaGVyZUNWLAogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgICBvZmZzZXRBdHRyaWJ1dGUKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQcmltaXRpdmVQaXBlbGluZS5wYWNrQ29tYmluZUdlb21ldHJ5UGFyYW1ldGVycyA9IGZ1bmN0aW9uKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgICAgICBjb25zdCBjcmVhdGVHZW9tZXRyeVJlc3VsdHMgPSBwYXJhbWV0ZXJzLmNyZWF0ZUdlb21ldHJ5UmVzdWx0czsKICAgICAgICBjb25zdCBsZW5ndGggPSBjcmVhdGVHZW9tZXRyeVJlc3VsdHMubGVuZ3RoOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChjcmVhdGVHZW9tZXRyeVJlc3VsdHNbaTJdLnBhY2tlZERhdGEuYnVmZmVyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIGNyZWF0ZUdlb21ldHJ5UmVzdWx0czogcGFyYW1ldGVycy5jcmVhdGVHZW9tZXRyeVJlc3VsdHMsCiAgICAgICAgICBwYWNrZWRJbnN0YW5jZXM6IHBhY2tJbnN0YW5jZXNGb3JDb21iaW5lKAogICAgICAgICAgICBwYXJhbWV0ZXJzLmluc3RhbmNlcywKICAgICAgICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cwogICAgICAgICAgKSwKICAgICAgICAgIGVsbGlwc29pZDogcGFyYW1ldGVycy5lbGxpcHNvaWQsCiAgICAgICAgICBpc0dlb2dyYXBoaWM6IHBhcmFtZXRlcnMucHJvamVjdGlvbiBpbnN0YW5jZW9mIEdlb2dyYXBoaWNQcm9qZWN0aW9uX2RlZmF1bHQsCiAgICAgICAgICBlbGVtZW50SW5kZXhVaW50U3VwcG9ydGVkOiBwYXJhbWV0ZXJzLmVsZW1lbnRJbmRleFVpbnRTdXBwb3J0ZWQsCiAgICAgICAgICBzY2VuZTNET25seTogcGFyYW1ldGVycy5zY2VuZTNET25seSwKICAgICAgICAgIHZlcnRleENhY2hlT3B0aW1pemU6IHBhcmFtZXRlcnMudmVydGV4Q2FjaGVPcHRpbWl6ZSwKICAgICAgICAgIGNvbXByZXNzVmVydGljZXM6IHBhcmFtZXRlcnMuY29tcHJlc3NWZXJ0aWNlcywKICAgICAgICAgIG1vZGVsTWF0cml4OiBwYXJhbWV0ZXJzLm1vZGVsTWF0cml4LAogICAgICAgICAgY3JlYXRlUGlja09mZnNldHM6IHBhcmFtZXRlcnMuY3JlYXRlUGlja09mZnNldHMKICAgICAgICB9OwogICAgICB9OwogICAgICBQcmltaXRpdmVQaXBlbGluZS51bnBhY2tDb21iaW5lR2VvbWV0cnlQYXJhbWV0ZXJzID0gZnVuY3Rpb24ocGFja2VkUGFyYW1ldGVycykgewogICAgICAgIGNvbnN0IGluc3RhbmNlcyA9IHVucGFja0luc3RhbmNlc0ZvckNvbWJpbmUocGFja2VkUGFyYW1ldGVycy5wYWNrZWRJbnN0YW5jZXMpOwogICAgICAgIGNvbnN0IGNyZWF0ZUdlb21ldHJ5UmVzdWx0cyA9IHBhY2tlZFBhcmFtZXRlcnMuY3JlYXRlR2VvbWV0cnlSZXN1bHRzOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IGNyZWF0ZUdlb21ldHJ5UmVzdWx0cy5sZW5ndGg7CiAgICAgICAgbGV0IGluc3RhbmNlSW5kZXggPSAwOwogICAgICAgIGZvciAobGV0IHJlc3VsdEluZGV4ID0gMDsgcmVzdWx0SW5kZXggPCBsZW5ndGg7IHJlc3VsdEluZGV4KyspIHsKICAgICAgICAgIGNvbnN0IGdlb21ldHJpZXMgPSBQcmltaXRpdmVQaXBlbGluZS51bnBhY2tDcmVhdGVHZW9tZXRyeVJlc3VsdHMoCiAgICAgICAgICAgIGNyZWF0ZUdlb21ldHJ5UmVzdWx0c1tyZXN1bHRJbmRleF0KICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBnZW9tZXRyaWVzTGVuZ3RoID0gZ2VvbWV0cmllcy5sZW5ndGg7CiAgICAgICAgICBmb3IgKGxldCBnZW9tZXRyeUluZGV4ID0gMDsgZ2VvbWV0cnlJbmRleCA8IGdlb21ldHJpZXNMZW5ndGg7IGdlb21ldHJ5SW5kZXgrKykgewogICAgICAgICAgICBjb25zdCBnZW9tZXRyeSA9IGdlb21ldHJpZXNbZ2VvbWV0cnlJbmRleF07CiAgICAgICAgICAgIGNvbnN0IGluc3RhbmNlID0gaW5zdGFuY2VzW2luc3RhbmNlSW5kZXhdOwogICAgICAgICAgICBpbnN0YW5jZS5nZW9tZXRyeSA9IGdlb21ldHJ5OwogICAgICAgICAgICArK2luc3RhbmNlSW5kZXg7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKHBhY2tlZFBhcmFtZXRlcnMuZWxsaXBzb2lkKTsKICAgICAgICBjb25zdCBwcm9qZWN0aW9uID0gcGFja2VkUGFyYW1ldGVycy5pc0dlb2dyYXBoaWMgPyBuZXcgR2VvZ3JhcGhpY1Byb2plY3Rpb25fZGVmYXVsdChlbGxpcHNvaWQpIDogbmV3IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0KGVsbGlwc29pZCk7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIGluc3RhbmNlcywKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHByb2plY3Rpb24sCiAgICAgICAgICBlbGVtZW50SW5kZXhVaW50U3VwcG9ydGVkOiBwYWNrZWRQYXJhbWV0ZXJzLmVsZW1lbnRJbmRleFVpbnRTdXBwb3J0ZWQsCiAgICAgICAgICBzY2VuZTNET25seTogcGFja2VkUGFyYW1ldGVycy5zY2VuZTNET25seSwKICAgICAgICAgIHZlcnRleENhY2hlT3B0aW1pemU6IHBhY2tlZFBhcmFtZXRlcnMudmVydGV4Q2FjaGVPcHRpbWl6ZSwKICAgICAgICAgIGNvbXByZXNzVmVydGljZXM6IHBhY2tlZFBhcmFtZXRlcnMuY29tcHJlc3NWZXJ0aWNlcywKICAgICAgICAgIG1vZGVsTWF0cml4OiBNYXRyaXg0X2RlZmF1bHQuY2xvbmUocGFja2VkUGFyYW1ldGVycy5tb2RlbE1hdHJpeCksCiAgICAgICAgICBjcmVhdGVQaWNrT2Zmc2V0czogcGFja2VkUGFyYW1ldGVycy5jcmVhdGVQaWNrT2Zmc2V0cwogICAgICAgIH07CiAgICAgIH07CiAgICAgIFByaW1pdGl2ZVBpcGVsaW5lLnBhY2tDb21iaW5lR2VvbWV0cnlSZXN1bHRzID0gZnVuY3Rpb24ocmVzdWx0cywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocmVzdWx0cy5nZW9tZXRyaWVzKSkgewogICAgICAgICAgdHJhbnNmZXJHZW9tZXRyaWVzKHJlc3VsdHMuZ2VvbWV0cmllcywgdHJhbnNmZXJhYmxlT2JqZWN0cyk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBhY2tlZEJvdW5kaW5nU3BoZXJlcyA9IHBhY2tCb3VuZGluZ1NwaGVyZXMocmVzdWx0cy5ib3VuZGluZ1NwaGVyZXMpOwogICAgICAgIGNvbnN0IHBhY2tlZEJvdW5kaW5nU3BoZXJlc0NWID0gcGFja0JvdW5kaW5nU3BoZXJlcygKICAgICAgICAgIHJlc3VsdHMuYm91bmRpbmdTcGhlcmVzQ1YKICAgICAgICApOwogICAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaCgKICAgICAgICAgIHBhY2tlZEJvdW5kaW5nU3BoZXJlcy5idWZmZXIsCiAgICAgICAgICBwYWNrZWRCb3VuZGluZ1NwaGVyZXNDVi5idWZmZXIKICAgICAgICApOwogICAgICAgIHJldHVybiB7CiAgICAgICAgICBnZW9tZXRyaWVzOiByZXN1bHRzLmdlb21ldHJpZXMsCiAgICAgICAgICBhdHRyaWJ1dGVMb2NhdGlvbnM6IHJlc3VsdHMuYXR0cmlidXRlTG9jYXRpb25zLAogICAgICAgICAgbW9kZWxNYXRyaXg6IHJlc3VsdHMubW9kZWxNYXRyaXgsCiAgICAgICAgICBwaWNrT2Zmc2V0czogcmVzdWx0cy5waWNrT2Zmc2V0cywKICAgICAgICAgIG9mZnNldEluc3RhbmNlRXh0ZW5kOiByZXN1bHRzLm9mZnNldEluc3RhbmNlRXh0ZW5kLAogICAgICAgICAgYm91bmRpbmdTcGhlcmVzOiBwYWNrZWRCb3VuZGluZ1NwaGVyZXMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZXNDVjogcGFja2VkQm91bmRpbmdTcGhlcmVzQ1YKICAgICAgICB9OwogICAgICB9OwogICAgICBQcmltaXRpdmVQaXBlbGluZS51bnBhY2tDb21iaW5lR2VvbWV0cnlSZXN1bHRzID0gZnVuY3Rpb24ocGFja2VkUmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIGdlb21ldHJpZXM6IHBhY2tlZFJlc3VsdC5nZW9tZXRyaWVzLAogICAgICAgICAgYXR0cmlidXRlTG9jYXRpb25zOiBwYWNrZWRSZXN1bHQuYXR0cmlidXRlTG9jYXRpb25zLAogICAgICAgICAgbW9kZWxNYXRyaXg6IHBhY2tlZFJlc3VsdC5tb2RlbE1hdHJpeCwKICAgICAgICAgIHBpY2tPZmZzZXRzOiBwYWNrZWRSZXN1bHQucGlja09mZnNldHMsCiAgICAgICAgICBvZmZzZXRJbnN0YW5jZUV4dGVuZDogcGFja2VkUmVzdWx0Lm9mZnNldEluc3RhbmNlRXh0ZW5kLAogICAgICAgICAgYm91bmRpbmdTcGhlcmVzOiB1bnBhY2tCb3VuZGluZ1NwaGVyZXMocGFja2VkUmVzdWx0LmJvdW5kaW5nU3BoZXJlcyksCiAgICAgICAgICBib3VuZGluZ1NwaGVyZXNDVjogdW5wYWNrQm91bmRpbmdTcGhlcmVzKHBhY2tlZFJlc3VsdC5ib3VuZGluZ1NwaGVyZXNDVikKICAgICAgICB9OwogICAgICB9OwogICAgICBQcmltaXRpdmVQaXBlbGluZV9kZWZhdWx0ID0gUHJpbWl0aXZlUGlwZWxpbmU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9mb3JtYXRFcnJvci5qcwogIGZ1bmN0aW9uIGZvcm1hdEVycm9yKG9iamVjdCkgewogICAgbGV0IHJlc3VsdDsKICAgIGNvbnN0IG5hbWUgPSBvYmplY3QubmFtZTsKICAgIGNvbnN0IG1lc3NhZ2UgPSBvYmplY3QubWVzc2FnZTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobmFtZSkgJiYgZGVmaW5lZF9kZWZhdWx0KG1lc3NhZ2UpKSB7CiAgICAgIHJlc3VsdCA9IGAke25hbWV9OiAke21lc3NhZ2V9YDsKICAgIH0gZWxzZSB7CiAgICAgIHJlc3VsdCA9IG9iamVjdC50b1N0cmluZygpOwogICAgfQogICAgY29uc3Qgc3RhY2sgPSBvYmplY3Quc3RhY2s7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHN0YWNrKSkgewogICAgICByZXN1bHQgKz0gYAoke3N0YWNrfWA7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICB2YXIgZm9ybWF0RXJyb3JfZGVmYXVsdDsKICB2YXIgaW5pdF9mb3JtYXRFcnJvciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZm9ybWF0RXJyb3IuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgZm9ybWF0RXJyb3JfZGVmYXVsdCA9IGZvcm1hdEVycm9yOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlci5qcwogIHZhciBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIod29ya2VyRnVuY3Rpb24pIHsKICAgIGFzeW5jIGZ1bmN0aW9uIG9uTWVzc2FnZUhhbmRsZXIoeyBkYXRhIH0pIHsKICAgICAgY29uc3QgdHJhbnNmZXJhYmxlT2JqZWN0cyA9IFtdOwogICAgICBjb25zdCByZXNwb25zZU1lc3NhZ2UgPSB7CiAgICAgICAgaWQ6IGRhdGEuaWQsCiAgICAgICAgcmVzdWx0OiB2b2lkIDAsCiAgICAgICAgZXJyb3I6IHZvaWQgMAogICAgICB9OwogICAgICBzZWxmLkNFU0lVTV9CQVNFX1VSTCA9IGRhdGEuYmFzZVVybDsKICAgICAgdHJ5IHsKICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB3b3JrZXJGdW5jdGlvbihkYXRhLnBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpOwogICAgICAgIHJlc3BvbnNlTWVzc2FnZS5yZXN1bHQgPSByZXN1bHQ7CiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7CiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHsKICAgICAgICAgIHJlc3BvbnNlTWVzc2FnZS5lcnJvciA9IHsKICAgICAgICAgICAgbmFtZTogZXJyb3IubmFtZSwKICAgICAgICAgICAgbWVzc2FnZTogZXJyb3IubWVzc2FnZSwKICAgICAgICAgICAgc3RhY2s6IGVycm9yLnN0YWNrCiAgICAgICAgICB9OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXNwb25zZU1lc3NhZ2UuZXJyb3IgPSBlcnJvcjsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKCFkYXRhLmNhblRyYW5zZmVyQXJyYXlCdWZmZXIpIHsKICAgICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLmxlbmd0aCA9IDA7CiAgICAgIH0KICAgICAgdHJ5IHsKICAgICAgICBwb3N0TWVzc2FnZShyZXNwb25zZU1lc3NhZ2UsIHRyYW5zZmVyYWJsZU9iamVjdHMpOwogICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgIHJlc3BvbnNlTWVzc2FnZS5yZXN1bHQgPSB2b2lkIDA7CiAgICAgICAgcmVzcG9uc2VNZXNzYWdlLmVycm9yID0gYHBvc3RNZXNzYWdlIGZhaWxlZCB3aXRoIGVycm9yOiAke2Zvcm1hdEVycm9yX2RlZmF1bHQoCiAgICAgICAgICBlcnJvcgogICAgICAgICl9CiAgd2l0aCByZXNwb25zZU1lc3NhZ2U6ICR7SlNPTi5zdHJpbmdpZnkocmVzcG9uc2VNZXNzYWdlKX1gOwogICAgICAgIHBvc3RNZXNzYWdlKHJlc3BvbnNlTWVzc2FnZSk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIG9uTWVzc2FnZUVycm9ySGFuZGxlcihldmVudCkgewogICAgICBwb3N0TWVzc2FnZSh7CiAgICAgICAgaWQ6IGV2ZW50LmRhdGE/LmlkLAogICAgICAgIGVycm9yOiBgcG9zdE1lc3NhZ2UgZmFpbGVkIHdpdGggZXJyb3I6ICR7SlNPTi5zdHJpbmdpZnkoZXZlbnQpfWAKICAgICAgfSk7CiAgICB9CiAgICBzZWxmLm9ubWVzc2FnZSA9IG9uTWVzc2FnZUhhbmRsZXI7CiAgICBzZWxmLm9ubWVzc2FnZWVycm9yID0gb25NZXNzYWdlRXJyb3JIYW5kbGVyOwogICAgcmV0dXJuIHNlbGY7CiAgfQogIHZhciBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlci5qcyIoKSB7CiAgICAgIGluaXRfZm9ybWF0RXJyb3IoKTsKICAgICAgY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NvbWJpbmVHZW9tZXRyeS5qcwogIHZhciBjb21iaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNvbWJpbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjb21iaW5lR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNvbWJpbmVHZW9tZXRyeShwYWNrZWRQYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBwYXJhbWV0ZXJzID0gUHJpbWl0aXZlUGlwZWxpbmVfZGVmYXVsdC51bnBhY2tDb21iaW5lR2VvbWV0cnlQYXJhbWV0ZXJzKHBhY2tlZFBhcmFtZXRlcnMpOwogICAgY29uc3QgcmVzdWx0cyA9IFByaW1pdGl2ZVBpcGVsaW5lX2RlZmF1bHQuY29tYmluZUdlb21ldHJ5KHBhcmFtZXRlcnMpOwogICAgcmV0dXJuIFByaW1pdGl2ZVBpcGVsaW5lX2RlZmF1bHQucGFja0NvbWJpbmVHZW9tZXRyeVJlc3VsdHMoCiAgICAgIHJlc3VsdHMsCiAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMKICAgICk7CiAgfQogIHZhciBjb21iaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jb21iaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NvbWJpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfUHJpbWl0aXZlUGlwZWxpbmUoKTsKICAgICAgaW5pdF9jcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyKCk7CiAgICAgIGNvbWJpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KGNvbWJpbmVHZW9tZXRyeSk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZS5qcwogIHZhciBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSwgR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdDsKICB2YXIgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUuanMiKCkgewogICAgICBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSA9IHsKICAgICAgICBOT05FOiAwLAogICAgICAgIFRPUDogMSwKICAgICAgICBBTEw6IDIKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSk7CiAgICAgIEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQgPSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1ZlcnRleEZvcm1hdC5qcwogIGZ1bmN0aW9uIFZlcnRleEZvcm1hdChvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICB0aGlzLnBvc2l0aW9uID0gb3B0aW9ucy5wb3NpdGlvbiA/PyBmYWxzZTsKICAgIHRoaXMubm9ybWFsID0gb3B0aW9ucy5ub3JtYWwgPz8gZmFsc2U7CiAgICB0aGlzLnN0ID0gb3B0aW9ucy5zdCA/PyBmYWxzZTsKICAgIHRoaXMuYml0YW5nZW50ID0gb3B0aW9ucy5iaXRhbmdlbnQgPz8gZmFsc2U7CiAgICB0aGlzLnRhbmdlbnQgPSBvcHRpb25zLnRhbmdlbnQgPz8gZmFsc2U7CiAgICB0aGlzLmNvbG9yID0gb3B0aW9ucy5jb2xvciA/PyBmYWxzZTsKICB9CiAgdmFyIFZlcnRleEZvcm1hdF9kZWZhdWx0OwogIHZhciBpbml0X1ZlcnRleEZvcm1hdCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVmVydGV4Rm9ybWF0LmpzIigpIHsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgVmVydGV4Rm9ybWF0LlBPU0lUSU9OX09OTFkgPSBPYmplY3QuZnJlZXplKAogICAgICAgIG5ldyBWZXJ0ZXhGb3JtYXQoewogICAgICAgICAgcG9zaXRpb246IHRydWUKICAgICAgICB9KQogICAgICApOwogICAgICBWZXJ0ZXhGb3JtYXQuUE9TSVRJT05fQU5EX05PUk1BTCA9IE9iamVjdC5mcmVlemUoCiAgICAgICAgbmV3IFZlcnRleEZvcm1hdCh7CiAgICAgICAgICBwb3NpdGlvbjogdHJ1ZSwKICAgICAgICAgIG5vcm1hbDogdHJ1ZQogICAgICAgIH0pCiAgICAgICk7CiAgICAgIFZlcnRleEZvcm1hdC5QT1NJVElPTl9OT1JNQUxfQU5EX1NUID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgVmVydGV4Rm9ybWF0KHsKICAgICAgICAgIHBvc2l0aW9uOiB0cnVlLAogICAgICAgICAgbm9ybWFsOiB0cnVlLAogICAgICAgICAgc3Q6IHRydWUKICAgICAgICB9KQogICAgICApOwogICAgICBWZXJ0ZXhGb3JtYXQuUE9TSVRJT05fQU5EX1NUID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgVmVydGV4Rm9ybWF0KHsKICAgICAgICAgIHBvc2l0aW9uOiB0cnVlLAogICAgICAgICAgc3Q6IHRydWUKICAgICAgICB9KQogICAgICApOwogICAgICBWZXJ0ZXhGb3JtYXQuUE9TSVRJT05fQU5EX0NPTE9SID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgVmVydGV4Rm9ybWF0KHsKICAgICAgICAgIHBvc2l0aW9uOiB0cnVlLAogICAgICAgICAgY29sb3I6IHRydWUKICAgICAgICB9KQogICAgICApOwogICAgICBWZXJ0ZXhGb3JtYXQuQUxMID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgVmVydGV4Rm9ybWF0KHsKICAgICAgICAgIHBvc2l0aW9uOiB0cnVlLAogICAgICAgICAgbm9ybWFsOiB0cnVlLAogICAgICAgICAgc3Q6IHRydWUsCiAgICAgICAgICB0YW5nZW50OiB0cnVlLAogICAgICAgICAgYml0YW5nZW50OiB0cnVlCiAgICAgICAgfSkKICAgICAgKTsKICAgICAgVmVydGV4Rm9ybWF0LkRFRkFVTFQgPSBWZXJ0ZXhGb3JtYXQuUE9TSVRJT05fTk9STUFMX0FORF9TVDsKICAgICAgVmVydGV4Rm9ybWF0LnBhY2tlZExlbmd0aCA9IDY7CiAgICAgIFZlcnRleEZvcm1hdC5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmFsdWUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmFsdWUgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXJyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUucG9zaXRpb24gPyAxIDogMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUubm9ybWFsID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLnN0ID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLnRhbmdlbnQgPyAxIDogMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuYml0YW5nZW50ID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5jb2xvciA/IDEgOiAwOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgVmVydGV4Rm9ybWF0LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBWZXJ0ZXhGb3JtYXQoKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnBvc2l0aW9uID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICByZXN1bHQubm9ybWFsID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICByZXN1bHQuc3QgPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIHJlc3VsdC50YW5nZW50ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICByZXN1bHQuYml0YW5nZW50ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICByZXN1bHQuY29sb3IgPSBhcnJheVtzdGFydGluZ0luZGV4XSA9PT0gMTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBWZXJ0ZXhGb3JtYXQuY2xvbmUgPSBmdW5jdGlvbih2ZXJ0ZXhGb3JtYXQsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZlcnRleEZvcm1hdCkpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBWZXJ0ZXhGb3JtYXQoKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnBvc2l0aW9uID0gdmVydGV4Rm9ybWF0LnBvc2l0aW9uOwogICAgICAgIHJlc3VsdC5ub3JtYWwgPSB2ZXJ0ZXhGb3JtYXQubm9ybWFsOwogICAgICAgIHJlc3VsdC5zdCA9IHZlcnRleEZvcm1hdC5zdDsKICAgICAgICByZXN1bHQudGFuZ2VudCA9IHZlcnRleEZvcm1hdC50YW5nZW50OwogICAgICAgIHJlc3VsdC5iaXRhbmdlbnQgPSB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50OwogICAgICAgIHJlc3VsdC5jb2xvciA9IHZlcnRleEZvcm1hdC5jb2xvcjsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCA9IFZlcnRleEZvcm1hdDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0JveEdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gQm94R2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgbWluMyA9IG9wdGlvbnMubWluaW11bTsKICAgIGNvbnN0IG1heDMgPSBvcHRpb25zLm1heGltdW07CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1pbiIsIG1pbjMpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXgiLCBtYXgzKTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpICYmIG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUuVE9QIGlzIG5vdCBhIHN1cHBvcnRlZCBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSBmb3IgdGhpcyBnZW9tZXRyeS4iCiAgICAgICk7CiAgICB9CiAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBvcHRpb25zLnZlcnRleEZvcm1hdCA/PyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5ERUZBVUxUOwogICAgdGhpcy5fbWluaW11bSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShtaW4zKTsKICAgIHRoaXMuX21heGltdW0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUobWF4Myk7CiAgICB0aGlzLl92ZXJ0ZXhGb3JtYXQgPSB2ZXJ0ZXhGb3JtYXQ7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlQm94R2VvbWV0cnkiOwogIH0KICB2YXIgZGlmZlNjcmF0Y2gsIHNjcmF0Y2hNaW4sIHNjcmF0Y2hNYXgsIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQsIHNjcmF0Y2hPcHRpb25zLCB1bml0Qm94R2VvbWV0cnksIEJveEdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfQm94R2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0JveEdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1ZlcnRleEZvcm1hdCgpOwogICAgICBkaWZmU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgQm94R2VvbWV0cnkuZnJvbURpbWVuc2lvbnMgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IGRpbWVuc2lvbnMgPSBvcHRpb25zLmRpbWVuc2lvbnM7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJkaW1lbnNpb25zIiwgZGltZW5zaW9ucyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImRpbWVuc2lvbnMueCIsIGRpbWVuc2lvbnMueCwgMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImRpbWVuc2lvbnMueSIsIGRpbWVuc2lvbnMueSwgMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImRpbWVuc2lvbnMueiIsIGRpbWVuc2lvbnMueiwgMCk7CiAgICAgICAgY29uc3QgY29ybmVyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZGltZW5zaW9ucywgMC41LCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkpOwogICAgICAgIHJldHVybiBuZXcgQm94R2VvbWV0cnkoewogICAgICAgICAgbWluaW11bTogQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShjb3JuZXIsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSksCiAgICAgICAgICBtYXhpbXVtOiBjb3JuZXIsCiAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IG9wdGlvbnMudmVydGV4Rm9ybWF0LAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBCb3hHZW9tZXRyeS5mcm9tQXhpc0FsaWduZWRCb3VuZGluZ0JveCA9IGZ1bmN0aW9uKGJvdW5kaW5nQm94KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJib3VuZGluZ0JveCIsIGJvdW5kaW5nQm94KTsKICAgICAgICByZXR1cm4gbmV3IEJveEdlb21ldHJ5KHsKICAgICAgICAgIG1pbmltdW06IGJvdW5kaW5nQm94Lm1pbmltdW0sCiAgICAgICAgICBtYXhpbXVtOiBib3VuZGluZ0JveC5tYXhpbXVtCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEJveEdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IDIgKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgMTsKICAgICAgQm94R2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9taW5pbXVtLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soCiAgICAgICAgICB2YWx1ZS5fbWF4aW11bSwKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgKICAgICAgICApOwogICAgICAgIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2soCiAgICAgICAgICB2YWx1ZS5fdmVydGV4Rm9ybWF0LAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4ICsgMiAqIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgKICAgICAgICApOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXggKyAyICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaE1pbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdCA9IG5ldyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9ucyA9IHsKICAgICAgICBtaW5pbXVtOiBzY3JhdGNoTWluLAogICAgICAgIG1heGltdW06IHNjcmF0Y2hNYXgsCiAgICAgICAgdmVydGV4Rm9ybWF0OiBzY3JhdGNoVmVydGV4Rm9ybWF0LAogICAgICAgIG9mZnNldEF0dHJpYnV0ZTogdm9pZCAwCiAgICAgIH07CiAgICAgIEJveEdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgbWluMyA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hNaW4pOwogICAgICAgIGNvbnN0IG1heDMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4ICsgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCwKICAgICAgICAgIHNjcmF0Y2hNYXgKICAgICAgICApOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCArIDIgKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoLAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdAogICAgICAgICk7CiAgICAgICAgY29uc3Qgb2Zmc2V0QXR0cmlidXRlID0gYXJyYXlbc3RhcnRpbmdJbmRleCArIDIgKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgcmV0dXJuIG5ldyBCb3hHZW9tZXRyeShzY3JhdGNoT3B0aW9ucyk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fbWluaW11bSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShtaW4zLCByZXN1bHQuX21pbmltdW0pOwogICAgICAgIHJlc3VsdC5fbWF4aW11bSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShtYXgzLCByZXN1bHQuX21heGltdW0pOwogICAgICAgIHJlc3VsdC5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0LCByZXN1bHQuX3ZlcnRleEZvcm1hdCk7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEJveEdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24oYm94R2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBtaW4zID0gYm94R2VvbWV0cnkuX21pbmltdW07CiAgICAgICAgY29uc3QgbWF4MyA9IGJveEdlb21ldHJ5Ll9tYXhpbXVtOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IGJveEdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMobWluMywgbWF4MykpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCgpOwogICAgICAgIGxldCBpbmRpY2VzOwogICAgICAgIGxldCBwb3NpdGlvbnM7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5wb3NpdGlvbiAmJiAodmVydGV4Rm9ybWF0LnN0IHx8IHZlcnRleEZvcm1hdC5ub3JtYWwgfHwgdmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkpIHsKICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQucG9zaXRpb24pIHsKICAgICAgICAgICAgcG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSg2ICogNCAqIDMpOwogICAgICAgICAgICBwb3NpdGlvbnNbMF0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxXSA9IG1pbjMueTsKICAgICAgICAgICAgcG9zaXRpb25zWzJdID0gbWF4My56OwogICAgICAgICAgICBwb3NpdGlvbnNbM10gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0XSA9IG1pbjMueTsKICAgICAgICAgICAgcG9zaXRpb25zWzVdID0gbWF4My56OwogICAgICAgICAgICBwb3NpdGlvbnNbNl0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s3XSA9IG1heDMueTsKICAgICAgICAgICAgcG9zaXRpb25zWzhdID0gbWF4My56OwogICAgICAgICAgICBwb3NpdGlvbnNbOV0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxMF0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxMV0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxMl0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxM10gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxNF0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxNV0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxNl0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxN10gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxOF0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1sxOV0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1syMF0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1syMV0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1syMl0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1syM10gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1syNF0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1syNV0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1syNl0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1syN10gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1syOF0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1syOV0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1szMF0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1szMV0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1szMl0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1szM10gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1szNF0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1szNV0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1szNl0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1szN10gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1szOF0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1szOV0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0MF0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0MV0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0Ml0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0M10gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0NF0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0NV0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0Nl0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0N10gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0OF0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s0OV0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1MF0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1MV0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1Ml0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1M10gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1NF0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1NV0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1Nl0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1N10gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1OF0gPSBtYXgzLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s1OV0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2MF0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2MV0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2Ml0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2M10gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2NF0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2NV0gPSBtaW4zLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2Nl0gPSBtYXgzLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2N10gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2OF0gPSBtYXgzLno7CiAgICAgICAgICAgIHBvc2l0aW9uc1s2OV0gPSBtaW4zLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1s3MF0gPSBtaW4zLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1s3MV0gPSBtYXgzLno7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBwb3NpdGlvbnMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgICBjb25zdCBub3JtYWxzID0gbmV3IEZsb2F0MzJBcnJheSg2ICogNCAqIDMpOwogICAgICAgICAgICBub3JtYWxzWzBdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1sxXSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbMl0gPSAxOwogICAgICAgICAgICBub3JtYWxzWzNdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s0XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbNV0gPSAxOwogICAgICAgICAgICBub3JtYWxzWzZdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s3XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbOF0gPSAxOwogICAgICAgICAgICBub3JtYWxzWzldID0gMDsKICAgICAgICAgICAgbm9ybWFsc1sxMF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzExXSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbMTJdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1sxM10gPSAwOwogICAgICAgICAgICBub3JtYWxzWzE0XSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzE1XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbMTZdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1sxN10gPSAtMTsKICAgICAgICAgICAgbm9ybWFsc1sxOF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzE5XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbMjBdID0gLTE7CiAgICAgICAgICAgIG5vcm1hbHNbMjFdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1syMl0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzIzXSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzI0XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbMjVdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1syNl0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzI3XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbMjhdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1syOV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzMwXSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbMzFdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1szMl0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzMzXSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbMzRdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1szNV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzM2XSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzM3XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbMzhdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1szOV0gPSAtMTsKICAgICAgICAgICAgbm9ybWFsc1s0MF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzQxXSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbNDJdID0gLTE7CiAgICAgICAgICAgIG5vcm1hbHNbNDNdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s0NF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzQ1XSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzQ2XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbNDddID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s0OF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzQ5XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbNTBdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s1MV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzUyXSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbNTNdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s1NF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzU1XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbNTZdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s1N10gPSAwOwogICAgICAgICAgICBub3JtYWxzWzU4XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbNTldID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s2MF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzYxXSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzYyXSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbNjNdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s2NF0gPSAtMTsKICAgICAgICAgICAgbm9ybWFsc1s2NV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzY2XSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbNjddID0gLTE7CiAgICAgICAgICAgIG5vcm1hbHNbNjhdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s2OV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzcwXSA9IC0xOwogICAgICAgICAgICBub3JtYWxzWzcxXSA9IDA7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMubm9ybWFsID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBub3JtYWxzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgICBjb25zdCB0ZXhDb29yZHMgPSBuZXcgRmxvYXQzMkFycmF5KDYgKiA0ICogMik7CiAgICAgICAgICAgIHRleENvb3Jkc1swXSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1sxXSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1syXSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1szXSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1s0XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s1XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s2XSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1s3XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s4XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s5XSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1sxMF0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMTFdID0gMDsKICAgICAgICAgICAgdGV4Q29vcmRzWzEyXSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1sxM10gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbMTRdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzE1XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1sxNl0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMTddID0gMDsKICAgICAgICAgICAgdGV4Q29vcmRzWzE4XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1sxOV0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMjBdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzIxXSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1syMl0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMjNdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzI0XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1syNV0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMjZdID0gMDsKICAgICAgICAgICAgdGV4Q29vcmRzWzI3XSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1syOF0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMjldID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzMwXSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1szMV0gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbMzJdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzMzXSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1szNF0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMzVdID0gMDsKICAgICAgICAgICAgdGV4Q29vcmRzWzM2XSA9IDA7CiAgICAgICAgICAgIHRleENvb3Jkc1szN10gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbMzhdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzM5XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s0MF0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbNDFdID0gMDsKICAgICAgICAgICAgdGV4Q29vcmRzWzQyXSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s0M10gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbNDRdID0gMTsKICAgICAgICAgICAgdGV4Q29vcmRzWzQ1XSA9IDE7CiAgICAgICAgICAgIHRleENvb3Jkc1s0Nl0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbNDddID0gMTsKICAgICAgICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICAgIHZhbHVlczogdGV4Q29vcmRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICAgIGNvbnN0IHRhbmdlbnRzID0gbmV3IEZsb2F0MzJBcnJheSg2ICogNCAqIDMpOwogICAgICAgICAgICB0YW5nZW50c1swXSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzFdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbMl0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szXSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzRdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNV0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s2XSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzddID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbOF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s5XSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzEwXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzExXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzEyXSA9IC0xOwogICAgICAgICAgICB0YW5nZW50c1sxM10gPSAwOwogICAgICAgICAgICB0YW5nZW50c1sxNF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1sxNV0gPSAtMTsKICAgICAgICAgICAgdGFuZ2VudHNbMTZdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbMTddID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbMThdID0gLTE7CiAgICAgICAgICAgIHRhbmdlbnRzWzE5XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzIwXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzIxXSA9IC0xOwogICAgICAgICAgICB0YW5nZW50c1syMl0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1syM10gPSAwOwogICAgICAgICAgICB0YW5nZW50c1syNF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1syNV0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1syNl0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1syN10gPSAwOwogICAgICAgICAgICB0YW5nZW50c1syOF0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1syOV0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szMF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szMV0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1szMl0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szM10gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szNF0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1szNV0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szNl0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1szN10gPSAtMTsKICAgICAgICAgICAgdGFuZ2VudHNbMzhdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbMzldID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNDBdID0gLTE7CiAgICAgICAgICAgIHRhbmdlbnRzWzQxXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzQyXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzQzXSA9IC0xOwogICAgICAgICAgICB0YW5nZW50c1s0NF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s0NV0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s0Nl0gPSAtMTsKICAgICAgICAgICAgdGFuZ2VudHNbNDddID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNDhdID0gLTE7CiAgICAgICAgICAgIHRhbmdlbnRzWzQ5XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzUwXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzUxXSA9IC0xOwogICAgICAgICAgICB0YW5nZW50c1s1Ml0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s1M10gPSAwOwogICAgICAgICAgICB0YW5nZW50c1s1NF0gPSAtMTsKICAgICAgICAgICAgdGFuZ2VudHNbNTVdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNTZdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNTddID0gLTE7CiAgICAgICAgICAgIHRhbmdlbnRzWzU4XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzU5XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzYwXSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzYxXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzYyXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzYzXSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzY0XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzY1XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzY2XSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzY3XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzY4XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzY5XSA9IDE7CiAgICAgICAgICAgIHRhbmdlbnRzWzcwXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzcxXSA9IDA7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMudGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICAgIHZhbHVlczogdGFuZ2VudHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICBjb25zdCBiaXRhbmdlbnRzID0gbmV3IEZsb2F0MzJBcnJheSg2ICogNCAqIDMpOwogICAgICAgICAgICBiaXRhbmdlbnRzWzBdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMl0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzNdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzZdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s3XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbOF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzldID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxMF0gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzExXSA9IDA7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMTJdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxM10gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzE0XSA9IDA7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMTVdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxNl0gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzE3XSA9IDA7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMThdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxOV0gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzIwXSA9IDA7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMjFdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1syMl0gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzIzXSA9IDA7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMjRdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1syNV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzI2XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMjddID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1syOF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzI5XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMzBdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1szMV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzMyXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMzNdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1szNF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzM1XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMzZdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1szN10gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzM4XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMzldID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0MF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzQxXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNDJdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0M10gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzQ0XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNDVdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0Nl0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzQ3XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNDhdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0OV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzUwXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNTFdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s1Ml0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzUzXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNTRdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s1NV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzU2XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNTddID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s1OF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzU5XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNjBdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s2MV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzYyXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNjNdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s2NF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzY1XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNjZdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s2N10gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzY4XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNjldID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s3MF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzcxXSA9IDE7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSg2ICogMiAqIDMpOwogICAgICAgICAgaW5kaWNlc1swXSA9IDA7CiAgICAgICAgICBpbmRpY2VzWzFdID0gMTsKICAgICAgICAgIGluZGljZXNbMl0gPSAyOwogICAgICAgICAgaW5kaWNlc1szXSA9IDA7CiAgICAgICAgICBpbmRpY2VzWzRdID0gMjsKICAgICAgICAgIGluZGljZXNbNV0gPSAzOwogICAgICAgICAgaW5kaWNlc1s2XSA9IDQgKyAyOwogICAgICAgICAgaW5kaWNlc1s3XSA9IDQgKyAxOwogICAgICAgICAgaW5kaWNlc1s4XSA9IDQgKyAwOwogICAgICAgICAgaW5kaWNlc1s5XSA9IDQgKyAzOwogICAgICAgICAgaW5kaWNlc1sxMF0gPSA0ICsgMjsKICAgICAgICAgIGluZGljZXNbMTFdID0gNCArIDA7CiAgICAgICAgICBpbmRpY2VzWzEyXSA9IDggKyAwOwogICAgICAgICAgaW5kaWNlc1sxM10gPSA4ICsgMTsKICAgICAgICAgIGluZGljZXNbMTRdID0gOCArIDI7CiAgICAgICAgICBpbmRpY2VzWzE1XSA9IDggKyAwOwogICAgICAgICAgaW5kaWNlc1sxNl0gPSA4ICsgMjsKICAgICAgICAgIGluZGljZXNbMTddID0gOCArIDM7CiAgICAgICAgICBpbmRpY2VzWzE4XSA9IDEyICsgMjsKICAgICAgICAgIGluZGljZXNbMTldID0gMTIgKyAxOwogICAgICAgICAgaW5kaWNlc1syMF0gPSAxMiArIDA7CiAgICAgICAgICBpbmRpY2VzWzIxXSA9IDEyICsgMzsKICAgICAgICAgIGluZGljZXNbMjJdID0gMTIgKyAyOwogICAgICAgICAgaW5kaWNlc1syM10gPSAxMiArIDA7CiAgICAgICAgICBpbmRpY2VzWzI0XSA9IDE2ICsgMjsKICAgICAgICAgIGluZGljZXNbMjVdID0gMTYgKyAxOwogICAgICAgICAgaW5kaWNlc1syNl0gPSAxNiArIDA7CiAgICAgICAgICBpbmRpY2VzWzI3XSA9IDE2ICsgMzsKICAgICAgICAgIGluZGljZXNbMjhdID0gMTYgKyAyOwogICAgICAgICAgaW5kaWNlc1syOV0gPSAxNiArIDA7CiAgICAgICAgICBpbmRpY2VzWzMwXSA9IDIwICsgMDsKICAgICAgICAgIGluZGljZXNbMzFdID0gMjAgKyAxOwogICAgICAgICAgaW5kaWNlc1szMl0gPSAyMCArIDI7CiAgICAgICAgICBpbmRpY2VzWzMzXSA9IDIwICsgMDsKICAgICAgICAgIGluZGljZXNbMzRdID0gMjAgKyAyOwogICAgICAgICAgaW5kaWNlc1szNV0gPSAyMCArIDM7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoOCAqIDMpOwogICAgICAgICAgcG9zaXRpb25zWzBdID0gbWluMy54OwogICAgICAgICAgcG9zaXRpb25zWzFdID0gbWluMy55OwogICAgICAgICAgcG9zaXRpb25zWzJdID0gbWluMy56OwogICAgICAgICAgcG9zaXRpb25zWzNdID0gbWF4My54OwogICAgICAgICAgcG9zaXRpb25zWzRdID0gbWluMy55OwogICAgICAgICAgcG9zaXRpb25zWzVdID0gbWluMy56OwogICAgICAgICAgcG9zaXRpb25zWzZdID0gbWF4My54OwogICAgICAgICAgcG9zaXRpb25zWzddID0gbWF4My55OwogICAgICAgICAgcG9zaXRpb25zWzhdID0gbWluMy56OwogICAgICAgICAgcG9zaXRpb25zWzldID0gbWluMy54OwogICAgICAgICAgcG9zaXRpb25zWzEwXSA9IG1heDMueTsKICAgICAgICAgIHBvc2l0aW9uc1sxMV0gPSBtaW4zLno7CiAgICAgICAgICBwb3NpdGlvbnNbMTJdID0gbWluMy54OwogICAgICAgICAgcG9zaXRpb25zWzEzXSA9IG1pbjMueTsKICAgICAgICAgIHBvc2l0aW9uc1sxNF0gPSBtYXgzLno7CiAgICAgICAgICBwb3NpdGlvbnNbMTVdID0gbWF4My54OwogICAgICAgICAgcG9zaXRpb25zWzE2XSA9IG1pbjMueTsKICAgICAgICAgIHBvc2l0aW9uc1sxN10gPSBtYXgzLno7CiAgICAgICAgICBwb3NpdGlvbnNbMThdID0gbWF4My54OwogICAgICAgICAgcG9zaXRpb25zWzE5XSA9IG1heDMueTsKICAgICAgICAgIHBvc2l0aW9uc1syMF0gPSBtYXgzLno7CiAgICAgICAgICBwb3NpdGlvbnNbMjFdID0gbWluMy54OwogICAgICAgICAgcG9zaXRpb25zWzIyXSA9IG1heDMueTsKICAgICAgICAgIHBvc2l0aW9uc1syM10gPSBtYXgzLno7CiAgICAgICAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICAgICAgICB9KTsKICAgICAgICAgIGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkoNiAqIDIgKiAzKTsKICAgICAgICAgIGluZGljZXNbMF0gPSA0OwogICAgICAgICAgaW5kaWNlc1sxXSA9IDU7CiAgICAgICAgICBpbmRpY2VzWzJdID0gNjsKICAgICAgICAgIGluZGljZXNbM10gPSA0OwogICAgICAgICAgaW5kaWNlc1s0XSA9IDY7CiAgICAgICAgICBpbmRpY2VzWzVdID0gNzsKICAgICAgICAgIGluZGljZXNbNl0gPSAxOwogICAgICAgICAgaW5kaWNlc1s3XSA9IDA7CiAgICAgICAgICBpbmRpY2VzWzhdID0gMzsKICAgICAgICAgIGluZGljZXNbOV0gPSAxOwogICAgICAgICAgaW5kaWNlc1sxMF0gPSAzOwogICAgICAgICAgaW5kaWNlc1sxMV0gPSAyOwogICAgICAgICAgaW5kaWNlc1sxMl0gPSAxOwogICAgICAgICAgaW5kaWNlc1sxM10gPSA2OwogICAgICAgICAgaW5kaWNlc1sxNF0gPSA1OwogICAgICAgICAgaW5kaWNlc1sxNV0gPSAxOwogICAgICAgICAgaW5kaWNlc1sxNl0gPSAyOwogICAgICAgICAgaW5kaWNlc1sxN10gPSA2OwogICAgICAgICAgaW5kaWNlc1sxOF0gPSAyOwogICAgICAgICAgaW5kaWNlc1sxOV0gPSAzOwogICAgICAgICAgaW5kaWNlc1syMF0gPSA3OwogICAgICAgICAgaW5kaWNlc1syMV0gPSAyOwogICAgICAgICAgaW5kaWNlc1syMl0gPSA3OwogICAgICAgICAgaW5kaWNlc1syM10gPSA2OwogICAgICAgICAgaW5kaWNlc1syNF0gPSAzOwogICAgICAgICAgaW5kaWNlc1syNV0gPSAwOwogICAgICAgICAgaW5kaWNlc1syNl0gPSA0OwogICAgICAgICAgaW5kaWNlc1syN10gPSAzOwogICAgICAgICAgaW5kaWNlc1syOF0gPSA0OwogICAgICAgICAgaW5kaWNlc1syOV0gPSA3OwogICAgICAgICAgaW5kaWNlc1szMF0gPSAwOwogICAgICAgICAgaW5kaWNlc1szMV0gPSAxOwogICAgICAgICAgaW5kaWNlc1szMl0gPSA1OwogICAgICAgICAgaW5kaWNlc1szM10gPSAwOwogICAgICAgICAgaW5kaWNlc1szNF0gPSA1OwogICAgICAgICAgaW5kaWNlc1szNV0gPSA0OwogICAgICAgIH0KICAgICAgICBjb25zdCBkaWZmID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KG1heDMsIG1pbjMsIGRpZmZTY3JhdGNoKTsKICAgICAgICBjb25zdCByYWRpdXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKGRpZmYpICogMC41OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoYm94R2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGJveEdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgIGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgIHZhbHVlczogYXBwbHlPZmZzZXQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCByYWRpdXMpLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBib3hHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEJveEdlb21ldHJ5LmdldFVuaXRCb3ggPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1bml0Qm94R2VvbWV0cnkpKSB7CiAgICAgICAgICB1bml0Qm94R2VvbWV0cnkgPSBCb3hHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSgKICAgICAgICAgICAgQm94R2VvbWV0cnkuZnJvbURpbWVuc2lvbnMoewogICAgICAgICAgICAgIGRpbWVuc2lvbnM6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoMSwgMSwgMSksCiAgICAgICAgICAgICAgdmVydGV4Rm9ybWF0OiBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5QT1NJVElPTl9PTkxZCiAgICAgICAgICAgIH0pCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdW5pdEJveEdlb21ldHJ5OwogICAgICB9OwogICAgICBCb3hHZW9tZXRyeV9kZWZhdWx0ID0gQm94R2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVCb3hHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVCb3hHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQm94R2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlQm94R2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUJveEdlb21ldHJ5KGJveEdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBib3hHZW9tZXRyeSA9IEJveEdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGJveEdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcmV0dXJuIEJveEdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoYm94R2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlQm94R2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVCb3hHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlQm94R2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JveEdlb21ldHJ5KCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBjcmVhdGVCb3hHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlQm94R2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Cb3hPdXRsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBCb3hPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgbWluMyA9IG9wdGlvbnMubWluaW11bTsKICAgIGNvbnN0IG1heDMgPSBvcHRpb25zLm1heGltdW07CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm1pbiIsIG1pbjMpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJtYXgiLCBtYXgzKTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpICYmIG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUuVE9QIGlzIG5vdCBhIHN1cHBvcnRlZCBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSBmb3IgdGhpcyBnZW9tZXRyeS4iCiAgICAgICk7CiAgICB9CiAgICB0aGlzLl9taW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUobWluMyk7CiAgICB0aGlzLl9tYXggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUobWF4Myk7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5IjsKICB9CiAgdmFyIGRpZmZTY3JhdGNoMiwgc2NyYXRjaE1pbjIsIHNjcmF0Y2hNYXgyLCBzY3JhdGNoT3B0aW9uczIsIEJveE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X0JveE91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQm94T3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBkaWZmU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEJveE91dGxpbmVHZW9tZXRyeS5mcm9tRGltZW5zaW9ucyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgY29uc3QgZGltZW5zaW9ucyA9IG9wdGlvbnMuZGltZW5zaW9uczsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImRpbWVuc2lvbnMiLCBkaW1lbnNpb25zKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiZGltZW5zaW9ucy54IiwgZGltZW5zaW9ucy54LCAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiZGltZW5zaW9ucy55IiwgZGltZW5zaW9ucy55LCAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiZGltZW5zaW9ucy56IiwgZGltZW5zaW9ucy56LCAwKTsKICAgICAgICBjb25zdCBjb3JuZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihkaW1lbnNpb25zLCAwLjUsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSk7CiAgICAgICAgcmV0dXJuIG5ldyBCb3hPdXRsaW5lR2VvbWV0cnkoewogICAgICAgICAgbWluaW11bTogQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShjb3JuZXIsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSksCiAgICAgICAgICBtYXhpbXVtOiBjb3JuZXIsCiAgICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEJveE91dGxpbmVHZW9tZXRyeS5mcm9tQXhpc0FsaWduZWRCb3VuZGluZ0JveCA9IGZ1bmN0aW9uKGJvdW5kaW5nQm94KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJib3VuZGluZEJveCIsIGJvdW5kaW5nQm94KTsKICAgICAgICByZXR1cm4gbmV3IEJveE91dGxpbmVHZW9tZXRyeSh7CiAgICAgICAgICBtaW5pbXVtOiBib3VuZGluZ0JveC5taW5pbXVtLAogICAgICAgICAgbWF4aW11bTogYm91bmRpbmdCb3gubWF4aW11bQogICAgICAgIH0pOwogICAgICB9OwogICAgICBCb3hPdXRsaW5lR2VvbWV0cnkucGFja2VkTGVuZ3RoID0gMiAqIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAxOwogICAgICBCb3hPdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9taW4sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayh2YWx1ZS5fbWF4LCBhcnJheSwgc3RhcnRpbmdJbmRleCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXggKyBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICogMl0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaE1pbjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNYXgyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczIgPSB7CiAgICAgICAgbWluaW11bTogc2NyYXRjaE1pbjIsCiAgICAgICAgbWF4aW11bTogc2NyYXRjaE1heDIsCiAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiB2b2lkIDAKICAgICAgfTsKICAgICAgQm94T3V0bGluZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgbWluMyA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hNaW4yKTsKICAgICAgICBjb25zdCBtYXgzID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgsCiAgICAgICAgICBzY3JhdGNoTWF4MgogICAgICAgICk7CiAgICAgICAgY29uc3Qgb2Zmc2V0QXR0cmlidXRlID0gYXJyYXlbc3RhcnRpbmdJbmRleCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGggKiAyXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczIub2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIHJldHVybiBuZXcgQm94T3V0bGluZUdlb21ldHJ5KHNjcmF0Y2hPcHRpb25zMik7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fbWluID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG1pbjMsIHJlc3VsdC5fbWluKTsKICAgICAgICByZXN1bHQuX21heCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShtYXgzLCByZXN1bHQuX21heCk7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEJveE91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGJveEdlb21ldHJ5KSB7CiAgICAgICAgY29uc3QgbWluMyA9IGJveEdlb21ldHJ5Ll9taW47CiAgICAgICAgY29uc3QgbWF4MyA9IGJveEdlb21ldHJ5Ll9tYXg7CiAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMobWluMywgbWF4MykpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCgpOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkoMTIgKiAyKTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KDggKiAzKTsKICAgICAgICBwb3NpdGlvbnNbMF0gPSBtaW4zLng7CiAgICAgICAgcG9zaXRpb25zWzFdID0gbWluMy55OwogICAgICAgIHBvc2l0aW9uc1syXSA9IG1pbjMuejsKICAgICAgICBwb3NpdGlvbnNbM10gPSBtYXgzLng7CiAgICAgICAgcG9zaXRpb25zWzRdID0gbWluMy55OwogICAgICAgIHBvc2l0aW9uc1s1XSA9IG1pbjMuejsKICAgICAgICBwb3NpdGlvbnNbNl0gPSBtYXgzLng7CiAgICAgICAgcG9zaXRpb25zWzddID0gbWF4My55OwogICAgICAgIHBvc2l0aW9uc1s4XSA9IG1pbjMuejsKICAgICAgICBwb3NpdGlvbnNbOV0gPSBtaW4zLng7CiAgICAgICAgcG9zaXRpb25zWzEwXSA9IG1heDMueTsKICAgICAgICBwb3NpdGlvbnNbMTFdID0gbWluMy56OwogICAgICAgIHBvc2l0aW9uc1sxMl0gPSBtaW4zLng7CiAgICAgICAgcG9zaXRpb25zWzEzXSA9IG1pbjMueTsKICAgICAgICBwb3NpdGlvbnNbMTRdID0gbWF4My56OwogICAgICAgIHBvc2l0aW9uc1sxNV0gPSBtYXgzLng7CiAgICAgICAgcG9zaXRpb25zWzE2XSA9IG1pbjMueTsKICAgICAgICBwb3NpdGlvbnNbMTddID0gbWF4My56OwogICAgICAgIHBvc2l0aW9uc1sxOF0gPSBtYXgzLng7CiAgICAgICAgcG9zaXRpb25zWzE5XSA9IG1heDMueTsKICAgICAgICBwb3NpdGlvbnNbMjBdID0gbWF4My56OwogICAgICAgIHBvc2l0aW9uc1syMV0gPSBtaW4zLng7CiAgICAgICAgcG9zaXRpb25zWzIyXSA9IG1heDMueTsKICAgICAgICBwb3NpdGlvbnNbMjNdID0gbWF4My56OwogICAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgdmFsdWVzOiBwb3NpdGlvbnMKICAgICAgICB9KTsKICAgICAgICBpbmRpY2VzWzBdID0gNDsKICAgICAgICBpbmRpY2VzWzFdID0gNTsKICAgICAgICBpbmRpY2VzWzJdID0gNTsKICAgICAgICBpbmRpY2VzWzNdID0gNjsKICAgICAgICBpbmRpY2VzWzRdID0gNjsKICAgICAgICBpbmRpY2VzWzVdID0gNzsKICAgICAgICBpbmRpY2VzWzZdID0gNzsKICAgICAgICBpbmRpY2VzWzddID0gNDsKICAgICAgICBpbmRpY2VzWzhdID0gMDsKICAgICAgICBpbmRpY2VzWzldID0gMTsKICAgICAgICBpbmRpY2VzWzEwXSA9IDE7CiAgICAgICAgaW5kaWNlc1sxMV0gPSAyOwogICAgICAgIGluZGljZXNbMTJdID0gMjsKICAgICAgICBpbmRpY2VzWzEzXSA9IDM7CiAgICAgICAgaW5kaWNlc1sxNF0gPSAzOwogICAgICAgIGluZGljZXNbMTVdID0gMDsKICAgICAgICBpbmRpY2VzWzE2XSA9IDA7CiAgICAgICAgaW5kaWNlc1sxN10gPSA0OwogICAgICAgIGluZGljZXNbMThdID0gMTsKICAgICAgICBpbmRpY2VzWzE5XSA9IDU7CiAgICAgICAgaW5kaWNlc1syMF0gPSAyOwogICAgICAgIGluZGljZXNbMjFdID0gNjsKICAgICAgICBpbmRpY2VzWzIyXSA9IDM7CiAgICAgICAgaW5kaWNlc1syM10gPSA3OwogICAgICAgIGNvbnN0IGRpZmYgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobWF4MywgbWluMywgZGlmZlNjcmF0Y2gyKTsKICAgICAgICBjb25zdCByYWRpdXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKGRpZmYpICogMC41OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoYm94R2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGJveEdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgIGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgIHZhbHVlczogYXBwbHlPZmZzZXQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZTogbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJhZGl1cyksCiAgICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IGJveEdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgQm94T3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBCb3hPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnkoYm94R2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGJveEdlb21ldHJ5ID0gQm94T3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGJveEdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcmV0dXJuIEJveE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGJveEdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUJveE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUJveE91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3hPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGNyZWF0ZUJveE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzZUdlb21ldHJ5TGlicmFyeS5qcwogIGZ1bmN0aW9uIHBvaW50T25FbGxpcHNvaWQodGhldGEsIHJvdGF0aW9uLCBub3J0aFZlYywgZWFzdFZlYywgYVNxciwgYWIsIGJTcXIsIG1hZywgdW5pdFBvcywgcmVzdWx0KSB7CiAgICBjb25zdCBhemltdXRoID0gdGhldGEgKyByb3RhdGlvbjsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGVhc3RWZWMsIE1hdGguY29zKGF6aW11dGgpLCByb3RBeGlzKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG5vcnRoVmVjLCBNYXRoLnNpbihhemltdXRoKSwgdGVtcFZlYyk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJvdEF4aXMsIHRlbXBWZWMsIHJvdEF4aXMpOwogICAgbGV0IGNvc1RoZXRhU3F1YXJlZCA9IE1hdGguY29zKHRoZXRhKTsKICAgIGNvc1RoZXRhU3F1YXJlZCA9IGNvc1RoZXRhU3F1YXJlZCAqIGNvc1RoZXRhU3F1YXJlZDsKICAgIGxldCBzaW5UaGV0YVNxdWFyZWQgPSBNYXRoLnNpbih0aGV0YSk7CiAgICBzaW5UaGV0YVNxdWFyZWQgPSBzaW5UaGV0YVNxdWFyZWQgKiBzaW5UaGV0YVNxdWFyZWQ7CiAgICBjb25zdCByYWRpdXMgPSBhYiAvIE1hdGguc3FydChiU3FyICogY29zVGhldGFTcXVhcmVkICsgYVNxciAqIHNpblRoZXRhU3F1YXJlZCk7CiAgICBjb25zdCBhbmdsZSA9IHJhZGl1cyAvIG1hZzsKICAgIFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKHJvdEF4aXMsIGFuZ2xlLCB1bml0UXVhdCk7CiAgICBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24odW5pdFF1YXQsIHJvdE10eCk7CiAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3Rvcihyb3RNdHgsIHVuaXRQb3MsIHJlc3VsdCk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHJlc3VsdCwgcmVzdWx0KTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHJlc3VsdCwgbWFnLCByZXN1bHQpOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgdmFyIEVsbGlwc2VHZW9tZXRyeUxpYnJhcnksIHJvdEF4aXMsIHRlbXBWZWMsIHVuaXRRdWF0LCByb3RNdHgsIHNjcmF0Y2hDYXJ0ZXNpYW4xMiwgc2NyYXRjaENhcnRlc2lhbjIzLCBzY3JhdGNoQ2FydGVzaWFuMzQsIHNjcmF0Y2hOb3JtYWwyLCB1bml0UG9zU2NyYXRjaCwgZWFzdFZlY1NjcmF0Y2gsIG5vcnRoVmVjU2NyYXRjaCwgRWxsaXBzZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0OwogIHZhciBpbml0X0VsbGlwc2VHZW9tZXRyeUxpYnJhcnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0VsbGlwc2VHZW9tZXRyeUxpYnJhcnkuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X1F1YXRlcm5pb24oKTsKICAgICAgRWxsaXBzZUdlb21ldHJ5TGlicmFyeSA9IHt9OwogICAgICByb3RBeGlzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0ZW1wVmVjID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB1bml0UXVhdCA9IG5ldyBRdWF0ZXJuaW9uX2RlZmF1bHQoKTsKICAgICAgcm90TXR4ID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjM0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgRWxsaXBzZUdlb21ldHJ5TGlicmFyeS5yYWlzZVBvc2l0aW9uc1RvSGVpZ2h0ID0gZnVuY3Rpb24ocG9zaXRpb25zLCBvcHRpb25zLCBleHRydWRlKSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQ7CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGNvbnN0IHNpemUgPSBleHRydWRlID8gcG9zaXRpb25zLmxlbmd0aCAvIDMgKiAyIDogcG9zaXRpb25zLmxlbmd0aCAvIDM7CiAgICAgICAgY29uc3QgZmluYWxQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KHNpemUgKiAzKTsKICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGNvbnN0IGJvdHRvbU9mZnNldCA9IGV4dHJ1ZGUgPyBsZW5ndGggOiAwOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDMpIHsKICAgICAgICAgIGNvbnN0IGkxID0gaTIgKyAxOwogICAgICAgICAgY29uc3QgaTIyID0gaTIgKyAyOwogICAgICAgICAgY29uc3QgcG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIsIHNjcmF0Y2hDYXJ0ZXNpYW4xMik7CiAgICAgICAgICBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwb3NpdGlvbiwgcG9zaXRpb24pOwogICAgICAgICAgY29uc3QgZXh0cnVkZWRQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgc2NyYXRjaENhcnRlc2lhbjIzKTsKICAgICAgICAgIGNvbnN0IG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBzY3JhdGNoTm9ybWFsMik7CiAgICAgICAgICBjb25zdCBzY2FsZWROb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgbm9ybWFsMiwKICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMzQKICAgICAgICAgICk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBzY2FsZWROb3JtYWwsIHBvc2l0aW9uKTsKICAgICAgICAgIGlmIChleHRydWRlKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG5vcm1hbDIsIGV4dHJ1ZGVkSGVpZ2h0LCBzY2FsZWROb3JtYWwpOwogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGV4dHJ1ZGVkUG9zaXRpb24sIHNjYWxlZE5vcm1hbCwgZXh0cnVkZWRQb3NpdGlvbik7CiAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zW2kyICsgYm90dG9tT2Zmc2V0XSA9IGV4dHJ1ZGVkUG9zaXRpb24ueDsKICAgICAgICAgICAgZmluYWxQb3NpdGlvbnNbaTEgKyBib3R0b21PZmZzZXRdID0gZXh0cnVkZWRQb3NpdGlvbi55OwogICAgICAgICAgICBmaW5hbFBvc2l0aW9uc1tpMjIgKyBib3R0b21PZmZzZXRdID0gZXh0cnVkZWRQb3NpdGlvbi56OwogICAgICAgICAgfQogICAgICAgICAgZmluYWxQb3NpdGlvbnNbaTJdID0gcG9zaXRpb24ueDsKICAgICAgICAgIGZpbmFsUG9zaXRpb25zW2kxXSA9IHBvc2l0aW9uLnk7CiAgICAgICAgICBmaW5hbFBvc2l0aW9uc1tpMjJdID0gcG9zaXRpb24uejsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGZpbmFsUG9zaXRpb25zOwogICAgICB9OwogICAgICB1bml0UG9zU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZWFzdFZlY1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIG5vcnRoVmVjU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgRWxsaXBzZUdlb21ldHJ5TGlicmFyeS5jb21wdXRlRWxsaXBzZVBvc2l0aW9ucyA9IGZ1bmN0aW9uKG9wdGlvbnMsIGFkZEZpbGxQb3NpdGlvbnMsIGFkZEVkZ2VQb3NpdGlvbnMpIHsKICAgICAgICBjb25zdCBzZW1pTWlub3JBeGlzID0gb3B0aW9ucy5zZW1pTWlub3JBeGlzOwogICAgICAgIGNvbnN0IHNlbWlNYWpvckF4aXMgPSBvcHRpb25zLnNlbWlNYWpvckF4aXM7CiAgICAgICAgY29uc3Qgcm90YXRpb24gPSBvcHRpb25zLnJvdGF0aW9uOwogICAgICAgIGNvbnN0IGNlbnRlciA9IG9wdGlvbnMuY2VudGVyOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSAqIDg7CiAgICAgICAgY29uc3QgYVNxciA9IHNlbWlNaW5vckF4aXMgKiBzZW1pTWlub3JBeGlzOwogICAgICAgIGNvbnN0IGJTcXIgPSBzZW1pTWFqb3JBeGlzICogc2VtaU1ham9yQXhpczsKICAgICAgICBjb25zdCBhYiA9IHNlbWlNYWpvckF4aXMgKiBzZW1pTWlub3JBeGlzOwogICAgICAgIGNvbnN0IG1hZyA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoY2VudGVyKTsKICAgICAgICBjb25zdCB1bml0UG9zID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShjZW50ZXIsIHVuaXRQb3NTY3JhdGNoKTsKICAgICAgICBsZXQgZWFzdFZlYyA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9aLCBjZW50ZXIsIGVhc3RWZWNTY3JhdGNoKTsKICAgICAgICBlYXN0VmVjID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShlYXN0VmVjLCBlYXN0VmVjKTsKICAgICAgICBjb25zdCBub3J0aFZlYyA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyh1bml0UG9zLCBlYXN0VmVjLCBub3J0aFZlY1NjcmF0Y2gpOwogICAgICAgIGxldCBudW1QdHMgPSAxICsgTWF0aC5jZWlsKE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAvIGdyYW51bGFyaXR5KTsKICAgICAgICBjb25zdCBkZWx0YVRoZXRhID0gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIC8gKG51bVB0cyAtIDEpOwogICAgICAgIGxldCB0aGV0YSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIG51bVB0cyAqIGRlbHRhVGhldGE7CiAgICAgICAgaWYgKHRoZXRhIDwgMCkgewogICAgICAgICAgbnVtUHRzIC09IE1hdGguY2VpbChNYXRoLmFicyh0aGV0YSkgLyBkZWx0YVRoZXRhKTsKICAgICAgICB9CiAgICAgICAgY29uc3Qgc2l6ZSA9IDIgKiAobnVtUHRzICogKG51bVB0cyArIDIpKTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBhZGRGaWxsUG9zaXRpb25zID8gbmV3IEFycmF5KHNpemUgKiAzKSA6IHZvaWQgMDsKICAgICAgICBsZXQgcG9zaXRpb25JbmRleCA9IDA7CiAgICAgICAgbGV0IHBvc2l0aW9uID0gc2NyYXRjaENhcnRlc2lhbjEyOwogICAgICAgIGxldCByZWZsZWN0ZWRQb3NpdGlvbiA9IHNjcmF0Y2hDYXJ0ZXNpYW4yMzsKICAgICAgICBjb25zdCBvdXRlclBvc2l0aW9uc0xlbmd0aCA9IG51bVB0cyAqIDQgKiAzOwogICAgICAgIGxldCBvdXRlclJpZ2h0SW5kZXggPSBvdXRlclBvc2l0aW9uc0xlbmd0aCAtIDE7CiAgICAgICAgbGV0IG91dGVyTGVmdEluZGV4ID0gMDsKICAgICAgICBjb25zdCBvdXRlclBvc2l0aW9ucyA9IGFkZEVkZ2VQb3NpdGlvbnMgPyBuZXcgQXJyYXkob3V0ZXJQb3NpdGlvbnNMZW5ndGgpIDogdm9pZCAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgajI7CiAgICAgICAgbGV0IG51bUludGVyaW9yOwogICAgICAgIGxldCB0MjsKICAgICAgICBsZXQgaW50ZXJpb3JQb3NpdGlvbjsKICAgICAgICB0aGV0YSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICBwb3NpdGlvbiA9IHBvaW50T25FbGxpcHNvaWQoCiAgICAgICAgICB0aGV0YSwKICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgbm9ydGhWZWMsCiAgICAgICAgICBlYXN0VmVjLAogICAgICAgICAgYVNxciwKICAgICAgICAgIGFiLAogICAgICAgICAgYlNxciwKICAgICAgICAgIG1hZywKICAgICAgICAgIHVuaXRQb3MsCiAgICAgICAgICBwb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgaWYgKGFkZEZpbGxQb3NpdGlvbnMpIHsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24uejsKICAgICAgICB9CiAgICAgICAgaWYgKGFkZEVkZ2VQb3NpdGlvbnMpIHsKICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyUmlnaHRJbmRleC0tXSA9IHBvc2l0aW9uLno7CiAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlclJpZ2h0SW5kZXgtLV0gPSBwb3NpdGlvbi55OwogICAgICAgICAgb3V0ZXJQb3NpdGlvbnNbb3V0ZXJSaWdodEluZGV4LS1dID0gcG9zaXRpb24ueDsKICAgICAgICB9CiAgICAgICAgdGhldGEgPSBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gLSBkZWx0YVRoZXRhOwogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IG51bVB0cyArIDE7ICsraTIpIHsKICAgICAgICAgIHBvc2l0aW9uID0gcG9pbnRPbkVsbGlwc29pZCgKICAgICAgICAgICAgdGhldGEsCiAgICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgICBub3J0aFZlYywKICAgICAgICAgICAgZWFzdFZlYywKICAgICAgICAgICAgYVNxciwKICAgICAgICAgICAgYWIsCiAgICAgICAgICAgIGJTcXIsCiAgICAgICAgICAgIG1hZywKICAgICAgICAgICAgdW5pdFBvcywKICAgICAgICAgICAgcG9zaXRpb24KICAgICAgICAgICk7CiAgICAgICAgICByZWZsZWN0ZWRQb3NpdGlvbiA9IHBvaW50T25FbGxpcHNvaWQoCiAgICAgICAgICAgIE1hdGguUEkgLSB0aGV0YSwKICAgICAgICAgICAgcm90YXRpb24sCiAgICAgICAgICAgIG5vcnRoVmVjLAogICAgICAgICAgICBlYXN0VmVjLAogICAgICAgICAgICBhU3FyLAogICAgICAgICAgICBhYiwKICAgICAgICAgICAgYlNxciwKICAgICAgICAgICAgbWFnLAogICAgICAgICAgICB1bml0UG9zLAogICAgICAgICAgICByZWZsZWN0ZWRQb3NpdGlvbgogICAgICAgICAgKTsKICAgICAgICAgIGlmIChhZGRGaWxsUG9zaXRpb25zKSB7CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBwb3NpdGlvbi55OwogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHBvc2l0aW9uLno7CiAgICAgICAgICAgIG51bUludGVyaW9yID0gMiAqIGkyICsgMjsKICAgICAgICAgICAgZm9yIChqMiA9IDE7IGoyIDwgbnVtSW50ZXJpb3IgLSAxOyArK2oyKSB7CiAgICAgICAgICAgICAgdDIgPSBqMiAvIChudW1JbnRlcmlvciAtIDEpOwogICAgICAgICAgICAgIGludGVyaW9yUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubGVycCgKICAgICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgICAgcmVmbGVjdGVkUG9zaXRpb24sCiAgICAgICAgICAgICAgICB0MiwKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zNAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBpbnRlcmlvclBvc2l0aW9uLng7CiAgICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBpbnRlcmlvclBvc2l0aW9uLnk7CiAgICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBpbnRlcmlvclBvc2l0aW9uLno7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSByZWZsZWN0ZWRQb3NpdGlvbi54OwogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHJlZmxlY3RlZFBvc2l0aW9uLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcmVmbGVjdGVkUG9zaXRpb24uejsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChhZGRFZGdlUG9zaXRpb25zKSB7CiAgICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyUmlnaHRJbmRleC0tXSA9IHBvc2l0aW9uLno7CiAgICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyUmlnaHRJbmRleC0tXSA9IHBvc2l0aW9uLnk7CiAgICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyUmlnaHRJbmRleC0tXSA9IHBvc2l0aW9uLng7CiAgICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyTGVmdEluZGV4KytdID0gcmVmbGVjdGVkUG9zaXRpb24ueDsKICAgICAgICAgICAgb3V0ZXJQb3NpdGlvbnNbb3V0ZXJMZWZ0SW5kZXgrK10gPSByZWZsZWN0ZWRQb3NpdGlvbi55OwogICAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlckxlZnRJbmRleCsrXSA9IHJlZmxlY3RlZFBvc2l0aW9uLno7CiAgICAgICAgICB9CiAgICAgICAgICB0aGV0YSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIChpMiArIDEpICogZGVsdGFUaGV0YTsKICAgICAgICB9CiAgICAgICAgZm9yIChpMiA9IG51bVB0czsgaTIgPiAxOyAtLWkyKSB7CiAgICAgICAgICB0aGV0YSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIChpMiAtIDEpICogZGVsdGFUaGV0YTsKICAgICAgICAgIHBvc2l0aW9uID0gcG9pbnRPbkVsbGlwc29pZCgKICAgICAgICAgICAgLXRoZXRhLAogICAgICAgICAgICByb3RhdGlvbiwKICAgICAgICAgICAgbm9ydGhWZWMsCiAgICAgICAgICAgIGVhc3RWZWMsCiAgICAgICAgICAgIGFTcXIsCiAgICAgICAgICAgIGFiLAogICAgICAgICAgICBiU3FyLAogICAgICAgICAgICBtYWcsCiAgICAgICAgICAgIHVuaXRQb3MsCiAgICAgICAgICAgIHBvc2l0aW9uCiAgICAgICAgICApOwogICAgICAgICAgcmVmbGVjdGVkUG9zaXRpb24gPSBwb2ludE9uRWxsaXBzb2lkKAogICAgICAgICAgICB0aGV0YSArIE1hdGguUEksCiAgICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgICBub3J0aFZlYywKICAgICAgICAgICAgZWFzdFZlYywKICAgICAgICAgICAgYVNxciwKICAgICAgICAgICAgYWIsCiAgICAgICAgICAgIGJTcXIsCiAgICAgICAgICAgIG1hZywKICAgICAgICAgICAgdW5pdFBvcywKICAgICAgICAgICAgcmVmbGVjdGVkUG9zaXRpb24KICAgICAgICAgICk7CiAgICAgICAgICBpZiAoYWRkRmlsbFBvc2l0aW9ucykgewogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHBvc2l0aW9uLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBwb3NpdGlvbi56OwogICAgICAgICAgICBudW1JbnRlcmlvciA9IDIgKiAoaTIgLSAxKSArIDI7CiAgICAgICAgICAgIGZvciAoajIgPSAxOyBqMiA8IG51bUludGVyaW9yIC0gMTsgKytqMikgewogICAgICAgICAgICAgIHQyID0gajIgLyAobnVtSW50ZXJpb3IgLSAxKTsKICAgICAgICAgICAgICBpbnRlcmlvclBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmxlcnAoCiAgICAgICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgICAgIHJlZmxlY3RlZFBvc2l0aW9uLAogICAgICAgICAgICAgICAgdDIsCiAgICAgICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMzQKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gaW50ZXJpb3JQb3NpdGlvbi54OwogICAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gaW50ZXJpb3JQb3NpdGlvbi55OwogICAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gaW50ZXJpb3JQb3NpdGlvbi56OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcmVmbGVjdGVkUG9zaXRpb24ueDsKICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSByZWZsZWN0ZWRQb3NpdGlvbi55OwogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHJlZmxlY3RlZFBvc2l0aW9uLno7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoYWRkRWRnZVBvc2l0aW9ucykgewogICAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlclJpZ2h0SW5kZXgtLV0gPSBwb3NpdGlvbi56OwogICAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlclJpZ2h0SW5kZXgtLV0gPSBwb3NpdGlvbi55OwogICAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlclJpZ2h0SW5kZXgtLV0gPSBwb3NpdGlvbi54OwogICAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlckxlZnRJbmRleCsrXSA9IHJlZmxlY3RlZFBvc2l0aW9uLng7CiAgICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyTGVmdEluZGV4KytdID0gcmVmbGVjdGVkUG9zaXRpb24ueTsKICAgICAgICAgICAgb3V0ZXJQb3NpdGlvbnNbb3V0ZXJMZWZ0SW5kZXgrK10gPSByZWZsZWN0ZWRQb3NpdGlvbi56OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB0aGV0YSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICBwb3NpdGlvbiA9IHBvaW50T25FbGxpcHNvaWQoCiAgICAgICAgICAtdGhldGEsCiAgICAgICAgICByb3RhdGlvbiwKICAgICAgICAgIG5vcnRoVmVjLAogICAgICAgICAgZWFzdFZlYywKICAgICAgICAgIGFTcXIsCiAgICAgICAgICBhYiwKICAgICAgICAgIGJTcXIsCiAgICAgICAgICBtYWcsCiAgICAgICAgICB1bml0UG9zLAogICAgICAgICAgcG9zaXRpb24KICAgICAgICApOwogICAgICAgIGNvbnN0IHIyID0ge307CiAgICAgICAgaWYgKGFkZEZpbGxQb3NpdGlvbnMpIHsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4XSA9IHBvc2l0aW9uLno7CiAgICAgICAgICByMi5wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgICByMi5udW1QdHMgPSBudW1QdHM7CiAgICAgICAgfQogICAgICAgIGlmIChhZGRFZGdlUG9zaXRpb25zKSB7CiAgICAgICAgICBvdXRlclBvc2l0aW9uc1tvdXRlclJpZ2h0SW5kZXgtLV0gPSBwb3NpdGlvbi56OwogICAgICAgICAgb3V0ZXJQb3NpdGlvbnNbb3V0ZXJSaWdodEluZGV4LS1dID0gcG9zaXRpb24ueTsKICAgICAgICAgIG91dGVyUG9zaXRpb25zW291dGVyUmlnaHRJbmRleF0gPSBwb3NpdGlvbi54OwogICAgICAgICAgcjIub3V0ZXJQb3NpdGlvbnMgPSBvdXRlclBvc2l0aW9uczsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHIyOwogICAgICB9OwogICAgICBFbGxpcHNlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQgPSBFbGxpcHNlR2VvbWV0cnlMaWJyYXJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnlJbnN0YW5jZS5qcwogIGZ1bmN0aW9uIEdlb21ldHJ5SW5zdGFuY2Uob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5nZW9tZXRyeSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMuZ2VvbWV0cnkgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICB0aGlzLmdlb21ldHJ5ID0gb3B0aW9ucy5nZW9tZXRyeTsKICAgIHRoaXMubW9kZWxNYXRyaXggPSBNYXRyaXg0X2RlZmF1bHQuY2xvbmUob3B0aW9ucy5tb2RlbE1hdHJpeCA/PyBNYXRyaXg0X2RlZmF1bHQuSURFTlRJVFkpOwogICAgdGhpcy5pZCA9IG9wdGlvbnMuaWQ7CiAgICB0aGlzLnBpY2tQcmltaXRpdmUgPSBvcHRpb25zLnBpY2tQcmltaXRpdmU7CiAgICB0aGlzLmF0dHJpYnV0ZXMgPSBvcHRpb25zLmF0dHJpYnV0ZXMgPz8ge307CiAgICB0aGlzLndlc3RIZW1pc3BoZXJlR2VvbWV0cnkgPSB2b2lkIDA7CiAgICB0aGlzLmVhc3RIZW1pc3BoZXJlR2VvbWV0cnkgPSB2b2lkIDA7CiAgfQogIHZhciBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQ7CiAgdmFyIGluaXRfR2VvbWV0cnlJbnN0YW5jZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvbWV0cnlJbnN0YW5jZS5qcyIoKSB7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQgPSBHZW9tZXRyeUluc3RhbmNlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gY29tcHV0ZVRvcEJvdHRvbUF0dHJpYnV0ZXMocG9zaXRpb25zLCBvcHRpb25zLCBleHRydWRlKSB7CiAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBvcHRpb25zLnZlcnRleEZvcm1hdDsKICAgIGNvbnN0IGNlbnRlciA9IG9wdGlvbnMuY2VudGVyOwogICAgY29uc3Qgc2VtaU1ham9yQXhpcyA9IG9wdGlvbnMuc2VtaU1ham9yQXhpczsKICAgIGNvbnN0IHNlbWlNaW5vckF4aXMgPSBvcHRpb25zLnNlbWlNaW5vckF4aXM7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZDsKICAgIGNvbnN0IHN0Um90YXRpb24gPSBvcHRpb25zLnN0Um90YXRpb247CiAgICBjb25zdCBzaXplID0gZXh0cnVkZSA/IHBvc2l0aW9ucy5sZW5ndGggLyAzICogMiA6IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gb3B0aW9ucy5zaGFkb3dWb2x1bWU7CiAgICBjb25zdCB0ZXh0dXJlQ29vcmRpbmF0ZXMgPSB2ZXJ0ZXhGb3JtYXQuc3QgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAyKSA6IHZvaWQgMDsKICAgIGNvbnN0IG5vcm1hbHMgPSB2ZXJ0ZXhGb3JtYXQubm9ybWFsID8gbmV3IEZsb2F0MzJBcnJheShzaXplICogMykgOiB2b2lkIDA7CiAgICBjb25zdCB0YW5nZW50cyA9IHZlcnRleEZvcm1hdC50YW5nZW50ID8gbmV3IEZsb2F0MzJBcnJheShzaXplICogMykgOiB2b2lkIDA7CiAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIDMpIDogdm9pZCAwOwogICAgY29uc3QgZXh0cnVkZU5vcm1hbHMgPSBzaGFkb3dWb2x1bWUgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAzKSA6IHZvaWQgMDsKICAgIGxldCB0ZXh0dXJlQ29vcmRJbmRleCA9IDA7CiAgICBsZXQgbm9ybWFsMiA9IHNjcmF0Y2hOb3JtYWwzOwogICAgbGV0IHRhbmdlbnQgPSBzY3JhdGNoVGFuZ2VudDsKICAgIGxldCBiaXRhbmdlbnQgPSBzY3JhdGNoQml0YW5nZW50OwogICAgY29uc3QgcHJvamVjdGlvbiA9IG5ldyBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0KGVsbGlwc29pZCk7CiAgICBjb25zdCBwcm9qZWN0ZWRDZW50ZXIgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgIGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhjZW50ZXIsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMyKSwKICAgICAgcHJvamVjdGVkQ2VudGVyU2NyYXRjaAogICAgKTsKICAgIGNvbnN0IGdlb2RldGljTm9ybWFsID0gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UoCiAgICAgIGNlbnRlciwKICAgICAgc2NyYXRjaENhcnRlc2lhbjEzCiAgICApOwogICAgZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChnZW9kZXRpY05vcm1hbCwgZ2VvZGV0aWNOb3JtYWwpOwogICAgbGV0IHRleHR1cmVNYXRyaXggPSB0ZXh0dXJlTWF0cml4U2NyYXRjaDsKICAgIGxldCB0YW5nZW50TWF0cml4ID0gdGFuZ2VudE1hdHJpeFNjcmF0Y2g7CiAgICBpZiAoc3RSb3RhdGlvbiAhPT0gMCkgewogICAgICBsZXQgcm90YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuZnJvbUF4aXNBbmdsZSgKICAgICAgICBnZW9kZXRpY05vcm1hbCwKICAgICAgICBzdFJvdGF0aW9uLAogICAgICAgIHF1YXRlcm5pb25TY3JhdGNoCiAgICAgICk7CiAgICAgIHRleHR1cmVNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24ocm90YXRpb24sIHRleHR1cmVNYXRyaXgpOwogICAgICByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgIGdlb2RldGljTm9ybWFsLAogICAgICAgIC1zdFJvdGF0aW9uLAogICAgICAgIHF1YXRlcm5pb25TY3JhdGNoCiAgICAgICk7CiAgICAgIHRhbmdlbnRNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24ocm90YXRpb24sIHRhbmdlbnRNYXRyaXgpOwogICAgfSBlbHNlIHsKICAgICAgdGV4dHVyZU1hdHJpeCA9IE1hdHJpeDNfZGVmYXVsdC5jbG9uZShNYXRyaXgzX2RlZmF1bHQuSURFTlRJVFksIHRleHR1cmVNYXRyaXgpOwogICAgICB0YW5nZW50TWF0cml4ID0gTWF0cml4M19kZWZhdWx0LmNsb25lKE1hdHJpeDNfZGVmYXVsdC5JREVOVElUWSwgdGFuZ2VudE1hdHJpeCk7CiAgICB9CiAgICBjb25zdCBtaW5UZXhDb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgIE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwKICAgICAgTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLAogICAgICBzY3JhdGNoTWluVGV4Q29vcmQKICAgICk7CiAgICBjb25zdCBtYXhUZXhDb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICBzY3JhdGNoTWF4VGV4Q29vcmQKICAgICk7CiAgICBsZXQgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgIGNvbnN0IGJvdHRvbU9mZnNldCA9IGV4dHJ1ZGUgPyBsZW5ndGggOiAwOwogICAgY29uc3Qgc3RPZmZzZXQgPSBib3R0b21PZmZzZXQgLyAzICogMjsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDMpIHsKICAgICAgY29uc3QgaTEgPSBpMiArIDE7CiAgICAgIGNvbnN0IGkyMiA9IGkyICsgMjsKICAgICAgY29uc3QgcG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIsIHNjcmF0Y2hDYXJ0ZXNpYW4xMyk7CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICBjb25zdCByb3RhdGVkUG9pbnQgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcigKICAgICAgICAgIHRleHR1cmVNYXRyaXgsCiAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yNAogICAgICAgICk7CiAgICAgICAgY29uc3QgcHJvamVjdGVkUG9pbnQgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgICAgICBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocm90YXRlZFBvaW50LCBzY3JhdGNoQ2FydG9ncmFwaGljMiksCiAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMzUKICAgICAgICApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwcm9qZWN0ZWRQb2ludCwgcHJvamVjdGVkQ2VudGVyLCBwcm9qZWN0ZWRQb2ludCk7CiAgICAgICAgdGV4Q29vcmRTY3JhdGNoLnggPSAocHJvamVjdGVkUG9pbnQueCArIHNlbWlNYWpvckF4aXMpIC8gKDIgKiBzZW1pTWFqb3JBeGlzKTsKICAgICAgICB0ZXhDb29yZFNjcmF0Y2gueSA9IChwcm9qZWN0ZWRQb2ludC55ICsgc2VtaU1pbm9yQXhpcykgLyAoMiAqIHNlbWlNaW5vckF4aXMpOwogICAgICAgIG1pblRleENvb3JkLnggPSBNYXRoLm1pbih0ZXhDb29yZFNjcmF0Y2gueCwgbWluVGV4Q29vcmQueCk7CiAgICAgICAgbWluVGV4Q29vcmQueSA9IE1hdGgubWluKHRleENvb3JkU2NyYXRjaC55LCBtaW5UZXhDb29yZC55KTsKICAgICAgICBtYXhUZXhDb29yZC54ID0gTWF0aC5tYXgodGV4Q29vcmRTY3JhdGNoLngsIG1heFRleENvb3JkLngpOwogICAgICAgIG1heFRleENvb3JkLnkgPSBNYXRoLm1heCh0ZXhDb29yZFNjcmF0Y2gueSwgbWF4VGV4Q29vcmQueSk7CiAgICAgICAgaWYgKGV4dHJ1ZGUpIHsKICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlc1t0ZXh0dXJlQ29vcmRJbmRleCArIHN0T2Zmc2V0XSA9IHRleENvb3JkU2NyYXRjaC54OwogICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3RleHR1cmVDb29yZEluZGV4ICsgMSArIHN0T2Zmc2V0XSA9IHRleENvb3JkU2NyYXRjaC55OwogICAgICAgIH0KICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbdGV4dHVyZUNvb3JkSW5kZXgrK10gPSB0ZXhDb29yZFNjcmF0Y2gueDsKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbdGV4dHVyZUNvb3JkSW5kZXgrK10gPSB0ZXhDb29yZFNjcmF0Y2gueTsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50IHx8IHNoYWRvd1ZvbHVtZSkgewogICAgICAgIG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBub3JtYWwyKTsKICAgICAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgICAgICBleHRydWRlTm9ybWFsc1tpMiArIGJvdHRvbU9mZnNldF0gPSAtbm9ybWFsMi54OwogICAgICAgICAgZXh0cnVkZU5vcm1hbHNbaTEgKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIueTsKICAgICAgICAgIGV4dHJ1ZGVOb3JtYWxzW2kyMiArIGJvdHRvbU9mZnNldF0gPSAtbm9ybWFsMi56OwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICB0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwgbm9ybWFsMiwgdGFuZ2VudCksCiAgICAgICAgICAgICAgdGFuZ2VudAogICAgICAgICAgICApOwogICAgICAgICAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3Rvcih0YW5nZW50TWF0cml4LCB0YW5nZW50LCB0YW5nZW50KTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsKSB7CiAgICAgICAgICAgIG5vcm1hbHNbaTJdID0gbm9ybWFsMi54OwogICAgICAgICAgICBub3JtYWxzW2kxXSA9IG5vcm1hbDIueTsKICAgICAgICAgICAgbm9ybWFsc1tpMjJdID0gbm9ybWFsMi56OwogICAgICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgICAgIG5vcm1hbHNbaTIgKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIueDsKICAgICAgICAgICAgICBub3JtYWxzW2kxICsgYm90dG9tT2Zmc2V0XSA9IC1ub3JtYWwyLnk7CiAgICAgICAgICAgICAgbm9ybWFsc1tpMjIgKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIuejsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICAgIHRhbmdlbnRzW2kyXSA9IHRhbmdlbnQueDsKICAgICAgICAgICAgdGFuZ2VudHNbaTFdID0gdGFuZ2VudC55OwogICAgICAgICAgICB0YW5nZW50c1tpMjJdID0gdGFuZ2VudC56OwogICAgICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgICAgIHRhbmdlbnRzW2kyICsgYm90dG9tT2Zmc2V0XSA9IC10YW5nZW50Lng7CiAgICAgICAgICAgICAgdGFuZ2VudHNbaTEgKyBib3R0b21PZmZzZXRdID0gLXRhbmdlbnQueTsKICAgICAgICAgICAgICB0YW5nZW50c1tpMjIgKyBib3R0b21PZmZzZXRdID0gLXRhbmdlbnQuejsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Mobm9ybWFsMiwgdGFuZ2VudCwgYml0YW5nZW50KSwKICAgICAgICAgICAgICBiaXRhbmdlbnQKICAgICAgICAgICAgKTsKICAgICAgICAgICAgYml0YW5nZW50c1tpMl0gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgYml0YW5nZW50c1tpMV0gPSBiaXRhbmdlbnQueTsKICAgICAgICAgICAgYml0YW5nZW50c1tpMjJdID0gYml0YW5nZW50Lno7CiAgICAgICAgICAgIGlmIChleHRydWRlKSB7CiAgICAgICAgICAgICAgYml0YW5nZW50c1tpMiArIGJvdHRvbU9mZnNldF0gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2kxICsgYm90dG9tT2Zmc2V0XSA9IGJpdGFuZ2VudC55OwogICAgICAgICAgICAgIGJpdGFuZ2VudHNbaTIyICsgYm90dG9tT2Zmc2V0XSA9IGJpdGFuZ2VudC56OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgIGxlbmd0aCA9IHRleHR1cmVDb29yZGluYXRlcy5sZW5ndGg7CiAgICAgIGZvciAobGV0IGsyID0gMDsgazIgPCBsZW5ndGg7IGsyICs9IDIpIHsKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbazJdID0gKHRleHR1cmVDb29yZGluYXRlc1trMl0gLSBtaW5UZXhDb29yZC54KSAvIChtYXhUZXhDb29yZC54IC0gbWluVGV4Q29vcmQueCk7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW2syICsgMV0gPSAodGV4dHVyZUNvb3JkaW5hdGVzW2syICsgMV0gLSBtaW5UZXhDb29yZC55KSAvIChtYXhUZXhDb29yZC55IC0gbWluVGV4Q29vcmQueSk7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgIGlmICh2ZXJ0ZXhGb3JtYXQucG9zaXRpb24pIHsKICAgICAgY29uc3QgZmluYWxQb3NpdGlvbnMgPSBFbGxpcHNlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucmFpc2VQb3NpdGlvbnNUb0hlaWdodCgKICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgb3B0aW9ucywKICAgICAgICBleHRydWRlCiAgICAgICk7CiAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBmaW5hbFBvc2l0aW9ucwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgIHZhbHVlczogdGV4dHVyZUNvb3JkaW5hdGVzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgYXR0cmlidXRlcy50YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiB0YW5nZW50cwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICBhdHRyaWJ1dGVzLmV4dHJ1ZGVEaXJlY3Rpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IGV4dHJ1ZGVOb3JtYWxzCiAgICAgIH0pOwogICAgfQogICAgaWYgKGV4dHJ1ZGUgJiYgZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlKSkgewogICAgICBsZXQgb2Zmc2V0QXR0cmlidXRlID0gbmV3IFVpbnQ4QXJyYXkoc2l6ZSk7CiAgICAgIGlmIChvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5UT1ApIHsKICAgICAgICBvZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUuZmlsbCgxLCAwLCBzaXplIC8gMik7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5OT05FID8gMCA6IDE7CiAgICAgICAgb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlLmZpbGwob2Zmc2V0VmFsdWUpOwogICAgICB9CiAgICAgIGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAxLAogICAgICAgIHZhbHVlczogb2Zmc2V0QXR0cmlidXRlCiAgICAgIH0pOwogICAgfQogICAgcmV0dXJuIGF0dHJpYnV0ZXM7CiAgfQogIGZ1bmN0aW9uIHRvcEluZGljZXMobnVtUHRzKSB7CiAgICBjb25zdCBpbmRpY2VzID0gbmV3IEFycmF5KDEyICogKG51bVB0cyAqIChudW1QdHMgKyAxKSkgLSA2KTsKICAgIGxldCBpbmRpY2VzSW5kZXggPSAwOwogICAgbGV0IHByZXZJbmRleDsKICAgIGxldCBudW1JbnRlcmlvcjsKICAgIGxldCBwb3NpdGlvbkluZGV4OwogICAgbGV0IGkyOwogICAgbGV0IGoyOwogICAgcHJldkluZGV4ID0gMDsKICAgIHBvc2l0aW9uSW5kZXggPSAxOwogICAgZm9yIChpMiA9IDA7IGkyIDwgMzsgaTIrKykgewogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXgrKzsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXg7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcG9zaXRpb25JbmRleDsKICAgIH0KICAgIGZvciAoaTIgPSAyOyBpMiA8IG51bVB0cyArIDE7ICsraTIpIHsKICAgICAgcG9zaXRpb25JbmRleCA9IGkyICogKGkyICsgMSkgLSAxOwogICAgICBwcmV2SW5kZXggPSAoaTIgLSAxKSAqIGkyIC0gMTsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwb3NpdGlvbkluZGV4Kys7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgIG51bUludGVyaW9yID0gMiAqIGkyOwogICAgICBmb3IgKGoyID0gMDsgajIgPCBudW1JbnRlcmlvciAtIDE7ICsrajIpIHsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXgrKzsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHByZXZJbmRleDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXgrKzsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHByZXZJbmRleDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgIH0KICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwb3NpdGlvbkluZGV4Kys7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICB9CiAgICBudW1JbnRlcmlvciA9IG51bVB0cyAqIDI7CiAgICArK3Bvc2l0aW9uSW5kZXg7CiAgICArK3ByZXZJbmRleDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bUludGVyaW9yIC0gMTsgKytpMikgewogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4Kys7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXgrKzsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXg7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcG9zaXRpb25JbmRleDsKICAgIH0KICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcG9zaXRpb25JbmRleDsKICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4Kys7CiAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHByZXZJbmRleDsKICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcG9zaXRpb25JbmRleCsrOwogICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXgrKzsKICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgKytwcmV2SW5kZXg7CiAgICBmb3IgKGkyID0gbnVtUHRzIC0gMTsgaTIgPiAxOyAtLWkyKSB7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4Kys7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgIG51bUludGVyaW9yID0gMiAqIGkyOwogICAgICBmb3IgKGoyID0gMDsgajIgPCBudW1JbnRlcmlvciAtIDE7ICsrajIpIHsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXgrKzsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHByZXZJbmRleDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXgrKzsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHByZXZJbmRleDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICAgIH0KICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXgrKzsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwcmV2SW5kZXgrKzsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwb3NpdGlvbkluZGV4Kys7CiAgICB9CiAgICBmb3IgKGkyID0gMDsgaTIgPCAzOyBpMisrKSB7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4Kys7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gcHJldkluZGV4OwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHBvc2l0aW9uSW5kZXg7CiAgICB9CiAgICByZXR1cm4gaW5kaWNlczsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUVsbGlwc2Uob3B0aW9ucykgewogICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICBib3VuZGluZ1NwaGVyZUNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICBvcHRpb25zLmVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoY2VudGVyLCBib3VuZGluZ1NwaGVyZUNlbnRlciksCiAgICAgIG9wdGlvbnMuaGVpZ2h0LAogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlcgogICAgKTsKICAgIGJvdW5kaW5nU3BoZXJlQ2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgY2VudGVyLAogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlciwKICAgICAgYm91bmRpbmdTcGhlcmVDZW50ZXIKICAgICk7CiAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KAogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlciwKICAgICAgb3B0aW9ucy5zZW1pTWFqb3JBeGlzCiAgICApOwogICAgY29uc3QgY2VwID0gRWxsaXBzZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVFbGxpcHNlUG9zaXRpb25zKAogICAgICBvcHRpb25zLAogICAgICB0cnVlLAogICAgICBmYWxzZQogICAgKTsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGNlcC5wb3NpdGlvbnM7CiAgICBjb25zdCBudW1QdHMgPSBjZXAubnVtUHRzOwogICAgY29uc3QgYXR0cmlidXRlcyA9IGNvbXB1dGVUb3BCb3R0b21BdHRyaWJ1dGVzKHBvc2l0aW9ucywgb3B0aW9ucywgZmFsc2UpOwogICAgbGV0IGluZGljZXMgPSB0b3BJbmRpY2VzKG51bVB0cyk7CiAgICBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkocG9zaXRpb25zLmxlbmd0aCAvIDMsIGluZGljZXMpOwogICAgcmV0dXJuIHsKICAgICAgYm91bmRpbmdTcGhlcmUsCiAgICAgIGF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXMKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVXYWxsQXR0cmlidXRlcyhwb3NpdGlvbnMsIG9wdGlvbnMpIHsKICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IG9wdGlvbnMudmVydGV4Rm9ybWF0OwogICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICBjb25zdCBzZW1pTWFqb3JBeGlzID0gb3B0aW9ucy5zZW1pTWFqb3JBeGlzOwogICAgY29uc3Qgc2VtaU1pbm9yQXhpcyA9IG9wdGlvbnMuc2VtaU1pbm9yQXhpczsKICAgIGNvbnN0IGVsbGlwc29pZCA9IG9wdGlvbnMuZWxsaXBzb2lkOwogICAgY29uc3QgaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQ7CiAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQ7CiAgICBjb25zdCBzdFJvdGF0aW9uID0gb3B0aW9ucy5zdFJvdGF0aW9uOwogICAgY29uc3Qgc2l6ZSA9IHBvc2l0aW9ucy5sZW5ndGggLyAzICogMjsKICAgIGNvbnN0IGZpbmFsUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShzaXplICogMyk7CiAgICBjb25zdCB0ZXh0dXJlQ29vcmRpbmF0ZXMgPSB2ZXJ0ZXhGb3JtYXQuc3QgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAyKSA6IHZvaWQgMDsKICAgIGNvbnN0IG5vcm1hbHMgPSB2ZXJ0ZXhGb3JtYXQubm9ybWFsID8gbmV3IEZsb2F0MzJBcnJheShzaXplICogMykgOiB2b2lkIDA7CiAgICBjb25zdCB0YW5nZW50cyA9IHZlcnRleEZvcm1hdC50YW5nZW50ID8gbmV3IEZsb2F0MzJBcnJheShzaXplICogMykgOiB2b2lkIDA7CiAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIDMpIDogdm9pZCAwOwogICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gb3B0aW9ucy5zaGFkb3dWb2x1bWU7CiAgICBjb25zdCBleHRydWRlTm9ybWFscyA9IHNoYWRvd1ZvbHVtZSA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIDMpIDogdm9pZCAwOwogICAgbGV0IHRleHR1cmVDb29yZEluZGV4ID0gMDsKICAgIGxldCBub3JtYWwyID0gc2NyYXRjaE5vcm1hbDM7CiAgICBsZXQgdGFuZ2VudCA9IHNjcmF0Y2hUYW5nZW50OwogICAgbGV0IGJpdGFuZ2VudCA9IHNjcmF0Y2hCaXRhbmdlbnQ7CiAgICBjb25zdCBwcm9qZWN0aW9uID0gbmV3IEdlb2dyYXBoaWNQcm9qZWN0aW9uX2RlZmF1bHQoZWxsaXBzb2lkKTsKICAgIGNvbnN0IHByb2plY3RlZENlbnRlciA9IHByb2plY3Rpb24ucHJvamVjdCgKICAgICAgZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKGNlbnRlciwgc2NyYXRjaENhcnRvZ3JhcGhpYzIpLAogICAgICBwcm9qZWN0ZWRDZW50ZXJTY3JhdGNoCiAgICApOwogICAgY29uc3QgZ2VvZGV0aWNOb3JtYWwgPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZSgKICAgICAgY2VudGVyLAogICAgICBzY3JhdGNoQ2FydGVzaWFuMTMKICAgICk7CiAgICBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKGdlb2RldGljTm9ybWFsLCBnZW9kZXRpY05vcm1hbCk7CiAgICBjb25zdCByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICBnZW9kZXRpY05vcm1hbCwKICAgICAgc3RSb3RhdGlvbiwKICAgICAgcXVhdGVybmlvblNjcmF0Y2gKICAgICk7CiAgICBjb25zdCB0ZXh0dXJlTWF0cml4ID0gTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKHJvdGF0aW9uLCB0ZXh0dXJlTWF0cml4U2NyYXRjaCk7CiAgICBjb25zdCBtaW5UZXhDb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgIE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwKICAgICAgTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZLAogICAgICBzY3JhdGNoTWluVGV4Q29vcmQKICAgICk7CiAgICBjb25zdCBtYXhUZXhDb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICBzY3JhdGNoTWF4VGV4Q29vcmQKICAgICk7CiAgICBsZXQgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgIGNvbnN0IHN0T2Zmc2V0ID0gbGVuZ3RoIC8gMyAqIDI7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgIGNvbnN0IGkxID0gaTIgKyAxOwogICAgICBjb25zdCBpMjIgPSBpMiArIDI7CiAgICAgIGxldCBwb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBpMiwgc2NyYXRjaENhcnRlc2lhbjEzKTsKICAgICAgbGV0IGV4dHJ1ZGVkUG9zaXRpb247CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICBjb25zdCByb3RhdGVkUG9pbnQgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcigKICAgICAgICAgIHRleHR1cmVNYXRyaXgsCiAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yNAogICAgICAgICk7CiAgICAgICAgY29uc3QgcHJvamVjdGVkUG9pbnQgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgICAgICBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocm90YXRlZFBvaW50LCBzY3JhdGNoQ2FydG9ncmFwaGljMiksCiAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMzUKICAgICAgICApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwcm9qZWN0ZWRQb2ludCwgcHJvamVjdGVkQ2VudGVyLCBwcm9qZWN0ZWRQb2ludCk7CiAgICAgICAgdGV4Q29vcmRTY3JhdGNoLnggPSAocHJvamVjdGVkUG9pbnQueCArIHNlbWlNYWpvckF4aXMpIC8gKDIgKiBzZW1pTWFqb3JBeGlzKTsKICAgICAgICB0ZXhDb29yZFNjcmF0Y2gueSA9IChwcm9qZWN0ZWRQb2ludC55ICsgc2VtaU1pbm9yQXhpcykgLyAoMiAqIHNlbWlNaW5vckF4aXMpOwogICAgICAgIG1pblRleENvb3JkLnggPSBNYXRoLm1pbih0ZXhDb29yZFNjcmF0Y2gueCwgbWluVGV4Q29vcmQueCk7CiAgICAgICAgbWluVGV4Q29vcmQueSA9IE1hdGgubWluKHRleENvb3JkU2NyYXRjaC55LCBtaW5UZXhDb29yZC55KTsKICAgICAgICBtYXhUZXhDb29yZC54ID0gTWF0aC5tYXgodGV4Q29vcmRTY3JhdGNoLngsIG1heFRleENvb3JkLngpOwogICAgICAgIG1heFRleENvb3JkLnkgPSBNYXRoLm1heCh0ZXhDb29yZFNjcmF0Y2gueSwgbWF4VGV4Q29vcmQueSk7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3RleHR1cmVDb29yZEluZGV4ICsgc3RPZmZzZXRdID0gdGV4Q29vcmRTY3JhdGNoLng7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3RleHR1cmVDb29yZEluZGV4ICsgMSArIHN0T2Zmc2V0XSA9IHRleENvb3JkU2NyYXRjaC55OwogICAgICAgIHRleHR1cmVDb29yZGluYXRlc1t0ZXh0dXJlQ29vcmRJbmRleCsrXSA9IHRleENvb3JkU2NyYXRjaC54OwogICAgICAgIHRleHR1cmVDb29yZGluYXRlc1t0ZXh0dXJlQ29vcmRJbmRleCsrXSA9IHRleENvb3JkU2NyYXRjaC55OwogICAgICB9CiAgICAgIHBvc2l0aW9uID0gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UocG9zaXRpb24sIHBvc2l0aW9uKTsKICAgICAgZXh0cnVkZWRQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgc2NyYXRjaENhcnRlc2lhbjI0KTsKICAgICAgbm9ybWFsMiA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocG9zaXRpb24sIG5vcm1hbDIpOwogICAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgICAgZXh0cnVkZU5vcm1hbHNbaTIgKyBsZW5ndGhdID0gLW5vcm1hbDIueDsKICAgICAgICBleHRydWRlTm9ybWFsc1tpMSArIGxlbmd0aF0gPSAtbm9ybWFsMi55OwogICAgICAgIGV4dHJ1ZGVOb3JtYWxzW2kyMiArIGxlbmd0aF0gPSAtbm9ybWFsMi56OwogICAgICB9CiAgICAgIGxldCBzY2FsZWROb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICBub3JtYWwyLAogICAgICAgIGhlaWdodCwKICAgICAgICBzY3JhdGNoQ2FydGVzaWFuNAogICAgICApOwogICAgICBwb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIHNjYWxlZE5vcm1hbCwgcG9zaXRpb24pOwogICAgICBzY2FsZWROb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICBub3JtYWwyLAogICAgICAgIGV4dHJ1ZGVkSGVpZ2h0LAogICAgICAgIHNjYWxlZE5vcm1hbAogICAgICApOwogICAgICBleHRydWRlZFBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICBleHRydWRlZFBvc2l0aW9uLAogICAgICAgIHNjYWxlZE5vcm1hbCwKICAgICAgICBleHRydWRlZFBvc2l0aW9uCiAgICAgICk7CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQucG9zaXRpb24pIHsKICAgICAgICBmaW5hbFBvc2l0aW9uc1tpMiArIGxlbmd0aF0gPSBleHRydWRlZFBvc2l0aW9uLng7CiAgICAgICAgZmluYWxQb3NpdGlvbnNbaTEgKyBsZW5ndGhdID0gZXh0cnVkZWRQb3NpdGlvbi55OwogICAgICAgIGZpbmFsUG9zaXRpb25zW2kyMiArIGxlbmd0aF0gPSBleHRydWRlZFBvc2l0aW9uLno7CiAgICAgICAgZmluYWxQb3NpdGlvbnNbaTJdID0gcG9zaXRpb24ueDsKICAgICAgICBmaW5hbFBvc2l0aW9uc1tpMV0gPSBwb3NpdGlvbi55OwogICAgICAgIGZpbmFsUG9zaXRpb25zW2kyMl0gPSBwb3NpdGlvbi56OwogICAgICB9CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsIHx8IHZlcnRleEZvcm1hdC50YW5nZW50IHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICBiaXRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUobm9ybWFsMiwgYml0YW5nZW50KTsKICAgICAgICBjb25zdCBuZXh0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIChpMiArIDMpICUgbGVuZ3RoLAogICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjQKICAgICAgICApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChuZXh0LCBwb3NpdGlvbiwgbmV4dCk7CiAgICAgICAgY29uc3QgYm90dG9tID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgZXh0cnVkZWRQb3NpdGlvbiwKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjM1CiAgICAgICAgKTsKICAgICAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhib3R0b20sIG5leHQsIG5vcm1hbDIpLAogICAgICAgICAgbm9ybWFsMgogICAgICAgICk7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgIG5vcm1hbHNbaTJdID0gbm9ybWFsMi54OwogICAgICAgICAgbm9ybWFsc1tpMV0gPSBub3JtYWwyLnk7CiAgICAgICAgICBub3JtYWxzW2kyMl0gPSBub3JtYWwyLno7CiAgICAgICAgICBub3JtYWxzW2kyICsgbGVuZ3RoXSA9IG5vcm1hbDIueDsKICAgICAgICAgIG5vcm1hbHNbaTEgKyBsZW5ndGhdID0gbm9ybWFsMi55OwogICAgICAgICAgbm9ybWFsc1tpMjIgKyBsZW5ndGhdID0gbm9ybWFsMi56OwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoYml0YW5nZW50LCBub3JtYWwyLCB0YW5nZW50KSwKICAgICAgICAgICAgdGFuZ2VudAogICAgICAgICAgKTsKICAgICAgICAgIHRhbmdlbnRzW2kyXSA9IHRhbmdlbnQueDsKICAgICAgICAgIHRhbmdlbnRzW2kxXSA9IHRhbmdlbnQueTsKICAgICAgICAgIHRhbmdlbnRzW2kyMl0gPSB0YW5nZW50Lno7CiAgICAgICAgICB0YW5nZW50c1tpMiArIGxlbmd0aF0gPSB0YW5nZW50Lng7CiAgICAgICAgICB0YW5nZW50c1tpMiArIDEgKyBsZW5ndGhdID0gdGFuZ2VudC55OwogICAgICAgICAgdGFuZ2VudHNbaTIgKyAyICsgbGVuZ3RoXSA9IHRhbmdlbnQuejsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgIGJpdGFuZ2VudHNbaTJdID0gYml0YW5nZW50Lng7CiAgICAgICAgICBiaXRhbmdlbnRzW2kxXSA9IGJpdGFuZ2VudC55OwogICAgICAgICAgYml0YW5nZW50c1tpMjJdID0gYml0YW5nZW50Lno7CiAgICAgICAgICBiaXRhbmdlbnRzW2kyICsgbGVuZ3RoXSA9IGJpdGFuZ2VudC54OwogICAgICAgICAgYml0YW5nZW50c1tpMSArIGxlbmd0aF0gPSBiaXRhbmdlbnQueTsKICAgICAgICAgIGJpdGFuZ2VudHNbaTIyICsgbGVuZ3RoXSA9IGJpdGFuZ2VudC56OwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICBsZW5ndGggPSB0ZXh0dXJlQ29vcmRpbmF0ZXMubGVuZ3RoOwogICAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgbGVuZ3RoOyBrMiArPSAyKSB7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW2syXSA9ICh0ZXh0dXJlQ29vcmRpbmF0ZXNbazJdIC0gbWluVGV4Q29vcmQueCkgLyAobWF4VGV4Q29vcmQueCAtIG1pblRleENvb3JkLngpOwogICAgICAgIHRleHR1cmVDb29yZGluYXRlc1trMiArIDFdID0gKHRleHR1cmVDb29yZGluYXRlc1trMiArIDFdIC0gbWluVGV4Q29vcmQueSkgLyAobWF4VGV4Q29vcmQueSAtIG1pblRleENvb3JkLnkpOwogICAgICB9CiAgICB9CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBmaW5hbFBvc2l0aW9ucwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgIHZhbHVlczogdGV4dHVyZUNvb3JkaW5hdGVzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgYXR0cmlidXRlcy50YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiB0YW5nZW50cwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICBhdHRyaWJ1dGVzLmV4dHJ1ZGVEaXJlY3Rpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IGV4dHJ1ZGVOb3JtYWxzCiAgICAgIH0pOwogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgbGV0IG9mZnNldEF0dHJpYnV0ZSA9IG5ldyBVaW50OEFycmF5KHNpemUpOwogICAgICBpZiAob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuVE9QKSB7CiAgICAgICAgb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlLmZpbGwoMSwgMCwgc2l6ZSAvIDIpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IG9mZnNldFZhbHVlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICB2YWx1ZXM6IG9mZnNldEF0dHJpYnV0ZQogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBhdHRyaWJ1dGVzOwogIH0KICBmdW5jdGlvbiBjb21wdXRlV2FsbEluZGljZXMocG9zaXRpb25zKSB7CiAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShsZW5ndGgsIGxlbmd0aCAqIDYpOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgVUwgPSBpMjsKICAgICAgY29uc3QgTEwgPSBpMiArIGxlbmd0aDsKICAgICAgY29uc3QgVVIgPSAoVUwgKyAxKSAlIGxlbmd0aDsKICAgICAgY29uc3QgTFIgPSBVUiArIGxlbmd0aDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVMOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVUjsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMUjsKICAgIH0KICAgIHJldHVybiBpbmRpY2VzOwogIH0KICBmdW5jdGlvbiBjb21wdXRlRXh0cnVkZWRFbGxpcHNlKG9wdGlvbnMpIHsKICAgIGNvbnN0IGNlbnRlciA9IG9wdGlvbnMuY2VudGVyOwogICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQ7CiAgICBjb25zdCBzZW1pTWFqb3JBeGlzID0gb3B0aW9ucy5zZW1pTWFqb3JBeGlzOwogICAgbGV0IHNjYWxlZE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKGNlbnRlciwgc2NyYXRjaENhcnRlc2lhbjEzKSwKICAgICAgb3B0aW9ucy5oZWlnaHQsCiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4xMwogICAgKTsKICAgIHRvcEJvdW5kaW5nU3BoZXJlLmNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgIGNlbnRlciwKICAgICAgc2NhbGVkTm9ybWFsLAogICAgICB0b3BCb3VuZGluZ1NwaGVyZS5jZW50ZXIKICAgICk7CiAgICB0b3BCb3VuZGluZ1NwaGVyZS5yYWRpdXMgPSBzZW1pTWFqb3JBeGlzOwogICAgc2NhbGVkTm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgIGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoY2VudGVyLCBzY2FsZWROb3JtYWwpLAogICAgICBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0LAogICAgICBzY2FsZWROb3JtYWwKICAgICk7CiAgICBib3R0b21Cb3VuZGluZ1NwaGVyZS5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICBjZW50ZXIsCiAgICAgIHNjYWxlZE5vcm1hbCwKICAgICAgYm90dG9tQm91bmRpbmdTcGhlcmUuY2VudGVyCiAgICApOwogICAgYm90dG9tQm91bmRpbmdTcGhlcmUucmFkaXVzID0gc2VtaU1ham9yQXhpczsKICAgIGNvbnN0IGNlcCA9IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlRWxsaXBzZVBvc2l0aW9ucygKICAgICAgb3B0aW9ucywKICAgICAgdHJ1ZSwKICAgICAgdHJ1ZQogICAgKTsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGNlcC5wb3NpdGlvbnM7CiAgICBjb25zdCBudW1QdHMgPSBjZXAubnVtUHRzOwogICAgY29uc3Qgb3V0ZXJQb3NpdGlvbnMgPSBjZXAub3V0ZXJQb3NpdGlvbnM7CiAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQudW5pb24oCiAgICAgIHRvcEJvdW5kaW5nU3BoZXJlLAogICAgICBib3R0b21Cb3VuZGluZ1NwaGVyZQogICAgKTsKICAgIGNvbnN0IHRvcEJvdHRvbUF0dHJpYnV0ZXMgPSBjb21wdXRlVG9wQm90dG9tQXR0cmlidXRlcygKICAgICAgcG9zaXRpb25zLAogICAgICBvcHRpb25zLAogICAgICB0cnVlCiAgICApOwogICAgbGV0IGluZGljZXMgPSB0b3BJbmRpY2VzKG51bVB0cyk7CiAgICBjb25zdCBsZW5ndGggPSBpbmRpY2VzLmxlbmd0aDsKICAgIGluZGljZXMubGVuZ3RoID0gbGVuZ3RoICogMjsKICAgIGNvbnN0IHBvc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICBpbmRpY2VzW2kyICsgbGVuZ3RoXSA9IGluZGljZXNbaTIgKyAyXSArIHBvc0xlbmd0aDsKICAgICAgaW5kaWNlc1tpMiArIDEgKyBsZW5ndGhdID0gaW5kaWNlc1tpMiArIDFdICsgcG9zTGVuZ3RoOwogICAgICBpbmRpY2VzW2kyICsgMiArIGxlbmd0aF0gPSBpbmRpY2VzW2kyXSArIHBvc0xlbmd0aDsKICAgIH0KICAgIGNvbnN0IHRvcEJvdHRvbUluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgcG9zTGVuZ3RoICogMiAvIDMsCiAgICAgIGluZGljZXMKICAgICk7CiAgICBjb25zdCB0b3BCb3R0b21HZW8gPSBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgIGF0dHJpYnV0ZXM6IHRvcEJvdHRvbUF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXM6IHRvcEJvdHRvbUluZGljZXMsCiAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMKICAgIH0pOwogICAgY29uc3Qgd2FsbEF0dHJpYnV0ZXMgPSBjb21wdXRlV2FsbEF0dHJpYnV0ZXMob3V0ZXJQb3NpdGlvbnMsIG9wdGlvbnMpOwogICAgaW5kaWNlcyA9IGNvbXB1dGVXYWxsSW5kaWNlcyhvdXRlclBvc2l0aW9ucyk7CiAgICBjb25zdCB3YWxsSW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBvdXRlclBvc2l0aW9ucy5sZW5ndGggKiAyIC8gMywKICAgICAgaW5kaWNlcwogICAgKTsKICAgIGNvbnN0IHdhbGxHZW8gPSBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgIGF0dHJpYnV0ZXM6IHdhbGxBdHRyaWJ1dGVzLAogICAgICBpbmRpY2VzOiB3YWxsSW5kaWNlcywKICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUwogICAgfSk7CiAgICBjb25zdCBnZW8gPSBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQuY29tYmluZUluc3RhbmNlcyhbCiAgICAgIG5ldyBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQoewogICAgICAgIGdlb21ldHJ5OiB0b3BCb3R0b21HZW8KICAgICAgfSksCiAgICAgIG5ldyBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQoewogICAgICAgIGdlb21ldHJ5OiB3YWxsR2VvCiAgICAgIH0pCiAgICBdKTsKICAgIHJldHVybiB7CiAgICAgIGJvdW5kaW5nU3BoZXJlLAogICAgICBhdHRyaWJ1dGVzOiBnZW9bMF0uYXR0cmlidXRlcywKICAgICAgaW5kaWNlczogZ2VvWzBdLmluZGljZXMKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVSZWN0YW5nbGUoY2VudGVyLCBzZW1pTWFqb3JBeGlzLCBzZW1pTWlub3JBeGlzLCByb3RhdGlvbiwgZ3JhbnVsYXJpdHksIGVsbGlwc29pZCwgcmVzdWx0KSB7CiAgICBjb25zdCBjZXAgPSBFbGxpcHNlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZUVsbGlwc2VQb3NpdGlvbnMoCiAgICAgIHsKICAgICAgICBjZW50ZXIsCiAgICAgICAgc2VtaU1ham9yQXhpcywKICAgICAgICBzZW1pTWlub3JBeGlzLAogICAgICAgIHJvdGF0aW9uLAogICAgICAgIGdyYW51bGFyaXR5CiAgICAgIH0sCiAgICAgIGZhbHNlLAogICAgICB0cnVlCiAgICApOwogICAgY29uc3QgcG9zaXRpb25zRmxhdCA9IGNlcC5vdXRlclBvc2l0aW9uczsKICAgIGNvbnN0IHBvc2l0aW9uc0NvdW50ID0gcG9zaXRpb25zRmxhdC5sZW5ndGggLyAzOwogICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEFycmF5KHBvc2l0aW9uc0NvdW50KTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnNDb3VudDsgKytpMikgewogICAgICBwb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnNGbGF0LCBpMiAqIDMpOwogICAgfQogICAgY29uc3QgcmVjdGFuZ2xlID0gUmVjdGFuZ2xlX2RlZmF1bHQuZnJvbUNhcnRlc2lhbkFycmF5KHBvc2l0aW9ucywgZWxsaXBzb2lkLCByZXN1bHQpOwogICAgaWYgKHJlY3RhbmdsZS53aWR0aCA+IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICByZWN0YW5nbGUubm9ydGggPSByZWN0YW5nbGUubm9ydGggPiAwID8gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIC0gTWF0aF9kZWZhdWx0LkVQU0lMT043IDogcmVjdGFuZ2xlLm5vcnRoOwogICAgICByZWN0YW5nbGUuc291dGggPSByZWN0YW5nbGUuc291dGggPCAwID8gTWF0aF9kZWZhdWx0LkVQU0lMT043IC0gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIDogcmVjdGFuZ2xlLnNvdXRoOwogICAgICByZWN0YW5nbGUuZWFzdCA9IE1hdGhfZGVmYXVsdC5QSTsKICAgICAgcmVjdGFuZ2xlLndlc3QgPSAtTWF0aF9kZWZhdWx0LlBJOwogICAgfQogICAgcmV0dXJuIHJlY3RhbmdsZTsKICB9CiAgZnVuY3Rpb24gRWxsaXBzZUdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IGNlbnRlciA9IG9wdGlvbnMuY2VudGVyOwogICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIGNvbnN0IHNlbWlNYWpvckF4aXMgPSBvcHRpb25zLnNlbWlNYWpvckF4aXM7CiAgICBjb25zdCBzZW1pTWlub3JBeGlzID0gb3B0aW9ucy5zZW1pTWlub3JBeGlzOwogICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBvcHRpb25zLmdyYW51bGFyaXR5ID8/IE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBvcHRpb25zLnZlcnRleEZvcm1hdCA/PyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5ERUZBVUxUOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLmNlbnRlciIsIGNlbnRlcik7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIm9wdGlvbnMuc2VtaU1ham9yQXhpcyIsIHNlbWlNYWpvckF4aXMpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJvcHRpb25zLnNlbWlNaW5vckF4aXMiLCBzZW1pTWlub3JBeGlzKTsKICAgIGlmIChzZW1pTWFqb3JBeGlzIDwgc2VtaU1pbm9yQXhpcykgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAic2VtaU1ham9yQXhpcyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgc2VtaU1pbm9yQXhpcy4iCiAgICAgICk7CiAgICB9CiAgICBpZiAoZ3JhbnVsYXJpdHkgPD0gMCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ3JhbnVsYXJpdHkgbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgIH0KICAgIGNvbnN0IGhlaWdodCA9IG9wdGlvbnMuaGVpZ2h0ID8/IDA7CiAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQgPz8gaGVpZ2h0OwogICAgdGhpcy5fY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlcik7CiAgICB0aGlzLl9zZW1pTWFqb3JBeGlzID0gc2VtaU1ham9yQXhpczsKICAgIHRoaXMuX3NlbWlNaW5vckF4aXMgPSBzZW1pTWlub3JBeGlzOwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkKTsKICAgIHRoaXMuX3JvdGF0aW9uID0gb3B0aW9ucy5yb3RhdGlvbiA/PyAwOwogICAgdGhpcy5fc3RSb3RhdGlvbiA9IG9wdGlvbnMuc3RSb3RhdGlvbiA/PyAwOwogICAgdGhpcy5faGVpZ2h0ID0gTWF0aC5tYXgoZXh0cnVkZWRIZWlnaHQsIGhlaWdodCk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgdGhpcy5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0KTsKICAgIHRoaXMuX2V4dHJ1ZGVkSGVpZ2h0ID0gTWF0aC5taW4oZXh0cnVkZWRIZWlnaHQsIGhlaWdodCk7CiAgICB0aGlzLl9zaGFkb3dWb2x1bWUgPSBvcHRpb25zLnNoYWRvd1ZvbHVtZSA/PyBmYWxzZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlRWxsaXBzZUdlb21ldHJ5IjsKICAgIHRoaXMuX29mZnNldEF0dHJpYnV0ZSA9IG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlOwogICAgdGhpcy5fcmVjdGFuZ2xlID0gdm9pZCAwOwogICAgdGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cyA9IHZvaWQgMDsKICB9CiAgZnVuY3Rpb24gdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cyhlbGxpcHNlR2VvbWV0cnkpIHsKICAgIGNvbnN0IHN0Um90YXRpb24gPSAtZWxsaXBzZUdlb21ldHJ5Ll9zdFJvdGF0aW9uOwogICAgaWYgKHN0Um90YXRpb24gPT09IDApIHsKICAgICAgcmV0dXJuIFswLCAwLCAwLCAxLCAxLCAwXTsKICAgIH0KICAgIGNvbnN0IGNlcCA9IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlRWxsaXBzZVBvc2l0aW9ucygKICAgICAgewogICAgICAgIGNlbnRlcjogZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIsCiAgICAgICAgc2VtaU1ham9yQXhpczogZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWFqb3JBeGlzLAogICAgICAgIHNlbWlNaW5vckF4aXM6IGVsbGlwc2VHZW9tZXRyeS5fc2VtaU1pbm9yQXhpcywKICAgICAgICByb3RhdGlvbjogZWxsaXBzZUdlb21ldHJ5Ll9yb3RhdGlvbiwKICAgICAgICBncmFudWxhcml0eTogZWxsaXBzZUdlb21ldHJ5Ll9ncmFudWxhcml0eQogICAgICB9LAogICAgICBmYWxzZSwKICAgICAgdHJ1ZQogICAgKTsKICAgIGNvbnN0IHBvc2l0aW9uc0ZsYXQgPSBjZXAub3V0ZXJQb3NpdGlvbnM7CiAgICBjb25zdCBwb3NpdGlvbnNDb3VudCA9IHBvc2l0aW9uc0ZsYXQubGVuZ3RoIC8gMzsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShwb3NpdGlvbnNDb3VudCk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zQ291bnQ7ICsraTIpIHsKICAgICAgcG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zRmxhdCwgaTIgKiAzKTsKICAgIH0KICAgIGNvbnN0IGVsbGlwc29pZCA9IGVsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgY29uc3QgYm91bmRpbmdSZWN0YW5nbGUgPSBlbGxpcHNlR2VvbWV0cnkucmVjdGFuZ2xlOwogICAgcmV0dXJuIEdlb21ldHJ5X2RlZmF1bHQuX3RleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHMoCiAgICAgIHBvc2l0aW9ucywKICAgICAgc3RSb3RhdGlvbiwKICAgICAgZWxsaXBzb2lkLAogICAgICBib3VuZGluZ1JlY3RhbmdsZQogICAgKTsKICB9CiAgdmFyIHNjcmF0Y2hDYXJ0ZXNpYW4xMywgc2NyYXRjaENhcnRlc2lhbjI0LCBzY3JhdGNoQ2FydGVzaWFuMzUsIHNjcmF0Y2hDYXJ0ZXNpYW40LCB0ZXhDb29yZFNjcmF0Y2gsIHRleHR1cmVNYXRyaXhTY3JhdGNoLCB0YW5nZW50TWF0cml4U2NyYXRjaCwgcXVhdGVybmlvblNjcmF0Y2gsIHNjcmF0Y2hOb3JtYWwzLCBzY3JhdGNoVGFuZ2VudCwgc2NyYXRjaEJpdGFuZ2VudCwgc2NyYXRjaENhcnRvZ3JhcGhpYzIsIHByb2plY3RlZENlbnRlclNjcmF0Y2gsIHNjcmF0Y2hNaW5UZXhDb29yZCwgc2NyYXRjaE1heFRleENvb3JkLCBib3VuZGluZ1NwaGVyZUNlbnRlciwgdG9wQm91bmRpbmdTcGhlcmUsIGJvdHRvbUJvdW5kaW5nU3BoZXJlLCBzY3JhdGNoQ2VudGVyMiwgc2NyYXRjaEVsbGlwc29pZCwgc2NyYXRjaFZlcnRleEZvcm1hdDIsIHNjcmF0Y2hPcHRpb25zMywgRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfRWxsaXBzZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNlR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzZUdlb21ldHJ5TGlicmFyeSgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb2dyYXBoaWNQcm9qZWN0aW9uKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5SW5zdGFuY2UoKTsKICAgICAgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5UGlwZWxpbmUoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1ZlcnRleEZvcm1hdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMTMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjM1ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdGV4Q29vcmRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICB0ZXh0dXJlTWF0cml4U2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgdGFuZ2VudE1hdHJpeFNjcmF0Y2ggPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIHF1YXRlcm5pb25TY3JhdGNoID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRhbmdlbnQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCaXRhbmdlbnQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWMyID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHByb2plY3RlZENlbnRlclNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5UZXhDb29yZCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heFRleENvb3JkID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlciA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdG9wQm91bmRpbmdTcGhlcmUgPSBuZXcgQm91bmRpbmdTcGhlcmVfZGVmYXVsdCgpOwogICAgICBib3R0b21Cb3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIEVsbGlwc2VHZW9tZXRyeS5wYWNrZWRMZW5ndGggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgOTsKICAgICAgRWxsaXBzZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayh2YWx1ZS5fY2VudGVyLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIEVsbGlwc29pZF9kZWZhdWx0LnBhY2sodmFsdWUuX2VsbGlwc29pZCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2sodmFsdWUuX3ZlcnRleEZvcm1hdCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc2VtaU1ham9yQXhpczsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3NlbWlNaW5vckF4aXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9yb3RhdGlvbjsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3N0Um90YXRpb247CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9oZWlnaHQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc2hhZG93Vm9sdW1lID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaENlbnRlcjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQgPSBuZXcgRWxsaXBzb2lkX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDIgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE9wdGlvbnMzID0gewogICAgICAgIGNlbnRlcjogc2NyYXRjaENlbnRlcjIsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkLAogICAgICAgIHZlcnRleEZvcm1hdDogc2NyYXRjaFZlcnRleEZvcm1hdDIsCiAgICAgICAgc2VtaU1ham9yQXhpczogdm9pZCAwLAogICAgICAgIHNlbWlNaW5vckF4aXM6IHZvaWQgMCwKICAgICAgICByb3RhdGlvbjogdm9pZCAwLAogICAgICAgIHN0Um90YXRpb246IHZvaWQgMCwKICAgICAgICBoZWlnaHQ6IHZvaWQgMCwKICAgICAgICBncmFudWxhcml0eTogdm9pZCAwLAogICAgICAgIGV4dHJ1ZGVkSGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgc2hhZG93Vm9sdW1lOiB2b2lkIDAsCiAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiB2b2lkIDAKICAgICAgfTsKICAgICAgRWxsaXBzZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaENlbnRlcjIpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQyCiAgICAgICAgKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBzZW1pTWFqb3JBeGlzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBzZW1pTWlub3JBeGlzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCByb3RhdGlvbiA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHNoYWRvd1ZvbHVtZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPT09IDE7CiAgICAgICAgY29uc3Qgb2Zmc2V0QXR0cmlidXRlID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnMzLmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMy5leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMzLmdyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczMuc3RSb3RhdGlvbiA9IHN0Um90YXRpb247CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczMucm90YXRpb24gPSByb3RhdGlvbjsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMy5zZW1pTWFqb3JBeGlzID0gc2VtaU1ham9yQXhpczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMy5zZW1pTWlub3JBeGlzID0gc2VtaU1pbm9yQXhpczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMy5zaGFkb3dWb2x1bWUgPSBzaGFkb3dWb2x1bWU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczMub2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIHJldHVybiBuZXcgRWxsaXBzZUdlb21ldHJ5KHNjcmF0Y2hPcHRpb25zMyk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlciwgcmVzdWx0Ll9jZW50ZXIpOwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXN1bHQuX3NlbWlNYWpvckF4aXMgPSBzZW1pTWFqb3JBeGlzOwogICAgICAgIHJlc3VsdC5fc2VtaU1pbm9yQXhpcyA9IHNlbWlNaW5vckF4aXM7CiAgICAgICAgcmVzdWx0Ll9yb3RhdGlvbiA9IHJvdGF0aW9uOwogICAgICAgIHJlc3VsdC5fc3RSb3RhdGlvbiA9IHN0Um90YXRpb247CiAgICAgICAgcmVzdWx0Ll9oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgIHJlc3VsdC5fZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICByZXN1bHQuX3NoYWRvd1ZvbHVtZSA9IHNoYWRvd1ZvbHVtZTsKICAgICAgICByZXN1bHQuX29mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWxsaXBzZUdlb21ldHJ5LmNvbXB1dGVSZWN0YW5nbGUgPSBmdW5jdGlvbihvcHRpb25zLCByZXN1bHQpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCBzZW1pTWFqb3JBeGlzID0gb3B0aW9ucy5zZW1pTWFqb3JBeGlzOwogICAgICAgIGNvbnN0IHNlbWlNaW5vckF4aXMgPSBvcHRpb25zLnNlbWlNaW5vckF4aXM7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBvcHRpb25zLmdyYW51bGFyaXR5ID8/IE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICAgICAgY29uc3Qgcm90YXRpb24gPSBvcHRpb25zLnJvdGF0aW9uID8/IDA7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLmNlbnRlciIsIGNlbnRlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJvcHRpb25zLnNlbWlNYWpvckF4aXMiLCBzZW1pTWFqb3JBeGlzKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIm9wdGlvbnMuc2VtaU1pbm9yQXhpcyIsIHNlbWlNaW5vckF4aXMpOwogICAgICAgIGlmIChzZW1pTWFqb3JBeGlzIDwgc2VtaU1pbm9yQXhpcykgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJzZW1pTWFqb3JBeGlzIG11c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHRoZSBzZW1pTWlub3JBeGlzLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGlmIChncmFudWxhcml0eSA8PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZ3JhbnVsYXJpdHkgbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNvbXB1dGVSZWN0YW5nbGUoCiAgICAgICAgICBjZW50ZXIsCiAgICAgICAgICBzZW1pTWFqb3JBeGlzLAogICAgICAgICAgc2VtaU1pbm9yQXhpcywKICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBFbGxpcHNlR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihlbGxpcHNlR2VvbWV0cnkpIHsKICAgICAgICBpZiAoZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWFqb3JBeGlzIDw9IDAgfHwgZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWlub3JBeGlzIDw9IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gZWxsaXBzZUdlb21ldHJ5Ll9oZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBlbGxpcHNlR2VvbWV0cnkuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGUgPSAhTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICBleHRydWRlZEhlaWdodCwKICAgICAgICAgIDAsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjIKICAgICAgICApOwogICAgICAgIGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyID0gZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZSgKICAgICAgICAgIGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyLAogICAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIKICAgICAgICApOwogICAgICAgIGNvbnN0IG9wdGlvbnMgPSB7CiAgICAgICAgICBjZW50ZXI6IGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyLAogICAgICAgICAgc2VtaU1ham9yQXhpczogZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWFqb3JBeGlzLAogICAgICAgICAgc2VtaU1pbm9yQXhpczogZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWlub3JBeGlzLAogICAgICAgICAgZWxsaXBzb2lkOiBlbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZCwKICAgICAgICAgIHJvdGF0aW9uOiBlbGxpcHNlR2VvbWV0cnkuX3JvdGF0aW9uLAogICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgZ3JhbnVsYXJpdHk6IGVsbGlwc2VHZW9tZXRyeS5fZ3JhbnVsYXJpdHksCiAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IGVsbGlwc2VHZW9tZXRyeS5fdmVydGV4Rm9ybWF0LAogICAgICAgICAgc3RSb3RhdGlvbjogZWxsaXBzZUdlb21ldHJ5Ll9zdFJvdGF0aW9uCiAgICAgICAgfTsKICAgICAgICBsZXQgZ2VvbWV0cnk7CiAgICAgICAgaWYgKGV4dHJ1ZGUpIHsKICAgICAgICAgIG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICAgIG9wdGlvbnMuc2hhZG93Vm9sdW1lID0gZWxsaXBzZUdlb21ldHJ5Ll9zaGFkb3dWb2x1bWU7CiAgICAgICAgICBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9IGVsbGlwc2VHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgZ2VvbWV0cnkgPSBjb21wdXRlRXh0cnVkZWRFbGxpcHNlKG9wdGlvbnMpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBnZW9tZXRyeSA9IGNvbXB1dGVFbGxpcHNlKG9wdGlvbnMpOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChlbGxpcHNlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoOwogICAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGVsbGlwc2VHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXM6IGdlb21ldHJ5LmF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBnZW9tZXRyeS5pbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUywKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlOiBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogZWxsaXBzZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgRWxsaXBzZUdlb21ldHJ5LmNyZWF0ZVNoYWRvd1ZvbHVtZSA9IGZ1bmN0aW9uKGVsbGlwc2VHZW9tZXRyeSwgbWluSGVpZ2h0RnVuYywgbWF4SGVpZ2h0RnVuYykgewogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gZWxsaXBzZUdlb21ldHJ5Ll9ncmFudWxhcml0eTsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBlbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBtaW5IZWlnaHRGdW5jKGdyYW51bGFyaXR5LCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IG1heEhlaWdodCA9IG1heEhlaWdodEZ1bmMoZ3JhbnVsYXJpdHksIGVsbGlwc29pZCk7CiAgICAgICAgcmV0dXJuIG5ldyBFbGxpcHNlR2VvbWV0cnkoewogICAgICAgICAgY2VudGVyOiBlbGxpcHNlR2VvbWV0cnkuX2NlbnRlciwKICAgICAgICAgIHNlbWlNYWpvckF4aXM6IGVsbGlwc2VHZW9tZXRyeS5fc2VtaU1ham9yQXhpcywKICAgICAgICAgIHNlbWlNaW5vckF4aXM6IGVsbGlwc2VHZW9tZXRyeS5fc2VtaU1pbm9yQXhpcywKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHJvdGF0aW9uOiBlbGxpcHNlR2VvbWV0cnkuX3JvdGF0aW9uLAogICAgICAgICAgc3RSb3RhdGlvbjogZWxsaXBzZUdlb21ldHJ5Ll9zdFJvdGF0aW9uLAogICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICBleHRydWRlZEhlaWdodDogbWluSGVpZ2h0LAogICAgICAgICAgaGVpZ2h0OiBtYXhIZWlnaHQsCiAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IFZlcnRleEZvcm1hdF9kZWZhdWx0LlBPU0lUSU9OX09OTFksCiAgICAgICAgICBzaGFkb3dWb2x1bWU6IHRydWUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRWxsaXBzZUdlb21ldHJ5LnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgcmVjdGFuZ2xlOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLl9yZWN0YW5nbGUpKSB7CiAgICAgICAgICAgICAgdGhpcy5fcmVjdGFuZ2xlID0gY29tcHV0ZVJlY3RhbmdsZSgKICAgICAgICAgICAgICAgIHRoaXMuX2NlbnRlciwKICAgICAgICAgICAgICAgIHRoaXMuX3NlbWlNYWpvckF4aXMsCiAgICAgICAgICAgICAgICB0aGlzLl9zZW1pTWlub3JBeGlzLAogICAgICAgICAgICAgICAgdGhpcy5fcm90YXRpb24sCiAgICAgICAgICAgICAgICB0aGlzLl9ncmFudWxhcml0eSwKICAgICAgICAgICAgICAgIHRoaXMuX2VsbGlwc29pZAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3JlY3RhbmdsZTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEZvciByZW1hcHBpbmcgdGV4dHVyZSBjb29yZGluYXRlcyB3aGVuIHJlbmRlcmluZyBFbGxpcHNlR2VvbWV0cmllcyBhcyBHcm91bmRQcmltaXRpdmVzLgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cykpIHsKICAgICAgICAgICAgICB0aGlzLl90ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzID0gdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cyh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBFbGxpcHNlR2VvbWV0cnlfZGVmYXVsdCA9IEVsbGlwc2VHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NpcmNsZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gQ2lyY2xlR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcmFkaXVzID0gb3B0aW9ucy5yYWRpdXM7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInJhZGl1cyIsIHJhZGl1cyk7CiAgICBjb25zdCBlbGxpcHNlR2VvbWV0cnlPcHRpb25zID0gewogICAgICBjZW50ZXI6IG9wdGlvbnMuY2VudGVyLAogICAgICBzZW1pTWFqb3JBeGlzOiByYWRpdXMsCiAgICAgIHNlbWlNaW5vckF4aXM6IHJhZGl1cywKICAgICAgZWxsaXBzb2lkOiBvcHRpb25zLmVsbGlwc29pZCwKICAgICAgaGVpZ2h0OiBvcHRpb25zLmhlaWdodCwKICAgICAgZXh0cnVkZWRIZWlnaHQ6IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQsCiAgICAgIGdyYW51bGFyaXR5OiBvcHRpb25zLmdyYW51bGFyaXR5LAogICAgICB2ZXJ0ZXhGb3JtYXQ6IG9wdGlvbnMudmVydGV4Rm9ybWF0LAogICAgICBzdFJvdGF0aW9uOiBvcHRpb25zLnN0Um90YXRpb24sCiAgICAgIHNoYWRvd1ZvbHVtZTogb3B0aW9ucy5zaGFkb3dWb2x1bWUKICAgIH07CiAgICB0aGlzLl9lbGxpcHNlR2VvbWV0cnkgPSBuZXcgRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQoZWxsaXBzZUdlb21ldHJ5T3B0aW9ucyk7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUNpcmNsZUdlb21ldHJ5IjsKICB9CiAgdmFyIHNjcmF0Y2hFbGxpcHNlR2VvbWV0cnksIHNjcmF0Y2hPcHRpb25zNCwgQ2lyY2xlR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9DaXJjbGVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ2lyY2xlR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNlR2VvbWV0cnkoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9WZXJ0ZXhGb3JtYXQoKTsKICAgICAgQ2lyY2xlR2VvbWV0cnkucGFja2VkTGVuZ3RoID0gRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICBDaXJjbGVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICByZXR1cm4gRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzZUdlb21ldHJ5LCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNlR2VvbWV0cnkgPSBuZXcgRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgIGNlbnRlcjogbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIHNlbWlNYWpvckF4aXM6IDEsCiAgICAgICAgc2VtaU1pbm9yQXhpczogMQogICAgICB9KTsKICAgICAgc2NyYXRjaE9wdGlvbnM0ID0gewogICAgICAgIGNlbnRlcjogbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIHJhZGl1czogdm9pZCAwLAogICAgICAgIGVsbGlwc29pZDogRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCksCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IHZvaWQgMCwKICAgICAgICBncmFudWxhcml0eTogdm9pZCAwLAogICAgICAgIHZlcnRleEZvcm1hdDogbmV3IFZlcnRleEZvcm1hdF9kZWZhdWx0KCksCiAgICAgICAgc3RSb3RhdGlvbjogdm9pZCAwLAogICAgICAgIHNlbWlNYWpvckF4aXM6IHZvaWQgMCwKICAgICAgICBzZW1pTWlub3JBeGlzOiB2b2lkIDAsCiAgICAgICAgc2hhZG93Vm9sdW1lOiB2b2lkIDAKICAgICAgfTsKICAgICAgQ2lyY2xlR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGNvbnN0IGVsbGlwc2VHZW9tZXRyeSA9IEVsbGlwc2VHZW9tZXRyeV9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIHNjcmF0Y2hFbGxpcHNlR2VvbWV0cnkKICAgICAgICApOwogICAgICAgIHNjcmF0Y2hPcHRpb25zNC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgICAgICBlbGxpcHNlR2VvbWV0cnkuX2NlbnRlciwKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zNC5jZW50ZXIKICAgICAgICApOwogICAgICAgIHNjcmF0Y2hPcHRpb25zNC5lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZSgKICAgICAgICAgIGVsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkLAogICAgICAgICAgc2NyYXRjaE9wdGlvbnM0LmVsbGlwc29pZAogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM0LmVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKAogICAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoRWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQKICAgICAgICApOwogICAgICAgIHNjcmF0Y2hPcHRpb25zNC5oZWlnaHQgPSBlbGxpcHNlR2VvbWV0cnkuX2hlaWdodDsKICAgICAgICBzY3JhdGNoT3B0aW9uczQuZXh0cnVkZWRIZWlnaHQgPSBlbGxpcHNlR2VvbWV0cnkuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIHNjcmF0Y2hPcHRpb25zNC5ncmFudWxhcml0eSA9IGVsbGlwc2VHZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM0LnZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKAogICAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQsCiAgICAgICAgICBzY3JhdGNoT3B0aW9uczQudmVydGV4Rm9ybWF0CiAgICAgICAgKTsKICAgICAgICBzY3JhdGNoT3B0aW9uczQuc3RSb3RhdGlvbiA9IGVsbGlwc2VHZW9tZXRyeS5fc3RSb3RhdGlvbjsKICAgICAgICBzY3JhdGNoT3B0aW9uczQuc2hhZG93Vm9sdW1lID0gZWxsaXBzZUdlb21ldHJ5Ll9zaGFkb3dWb2x1bWU7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnM0LnJhZGl1cyA9IGVsbGlwc2VHZW9tZXRyeS5fc2VtaU1ham9yQXhpczsKICAgICAgICAgIHJldHVybiBuZXcgQ2lyY2xlR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnM0KTsKICAgICAgICB9CiAgICAgICAgc2NyYXRjaE9wdGlvbnM0LnNlbWlNYWpvckF4aXMgPSBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNYWpvckF4aXM7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM0LnNlbWlNaW5vckF4aXMgPSBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNaW5vckF4aXM7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNlR2VvbWV0cnkgPSBuZXcgRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQoc2NyYXRjaE9wdGlvbnM0KTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBDaXJjbGVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGNpcmNsZUdlb21ldHJ5KSB7CiAgICAgICAgcmV0dXJuIEVsbGlwc2VHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkpOwogICAgICB9OwogICAgICBDaXJjbGVHZW9tZXRyeS5jcmVhdGVTaGFkb3dWb2x1bWUgPSBmdW5jdGlvbihjaXJjbGVHZW9tZXRyeSwgbWluSGVpZ2h0RnVuYywgbWF4SGVpZ2h0RnVuYykgewogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IG1pbkhlaWdodEZ1bmMoZ3JhbnVsYXJpdHksIGVsbGlwc29pZCk7CiAgICAgICAgY29uc3QgbWF4SGVpZ2h0ID0gbWF4SGVpZ2h0RnVuYyhncmFudWxhcml0eSwgZWxsaXBzb2lkKTsKICAgICAgICByZXR1cm4gbmV3IENpcmNsZUdlb21ldHJ5KHsKICAgICAgICAgIGNlbnRlcjogY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fY2VudGVyLAogICAgICAgICAgcmFkaXVzOiBjaXJjbGVHZW9tZXRyeS5fZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWFqb3JBeGlzLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc3RSb3RhdGlvbjogY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fc3RSb3RhdGlvbiwKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IG1pbkhlaWdodCwKICAgICAgICAgIGhlaWdodDogbWF4SGVpZ2h0LAogICAgICAgICAgdmVydGV4Rm9ybWF0OiBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5QT1NJVElPTl9PTkxZLAogICAgICAgICAgc2hhZG93Vm9sdW1lOiB0cnVlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENpcmNsZUdlb21ldHJ5LnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgcmVjdGFuZ2xlOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fZWxsaXBzZUdlb21ldHJ5LnJlY3RhbmdsZTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEZvciByZW1hcHBpbmcgdGV4dHVyZSBjb29yZGluYXRlcyB3aGVuIHJlbmRlcmluZyBDaXJjbGVHZW9tZXRyaWVzIGFzIEdyb3VuZFByaW1pdGl2ZXMuCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gdGhpcy5fZWxsaXBzZUdlb21ldHJ5LnRleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHM7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgQ2lyY2xlR2VvbWV0cnlfZGVmYXVsdCA9IENpcmNsZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlQ2lyY2xlR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlQ2lyY2xlR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZUNpcmNsZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZUNpcmNsZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVDaXJjbGVHZW9tZXRyeShjaXJjbGVHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgY2lyY2xlR2VvbWV0cnkgPSBDaXJjbGVHZW9tZXRyeV9kZWZhdWx0LnVucGFjayhjaXJjbGVHZW9tZXRyeSwgb2Zmc2V0KTsKICAgIH0KICAgIGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkuX2NlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSgKICAgICAgY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fY2VudGVyCiAgICApOwogICAgY2lyY2xlR2VvbWV0cnkuX2VsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoCiAgICAgIGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZAogICAgKTsKICAgIHJldHVybiBDaXJjbGVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGNpcmNsZUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUNpcmNsZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlQ2lyY2xlR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUNpcmNsZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2lyY2xlR2VvbWV0cnkoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGNyZWF0ZUNpcmNsZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVDaXJjbGVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0VsbGlwc2VPdXRsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBjb21wdXRlRWxsaXBzZTIob3B0aW9ucykgewogICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICBib3VuZGluZ1NwaGVyZUNlbnRlcjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgb3B0aW9ucy5lbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKGNlbnRlciwgYm91bmRpbmdTcGhlcmVDZW50ZXIyKSwKICAgICAgb3B0aW9ucy5oZWlnaHQsCiAgICAgIGJvdW5kaW5nU3BoZXJlQ2VudGVyMgogICAgKTsKICAgIGJvdW5kaW5nU3BoZXJlQ2VudGVyMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgIGNlbnRlciwKICAgICAgYm91bmRpbmdTcGhlcmVDZW50ZXIyLAogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlcjIKICAgICk7CiAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KAogICAgICBib3VuZGluZ1NwaGVyZUNlbnRlcjIsCiAgICAgIG9wdGlvbnMuc2VtaU1ham9yQXhpcwogICAgKTsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlRWxsaXBzZVBvc2l0aW9ucygKICAgICAgb3B0aW9ucywKICAgICAgZmFsc2UsCiAgICAgIHRydWUKICAgICkub3V0ZXJQb3NpdGlvbnM7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KHsKICAgICAgcG9zaXRpb246IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5yYWlzZVBvc2l0aW9uc1RvSGVpZ2h0KAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgb3B0aW9ucywKICAgICAgICAgIGZhbHNlCiAgICAgICAgKQogICAgICB9KQogICAgfSk7CiAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShsZW5ndGgsIGxlbmd0aCAqIDIpOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gKGkyICsgMSkgJSBsZW5ndGg7CiAgICB9CiAgICByZXR1cm4gewogICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlcwogICAgfTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUV4dHJ1ZGVkRWxsaXBzZTIob3B0aW9ucykgewogICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZDsKICAgIGNvbnN0IHNlbWlNYWpvckF4aXMgPSBvcHRpb25zLnNlbWlNYWpvckF4aXM7CiAgICBsZXQgc2NhbGVkTm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgIGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoY2VudGVyLCBzY3JhdGNoQ2FydGVzaWFuMTQpLAogICAgICBvcHRpb25zLmhlaWdodCwKICAgICAgc2NyYXRjaENhcnRlc2lhbjE0CiAgICApOwogICAgdG9wQm91bmRpbmdTcGhlcmUyLmNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgIGNlbnRlciwKICAgICAgc2NhbGVkTm9ybWFsLAogICAgICB0b3BCb3VuZGluZ1NwaGVyZTIuY2VudGVyCiAgICApOwogICAgdG9wQm91bmRpbmdTcGhlcmUyLnJhZGl1cyA9IHNlbWlNYWpvckF4aXM7CiAgICBzY2FsZWROb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChjZW50ZXIsIHNjYWxlZE5vcm1hbCksCiAgICAgIG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQsCiAgICAgIHNjYWxlZE5vcm1hbAogICAgKTsKICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlMi5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICBjZW50ZXIsCiAgICAgIHNjYWxlZE5vcm1hbCwKICAgICAgYm90dG9tQm91bmRpbmdTcGhlcmUyLmNlbnRlcgogICAgKTsKICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlMi5yYWRpdXMgPSBzZW1pTWFqb3JBeGlzOwogICAgbGV0IHBvc2l0aW9ucyA9IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlRWxsaXBzZVBvc2l0aW9ucygKICAgICAgb3B0aW9ucywKICAgICAgZmFsc2UsCiAgICAgIHRydWUKICAgICkub3V0ZXJQb3NpdGlvbnM7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KHsKICAgICAgcG9zaXRpb246IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IEVsbGlwc2VHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5yYWlzZVBvc2l0aW9uc1RvSGVpZ2h0KAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgb3B0aW9ucywKICAgICAgICAgIHRydWUKICAgICAgICApCiAgICAgIH0pCiAgICB9KTsKICAgIHBvc2l0aW9ucyA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgY29uc3QgYm91bmRpbmdTcGhlcmUgPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnVuaW9uKAogICAgICB0b3BCb3VuZGluZ1NwaGVyZTIsCiAgICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlMgogICAgKTsKICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgIGxldCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCk7CiAgICAgIGlmIChvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5UT1ApIHsKICAgICAgICBhcHBseU9mZnNldCA9IGFwcGx5T2Zmc2V0LmZpbGwoMSwgMCwgbGVuZ3RoIC8gMik7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5OT05FID8gMCA6IDE7CiAgICAgICAgYXBwbHlPZmZzZXQgPSBhcHBseU9mZnNldC5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgIH0pOwogICAgfQogICAgbGV0IG51bWJlck9mVmVydGljYWxMaW5lcyA9IG9wdGlvbnMubnVtYmVyT2ZWZXJ0aWNhbExpbmVzID8/IDE2OwogICAgbnVtYmVyT2ZWZXJ0aWNhbExpbmVzID0gTWF0aF9kZWZhdWx0LmNsYW1wKAogICAgICBudW1iZXJPZlZlcnRpY2FsTGluZXMsCiAgICAgIDAsCiAgICAgIGxlbmd0aCAvIDIKICAgICk7CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIGxlbmd0aCwKICAgICAgbGVuZ3RoICogMiArIG51bWJlck9mVmVydGljYWxMaW5lcyAqIDIKICAgICk7CiAgICBsZW5ndGggLz0gMjsKICAgIGxldCBpbmRleCA9IDA7CiAgICBsZXQgaTI7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gKGkyICsgMSkgJSBsZW5ndGg7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMiArIGxlbmd0aDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IChpMiArIDEpICUgbGVuZ3RoICsgbGVuZ3RoOwogICAgfQogICAgbGV0IG51bVNpZGU7CiAgICBpZiAobnVtYmVyT2ZWZXJ0aWNhbExpbmVzID4gMCkgewogICAgICBjb25zdCBudW1TaWRlTGluZXMgPSBNYXRoLm1pbihudW1iZXJPZlZlcnRpY2FsTGluZXMsIGxlbmd0aCk7CiAgICAgIG51bVNpZGUgPSBNYXRoLnJvdW5kKGxlbmd0aCAvIG51bVNpZGVMaW5lcyk7CiAgICAgIGNvbnN0IG1heEkgPSBNYXRoLm1pbihudW1TaWRlICogbnVtYmVyT2ZWZXJ0aWNhbExpbmVzLCBsZW5ndGgpOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBtYXhJOyBpMiArPSBudW1TaWRlKSB7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMiArIGxlbmd0aDsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHsKICAgICAgYm91bmRpbmdTcGhlcmUsCiAgICAgIGF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXMKICAgIH07CiAgfQogIGZ1bmN0aW9uIEVsbGlwc2VPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgY2VudGVyID0gb3B0aW9ucy5jZW50ZXI7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgY29uc3Qgc2VtaU1ham9yQXhpcyA9IG9wdGlvbnMuc2VtaU1ham9yQXhpczsKICAgIGNvbnN0IHNlbWlNaW5vckF4aXMgPSBvcHRpb25zLnNlbWlNaW5vckF4aXM7CiAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNlbnRlcikpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNlbnRlciBpcyByZXF1aXJlZC4iKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHNlbWlNYWpvckF4aXMpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzZW1pTWFqb3JBeGlzIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoc2VtaU1pbm9yQXhpcykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInNlbWlNaW5vckF4aXMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBpZiAoc2VtaU1ham9yQXhpcyA8IHNlbWlNaW5vckF4aXMpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgInNlbWlNYWpvckF4aXMgbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHNlbWlNaW5vckF4aXMuIgogICAgICApOwogICAgfQogICAgaWYgKGdyYW51bGFyaXR5IDw9IDApIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImdyYW51bGFyaXR5IG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uIik7CiAgICB9CiAgICBjb25zdCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodCA/PyAwOwogICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0ID8/IGhlaWdodDsKICAgIHRoaXMuX2NlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIpOwogICAgdGhpcy5fc2VtaU1ham9yQXhpcyA9IHNlbWlNYWpvckF4aXM7CiAgICB0aGlzLl9zZW1pTWlub3JBeGlzID0gc2VtaU1pbm9yQXhpczsKICAgIHRoaXMuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCk7CiAgICB0aGlzLl9yb3RhdGlvbiA9IG9wdGlvbnMucm90YXRpb24gPz8gMDsKICAgIHRoaXMuX2hlaWdodCA9IE1hdGgubWF4KGV4dHJ1ZGVkSGVpZ2h0LCBoZWlnaHQpOwogICAgdGhpcy5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgIHRoaXMuX2V4dHJ1ZGVkSGVpZ2h0ID0gTWF0aC5taW4oZXh0cnVkZWRIZWlnaHQsIGhlaWdodCk7CiAgICB0aGlzLl9udW1iZXJPZlZlcnRpY2FsTGluZXMgPSBNYXRoLm1heCgKICAgICAgb3B0aW9ucy5udW1iZXJPZlZlcnRpY2FsTGluZXMgPz8gMTYsCiAgICAgIDAKICAgICk7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlRWxsaXBzZU91dGxpbmVHZW9tZXRyeSI7CiAgfQogIHZhciBzY3JhdGNoQ2FydGVzaWFuMTQsIGJvdW5kaW5nU3BoZXJlQ2VudGVyMiwgdG9wQm91bmRpbmdTcGhlcmUyLCBib3R0b21Cb3VuZGluZ1NwaGVyZTIsIHNjcmF0Y2hDZW50ZXIzLCBzY3JhdGNoRWxsaXBzb2lkMiwgc2NyYXRjaE9wdGlvbnM1LCBFbGxpcHNlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfRWxsaXBzZU91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzZU91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNlR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4xNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYm91bmRpbmdTcGhlcmVDZW50ZXIyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0b3BCb3VuZGluZ1NwaGVyZTIgPSBuZXcgQm91bmRpbmdTcGhlcmVfZGVmYXVsdCgpOwogICAgICBib3R0b21Cb3VuZGluZ1NwaGVyZTIgPSBuZXcgQm91bmRpbmdTcGhlcmVfZGVmYXVsdCgpOwogICAgICBFbGxpcHNlT3V0bGluZUdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyA4OwogICAgICBFbGxpcHNlT3V0bGluZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2YWx1ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ2YWx1ZSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9jZW50ZXIsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgRWxsaXBzb2lkX2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzb2lkLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zZW1pTWFqb3JBeGlzOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc2VtaU1pbm9yQXhpczsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3JvdGF0aW9uOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5faGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9leHRydWRlZEhlaWdodDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX251bWJlck9mVmVydGljYWxMaW5lczsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9vZmZzZXRBdHRyaWJ1dGUgPz8gLTE7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBzY3JhdGNoQ2VudGVyMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDIgPSBuZXcgRWxsaXBzb2lkX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE9wdGlvbnM1ID0gewogICAgICAgIGNlbnRlcjogc2NyYXRjaENlbnRlcjMsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkMiwKICAgICAgICBzZW1pTWFqb3JBeGlzOiB2b2lkIDAsCiAgICAgICAgc2VtaU1pbm9yQXhpczogdm9pZCAwLAogICAgICAgIHJvdGF0aW9uOiB2b2lkIDAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgZ3JhbnVsYXJpdHk6IHZvaWQgMCwKICAgICAgICBleHRydWRlZEhlaWdodDogdm9pZCAwLAogICAgICAgIG51bWJlck9mVmVydGljYWxMaW5lczogdm9pZCAwLAogICAgICAgIG9mZnNldEF0dHJpYnV0ZTogdm9pZCAwCiAgICAgIH07CiAgICAgIEVsbGlwc2VPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaENlbnRlcjMpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQyKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBzZW1pTWFqb3JBeGlzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBzZW1pTWlub3JBeGlzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCByb3RhdGlvbiA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG51bWJlck9mVmVydGljYWxMaW5lcyA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgb2Zmc2V0QXR0cmlidXRlID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnM1LmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zNS5leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnM1LmdyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczUucm90YXRpb24gPSByb3RhdGlvbjsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zNS5zZW1pTWFqb3JBeGlzID0gc2VtaU1ham9yQXhpczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zNS5zZW1pTWlub3JBeGlzID0gc2VtaU1pbm9yQXhpczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zNS5udW1iZXJPZlZlcnRpY2FsTGluZXMgPSBudW1iZXJPZlZlcnRpY2FsTGluZXM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczUub2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIHJldHVybiBuZXcgRWxsaXBzZU91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczUpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX2NlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHJlc3VsdC5fY2VudGVyKTsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCwgcmVzdWx0Ll9lbGxpcHNvaWQpOwogICAgICAgIHJlc3VsdC5fc2VtaU1ham9yQXhpcyA9IHNlbWlNYWpvckF4aXM7CiAgICAgICAgcmVzdWx0Ll9zZW1pTWlub3JBeGlzID0gc2VtaU1pbm9yQXhpczsKICAgICAgICByZXN1bHQuX3JvdGF0aW9uID0gcm90YXRpb247CiAgICAgICAgcmVzdWx0Ll9oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgIHJlc3VsdC5fZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICByZXN1bHQuX251bWJlck9mVmVydGljYWxMaW5lcyA9IG51bWJlck9mVmVydGljYWxMaW5lczsKICAgICAgICByZXN1bHQuX29mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWxsaXBzZU91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGVsbGlwc2VHZW9tZXRyeSkgewogICAgICAgIGlmIChlbGxpcHNlR2VvbWV0cnkuX3NlbWlNYWpvckF4aXMgPD0gMCB8fCBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNaW5vckF4aXMgPD0gMCkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBjb25zdCBoZWlnaHQgPSBlbGxpcHNlR2VvbWV0cnkuX2hlaWdodDsKICAgICAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IGVsbGlwc2VHZW9tZXRyeS5fZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZSA9ICFNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIGhlaWdodCwKICAgICAgICAgIGV4dHJ1ZGVkSGVpZ2h0LAogICAgICAgICAgMCwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMgogICAgICAgICk7CiAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIgPSBlbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKAogICAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIsCiAgICAgICAgICBlbGxpcHNlR2VvbWV0cnkuX2NlbnRlcgogICAgICAgICk7CiAgICAgICAgY29uc3Qgb3B0aW9ucyA9IHsKICAgICAgICAgIGNlbnRlcjogZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIsCiAgICAgICAgICBzZW1pTWFqb3JBeGlzOiBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNYWpvckF4aXMsCiAgICAgICAgICBzZW1pTWlub3JBeGlzOiBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNaW5vckF4aXMsCiAgICAgICAgICBlbGxpcHNvaWQ6IGVsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkLAogICAgICAgICAgcm90YXRpb246IGVsbGlwc2VHZW9tZXRyeS5fcm90YXRpb24sCiAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICBncmFudWxhcml0eTogZWxsaXBzZUdlb21ldHJ5Ll9ncmFudWxhcml0eSwKICAgICAgICAgIG51bWJlck9mVmVydGljYWxMaW5lczogZWxsaXBzZUdlb21ldHJ5Ll9udW1iZXJPZlZlcnRpY2FsTGluZXMKICAgICAgICB9OwogICAgICAgIGxldCBnZW9tZXRyeTsKICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgb3B0aW9ucy5leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgICAgb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgPSBlbGxpcHNlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIGdlb21ldHJ5ID0gY29tcHV0ZUV4dHJ1ZGVkRWxsaXBzZTIob3B0aW9ucyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGdlb21ldHJ5ID0gY29tcHV0ZUVsbGlwc2UyKG9wdGlvbnMpOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChlbGxpcHNlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoOwogICAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGVsbGlwc2VHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXM6IGdlb21ldHJ5LmF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBnZW9tZXRyeS5pbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBlbGxpcHNlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBFbGxpcHNlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBFbGxpcHNlT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ2lyY2xlT3V0bGluZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gQ2lyY2xlT3V0bGluZUdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IHJhZGl1cyA9IG9wdGlvbnMucmFkaXVzOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJyYWRpdXMiLCByYWRpdXMpOwogICAgY29uc3QgZWxsaXBzZUdlb21ldHJ5T3B0aW9ucyA9IHsKICAgICAgY2VudGVyOiBvcHRpb25zLmNlbnRlciwKICAgICAgc2VtaU1ham9yQXhpczogcmFkaXVzLAogICAgICBzZW1pTWlub3JBeGlzOiByYWRpdXMsCiAgICAgIGVsbGlwc29pZDogb3B0aW9ucy5lbGxpcHNvaWQsCiAgICAgIGhlaWdodDogb3B0aW9ucy5oZWlnaHQsCiAgICAgIGV4dHJ1ZGVkSGVpZ2h0OiBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0LAogICAgICBncmFudWxhcml0eTogb3B0aW9ucy5ncmFudWxhcml0eSwKICAgICAgbnVtYmVyT2ZWZXJ0aWNhbExpbmVzOiBvcHRpb25zLm51bWJlck9mVmVydGljYWxMaW5lcwogICAgfTsKICAgIHRoaXMuX2VsbGlwc2VHZW9tZXRyeSA9IG5ldyBFbGxpcHNlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQoZWxsaXBzZUdlb21ldHJ5T3B0aW9ucyk7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeSI7CiAgfQogIHZhciBzY3JhdGNoRWxsaXBzZUdlb21ldHJ5Miwgc2NyYXRjaE9wdGlvbnM2LCBDaXJjbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9DaXJjbGVPdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NpcmNsZU91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc2VPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgQ2lyY2xlT3V0bGluZUdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IEVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgIENpcmNsZU91dGxpbmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICByZXR1cm4gRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LnBhY2soCiAgICAgICAgICB2YWx1ZS5fZWxsaXBzZUdlb21ldHJ5LAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVsbGlwc2VHZW9tZXRyeTIgPSBuZXcgRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICBjZW50ZXI6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBzZW1pTWFqb3JBeGlzOiAxLAogICAgICAgIHNlbWlNaW5vckF4aXM6IDEKICAgICAgfSk7CiAgICAgIHNjcmF0Y2hPcHRpb25zNiA9IHsKICAgICAgICBjZW50ZXI6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICByYWRpdXM6IHZvaWQgMCwKICAgICAgICBlbGxpcHNvaWQ6IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKSwKICAgICAgICBoZWlnaHQ6IHZvaWQgMCwKICAgICAgICBleHRydWRlZEhlaWdodDogdm9pZCAwLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAsCiAgICAgICAgbnVtYmVyT2ZWZXJ0aWNhbExpbmVzOiB2b2lkIDAsCiAgICAgICAgc2VtaU1ham9yQXhpczogdm9pZCAwLAogICAgICAgIHNlbWlNaW5vckF4aXM6IHZvaWQgMAogICAgICB9OwogICAgICBDaXJjbGVPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGNvbnN0IGVsbGlwc2VHZW9tZXRyeSA9IEVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBzY3JhdGNoRWxsaXBzZUdlb21ldHJ5MgogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM2LmNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSgKICAgICAgICAgIGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyLAogICAgICAgICAgc2NyYXRjaE9wdGlvbnM2LmNlbnRlcgogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM2LmVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKAogICAgICAgICAgZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoT3B0aW9uczYuZWxsaXBzb2lkCiAgICAgICAgKTsKICAgICAgICBzY3JhdGNoT3B0aW9uczYuaGVpZ2h0ID0gZWxsaXBzZUdlb21ldHJ5Ll9oZWlnaHQ7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM2LmV4dHJ1ZGVkSGVpZ2h0ID0gZWxsaXBzZUdlb21ldHJ5Ll9leHRydWRlZEhlaWdodDsKICAgICAgICBzY3JhdGNoT3B0aW9uczYuZ3JhbnVsYXJpdHkgPSBlbGxpcHNlR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIHNjcmF0Y2hPcHRpb25zNi5udW1iZXJPZlZlcnRpY2FsTGluZXMgPSBlbGxpcHNlR2VvbWV0cnkuX251bWJlck9mVmVydGljYWxMaW5lczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczYucmFkaXVzID0gZWxsaXBzZUdlb21ldHJ5Ll9zZW1pTWFqb3JBeGlzOwogICAgICAgICAgcmV0dXJuIG5ldyBDaXJjbGVPdXRsaW5lR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnM2KTsKICAgICAgICB9CiAgICAgICAgc2NyYXRjaE9wdGlvbnM2LnNlbWlNYWpvckF4aXMgPSBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNYWpvckF4aXM7CiAgICAgICAgc2NyYXRjaE9wdGlvbnM2LnNlbWlNaW5vckF4aXMgPSBlbGxpcHNlR2VvbWV0cnkuX3NlbWlNaW5vckF4aXM7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNlR2VvbWV0cnkgPSBuZXcgRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0KHNjcmF0Y2hPcHRpb25zNik7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ2lyY2xlT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24oY2lyY2xlR2VvbWV0cnkpIHsKICAgICAgICByZXR1cm4gRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkpOwogICAgICB9OwogICAgICBDaXJjbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IENpcmNsZU91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVDaXJjbGVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVDaXJjbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeShjaXJjbGVHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgY2lyY2xlR2VvbWV0cnkgPSBDaXJjbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2soY2lyY2xlR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICBjaXJjbGVHZW9tZXRyeS5fZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgIGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkuX2NlbnRlcgogICAgKTsKICAgIGNpcmNsZUdlb21ldHJ5Ll9lbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKAogICAgICBjaXJjbGVHZW9tZXRyeS5fZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQKICAgICk7CiAgICByZXR1cm4gQ2lyY2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoY2lyY2xlR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVDaXJjbGVPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaXJjbGVPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvYXJyYXlSZW1vdmVEdXBsaWNhdGVzLmpzCiAgZnVuY3Rpb24gYXJyYXlSZW1vdmVEdXBsaWNhdGVzKHZhbHVlcywgZXF1YWxzRXBzaWxvbiwgd3JhcEFyb3VuZCwgcmVtb3ZlZEluZGljZXMpIHsKICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZXF1YWxzRXBzaWxvbiIsIGVxdWFsc0Vwc2lsb24pOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmFsdWVzKSkgewogICAgICByZXR1cm4gdm9pZCAwOwogICAgfQogICAgd3JhcEFyb3VuZCA9IHdyYXBBcm91bmQgPz8gZmFsc2U7CiAgICBjb25zdCBzdG9yZVJlbW92ZWRJbmRpY2VzID0gZGVmaW5lZF9kZWZhdWx0KHJlbW92ZWRJbmRpY2VzKTsKICAgIGNvbnN0IGxlbmd0aCA9IHZhbHVlcy5sZW5ndGg7CiAgICBpZiAobGVuZ3RoIDwgMikgewogICAgICByZXR1cm4gdmFsdWVzOwogICAgfQogICAgbGV0IGkyOwogICAgbGV0IHYwMiA9IHZhbHVlc1swXTsKICAgIGxldCB2MTI7CiAgICBsZXQgY2xlYW5lZFZhbHVlczsKICAgIGxldCBsYXN0Q2xlYW5JbmRleCA9IDA7CiAgICBsZXQgcmVtb3ZlZEluZGV4TENJID0gLTE7CiAgICBmb3IgKGkyID0gMTsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgdjEyID0gdmFsdWVzW2kyXTsKICAgICAgaWYgKGVxdWFsc0Vwc2lsb24odjAyLCB2MTIsIHJlbW92ZUR1cGxpY2F0ZXNFcHNpbG9uKSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNsZWFuZWRWYWx1ZXMpKSB7CiAgICAgICAgICBjbGVhbmVkVmFsdWVzID0gdmFsdWVzLnNsaWNlKDAsIGkyKTsKICAgICAgICAgIGxhc3RDbGVhbkluZGV4ID0gaTIgLSAxOwogICAgICAgICAgcmVtb3ZlZEluZGV4TENJID0gMDsKICAgICAgICB9CiAgICAgICAgaWYgKHN0b3JlUmVtb3ZlZEluZGljZXMpIHsKICAgICAgICAgIHJlbW92ZWRJbmRpY2VzLnB1c2goaTIpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNsZWFuZWRWYWx1ZXMpKSB7CiAgICAgICAgICBjbGVhbmVkVmFsdWVzLnB1c2godjEyKTsKICAgICAgICAgIGxhc3RDbGVhbkluZGV4ID0gaTI7CiAgICAgICAgICBpZiAoc3RvcmVSZW1vdmVkSW5kaWNlcykgewogICAgICAgICAgICByZW1vdmVkSW5kZXhMQ0kgPSByZW1vdmVkSW5kaWNlcy5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHYwMiA9IHYxMjsKICAgICAgfQogICAgfQogICAgaWYgKHdyYXBBcm91bmQgJiYgZXF1YWxzRXBzaWxvbih2YWx1ZXNbMF0sIHZhbHVlc1tsZW5ndGggLSAxXSwgcmVtb3ZlRHVwbGljYXRlc0Vwc2lsb24pKSB7CiAgICAgIGlmIChzdG9yZVJlbW92ZWRJbmRpY2VzKSB7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjbGVhbmVkVmFsdWVzKSkgewogICAgICAgICAgcmVtb3ZlZEluZGljZXMuc3BsaWNlKHJlbW92ZWRJbmRleExDSSwgMCwgbGFzdENsZWFuSW5kZXgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZW1vdmVkSW5kaWNlcy5wdXNoKGxlbmd0aCAtIDEpOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNsZWFuZWRWYWx1ZXMpKSB7CiAgICAgICAgY2xlYW5lZFZhbHVlcy5sZW5ndGggLT0gMTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjbGVhbmVkVmFsdWVzID0gdmFsdWVzLnNsaWNlKDAsIC0xKTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGRlZmluZWRfZGVmYXVsdChjbGVhbmVkVmFsdWVzKSA/IGNsZWFuZWRWYWx1ZXMgOiB2YWx1ZXM7CiAgfQogIHZhciByZW1vdmVEdXBsaWNhdGVzRXBzaWxvbiwgYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQ7CiAgdmFyIGluaXRfYXJyYXlSZW1vdmVEdXBsaWNhdGVzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9hcnJheVJlbW92ZUR1cGxpY2F0ZXMuanMiKCkgewogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgcmVtb3ZlRHVwbGljYXRlc0Vwc2lsb24gPSBNYXRoX2RlZmF1bHQuRVBTSUxPTjEwOwogICAgICBhcnJheVJlbW92ZUR1cGxpY2F0ZXNfZGVmYXVsdCA9IGFycmF5UmVtb3ZlRHVwbGljYXRlczsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0JvdW5kaW5nUmVjdGFuZ2xlLmpzCiAgZnVuY3Rpb24gQm91bmRpbmdSZWN0YW5nbGUoeDIsIHkyLCB3aWR0aCwgaGVpZ2h0KSB7CiAgICB0aGlzLnggPSB4MiA/PyAwOwogICAgdGhpcy55ID0geTIgPz8gMDsKICAgIHRoaXMud2lkdGggPSB3aWR0aCA/PyAwOwogICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQgPz8gMDsKICB9CiAgdmFyIGRlZmF1bHRQcm9qZWN0aW9uMiwgZnJvbVJlY3RhbmdsZUxvd2VyTGVmdCwgZnJvbVJlY3RhbmdsZVVwcGVyUmlnaHQsIEJvdW5kaW5nUmVjdGFuZ2xlX2RlZmF1bHQ7CiAgdmFyIGluaXRfQm91bmRpbmdSZWN0YW5nbGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0JvdW5kaW5nUmVjdGFuZ2xlLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvZ3JhcGhpY1Byb2plY3Rpb24oKTsKICAgICAgaW5pdF9JbnRlcnNlY3QoKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUucGFja2VkTGVuZ3RoID0gNDsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS54OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS55OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS53aWR0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLmhlaWdodDsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIEJvdW5kaW5nUmVjdGFuZ2xlLnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEJvdW5kaW5nUmVjdGFuZ2xlKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQueSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgcmVzdWx0LndpZHRoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQuaGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUuZnJvbVBvaW50cyA9IGZ1bmN0aW9uKHBvc2l0aW9ucywgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEJvdW5kaW5nUmVjdGFuZ2xlKCk7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykgfHwgcG9zaXRpb25zLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmVzdWx0LnggPSAwOwogICAgICAgICAgcmVzdWx0LnkgPSAwOwogICAgICAgICAgcmVzdWx0LndpZHRoID0gMDsKICAgICAgICAgIHJlc3VsdC5oZWlnaHQgPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBsZXQgbWluaW11bVggPSBwb3NpdGlvbnNbMF0ueDsKICAgICAgICBsZXQgbWluaW11bVkgPSBwb3NpdGlvbnNbMF0ueTsKICAgICAgICBsZXQgbWF4aW11bVggPSBwb3NpdGlvbnNbMF0ueDsKICAgICAgICBsZXQgbWF4aW11bVkgPSBwb3NpdGlvbnNbMF0ueTsKICAgICAgICBmb3IgKGxldCBpMiA9IDE7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBwMiA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICBjb25zdCB4MiA9IHAyLng7CiAgICAgICAgICBjb25zdCB5MiA9IHAyLnk7CiAgICAgICAgICBtaW5pbXVtWCA9IE1hdGgubWluKHgyLCBtaW5pbXVtWCk7CiAgICAgICAgICBtYXhpbXVtWCA9IE1hdGgubWF4KHgyLCBtYXhpbXVtWCk7CiAgICAgICAgICBtaW5pbXVtWSA9IE1hdGgubWluKHkyLCBtaW5pbXVtWSk7CiAgICAgICAgICBtYXhpbXVtWSA9IE1hdGgubWF4KHkyLCBtYXhpbXVtWSk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gbWluaW11bVg7CiAgICAgICAgcmVzdWx0LnkgPSBtaW5pbXVtWTsKICAgICAgICByZXN1bHQud2lkdGggPSBtYXhpbXVtWCAtIG1pbmltdW1YOwogICAgICAgIHJlc3VsdC5oZWlnaHQgPSBtYXhpbXVtWSAtIG1pbmltdW1ZOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIGRlZmF1bHRQcm9qZWN0aW9uMiA9IG5ldyBHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0KCk7CiAgICAgIGZyb21SZWN0YW5nbGVMb3dlckxlZnQgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgZnJvbVJlY3RhbmdsZVVwcGVyUmlnaHQgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUuZnJvbVJlY3RhbmdsZSA9IGZ1bmN0aW9uKHJlY3RhbmdsZSwgcHJvamVjdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEJvdW5kaW5nUmVjdGFuZ2xlKCk7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlY3RhbmdsZSkpIHsKICAgICAgICAgIHJlc3VsdC54ID0gMDsKICAgICAgICAgIHJlc3VsdC55ID0gMDsKICAgICAgICAgIHJlc3VsdC53aWR0aCA9IDA7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gMDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIGRlZmF1bHRQcm9qZWN0aW9uMi5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBwcm9qZWN0aW9uID0gcHJvamVjdGlvbiA/PyBkZWZhdWx0UHJvamVjdGlvbjI7CiAgICAgICAgY29uc3QgbG93ZXJMZWZ0ID0gcHJvamVjdGlvbi5wcm9qZWN0KAogICAgICAgICAgUmVjdGFuZ2xlX2RlZmF1bHQuc291dGh3ZXN0KHJlY3RhbmdsZSwgZnJvbVJlY3RhbmdsZUxvd2VyTGVmdCkKICAgICAgICApOwogICAgICAgIGNvbnN0IHVwcGVyUmlnaHQgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgICAgICBSZWN0YW5nbGVfZGVmYXVsdC5ub3J0aGVhc3QocmVjdGFuZ2xlLCBmcm9tUmVjdGFuZ2xlVXBwZXJSaWdodCkKICAgICAgICApOwogICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5zdWJ0cmFjdCh1cHBlclJpZ2h0LCBsb3dlckxlZnQsIHVwcGVyUmlnaHQpOwogICAgICAgIHJlc3VsdC54ID0gbG93ZXJMZWZ0Lng7CiAgICAgICAgcmVzdWx0LnkgPSBsb3dlckxlZnQueTsKICAgICAgICByZXN1bHQud2lkdGggPSB1cHBlclJpZ2h0Lng7CiAgICAgICAgcmVzdWx0LmhlaWdodCA9IHVwcGVyUmlnaHQueTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBCb3VuZGluZ1JlY3RhbmdsZS5jbG9uZSA9IGZ1bmN0aW9uKHJlY3RhbmdsZSwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVjdGFuZ2xlKSkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBCb3VuZGluZ1JlY3RhbmdsZSgKICAgICAgICAgICAgcmVjdGFuZ2xlLngsCiAgICAgICAgICAgIHJlY3RhbmdsZS55LAogICAgICAgICAgICByZWN0YW5nbGUud2lkdGgsCiAgICAgICAgICAgIHJlY3RhbmdsZS5oZWlnaHQKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gcmVjdGFuZ2xlLng7CiAgICAgICAgcmVzdWx0LnkgPSByZWN0YW5nbGUueTsKICAgICAgICByZXN1bHQud2lkdGggPSByZWN0YW5nbGUud2lkdGg7CiAgICAgICAgcmVzdWx0LmhlaWdodCA9IHJlY3RhbmdsZS5oZWlnaHQ7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUudW5pb24gPSBmdW5jdGlvbihsZWZ0LCByaWdodCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgQm91bmRpbmdSZWN0YW5nbGUoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbG93ZXJMZWZ0WCA9IE1hdGgubWluKGxlZnQueCwgcmlnaHQueCk7CiAgICAgICAgY29uc3QgbG93ZXJMZWZ0WSA9IE1hdGgubWluKGxlZnQueSwgcmlnaHQueSk7CiAgICAgICAgY29uc3QgdXBwZXJSaWdodFggPSBNYXRoLm1heChsZWZ0LnggKyBsZWZ0LndpZHRoLCByaWdodC54ICsgcmlnaHQud2lkdGgpOwogICAgICAgIGNvbnN0IHVwcGVyUmlnaHRZID0gTWF0aC5tYXgobGVmdC55ICsgbGVmdC5oZWlnaHQsIHJpZ2h0LnkgKyByaWdodC5oZWlnaHQpOwogICAgICAgIHJlc3VsdC54ID0gbG93ZXJMZWZ0WDsKICAgICAgICByZXN1bHQueSA9IGxvd2VyTGVmdFk7CiAgICAgICAgcmVzdWx0LndpZHRoID0gdXBwZXJSaWdodFggLSBsb3dlckxlZnRYOwogICAgICAgIHJlc3VsdC5oZWlnaHQgPSB1cHBlclJpZ2h0WSAtIGxvd2VyTGVmdFk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUuZXhwYW5kID0gZnVuY3Rpb24ocmVjdGFuZ2xlLCBwb2ludCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicG9pbnQiLCBwb2ludCk7CiAgICAgICAgcmVzdWx0ID0gQm91bmRpbmdSZWN0YW5nbGUuY2xvbmUocmVjdGFuZ2xlLCByZXN1bHQpOwogICAgICAgIGNvbnN0IHdpZHRoID0gcG9pbnQueCAtIHJlc3VsdC54OwogICAgICAgIGNvbnN0IGhlaWdodCA9IHBvaW50LnkgLSByZXN1bHQueTsKICAgICAgICBpZiAod2lkdGggPiByZXN1bHQud2lkdGgpIHsKICAgICAgICAgIHJlc3VsdC53aWR0aCA9IHdpZHRoOwogICAgICAgIH0gZWxzZSBpZiAod2lkdGggPCAwKSB7CiAgICAgICAgICByZXN1bHQud2lkdGggLT0gd2lkdGg7CiAgICAgICAgICByZXN1bHQueCA9IHBvaW50Lng7CiAgICAgICAgfQogICAgICAgIGlmIChoZWlnaHQgPiByZXN1bHQuaGVpZ2h0KSB7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgIH0gZWxzZSBpZiAoaGVpZ2h0IDwgMCkgewogICAgICAgICAgcmVzdWx0LmhlaWdodCAtPSBoZWlnaHQ7CiAgICAgICAgICByZXN1bHQueSA9IHBvaW50Lnk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEJvdW5kaW5nUmVjdGFuZ2xlLmludGVyc2VjdCA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICBjb25zdCBsZWZ0WCA9IGxlZnQueDsKICAgICAgICBjb25zdCBsZWZ0WSA9IGxlZnQueTsKICAgICAgICBjb25zdCByaWdodFggPSByaWdodC54OwogICAgICAgIGNvbnN0IHJpZ2h0WSA9IHJpZ2h0Lnk7CiAgICAgICAgaWYgKCEobGVmdFggPiByaWdodFggKyByaWdodC53aWR0aCB8fCBsZWZ0WCArIGxlZnQud2lkdGggPCByaWdodFggfHwgbGVmdFkgKyBsZWZ0LmhlaWdodCA8IHJpZ2h0WSB8fCBsZWZ0WSA+IHJpZ2h0WSArIHJpZ2h0LmhlaWdodCkpIHsKICAgICAgICAgIHJldHVybiBJbnRlcnNlY3RfZGVmYXVsdC5JTlRFUlNFQ1RJTkc7CiAgICAgICAgfQogICAgICAgIHJldHVybiBJbnRlcnNlY3RfZGVmYXVsdC5PVVRTSURFOwogICAgICB9OwogICAgICBCb3VuZGluZ1JlY3RhbmdsZS5lcXVhbHMgPSBmdW5jdGlvbihsZWZ0LCByaWdodCkgewogICAgICAgIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCBkZWZpbmVkX2RlZmF1bHQobGVmdCkgJiYgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiBsZWZ0LnggPT09IHJpZ2h0LnggJiYgbGVmdC55ID09PSByaWdodC55ICYmIGxlZnQud2lkdGggPT09IHJpZ2h0LndpZHRoICYmIGxlZnQuaGVpZ2h0ID09PSByaWdodC5oZWlnaHQ7CiAgICAgIH07CiAgICAgIEJvdW5kaW5nUmVjdGFuZ2xlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uKHJlc3VsdCkgewogICAgICAgIHJldHVybiBCb3VuZGluZ1JlY3RhbmdsZS5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICB9OwogICAgICBCb3VuZGluZ1JlY3RhbmdsZS5wcm90b3R5cGUuaW50ZXJzZWN0ID0gZnVuY3Rpb24ocmlnaHQpIHsKICAgICAgICByZXR1cm4gQm91bmRpbmdSZWN0YW5nbGUuaW50ZXJzZWN0KHRoaXMsIHJpZ2h0KTsKICAgICAgfTsKICAgICAgQm91bmRpbmdSZWN0YW5nbGUucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uKHJpZ2h0KSB7CiAgICAgICAgcmV0dXJuIEJvdW5kaW5nUmVjdGFuZ2xlLmVxdWFscyh0aGlzLCByaWdodCk7CiAgICAgIH07CiAgICAgIEJvdW5kaW5nUmVjdGFuZ2xlX2RlZmF1bHQgPSBCb3VuZGluZ1JlY3RhbmdsZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0F4aXNBbGlnbmVkQm91bmRpbmdCb3guanMKICBmdW5jdGlvbiBBeGlzQWxpZ25lZEJvdW5kaW5nQm94KG1pbmltdW0sIG1heGltdW0sIGNlbnRlcikgewogICAgdGhpcy5taW5pbXVtID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG1pbmltdW0gPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pOwogICAgdGhpcy5tYXhpbXVtID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG1heGltdW0gPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2VudGVyKSkgewogICAgICBjZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWlkcG9pbnQodGhpcy5taW5pbXVtLCB0aGlzLm1heGltdW0sIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSk7CiAgICB9IGVsc2UgewogICAgICBjZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyKTsKICAgIH0KICAgIHRoaXMuY2VudGVyID0gY2VudGVyOwogIH0KICB2YXIgaW50ZXJzZWN0U2NyYXRjaCwgQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0OwogIHZhciBpbml0X0F4aXNBbGlnbmVkQm91bmRpbmdCb3ggPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0F4aXNBbGlnbmVkQm91bmRpbmdCb3guanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9JbnRlcnNlY3QoKTsKICAgICAgQXhpc0FsaWduZWRCb3VuZGluZ0JveC5mcm9tQ29ybmVycyA9IGZ1bmN0aW9uKG1pbmltdW0sIG1heGltdW0sIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgibWluaW11bSIsIG1pbmltdW0pOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgibWF4aW11bSIsIG1heGltdW0pOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBBeGlzQWxpZ25lZEJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5taW5pbXVtID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG1pbmltdW0sIHJlc3VsdC5taW5pbXVtKTsKICAgICAgICByZXN1bHQubWF4aW11bSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShtYXhpbXVtLCByZXN1bHQubWF4aW11bSk7CiAgICAgICAgcmVzdWx0LmNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5taWRwb2ludChtaW5pbXVtLCBtYXhpbXVtLCByZXN1bHQuY2VudGVyKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBBeGlzQWxpZ25lZEJvdW5kaW5nQm94LmZyb21Qb2ludHMgPSBmdW5jdGlvbihwb3NpdGlvbnMsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBBeGlzQWxpZ25lZEJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykgfHwgcG9zaXRpb25zLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmVzdWx0Lm1pbmltdW0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIHJlc3VsdC5taW5pbXVtKTsKICAgICAgICAgIHJlc3VsdC5tYXhpbXVtID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCByZXN1bHQubWF4aW11bSk7CiAgICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCByZXN1bHQuY2VudGVyKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIGxldCBtaW5pbXVtWCA9IHBvc2l0aW9uc1swXS54OwogICAgICAgIGxldCBtaW5pbXVtWSA9IHBvc2l0aW9uc1swXS55OwogICAgICAgIGxldCBtaW5pbXVtWiA9IHBvc2l0aW9uc1swXS56OwogICAgICAgIGxldCBtYXhpbXVtWCA9IHBvc2l0aW9uc1swXS54OwogICAgICAgIGxldCBtYXhpbXVtWSA9IHBvc2l0aW9uc1swXS55OwogICAgICAgIGxldCBtYXhpbXVtWiA9IHBvc2l0aW9uc1swXS56OwogICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgcDIgPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgY29uc3QgeDIgPSBwMi54OwogICAgICAgICAgY29uc3QgeTIgPSBwMi55OwogICAgICAgICAgY29uc3QgejIgPSBwMi56OwogICAgICAgICAgbWluaW11bVggPSBNYXRoLm1pbih4MiwgbWluaW11bVgpOwogICAgICAgICAgbWF4aW11bVggPSBNYXRoLm1heCh4MiwgbWF4aW11bVgpOwogICAgICAgICAgbWluaW11bVkgPSBNYXRoLm1pbih5MiwgbWluaW11bVkpOwogICAgICAgICAgbWF4aW11bVkgPSBNYXRoLm1heCh5MiwgbWF4aW11bVkpOwogICAgICAgICAgbWluaW11bVogPSBNYXRoLm1pbih6MiwgbWluaW11bVopOwogICAgICAgICAgbWF4aW11bVogPSBNYXRoLm1heCh6MiwgbWF4aW11bVopOwogICAgICAgIH0KICAgICAgICBjb25zdCBtaW5pbXVtID0gcmVzdWx0Lm1pbmltdW07CiAgICAgICAgbWluaW11bS54ID0gbWluaW11bVg7CiAgICAgICAgbWluaW11bS55ID0gbWluaW11bVk7CiAgICAgICAgbWluaW11bS56ID0gbWluaW11bVo7CiAgICAgICAgY29uc3QgbWF4aW11bSA9IHJlc3VsdC5tYXhpbXVtOwogICAgICAgIG1heGltdW0ueCA9IG1heGltdW1YOwogICAgICAgIG1heGltdW0ueSA9IG1heGltdW1ZOwogICAgICAgIG1heGltdW0ueiA9IG1heGltdW1aOwogICAgICAgIHJlc3VsdC5jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWlkcG9pbnQobWluaW11bSwgbWF4aW11bSwgcmVzdWx0LmNlbnRlcik7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQXhpc0FsaWduZWRCb3VuZGluZ0JveC5jbG9uZSA9IGZ1bmN0aW9uKGJveCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm94KSkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBBeGlzQWxpZ25lZEJvdW5kaW5nQm94KGJveC5taW5pbXVtLCBib3gubWF4aW11bSwgYm94LmNlbnRlcik7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5taW5pbXVtID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGJveC5taW5pbXVtLCByZXN1bHQubWluaW11bSk7CiAgICAgICAgcmVzdWx0Lm1heGltdW0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoYm94Lm1heGltdW0sIHJlc3VsdC5tYXhpbXVtKTsKICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGJveC5jZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEF4aXNBbGlnbmVkQm91bmRpbmdCb3guZXF1YWxzID0gZnVuY3Rpb24obGVmdCwgcmlnaHQpIHsKICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgZGVmaW5lZF9kZWZhdWx0KGxlZnQpICYmIGRlZmluZWRfZGVmYXVsdChyaWdodCkgJiYgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhsZWZ0LmNlbnRlciwgcmlnaHQuY2VudGVyKSAmJiBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGxlZnQubWluaW11bSwgcmlnaHQubWluaW11bSkgJiYgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhsZWZ0Lm1heGltdW0sIHJpZ2h0Lm1heGltdW0pOwogICAgICB9OwogICAgICBpbnRlcnNlY3RTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBBeGlzQWxpZ25lZEJvdW5kaW5nQm94LmludGVyc2VjdFBsYW5lID0gZnVuY3Rpb24oYm94LCBwbGFuZSkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYm94IiwgYm94KTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBsYW5lIiwgcGxhbmUpOwogICAgICAgIGludGVyc2VjdFNjcmF0Y2ggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICBib3gubWF4aW11bSwKICAgICAgICAgIGJveC5taW5pbXVtLAogICAgICAgICAgaW50ZXJzZWN0U2NyYXRjaAogICAgICAgICk7CiAgICAgICAgY29uc3QgaDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgIGludGVyc2VjdFNjcmF0Y2gsCiAgICAgICAgICAwLjUsCiAgICAgICAgICBpbnRlcnNlY3RTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBub3JtYWwyID0gcGxhbmUubm9ybWFsOwogICAgICAgIGNvbnN0IGUyID0gaDIueCAqIE1hdGguYWJzKG5vcm1hbDIueCkgKyBoMi55ICogTWF0aC5hYnMobm9ybWFsMi55KSArIGgyLnogKiBNYXRoLmFicyhub3JtYWwyLnopOwogICAgICAgIGNvbnN0IHMyID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChib3guY2VudGVyLCBub3JtYWwyKSArIHBsYW5lLmRpc3RhbmNlOwogICAgICAgIGlmIChzMiAtIGUyID4gMCkgewogICAgICAgICAgcmV0dXJuIEludGVyc2VjdF9kZWZhdWx0LklOU0lERTsKICAgICAgICB9CiAgICAgICAgaWYgKHMyICsgZTIgPCAwKSB7CiAgICAgICAgICByZXR1cm4gSW50ZXJzZWN0X2RlZmF1bHQuT1VUU0lERTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIEludGVyc2VjdF9kZWZhdWx0LklOVEVSU0VDVElORzsKICAgICAgfTsKICAgICAgQXhpc0FsaWduZWRCb3VuZGluZ0JveC5pbnRlcnNlY3RBeGlzQWxpZ25lZEJvdW5kaW5nQm94ID0gZnVuY3Rpb24oYm94LCBvdGhlcikgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYm94IiwgYm94KTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm90aGVyIiwgb3RoZXIpOwogICAgICAgIHJldHVybiBib3gubWluaW11bS54IDw9IG90aGVyLm1heGltdW0ueCAmJiBib3gubWF4aW11bS54ID49IG90aGVyLm1pbmltdW0ueCAmJiBib3gubWluaW11bS55IDw9IG90aGVyLm1heGltdW0ueSAmJiBib3gubWF4aW11bS55ID49IG90aGVyLm1pbmltdW0ueSAmJiBib3gubWluaW11bS56IDw9IG90aGVyLm1heGltdW0ueiAmJiBib3gubWF4aW11bS56ID49IG90aGVyLm1pbmltdW0uejsKICAgICAgfTsKICAgICAgQXhpc0FsaWduZWRCb3VuZGluZ0JveC5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICByZXR1cm4gQXhpc0FsaWduZWRCb3VuZGluZ0JveC5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICB9OwogICAgICBBeGlzQWxpZ25lZEJvdW5kaW5nQm94LnByb3RvdHlwZS5pbnRlcnNlY3RQbGFuZSA9IGZ1bmN0aW9uKHBsYW5lKSB7CiAgICAgICAgcmV0dXJuIEF4aXNBbGlnbmVkQm91bmRpbmdCb3guaW50ZXJzZWN0UGxhbmUodGhpcywgcGxhbmUpOwogICAgICB9OwogICAgICBBeGlzQWxpZ25lZEJvdW5kaW5nQm94LnByb3RvdHlwZS5pbnRlcnNlY3RBeGlzQWxpZ25lZEJvdW5kaW5nQm94ID0gZnVuY3Rpb24ob3RoZXIpIHsKICAgICAgICByZXR1cm4gQXhpc0FsaWduZWRCb3VuZGluZ0JveC5pbnRlcnNlY3RBeGlzQWxpZ25lZEJvdW5kaW5nQm94KHRoaXMsIG90aGVyKTsKICAgICAgfTsKICAgICAgQXhpc0FsaWduZWRCb3VuZGluZ0JveC5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24ocmlnaHQpIHsKICAgICAgICByZXR1cm4gQXhpc0FsaWduZWRCb3VuZGluZ0JveC5lcXVhbHModGhpcywgcmlnaHQpOwogICAgICB9OwogICAgICBBeGlzQWxpZ25lZEJvdW5kaW5nQm94X2RlZmF1bHQgPSBBeGlzQWxpZ25lZEJvdW5kaW5nQm94OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzb2lkVGFuZ2VudFBsYW5lLmpzCiAgZnVuY3Rpb24gRWxsaXBzb2lkVGFuZ2VudFBsYW5lKG9yaWdpbiwgZWxsaXBzb2lkKSB7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9yaWdpbiIsIG9yaWdpbik7CiAgICBlbGxpcHNvaWQgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIG9yaWdpbiA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKG9yaWdpbik7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvcmlnaW4pKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcmlnaW4gbXVzdCBub3QgYmUgYXQgdGhlIGNlbnRlciBvZiB0aGUgZWxsaXBzb2lkLiIKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IGVhc3ROb3J0aFVwID0gVHJhbnNmb3Jtc19kZWZhdWx0LmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKG9yaWdpbiwgZWxsaXBzb2lkKTsKICAgIHRoaXMuX2VsbGlwc29pZCA9IGVsbGlwc29pZDsKICAgIHRoaXMuX29yaWdpbiA9IG9yaWdpbjsKICAgIHRoaXMuX3hBeGlzID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21DYXJ0ZXNpYW40KAogICAgICBNYXRyaXg0X2RlZmF1bHQuZ2V0Q29sdW1uKGVhc3ROb3J0aFVwLCAwLCBzY3JhdGNoQ2FydDQpCiAgICApOwogICAgdGhpcy5feUF4aXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUNhcnRlc2lhbjQoCiAgICAgIE1hdHJpeDRfZGVmYXVsdC5nZXRDb2x1bW4oZWFzdE5vcnRoVXAsIDEsIHNjcmF0Y2hDYXJ0NCkKICAgICk7CiAgICBjb25zdCBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21DYXJ0ZXNpYW40KAogICAgICBNYXRyaXg0X2RlZmF1bHQuZ2V0Q29sdW1uKGVhc3ROb3J0aFVwLCAyLCBzY3JhdGNoQ2FydDQpCiAgICApOwogICAgdGhpcy5fcGxhbmUgPSBQbGFuZV9kZWZhdWx0LmZyb21Qb2ludE5vcm1hbChvcmlnaW4sIG5vcm1hbDIpOwogIH0KICB2YXIgc2NyYXRjaENhcnQ0LCB0bXAsIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVSYXksIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVDYXJ0ZXNpYW4zLCBwcm9qZWN0UG9pbnRzT250b0VsbGlwc29pZFNjcmF0Y2gsIEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0OwogIHZhciBpbml0X0VsbGlwc29pZFRhbmdlbnRQbGFuZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzb2lkVGFuZ2VudFBsYW5lLmpzIigpIHsKICAgICAgaW5pdF9BeGlzQWxpZ25lZEJvdW5kaW5nQm94KCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW40KCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9JbnRlcnNlY3Rpb25UZXN0cygpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9QbGFuZSgpOwogICAgICBpbml0X1JheSgpOwogICAgICBpbml0X1RyYW5zZm9ybXMoKTsKICAgICAgc2NyYXRjaENhcnQ0ID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhFbGxpcHNvaWRUYW5nZW50UGxhbmUucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRUYW5nZW50UGxhbmUucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0VsbGlwc29pZH0KICAgICAgICAgKi8KICAgICAgICBlbGxpcHNvaWQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbGxpcHNvaWQ7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBvcmlnaW4uCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7Q2FydGVzaWFuM30KICAgICAgICAgKi8KICAgICAgICBvcmlnaW46IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vcmlnaW47CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBwbGFuZSB3aGljaCBpcyB0YW5nZW50IHRvIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAdHlwZSB7UGxhbmV9CiAgICAgICAgICovCiAgICAgICAgcGxhbmU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9wbGFuZTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGxvY2FsIFgtYXhpcyAoZWFzdCkgb2YgdGhlIHRhbmdlbnQgcGxhbmUuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAdHlwZSB7Q2FydGVzaWFuM30KICAgICAgICAgKi8KICAgICAgICB4QXhpczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3hBeGlzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgbG9jYWwgWS1heGlzIChub3J0aCkgb2YgdGhlIHRhbmdlbnQgcGxhbmUuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAdHlwZSB7Q2FydGVzaWFuM30KICAgICAgICAgKi8KICAgICAgICB5QXhpczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3lBeGlzOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgbG9jYWwgWi1heGlzICh1cCkgb2YgdGhlIHRhbmdlbnQgcGxhbmUuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUKICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAdHlwZSB7Q2FydGVzaWFuM30KICAgICAgICAgKi8KICAgICAgICB6QXhpczogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3BsYW5lLm5vcm1hbDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICB0bXAgPSBuZXcgQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0KCk7CiAgICAgIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5mcm9tUG9pbnRzID0gZnVuY3Rpb24oY2FydGVzaWFucywgZWxsaXBzb2lkKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjYXJ0ZXNpYW5zIiwgY2FydGVzaWFucyk7CiAgICAgICAgY29uc3QgYm94ID0gQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21Qb2ludHMoY2FydGVzaWFucywgdG1wKTsKICAgICAgICByZXR1cm4gbmV3IEVsbGlwc29pZFRhbmdlbnRQbGFuZShib3guY2VudGVyLCBlbGxpcHNvaWQpOwogICAgICB9OwogICAgICBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lUmF5ID0gbmV3IFJheV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVDYXJ0ZXNpYW4zID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBFbGxpcHNvaWRUYW5nZW50UGxhbmUucHJvdG90eXBlLnByb2plY3RQb2ludE9udG9QbGFuZSA9IGZ1bmN0aW9uKGNhcnRlc2lhbjExLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImNhcnRlc2lhbiIsIGNhcnRlc2lhbjExKTsKICAgICAgICBjb25zdCByYXkgPSBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lUmF5OwogICAgICAgIHJheS5vcmlnaW4gPSBjYXJ0ZXNpYW4xMTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGNhcnRlc2lhbjExLCByYXkuZGlyZWN0aW9uKTsKICAgICAgICBsZXQgaW50ZXJzZWN0aW9uUG9pbnQgPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LnJheVBsYW5lKAogICAgICAgICAgcmF5LAogICAgICAgICAgdGhpcy5fcGxhbmUsCiAgICAgICAgICBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lQ2FydGVzaWFuMwogICAgICAgICk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW50ZXJzZWN0aW9uUG9pbnQpKSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKHJheS5kaXJlY3Rpb24sIHJheS5kaXJlY3Rpb24pOwogICAgICAgICAgaW50ZXJzZWN0aW9uUG9pbnQgPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LnJheVBsYW5lKAogICAgICAgICAgICByYXksCiAgICAgICAgICAgIHRoaXMuX3BsYW5lLAogICAgICAgICAgICBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lQ2FydGVzaWFuMwogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb25Qb2ludCkpIHsKICAgICAgICAgIGNvbnN0IHY0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgICBpbnRlcnNlY3Rpb25Qb2ludCwKICAgICAgICAgICAgdGhpcy5fb3JpZ2luLAogICAgICAgICAgICBpbnRlcnNlY3Rpb25Qb2ludAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHgyID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh0aGlzLl94QXhpcywgdjQpOwogICAgICAgICAgY29uc3QgeTIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHRoaXMuX3lBeGlzLCB2NCk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KHgyLCB5Mik7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQueCA9IHgyOwogICAgICAgICAgcmVzdWx0LnkgPSB5MjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUucHJvamVjdFBvaW50c09udG9QbGFuZSA9IGZ1bmN0aW9uKGNhcnRlc2lhbnMsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydGVzaWFucyIsIGNhcnRlc2lhbnMpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IFtdOwogICAgICAgIH0KICAgICAgICBsZXQgY291bnQgPSAwOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IGNhcnRlc2lhbnMubGVuZ3RoOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHAyID0gdGhpcy5wcm9qZWN0UG9pbnRPbnRvUGxhbmUoY2FydGVzaWFuc1tpMl0sIHJlc3VsdFtjb3VudF0pOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChwMikpIHsKICAgICAgICAgICAgcmVzdWx0W2NvdW50XSA9IHAyOwogICAgICAgICAgICBjb3VudCsrOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXN1bHQubGVuZ3RoID0gY291bnQ7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkVGFuZ2VudFBsYW5lLnByb3RvdHlwZS5wcm9qZWN0UG9pbnRUb05lYXJlc3RPblBsYW5lID0gZnVuY3Rpb24oY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcmF5ID0gc2NyYXRjaFByb2plY3RQb2ludE9udG9QbGFuZVJheTsKICAgICAgICByYXkub3JpZ2luID0gY2FydGVzaWFuMTE7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHRoaXMuX3BsYW5lLm5vcm1hbCwgcmF5LmRpcmVjdGlvbik7CiAgICAgICAgbGV0IGludGVyc2VjdGlvblBvaW50ID0gSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdC5yYXlQbGFuZSgKICAgICAgICAgIHJheSwKICAgICAgICAgIHRoaXMuX3BsYW5lLAogICAgICAgICAgc2NyYXRjaFByb2plY3RQb2ludE9udG9QbGFuZUNhcnRlc2lhbjMKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGludGVyc2VjdGlvblBvaW50KSkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShyYXkuZGlyZWN0aW9uLCByYXkuZGlyZWN0aW9uKTsKICAgICAgICAgIGludGVyc2VjdGlvblBvaW50ID0gSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdC5yYXlQbGFuZSgKICAgICAgICAgICAgcmF5LAogICAgICAgICAgICB0aGlzLl9wbGFuZSwKICAgICAgICAgICAgc2NyYXRjaFByb2plY3RQb2ludE9udG9QbGFuZUNhcnRlc2lhbjMKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHY0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgaW50ZXJzZWN0aW9uUG9pbnQsCiAgICAgICAgICB0aGlzLl9vcmlnaW4sCiAgICAgICAgICBpbnRlcnNlY3Rpb25Qb2ludAogICAgICAgICk7CiAgICAgICAgY29uc3QgeDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHRoaXMuX3hBeGlzLCB2NCk7CiAgICAgICAgY29uc3QgeTIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHRoaXMuX3lBeGlzLCB2NCk7CiAgICAgICAgcmVzdWx0LnggPSB4MjsKICAgICAgICByZXN1bHQueSA9IHkyOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZFRhbmdlbnRQbGFuZS5wcm90b3R5cGUucHJvamVjdFBvaW50c1RvTmVhcmVzdE9uUGxhbmUgPSBmdW5jdGlvbihjYXJ0ZXNpYW5zLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImNhcnRlc2lhbnMiLCBjYXJ0ZXNpYW5zKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBbXTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbGVuZ3RoID0gY2FydGVzaWFucy5sZW5ndGg7CiAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IGxlbmd0aDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICByZXN1bHRbaTJdID0gdGhpcy5wcm9qZWN0UG9pbnRUb05lYXJlc3RPblBsYW5lKGNhcnRlc2lhbnNbaTJdLCByZXN1bHRbaTJdKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgcHJvamVjdFBvaW50c09udG9FbGxpcHNvaWRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBFbGxpcHNvaWRUYW5nZW50UGxhbmUucHJvdG90eXBlLnByb2plY3RQb2ludE9udG9FbGxpcHNvaWQgPSBmdW5jdGlvbihjYXJ0ZXNpYW4xMSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSB0aGlzLl9lbGxpcHNvaWQ7CiAgICAgICAgY29uc3Qgb3JpZ2luID0gdGhpcy5fb3JpZ2luOwogICAgICAgIGNvbnN0IHhBeGlzID0gdGhpcy5feEF4aXM7CiAgICAgICAgY29uc3QgeUF4aXMgPSB0aGlzLl95QXhpczsKICAgICAgICBjb25zdCB0bXAyID0gcHJvamVjdFBvaW50c09udG9FbGxpcHNvaWRTY3JhdGNoOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHhBeGlzLCBjYXJ0ZXNpYW4xMS54LCB0bXAyKTsKICAgICAgICByZXN1bHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG9yaWdpbiwgdG1wMiwgcmVzdWx0KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcih5QXhpcywgY2FydGVzaWFuMTEueSwgdG1wMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHQsIHRtcDIsIHJlc3VsdCk7CiAgICAgICAgZWxsaXBzb2lkLnNjYWxlVG9HZW9jZW50cmljU3VyZmFjZShyZXN1bHQsIHJlc3VsdCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkVGFuZ2VudFBsYW5lLnByb3RvdHlwZS5wcm9qZWN0UG9pbnRzT250b0VsbGlwc29pZCA9IGZ1bmN0aW9uKGNhcnRlc2lhbnMsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydGVzaWFucyIsIGNhcnRlc2lhbnMpOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IGNhcnRlc2lhbnMubGVuZ3RoOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXN1bHQubGVuZ3RoID0gbGVuZ3RoOwogICAgICAgIH0KICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICByZXN1bHRbaTJdID0gdGhpcy5wcm9qZWN0UG9pbnRPbnRvRWxsaXBzb2lkKGNhcnRlc2lhbnNbaTJdLCByZXN1bHRbaTJdKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkVGFuZ2VudFBsYW5lX2RlZmF1bHQgPSBFbGxpcHNvaWRUYW5nZW50UGxhbmU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9PcmllbnRlZEJvdW5kaW5nQm94LmpzCiAgZnVuY3Rpb24gT3JpZW50ZWRCb3VuZGluZ0JveChjZW50ZXIsIGhhbGZBeGVzKSB7CiAgICB0aGlzLmNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIgPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8pOwogICAgdGhpcy5oYWxmQXhlcyA9IE1hdHJpeDNfZGVmYXVsdC5jbG9uZShoYWxmQXhlcyA/PyBNYXRyaXgzX2RlZmF1bHQuWkVSTyk7CiAgfQogIGZ1bmN0aW9uIGZyb21QbGFuZUV4dGVudHMocGxhbmVPcmlnaW4sIHBsYW5lWEF4aXMsIHBsYW5lWUF4aXMsIHBsYW5lWkF4aXMsIG1pbmltdW1YLCBtYXhpbXVtWCwgbWluaW11bVksIG1heGltdW1ZLCBtaW5pbXVtWiwgbWF4aW11bVosIHJlc3VsdCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobWluaW11bVgpIHx8ICFkZWZpbmVkX2RlZmF1bHQobWF4aW11bVgpIHx8ICFkZWZpbmVkX2RlZmF1bHQobWluaW11bVkpIHx8ICFkZWZpbmVkX2RlZmF1bHQobWF4aW11bVkpIHx8ICFkZWZpbmVkX2RlZmF1bHQobWluaW11bVopIHx8ICFkZWZpbmVkX2RlZmF1bHQobWF4aW11bVopKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJhbGwgZXh0ZW50cyAobWluaW11bS9tYXhpbXVtIFgvWS9aKSBhcmUgcmVxdWlyZWQuIgogICAgICApOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICByZXN1bHQgPSBuZXcgT3JpZW50ZWRCb3VuZGluZ0JveCgpOwogICAgfQogICAgY29uc3QgaGFsZkF4ZXMgPSByZXN1bHQuaGFsZkF4ZXM7CiAgICBNYXRyaXgzX2RlZmF1bHQuc2V0Q29sdW1uKGhhbGZBeGVzLCAwLCBwbGFuZVhBeGlzLCBoYWxmQXhlcyk7CiAgICBNYXRyaXgzX2RlZmF1bHQuc2V0Q29sdW1uKGhhbGZBeGVzLCAxLCBwbGFuZVlBeGlzLCBoYWxmQXhlcyk7CiAgICBNYXRyaXgzX2RlZmF1bHQuc2V0Q29sdW1uKGhhbGZBeGVzLCAyLCBwbGFuZVpBeGlzLCBoYWxmQXhlcyk7CiAgICBsZXQgY2VudGVyT2Zmc2V0ID0gc2NyYXRjaE9mZnNldDsKICAgIGNlbnRlck9mZnNldC54ID0gKG1pbmltdW1YICsgbWF4aW11bVgpIC8gMjsKICAgIGNlbnRlck9mZnNldC55ID0gKG1pbmltdW1ZICsgbWF4aW11bVkpIC8gMjsKICAgIGNlbnRlck9mZnNldC56ID0gKG1pbmltdW1aICsgbWF4aW11bVopIC8gMjsKICAgIGNvbnN0IHNjYWxlID0gc2NyYXRjaFNjYWxlMjsKICAgIHNjYWxlLnggPSAobWF4aW11bVggLSBtaW5pbXVtWCkgLyAyOwogICAgc2NhbGUueSA9IChtYXhpbXVtWSAtIG1pbmltdW1ZKSAvIDI7CiAgICBzY2FsZS56ID0gKG1heGltdW1aIC0gbWluaW11bVopIC8gMjsKICAgIGNvbnN0IGNlbnRlciA9IHJlc3VsdC5jZW50ZXI7CiAgICBjZW50ZXJPZmZzZXQgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcihoYWxmQXhlcywgY2VudGVyT2Zmc2V0LCBjZW50ZXJPZmZzZXQpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwbGFuZU9yaWdpbiwgY2VudGVyT2Zmc2V0LCBjZW50ZXIpOwogICAgTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsZShoYWxmQXhlcywgc2NhbGUsIGhhbGZBeGVzKTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBzY3JhdGNoQ2FydGVzaWFuMTUsIHNjcmF0Y2hDYXJ0ZXNpYW4yNSwgc2NyYXRjaENhcnRlc2lhbjM2LCBzY3JhdGNoQ2FydGVzaWFuNDIsIHNjcmF0Y2hDYXJ0ZXNpYW41LCBzY3JhdGNoQ2FydGVzaWFuNiwgc2NyYXRjaENvdmFyaWFuY2VSZXN1bHQsIHNjcmF0Y2hFaWdlblJlc3VsdCwgc2NyYXRjaE9mZnNldCwgc2NyYXRjaFNjYWxlMiwgc2NyYXRjaFJlY3RhbmdsZUNlbnRlckNhcnRvZ3JhcGhpYywgc2NyYXRjaFJlY3RhbmdsZUNlbnRlciwgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY05DLCBzY3JhdGNoUGVyaW1ldGVyQ2FydG9ncmFwaGljTlcsIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0b2dyYXBoaWNDVywgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY1NXLCBzY3JhdGNoUGVyaW1ldGVyQ2FydG9ncmFwaGljU0MsIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0ZXNpYW5OQywgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhbk5XLCBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuQ1csIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0ZXNpYW5TVywgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhblNDLCBzY3JhdGNoUGVyaW1ldGVyUHJvamVjdGVkTkMsIHNjcmF0Y2hQZXJpbWV0ZXJQcm9qZWN0ZWROVywgc2NyYXRjaFBlcmltZXRlclByb2plY3RlZENXLCBzY3JhdGNoUGVyaW1ldGVyUHJvamVjdGVkU1csIHNjcmF0Y2hQZXJpbWV0ZXJQcm9qZWN0ZWRTQywgc2NyYXRjaFBsYW5lT3JpZ2luLCBzY3JhdGNoUGxhbmVOb3JtYWwsIHNjcmF0Y2hQbGFuZVhBeGlzLCBzY3JhdGNoSG9yaXpvbkNhcnRlc2lhbiwgc2NyYXRjaEhvcml6b25Qcm9qZWN0ZWQsIHNjcmF0Y2hNYXhZLCBzY3JhdGNoTWluWSwgc2NyYXRjaFosIHNjcmF0Y2hQbGFuZSwgc2NyYXRjaENhcnRlc2lhblUsIHNjcmF0Y2hDYXJ0ZXNpYW5WLCBzY3JhdGNoQ2FydGVzaWFuVywgc2NyYXRjaFZhbGlkQXhpczIsIHNjcmF0Y2hWYWxpZEF4aXMzLCBzY3JhdGNoUFByaW1lLCBzY3JhdGNoQ29ybmVyLCBzY3JhdGNoVG9DZW50ZXIsIHNjcmF0Y2hYQXhpcywgc2NyYXRjaFlBeGlzLCBzY3JhdGNoWkF4aXMsIHNjcmF0Y2hSb3RhdGlvblNjYWxlLCBzY3JhdGNoQm91bmRpbmdTcGhlcmUsIE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdDsKICB2YXIgaW5pdF9PcmllbnRlZEJvdW5kaW5nQm94ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9PcmllbnRlZEJvdW5kaW5nQm94LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWRUYW5nZW50UGxhbmUoKTsKICAgICAgaW5pdF9JbnRlcnNlY3QoKTsKICAgICAgaW5pdF9JbnRlcnZhbCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBpbml0X1BsYW5lKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlKCk7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3gucGFja2VkTGVuZ3RoID0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIE1hdHJpeDNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3gucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLmNlbnRlciwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5wYWNrKHZhbHVlLmhhbGZBeGVzLCBhcnJheSwgc3RhcnRpbmdJbmRleCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgT3JpZW50ZWRCb3VuZGluZ0JveC51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBPcmllbnRlZEJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggKyBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoLAogICAgICAgICAgcmVzdWx0LmhhbGZBeGVzCiAgICAgICAgKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoQ2FydGVzaWFuMTUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4yNSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjM2ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuNDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW41ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuNiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENvdmFyaWFuY2VSZXN1bHQgPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFaWdlblJlc3VsdCA9IHsKICAgICAgICB1bml0YXJ5OiBuZXcgTWF0cml4M19kZWZhdWx0KCksCiAgICAgICAgZGlhZ29uYWw6IG5ldyBNYXRyaXgzX2RlZmF1bHQoKQogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmZyb21Qb2ludHMgPSBmdW5jdGlvbihwb3NpdGlvbnMsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBPcmllbnRlZEJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykgfHwgcG9zaXRpb25zLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmVzdWx0LmhhbGZBeGVzID0gTWF0cml4M19kZWZhdWx0LlpFUk87CiAgICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk87CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBsZXQgaTI7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBjb25zdCBtZWFuUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb25zWzBdLCBzY3JhdGNoQ2FydGVzaWFuMTUpOwogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChtZWFuUG9pbnQsIHBvc2l0aW9uc1tpMl0sIG1lYW5Qb2ludCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGludkxlbmd0aCA9IDEgLyBsZW5ndGg7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWVhblBvaW50LCBpbnZMZW5ndGgsIG1lYW5Qb2ludCk7CiAgICAgICAgbGV0IGV4eCA9IDA7CiAgICAgICAgbGV0IGV4eSA9IDA7CiAgICAgICAgbGV0IGV4eiA9IDA7CiAgICAgICAgbGV0IGV5eSA9IDA7CiAgICAgICAgbGV0IGV5eiA9IDA7CiAgICAgICAgbGV0IGV6eiA9IDA7CiAgICAgICAgbGV0IHAyOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgcDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocG9zaXRpb25zW2kyXSwgbWVhblBvaW50LCBzY3JhdGNoQ2FydGVzaWFuMjUpOwogICAgICAgICAgZXh4ICs9IHAyLnggKiBwMi54OwogICAgICAgICAgZXh5ICs9IHAyLnggKiBwMi55OwogICAgICAgICAgZXh6ICs9IHAyLnggKiBwMi56OwogICAgICAgICAgZXl5ICs9IHAyLnkgKiBwMi55OwogICAgICAgICAgZXl6ICs9IHAyLnkgKiBwMi56OwogICAgICAgICAgZXp6ICs9IHAyLnogKiBwMi56OwogICAgICAgIH0KICAgICAgICBleHggKj0gaW52TGVuZ3RoOwogICAgICAgIGV4eSAqPSBpbnZMZW5ndGg7CiAgICAgICAgZXh6ICo9IGludkxlbmd0aDsKICAgICAgICBleXkgKj0gaW52TGVuZ3RoOwogICAgICAgIGV5eiAqPSBpbnZMZW5ndGg7CiAgICAgICAgZXp6ICo9IGludkxlbmd0aDsKICAgICAgICBjb25zdCBjb3ZhcmlhbmNlTWF0cml4ID0gc2NyYXRjaENvdmFyaWFuY2VSZXN1bHQ7CiAgICAgICAgY292YXJpYW5jZU1hdHJpeFswXSA9IGV4eDsKICAgICAgICBjb3ZhcmlhbmNlTWF0cml4WzFdID0gZXh5OwogICAgICAgIGNvdmFyaWFuY2VNYXRyaXhbMl0gPSBleHo7CiAgICAgICAgY292YXJpYW5jZU1hdHJpeFszXSA9IGV4eTsKICAgICAgICBjb3ZhcmlhbmNlTWF0cml4WzRdID0gZXl5OwogICAgICAgIGNvdmFyaWFuY2VNYXRyaXhbNV0gPSBleXo7CiAgICAgICAgY292YXJpYW5jZU1hdHJpeFs2XSA9IGV4ejsKICAgICAgICBjb3ZhcmlhbmNlTWF0cml4WzddID0gZXl6OwogICAgICAgIGNvdmFyaWFuY2VNYXRyaXhbOF0gPSBleno7CiAgICAgICAgY29uc3QgZWlnZW5EZWNvbXBvc2l0aW9uID0gTWF0cml4M19kZWZhdWx0LmNvbXB1dGVFaWdlbkRlY29tcG9zaXRpb24oCiAgICAgICAgICBjb3ZhcmlhbmNlTWF0cml4LAogICAgICAgICAgc2NyYXRjaEVpZ2VuUmVzdWx0CiAgICAgICAgKTsKICAgICAgICBjb25zdCByb3RhdGlvbiA9IE1hdHJpeDNfZGVmYXVsdC5jbG9uZShlaWdlbkRlY29tcG9zaXRpb24udW5pdGFyeSwgcmVzdWx0LmhhbGZBeGVzKTsKICAgICAgICBsZXQgdjEyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihyb3RhdGlvbiwgMCwgc2NyYXRjaENhcnRlc2lhbjQyKTsKICAgICAgICBsZXQgdjIyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihyb3RhdGlvbiwgMSwgc2NyYXRjaENhcnRlc2lhbjUpOwogICAgICAgIGxldCB2MzIgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKHJvdGF0aW9uLCAyLCBzY3JhdGNoQ2FydGVzaWFuNik7CiAgICAgICAgbGV0IHUxMiA9IC1OdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgIGxldCB1MjIgPSAtTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICBsZXQgdTMyID0gLU51bWJlci5NQVhfVkFMVUU7CiAgICAgICAgbGV0IGwxID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgICAgICBsZXQgbDIgPSBOdW1iZXIuTUFYX1ZBTFVFOwogICAgICAgIGxldCBsMyA9IE51bWJlci5NQVhfVkFMVUU7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBwMiA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICB1MTIgPSBNYXRoLm1heChDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYxMiwgcDIpLCB1MTIpOwogICAgICAgICAgdTIyID0gTWF0aC5tYXgoQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh2MjIsIHAyKSwgdTIyKTsKICAgICAgICAgIHUzMiA9IE1hdGgubWF4KENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodjMyLCBwMiksIHUzMik7CiAgICAgICAgICBsMSA9IE1hdGgubWluKENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodjEyLCBwMiksIGwxKTsKICAgICAgICAgIGwyID0gTWF0aC5taW4oQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh2MjIsIHAyKSwgbDIpOwogICAgICAgICAgbDMgPSBNYXRoLm1pbihDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHYzMiwgcDIpLCBsMyk7CiAgICAgICAgfQogICAgICAgIHYxMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHYxMiwgMC41ICogKGwxICsgdTEyKSwgdjEyKTsKICAgICAgICB2MjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcih2MjIsIDAuNSAqIChsMiArIHUyMiksIHYyMik7CiAgICAgICAgdjMyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIodjMyLCAwLjUgKiAobDMgKyB1MzIpLCB2MzIpOwogICAgICAgIGNvbnN0IGNlbnRlciA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQodjEyLCB2MjIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCB2MzIsIGNlbnRlcik7CiAgICAgICAgY29uc3Qgc2NhbGUgPSBzY3JhdGNoQ2FydGVzaWFuMzY7CiAgICAgICAgc2NhbGUueCA9IHUxMiAtIGwxOwogICAgICAgIHNjYWxlLnkgPSB1MjIgLSBsMjsKICAgICAgICBzY2FsZS56ID0gdTMyIC0gbDM7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoc2NhbGUsIDAuNSwgc2NhbGUpOwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGUocmVzdWx0LmhhbGZBeGVzLCBzY2FsZSwgcmVzdWx0LmhhbGZBeGVzKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoT2Zmc2V0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoU2NhbGUyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUmVjdGFuZ2xlQ2VudGVyQ2FydG9ncmFwaGljID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hSZWN0YW5nbGVDZW50ZXIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0b2dyYXBoaWNOQyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydG9ncmFwaGljTlcgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY0NXID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0b2dyYXBoaWNTVyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydG9ncmFwaGljU0MgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhbk5DID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuTlcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0ZXNpYW5DVyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhblNXID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuU0MgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJQcm9qZWN0ZWROQyA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlcmltZXRlclByb2plY3RlZE5XID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyaW1ldGVyUHJvamVjdGVkQ1cgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJQcm9qZWN0ZWRTVyA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlcmltZXRlclByb2plY3RlZFNDID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGxhbmVPcmlnaW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQbGFuZU5vcm1hbCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBsYW5lWEF4aXMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hIb3Jpem9uQ2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoSG9yaXpvblByb2plY3RlZCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heFkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5ZID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoWiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBsYW5lID0gbmV3IFBsYW5lX2RlZmF1bHQoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgMCk7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3guZnJvbVJlY3RhbmdsZSA9IGZ1bmN0aW9uKHJlY3RhbmdsZSwgbWluaW11bUhlaWdodCwgbWF4aW11bUhlaWdodCwgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmVjdGFuZ2xlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmIChyZWN0YW5nbGUud2lkdGggPCAwIHx8IHJlY3RhbmdsZS53aWR0aCA+IE1hdGhfZGVmYXVsdC5UV09fUEkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJSZWN0YW5nbGUgd2lkdGggbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIDIgKiBwaSIpOwogICAgICAgIH0KICAgICAgICBpZiAocmVjdGFuZ2xlLmhlaWdodCA8IDAgfHwgcmVjdGFuZ2xlLmhlaWdodCA+IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIlJlY3RhbmdsZSBoZWlnaHQgbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIHBpIik7CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSAmJiAhTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBlbGxpcHNvaWQucmFkaWkueCwKICAgICAgICAgIGVsbGlwc29pZC5yYWRpaS55LAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xNQogICAgICAgICkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiRWxsaXBzb2lkIG11c3QgYmUgYW4gZWxsaXBzb2lkIG9mIHJldm9sdXRpb24gKHJhZGlpLnggPT0gcmFkaWkueSkiCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBtaW5pbXVtSGVpZ2h0ID0gbWluaW11bUhlaWdodCA/PyAwOwogICAgICAgIG1heGltdW1IZWlnaHQgPSBtYXhpbXVtSGVpZ2h0ID8/IDA7CiAgICAgICAgZWxsaXBzb2lkID0gZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICAgICAgbGV0IG1pblgsIG1heFgsIG1pblksIG1heFksIG1pblosIG1heFosIHBsYW5lOwogICAgICAgIGlmIChyZWN0YW5nbGUud2lkdGggPD0gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICBjb25zdCB0YW5nZW50UG9pbnRDYXJ0b2dyYXBoaWMgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgICAgc2NyYXRjaFJlY3RhbmdsZUNlbnRlckNhcnRvZ3JhcGhpYwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHRhbmdlbnRQb2ludCA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICAgICAgdGFuZ2VudFBvaW50Q2FydG9ncmFwaGljLAogICAgICAgICAgICBzY3JhdGNoUmVjdGFuZ2xlQ2VudGVyCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgdGFuZ2VudFBsYW5lID0gbmV3IEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0KHRhbmdlbnRQb2ludCwgZWxsaXBzb2lkKTsKICAgICAgICAgIHBsYW5lID0gdGFuZ2VudFBsYW5lLnBsYW5lOwogICAgICAgICAgY29uc3QgbG9uQ2VudGVyID0gdGFuZ2VudFBvaW50Q2FydG9ncmFwaGljLmxvbmdpdHVkZTsKICAgICAgICAgIGNvbnN0IGxhdENlbnRlciA9IHJlY3RhbmdsZS5zb3V0aCA8IDAgJiYgcmVjdGFuZ2xlLm5vcnRoID4gMCA/IDAgOiB0YW5nZW50UG9pbnRDYXJ0b2dyYXBoaWMubGF0aXR1ZGU7CiAgICAgICAgICBjb25zdCBwZXJpbWV0ZXJDYXJ0b2dyYXBoaWNOQyA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21SYWRpYW5zKAogICAgICAgICAgICBsb25DZW50ZXIsCiAgICAgICAgICAgIHJlY3RhbmdsZS5ub3J0aCwKICAgICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY05DCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyQ2FydG9ncmFwaGljTlcgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgICAgcmVjdGFuZ2xlLndlc3QsCiAgICAgICAgICAgIHJlY3RhbmdsZS5ub3J0aCwKICAgICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY05XCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyQ2FydG9ncmFwaGljQ1cgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgICAgcmVjdGFuZ2xlLndlc3QsCiAgICAgICAgICAgIGxhdENlbnRlciwKICAgICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY0NXCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyQ2FydG9ncmFwaGljU1cgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgICAgcmVjdGFuZ2xlLndlc3QsCiAgICAgICAgICAgIHJlY3RhbmdsZS5zb3V0aCwKICAgICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRvZ3JhcGhpY1NXCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyQ2FydG9ncmFwaGljU0MgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgICAgbG9uQ2VudGVyLAogICAgICAgICAgICByZWN0YW5nbGUuc291dGgsCiAgICAgICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0b2dyYXBoaWNTQwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBlcmltZXRlckNhcnRlc2lhbk5DID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgICAgICBwZXJpbWV0ZXJDYXJ0b2dyYXBoaWNOQywKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhbk5DCiAgICAgICAgICApOwogICAgICAgICAgbGV0IHBlcmltZXRlckNhcnRlc2lhbk5XID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgICAgICBwZXJpbWV0ZXJDYXJ0b2dyYXBoaWNOVywKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhbk5XCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyQ2FydGVzaWFuQ1cgPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgICAgIHBlcmltZXRlckNhcnRvZ3JhcGhpY0NXLAogICAgICAgICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuQ1cKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgcGVyaW1ldGVyQ2FydGVzaWFuU1cgPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgICAgIHBlcmltZXRlckNhcnRvZ3JhcGhpY1NXLAogICAgICAgICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuU1cKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwZXJpbWV0ZXJDYXJ0ZXNpYW5TQyA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICAgICAgcGVyaW1ldGVyQ2FydG9ncmFwaGljU0MsCiAgICAgICAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJDYXJ0ZXNpYW5TQwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBlcmltZXRlclByb2plY3RlZE5DID0gdGFuZ2VudFBsYW5lLnByb2plY3RQb2ludFRvTmVhcmVzdE9uUGxhbmUoCiAgICAgICAgICAgIHBlcmltZXRlckNhcnRlc2lhbk5DLAogICAgICAgICAgICBzY3JhdGNoUGVyaW1ldGVyUHJvamVjdGVkTkMKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwZXJpbWV0ZXJQcm9qZWN0ZWROVyA9IHRhbmdlbnRQbGFuZS5wcm9qZWN0UG9pbnRUb05lYXJlc3RPblBsYW5lKAogICAgICAgICAgICBwZXJpbWV0ZXJDYXJ0ZXNpYW5OVywKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlclByb2plY3RlZE5XCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcGVyaW1ldGVyUHJvamVjdGVkQ1cgPSB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50VG9OZWFyZXN0T25QbGFuZSgKICAgICAgICAgICAgcGVyaW1ldGVyQ2FydGVzaWFuQ1csCiAgICAgICAgICAgIHNjcmF0Y2hQZXJpbWV0ZXJQcm9qZWN0ZWRDVwogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBlcmltZXRlclByb2plY3RlZFNXID0gdGFuZ2VudFBsYW5lLnByb2plY3RQb2ludFRvTmVhcmVzdE9uUGxhbmUoCiAgICAgICAgICAgIHBlcmltZXRlckNhcnRlc2lhblNXLAogICAgICAgICAgICBzY3JhdGNoUGVyaW1ldGVyUHJvamVjdGVkU1cKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwZXJpbWV0ZXJQcm9qZWN0ZWRTQyA9IHRhbmdlbnRQbGFuZS5wcm9qZWN0UG9pbnRUb05lYXJlc3RPblBsYW5lKAogICAgICAgICAgICBwZXJpbWV0ZXJDYXJ0ZXNpYW5TQywKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlclByb2plY3RlZFNDCiAgICAgICAgICApOwogICAgICAgICAgbWluWCA9IE1hdGgubWluKAogICAgICAgICAgICBwZXJpbWV0ZXJQcm9qZWN0ZWROVy54LAogICAgICAgICAgICBwZXJpbWV0ZXJQcm9qZWN0ZWRDVy54LAogICAgICAgICAgICBwZXJpbWV0ZXJQcm9qZWN0ZWRTVy54CiAgICAgICAgICApOwogICAgICAgICAgbWF4WCA9IC1taW5YOwogICAgICAgICAgbWF4WSA9IE1hdGgubWF4KHBlcmltZXRlclByb2plY3RlZE5XLnksIHBlcmltZXRlclByb2plY3RlZE5DLnkpOwogICAgICAgICAgbWluWSA9IE1hdGgubWluKHBlcmltZXRlclByb2plY3RlZFNXLnksIHBlcmltZXRlclByb2plY3RlZFNDLnkpOwogICAgICAgICAgcGVyaW1ldGVyQ2FydG9ncmFwaGljTlcuaGVpZ2h0ID0gcGVyaW1ldGVyQ2FydG9ncmFwaGljU1cuaGVpZ2h0ID0gbWluaW11bUhlaWdodDsKICAgICAgICAgIHBlcmltZXRlckNhcnRlc2lhbk5XID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgICAgICBwZXJpbWV0ZXJDYXJ0b2dyYXBoaWNOVywKICAgICAgICAgICAgc2NyYXRjaFBlcmltZXRlckNhcnRlc2lhbk5XCiAgICAgICAgICApOwogICAgICAgICAgcGVyaW1ldGVyQ2FydGVzaWFuU1cgPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgICAgIHBlcmltZXRlckNhcnRvZ3JhcGhpY1NXLAogICAgICAgICAgICBzY3JhdGNoUGVyaW1ldGVyQ2FydGVzaWFuU1cKICAgICAgICAgICk7CiAgICAgICAgICBtaW5aID0gTWF0aC5taW4oCiAgICAgICAgICAgIFBsYW5lX2RlZmF1bHQuZ2V0UG9pbnREaXN0YW5jZShwbGFuZSwgcGVyaW1ldGVyQ2FydGVzaWFuTlcpLAogICAgICAgICAgICBQbGFuZV9kZWZhdWx0LmdldFBvaW50RGlzdGFuY2UocGxhbmUsIHBlcmltZXRlckNhcnRlc2lhblNXKQogICAgICAgICAgKTsKICAgICAgICAgIG1heFogPSBtYXhpbXVtSGVpZ2h0OwogICAgICAgICAgcmV0dXJuIGZyb21QbGFuZUV4dGVudHMoCiAgICAgICAgICAgIHRhbmdlbnRQbGFuZS5vcmlnaW4sCiAgICAgICAgICAgIHRhbmdlbnRQbGFuZS54QXhpcywKICAgICAgICAgICAgdGFuZ2VudFBsYW5lLnlBeGlzLAogICAgICAgICAgICB0YW5nZW50UGxhbmUuekF4aXMsCiAgICAgICAgICAgIG1pblgsCiAgICAgICAgICAgIG1heFgsCiAgICAgICAgICAgIG1pblksCiAgICAgICAgICAgIG1heFksCiAgICAgICAgICAgIG1pblosCiAgICAgICAgICAgIG1heFosCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZnVsbHlBYm92ZUVxdWF0b3IgPSByZWN0YW5nbGUuc291dGggPiAwOwogICAgICAgIGNvbnN0IGZ1bGx5QmVsb3dFcXVhdG9yID0gcmVjdGFuZ2xlLm5vcnRoIDwgMDsKICAgICAgICBjb25zdCBsYXRpdHVkZU5lYXJlc3RUb0VxdWF0b3IgPSBmdWxseUFib3ZlRXF1YXRvciA/IHJlY3RhbmdsZS5zb3V0aCA6IGZ1bGx5QmVsb3dFcXVhdG9yID8gcmVjdGFuZ2xlLm5vcnRoIDogMDsKICAgICAgICBjb25zdCBjZW50ZXJMb25naXR1ZGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICBzY3JhdGNoUmVjdGFuZ2xlQ2VudGVyQ2FydG9ncmFwaGljCiAgICAgICAgKS5sb25naXR1ZGU7CiAgICAgICAgY29uc3QgcGxhbmVPcmlnaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICBjZW50ZXJMb25naXR1ZGUsCiAgICAgICAgICBsYXRpdHVkZU5lYXJlc3RUb0VxdWF0b3IsCiAgICAgICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc2NyYXRjaFBsYW5lT3JpZ2luCiAgICAgICAgKTsKICAgICAgICBwbGFuZU9yaWdpbi56ID0gMDsKICAgICAgICBjb25zdCBpc1BvbGUgPSBNYXRoLmFicyhwbGFuZU9yaWdpbi54KSA8IE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAgJiYgTWF0aC5hYnMocGxhbmVPcmlnaW4ueSkgPCBNYXRoX2RlZmF1bHQuRVBTSUxPTjEwOwogICAgICAgIGNvbnN0IHBsYW5lTm9ybWFsID0gIWlzUG9sZSA/IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocGxhbmVPcmlnaW4sIHNjcmF0Y2hQbGFuZU5vcm1hbCkgOiBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9YOwogICAgICAgIGNvbnN0IHBsYW5lWUF4aXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9aOwogICAgICAgIGNvbnN0IHBsYW5lWEF4aXMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoCiAgICAgICAgICBwbGFuZU5vcm1hbCwKICAgICAgICAgIHBsYW5lWUF4aXMsCiAgICAgICAgICBzY3JhdGNoUGxhbmVYQXhpcwogICAgICAgICk7CiAgICAgICAgcGxhbmUgPSBQbGFuZV9kZWZhdWx0LmZyb21Qb2ludE5vcm1hbChwbGFuZU9yaWdpbiwgcGxhbmVOb3JtYWwsIHNjcmF0Y2hQbGFuZSk7CiAgICAgICAgY29uc3QgaG9yaXpvbkNhcnRlc2lhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgIGNlbnRlckxvbmdpdHVkZSArIE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTywKICAgICAgICAgIGxhdGl0dWRlTmVhcmVzdFRvRXF1YXRvciwKICAgICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoSG9yaXpvbkNhcnRlc2lhbgogICAgICAgICk7CiAgICAgICAgbWF4WCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoCiAgICAgICAgICBQbGFuZV9kZWZhdWx0LnByb2plY3RQb2ludE9udG9QbGFuZSgKICAgICAgICAgICAgcGxhbmUsCiAgICAgICAgICAgIGhvcml6b25DYXJ0ZXNpYW4sCiAgICAgICAgICAgIHNjcmF0Y2hIb3Jpem9uUHJvamVjdGVkCiAgICAgICAgICApLAogICAgICAgICAgcGxhbmVYQXhpcwogICAgICAgICk7CiAgICAgICAgbWluWCA9IC1tYXhYOwogICAgICAgIG1heFkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICAwLAogICAgICAgICAgcmVjdGFuZ2xlLm5vcnRoLAogICAgICAgICAgZnVsbHlCZWxvd0VxdWF0b3IgPyBtaW5pbXVtSGVpZ2h0IDogbWF4aW11bUhlaWdodCwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHNjcmF0Y2hNYXhZCiAgICAgICAgKS56OwogICAgICAgIG1pblkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICAwLAogICAgICAgICAgcmVjdGFuZ2xlLnNvdXRoLAogICAgICAgICAgZnVsbHlBYm92ZUVxdWF0b3IgPyBtaW5pbXVtSGVpZ2h0IDogbWF4aW11bUhlaWdodCwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHNjcmF0Y2hNaW5ZCiAgICAgICAgKS56OwogICAgICAgIGNvbnN0IGZhclogPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICByZWN0YW5nbGUuZWFzdCwKICAgICAgICAgIGxhdGl0dWRlTmVhcmVzdFRvRXF1YXRvciwKICAgICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoWgogICAgICAgICk7CiAgICAgICAgbWluWiA9IFBsYW5lX2RlZmF1bHQuZ2V0UG9pbnREaXN0YW5jZShwbGFuZSwgZmFyWik7CiAgICAgICAgbWF4WiA9IDA7CiAgICAgICAgcmV0dXJuIGZyb21QbGFuZUV4dGVudHMoCiAgICAgICAgICBwbGFuZU9yaWdpbiwKICAgICAgICAgIHBsYW5lWEF4aXMsCiAgICAgICAgICBwbGFuZVlBeGlzLAogICAgICAgICAgcGxhbmVOb3JtYWwsCiAgICAgICAgICBtaW5YLAogICAgICAgICAgbWF4WCwKICAgICAgICAgIG1pblksCiAgICAgICAgICBtYXhZLAogICAgICAgICAgbWluWiwKICAgICAgICAgIG1heFosCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmZyb21UcmFuc2Zvcm1hdGlvbiA9IGZ1bmN0aW9uKHRyYW5zZm9ybWF0aW9uLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zZm9ybWF0aW9uIiwgdHJhbnNmb3JtYXRpb24pOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBPcmllbnRlZEJvdW5kaW5nQm94KCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5jZW50ZXIgPSBNYXRyaXg0X2RlZmF1bHQuZ2V0VHJhbnNsYXRpb24odHJhbnNmb3JtYXRpb24sIHJlc3VsdC5jZW50ZXIpOwogICAgICAgIHJlc3VsdC5oYWxmQXhlcyA9IE1hdHJpeDRfZGVmYXVsdC5nZXRNYXRyaXgzKHRyYW5zZm9ybWF0aW9uLCByZXN1bHQuaGFsZkF4ZXMpOwogICAgICAgIHJlc3VsdC5oYWxmQXhlcyA9IE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgcmVzdWx0LmhhbGZBeGVzLAogICAgICAgICAgMC41LAogICAgICAgICAgcmVzdWx0LmhhbGZBeGVzCiAgICAgICAgKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmNsb25lID0gZnVuY3Rpb24oYm94LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChib3gpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IE9yaWVudGVkQm91bmRpbmdCb3goYm94LmNlbnRlciwgYm94LmhhbGZBeGVzKTsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGJveC5jZW50ZXIsIHJlc3VsdC5jZW50ZXIpOwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5jbG9uZShib3guaGFsZkF4ZXMsIHJlc3VsdC5oYWxmQXhlcyk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgT3JpZW50ZWRCb3VuZGluZ0JveC5pbnRlcnNlY3RQbGFuZSA9IGZ1bmN0aW9uKGJveCwgcGxhbmUpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChib3gpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYm94IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwbGFuZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY2VudGVyID0gYm94LmNlbnRlcjsKICAgICAgICBjb25zdCBub3JtYWwyID0gcGxhbmUubm9ybWFsOwogICAgICAgIGNvbnN0IGhhbGZBeGVzID0gYm94LmhhbGZBeGVzOwogICAgICAgIGNvbnN0IG5vcm1hbFggPSBub3JtYWwyLngsIG5vcm1hbFkgPSBub3JtYWwyLnksIG5vcm1hbFogPSBub3JtYWwyLno7CiAgICAgICAgY29uc3QgcmFkRWZmZWN0aXZlID0gTWF0aC5hYnMoCiAgICAgICAgICBub3JtYWxYICogaGFsZkF4ZXNbTWF0cml4M19kZWZhdWx0LkNPTFVNTjBST1cwXSArIG5vcm1hbFkgKiBoYWxmQXhlc1tNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMFJPVzFdICsgbm9ybWFsWiAqIGhhbGZBeGVzW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4wUk9XMl0KICAgICAgICApICsgTWF0aC5hYnMoCiAgICAgICAgICBub3JtYWxYICogaGFsZkF4ZXNbTWF0cml4M19kZWZhdWx0LkNPTFVNTjFST1cwXSArIG5vcm1hbFkgKiBoYWxmQXhlc1tNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMVJPVzFdICsgbm9ybWFsWiAqIGhhbGZBeGVzW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4xUk9XMl0KICAgICAgICApICsgTWF0aC5hYnMoCiAgICAgICAgICBub3JtYWxYICogaGFsZkF4ZXNbTWF0cml4M19kZWZhdWx0LkNPTFVNTjJST1cwXSArIG5vcm1hbFkgKiBoYWxmQXhlc1tNYXRyaXgzX2RlZmF1bHQuQ09MVU1OMlJPVzFdICsgbm9ybWFsWiAqIGhhbGZBeGVzW01hdHJpeDNfZGVmYXVsdC5DT0xVTU4yUk9XMl0KICAgICAgICApOwogICAgICAgIGNvbnN0IGRpc3RhbmNlVG9QbGFuZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgY2VudGVyKSArIHBsYW5lLmRpc3RhbmNlOwogICAgICAgIGlmIChkaXN0YW5jZVRvUGxhbmUgPD0gLXJhZEVmZmVjdGl2ZSkgewogICAgICAgICAgcmV0dXJuIEludGVyc2VjdF9kZWZhdWx0Lk9VVFNJREU7CiAgICAgICAgfSBlbHNlIGlmIChkaXN0YW5jZVRvUGxhbmUgPj0gcmFkRWZmZWN0aXZlKSB7CiAgICAgICAgICByZXR1cm4gSW50ZXJzZWN0X2RlZmF1bHQuSU5TSURFOwogICAgICAgIH0KICAgICAgICByZXR1cm4gSW50ZXJzZWN0X2RlZmF1bHQuSU5URVJTRUNUSU5HOwogICAgICB9OwogICAgICBzY3JhdGNoQ2FydGVzaWFuVSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhblYgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW5XID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVmFsaWRBeGlzMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFZhbGlkQXhpczMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQUHJpbWUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3guZGlzdGFuY2VTcXVhcmVkVG8gPSBmdW5jdGlvbihib3gsIGNhcnRlc2lhbjExKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm94KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImJveCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY2FydGVzaWFuMTEpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiY2FydGVzaWFuIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBvZmZzZXQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY2FydGVzaWFuMTEsIGJveC5jZW50ZXIsIHNjcmF0Y2hPZmZzZXQpOwogICAgICAgIGNvbnN0IGhhbGZBeGVzID0gYm94LmhhbGZBeGVzOwogICAgICAgIGxldCB1NCA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDAsIHNjcmF0Y2hDYXJ0ZXNpYW5VKTsKICAgICAgICBsZXQgdjQgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKGhhbGZBeGVzLCAxLCBzY3JhdGNoQ2FydGVzaWFuVik7CiAgICAgICAgbGV0IHcyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihoYWxmQXhlcywgMiwgc2NyYXRjaENhcnRlc2lhblcpOwogICAgICAgIGNvbnN0IHVIYWxmID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSh1NCk7CiAgICAgICAgY29uc3QgdkhhbGYgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKHY0KTsKICAgICAgICBjb25zdCB3SGFsZiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUodzIpOwogICAgICAgIGxldCB1VmFsaWQgPSB0cnVlOwogICAgICAgIGxldCB2VmFsaWQgPSB0cnVlOwogICAgICAgIGxldCB3VmFsaWQgPSB0cnVlOwogICAgICAgIGlmICh1SGFsZiA+IDApIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kaXZpZGVCeVNjYWxhcih1NCwgdUhhbGYsIHU0KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdVZhbGlkID0gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGlmICh2SGFsZiA+IDApIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kaXZpZGVCeVNjYWxhcih2NCwgdkhhbGYsIHY0KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdlZhbGlkID0gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGlmICh3SGFsZiA+IDApIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kaXZpZGVCeVNjYWxhcih3Miwgd0hhbGYsIHcyKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgd1ZhbGlkID0gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG51bWJlck9mRGVnZW5lcmF0ZUF4ZXMgPSAhdVZhbGlkICsgIXZWYWxpZCArICF3VmFsaWQ7CiAgICAgICAgbGV0IHZhbGlkQXhpczE7CiAgICAgICAgbGV0IHZhbGlkQXhpczI7CiAgICAgICAgbGV0IHZhbGlkQXhpczM7CiAgICAgICAgaWYgKG51bWJlck9mRGVnZW5lcmF0ZUF4ZXMgPT09IDEpIHsKICAgICAgICAgIGxldCBkZWdlbmVyYXRlQXhpcyA9IHU0OwogICAgICAgICAgdmFsaWRBeGlzMSA9IHY0OwogICAgICAgICAgdmFsaWRBeGlzMiA9IHcyOwogICAgICAgICAgaWYgKCF2VmFsaWQpIHsKICAgICAgICAgICAgZGVnZW5lcmF0ZUF4aXMgPSB2NDsKICAgICAgICAgICAgdmFsaWRBeGlzMSA9IHU0OwogICAgICAgICAgfSBlbHNlIGlmICghd1ZhbGlkKSB7CiAgICAgICAgICAgIGRlZ2VuZXJhdGVBeGlzID0gdzI7CiAgICAgICAgICAgIHZhbGlkQXhpczIgPSB1NDsKICAgICAgICAgIH0KICAgICAgICAgIHZhbGlkQXhpczMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModmFsaWRBeGlzMSwgdmFsaWRBeGlzMiwgc2NyYXRjaFZhbGlkQXhpczMpOwogICAgICAgICAgaWYgKGRlZ2VuZXJhdGVBeGlzID09PSB1NCkgewogICAgICAgICAgICB1NCA9IHZhbGlkQXhpczM7CiAgICAgICAgICB9IGVsc2UgaWYgKGRlZ2VuZXJhdGVBeGlzID09PSB2NCkgewogICAgICAgICAgICB2NCA9IHZhbGlkQXhpczM7CiAgICAgICAgICB9IGVsc2UgaWYgKGRlZ2VuZXJhdGVBeGlzID09PSB3MikgewogICAgICAgICAgICB3MiA9IHZhbGlkQXhpczM7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIGlmIChudW1iZXJPZkRlZ2VuZXJhdGVBeGVzID09PSAyKSB7CiAgICAgICAgICB2YWxpZEF4aXMxID0gdTQ7CiAgICAgICAgICBpZiAodlZhbGlkKSB7CiAgICAgICAgICAgIHZhbGlkQXhpczEgPSB2NDsKICAgICAgICAgIH0gZWxzZSBpZiAod1ZhbGlkKSB7CiAgICAgICAgICAgIHZhbGlkQXhpczEgPSB3MjsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBjcm9zc1ZlY3RvciA9IENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1k7CiAgICAgICAgICBpZiAoY3Jvc3NWZWN0b3IuZXF1YWxzRXBzaWxvbih2YWxpZEF4aXMxLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjMpKSB7CiAgICAgICAgICAgIGNyb3NzVmVjdG9yID0gQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWDsKICAgICAgICAgIH0KICAgICAgICAgIHZhbGlkQXhpczIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModmFsaWRBeGlzMSwgY3Jvc3NWZWN0b3IsIHNjcmF0Y2hWYWxpZEF4aXMyKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUodmFsaWRBeGlzMiwgdmFsaWRBeGlzMik7CiAgICAgICAgICB2YWxpZEF4aXMzID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHZhbGlkQXhpczEsIHZhbGlkQXhpczIsIHNjcmF0Y2hWYWxpZEF4aXMzKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUodmFsaWRBeGlzMywgdmFsaWRBeGlzMyk7CiAgICAgICAgICBpZiAodmFsaWRBeGlzMSA9PT0gdTQpIHsKICAgICAgICAgICAgdjQgPSB2YWxpZEF4aXMyOwogICAgICAgICAgICB3MiA9IHZhbGlkQXhpczM7CiAgICAgICAgICB9IGVsc2UgaWYgKHZhbGlkQXhpczEgPT09IHY0KSB7CiAgICAgICAgICAgIHcyID0gdmFsaWRBeGlzMjsKICAgICAgICAgICAgdTQgPSB2YWxpZEF4aXMzOwogICAgICAgICAgfSBlbHNlIGlmICh2YWxpZEF4aXMxID09PSB3MikgewogICAgICAgICAgICB1NCA9IHZhbGlkQXhpczI7CiAgICAgICAgICAgIHY0ID0gdmFsaWRBeGlzMzsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYgKG51bWJlck9mRGVnZW5lcmF0ZUF4ZXMgPT09IDMpIHsKICAgICAgICAgIHU0ID0gQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWDsKICAgICAgICAgIHY0ID0gQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWTsKICAgICAgICAgIHcyID0gQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWjsKICAgICAgICB9CiAgICAgICAgY29uc3QgcFByaW1lID0gc2NyYXRjaFBQcmltZTsKICAgICAgICBwUHJpbWUueCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3Qob2Zmc2V0LCB1NCk7CiAgICAgICAgcFByaW1lLnkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG9mZnNldCwgdjQpOwogICAgICAgIHBQcmltZS56ID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChvZmZzZXQsIHcyKTsKICAgICAgICBsZXQgZGlzdGFuY2VTcXVhcmVkID0gMDsKICAgICAgICBsZXQgZDI7CiAgICAgICAgaWYgKHBQcmltZS54IDwgLXVIYWxmKSB7CiAgICAgICAgICBkMiA9IHBQcmltZS54ICsgdUhhbGY7CiAgICAgICAgICBkaXN0YW5jZVNxdWFyZWQgKz0gZDIgKiBkMjsKICAgICAgICB9IGVsc2UgaWYgKHBQcmltZS54ID4gdUhhbGYpIHsKICAgICAgICAgIGQyID0gcFByaW1lLnggLSB1SGFsZjsKICAgICAgICAgIGRpc3RhbmNlU3F1YXJlZCArPSBkMiAqIGQyOwogICAgICAgIH0KICAgICAgICBpZiAocFByaW1lLnkgPCAtdkhhbGYpIHsKICAgICAgICAgIGQyID0gcFByaW1lLnkgKyB2SGFsZjsKICAgICAgICAgIGRpc3RhbmNlU3F1YXJlZCArPSBkMiAqIGQyOwogICAgICAgIH0gZWxzZSBpZiAocFByaW1lLnkgPiB2SGFsZikgewogICAgICAgICAgZDIgPSBwUHJpbWUueSAtIHZIYWxmOwogICAgICAgICAgZGlzdGFuY2VTcXVhcmVkICs9IGQyICogZDI7CiAgICAgICAgfQogICAgICAgIGlmIChwUHJpbWUueiA8IC13SGFsZikgewogICAgICAgICAgZDIgPSBwUHJpbWUueiArIHdIYWxmOwogICAgICAgICAgZGlzdGFuY2VTcXVhcmVkICs9IGQyICogZDI7CiAgICAgICAgfSBlbHNlIGlmIChwUHJpbWUueiA+IHdIYWxmKSB7CiAgICAgICAgICBkMiA9IHBQcmltZS56IC0gd0hhbGY7CiAgICAgICAgICBkaXN0YW5jZVNxdWFyZWQgKz0gZDIgKiBkMjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGRpc3RhbmNlU3F1YXJlZDsKICAgICAgfTsKICAgICAgc2NyYXRjaENvcm5lciA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRvQ2VudGVyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmNvbXB1dGVQbGFuZURpc3RhbmNlcyA9IGZ1bmN0aW9uKGJveCwgcG9zaXRpb24sIGRpcmVjdGlvbjIsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJveCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJib3ggaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9uKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInBvc2l0aW9uIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkaXJlY3Rpb24yKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRpcmVjdGlvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IEludGVydmFsX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgbGV0IG1pbkRpc3QgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IG1heERpc3QgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgY29uc3QgY2VudGVyID0gYm94LmNlbnRlcjsKICAgICAgICBjb25zdCBoYWxmQXhlcyA9IGJveC5oYWxmQXhlczsKICAgICAgICBjb25zdCB1NCA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDAsIHNjcmF0Y2hDYXJ0ZXNpYW5VKTsKICAgICAgICBjb25zdCB2NCA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDEsIHNjcmF0Y2hDYXJ0ZXNpYW5WKTsKICAgICAgICBjb25zdCB3MiA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDIsIHNjcmF0Y2hDYXJ0ZXNpYW5XKTsKICAgICAgICBjb25zdCBjb3JuZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHU0LCB2NCwgc2NyYXRjaENvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHcyLCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY29ybmVyLCBjZW50ZXIsIGNvcm5lcik7CiAgICAgICAgY29uc3QgdG9DZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY29ybmVyLCBwb3NpdGlvbiwgc2NyYXRjaFRvQ2VudGVyKTsKICAgICAgICBsZXQgbWFnID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCB0b0NlbnRlcik7CiAgICAgICAgbWluRGlzdCA9IE1hdGgubWluKG1hZywgbWluRGlzdCk7CiAgICAgICAgbWF4RGlzdCA9IE1hdGgubWF4KG1hZywgbWF4RGlzdCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjZW50ZXIsIHU0LCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY29ybmVyLCB2NCwgY29ybmVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY29ybmVyLCB3MiwgY29ybmVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY29ybmVyLCBwb3NpdGlvbiwgdG9DZW50ZXIpOwogICAgICAgIG1hZyA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZGlyZWN0aW9uMiwgdG9DZW50ZXIpOwogICAgICAgIG1pbkRpc3QgPSBNYXRoLm1pbihtYWcsIG1pbkRpc3QpOwogICAgICAgIG1heERpc3QgPSBNYXRoLm1heChtYWcsIG1heERpc3QpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoY2VudGVyLCB1NCwgY29ybmVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY29ybmVyLCB2NCwgY29ybmVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgdzIsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgcG9zaXRpb24sIHRvQ2VudGVyKTsKICAgICAgICBtYWcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIHRvQ2VudGVyKTsKICAgICAgICBtaW5EaXN0ID0gTWF0aC5taW4obWFnLCBtaW5EaXN0KTsKICAgICAgICBtYXhEaXN0ID0gTWF0aC5tYXgobWFnLCBtYXhEaXN0KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNlbnRlciwgdTQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgdjQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgdzIsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgcG9zaXRpb24sIHRvQ2VudGVyKTsKICAgICAgICBtYWcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIHRvQ2VudGVyKTsKICAgICAgICBtaW5EaXN0ID0gTWF0aC5taW4obWFnLCBtaW5EaXN0KTsKICAgICAgICBtYXhEaXN0ID0gTWF0aC5tYXgobWFnLCBtYXhEaXN0KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoY2VudGVyLCB1NCwgY29ybmVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNvcm5lciwgdjQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHcyLCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjb3JuZXIsIHBvc2l0aW9uLCB0b0NlbnRlcik7CiAgICAgICAgbWFnID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCB0b0NlbnRlcik7CiAgICAgICAgbWluRGlzdCA9IE1hdGgubWluKG1hZywgbWluRGlzdCk7CiAgICAgICAgbWF4RGlzdCA9IE1hdGgubWF4KG1hZywgbWF4RGlzdCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNlbnRlciwgdTQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHY0LCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjb3JuZXIsIHcyLCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjb3JuZXIsIHBvc2l0aW9uLCB0b0NlbnRlcik7CiAgICAgICAgbWFnID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCB0b0NlbnRlcik7CiAgICAgICAgbWluRGlzdCA9IE1hdGgubWluKG1hZywgbWluRGlzdCk7CiAgICAgICAgbWF4RGlzdCA9IE1hdGgubWF4KG1hZywgbWF4RGlzdCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNlbnRlciwgdTQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgdjQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIHcyLCBjb3JuZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjb3JuZXIsIHBvc2l0aW9uLCB0b0NlbnRlcik7CiAgICAgICAgbWFnID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCB0b0NlbnRlcik7CiAgICAgICAgbWluRGlzdCA9IE1hdGgubWluKG1hZywgbWluRGlzdCk7CiAgICAgICAgbWF4RGlzdCA9IE1hdGgubWF4KG1hZywgbWF4RGlzdCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNlbnRlciwgdTQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgdjQsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgdzIsIGNvcm5lcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGNvcm5lciwgcG9zaXRpb24sIHRvQ2VudGVyKTsKICAgICAgICBtYWcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIHRvQ2VudGVyKTsKICAgICAgICBtaW5EaXN0ID0gTWF0aC5taW4obWFnLCBtaW5EaXN0KTsKICAgICAgICBtYXhEaXN0ID0gTWF0aC5tYXgobWFnLCBtYXhEaXN0KTsKICAgICAgICByZXN1bHQuc3RhcnQgPSBtaW5EaXN0OwogICAgICAgIHJlc3VsdC5zdG9wID0gbWF4RGlzdDsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoWEF4aXMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hZQXhpcyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFpBeGlzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmNvbXB1dGVDb3JuZXJzID0gZnVuY3Rpb24oYm94LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImJveCIsIGJveCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gWwogICAgICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKQogICAgICAgICAgXTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY2VudGVyID0gYm94LmNlbnRlcjsKICAgICAgICBjb25zdCBoYWxmQXhlcyA9IGJveC5oYWxmQXhlczsKICAgICAgICBjb25zdCB4QXhpcyA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDAsIHNjcmF0Y2hYQXhpcyk7CiAgICAgICAgY29uc3QgeUF4aXMgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKGhhbGZBeGVzLCAxLCBzY3JhdGNoWUF4aXMpOwogICAgICAgIGNvbnN0IHpBeGlzID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihoYWxmQXhlcywgMiwgc2NyYXRjaFpBeGlzKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyLCByZXN1bHRbMF0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChyZXN1bHRbMF0sIHhBeGlzLCByZXN1bHRbMF0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChyZXN1bHRbMF0sIHlBeGlzLCByZXN1bHRbMF0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChyZXN1bHRbMF0sIHpBeGlzLCByZXN1bHRbMF0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHJlc3VsdFsxXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHJlc3VsdFsxXSwgeEF4aXMsIHJlc3VsdFsxXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHJlc3VsdFsxXSwgeUF4aXMsIHJlc3VsdFsxXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHRbMV0sIHpBeGlzLCByZXN1bHRbMV0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHJlc3VsdFsyXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHJlc3VsdFsyXSwgeEF4aXMsIHJlc3VsdFsyXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHRbMl0sIHlBeGlzLCByZXN1bHRbMl0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChyZXN1bHRbMl0sIHpBeGlzLCByZXN1bHRbMl0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHJlc3VsdFszXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHJlc3VsdFszXSwgeEF4aXMsIHJlc3VsdFszXSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHRbM10sIHlBeGlzLCByZXN1bHRbM10pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmVzdWx0WzNdLCB6QXhpcywgcmVzdWx0WzNdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyLCByZXN1bHRbNF0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmVzdWx0WzRdLCB4QXhpcywgcmVzdWx0WzRdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocmVzdWx0WzRdLCB5QXhpcywgcmVzdWx0WzRdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocmVzdWx0WzRdLCB6QXhpcywgcmVzdWx0WzRdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyLCByZXN1bHRbNV0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmVzdWx0WzVdLCB4QXhpcywgcmVzdWx0WzVdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocmVzdWx0WzVdLCB5QXhpcywgcmVzdWx0WzVdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJlc3VsdFs1XSwgekF4aXMsIHJlc3VsdFs1XSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlciwgcmVzdWx0WzZdKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJlc3VsdFs2XSwgeEF4aXMsIHJlc3VsdFs2XSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHRbNl0sIHlBeGlzLCByZXN1bHRbNl0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChyZXN1bHRbNl0sIHpBeGlzLCByZXN1bHRbNl0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHJlc3VsdFs3XSk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyZXN1bHRbN10sIHhBeGlzLCByZXN1bHRbN10pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmVzdWx0WzddLCB5QXhpcywgcmVzdWx0WzddKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJlc3VsdFs3XSwgekF4aXMsIHJlc3VsdFs3XSk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgc2NyYXRjaFJvdGF0aW9uU2NhbGUgPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3guY29tcHV0ZVRyYW5zZm9ybWF0aW9uID0gZnVuY3Rpb24oYm94LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImJveCIsIGJveCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBjb25zdCB0cmFuc2xhdGlvbjIgPSBib3guY2VudGVyOwogICAgICAgIGNvbnN0IHJvdGF0aW9uU2NhbGUgPSBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVVuaWZvcm1TY2FsZSgKICAgICAgICAgIGJveC5oYWxmQXhlcywKICAgICAgICAgIDIsCiAgICAgICAgICBzY3JhdGNoUm90YXRpb25TY2FsZQogICAgICAgICk7CiAgICAgICAgcmV0dXJuIE1hdHJpeDRfZGVmYXVsdC5mcm9tUm90YXRpb25UcmFuc2xhdGlvbihyb3RhdGlvblNjYWxlLCB0cmFuc2xhdGlvbjIsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hCb3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3guaXNPY2NsdWRlZCA9IGZ1bmN0aW9uKGJveCwgb2NjbHVkZXIpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChib3gpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYm94IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvY2NsdWRlcikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvY2NsdWRlciBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3Qgc3BoZXJlID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tT3JpZW50ZWRCb3VuZGluZ0JveCgKICAgICAgICAgIGJveCwKICAgICAgICAgIHNjcmF0Y2hCb3VuZGluZ1NwaGVyZQogICAgICAgICk7CiAgICAgICAgcmV0dXJuICFvY2NsdWRlci5pc0JvdW5kaW5nU3BoZXJlVmlzaWJsZShzcGhlcmUpOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LnByb3RvdHlwZS5pbnRlcnNlY3RQbGFuZSA9IGZ1bmN0aW9uKHBsYW5lKSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guaW50ZXJzZWN0UGxhbmUodGhpcywgcGxhbmUpOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LnByb3RvdHlwZS5kaXN0YW5jZVNxdWFyZWRUbyA9IGZ1bmN0aW9uKGNhcnRlc2lhbjExKSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guZGlzdGFuY2VTcXVhcmVkVG8odGhpcywgY2FydGVzaWFuMTEpOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LnByb3RvdHlwZS5jb21wdXRlUGxhbmVEaXN0YW5jZXMgPSBmdW5jdGlvbihwb3NpdGlvbiwgZGlyZWN0aW9uMiwgcmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guY29tcHV0ZVBsYW5lRGlzdGFuY2VzKAogICAgICAgICAgdGhpcywKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgZGlyZWN0aW9uMiwKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgIH07CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3gucHJvdG90eXBlLmNvbXB1dGVDb3JuZXJzID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guY29tcHV0ZUNvcm5lcnModGhpcywgcmVzdWx0KTsKICAgICAgfTsKICAgICAgT3JpZW50ZWRCb3VuZGluZ0JveC5wcm90b3R5cGUuY29tcHV0ZVRyYW5zZm9ybWF0aW9uID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guY29tcHV0ZVRyYW5zZm9ybWF0aW9uKHRoaXMsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3gucHJvdG90eXBlLmlzT2NjbHVkZWQgPSBmdW5jdGlvbihvY2NsdWRlcikgewogICAgICAgIHJldHVybiBPcmllbnRlZEJvdW5kaW5nQm94LmlzT2NjbHVkZWQodGhpcywgb2NjbHVkZXIpOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94LmVxdWFscyA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgcmV0dXJuIGxlZnQgPT09IHJpZ2h0IHx8IGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiBkZWZpbmVkX2RlZmF1bHQocmlnaHQpICYmIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMobGVmdC5jZW50ZXIsIHJpZ2h0LmNlbnRlcikgJiYgTWF0cml4M19kZWZhdWx0LmVxdWFscyhsZWZ0LmhhbGZBeGVzLCByaWdodC5oYWxmQXhlcyk7CiAgICAgIH07CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3gucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIE9yaWVudGVkQm91bmRpbmdCb3guY2xvbmUodGhpcywgcmVzdWx0KTsKICAgICAgfTsKICAgICAgT3JpZW50ZWRCb3VuZGluZ0JveC5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24ocmlnaHQpIHsKICAgICAgICByZXR1cm4gT3JpZW50ZWRCb3VuZGluZ0JveC5lcXVhbHModGhpcywgcmlnaHQpOwogICAgICB9OwogICAgICBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQgPSBPcmllbnRlZEJvdW5kaW5nQm94OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LmpzCiAgZnVuY3Rpb24gcHJvamVjdFRvMkQocG9zaXRpb24sIGNlbnRlciwgYXhpczEsIGF4aXMyLCByZXN1bHQpIHsKICAgIGNvbnN0IHY0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHBvc2l0aW9uLCBjZW50ZXIsIHNjcmF0Y2hJbnRlcnNlY3Rpb25Qb2ludCk7CiAgICBjb25zdCB4MiA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoYXhpczEsIHY0KTsKICAgIGNvbnN0IHkyID0gQ2FydGVzaWFuM19kZWZhdWx0LmRvdChheGlzMiwgdjQpOwogICAgcmV0dXJuIENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoeDIsIHkyLCByZXN1bHQpOwogIH0KICB2YXIgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LCBzY3JhdGNoSW50ZXJzZWN0aW9uUG9pbnQsIHNjcmF0Y2hYQXhpczIsIHNjcmF0Y2hZQXhpczIsIHNjcmF0Y2haQXhpczIsIG9iYlNjcmF0Y2gsIENvcGxhbmFyUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0OwogIHZhciBpbml0X0NvcGxhbmFyUG9seWdvbkdlb21ldHJ5TGlicmFyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X09yaWVudGVkQm91bmRpbmdCb3goKTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5ID0ge307CiAgICAgIHNjcmF0Y2hJbnRlcnNlY3Rpb25Qb2ludCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFhBeGlzMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFlBeGlzMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFpBeGlzMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgb2JiU2NyYXRjaCA9IG5ldyBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQoKTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnZhbGlkT3V0bGluZSA9IGZ1bmN0aW9uKHBvc2l0aW9ucykgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicG9zaXRpb25zIiwgcG9zaXRpb25zKTsKICAgICAgICBjb25zdCBvcmllbnRlZEJvdW5kaW5nQm94ID0gT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21Qb2ludHMoCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBvYmJTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBoYWxmQXhlcyA9IG9yaWVudGVkQm91bmRpbmdCb3guaGFsZkF4ZXM7CiAgICAgICAgY29uc3QgeEF4aXMgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKGhhbGZBeGVzLCAwLCBzY3JhdGNoWEF4aXMyKTsKICAgICAgICBjb25zdCB5QXhpcyA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDEsIHNjcmF0Y2hZQXhpczIpOwogICAgICAgIGNvbnN0IHpBeGlzID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihoYWxmQXhlcywgMiwgc2NyYXRjaFpBeGlzMik7CiAgICAgICAgY29uc3QgeE1hZyA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoeEF4aXMpOwogICAgICAgIGNvbnN0IHlNYWcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKHlBeGlzKTsKICAgICAgICBjb25zdCB6TWFnID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSh6QXhpcyk7CiAgICAgICAgcmV0dXJuICEoeE1hZyA9PT0gMCAmJiAoeU1hZyA9PT0gMCB8fCB6TWFnID09PSAwKSB8fCB5TWFnID09PSAwICYmIHpNYWcgPT09IDApOwogICAgICB9OwogICAgICBDb3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnkuY29tcHV0ZVByb2plY3RUbzJEQXJndW1lbnRzID0gZnVuY3Rpb24ocG9zaXRpb25zLCBjZW50ZXJSZXN1bHQsIHBsYW5lQXhpczFSZXN1bHQsIHBsYW5lQXhpczJSZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJjZW50ZXJSZXN1bHQiLCBjZW50ZXJSZXN1bHQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicGxhbmVBeGlzMVJlc3VsdCIsIHBsYW5lQXhpczFSZXN1bHQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicGxhbmVBeGlzMlJlc3VsdCIsIHBsYW5lQXhpczJSZXN1bHQpOwogICAgICAgIGNvbnN0IG9yaWVudGVkQm91bmRpbmdCb3ggPSBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQuZnJvbVBvaW50cygKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIG9iYlNjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IGhhbGZBeGVzID0gb3JpZW50ZWRCb3VuZGluZ0JveC5oYWxmQXhlczsKICAgICAgICBjb25zdCB4QXhpcyA9IE1hdHJpeDNfZGVmYXVsdC5nZXRDb2x1bW4oaGFsZkF4ZXMsIDAsIHNjcmF0Y2hYQXhpczIpOwogICAgICAgIGNvbnN0IHlBeGlzID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihoYWxmQXhlcywgMSwgc2NyYXRjaFlBeGlzMik7CiAgICAgICAgY29uc3QgekF4aXMgPSBNYXRyaXgzX2RlZmF1bHQuZ2V0Q29sdW1uKGhhbGZBeGVzLCAyLCBzY3JhdGNoWkF4aXMyKTsKICAgICAgICBjb25zdCB4TWFnID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSh4QXhpcyk7CiAgICAgICAgY29uc3QgeU1hZyA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoeUF4aXMpOwogICAgICAgIGNvbnN0IHpNYWcgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKHpBeGlzKTsKICAgICAgICBjb25zdCBtaW4zID0gTWF0aC5taW4oeE1hZywgeU1hZywgek1hZyk7CiAgICAgICAgaWYgKHhNYWcgPT09IDAgJiYgKHlNYWcgPT09IDAgfHwgek1hZyA9PT0gMCkgfHwgeU1hZyA9PT0gMCAmJiB6TWFnID09PSAwKSB7CiAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGxldCBwbGFuZUF4aXMxOwogICAgICAgIGxldCBwbGFuZUF4aXMyOwogICAgICAgIGlmIChtaW4zID09PSB5TWFnIHx8IG1pbjMgPT09IHpNYWcpIHsKICAgICAgICAgIHBsYW5lQXhpczEgPSB4QXhpczsKICAgICAgICB9CiAgICAgICAgaWYgKG1pbjMgPT09IHhNYWcpIHsKICAgICAgICAgIHBsYW5lQXhpczEgPSB5QXhpczsKICAgICAgICB9IGVsc2UgaWYgKG1pbjMgPT09IHpNYWcpIHsKICAgICAgICAgIHBsYW5lQXhpczIgPSB5QXhpczsKICAgICAgICB9CiAgICAgICAgaWYgKG1pbjMgPT09IHhNYWcgfHwgbWluMyA9PT0geU1hZykgewogICAgICAgICAgcGxhbmVBeGlzMiA9IHpBeGlzOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHBsYW5lQXhpczEsIHBsYW5lQXhpczFSZXN1bHQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocGxhbmVBeGlzMiwgcGxhbmVBeGlzMlJlc3VsdCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG9yaWVudGVkQm91bmRpbmdCb3guY2VudGVyLCBjZW50ZXJSZXN1bHQpOwogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9OwogICAgICBDb3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnkuY3JlYXRlUHJvamVjdFBvaW50c1RvMkRGdW5jdGlvbiA9IGZ1bmN0aW9uKGNlbnRlciwgYXhpczEsIGF4aXMyKSB7CiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHBvc2l0aW9ucykgewogICAgICAgICAgY29uc3QgcG9zaXRpb25SZXN1bHRzID0gbmV3IEFycmF5KHBvc2l0aW9ucy5sZW5ndGgpOwogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvc2l0aW9ucy5sZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgcG9zaXRpb25SZXN1bHRzW2kyXSA9IHByb2plY3RUbzJEKHBvc2l0aW9uc1tpMl0sIGNlbnRlciwgYXhpczEsIGF4aXMyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBwb3NpdGlvblJlc3VsdHM7CiAgICAgICAgfTsKICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LmNyZWF0ZVByb2plY3RQb2ludFRvMkRGdW5jdGlvbiA9IGZ1bmN0aW9uKGNlbnRlciwgYXhpczEsIGF4aXMyKSB7CiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHBvc2l0aW9uLCByZXN1bHQpIHsKICAgICAgICAgIHJldHVybiBwcm9qZWN0VG8yRChwb3NpdGlvbiwgY2VudGVyLCBheGlzMSwgYXhpczIsIHJlc3VsdCk7CiAgICAgICAgfTsKICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQgPSBDb3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9BcmNUeXBlLmpzCiAgdmFyIEFyY1R5cGUsIEFyY1R5cGVfZGVmYXVsdDsKICB2YXIgaW5pdF9BcmNUeXBlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9BcmNUeXBlLmpzIigpIHsKICAgICAgQXJjVHlwZSA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBTdHJhaWdodCBsaW5lIHRoYXQgZG9lcyBub3QgY29uZm9ybSB0byB0aGUgc3VyZmFjZSBvZiB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBOT05FOiAwLAogICAgICAgIC8qKgogICAgICAgICAqIEZvbGxvdyBnZW9kZXNpYyBwYXRoLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBHRU9ERVNJQzogMSwKICAgICAgICAvKioKICAgICAgICAgKiBGb2xsb3cgcmh1bWIgb3IgbG94b2Ryb21lIHBhdGguCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJIVU1COiAyCiAgICAgIH07CiAgICAgIE9iamVjdC5mcmVlemUoQXJjVHlwZSk7CiAgICAgIEFyY1R5cGVfZGVmYXVsdCA9IEFyY1R5cGU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRSaHVtYkxpbmUuanMKICBmdW5jdGlvbiBjYWxjdWxhdGVNKGVsbGlwdGljaXR5LCBtYWpvciwgbGF0aXR1ZGUpIHsKICAgIGlmIChlbGxpcHRpY2l0eSA9PT0gMCkgewogICAgICByZXR1cm4gbWFqb3IgKiBsYXRpdHVkZTsKICAgIH0KICAgIGNvbnN0IGUyID0gZWxsaXB0aWNpdHkgKiBlbGxpcHRpY2l0eTsKICAgIGNvbnN0IGU0ID0gZTIgKiBlMjsKICAgIGNvbnN0IGU2ID0gZTQgKiBlMjsKICAgIGNvbnN0IGU4ID0gZTYgKiBlMjsKICAgIGNvbnN0IGUxMCA9IGU4ICogZTI7CiAgICBjb25zdCBlMTIgPSBlMTAgKiBlMjsKICAgIGNvbnN0IHBoaSA9IGxhdGl0dWRlOwogICAgY29uc3Qgc2luMlBoaSA9IE1hdGguc2luKDIgKiBwaGkpOwogICAgY29uc3Qgc2luNFBoaSA9IE1hdGguc2luKDQgKiBwaGkpOwogICAgY29uc3Qgc2luNlBoaSA9IE1hdGguc2luKDYgKiBwaGkpOwogICAgY29uc3Qgc2luOFBoaSA9IE1hdGguc2luKDggKiBwaGkpOwogICAgY29uc3Qgc2luMTBQaGkgPSBNYXRoLnNpbigxMCAqIHBoaSk7CiAgICBjb25zdCBzaW4xMlBoaSA9IE1hdGguc2luKDEyICogcGhpKTsKICAgIHJldHVybiBtYWpvciAqICgoMSAtIGUyIC8gNCAtIDMgKiBlNCAvIDY0IC0gNSAqIGU2IC8gMjU2IC0gMTc1ICogZTggLyAxNjM4NCAtIDQ0MSAqIGUxMCAvIDY1NTM2IC0gNDg1MSAqIGUxMiAvIDEwNDg1NzYpICogcGhpIC0gKDMgKiBlMiAvIDggKyAzICogZTQgLyAzMiArIDQ1ICogZTYgLyAxMDI0ICsgMTA1ICogZTggLyA0MDk2ICsgMjIwNSAqIGUxMCAvIDEzMTA3MiArIDYyMzcgKiBlMTIgLyA1MjQyODgpICogc2luMlBoaSArICgxNSAqIGU0IC8gMjU2ICsgNDUgKiBlNiAvIDEwMjQgKyA1MjUgKiBlOCAvIDE2Mzg0ICsgMTU3NSAqIGUxMCAvIDY1NTM2ICsgMTU1OTI1ICogZTEyIC8gODM4ODYwOCkgKiBzaW40UGhpIC0gKDM1ICogZTYgLyAzMDcyICsgMTc1ICogZTggLyAxMjI4OCArIDM2NzUgKiBlMTAgLyAyNjIxNDQgKyAxMzQ3NSAqIGUxMiAvIDEwNDg1NzYpICogc2luNlBoaSArICgzMTUgKiBlOCAvIDEzMTA3MiArIDIyMDUgKiBlMTAgLyA1MjQyODggKyA0MzY1OSAqIGUxMiAvIDgzODg2MDgpICogc2luOFBoaSAtICg2OTMgKiBlMTAgLyAxMzEwNzIwICsgNjIzNyAqIGUxMiAvIDUyNDI4ODApICogc2luMTBQaGkgKyAxMDAxICogZTEyIC8gODM4ODYwOCAqIHNpbjEyUGhpKTsKICB9CiAgZnVuY3Rpb24gY2FsY3VsYXRlSW52ZXJzZU0oTTIsIGVsbGlwdGljaXR5LCBtYWpvcikgewogICAgY29uc3QgZDIgPSBNMiAvIG1ham9yOwogICAgaWYgKGVsbGlwdGljaXR5ID09PSAwKSB7CiAgICAgIHJldHVybiBkMjsKICAgIH0KICAgIGNvbnN0IGQyMiA9IGQyICogZDI7CiAgICBjb25zdCBkMyA9IGQyMiAqIGQyOwogICAgY29uc3QgZDQgPSBkMyAqIGQyOwogICAgY29uc3QgZTIgPSBlbGxpcHRpY2l0eTsKICAgIGNvbnN0IGUyMiA9IGUyICogZTI7CiAgICBjb25zdCBlNCA9IGUyMiAqIGUyMjsKICAgIGNvbnN0IGU2ID0gZTQgKiBlMjI7CiAgICBjb25zdCBlOCA9IGU2ICogZTIyOwogICAgY29uc3QgZTEwID0gZTggKiBlMjI7CiAgICBjb25zdCBlMTIgPSBlMTAgKiBlMjI7CiAgICBjb25zdCBzaW4yRCA9IE1hdGguc2luKDIgKiBkMik7CiAgICBjb25zdCBjb3MyRCA9IE1hdGguY29zKDIgKiBkMik7CiAgICBjb25zdCBzaW40RCA9IE1hdGguc2luKDQgKiBkMik7CiAgICBjb25zdCBjb3M0RCA9IE1hdGguY29zKDQgKiBkMik7CiAgICBjb25zdCBzaW42RCA9IE1hdGguc2luKDYgKiBkMik7CiAgICBjb25zdCBjb3M2RCA9IE1hdGguY29zKDYgKiBkMik7CiAgICBjb25zdCBzaW44RCA9IE1hdGguc2luKDggKiBkMik7CiAgICBjb25zdCBjb3M4RCA9IE1hdGguY29zKDggKiBkMik7CiAgICBjb25zdCBzaW4xMEQgPSBNYXRoLnNpbigxMCAqIGQyKTsKICAgIGNvbnN0IGNvczEwRCA9IE1hdGguY29zKDEwICogZDIpOwogICAgY29uc3Qgc2luMTJEID0gTWF0aC5zaW4oMTIgKiBkMik7CiAgICByZXR1cm4gZDIgKyBkMiAqIGUyMiAvIDQgKyA3ICogZDIgKiBlNCAvIDY0ICsgMTUgKiBkMiAqIGU2IC8gMjU2ICsgNTc5ICogZDIgKiBlOCAvIDE2Mzg0ICsgMTUxNSAqIGQyICogZTEwIC8gNjU1MzYgKyAxNjgzNyAqIGQyICogZTEyIC8gMTA0ODU3NiArICgzICogZDIgKiBlNCAvIDE2ICsgNDUgKiBkMiAqIGU2IC8gMjU2IC0gZDIgKiAoMzIgKiBkMjIgLSA1NjEpICogZTggLyA0MDk2IC0gZDIgKiAoMjMyICogZDIyIC0gMTY3NykgKiBlMTAgLyAxNjM4NCArIGQyICogKDM5OTk4NSAtIDkwNTYwICogZDIyICsgNTEyICogZDQpICogZTEyIC8gNTI0Mjg4MCkgKiBjb3MyRCArICgyMSAqIGQyICogZTYgLyAyNTYgKyA0ODMgKiBkMiAqIGU4IC8gNDA5NiAtIGQyICogKDIyNCAqIGQyMiAtIDE5NjkpICogZTEwIC8gMTYzODQgLSBkMiAqICgzMzE1MiAqIGQyMiAtIDExMjU5OSkgKiBlMTIgLyAxMDQ4NTc2KSAqIGNvczREICsgKDE1MSAqIGQyICogZTggLyA0MDk2ICsgNDY4MSAqIGQyICogZTEwIC8gNjU1MzYgKyAxNDc5ICogZDIgKiBlMTIgLyAxNjM4NCAtIDQ1MyAqIGQzICogZTEyIC8gMzI3NjgpICogY29zNkQgKyAoMTA5NyAqIGQyICogZTEwIC8gNjU1MzYgKyA0Mjc4MyAqIGQyICogZTEyIC8gMTA0ODU3NikgKiBjb3M4RCArIDgwMTEgKiBkMiAqIGUxMiAvIDEwNDg1NzYgKiBjb3MxMEQgKyAoMyAqIGUyMiAvIDggKyAzICogZTQgLyAxNiArIDIxMyAqIGU2IC8gMjA0OCAtIDMgKiBkMjIgKiBlNiAvIDY0ICsgMjU1ICogZTggLyA0MDk2IC0gMzMgKiBkMjIgKiBlOCAvIDUxMiArIDIwODYxICogZTEwIC8gNTI0Mjg4IC0gMzMgKiBkMjIgKiBlMTAgLyA1MTIgKyBkNCAqIGUxMCAvIDEwMjQgKyAyODI3MyAqIGUxMiAvIDEwNDg1NzYgLSA0NzEgKiBkMjIgKiBlMTIgLyA4MTkyICsgOSAqIGQ0ICogZTEyIC8gNDA5NikgKiBzaW4yRCArICgyMSAqIGU0IC8gMjU2ICsgMjEgKiBlNiAvIDI1NiArIDUzMyAqIGU4IC8gODE5MiAtIDIxICogZDIyICogZTggLyA1MTIgKyAxOTcgKiBlMTAgLyA0MDk2IC0gMzE1ICogZDIyICogZTEwIC8gNDA5NiArIDU4NDAzOSAqIGUxMiAvIDE2Nzc3MjE2IC0gMTI1MTcgKiBkMjIgKiBlMTIgLyAxMzEwNzIgKyA3ICogZDQgKiBlMTIgLyAyMDQ4KSAqIHNpbjREICsgKDE1MSAqIGU2IC8gNjE0NCArIDE1MSAqIGU4IC8gNDA5NiArIDUwMTkgKiBlMTAgLyAxMzEwNzIgLSA0NTMgKiBkMjIgKiBlMTAgLyAxNjM4NCArIDI2OTY1ICogZTEyIC8gNzg2NDMyIC0gODYwNyAqIGQyMiAqIGUxMiAvIDEzMTA3MikgKiBzaW42RCArICgxMDk3ICogZTggLyAxMzEwNzIgKyAxMDk3ICogZTEwIC8gNjU1MzYgKyAyMjU3OTcgKiBlMTIgLyAxMDQ4NTc2MCAtIDEwOTcgKiBkMjIgKiBlMTIgLyA2NTUzNikgKiBzaW44RCArICg4MDExICogZTEwIC8gMjYyMTQ0MCArIDgwMTEgKiBlMTIgLyAxMDQ4NTc2KSAqIHNpbjEwRCArIDI5MzM5MyAqIGUxMiAvIDI1MTY1ODI0MCAqIHNpbjEyRDsKICB9CiAgZnVuY3Rpb24gY2FsY3VsYXRlU2lnbWEoZWxsaXB0aWNpdHksIGxhdGl0dWRlKSB7CiAgICBpZiAoZWxsaXB0aWNpdHkgPT09IDApIHsKICAgICAgcmV0dXJuIE1hdGgubG9nKE1hdGgudGFuKDAuNSAqIChNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gKyBsYXRpdHVkZSkpKTsKICAgIH0KICAgIGNvbnN0IGVTaW5MID0gZWxsaXB0aWNpdHkgKiBNYXRoLnNpbihsYXRpdHVkZSk7CiAgICByZXR1cm4gTWF0aC5sb2coTWF0aC50YW4oMC41ICogKE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyArIGxhdGl0dWRlKSkpIC0gZWxsaXB0aWNpdHkgLyAyICogTWF0aC5sb2coKDEgKyBlU2luTCkgLyAoMSAtIGVTaW5MKSk7CiAgfQogIGZ1bmN0aW9uIGNhbGN1bGF0ZUhlYWRpbmcoZWxsaXBzb2lkUmh1bWJMaW5lLCBmaXJzdExvbmdpdHVkZSwgZmlyc3RMYXRpdHVkZSwgc2Vjb25kTG9uZ2l0dWRlLCBzZWNvbmRMYXRpdHVkZSkgewogICAgY29uc3Qgc2lnbWExID0gY2FsY3VsYXRlU2lnbWEoZWxsaXBzb2lkUmh1bWJMaW5lLl9lbGxpcHRpY2l0eSwgZmlyc3RMYXRpdHVkZSk7CiAgICBjb25zdCBzaWdtYTIgPSBjYWxjdWxhdGVTaWdtYSgKICAgICAgZWxsaXBzb2lkUmh1bWJMaW5lLl9lbGxpcHRpY2l0eSwKICAgICAgc2Vjb25kTGF0aXR1ZGUKICAgICk7CiAgICByZXR1cm4gTWF0aC5hdGFuMigKICAgICAgTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKHNlY29uZExvbmdpdHVkZSAtIGZpcnN0TG9uZ2l0dWRlKSwKICAgICAgc2lnbWEyIC0gc2lnbWExCiAgICApOwogIH0KICBmdW5jdGlvbiBjYWxjdWxhdGVBcmNMZW5ndGgoZWxsaXBzb2lkUmh1bWJMaW5lLCBtYWpvciwgbWlub3IsIGZpcnN0TG9uZ2l0dWRlLCBmaXJzdExhdGl0dWRlLCBzZWNvbmRMb25naXR1ZGUsIHNlY29uZExhdGl0dWRlKSB7CiAgICBjb25zdCBoZWFkaW5nID0gZWxsaXBzb2lkUmh1bWJMaW5lLl9oZWFkaW5nOwogICAgY29uc3QgZGVsdGFMb25naXR1ZGUgPSBzZWNvbmRMb25naXR1ZGUgLSBmaXJzdExvbmdpdHVkZTsKICAgIGxldCBkaXN0YW5jZTsKICAgIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgTWF0aC5hYnMoaGVhZGluZyksCiAgICAgIE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTywKICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT044CiAgICApKSB7CiAgICAgIGlmIChtYWpvciA9PT0gbWlub3IpIHsKICAgICAgICBkaXN0YW5jZSA9IG1ham9yICogTWF0aC5jb3MoZmlyc3RMYXRpdHVkZSkgKiBNYXRoX2RlZmF1bHQubmVnYXRpdmVQaVRvUGkoZGVsdGFMb25naXR1ZGUpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IHNpblBoaSA9IE1hdGguc2luKGZpcnN0TGF0aXR1ZGUpOwogICAgICAgIGRpc3RhbmNlID0gbWFqb3IgKiBNYXRoLmNvcyhmaXJzdExhdGl0dWRlKSAqIE1hdGhfZGVmYXVsdC5uZWdhdGl2ZVBpVG9QaShkZWx0YUxvbmdpdHVkZSkgLyBNYXRoLnNxcnQoMSAtIGVsbGlwc29pZFJodW1iTGluZS5fZWxsaXB0aWNpdHlTcXVhcmVkICogc2luUGhpICogc2luUGhpKTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgY29uc3QgTTEgPSBjYWxjdWxhdGVNKAogICAgICAgIGVsbGlwc29pZFJodW1iTGluZS5fZWxsaXB0aWNpdHksCiAgICAgICAgbWFqb3IsCiAgICAgICAgZmlyc3RMYXRpdHVkZQogICAgICApOwogICAgICBjb25zdCBNMiA9IGNhbGN1bGF0ZU0oCiAgICAgICAgZWxsaXBzb2lkUmh1bWJMaW5lLl9lbGxpcHRpY2l0eSwKICAgICAgICBtYWpvciwKICAgICAgICBzZWNvbmRMYXRpdHVkZQogICAgICApOwogICAgICBkaXN0YW5jZSA9IChNMiAtIE0xKSAvIE1hdGguY29zKGhlYWRpbmcpOwogICAgfQogICAgcmV0dXJuIE1hdGguYWJzKGRpc3RhbmNlKTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZVByb3BlcnRpZXMoZWxsaXBzb2lkUmh1bWJMaW5lLCBzdGFydCwgZW5kLCBlbGxpcHNvaWQpIHsKICAgIGNvbnN0IGZpcnN0Q2FydGVzaWFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKHN0YXJ0LCBzY3JhdGNoQ2FydDIpLAogICAgICBzY3JhdGNoQ2FydDEKICAgICk7CiAgICBjb25zdCBsYXN0Q2FydGVzaWFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGVuZCwgc2NyYXRjaENhcnQyKSwKICAgICAgc2NyYXRjaENhcnQyCiAgICApOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoCiAgICAgICJ2YWx1ZSIsCiAgICAgIE1hdGguYWJzKAogICAgICAgIE1hdGguYWJzKENhcnRlc2lhbjNfZGVmYXVsdC5hbmdsZUJldHdlZW4oZmlyc3RDYXJ0ZXNpYW4sIGxhc3RDYXJ0ZXNpYW4pKSAtIE1hdGguUEkKICAgICAgKSwKICAgICAgMC4wMTI1CiAgICApOwogICAgY29uc3QgbWFqb3IgPSBlbGxpcHNvaWQubWF4aW11bVJhZGl1czsKICAgIGNvbnN0IG1pbm9yID0gZWxsaXBzb2lkLm1pbmltdW1SYWRpdXM7CiAgICBjb25zdCBtYWpvclNxdWFyZWQgPSBtYWpvciAqIG1ham9yOwogICAgY29uc3QgbWlub3JTcXVhcmVkID0gbWlub3IgKiBtaW5vcjsKICAgIGVsbGlwc29pZFJodW1iTGluZS5fZWxsaXB0aWNpdHlTcXVhcmVkID0gKG1ham9yU3F1YXJlZCAtIG1pbm9yU3F1YXJlZCkgLyBtYWpvclNxdWFyZWQ7CiAgICBlbGxpcHNvaWRSaHVtYkxpbmUuX2VsbGlwdGljaXR5ID0gTWF0aC5zcXJ0KAogICAgICBlbGxpcHNvaWRSaHVtYkxpbmUuX2VsbGlwdGljaXR5U3F1YXJlZAogICAgKTsKICAgIGVsbGlwc29pZFJodW1iTGluZS5fc3RhcnQgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5jbG9uZSgKICAgICAgc3RhcnQsCiAgICAgIGVsbGlwc29pZFJodW1iTGluZS5fc3RhcnQKICAgICk7CiAgICBlbGxpcHNvaWRSaHVtYkxpbmUuX3N0YXJ0LmhlaWdodCA9IDA7CiAgICBlbGxpcHNvaWRSaHVtYkxpbmUuX2VuZCA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKGVuZCwgZWxsaXBzb2lkUmh1bWJMaW5lLl9lbmQpOwogICAgZWxsaXBzb2lkUmh1bWJMaW5lLl9lbmQuaGVpZ2h0ID0gMDsKICAgIGVsbGlwc29pZFJodW1iTGluZS5faGVhZGluZyA9IGNhbGN1bGF0ZUhlYWRpbmcoCiAgICAgIGVsbGlwc29pZFJodW1iTGluZSwKICAgICAgc3RhcnQubG9uZ2l0dWRlLAogICAgICBzdGFydC5sYXRpdHVkZSwKICAgICAgZW5kLmxvbmdpdHVkZSwKICAgICAgZW5kLmxhdGl0dWRlCiAgICApOwogICAgZWxsaXBzb2lkUmh1bWJMaW5lLl9kaXN0YW5jZSA9IGNhbGN1bGF0ZUFyY0xlbmd0aCgKICAgICAgZWxsaXBzb2lkUmh1bWJMaW5lLAogICAgICBlbGxpcHNvaWQubWF4aW11bVJhZGl1cywKICAgICAgZWxsaXBzb2lkLm1pbmltdW1SYWRpdXMsCiAgICAgIHN0YXJ0LmxvbmdpdHVkZSwKICAgICAgc3RhcnQubGF0aXR1ZGUsCiAgICAgIGVuZC5sb25naXR1ZGUsCiAgICAgIGVuZC5sYXRpdHVkZQogICAgKTsKICB9CiAgZnVuY3Rpb24gaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZShzdGFydCwgaGVhZGluZywgZGlzdGFuY2UsIG1ham9yLCBlbGxpcHRpY2l0eSwgcmVzdWx0KSB7CiAgICBpZiAoZGlzdGFuY2UgPT09IDApIHsKICAgICAgcmV0dXJuIENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKHN0YXJ0LCByZXN1bHQpOwogICAgfQogICAgY29uc3QgZWxsaXB0aWNpdHlTcXVhcmVkID0gZWxsaXB0aWNpdHkgKiBlbGxpcHRpY2l0eTsKICAgIGxldCBsb25naXR1ZGU7CiAgICBsZXQgbGF0aXR1ZGU7CiAgICBsZXQgZGVsdGFMb25naXR1ZGU7CiAgICBpZiAoTWF0aC5hYnMoTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIC0gTWF0aC5hYnMoaGVhZGluZykpID4gTWF0aF9kZWZhdWx0LkVQU0lMT044KSB7CiAgICAgIGNvbnN0IE0xID0gY2FsY3VsYXRlTShlbGxpcHRpY2l0eSwgbWFqb3IsIHN0YXJ0LmxhdGl0dWRlKTsKICAgICAgY29uc3QgZGVsdGFNID0gZGlzdGFuY2UgKiBNYXRoLmNvcyhoZWFkaW5nKTsKICAgICAgY29uc3QgTTIgPSBNMSArIGRlbHRhTTsKICAgICAgbGF0aXR1ZGUgPSBjYWxjdWxhdGVJbnZlcnNlTShNMiwgZWxsaXB0aWNpdHksIG1ham9yKTsKICAgICAgaWYgKE1hdGguYWJzKGhlYWRpbmcpIDwgTWF0aF9kZWZhdWx0LkVQU0lMT04xMCkgewogICAgICAgIGxvbmdpdHVkZSA9IE1hdGhfZGVmYXVsdC5uZWdhdGl2ZVBpVG9QaShzdGFydC5sb25naXR1ZGUpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IHNpZ21hMSA9IGNhbGN1bGF0ZVNpZ21hKGVsbGlwdGljaXR5LCBzdGFydC5sYXRpdHVkZSk7CiAgICAgICAgY29uc3Qgc2lnbWEyID0gY2FsY3VsYXRlU2lnbWEoZWxsaXB0aWNpdHksIGxhdGl0dWRlKTsKICAgICAgICBkZWx0YUxvbmdpdHVkZSA9IE1hdGgudGFuKGhlYWRpbmcpICogKHNpZ21hMiAtIHNpZ21hMSk7CiAgICAgICAgbG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKHN0YXJ0LmxvbmdpdHVkZSArIGRlbHRhTG9uZ2l0dWRlKTsKICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgbGF0aXR1ZGUgPSBzdGFydC5sYXRpdHVkZTsKICAgICAgbGV0IGxvY2FsUmFkOwogICAgICBpZiAoZWxsaXB0aWNpdHkgPT09IDApIHsKICAgICAgICBsb2NhbFJhZCA9IG1ham9yICogTWF0aC5jb3Moc3RhcnQubGF0aXR1ZGUpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IHNpblBoaSA9IE1hdGguc2luKHN0YXJ0LmxhdGl0dWRlKTsKICAgICAgICBsb2NhbFJhZCA9IG1ham9yICogTWF0aC5jb3Moc3RhcnQubGF0aXR1ZGUpIC8gTWF0aC5zcXJ0KDEgLSBlbGxpcHRpY2l0eVNxdWFyZWQgKiBzaW5QaGkgKiBzaW5QaGkpOwogICAgICB9CiAgICAgIGRlbHRhTG9uZ2l0dWRlID0gZGlzdGFuY2UgLyBsb2NhbFJhZDsKICAgICAgaWYgKGhlYWRpbmcgPiAwKSB7CiAgICAgICAgbG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKHN0YXJ0LmxvbmdpdHVkZSArIGRlbHRhTG9uZ2l0dWRlKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBsb25naXR1ZGUgPSBNYXRoX2RlZmF1bHQubmVnYXRpdmVQaVRvUGkoc3RhcnQubG9uZ2l0dWRlIC0gZGVsdGFMb25naXR1ZGUpOwogICAgICB9CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGxvbmdpdHVkZTsKICAgICAgcmVzdWx0LmxhdGl0dWRlID0gbGF0aXR1ZGU7CiAgICAgIHJlc3VsdC5oZWlnaHQgPSAwOwogICAgICByZXR1cm4gcmVzdWx0OwogICAgfQogICAgcmV0dXJuIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdChsb25naXR1ZGUsIGxhdGl0dWRlLCAwKTsKICB9CiAgZnVuY3Rpb24gRWxsaXBzb2lkUmh1bWJMaW5lKHN0YXJ0LCBlbmQsIGVsbGlwc29pZCkgewogICAgY29uc3QgZTIgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIHRoaXMuX2VsbGlwc29pZCA9IGUyOwogICAgdGhpcy5fc3RhcnQgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgIHRoaXMuX2VuZCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgdGhpcy5faGVhZGluZyA9IHZvaWQgMDsKICAgIHRoaXMuX2Rpc3RhbmNlID0gdm9pZCAwOwogICAgdGhpcy5fZWxsaXB0aWNpdHkgPSB2b2lkIDA7CiAgICB0aGlzLl9lbGxpcHRpY2l0eVNxdWFyZWQgPSB2b2lkIDA7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHN0YXJ0KSAmJiBkZWZpbmVkX2RlZmF1bHQoZW5kKSkgewogICAgICBjb21wdXRlUHJvcGVydGllcyh0aGlzLCBzdGFydCwgZW5kLCBlMik7CiAgICB9CiAgfQogIHZhciBzY3JhdGNoQ2FydDEsIHNjcmF0Y2hDYXJ0MiwgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQ7CiAgdmFyIGluaXRfRWxsaXBzb2lkUmh1bWJMaW5lID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRSaHVtYkxpbmUuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgc2NyYXRjaENhcnQxID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEVsbGlwc29pZFJodW1iTGluZS5wcm90b3R5cGUsIHsKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBlbGxpcHNvaWQuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFJodW1iTGluZS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGVsbGlwc29pZDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2VsbGlwc29pZDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHN1cmZhY2UgZGlzdGFuY2UgYmV0d2VlbiB0aGUgc3RhcnQgYW5kIGVuZCBwb2ludAogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBzdXJmYWNlRGlzdGFuY2U6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZGlzdGFuY2UiLCB0aGlzLl9kaXN0YW5jZSk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9kaXN0YW5jZTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGluaXRpYWwgcGxhbmV0b2RldGljIHBvaW50IG9uIHRoZSBwYXRoLgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0NhcnRvZ3JhcGhpY30KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBzdGFydDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXJ0OwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgZmluYWwgcGxhbmV0b2RldGljIHBvaW50IG9uIHRoZSBwYXRoLgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0NhcnRvZ3JhcGhpY30KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBlbmQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbmQ7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBoZWFkaW5nIGZyb20gdGhlIHN0YXJ0IHBvaW50IHRvIHRoZSBlbmQgcG9pbnQuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZFJodW1iTGluZS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGhlYWRpbmc6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZGlzdGFuY2UiLCB0aGlzLl9kaXN0YW5jZSk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9oZWFkaW5nOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIEVsbGlwc29pZFJodW1iTGluZS5mcm9tU3RhcnRIZWFkaW5nRGlzdGFuY2UgPSBmdW5jdGlvbihzdGFydCwgaGVhZGluZywgZGlzdGFuY2UsIGVsbGlwc29pZCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJzdGFydCIsIHN0YXJ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImhlYWRpbmciLCBoZWFkaW5nKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImRpc3RhbmNlIiwgZGlzdGFuY2UpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbigiZGlzdGFuY2UiLCBkaXN0YW5jZSwgMCk7CiAgICAgICAgY29uc3QgZTIgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCBtYWpvciA9IGUyLm1heGltdW1SYWRpdXM7CiAgICAgICAgY29uc3QgbWlub3IgPSBlMi5taW5pbXVtUmFkaXVzOwogICAgICAgIGNvbnN0IG1ham9yU3F1YXJlZCA9IG1ham9yICogbWFqb3I7CiAgICAgICAgY29uc3QgbWlub3JTcXVhcmVkID0gbWlub3IgKiBtaW5vcjsKICAgICAgICBjb25zdCBlbGxpcHRpY2l0eSA9IE1hdGguc3FydCgobWFqb3JTcXVhcmVkIC0gbWlub3JTcXVhcmVkKSAvIG1ham9yU3F1YXJlZCk7CiAgICAgICAgaGVhZGluZyA9IE1hdGhfZGVmYXVsdC5uZWdhdGl2ZVBpVG9QaShoZWFkaW5nKTsKICAgICAgICBjb25zdCBlbmQgPSBpbnRlcnBvbGF0ZVVzaW5nU3VyZmFjZURpc3RhbmNlKAogICAgICAgICAgc3RhcnQsCiAgICAgICAgICBoZWFkaW5nLAogICAgICAgICAgZGlzdGFuY2UsCiAgICAgICAgICBlMi5tYXhpbXVtUmFkaXVzLAogICAgICAgICAgZWxsaXB0aWNpdHkKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkgfHwgZGVmaW5lZF9kZWZhdWx0KGVsbGlwc29pZCkgJiYgIWVsbGlwc29pZC5lcXVhbHMocmVzdWx0LmVsbGlwc29pZCkpIHsKICAgICAgICAgIHJldHVybiBuZXcgRWxsaXBzb2lkUmh1bWJMaW5lKHN0YXJ0LCBlbmQsIGUyKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnNldEVuZFBvaW50cyhzdGFydCwgZW5kKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlLnNldEVuZFBvaW50cyA9IGZ1bmN0aW9uKHN0YXJ0LCBlbmQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInN0YXJ0Iiwgc3RhcnQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZW5kIiwgZW5kKTsKICAgICAgICBjb21wdXRlUHJvcGVydGllcyh0aGlzLCBzdGFydCwgZW5kLCB0aGlzLl9lbGxpcHNvaWQpOwogICAgICB9OwogICAgICBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlLmludGVycG9sYXRlVXNpbmdGcmFjdGlvbiA9IGZ1bmN0aW9uKGZyYWN0aW9uLCByZXN1bHQpIHsKICAgICAgICByZXR1cm4gdGhpcy5pbnRlcnBvbGF0ZVVzaW5nU3VyZmFjZURpc3RhbmNlKAogICAgICAgICAgZnJhY3Rpb24gKiB0aGlzLl9kaXN0YW5jZSwKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZFJodW1iTGluZS5wcm90b3R5cGUuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSA9IGZ1bmN0aW9uKGRpc3RhbmNlLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImRpc3RhbmNlIiwgZGlzdGFuY2UpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXMuX2Rpc3RhbmNlKSB8fCB0aGlzLl9kaXN0YW5jZSA9PT0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJFbGxpcHNvaWRSaHVtYkxpbmUgbXVzdCBoYXZlIGRpc3RpbmN0IHN0YXJ0IGFuZCBlbmQgc2V0LiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbnRlcnBvbGF0ZVVzaW5nU3VyZmFjZURpc3RhbmNlKAogICAgICAgICAgdGhpcy5fc3RhcnQsCiAgICAgICAgICB0aGlzLl9oZWFkaW5nLAogICAgICAgICAgZGlzdGFuY2UsCiAgICAgICAgICB0aGlzLl9lbGxpcHNvaWQubWF4aW11bVJhZGl1cywKICAgICAgICAgIHRoaXMuX2VsbGlwdGljaXR5LAogICAgICAgICAgcmVzdWx0CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkUmh1bWJMaW5lLnByb3RvdHlwZS5maW5kSW50ZXJzZWN0aW9uV2l0aExvbmdpdHVkZSA9IGZ1bmN0aW9uKGludGVyc2VjdGlvbkxvbmdpdHVkZSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJpbnRlcnNlY3Rpb25Mb25naXR1ZGUiLCBpbnRlcnNlY3Rpb25Mb25naXR1ZGUpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXMuX2Rpc3RhbmNlKSB8fCB0aGlzLl9kaXN0YW5jZSA9PT0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJFbGxpcHNvaWRSaHVtYkxpbmUgbXVzdCBoYXZlIGRpc3RpbmN0IHN0YXJ0IGFuZCBlbmQgc2V0LiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGVsbGlwdGljaXR5ID0gdGhpcy5fZWxsaXB0aWNpdHk7CiAgICAgICAgY29uc3QgaGVhZGluZyA9IHRoaXMuX2hlYWRpbmc7CiAgICAgICAgY29uc3QgYWJzSGVhZGluZyA9IE1hdGguYWJzKGhlYWRpbmcpOwogICAgICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5fc3RhcnQ7CiAgICAgICAgaW50ZXJzZWN0aW9uTG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKGludGVyc2VjdGlvbkxvbmdpdHVkZSk7CiAgICAgICAgaWYgKE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgTWF0aC5hYnMoaW50ZXJzZWN0aW9uTG9uZ2l0dWRlKSwKICAgICAgICAgIE1hdGguUEksCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjE0CiAgICAgICAgKSkgewogICAgICAgICAgaW50ZXJzZWN0aW9uTG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0LnNpZ24oc3RhcnQubG9uZ2l0dWRlKSAqIE1hdGguUEk7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBpZiAoTWF0aC5hYnMoTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIC0gYWJzSGVhZGluZykgPD0gTWF0aF9kZWZhdWx0LkVQU0lMT044KSB7CiAgICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gaW50ZXJzZWN0aW9uTG9uZ2l0dWRlOwogICAgICAgICAgcmVzdWx0LmxhdGl0dWRlID0gc3RhcnQubGF0aXR1ZGU7CiAgICAgICAgICByZXN1bHQuaGVpZ2h0ID0gMDsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfSBlbHNlIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIE1hdGguYWJzKE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIGFic0hlYWRpbmcpLAogICAgICAgICAgTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPLAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT044CiAgICAgICAgKSkgewogICAgICAgICAgaWYgKE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBpbnRlcnNlY3Rpb25Mb25naXR1ZGUsCiAgICAgICAgICAgIHN0YXJ0LmxvbmdpdHVkZSwKICAgICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xMgogICAgICAgICAgKSkgewogICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LmxvbmdpdHVkZSA9IGludGVyc2VjdGlvbkxvbmdpdHVkZTsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAqIE1hdGhfZGVmYXVsdC5zaWduKE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIGhlYWRpbmcpOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBjb25zdCBwaGkxID0gc3RhcnQubGF0aXR1ZGU7CiAgICAgICAgY29uc3QgZVNpblBoaTEgPSBlbGxpcHRpY2l0eSAqIE1hdGguc2luKHBoaTEpOwogICAgICAgIGNvbnN0IGxlZnRDb21wb25lbnQgPSBNYXRoLnRhbigwLjUgKiAoTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPICsgcGhpMSkpICogTWF0aC5leHAoKGludGVyc2VjdGlvbkxvbmdpdHVkZSAtIHN0YXJ0LmxvbmdpdHVkZSkgLyBNYXRoLnRhbihoZWFkaW5nKSk7CiAgICAgICAgY29uc3QgZGVub21pbmF0b3IgPSAoMSArIGVTaW5QaGkxKSAvICgxIC0gZVNpblBoaTEpOwogICAgICAgIGxldCBuZXdQaGkgPSBzdGFydC5sYXRpdHVkZTsKICAgICAgICBsZXQgcGhpOwogICAgICAgIGRvIHsKICAgICAgICAgIHBoaSA9IG5ld1BoaTsKICAgICAgICAgIGNvbnN0IGVTaW5QaGkgPSBlbGxpcHRpY2l0eSAqIE1hdGguc2luKHBoaSk7CiAgICAgICAgICBjb25zdCBudW1lcmF0b3IgPSAoMSArIGVTaW5QaGkpIC8gKDEgLSBlU2luUGhpKTsKICAgICAgICAgIG5ld1BoaSA9IDIgKiBNYXRoLmF0YW4oCiAgICAgICAgICAgIGxlZnRDb21wb25lbnQgKiBNYXRoLnBvdyhudW1lcmF0b3IgLyBkZW5vbWluYXRvciwgZWxsaXB0aWNpdHkgLyAyKQogICAgICAgICAgKSAtIE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICB9IHdoaWxlICghTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24obmV3UGhpLCBwaGksIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTIpKTsKICAgICAgICByZXN1bHQubG9uZ2l0dWRlID0gaW50ZXJzZWN0aW9uTG9uZ2l0dWRlOwogICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IG5ld1BoaTsKICAgICAgICByZXN1bHQuaGVpZ2h0ID0gMDsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBFbGxpcHNvaWRSaHVtYkxpbmUucHJvdG90eXBlLmZpbmRJbnRlcnNlY3Rpb25XaXRoTGF0aXR1ZGUgPSBmdW5jdGlvbihpbnRlcnNlY3Rpb25MYXRpdHVkZSwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJpbnRlcnNlY3Rpb25MYXRpdHVkZSIsIGludGVyc2VjdGlvbkxhdGl0dWRlKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLl9kaXN0YW5jZSkgfHwgdGhpcy5fZGlzdGFuY2UgPT09IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiRWxsaXBzb2lkUmh1bWJMaW5lIG11c3QgaGF2ZSBkaXN0aW5jdCBzdGFydCBhbmQgZW5kIHNldC4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHRpY2l0eSA9IHRoaXMuX2VsbGlwdGljaXR5OwogICAgICAgIGNvbnN0IGhlYWRpbmcgPSB0aGlzLl9oZWFkaW5nOwogICAgICAgIGNvbnN0IHN0YXJ0ID0gdGhpcy5fc3RhcnQ7CiAgICAgICAgaWYgKE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgTWF0aC5hYnMoaGVhZGluZyksCiAgICAgICAgICBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08sCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjgKICAgICAgICApKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IHNpZ21hMSA9IGNhbGN1bGF0ZVNpZ21hKGVsbGlwdGljaXR5LCBzdGFydC5sYXRpdHVkZSk7CiAgICAgICAgY29uc3Qgc2lnbWEyID0gY2FsY3VsYXRlU2lnbWEoZWxsaXB0aWNpdHksIGludGVyc2VjdGlvbkxhdGl0dWRlKTsKICAgICAgICBjb25zdCBkZWx0YUxvbmdpdHVkZSA9IE1hdGgudGFuKGhlYWRpbmcpICogKHNpZ21hMiAtIHNpZ21hMSk7CiAgICAgICAgY29uc3QgbG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0Lm5lZ2F0aXZlUGlUb1BpKHN0YXJ0LmxvbmdpdHVkZSArIGRlbHRhTG9uZ2l0dWRlKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdC5sb25naXR1ZGUgPSBsb25naXR1ZGU7CiAgICAgICAgICByZXN1bHQubGF0aXR1ZGUgPSBpbnRlcnNlY3Rpb25MYXRpdHVkZTsKICAgICAgICAgIHJlc3VsdC5oZWlnaHQgPSAwOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdChsb25naXR1ZGUsIGludGVyc2VjdGlvbkxhdGl0dWRlLCAwKTsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQgPSBFbGxpcHNvaWRSaHVtYkxpbmU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Qb2x5Z29uSGllcmFyY2h5LmpzCiAgZnVuY3Rpb24gUG9seWdvbkhpZXJhcmNoeShwb3NpdGlvbnMsIGhvbGVzKSB7CiAgICB0aGlzLnBvc2l0aW9ucyA9IGRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpID8gcG9zaXRpb25zIDogW107CiAgICB0aGlzLmhvbGVzID0gZGVmaW5lZF9kZWZhdWx0KGhvbGVzKSA/IGhvbGVzIDogW107CiAgfQogIHZhciBQb2x5Z29uSGllcmFyY2h5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWdvbkhpZXJhcmNoeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWdvbkhpZXJhcmNoeS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBQb2x5Z29uSGllcmFyY2h5X2RlZmF1bHQgPSBQb2x5Z29uSGllcmFyY2h5OwogICAgfQogIH0pOwoKICAvLyBub2RlX21vZHVsZXMvZWFyY3V0L3NyYy9lYXJjdXQuanMKICBmdW5jdGlvbiBlYXJjdXQoZGF0YSwgaG9sZUluZGljZXMsIGRpbSA9IDIpIHsKICAgIGNvbnN0IGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoOwogICAgY29uc3Qgb3V0ZXJMZW4gPSBoYXNIb2xlcyA/IGhvbGVJbmRpY2VzWzBdICogZGltIDogZGF0YS5sZW5ndGg7CiAgICBsZXQgb3V0ZXJOb2RlID0gbGlua2VkTGlzdChkYXRhLCAwLCBvdXRlckxlbiwgZGltLCB0cnVlKTsKICAgIGNvbnN0IHRyaWFuZ2xlcyA9IFtdOwogICAgaWYgKCFvdXRlck5vZGUgfHwgb3V0ZXJOb2RlLm5leHQgPT09IG91dGVyTm9kZS5wcmV2KSByZXR1cm4gdHJpYW5nbGVzOwogICAgbGV0IG1pblgsIG1pblksIGludlNpemU7CiAgICBpZiAoaGFzSG9sZXMpIG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGVzKGRhdGEsIGhvbGVJbmRpY2VzLCBvdXRlck5vZGUsIGRpbSk7CiAgICBpZiAoZGF0YS5sZW5ndGggPiA4MCAqIGRpbSkgewogICAgICBtaW5YID0gZGF0YVswXTsKICAgICAgbWluWSA9IGRhdGFbMV07CiAgICAgIGxldCBtYXhYID0gbWluWDsKICAgICAgbGV0IG1heFkgPSBtaW5ZOwogICAgICBmb3IgKGxldCBpMiA9IGRpbTsgaTIgPCBvdXRlckxlbjsgaTIgKz0gZGltKSB7CiAgICAgICAgY29uc3QgeDIgPSBkYXRhW2kyXTsKICAgICAgICBjb25zdCB5MiA9IGRhdGFbaTIgKyAxXTsKICAgICAgICBpZiAoeDIgPCBtaW5YKSBtaW5YID0geDI7CiAgICAgICAgaWYgKHkyIDwgbWluWSkgbWluWSA9IHkyOwogICAgICAgIGlmICh4MiA+IG1heFgpIG1heFggPSB4MjsKICAgICAgICBpZiAoeTIgPiBtYXhZKSBtYXhZID0geTI7CiAgICAgIH0KICAgICAgaW52U2l6ZSA9IE1hdGgubWF4KG1heFggLSBtaW5YLCBtYXhZIC0gbWluWSk7CiAgICAgIGludlNpemUgPSBpbnZTaXplICE9PSAwID8gMzI3NjcgLyBpbnZTaXplIDogMDsKICAgIH0KICAgIGVhcmN1dExpbmtlZChvdXRlck5vZGUsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwKTsKICAgIHJldHVybiB0cmlhbmdsZXM7CiAgfQogIGZ1bmN0aW9uIGxpbmtlZExpc3QoZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBjbG9ja3dpc2UpIHsKICAgIGxldCBsYXN0OwogICAgaWYgKGNsb2Nrd2lzZSA9PT0gc2lnbmVkQXJlYShkYXRhLCBzdGFydCwgZW5kLCBkaW0pID4gMCkgewogICAgICBmb3IgKGxldCBpMiA9IHN0YXJ0OyBpMiA8IGVuZDsgaTIgKz0gZGltKSBsYXN0ID0gaW5zZXJ0Tm9kZShpMiAvIGRpbSB8IDAsIGRhdGFbaTJdLCBkYXRhW2kyICsgMV0sIGxhc3QpOwogICAgfSBlbHNlIHsKICAgICAgZm9yIChsZXQgaTIgPSBlbmQgLSBkaW07IGkyID49IHN0YXJ0OyBpMiAtPSBkaW0pIGxhc3QgPSBpbnNlcnROb2RlKGkyIC8gZGltIHwgMCwgZGF0YVtpMl0sIGRhdGFbaTIgKyAxXSwgbGFzdCk7CiAgICB9CiAgICBpZiAobGFzdCAmJiBlcXVhbHMobGFzdCwgbGFzdC5uZXh0KSkgewogICAgICByZW1vdmVOb2RlKGxhc3QpOwogICAgICBsYXN0ID0gbGFzdC5uZXh0OwogICAgfQogICAgcmV0dXJuIGxhc3Q7CiAgfQogIGZ1bmN0aW9uIGZpbHRlclBvaW50cyhzdGFydCwgZW5kKSB7CiAgICBpZiAoIXN0YXJ0KSByZXR1cm4gc3RhcnQ7CiAgICBpZiAoIWVuZCkgZW5kID0gc3RhcnQ7CiAgICBsZXQgcDIgPSBzdGFydCwgYWdhaW47CiAgICBkbyB7CiAgICAgIGFnYWluID0gZmFsc2U7CiAgICAgIGlmICghcDIuc3RlaW5lciAmJiAoZXF1YWxzKHAyLCBwMi5uZXh0KSB8fCBhcmVhKHAyLnByZXYsIHAyLCBwMi5uZXh0KSA9PT0gMCkpIHsKICAgICAgICByZW1vdmVOb2RlKHAyKTsKICAgICAgICBwMiA9IGVuZCA9IHAyLnByZXY7CiAgICAgICAgaWYgKHAyID09PSBwMi5uZXh0KSBicmVhazsKICAgICAgICBhZ2FpbiA9IHRydWU7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgcDIgPSBwMi5uZXh0OwogICAgICB9CiAgICB9IHdoaWxlIChhZ2FpbiB8fCBwMiAhPT0gZW5kKTsKICAgIHJldHVybiBlbmQ7CiAgfQogIGZ1bmN0aW9uIGVhcmN1dExpbmtlZChlYXIsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCBwYXNzKSB7CiAgICBpZiAoIWVhcikgcmV0dXJuOwogICAgaWYgKCFwYXNzICYmIGludlNpemUpIGluZGV4Q3VydmUoZWFyLCBtaW5YLCBtaW5ZLCBpbnZTaXplKTsKICAgIGxldCBzdG9wID0gZWFyOwogICAgd2hpbGUgKGVhci5wcmV2ICE9PSBlYXIubmV4dCkgewogICAgICBjb25zdCBwcmV2ID0gZWFyLnByZXY7CiAgICAgIGNvbnN0IG5leHQgPSBlYXIubmV4dDsKICAgICAgaWYgKGludlNpemUgPyBpc0Vhckhhc2hlZChlYXIsIG1pblgsIG1pblksIGludlNpemUpIDogaXNFYXIoZWFyKSkgewogICAgICAgIHRyaWFuZ2xlcy5wdXNoKHByZXYuaSwgZWFyLmksIG5leHQuaSk7CiAgICAgICAgcmVtb3ZlTm9kZShlYXIpOwogICAgICAgIGVhciA9IG5leHQubmV4dDsKICAgICAgICBzdG9wID0gbmV4dC5uZXh0OwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGVhciA9IG5leHQ7CiAgICAgIGlmIChlYXIgPT09IHN0b3ApIHsKICAgICAgICBpZiAoIXBhc3MpIHsKICAgICAgICAgIGVhcmN1dExpbmtlZChmaWx0ZXJQb2ludHMoZWFyKSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDEpOwogICAgICAgIH0gZWxzZSBpZiAocGFzcyA9PT0gMSkgewogICAgICAgICAgZWFyID0gY3VyZUxvY2FsSW50ZXJzZWN0aW9ucyhmaWx0ZXJQb2ludHMoZWFyKSwgdHJpYW5nbGVzKTsKICAgICAgICAgIGVhcmN1dExpbmtlZChlYXIsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAyKTsKICAgICAgICB9IGVsc2UgaWYgKHBhc3MgPT09IDIpIHsKICAgICAgICAgIHNwbGl0RWFyY3V0KGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUpOwogICAgICAgIH0KICAgICAgICBicmVhazsKICAgICAgfQogICAgfQogIH0KICBmdW5jdGlvbiBpc0VhcihlYXIpIHsKICAgIGNvbnN0IGE0ID0gZWFyLnByZXYsIGIyID0gZWFyLCBjMiA9IGVhci5uZXh0OwogICAgaWYgKGFyZWEoYTQsIGIyLCBjMikgPj0gMCkgcmV0dXJuIGZhbHNlOwogICAgY29uc3QgYXggPSBhNC54LCBieCA9IGIyLngsIGN4ID0gYzIueCwgYXkgPSBhNC55LCBieSA9IGIyLnksIGN5ID0gYzIueTsKICAgIGNvbnN0IHgwID0gTWF0aC5taW4oYXgsIGJ4LCBjeCksIHkwID0gTWF0aC5taW4oYXksIGJ5LCBjeSksIHgxID0gTWF0aC5tYXgoYXgsIGJ4LCBjeCksIHkxID0gTWF0aC5tYXgoYXksIGJ5LCBjeSk7CiAgICBsZXQgcDIgPSBjMi5uZXh0OwogICAgd2hpbGUgKHAyICE9PSBhNCkgewogICAgICBpZiAocDIueCA+PSB4MCAmJiBwMi54IDw9IHgxICYmIHAyLnkgPj0geTAgJiYgcDIueSA8PSB5MSAmJiBwb2ludEluVHJpYW5nbGVFeGNlcHRGaXJzdChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBwMi54LCBwMi55KSAmJiBhcmVhKHAyLnByZXYsIHAyLCBwMi5uZXh0KSA+PSAwKSByZXR1cm4gZmFsc2U7CiAgICAgIHAyID0gcDIubmV4dDsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KICBmdW5jdGlvbiBpc0Vhckhhc2hlZChlYXIsIG1pblgsIG1pblksIGludlNpemUpIHsKICAgIGNvbnN0IGE0ID0gZWFyLnByZXYsIGIyID0gZWFyLCBjMiA9IGVhci5uZXh0OwogICAgaWYgKGFyZWEoYTQsIGIyLCBjMikgPj0gMCkgcmV0dXJuIGZhbHNlOwogICAgY29uc3QgYXggPSBhNC54LCBieCA9IGIyLngsIGN4ID0gYzIueCwgYXkgPSBhNC55LCBieSA9IGIyLnksIGN5ID0gYzIueTsKICAgIGNvbnN0IHgwID0gTWF0aC5taW4oYXgsIGJ4LCBjeCksIHkwID0gTWF0aC5taW4oYXksIGJ5LCBjeSksIHgxID0gTWF0aC5tYXgoYXgsIGJ4LCBjeCksIHkxID0gTWF0aC5tYXgoYXksIGJ5LCBjeSk7CiAgICBjb25zdCBtaW5aID0gek9yZGVyKHgwLCB5MCwgbWluWCwgbWluWSwgaW52U2l6ZSksIG1heFogPSB6T3JkZXIoeDEsIHkxLCBtaW5YLCBtaW5ZLCBpbnZTaXplKTsKICAgIGxldCBwMiA9IGVhci5wcmV2WiwgbjIgPSBlYXIubmV4dFo7CiAgICB3aGlsZSAocDIgJiYgcDIueiA+PSBtaW5aICYmIG4yICYmIG4yLnogPD0gbWF4WikgewogICAgICBpZiAocDIueCA+PSB4MCAmJiBwMi54IDw9IHgxICYmIHAyLnkgPj0geTAgJiYgcDIueSA8PSB5MSAmJiBwMiAhPT0gYTQgJiYgcDIgIT09IGMyICYmIHBvaW50SW5UcmlhbmdsZUV4Y2VwdEZpcnN0KGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAyLngsIHAyLnkpICYmIGFyZWEocDIucHJldiwgcDIsIHAyLm5leHQpID49IDApIHJldHVybiBmYWxzZTsKICAgICAgcDIgPSBwMi5wcmV2WjsKICAgICAgaWYgKG4yLnggPj0geDAgJiYgbjIueCA8PSB4MSAmJiBuMi55ID49IHkwICYmIG4yLnkgPD0geTEgJiYgbjIgIT09IGE0ICYmIG4yICE9PSBjMiAmJiBwb2ludEluVHJpYW5nbGVFeGNlcHRGaXJzdChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBuMi54LCBuMi55KSAmJiBhcmVhKG4yLnByZXYsIG4yLCBuMi5uZXh0KSA+PSAwKSByZXR1cm4gZmFsc2U7CiAgICAgIG4yID0gbjIubmV4dFo7CiAgICB9CiAgICB3aGlsZSAocDIgJiYgcDIueiA+PSBtaW5aKSB7CiAgICAgIGlmIChwMi54ID49IHgwICYmIHAyLnggPD0geDEgJiYgcDIueSA+PSB5MCAmJiBwMi55IDw9IHkxICYmIHAyICE9PSBhNCAmJiBwMiAhPT0gYzIgJiYgcG9pbnRJblRyaWFuZ2xlRXhjZXB0Rmlyc3QoYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcDIueCwgcDIueSkgJiYgYXJlYShwMi5wcmV2LCBwMiwgcDIubmV4dCkgPj0gMCkgcmV0dXJuIGZhbHNlOwogICAgICBwMiA9IHAyLnByZXZaOwogICAgfQogICAgd2hpbGUgKG4yICYmIG4yLnogPD0gbWF4WikgewogICAgICBpZiAobjIueCA+PSB4MCAmJiBuMi54IDw9IHgxICYmIG4yLnkgPj0geTAgJiYgbjIueSA8PSB5MSAmJiBuMiAhPT0gYTQgJiYgbjIgIT09IGMyICYmIHBvaW50SW5UcmlhbmdsZUV4Y2VwdEZpcnN0KGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIG4yLngsIG4yLnkpICYmIGFyZWEobjIucHJldiwgbjIsIG4yLm5leHQpID49IDApIHJldHVybiBmYWxzZTsKICAgICAgbjIgPSBuMi5uZXh0WjsKICAgIH0KICAgIHJldHVybiB0cnVlOwogIH0KICBmdW5jdGlvbiBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKHN0YXJ0LCB0cmlhbmdsZXMpIHsKICAgIGxldCBwMiA9IHN0YXJ0OwogICAgZG8gewogICAgICBjb25zdCBhNCA9IHAyLnByZXYsIGIyID0gcDIubmV4dC5uZXh0OwogICAgICBpZiAoIWVxdWFscyhhNCwgYjIpICYmIGludGVyc2VjdHMoYTQsIHAyLCBwMi5uZXh0LCBiMikgJiYgbG9jYWxseUluc2lkZShhNCwgYjIpICYmIGxvY2FsbHlJbnNpZGUoYjIsIGE0KSkgewogICAgICAgIHRyaWFuZ2xlcy5wdXNoKGE0LmksIHAyLmksIGIyLmkpOwogICAgICAgIHJlbW92ZU5vZGUocDIpOwogICAgICAgIHJlbW92ZU5vZGUocDIubmV4dCk7CiAgICAgICAgcDIgPSBzdGFydCA9IGIyOwogICAgICB9CiAgICAgIHAyID0gcDIubmV4dDsKICAgIH0gd2hpbGUgKHAyICE9PSBzdGFydCk7CiAgICByZXR1cm4gZmlsdGVyUG9pbnRzKHAyKTsKICB9CiAgZnVuY3Rpb24gc3BsaXRFYXJjdXQoc3RhcnQsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplKSB7CiAgICBsZXQgYTQgPSBzdGFydDsKICAgIGRvIHsKICAgICAgbGV0IGIyID0gYTQubmV4dC5uZXh0OwogICAgICB3aGlsZSAoYjIgIT09IGE0LnByZXYpIHsKICAgICAgICBpZiAoYTQuaSAhPT0gYjIuaSAmJiBpc1ZhbGlkRGlhZ29uYWwoYTQsIGIyKSkgewogICAgICAgICAgbGV0IGMyID0gc3BsaXRQb2x5Z29uKGE0LCBiMik7CiAgICAgICAgICBhNCA9IGZpbHRlclBvaW50cyhhNCwgYTQubmV4dCk7CiAgICAgICAgICBjMiA9IGZpbHRlclBvaW50cyhjMiwgYzIubmV4dCk7CiAgICAgICAgICBlYXJjdXRMaW5rZWQoYTQsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwKTsKICAgICAgICAgIGVhcmN1dExpbmtlZChjMiwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDApOwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBiMiA9IGIyLm5leHQ7CiAgICAgIH0KICAgICAgYTQgPSBhNC5uZXh0OwogICAgfSB3aGlsZSAoYTQgIT09IHN0YXJ0KTsKICB9CiAgZnVuY3Rpb24gZWxpbWluYXRlSG9sZXMoZGF0YSwgaG9sZUluZGljZXMsIG91dGVyTm9kZSwgZGltKSB7CiAgICBjb25zdCBxdWV1ZSA9IFtdOwogICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSBob2xlSW5kaWNlcy5sZW5ndGg7IGkyIDwgbGVuOyBpMisrKSB7CiAgICAgIGNvbnN0IHN0YXJ0ID0gaG9sZUluZGljZXNbaTJdICogZGltOwogICAgICBjb25zdCBlbmQgPSBpMiA8IGxlbiAtIDEgPyBob2xlSW5kaWNlc1tpMiArIDFdICogZGltIDogZGF0YS5sZW5ndGg7CiAgICAgIGNvbnN0IGxpc3QgPSBsaW5rZWRMaXN0KGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSwgZmFsc2UpOwogICAgICBpZiAobGlzdCA9PT0gbGlzdC5uZXh0KSBsaXN0LnN0ZWluZXIgPSB0cnVlOwogICAgICBxdWV1ZS5wdXNoKGdldExlZnRtb3N0KGxpc3QpKTsKICAgIH0KICAgIHF1ZXVlLnNvcnQoY29tcGFyZVhZU2xvcGUpOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHF1ZXVlLmxlbmd0aDsgaTIrKykgewogICAgICBvdXRlck5vZGUgPSBlbGltaW5hdGVIb2xlKHF1ZXVlW2kyXSwgb3V0ZXJOb2RlKTsKICAgIH0KICAgIHJldHVybiBvdXRlck5vZGU7CiAgfQogIGZ1bmN0aW9uIGNvbXBhcmVYWVNsb3BlKGE0LCBiMikgewogICAgbGV0IHJlc3VsdCA9IGE0LnggLSBiMi54OwogICAgaWYgKHJlc3VsdCA9PT0gMCkgewogICAgICByZXN1bHQgPSBhNC55IC0gYjIueTsKICAgICAgaWYgKHJlc3VsdCA9PT0gMCkgewogICAgICAgIGNvbnN0IGFTbG9wZSA9IChhNC5uZXh0LnkgLSBhNC55KSAvIChhNC5uZXh0LnggLSBhNC54KTsKICAgICAgICBjb25zdCBiU2xvcGUgPSAoYjIubmV4dC55IC0gYjIueSkgLyAoYjIubmV4dC54IC0gYjIueCk7CiAgICAgICAgcmVzdWx0ID0gYVNsb3BlIC0gYlNsb3BlOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBlbGltaW5hdGVIb2xlKGhvbGUsIG91dGVyTm9kZSkgewogICAgY29uc3QgYnJpZGdlID0gZmluZEhvbGVCcmlkZ2UoaG9sZSwgb3V0ZXJOb2RlKTsKICAgIGlmICghYnJpZGdlKSB7CiAgICAgIHJldHVybiBvdXRlck5vZGU7CiAgICB9CiAgICBjb25zdCBicmlkZ2VSZXZlcnNlID0gc3BsaXRQb2x5Z29uKGJyaWRnZSwgaG9sZSk7CiAgICBmaWx0ZXJQb2ludHMoYnJpZGdlUmV2ZXJzZSwgYnJpZGdlUmV2ZXJzZS5uZXh0KTsKICAgIHJldHVybiBmaWx0ZXJQb2ludHMoYnJpZGdlLCBicmlkZ2UubmV4dCk7CiAgfQogIGZ1bmN0aW9uIGZpbmRIb2xlQnJpZGdlKGhvbGUsIG91dGVyTm9kZSkgewogICAgbGV0IHAyID0gb3V0ZXJOb2RlOwogICAgY29uc3QgaHggPSBob2xlLng7CiAgICBjb25zdCBoeSA9IGhvbGUueTsKICAgIGxldCBxeCA9IC1JbmZpbml0eTsKICAgIGxldCBtMjsKICAgIGlmIChlcXVhbHMoaG9sZSwgcDIpKSByZXR1cm4gcDI7CiAgICBkbyB7CiAgICAgIGlmIChlcXVhbHMoaG9sZSwgcDIubmV4dCkpIHJldHVybiBwMi5uZXh0OwogICAgICBlbHNlIGlmIChoeSA8PSBwMi55ICYmIGh5ID49IHAyLm5leHQueSAmJiBwMi5uZXh0LnkgIT09IHAyLnkpIHsKICAgICAgICBjb25zdCB4MiA9IHAyLnggKyAoaHkgLSBwMi55KSAqIChwMi5uZXh0LnggLSBwMi54KSAvIChwMi5uZXh0LnkgLSBwMi55KTsKICAgICAgICBpZiAoeDIgPD0gaHggJiYgeDIgPiBxeCkgewogICAgICAgICAgcXggPSB4MjsKICAgICAgICAgIG0yID0gcDIueCA8IHAyLm5leHQueCA/IHAyIDogcDIubmV4dDsKICAgICAgICAgIGlmICh4MiA9PT0gaHgpIHJldHVybiBtMjsKICAgICAgICB9CiAgICAgIH0KICAgICAgcDIgPSBwMi5uZXh0OwogICAgfSB3aGlsZSAocDIgIT09IG91dGVyTm9kZSk7CiAgICBpZiAoIW0yKSByZXR1cm4gbnVsbDsKICAgIGNvbnN0IHN0b3AgPSBtMjsKICAgIGNvbnN0IG14ID0gbTIueDsKICAgIGNvbnN0IG15ID0gbTIueTsKICAgIGxldCB0YW5NaW4gPSBJbmZpbml0eTsKICAgIHAyID0gbTI7CiAgICBkbyB7CiAgICAgIGlmIChoeCA+PSBwMi54ICYmIHAyLnggPj0gbXggJiYgaHggIT09IHAyLnggJiYgcG9pbnRJblRyaWFuZ2xlKGh5IDwgbXkgPyBoeCA6IHF4LCBoeSwgbXgsIG15LCBoeSA8IG15ID8gcXggOiBoeCwgaHksIHAyLngsIHAyLnkpKSB7CiAgICAgICAgY29uc3QgdGFuID0gTWF0aC5hYnMoaHkgLSBwMi55KSAvIChoeCAtIHAyLngpOwogICAgICAgIGlmIChsb2NhbGx5SW5zaWRlKHAyLCBob2xlKSAmJiAodGFuIDwgdGFuTWluIHx8IHRhbiA9PT0gdGFuTWluICYmIChwMi54ID4gbTIueCB8fCBwMi54ID09PSBtMi54ICYmIHNlY3RvckNvbnRhaW5zU2VjdG9yKG0yLCBwMikpKSkgewogICAgICAgICAgbTIgPSBwMjsKICAgICAgICAgIHRhbk1pbiA9IHRhbjsKICAgICAgICB9CiAgICAgIH0KICAgICAgcDIgPSBwMi5uZXh0OwogICAgfSB3aGlsZSAocDIgIT09IHN0b3ApOwogICAgcmV0dXJuIG0yOwogIH0KICBmdW5jdGlvbiBzZWN0b3JDb250YWluc1NlY3RvcihtMiwgcDIpIHsKICAgIHJldHVybiBhcmVhKG0yLnByZXYsIG0yLCBwMi5wcmV2KSA8IDAgJiYgYXJlYShwMi5uZXh0LCBtMiwgbTIubmV4dCkgPCAwOwogIH0KICBmdW5jdGlvbiBpbmRleEN1cnZlKHN0YXJ0LCBtaW5YLCBtaW5ZLCBpbnZTaXplKSB7CiAgICBsZXQgcDIgPSBzdGFydDsKICAgIGRvIHsKICAgICAgaWYgKHAyLnogPT09IDApIHAyLnogPSB6T3JkZXIocDIueCwgcDIueSwgbWluWCwgbWluWSwgaW52U2l6ZSk7CiAgICAgIHAyLnByZXZaID0gcDIucHJldjsKICAgICAgcDIubmV4dFogPSBwMi5uZXh0OwogICAgICBwMiA9IHAyLm5leHQ7CiAgICB9IHdoaWxlIChwMiAhPT0gc3RhcnQpOwogICAgcDIucHJldloubmV4dFogPSBudWxsOwogICAgcDIucHJldlogPSBudWxsOwogICAgc29ydExpbmtlZChwMik7CiAgfQogIGZ1bmN0aW9uIHNvcnRMaW5rZWQobGlzdCkgewogICAgbGV0IG51bU1lcmdlczsKICAgIGxldCBpblNpemUgPSAxOwogICAgZG8gewogICAgICBsZXQgcDIgPSBsaXN0OwogICAgICBsZXQgZTI7CiAgICAgIGxpc3QgPSBudWxsOwogICAgICBsZXQgdGFpbCA9IG51bGw7CiAgICAgIG51bU1lcmdlcyA9IDA7CiAgICAgIHdoaWxlIChwMikgewogICAgICAgIG51bU1lcmdlcysrOwogICAgICAgIGxldCBxMyA9IHAyOwogICAgICAgIGxldCBwU2l6ZSA9IDA7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGluU2l6ZTsgaTIrKykgewogICAgICAgICAgcFNpemUrKzsKICAgICAgICAgIHEzID0gcTMubmV4dFo7CiAgICAgICAgICBpZiAoIXEzKSBicmVhazsKICAgICAgICB9CiAgICAgICAgbGV0IHFTaXplID0gaW5TaXplOwogICAgICAgIHdoaWxlIChwU2l6ZSA+IDAgfHwgcVNpemUgPiAwICYmIHEzKSB7CiAgICAgICAgICBpZiAocFNpemUgIT09IDAgJiYgKHFTaXplID09PSAwIHx8ICFxMyB8fCBwMi56IDw9IHEzLnopKSB7CiAgICAgICAgICAgIGUyID0gcDI7CiAgICAgICAgICAgIHAyID0gcDIubmV4dFo7CiAgICAgICAgICAgIHBTaXplLS07CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBlMiA9IHEzOwogICAgICAgICAgICBxMyA9IHEzLm5leHRaOwogICAgICAgICAgICBxU2l6ZS0tOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHRhaWwpIHRhaWwubmV4dFogPSBlMjsKICAgICAgICAgIGVsc2UgbGlzdCA9IGUyOwogICAgICAgICAgZTIucHJldlogPSB0YWlsOwogICAgICAgICAgdGFpbCA9IGUyOwogICAgICAgIH0KICAgICAgICBwMiA9IHEzOwogICAgICB9CiAgICAgIHRhaWwubmV4dFogPSBudWxsOwogICAgICBpblNpemUgKj0gMjsKICAgIH0gd2hpbGUgKG51bU1lcmdlcyA+IDEpOwogICAgcmV0dXJuIGxpc3Q7CiAgfQogIGZ1bmN0aW9uIHpPcmRlcih4MiwgeTIsIG1pblgsIG1pblksIGludlNpemUpIHsKICAgIHgyID0gKHgyIC0gbWluWCkgKiBpbnZTaXplIHwgMDsKICAgIHkyID0gKHkyIC0gbWluWSkgKiBpbnZTaXplIHwgMDsKICAgIHgyID0gKHgyIHwgeDIgPDwgOCkgJiAxNjcxMTkzNTsKICAgIHgyID0gKHgyIHwgeDIgPDwgNCkgJiAyNTI2NDUxMzU7CiAgICB4MiA9ICh4MiB8IHgyIDw8IDIpICYgODU4OTkzNDU5OwogICAgeDIgPSAoeDIgfCB4MiA8PCAxKSAmIDE0MzE2NTU3NjU7CiAgICB5MiA9ICh5MiB8IHkyIDw8IDgpICYgMTY3MTE5MzU7CiAgICB5MiA9ICh5MiB8IHkyIDw8IDQpICYgMjUyNjQ1MTM1OwogICAgeTIgPSAoeTIgfCB5MiA8PCAyKSAmIDg1ODk5MzQ1OTsKICAgIHkyID0gKHkyIHwgeTIgPDwgMSkgJiAxNDMxNjU1NzY1OwogICAgcmV0dXJuIHgyIHwgeTIgPDwgMTsKICB9CiAgZnVuY3Rpb24gZ2V0TGVmdG1vc3Qoc3RhcnQpIHsKICAgIGxldCBwMiA9IHN0YXJ0LCBsZWZ0bW9zdCA9IHN0YXJ0OwogICAgZG8gewogICAgICBpZiAocDIueCA8IGxlZnRtb3N0LnggfHwgcDIueCA9PT0gbGVmdG1vc3QueCAmJiBwMi55IDwgbGVmdG1vc3QueSkgbGVmdG1vc3QgPSBwMjsKICAgICAgcDIgPSBwMi5uZXh0OwogICAgfSB3aGlsZSAocDIgIT09IHN0YXJ0KTsKICAgIHJldHVybiBsZWZ0bW9zdDsKICB9CiAgZnVuY3Rpb24gcG9pbnRJblRyaWFuZ2xlKGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSkgewogICAgcmV0dXJuIChjeCAtIHB4KSAqIChheSAtIHB5KSA+PSAoYXggLSBweCkgKiAoY3kgLSBweSkgJiYgKGF4IC0gcHgpICogKGJ5IC0gcHkpID49IChieCAtIHB4KSAqIChheSAtIHB5KSAmJiAoYnggLSBweCkgKiAoY3kgLSBweSkgPj0gKGN4IC0gcHgpICogKGJ5IC0gcHkpOwogIH0KICBmdW5jdGlvbiBwb2ludEluVHJpYW5nbGVFeGNlcHRGaXJzdChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBweCwgcHkpIHsKICAgIHJldHVybiAhKGF4ID09PSBweCAmJiBheSA9PT0gcHkpICYmIHBvaW50SW5UcmlhbmdsZShheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBweCwgcHkpOwogIH0KICBmdW5jdGlvbiBpc1ZhbGlkRGlhZ29uYWwoYTQsIGIyKSB7CiAgICByZXR1cm4gYTQubmV4dC5pICE9PSBiMi5pICYmIGE0LnByZXYuaSAhPT0gYjIuaSAmJiAhaW50ZXJzZWN0c1BvbHlnb24oYTQsIGIyKSAmJiAvLyBkb2Vzbid0IGludGVyc2VjdCBvdGhlciBlZGdlcwogICAgKGxvY2FsbHlJbnNpZGUoYTQsIGIyKSAmJiBsb2NhbGx5SW5zaWRlKGIyLCBhNCkgJiYgbWlkZGxlSW5zaWRlKGE0LCBiMikgJiYgLy8gbG9jYWxseSB2aXNpYmxlCiAgICAoYXJlYShhNC5wcmV2LCBhNCwgYjIucHJldikgfHwgYXJlYShhNCwgYjIucHJldiwgYjIpKSB8fCAvLyBkb2VzIG5vdCBjcmVhdGUgb3Bwb3NpdGUtZmFjaW5nIHNlY3RvcnMKICAgIGVxdWFscyhhNCwgYjIpICYmIGFyZWEoYTQucHJldiwgYTQsIGE0Lm5leHQpID4gMCAmJiBhcmVhKGIyLnByZXYsIGIyLCBiMi5uZXh0KSA+IDApOwogIH0KICBmdW5jdGlvbiBhcmVhKHAyLCBxMywgcjIpIHsKICAgIHJldHVybiAocTMueSAtIHAyLnkpICogKHIyLnggLSBxMy54KSAtIChxMy54IC0gcDIueCkgKiAocjIueSAtIHEzLnkpOwogIH0KICBmdW5jdGlvbiBlcXVhbHMocDEsIHAyKSB7CiAgICByZXR1cm4gcDEueCA9PT0gcDIueCAmJiBwMS55ID09PSBwMi55OwogIH0KICBmdW5jdGlvbiBpbnRlcnNlY3RzKHAxLCBxMTIsIHAyLCBxMjIpIHsKICAgIGNvbnN0IG8xID0gc2lnbjIoYXJlYShwMSwgcTEyLCBwMikpOwogICAgY29uc3QgbzIgPSBzaWduMihhcmVhKHAxLCBxMTIsIHEyMikpOwogICAgY29uc3QgbzMgPSBzaWduMihhcmVhKHAyLCBxMjIsIHAxKSk7CiAgICBjb25zdCBvNCA9IHNpZ24yKGFyZWEocDIsIHEyMiwgcTEyKSk7CiAgICBpZiAobzEgIT09IG8yICYmIG8zICE9PSBvNCkgcmV0dXJuIHRydWU7CiAgICBpZiAobzEgPT09IDAgJiYgb25TZWdtZW50KHAxLCBwMiwgcTEyKSkgcmV0dXJuIHRydWU7CiAgICBpZiAobzIgPT09IDAgJiYgb25TZWdtZW50KHAxLCBxMjIsIHExMikpIHJldHVybiB0cnVlOwogICAgaWYgKG8zID09PSAwICYmIG9uU2VnbWVudChwMiwgcDEsIHEyMikpIHJldHVybiB0cnVlOwogICAgaWYgKG80ID09PSAwICYmIG9uU2VnbWVudChwMiwgcTEyLCBxMjIpKSByZXR1cm4gdHJ1ZTsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgZnVuY3Rpb24gb25TZWdtZW50KHAyLCBxMywgcjIpIHsKICAgIHJldHVybiBxMy54IDw9IE1hdGgubWF4KHAyLngsIHIyLngpICYmIHEzLnggPj0gTWF0aC5taW4ocDIueCwgcjIueCkgJiYgcTMueSA8PSBNYXRoLm1heChwMi55LCByMi55KSAmJiBxMy55ID49IE1hdGgubWluKHAyLnksIHIyLnkpOwogIH0KICBmdW5jdGlvbiBzaWduMihudW0pIHsKICAgIHJldHVybiBudW0gPiAwID8gMSA6IG51bSA8IDAgPyAtMSA6IDA7CiAgfQogIGZ1bmN0aW9uIGludGVyc2VjdHNQb2x5Z29uKGE0LCBiMikgewogICAgbGV0IHAyID0gYTQ7CiAgICBkbyB7CiAgICAgIGlmIChwMi5pICE9PSBhNC5pICYmIHAyLm5leHQuaSAhPT0gYTQuaSAmJiBwMi5pICE9PSBiMi5pICYmIHAyLm5leHQuaSAhPT0gYjIuaSAmJiBpbnRlcnNlY3RzKHAyLCBwMi5uZXh0LCBhNCwgYjIpKSByZXR1cm4gdHJ1ZTsKICAgICAgcDIgPSBwMi5uZXh0OwogICAgfSB3aGlsZSAocDIgIT09IGE0KTsKICAgIHJldHVybiBmYWxzZTsKICB9CiAgZnVuY3Rpb24gbG9jYWxseUluc2lkZShhNCwgYjIpIHsKICAgIHJldHVybiBhcmVhKGE0LnByZXYsIGE0LCBhNC5uZXh0KSA8IDAgPyBhcmVhKGE0LCBiMiwgYTQubmV4dCkgPj0gMCAmJiBhcmVhKGE0LCBhNC5wcmV2LCBiMikgPj0gMCA6IGFyZWEoYTQsIGIyLCBhNC5wcmV2KSA8IDAgfHwgYXJlYShhNCwgYTQubmV4dCwgYjIpIDwgMDsKICB9CiAgZnVuY3Rpb24gbWlkZGxlSW5zaWRlKGE0LCBiMikgewogICAgbGV0IHAyID0gYTQ7CiAgICBsZXQgaW5zaWRlMiA9IGZhbHNlOwogICAgY29uc3QgcHggPSAoYTQueCArIGIyLngpIC8gMjsKICAgIGNvbnN0IHB5ID0gKGE0LnkgKyBiMi55KSAvIDI7CiAgICBkbyB7CiAgICAgIGlmIChwMi55ID4gcHkgIT09IHAyLm5leHQueSA+IHB5ICYmIHAyLm5leHQueSAhPT0gcDIueSAmJiBweCA8IChwMi5uZXh0LnggLSBwMi54KSAqIChweSAtIHAyLnkpIC8gKHAyLm5leHQueSAtIHAyLnkpICsgcDIueCkKICAgICAgICBpbnNpZGUyID0gIWluc2lkZTI7CiAgICAgIHAyID0gcDIubmV4dDsKICAgIH0gd2hpbGUgKHAyICE9PSBhNCk7CiAgICByZXR1cm4gaW5zaWRlMjsKICB9CiAgZnVuY3Rpb24gc3BsaXRQb2x5Z29uKGE0LCBiMikgewogICAgY29uc3QgYTIyID0gY3JlYXRlTm9kZShhNC5pLCBhNC54LCBhNC55KSwgYjIyID0gY3JlYXRlTm9kZShiMi5pLCBiMi54LCBiMi55KSwgYW4gPSBhNC5uZXh0LCBicCA9IGIyLnByZXY7CiAgICBhNC5uZXh0ID0gYjI7CiAgICBiMi5wcmV2ID0gYTQ7CiAgICBhMjIubmV4dCA9IGFuOwogICAgYW4ucHJldiA9IGEyMjsKICAgIGIyMi5uZXh0ID0gYTIyOwogICAgYTIyLnByZXYgPSBiMjI7CiAgICBicC5uZXh0ID0gYjIyOwogICAgYjIyLnByZXYgPSBicDsKICAgIHJldHVybiBiMjI7CiAgfQogIGZ1bmN0aW9uIGluc2VydE5vZGUoaTIsIHgyLCB5MiwgbGFzdCkgewogICAgY29uc3QgcDIgPSBjcmVhdGVOb2RlKGkyLCB4MiwgeTIpOwogICAgaWYgKCFsYXN0KSB7CiAgICAgIHAyLnByZXYgPSBwMjsKICAgICAgcDIubmV4dCA9IHAyOwogICAgfSBlbHNlIHsKICAgICAgcDIubmV4dCA9IGxhc3QubmV4dDsKICAgICAgcDIucHJldiA9IGxhc3Q7CiAgICAgIGxhc3QubmV4dC5wcmV2ID0gcDI7CiAgICAgIGxhc3QubmV4dCA9IHAyOwogICAgfQogICAgcmV0dXJuIHAyOwogIH0KICBmdW5jdGlvbiByZW1vdmVOb2RlKHAyKSB7CiAgICBwMi5uZXh0LnByZXYgPSBwMi5wcmV2OwogICAgcDIucHJldi5uZXh0ID0gcDIubmV4dDsKICAgIGlmIChwMi5wcmV2WikgcDIucHJldloubmV4dFogPSBwMi5uZXh0WjsKICAgIGlmIChwMi5uZXh0WikgcDIubmV4dFoucHJldlogPSBwMi5wcmV2WjsKICB9CiAgZnVuY3Rpb24gY3JlYXRlTm9kZShpMiwgeDIsIHkyKSB7CiAgICByZXR1cm4gewogICAgICBpOiBpMiwKICAgICAgLy8gdmVydGV4IGluZGV4IGluIGNvb3JkaW5hdGVzIGFycmF5CiAgICAgIHg6IHgyLAogICAgICB5OiB5MiwKICAgICAgLy8gdmVydGV4IGNvb3JkaW5hdGVzCiAgICAgIHByZXY6IG51bGwsCiAgICAgIC8vIHByZXZpb3VzIGFuZCBuZXh0IHZlcnRleCBub2RlcyBpbiBhIHBvbHlnb24gcmluZwogICAgICBuZXh0OiBudWxsLAogICAgICB6OiAwLAogICAgICAvLyB6LW9yZGVyIGN1cnZlIHZhbHVlCiAgICAgIHByZXZaOiBudWxsLAogICAgICAvLyBwcmV2aW91cyBhbmQgbmV4dCBub2RlcyBpbiB6LW9yZGVyCiAgICAgIG5leHRaOiBudWxsLAogICAgICBzdGVpbmVyOiBmYWxzZQogICAgICAvLyBpbmRpY2F0ZXMgd2hldGhlciB0aGlzIGlzIGEgc3RlaW5lciBwb2ludAogICAgfTsKICB9CiAgZnVuY3Rpb24gc2lnbmVkQXJlYShkYXRhLCBzdGFydCwgZW5kLCBkaW0pIHsKICAgIGxldCBzdW0gPSAwOwogICAgZm9yIChsZXQgaTIgPSBzdGFydCwgajIgPSBlbmQgLSBkaW07IGkyIDwgZW5kOyBpMiArPSBkaW0pIHsKICAgICAgc3VtICs9IChkYXRhW2oyXSAtIGRhdGFbaTJdKSAqIChkYXRhW2kyICsgMV0gKyBkYXRhW2oyICsgMV0pOwogICAgICBqMiA9IGkyOwogICAgfQogICAgcmV0dXJuIHN1bTsKICB9CiAgdmFyIGluaXRfZWFyY3V0ID0gX19lc20oewogICAgIm5vZGVfbW9kdWxlcy9lYXJjdXQvc3JjL2VhcmN1dC5qcyIoKSB7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9XaW5kaW5nT3JkZXIuanMKICB2YXIgV2luZGluZ09yZGVyLCBXaW5kaW5nT3JkZXJfZGVmYXVsdDsKICB2YXIgaW5pdF9XaW5kaW5nT3JkZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1dpbmRpbmdPcmRlci5qcyIoKSB7CiAgICAgIGluaXRfV2ViR0xDb25zdGFudHMoKTsKICAgICAgV2luZGluZ09yZGVyID0gewogICAgICAgIC8qKgogICAgICAgICAqIFZlcnRpY2VzIGFyZSBpbiBjbG9ja3dpc2Ugb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIENMT0NLV0lTRTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DVywKICAgICAgICAvKioKICAgICAgICAgKiBWZXJ0aWNlcyBhcmUgaW4gY291bnRlci1jbG9ja3dpc2Ugb3JkZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIENPVU5URVJfQ0xPQ0tXSVNFOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkNDVwogICAgICB9OwogICAgICBXaW5kaW5nT3JkZXIudmFsaWRhdGUgPSBmdW5jdGlvbih3aW5kaW5nT3JkZXIpIHsKICAgICAgICByZXR1cm4gd2luZGluZ09yZGVyID09PSBXaW5kaW5nT3JkZXIuQ0xPQ0tXSVNFIHx8IHdpbmRpbmdPcmRlciA9PT0gV2luZGluZ09yZGVyLkNPVU5URVJfQ0xPQ0tXSVNFOwogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKFdpbmRpbmdPcmRlcik7CiAgICAgIFdpbmRpbmdPcmRlcl9kZWZhdWx0ID0gV2luZGluZ09yZGVyOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWdvblBpcGVsaW5lLmpzCiAgdmFyIHNjYWxlVG9HZW9kZXRpY0hlaWdodE4sIHNjYWxlVG9HZW9kZXRpY0hlaWdodFAsIFBvbHlnb25QaXBlbGluZSwgc3ViZGl2aXNpb25WMFNjcmF0Y2gsIHN1YmRpdmlzaW9uVjFTY3JhdGNoLCBzdWJkaXZpc2lvblYyU2NyYXRjaCwgc3ViZGl2aXNpb25TMFNjcmF0Y2gsIHN1YmRpdmlzaW9uUzFTY3JhdGNoLCBzdWJkaXZpc2lvblMyU2NyYXRjaCwgc3ViZGl2aXNpb25NaWRTY3JhdGNoLCBzdWJkaXZpc2lvblQwU2NyYXRjaCwgc3ViZGl2aXNpb25UMVNjcmF0Y2gsIHN1YmRpdmlzaW9uVDJTY3JhdGNoLCBzdWJkaXZpc2lvblRleGNvb3JkTWlkU2NyYXRjaCwgc3ViZGl2aXNpb25DMFNjcmF0Y2gsIHN1YmRpdmlzaW9uQzFTY3JhdGNoLCBzdWJkaXZpc2lvbkMyU2NyYXRjaCwgc3ViZGl2aXNpb25DYXJ0b2dyYXBoaWNTY3JhdGNoLCBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdDsKICB2YXIgaW5pdF9Qb2x5Z29uUGlwZWxpbmUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlnb25QaXBlbGluZS5qcyIoKSB7CiAgICAgIGluaXRfZWFyY3V0KCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZFJodW1iTGluZSgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1dpbmRpbmdPcmRlcigpOwogICAgICBzY2FsZVRvR2VvZGV0aWNIZWlnaHROID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY2FsZVRvR2VvZGV0aWNIZWlnaHRQID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBQb2x5Z29uUGlwZWxpbmUgPSB7fTsKICAgICAgUG9seWdvblBpcGVsaW5lLmNvbXB1dGVBcmVhMkQgPSBmdW5jdGlvbihwb3NpdGlvbnMpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoCiAgICAgICAgICAicG9zaXRpb25zLmxlbmd0aCIsCiAgICAgICAgICBwb3NpdGlvbnMubGVuZ3RoLAogICAgICAgICAgMwogICAgICAgICk7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBsZXQgYXJlYTIgPSAwOwogICAgICAgIGZvciAobGV0IGkwID0gbGVuZ3RoIC0gMSwgaTEgPSAwOyBpMSA8IGxlbmd0aDsgaTAgPSBpMSsrKSB7CiAgICAgICAgICBjb25zdCB2MDIgPSBwb3NpdGlvbnNbaTBdOwogICAgICAgICAgY29uc3QgdjEyID0gcG9zaXRpb25zW2kxXTsKICAgICAgICAgIGFyZWEyICs9IHYwMi54ICogdjEyLnkgLSB2MTIueCAqIHYwMi55OwogICAgICAgIH0KICAgICAgICByZXR1cm4gYXJlYTIgKiAwLjU7CiAgICAgIH07CiAgICAgIFBvbHlnb25QaXBlbGluZS5jb21wdXRlV2luZGluZ09yZGVyMkQgPSBmdW5jdGlvbihwb3NpdGlvbnMpIHsKICAgICAgICBjb25zdCBhcmVhMiA9IFBvbHlnb25QaXBlbGluZS5jb21wdXRlQXJlYTJEKHBvc2l0aW9ucyk7CiAgICAgICAgcmV0dXJuIGFyZWEyID4gMCA/IFdpbmRpbmdPcmRlcl9kZWZhdWx0LkNPVU5URVJfQ0xPQ0tXSVNFIDogV2luZGluZ09yZGVyX2RlZmF1bHQuQ0xPQ0tXSVNFOwogICAgICB9OwogICAgICBQb2x5Z29uUGlwZWxpbmUudHJpYW5ndWxhdGUgPSBmdW5jdGlvbihwb3NpdGlvbnMsIGhvbGVzKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJwb3NpdGlvbnMiLCBwb3NpdGlvbnMpOwogICAgICAgIGNvbnN0IGZsYXR0ZW5lZFBvc2l0aW9ucyA9IENhcnRlc2lhbjJfZGVmYXVsdC5wYWNrQXJyYXkocG9zaXRpb25zKTsKICAgICAgICByZXR1cm4gZWFyY3V0KGZsYXR0ZW5lZFBvc2l0aW9ucywgaG9sZXMsIDIpOwogICAgICB9OwogICAgICBzdWJkaXZpc2lvblYwU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc3ViZGl2aXNpb25WMVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN1YmRpdmlzaW9uVjJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvblMwU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc3ViZGl2aXNpb25TMVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN1YmRpdmlzaW9uUzJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvbk1pZFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN1YmRpdmlzaW9uVDBTY3JhdGNoID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvblQxU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc3ViZGl2aXNpb25UMlNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHN1YmRpdmlzaW9uVGV4Y29vcmRNaWRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBQb2x5Z29uUGlwZWxpbmUuY29tcHV0ZVN1YmRpdmlzaW9uID0gZnVuY3Rpb24oZWxsaXBzb2lkLCBwb3NpdGlvbnMsIGluZGljZXMsIHRleGNvb3JkcywgZ3JhbnVsYXJpdHkpIHsKICAgICAgICBncmFudWxhcml0eSA9IGdyYW51bGFyaXR5ID8/IE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICAgICAgY29uc3QgaGFzVGV4Y29vcmRzID0gZGVmaW5lZF9kZWZhdWx0KHRleGNvb3Jkcyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJlbGxpcHNvaWQiLCBlbGxpcHNvaWQpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicG9zaXRpb25zIiwgcG9zaXRpb25zKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImluZGljZXMiLCBpbmRpY2VzKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiaW5kaWNlcy5sZW5ndGgiLCBpbmRpY2VzLmxlbmd0aCwgMyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmVxdWFscygiaW5kaWNlcy5sZW5ndGggJSAzIiwgIjAiLCBpbmRpY2VzLmxlbmd0aCAlIDMsIDApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbigiZ3JhbnVsYXJpdHkiLCBncmFudWxhcml0eSwgMCk7CiAgICAgICAgY29uc3QgdHJpYW5nbGVzID0gaW5kaWNlcy5zbGljZSgwKTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBjb25zdCBzdWJkaXZpZGVkUG9zaXRpb25zID0gbmV3IEFycmF5KGxlbmd0aCAqIDMpOwogICAgICAgIGNvbnN0IHN1YmRpdmlkZWRUZXhjb29yZHMgPSBuZXcgQXJyYXkobGVuZ3RoICogMik7CiAgICAgICAgbGV0IHEzID0gMDsKICAgICAgICBsZXQgcDIgPSAwOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgaXRlbSA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zW3EzKytdID0gaXRlbS54OwogICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1txMysrXSA9IGl0ZW0ueTsKICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbcTMrK10gPSBpdGVtLno7CiAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgIGNvbnN0IHRleGNvb3JkSXRlbSA9IHRleGNvb3Jkc1tpMl07CiAgICAgICAgICAgIHN1YmRpdmlkZWRUZXhjb29yZHNbcDIrK10gPSB0ZXhjb29yZEl0ZW0ueDsKICAgICAgICAgICAgc3ViZGl2aWRlZFRleGNvb3Jkc1twMisrXSA9IHRleGNvb3JkSXRlbS55OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBzdWJkaXZpZGVkSW5kaWNlcyA9IFtdOwogICAgICAgIGNvbnN0IGVkZ2VzID0ge307CiAgICAgICAgY29uc3QgcmFkaXVzID0gZWxsaXBzb2lkLm1heGltdW1SYWRpdXM7CiAgICAgICAgY29uc3QgbWluRGlzdGFuY2UgPSBNYXRoX2RlZmF1bHQuY2hvcmRMZW5ndGgoZ3JhbnVsYXJpdHksIHJhZGl1cyk7CiAgICAgICAgY29uc3QgbWluRGlzdGFuY2VTcXJkID0gbWluRGlzdGFuY2UgKiBtaW5EaXN0YW5jZTsKICAgICAgICB3aGlsZSAodHJpYW5nbGVzLmxlbmd0aCA+IDApIHsKICAgICAgICAgIGNvbnN0IGkyMiA9IHRyaWFuZ2xlcy5wb3AoKTsKICAgICAgICAgIGNvbnN0IGkxID0gdHJpYW5nbGVzLnBvcCgpOwogICAgICAgICAgY29uc3QgaTAgPSB0cmlhbmdsZXMucG9wKCk7CiAgICAgICAgICBjb25zdCB2MDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLAogICAgICAgICAgICBpMCAqIDMsCiAgICAgICAgICAgIHN1YmRpdmlzaW9uVjBTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgdjEyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucywKICAgICAgICAgICAgaTEgKiAzLAogICAgICAgICAgICBzdWJkaXZpc2lvblYxU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHYyMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMsCiAgICAgICAgICAgIGkyMiAqIDMsCiAgICAgICAgICAgIHN1YmRpdmlzaW9uVjJTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgbGV0IHQwLCB0MSwgdDI7CiAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgIHQwID0gQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzLAogICAgICAgICAgICAgIGkwICogMiwKICAgICAgICAgICAgICBzdWJkaXZpc2lvblQwU2NyYXRjaAogICAgICAgICAgICApOwogICAgICAgICAgICB0MSA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgICAgc3ViZGl2aWRlZFRleGNvb3JkcywKICAgICAgICAgICAgICBpMSAqIDIsCiAgICAgICAgICAgICAgc3ViZGl2aXNpb25UMVNjcmF0Y2gKICAgICAgICAgICAgKTsKICAgICAgICAgICAgdDIgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICAgIHN1YmRpdmlkZWRUZXhjb29yZHMsCiAgICAgICAgICAgICAgaTIyICogMiwKICAgICAgICAgICAgICBzdWJkaXZpc2lvblQyU2NyYXRjaAogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgczAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSh2MDIsIHN1YmRpdmlzaW9uUzBTY3JhdGNoKSwKICAgICAgICAgICAgcmFkaXVzLAogICAgICAgICAgICBzdWJkaXZpc2lvblMwU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHMxID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUodjEyLCBzdWJkaXZpc2lvblMxU2NyYXRjaCksCiAgICAgICAgICAgIHJhZGl1cywKICAgICAgICAgICAgc3ViZGl2aXNpb25TMVNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBzMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHYyMiwgc3ViZGl2aXNpb25TMlNjcmF0Y2gpLAogICAgICAgICAgICByYWRpdXMsCiAgICAgICAgICAgIHN1YmRpdmlzaW9uUzJTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgZzAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZCgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHMwLCBzMSwgc3ViZGl2aXNpb25NaWRTY3JhdGNoKQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IGcxID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChzMSwgczIsIHN1YmRpdmlzaW9uTWlkU2NyYXRjaCkKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBnMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGVTcXVhcmVkKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoczIsIHMwLCBzdWJkaXZpc2lvbk1pZFNjcmF0Y2gpCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgbWF4MyA9IE1hdGgubWF4KGcwLCBnMSwgZzIpOwogICAgICAgICAgbGV0IGVkZ2U7CiAgICAgICAgICBsZXQgbWlkOwogICAgICAgICAgbGV0IG1pZFRleGNvb3JkOwogICAgICAgICAgaWYgKG1heDMgPiBtaW5EaXN0YW5jZVNxcmQpIHsKICAgICAgICAgICAgaWYgKGcwID09PSBtYXgzKSB7CiAgICAgICAgICAgICAgZWRnZSA9IGAke01hdGgubWluKGkwLCBpMSl9ICR7TWF0aC5tYXgoaTAsIGkxKX1gOwogICAgICAgICAgICAgIGkyID0gZWRnZXNbZWRnZV07CiAgICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaTIpKSB7CiAgICAgICAgICAgICAgICBtaWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHYwMiwgdjEyLCBzdWJkaXZpc2lvbk1pZFNjcmF0Y2gpOwogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWlkLCAwLjUsIG1pZCk7CiAgICAgICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLnB1c2gobWlkLngsIG1pZC55LCBtaWQueik7CiAgICAgICAgICAgICAgICBpMiA9IHN1YmRpdmlkZWRQb3NpdGlvbnMubGVuZ3RoIC8gMyAtIDE7CiAgICAgICAgICAgICAgICBlZGdlc1tlZGdlXSA9IGkyOwogICAgICAgICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICAgICAgICBtaWRUZXhjb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5hZGQodDAsIHQxLCBzdWJkaXZpc2lvblRleGNvb3JkTWlkU2NyYXRjaCk7CiAgICAgICAgICAgICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG1pZFRleGNvb3JkLCAwLjUsIG1pZFRleGNvb3JkKTsKICAgICAgICAgICAgICAgICAgc3ViZGl2aWRlZFRleGNvb3Jkcy5wdXNoKG1pZFRleGNvb3JkLngsIG1pZFRleGNvb3JkLnkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB0cmlhbmdsZXMucHVzaChpMCwgaTIsIGkyMik7CiAgICAgICAgICAgICAgdHJpYW5nbGVzLnB1c2goaTIsIGkxLCBpMjIpOwogICAgICAgICAgICB9IGVsc2UgaWYgKGcxID09PSBtYXgzKSB7CiAgICAgICAgICAgICAgZWRnZSA9IGAke01hdGgubWluKGkxLCBpMjIpfSAke01hdGgubWF4KGkxLCBpMjIpfWA7CiAgICAgICAgICAgICAgaTIgPSBlZGdlc1tlZGdlXTsKICAgICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpMikpIHsKICAgICAgICAgICAgICAgIG1pZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQodjEyLCB2MjIsIHN1YmRpdmlzaW9uTWlkU2NyYXRjaCk7CiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihtaWQsIDAuNSwgbWlkKTsKICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMucHVzaChtaWQueCwgbWlkLnksIG1pZC56KTsKICAgICAgICAgICAgICAgIGkyID0gc3ViZGl2aWRlZFBvc2l0aW9ucy5sZW5ndGggLyAzIC0gMTsKICAgICAgICAgICAgICAgIGVkZ2VzW2VkZ2VdID0gaTI7CiAgICAgICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgICAgIG1pZFRleGNvb3JkID0gQ2FydGVzaWFuMl9kZWZhdWx0LmFkZCh0MSwgdDIsIHN1YmRpdmlzaW9uVGV4Y29vcmRNaWRTY3JhdGNoKTsKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWlkVGV4Y29vcmQsIDAuNSwgbWlkVGV4Y29vcmQpOwogICAgICAgICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzLnB1c2gobWlkVGV4Y29vcmQueCwgbWlkVGV4Y29vcmQueSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkxLCBpMiwgaTApOwogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkyLCBpMjIsIGkwKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChnMiA9PT0gbWF4MykgewogICAgICAgICAgICAgIGVkZ2UgPSBgJHtNYXRoLm1pbihpMjIsIGkwKX0gJHtNYXRoLm1heChpMjIsIGkwKX1gOwogICAgICAgICAgICAgIGkyID0gZWRnZXNbZWRnZV07CiAgICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaTIpKSB7CiAgICAgICAgICAgICAgICBtaWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHYyMiwgdjAyLCBzdWJkaXZpc2lvbk1pZFNjcmF0Y2gpOwogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWlkLCAwLjUsIG1pZCk7CiAgICAgICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLnB1c2gobWlkLngsIG1pZC55LCBtaWQueik7CiAgICAgICAgICAgICAgICBpMiA9IHN1YmRpdmlkZWRQb3NpdGlvbnMubGVuZ3RoIC8gMyAtIDE7CiAgICAgICAgICAgICAgICBlZGdlc1tlZGdlXSA9IGkyOwogICAgICAgICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICAgICAgICBtaWRUZXhjb29yZCA9IENhcnRlc2lhbjJfZGVmYXVsdC5hZGQodDIsIHQwLCBzdWJkaXZpc2lvblRleGNvb3JkTWlkU2NyYXRjaCk7CiAgICAgICAgICAgICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG1pZFRleGNvb3JkLCAwLjUsIG1pZFRleGNvb3JkKTsKICAgICAgICAgICAgICAgICAgc3ViZGl2aWRlZFRleGNvb3Jkcy5wdXNoKG1pZFRleGNvb3JkLngsIG1pZFRleGNvb3JkLnkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB0cmlhbmdsZXMucHVzaChpMjIsIGkyLCBpMSk7CiAgICAgICAgICAgICAgdHJpYW5nbGVzLnB1c2goaTIsIGkwLCBpMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHN1YmRpdmlkZWRJbmRpY2VzLnB1c2goaTApOwogICAgICAgICAgICBzdWJkaXZpZGVkSW5kaWNlcy5wdXNoKGkxKTsKICAgICAgICAgICAgc3ViZGl2aWRlZEluZGljZXMucHVzaChpMjIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBnZW9tZXRyeU9wdGlvbnMgPSB7CiAgICAgICAgICBhdHRyaWJ1dGVzOiB7CiAgICAgICAgICAgIHBvc2l0aW9uOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBzdWJkaXZpZGVkUG9zaXRpb25zCiAgICAgICAgICAgIH0pCiAgICAgICAgICB9LAogICAgICAgICAgaW5kaWNlczogc3ViZGl2aWRlZEluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTCiAgICAgICAgfTsKICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICBnZW9tZXRyeU9wdGlvbnMuYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgIHZhbHVlczogc3ViZGl2aWRlZFRleGNvb3JkcwogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdChnZW9tZXRyeU9wdGlvbnMpOwogICAgICB9OwogICAgICBzdWJkaXZpc2lvbkMwU2NyYXRjaCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvbkMxU2NyYXRjaCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvbkMyU2NyYXRjaCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzdWJkaXZpc2lvbkNhcnRvZ3JhcGhpY1NjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgUG9seWdvblBpcGVsaW5lLmNvbXB1dGVSaHVtYkxpbmVTdWJkaXZpc2lvbiA9IGZ1bmN0aW9uKGVsbGlwc29pZCwgcG9zaXRpb25zLCBpbmRpY2VzLCB0ZXhjb29yZHMsIGdyYW51bGFyaXR5KSB7CiAgICAgICAgZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgICAgIGNvbnN0IGhhc1RleGNvb3JkcyA9IGRlZmluZWRfZGVmYXVsdCh0ZXhjb29yZHMpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZWxsaXBzb2lkIiwgZWxsaXBzb2lkKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJpbmRpY2VzIiwgaW5kaWNlcyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoImluZGljZXMubGVuZ3RoIiwgaW5kaWNlcy5sZW5ndGgsIDMpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5lcXVhbHMoImluZGljZXMubGVuZ3RoICUgMyIsICIwIiwgaW5kaWNlcy5sZW5ndGggJSAzLCAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW4oImdyYW51bGFyaXR5IiwgZ3JhbnVsYXJpdHksIDApOwogICAgICAgIGNvbnN0IHRyaWFuZ2xlcyA9IGluZGljZXMuc2xpY2UoMCk7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3Qgc3ViZGl2aWRlZFBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGggKiAzKTsKICAgICAgICBjb25zdCBzdWJkaXZpZGVkVGV4Y29vcmRzID0gbmV3IEFycmF5KGxlbmd0aCAqIDIpOwogICAgICAgIGxldCBxMyA9IDA7CiAgICAgICAgbGV0IHAyID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IGl0ZW0gPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1txMysrXSA9IGl0ZW0ueDsKICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbcTMrK10gPSBpdGVtLnk7CiAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zW3EzKytdID0gaXRlbS56OwogICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICBjb25zdCB0ZXhjb29yZEl0ZW0gPSB0ZXhjb29yZHNbaTJdOwogICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzW3AyKytdID0gdGV4Y29vcmRJdGVtLng7CiAgICAgICAgICAgIHN1YmRpdmlkZWRUZXhjb29yZHNbcDIrK10gPSB0ZXhjb29yZEl0ZW0ueTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uc3Qgc3ViZGl2aWRlZEluZGljZXMgPSBbXTsKICAgICAgICBjb25zdCBlZGdlcyA9IHt9OwogICAgICAgIGNvbnN0IHJhZGl1cyA9IGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzOwogICAgICAgIGNvbnN0IG1pbkRpc3RhbmNlID0gTWF0aF9kZWZhdWx0LmNob3JkTGVuZ3RoKGdyYW51bGFyaXR5LCByYWRpdXMpOwogICAgICAgIGNvbnN0IHJodW1iMCA9IG5ldyBFbGxpcHNvaWRSaHVtYkxpbmVfZGVmYXVsdCh2b2lkIDAsIHZvaWQgMCwgZWxsaXBzb2lkKTsKICAgICAgICBjb25zdCByaHVtYjEgPSBuZXcgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQodm9pZCAwLCB2b2lkIDAsIGVsbGlwc29pZCk7CiAgICAgICAgY29uc3Qgcmh1bWIyID0gbmV3IEVsbGlwc29pZFJodW1iTGluZV9kZWZhdWx0KHZvaWQgMCwgdm9pZCAwLCBlbGxpcHNvaWQpOwogICAgICAgIHdoaWxlICh0cmlhbmdsZXMubGVuZ3RoID4gMCkgewogICAgICAgICAgY29uc3QgaTIyID0gdHJpYW5nbGVzLnBvcCgpOwogICAgICAgICAgY29uc3QgaTEgPSB0cmlhbmdsZXMucG9wKCk7CiAgICAgICAgICBjb25zdCBpMCA9IHRyaWFuZ2xlcy5wb3AoKTsKICAgICAgICAgIGNvbnN0IHYwMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMsCiAgICAgICAgICAgIGkwICogMywKICAgICAgICAgICAgc3ViZGl2aXNpb25WMFNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCB2MTIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLAogICAgICAgICAgICBpMSAqIDMsCiAgICAgICAgICAgIHN1YmRpdmlzaW9uVjFTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgdjIyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucywKICAgICAgICAgICAgaTIyICogMywKICAgICAgICAgICAgc3ViZGl2aXNpb25WMlNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBsZXQgdDAsIHQxLCB0MjsKICAgICAgICAgIGlmIChoYXNUZXhjb29yZHMpIHsKICAgICAgICAgICAgdDAgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICAgIHN1YmRpdmlkZWRUZXhjb29yZHMsCiAgICAgICAgICAgICAgaTAgKiAyLAogICAgICAgICAgICAgIHN1YmRpdmlzaW9uVDBTY3JhdGNoCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIHQxID0gQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzLAogICAgICAgICAgICAgIGkxICogMiwKICAgICAgICAgICAgICBzdWJkaXZpc2lvblQxU2NyYXRjaAogICAgICAgICAgICApOwogICAgICAgICAgICB0MiA9IENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgICAgc3ViZGl2aWRlZFRleGNvb3JkcywKICAgICAgICAgICAgICBpMjIgKiAyLAogICAgICAgICAgICAgIHN1YmRpdmlzaW9uVDJTY3JhdGNoCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBjMCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyh2MDIsIHN1YmRpdmlzaW9uQzBTY3JhdGNoKTsKICAgICAgICAgIGNvbnN0IGMxID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKHYxMiwgc3ViZGl2aXNpb25DMVNjcmF0Y2gpOwogICAgICAgICAgY29uc3QgYzIgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWModjIyLCBzdWJkaXZpc2lvbkMyU2NyYXRjaCk7CiAgICAgICAgICByaHVtYjAuc2V0RW5kUG9pbnRzKGMwLCBjMSk7CiAgICAgICAgICBjb25zdCBnMCA9IHJodW1iMC5zdXJmYWNlRGlzdGFuY2U7CiAgICAgICAgICByaHVtYjEuc2V0RW5kUG9pbnRzKGMxLCBjMik7CiAgICAgICAgICBjb25zdCBnMSA9IHJodW1iMS5zdXJmYWNlRGlzdGFuY2U7CiAgICAgICAgICByaHVtYjIuc2V0RW5kUG9pbnRzKGMyLCBjMCk7CiAgICAgICAgICBjb25zdCBnMiA9IHJodW1iMi5zdXJmYWNlRGlzdGFuY2U7CiAgICAgICAgICBjb25zdCBtYXgzID0gTWF0aC5tYXgoZzAsIGcxLCBnMik7CiAgICAgICAgICBsZXQgZWRnZTsKICAgICAgICAgIGxldCBtaWQ7CiAgICAgICAgICBsZXQgbWlkSGVpZ2h0OwogICAgICAgICAgbGV0IG1pZENhcnRlc2lhbjM7CiAgICAgICAgICBsZXQgbWlkVGV4Y29vcmQ7CiAgICAgICAgICBpZiAobWF4MyA+IG1pbkRpc3RhbmNlKSB7CiAgICAgICAgICAgIGlmIChnMCA9PT0gbWF4MykgewogICAgICAgICAgICAgIGVkZ2UgPSBgJHtNYXRoLm1pbihpMCwgaTEpfSAke01hdGgubWF4KGkwLCBpMSl9YDsKICAgICAgICAgICAgICBpMiA9IGVkZ2VzW2VkZ2VdOwogICAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGkyKSkgewogICAgICAgICAgICAgICAgbWlkID0gcmh1bWIwLmludGVycG9sYXRlVXNpbmdGcmFjdGlvbigKICAgICAgICAgICAgICAgICAgMC41LAogICAgICAgICAgICAgICAgICBzdWJkaXZpc2lvbkNhcnRvZ3JhcGhpY1NjcmF0Y2gKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICBtaWRIZWlnaHQgPSAoYzAuaGVpZ2h0ICsgYzEuaGVpZ2h0KSAqIDAuNTsKICAgICAgICAgICAgICAgIG1pZENhcnRlc2lhbjMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICAgICAgICAgIG1pZC5sb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgIG1pZC5sYXRpdHVkZSwKICAgICAgICAgICAgICAgICAgbWlkSGVpZ2h0LAogICAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICAgIHN1YmRpdmlzaW9uTWlkU2NyYXRjaAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMucHVzaCgKICAgICAgICAgICAgICAgICAgbWlkQ2FydGVzaWFuMy54LAogICAgICAgICAgICAgICAgICBtaWRDYXJ0ZXNpYW4zLnksCiAgICAgICAgICAgICAgICAgIG1pZENhcnRlc2lhbjMuegogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIGkyID0gc3ViZGl2aWRlZFBvc2l0aW9ucy5sZW5ndGggLyAzIC0gMTsKICAgICAgICAgICAgICAgIGVkZ2VzW2VkZ2VdID0gaTI7CiAgICAgICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgICAgIG1pZFRleGNvb3JkID0gQ2FydGVzaWFuMl9kZWZhdWx0LmFkZCh0MCwgdDEsIHN1YmRpdmlzaW9uVGV4Y29vcmRNaWRTY3JhdGNoKTsKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWlkVGV4Y29vcmQsIDAuNSwgbWlkVGV4Y29vcmQpOwogICAgICAgICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzLnB1c2gobWlkVGV4Y29vcmQueCwgbWlkVGV4Y29vcmQueSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkwLCBpMiwgaTIyKTsKICAgICAgICAgICAgICB0cmlhbmdsZXMucHVzaChpMiwgaTEsIGkyMik7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZzEgPT09IG1heDMpIHsKICAgICAgICAgICAgICBlZGdlID0gYCR7TWF0aC5taW4oaTEsIGkyMil9ICR7TWF0aC5tYXgoaTEsIGkyMil9YDsKICAgICAgICAgICAgICBpMiA9IGVkZ2VzW2VkZ2VdOwogICAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGkyKSkgewogICAgICAgICAgICAgICAgbWlkID0gcmh1bWIxLmludGVycG9sYXRlVXNpbmdGcmFjdGlvbigKICAgICAgICAgICAgICAgICAgMC41LAogICAgICAgICAgICAgICAgICBzdWJkaXZpc2lvbkNhcnRvZ3JhcGhpY1NjcmF0Y2gKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICBtaWRIZWlnaHQgPSAoYzEuaGVpZ2h0ICsgYzIuaGVpZ2h0KSAqIDAuNTsKICAgICAgICAgICAgICAgIG1pZENhcnRlc2lhbjMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICAgICAgICAgIG1pZC5sb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgIG1pZC5sYXRpdHVkZSwKICAgICAgICAgICAgICAgICAgbWlkSGVpZ2h0LAogICAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICAgIHN1YmRpdmlzaW9uTWlkU2NyYXRjaAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMucHVzaCgKICAgICAgICAgICAgICAgICAgbWlkQ2FydGVzaWFuMy54LAogICAgICAgICAgICAgICAgICBtaWRDYXJ0ZXNpYW4zLnksCiAgICAgICAgICAgICAgICAgIG1pZENhcnRlc2lhbjMuegogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIGkyID0gc3ViZGl2aWRlZFBvc2l0aW9ucy5sZW5ndGggLyAzIC0gMTsKICAgICAgICAgICAgICAgIGVkZ2VzW2VkZ2VdID0gaTI7CiAgICAgICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgICAgIG1pZFRleGNvb3JkID0gQ2FydGVzaWFuMl9kZWZhdWx0LmFkZCh0MSwgdDIsIHN1YmRpdmlzaW9uVGV4Y29vcmRNaWRTY3JhdGNoKTsKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobWlkVGV4Y29vcmQsIDAuNSwgbWlkVGV4Y29vcmQpOwogICAgICAgICAgICAgICAgICBzdWJkaXZpZGVkVGV4Y29vcmRzLnB1c2gobWlkVGV4Y29vcmQueCwgbWlkVGV4Y29vcmQueSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkxLCBpMiwgaTApOwogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkyLCBpMjIsIGkwKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChnMiA9PT0gbWF4MykgewogICAgICAgICAgICAgIGVkZ2UgPSBgJHtNYXRoLm1pbihpMjIsIGkwKX0gJHtNYXRoLm1heChpMjIsIGkwKX1gOwogICAgICAgICAgICAgIGkyID0gZWRnZXNbZWRnZV07CiAgICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaTIpKSB7CiAgICAgICAgICAgICAgICBtaWQgPSByaHVtYjIuaW50ZXJwb2xhdGVVc2luZ0ZyYWN0aW9uKAogICAgICAgICAgICAgICAgICAwLjUsCiAgICAgICAgICAgICAgICAgIHN1YmRpdmlzaW9uQ2FydG9ncmFwaGljU2NyYXRjaAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIG1pZEhlaWdodCA9IChjMi5oZWlnaHQgKyBjMC5oZWlnaHQpICogMC41OwogICAgICAgICAgICAgICAgbWlkQ2FydGVzaWFuMyA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgICAgICAgICAgbWlkLmxvbmdpdHVkZSwKICAgICAgICAgICAgICAgICAgbWlkLmxhdGl0dWRlLAogICAgICAgICAgICAgICAgICBtaWRIZWlnaHQsCiAgICAgICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAgICAgc3ViZGl2aXNpb25NaWRTY3JhdGNoCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucy5wdXNoKAogICAgICAgICAgICAgICAgICBtaWRDYXJ0ZXNpYW4zLngsCiAgICAgICAgICAgICAgICAgIG1pZENhcnRlc2lhbjMueSwKICAgICAgICAgICAgICAgICAgbWlkQ2FydGVzaWFuMy56CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgaTIgPSBzdWJkaXZpZGVkUG9zaXRpb25zLmxlbmd0aCAvIDMgLSAxOwogICAgICAgICAgICAgICAgZWRnZXNbZWRnZV0gPSBpMjsKICAgICAgICAgICAgICAgIGlmIChoYXNUZXhjb29yZHMpIHsKICAgICAgICAgICAgICAgICAgbWlkVGV4Y29vcmQgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuYWRkKHQyLCB0MCwgc3ViZGl2aXNpb25UZXhjb29yZE1pZFNjcmF0Y2gpOwogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihtaWRUZXhjb29yZCwgMC41LCBtaWRUZXhjb29yZCk7CiAgICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRUZXhjb29yZHMucHVzaChtaWRUZXhjb29yZC54LCBtaWRUZXhjb29yZC55KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdHJpYW5nbGVzLnB1c2goaTIyLCBpMiwgaTEpOwogICAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGkyLCBpMCwgaTEpOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBzdWJkaXZpZGVkSW5kaWNlcy5wdXNoKGkwKTsKICAgICAgICAgICAgc3ViZGl2aWRlZEluZGljZXMucHVzaChpMSk7CiAgICAgICAgICAgIHN1YmRpdmlkZWRJbmRpY2VzLnB1c2goaTIyKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uc3QgZ2VvbWV0cnlPcHRpb25zID0gewogICAgICAgICAgYXR0cmlidXRlczogewogICAgICAgICAgICBwb3NpdGlvbjogbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICAgIHZhbHVlczogc3ViZGl2aWRlZFBvc2l0aW9ucwogICAgICAgICAgICB9KQogICAgICAgICAgfSwKICAgICAgICAgIGluZGljZXM6IHN1YmRpdmlkZWRJbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUwogICAgICAgIH07CiAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgZ2VvbWV0cnlPcHRpb25zLmF0dHJpYnV0ZXMuc3QgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICB2YWx1ZXM6IHN1YmRpdmlkZWRUZXhjb29yZHMKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoZ2VvbWV0cnlPcHRpb25zKTsKICAgICAgfTsKICAgICAgUG9seWdvblBpcGVsaW5lLnNjYWxlVG9HZW9kZXRpY0hlaWdodCA9IGZ1bmN0aW9uKHBvc2l0aW9ucywgaGVpZ2h0LCBlbGxpcHNvaWQsIHNjYWxlVG9TdXJmYWNlNCkgewogICAgICAgIGVsbGlwc29pZCA9IGVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgIGxldCBuMiA9IHNjYWxlVG9HZW9kZXRpY0hlaWdodE47CiAgICAgICAgbGV0IHAyID0gc2NhbGVUb0dlb2RldGljSGVpZ2h0UDsKICAgICAgICBoZWlnaHQgPSBoZWlnaHQgPz8gMDsKICAgICAgICBzY2FsZVRvU3VyZmFjZTQgPSBzY2FsZVRvU3VyZmFjZTQgPz8gdHJ1ZTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykpIHsKICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBpMiwgcDIpOwogICAgICAgICAgICBpZiAoc2NhbGVUb1N1cmZhY2U0KSB7CiAgICAgICAgICAgICAgcDIgPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwMiwgcDIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChoZWlnaHQgIT09IDApIHsKICAgICAgICAgICAgICBuMiA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocDIsIG4yKTsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihuMiwgaGVpZ2h0LCBuMik7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwMiwgbjIsIHAyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBwb3NpdGlvbnNbaTJdID0gcDIueDsKICAgICAgICAgICAgcG9zaXRpb25zW2kyICsgMV0gPSBwMi55OwogICAgICAgICAgICBwb3NpdGlvbnNbaTIgKyAyXSA9IHAyLno7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBwb3NpdGlvbnM7CiAgICAgIH07CiAgICAgIFBvbHlnb25QaXBlbGluZV9kZWZhdWx0ID0gUG9seWdvblBpcGVsaW5lOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUXVldWUuanMKICBmdW5jdGlvbiBRdWV1ZSgpIHsKICAgIHRoaXMuX2FycmF5ID0gW107CiAgICB0aGlzLl9vZmZzZXQgPSAwOwogICAgdGhpcy5fbGVuZ3RoID0gMDsKICB9CiAgdmFyIFF1ZXVlX2RlZmF1bHQ7CiAgdmFyIGluaXRfUXVldWUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1F1ZXVlLmpzIigpIHsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoUXVldWUucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIGxlbmd0aCBvZiB0aGUgcXVldWUuCiAgICAgICAgICoKICAgICAgICAgKiBAbWVtYmVyb2YgUXVldWUucHJvdG90eXBlCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGxlbmd0aDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xlbmd0aDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBRdWV1ZS5wcm90b3R5cGUuZW5xdWV1ZSA9IGZ1bmN0aW9uKGl0ZW0pIHsKICAgICAgICB0aGlzLl9hcnJheS5wdXNoKGl0ZW0pOwogICAgICAgIHRoaXMuX2xlbmd0aCsrOwogICAgICB9OwogICAgICBRdWV1ZS5wcm90b3R5cGUuZGVxdWV1ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmICh0aGlzLl9sZW5ndGggPT09IDApIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGFycmF5ID0gdGhpcy5fYXJyYXk7CiAgICAgICAgbGV0IG9mZnNldCA9IHRoaXMuX29mZnNldDsKICAgICAgICBjb25zdCBpdGVtID0gYXJyYXlbb2Zmc2V0XTsKICAgICAgICBhcnJheVtvZmZzZXRdID0gdm9pZCAwOwogICAgICAgIG9mZnNldCsrOwogICAgICAgIGlmIChvZmZzZXQgPiAxMCAmJiBvZmZzZXQgKiAyID4gYXJyYXkubGVuZ3RoKSB7CiAgICAgICAgICB0aGlzLl9hcnJheSA9IGFycmF5LnNsaWNlKG9mZnNldCk7CiAgICAgICAgICBvZmZzZXQgPSAwOwogICAgICAgIH0KICAgICAgICB0aGlzLl9vZmZzZXQgPSBvZmZzZXQ7CiAgICAgICAgdGhpcy5fbGVuZ3RoLS07CiAgICAgICAgcmV0dXJuIGl0ZW07CiAgICAgIH07CiAgICAgIFF1ZXVlLnByb3RvdHlwZS5wZWVrID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKHRoaXMuX2xlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuX2FycmF5W3RoaXMuX29mZnNldF07CiAgICAgIH07CiAgICAgIFF1ZXVlLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uKGl0ZW0pIHsKICAgICAgICByZXR1cm4gdGhpcy5fYXJyYXkuaW5kZXhPZihpdGVtKSAhPT0gLTE7CiAgICAgIH07CiAgICAgIFF1ZXVlLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uKCkgewogICAgICAgIHRoaXMuX2FycmF5Lmxlbmd0aCA9IHRoaXMuX29mZnNldCA9IHRoaXMuX2xlbmd0aCA9IDA7CiAgICAgIH07CiAgICAgIFF1ZXVlLnByb3RvdHlwZS5zb3J0ID0gZnVuY3Rpb24oY29tcGFyZUZ1bmN0aW9uKSB7CiAgICAgICAgaWYgKHRoaXMuX29mZnNldCA+IDApIHsKICAgICAgICAgIHRoaXMuX2FycmF5ID0gdGhpcy5fYXJyYXkuc2xpY2UodGhpcy5fb2Zmc2V0KTsKICAgICAgICAgIHRoaXMuX29mZnNldCA9IDA7CiAgICAgICAgfQogICAgICAgIHRoaXMuX2FycmF5LnNvcnQoY29tcGFyZUZ1bmN0aW9uKTsKICAgICAgfTsKICAgICAgUXVldWVfZGVmYXVsdCA9IFF1ZXVlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWdvbkdlb21ldHJ5TGlicmFyeS5qcwogIGZ1bmN0aW9uIGdldFBvaW50QXREaXN0YW5jZTJEKHAwLCBwMSwgZGlzdGFuY2UsIGxlbmd0aCkgewogICAgQ2FydGVzaWFuMl9kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMCwgZGlzdGFuY2UyRFNjcmF0Y2gpOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgIGRpc3RhbmNlMkRTY3JhdGNoLAogICAgICBkaXN0YW5jZSAvIGxlbmd0aCwKICAgICAgZGlzdGFuY2UyRFNjcmF0Y2gKICAgICk7CiAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQuYWRkKHAwLCBkaXN0YW5jZTJEU2NyYXRjaCwgZGlzdGFuY2UyRFNjcmF0Y2gpOwogICAgcmV0dXJuIFtkaXN0YW5jZTJEU2NyYXRjaC54LCBkaXN0YW5jZTJEU2NyYXRjaC55XTsKICB9CiAgZnVuY3Rpb24gZ2V0UG9pbnRBdERpc3RhbmNlKHAwLCBwMSwgZGlzdGFuY2UsIGxlbmd0aCkgewogICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHAxLCBwMCwgZGlzdGFuY2VTY3JhdGNoNCk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgZGlzdGFuY2VTY3JhdGNoNCwKICAgICAgZGlzdGFuY2UgLyBsZW5ndGgsCiAgICAgIGRpc3RhbmNlU2NyYXRjaDQKICAgICk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHAwLCBkaXN0YW5jZVNjcmF0Y2g0LCBkaXN0YW5jZVNjcmF0Y2g0KTsKICAgIHJldHVybiBbZGlzdGFuY2VTY3JhdGNoNC54LCBkaXN0YW5jZVNjcmF0Y2g0LnksIGRpc3RhbmNlU2NyYXRjaDQuel07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVFcXVhdG9ySW50ZXJzZWN0aW9uUmh1bWIoc3RhcnQsIGVuZCwgZWxsaXBzb2lkKSB7CiAgICBjb25zdCBjMCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhzdGFydCwgc2NyYXRjaENhcnRvZ3JhcGhpYzApOwogICAgY29uc3QgYzEgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoZW5kLCBzY3JhdGNoQ2FydG9ncmFwaGljMSk7CiAgICBpZiAoTWF0aC5zaWduKGMwLmxhdGl0dWRlKSA9PT0gTWF0aC5zaWduKGMxLmxhdGl0dWRlKSkgewogICAgICByZXR1cm47CiAgICB9CiAgICBzY3JhdGNoUmh1bWJMaW5lLnNldEVuZFBvaW50cyhjMCwgYzEpOwogICAgY29uc3QgaW50ZXJzZWN0aW9uID0gc2NyYXRjaFJodW1iTGluZS5maW5kSW50ZXJzZWN0aW9uV2l0aExhdGl0dWRlKAogICAgICAwLAogICAgICBzY3JhdGNoUmh1bWJJbnRlcnNlY3Rpb24KICAgICk7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb24pKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGxldCBtaW5Mb25naXR1ZGUgPSBNYXRoLm1pbihjMC5sb25naXR1ZGUsIGMxLmxvbmdpdHVkZSk7CiAgICBsZXQgbWF4TG9uZ2l0dWRlID0gTWF0aC5tYXgoYzAubG9uZ2l0dWRlLCBjMS5sb25naXR1ZGUpOwogICAgaWYgKE1hdGguYWJzKG1heExvbmdpdHVkZSAtIG1pbkxvbmdpdHVkZSkgPiBNYXRoX2RlZmF1bHQuUEkpIHsKICAgICAgY29uc3Qgc3dhcDIgPSBtaW5Mb25naXR1ZGU7CiAgICAgIG1pbkxvbmdpdHVkZSA9IG1heExvbmdpdHVkZTsKICAgICAgbWF4TG9uZ2l0dWRlID0gc3dhcDI7CiAgICB9CiAgICBpZiAoaW50ZXJzZWN0aW9uLmxvbmdpdHVkZSA8IG1pbkxvbmdpdHVkZSB8fCBpbnRlcnNlY3Rpb24ubG9uZ2l0dWRlID4gbWF4TG9uZ2l0dWRlKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIHJldHVybiBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oaW50ZXJzZWN0aW9uKTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUVxdWF0b3JJbnRlcnNlY3Rpb24oc3RhcnQsIGVuZCwgZWxsaXBzb2lkLCBhcmNUeXBlKSB7CiAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgIHJldHVybiBjb21wdXRlRXF1YXRvckludGVyc2VjdGlvblJodW1iKHN0YXJ0LCBlbmQsIGVsbGlwc29pZCk7CiAgICB9CiAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LmxpbmVTZWdtZW50UGxhbmUoCiAgICAgIHN0YXJ0LAogICAgICBlbmQsCiAgICAgIFBsYW5lX2RlZmF1bHQuT1JJR0lOX1hZX1BMQU5FCiAgICApOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW50ZXJzZWN0aW9uKSkgewogICAgICByZXR1cm47CiAgICB9CiAgICByZXR1cm4gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UoaW50ZXJzZWN0aW9uLCBpbnRlcnNlY3Rpb24pOwogIH0KICBmdW5jdGlvbiBjb21wdXRlRWRnZXNPblBsYW5lKHBvc2l0aW9ucywgZWxsaXBzb2lkLCBhcmNUeXBlKSB7CiAgICBjb25zdCBlZGdlc09uUGxhbmUgPSBbXTsKICAgIGxldCBzdGFydFBvaW50LCBlbmRQb2ludCwgdHlwZSwgbmV4dCwgaW50ZXJzZWN0aW9uLCBpMiA9IDA7CiAgICB3aGlsZSAoaTIgPCBwb3NpdGlvbnMubGVuZ3RoKSB7CiAgICAgIHN0YXJ0UG9pbnQgPSBwb3NpdGlvbnNbaTJdOwogICAgICBlbmRQb2ludCA9IHBvc2l0aW9uc1soaTIgKyAxKSAlIHBvc2l0aW9ucy5sZW5ndGhdOwogICAgICB0eXBlID0gTWF0aF9kZWZhdWx0LnNpZ24oc3RhcnRQb2ludC56KTsKICAgICAgbmV4dCA9IE1hdGhfZGVmYXVsdC5zaWduKGVuZFBvaW50LnopOwogICAgICBjb25zdCBnZXRMb25naXR1ZGUgPSAocG9zaXRpb24pID0+IHsKICAgICAgICBjb25zdCBjYXJ0b2dyYXBoaWMyID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljMwogICAgICAgICk7CiAgICAgICAgcmV0dXJuIGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlOwogICAgICB9OwogICAgICBpZiAodHlwZSA9PT0gMCkgewogICAgICAgIGVkZ2VzT25QbGFuZS5wdXNoKHsKICAgICAgICAgIHBvc2l0aW9uOiBpMiwKICAgICAgICAgIHR5cGUsCiAgICAgICAgICB2aXNpdGVkOiBmYWxzZSwKICAgICAgICAgIG5leHQsCiAgICAgICAgICB0aGV0YTogZ2V0TG9uZ2l0dWRlKHN0YXJ0UG9pbnQpCiAgICAgICAgfSk7CiAgICAgIH0gZWxzZSBpZiAobmV4dCAhPT0gMCkgewogICAgICAgIGludGVyc2VjdGlvbiA9IGNvbXB1dGVFcXVhdG9ySW50ZXJzZWN0aW9uKAogICAgICAgICAgc3RhcnRQb2ludCwKICAgICAgICAgIGVuZFBvaW50LAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgYXJjVHlwZQogICAgICAgICk7CiAgICAgICAgKytpMjsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb24pKSB7CiAgICAgICAgICBjb250aW51ZTsKICAgICAgICB9CiAgICAgICAgcG9zaXRpb25zLnNwbGljZShpMiwgMCwgaW50ZXJzZWN0aW9uKTsKICAgICAgICBlZGdlc09uUGxhbmUucHVzaCh7CiAgICAgICAgICBwb3NpdGlvbjogaTIsCiAgICAgICAgICB0eXBlLAogICAgICAgICAgdmlzaXRlZDogZmFsc2UsCiAgICAgICAgICBuZXh0LAogICAgICAgICAgdGhldGE6IGdldExvbmdpdHVkZShpbnRlcnNlY3Rpb24pCiAgICAgICAgfSk7CiAgICAgIH0KICAgICAgKytpMjsKICAgIH0KICAgIHJldHVybiBlZGdlc09uUGxhbmU7CiAgfQogIGZ1bmN0aW9uIHdpcmVQb2x5Z29uKHBvbHlnb25zLCBwb2x5Z29uSW5kZXgsIHBvc2l0aW9ucywgZWRnZXNPblBsYW5lLCB0b0RlbGV0ZSwgc3RhcnRJbmRleCwgYWJvdmVQbGFuZSkgewogICAgY29uc3QgcG9seWdvbjIgPSBbXTsKICAgIGxldCBpMiA9IHN0YXJ0SW5kZXg7CiAgICBjb25zdCBnZXRNYXRjaGluZ0VkZ2UgPSAoaTMpID0+IChlZGdlKSA9PiBlZGdlLnBvc2l0aW9uID09PSBpMzsKICAgIGNvbnN0IHBvbHlnb25zVG9XaXJlID0gW107CiAgICBkbyB7CiAgICAgIGNvbnN0IHBvc2l0aW9uID0gcG9zaXRpb25zW2kyXTsKICAgICAgcG9seWdvbjIucHVzaChwb3NpdGlvbik7CiAgICAgIGNvbnN0IGVkZ2VJbmRleCA9IGVkZ2VzT25QbGFuZS5maW5kSW5kZXgoZ2V0TWF0Y2hpbmdFZGdlKGkyKSk7CiAgICAgIGNvbnN0IGVkZ2UgPSBlZGdlc09uUGxhbmVbZWRnZUluZGV4XTsKICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZWRnZSkpIHsKICAgICAgICArK2kyOwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGNvbnN0IHsgdmlzaXRlZDogaGFzQmVlblZpc2l0ZWQsIHR5cGUsIG5leHQgfSA9IGVkZ2U7CiAgICAgIGVkZ2UudmlzaXRlZCA9IHRydWU7CiAgICAgIGlmICh0eXBlID09PSAwKSB7CiAgICAgICAgaWYgKG5leHQgPT09IDApIHsKICAgICAgICAgIGNvbnN0IHByZXZpb3VzRWRnZSA9IGVkZ2VzT25QbGFuZVtlZGdlSW5kZXggLSAoYWJvdmVQbGFuZSA/IDEgOiAtMSldOwogICAgICAgICAgaWYgKHByZXZpb3VzRWRnZT8ucG9zaXRpb24gPT09IGkyICsgMSkgewogICAgICAgICAgICBwcmV2aW91c0VkZ2UudmlzaXRlZCA9IHRydWU7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICArK2kyOwogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKCFoYXNCZWVuVmlzaXRlZCAmJiBhYm92ZVBsYW5lICYmIG5leHQgPiAwIHx8IHN0YXJ0SW5kZXggPT09IGkyICYmICFhYm92ZVBsYW5lICYmIG5leHQgPCAwKSB7CiAgICAgICAgICArK2kyOwogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IGZvbGxvd0VkZ2UgPSBhYm92ZVBsYW5lID8gdHlwZSA+PSAwIDogdHlwZSA8PSAwOwogICAgICBpZiAoIWZvbGxvd0VkZ2UpIHsKICAgICAgICArK2kyOwogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGlmICghaGFzQmVlblZpc2l0ZWQpIHsKICAgICAgICBwb2x5Z29uc1RvV2lyZS5wdXNoKGkyKTsKICAgICAgfQogICAgICBjb25zdCBuZXh0RWRnZUluZGV4ID0gZWRnZUluZGV4ICsgKGFib3ZlUGxhbmUgPyAxIDogLTEpOwogICAgICBjb25zdCBuZXh0RWRnZSA9IGVkZ2VzT25QbGFuZVtuZXh0RWRnZUluZGV4XTsKICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobmV4dEVkZ2UpKSB7CiAgICAgICAgKytpMjsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBpMiA9IG5leHRFZGdlLnBvc2l0aW9uOwogICAgfSB3aGlsZSAoaTIgPCBwb3NpdGlvbnMubGVuZ3RoICYmIGkyID49IDAgJiYgaTIgIT09IHN0YXJ0SW5kZXggJiYgcG9seWdvbjIubGVuZ3RoIDwgcG9zaXRpb25zLmxlbmd0aCk7CiAgICBwb2x5Z29ucy5zcGxpY2UocG9seWdvbkluZGV4LCB0b0RlbGV0ZSwgcG9seWdvbjIpOwogICAgZm9yIChjb25zdCBpbmRleCBvZiBwb2x5Z29uc1RvV2lyZSkgewogICAgICBwb2x5Z29uSW5kZXggPSB3aXJlUG9seWdvbigKICAgICAgICBwb2x5Z29ucywKICAgICAgICBwb2x5Z29uSW5kZXggKyAxLAogICAgICAgIHBvc2l0aW9ucywKICAgICAgICBlZGdlc09uUGxhbmUsCiAgICAgICAgMCwKICAgICAgICBpbmRleCwKICAgICAgICAhYWJvdmVQbGFuZQogICAgICApOwogICAgfQogICAgcmV0dXJuIHBvbHlnb25JbmRleDsKICB9CiAgdmFyIFBvbHlnb25HZW9tZXRyeUxpYnJhcnksIGRpc3RhbmNlMkRTY3JhdGNoLCBkaXN0YW5jZVNjcmF0Y2g0LCBzY3JhdGNoQ2FydG9ncmFwaGljMCwgc2NyYXRjaENhcnRvZ3JhcGhpYzEsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMyMiwgc2NyYXRjaENhcnRlc2lhbjAsIHNjcmF0Y2hSaHVtYkxpbmUsIHNjYWxlVG9HZW9kZXRpY0hlaWdodE4xLCBzY2FsZVRvR2VvZGV0aWNIZWlnaHROMiwgc2NhbGVUb0dlb2RldGljSGVpZ2h0UDEsIHNjYWxlVG9HZW9kZXRpY0hlaWdodFAyLCBzY3JhdGNoUmh1bWJJbnRlcnNlY3Rpb24sIHNjcmF0Y2hDYXJ0b2dyYXBoaWMzLCBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVDYXJ0ZXNpYW4yLCBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVDYXJ0ZXNpYW4zLCBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVRdWF0ZXJuaW9uLCBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVNYXRyaXgzLCBjb21wdXRlV2FsbFRleGNvb3Jkc1N1YmRpdmlkZWQsIGNvbXB1dGVXYWxsSW5kaWNlc1N1YmRpdmlkZWQsIHAxU2NyYXRjaDIsIHAyU2NyYXRjaDIsIFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdDsKICB2YXIgaW5pdF9Qb2x5Z29uR2VvbWV0cnlMaWJyYXJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Qb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LmpzIigpIHsKICAgICAgaW5pdF9BcmNUeXBlKCk7CiAgICAgIGluaXRfYXJyYXlSZW1vdmVEdXBsaWNhdGVzKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWRSaHVtYkxpbmUoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfR2VvbWV0cnlQaXBlbGluZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9JbnRlcnNlY3Rpb25UZXN0cygpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfUGxhbmUoKTsKICAgICAgaW5pdF9Qb2x5Z29uSGllcmFyY2h5KCk7CiAgICAgIGluaXRfUG9seWdvblBpcGVsaW5lKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1F1YXRlcm5pb24oKTsKICAgICAgaW5pdF9RdWV1ZSgpOwogICAgICBpbml0X1dpbmRpbmdPcmRlcigpOwogICAgICBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5ID0ge307CiAgICAgIFBvbHlnb25HZW9tZXRyeUxpYnJhcnkuY29tcHV0ZUhpZXJhcmNoeVBhY2tlZExlbmd0aCA9IGZ1bmN0aW9uKHBvbHlnb25IaWVyYXJjaHksIENhcnRlc2lhblgpIHsKICAgICAgICBsZXQgbnVtQ29tcG9uZW50cyA9IDA7CiAgICAgICAgY29uc3Qgc3RhY2sgPSBbcG9seWdvbkhpZXJhcmNoeV07CiAgICAgICAgd2hpbGUgKHN0YWNrLmxlbmd0aCA+IDApIHsKICAgICAgICAgIGNvbnN0IGhpZXJhcmNoeSA9IHN0YWNrLnBvcCgpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaGllcmFyY2h5KSkgewogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICAgIG51bUNvbXBvbmVudHMgKz0gMjsKICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IGhpZXJhcmNoeS5wb3NpdGlvbnM7CiAgICAgICAgICBjb25zdCBob2xlcyA9IGhpZXJhcmNoeS5ob2xlczsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSAmJiBwb3NpdGlvbnMubGVuZ3RoID4gMCkgewogICAgICAgICAgICBudW1Db21wb25lbnRzICs9IHBvc2l0aW9ucy5sZW5ndGggKiBDYXJ0ZXNpYW5YLnBhY2tlZExlbmd0aDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaG9sZXMpKSB7CiAgICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGhvbGVzLmxlbmd0aDsKICAgICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgIHN0YWNrLnB1c2goaG9sZXNbaTJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gbnVtQ29tcG9uZW50czsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5wYWNrUG9seWdvbkhpZXJhcmNoeSA9IGZ1bmN0aW9uKHBvbHlnb25IaWVyYXJjaHksIGFycmF5LCBzdGFydGluZ0luZGV4LCBDYXJ0ZXNpYW5YKSB7CiAgICAgICAgY29uc3Qgc3RhY2sgPSBbcG9seWdvbkhpZXJhcmNoeV07CiAgICAgICAgd2hpbGUgKHN0YWNrLmxlbmd0aCA+IDApIHsKICAgICAgICAgIGNvbnN0IGhpZXJhcmNoeSA9IHN0YWNrLnBvcCgpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaGllcmFyY2h5KSkgewogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IGhpZXJhcmNoeS5wb3NpdGlvbnM7CiAgICAgICAgICBjb25zdCBob2xlcyA9IGhpZXJhcmNoeS5ob2xlczsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSA/IHBvc2l0aW9ucy5sZW5ndGggOiAwOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGRlZmluZWRfZGVmYXVsdChob2xlcykgPyBob2xlcy5sZW5ndGggOiAwOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpKSB7CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuWC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW5YLnBhY2socG9zaXRpb25zW2kyXSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGhvbGVzKSkgewogICAgICAgICAgICBjb25zdCBob2xlc0xlbmd0aCA9IGhvbGVzLmxlbmd0aDsKICAgICAgICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGhvbGVzTGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICAgICAgc3RhY2sucHVzaChob2xlc1tqMl0pOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBzdGFydGluZ0luZGV4OwogICAgICB9OwogICAgICBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnVucGFja1BvbHlnb25IaWVyYXJjaHkgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgQ2FydGVzaWFuWCkgewogICAgICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgaG9sZXNMZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShwb3NpdGlvbnNMZW5ndGgpOwogICAgICAgIGNvbnN0IGhvbGVzID0gaG9sZXNMZW5ndGggPiAwID8gbmV3IEFycmF5KGhvbGVzTGVuZ3RoKSA6IHZvaWQgMDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zTGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhblgucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBwb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuWC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgaG9sZXNMZW5ndGg7ICsrajIpIHsKICAgICAgICAgIGhvbGVzW2oyXSA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnkudW5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgICAgYXJyYXksCiAgICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICAgIENhcnRlc2lhblgKICAgICAgICAgICk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ID0gaG9sZXNbajJdLnN0YXJ0aW5nSW5kZXg7CiAgICAgICAgICBkZWxldGUgaG9sZXNbajJdLnN0YXJ0aW5nSW5kZXg7CiAgICAgICAgfQogICAgICAgIHJldHVybiB7CiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBob2xlcywKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgKICAgICAgICB9OwogICAgICB9OwogICAgICBkaXN0YW5jZTJEU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgZGlzdGFuY2VTY3JhdGNoNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVMaW5lQ291bnQgPSBmdW5jdGlvbihwMCwgcDEsIG1pbkRpc3RhbmNlKSB7CiAgICAgICAgY29uc3QgZGlzdGFuY2UgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZGlzdGFuY2UocDAsIHAxKTsKICAgICAgICBjb25zdCBuMiA9IGRpc3RhbmNlIC8gbWluRGlzdGFuY2U7CiAgICAgICAgY29uc3QgY291bnREaXZpZGUgPSBNYXRoLm1heCgwLCBNYXRoLmNlaWwoTWF0aF9kZWZhdWx0LmxvZzIobjIpKSk7CiAgICAgICAgcmV0dXJuIE1hdGgucG93KDIsIGNvdW50RGl2aWRlKTsKICAgICAgfTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzAgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzEgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzIyID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4wID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUmh1bWJMaW5lID0gbmV3IEVsbGlwc29pZFJodW1iTGluZV9kZWZhdWx0KCk7CiAgICAgIFBvbHlnb25HZW9tZXRyeUxpYnJhcnkuc3ViZGl2aWRlUmh1bWJMaW5lQ291bnQgPSBmdW5jdGlvbihlbGxpcHNvaWQsIHAwLCBwMSwgbWluRGlzdGFuY2UpIHsKICAgICAgICBjb25zdCBjMCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMCwgc2NyYXRjaENhcnRvZ3JhcGhpYzApOwogICAgICAgIGNvbnN0IGMxID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKHAxLCBzY3JhdGNoQ2FydG9ncmFwaGljMSk7CiAgICAgICAgY29uc3Qgcmh1bWIgPSBuZXcgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQoYzAsIGMxLCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IG4yID0gcmh1bWIuc3VyZmFjZURpc3RhbmNlIC8gbWluRGlzdGFuY2U7CiAgICAgICAgY29uc3QgY291bnREaXZpZGUgPSBNYXRoLm1heCgwLCBNYXRoLmNlaWwoTWF0aF9kZWZhdWx0LmxvZzIobjIpKSk7CiAgICAgICAgcmV0dXJuIE1hdGgucG93KDIsIGNvdW50RGl2aWRlKTsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVUZXhjb29yZExpbmUgPSBmdW5jdGlvbih0MCwgdDEsIHAwLCBwMSwgbWluRGlzdGFuY2UsIHJlc3VsdCkgewogICAgICAgIGNvbnN0IHN1YmRpdmlzaW9ucyA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnkuc3ViZGl2aWRlTGluZUNvdW50KAogICAgICAgICAgcDAsCiAgICAgICAgICBwMSwKICAgICAgICAgIG1pbkRpc3RhbmNlCiAgICAgICAgKTsKICAgICAgICBjb25zdCBsZW5ndGgyRCA9IENhcnRlc2lhbjJfZGVmYXVsdC5kaXN0YW5jZSh0MCwgdDEpOwogICAgICAgIGNvbnN0IGRpc3RhbmNlQmV0d2VlbkNvb3JkcyA9IGxlbmd0aDJEIC8gc3ViZGl2aXNpb25zOwogICAgICAgIGNvbnN0IHRleGNvb3JkcyA9IHJlc3VsdDsKICAgICAgICB0ZXhjb29yZHMubGVuZ3RoID0gc3ViZGl2aXNpb25zICogMjsKICAgICAgICBsZXQgaW5kZXggPSAwOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBzdWJkaXZpc2lvbnM7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHQyID0gZ2V0UG9pbnRBdERpc3RhbmNlMkQodDAsIHQxLCBpMiAqIGRpc3RhbmNlQmV0d2VlbkNvb3JkcywgbGVuZ3RoMkQpOwogICAgICAgICAgdGV4Y29vcmRzW2luZGV4KytdID0gdDJbMF07CiAgICAgICAgICB0ZXhjb29yZHNbaW5kZXgrK10gPSB0MlsxXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRleGNvb3JkczsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVMaW5lID0gZnVuY3Rpb24ocDAsIHAxLCBtaW5EaXN0YW5jZSwgcmVzdWx0KSB7CiAgICAgICAgY29uc3QgbnVtVmVydGljZXMgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnN1YmRpdmlkZUxpbmVDb3VudCgKICAgICAgICAgIHAwLAogICAgICAgICAgcDEsCiAgICAgICAgICBtaW5EaXN0YW5jZQogICAgICAgICk7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gQ2FydGVzaWFuM19kZWZhdWx0LmRpc3RhbmNlKHAwLCBwMSk7CiAgICAgICAgY29uc3QgZGlzdGFuY2VCZXR3ZWVuVmVydGljZXMgPSBsZW5ndGggLyBudW1WZXJ0aWNlczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBbXTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gcmVzdWx0OwogICAgICAgIHBvc2l0aW9ucy5sZW5ndGggPSBudW1WZXJ0aWNlcyAqIDM7CiAgICAgICAgbGV0IGluZGV4ID0gMDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtVmVydGljZXM7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHAyID0gZ2V0UG9pbnRBdERpc3RhbmNlKHAwLCBwMSwgaTIgKiBkaXN0YW5jZUJldHdlZW5WZXJ0aWNlcywgbGVuZ3RoKTsKICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHAyWzBdOwogICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gcDJbMV07CiAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBwMlsyXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBvc2l0aW9uczsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVUZXhjb29yZFJodW1iTGluZSA9IGZ1bmN0aW9uKHQwLCB0MSwgZWxsaXBzb2lkLCBwMCwgcDEsIG1pbkRpc3RhbmNlLCByZXN1bHQpIHsKICAgICAgICBjb25zdCBjMCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMCwgc2NyYXRjaENhcnRvZ3JhcGhpYzApOwogICAgICAgIGNvbnN0IGMxID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKHAxLCBzY3JhdGNoQ2FydG9ncmFwaGljMSk7CiAgICAgICAgc2NyYXRjaFJodW1iTGluZS5zZXRFbmRQb2ludHMoYzAsIGMxKTsKICAgICAgICBjb25zdCBuMiA9IHNjcmF0Y2hSaHVtYkxpbmUuc3VyZmFjZURpc3RhbmNlIC8gbWluRGlzdGFuY2U7CiAgICAgICAgY29uc3QgY291bnREaXZpZGUgPSBNYXRoLm1heCgwLCBNYXRoLmNlaWwoTWF0aF9kZWZhdWx0LmxvZzIobjIpKSk7CiAgICAgICAgY29uc3Qgc3ViZGl2aXNpb25zID0gTWF0aC5wb3coMiwgY291bnREaXZpZGUpOwogICAgICAgIGNvbnN0IGxlbmd0aDJEID0gQ2FydGVzaWFuMl9kZWZhdWx0LmRpc3RhbmNlKHQwLCB0MSk7CiAgICAgICAgY29uc3QgZGlzdGFuY2VCZXR3ZWVuQ29vcmRzID0gbGVuZ3RoMkQgLyBzdWJkaXZpc2lvbnM7CiAgICAgICAgY29uc3QgdGV4Y29vcmRzID0gcmVzdWx0OwogICAgICAgIHRleGNvb3Jkcy5sZW5ndGggPSBzdWJkaXZpc2lvbnMgKiAyOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHN1YmRpdmlzaW9uczsgaTIrKykgewogICAgICAgICAgY29uc3QgdDIgPSBnZXRQb2ludEF0RGlzdGFuY2UyRCh0MCwgdDEsIGkyICogZGlzdGFuY2VCZXR3ZWVuQ29vcmRzLCBsZW5ndGgyRCk7CiAgICAgICAgICB0ZXhjb29yZHNbaW5kZXgrK10gPSB0MlswXTsKICAgICAgICAgIHRleGNvb3Jkc1tpbmRleCsrXSA9IHQyWzFdOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdGV4Y29vcmRzOwogICAgICB9OwogICAgICBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnN1YmRpdmlkZVJodW1iTGluZSA9IGZ1bmN0aW9uKGVsbGlwc29pZCwgcDAsIHAxLCBtaW5EaXN0YW5jZSwgcmVzdWx0KSB7CiAgICAgICAgY29uc3QgYzAgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocDAsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMwKTsKICAgICAgICBjb25zdCBjMSA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMSwgc2NyYXRjaENhcnRvZ3JhcGhpYzEpOwogICAgICAgIGNvbnN0IHJodW1iID0gbmV3IEVsbGlwc29pZFJodW1iTGluZV9kZWZhdWx0KGMwLCBjMSwgZWxsaXBzb2lkKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBbXTsKICAgICAgICB9CiAgICAgICAgaWYgKHJodW1iLnN1cmZhY2VEaXN0YW5jZSA8PSBtaW5EaXN0YW5jZSkgewogICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IDM7CiAgICAgICAgICByZXN1bHRbMF0gPSBwMC54OwogICAgICAgICAgcmVzdWx0WzFdID0gcDAueTsKICAgICAgICAgIHJlc3VsdFsyXSA9IHAwLno7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBjb25zdCBuMiA9IHJodW1iLnN1cmZhY2VEaXN0YW5jZSAvIG1pbkRpc3RhbmNlOwogICAgICAgIGNvbnN0IGNvdW50RGl2aWRlID0gTWF0aC5tYXgoMCwgTWF0aC5jZWlsKE1hdGhfZGVmYXVsdC5sb2cyKG4yKSkpOwogICAgICAgIGNvbnN0IG51bVZlcnRpY2VzID0gTWF0aC5wb3coMiwgY291bnREaXZpZGUpOwogICAgICAgIGNvbnN0IGRpc3RhbmNlQmV0d2VlblZlcnRpY2VzID0gcmh1bWIuc3VyZmFjZURpc3RhbmNlIC8gbnVtVmVydGljZXM7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gcmVzdWx0OwogICAgICAgIHBvc2l0aW9ucy5sZW5ndGggPSBudW1WZXJ0aWNlcyAqIDM7CiAgICAgICAgbGV0IGluZGV4ID0gMDsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtVmVydGljZXM7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IGMyID0gcmh1bWIuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSgKICAgICAgICAgICAgaTIgKiBkaXN0YW5jZUJldHdlZW5WZXJ0aWNlcywKICAgICAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzIyCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcDIgPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oYzIsIHNjcmF0Y2hDYXJ0ZXNpYW4wKTsKICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHAyLng7CiAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBwMi55OwogICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gcDIuejsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBvc2l0aW9uczsKICAgICAgfTsKICAgICAgc2NhbGVUb0dlb2RldGljSGVpZ2h0TjEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlVG9HZW9kZXRpY0hlaWdodE4yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY2FsZVRvR2VvZGV0aWNIZWlnaHRQMSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVUb0dlb2RldGljSGVpZ2h0UDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFBvbHlnb25HZW9tZXRyeUxpYnJhcnkuc2NhbGVUb0dlb2RldGljSGVpZ2h0RXh0cnVkZWQgPSBmdW5jdGlvbihnZW9tZXRyeSwgbWF4SGVpZ2h0LCBtaW5IZWlnaHQsIGVsbGlwc29pZCwgcGVyUG9zaXRpb25IZWlnaHQpIHsKICAgICAgICBlbGxpcHNvaWQgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCBuMSA9IHNjYWxlVG9HZW9kZXRpY0hlaWdodE4xOwogICAgICAgIGxldCBuMiA9IHNjYWxlVG9HZW9kZXRpY0hlaWdodE4yOwogICAgICAgIGNvbnN0IHAyID0gc2NhbGVUb0dlb2RldGljSGVpZ2h0UDE7CiAgICAgICAgbGV0IHAyMiA9IHNjYWxlVG9HZW9kZXRpY0hlaWdodFAyOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkpICYmIGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeS5hdHRyaWJ1dGVzKSAmJiBkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbikpIHsKICAgICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aCAvIDI7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBpMiwgcDIpOwogICAgICAgICAgICBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHAyLCBuMSk7CiAgICAgICAgICAgIHAyMiA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKHAyLCBwMjIpOwogICAgICAgICAgICBuMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG4xLCBtaW5IZWlnaHQsIG4yKTsKICAgICAgICAgICAgbjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHAyMiwgbjIsIG4yKTsKICAgICAgICAgICAgcG9zaXRpb25zW2kyICsgbGVuZ3RoXSA9IG4yLng7CiAgICAgICAgICAgIHBvc2l0aW9uc1tpMiArIDEgKyBsZW5ndGhdID0gbjIueTsKICAgICAgICAgICAgcG9zaXRpb25zW2kyICsgMiArIGxlbmd0aF0gPSBuMi56OwogICAgICAgICAgICBpZiAocGVyUG9zaXRpb25IZWlnaHQpIHsKICAgICAgICAgICAgICBwMjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocDIsIHAyMik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihuMSwgbWF4SGVpZ2h0LCBuMik7CiAgICAgICAgICAgIG4yID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwMjIsIG4yLCBuMik7CiAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0gPSBuMi54OwogICAgICAgICAgICBwb3NpdGlvbnNbaTIgKyAxXSA9IG4yLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1tpMiArIDJdID0gbjIuejsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGdlb21ldHJ5OwogICAgICB9OwogICAgICBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnBvbHlnb25PdXRsaW5lc0Zyb21IaWVyYXJjaHkgPSBmdW5jdGlvbihwb2x5Z29uSGllcmFyY2h5LCBzY2FsZVRvRWxsaXBzb2lkU3VyZmFjZSwgZWxsaXBzb2lkKSB7CiAgICAgICAgY29uc3QgcG9seWdvbnMgPSBbXTsKICAgICAgICBjb25zdCBxdWV1ZSA9IG5ldyBRdWV1ZV9kZWZhdWx0KCk7CiAgICAgICAgcXVldWUuZW5xdWV1ZShwb2x5Z29uSGllcmFyY2h5KTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IGoyOwogICAgICAgIGxldCBsZW5ndGg7CiAgICAgICAgd2hpbGUgKHF1ZXVlLmxlbmd0aCAhPT0gMCkgewogICAgICAgICAgY29uc3Qgb3V0ZXJOb2RlID0gcXVldWUuZGVxdWV1ZSgpOwogICAgICAgICAgbGV0IG91dGVyUmluZyA9IG91dGVyTm9kZS5wb3NpdGlvbnM7CiAgICAgICAgICBpZiAoc2NhbGVUb0VsbGlwc29pZFN1cmZhY2UpIHsKICAgICAgICAgICAgbGVuZ3RoID0gb3V0ZXJSaW5nLmxlbmd0aDsKICAgICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgICAgZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2Uob3V0ZXJSaW5nW2kyXSwgb3V0ZXJSaW5nW2kyXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIG91dGVyUmluZyA9IGFycmF5UmVtb3ZlRHVwbGljYXRlc19kZWZhdWx0KAogICAgICAgICAgICBvdXRlclJpbmcsCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uLAogICAgICAgICAgICB0cnVlCiAgICAgICAgICApOwogICAgICAgICAgaWYgKG91dGVyUmluZy5sZW5ndGggPCAzKSB7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgbnVtQ2hpbGRyZW4gPSBvdXRlck5vZGUuaG9sZXMgPyBvdXRlck5vZGUuaG9sZXMubGVuZ3RoIDogMDsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bUNoaWxkcmVuOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IGhvbGUgPSBvdXRlck5vZGUuaG9sZXNbaTJdOwogICAgICAgICAgICBsZXQgaG9sZVBvc2l0aW9ucyA9IGhvbGUucG9zaXRpb25zOwogICAgICAgICAgICBpZiAoc2NhbGVUb0VsbGlwc29pZFN1cmZhY2UpIHsKICAgICAgICAgICAgICBsZW5ndGggPSBob2xlUG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBsZW5ndGg7ICsrajIpIHsKICAgICAgICAgICAgICAgIGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKGhvbGVQb3NpdGlvbnNbajJdLCBob2xlUG9zaXRpb25zW2oyXSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGhvbGVQb3NpdGlvbnMgPSBhcnJheVJlbW92ZUR1cGxpY2F0ZXNfZGVmYXVsdCgKICAgICAgICAgICAgICBob2xlUG9zaXRpb25zLAogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uLAogICAgICAgICAgICAgIHRydWUKICAgICAgICAgICAgKTsKICAgICAgICAgICAgaWYgKGhvbGVQb3NpdGlvbnMubGVuZ3RoIDwgMykgewogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvbHlnb25zLnB1c2goaG9sZVBvc2l0aW9ucyk7CiAgICAgICAgICAgIGxldCBudW1HcmFuZGNoaWxkcmVuID0gMDsKICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChob2xlLmhvbGVzKSkgewogICAgICAgICAgICAgIG51bUdyYW5kY2hpbGRyZW4gPSBob2xlLmhvbGVzLmxlbmd0aDsKICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBudW1HcmFuZGNoaWxkcmVuOyBqMisrKSB7CiAgICAgICAgICAgICAgcXVldWUuZW5xdWV1ZShob2xlLmhvbGVzW2oyXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHBvbHlnb25zLnB1c2gob3V0ZXJSaW5nKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBvbHlnb25zOwogICAgICB9OwogICAgICBzY3JhdGNoUmh1bWJJbnRlcnNlY3Rpb24gPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzMgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zcGxpdFBvbHlnb25zT25FcXVhdG9yID0gZnVuY3Rpb24ob3V0ZXJSaW5ncywgZWxsaXBzb2lkLCBhcmNUeXBlLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBbXTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnNwbGljZSgwLCAwLCAuLi5vdXRlclJpbmdzKTsKICAgICAgICByZXN1bHQubGVuZ3RoID0gb3V0ZXJSaW5ncy5sZW5ndGg7CiAgICAgICAgbGV0IGN1cnJlbnRQb2x5Z29uID0gMDsKICAgICAgICB3aGlsZSAoY3VycmVudFBvbHlnb24gPCByZXN1bHQubGVuZ3RoKSB7CiAgICAgICAgICBjb25zdCBvdXRlclJpbmcgPSByZXN1bHRbY3VycmVudFBvbHlnb25dOwogICAgICAgICAgY29uc3QgcG9zaXRpb25zID0gb3V0ZXJSaW5nLnNsaWNlKCk7CiAgICAgICAgICBpZiAob3V0ZXJSaW5nLmxlbmd0aCA8IDMpIHsKICAgICAgICAgICAgcmVzdWx0W2N1cnJlbnRQb2x5Z29uXSA9IHBvc2l0aW9uczsKICAgICAgICAgICAgKytjdXJyZW50UG9seWdvbjsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBlZGdlc09uUGxhbmUgPSBjb21wdXRlRWRnZXNPblBsYW5lKHBvc2l0aW9ucywgZWxsaXBzb2lkLCBhcmNUeXBlKTsKICAgICAgICAgIGlmIChwb3NpdGlvbnMubGVuZ3RoID09PSBvdXRlclJpbmcubGVuZ3RoIHx8IGVkZ2VzT25QbGFuZS5sZW5ndGggPD0gMSkgewogICAgICAgICAgICByZXN1bHRbY3VycmVudFBvbHlnb25dID0gcG9zaXRpb25zOwogICAgICAgICAgICArK2N1cnJlbnRQb2x5Z29uOwogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICAgIGVkZ2VzT25QbGFuZS5zb3J0KChhNCwgYjIpID0+IHsKICAgICAgICAgICAgcmV0dXJuIGE0LnRoZXRhIC0gYjIudGhldGE7CiAgICAgICAgICB9KTsKICAgICAgICAgIGNvbnN0IG5vcnRoID0gcG9zaXRpb25zWzBdLnogPj0gMDsKICAgICAgICAgIGN1cnJlbnRQb2x5Z29uID0gd2lyZVBvbHlnb24oCiAgICAgICAgICAgIHJlc3VsdCwKICAgICAgICAgICAgY3VycmVudFBvbHlnb24sCiAgICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgICAgZWRnZXNPblBsYW5lLAogICAgICAgICAgICAxLAogICAgICAgICAgICAwLAogICAgICAgICAgICBub3J0aAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5wb2x5Z29uc0Zyb21IaWVyYXJjaHkgPSBmdW5jdGlvbihwb2x5Z29uSGllcmFyY2h5LCBrZWVwRHVwbGljYXRlcywgcHJvamVjdFBvaW50c1RvMkQsIHNjYWxlVG9FbGxpcHNvaWRTdXJmYWNlLCBlbGxpcHNvaWQsIHNwbGl0UG9seWdvbnMpIHsKICAgICAgICBjb25zdCBoaWVyYXJjaHkgPSBbXTsKICAgICAgICBjb25zdCBwb2x5Z29ucyA9IFtdOwogICAgICAgIGNvbnN0IHF1ZXVlID0gbmV3IFF1ZXVlX2RlZmF1bHQoKTsKICAgICAgICBxdWV1ZS5lbnF1ZXVlKHBvbHlnb25IaWVyYXJjaHkpOwogICAgICAgIGxldCBzcGxpdCA9IGRlZmluZWRfZGVmYXVsdChzcGxpdFBvbHlnb25zKTsKICAgICAgICB3aGlsZSAocXVldWUubGVuZ3RoICE9PSAwKSB7CiAgICAgICAgICBjb25zdCBvdXRlck5vZGUgPSBxdWV1ZS5kZXF1ZXVlKCk7CiAgICAgICAgICBsZXQgb3V0ZXJSaW5nID0gb3V0ZXJOb2RlLnBvc2l0aW9uczsKICAgICAgICAgIGNvbnN0IGhvbGVzID0gb3V0ZXJOb2RlLmhvbGVzOwogICAgICAgICAgbGV0IGkyOwogICAgICAgICAgbGV0IGxlbmd0aDsKICAgICAgICAgIGlmIChzY2FsZVRvRWxsaXBzb2lkU3VyZmFjZSkgewogICAgICAgICAgICBsZW5ndGggPSBvdXRlclJpbmcubGVuZ3RoOwogICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgICBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShvdXRlclJpbmdbaTJdLCBvdXRlclJpbmdbaTJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKCFrZWVwRHVwbGljYXRlcykgewogICAgICAgICAgICBvdXRlclJpbmcgPSBhcnJheVJlbW92ZUR1cGxpY2F0ZXNfZGVmYXVsdCgKICAgICAgICAgICAgICBvdXRlclJpbmcsCiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24sCiAgICAgICAgICAgICAgdHJ1ZQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgICAgaWYgKG91dGVyUmluZy5sZW5ndGggPCAzKSB7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgbGV0IHBvc2l0aW9uczJEID0gcHJvamVjdFBvaW50c1RvMkQob3V0ZXJSaW5nKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9uczJEKSkgewogICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhvbGVJbmRpY2VzID0gW107CiAgICAgICAgICBsZXQgb3JpZ2luYWxXaW5kaW5nT3JkZXIgPSBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5jb21wdXRlV2luZGluZ09yZGVyMkQocG9zaXRpb25zMkQpOwogICAgICAgICAgaWYgKG9yaWdpbmFsV2luZGluZ09yZGVyID09PSBXaW5kaW5nT3JkZXJfZGVmYXVsdC5DTE9DS1dJU0UpIHsKICAgICAgICAgICAgcG9zaXRpb25zMkQucmV2ZXJzZSgpOwogICAgICAgICAgICBvdXRlclJpbmcgPSBvdXRlclJpbmcuc2xpY2UoKS5yZXZlcnNlKCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoc3BsaXQpIHsKICAgICAgICAgICAgc3BsaXQgPSBmYWxzZTsKICAgICAgICAgICAgbGV0IHBvbHlnb25zMiA9IFtvdXRlclJpbmddOwogICAgICAgICAgICBwb2x5Z29uczIgPSBzcGxpdFBvbHlnb25zKHBvbHlnb25zMiwgcG9seWdvbnMyKTsKICAgICAgICAgICAgaWYgKHBvbHlnb25zMi5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgZm9yIChjb25zdCBwb3NpdGlvbnMyIG9mIHBvbHlnb25zMikgewogICAgICAgICAgICAgICAgcXVldWUuZW5xdWV1ZShuZXcgUG9seWdvbkhpZXJhcmNoeV9kZWZhdWx0KHBvc2l0aW9uczIsIGhvbGVzKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgcG9zaXRpb25zID0gb3V0ZXJSaW5nLnNsaWNlKCk7CiAgICAgICAgICBjb25zdCBudW1DaGlsZHJlbiA9IGRlZmluZWRfZGVmYXVsdChob2xlcykgPyBob2xlcy5sZW5ndGggOiAwOwogICAgICAgICAgY29uc3QgcG9seWdvbkhvbGVzID0gW107CiAgICAgICAgICBsZXQgajI7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1DaGlsZHJlbjsgaTIrKykgewogICAgICAgICAgICBjb25zdCBob2xlID0gaG9sZXNbaTJdOwogICAgICAgICAgICBsZXQgaG9sZVBvc2l0aW9ucyA9IGhvbGUucG9zaXRpb25zOwogICAgICAgICAgICBpZiAoc2NhbGVUb0VsbGlwc29pZFN1cmZhY2UpIHsKICAgICAgICAgICAgICBsZW5ndGggPSBob2xlUG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBsZW5ndGg7ICsrajIpIHsKICAgICAgICAgICAgICAgIGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKGhvbGVQb3NpdGlvbnNbajJdLCBob2xlUG9zaXRpb25zW2oyXSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICgha2VlcER1cGxpY2F0ZXMpIHsKICAgICAgICAgICAgICBob2xlUG9zaXRpb25zID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICAgICAgICBob2xlUG9zaXRpb25zLAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24sCiAgICAgICAgICAgICAgICB0cnVlCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoaG9sZVBvc2l0aW9ucy5sZW5ndGggPCAzKSB7CiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgaG9sZVBvc2l0aW9uczJEID0gcHJvamVjdFBvaW50c1RvMkQoaG9sZVBvc2l0aW9ucyk7CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGhvbGVQb3NpdGlvbnMyRCkpIHsKICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBvcmlnaW5hbFdpbmRpbmdPcmRlciA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LmNvbXB1dGVXaW5kaW5nT3JkZXIyRChob2xlUG9zaXRpb25zMkQpOwogICAgICAgICAgICBpZiAob3JpZ2luYWxXaW5kaW5nT3JkZXIgPT09IFdpbmRpbmdPcmRlcl9kZWZhdWx0LkNMT0NLV0lTRSkgewogICAgICAgICAgICAgIGhvbGVQb3NpdGlvbnMyRC5yZXZlcnNlKCk7CiAgICAgICAgICAgICAgaG9sZVBvc2l0aW9ucyA9IGhvbGVQb3NpdGlvbnMuc2xpY2UoKS5yZXZlcnNlKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcG9seWdvbkhvbGVzLnB1c2goaG9sZVBvc2l0aW9ucyk7CiAgICAgICAgICAgIGhvbGVJbmRpY2VzLnB1c2gocG9zaXRpb25zLmxlbmd0aCk7CiAgICAgICAgICAgIHBvc2l0aW9ucyA9IHBvc2l0aW9ucy5jb25jYXQoaG9sZVBvc2l0aW9ucyk7CiAgICAgICAgICAgIHBvc2l0aW9uczJEID0gcG9zaXRpb25zMkQuY29uY2F0KGhvbGVQb3NpdGlvbnMyRCk7CiAgICAgICAgICAgIGxldCBudW1HcmFuZGNoaWxkcmVuID0gMDsKICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChob2xlLmhvbGVzKSkgewogICAgICAgICAgICAgIG51bUdyYW5kY2hpbGRyZW4gPSBob2xlLmhvbGVzLmxlbmd0aDsKICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBudW1HcmFuZGNoaWxkcmVuOyBqMisrKSB7CiAgICAgICAgICAgICAgcXVldWUuZW5xdWV1ZShob2xlLmhvbGVzW2oyXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGhpZXJhcmNoeS5wdXNoKHsKICAgICAgICAgICAgb3V0ZXJSaW5nLAogICAgICAgICAgICBob2xlczogcG9seWdvbkhvbGVzCiAgICAgICAgICB9KTsKICAgICAgICAgIHBvbHlnb25zLnB1c2goewogICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgIHBvc2l0aW9uczJELAogICAgICAgICAgICBob2xlczogaG9sZUluZGljZXMKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgaGllcmFyY2h5LAogICAgICAgICAgcG9seWdvbnMKICAgICAgICB9OwogICAgICB9OwogICAgICBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVDYXJ0ZXNpYW4yID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVDYXJ0ZXNpYW4zID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVRdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBjb21wdXRlQm91bmRpbmdSZWN0YW5nbGVNYXRyaXgzID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LmNvbXB1dGVCb3VuZGluZ1JlY3RhbmdsZSA9IGZ1bmN0aW9uKHBsYW5lTm9ybWFsLCBwcm9qZWN0UG9pbnRUbzJELCBwb3NpdGlvbnMsIGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICBjb25zdCByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgcGxhbmVOb3JtYWwsCiAgICAgICAgICBhbmdsZSwKICAgICAgICAgIGNvbXB1dGVCb3VuZGluZ1JlY3RhbmdsZVF1YXRlcm5pb24KICAgICAgICApOwogICAgICAgIGNvbnN0IHRleHR1cmVNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24oCiAgICAgICAgICByb3RhdGlvbiwKICAgICAgICAgIGNvbXB1dGVCb3VuZGluZ1JlY3RhbmdsZU1hdHJpeDMKICAgICAgICApOwogICAgICAgIGxldCBtaW5YID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgIGxldCBtYXhYID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgICAgIGxldCBtaW5ZID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgIGxldCBtYXhZID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY29uc3QgcDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0sCiAgICAgICAgICAgIGNvbXB1dGVCb3VuZGluZ1JlY3RhbmdsZUNhcnRlc2lhbjMKICAgICAgICAgICk7CiAgICAgICAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3Rvcih0ZXh0dXJlTWF0cml4LCBwMiwgcDIpOwogICAgICAgICAgY29uc3Qgc3QyID0gcHJvamVjdFBvaW50VG8yRChwMiwgY29tcHV0ZUJvdW5kaW5nUmVjdGFuZ2xlQ2FydGVzaWFuMik7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHN0MikpIHsKICAgICAgICAgICAgbWluWCA9IE1hdGgubWluKG1pblgsIHN0Mi54KTsKICAgICAgICAgICAgbWF4WCA9IE1hdGgubWF4KG1heFgsIHN0Mi54KTsKICAgICAgICAgICAgbWluWSA9IE1hdGgubWluKG1pblksIHN0Mi55KTsKICAgICAgICAgICAgbWF4WSA9IE1hdGgubWF4KG1heFksIHN0Mi55KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmVzdWx0LnggPSBtaW5YOwogICAgICAgIHJlc3VsdC55ID0gbWluWTsKICAgICAgICByZXN1bHQud2lkdGggPSBtYXhYIC0gbWluWDsKICAgICAgICByZXN1bHQuaGVpZ2h0ID0gbWF4WSAtIG1pblk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5jcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnMgPSBmdW5jdGlvbihlbGxpcHNvaWQsIHBvbHlnb24yLCB0ZXh0dXJlQ29vcmRpbmF0ZXMsIGdyYW51bGFyaXR5LCBwZXJQb3NpdGlvbkhlaWdodCwgdmVydGV4Rm9ybWF0LCBhcmNUeXBlKSB7CiAgICAgICAgbGV0IGluZGljZXMgPSBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC50cmlhbmd1bGF0ZShwb2x5Z29uMi5wb3NpdGlvbnMyRCwgcG9seWdvbjIuaG9sZXMpOwogICAgICAgIGlmIChpbmRpY2VzLmxlbmd0aCA8IDMpIHsKICAgICAgICAgIGluZGljZXMgPSBbMCwgMSwgMl07CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHBvbHlnb24yLnBvc2l0aW9uczsKICAgICAgICBjb25zdCBoYXNUZXhjb29yZHMgPSBkZWZpbmVkX2RlZmF1bHQodGV4dHVyZUNvb3JkaW5hdGVzKTsKICAgICAgICBjb25zdCB0ZXhjb29yZHMgPSBoYXNUZXhjb29yZHMgPyB0ZXh0dXJlQ29vcmRpbmF0ZXMucG9zaXRpb25zIDogdm9pZCAwOwogICAgICAgIGlmIChwZXJQb3NpdGlvbkhlaWdodCkgewogICAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgIGNvbnN0IGZsYXR0ZW5lZFBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGggKiAzKTsKICAgICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IHAyID0gcG9zaXRpb25zW2kyXTsKICAgICAgICAgICAgZmxhdHRlbmVkUG9zaXRpb25zW2luZGV4KytdID0gcDIueDsKICAgICAgICAgICAgZmxhdHRlbmVkUG9zaXRpb25zW2luZGV4KytdID0gcDIueTsKICAgICAgICAgICAgZmxhdHRlbmVkUG9zaXRpb25zW2luZGV4KytdID0gcDIuejsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGdlb21ldHJ5T3B0aW9ucyA9IHsKICAgICAgICAgICAgYXR0cmlidXRlczogewogICAgICAgICAgICAgIHBvc2l0aW9uOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICAgICAgdmFsdWVzOiBmbGF0dGVuZWRQb3NpdGlvbnMKICAgICAgICAgICAgICB9KQogICAgICAgICAgICB9LAogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTCiAgICAgICAgICB9OwogICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICBnZW9tZXRyeU9wdGlvbnMuYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICAgIHZhbHVlczogQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2tBcnJheSh0ZXhjb29yZHMpCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgZ2VvbWV0cnkgPSBuZXcgR2VvbWV0cnlfZGVmYXVsdChnZW9tZXRyeU9wdGlvbnMpOwogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgICAgcmV0dXJuIEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5jb21wdXRlTm9ybWFsKGdlb21ldHJ5KTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBnZW9tZXRyeTsKICAgICAgICB9CiAgICAgICAgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQykgewogICAgICAgICAgcmV0dXJuIFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LmNvbXB1dGVTdWJkaXZpc2lvbigKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICAgIHRleGNvb3JkcywKICAgICAgICAgICAgZ3JhbnVsYXJpdHkKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgICAgIHJldHVybiBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5jb21wdXRlUmh1bWJMaW5lU3ViZGl2aXNpb24oCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICB0ZXhjb29yZHMsCiAgICAgICAgICAgIGdyYW51bGFyaXR5CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgfTsKICAgICAgY29tcHV0ZVdhbGxUZXhjb29yZHNTdWJkaXZpZGVkID0gW107CiAgICAgIGNvbXB1dGVXYWxsSW5kaWNlc1N1YmRpdmlkZWQgPSBbXTsKICAgICAgcDFTY3JhdGNoMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcDJTY3JhdGNoMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgUG9seWdvbkdlb21ldHJ5TGlicmFyeS5jb21wdXRlV2FsbEdlb21ldHJ5ID0gZnVuY3Rpb24ocG9zaXRpb25zLCB0ZXh0dXJlQ29vcmRpbmF0ZXMsIGVsbGlwc29pZCwgZ3JhbnVsYXJpdHksIHBlclBvc2l0aW9uSGVpZ2h0LCBhcmNUeXBlKSB7CiAgICAgICAgbGV0IGVkZ2VQb3NpdGlvbnM7CiAgICAgICAgbGV0IHRvcEVkZ2VMZW5ndGg7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGxldCBwMTsKICAgICAgICBsZXQgcDI7CiAgICAgICAgbGV0IHQxOwogICAgICAgIGxldCB0MjsKICAgICAgICBsZXQgZWRnZVRleGNvb3JkczsKICAgICAgICBsZXQgdG9wRWRnZVRleGNvb3JkTGVuZ3RoOwogICAgICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgbGV0IHRleHR1cmVJbmRleCA9IDA7CiAgICAgICAgY29uc3QgaGFzVGV4Y29vcmRzID0gZGVmaW5lZF9kZWZhdWx0KHRleHR1cmVDb29yZGluYXRlcyk7CiAgICAgICAgY29uc3QgdGV4Y29vcmRzID0gaGFzVGV4Y29vcmRzID8gdGV4dHVyZUNvb3JkaW5hdGVzLnBvc2l0aW9ucyA6IHZvaWQgMDsKICAgICAgICBpZiAoIXBlclBvc2l0aW9uSGVpZ2h0KSB7CiAgICAgICAgICBjb25zdCBtaW5EaXN0YW5jZSA9IE1hdGhfZGVmYXVsdC5jaG9yZExlbmd0aCgKICAgICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICAgIGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzCiAgICAgICAgICApOwogICAgICAgICAgbGV0IG51bVZlcnRpY2VzID0gMDsKICAgICAgICAgIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMpIHsKICAgICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgICAgbnVtVmVydGljZXMgKz0gUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVMaW5lQ291bnQoCiAgICAgICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICAgICAgcG9zaXRpb25zWyhpMiArIDEpICUgbGVuZ3RoXSwKICAgICAgICAgICAgICAgIG1pbkRpc3RhbmNlCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgICAgbnVtVmVydGljZXMgKz0gUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVSaHVtYkxpbmVDb3VudCgKICAgICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0sCiAgICAgICAgICAgICAgICBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdLAogICAgICAgICAgICAgICAgbWluRGlzdGFuY2UKICAgICAgICAgICAgICApOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICB0b3BFZGdlTGVuZ3RoID0gKG51bVZlcnRpY2VzICsgbGVuZ3RoKSAqIDM7CiAgICAgICAgICBlZGdlUG9zaXRpb25zID0gbmV3IEFycmF5KHRvcEVkZ2VMZW5ndGggKiAyKTsKICAgICAgICAgIGlmIChoYXNUZXhjb29yZHMpIHsKICAgICAgICAgICAgdG9wRWRnZVRleGNvb3JkTGVuZ3RoID0gKG51bVZlcnRpY2VzICsgbGVuZ3RoKSAqIDI7CiAgICAgICAgICAgIGVkZ2VUZXhjb29yZHMgPSBuZXcgQXJyYXkodG9wRWRnZVRleGNvb3JkTGVuZ3RoICogMik7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgcDEgPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgICBwMiA9IHBvc2l0aW9uc1soaTIgKyAxKSAlIGxlbmd0aF07CiAgICAgICAgICAgIGxldCB0ZW1wUG9zaXRpb25zOwogICAgICAgICAgICBsZXQgdGVtcFRleGNvb3JkczsKICAgICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICAgIHQxID0gdGV4Y29vcmRzW2kyXTsKICAgICAgICAgICAgICB0MiA9IHRleGNvb3Jkc1soaTIgKyAxKSAlIGxlbmd0aF07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQykgewogICAgICAgICAgICAgIHRlbXBQb3NpdGlvbnMgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5LnN1YmRpdmlkZUxpbmUoCiAgICAgICAgICAgICAgICBwMSwKICAgICAgICAgICAgICAgIHAyLAogICAgICAgICAgICAgICAgbWluRGlzdGFuY2UsCiAgICAgICAgICAgICAgICBjb21wdXRlV2FsbEluZGljZXNTdWJkaXZpZGVkCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgICB0ZW1wVGV4Y29vcmRzID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVUZXhjb29yZExpbmUoCiAgICAgICAgICAgICAgICAgIHQxLAogICAgICAgICAgICAgICAgICB0MiwKICAgICAgICAgICAgICAgICAgcDEsCiAgICAgICAgICAgICAgICAgIHAyLAogICAgICAgICAgICAgICAgICBtaW5EaXN0YW5jZSwKICAgICAgICAgICAgICAgICAgY29tcHV0ZVdhbGxUZXhjb29yZHNTdWJkaXZpZGVkCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgICAgICAgICB0ZW1wUG9zaXRpb25zID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVSaHVtYkxpbmUoCiAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICBwMSwKICAgICAgICAgICAgICAgIHAyLAogICAgICAgICAgICAgICAgbWluRGlzdGFuY2UsCiAgICAgICAgICAgICAgICBjb21wdXRlV2FsbEluZGljZXNTdWJkaXZpZGVkCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgICB0ZW1wVGV4Y29vcmRzID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeS5zdWJkaXZpZGVUZXhjb29yZFJodW1iTGluZSgKICAgICAgICAgICAgICAgICAgdDEsCiAgICAgICAgICAgICAgICAgIHQyLAogICAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICAgIHAxLAogICAgICAgICAgICAgICAgICBwMiwKICAgICAgICAgICAgICAgICAgbWluRGlzdGFuY2UsCiAgICAgICAgICAgICAgICAgIGNvbXB1dGVXYWxsVGV4Y29vcmRzU3ViZGl2aWRlZAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgdGVtcFBvc2l0aW9uc0xlbmd0aCA9IHRlbXBQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgdGVtcFBvc2l0aW9uc0xlbmd0aDsgKytqMiwgKytpbmRleCkgewogICAgICAgICAgICAgIGVkZ2VQb3NpdGlvbnNbaW5kZXhdID0gdGVtcFBvc2l0aW9uc1tqMl07CiAgICAgICAgICAgICAgZWRnZVBvc2l0aW9uc1tpbmRleCArIHRvcEVkZ2VMZW5ndGhdID0gdGVtcFBvc2l0aW9uc1tqMl07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWRnZVBvc2l0aW9uc1tpbmRleF0gPSBwMi54OwogICAgICAgICAgICBlZGdlUG9zaXRpb25zW2luZGV4ICsgdG9wRWRnZUxlbmd0aF0gPSBwMi54OwogICAgICAgICAgICArK2luZGV4OwogICAgICAgICAgICBlZGdlUG9zaXRpb25zW2luZGV4XSA9IHAyLnk7CiAgICAgICAgICAgIGVkZ2VQb3NpdGlvbnNbaW5kZXggKyB0b3BFZGdlTGVuZ3RoXSA9IHAyLnk7CiAgICAgICAgICAgICsraW5kZXg7CiAgICAgICAgICAgIGVkZ2VQb3NpdGlvbnNbaW5kZXhdID0gcDIuejsKICAgICAgICAgICAgZWRnZVBvc2l0aW9uc1tpbmRleCArIHRvcEVkZ2VMZW5ndGhdID0gcDIuejsKICAgICAgICAgICAgKytpbmRleDsKICAgICAgICAgICAgaWYgKGhhc1RleGNvb3JkcykgewogICAgICAgICAgICAgIGNvbnN0IHRlbXBUZXhjb29yZHNMZW5ndGggPSB0ZW1wVGV4Y29vcmRzLmxlbmd0aDsKICAgICAgICAgICAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgdGVtcFRleGNvb3Jkc0xlbmd0aDsgKytrMiwgKyt0ZXh0dXJlSW5kZXgpIHsKICAgICAgICAgICAgICAgIGVkZ2VUZXhjb29yZHNbdGV4dHVyZUluZGV4XSA9IHRlbXBUZXhjb29yZHNbazJdOwogICAgICAgICAgICAgICAgZWRnZVRleGNvb3Jkc1t0ZXh0dXJlSW5kZXggKyB0b3BFZGdlVGV4Y29vcmRMZW5ndGhdID0gdGVtcFRleGNvb3Jkc1trMl07CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGVkZ2VUZXhjb29yZHNbdGV4dHVyZUluZGV4XSA9IHQyLng7CiAgICAgICAgICAgICAgZWRnZVRleGNvb3Jkc1t0ZXh0dXJlSW5kZXggKyB0b3BFZGdlVGV4Y29vcmRMZW5ndGhdID0gdDIueDsKICAgICAgICAgICAgICArK3RleHR1cmVJbmRleDsKICAgICAgICAgICAgICBlZGdlVGV4Y29vcmRzW3RleHR1cmVJbmRleF0gPSB0Mi55OwogICAgICAgICAgICAgIGVkZ2VUZXhjb29yZHNbdGV4dHVyZUluZGV4ICsgdG9wRWRnZVRleGNvb3JkTGVuZ3RoXSA9IHQyLnk7CiAgICAgICAgICAgICAgKyt0ZXh0dXJlSW5kZXg7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgdG9wRWRnZUxlbmd0aCA9IGxlbmd0aCAqIDMgKiAyOwogICAgICAgICAgZWRnZVBvc2l0aW9ucyA9IG5ldyBBcnJheSh0b3BFZGdlTGVuZ3RoICogMik7CiAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgIHRvcEVkZ2VUZXhjb29yZExlbmd0aCA9IGxlbmd0aCAqIDIgKiAyOwogICAgICAgICAgICBlZGdlVGV4Y29vcmRzID0gbmV3IEFycmF5KHRvcEVkZ2VUZXhjb29yZExlbmd0aCAqIDIpOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIHAxID0gcG9zaXRpb25zW2kyXTsKICAgICAgICAgICAgcDIgPSBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdOwogICAgICAgICAgICBlZGdlUG9zaXRpb25zW2luZGV4XSA9IGVkZ2VQb3NpdGlvbnNbaW5kZXggKyB0b3BFZGdlTGVuZ3RoXSA9IHAxLng7CiAgICAgICAgICAgICsraW5kZXg7CiAgICAgICAgICAgIGVkZ2VQb3NpdGlvbnNbaW5kZXhdID0gZWRnZVBvc2l0aW9uc1tpbmRleCArIHRvcEVkZ2VMZW5ndGhdID0gcDEueTsKICAgICAgICAgICAgKytpbmRleDsKICAgICAgICAgICAgZWRnZVBvc2l0aW9uc1tpbmRleF0gPSBlZGdlUG9zaXRpb25zW2luZGV4ICsgdG9wRWRnZUxlbmd0aF0gPSBwMS56OwogICAgICAgICAgICArK2luZGV4OwogICAgICAgICAgICBlZGdlUG9zaXRpb25zW2luZGV4XSA9IGVkZ2VQb3NpdGlvbnNbaW5kZXggKyB0b3BFZGdlTGVuZ3RoXSA9IHAyLng7CiAgICAgICAgICAgICsraW5kZXg7CiAgICAgICAgICAgIGVkZ2VQb3NpdGlvbnNbaW5kZXhdID0gZWRnZVBvc2l0aW9uc1tpbmRleCArIHRvcEVkZ2VMZW5ndGhdID0gcDIueTsKICAgICAgICAgICAgKytpbmRleDsKICAgICAgICAgICAgZWRnZVBvc2l0aW9uc1tpbmRleF0gPSBlZGdlUG9zaXRpb25zW2luZGV4ICsgdG9wRWRnZUxlbmd0aF0gPSBwMi56OwogICAgICAgICAgICArK2luZGV4OwogICAgICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICAgICAgdDEgPSB0ZXhjb29yZHNbaTJdOwogICAgICAgICAgICAgIHQyID0gdGV4Y29vcmRzWyhpMiArIDEpICUgbGVuZ3RoXTsKICAgICAgICAgICAgICBlZGdlVGV4Y29vcmRzW3RleHR1cmVJbmRleF0gPSBlZGdlVGV4Y29vcmRzW3RleHR1cmVJbmRleCArIHRvcEVkZ2VUZXhjb29yZExlbmd0aF0gPSB0MS54OwogICAgICAgICAgICAgICsrdGV4dHVyZUluZGV4OwogICAgICAgICAgICAgIGVkZ2VUZXhjb29yZHNbdGV4dHVyZUluZGV4XSA9IGVkZ2VUZXhjb29yZHNbdGV4dHVyZUluZGV4ICsgdG9wRWRnZVRleGNvb3JkTGVuZ3RoXSA9IHQxLnk7CiAgICAgICAgICAgICAgKyt0ZXh0dXJlSW5kZXg7CiAgICAgICAgICAgICAgZWRnZVRleGNvb3Jkc1t0ZXh0dXJlSW5kZXhdID0gZWRnZVRleGNvb3Jkc1t0ZXh0dXJlSW5kZXggKyB0b3BFZGdlVGV4Y29vcmRMZW5ndGhdID0gdDIueDsKICAgICAgICAgICAgICArK3RleHR1cmVJbmRleDsKICAgICAgICAgICAgICBlZGdlVGV4Y29vcmRzW3RleHR1cmVJbmRleF0gPSBlZGdlVGV4Y29vcmRzW3RleHR1cmVJbmRleCArIHRvcEVkZ2VUZXhjb29yZExlbmd0aF0gPSB0Mi55OwogICAgICAgICAgICAgICsrdGV4dHVyZUluZGV4OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGxlbmd0aCA9IGVkZ2VQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgIGxlbmd0aCAvIDMsCiAgICAgICAgICBsZW5ndGggLSBwb3NpdGlvbnMubGVuZ3RoICogNgogICAgICAgICk7CiAgICAgICAgbGV0IGVkZ2VJbmRleCA9IDA7CiAgICAgICAgbGVuZ3RoIC89IDY7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBVTCA9IGkyOwogICAgICAgICAgY29uc3QgVVIgPSBVTCArIDE7CiAgICAgICAgICBjb25zdCBMTCA9IFVMICsgbGVuZ3RoOwogICAgICAgICAgY29uc3QgTFIgPSBMTCArIDE7CiAgICAgICAgICBwMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoZWRnZVBvc2l0aW9ucywgVUwgKiAzLCBwMVNjcmF0Y2gyKTsKICAgICAgICAgIHAyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShlZGdlUG9zaXRpb25zLCBVUiAqIDMsIHAyU2NyYXRjaDIpOwogICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBwMSwKICAgICAgICAgICAgcDIsCiAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAsCiAgICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAKICAgICAgICAgICkpIHsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IFVMOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBMTDsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gVVI7CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IFVSOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBMTDsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gTFI7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJ5T3B0aW9ucyA9IHsKICAgICAgICAgIGF0dHJpYnV0ZXM6IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCh7CiAgICAgICAgICAgIHBvc2l0aW9uOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBlZGdlUG9zaXRpb25zCiAgICAgICAgICAgIH0pCiAgICAgICAgICB9KSwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTCiAgICAgICAgfTsKICAgICAgICBpZiAoaGFzVGV4Y29vcmRzKSB7CiAgICAgICAgICBnZW9tZXRyeU9wdGlvbnMuYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgIHZhbHVlczogZWRnZVRleGNvb3JkcwogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJ5ID0gbmV3IEdlb21ldHJ5X2RlZmF1bHQoZ2VvbWV0cnlPcHRpb25zKTsKICAgICAgICByZXR1cm4gZ2VvbWV0cnk7CiAgICAgIH07CiAgICAgIFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdCA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Db3BsYW5hclBvbHlnb25HZW9tZXRyeS5qcwogIGZ1bmN0aW9uIGNyZWF0ZUdlb21ldHJ5RnJvbVBvbHlnb24ocG9seWdvbjIsIHZlcnRleEZvcm1hdCwgYm91bmRpbmdSZWN0YW5nbGUsIHN0Um90YXRpb24sIGhhcmRjb2RlZFRleHR1cmVDb29yZGluYXRlcywgcHJvamVjdFBvaW50VG8yRCwgbm9ybWFsMiwgdGFuZ2VudCwgYml0YW5nZW50KSB7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBwb2x5Z29uMi5wb3NpdGlvbnM7CiAgICBsZXQgaW5kaWNlcyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnRyaWFuZ3VsYXRlKHBvbHlnb24yLnBvc2l0aW9uczJELCBwb2x5Z29uMi5ob2xlcyk7CiAgICBpZiAoaW5kaWNlcy5sZW5ndGggPCAzKSB7CiAgICAgIGluZGljZXMgPSBbMCwgMSwgMl07CiAgICB9CiAgICBjb25zdCBuZXdJbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIHBvc2l0aW9ucy5sZW5ndGgsCiAgICAgIGluZGljZXMubGVuZ3RoCiAgICApOwogICAgbmV3SW5kaWNlcy5zZXQoaW5kaWNlcyk7CiAgICBsZXQgdGV4dHVyZU1hdHJpeCA9IHRleHR1cmVNYXRyaXhTY3JhdGNoMjsKICAgIGlmIChzdFJvdGF0aW9uICE9PSAwKSB7CiAgICAgIGxldCByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgIG5vcm1hbDIsCiAgICAgICAgc3RSb3RhdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uU2NyYXRjaDIKICAgICAgKTsKICAgICAgdGV4dHVyZU1hdHJpeCA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tUXVhdGVybmlvbihyb3RhdGlvbiwgdGV4dHVyZU1hdHJpeCk7CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgcm90YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuZnJvbUF4aXNBbmdsZSgKICAgICAgICAgIG5vcm1hbDIsCiAgICAgICAgICAtc3RSb3RhdGlvbiwKICAgICAgICAgIHF1YXRlcm5pb25TY3JhdGNoMgogICAgICAgICk7CiAgICAgICAgY29uc3QgdGFuZ2VudFJvdGF0aW9uID0gTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKAogICAgICAgICAgcm90YXRpb24sCiAgICAgICAgICB0YW5nZW50Um90YXRpb25TY3JhdGNoCiAgICAgICAgKTsKICAgICAgICB0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKHRhbmdlbnRSb3RhdGlvbiwgdGFuZ2VudCwgdGFuZ2VudCksCiAgICAgICAgICB0YW5nZW50CiAgICAgICAgKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIHRhbmdlbnQsIGJpdGFuZ2VudCksCiAgICAgICAgICAgIGJpdGFuZ2VudAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIHRleHR1cmVNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuY2xvbmUoTWF0cml4M19kZWZhdWx0LklERU5USVRZLCB0ZXh0dXJlTWF0cml4KTsKICAgIH0KICAgIGNvbnN0IHN0T3JpZ2luID0gdGV4dHVyZUNvb3JkaW5hdGVzT3JpZ2luOwogICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICBzdE9yaWdpbi54ID0gYm91bmRpbmdSZWN0YW5nbGUueDsKICAgICAgc3RPcmlnaW4ueSA9IGJvdW5kaW5nUmVjdGFuZ2xlLnk7CiAgICB9CiAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgY29uc3Qgc2l6ZSA9IGxlbmd0aCAqIDM7CiAgICBjb25zdCBmbGF0UG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShzaXplKTsKICAgIGNvbnN0IG5vcm1hbHMgPSB2ZXJ0ZXhGb3JtYXQubm9ybWFsID8gbmV3IEZsb2F0MzJBcnJheShzaXplKSA6IHZvaWQgMDsKICAgIGNvbnN0IHRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LnRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUpIDogdm9pZCAwOwogICAgY29uc3QgYml0YW5nZW50cyA9IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUpIDogdm9pZCAwOwogICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gdmVydGV4Rm9ybWF0LnN0ID8gbmV3IEZsb2F0MzJBcnJheShsZW5ndGggKiAyKSA6IHZvaWQgMDsKICAgIGxldCBwb3NpdGlvbkluZGV4ID0gMDsKICAgIGxldCBub3JtYWxJbmRleCA9IDA7CiAgICBsZXQgYml0YW5nZW50SW5kZXggPSAwOwogICAgbGV0IHRhbmdlbnRJbmRleCA9IDA7CiAgICBsZXQgc3RJbmRleCA9IDA7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgIGNvbnN0IHBvc2l0aW9uID0gcG9zaXRpb25zW2kyXTsKICAgICAgZmxhdFBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgZmxhdFBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgZmxhdFBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gcG9zaXRpb24uejsKICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaGFyZGNvZGVkVGV4dHVyZUNvb3JkaW5hdGVzKSAmJiBoYXJkY29kZWRUZXh0dXJlQ29vcmRpbmF0ZXMucG9zaXRpb25zLmxlbmd0aCA9PT0gbGVuZ3RoKSB7CiAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IGhhcmRjb2RlZFRleHR1cmVDb29yZGluYXRlcy5wb3NpdGlvbnNbaTJdLng7CiAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IGhhcmRjb2RlZFRleHR1cmVDb29yZGluYXRlcy5wb3NpdGlvbnNbaTJdLnk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGNvbnN0IHAyID0gTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IoCiAgICAgICAgICAgIHRleHR1cmVNYXRyaXgsCiAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICBzY3JhdGNoUG9zaXRpb24KICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBzdDIgPSBwcm9qZWN0UG9pbnRUbzJEKHAyLCBzdFNjcmF0Y2gpOwogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LnN1YnRyYWN0KHN0Miwgc3RPcmlnaW4sIHN0Mik7CiAgICAgICAgICBjb25zdCBzdHggPSBNYXRoX2RlZmF1bHQuY2xhbXAoc3QyLnggLyBib3VuZGluZ1JlY3RhbmdsZS53aWR0aCwgMCwgMSk7CiAgICAgICAgICBjb25zdCBzdHkgPSBNYXRoX2RlZmF1bHQuY2xhbXAoc3QyLnkgLyBib3VuZGluZ1JlY3RhbmdsZS5oZWlnaHQsIDAsIDEpOwogICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3N0SW5kZXgrK10gPSBzdHg7CiAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IHN0eTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi54OwogICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLnk7CiAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIuejsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lng7CiAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC55OwogICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQuejsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lnk7CiAgICAgICAgYml0YW5nZW50c1tiaXRhbmdlbnRJbmRleCsrXSA9IGJpdGFuZ2VudC56OwogICAgICB9CiAgICB9CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBmbGF0UG9zaXRpb25zCiAgICAgIH0pOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgYXR0cmlidXRlcy50YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiB0YW5nZW50cwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICBhdHRyaWJ1dGVzLnN0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgdmFsdWVzOiB0ZXh0dXJlQ29vcmRpbmF0ZXMKICAgICAgfSk7CiAgICB9CiAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICBhdHRyaWJ1dGVzLAogICAgICBpbmRpY2VzOiBuZXdJbmRpY2VzLAogICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTCiAgICB9KTsKICB9CiAgZnVuY3Rpb24gQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9seWdvbkhpZXJhcmNoeSA9IG9wdGlvbnMucG9seWdvbkhpZXJhcmNoeTsKICAgIGNvbnN0IHRleHR1cmVDb29yZGluYXRlcyA9IG9wdGlvbnMudGV4dHVyZUNvb3JkaW5hdGVzOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLnBvbHlnb25IaWVyYXJjaHkiLCBwb2x5Z29uSGllcmFyY2h5KTsKICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IG9wdGlvbnMudmVydGV4Rm9ybWF0ID8/IFZlcnRleEZvcm1hdF9kZWZhdWx0LkRFRkFVTFQ7CiAgICB0aGlzLl92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQpOwogICAgdGhpcy5fcG9seWdvbkhpZXJhcmNoeSA9IHBvbHlnb25IaWVyYXJjaHk7CiAgICB0aGlzLl9zdFJvdGF0aW9uID0gb3B0aW9ucy5zdFJvdGF0aW9uID8/IDA7CiAgICB0aGlzLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShvcHRpb25zLmVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0KTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkiOwogICAgdGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVzID0gdGV4dHVyZUNvb3JkaW5hdGVzOwogICAgdGhpcy5wYWNrZWRMZW5ndGggPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZUhpZXJhcmNoeVBhY2tlZExlbmd0aCgKICAgICAgcG9seWdvbkhpZXJhcmNoeSwKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0CiAgICApICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgKGRlZmluZWRfZGVmYXVsdCh0ZXh0dXJlQ29vcmRpbmF0ZXMpID8gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVIaWVyYXJjaHlQYWNrZWRMZW5ndGgoCiAgICAgIHRleHR1cmVDb29yZGluYXRlcywKICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0CiAgICApIDogMSkgKyAyOwogIH0KICB2YXIgc2NyYXRjaFBvc2l0aW9uLCBzY3JhdGNoQlIsIHN0U2NyYXRjaCwgdGV4dHVyZUNvb3JkaW5hdGVzT3JpZ2luLCBzY3JhdGNoTm9ybWFsNCwgc2NyYXRjaFRhbmdlbnQyLCBzY3JhdGNoQml0YW5nZW50MiwgY2VudGVyU2NyYXRjaCwgYXhpczFTY3JhdGNoLCBheGlzMlNjcmF0Y2gsIHF1YXRlcm5pb25TY3JhdGNoMiwgdGV4dHVyZU1hdHJpeFNjcmF0Y2gyLCB0YW5nZW50Um90YXRpb25TY3JhdGNoLCBzdXJmYWNlTm9ybWFsU2NyYXRjaCwgc2NyYXRjaEVsbGlwc29pZDMsIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQzLCBzY3JhdGNoT3B0aW9uczcsIENvcGxhbmFyUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NvcGxhbmFyUG9seWdvbkdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9hcnJheVJlbW92ZUR1cGxpY2F0ZXMoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1JlY3RhbmdsZSgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9HZW9tZXRyeUluc3RhbmNlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlQaXBlbGluZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X1BvbHlnb25HZW9tZXRyeUxpYnJhcnkoKTsKICAgICAgaW5pdF9Qb2x5Z29uUGlwZWxpbmUoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBpbml0X1ZlcnRleEZvcm1hdCgpOwogICAgICBzY3JhdGNoUG9zaXRpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCUiA9IG5ldyBCb3VuZGluZ1JlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIHN0U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzT3JpZ2luID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsNCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRhbmdlbnQyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQml0YW5nZW50MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2VudGVyU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYXhpczFTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBheGlzMlNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHF1YXRlcm5pb25TY3JhdGNoMiA9IG5ldyBRdWF0ZXJuaW9uX2RlZmF1bHQoKTsKICAgICAgdGV4dHVyZU1hdHJpeFNjcmF0Y2gyID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICB0YW5nZW50Um90YXRpb25TY3JhdGNoID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBzdXJmYWNlTm9ybWFsU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkuZnJvbVBvc2l0aW9ucyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLnBvc2l0aW9ucyIsIG9wdGlvbnMucG9zaXRpb25zKTsKICAgICAgICBjb25zdCBuZXdPcHRpb25zID0gewogICAgICAgICAgcG9seWdvbkhpZXJhcmNoeTogewogICAgICAgICAgICBwb3NpdGlvbnM6IG9wdGlvbnMucG9zaXRpb25zCiAgICAgICAgICB9LAogICAgICAgICAgdmVydGV4Rm9ybWF0OiBvcHRpb25zLnZlcnRleEZvcm1hdCwKICAgICAgICAgIHN0Um90YXRpb246IG9wdGlvbnMuc3RSb3RhdGlvbiwKICAgICAgICAgIGVsbGlwc29pZDogb3B0aW9ucy5lbGxpcHNvaWQsCiAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXM6IG9wdGlvbnMudGV4dHVyZUNvb3JkaW5hdGVzCiAgICAgICAgfTsKICAgICAgICByZXR1cm4gbmV3IENvcGxhbmFyUG9seWdvbkdlb21ldHJ5KG5ld09wdGlvbnMpOwogICAgICB9OwogICAgICBDb3BsYW5hclBvbHlnb25HZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgIHZhbHVlLl9wb2x5Z29uSGllcmFyY2h5LAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0CiAgICAgICAgKTsKICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrKHZhbHVlLl92ZXJ0ZXhGb3JtYXQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3N0Um90YXRpb247CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh2YWx1ZS5fdGV4dHVyZUNvb3JkaW5hdGVzKSkgewogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgICAgdmFsdWUuX3RleHR1cmVDb29yZGluYXRlcywKICAgICAgICAgICAgYXJyYXksCiAgICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdAogICAgICAgICAgKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IC0xOwogICAgICAgIH0KICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLnBhY2tlZExlbmd0aDsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQzID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoRWxsaXBzb2lkX2RlZmF1bHQuVU5JVF9TUEhFUkUpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MyA9IG5ldyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczcgPSB7CiAgICAgICAgcG9seWdvbkhpZXJhcmNoeToge30KICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnVucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBwb2x5Z29uSGllcmFyY2h5LnN0YXJ0aW5nSW5kZXg7CiAgICAgICAgZGVsZXRlIHBvbHlnb25IaWVyYXJjaHkuc3RhcnRpbmdJbmRleDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQzKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MwogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gYXJyYXlbc3RhcnRpbmdJbmRleF0gPT09IC0xID8gdm9pZCAwIDogUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnVucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQKICAgICAgICApOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGV4dHVyZUNvb3JkaW5hdGVzKSkgewogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHRleHR1cmVDb29yZGluYXRlcy5zdGFydGluZ0luZGV4OwogICAgICAgICAgZGVsZXRlIHRleHR1cmVDb29yZGluYXRlcy5zdGFydGluZ0luZGV4OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBzdGFydGluZ0luZGV4Kys7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBhY2tlZExlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDb3BsYW5hclBvbHlnb25HZW9tZXRyeShzY3JhdGNoT3B0aW9uczcpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXN1bHQuX3N0Um90YXRpb24gPSBzdFJvdGF0aW9uOwogICAgICAgIHJlc3VsdC5fdGV4dHVyZUNvb3JkaW5hdGVzID0gdGV4dHVyZUNvb3JkaW5hdGVzOwogICAgICAgIHJlc3VsdC5wYWNrZWRMZW5ndGggPSBwYWNrZWRMZW5ndGg7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihwb2x5Z29uR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBwb2x5Z29uR2VvbWV0cnkuX3ZlcnRleEZvcm1hdDsKICAgICAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gcG9seWdvbkdlb21ldHJ5Ll9wb2x5Z29uSGllcmFyY2h5OwogICAgICAgIGNvbnN0IHN0Um90YXRpb24gPSBwb2x5Z29uR2VvbWV0cnkuX3N0Um90YXRpb247CiAgICAgICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gcG9seWdvbkdlb21ldHJ5Ll90ZXh0dXJlQ29vcmRpbmF0ZXM7CiAgICAgICAgY29uc3QgaGFzVGV4dHVyZUNvb3JkaW5hdGVzID0gZGVmaW5lZF9kZWZhdWx0KHRleHR1cmVDb29yZGluYXRlcyk7CiAgICAgICAgbGV0IG91dGVyUG9zaXRpb25zID0gcG9seWdvbkhpZXJhcmNoeS5wb3NpdGlvbnM7CiAgICAgICAgb3V0ZXJQb3NpdGlvbnMgPSBhcnJheVJlbW92ZUR1cGxpY2F0ZXNfZGVmYXVsdCgKICAgICAgICAgIG91dGVyUG9zaXRpb25zLAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24sCiAgICAgICAgICB0cnVlCiAgICAgICAgKTsKICAgICAgICBpZiAob3V0ZXJQb3NpdGlvbnMubGVuZ3RoIDwgMykgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBsZXQgbm9ybWFsMiA9IHNjcmF0Y2hOb3JtYWw0OwogICAgICAgIGxldCB0YW5nZW50ID0gc2NyYXRjaFRhbmdlbnQyOwogICAgICAgIGxldCBiaXRhbmdlbnQgPSBzY3JhdGNoQml0YW5nZW50MjsKICAgICAgICBsZXQgYXhpczEgPSBheGlzMVNjcmF0Y2g7CiAgICAgICAgY29uc3QgYXhpczIgPSBheGlzMlNjcmF0Y2g7CiAgICAgICAgY29uc3QgdmFsaWRHZW9tZXRyeSA9IENvcGxhbmFyUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQcm9qZWN0VG8yREFyZ3VtZW50cygKICAgICAgICAgIG91dGVyUG9zaXRpb25zLAogICAgICAgICAgY2VudGVyU2NyYXRjaCwKICAgICAgICAgIGF4aXMxLAogICAgICAgICAgYXhpczIKICAgICAgICApOwogICAgICAgIGlmICghdmFsaWRHZW9tZXRyeSkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgbm9ybWFsMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhheGlzMSwgYXhpczIsIG5vcm1hbDIpOwogICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG5vcm1hbDIsIG5vcm1hbDIpOwogICAgICAgIGlmICghQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBjZW50ZXJTY3JhdGNoLAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjYKICAgICAgICApKSB7CiAgICAgICAgICBjb25zdCBzdXJmYWNlTm9ybWFsID0gcG9seWdvbkdlb21ldHJ5Ll9lbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgICBjZW50ZXJTY3JhdGNoLAogICAgICAgICAgICBzdXJmYWNlTm9ybWFsU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KG5vcm1hbDIsIHN1cmZhY2VOb3JtYWwpIDwgMCkgewogICAgICAgICAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICAgICAgYXhpczEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGF4aXMxLCBheGlzMSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IHByb2plY3RQb2ludHMgPSBDb3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jcmVhdGVQcm9qZWN0UG9pbnRzVG8yREZ1bmN0aW9uKAogICAgICAgICAgY2VudGVyU2NyYXRjaCwKICAgICAgICAgIGF4aXMxLAogICAgICAgICAgYXhpczIKICAgICAgICApOwogICAgICAgIGNvbnN0IHByb2plY3RQb2ludCA9IENvcGxhbmFyUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNyZWF0ZVByb2plY3RQb2ludFRvMkRGdW5jdGlvbigKICAgICAgICAgIGNlbnRlclNjcmF0Y2gsCiAgICAgICAgICBheGlzMSwKICAgICAgICAgIGF4aXMyCiAgICAgICAgKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoYXhpczEsIHRhbmdlbnQpOwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGF4aXMyLCBiaXRhbmdlbnQpOwogICAgICAgIH0KICAgICAgICBjb25zdCByZXN1bHRzID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnBvbHlnb25zRnJvbUhpZXJhcmNoeSgKICAgICAgICAgIHBvbHlnb25IaWVyYXJjaHksCiAgICAgICAgICBoYXNUZXh0dXJlQ29vcmRpbmF0ZXMsCiAgICAgICAgICBwcm9qZWN0UG9pbnRzLAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGNvbnN0IGhpZXJhcmNoeSA9IHJlc3VsdHMuaGllcmFyY2h5OwogICAgICAgIGNvbnN0IHBvbHlnb25zID0gcmVzdWx0cy5wb2x5Z29uczsKICAgICAgICBjb25zdCBkdW1teUZ1bmN0aW9uID0gZnVuY3Rpb24oaWRlbnRpdHkpIHsKICAgICAgICAgIHJldHVybiBpZGVudGl0eTsKICAgICAgICB9OwogICAgICAgIGNvbnN0IHRleHR1cmVDb29yZGluYXRlUG9seWdvbnMgPSBoYXNUZXh0dXJlQ29vcmRpbmF0ZXMgPyBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucG9seWdvbnNGcm9tSGllcmFyY2h5KAogICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzLAogICAgICAgICAgdHJ1ZSwKICAgICAgICAgIGR1bW15RnVuY3Rpb24sCiAgICAgICAgICBmYWxzZQogICAgICAgICkucG9seWdvbnMgOiB2b2lkIDA7CiAgICAgICAgaWYgKGhpZXJhcmNoeS5sZW5ndGggPT09IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgb3V0ZXJQb3NpdGlvbnMgPSBoaWVyYXJjaHlbMF0ub3V0ZXJSaW5nOwogICAgICAgIGNvbnN0IGJvdW5kaW5nU3BoZXJlID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUG9pbnRzKG91dGVyUG9zaXRpb25zKTsKICAgICAgICBjb25zdCBib3VuZGluZ1JlY3RhbmdsZSA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlQm91bmRpbmdSZWN0YW5nbGUoCiAgICAgICAgICBub3JtYWwyLAogICAgICAgICAgcHJvamVjdFBvaW50LAogICAgICAgICAgb3V0ZXJQb3NpdGlvbnMsCiAgICAgICAgICBzdFJvdGF0aW9uLAogICAgICAgICAgc2NyYXRjaEJSCiAgICAgICAgKTsKICAgICAgICBjb25zdCBnZW9tZXRyaWVzID0gW107CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvbHlnb25zLmxlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgZ2VvbWV0cnlJbnN0YW5jZSA9IG5ldyBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQoewogICAgICAgICAgICBnZW9tZXRyeTogY3JlYXRlR2VvbWV0cnlGcm9tUG9seWdvbigKICAgICAgICAgICAgICBwb2x5Z29uc1tpMl0sCiAgICAgICAgICAgICAgdmVydGV4Rm9ybWF0LAogICAgICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLAogICAgICAgICAgICAgIHN0Um90YXRpb24sCiAgICAgICAgICAgICAgaGFzVGV4dHVyZUNvb3JkaW5hdGVzID8gdGV4dHVyZUNvb3JkaW5hdGVQb2x5Z29uc1tpMl0gOiB2b2lkIDAsCiAgICAgICAgICAgICAgcHJvamVjdFBvaW50LAogICAgICAgICAgICAgIG5vcm1hbDIsCiAgICAgICAgICAgICAgdGFuZ2VudCwKICAgICAgICAgICAgICBiaXRhbmdlbnQKICAgICAgICAgICAgKQogICAgICAgICAgfSk7CiAgICAgICAgICBnZW9tZXRyaWVzLnB1c2goZ2VvbWV0cnlJbnN0YW5jZSk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJ5ID0gR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmNvbWJpbmVJbnN0YW5jZXMoZ2VvbWV0cmllcylbMF07CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMgPSBuZXcgRmxvYXQ2NEFycmF5KAogICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMKICAgICAgICApOwogICAgICAgIGdlb21ldHJ5LmluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aCAvIDMsCiAgICAgICAgICBnZW9tZXRyeS5pbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICBpZiAoIXZlcnRleEZvcm1hdC5wb3NpdGlvbikgewogICAgICAgICAgZGVsZXRlIGF0dHJpYnV0ZXMucG9zaXRpb247CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlczogZ2VvbWV0cnkuaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBDb3BsYW5hclBvbHlnb25HZW9tZXRyeV9kZWZhdWx0ID0gQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVDb3BsYW5hclBvbHlnb25HZW9tZXRyeS5qcwogIHZhciBjcmVhdGVDb3BsYW5hclBvbHlnb25HZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5KHBvbHlnb25HZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcG9seWdvbkdlb21ldHJ5ID0gQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdC51bnBhY2socG9seWdvbkdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcmV0dXJuIENvcGxhbmFyUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkocG9seWdvbkdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Db3BsYW5hclBvbHlnb25HZW9tZXRyeSgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zKHBvc2l0aW9ucykgewogICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgIGNvbnN0IGZsYXRQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KGxlbmd0aCAqIDMpOwogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KGxlbmd0aCwgbGVuZ3RoICogMik7CiAgICBsZXQgcG9zaXRpb25JbmRleCA9IDA7CiAgICBsZXQgaW5kZXggPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICBjb25zdCBwb3NpdGlvbiA9IHBvc2l0aW9uc1tpMl07CiAgICAgIGZsYXRQb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHBvc2l0aW9uLng7CiAgICAgIGZsYXRQb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHBvc2l0aW9uLnk7CiAgICAgIGZsYXRQb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHBvc2l0aW9uLno7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMjsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IChpMiArIDEpICUgbGVuZ3RoOwogICAgfQogICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCh7CiAgICAgIHBvc2l0aW9uOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBmbGF0UG9zaXRpb25zCiAgICAgIH0pCiAgICB9KTsKICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgIGF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXMsCiAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5MSU5FUwogICAgfSk7CiAgfQogIGZ1bmN0aW9uIENvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gb3B0aW9ucy5wb2x5Z29uSGllcmFyY2h5OwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLnBvbHlnb25IaWVyYXJjaHkiLCBwb2x5Z29uSGllcmFyY2h5KTsKICAgIHRoaXMuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgdGhpcy5fd29ya2VyTmFtZSA9ICJjcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkiOwogICAgdGhpcy5wYWNrZWRMZW5ndGggPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZUhpZXJhcmNoeVBhY2tlZExlbmd0aCgKICAgICAgcG9seWdvbkhpZXJhcmNoeSwKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0CiAgICApICsgMTsKICB9CiAgdmFyIHNjcmF0Y2hPcHRpb25zOCwgQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Db3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2FycmF5UmVtb3ZlRHVwbGljYXRlcygpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Db3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnkoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5SW5zdGFuY2UoKTsKICAgICAgaW5pdF9HZW9tZXRyeVBpcGVsaW5lKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X1BvbHlnb25HZW9tZXRyeUxpYnJhcnkoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIENvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeS5mcm9tUG9zaXRpb25zID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9wdGlvbnMucG9zaXRpb25zIiwgb3B0aW9ucy5wb3NpdGlvbnMpOwogICAgICAgIGNvbnN0IG5ld09wdGlvbnMgPSB7CiAgICAgICAgICBwb2x5Z29uSGllcmFyY2h5OiB7CiAgICAgICAgICAgIHBvc2l0aW9uczogb3B0aW9ucy5wb3NpdGlvbnMKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIHJldHVybiBuZXcgQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5KG5ld09wdGlvbnMpOwogICAgICB9OwogICAgICBDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICB2YWx1ZS5fcG9seWdvbkhpZXJhcmNoeSwKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdAogICAgICAgICk7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5wYWNrZWRMZW5ndGg7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBzY3JhdGNoT3B0aW9uczggPSB7CiAgICAgICAgcG9seWdvbkhpZXJhcmNoeToge30KICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgcG9seWdvbkhpZXJhcmNoeSA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC51bnBhY2tQb2x5Z29uSGllcmFyY2h5KAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0CiAgICAgICAgKTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gcG9seWdvbkhpZXJhcmNoeS5zdGFydGluZ0luZGV4OwogICAgICAgIGRlbGV0ZSBwb2x5Z29uSGllcmFyY2h5LnN0YXJ0aW5nSW5kZXg7CiAgICAgICAgY29uc3QgcGFja2VkTGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IENvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczgpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgICAgIHJlc3VsdC5wYWNrZWRMZW5ndGggPSBwYWNrZWRMZW5ndGg7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24ocG9seWdvbkdlb21ldHJ5KSB7CiAgICAgICAgY29uc3QgcG9seWdvbkhpZXJhcmNoeSA9IHBvbHlnb25HZW9tZXRyeS5fcG9seWdvbkhpZXJhcmNoeTsKICAgICAgICBsZXQgb3V0ZXJQb3NpdGlvbnMgPSBwb2x5Z29uSGllcmFyY2h5LnBvc2l0aW9uczsKICAgICAgICBvdXRlclBvc2l0aW9ucyA9IGFycmF5UmVtb3ZlRHVwbGljYXRlc19kZWZhdWx0KAogICAgICAgICAgb3V0ZXJQb3NpdGlvbnMsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbiwKICAgICAgICAgIHRydWUKICAgICAgICApOwogICAgICAgIGlmIChvdXRlclBvc2l0aW9ucy5sZW5ndGggPCAzKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IGlzVmFsaWQgPSBDb3BsYW5hclBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC52YWxpZE91dGxpbmUob3V0ZXJQb3NpdGlvbnMpOwogICAgICAgIGlmICghaXNWYWxpZCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgcG9seWdvbnMgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucG9seWdvbk91dGxpbmVzRnJvbUhpZXJhcmNoeSgKICAgICAgICAgIHBvbHlnb25IaWVyYXJjaHksCiAgICAgICAgICBmYWxzZQogICAgICAgICk7CiAgICAgICAgaWYgKHBvbHlnb25zLmxlbmd0aCA9PT0gMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgZ2VvbWV0cmllcyA9IFtdOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb2x5Z29ucy5sZW5ndGg7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IGdlb21ldHJ5SW5zdGFuY2UgPSBuZXcgR2VvbWV0cnlJbnN0YW5jZV9kZWZhdWx0KHsKICAgICAgICAgICAgZ2VvbWV0cnk6IGNyZWF0ZUdlb21ldHJ5RnJvbVBvc2l0aW9ucyhwb2x5Z29uc1tpMl0pCiAgICAgICAgICB9KTsKICAgICAgICAgIGdlb21ldHJpZXMucHVzaChnZW9tZXRyeUluc3RhbmNlKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZ2VvbWV0cnkgPSBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQuY29tYmluZUluc3RhbmNlcyhnZW9tZXRyaWVzKVswXTsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVBvaW50cyhwb2x5Z29uSGllcmFyY2h5LnBvc2l0aW9ucyk7CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXM6IGdlb21ldHJ5LmF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBnZW9tZXRyeS5pbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSwKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIENvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5KHBvbHlnb25HZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcG9seWdvbkdlb21ldHJ5ID0gQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgIHBvbHlnb25HZW9tZXRyeSwKICAgICAgICBvZmZzZXQKICAgICAgKTsKICAgIH0KICAgIHBvbHlnb25HZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUocG9seWdvbkdlb21ldHJ5Ll9lbGxpcHNvaWQpOwogICAgcmV0dXJuIENvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHBvbHlnb25HZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5KCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBjcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0Nvcm5lclR5cGUuanMKICB2YXIgQ29ybmVyVHlwZSwgQ29ybmVyVHlwZV9kZWZhdWx0OwogIHZhciBpbml0X0Nvcm5lclR5cGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0Nvcm5lclR5cGUuanMiKCkgewogICAgICBDb3JuZXJUeXBlID0gewogICAgICAgIC8qKgogICAgICAgICAqIDxpbWcgc3JjPSJJbWFnZXMvQ29ybmVyVHlwZVJvdW5kZWQucG5nIiBzdHlsZT0idmVydGljYWwtYWxpZ246IG1pZGRsZTsiIHdpZHRoPSIxODYiIGhlaWdodD0iMTg5IiAvPgogICAgICAgICAqCiAgICAgICAgICogQ29ybmVyIGhhcyBhIHNtb290aCBlZGdlLgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUk9VTkRFRDogMCwKICAgICAgICAvKioKICAgICAgICAgKiA8aW1nIHNyYz0iSW1hZ2VzL0Nvcm5lclR5cGVNaXRlcmVkLnBuZyIgc3R5bGU9InZlcnRpY2FsLWFsaWduOiBtaWRkbGU7IiB3aWR0aD0iMTg2IiBoZWlnaHQ9IjE4OSIgLz4KICAgICAgICAgKgogICAgICAgICAqIENvcm5lciBwb2ludCBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIGFkamFjZW50IGVkZ2VzLgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgTUlURVJFRDogMSwKICAgICAgICAvKioKICAgICAgICAgKiA8aW1nIHNyYz0iSW1hZ2VzL0Nvcm5lclR5cGVCZXZlbGVkLnBuZyIgc3R5bGU9InZlcnRpY2FsLWFsaWduOiBtaWRkbGU7IiB3aWR0aD0iMTg2IiBoZWlnaHQ9IjE4OSIgLz4KICAgICAgICAgKgogICAgICAgICAqIENvcm5lciBpcyBjbGlwcGVkLgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgQkVWRUxFRDogMgogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKENvcm5lclR5cGUpOwogICAgICBDb3JuZXJUeXBlX2RlZmF1bHQgPSBDb3JuZXJUeXBlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzb2lkR2VvZGVzaWMuanMKICBmdW5jdGlvbiBzZXRDb25zdGFudHMoZWxsaXBzb2lkR2VvZGVzaWMyKSB7CiAgICBjb25zdCB1U3F1YXJlZCA9IGVsbGlwc29pZEdlb2Rlc2ljMi5fdVNxdWFyZWQ7CiAgICBjb25zdCBhNCA9IGVsbGlwc29pZEdlb2Rlc2ljMi5fZWxsaXBzb2lkLm1heGltdW1SYWRpdXM7CiAgICBjb25zdCBiMiA9IGVsbGlwc29pZEdlb2Rlc2ljMi5fZWxsaXBzb2lkLm1pbmltdW1SYWRpdXM7CiAgICBjb25zdCBmMiA9IChhNCAtIGIyKSAvIGE0OwogICAgY29uc3QgY29zaW5lSGVhZGluZyA9IE1hdGguY29zKGVsbGlwc29pZEdlb2Rlc2ljMi5fc3RhcnRIZWFkaW5nKTsKICAgIGNvbnN0IHNpbmVIZWFkaW5nID0gTWF0aC5zaW4oZWxsaXBzb2lkR2VvZGVzaWMyLl9zdGFydEhlYWRpbmcpOwogICAgY29uc3QgdGFuVSA9ICgxIC0gZjIpICogTWF0aC50YW4oZWxsaXBzb2lkR2VvZGVzaWMyLl9zdGFydC5sYXRpdHVkZSk7CiAgICBjb25zdCBjb3NpbmVVID0gMSAvIE1hdGguc3FydCgxICsgdGFuVSAqIHRhblUpOwogICAgY29uc3Qgc2luZVUgPSBjb3NpbmVVICogdGFuVTsKICAgIGNvbnN0IHNpZ21hID0gTWF0aC5hdGFuMih0YW5VLCBjb3NpbmVIZWFkaW5nKTsKICAgIGNvbnN0IHNpbmVBbHBoYSA9IGNvc2luZVUgKiBzaW5lSGVhZGluZzsKICAgIGNvbnN0IHNpbmVTcXVhcmVkQWxwaGEgPSBzaW5lQWxwaGEgKiBzaW5lQWxwaGE7CiAgICBjb25zdCBjb3NpbmVTcXVhcmVkQWxwaGEgPSAxIC0gc2luZVNxdWFyZWRBbHBoYTsKICAgIGNvbnN0IGNvc2luZUFscGhhID0gTWF0aC5zcXJ0KGNvc2luZVNxdWFyZWRBbHBoYSk7CiAgICBjb25zdCB1Mk92ZXI0ID0gdVNxdWFyZWQgLyA0OwogICAgY29uc3QgdTRPdmVyMTYgPSB1Mk92ZXI0ICogdTJPdmVyNDsKICAgIGNvbnN0IHU2T3ZlcjY0ID0gdTRPdmVyMTYgKiB1Mk92ZXI0OwogICAgY29uc3QgdThPdmVyMjU2ID0gdTRPdmVyMTYgKiB1NE92ZXIxNjsKICAgIGNvbnN0IGEwID0gMSArIHUyT3ZlcjQgLSAzICogdTRPdmVyMTYgLyA0ICsgNSAqIHU2T3ZlcjY0IC8gNCAtIDE3NSAqIHU4T3ZlcjI1NiAvIDY0OwogICAgY29uc3QgYTEgPSAxIC0gdTJPdmVyNCArIDE1ICogdTRPdmVyMTYgLyA4IC0gMzUgKiB1Nk92ZXI2NCAvIDg7CiAgICBjb25zdCBhMjIgPSAxIC0gMyAqIHUyT3ZlcjQgKyAzNSAqIHU0T3ZlcjE2IC8gNDsKICAgIGNvbnN0IGEzMiA9IDEgLSA1ICogdTJPdmVyNDsKICAgIGNvbnN0IGRpc3RhbmNlUmF0aW8gPSBhMCAqIHNpZ21hIC0gYTEgKiBNYXRoLnNpbigyICogc2lnbWEpICogdTJPdmVyNCAvIDIgLSBhMjIgKiBNYXRoLnNpbig0ICogc2lnbWEpICogdTRPdmVyMTYgLyAxNiAtIGEzMiAqIE1hdGguc2luKDYgKiBzaWdtYSkgKiB1Nk92ZXI2NCAvIDQ4IC0gTWF0aC5zaW4oOCAqIHNpZ21hKSAqIDUgKiB1OE92ZXIyNTYgLyA1MTI7CiAgICBjb25zdCBjb25zdGFudHMgPSBlbGxpcHNvaWRHZW9kZXNpYzIuX2NvbnN0YW50czsKICAgIGNvbnN0YW50cy5hID0gYTQ7CiAgICBjb25zdGFudHMuYiA9IGIyOwogICAgY29uc3RhbnRzLmYgPSBmMjsKICAgIGNvbnN0YW50cy5jb3NpbmVIZWFkaW5nID0gY29zaW5lSGVhZGluZzsKICAgIGNvbnN0YW50cy5zaW5lSGVhZGluZyA9IHNpbmVIZWFkaW5nOwogICAgY29uc3RhbnRzLnRhblUgPSB0YW5VOwogICAgY29uc3RhbnRzLmNvc2luZVUgPSBjb3NpbmVVOwogICAgY29uc3RhbnRzLnNpbmVVID0gc2luZVU7CiAgICBjb25zdGFudHMuc2lnbWEgPSBzaWdtYTsKICAgIGNvbnN0YW50cy5zaW5lQWxwaGEgPSBzaW5lQWxwaGE7CiAgICBjb25zdGFudHMuc2luZVNxdWFyZWRBbHBoYSA9IHNpbmVTcXVhcmVkQWxwaGE7CiAgICBjb25zdGFudHMuY29zaW5lU3F1YXJlZEFscGhhID0gY29zaW5lU3F1YXJlZEFscGhhOwogICAgY29uc3RhbnRzLmNvc2luZUFscGhhID0gY29zaW5lQWxwaGE7CiAgICBjb25zdGFudHMudTJPdmVyNCA9IHUyT3ZlcjQ7CiAgICBjb25zdGFudHMudTRPdmVyMTYgPSB1NE92ZXIxNjsKICAgIGNvbnN0YW50cy51Nk92ZXI2NCA9IHU2T3ZlcjY0OwogICAgY29uc3RhbnRzLnU4T3ZlcjI1NiA9IHU4T3ZlcjI1NjsKICAgIGNvbnN0YW50cy5hMCA9IGEwOwogICAgY29uc3RhbnRzLmExID0gYTE7CiAgICBjb25zdGFudHMuYTIgPSBhMjI7CiAgICBjb25zdGFudHMuYTMgPSBhMzI7CiAgICBjb25zdGFudHMuZGlzdGFuY2VSYXRpbyA9IGRpc3RhbmNlUmF0aW87CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVDKGYyLCBjb3NpbmVTcXVhcmVkQWxwaGEpIHsKICAgIHJldHVybiBmMiAqIGNvc2luZVNxdWFyZWRBbHBoYSAqICg0ICsgZjIgKiAoNCAtIDMgKiBjb3NpbmVTcXVhcmVkQWxwaGEpKSAvIDE2OwogIH0KICBmdW5jdGlvbiBjb21wdXRlRGVsdGFMYW1iZGEoZjIsIHNpbmVBbHBoYSwgY29zaW5lU3F1YXJlZEFscGhhLCBzaWdtYSwgc2luZVNpZ21hLCBjb3NpbmVTaWdtYSwgY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50KSB7CiAgICBjb25zdCBDMiA9IGNvbXB1dGVDKGYyLCBjb3NpbmVTcXVhcmVkQWxwaGEpOwogICAgcmV0dXJuICgxIC0gQzIpICogZjIgKiBzaW5lQWxwaGEgKiAoc2lnbWEgKyBDMiAqIHNpbmVTaWdtYSAqIChjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQgKyBDMiAqIGNvc2luZVNpZ21hICogKDIgKiBjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQgKiBjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQgLSAxKSkpOwogIH0KICBmdW5jdGlvbiB2aW5jZW50eUludmVyc2VGb3JtdWxhKGVsbGlwc29pZEdlb2Rlc2ljMiwgbWFqb3IsIG1pbm9yLCBmaXJzdExvbmdpdHVkZSwgZmlyc3RMYXRpdHVkZSwgc2Vjb25kTG9uZ2l0dWRlLCBzZWNvbmRMYXRpdHVkZSkgewogICAgY29uc3QgZWZmID0gKG1ham9yIC0gbWlub3IpIC8gbWFqb3I7CiAgICBjb25zdCBsMiA9IHNlY29uZExvbmdpdHVkZSAtIGZpcnN0TG9uZ2l0dWRlOwogICAgY29uc3QgdTEyID0gTWF0aC5hdGFuKCgxIC0gZWZmKSAqIE1hdGgudGFuKGZpcnN0TGF0aXR1ZGUpKTsKICAgIGNvbnN0IHUyMiA9IE1hdGguYXRhbigoMSAtIGVmZikgKiBNYXRoLnRhbihzZWNvbmRMYXRpdHVkZSkpOwogICAgY29uc3QgY29zaW5lVTEgPSBNYXRoLmNvcyh1MTIpOwogICAgY29uc3Qgc2luZVUxID0gTWF0aC5zaW4odTEyKTsKICAgIGNvbnN0IGNvc2luZVUyID0gTWF0aC5jb3ModTIyKTsKICAgIGNvbnN0IHNpbmVVMiA9IE1hdGguc2luKHUyMik7CiAgICBjb25zdCBjYyA9IGNvc2luZVUxICogY29zaW5lVTI7CiAgICBjb25zdCBjcyA9IGNvc2luZVUxICogc2luZVUyOwogICAgY29uc3Qgc3MgPSBzaW5lVTEgKiBzaW5lVTI7CiAgICBjb25zdCBzYyA9IHNpbmVVMSAqIGNvc2luZVUyOwogICAgbGV0IGxhbWJkYSA9IGwyOwogICAgbGV0IGxhbWJkYURvdDsKICAgIGxldCBjb3NpbmVMYW1iZGE7CiAgICBsZXQgc2luZUxhbWJkYTsKICAgIGxldCBzaWdtYTsKICAgIGxldCBjb3NpbmVTaWdtYTsKICAgIGxldCBzaW5lU2lnbWE7CiAgICBsZXQgY29zaW5lU3F1YXJlZEFscGhhOwogICAgbGV0IGNvc2luZVR3aWNlU2lnbWFNaWRwb2ludDsKICAgIGRvIHsKICAgICAgY29zaW5lTGFtYmRhID0gTWF0aC5jb3MobGFtYmRhKTsKICAgICAgc2luZUxhbWJkYSA9IE1hdGguc2luKGxhbWJkYSk7CiAgICAgIGNvbnN0IHRlbXAgPSBjcyAtIHNjICogY29zaW5lTGFtYmRhOwogICAgICBzaW5lU2lnbWEgPSBNYXRoLnNxcnQoCiAgICAgICAgY29zaW5lVTIgKiBjb3NpbmVVMiAqIHNpbmVMYW1iZGEgKiBzaW5lTGFtYmRhICsgdGVtcCAqIHRlbXAKICAgICAgKTsKICAgICAgY29zaW5lU2lnbWEgPSBzcyArIGNjICogY29zaW5lTGFtYmRhOwogICAgICBzaWdtYSA9IE1hdGguYXRhbjIoc2luZVNpZ21hLCBjb3NpbmVTaWdtYSk7CiAgICAgIGxldCBzaW5lQWxwaGE7CiAgICAgIGlmIChzaW5lU2lnbWEgPT09IDApIHsKICAgICAgICBzaW5lQWxwaGEgPSAwOwogICAgICAgIGNvc2luZVNxdWFyZWRBbHBoYSA9IDE7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgc2luZUFscGhhID0gY2MgKiBzaW5lTGFtYmRhIC8gc2luZVNpZ21hOwogICAgICAgIGNvc2luZVNxdWFyZWRBbHBoYSA9IDEgLSBzaW5lQWxwaGEgKiBzaW5lQWxwaGE7CiAgICAgIH0KICAgICAgbGFtYmRhRG90ID0gbGFtYmRhOwogICAgICBjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQgPSBjb3NpbmVTaWdtYSAtIDIgKiBzcyAvIGNvc2luZVNxdWFyZWRBbHBoYTsKICAgICAgaWYgKCFpc0Zpbml0ZShjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQpKSB7CiAgICAgICAgY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50ID0gMDsKICAgICAgfQogICAgICBsYW1iZGEgPSBsMiArIGNvbXB1dGVEZWx0YUxhbWJkYSgKICAgICAgICBlZmYsCiAgICAgICAgc2luZUFscGhhLAogICAgICAgIGNvc2luZVNxdWFyZWRBbHBoYSwKICAgICAgICBzaWdtYSwKICAgICAgICBzaW5lU2lnbWEsCiAgICAgICAgY29zaW5lU2lnbWEsCiAgICAgICAgY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50CiAgICAgICk7CiAgICB9IHdoaWxlIChNYXRoLmFicyhsYW1iZGEgLSBsYW1iZGFEb3QpID4gTWF0aF9kZWZhdWx0LkVQU0lMT04xMik7CiAgICBjb25zdCB1U3F1YXJlZCA9IGNvc2luZVNxdWFyZWRBbHBoYSAqIChtYWpvciAqIG1ham9yIC0gbWlub3IgKiBtaW5vcikgLyAobWlub3IgKiBtaW5vcik7CiAgICBjb25zdCBBMiA9IDEgKyB1U3F1YXJlZCAqICg0MDk2ICsgdVNxdWFyZWQgKiAodVNxdWFyZWQgKiAoMzIwIC0gMTc1ICogdVNxdWFyZWQpIC0gNzY4KSkgLyAxNjM4NDsKICAgIGNvbnN0IEIyID0gdVNxdWFyZWQgKiAoMjU2ICsgdVNxdWFyZWQgKiAodVNxdWFyZWQgKiAoNzQgLSA0NyAqIHVTcXVhcmVkKSAtIDEyOCkpIC8gMTAyNDsKICAgIGNvbnN0IGNvc2luZVNxdWFyZWRUd2ljZVNpZ21hTWlkcG9pbnQgPSBjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQgKiBjb3NpbmVUd2ljZVNpZ21hTWlkcG9pbnQ7CiAgICBjb25zdCBkZWx0YVNpZ21hID0gQjIgKiBzaW5lU2lnbWEgKiAoY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50ICsgQjIgKiAoY29zaW5lU2lnbWEgKiAoMiAqIGNvc2luZVNxdWFyZWRUd2ljZVNpZ21hTWlkcG9pbnQgLSAxKSAtIEIyICogY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50ICogKDQgKiBzaW5lU2lnbWEgKiBzaW5lU2lnbWEgLSAzKSAqICg0ICogY29zaW5lU3F1YXJlZFR3aWNlU2lnbWFNaWRwb2ludCAtIDMpIC8gNikgLyA0KTsKICAgIGNvbnN0IGRpc3RhbmNlID0gbWlub3IgKiBBMiAqIChzaWdtYSAtIGRlbHRhU2lnbWEpOwogICAgY29uc3Qgc3RhcnRIZWFkaW5nID0gTWF0aC5hdGFuMigKICAgICAgY29zaW5lVTIgKiBzaW5lTGFtYmRhLAogICAgICBjcyAtIHNjICogY29zaW5lTGFtYmRhCiAgICApOwogICAgY29uc3QgZW5kSGVhZGluZyA9IE1hdGguYXRhbjIoY29zaW5lVTEgKiBzaW5lTGFtYmRhLCBjcyAqIGNvc2luZUxhbWJkYSAtIHNjKTsKICAgIGVsbGlwc29pZEdlb2Rlc2ljMi5fZGlzdGFuY2UgPSBkaXN0YW5jZTsKICAgIGVsbGlwc29pZEdlb2Rlc2ljMi5fc3RhcnRIZWFkaW5nID0gc3RhcnRIZWFkaW5nOwogICAgZWxsaXBzb2lkR2VvZGVzaWMyLl9lbmRIZWFkaW5nID0gZW5kSGVhZGluZzsKICAgIGVsbGlwc29pZEdlb2Rlc2ljMi5fdVNxdWFyZWQgPSB1U3F1YXJlZDsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZVByb3BlcnRpZXMyKGVsbGlwc29pZEdlb2Rlc2ljMiwgc3RhcnQsIGVuZCwgZWxsaXBzb2lkKSB7CiAgICBjb25zdCBmaXJzdENhcnRlc2lhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgIGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihzdGFydCwgc2NyYXRjaENhcnQyMiksCiAgICAgIHNjcmF0Y2hDYXJ0MTIKICAgICk7CiAgICBjb25zdCBsYXN0Q2FydGVzaWFuID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGVuZCwgc2NyYXRjaENhcnQyMiksCiAgICAgIHNjcmF0Y2hDYXJ0MjIKICAgICk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygKICAgICAgInZhbHVlIiwKICAgICAgTWF0aC5hYnMoCiAgICAgICAgTWF0aC5hYnMoQ2FydGVzaWFuM19kZWZhdWx0LmFuZ2xlQmV0d2VlbihmaXJzdENhcnRlc2lhbiwgbGFzdENhcnRlc2lhbikpIC0gTWF0aC5QSQogICAgICApLAogICAgICAwLjAxMjUKICAgICk7CiAgICB2aW5jZW50eUludmVyc2VGb3JtdWxhKAogICAgICBlbGxpcHNvaWRHZW9kZXNpYzIsCiAgICAgIGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzLAogICAgICBlbGxpcHNvaWQubWluaW11bVJhZGl1cywKICAgICAgc3RhcnQubG9uZ2l0dWRlLAogICAgICBzdGFydC5sYXRpdHVkZSwKICAgICAgZW5kLmxvbmdpdHVkZSwKICAgICAgZW5kLmxhdGl0dWRlCiAgICApOwogICAgZWxsaXBzb2lkR2VvZGVzaWMyLl9zdGFydCA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKAogICAgICBzdGFydCwKICAgICAgZWxsaXBzb2lkR2VvZGVzaWMyLl9zdGFydAogICAgKTsKICAgIGVsbGlwc29pZEdlb2Rlc2ljMi5fZW5kID0gQ2FydG9ncmFwaGljX2RlZmF1bHQuY2xvbmUoZW5kLCBlbGxpcHNvaWRHZW9kZXNpYzIuX2VuZCk7CiAgICBlbGxpcHNvaWRHZW9kZXNpYzIuX3N0YXJ0LmhlaWdodCA9IDA7CiAgICBlbGxpcHNvaWRHZW9kZXNpYzIuX2VuZC5oZWlnaHQgPSAwOwogICAgc2V0Q29uc3RhbnRzKGVsbGlwc29pZEdlb2Rlc2ljMik7CiAgfQogIGZ1bmN0aW9uIEVsbGlwc29pZEdlb2Rlc2ljKHN0YXJ0LCBlbmQsIGVsbGlwc29pZCkgewogICAgY29uc3QgZTIgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIHRoaXMuX2VsbGlwc29pZCA9IGUyOwogICAgdGhpcy5fc3RhcnQgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgIHRoaXMuX2VuZCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgdGhpcy5fY29uc3RhbnRzID0ge307CiAgICB0aGlzLl9zdGFydEhlYWRpbmcgPSB2b2lkIDA7CiAgICB0aGlzLl9lbmRIZWFkaW5nID0gdm9pZCAwOwogICAgdGhpcy5fZGlzdGFuY2UgPSB2b2lkIDA7CiAgICB0aGlzLl91U3F1YXJlZCA9IHZvaWQgMDsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoc3RhcnQpICYmIGRlZmluZWRfZGVmYXVsdChlbmQpKSB7CiAgICAgIGNvbXB1dGVQcm9wZXJ0aWVzMih0aGlzLCBzdGFydCwgZW5kLCBlMik7CiAgICB9CiAgfQogIHZhciBzY3JhdGNoQ2FydDEyLCBzY3JhdGNoQ2FydDIyLCBFbGxpcHNvaWRHZW9kZXNpY19kZWZhdWx0OwogIHZhciBpbml0X0VsbGlwc29pZEdlb2Rlc2ljID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRHZW9kZXNpYy5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgc2NyYXRjaENhcnQxMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnQyMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRWxsaXBzb2lkR2VvZGVzaWMucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgZWxsaXBzb2lkLgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRHZW9kZXNpYy5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGVsbGlwc29pZDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2VsbGlwc29pZDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHN1cmZhY2UgZGlzdGFuY2UgYmV0d2VlbiB0aGUgc3RhcnQgYW5kIGVuZCBwb2ludAogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRHZW9kZXNpYy5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIHN1cmZhY2VEaXN0YW5jZTogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJkaXN0YW5jZSIsIHRoaXMuX2Rpc3RhbmNlKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2Rpc3RhbmNlOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgaW5pdGlhbCBwbGFuZXRvZGV0aWMgcG9pbnQgb24gdGhlIHBhdGguCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZEdlb2Rlc2ljLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtDYXJ0b2dyYXBoaWN9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgc3RhcnQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9zdGFydDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGZpbmFsIHBsYW5ldG9kZXRpYyBwb2ludCBvbiB0aGUgcGF0aC4KICAgICAgICAgKiBAbWVtYmVyb2YgRWxsaXBzb2lkR2VvZGVzaWMucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0NhcnRvZ3JhcGhpY30KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBlbmQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbmQ7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBoZWFkaW5nIGF0IHRoZSBpbml0aWFsIHBvaW50LgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRHZW9kZXNpYy5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIHN0YXJ0SGVhZGluZzogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJkaXN0YW5jZSIsIHRoaXMuX2Rpc3RhbmNlKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0YXJ0SGVhZGluZzsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGhlYWRpbmcgYXQgdGhlIGZpbmFsIHBvaW50LgogICAgICAgICAqIEBtZW1iZXJvZiBFbGxpcHNvaWRHZW9kZXNpYy5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGVuZEhlYWRpbmc6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiZGlzdGFuY2UiLCB0aGlzLl9kaXN0YW5jZSk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbmRIZWFkaW5nOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIEVsbGlwc29pZEdlb2Rlc2ljLnByb3RvdHlwZS5zZXRFbmRQb2ludHMgPSBmdW5jdGlvbihzdGFydCwgZW5kKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJzdGFydCIsIHN0YXJ0KTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImVuZCIsIGVuZCk7CiAgICAgICAgY29tcHV0ZVByb3BlcnRpZXMyKHRoaXMsIHN0YXJ0LCBlbmQsIHRoaXMuX2VsbGlwc29pZCk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZEdlb2Rlc2ljLnByb3RvdHlwZS5pbnRlcnBvbGF0ZVVzaW5nRnJhY3Rpb24gPSBmdW5jdGlvbihmcmFjdGlvbiwgcmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIHRoaXMuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSgKICAgICAgICAgIHRoaXMuX2Rpc3RhbmNlICogZnJhY3Rpb24sCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBFbGxpcHNvaWRHZW9kZXNpYy5wcm90b3R5cGUuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSA9IGZ1bmN0aW9uKGRpc3RhbmNlLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImRpc3RhbmNlIiwgdGhpcy5fZGlzdGFuY2UpOwogICAgICAgIGNvbnN0IGNvbnN0YW50cyA9IHRoaXMuX2NvbnN0YW50czsKICAgICAgICBjb25zdCBzMiA9IGNvbnN0YW50cy5kaXN0YW5jZVJhdGlvICsgZGlzdGFuY2UgLyBjb25zdGFudHMuYjsKICAgICAgICBjb25zdCBjb3NpbmUyUyA9IE1hdGguY29zKDIgKiBzMik7CiAgICAgICAgY29uc3QgY29zaW5lNFMgPSBNYXRoLmNvcyg0ICogczIpOwogICAgICAgIGNvbnN0IGNvc2luZTZTID0gTWF0aC5jb3MoNiAqIHMyKTsKICAgICAgICBjb25zdCBzaW5lMlMgPSBNYXRoLnNpbigyICogczIpOwogICAgICAgIGNvbnN0IHNpbmU0UyA9IE1hdGguc2luKDQgKiBzMik7CiAgICAgICAgY29uc3Qgc2luZTZTID0gTWF0aC5zaW4oNiAqIHMyKTsKICAgICAgICBjb25zdCBzaW5lOFMgPSBNYXRoLnNpbig4ICogczIpOwogICAgICAgIGNvbnN0IHMyMiA9IHMyICogczI7CiAgICAgICAgY29uc3QgczMgPSBzMiAqIHMyMjsKICAgICAgICBjb25zdCB1OE92ZXIyNTYgPSBjb25zdGFudHMudThPdmVyMjU2OwogICAgICAgIGNvbnN0IHUyT3ZlcjQgPSBjb25zdGFudHMudTJPdmVyNDsKICAgICAgICBjb25zdCB1Nk92ZXI2NCA9IGNvbnN0YW50cy51Nk92ZXI2NDsKICAgICAgICBjb25zdCB1NE92ZXIxNiA9IGNvbnN0YW50cy51NE92ZXIxNjsKICAgICAgICBsZXQgc2lnbWEgPSAyICogczMgKiB1OE92ZXIyNTYgKiBjb3NpbmUyUyAvIDMgKyBzMiAqICgxIC0gdTJPdmVyNCArIDcgKiB1NE92ZXIxNiAvIDQgLSAxNSAqIHU2T3ZlcjY0IC8gNCArIDU3OSAqIHU4T3ZlcjI1NiAvIDY0IC0gKHU0T3ZlcjE2IC0gMTUgKiB1Nk92ZXI2NCAvIDQgKyAxODcgKiB1OE92ZXIyNTYgLyAxNikgKiBjb3NpbmUyUyAtICg1ICogdTZPdmVyNjQgLyA0IC0gMTE1ICogdThPdmVyMjU2IC8gMTYpICogY29zaW5lNFMgLSAyOSAqIHU4T3ZlcjI1NiAqIGNvc2luZTZTIC8gMTYpICsgKHUyT3ZlcjQgLyAyIC0gdTRPdmVyMTYgKyA3MSAqIHU2T3ZlcjY0IC8gMzIgLSA4NSAqIHU4T3ZlcjI1NiAvIDE2KSAqIHNpbmUyUyArICg1ICogdTRPdmVyMTYgLyAxNiAtIDUgKiB1Nk92ZXI2NCAvIDQgKyAzODMgKiB1OE92ZXIyNTYgLyA5NikgKiBzaW5lNFMgLSBzMjIgKiAoKHU2T3ZlcjY0IC0gMTEgKiB1OE92ZXIyNTYgLyAyKSAqIHNpbmUyUyArIDUgKiB1OE92ZXIyNTYgKiBzaW5lNFMgLyAyKSArICgyOSAqIHU2T3ZlcjY0IC8gOTYgLSAyOSAqIHU4T3ZlcjI1NiAvIDE2KSAqIHNpbmU2UyArIDUzOSAqIHU4T3ZlcjI1NiAqIHNpbmU4UyAvIDE1MzY7CiAgICAgICAgY29uc3QgdGhldGEgPSBNYXRoLmFzaW4oTWF0aC5zaW4oc2lnbWEpICogY29uc3RhbnRzLmNvc2luZUFscGhhKTsKICAgICAgICBjb25zdCBsYXRpdHVkZSA9IE1hdGguYXRhbihjb25zdGFudHMuYSAvIGNvbnN0YW50cy5iICogTWF0aC50YW4odGhldGEpKTsKICAgICAgICBzaWdtYSA9IHNpZ21hIC0gY29uc3RhbnRzLnNpZ21hOwogICAgICAgIGNvbnN0IGNvc2luZVR3aWNlU2lnbWFNaWRwb2ludCA9IE1hdGguY29zKDIgKiBjb25zdGFudHMuc2lnbWEgKyBzaWdtYSk7CiAgICAgICAgY29uc3Qgc2luZVNpZ21hID0gTWF0aC5zaW4oc2lnbWEpOwogICAgICAgIGNvbnN0IGNvc2luZVNpZ21hID0gTWF0aC5jb3Moc2lnbWEpOwogICAgICAgIGNvbnN0IGNjID0gY29uc3RhbnRzLmNvc2luZVUgKiBjb3NpbmVTaWdtYTsKICAgICAgICBjb25zdCBzcyA9IGNvbnN0YW50cy5zaW5lVSAqIHNpbmVTaWdtYTsKICAgICAgICBjb25zdCBsYW1iZGEgPSBNYXRoLmF0YW4yKAogICAgICAgICAgc2luZVNpZ21hICogY29uc3RhbnRzLnNpbmVIZWFkaW5nLAogICAgICAgICAgY2MgLSBzcyAqIGNvbnN0YW50cy5jb3NpbmVIZWFkaW5nCiAgICAgICAgKTsKICAgICAgICBjb25zdCBsMiA9IGxhbWJkYSAtIGNvbXB1dGVEZWx0YUxhbWJkYSgKICAgICAgICAgIGNvbnN0YW50cy5mLAogICAgICAgICAgY29uc3RhbnRzLnNpbmVBbHBoYSwKICAgICAgICAgIGNvbnN0YW50cy5jb3NpbmVTcXVhcmVkQWxwaGEsCiAgICAgICAgICBzaWdtYSwKICAgICAgICAgIHNpbmVTaWdtYSwKICAgICAgICAgIGNvc2luZVNpZ21hLAogICAgICAgICAgY29zaW5lVHdpY2VTaWdtYU1pZHBvaW50CiAgICAgICAgKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdC5sb25naXR1ZGUgPSB0aGlzLl9zdGFydC5sb25naXR1ZGUgKyBsMjsKICAgICAgICAgIHJlc3VsdC5sYXRpdHVkZSA9IGxhdGl0dWRlOwogICAgICAgICAgcmVzdWx0LmhlaWdodCA9IDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KHRoaXMuX3N0YXJ0LmxvbmdpdHVkZSArIGwyLCBsYXRpdHVkZSwgMCk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZEdlb2Rlc2ljX2RlZmF1bHQgPSBFbGxpcHNvaWRHZW9kZXNpYzsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lUGlwZWxpbmUuanMKICBmdW5jdGlvbiBzdWJkaXZpZGVIZWlnaHRzKG51bVBvaW50cywgaDAsIGgxKSB7CiAgICBjb25zdCBoZWlnaHRzID0gc3ViZGl2aWRlSGVpZ2h0c1NjcmF0Y2hBcnJheTsKICAgIGhlaWdodHMubGVuZ3RoID0gbnVtUG9pbnRzOwogICAgbGV0IGkyOwogICAgaWYgKGgwID09PSBoMSkgewogICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1Qb2ludHM7IGkyKyspIHsKICAgICAgICBoZWlnaHRzW2kyXSA9IGgwOwogICAgICB9CiAgICAgIHJldHVybiBoZWlnaHRzOwogICAgfQogICAgY29uc3QgZEhlaWdodCA9IGgxIC0gaDA7CiAgICBjb25zdCBoZWlnaHRQZXJWZXJ0ZXggPSBkSGVpZ2h0IC8gbnVtUG9pbnRzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtUG9pbnRzOyBpMisrKSB7CiAgICAgIGNvbnN0IGgyID0gaDAgKyBpMiAqIGhlaWdodFBlclZlcnRleDsKICAgICAgaGVpZ2h0c1tpMl0gPSBoMjsKICAgIH0KICAgIHJldHVybiBoZWlnaHRzOwogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZUNhcnRlc2lhbkFyYyhwMCwgcDEsIG1pbkRpc3RhbmNlLCBlbGxpcHNvaWQsIGgwLCBoMSwgYXJyYXksIG9mZnNldCkgewogICAgY29uc3QgZmlyc3QgPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwMCwgc2NhbGVGaXJzdCk7CiAgICBjb25zdCBsYXN0ID0gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UocDEsIHNjYWxlTGFzdCk7CiAgICBjb25zdCBudW1Qb2ludHMgPSBQb2x5bGluZVBpcGVsaW5lLm51bWJlck9mUG9pbnRzKHAwLCBwMSwgbWluRGlzdGFuY2UpOwogICAgY29uc3Qgc3RhcnQgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoZmlyc3QsIGNhcnRvMSk7CiAgICBjb25zdCBlbmQgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMobGFzdCwgY2FydG8yKTsKICAgIGNvbnN0IGhlaWdodHMgPSBzdWJkaXZpZGVIZWlnaHRzKG51bVBvaW50cywgaDAsIGgxKTsKICAgIGVsbGlwc29pZEdlb2Rlc2ljLnNldEVuZFBvaW50cyhzdGFydCwgZW5kKTsKICAgIGNvbnN0IHN1cmZhY2VEaXN0YW5jZUJldHdlZW5Qb2ludHMgPSBlbGxpcHNvaWRHZW9kZXNpYy5zdXJmYWNlRGlzdGFuY2UgLyBudW1Qb2ludHM7CiAgICBsZXQgaW5kZXggPSBvZmZzZXQ7CiAgICBzdGFydC5oZWlnaHQgPSBoMDsKICAgIGxldCBjYXJ0ID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKHN0YXJ0LCBjYXJ0ZXNpYW4pOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soY2FydCwgYXJyYXksIGluZGV4KTsKICAgIGluZGV4ICs9IDM7CiAgICBmb3IgKGxldCBpMiA9IDE7IGkyIDwgbnVtUG9pbnRzOyBpMisrKSB7CiAgICAgIGNvbnN0IGNhcnRvID0gZWxsaXBzb2lkR2VvZGVzaWMuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSgKICAgICAgICBpMiAqIHN1cmZhY2VEaXN0YW5jZUJldHdlZW5Qb2ludHMsCiAgICAgICAgY2FydG8yCiAgICAgICk7CiAgICAgIGNhcnRvLmhlaWdodCA9IGhlaWdodHNbaTJdOwogICAgICBjYXJ0ID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGNhcnRvLCBjYXJ0ZXNpYW4pOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhjYXJ0LCBhcnJheSwgaW5kZXgpOwogICAgICBpbmRleCArPSAzOwogICAgfQogICAgcmV0dXJuIGluZGV4OwogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZUNhcnRlc2lhblJodW1iQXJjKHAwLCBwMSwgZ3JhbnVsYXJpdHksIGVsbGlwc29pZCwgaDAsIGgxLCBhcnJheSwgb2Zmc2V0KSB7CiAgICBjb25zdCBzdGFydCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMCwgY2FydG8xKTsKICAgIGNvbnN0IGVuZCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMSwgY2FydG8yKTsKICAgIGNvbnN0IG51bVBvaW50cyA9IFBvbHlsaW5lUGlwZWxpbmUubnVtYmVyT2ZQb2ludHNSaHVtYkxpbmUoCiAgICAgIHN0YXJ0LAogICAgICBlbmQsCiAgICAgIGdyYW51bGFyaXR5CiAgICApOwogICAgc3RhcnQuaGVpZ2h0ID0gMDsKICAgIGVuZC5oZWlnaHQgPSAwOwogICAgY29uc3QgaGVpZ2h0cyA9IHN1YmRpdmlkZUhlaWdodHMobnVtUG9pbnRzLCBoMCwgaDEpOwogICAgaWYgKCFlbGxpcHNvaWRSaHVtYi5lbGxpcHNvaWQuZXF1YWxzKGVsbGlwc29pZCkpIHsKICAgICAgZWxsaXBzb2lkUmh1bWIgPSBuZXcgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQodm9pZCAwLCB2b2lkIDAsIGVsbGlwc29pZCk7CiAgICB9CiAgICBlbGxpcHNvaWRSaHVtYi5zZXRFbmRQb2ludHMoc3RhcnQsIGVuZCk7CiAgICBjb25zdCBzdXJmYWNlRGlzdGFuY2VCZXR3ZWVuUG9pbnRzID0gZWxsaXBzb2lkUmh1bWIuc3VyZmFjZURpc3RhbmNlIC8gbnVtUG9pbnRzOwogICAgbGV0IGluZGV4ID0gb2Zmc2V0OwogICAgc3RhcnQuaGVpZ2h0ID0gaDA7CiAgICBsZXQgY2FydCA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihzdGFydCwgY2FydGVzaWFuKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGNhcnQsIGFycmF5LCBpbmRleCk7CiAgICBpbmRleCArPSAzOwogICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IG51bVBvaW50czsgaTIrKykgewogICAgICBjb25zdCBjYXJ0byA9IGVsbGlwc29pZFJodW1iLmludGVycG9sYXRlVXNpbmdTdXJmYWNlRGlzdGFuY2UoCiAgICAgICAgaTIgKiBzdXJmYWNlRGlzdGFuY2VCZXR3ZWVuUG9pbnRzLAogICAgICAgIGNhcnRvMgogICAgICApOwogICAgICBjYXJ0by5oZWlnaHQgPSBoZWlnaHRzW2kyXTsKICAgICAgY2FydCA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihjYXJ0bywgY2FydGVzaWFuKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soY2FydCwgYXJyYXksIGluZGV4KTsKICAgICAgaW5kZXggKz0gMzsKICAgIH0KICAgIHJldHVybiBpbmRleDsKICB9CiAgdmFyIFBvbHlsaW5lUGlwZWxpbmUsIGNhcnRvU2NyYXRjaCwgd3JhcExvbmdpdHVkZUludmVyc01hdHJpeCwgd3JhcExvbmdpdHVkZU9yaWdpbiwgd3JhcExvbmdpdHVkZVhaTm9ybWFsLCB3cmFwTG9uZ2l0dWRlWFpQbGFuZSwgd3JhcExvbmdpdHVkZVlaTm9ybWFsLCB3cmFwTG9uZ2l0dWRlWVpQbGFuZSwgd3JhcExvbmdpdHVkZUludGVyc2VjdGlvbiwgd3JhcExvbmdpdHVkZU9mZnNldCwgc3ViZGl2aWRlSGVpZ2h0c1NjcmF0Y2hBcnJheSwgY2FydG8xLCBjYXJ0bzIsIGNhcnRlc2lhbiwgc2NhbGVGaXJzdCwgc2NhbGVMYXN0LCBlbGxpcHNvaWRHZW9kZXNpYywgZWxsaXBzb2lkUmh1bWIsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMwMiwgc2NyYXRjaENhcnRvZ3JhcGhpYzEyLCBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWxpbmVQaXBlbGluZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWxpbmVQaXBlbGluZS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZEdlb2Rlc2ljKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkUmh1bWJMaW5lKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0aW9uVGVzdHMoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBpbml0X1BsYW5lKCk7CiAgICAgIFBvbHlsaW5lUGlwZWxpbmUgPSB7fTsKICAgICAgUG9seWxpbmVQaXBlbGluZS5udW1iZXJPZlBvaW50cyA9IGZ1bmN0aW9uKHAwLCBwMSwgbWluRGlzdGFuY2UpIHsKICAgICAgICBjb25zdCBkaXN0YW5jZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5kaXN0YW5jZShwMCwgcDEpOwogICAgICAgIHJldHVybiBNYXRoLmNlaWwoZGlzdGFuY2UgLyBtaW5EaXN0YW5jZSk7CiAgICAgIH07CiAgICAgIFBvbHlsaW5lUGlwZWxpbmUubnVtYmVyT2ZQb2ludHNSaHVtYkxpbmUgPSBmdW5jdGlvbihwMCwgcDEsIGdyYW51bGFyaXR5KSB7CiAgICAgICAgY29uc3QgcmFkaWFuc0Rpc3RhbmNlU3F1YXJlZCA9IE1hdGgucG93KHAwLmxvbmdpdHVkZSAtIHAxLmxvbmdpdHVkZSwgMikgKyBNYXRoLnBvdyhwMC5sYXRpdHVkZSAtIHAxLmxhdGl0dWRlLCAyKTsKICAgICAgICByZXR1cm4gTWF0aC5tYXgoCiAgICAgICAgICAxLAogICAgICAgICAgTWF0aC5jZWlsKE1hdGguc3FydChyYWRpYW5zRGlzdGFuY2VTcXVhcmVkIC8gKGdyYW51bGFyaXR5ICogZ3JhbnVsYXJpdHkpKSkKICAgICAgICApOwogICAgICB9OwogICAgICBjYXJ0b1NjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgUG9seWxpbmVQaXBlbGluZS5leHRyYWN0SGVpZ2h0cyA9IGZ1bmN0aW9uKHBvc2l0aW9ucywgZWxsaXBzb2lkKSB7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBjb25zdCBoZWlnaHRzID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgcDIgPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgaGVpZ2h0c1tpMl0gPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocDIsIGNhcnRvU2NyYXRjaCkuaGVpZ2h0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gaGVpZ2h0czsKICAgICAgfTsKICAgICAgd3JhcExvbmdpdHVkZUludmVyc01hdHJpeCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgd3JhcExvbmdpdHVkZU9yaWdpbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgd3JhcExvbmdpdHVkZVhaTm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB3cmFwTG9uZ2l0dWRlWFpQbGFuZSA9IG5ldyBQbGFuZV9kZWZhdWx0KENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1gsIDApOwogICAgICB3cmFwTG9uZ2l0dWRlWVpOb3JtYWwgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHdyYXBMb25naXR1ZGVZWlBsYW5lID0gbmV3IFBsYW5lX2RlZmF1bHQoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgMCk7CiAgICAgIHdyYXBMb25naXR1ZGVJbnRlcnNlY3Rpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHdyYXBMb25naXR1ZGVPZmZzZXQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN1YmRpdmlkZUhlaWdodHNTY3JhdGNoQXJyYXkgPSBbXTsKICAgICAgY2FydG8xID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIGNhcnRvMiA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlRmlyc3QgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjYWxlTGFzdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZWxsaXBzb2lkR2VvZGVzaWMgPSBuZXcgRWxsaXBzb2lkR2VvZGVzaWNfZGVmYXVsdCgpOwogICAgICBlbGxpcHNvaWRSaHVtYiA9IG5ldyBFbGxpcHNvaWRSaHVtYkxpbmVfZGVmYXVsdCgpOwogICAgICBQb2x5bGluZVBpcGVsaW5lLndyYXBMb25naXR1ZGUgPSBmdW5jdGlvbihwb3NpdGlvbnMsIG1vZGVsTWF0cml4KSB7CiAgICAgICAgY29uc3QgY2FydGVzaWFucyA9IFtdOwogICAgICAgIGNvbnN0IHNlZ21lbnRzID0gW107CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpICYmIHBvc2l0aW9ucy5sZW5ndGggPiAwKSB7CiAgICAgICAgICBtb2RlbE1hdHJpeCA9IG1vZGVsTWF0cml4ID8/IE1hdHJpeDRfZGVmYXVsdC5JREVOVElUWTsKICAgICAgICAgIGNvbnN0IGludmVyc2VNb2RlbE1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC5pbnZlcnNlVHJhbnNmb3JtYXRpb24oCiAgICAgICAgICAgIG1vZGVsTWF0cml4LAogICAgICAgICAgICB3cmFwTG9uZ2l0dWRlSW52ZXJzTWF0cml4CiAgICAgICAgICApOwogICAgICAgICAgY29uc3Qgb3JpZ2luID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCgKICAgICAgICAgICAgaW52ZXJzZU1vZGVsTWF0cml4LAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTywKICAgICAgICAgICAgd3JhcExvbmdpdHVkZU9yaWdpbgogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHh6Tm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludEFzVmVjdG9yKAogICAgICAgICAgICAgIGludmVyc2VNb2RlbE1hdHJpeCwKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZLAogICAgICAgICAgICAgIHdyYXBMb25naXR1ZGVYWk5vcm1hbAogICAgICAgICAgICApLAogICAgICAgICAgICB3cmFwTG9uZ2l0dWRlWFpOb3JtYWwKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCB4elBsYW5lMiA9IFBsYW5lX2RlZmF1bHQuZnJvbVBvaW50Tm9ybWFsKAogICAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICAgIHh6Tm9ybWFsLAogICAgICAgICAgICB3cmFwTG9uZ2l0dWRlWFpQbGFuZQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHl6Tm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludEFzVmVjdG9yKAogICAgICAgICAgICAgIGludmVyc2VNb2RlbE1hdHJpeCwKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9YLAogICAgICAgICAgICAgIHdyYXBMb25naXR1ZGVZWk5vcm1hbAogICAgICAgICAgICApLAogICAgICAgICAgICB3cmFwTG9uZ2l0dWRlWVpOb3JtYWwKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCB5elBsYW5lID0gUGxhbmVfZGVmYXVsdC5mcm9tUG9pbnROb3JtYWwoCiAgICAgICAgICAgIG9yaWdpbiwKICAgICAgICAgICAgeXpOb3JtYWwsCiAgICAgICAgICAgIHdyYXBMb25naXR1ZGVZWlBsYW5lCiAgICAgICAgICApOwogICAgICAgICAgbGV0IGNvdW50ID0gMTsKICAgICAgICAgIGNhcnRlc2lhbnMucHVzaChDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb25zWzBdKSk7CiAgICAgICAgICBsZXQgcHJldiA9IGNhcnRlc2lhbnNbMF07CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBjb25zdCBjdXIgPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgICBpZiAoUGxhbmVfZGVmYXVsdC5nZXRQb2ludERpc3RhbmNlKHl6UGxhbmUsIHByZXYpIDwgMCB8fCBQbGFuZV9kZWZhdWx0LmdldFBvaW50RGlzdGFuY2UoeXpQbGFuZSwgY3VyKSA8IDApIHsKICAgICAgICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LmxpbmVTZWdtZW50UGxhbmUoCiAgICAgICAgICAgICAgICBwcmV2LAogICAgICAgICAgICAgICAgY3VyLAogICAgICAgICAgICAgICAgeHpQbGFuZTIsCiAgICAgICAgICAgICAgICB3cmFwTG9uZ2l0dWRlSW50ZXJzZWN0aW9uCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGludGVyc2VjdGlvbikpIHsKICAgICAgICAgICAgICAgIGNvbnN0IG9mZnNldCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICAgICAgICB4ek5vcm1hbCwKICAgICAgICAgICAgICAgICAgNWUtOSwKICAgICAgICAgICAgICAgICAgd3JhcExvbmdpdHVkZU9mZnNldAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIGlmIChQbGFuZV9kZWZhdWx0LmdldFBvaW50RGlzdGFuY2UoeHpQbGFuZTIsIHByZXYpIDwgMCkgewogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKG9mZnNldCwgb2Zmc2V0KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGNhcnRlc2lhbnMucHVzaCgKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChpbnRlcnNlY3Rpb24sIG9mZnNldCwgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpKQogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHNlZ21lbnRzLnB1c2goY291bnQgKyAxKTsKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUob2Zmc2V0LCBvZmZzZXQpOwogICAgICAgICAgICAgICAgY2FydGVzaWFucy5wdXNoKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGludGVyc2VjdGlvbiwgb2Zmc2V0LCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkpCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgY291bnQgPSAxOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBjYXJ0ZXNpYW5zLnB1c2goQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHBvc2l0aW9uc1tpMl0pKTsKICAgICAgICAgICAgY291bnQrKzsKICAgICAgICAgICAgcHJldiA9IGN1cjsKICAgICAgICAgIH0KICAgICAgICAgIHNlZ21lbnRzLnB1c2goY291bnQpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgcG9zaXRpb25zOiBjYXJ0ZXNpYW5zLAogICAgICAgICAgbGVuZ3Roczogc2VnbWVudHMKICAgICAgICB9OwogICAgICB9OwogICAgICBQb2x5bGluZVBpcGVsaW5lLmdlbmVyYXRlQXJjID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMpKSB7CiAgICAgICAgICBvcHRpb25zID0ge307CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG9wdGlvbnMucG9zaXRpb25zOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcHRpb25zLnBvc2l0aW9ucyBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgIGxldCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodCA/PyAwOwogICAgICAgIGNvbnN0IGhhc0hlaWdodEFycmF5ID0gQXJyYXkuaXNBcnJheShoZWlnaHQpOwogICAgICAgIGlmIChsZW5ndGggPCAxKSB7CiAgICAgICAgICByZXR1cm4gW107CiAgICAgICAgfSBlbHNlIGlmIChsZW5ndGggPT09IDEpIHsKICAgICAgICAgIGNvbnN0IHAyID0gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UocG9zaXRpb25zWzBdLCBzY2FsZUZpcnN0KTsKICAgICAgICAgIGhlaWdodCA9IGhhc0hlaWdodEFycmF5ID8gaGVpZ2h0WzBdIDogaGVpZ2h0OwogICAgICAgICAgaWYgKGhlaWdodCAhPT0gMCkgewogICAgICAgICAgICBjb25zdCBuMiA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocDIsIGNhcnRlc2lhbik7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG4yLCBoZWlnaHQsIG4yKTsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwMiwgbjIsIHAyKTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBbcDIueCwgcDIueSwgcDIuel07CiAgICAgICAgfQogICAgICAgIGxldCBtaW5EaXN0YW5jZSA9IG9wdGlvbnMubWluRGlzdGFuY2U7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQobWluRGlzdGFuY2UpKSB7CiAgICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgICAgICAgIG1pbkRpc3RhbmNlID0gTWF0aF9kZWZhdWx0LmNob3JkTGVuZ3RoKGdyYW51bGFyaXR5LCBlbGxpcHNvaWQubWF4aW11bVJhZGl1cyk7CiAgICAgICAgfQogICAgICAgIGxldCBudW1Qb2ludHMgPSAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGggLSAxOyBpMisrKSB7CiAgICAgICAgICBudW1Qb2ludHMgKz0gUG9seWxpbmVQaXBlbGluZS5udW1iZXJPZlBvaW50cygKICAgICAgICAgICAgcG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgcG9zaXRpb25zW2kyICsgMV0sCiAgICAgICAgICAgIG1pbkRpc3RhbmNlCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBjb25zdCBhcnJheUxlbmd0aCA9IChudW1Qb2ludHMgKyAxKSAqIDM7CiAgICAgICAgY29uc3QgbmV3UG9zaXRpb25zID0gbmV3IEFycmF5KGFycmF5TGVuZ3RoKTsKICAgICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGggLSAxOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBwMCA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICBjb25zdCBwMSA9IHBvc2l0aW9uc1tpMiArIDFdOwogICAgICAgICAgY29uc3QgaDAgPSBoYXNIZWlnaHRBcnJheSA/IGhlaWdodFtpMl0gOiBoZWlnaHQ7CiAgICAgICAgICBjb25zdCBoMSA9IGhhc0hlaWdodEFycmF5ID8gaGVpZ2h0W2kyICsgMV0gOiBoZWlnaHQ7CiAgICAgICAgICBvZmZzZXQgPSBnZW5lcmF0ZUNhcnRlc2lhbkFyYygKICAgICAgICAgICAgcDAsCiAgICAgICAgICAgIHAxLAogICAgICAgICAgICBtaW5EaXN0YW5jZSwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBoMCwKICAgICAgICAgICAgaDEsCiAgICAgICAgICAgIG5ld1Bvc2l0aW9ucywKICAgICAgICAgICAgb2Zmc2V0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBzdWJkaXZpZGVIZWlnaHRzU2NyYXRjaEFycmF5Lmxlbmd0aCA9IDA7CiAgICAgICAgY29uc3QgbGFzdFBvaW50ID0gcG9zaXRpb25zW2xlbmd0aCAtIDFdOwogICAgICAgIGNvbnN0IGNhcnRvID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKGxhc3RQb2ludCwgY2FydG8xKTsKICAgICAgICBjYXJ0by5oZWlnaHQgPSBoYXNIZWlnaHRBcnJheSA/IGhlaWdodFtsZW5ndGggLSAxXSA6IGhlaWdodDsKICAgICAgICBjb25zdCBjYXJ0ID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGNhcnRvLCBjYXJ0ZXNpYW4pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGNhcnQsIG5ld1Bvc2l0aW9ucywgYXJyYXlMZW5ndGggLSAzKTsKICAgICAgICByZXR1cm4gbmV3UG9zaXRpb25zOwogICAgICB9OwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljMDIgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzEyID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIFBvbHlsaW5lUGlwZWxpbmUuZ2VuZXJhdGVSaHVtYkFyYyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvcHRpb25zKSkgewogICAgICAgICAgb3B0aW9ucyA9IHt9OwogICAgICAgIH0KICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBvcHRpb25zLnBvc2l0aW9uczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy5wb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBsZXQgaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQgPz8gMDsKICAgICAgICBjb25zdCBoYXNIZWlnaHRBcnJheSA9IEFycmF5LmlzQXJyYXkoaGVpZ2h0KTsKICAgICAgICBpZiAobGVuZ3RoIDwgMSkgewogICAgICAgICAgcmV0dXJuIFtdOwogICAgICAgIH0gZWxzZSBpZiAobGVuZ3RoID09PSAxKSB7CiAgICAgICAgICBjb25zdCBwMiA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKHBvc2l0aW9uc1swXSwgc2NhbGVGaXJzdCk7CiAgICAgICAgICBoZWlnaHQgPSBoYXNIZWlnaHRBcnJheSA/IGhlaWdodFswXSA6IGhlaWdodDsKICAgICAgICAgIGlmIChoZWlnaHQgIT09IDApIHsKICAgICAgICAgICAgY29uc3QgbjIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHAyLCBjYXJ0ZXNpYW4pOwogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihuMiwgaGVpZ2h0LCBuMik7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocDIsIG4yLCBwMik7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gW3AyLngsIHAyLnksIHAyLnpdOwogICAgICAgIH0KICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgICAgICBsZXQgbnVtUG9pbnRzID0gMDsKICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IGMwID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgcG9zaXRpb25zWzBdLAogICAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzAyCiAgICAgICAgKTsKICAgICAgICBsZXQgYzE7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoIC0gMTsgaTIrKykgewogICAgICAgICAgYzEgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgICAgICAgIHBvc2l0aW9uc1tpMiArIDFdLAogICAgICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljMTIKICAgICAgICAgICk7CiAgICAgICAgICBudW1Qb2ludHMgKz0gUG9seWxpbmVQaXBlbGluZS5udW1iZXJPZlBvaW50c1JodW1iTGluZShjMCwgYzEsIGdyYW51bGFyaXR5KTsKICAgICAgICAgIGMwID0gQ2FydG9ncmFwaGljX2RlZmF1bHQuY2xvbmUoYzEsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMwMik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGFycmF5TGVuZ3RoID0gKG51bVBvaW50cyArIDEpICogMzsKICAgICAgICBjb25zdCBuZXdQb3NpdGlvbnMgPSBuZXcgQXJyYXkoYXJyYXlMZW5ndGgpOwogICAgICAgIGxldCBvZmZzZXQgPSAwOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHAwID0gcG9zaXRpb25zW2kyXTsKICAgICAgICAgIGNvbnN0IHAxID0gcG9zaXRpb25zW2kyICsgMV07CiAgICAgICAgICBjb25zdCBoMCA9IGhhc0hlaWdodEFycmF5ID8gaGVpZ2h0W2kyXSA6IGhlaWdodDsKICAgICAgICAgIGNvbnN0IGgxID0gaGFzSGVpZ2h0QXJyYXkgPyBoZWlnaHRbaTIgKyAxXSA6IGhlaWdodDsKICAgICAgICAgIG9mZnNldCA9IGdlbmVyYXRlQ2FydGVzaWFuUmh1bWJBcmMoCiAgICAgICAgICAgIHAwLAogICAgICAgICAgICBwMSwKICAgICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgaDAsCiAgICAgICAgICAgIGgxLAogICAgICAgICAgICBuZXdQb3NpdGlvbnMsCiAgICAgICAgICAgIG9mZnNldAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgc3ViZGl2aWRlSGVpZ2h0c1NjcmF0Y2hBcnJheS5sZW5ndGggPSAwOwogICAgICAgIGNvbnN0IGxhc3RQb2ludCA9IHBvc2l0aW9uc1tsZW5ndGggLSAxXTsKICAgICAgICBjb25zdCBjYXJ0byA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhsYXN0UG9pbnQsIGNhcnRvMSk7CiAgICAgICAgY2FydG8uaGVpZ2h0ID0gaGFzSGVpZ2h0QXJyYXkgPyBoZWlnaHRbbGVuZ3RoIC0gMV0gOiBoZWlnaHQ7CiAgICAgICAgY29uc3QgY2FydCA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihjYXJ0bywgY2FydGVzaWFuKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhjYXJ0LCBuZXdQb3NpdGlvbnMsIGFycmF5TGVuZ3RoIC0gMyk7CiAgICAgICAgcmV0dXJuIG5ld1Bvc2l0aW9uczsKICAgICAgfTsKICAgICAgUG9seWxpbmVQaXBlbGluZS5nZW5lcmF0ZUNhcnRlc2lhbkFyYyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBjb25zdCBudW1iZXJBcnJheSA9IFBvbHlsaW5lUGlwZWxpbmUuZ2VuZXJhdGVBcmMob3B0aW9ucyk7CiAgICAgICAgY29uc3Qgc2l6ZSA9IG51bWJlckFycmF5Lmxlbmd0aCAvIDM7CiAgICAgICAgY29uc3QgbmV3UG9zaXRpb25zID0gbmV3IEFycmF5KHNpemUpOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBzaXplOyBpMisrKSB7CiAgICAgICAgICBuZXdQb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhudW1iZXJBcnJheSwgaTIgKiAzKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ld1Bvc2l0aW9uczsKICAgICAgfTsKICAgICAgUG9seWxpbmVQaXBlbGluZS5nZW5lcmF0ZUNhcnRlc2lhblJodW1iQXJjID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIGNvbnN0IG51bWJlckFycmF5ID0gUG9seWxpbmVQaXBlbGluZS5nZW5lcmF0ZVJodW1iQXJjKG9wdGlvbnMpOwogICAgICAgIGNvbnN0IHNpemUgPSBudW1iZXJBcnJheS5sZW5ndGggLyAzOwogICAgICAgIGNvbnN0IG5ld1Bvc2l0aW9ucyA9IG5ldyBBcnJheShzaXplKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgc2l6ZTsgaTIrKykgewogICAgICAgICAgbmV3UG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2sobnVtYmVyQXJyYXksIGkyICogMyk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXdQb3NpdGlvbnM7CiAgICAgIH07CiAgICAgIFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdCA9IFBvbHlsaW5lUGlwZWxpbmU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9vbmVUaW1lV2FybmluZy5qcwogIGZ1bmN0aW9uIG9uZVRpbWVXYXJuaW5nKGlkZW50aWZpZXIsIG1lc3NhZ2UpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGlkZW50aWZpZXIpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJpZGVudGlmaWVyIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQod2FybmluZ3NbaWRlbnRpZmllcl0pKSB7CiAgICAgIHdhcm5pbmdzW2lkZW50aWZpZXJdID0gdHJ1ZTsKICAgICAgY29uc29sZS53YXJuKG1lc3NhZ2UgPz8gaWRlbnRpZmllcik7CiAgICB9CiAgfQogIHZhciB3YXJuaW5ncywgb25lVGltZVdhcm5pbmdfZGVmYXVsdDsKICB2YXIgaW5pdF9vbmVUaW1lV2FybmluZyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvb25lVGltZVdhcm5pbmcuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICB3YXJuaW5ncyA9IHt9OwogICAgICBvbmVUaW1lV2FybmluZy5nZW9tZXRyeU91dGxpbmVzID0gIkVudGl0eSBnZW9tZXRyeSBvdXRsaW5lcyBhcmUgdW5zdXBwb3J0ZWQgb24gdGVycmFpbi4gT3V0bGluZXMgd2lsbCBiZSBkaXNhYmxlZC4gVG8gZW5hYmxlIG91dGxpbmVzLCBkaXNhYmxlIGdlb21ldHJ5IHRlcnJhaW4gY2xhbXBpbmcgYnkgZXhwbGljaXRseSBzZXR0aW5nIGhlaWdodCB0byAwLiI7CiAgICAgIG9uZVRpbWVXYXJuaW5nLmdlb21ldHJ5WkluZGV4ID0gIkVudGl0eSBnZW9tZXRyeSB3aXRoIHpJbmRleCBhcmUgdW5zdXBwb3J0ZWQgd2hlbiBoZWlnaHQgb3IgZXh0cnVkZWRIZWlnaHQgYXJlIGRlZmluZWQuICB6SW5kZXggd2lsbCBiZSBpZ25vcmVkIjsKICAgICAgb25lVGltZVdhcm5pbmcuZ2VvbWV0cnlIZWlnaHRSZWZlcmVuY2UgPSAiRW50aXR5IGNvcnJpZG9yLCBlbGxpcHNlLCBwb2x5Z29uIG9yIHJlY3RhbmdsZSB3aXRoIGhlaWdodFJlZmVyZW5jZSBtdXN0IGFsc28gaGF2ZSBhIGRlZmluZWQgaGVpZ2h0LiAgaGVpZ2h0UmVmZXJlbmNlIHdpbGwgYmUgaWdub3JlZCI7CiAgICAgIG9uZVRpbWVXYXJuaW5nLmdlb21ldHJ5RXh0cnVkZWRIZWlnaHRSZWZlcmVuY2UgPSAiRW50aXR5IGNvcnJpZG9yLCBlbGxpcHNlLCBwb2x5Z29uIG9yIHJlY3RhbmdsZSB3aXRoIGV4dHJ1ZGVkSGVpZ2h0UmVmZXJlbmNlIG11c3QgYWxzbyBoYXZlIGEgZGVmaW5lZCBleHRydWRlZEhlaWdodC4gIGV4dHJ1ZGVkSGVpZ2h0UmVmZXJlbmNlIHdpbGwgYmUgaWdub3JlZCI7CiAgICAgIG9uZVRpbWVXYXJuaW5nX2RlZmF1bHQgPSBvbmVUaW1lV2FybmluZzsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5LmpzCiAgZnVuY3Rpb24gc2NhbGVUb1N1cmZhY2UocG9zaXRpb25zLCBlbGxpcHNvaWQpIHsKICAgIGNvbnN0IGhlaWdodHMgPSBuZXcgQXJyYXkocG9zaXRpb25zLmxlbmd0aCk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zLmxlbmd0aDsgaTIrKykgewogICAgICBjb25zdCBwb3MgPSBwb3NpdGlvbnNbaTJdOwogICAgICBjYXJ0b2dyYXBoaWMgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocG9zLCBjYXJ0b2dyYXBoaWMpOwogICAgICBoZWlnaHRzW2kyXSA9IGNhcnRvZ3JhcGhpYy5oZWlnaHQ7CiAgICAgIHBvc2l0aW9uc1tpMl0gPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwb3MsIHBvcyk7CiAgICB9CiAgICByZXR1cm4gaGVpZ2h0czsKICB9CiAgZnVuY3Rpb24gc3ViZGl2aWRlSGVpZ2h0czIocG9pbnRzLCBoMCwgaDEsIGdyYW51bGFyaXR5KSB7CiAgICBjb25zdCBwMCA9IHBvaW50c1swXTsKICAgIGNvbnN0IHAxID0gcG9pbnRzWzFdOwogICAgY29uc3QgYW5nbGVCZXR3ZWVuID0gQ2FydGVzaWFuM19kZWZhdWx0LmFuZ2xlQmV0d2VlbihwMCwgcDEpOwogICAgY29uc3QgbnVtUG9pbnRzID0gTWF0aC5jZWlsKGFuZ2xlQmV0d2VlbiAvIGdyYW51bGFyaXR5KTsKICAgIGNvbnN0IGhlaWdodHMgPSBuZXcgQXJyYXkobnVtUG9pbnRzKTsKICAgIGxldCBpMjsKICAgIGlmIChoMCA9PT0gaDEpIHsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtUG9pbnRzOyBpMisrKSB7CiAgICAgICAgaGVpZ2h0c1tpMl0gPSBoMDsKICAgICAgfQogICAgICBoZWlnaHRzLnB1c2goaDEpOwogICAgICByZXR1cm4gaGVpZ2h0czsKICAgIH0KICAgIGNvbnN0IGRIZWlnaHQgPSBoMSAtIGgwOwogICAgY29uc3QgaGVpZ2h0UGVyVmVydGV4ID0gZEhlaWdodCAvIG51bVBvaW50czsKICAgIGZvciAoaTIgPSAxOyBpMiA8IG51bVBvaW50czsgaTIrKykgewogICAgICBjb25zdCBoMiA9IGgwICsgaTIgKiBoZWlnaHRQZXJWZXJ0ZXg7CiAgICAgIGhlaWdodHNbaTJdID0gaDI7CiAgICB9CiAgICBoZWlnaHRzWzBdID0gaDA7CiAgICBoZWlnaHRzLnB1c2goaDEpOwogICAgcmV0dXJuIGhlaWdodHM7CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVSb3RhdGlvbkFuZ2xlKHN0YXJ0LCBlbmQsIHBvc2l0aW9uLCBlbGxpcHNvaWQpIHsKICAgIGNvbnN0IHRhbmdlbnRQbGFuZSA9IG5ldyBFbGxpcHNvaWRUYW5nZW50UGxhbmVfZGVmYXVsdChwb3NpdGlvbiwgZWxsaXBzb2lkKTsKICAgIGNvbnN0IG5leHQgPSB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50T250b1BsYW5lKAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBzdGFydCwgbmV4dFNjcmF0Y2gpLAogICAgICBuZXh0U2NyYXRjaAogICAgKTsKICAgIGNvbnN0IHByZXYgPSB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50T250b1BsYW5lKAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBlbmQsIHByZXZTY3JhdGNoKSwKICAgICAgcHJldlNjcmF0Y2gKICAgICk7CiAgICBjb25zdCBhbmdsZSA9IENhcnRlc2lhbjJfZGVmYXVsdC5hbmdsZUJldHdlZW4obmV4dCwgcHJldik7CiAgICByZXR1cm4gcHJldi54ICogbmV4dC55IC0gcHJldi55ICogbmV4dC54ID49IDAgPyAtYW5nbGUgOiBhbmdsZTsKICB9CiAgZnVuY3Rpb24gYWRkUG9zaXRpb24oY2VudGVyLCBsZWZ0LCBzaGFwZSwgZmluYWxQb3NpdGlvbnMsIGVsbGlwc29pZCwgaGVpZ2h0LCB4U2NhbGFyLCByZXBlYXQpIHsKICAgIGxldCB3ZXN0ID0gd2VzdFNjcmF0Y2g7CiAgICBsZXQgZmluYWxQb3NpdGlvbiA9IGZpbmFsUG9zU2NyYXRjaDsKICAgIHRyYW5zZm9ybSA9IFRyYW5zZm9ybXNfZGVmYXVsdC5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZShjZW50ZXIsIGVsbGlwc29pZCwgdHJhbnNmb3JtKTsKICAgIHdlc3QgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50QXNWZWN0b3IodHJhbnNmb3JtLCBuZWdhdGl2ZVgsIHdlc3QpOwogICAgd2VzdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUod2VzdCwgd2VzdCk7CiAgICBjb25zdCBhbmdsZSA9IGNvbXB1dGVSb3RhdGlvbkFuZ2xlKHdlc3QsIGxlZnQsIGNlbnRlciwgZWxsaXBzb2lkKTsKICAgIHJvdGF0aW9uWiA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tUm90YXRpb25aKGFuZ2xlLCByb3RhdGlvblopOwogICAgaGVpZ2h0Q2FydGVzaWFuLnogPSBoZWlnaHQ7CiAgICB0cmFuc2Zvcm0gPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlUcmFuc2Zvcm1hdGlvbigKICAgICAgdHJhbnNmb3JtLAogICAgICBNYXRyaXg0X2RlZmF1bHQuZnJvbVJvdGF0aW9uVHJhbnNsYXRpb24ocm90YXRpb25aLCBoZWlnaHRDYXJ0ZXNpYW4sIHRyYW5zbGF0aW9uKSwKICAgICAgdHJhbnNmb3JtCiAgICApOwogICAgY29uc3Qgc2NhbGUgPSBzY2FsZU1hdHJpeDsKICAgIHNjYWxlWzBdID0geFNjYWxhcjsKICAgIGZvciAobGV0IGoyID0gMDsgajIgPCByZXBlYXQ7IGoyKyspIHsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHNoYXBlLmxlbmd0aDsgaTIgKz0gMykgewogICAgICAgIGZpbmFsUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHNoYXBlLCBpMiwgZmluYWxQb3NpdGlvbik7CiAgICAgICAgZmluYWxQb3NpdGlvbiA9IE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKAogICAgICAgICAgc2NhbGUsCiAgICAgICAgICBmaW5hbFBvc2l0aW9uLAogICAgICAgICAgZmluYWxQb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgZmluYWxQb3NpdGlvbiA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQoCiAgICAgICAgICB0cmFuc2Zvcm0sCiAgICAgICAgICBmaW5hbFBvc2l0aW9uLAogICAgICAgICAgZmluYWxQb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgZmluYWxQb3NpdGlvbnMucHVzaChmaW5hbFBvc2l0aW9uLngsIGZpbmFsUG9zaXRpb24ueSwgZmluYWxQb3NpdGlvbi56KTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIGZpbmFsUG9zaXRpb25zOwogIH0KICBmdW5jdGlvbiBhZGRQb3NpdGlvbnMoY2VudGVycywgbGVmdCwgc2hhcGUsIGZpbmFsUG9zaXRpb25zLCBlbGxpcHNvaWQsIGhlaWdodHMsIHhTY2FsYXIpIHsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBjZW50ZXJzLmxlbmd0aDsgaTIgKz0gMykgewogICAgICBjb25zdCBjZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGNlbnRlcnMsIGkyLCBjZW50ZXJTY3JhdGNoMik7CiAgICAgIGZpbmFsUG9zaXRpb25zID0gYWRkUG9zaXRpb24oCiAgICAgICAgY2VudGVyLAogICAgICAgIGxlZnQsCiAgICAgICAgc2hhcGUsCiAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIGhlaWdodHNbaTIgLyAzXSwKICAgICAgICB4U2NhbGFyLAogICAgICAgIDEKICAgICAgKTsKICAgIH0KICAgIHJldHVybiBmaW5hbFBvc2l0aW9uczsKICB9CiAgZnVuY3Rpb24gY29udmVydFNoYXBlVG8zRER1cGxpY2F0ZShzaGFwZTJELCBib3VuZGluZ1JlY3RhbmdsZSkgewogICAgY29uc3QgbGVuZ3RoID0gc2hhcGUyRC5sZW5ndGg7CiAgICBjb25zdCBzaGFwZSA9IG5ldyBBcnJheShsZW5ndGggKiA2KTsKICAgIGxldCBpbmRleCA9IDA7CiAgICBjb25zdCB4T2Zmc2V0ID0gYm91bmRpbmdSZWN0YW5nbGUueCArIGJvdW5kaW5nUmVjdGFuZ2xlLndpZHRoIC8gMjsKICAgIGNvbnN0IHlPZmZzZXQgPSBib3VuZGluZ1JlY3RhbmdsZS55ICsgYm91bmRpbmdSZWN0YW5nbGUuaGVpZ2h0IC8gMjsKICAgIGxldCBwb2ludCA9IHNoYXBlMkRbMF07CiAgICBzaGFwZVtpbmRleCsrXSA9IHBvaW50LnggLSB4T2Zmc2V0OwogICAgc2hhcGVbaW5kZXgrK10gPSAwOwogICAgc2hhcGVbaW5kZXgrK10gPSBwb2ludC55IC0geU9mZnNldDsKICAgIGZvciAobGV0IGkyID0gMTsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgcG9pbnQgPSBzaGFwZTJEW2kyXTsKICAgICAgY29uc3QgeDIgPSBwb2ludC54IC0geE9mZnNldDsKICAgICAgY29uc3QgejIgPSBwb2ludC55IC0geU9mZnNldDsKICAgICAgc2hhcGVbaW5kZXgrK10gPSB4MjsKICAgICAgc2hhcGVbaW5kZXgrK10gPSAwOwogICAgICBzaGFwZVtpbmRleCsrXSA9IHoyOwogICAgICBzaGFwZVtpbmRleCsrXSA9IHgyOwogICAgICBzaGFwZVtpbmRleCsrXSA9IDA7CiAgICAgIHNoYXBlW2luZGV4KytdID0gejI7CiAgICB9CiAgICBwb2ludCA9IHNoYXBlMkRbMF07CiAgICBzaGFwZVtpbmRleCsrXSA9IHBvaW50LnggLSB4T2Zmc2V0OwogICAgc2hhcGVbaW5kZXgrK10gPSAwOwogICAgc2hhcGVbaW5kZXhdID0gcG9pbnQueSAtIHlPZmZzZXQ7CiAgICByZXR1cm4gc2hhcGU7CiAgfQogIGZ1bmN0aW9uIGNvbnZlcnRTaGFwZVRvM0Qoc2hhcGUyRCwgYm91bmRpbmdSZWN0YW5nbGUpIHsKICAgIGNvbnN0IGxlbmd0aCA9IHNoYXBlMkQubGVuZ3RoOwogICAgY29uc3Qgc2hhcGUgPSBuZXcgQXJyYXkobGVuZ3RoICogMyk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgY29uc3QgeE9mZnNldCA9IGJvdW5kaW5nUmVjdGFuZ2xlLnggKyBib3VuZGluZ1JlY3RhbmdsZS53aWR0aCAvIDI7CiAgICBjb25zdCB5T2Zmc2V0ID0gYm91bmRpbmdSZWN0YW5nbGUueSArIGJvdW5kaW5nUmVjdGFuZ2xlLmhlaWdodCAvIDI7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgIHNoYXBlW2luZGV4KytdID0gc2hhcGUyRFtpMl0ueCAtIHhPZmZzZXQ7CiAgICAgIHNoYXBlW2luZGV4KytdID0gMDsKICAgICAgc2hhcGVbaW5kZXgrK10gPSBzaGFwZTJEW2kyXS55IC0geU9mZnNldDsKICAgIH0KICAgIHJldHVybiBzaGFwZTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZVJvdW5kQ29ybmVyKHBpdm90LCBzdGFydFBvaW50LCBlbmRQb2ludCwgY29ybmVyVHlwZSwgbGVmdElzT3V0c2lkZSwgZWxsaXBzb2lkLCBmaW5hbFBvc2l0aW9ucywgc2hhcGUsIGhlaWdodCwgZHVwbGljYXRlUG9pbnRzKSB7CiAgICBjb25zdCBhbmdsZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5hbmdsZUJldHdlZW4oCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChzdGFydFBvaW50LCBwaXZvdCwgc2NyYXRjaDEpLAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoZW5kUG9pbnQsIHBpdm90LCBzY3JhdGNoMikKICAgICk7CiAgICBjb25zdCBncmFudWxhcml0eSA9IGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5CRVZFTEVEID8gMCA6IE1hdGguY2VpbChhbmdsZSAvIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoNSkpOwogICAgbGV0IG0yOwogICAgaWYgKGxlZnRJc091dHNpZGUpIHsKICAgICAgbTIgPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24oCiAgICAgICAgUXVhdGVybmlvbl9kZWZhdWx0LmZyb21BeGlzQW5nbGUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKHBpdm90LCBzY3JhdGNoMSksCiAgICAgICAgICBhbmdsZSAvIChncmFudWxhcml0eSArIDEpLAogICAgICAgICAgcXVhdGVyaW9uCiAgICAgICAgKSwKICAgICAgICByb3RNYXRyaXgKICAgICAgKTsKICAgIH0gZWxzZSB7CiAgICAgIG0yID0gTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKAogICAgICAgIFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKHBpdm90LCBhbmdsZSAvIChncmFudWxhcml0eSArIDEpLCBxdWF0ZXJpb24pLAogICAgICAgIHJvdE1hdHJpeAogICAgICApOwogICAgfQogICAgbGV0IGxlZnQ7CiAgICBsZXQgc3VyZmFjZVBvaW50OwogICAgc3RhcnRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShzdGFydFBvaW50LCBzdGFydFBvaW50U2NyYXRjaCk7CiAgICBpZiAoZ3JhbnVsYXJpdHkgPiAwKSB7CiAgICAgIGNvbnN0IHJlcGVhdCA9IGR1cGxpY2F0ZVBvaW50cyA/IDIgOiAxOwogICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgZ3JhbnVsYXJpdHk7IGkyKyspIHsKICAgICAgICBzdGFydFBvaW50ID0gTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IobTIsIHN0YXJ0UG9pbnQsIHN0YXJ0UG9pbnQpOwogICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qoc3RhcnRQb2ludCwgcGl2b3QsIHNjcmF0Y2gxKTsKICAgICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShsZWZ0LCBsZWZ0KTsKICAgICAgICBpZiAoIWxlZnRJc091dHNpZGUpIHsKICAgICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGxlZnQsIGxlZnQpOwogICAgICAgIH0KICAgICAgICBzdXJmYWNlUG9pbnQgPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShzdGFydFBvaW50LCBzY3JhdGNoMik7CiAgICAgICAgZmluYWxQb3NpdGlvbnMgPSBhZGRQb3NpdGlvbigKICAgICAgICAgIHN1cmZhY2VQb2ludCwKICAgICAgICAgIGxlZnQsCiAgICAgICAgICBzaGFwZSwKICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgMSwKICAgICAgICAgIHJlcGVhdAogICAgICAgICk7CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qoc3RhcnRQb2ludCwgcGl2b3QsIHNjcmF0Y2gxKTsKICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUobGVmdCwgbGVmdCk7CiAgICAgIGlmICghbGVmdElzT3V0c2lkZSkgewogICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGxlZnQsIGxlZnQpOwogICAgICB9CiAgICAgIHN1cmZhY2VQb2ludCA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKHN0YXJ0UG9pbnQsIHNjcmF0Y2gyKTsKICAgICAgZmluYWxQb3NpdGlvbnMgPSBhZGRQb3NpdGlvbigKICAgICAgICBzdXJmYWNlUG9pbnQsCiAgICAgICAgbGVmdCwKICAgICAgICBzaGFwZSwKICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIDEsCiAgICAgICAgMQogICAgICApOwogICAgICBlbmRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShlbmRQb2ludCwgc3RhcnRQb2ludFNjcmF0Y2gpOwogICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGVuZFBvaW50LCBwaXZvdCwgc2NyYXRjaDEpOwogICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShsZWZ0LCBsZWZ0KTsKICAgICAgaWYgKCFsZWZ0SXNPdXRzaWRlKSB7CiAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUobGVmdCwgbGVmdCk7CiAgICAgIH0KICAgICAgc3VyZmFjZVBvaW50ID0gZWxsaXBzb2lkLnNjYWxlVG9HZW9kZXRpY1N1cmZhY2UoZW5kUG9pbnQsIHNjcmF0Y2gyKTsKICAgICAgZmluYWxQb3NpdGlvbnMgPSBhZGRQb3NpdGlvbigKICAgICAgICBzdXJmYWNlUG9pbnQsCiAgICAgICAgbGVmdCwKICAgICAgICBzaGFwZSwKICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIDEsCiAgICAgICAgMQogICAgICApOwogICAgfQogICAgcmV0dXJuIGZpbmFsUG9zaXRpb25zOwogIH0KICB2YXIgc2NyYXRjaDJBcnJheSwgc2NyYXRjaENhcnRlc2lhbjE2LCBzY3JhdGNoQ2FydGVzaWFuMjYsIHNjcmF0Y2hDYXJ0ZXNpYW4zNywgc2NyYXRjaENhcnRlc2lhbjQzLCBzY3JhdGNoQ2FydGVzaWFuNTIsIHNjcmF0Y2hDYXJ0ZXNpYW42Miwgc2NyYXRjaENhcnRlc2lhbjcsIHNjcmF0Y2hDYXJ0ZXNpYW44LCBzY3JhdGNoQ2FydGVzaWFuOSwgc2NyYXRjaDEsIHNjcmF0Y2gyLCBQb2x5bGluZVZvbHVtZUdlb21ldHJ5TGlicmFyeSwgY2FydG9ncmFwaGljLCBuZXh0U2NyYXRjaCwgcHJldlNjcmF0Y2gsIG5lZ2F0aXZlWCwgdHJhbnNmb3JtLCB0cmFuc2xhdGlvbiwgcm90YXRpb25aLCBzY2FsZU1hdHJpeCwgd2VzdFNjcmF0Y2gsIGZpbmFsUG9zU2NyYXRjaCwgaGVpZ2h0Q2FydGVzaWFuLCBjZW50ZXJTY3JhdGNoMiwgcXVhdGVyaW9uLCBzdGFydFBvaW50U2NyYXRjaCwgcm90TWF0cml4LCBzY3JhdGNoRm9yd2FyZFByb2plY3Rpb24sIHNjcmF0Y2hCYWNrd2FyZFByb2plY3Rpb24sIFBvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5LmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRlc2lhbjQoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9Db3JuZXJUeXBlKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkVGFuZ2VudFBsYW5lKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfUG9seWxpbmVQaXBlbGluZSgpOwogICAgICBpbml0X1F1YXRlcm5pb24oKTsKICAgICAgaW5pdF9UcmFuc2Zvcm1zKCk7CiAgICAgIGluaXRfb25lVGltZVdhcm5pbmcoKTsKICAgICAgc2NyYXRjaDJBcnJheSA9IFtuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKV07CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4xNiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjI2ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMzcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW40MyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjUyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuNjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW43ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuOCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2gxID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnkgPSB7fTsKICAgICAgY2FydG9ncmFwaGljID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIG5leHRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwcmV2U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgbmVnYXRpdmVYID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgtMSwgMCwgMCk7CiAgICAgIHRyYW5zZm9ybSA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgdHJhbnNsYXRpb24gPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIHJvdGF0aW9uWiA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgc2NhbGVNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuSURFTlRJVFkuY2xvbmUoKTsKICAgICAgd2VzdFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGZpbmFsUG9zU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoKTsKICAgICAgaGVpZ2h0Q2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjZW50ZXJTY3JhdGNoMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcXVhdGVyaW9uID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBzdGFydFBvaW50U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcm90TWF0cml4ID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBQb2x5bGluZVZvbHVtZUdlb21ldHJ5TGlicmFyeS5yZW1vdmVEdXBsaWNhdGVzRnJvbVNoYXBlID0gZnVuY3Rpb24oc2hhcGVQb3NpdGlvbnMpIHsKICAgICAgICBjb25zdCBsZW5ndGggPSBzaGFwZVBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3QgY2xlYW5lZFBvc2l0aW9ucyA9IFtdOwogICAgICAgIGZvciAobGV0IGkwID0gbGVuZ3RoIC0gMSwgaTEgPSAwOyBpMSA8IGxlbmd0aDsgaTAgPSBpMSsrKSB7CiAgICAgICAgICBjb25zdCB2MDIgPSBzaGFwZVBvc2l0aW9uc1tpMF07CiAgICAgICAgICBjb25zdCB2MTIgPSBzaGFwZVBvc2l0aW9uc1tpMV07CiAgICAgICAgICBpZiAoIUNhcnRlc2lhbjJfZGVmYXVsdC5lcXVhbHModjAyLCB2MTIpKSB7CiAgICAgICAgICAgIGNsZWFuZWRQb3NpdGlvbnMucHVzaCh2MTIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gY2xlYW5lZFBvc2l0aW9uczsKICAgICAgfTsKICAgICAgUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnkuYW5nbGVJc0dyZWF0ZXJUaGFuUGkgPSBmdW5jdGlvbihmb3J3YXJkLCBiYWNrd2FyZCwgcG9zaXRpb24sIGVsbGlwc29pZCkgewogICAgICAgIGNvbnN0IHRhbmdlbnRQbGFuZSA9IG5ldyBFbGxpcHNvaWRUYW5nZW50UGxhbmVfZGVmYXVsdChwb3NpdGlvbiwgZWxsaXBzb2lkKTsKICAgICAgICBjb25zdCBuZXh0ID0gdGFuZ2VudFBsYW5lLnByb2plY3RQb2ludE9udG9QbGFuZSgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIGZvcndhcmQsIG5leHRTY3JhdGNoKSwKICAgICAgICAgIG5leHRTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBwcmV2ID0gdGFuZ2VudFBsYW5lLnByb2plY3RQb2ludE9udG9QbGFuZSgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIGJhY2t3YXJkLCBwcmV2U2NyYXRjaCksCiAgICAgICAgICBwcmV2U2NyYXRjaAogICAgICAgICk7CiAgICAgICAgcmV0dXJuIHByZXYueCAqIG5leHQueSAtIHByZXYueSAqIG5leHQueCA+PSAwOwogICAgICB9OwogICAgICBzY3JhdGNoRm9yd2FyZFByb2plY3Rpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCYWNrd2FyZFByb2plY3Rpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFBvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5LmNvbXB1dGVQb3NpdGlvbnMgPSBmdW5jdGlvbihwb3NpdGlvbnMsIHNoYXBlMkQsIGJvdW5kaW5nUmVjdGFuZ2xlLCBnZW9tZXRyeSwgZHVwbGljYXRlUG9pbnRzKSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gZ2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBoZWlnaHRzID0gc2NhbGVUb1N1cmZhY2UocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gZ2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IGNvcm5lclR5cGUgPSBnZW9tZXRyeS5fY29ybmVyVHlwZTsKICAgICAgICBjb25zdCBzaGFwZUZvclNpZGVzID0gZHVwbGljYXRlUG9pbnRzID8gY29udmVydFNoYXBlVG8zRER1cGxpY2F0ZShzaGFwZTJELCBib3VuZGluZ1JlY3RhbmdsZSkgOiBjb252ZXJ0U2hhcGVUbzNEKHNoYXBlMkQsIGJvdW5kaW5nUmVjdGFuZ2xlKTsKICAgICAgICBjb25zdCBzaGFwZUZvckVuZHMgPSBkdXBsaWNhdGVQb2ludHMgPyBjb252ZXJ0U2hhcGVUbzNEKHNoYXBlMkQsIGJvdW5kaW5nUmVjdGFuZ2xlKSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBoZWlnaHRPZmZzZXQgPSBib3VuZGluZ1JlY3RhbmdsZS5oZWlnaHQgLyAyOwogICAgICAgIGNvbnN0IHdpZHRoID0gYm91bmRpbmdSZWN0YW5nbGUud2lkdGggLyAyOwogICAgICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGxldCBmaW5hbFBvc2l0aW9ucyA9IFtdOwogICAgICAgIGxldCBlbmRzID0gZHVwbGljYXRlUG9pbnRzID8gW10gOiB2b2lkIDA7CiAgICAgICAgbGV0IGZvcndhcmQgPSBzY3JhdGNoQ2FydGVzaWFuMTY7CiAgICAgICAgbGV0IGJhY2t3YXJkID0gc2NyYXRjaENhcnRlc2lhbjI2OwogICAgICAgIGxldCBjb3JuZXJEaXJlY3Rpb24gPSBzY3JhdGNoQ2FydGVzaWFuMzc7CiAgICAgICAgbGV0IHN1cmZhY2VOb3JtYWwgPSBzY3JhdGNoQ2FydGVzaWFuNDM7CiAgICAgICAgbGV0IHBpdm90ID0gc2NyYXRjaENhcnRlc2lhbjUyOwogICAgICAgIGxldCBzdGFydCA9IHNjcmF0Y2hDYXJ0ZXNpYW42MjsKICAgICAgICBsZXQgZW5kID0gc2NyYXRjaENhcnRlc2lhbjc7CiAgICAgICAgbGV0IGxlZnQgPSBzY3JhdGNoQ2FydGVzaWFuODsKICAgICAgICBsZXQgcHJldmlvdXNQb3NpdGlvbiA9IHNjcmF0Y2hDYXJ0ZXNpYW45OwogICAgICAgIGxldCBwb3NpdGlvbiA9IHBvc2l0aW9uc1swXTsKICAgICAgICBsZXQgbmV4dFBvc2l0aW9uID0gcG9zaXRpb25zWzFdOwogICAgICAgIHN1cmZhY2VOb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBzdXJmYWNlTm9ybWFsKTsKICAgICAgICBmb3J3YXJkID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KG5leHRQb3NpdGlvbiwgcG9zaXRpb24sIGZvcndhcmQpOwogICAgICAgIGZvcndhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGZvcndhcmQsIGZvcndhcmQpOwogICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Moc3VyZmFjZU5vcm1hbCwgZm9yd2FyZCwgbGVmdCk7CiAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUobGVmdCwgbGVmdCk7CiAgICAgICAgbGV0IGgwID0gaGVpZ2h0c1swXTsKICAgICAgICBsZXQgaDEgPSBoZWlnaHRzWzFdOwogICAgICAgIGlmIChkdXBsaWNhdGVQb2ludHMpIHsKICAgICAgICAgIGVuZHMgPSBhZGRQb3NpdGlvbigKICAgICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICAgIGxlZnQsCiAgICAgICAgICAgIHNoYXBlRm9yRW5kcywKICAgICAgICAgICAgZW5kcywKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBoMCArIGhlaWdodE9mZnNldCwKICAgICAgICAgICAgMSwKICAgICAgICAgICAgMQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcHJldmlvdXNQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgcHJldmlvdXNQb3NpdGlvbik7CiAgICAgICAgcG9zaXRpb24gPSBuZXh0UG9zaXRpb247CiAgICAgICAgYmFja3dhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGZvcndhcmQsIGJhY2t3YXJkKTsKICAgICAgICBsZXQgc3ViZGl2aWRlZEhlaWdodHM7CiAgICAgICAgbGV0IHN1YmRpdmlkZWRQb3NpdGlvbnM7CiAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHJlcGVhdCA9IGR1cGxpY2F0ZVBvaW50cyA/IDIgOiAxOwogICAgICAgICAgbmV4dFBvc2l0aW9uID0gcG9zaXRpb25zW2kyICsgMV07CiAgICAgICAgICBpZiAocG9zaXRpb24uZXF1YWxzKG5leHRQb3NpdGlvbikpIHsKICAgICAgICAgICAgb25lVGltZVdhcm5pbmdfZGVmYXVsdCgKICAgICAgICAgICAgICAiUG9zaXRpb25zIGFyZSB0b28gY2xvc2UgYW5kIGFyZSBjb25zaWRlcmVkIGVxdWl2YWxlbnQgd2l0aCByb3VuZGluZyBlcnJvci4iCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgZm9yd2FyZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChuZXh0UG9zaXRpb24sIHBvc2l0aW9uLCBmb3J3YXJkKTsKICAgICAgICAgIGZvcndhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGZvcndhcmQsIGZvcndhcmQpOwogICAgICAgICAgc3VyZmFjZU5vcm1hbCA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocG9zaXRpb24sIHN1cmZhY2VOb3JtYWwpOwogICAgICAgICAgY29uc3QgZm9yd2FyZFByb2plY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgc3VyZmFjZU5vcm1hbCwKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmRvdChmb3J3YXJkLCBzdXJmYWNlTm9ybWFsKSwKICAgICAgICAgICAgc2NyYXRjaEZvcndhcmRQcm9qZWN0aW9uCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGZvcndhcmQsIGZvcndhcmRQcm9qZWN0aW9uLCBmb3J3YXJkUHJvamVjdGlvbik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGZvcndhcmRQcm9qZWN0aW9uLCBmb3J3YXJkUHJvamVjdGlvbik7CiAgICAgICAgICBjb25zdCBiYWNrd2FyZFByb2plY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgc3VyZmFjZU5vcm1hbCwKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmRvdChiYWNrd2FyZCwgc3VyZmFjZU5vcm1hbCksCiAgICAgICAgICAgIHNjcmF0Y2hCYWNrd2FyZFByb2plY3Rpb24KICAgICAgICAgICk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoYmFja3dhcmQsIGJhY2t3YXJkUHJvamVjdGlvbiwgYmFja3dhcmRQcm9qZWN0aW9uKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoYmFja3dhcmRQcm9qZWN0aW9uLCBiYWNrd2FyZFByb2plY3Rpb24pOwogICAgICAgICAgY29uc3QgZG9Db3JuZXIgPSAhTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICAgIE1hdGguYWJzKENhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZm9yd2FyZFByb2plY3Rpb24sIGJhY2t3YXJkUHJvamVjdGlvbikpLAogICAgICAgICAgICAxLAogICAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjcKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZG9Db3JuZXIpIHsKICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChmb3J3YXJkLCBiYWNrd2FyZCwgY29ybmVyRGlyZWN0aW9uKTsKICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShjb3JuZXJEaXJlY3Rpb24sIGNvcm5lckRpcmVjdGlvbik7CiAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcygKICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24sCiAgICAgICAgICAgICAgc3VyZmFjZU5vcm1hbCwKICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24KICAgICAgICAgICAgKTsKICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKAogICAgICAgICAgICAgIHN1cmZhY2VOb3JtYWwsCiAgICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uLAogICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbgogICAgICAgICAgICApOwogICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGNvcm5lckRpcmVjdGlvbiwgY29ybmVyRGlyZWN0aW9uKTsKICAgICAgICAgICAgY29uc3Qgc2NhbGFyID0gMSAvIE1hdGgubWF4KAogICAgICAgICAgICAgIDAuMjUsCiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhjb3JuZXJEaXJlY3Rpb24sIGJhY2t3YXJkLCBzY3JhdGNoMSkKICAgICAgICAgICAgICApCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGNvbnN0IGxlZnRJc091dHNpZGUgPSBQb2x5bGluZVZvbHVtZUdlb21ldHJ5TGlicmFyeS5hbmdsZUlzR3JlYXRlclRoYW5QaSgKICAgICAgICAgICAgICBmb3J3YXJkLAogICAgICAgICAgICAgIGJhY2t3YXJkLAogICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAobGVmdElzT3V0c2lkZSkgewogICAgICAgICAgICAgIHBpdm90ID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiwKICAgICAgICAgICAgICAgICAgc2NhbGFyICogd2lkdGgsCiAgICAgICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbgogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIHBpdm90CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBzdGFydCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICBwaXZvdCwKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGxlZnQsIHdpZHRoLCBzdGFydCksCiAgICAgICAgICAgICAgICBzdGFydAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgc2NyYXRjaDJBcnJheVswXSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwcmV2aW91c1Bvc2l0aW9uLCBzY3JhdGNoMkFycmF5WzBdKTsKICAgICAgICAgICAgICBzY3JhdGNoMkFycmF5WzFdID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHN0YXJ0LCBzY3JhdGNoMkFycmF5WzFdKTsKICAgICAgICAgICAgICBzdWJkaXZpZGVkSGVpZ2h0cyA9IHN1YmRpdmlkZUhlaWdodHMyKAogICAgICAgICAgICAgICAgc2NyYXRjaDJBcnJheSwKICAgICAgICAgICAgICAgIGgwICsgaGVpZ2h0T2Zmc2V0LAogICAgICAgICAgICAgICAgaDEgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICAgICAgICBncmFudWxhcml0eQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucyA9IFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdC5nZW5lcmF0ZUFyYyh7CiAgICAgICAgICAgICAgICBwb3NpdGlvbnM6IHNjcmF0Y2gyQXJyYXksCiAgICAgICAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zID0gYWRkUG9zaXRpb25zKAogICAgICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucywKICAgICAgICAgICAgICAgIGxlZnQsCiAgICAgICAgICAgICAgICBzaGFwZUZvclNpZGVzLAogICAgICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICBzdWJkaXZpZGVkSGVpZ2h0cywKICAgICAgICAgICAgICAgIDEKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Moc3VyZmFjZU5vcm1hbCwgZm9yd2FyZCwgbGVmdCk7CiAgICAgICAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUobGVmdCwgbGVmdCk7CiAgICAgICAgICAgICAgZW5kID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICAgICAgICAgIHBpdm90LAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobGVmdCwgd2lkdGgsIGVuZCksCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmIChjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRCB8fCBjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuQkVWRUxFRCkgewogICAgICAgICAgICAgICAgY29tcHV0ZVJvdW5kQ29ybmVyKAogICAgICAgICAgICAgICAgICBwaXZvdCwKICAgICAgICAgICAgICAgICAgc3RhcnQsCiAgICAgICAgICAgICAgICAgIGVuZCwKICAgICAgICAgICAgICAgICAgY29ybmVyVHlwZSwKICAgICAgICAgICAgICAgICAgbGVmdElzT3V0c2lkZSwKICAgICAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgICAgICAgc2hhcGVGb3JTaWRlcywKICAgICAgICAgICAgICAgICAgaDEgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICAgICAgICAgIGR1cGxpY2F0ZVBvaW50cwogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShjb3JuZXJEaXJlY3Rpb24sIGNvcm5lckRpcmVjdGlvbik7CiAgICAgICAgICAgICAgICBmaW5hbFBvc2l0aW9ucyA9IGFkZFBvc2l0aW9uKAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uLAogICAgICAgICAgICAgICAgICBzaGFwZUZvclNpZGVzLAogICAgICAgICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgICAgICBoMSArIGhlaWdodE9mZnNldCwKICAgICAgICAgICAgICAgICAgc2NhbGFyLAogICAgICAgICAgICAgICAgICByZXBlYXQKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHByZXZpb3VzUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoZW5kLCBwcmV2aW91c1Bvc2l0aW9uKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBwaXZvdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24sCiAgICAgICAgICAgICAgICAgIHNjYWxhciAqIHdpZHRoLAogICAgICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24KICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICBwaXZvdAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgc3RhcnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgICAgICAgcGl2b3QsCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihsZWZ0LCAtd2lkdGgsIHN0YXJ0KSwKICAgICAgICAgICAgICAgIHN0YXJ0CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBzY3JhdGNoMkFycmF5WzBdID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHByZXZpb3VzUG9zaXRpb24sIHNjcmF0Y2gyQXJyYXlbMF0pOwogICAgICAgICAgICAgIHNjcmF0Y2gyQXJyYXlbMV0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoc3RhcnQsIHNjcmF0Y2gyQXJyYXlbMV0pOwogICAgICAgICAgICAgIHN1YmRpdmlkZWRIZWlnaHRzID0gc3ViZGl2aWRlSGVpZ2h0czIoCiAgICAgICAgICAgICAgICBzY3JhdGNoMkFycmF5LAogICAgICAgICAgICAgICAgaDAgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICAgICAgICBoMSArIGhlaWdodE9mZnNldCwKICAgICAgICAgICAgICAgIGdyYW51bGFyaXR5CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjKHsKICAgICAgICAgICAgICAgIHBvc2l0aW9uczogc2NyYXRjaDJBcnJheSwKICAgICAgICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgICAgICAgZWxsaXBzb2lkCiAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMgPSBhZGRQb3NpdGlvbnMoCiAgICAgICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLAogICAgICAgICAgICAgICAgbGVmdCwKICAgICAgICAgICAgICAgIHNoYXBlRm9yU2lkZXMsCiAgICAgICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRIZWlnaHRzLAogICAgICAgICAgICAgICAgMQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhzdXJmYWNlTm9ybWFsLCBmb3J3YXJkLCBsZWZ0KTsKICAgICAgICAgICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShsZWZ0LCBsZWZ0KTsKICAgICAgICAgICAgICBlbmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgICAgICAgcGl2b3QsCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihsZWZ0LCAtd2lkdGgsIGVuZCksCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmIChjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRCB8fCBjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuQkVWRUxFRCkgewogICAgICAgICAgICAgICAgY29tcHV0ZVJvdW5kQ29ybmVyKAogICAgICAgICAgICAgICAgICBwaXZvdCwKICAgICAgICAgICAgICAgICAgc3RhcnQsCiAgICAgICAgICAgICAgICAgIGVuZCwKICAgICAgICAgICAgICAgICAgY29ybmVyVHlwZSwKICAgICAgICAgICAgICAgICAgbGVmdElzT3V0c2lkZSwKICAgICAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgICAgICAgc2hhcGVGb3JTaWRlcywKICAgICAgICAgICAgICAgICAgaDEgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICAgICAgICAgIGR1cGxpY2F0ZVBvaW50cwogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMgPSBhZGRQb3NpdGlvbigKICAgICAgICAgICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiwKICAgICAgICAgICAgICAgICAgc2hhcGVGb3JTaWRlcywKICAgICAgICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAgICAgaDEgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICAgICAgICAgIHNjYWxhciwKICAgICAgICAgICAgICAgICAgcmVwZWF0CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBwcmV2aW91c1Bvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVuZCwgcHJldmlvdXNQb3NpdGlvbik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYmFja3dhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGZvcndhcmQsIGJhY2t3YXJkKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zID0gYWRkUG9zaXRpb24oCiAgICAgICAgICAgICAgcHJldmlvdXNQb3NpdGlvbiwKICAgICAgICAgICAgICBsZWZ0LAogICAgICAgICAgICAgIHNoYXBlRm9yU2lkZXMsCiAgICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgIGgwICsgaGVpZ2h0T2Zmc2V0LAogICAgICAgICAgICAgIDEsCiAgICAgICAgICAgICAgMQogICAgICAgICAgICApOwogICAgICAgICAgICBwcmV2aW91c1Bvc2l0aW9uID0gcG9zaXRpb247CiAgICAgICAgICB9CiAgICAgICAgICBoMCA9IGgxOwogICAgICAgICAgaDEgPSBoZWlnaHRzW2kyICsgMV07CiAgICAgICAgICBwb3NpdGlvbiA9IG5leHRQb3NpdGlvbjsKICAgICAgICB9CiAgICAgICAgc2NyYXRjaDJBcnJheVswXSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwcmV2aW91c1Bvc2l0aW9uLCBzY3JhdGNoMkFycmF5WzBdKTsKICAgICAgICBzY3JhdGNoMkFycmF5WzFdID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHBvc2l0aW9uLCBzY3JhdGNoMkFycmF5WzFdKTsKICAgICAgICBzdWJkaXZpZGVkSGVpZ2h0cyA9IHN1YmRpdmlkZUhlaWdodHMyKAogICAgICAgICAgc2NyYXRjaDJBcnJheSwKICAgICAgICAgIGgwICsgaGVpZ2h0T2Zmc2V0LAogICAgICAgICAgaDEgKyBoZWlnaHRPZmZzZXQsCiAgICAgICAgICBncmFudWxhcml0eQogICAgICAgICk7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucyA9IFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdC5nZW5lcmF0ZUFyYyh7CiAgICAgICAgICBwb3NpdGlvbnM6IHNjcmF0Y2gyQXJyYXksCiAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgIGVsbGlwc29pZAogICAgICAgIH0pOwogICAgICAgIGZpbmFsUG9zaXRpb25zID0gYWRkUG9zaXRpb25zKAogICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucywKICAgICAgICAgIGxlZnQsCiAgICAgICAgICBzaGFwZUZvclNpZGVzLAogICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzdWJkaXZpZGVkSGVpZ2h0cywKICAgICAgICAgIDEKICAgICAgICApOwogICAgICAgIGlmIChkdXBsaWNhdGVQb2ludHMpIHsKICAgICAgICAgIGVuZHMgPSBhZGRQb3NpdGlvbigKICAgICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICAgIGxlZnQsCiAgICAgICAgICAgIHNoYXBlRm9yRW5kcywKICAgICAgICAgICAgZW5kcywKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBoMSArIGhlaWdodE9mZnNldCwKICAgICAgICAgICAgMSwKICAgICAgICAgICAgMQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgbGVuZ3RoID0gZmluYWxQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGNvbnN0IHBvc0xlbmd0aCA9IGR1cGxpY2F0ZVBvaW50cyA/IGxlbmd0aCArIGVuZHMubGVuZ3RoIDogbGVuZ3RoOwogICAgICAgIGNvbnN0IGNvbWJpbmVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShwb3NMZW5ndGgpOwogICAgICAgIGNvbWJpbmVkUG9zaXRpb25zLnNldChmaW5hbFBvc2l0aW9ucyk7CiAgICAgICAgaWYgKGR1cGxpY2F0ZVBvaW50cykgewogICAgICAgICAgY29tYmluZWRQb3NpdGlvbnMuc2V0KGVuZHMsIGxlbmd0aCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBjb21iaW5lZFBvc2l0aW9uczsKICAgICAgfTsKICAgICAgUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdCA9IFBvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnkuanMKICBmdW5jdGlvbiBjb21wdXRlUm91bmRDb3JuZXIyKGNvcm5lclBvaW50LCBzdGFydFBvaW50LCBlbmRQb2ludCwgY29ybmVyVHlwZSwgbGVmdElzT3V0c2lkZSkgewogICAgY29uc3QgYW5nbGUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYW5nbGVCZXR3ZWVuKAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qoc3RhcnRQb2ludCwgY29ybmVyUG9pbnQsIHNjcmF0Y2gxMiksCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChlbmRQb2ludCwgY29ybmVyUG9pbnQsIHNjcmF0Y2gyMikKICAgICk7CiAgICBjb25zdCBncmFudWxhcml0eSA9IGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5CRVZFTEVEID8gMSA6IE1hdGguY2VpbChhbmdsZSAvIE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoNSkpICsgMTsKICAgIGNvbnN0IHNpemUgPSBncmFudWxhcml0eSAqIDM7CiAgICBjb25zdCBhcnJheSA9IG5ldyBBcnJheShzaXplKTsKICAgIGFycmF5W3NpemUgLSAzXSA9IGVuZFBvaW50Lng7CiAgICBhcnJheVtzaXplIC0gMl0gPSBlbmRQb2ludC55OwogICAgYXJyYXlbc2l6ZSAtIDFdID0gZW5kUG9pbnQuejsKICAgIGxldCBtMjsKICAgIGlmIChsZWZ0SXNPdXRzaWRlKSB7CiAgICAgIG0yID0gTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKAogICAgICAgIFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShjb3JuZXJQb2ludCwgc2NyYXRjaDEyKSwKICAgICAgICAgIGFuZ2xlIC8gZ3JhbnVsYXJpdHksCiAgICAgICAgICBxdWF0ZXJpb24yCiAgICAgICAgKSwKICAgICAgICByb3RNYXRyaXgyCiAgICAgICk7CiAgICB9IGVsc2UgewogICAgICBtMiA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tUXVhdGVybmlvbigKICAgICAgICBRdWF0ZXJuaW9uX2RlZmF1bHQuZnJvbUF4aXNBbmdsZShjb3JuZXJQb2ludCwgYW5nbGUgLyBncmFudWxhcml0eSwgcXVhdGVyaW9uMiksCiAgICAgICAgcm90TWF0cml4MgogICAgICApOwogICAgfQogICAgbGV0IGluZGV4ID0gMDsKICAgIHN0YXJ0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoc3RhcnRQb2ludCwgc2NyYXRjaDEyKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBncmFudWxhcml0eTsgaTIrKykgewogICAgICBzdGFydFBvaW50ID0gTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IobTIsIHN0YXJ0UG9pbnQsIHN0YXJ0UG9pbnQpOwogICAgICBhcnJheVtpbmRleCsrXSA9IHN0YXJ0UG9pbnQueDsKICAgICAgYXJyYXlbaW5kZXgrK10gPSBzdGFydFBvaW50Lnk7CiAgICAgIGFycmF5W2luZGV4KytdID0gc3RhcnRQb2ludC56OwogICAgfQogICAgcmV0dXJuIGFycmF5OwogIH0KICBmdW5jdGlvbiBhZGRFbmRDYXBzKGNhbGN1bGF0ZWRQb3NpdGlvbnMpIHsKICAgIGxldCBjb3JuZXJQb2ludCA9IGNhcnRlc2lhbjE7CiAgICBsZXQgc3RhcnRQb2ludCA9IGNhcnRlc2lhbjI7CiAgICBsZXQgZW5kUG9pbnQgPSBjYXJ0ZXNpYW4zOwogICAgbGV0IGxlZnRFZGdlID0gY2FsY3VsYXRlZFBvc2l0aW9uc1sxXTsKICAgIHN0YXJ0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICBjYWxjdWxhdGVkUG9zaXRpb25zWzFdLAogICAgICBsZWZ0RWRnZS5sZW5ndGggLSAzLAogICAgICBzdGFydFBvaW50CiAgICApOwogICAgZW5kUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGNhbGN1bGF0ZWRQb3NpdGlvbnNbMF0sIDAsIGVuZFBvaW50KTsKICAgIGNvcm5lclBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1pZHBvaW50KHN0YXJ0UG9pbnQsIGVuZFBvaW50LCBjb3JuZXJQb2ludCk7CiAgICBjb25zdCBmaXJzdEVuZENhcCA9IGNvbXB1dGVSb3VuZENvcm5lcjIoCiAgICAgIGNvcm5lclBvaW50LAogICAgICBzdGFydFBvaW50LAogICAgICBlbmRQb2ludCwKICAgICAgQ29ybmVyVHlwZV9kZWZhdWx0LlJPVU5ERUQsCiAgICAgIGZhbHNlCiAgICApOwogICAgY29uc3QgbGVuZ3RoID0gY2FsY3VsYXRlZFBvc2l0aW9ucy5sZW5ndGggLSAxOwogICAgY29uc3QgcmlnaHRFZGdlID0gY2FsY3VsYXRlZFBvc2l0aW9uc1tsZW5ndGggLSAxXTsKICAgIGxlZnRFZGdlID0gY2FsY3VsYXRlZFBvc2l0aW9uc1tsZW5ndGhdOwogICAgc3RhcnRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgIHJpZ2h0RWRnZSwKICAgICAgcmlnaHRFZGdlLmxlbmd0aCAtIDMsCiAgICAgIHN0YXJ0UG9pbnQKICAgICk7CiAgICBlbmRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobGVmdEVkZ2UsIDAsIGVuZFBvaW50KTsKICAgIGNvcm5lclBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1pZHBvaW50KHN0YXJ0UG9pbnQsIGVuZFBvaW50LCBjb3JuZXJQb2ludCk7CiAgICBjb25zdCBsYXN0RW5kQ2FwID0gY29tcHV0ZVJvdW5kQ29ybmVyMigKICAgICAgY29ybmVyUG9pbnQsCiAgICAgIHN0YXJ0UG9pbnQsCiAgICAgIGVuZFBvaW50LAogICAgICBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRCwKICAgICAgZmFsc2UKICAgICk7CiAgICByZXR1cm4gW2ZpcnN0RW5kQ2FwLCBsYXN0RW5kQ2FwXTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZU1pdGVyZWRDb3JuZXIocG9zaXRpb24sIGxlZnRDb3JuZXJEaXJlY3Rpb24sIGxhc3RQb2ludCwgbGVmdElzT3V0c2lkZSkgewogICAgbGV0IGNvcm5lclBvaW50ID0gc2NyYXRjaDEyOwogICAgaWYgKGxlZnRJc091dHNpZGUpIHsKICAgICAgY29ybmVyUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBsZWZ0Q29ybmVyRGlyZWN0aW9uLCBjb3JuZXJQb2ludCk7CiAgICB9IGVsc2UgewogICAgICBsZWZ0Q29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZSgKICAgICAgICBsZWZ0Q29ybmVyRGlyZWN0aW9uLAogICAgICAgIGxlZnRDb3JuZXJEaXJlY3Rpb24KICAgICAgKTsKICAgICAgY29ybmVyUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBsZWZ0Q29ybmVyRGlyZWN0aW9uLCBjb3JuZXJQb2ludCk7CiAgICB9CiAgICByZXR1cm4gWwogICAgICBjb3JuZXJQb2ludC54LAogICAgICBjb3JuZXJQb2ludC55LAogICAgICBjb3JuZXJQb2ludC56LAogICAgICBsYXN0UG9pbnQueCwKICAgICAgbGFzdFBvaW50LnksCiAgICAgIGxhc3RQb2ludC56CiAgICBdOwogIH0KICBmdW5jdGlvbiBhZGRTaGlmdGVkUG9zaXRpb25zKHBvc2l0aW9ucywgbGVmdCwgc2NhbGFyLCBjYWxjdWxhdGVkUG9zaXRpb25zKSB7CiAgICBjb25zdCByaWdodFBvc2l0aW9ucyA9IG5ldyBBcnJheShwb3NpdGlvbnMubGVuZ3RoKTsKICAgIGNvbnN0IGxlZnRQb3NpdGlvbnMgPSBuZXcgQXJyYXkocG9zaXRpb25zLmxlbmd0aCk7CiAgICBjb25zdCBzY2FsZWRMZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobGVmdCwgc2NhbGFyLCBzY3JhdGNoMTIpOwogICAgY29uc3Qgc2NhbGVkUmlnaHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKHNjYWxlZExlZnQsIHNjcmF0Y2gyMik7CiAgICBsZXQgcmlnaHRJbmRleCA9IDA7CiAgICBsZXQgbGVmdEluZGV4ID0gcG9zaXRpb25zLmxlbmd0aCAtIDE7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zLmxlbmd0aDsgaTIgKz0gMykgewogICAgICBjb25zdCBwb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIsIHNjcmF0Y2gzKTsKICAgICAgY29uc3QgcmlnaHRQb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvcywgc2NhbGVkUmlnaHQsIHNjcmF0Y2g0KTsKICAgICAgcmlnaHRQb3NpdGlvbnNbcmlnaHRJbmRleCsrXSA9IHJpZ2h0UG9zLng7CiAgICAgIHJpZ2h0UG9zaXRpb25zW3JpZ2h0SW5kZXgrK10gPSByaWdodFBvcy55OwogICAgICByaWdodFBvc2l0aW9uc1tyaWdodEluZGV4KytdID0gcmlnaHRQb3MuejsKICAgICAgY29uc3QgbGVmdFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zLCBzY2FsZWRMZWZ0LCBzY3JhdGNoNCk7CiAgICAgIGxlZnRQb3NpdGlvbnNbbGVmdEluZGV4LS1dID0gbGVmdFBvcy56OwogICAgICBsZWZ0UG9zaXRpb25zW2xlZnRJbmRleC0tXSA9IGxlZnRQb3MueTsKICAgICAgbGVmdFBvc2l0aW9uc1tsZWZ0SW5kZXgtLV0gPSBsZWZ0UG9zLng7CiAgICB9CiAgICBjYWxjdWxhdGVkUG9zaXRpb25zLnB1c2gocmlnaHRQb3NpdGlvbnMsIGxlZnRQb3NpdGlvbnMpOwogICAgcmV0dXJuIGNhbGN1bGF0ZWRQb3NpdGlvbnM7CiAgfQogIHZhciBDb3JyaWRvckdlb21ldHJ5TGlicmFyeSwgc2NyYXRjaDEyLCBzY3JhdGNoMjIsIHNjcmF0Y2gzLCBzY3JhdGNoNCwgc2NhbGVBcnJheTIsIGNhcnRlc2lhbjEsIGNhcnRlc2lhbjIsIGNhcnRlc2lhbjMsIGNhcnRlc2lhbjQsIGNhcnRlc2lhbjUsIGNhcnRlc2lhbjYsIGNhcnRlc2lhbjcsIGNhcnRlc2lhbjgsIGNhcnRlc2lhbjksIGNhcnRlc2lhbjEwLCBxdWF0ZXJpb24yLCByb3RNYXRyaXgyLCBzY3JhdGNoRm9yd2FyZFByb2plY3Rpb24yLCBzY3JhdGNoQmFja3dhcmRQcm9qZWN0aW9uMiwgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdDsKICB2YXIgaW5pdF9Db3JyaWRvckdlb21ldHJ5TGlicmFyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnkuanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db3JuZXJUeXBlKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfUG9seWxpbmVQaXBlbGluZSgpOwogICAgICBpbml0X1BvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeSA9IHt9OwogICAgICBzY3JhdGNoMTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2gyMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaDMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2g0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY2FsZUFycmF5MiA9IFtuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKV07CiAgICAgIGNhcnRlc2lhbjEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjYgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjEwID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBxdWF0ZXJpb24yID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICByb3RNYXRyaXgyID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeS5hZGRBdHRyaWJ1dGUgPSBmdW5jdGlvbihhdHRyaWJ1dGUsIHZhbHVlLCBmcm9udCwgYmFjaykgewogICAgICAgIGNvbnN0IHgyID0gdmFsdWUueDsKICAgICAgICBjb25zdCB5MiA9IHZhbHVlLnk7CiAgICAgICAgY29uc3QgejIgPSB2YWx1ZS56OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZnJvbnQpKSB7CiAgICAgICAgICBhdHRyaWJ1dGVbZnJvbnRdID0geDI7CiAgICAgICAgICBhdHRyaWJ1dGVbZnJvbnQgKyAxXSA9IHkyOwogICAgICAgICAgYXR0cmlidXRlW2Zyb250ICsgMl0gPSB6MjsKICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChiYWNrKSkgewogICAgICAgICAgYXR0cmlidXRlW2JhY2tdID0gejI7CiAgICAgICAgICBhdHRyaWJ1dGVbYmFjayAtIDFdID0geTI7CiAgICAgICAgICBhdHRyaWJ1dGVbYmFjayAtIDJdID0geDI7CiAgICAgICAgfQogICAgICB9OwogICAgICBzY3JhdGNoRm9yd2FyZFByb2plY3Rpb24yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQmFja3dhcmRQcm9qZWN0aW9uMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnkuY29tcHV0ZVBvc2l0aW9ucyA9IGZ1bmN0aW9uKHBhcmFtcykgewogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gcGFyYW1zLmdyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHBhcmFtcy5wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gcGFyYW1zLmVsbGlwc29pZDsKICAgICAgICBjb25zdCB3aWR0aCA9IHBhcmFtcy53aWR0aCAvIDI7CiAgICAgICAgY29uc3QgY29ybmVyVHlwZSA9IHBhcmFtcy5jb3JuZXJUeXBlOwogICAgICAgIGNvbnN0IHNhdmVBdHRyaWJ1dGVzID0gcGFyYW1zLnNhdmVBdHRyaWJ1dGVzOwogICAgICAgIGxldCBub3JtYWwyID0gY2FydGVzaWFuMTsKICAgICAgICBsZXQgZm9yd2FyZCA9IGNhcnRlc2lhbjI7CiAgICAgICAgbGV0IGJhY2t3YXJkID0gY2FydGVzaWFuMzsKICAgICAgICBsZXQgbGVmdCA9IGNhcnRlc2lhbjQ7CiAgICAgICAgbGV0IGNvcm5lckRpcmVjdGlvbiA9IGNhcnRlc2lhbjU7CiAgICAgICAgbGV0IHN0YXJ0UG9pbnQgPSBjYXJ0ZXNpYW42OwogICAgICAgIGxldCBwcmV2aW91c1BvcyA9IGNhcnRlc2lhbjc7CiAgICAgICAgbGV0IHJpZ2h0UG9zID0gY2FydGVzaWFuODsKICAgICAgICBsZXQgbGVmdFBvcyA9IGNhcnRlc2lhbjk7CiAgICAgICAgbGV0IGNlbnRlciA9IGNhcnRlc2lhbjEwOwogICAgICAgIGxldCBjYWxjdWxhdGVkUG9zaXRpb25zID0gW107CiAgICAgICAgY29uc3QgY2FsY3VsYXRlZExlZnRzID0gc2F2ZUF0dHJpYnV0ZXMgPyBbXSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBjYWxjdWxhdGVkTm9ybWFscyA9IHNhdmVBdHRyaWJ1dGVzID8gW10gOiB2b2lkIDA7CiAgICAgICAgbGV0IHBvc2l0aW9uID0gcG9zaXRpb25zWzBdOwogICAgICAgIGxldCBuZXh0UG9zaXRpb24gPSBwb3NpdGlvbnNbMV07CiAgICAgICAgZm9yd2FyZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobmV4dFBvc2l0aW9uLCBwb3NpdGlvbiwgZm9yd2FyZCksCiAgICAgICAgICBmb3J3YXJkCiAgICAgICAgKTsKICAgICAgICBub3JtYWwyID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChwb3NpdGlvbiwgbm9ybWFsMik7CiAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIGZvcndhcmQsIGxlZnQpLCBsZWZ0KTsKICAgICAgICBpZiAoc2F2ZUF0dHJpYnV0ZXMpIHsKICAgICAgICAgIGNhbGN1bGF0ZWRMZWZ0cy5wdXNoKGxlZnQueCwgbGVmdC55LCBsZWZ0LnopOwogICAgICAgICAgY2FsY3VsYXRlZE5vcm1hbHMucHVzaChub3JtYWwyLngsIG5vcm1hbDIueSwgbm9ybWFsMi56KTsKICAgICAgICB9CiAgICAgICAgcHJldmlvdXNQb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb24sIHByZXZpb3VzUG9zKTsKICAgICAgICBwb3NpdGlvbiA9IG5leHRQb3NpdGlvbjsKICAgICAgICBiYWNrd2FyZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoZm9yd2FyZCwgYmFja3dhcmQpOwogICAgICAgIGxldCBzdWJkaXZpZGVkUG9zaXRpb25zOwogICAgICAgIGNvbnN0IGNvcm5lcnMgPSBbXTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMTsgaTIgPCBsZW5ndGggLSAxOyBpMisrKSB7CiAgICAgICAgICBub3JtYWwyID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChwb3NpdGlvbiwgbm9ybWFsMik7CiAgICAgICAgICBuZXh0UG9zaXRpb24gPSBwb3NpdGlvbnNbaTIgKyAxXTsKICAgICAgICAgIGZvcndhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobmV4dFBvc2l0aW9uLCBwb3NpdGlvbiwgZm9yd2FyZCksCiAgICAgICAgICAgIGZvcndhcmQKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBmb3J3YXJkUHJvamVjdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgICBub3JtYWwyLAogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGZvcndhcmQsIG5vcm1hbDIpLAogICAgICAgICAgICBzY3JhdGNoRm9yd2FyZFByb2plY3Rpb24yCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGZvcndhcmQsIGZvcndhcmRQcm9qZWN0aW9uLCBmb3J3YXJkUHJvamVjdGlvbik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGZvcndhcmRQcm9qZWN0aW9uLCBmb3J3YXJkUHJvamVjdGlvbik7CiAgICAgICAgICBjb25zdCBiYWNrd2FyZFByb2plY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgbm9ybWFsMiwKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmRvdChiYWNrd2FyZCwgbm9ybWFsMiksCiAgICAgICAgICAgIHNjcmF0Y2hCYWNrd2FyZFByb2plY3Rpb24yCiAgICAgICAgICApOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGJhY2t3YXJkLCBiYWNrd2FyZFByb2plY3Rpb24sIGJhY2t3YXJkUHJvamVjdGlvbik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGJhY2t3YXJkUHJvamVjdGlvbiwgYmFja3dhcmRQcm9qZWN0aW9uKTsKICAgICAgICAgIGNvbnN0IGRvQ29ybmVyID0gIU1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgICBNYXRoLmFicyhDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGZvcndhcmRQcm9qZWN0aW9uLCBiYWNrd2FyZFByb2plY3Rpb24pKSwKICAgICAgICAgICAgMSwKICAgICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT043CiAgICAgICAgICApOwogICAgICAgICAgaWYgKGRvQ29ybmVyKSB7CiAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChmb3J3YXJkLCBiYWNrd2FyZCwgY29ybmVyRGlyZWN0aW9uKSwKICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24KICAgICAgICAgICAgKTsKICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKAogICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiwKICAgICAgICAgICAgICBub3JtYWwyLAogICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbgogICAgICAgICAgICApOwogICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoCiAgICAgICAgICAgICAgbm9ybWFsMiwKICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24sCiAgICAgICAgICAgICAgY29ybmVyRGlyZWN0aW9uCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoY29ybmVyRGlyZWN0aW9uLCBjb3JuZXJEaXJlY3Rpb24pOwogICAgICAgICAgICBjb25zdCBzY2FsYXIgPSB3aWR0aCAvIE1hdGgubWF4KAogICAgICAgICAgICAgIDAuMjUsCiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZSgKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhjb3JuZXJEaXJlY3Rpb24sIGJhY2t3YXJkLCBzY3JhdGNoMTIpCiAgICAgICAgICAgICAgKQogICAgICAgICAgICApOwogICAgICAgICAgICBjb25zdCBsZWZ0SXNPdXRzaWRlID0gUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hbmdsZUlzR3JlYXRlclRoYW5QaSgKICAgICAgICAgICAgICBmb3J3YXJkLAogICAgICAgICAgICAgIGJhY2t3YXJkLAogICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICAgICApOwogICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24sCiAgICAgICAgICAgICAgc2NhbGFyLAogICAgICAgICAgICAgIGNvcm5lckRpcmVjdGlvbgogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAobGVmdElzT3V0c2lkZSkgewogICAgICAgICAgICAgIHJpZ2h0UG9zID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwb3NpdGlvbiwgY29ybmVyRGlyZWN0aW9uLCByaWdodFBvcyk7CiAgICAgICAgICAgICAgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICAgICAgICAgIHJpZ2h0UG9zLAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobGVmdCwgd2lkdGgsIGNlbnRlciksCiAgICAgICAgICAgICAgICBjZW50ZXIKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGxlZnRQb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgICAgICAgcmlnaHRQb3MsCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihsZWZ0LCB3aWR0aCAqIDIsIGxlZnRQb3MpLAogICAgICAgICAgICAgICAgbGVmdFBvcwogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgc2NhbGVBcnJheTJbMF0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocHJldmlvdXNQb3MsIHNjYWxlQXJyYXkyWzBdKTsKICAgICAgICAgICAgICBzY2FsZUFycmF5MlsxXSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShjZW50ZXIsIHNjYWxlQXJyYXkyWzFdKTsKICAgICAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjKHsKICAgICAgICAgICAgICAgIHBvc2l0aW9uczogc2NhbGVBcnJheTIsCiAgICAgICAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIGNhbGN1bGF0ZWRQb3NpdGlvbnMgPSBhZGRTaGlmdGVkUG9zaXRpb25zKAogICAgICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucywKICAgICAgICAgICAgICAgIGxlZnQsCiAgICAgICAgICAgICAgICB3aWR0aCwKICAgICAgICAgICAgICAgIGNhbGN1bGF0ZWRQb3NpdGlvbnMKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmIChzYXZlQXR0cmlidXRlcykgewogICAgICAgICAgICAgICAgY2FsY3VsYXRlZExlZnRzLnB1c2gobGVmdC54LCBsZWZ0LnksIGxlZnQueik7CiAgICAgICAgICAgICAgICBjYWxjdWxhdGVkTm9ybWFscy5wdXNoKG5vcm1hbDIueCwgbm9ybWFsMi55LCBub3JtYWwyLnopOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBzdGFydFBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGxlZnRQb3MsIHN0YXJ0UG9pbnQpOwogICAgICAgICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIGZvcndhcmQsIGxlZnQpLAogICAgICAgICAgICAgICAgbGVmdAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgbGVmdFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICByaWdodFBvcywKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGxlZnQsIHdpZHRoICogMiwgbGVmdFBvcyksCiAgICAgICAgICAgICAgICBsZWZ0UG9zCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBwcmV2aW91c1BvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICByaWdodFBvcywKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGxlZnQsIHdpZHRoLCBwcmV2aW91c1BvcyksCiAgICAgICAgICAgICAgICBwcmV2aW91c1BvcwogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgaWYgKGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5ST1VOREVEIHx8IGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5CRVZFTEVEKSB7CiAgICAgICAgICAgICAgICBjb3JuZXJzLnB1c2goewogICAgICAgICAgICAgICAgICBsZWZ0UG9zaXRpb25zOiBjb21wdXRlUm91bmRDb3JuZXIyKAogICAgICAgICAgICAgICAgICAgIHJpZ2h0UG9zLAogICAgICAgICAgICAgICAgICAgIHN0YXJ0UG9pbnQsCiAgICAgICAgICAgICAgICAgICAgbGVmdFBvcywKICAgICAgICAgICAgICAgICAgICBjb3JuZXJUeXBlLAogICAgICAgICAgICAgICAgICAgIGxlZnRJc091dHNpZGUKICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGNvcm5lcnMucHVzaCh7CiAgICAgICAgICAgICAgICAgIGxlZnRQb3NpdGlvbnM6IGNvbXB1dGVNaXRlcmVkQ29ybmVyKAogICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoY29ybmVyRGlyZWN0aW9uLCBjb3JuZXJEaXJlY3Rpb24pLAogICAgICAgICAgICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICAgICAgICAgICAgbGVmdElzT3V0c2lkZQogICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgbGVmdFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIGNvcm5lckRpcmVjdGlvbiwgbGVmdFBvcyk7CiAgICAgICAgICAgICAgY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihsZWZ0LCB3aWR0aCwgY2VudGVyKSwKICAgICAgICAgICAgICAgICAgY2VudGVyCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgY2VudGVyCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICByaWdodFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICBsZWZ0UG9zLAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZSgKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobGVmdCwgd2lkdGggKiAyLCByaWdodFBvcyksCiAgICAgICAgICAgICAgICAgIHJpZ2h0UG9zCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgcmlnaHRQb3MKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIHNjYWxlQXJyYXkyWzBdID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHByZXZpb3VzUG9zLCBzY2FsZUFycmF5MlswXSk7CiAgICAgICAgICAgICAgc2NhbGVBcnJheTJbMV0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2VudGVyLCBzY2FsZUFycmF5MlsxXSk7CiAgICAgICAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9ucyA9IFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdC5nZW5lcmF0ZUFyYyh7CiAgICAgICAgICAgICAgICBwb3NpdGlvbnM6IHNjYWxlQXJyYXkyLAogICAgICAgICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICAgICAgICBlbGxpcHNvaWQKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICBjYWxjdWxhdGVkUG9zaXRpb25zID0gYWRkU2hpZnRlZFBvc2l0aW9ucygKICAgICAgICAgICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMsCiAgICAgICAgICAgICAgICBsZWZ0LAogICAgICAgICAgICAgICAgd2lkdGgsCiAgICAgICAgICAgICAgICBjYWxjdWxhdGVkUG9zaXRpb25zCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoc2F2ZUF0dHJpYnV0ZXMpIHsKICAgICAgICAgICAgICAgIGNhbGN1bGF0ZWRMZWZ0cy5wdXNoKGxlZnQueCwgbGVmdC55LCBsZWZ0LnopOwogICAgICAgICAgICAgICAgY2FsY3VsYXRlZE5vcm1hbHMucHVzaChub3JtYWwyLngsIG5vcm1hbDIueSwgbm9ybWFsMi56KTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgc3RhcnRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyaWdodFBvcywgc3RhcnRQb2ludCk7CiAgICAgICAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Mobm9ybWFsMiwgZm9yd2FyZCwgbGVmdCksCiAgICAgICAgICAgICAgICBsZWZ0CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICByaWdodFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICAgICAgICBsZWZ0UG9zLAogICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZSgKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIobGVmdCwgd2lkdGggKiAyLCByaWdodFBvcyksCiAgICAgICAgICAgICAgICAgIHJpZ2h0UG9zCiAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgcmlnaHRQb3MKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIHByZXZpb3VzUG9zID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZCgKICAgICAgICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihsZWZ0LCB3aWR0aCwgcHJldmlvdXNQb3MpLAogICAgICAgICAgICAgICAgICBwcmV2aW91c1BvcwogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgIHByZXZpb3VzUG9zCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBpZiAoY29ybmVyVHlwZSA9PT0gQ29ybmVyVHlwZV9kZWZhdWx0LlJPVU5ERUQgfHwgY29ybmVyVHlwZSA9PT0gQ29ybmVyVHlwZV9kZWZhdWx0LkJFVkVMRUQpIHsKICAgICAgICAgICAgICAgIGNvcm5lcnMucHVzaCh7CiAgICAgICAgICAgICAgICAgIHJpZ2h0UG9zaXRpb25zOiBjb21wdXRlUm91bmRDb3JuZXIyKAogICAgICAgICAgICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICAgICAgICAgICAgc3RhcnRQb2ludCwKICAgICAgICAgICAgICAgICAgICByaWdodFBvcywKICAgICAgICAgICAgICAgICAgICBjb3JuZXJUeXBlLAogICAgICAgICAgICAgICAgICAgIGxlZnRJc091dHNpZGUKICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGNvcm5lcnMucHVzaCh7CiAgICAgICAgICAgICAgICAgIHJpZ2h0UG9zaXRpb25zOiBjb21wdXRlTWl0ZXJlZENvcm5lcigKICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgICAgICAgICBjb3JuZXJEaXJlY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgcmlnaHRQb3MsCiAgICAgICAgICAgICAgICAgICAgbGVmdElzT3V0c2lkZQogICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYmFja3dhcmQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGZvcndhcmQsIGJhY2t3YXJkKTsKICAgICAgICAgIH0KICAgICAgICAgIHBvc2l0aW9uID0gbmV4dFBvc2l0aW9uOwogICAgICAgIH0KICAgICAgICBub3JtYWwyID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChwb3NpdGlvbiwgbm9ybWFsMik7CiAgICAgICAgc2NhbGVBcnJheTJbMF0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocHJldmlvdXNQb3MsIHNjYWxlQXJyYXkyWzBdKTsKICAgICAgICBzY2FsZUFycmF5MlsxXSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgc2NhbGVBcnJheTJbMV0pOwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMgPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQuZ2VuZXJhdGVBcmMoewogICAgICAgICAgcG9zaXRpb25zOiBzY2FsZUFycmF5MiwKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZWxsaXBzb2lkCiAgICAgICAgfSk7CiAgICAgICAgY2FsY3VsYXRlZFBvc2l0aW9ucyA9IGFkZFNoaWZ0ZWRQb3NpdGlvbnMoCiAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zLAogICAgICAgICAgbGVmdCwKICAgICAgICAgIHdpZHRoLAogICAgICAgICAgY2FsY3VsYXRlZFBvc2l0aW9ucwogICAgICAgICk7CiAgICAgICAgaWYgKHNhdmVBdHRyaWJ1dGVzKSB7CiAgICAgICAgICBjYWxjdWxhdGVkTGVmdHMucHVzaChsZWZ0LngsIGxlZnQueSwgbGVmdC56KTsKICAgICAgICAgIGNhbGN1bGF0ZWROb3JtYWxzLnB1c2gobm9ybWFsMi54LCBub3JtYWwyLnksIG5vcm1hbDIueik7CiAgICAgICAgfQogICAgICAgIGxldCBlbmRQb3NpdGlvbnM7CiAgICAgICAgaWYgKGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5ST1VOREVEKSB7CiAgICAgICAgICBlbmRQb3NpdGlvbnMgPSBhZGRFbmRDYXBzKGNhbGN1bGF0ZWRQb3NpdGlvbnMpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgcG9zaXRpb25zOiBjYWxjdWxhdGVkUG9zaXRpb25zLAogICAgICAgICAgY29ybmVycywKICAgICAgICAgIGxlZnRzOiBjYWxjdWxhdGVkTGVmdHMsCiAgICAgICAgICBub3JtYWxzOiBjYWxjdWxhdGVkTm9ybWFscywKICAgICAgICAgIGVuZFBvc2l0aW9ucwogICAgICAgIH07CiAgICAgIH07CiAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQgPSBDb3JyaWRvckdlb21ldHJ5TGlicmFyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0NvcnJpZG9yR2VvbWV0cnkuanMKICBmdW5jdGlvbiBzY2FsZVRvU3VyZmFjZTIocG9zaXRpb25zLCBlbGxpcHNvaWQpIHsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnMubGVuZ3RoOyBpMisrKSB7CiAgICAgIHBvc2l0aW9uc1tpMl0gPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwb3NpdGlvbnNbaTJdLCBwb3NpdGlvbnNbaTJdKTsKICAgIH0KICAgIHJldHVybiBwb3NpdGlvbnM7CiAgfQogIGZ1bmN0aW9uIGFkZE5vcm1hbHMoYXR0ciwgbm9ybWFsMiwgbGVmdCwgZnJvbnQsIGJhY2ssIHZlcnRleEZvcm1hdCkgewogICAgY29uc3Qgbm9ybWFscyA9IGF0dHIubm9ybWFsczsKICAgIGNvbnN0IHRhbmdlbnRzID0gYXR0ci50YW5nZW50czsKICAgIGNvbnN0IGJpdGFuZ2VudHMgPSBhdHRyLmJpdGFuZ2VudHM7CiAgICBjb25zdCBmb3J3YXJkID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGxlZnQsIG5vcm1hbDIsIHNjcmF0Y2gxMyksCiAgICAgIHNjcmF0Y2gxMwogICAgKTsKICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsKSB7CiAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKG5vcm1hbHMsIG5vcm1hbDIsIGZyb250LCBiYWNrKTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCkgewogICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSh0YW5nZW50cywgZm9yd2FyZCwgZnJvbnQsIGJhY2spOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoYml0YW5nZW50cywgbGVmdCwgZnJvbnQsIGJhY2spOwogICAgfQogIH0KICBmdW5jdGlvbiBjb21iaW5lMihjb21wdXRlZFBvc2l0aW9ucywgdmVydGV4Rm9ybWF0LCBlbGxpcHNvaWQpIHsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGNvbXB1dGVkUG9zaXRpb25zLnBvc2l0aW9uczsKICAgIGNvbnN0IGNvcm5lcnMgPSBjb21wdXRlZFBvc2l0aW9ucy5jb3JuZXJzOwogICAgY29uc3QgZW5kUG9zaXRpb25zID0gY29tcHV0ZWRQb3NpdGlvbnMuZW5kUG9zaXRpb25zOwogICAgY29uc3QgY29tcHV0ZWRMZWZ0cyA9IGNvbXB1dGVkUG9zaXRpb25zLmxlZnRzOwogICAgY29uc3QgY29tcHV0ZWROb3JtYWxzID0gY29tcHV0ZWRQb3NpdGlvbnMubm9ybWFsczsKICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgIGxldCBsZWZ0Q291bnQgPSAwOwogICAgbGV0IHJpZ2h0Q291bnQgPSAwOwogICAgbGV0IGkyOwogICAgbGV0IGluZGljZXNMZW5ndGggPSAwOwogICAgbGV0IGxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IHBvc2l0aW9ucy5sZW5ndGg7IGkyICs9IDIpIHsKICAgICAgbGVuZ3RoID0gcG9zaXRpb25zW2kyXS5sZW5ndGggLSAzOwogICAgICBsZWZ0Q291bnQgKz0gbGVuZ3RoOwogICAgICBpbmRpY2VzTGVuZ3RoICs9IGxlbmd0aCAqIDI7CiAgICAgIHJpZ2h0Q291bnQgKz0gcG9zaXRpb25zW2kyICsgMV0ubGVuZ3RoIC0gMzsKICAgIH0KICAgIGxlZnRDb3VudCArPSAzOwogICAgcmlnaHRDb3VudCArPSAzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgY29ybmVycy5sZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgbGVmdFNpZGUgPSBjb3JuZXJzW2kyXS5sZWZ0UG9zaXRpb25zOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGxlZnRTaWRlKSkgewogICAgICAgIGxlbmd0aCA9IGxlZnRTaWRlLmxlbmd0aDsKICAgICAgICBsZWZ0Q291bnQgKz0gbGVuZ3RoOwogICAgICAgIGluZGljZXNMZW5ndGggKz0gbGVuZ3RoOwogICAgICB9IGVsc2UgewogICAgICAgIGxlbmd0aCA9IGNvcm5lcnNbaTJdLnJpZ2h0UG9zaXRpb25zLmxlbmd0aDsKICAgICAgICByaWdodENvdW50ICs9IGxlbmd0aDsKICAgICAgICBpbmRpY2VzTGVuZ3RoICs9IGxlbmd0aDsKICAgICAgfQogICAgfQogICAgY29uc3QgYWRkRW5kUG9zaXRpb25zID0gZGVmaW5lZF9kZWZhdWx0KGVuZFBvc2l0aW9ucyk7CiAgICBsZXQgZW5kUG9zaXRpb25MZW5ndGg7CiAgICBpZiAoYWRkRW5kUG9zaXRpb25zKSB7CiAgICAgIGVuZFBvc2l0aW9uTGVuZ3RoID0gZW5kUG9zaXRpb25zWzBdLmxlbmd0aCAtIDM7CiAgICAgIGxlZnRDb3VudCArPSBlbmRQb3NpdGlvbkxlbmd0aDsKICAgICAgcmlnaHRDb3VudCArPSBlbmRQb3NpdGlvbkxlbmd0aDsKICAgICAgZW5kUG9zaXRpb25MZW5ndGggLz0gMzsKICAgICAgaW5kaWNlc0xlbmd0aCArPSBlbmRQb3NpdGlvbkxlbmd0aCAqIDY7CiAgICB9CiAgICBjb25zdCBzaXplID0gbGVmdENvdW50ICsgcmlnaHRDb3VudDsKICAgIGNvbnN0IGZpbmFsUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShzaXplKTsKICAgIGNvbnN0IG5vcm1hbHMgPSB2ZXJ0ZXhGb3JtYXQubm9ybWFsID8gbmV3IEZsb2F0MzJBcnJheShzaXplKSA6IHZvaWQgMDsKICAgIGNvbnN0IHRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LnRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUpIDogdm9pZCAwOwogICAgY29uc3QgYml0YW5nZW50cyA9IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUpIDogdm9pZCAwOwogICAgY29uc3QgYXR0ciA9IHsKICAgICAgbm9ybWFscywKICAgICAgdGFuZ2VudHMsCiAgICAgIGJpdGFuZ2VudHMKICAgIH07CiAgICBsZXQgZnJvbnQgPSAwOwogICAgbGV0IGJhY2sgPSBzaXplIC0gMTsKICAgIGxldCBVTCwgTEwsIFVSLCBMUjsKICAgIGxldCBub3JtYWwyID0gY2FydGVzaWFuMTI7CiAgICBsZXQgbGVmdCA9IGNhcnRlc2lhbjIyOwogICAgbGV0IHJpZ2h0UG9zLCBsZWZ0UG9zOwogICAgY29uc3QgaGFsZkxlbmd0aCA9IGVuZFBvc2l0aW9uTGVuZ3RoIC8gMjsKICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShzaXplIC8gMywgaW5kaWNlc0xlbmd0aCk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgaWYgKGFkZEVuZFBvc2l0aW9ucykgewogICAgICBsZWZ0UG9zID0gY2FydGVzaWFuMzI7CiAgICAgIHJpZ2h0UG9zID0gY2FydGVzaWFuNDI7CiAgICAgIGNvbnN0IGZpcnN0RW5kUG9zaXRpb25zID0gZW5kUG9zaXRpb25zWzBdOwogICAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShjb21wdXRlZE5vcm1hbHMsIDAsIG5vcm1hbDIpOwogICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShjb21wdXRlZExlZnRzLCAwLCBsZWZ0KTsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgaGFsZkxlbmd0aDsgaTIrKykgewogICAgICAgIGxlZnRQb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgZmlyc3RFbmRQb3NpdGlvbnMsCiAgICAgICAgICAoaGFsZkxlbmd0aCAtIDEgLSBpMikgKiAzLAogICAgICAgICAgbGVmdFBvcwogICAgICAgICk7CiAgICAgICAgcmlnaHRQb3MgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgZmlyc3RFbmRQb3NpdGlvbnMsCiAgICAgICAgICAoaGFsZkxlbmd0aCArIGkyKSAqIDMsCiAgICAgICAgICByaWdodFBvcwogICAgICAgICk7CiAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoZmluYWxQb3NpdGlvbnMsIHJpZ2h0UG9zLCBmcm9udCk7CiAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoCiAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICBiYWNrCiAgICAgICAgKTsKICAgICAgICBhZGROb3JtYWxzKGF0dHIsIG5vcm1hbDIsIGxlZnQsIGZyb250LCBiYWNrLCB2ZXJ0ZXhGb3JtYXQpOwogICAgICAgIExMID0gZnJvbnQgLyAzOwogICAgICAgIExSID0gTEwgKyAxOwogICAgICAgIFVMID0gKGJhY2sgLSAyKSAvIDM7CiAgICAgICAgVVIgPSBVTCAtIDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVVI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gTFI7CiAgICAgICAgZnJvbnQgKz0gMzsKICAgICAgICBiYWNrIC09IDM7CiAgICAgIH0KICAgIH0KICAgIGxldCBwb3NJbmRleCA9IDA7CiAgICBsZXQgY29tcEluZGV4ID0gMDsKICAgIGxldCByaWdodEVkZ2UgPSBwb3NpdGlvbnNbcG9zSW5kZXgrK107CiAgICBsZXQgbGVmdEVkZ2UgPSBwb3NpdGlvbnNbcG9zSW5kZXgrK107CiAgICBmaW5hbFBvc2l0aW9ucy5zZXQocmlnaHRFZGdlLCBmcm9udCk7CiAgICBmaW5hbFBvc2l0aW9ucy5zZXQobGVmdEVkZ2UsIGJhY2sgLSBsZWZ0RWRnZS5sZW5ndGggKyAxKTsKICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGNvbXB1dGVkTGVmdHMsIGNvbXBJbmRleCwgbGVmdCk7CiAgICBsZXQgcmlnaHROb3JtYWw7CiAgICBsZXQgbGVmdE5vcm1hbDsKICAgIGxlbmd0aCA9IGxlZnRFZGdlLmxlbmd0aCAtIDM7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyICs9IDMpIHsKICAgICAgcmlnaHROb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocmlnaHRFZGdlLCBpMiwgc2NyYXRjaDEzKSwKICAgICAgICBzY3JhdGNoMTMKICAgICAgKTsKICAgICAgbGVmdE5vcm1hbCA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoCiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShsZWZ0RWRnZSwgbGVuZ3RoIC0gaTIsIHNjcmF0Y2gyMyksCiAgICAgICAgc2NyYXRjaDIzCiAgICAgICk7CiAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmlnaHROb3JtYWwsIGxlZnROb3JtYWwsIG5vcm1hbDIpLAogICAgICAgIG5vcm1hbDIKICAgICAgKTsKICAgICAgYWRkTm9ybWFscyhhdHRyLCBub3JtYWwyLCBsZWZ0LCBmcm9udCwgYmFjaywgdmVydGV4Rm9ybWF0KTsKICAgICAgTEwgPSBmcm9udCAvIDM7CiAgICAgIExSID0gTEwgKyAxOwogICAgICBVTCA9IChiYWNrIC0gMikgLyAzOwogICAgICBVUiA9IFVMIC0gMTsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVMOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVUjsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMUjsKICAgICAgZnJvbnQgKz0gMzsKICAgICAgYmFjayAtPSAzOwogICAgfQogICAgcmlnaHROb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHJpZ2h0RWRnZSwgbGVuZ3RoLCBzY3JhdGNoMTMpLAogICAgICBzY3JhdGNoMTMKICAgICk7CiAgICBsZWZ0Tm9ybWFsID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbCgKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShsZWZ0RWRnZSwgbGVuZ3RoLCBzY3JhdGNoMjMpLAogICAgICBzY3JhdGNoMjMKICAgICk7CiAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChyaWdodE5vcm1hbCwgbGVmdE5vcm1hbCwgbm9ybWFsMiksCiAgICAgIG5vcm1hbDIKICAgICk7CiAgICBjb21wSW5kZXggKz0gMzsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGNvcm5lcnMubGVuZ3RoOyBpMisrKSB7CiAgICAgIGxldCBqMjsKICAgICAgY29uc3QgY29ybmVyID0gY29ybmVyc1tpMl07CiAgICAgIGNvbnN0IGwyID0gY29ybmVyLmxlZnRQb3NpdGlvbnM7CiAgICAgIGNvbnN0IHIyID0gY29ybmVyLnJpZ2h0UG9zaXRpb25zOwogICAgICBsZXQgcGl2b3Q7CiAgICAgIGxldCBzdGFydDsKICAgICAgbGV0IG91dHNpZGVQb2ludCA9IGNhcnRlc2lhbjYyOwogICAgICBsZXQgcHJldmlvdXNQb2ludCA9IGNhcnRlc2lhbjMyOwogICAgICBsZXQgbmV4dFBvaW50ID0gY2FydGVzaWFuNDI7CiAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGNvbXB1dGVkTm9ybWFscywgY29tcEluZGV4LCBub3JtYWwyKTsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChsMikpIHsKICAgICAgICBhZGROb3JtYWxzKGF0dHIsIG5vcm1hbDIsIGxlZnQsIHZvaWQgMCwgYmFjaywgdmVydGV4Rm9ybWF0KTsKICAgICAgICBiYWNrIC09IDM7CiAgICAgICAgcGl2b3QgPSBMUjsKICAgICAgICBzdGFydCA9IFVSOwogICAgICAgIGZvciAoajIgPSAwOyBqMiA8IGwyLmxlbmd0aCAvIDM7IGoyKyspIHsKICAgICAgICAgIG91dHNpZGVQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobDIsIGoyICogMywgb3V0c2lkZVBvaW50KTsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBwaXZvdDsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBzdGFydCAtIGoyIC0gMTsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBzdGFydCAtIGoyOwogICAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoCiAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgICBvdXRzaWRlUG9pbnQsCiAgICAgICAgICAgIHZvaWQgMCwKICAgICAgICAgICAgYmFjawogICAgICAgICAgKTsKICAgICAgICAgIHByZXZpb3VzUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgKHN0YXJ0IC0gajIgLSAxKSAqIDMsCiAgICAgICAgICAgIHByZXZpb3VzUG9pbnQKICAgICAgICAgICk7CiAgICAgICAgICBuZXh0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGZpbmFsUG9zaXRpb25zLCBwaXZvdCAqIDMsIG5leHRQb2ludCk7CiAgICAgICAgICBsZWZ0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHByZXZpb3VzUG9pbnQsIG5leHRQb2ludCwgbGVmdCksCiAgICAgICAgICAgIGxlZnQKICAgICAgICAgICk7CiAgICAgICAgICBhZGROb3JtYWxzKGF0dHIsIG5vcm1hbDIsIGxlZnQsIHZvaWQgMCwgYmFjaywgdmVydGV4Rm9ybWF0KTsKICAgICAgICAgIGJhY2sgLT0gMzsKICAgICAgICB9CiAgICAgICAgb3V0c2lkZVBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgcGl2b3QgKiAzLAogICAgICAgICAgb3V0c2lkZVBvaW50CiAgICAgICAgKTsKICAgICAgICBwcmV2aW91c1BvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShmaW5hbFBvc2l0aW9ucywgc3RhcnQgKiAzLCBwcmV2aW91c1BvaW50KSwKICAgICAgICAgIG91dHNpZGVQb2ludCwKICAgICAgICAgIHByZXZpb3VzUG9pbnQKICAgICAgICApOwogICAgICAgIG5leHRQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoZmluYWxQb3NpdGlvbnMsIChzdGFydCAtIGoyKSAqIDMsIG5leHRQb2ludCksCiAgICAgICAgICBvdXRzaWRlUG9pbnQsCiAgICAgICAgICBuZXh0UG9pbnQKICAgICAgICApOwogICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwcmV2aW91c1BvaW50LCBuZXh0UG9pbnQsIGxlZnQpLAogICAgICAgICAgbGVmdAogICAgICAgICk7CiAgICAgICAgYWRkTm9ybWFscyhhdHRyLCBub3JtYWwyLCBsZWZ0LCBmcm9udCwgdm9pZCAwLCB2ZXJ0ZXhGb3JtYXQpOwogICAgICAgIGZyb250ICs9IDM7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgYWRkTm9ybWFscyhhdHRyLCBub3JtYWwyLCBsZWZ0LCBmcm9udCwgdm9pZCAwLCB2ZXJ0ZXhGb3JtYXQpOwogICAgICAgIGZyb250ICs9IDM7CiAgICAgICAgcGl2b3QgPSBVUjsKICAgICAgICBzdGFydCA9IExSOwogICAgICAgIGZvciAoajIgPSAwOyBqMiA8IHIyLmxlbmd0aCAvIDM7IGoyKyspIHsKICAgICAgICAgIG91dHNpZGVQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocjIsIGoyICogMywgb3V0c2lkZVBvaW50KTsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBwaXZvdDsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBzdGFydCArIGoyOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHN0YXJ0ICsgajIgKyAxOwogICAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoCiAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgICBvdXRzaWRlUG9pbnQsCiAgICAgICAgICAgIGZyb250CiAgICAgICAgICApOwogICAgICAgICAgcHJldmlvdXNQb2ludCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgICBwaXZvdCAqIDMsCiAgICAgICAgICAgIHByZXZpb3VzUG9pbnQKICAgICAgICAgICk7CiAgICAgICAgICBuZXh0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgKHN0YXJ0ICsgajIpICogMywKICAgICAgICAgICAgbmV4dFBvaW50CiAgICAgICAgICApOwogICAgICAgICAgbGVmdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwcmV2aW91c1BvaW50LCBuZXh0UG9pbnQsIGxlZnQpLAogICAgICAgICAgICBsZWZ0CiAgICAgICAgICApOwogICAgICAgICAgYWRkTm9ybWFscyhhdHRyLCBub3JtYWwyLCBsZWZ0LCBmcm9udCwgdm9pZCAwLCB2ZXJ0ZXhGb3JtYXQpOwogICAgICAgICAgZnJvbnQgKz0gMzsKICAgICAgICB9CiAgICAgICAgb3V0c2lkZVBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGZpbmFsUG9zaXRpb25zLAogICAgICAgICAgcGl2b3QgKiAzLAogICAgICAgICAgb3V0c2lkZVBvaW50CiAgICAgICAgKTsKICAgICAgICBwcmV2aW91c1BvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShmaW5hbFBvc2l0aW9ucywgKHN0YXJ0ICsgajIpICogMywgcHJldmlvdXNQb2ludCksCiAgICAgICAgICBvdXRzaWRlUG9pbnQsCiAgICAgICAgICBwcmV2aW91c1BvaW50CiAgICAgICAgKTsKICAgICAgICBuZXh0UG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGZpbmFsUG9zaXRpb25zLCBzdGFydCAqIDMsIG5leHRQb2ludCksCiAgICAgICAgICBvdXRzaWRlUG9pbnQsCiAgICAgICAgICBuZXh0UG9pbnQKICAgICAgICApOwogICAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5leHRQb2ludCwgcHJldmlvdXNQb2ludCwgbGVmdCksIGxlZnQpLAogICAgICAgICAgbGVmdAogICAgICAgICk7CiAgICAgICAgYWRkTm9ybWFscyhhdHRyLCBub3JtYWwyLCBsZWZ0LCB2b2lkIDAsIGJhY2ssIHZlcnRleEZvcm1hdCk7CiAgICAgICAgYmFjayAtPSAzOwogICAgICB9CiAgICAgIHJpZ2h0RWRnZSA9IHBvc2l0aW9uc1twb3NJbmRleCsrXTsKICAgICAgbGVmdEVkZ2UgPSBwb3NpdGlvbnNbcG9zSW5kZXgrK107CiAgICAgIHJpZ2h0RWRnZS5zcGxpY2UoMCwgMyk7CiAgICAgIGxlZnRFZGdlLnNwbGljZShsZWZ0RWRnZS5sZW5ndGggLSAzLCAzKTsKICAgICAgZmluYWxQb3NpdGlvbnMuc2V0KHJpZ2h0RWRnZSwgZnJvbnQpOwogICAgICBmaW5hbFBvc2l0aW9ucy5zZXQobGVmdEVkZ2UsIGJhY2sgLSBsZWZ0RWRnZS5sZW5ndGggKyAxKTsKICAgICAgbGVuZ3RoID0gbGVmdEVkZ2UubGVuZ3RoIC0gMzsKICAgICAgY29tcEluZGV4ICs9IDM7CiAgICAgIGxlZnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGNvbXB1dGVkTGVmdHMsIGNvbXBJbmRleCwgbGVmdCk7CiAgICAgIGZvciAoajIgPSAwOyBqMiA8IGxlZnRFZGdlLmxlbmd0aDsgajIgKz0gMykgewogICAgICAgIHJpZ2h0Tm9ybWFsID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbCgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocmlnaHRFZGdlLCBqMiwgc2NyYXRjaDEzKSwKICAgICAgICAgIHNjcmF0Y2gxMwogICAgICAgICk7CiAgICAgICAgbGVmdE5vcm1hbCA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGxlZnRFZGdlLCBsZW5ndGggLSBqMiwgc2NyYXRjaDIzKSwKICAgICAgICAgIHNjcmF0Y2gyMwogICAgICAgICk7CiAgICAgICAgbm9ybWFsMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHJpZ2h0Tm9ybWFsLCBsZWZ0Tm9ybWFsLCBub3JtYWwyKSwKICAgICAgICAgIG5vcm1hbDIKICAgICAgICApOwogICAgICAgIGFkZE5vcm1hbHMoYXR0ciwgbm9ybWFsMiwgbGVmdCwgZnJvbnQsIGJhY2ssIHZlcnRleEZvcm1hdCk7CiAgICAgICAgTFIgPSBmcm9udCAvIDM7CiAgICAgICAgTEwgPSBMUiAtIDE7CiAgICAgICAgVVIgPSAoYmFjayAtIDIpIC8gMzsKICAgICAgICBVTCA9IFVSICsgMTsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVUw7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVUjsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVVI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMUjsKICAgICAgICBmcm9udCArPSAzOwogICAgICAgIGJhY2sgLT0gMzsKICAgICAgfQogICAgICBmcm9udCAtPSAzOwogICAgICBiYWNrICs9IDM7CiAgICB9CiAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgY29tcHV0ZWROb3JtYWxzLAogICAgICBjb21wdXRlZE5vcm1hbHMubGVuZ3RoIC0gMywKICAgICAgbm9ybWFsMgogICAgKTsKICAgIGFkZE5vcm1hbHMoYXR0ciwgbm9ybWFsMiwgbGVmdCwgZnJvbnQsIGJhY2ssIHZlcnRleEZvcm1hdCk7CiAgICBpZiAoYWRkRW5kUG9zaXRpb25zKSB7CiAgICAgIGZyb250ICs9IDM7CiAgICAgIGJhY2sgLT0gMzsKICAgICAgbGVmdFBvcyA9IGNhcnRlc2lhbjMyOwogICAgICByaWdodFBvcyA9IGNhcnRlc2lhbjQyOwogICAgICBjb25zdCBsYXN0RW5kUG9zaXRpb25zID0gZW5kUG9zaXRpb25zWzFdOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBoYWxmTGVuZ3RoOyBpMisrKSB7CiAgICAgICAgbGVmdFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICBsYXN0RW5kUG9zaXRpb25zLAogICAgICAgICAgKGVuZFBvc2l0aW9uTGVuZ3RoIC0gaTIgLSAxKSAqIDMsCiAgICAgICAgICBsZWZ0UG9zCiAgICAgICAgKTsKICAgICAgICByaWdodFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobGFzdEVuZFBvc2l0aW9ucywgaTIgKiAzLCByaWdodFBvcyk7CiAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoCiAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICBiYWNrCiAgICAgICAgKTsKICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZShmaW5hbFBvc2l0aW9ucywgcmlnaHRQb3MsIGZyb250KTsKICAgICAgICBhZGROb3JtYWxzKGF0dHIsIG5vcm1hbDIsIGxlZnQsIGZyb250LCBiYWNrLCB2ZXJ0ZXhGb3JtYXQpOwogICAgICAgIExSID0gZnJvbnQgLyAzOwogICAgICAgIExMID0gTFIgLSAxOwogICAgICAgIFVSID0gKGJhY2sgLSAyKSAvIDM7CiAgICAgICAgVUwgPSBVUiArIDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVVI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gTFI7CiAgICAgICAgZnJvbnQgKz0gMzsKICAgICAgICBiYWNrIC09IDM7CiAgICAgIH0KICAgIH0KICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgdmFsdWVzOiBmaW5hbFBvc2l0aW9ucwogICAgfSk7CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgIGNvbnN0IHN0MiA9IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAvIDMgKiAyKTsKICAgICAgbGV0IHJpZ2h0U3Q7CiAgICAgIGxldCBsZWZ0U3Q7CiAgICAgIGxldCBzdEluZGV4ID0gMDsKICAgICAgaWYgKGFkZEVuZFBvc2l0aW9ucykgewogICAgICAgIGxlZnRDb3VudCAvPSAzOwogICAgICAgIHJpZ2h0Q291bnQgLz0gMzsKICAgICAgICBjb25zdCB0aGV0YSA9IE1hdGguUEkgLyAoZW5kUG9zaXRpb25MZW5ndGggKyAxKTsKICAgICAgICBsZWZ0U3QgPSAxIC8gKGxlZnRDb3VudCAtIGVuZFBvc2l0aW9uTGVuZ3RoICsgMSk7CiAgICAgICAgcmlnaHRTdCA9IDEgLyAocmlnaHRDb3VudCAtIGVuZFBvc2l0aW9uTGVuZ3RoICsgMSk7CiAgICAgICAgbGV0IGE0OwogICAgICAgIGNvbnN0IGhhbGZFbmRQb3MgPSBlbmRQb3NpdGlvbkxlbmd0aCAvIDI7CiAgICAgICAgZm9yIChpMiA9IGhhbGZFbmRQb3MgKyAxOyBpMiA8IGVuZFBvc2l0aW9uTGVuZ3RoICsgMTsgaTIrKykgewogICAgICAgICAgYTQgPSBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gKyB0aGV0YSAqIGkyOwogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSByaWdodFN0ICogKDEgKyBNYXRoLmNvcyhhNCkpOwogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSAwLjUgKiAoMSArIE1hdGguc2luKGE0KSk7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IHJpZ2h0Q291bnQgLSBlbmRQb3NpdGlvbkxlbmd0aCArIDE7IGkyKyspIHsKICAgICAgICAgIHN0MltzdEluZGV4KytdID0gaTIgKiByaWdodFN0OwogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSAwOwogICAgICAgIH0KICAgICAgICBmb3IgKGkyID0gZW5kUG9zaXRpb25MZW5ndGg7IGkyID4gaGFsZkVuZFBvczsgaTItLSkgewogICAgICAgICAgYTQgPSBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gLSBpMiAqIHRoZXRhOwogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSAxIC0gcmlnaHRTdCAqICgxICsgTWF0aC5jb3MoYTQpKTsKICAgICAgICAgIHN0MltzdEluZGV4KytdID0gMC41ICogKDEgKyBNYXRoLnNpbihhNCkpOwogICAgICAgIH0KICAgICAgICBmb3IgKGkyID0gaGFsZkVuZFBvczsgaTIgPiAwOyBpMi0tKSB7CiAgICAgICAgICBhNCA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIHRoZXRhICogaTI7CiAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IDEgLSBsZWZ0U3QgKiAoMSArIE1hdGguY29zKGE0KSk7CiAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IDAuNSAqICgxICsgTWF0aC5zaW4oYTQpKTsKICAgICAgICB9CiAgICAgICAgZm9yIChpMiA9IGxlZnRDb3VudCAtIGVuZFBvc2l0aW9uTGVuZ3RoOyBpMiA+IDA7IGkyLS0pIHsKICAgICAgICAgIHN0MltzdEluZGV4KytdID0gaTIgKiBsZWZ0U3Q7CiAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IDE7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IGhhbGZFbmRQb3MgKyAxOyBpMisrKSB7CiAgICAgICAgICBhNCA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyArIHRoZXRhICogaTI7CiAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IGxlZnRTdCAqICgxICsgTWF0aC5jb3MoYTQpKTsKICAgICAgICAgIHN0MltzdEluZGV4KytdID0gMC41ICogKDEgKyBNYXRoLnNpbihhNCkpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBsZWZ0Q291bnQgLz0gMzsKICAgICAgICByaWdodENvdW50IC89IDM7CiAgICAgICAgbGVmdFN0ID0gMSAvIChsZWZ0Q291bnQgLSAxKTsKICAgICAgICByaWdodFN0ID0gMSAvIChyaWdodENvdW50IC0gMSk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgcmlnaHRDb3VudDsgaTIrKykgewogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSBpMiAqIHJpZ2h0U3Q7CiAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IDA7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSBsZWZ0Q291bnQ7IGkyID4gMDsgaTItLSkgewogICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSAoaTIgLSAxKSAqIGxlZnRTdDsKICAgICAgICAgIHN0MltzdEluZGV4KytdID0gMTsKICAgICAgICB9CiAgICAgIH0KICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgIHZhbHVlczogc3QyCiAgICAgIH0pOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IGF0dHIubm9ybWFscwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCkgewogICAgICBhdHRyaWJ1dGVzLnRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IGF0dHIudGFuZ2VudHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICBhdHRyaWJ1dGVzLmJpdGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgIHZhbHVlczogYXR0ci5iaXRhbmdlbnRzCiAgICAgIH0pOwogICAgfQogICAgcmV0dXJuIHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlcwogICAgfTsKICB9CiAgZnVuY3Rpb24gZXh0cnVkZWRBdHRyaWJ1dGVzKGF0dHJpYnV0ZXMsIHZlcnRleEZvcm1hdCkgewogICAgaWYgKCF2ZXJ0ZXhGb3JtYXQubm9ybWFsICYmICF2ZXJ0ZXhGb3JtYXQudGFuZ2VudCAmJiAhdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCAmJiAhdmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgIHJldHVybiBhdHRyaWJ1dGVzOwogICAgfQogICAgY29uc3QgcG9zaXRpb25zID0gYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXM7CiAgICBsZXQgdG9wTm9ybWFsczsKICAgIGxldCB0b3BCaXRhbmdlbnRzOwogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICB0b3BOb3JtYWxzID0gYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzOwogICAgICB0b3BCaXRhbmdlbnRzID0gYXR0cmlidXRlcy5iaXRhbmdlbnQudmFsdWVzOwogICAgfQogICAgY29uc3Qgc2l6ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aCAvIDE4OwogICAgY29uc3QgdGhyZWVTaXplID0gc2l6ZSAqIDM7CiAgICBjb25zdCB0d29TaXplID0gc2l6ZSAqIDI7CiAgICBjb25zdCBzaXhTaXplID0gdGhyZWVTaXplICogMjsKICAgIGxldCBpMjsKICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsIHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgY29uc3Qgbm9ybWFscyA9IHZlcnRleEZvcm1hdC5ub3JtYWwgPyBuZXcgRmxvYXQzMkFycmF5KHRocmVlU2l6ZSAqIDYpIDogdm9pZCAwOwogICAgICBjb25zdCB0YW5nZW50cyA9IHZlcnRleEZvcm1hdC50YW5nZW50ID8gbmV3IEZsb2F0MzJBcnJheSh0aHJlZVNpemUgKiA2KSA6IHZvaWQgMDsKICAgICAgY29uc3QgYml0YW5nZW50cyA9IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHRocmVlU2l6ZSAqIDYpIDogdm9pZCAwOwogICAgICBsZXQgdG9wUG9zaXRpb24gPSBjYXJ0ZXNpYW4xMjsKICAgICAgbGV0IGJvdHRvbVBvc2l0aW9uID0gY2FydGVzaWFuMjI7CiAgICAgIGxldCBwcmV2aW91c1Bvc2l0aW9uID0gY2FydGVzaWFuMzI7CiAgICAgIGxldCBub3JtYWwyID0gY2FydGVzaWFuNDI7CiAgICAgIGxldCB0YW5nZW50ID0gY2FydGVzaWFuNTI7CiAgICAgIGxldCBiaXRhbmdlbnQgPSBjYXJ0ZXNpYW42MjsKICAgICAgbGV0IGF0dHJJbmRleCA9IHNpeFNpemU7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHRocmVlU2l6ZTsgaTIgKz0gMykgewogICAgICAgIGNvbnN0IGF0dHJJbmRleE9mZnNldCA9IGF0dHJJbmRleCArIHNpeFNpemU7CiAgICAgICAgdG9wUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgaTIsIHRvcFBvc2l0aW9uKTsKICAgICAgICBib3R0b21Qb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBpMiArIHRocmVlU2l6ZSwKICAgICAgICAgIGJvdHRvbVBvc2l0aW9uCiAgICAgICAgKTsKICAgICAgICBwcmV2aW91c1Bvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIChpMiArIDMpICUgdGhyZWVTaXplLAogICAgICAgICAgcHJldmlvdXNQb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgYm90dG9tUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICBib3R0b21Qb3NpdGlvbiwKICAgICAgICAgIHRvcFBvc2l0aW9uLAogICAgICAgICAgYm90dG9tUG9zaXRpb24KICAgICAgICApOwogICAgICAgIHByZXZpb3VzUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICBwcmV2aW91c1Bvc2l0aW9uLAogICAgICAgICAgdG9wUG9zaXRpb24sCiAgICAgICAgICBwcmV2aW91c1Bvc2l0aW9uCiAgICAgICAgKTsKICAgICAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhib3R0b21Qb3NpdGlvbiwgcHJldmlvdXNQb3NpdGlvbiwgbm9ybWFsMiksCiAgICAgICAgICBub3JtYWwyCiAgICAgICAgKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUobm9ybWFscywgbm9ybWFsMiwgYXR0ckluZGV4T2Zmc2V0KTsKICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgICBub3JtYWxzLAogICAgICAgICAgICBub3JtYWwyLAogICAgICAgICAgICBhdHRySW5kZXhPZmZzZXQgKyAzCiAgICAgICAgICApOwogICAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUobm9ybWFscywgbm9ybWFsMiwgYXR0ckluZGV4KTsKICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKG5vcm1hbHMsIG5vcm1hbDIsIGF0dHJJbmRleCArIDMpOwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSh0b3BOb3JtYWxzLCBpMiwgYml0YW5nZW50KTsKICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgICAgIGJpdGFuZ2VudHMsCiAgICAgICAgICAgICAgYml0YW5nZW50LAogICAgICAgICAgICAgIGF0dHJJbmRleE9mZnNldAogICAgICAgICAgICApOwogICAgICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSgKICAgICAgICAgICAgICBiaXRhbmdlbnRzLAogICAgICAgICAgICAgIGJpdGFuZ2VudCwKICAgICAgICAgICAgICBhdHRySW5kZXhPZmZzZXQgKyAzCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgICAgIGJpdGFuZ2VudHMsCiAgICAgICAgICAgICAgYml0YW5nZW50LAogICAgICAgICAgICAgIGF0dHJJbmRleAogICAgICAgICAgICApOwogICAgICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSgKICAgICAgICAgICAgICBiaXRhbmdlbnRzLAogICAgICAgICAgICAgIGJpdGFuZ2VudCwKICAgICAgICAgICAgICBhdHRySW5kZXggKyAzCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgdGFuZ2VudCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGJpdGFuZ2VudCwgbm9ybWFsMiwgdGFuZ2VudCksCiAgICAgICAgICAgICAgdGFuZ2VudAogICAgICAgICAgICApOwogICAgICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSgKICAgICAgICAgICAgICB0YW5nZW50cywKICAgICAgICAgICAgICB0YW5nZW50LAogICAgICAgICAgICAgIGF0dHJJbmRleE9mZnNldAogICAgICAgICAgICApOwogICAgICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSgKICAgICAgICAgICAgICB0YW5nZW50cywKICAgICAgICAgICAgICB0YW5nZW50LAogICAgICAgICAgICAgIGF0dHJJbmRleE9mZnNldCArIDMKICAgICAgICAgICAgKTsKICAgICAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUodGFuZ2VudHMsIHRhbmdlbnQsIGF0dHJJbmRleCk7CiAgICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgICAgIHRhbmdlbnRzLAogICAgICAgICAgICAgIHRhbmdlbnQsCiAgICAgICAgICAgICAgYXR0ckluZGV4ICsgMwogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBhdHRySW5kZXggKz0gNjsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgIG5vcm1hbHMuc2V0KHRvcE5vcm1hbHMpOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHRocmVlU2l6ZTsgaTIgKz0gMykgewogICAgICAgICAgbm9ybWFsc1tpMiArIHRocmVlU2l6ZV0gPSAtdG9wTm9ybWFsc1tpMl07CiAgICAgICAgICBub3JtYWxzW2kyICsgdGhyZWVTaXplICsgMV0gPSAtdG9wTm9ybWFsc1tpMiArIDFdOwogICAgICAgICAgbm9ybWFsc1tpMiArIHRocmVlU2l6ZSArIDJdID0gLXRvcE5vcm1hbHNbaTIgKyAyXTsKICAgICAgICB9CiAgICAgICAgYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzID0gbm9ybWFsczsKICAgICAgfSBlbHNlIHsKICAgICAgICBhdHRyaWJ1dGVzLm5vcm1hbCA9IHZvaWQgMDsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgIGJpdGFuZ2VudHMuc2V0KHRvcEJpdGFuZ2VudHMpOwogICAgICAgIGJpdGFuZ2VudHMuc2V0KHRvcEJpdGFuZ2VudHMsIHRocmVlU2l6ZSk7CiAgICAgICAgYXR0cmlidXRlcy5iaXRhbmdlbnQudmFsdWVzID0gYml0YW5nZW50czsKICAgICAgfSBlbHNlIHsKICAgICAgICBhdHRyaWJ1dGVzLmJpdGFuZ2VudCA9IHZvaWQgMDsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICBjb25zdCB0b3BUYW5nZW50cyA9IGF0dHJpYnV0ZXMudGFuZ2VudC52YWx1ZXM7CiAgICAgICAgdGFuZ2VudHMuc2V0KHRvcFRhbmdlbnRzKTsKICAgICAgICB0YW5nZW50cy5zZXQodG9wVGFuZ2VudHMsIHRocmVlU2l6ZSk7CiAgICAgICAgYXR0cmlidXRlcy50YW5nZW50LnZhbHVlcyA9IHRhbmdlbnRzOwogICAgICB9CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgIGNvbnN0IHRvcFN0ID0gYXR0cmlidXRlcy5zdC52YWx1ZXM7CiAgICAgIGNvbnN0IHN0MiA9IG5ldyBGbG9hdDMyQXJyYXkodHdvU2l6ZSAqIDYpOwogICAgICBzdDIuc2V0KHRvcFN0KTsKICAgICAgc3QyLnNldCh0b3BTdCwgdHdvU2l6ZSk7CiAgICAgIGxldCBpbmRleCA9IHR3b1NpemUgKiAyOwogICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgMjsgajIrKykgewogICAgICAgIHN0MltpbmRleCsrXSA9IHRvcFN0WzBdOwogICAgICAgIHN0MltpbmRleCsrXSA9IHRvcFN0WzFdOwogICAgICAgIGZvciAoaTIgPSAyOyBpMiA8IHR3b1NpemU7IGkyICs9IDIpIHsKICAgICAgICAgIGNvbnN0IHMyID0gdG9wU3RbaTJdOwogICAgICAgICAgY29uc3QgdDIgPSB0b3BTdFtpMiArIDFdOwogICAgICAgICAgc3QyW2luZGV4KytdID0gczI7CiAgICAgICAgICBzdDJbaW5kZXgrK10gPSB0MjsKICAgICAgICAgIHN0MltpbmRleCsrXSA9IHMyOwogICAgICAgICAgc3QyW2luZGV4KytdID0gdDI7CiAgICAgICAgfQogICAgICAgIHN0MltpbmRleCsrXSA9IHRvcFN0WzBdOwogICAgICAgIHN0MltpbmRleCsrXSA9IHRvcFN0WzFdOwogICAgICB9CiAgICAgIGF0dHJpYnV0ZXMuc3QudmFsdWVzID0gc3QyOwogICAgfQogICAgcmV0dXJuIGF0dHJpYnV0ZXM7CiAgfQogIGZ1bmN0aW9uIGFkZFdhbGxQb3NpdGlvbnMocG9zaXRpb25zLCBpbmRleCwgd2FsbFBvc2l0aW9ucykgewogICAgd2FsbFBvc2l0aW9uc1tpbmRleCsrXSA9IHBvc2l0aW9uc1swXTsKICAgIHdhbGxQb3NpdGlvbnNbaW5kZXgrK10gPSBwb3NpdGlvbnNbMV07CiAgICB3YWxsUG9zaXRpb25zW2luZGV4KytdID0gcG9zaXRpb25zWzJdOwogICAgZm9yIChsZXQgaTIgPSAzOyBpMiA8IHBvc2l0aW9ucy5sZW5ndGg7IGkyICs9IDMpIHsKICAgICAgY29uc3QgeDIgPSBwb3NpdGlvbnNbaTJdOwogICAgICBjb25zdCB5MiA9IHBvc2l0aW9uc1tpMiArIDFdOwogICAgICBjb25zdCB6MiA9IHBvc2l0aW9uc1tpMiArIDJdOwogICAgICB3YWxsUG9zaXRpb25zW2luZGV4KytdID0geDI7CiAgICAgIHdhbGxQb3NpdGlvbnNbaW5kZXgrK10gPSB5MjsKICAgICAgd2FsbFBvc2l0aW9uc1tpbmRleCsrXSA9IHoyOwogICAgICB3YWxsUG9zaXRpb25zW2luZGV4KytdID0geDI7CiAgICAgIHdhbGxQb3NpdGlvbnNbaW5kZXgrK10gPSB5MjsKICAgICAgd2FsbFBvc2l0aW9uc1tpbmRleCsrXSA9IHoyOwogICAgfQogICAgd2FsbFBvc2l0aW9uc1tpbmRleCsrXSA9IHBvc2l0aW9uc1swXTsKICAgIHdhbGxQb3NpdGlvbnNbaW5kZXgrK10gPSBwb3NpdGlvbnNbMV07CiAgICB3YWxsUG9zaXRpb25zW2luZGV4XSA9IHBvc2l0aW9uc1syXTsKICAgIHJldHVybiB3YWxsUG9zaXRpb25zOwogIH0KICBmdW5jdGlvbiBjb21wdXRlUG9zaXRpb25zRXh0cnVkZWQocGFyYW1zLCB2ZXJ0ZXhGb3JtYXQpIHsKICAgIGNvbnN0IHRvcFZlcnRleEZvcm1hdCA9IG5ldyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCh7CiAgICAgIHBvc2l0aW9uOiB2ZXJ0ZXhGb3JtYXQucG9zaXRpb24sCiAgICAgIG5vcm1hbDogdmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50IHx8IHBhcmFtcy5zaGFkb3dWb2x1bWUsCiAgICAgIHRhbmdlbnQ6IHZlcnRleEZvcm1hdC50YW5nZW50LAogICAgICBiaXRhbmdlbnQ6IHZlcnRleEZvcm1hdC5ub3JtYWwgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCwKICAgICAgc3Q6IHZlcnRleEZvcm1hdC5zdAogICAgfSk7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBwYXJhbXMuZWxsaXBzb2lkOwogICAgY29uc3QgY29tcHV0ZWRQb3NpdGlvbnMgPSBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMocGFyYW1zKTsKICAgIGNvbnN0IGF0dHIgPSBjb21iaW5lMihjb21wdXRlZFBvc2l0aW9ucywgdG9wVmVydGV4Rm9ybWF0LCBlbGxpcHNvaWQpOwogICAgY29uc3QgaGVpZ2h0ID0gcGFyYW1zLmhlaWdodDsKICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gcGFyYW1zLmV4dHJ1ZGVkSGVpZ2h0OwogICAgbGV0IGF0dHJpYnV0ZXMgPSBhdHRyLmF0dHJpYnV0ZXM7CiAgICBjb25zdCBpbmRpY2VzID0gYXR0ci5pbmRpY2VzOwogICAgbGV0IHBvc2l0aW9ucyA9IGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgbGV0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCBuZXdQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KGxlbmd0aCAqIDYpOwogICAgbGV0IGV4dHJ1ZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGgpOwogICAgZXh0cnVkZWRQb3NpdGlvbnMuc2V0KHBvc2l0aW9ucyk7CiAgICBsZXQgd2FsbFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkobGVuZ3RoICogNCk7CiAgICBwb3NpdGlvbnMgPSBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5zY2FsZVRvR2VvZGV0aWNIZWlnaHQoCiAgICAgIHBvc2l0aW9ucywKICAgICAgaGVpZ2h0LAogICAgICBlbGxpcHNvaWQKICAgICk7CiAgICB3YWxsUG9zaXRpb25zID0gYWRkV2FsbFBvc2l0aW9ucyhwb3NpdGlvbnMsIDAsIHdhbGxQb3NpdGlvbnMpOwogICAgZXh0cnVkZWRQb3NpdGlvbnMgPSBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5zY2FsZVRvR2VvZGV0aWNIZWlnaHQoCiAgICAgIGV4dHJ1ZGVkUG9zaXRpb25zLAogICAgICBleHRydWRlZEhlaWdodCwKICAgICAgZWxsaXBzb2lkCiAgICApOwogICAgd2FsbFBvc2l0aW9ucyA9IGFkZFdhbGxQb3NpdGlvbnMoCiAgICAgIGV4dHJ1ZGVkUG9zaXRpb25zLAogICAgICBsZW5ndGggKiAyLAogICAgICB3YWxsUG9zaXRpb25zCiAgICApOwogICAgbmV3UG9zaXRpb25zLnNldChwb3NpdGlvbnMpOwogICAgbmV3UG9zaXRpb25zLnNldChleHRydWRlZFBvc2l0aW9ucywgbGVuZ3RoKTsKICAgIG5ld1Bvc2l0aW9ucy5zZXQod2FsbFBvc2l0aW9ucywgbGVuZ3RoICogMik7CiAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IG5ld1Bvc2l0aW9uczsKICAgIGF0dHJpYnV0ZXMgPSBleHRydWRlZEF0dHJpYnV0ZXMoYXR0cmlidXRlcywgdmVydGV4Rm9ybWF0KTsKICAgIGxldCBpMjsKICAgIGNvbnN0IHNpemUgPSBsZW5ndGggLyAzOwogICAgaWYgKHBhcmFtcy5zaGFkb3dWb2x1bWUpIHsKICAgICAgY29uc3QgdG9wTm9ybWFscyA9IGF0dHJpYnV0ZXMubm9ybWFsLnZhbHVlczsKICAgICAgbGVuZ3RoID0gdG9wTm9ybWFscy5sZW5ndGg7CiAgICAgIGxldCBleHRydWRlTm9ybWFscyA9IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoICogNik7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgIHRvcE5vcm1hbHNbaTJdID0gLXRvcE5vcm1hbHNbaTJdOwogICAgICB9CiAgICAgIGV4dHJ1ZGVOb3JtYWxzLnNldCh0b3BOb3JtYWxzLCBsZW5ndGgpOwogICAgICBleHRydWRlTm9ybWFscyA9IGFkZFdhbGxQb3NpdGlvbnModG9wTm9ybWFscywgbGVuZ3RoICogNCwgZXh0cnVkZU5vcm1hbHMpOwogICAgICBhdHRyaWJ1dGVzLmV4dHJ1ZGVEaXJlY3Rpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICB2YWx1ZXM6IGV4dHJ1ZGVOb3JtYWxzCiAgICAgIH0pOwogICAgICBpZiAoIXZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICBhdHRyaWJ1dGVzLm5vcm1hbCA9IHZvaWQgMDsKICAgICAgfQogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChwYXJhbXMub2Zmc2V0QXR0cmlidXRlKSkgewogICAgICBsZXQgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShzaXplICogNik7CiAgICAgIGlmIChwYXJhbXMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICAgIGFwcGx5T2Zmc2V0ID0gYXBwbHlPZmZzZXQuZmlsbCgxLCAwLCBzaXplKS5maWxsKDEsIHNpemUgKiAyLCBzaXplICogNCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgYXBwbHlPZmZzZXRWYWx1ZSA9IHBhcmFtcy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgIGFwcGx5T2Zmc2V0ID0gYXBwbHlPZmZzZXQuZmlsbChhcHBseU9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgIH0pOwogICAgfQogICAgY29uc3QgaUxlbmd0aCA9IGluZGljZXMubGVuZ3RoOwogICAgY29uc3QgdHdvU2l6ZSA9IHNpemUgKyBzaXplOwogICAgY29uc3QgbmV3SW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBuZXdQb3NpdGlvbnMubGVuZ3RoIC8gMywKICAgICAgaUxlbmd0aCAqIDIgKyB0d29TaXplICogMwogICAgKTsKICAgIG5ld0luZGljZXMuc2V0KGluZGljZXMpOwogICAgbGV0IGluZGV4ID0gaUxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGlMZW5ndGg7IGkyICs9IDMpIHsKICAgICAgY29uc3QgdjAyID0gaW5kaWNlc1tpMl07CiAgICAgIGNvbnN0IHYxMiA9IGluZGljZXNbaTIgKyAxXTsKICAgICAgY29uc3QgdjIyID0gaW5kaWNlc1tpMiArIDJdOwogICAgICBuZXdJbmRpY2VzW2luZGV4KytdID0gdjIyICsgc2l6ZTsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IHYxMiArIHNpemU7CiAgICAgIG5ld0luZGljZXNbaW5kZXgrK10gPSB2MDIgKyBzaXplOwogICAgfQogICAgbGV0IFVMLCBMTCwgVVIsIExSOwogICAgZm9yIChpMiA9IDA7IGkyIDwgdHdvU2l6ZTsgaTIgKz0gMikgewogICAgICBVTCA9IGkyICsgdHdvU2l6ZTsKICAgICAgTEwgPSBVTCArIHR3b1NpemU7CiAgICAgIFVSID0gVUwgKyAxOwogICAgICBMUiA9IExMICsgMTsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IFVMOwogICAgICBuZXdJbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIG5ld0luZGljZXNbaW5kZXgrK10gPSBVUjsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICBuZXdJbmRpY2VzW2luZGV4KytdID0gTEw7CiAgICAgIG5ld0luZGljZXNbaW5kZXgrK10gPSBMUjsKICAgIH0KICAgIHJldHVybiB7CiAgICAgIGF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXM6IG5ld0luZGljZXMKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVPZmZzZXRQb2ludHMocG9zaXRpb24xLCBwb3NpdGlvbjIsIGVsbGlwc29pZCwgaGFsZldpZHRoLCBtaW4zLCBtYXgzKSB7CiAgICBjb25zdCBkaXJlY3Rpb24yID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICBwb3NpdGlvbjIsCiAgICAgIHBvc2l0aW9uMSwKICAgICAgc2NyYXRjaENhcnRlc2lhbjE3CiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShkaXJlY3Rpb24yLCBkaXJlY3Rpb24yKTsKICAgIGNvbnN0IG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uMSwgc2NyYXRjaENhcnRlc2lhbjI3KTsKICAgIGNvbnN0IG9mZnNldERpcmVjdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcygKICAgICAgZGlyZWN0aW9uMiwKICAgICAgbm9ybWFsMiwKICAgICAgc2NyYXRjaENhcnRlc2lhbjE3CiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIob2Zmc2V0RGlyZWN0aW9uLCBoYWxmV2lkdGgsIG9mZnNldERpcmVjdGlvbik7CiAgICBsZXQgbWluTGF0ID0gbWluMy5sYXRpdHVkZTsKICAgIGxldCBtaW5Mb24gPSBtaW4zLmxvbmdpdHVkZTsKICAgIGxldCBtYXhMYXQgPSBtYXgzLmxhdGl0dWRlOwogICAgbGV0IG1heExvbiA9IG1heDMubG9uZ2l0dWRlOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwb3NpdGlvbjEsIG9mZnNldERpcmVjdGlvbiwgc2NyYXRjaENhcnRlc2lhbjI3KTsKICAgIGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhzY3JhdGNoQ2FydGVzaWFuMjcsIHNjcmF0Y2hDYXJ0b2dyYXBoaWM0KTsKICAgIGxldCBsYXQgPSBzY3JhdGNoQ2FydG9ncmFwaGljNC5sYXRpdHVkZTsKICAgIGxldCBsb24gPSBzY3JhdGNoQ2FydG9ncmFwaGljNC5sb25naXR1ZGU7CiAgICBtaW5MYXQgPSBNYXRoLm1pbihtaW5MYXQsIGxhdCk7CiAgICBtaW5Mb24gPSBNYXRoLm1pbihtaW5Mb24sIGxvbik7CiAgICBtYXhMYXQgPSBNYXRoLm1heChtYXhMYXQsIGxhdCk7CiAgICBtYXhMb24gPSBNYXRoLm1heChtYXhMb24sIGxvbik7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocG9zaXRpb24xLCBvZmZzZXREaXJlY3Rpb24sIHNjcmF0Y2hDYXJ0ZXNpYW4yNyk7CiAgICBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoc2NyYXRjaENhcnRlc2lhbjI3LCBzY3JhdGNoQ2FydG9ncmFwaGljNCk7CiAgICBsYXQgPSBzY3JhdGNoQ2FydG9ncmFwaGljNC5sYXRpdHVkZTsKICAgIGxvbiA9IHNjcmF0Y2hDYXJ0b2dyYXBoaWM0LmxvbmdpdHVkZTsKICAgIG1pbkxhdCA9IE1hdGgubWluKG1pbkxhdCwgbGF0KTsKICAgIG1pbkxvbiA9IE1hdGgubWluKG1pbkxvbiwgbG9uKTsKICAgIG1heExhdCA9IE1hdGgubWF4KG1heExhdCwgbGF0KTsKICAgIG1heExvbiA9IE1hdGgubWF4KG1heExvbiwgbG9uKTsKICAgIG1pbjMubGF0aXR1ZGUgPSBtaW5MYXQ7CiAgICBtaW4zLmxvbmdpdHVkZSA9IG1pbkxvbjsKICAgIG1heDMubGF0aXR1ZGUgPSBtYXhMYXQ7CiAgICBtYXgzLmxvbmdpdHVkZSA9IG1heExvbjsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZVJlY3RhbmdsZTIocG9zaXRpb25zLCBlbGxpcHNvaWQsIHdpZHRoLCBjb3JuZXJUeXBlLCByZXN1bHQpIHsKICAgIHBvc2l0aW9ucyA9IHNjYWxlVG9TdXJmYWNlMihwb3NpdGlvbnMsIGVsbGlwc29pZCk7CiAgICBjb25zdCBjbGVhblBvc2l0aW9ucyA9IGFycmF5UmVtb3ZlRHVwbGljYXRlc19kZWZhdWx0KAogICAgICBwb3NpdGlvbnMsCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uCiAgICApOwogICAgY29uc3QgbGVuZ3RoID0gY2xlYW5Qb3NpdGlvbnMubGVuZ3RoOwogICAgaWYgKGxlbmd0aCA8IDIgfHwgd2lkdGggPD0gMCkgewogICAgICByZXR1cm4gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICB9CiAgICBjb25zdCBoYWxmV2lkdGggPSB3aWR0aCAqIDAuNTsKICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNaW4ubGF0aXR1ZGUgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWluLmxvbmdpdHVkZSA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubGF0aXR1ZGUgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWF4LmxvbmdpdHVkZSA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgIGxldCBsYXQsIGxvbjsKICAgIGlmIChjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRCkgewogICAgICBjb25zdCBmaXJzdCA9IGNsZWFuUG9zaXRpb25zWzBdOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoZmlyc3QsIGNsZWFuUG9zaXRpb25zWzFdLCBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0LCBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgc2NyYXRjaENhcnRlc2lhbk9mZnNldCwKICAgICAgICBoYWxmV2lkdGgsCiAgICAgICAgc2NyYXRjaENhcnRlc2lhbk9mZnNldAogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGZpcnN0LCBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0LCBzY3JhdGNoQ2FydGVzaWFuRW5kcyk7CiAgICAgIGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICBzY3JhdGNoQ2FydGVzaWFuRW5kcywKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljNAogICAgICApOwogICAgICBsYXQgPSBzY3JhdGNoQ2FydG9ncmFwaGljNC5sYXRpdHVkZTsKICAgICAgbG9uID0gc2NyYXRjaENhcnRvZ3JhcGhpYzQubG9uZ2l0dWRlOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWluLmxhdGl0dWRlID0gTWF0aC5taW4oCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbi5sYXRpdHVkZSwKICAgICAgICBsYXQKICAgICAgKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbi5sb25naXR1ZGUgPSBNYXRoLm1pbigKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWluLmxvbmdpdHVkZSwKICAgICAgICBsb24KICAgICAgKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01heC5sYXRpdHVkZSA9IE1hdGgubWF4KAogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubGF0aXR1ZGUsCiAgICAgICAgbGF0CiAgICAgICk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubG9uZ2l0dWRlID0gTWF0aC5tYXgoCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01heC5sb25naXR1ZGUsCiAgICAgICAgbG9uCiAgICAgICk7CiAgICB9CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoIC0gMTsgKytpMikgewogICAgICBjb21wdXRlT2Zmc2V0UG9pbnRzKAogICAgICAgIGNsZWFuUG9zaXRpb25zW2kyXSwKICAgICAgICBjbGVhblBvc2l0aW9uc1tpMiArIDFdLAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICBoYWxmV2lkdGgsCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbiwKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWF4CiAgICAgICk7CiAgICB9CiAgICBjb25zdCBsYXN0ID0gY2xlYW5Qb3NpdGlvbnNbbGVuZ3RoIC0gMV07CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobGFzdCwgY2xlYW5Qb3NpdGlvbnNbbGVuZ3RoIC0gMl0sIHNjcmF0Y2hDYXJ0ZXNpYW5PZmZzZXQpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0LCBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0KTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0LAogICAgICBoYWxmV2lkdGgsCiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW5PZmZzZXQKICAgICk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGxhc3QsIHNjcmF0Y2hDYXJ0ZXNpYW5PZmZzZXQsIHNjcmF0Y2hDYXJ0ZXNpYW5FbmRzKTsKICAgIGNvbXB1dGVPZmZzZXRQb2ludHMoCiAgICAgIGxhc3QsCiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW5FbmRzLAogICAgICBlbGxpcHNvaWQsCiAgICAgIGhhbGZXaWR0aCwKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbiwKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01heAogICAgKTsKICAgIGlmIChjb3JuZXJUeXBlID09PSBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRCkgewogICAgICBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgICAgc2NyYXRjaENhcnRlc2lhbkVuZHMsCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzQKICAgICAgKTsKICAgICAgbGF0ID0gc2NyYXRjaENhcnRvZ3JhcGhpYzQubGF0aXR1ZGU7CiAgICAgIGxvbiA9IHNjcmF0Y2hDYXJ0b2dyYXBoaWM0LmxvbmdpdHVkZTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbi5sYXRpdHVkZSA9IE1hdGgubWluKAogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNaW4ubGF0aXR1ZGUsCiAgICAgICAgbGF0CiAgICAgICk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNaW4ubG9uZ2l0dWRlID0gTWF0aC5taW4oCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY01pbi5sb25naXR1ZGUsCiAgICAgICAgbG9uCiAgICAgICk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubGF0aXR1ZGUgPSBNYXRoLm1heCgKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWF4LmxhdGl0dWRlLAogICAgICAgIGxhdAogICAgICApOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWF4LmxvbmdpdHVkZSA9IE1hdGgubWF4KAogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubG9uZ2l0dWRlLAogICAgICAgIGxvbgogICAgICApOwogICAgfQogICAgY29uc3QgcmVjdGFuZ2xlID0gZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkgPyByZXN1bHQgOiBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQoKTsKICAgIHJlY3RhbmdsZS5ub3J0aCA9IHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXgubGF0aXR1ZGU7CiAgICByZWN0YW5nbGUuc291dGggPSBzY3JhdGNoQ2FydG9ncmFwaGljTWluLmxhdGl0dWRlOwogICAgcmVjdGFuZ2xlLmVhc3QgPSBzY3JhdGNoQ2FydG9ncmFwaGljTWF4LmxvbmdpdHVkZTsKICAgIHJlY3RhbmdsZS53ZXN0ID0gc2NyYXRjaENhcnRvZ3JhcGhpY01pbi5sb25naXR1ZGU7CiAgICByZXR1cm4gcmVjdGFuZ2xlOwogIH0KICBmdW5jdGlvbiBDb3JyaWRvckdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IG9wdGlvbnMucG9zaXRpb25zOwogICAgY29uc3Qgd2lkdGggPSBvcHRpb25zLndpZHRoOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJvcHRpb25zLnBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9wdGlvbnMud2lkdGgiLCB3aWR0aCk7CiAgICBjb25zdCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodCA/PyAwOwogICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0ID8/IGhlaWdodDsKICAgIHRoaXMuX3Bvc2l0aW9ucyA9IHBvc2l0aW9uczsKICAgIHRoaXMuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKG9wdGlvbnMuZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQpOwogICAgdGhpcy5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUoCiAgICAgIG9wdGlvbnMudmVydGV4Rm9ybWF0ID8/IFZlcnRleEZvcm1hdF9kZWZhdWx0LkRFRkFVTFQKICAgICk7CiAgICB0aGlzLl93aWR0aCA9IHdpZHRoOwogICAgdGhpcy5faGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICB0aGlzLl9leHRydWRlZEhlaWdodCA9IE1hdGgubWluKGhlaWdodCwgZXh0cnVkZWRIZWlnaHQpOwogICAgdGhpcy5fY29ybmVyVHlwZSA9IG9wdGlvbnMuY29ybmVyVHlwZSA/PyBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRDsKICAgIHRoaXMuX2dyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgdGhpcy5fc2hhZG93Vm9sdW1lID0gb3B0aW9ucy5zaGFkb3dWb2x1bWUgPz8gZmFsc2U7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUNvcnJpZG9yR2VvbWV0cnkiOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl9yZWN0YW5nbGUgPSB2b2lkIDA7CiAgICB0aGlzLnBhY2tlZExlbmd0aCA9IDEgKyBwb3NpdGlvbnMubGVuZ3RoICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDc7CiAgfQogIHZhciBjYXJ0ZXNpYW4xMiwgY2FydGVzaWFuMjIsIGNhcnRlc2lhbjMyLCBjYXJ0ZXNpYW40MiwgY2FydGVzaWFuNTIsIGNhcnRlc2lhbjYyLCBzY3JhdGNoMTMsIHNjcmF0Y2gyMywgc2NyYXRjaENhcnRlc2lhbjE3LCBzY3JhdGNoQ2FydGVzaWFuMjcsIHNjcmF0Y2hDYXJ0b2dyYXBoaWM0LCBzY3JhdGNoQ2FydGVzaWFuT2Zmc2V0LCBzY3JhdGNoQ2FydGVzaWFuRW5kcywgc2NyYXRjaENhcnRvZ3JhcGhpY01pbiwgc2NyYXRjaENhcnRvZ3JhcGhpY01heCwgc2NyYXRjaEVsbGlwc29pZDQsIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ0LCBzY3JhdGNoT3B0aW9uczksIENvcnJpZG9yR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9Db3JyaWRvckdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Db3JyaWRvckdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9hcnJheVJlbW92ZUR1cGxpY2F0ZXMoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfQ29ybmVyVHlwZSgpOwogICAgICBpbml0X0NvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUG9seWdvblBpcGVsaW5lKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1ZlcnRleEZvcm1hdCgpOwogICAgICBjYXJ0ZXNpYW4xMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuMjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjMyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW40MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydGVzaWFuNTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjYyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoMTMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2gyMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjE3ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMjcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM0ID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW5PZmZzZXQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW5FbmRzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljTWluID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNNYXggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgQ29ycmlkb3JHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gdmFsdWUuX3Bvc2l0aW9uczsKICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhwb3NpdGlvbnNbaTJdLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIEVsbGlwc29pZF9kZWZhdWx0LnBhY2sodmFsdWUuX2VsbGlwc29pZCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2sodmFsdWUuX3ZlcnRleEZvcm1hdCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fd2lkdGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9oZWlnaHQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9leHRydWRlZEhlaWdodDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2Nvcm5lclR5cGU7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3NoYWRvd1ZvbHVtZSA/IDEgOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWUuX29mZnNldEF0dHJpYnV0ZSA/PyAtMTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQ0ID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoRWxsaXBzb2lkX2RlZmF1bHQuVU5JVF9TUEhFUkUpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0NCA9IG5ldyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczkgPSB7CiAgICAgICAgcG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkNCwKICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ0LAogICAgICAgIHdpZHRoOiB2b2lkIDAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IHZvaWQgMCwKICAgICAgICBjb3JuZXJUeXBlOiB2b2lkIDAsCiAgICAgICAgZ3JhbnVsYXJpdHk6IHZvaWQgMCwKICAgICAgICBzaGFkb3dWb2x1bWU6IHZvaWQgMCwKICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IHZvaWQgMAogICAgICB9OwogICAgICBDb3JyaWRvckdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIHBvc2l0aW9uc1tpMl0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4LCBzY3JhdGNoRWxsaXBzb2lkNCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDQKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IHdpZHRoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBoZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBjb3JuZXJUeXBlID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczkucG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnM5LndpZHRoID0gd2lkdGg7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczkuaGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnM5LmV4dHJ1ZGVkSGVpZ2h0ID0gZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczkuY29ybmVyVHlwZSA9IGNvcm5lclR5cGU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczkuZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zOS5zaGFkb3dWb2x1bWUgPSBzaGFkb3dWb2x1bWU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczkub2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIHJldHVybiBuZXcgQ29ycmlkb3JHZW9tZXRyeShzY3JhdGNoT3B0aW9uczkpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3Bvc2l0aW9ucyA9IHBvc2l0aW9uczsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCwgcmVzdWx0Ll9lbGxpcHNvaWQpOwogICAgICAgIHJlc3VsdC5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0LCByZXN1bHQuX3ZlcnRleEZvcm1hdCk7CiAgICAgICAgcmVzdWx0Ll93aWR0aCA9IHdpZHRoOwogICAgICAgIHJlc3VsdC5faGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgIHJlc3VsdC5fZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICByZXN1bHQuX2Nvcm5lclR5cGUgPSBjb3JuZXJUeXBlOwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXN1bHQuX3NoYWRvd1ZvbHVtZSA9IHNoYWRvd1ZvbHVtZTsKICAgICAgICByZXN1bHQuX29mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ29ycmlkb3JHZW9tZXRyeS5jb21wdXRlUmVjdGFuZ2xlID0gZnVuY3Rpb24ob3B0aW9ucywgcmVzdWx0KSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG9wdGlvbnMucG9zaXRpb25zOwogICAgICAgIGNvbnN0IHdpZHRoID0gb3B0aW9ucy53aWR0aDsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9wdGlvbnMucG9zaXRpb25zIiwgcG9zaXRpb25zKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9wdGlvbnMud2lkdGgiLCB3aWR0aCk7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCBjb3JuZXJUeXBlID0gb3B0aW9ucy5jb3JuZXJUeXBlID8/IENvcm5lclR5cGVfZGVmYXVsdC5ST1VOREVEOwogICAgICAgIHJldHVybiBjb21wdXRlUmVjdGFuZ2xlMihwb3NpdGlvbnMsIGVsbGlwc29pZCwgd2lkdGgsIGNvcm5lclR5cGUsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIENvcnJpZG9yR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihjb3JyaWRvckdlb21ldHJ5KSB7CiAgICAgICAgbGV0IHBvc2l0aW9ucyA9IGNvcnJpZG9yR2VvbWV0cnkuX3Bvc2l0aW9uczsKICAgICAgICBjb25zdCB3aWR0aCA9IGNvcnJpZG9yR2VvbWV0cnkuX3dpZHRoOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IGNvcnJpZG9yR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBwb3NpdGlvbnMgPSBzY2FsZVRvU3VyZmFjZTIocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IGNsZWFuUG9zaXRpb25zID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbgogICAgICAgICk7CiAgICAgICAgaWYgKGNsZWFuUG9zaXRpb25zLmxlbmd0aCA8IDIgfHwgd2lkdGggPD0gMCkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBjb25zdCBoZWlnaHQgPSBjb3JyaWRvckdlb21ldHJ5Ll9oZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBjb3JyaWRvckdlb21ldHJ5Ll9leHRydWRlZEhlaWdodDsKICAgICAgICBjb25zdCBleHRydWRlID0gIU1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAwLAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04yCiAgICAgICAgKTsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBjb3JyaWRvckdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgY29uc3QgcGFyYW1zID0gewogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgcG9zaXRpb25zOiBjbGVhblBvc2l0aW9ucywKICAgICAgICAgIHdpZHRoLAogICAgICAgICAgY29ybmVyVHlwZTogY29ycmlkb3JHZW9tZXRyeS5fY29ybmVyVHlwZSwKICAgICAgICAgIGdyYW51bGFyaXR5OiBjb3JyaWRvckdlb21ldHJ5Ll9ncmFudWxhcml0eSwKICAgICAgICAgIHNhdmVBdHRyaWJ1dGVzOiB0cnVlCiAgICAgICAgfTsKICAgICAgICBsZXQgYXR0cjsKICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgcGFyYW1zLmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHBhcmFtcy5leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgICAgcGFyYW1zLnNoYWRvd1ZvbHVtZSA9IGNvcnJpZG9yR2VvbWV0cnkuX3NoYWRvd1ZvbHVtZTsKICAgICAgICAgIHBhcmFtcy5vZmZzZXRBdHRyaWJ1dGUgPSBjb3JyaWRvckdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgICBhdHRyID0gY29tcHV0ZVBvc2l0aW9uc0V4dHJ1ZGVkKHBhcmFtcywgdmVydGV4Rm9ybWF0KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3QgY29tcHV0ZWRQb3NpdGlvbnMgPSBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMocGFyYW1zKTsKICAgICAgICAgIGF0dHIgPSBjb21iaW5lMihjb21wdXRlZFBvc2l0aW9ucywgdmVydGV4Rm9ybWF0LCBlbGxpcHNvaWQpOwogICAgICAgICAgYXR0ci5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgICAgICAgYXR0ci5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcywKICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICBlbGxpcHNvaWQKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvcnJpZG9yR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXRWYWx1ZSA9IGNvcnJpZG9yR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5OT05FID8gMCA6IDE7CiAgICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGF0dHIuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoOwogICAgICAgICAgICBjb25zdCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCAvIDMpLmZpbGwoYXBwbHlPZmZzZXRWYWx1ZSk7CiAgICAgICAgICAgIGF0dHIuYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IGF0dHIuYXR0cmlidXRlczsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICAzCiAgICAgICAgKTsKICAgICAgICBpZiAoIXZlcnRleEZvcm1hdC5wb3NpdGlvbikgewogICAgICAgICAgYXR0ci5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBhdHRyLmluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmUsCiAgICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IGNvcnJpZG9yR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBDb3JyaWRvckdlb21ldHJ5LmNyZWF0ZVNoYWRvd1ZvbHVtZSA9IGZ1bmN0aW9uKGNvcnJpZG9yR2VvbWV0cnksIG1pbkhlaWdodEZ1bmMsIG1heEhlaWdodEZ1bmMpIHsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGNvcnJpZG9yR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IGNvcnJpZG9yR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBtaW5IZWlnaHRGdW5jKGdyYW51bGFyaXR5LCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IG1heEhlaWdodCA9IG1heEhlaWdodEZ1bmMoZ3JhbnVsYXJpdHksIGVsbGlwc29pZCk7CiAgICAgICAgcmV0dXJuIG5ldyBDb3JyaWRvckdlb21ldHJ5KHsKICAgICAgICAgIHBvc2l0aW9uczogY29ycmlkb3JHZW9tZXRyeS5fcG9zaXRpb25zLAogICAgICAgICAgd2lkdGg6IGNvcnJpZG9yR2VvbWV0cnkuX3dpZHRoLAogICAgICAgICAgY29ybmVyVHlwZTogY29ycmlkb3JHZW9tZXRyeS5fY29ybmVyVHlwZSwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IG1pbkhlaWdodCwKICAgICAgICAgIGhlaWdodDogbWF4SGVpZ2h0LAogICAgICAgICAgdmVydGV4Rm9ybWF0OiBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5QT1NJVElPTl9PTkxZLAogICAgICAgICAgc2hhZG93Vm9sdW1lOiB0cnVlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENvcnJpZG9yR2VvbWV0cnkucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICByZWN0YW5nbGU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXMuX3JlY3RhbmdsZSkpIHsKICAgICAgICAgICAgICB0aGlzLl9yZWN0YW5nbGUgPSBjb21wdXRlUmVjdGFuZ2xlMigKICAgICAgICAgICAgICAgIHRoaXMuX3Bvc2l0aW9ucywKICAgICAgICAgICAgICAgIHRoaXMuX2VsbGlwc29pZCwKICAgICAgICAgICAgICAgIHRoaXMuX3dpZHRoLAogICAgICAgICAgICAgICAgdGhpcy5fY29ybmVyVHlwZQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3JlY3RhbmdsZTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEZvciByZW1hcHBpbmcgdGV4dHVyZSBjb29yZGluYXRlcyB3aGVuIHJlbmRlcmluZyBDb3JyaWRvckdlb21ldHJpZXMgYXMgR3JvdW5kUHJpbWl0aXZlcy4KICAgICAgICAgKgogICAgICAgICAqIENvcnJpZG9ycyBkb24ndCBzdXBwb3J0IHN0Um90YXRpb24sCiAgICAgICAgICogc28ganVzdCByZXR1cm4gdGhlIGNvcm5lcnMgb2YgdGhlIG9yaWdpbmFsIHN5c3RlbS4KICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIHRleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHM6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBbMCwgMCwgMCwgMSwgMSwgMF07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgQ29ycmlkb3JHZW9tZXRyeV9kZWZhdWx0ID0gQ29ycmlkb3JHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUNvcnJpZG9yR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlQ29ycmlkb3JHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQ29ycmlkb3JHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVDb3JyaWRvckdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVDb3JyaWRvckdlb21ldHJ5KGNvcnJpZG9yR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGNvcnJpZG9yR2VvbWV0cnkgPSBDb3JyaWRvckdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGNvcnJpZG9yR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICBjb3JyaWRvckdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShjb3JyaWRvckdlb21ldHJ5Ll9lbGxpcHNvaWQpOwogICAgcmV0dXJuIENvcnJpZG9yR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShjb3JyaWRvckdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUNvcnJpZG9yR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVDb3JyaWRvckdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVDb3JyaWRvckdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Db3JyaWRvckdlb21ldHJ5KCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBjcmVhdGVDb3JyaWRvckdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVDb3JyaWRvckdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBzY2FsZVRvU3VyZmFjZTMocG9zaXRpb25zLCBlbGxpcHNvaWQpIHsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnMubGVuZ3RoOyBpMisrKSB7CiAgICAgIHBvc2l0aW9uc1tpMl0gPSBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwb3NpdGlvbnNbaTJdLCBwb3NpdGlvbnNbaTJdKTsKICAgIH0KICAgIHJldHVybiBwb3NpdGlvbnM7CiAgfQogIGZ1bmN0aW9uIGNvbWJpbmUzKGNvbXB1dGVkUG9zaXRpb25zLCBjb3JuZXJUeXBlKSB7CiAgICBjb25zdCB3YWxsSW5kaWNlcyA9IFtdOwogICAgY29uc3QgcG9zaXRpb25zID0gY29tcHV0ZWRQb3NpdGlvbnMucG9zaXRpb25zOwogICAgY29uc3QgY29ybmVycyA9IGNvbXB1dGVkUG9zaXRpb25zLmNvcm5lcnM7CiAgICBjb25zdCBlbmRQb3NpdGlvbnMgPSBjb21wdXRlZFBvc2l0aW9ucy5lbmRQb3NpdGlvbnM7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICBsZXQgY29ybmVyOwogICAgbGV0IGxlZnRDb3VudCA9IDA7CiAgICBsZXQgcmlnaHRDb3VudCA9IDA7CiAgICBsZXQgaTI7CiAgICBsZXQgaW5kaWNlc0xlbmd0aCA9IDA7CiAgICBsZXQgbGVuZ3RoOwogICAgZm9yIChpMiA9IDA7IGkyIDwgcG9zaXRpb25zLmxlbmd0aDsgaTIgKz0gMikgewogICAgICBsZW5ndGggPSBwb3NpdGlvbnNbaTJdLmxlbmd0aCAtIDM7CiAgICAgIGxlZnRDb3VudCArPSBsZW5ndGg7CiAgICAgIGluZGljZXNMZW5ndGggKz0gbGVuZ3RoIC8gMyAqIDQ7CiAgICAgIHJpZ2h0Q291bnQgKz0gcG9zaXRpb25zW2kyICsgMV0ubGVuZ3RoIC0gMzsKICAgIH0KICAgIGxlZnRDb3VudCArPSAzOwogICAgcmlnaHRDb3VudCArPSAzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgY29ybmVycy5sZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgbGVmdFNpZGUgPSBjb3JuZXJzW2kyXS5sZWZ0UG9zaXRpb25zOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGxlZnRTaWRlKSkgewogICAgICAgIGxlbmd0aCA9IGxlZnRTaWRlLmxlbmd0aDsKICAgICAgICBsZWZ0Q291bnQgKz0gbGVuZ3RoOwogICAgICAgIGluZGljZXNMZW5ndGggKz0gbGVuZ3RoIC8gMyAqIDI7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgbGVuZ3RoID0gY29ybmVyc1tpMl0ucmlnaHRQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIHJpZ2h0Q291bnQgKz0gbGVuZ3RoOwogICAgICAgIGluZGljZXNMZW5ndGggKz0gbGVuZ3RoIC8gMyAqIDI7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IGFkZEVuZFBvc2l0aW9ucyA9IGRlZmluZWRfZGVmYXVsdChlbmRQb3NpdGlvbnMpOwogICAgbGV0IGVuZFBvc2l0aW9uTGVuZ3RoOwogICAgaWYgKGFkZEVuZFBvc2l0aW9ucykgewogICAgICBlbmRQb3NpdGlvbkxlbmd0aCA9IGVuZFBvc2l0aW9uc1swXS5sZW5ndGggLSAzOwogICAgICBsZWZ0Q291bnQgKz0gZW5kUG9zaXRpb25MZW5ndGg7CiAgICAgIHJpZ2h0Q291bnQgKz0gZW5kUG9zaXRpb25MZW5ndGg7CiAgICAgIGVuZFBvc2l0aW9uTGVuZ3RoIC89IDM7CiAgICAgIGluZGljZXNMZW5ndGggKz0gZW5kUG9zaXRpb25MZW5ndGggKiA0OwogICAgfQogICAgY29uc3Qgc2l6ZSA9IGxlZnRDb3VudCArIHJpZ2h0Q291bnQ7CiAgICBjb25zdCBmaW5hbFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoc2l6ZSk7CiAgICBsZXQgZnJvbnQgPSAwOwogICAgbGV0IGJhY2sgPSBzaXplIC0gMTsKICAgIGxldCBVTCwgTEwsIFVSLCBMUjsKICAgIGxldCByaWdodFBvcywgbGVmdFBvczsKICAgIGNvbnN0IGhhbGZMZW5ndGggPSBlbmRQb3NpdGlvbkxlbmd0aCAvIDI7CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoc2l6ZSAvIDMsIGluZGljZXNMZW5ndGggKyA0KTsKICAgIGxldCBpbmRleCA9IDA7CiAgICBpbmRpY2VzW2luZGV4KytdID0gZnJvbnQgLyAzOwogICAgaW5kaWNlc1tpbmRleCsrXSA9IChiYWNrIC0gMikgLyAzOwogICAgaWYgKGFkZEVuZFBvc2l0aW9ucykgewogICAgICB3YWxsSW5kaWNlcy5wdXNoKGZyb250IC8gMyk7CiAgICAgIGxlZnRQb3MgPSBjYXJ0ZXNpYW4xMzsKICAgICAgcmlnaHRQb3MgPSBjYXJ0ZXNpYW4yMzsKICAgICAgY29uc3QgZmlyc3RFbmRQb3NpdGlvbnMgPSBlbmRQb3NpdGlvbnNbMF07CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGhhbGZMZW5ndGg7IGkyKyspIHsKICAgICAgICBsZWZ0UG9zID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGZpcnN0RW5kUG9zaXRpb25zLAogICAgICAgICAgKGhhbGZMZW5ndGggLSAxIC0gaTIpICogMywKICAgICAgICAgIGxlZnRQb3MKICAgICAgICApOwogICAgICAgIHJpZ2h0UG9zID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGZpcnN0RW5kUG9zaXRpb25zLAogICAgICAgICAgKGhhbGZMZW5ndGggKyBpMikgKiAzLAogICAgICAgICAgcmlnaHRQb3MKICAgICAgICApOwogICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKGZpbmFsUG9zaXRpb25zLCByaWdodFBvcywgZnJvbnQpOwogICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICBsZWZ0UG9zLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgYmFjawogICAgICAgICk7CiAgICAgICAgTEwgPSBmcm9udCAvIDM7CiAgICAgICAgTFIgPSBMTCArIDE7CiAgICAgICAgVUwgPSAoYmFjayAtIDIpIC8gMzsKICAgICAgICBVUiA9IFVMIC0gMTsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVUw7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IFVSOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gTFI7CiAgICAgICAgZnJvbnQgKz0gMzsKICAgICAgICBiYWNrIC09IDM7CiAgICAgIH0KICAgIH0KICAgIGxldCBwb3NJbmRleCA9IDA7CiAgICBsZXQgcmlnaHRFZGdlID0gcG9zaXRpb25zW3Bvc0luZGV4KytdOwogICAgbGV0IGxlZnRFZGdlID0gcG9zaXRpb25zW3Bvc0luZGV4KytdOwogICAgZmluYWxQb3NpdGlvbnMuc2V0KHJpZ2h0RWRnZSwgZnJvbnQpOwogICAgZmluYWxQb3NpdGlvbnMuc2V0KGxlZnRFZGdlLCBiYWNrIC0gbGVmdEVkZ2UubGVuZ3RoICsgMSk7CiAgICBsZW5ndGggPSBsZWZ0RWRnZS5sZW5ndGggLSAzOwogICAgd2FsbEluZGljZXMucHVzaChmcm9udCAvIDMsIChiYWNrIC0gMikgLyAzKTsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICBMTCA9IGZyb250IC8gMzsKICAgICAgTFIgPSBMTCArIDE7CiAgICAgIFVMID0gKGJhY2sgLSAyKSAvIDM7CiAgICAgIFVSID0gVUwgLSAxOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gVUw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVUjsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gTFI7CiAgICAgIGZyb250ICs9IDM7CiAgICAgIGJhY2sgLT0gMzsKICAgIH0KICAgIGZvciAoaTIgPSAwOyBpMiA8IGNvcm5lcnMubGVuZ3RoOyBpMisrKSB7CiAgICAgIGxldCBqMjsKICAgICAgY29ybmVyID0gY29ybmVyc1tpMl07CiAgICAgIGNvbnN0IGwyID0gY29ybmVyLmxlZnRQb3NpdGlvbnM7CiAgICAgIGNvbnN0IHIyID0gY29ybmVyLnJpZ2h0UG9zaXRpb25zOwogICAgICBsZXQgc3RhcnQ7CiAgICAgIGxldCBvdXRzaWRlUG9pbnQgPSBjYXJ0ZXNpYW4zMzsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChsMikpIHsKICAgICAgICBiYWNrIC09IDM7CiAgICAgICAgc3RhcnQgPSBVUjsKICAgICAgICB3YWxsSW5kaWNlcy5wdXNoKExSKTsKICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBsMi5sZW5ndGggLyAzOyBqMisrKSB7CiAgICAgICAgICBvdXRzaWRlUG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KGwyLCBqMiAqIDMsIG91dHNpZGVQb2ludCk7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gc3RhcnQgLSBqMiAtIDE7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gc3RhcnQgLSBqMjsKICAgICAgICAgIENvcnJpZG9yR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuYWRkQXR0cmlidXRlKAogICAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgICAgb3V0c2lkZVBvaW50LAogICAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICAgIGJhY2sKICAgICAgICAgICk7CiAgICAgICAgICBiYWNrIC09IDM7CiAgICAgICAgfQogICAgICAgIHdhbGxJbmRpY2VzLnB1c2goc3RhcnQgLSBNYXRoLmZsb29yKGwyLmxlbmd0aCAvIDYpKTsKICAgICAgICBpZiAoY29ybmVyVHlwZSA9PT0gQ29ybmVyVHlwZV9kZWZhdWx0LkJFVkVMRUQpIHsKICAgICAgICAgIHdhbGxJbmRpY2VzLnB1c2goKGJhY2sgLSAyKSAvIDMgKyAxKTsKICAgICAgICB9CiAgICAgICAgZnJvbnQgKz0gMzsKICAgICAgfSBlbHNlIHsKICAgICAgICBmcm9udCArPSAzOwogICAgICAgIHN0YXJ0ID0gTFI7CiAgICAgICAgd2FsbEluZGljZXMucHVzaChVUik7CiAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgcjIubGVuZ3RoIC8gMzsgajIrKykgewogICAgICAgICAgb3V0c2lkZVBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShyMiwgajIgKiAzLCBvdXRzaWRlUG9pbnQpOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHN0YXJ0ICsgajI7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gc3RhcnQgKyBqMiArIDE7CiAgICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZSgKICAgICAgICAgICAgZmluYWxQb3NpdGlvbnMsCiAgICAgICAgICAgIG91dHNpZGVQb2ludCwKICAgICAgICAgICAgZnJvbnQKICAgICAgICAgICk7CiAgICAgICAgICBmcm9udCArPSAzOwogICAgICAgIH0KICAgICAgICB3YWxsSW5kaWNlcy5wdXNoKHN0YXJ0ICsgTWF0aC5mbG9vcihyMi5sZW5ndGggLyA2KSk7CiAgICAgICAgaWYgKGNvcm5lclR5cGUgPT09IENvcm5lclR5cGVfZGVmYXVsdC5CRVZFTEVEKSB7CiAgICAgICAgICB3YWxsSW5kaWNlcy5wdXNoKGZyb250IC8gMyAtIDEpOwogICAgICAgIH0KICAgICAgICBiYWNrIC09IDM7CiAgICAgIH0KICAgICAgcmlnaHRFZGdlID0gcG9zaXRpb25zW3Bvc0luZGV4KytdOwogICAgICBsZWZ0RWRnZSA9IHBvc2l0aW9uc1twb3NJbmRleCsrXTsKICAgICAgcmlnaHRFZGdlLnNwbGljZSgwLCAzKTsKICAgICAgbGVmdEVkZ2Uuc3BsaWNlKGxlZnRFZGdlLmxlbmd0aCAtIDMsIDMpOwogICAgICBmaW5hbFBvc2l0aW9ucy5zZXQocmlnaHRFZGdlLCBmcm9udCk7CiAgICAgIGZpbmFsUG9zaXRpb25zLnNldChsZWZ0RWRnZSwgYmFjayAtIGxlZnRFZGdlLmxlbmd0aCArIDEpOwogICAgICBmb3IgKGoyID0gMDsgajIgPCBsZWZ0RWRnZS5sZW5ndGg7IGoyICs9IDMpIHsKICAgICAgICBMUiA9IGZyb250IC8gMzsKICAgICAgICBMTCA9IExSIC0gMTsKICAgICAgICBVUiA9IChiYWNrIC0gMikgLyAzOwogICAgICAgIFVMID0gVVIgKyAxOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVVI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMUjsKICAgICAgICBmcm9udCArPSAzOwogICAgICAgIGJhY2sgLT0gMzsKICAgICAgfQogICAgICBmcm9udCAtPSAzOwogICAgICBiYWNrICs9IDM7CiAgICAgIHdhbGxJbmRpY2VzLnB1c2goZnJvbnQgLyAzLCAoYmFjayAtIDIpIC8gMyk7CiAgICB9CiAgICBpZiAoYWRkRW5kUG9zaXRpb25zKSB7CiAgICAgIGZyb250ICs9IDM7CiAgICAgIGJhY2sgLT0gMzsKICAgICAgbGVmdFBvcyA9IGNhcnRlc2lhbjEzOwogICAgICByaWdodFBvcyA9IGNhcnRlc2lhbjIzOwogICAgICBjb25zdCBsYXN0RW5kUG9zaXRpb25zID0gZW5kUG9zaXRpb25zWzFdOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBoYWxmTGVuZ3RoOyBpMisrKSB7CiAgICAgICAgbGVmdFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICBsYXN0RW5kUG9zaXRpb25zLAogICAgICAgICAgKGVuZFBvc2l0aW9uTGVuZ3RoIC0gaTIgLSAxKSAqIDMsCiAgICAgICAgICBsZWZ0UG9zCiAgICAgICAgKTsKICAgICAgICByaWdodFBvcyA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkobGFzdEVuZFBvc2l0aW9ucywgaTIgKiAzLCByaWdodFBvcyk7CiAgICAgICAgQ29ycmlkb3JHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5hZGRBdHRyaWJ1dGUoCiAgICAgICAgICBmaW5hbFBvc2l0aW9ucywKICAgICAgICAgIGxlZnRQb3MsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICBiYWNrCiAgICAgICAgKTsKICAgICAgICBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmFkZEF0dHJpYnV0ZShmaW5hbFBvc2l0aW9ucywgcmlnaHRQb3MsIGZyb250KTsKICAgICAgICBMUiA9IGZyb250IC8gMzsKICAgICAgICBMTCA9IExSIC0gMTsKICAgICAgICBVUiA9IChiYWNrIC0gMikgLyAzOwogICAgICAgIFVMID0gVVIgKyAxOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBVTDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gVVI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBMUjsKICAgICAgICBmcm9udCArPSAzOwogICAgICAgIGJhY2sgLT0gMzsKICAgICAgfQogICAgICB3YWxsSW5kaWNlcy5wdXNoKGZyb250IC8gMyk7CiAgICB9IGVsc2UgewogICAgICB3YWxsSW5kaWNlcy5wdXNoKGZyb250IC8gMywgKGJhY2sgLSAyKSAvIDMpOwogICAgfQogICAgaW5kaWNlc1tpbmRleCsrXSA9IGZyb250IC8gMzsKICAgIGluZGljZXNbaW5kZXhdID0gKGJhY2sgLSAyKSAvIDM7CiAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgIHZhbHVlczogZmluYWxQb3NpdGlvbnMKICAgIH0pOwogICAgcmV0dXJuIHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlcywKICAgICAgd2FsbEluZGljZXMKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVQb3NpdGlvbnNFeHRydWRlZDIocGFyYW1zKSB7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBwYXJhbXMuZWxsaXBzb2lkOwogICAgY29uc3QgY29tcHV0ZWRQb3NpdGlvbnMgPSBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMocGFyYW1zKTsKICAgIGNvbnN0IGF0dHIgPSBjb21iaW5lMyhjb21wdXRlZFBvc2l0aW9ucywgcGFyYW1zLmNvcm5lclR5cGUpOwogICAgY29uc3Qgd2FsbEluZGljZXMgPSBhdHRyLndhbGxJbmRpY2VzOwogICAgY29uc3QgaGVpZ2h0ID0gcGFyYW1zLmhlaWdodDsKICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gcGFyYW1zLmV4dHJ1ZGVkSGVpZ2h0OwogICAgY29uc3QgYXR0cmlidXRlcyA9IGF0dHIuYXR0cmlidXRlczsKICAgIGNvbnN0IGluZGljZXMgPSBhdHRyLmluZGljZXM7CiAgICBsZXQgcG9zaXRpb25zID0gYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXM7CiAgICBsZXQgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgIGxldCBleHRydWRlZFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkobGVuZ3RoKTsKICAgIGV4dHJ1ZGVkUG9zaXRpb25zLnNldChwb3NpdGlvbnMpOwogICAgY29uc3QgbmV3UG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGggKiAyKTsKICAgIHBvc2l0aW9ucyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgcG9zaXRpb25zLAogICAgICBoZWlnaHQsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIGV4dHJ1ZGVkUG9zaXRpb25zID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICBleHRydWRlZFBvc2l0aW9ucywKICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIG5ld1Bvc2l0aW9ucy5zZXQocG9zaXRpb25zKTsKICAgIG5ld1Bvc2l0aW9ucy5zZXQoZXh0cnVkZWRQb3NpdGlvbnMsIGxlbmd0aCk7CiAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IG5ld1Bvc2l0aW9uczsKICAgIGxlbmd0aCAvPSAzOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChwYXJhbXMub2Zmc2V0QXR0cmlidXRlKSkgewogICAgICBsZXQgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggKiAyKTsKICAgICAgaWYgKHBhcmFtcy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuVE9QKSB7CiAgICAgICAgYXBwbHlPZmZzZXQgPSBhcHBseU9mZnNldC5maWxsKDEsIDAsIGxlbmd0aCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29uc3QgYXBwbHlPZmZzZXRWYWx1ZSA9IHBhcmFtcy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgIGFwcGx5T2Zmc2V0ID0gYXBwbHlPZmZzZXQuZmlsbChhcHBseU9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgIH0pOwogICAgfQogICAgbGV0IGkyOwogICAgY29uc3QgaUxlbmd0aCA9IGluZGljZXMubGVuZ3RoOwogICAgY29uc3QgbmV3SW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBuZXdQb3NpdGlvbnMubGVuZ3RoIC8gMywKICAgICAgKGlMZW5ndGggKyB3YWxsSW5kaWNlcy5sZW5ndGgpICogMgogICAgKTsKICAgIG5ld0luZGljZXMuc2V0KGluZGljZXMpOwogICAgbGV0IGluZGV4ID0gaUxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGlMZW5ndGg7IGkyICs9IDIpIHsKICAgICAgY29uc3QgdjAyID0gaW5kaWNlc1tpMl07CiAgICAgIGNvbnN0IHYxMiA9IGluZGljZXNbaTIgKyAxXTsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IHYwMiArIGxlbmd0aDsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IHYxMiArIGxlbmd0aDsKICAgIH0KICAgIGxldCBVTCwgTEw7CiAgICBmb3IgKGkyID0gMDsgaTIgPCB3YWxsSW5kaWNlcy5sZW5ndGg7IGkyKyspIHsKICAgICAgVUwgPSB3YWxsSW5kaWNlc1tpMl07CiAgICAgIExMID0gVUwgKyBsZW5ndGg7CiAgICAgIG5ld0luZGljZXNbaW5kZXgrK10gPSBVTDsKICAgICAgbmV3SW5kaWNlc1tpbmRleCsrXSA9IExMOwogICAgfQogICAgcmV0dXJuIHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlczogbmV3SW5kaWNlcwogICAgfTsKICB9CiAgZnVuY3Rpb24gQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICBjb25zdCB3aWR0aCA9IG9wdGlvbnMud2lkdGg7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMucG9zaXRpb25zIiwgcG9zaXRpb25zKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigib3B0aW9ucy53aWR0aCIsIHdpZHRoKTsKICAgIGNvbnN0IGhlaWdodCA9IG9wdGlvbnMuaGVpZ2h0ID8/IDA7CiAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQgPz8gaGVpZ2h0OwogICAgdGhpcy5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCk7CiAgICB0aGlzLl93aWR0aCA9IHdpZHRoOwogICAgdGhpcy5faGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICB0aGlzLl9leHRydWRlZEhlaWdodCA9IE1hdGgubWluKGhlaWdodCwgZXh0cnVkZWRIZWlnaHQpOwogICAgdGhpcy5fY29ybmVyVHlwZSA9IG9wdGlvbnMuY29ybmVyVHlwZSA/PyBDb3JuZXJUeXBlX2RlZmF1bHQuUk9VTkRFRDsKICAgIHRoaXMuX2dyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5IjsKICAgIHRoaXMucGFja2VkTGVuZ3RoID0gMSArIHBvc2l0aW9ucy5sZW5ndGggKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgNjsKICB9CiAgdmFyIGNhcnRlc2lhbjEzLCBjYXJ0ZXNpYW4yMywgY2FydGVzaWFuMzMsIHNjcmF0Y2hFbGxpcHNvaWQ1LCBzY3JhdGNoT3B0aW9uczEwLCBDb3JyaWRvck91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X0NvcnJpZG9yT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Db3JyaWRvck91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfYXJyYXlSZW1vdmVEdXBsaWNhdGVzKCk7CiAgICAgIGluaXRfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Nvcm5lclR5cGUoKTsKICAgICAgaW5pdF9Db3JyaWRvckdlb21ldHJ5TGlicmFyeSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1BvbHlnb25QaXBlbGluZSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgY2FydGVzaWFuMTMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjIzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4zMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHZhbHVlLl9wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gbGVuZ3RoOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2socG9zaXRpb25zW2kyXSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3dpZHRoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5faGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9jb3JuZXJUeXBlOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDUgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShFbGxpcHNvaWRfZGVmYXVsdC5VTklUX1NQSEVSRSk7CiAgICAgIHNjcmF0Y2hPcHRpb25zMTAgPSB7CiAgICAgICAgcG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkNSwKICAgICAgICB3aWR0aDogdm9pZCAwLAogICAgICAgIGhlaWdodDogdm9pZCAwLAogICAgICAgIGV4dHJ1ZGVkSGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgY29ybmVyVHlwZTogdm9pZCAwLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAsCiAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiB2b2lkIDAKICAgICAgfTsKICAgICAgQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgcG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQ1KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCB3aWR0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgY29ybmVyVHlwZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG9mZnNldEF0dHJpYnV0ZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTAucG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMC53aWR0aCA9IHdpZHRoOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMC5oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEwLmV4dHJ1ZGVkSGVpZ2h0ID0gZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEwLmNvcm5lclR5cGUgPSBjb3JuZXJUeXBlOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMC5ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMC5vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgcmV0dXJuIG5ldyBDb3JyaWRvck91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczEwKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNvaWQsIHJlc3VsdC5fZWxsaXBzb2lkKTsKICAgICAgICByZXN1bHQuX3dpZHRoID0gd2lkdGg7CiAgICAgICAgcmVzdWx0Ll9oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIHJlc3VsdC5fY29ybmVyVHlwZSA9IGNvcm5lclR5cGU7CiAgICAgICAgcmVzdWx0Ll9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgIHJlc3VsdC5fb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBDb3JyaWRvck91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5KSB7CiAgICAgICAgbGV0IHBvc2l0aW9ucyA9IGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5Ll9wb3NpdGlvbnM7CiAgICAgICAgY29uc3Qgd2lkdGggPSBjb3JyaWRvck91dGxpbmVHZW9tZXRyeS5fd2lkdGg7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gY29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBwb3NpdGlvbnMgPSBzY2FsZVRvU3VyZmFjZTMocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IGNsZWFuUG9zaXRpb25zID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbgogICAgICAgICk7CiAgICAgICAgaWYgKGNsZWFuUG9zaXRpb25zLmxlbmd0aCA8IDIgfHwgd2lkdGggPD0gMCkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBjb25zdCBoZWlnaHQgPSBjb3JyaWRvck91dGxpbmVHZW9tZXRyeS5faGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gY29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGUgPSAhTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICBleHRydWRlZEhlaWdodCwKICAgICAgICAgIDAsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjIKICAgICAgICApOwogICAgICAgIGNvbnN0IHBhcmFtcyA9IHsKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHBvc2l0aW9uczogY2xlYW5Qb3NpdGlvbnMsCiAgICAgICAgICB3aWR0aCwKICAgICAgICAgIGNvcm5lclR5cGU6IGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5Ll9jb3JuZXJUeXBlLAogICAgICAgICAgZ3JhbnVsYXJpdHk6IGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5Ll9ncmFudWxhcml0eSwKICAgICAgICAgIHNhdmVBdHRyaWJ1dGVzOiBmYWxzZQogICAgICAgIH07CiAgICAgICAgbGV0IGF0dHI7CiAgICAgICAgaWYgKGV4dHJ1ZGUpIHsKICAgICAgICAgIHBhcmFtcy5oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgICBwYXJhbXMuZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICAgIHBhcmFtcy5vZmZzZXRBdHRyaWJ1dGUgPSBjb3JyaWRvck91dGxpbmVHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgYXR0ciA9IGNvbXB1dGVQb3NpdGlvbnNFeHRydWRlZDIocGFyYW1zKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3QgY29tcHV0ZWRQb3NpdGlvbnMgPSBDb3JyaWRvckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMocGFyYW1zKTsKICAgICAgICAgIGF0dHIgPSBjb21iaW5lMyhjb21wdXRlZFBvc2l0aW9ucywgcGFyYW1zLmNvcm5lclR5cGUpOwogICAgICAgICAgYXR0ci5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgICAgICAgYXR0ci5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcywKICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICBlbGxpcHNvaWQKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGF0dHIuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoOwogICAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgICBjb25zdCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCAvIDMpLmZpbGwob2Zmc2V0VmFsdWUpOwogICAgICAgICAgICBhdHRyLmF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAxLAogICAgICAgICAgICAgIHZhbHVlczogYXBwbHlPZmZzZXQKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBhdHRyLmF0dHJpYnV0ZXM7CiAgICAgICAgY29uc3QgYm91bmRpbmdTcGhlcmUgPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcygKICAgICAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgMwogICAgICAgICk7CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBhdHRyLmluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogY29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBDb3JyaWRvck91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVDb3JyaWRvck91dGxpbmVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVDb3JyaWRvck91dGxpbmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5KGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBjb3JyaWRvck91dGxpbmVHZW9tZXRyeSA9IENvcnJpZG9yT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgIGNvcnJpZG9yT3V0bGluZUdlb21ldHJ5LAogICAgICAgIG9mZnNldAogICAgICApOwogICAgfQogICAgY29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKAogICAgICBjb3JyaWRvck91dGxpbmVHZW9tZXRyeS5fZWxsaXBzb2lkCiAgICApOwogICAgcmV0dXJuIENvcnJpZG9yT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoY29ycmlkb3JPdXRsaW5lR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVDb3JyaWRvck91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0NvcnJpZG9yT3V0bGluZUdlb21ldHJ5KCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBjcmVhdGVDb3JyaWRvck91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DeWxpbmRlckdlb21ldHJ5TGlicmFyeS5qcwogIHZhciBDeWxpbmRlckdlb21ldHJ5TGlicmFyeSwgQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdDsKICB2YXIgaW5pdF9DeWxpbmRlckdlb21ldHJ5TGlicmFyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnkuanMiKCkgewogICAgICBpbml0X01hdGgoKTsKICAgICAgQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnkgPSB7fTsKICAgICAgQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnkuY29tcHV0ZVBvc2l0aW9ucyA9IGZ1bmN0aW9uKGxlbmd0aCwgdG9wUmFkaXVzLCBib3R0b21SYWRpdXMsIHNsaWNlcywgZmlsbCkgewogICAgICAgIGNvbnN0IHRvcFogPSBsZW5ndGggKiAwLjU7CiAgICAgICAgY29uc3QgYm90dG9tWiA9IC10b3BaOwogICAgICAgIGNvbnN0IHR3b1NsaWNlID0gc2xpY2VzICsgc2xpY2VzOwogICAgICAgIGNvbnN0IHNpemUgPSBmaWxsID8gMiAqIHR3b1NsaWNlIDogdHdvU2xpY2U7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShzaXplICogMyk7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgbGV0IHRiSW5kZXggPSAwOwogICAgICAgIGNvbnN0IGJvdHRvbU9mZnNldCA9IGZpbGwgPyB0d29TbGljZSAqIDMgOiAwOwogICAgICAgIGNvbnN0IHRvcE9mZnNldCA9IGZpbGwgPyAodHdvU2xpY2UgKyBzbGljZXMpICogMyA6IHNsaWNlcyAqIDM7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc2xpY2VzOyBpMisrKSB7CiAgICAgICAgICBjb25zdCBhbmdsZSA9IGkyIC8gc2xpY2VzICogTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgICAgICAgIGNvbnN0IHgyID0gTWF0aC5jb3MoYW5nbGUpOwogICAgICAgICAgY29uc3QgeTIgPSBNYXRoLnNpbihhbmdsZSk7CiAgICAgICAgICBjb25zdCBib3R0b21YID0geDIgKiBib3R0b21SYWRpdXM7CiAgICAgICAgICBjb25zdCBib3R0b21ZID0geTIgKiBib3R0b21SYWRpdXM7CiAgICAgICAgICBjb25zdCB0b3BYID0geDIgKiB0b3BSYWRpdXM7CiAgICAgICAgICBjb25zdCB0b3BZID0geTIgKiB0b3BSYWRpdXM7CiAgICAgICAgICBwb3NpdGlvbnNbdGJJbmRleCArIGJvdHRvbU9mZnNldF0gPSBib3R0b21YOwogICAgICAgICAgcG9zaXRpb25zW3RiSW5kZXggKyBib3R0b21PZmZzZXQgKyAxXSA9IGJvdHRvbVk7CiAgICAgICAgICBwb3NpdGlvbnNbdGJJbmRleCArIGJvdHRvbU9mZnNldCArIDJdID0gYm90dG9tWjsKICAgICAgICAgIHBvc2l0aW9uc1t0YkluZGV4ICsgdG9wT2Zmc2V0XSA9IHRvcFg7CiAgICAgICAgICBwb3NpdGlvbnNbdGJJbmRleCArIHRvcE9mZnNldCArIDFdID0gdG9wWTsKICAgICAgICAgIHBvc2l0aW9uc1t0YkluZGV4ICsgdG9wT2Zmc2V0ICsgMl0gPSB0b3BaOwogICAgICAgICAgdGJJbmRleCArPSAzOwogICAgICAgICAgaWYgKGZpbGwpIHsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gYm90dG9tWDsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gYm90dG9tWTsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gYm90dG9tWjsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gdG9wWDsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gdG9wWTsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gdG9wWjsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBvc2l0aW9uczsKICAgICAgfTsKICAgICAgQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdCA9IEN5bGluZGVyR2VvbWV0cnlMaWJyYXJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ3lsaW5kZXJHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEN5bGluZGVyR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgbGVuZ3RoID0gb3B0aW9ucy5sZW5ndGg7CiAgICBjb25zdCB0b3BSYWRpdXMgPSBvcHRpb25zLnRvcFJhZGl1czsKICAgIGNvbnN0IGJvdHRvbVJhZGl1cyA9IG9wdGlvbnMuYm90dG9tUmFkaXVzOwogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIGNvbnN0IHNsaWNlcyA9IG9wdGlvbnMuc2xpY2VzID8/IDEyODsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGxlbmd0aCkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMubGVuZ3RoIG11c3QgYmUgZGVmaW5lZC4iKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRvcFJhZGl1cykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMudG9wUmFkaXVzIG11c3QgYmUgZGVmaW5lZC4iKTsKICAgIH0KICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJvdHRvbVJhZGl1cykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMuYm90dG9tUmFkaXVzIG11c3QgYmUgZGVmaW5lZC4iKTsKICAgIH0KICAgIGlmIChzbGljZXMgPCAzKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnNsaWNlcyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAzLiIKICAgICAgKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpICYmIG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUuVE9QIGlzIG5vdCBhIHN1cHBvcnRlZCBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSBmb3IgdGhpcyBnZW9tZXRyeS4iCiAgICAgICk7CiAgICB9CiAgICB0aGlzLl9sZW5ndGggPSBsZW5ndGg7CiAgICB0aGlzLl90b3BSYWRpdXMgPSB0b3BSYWRpdXM7CiAgICB0aGlzLl9ib3R0b21SYWRpdXMgPSBib3R0b21SYWRpdXM7CiAgICB0aGlzLl92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQpOwogICAgdGhpcy5fc2xpY2VzID0gc2xpY2VzOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUN5bGluZGVyR2VvbWV0cnkiOwogIH0KICB2YXIgcmFkaXVzU2NyYXRjaCwgbm9ybWFsU2NyYXRjaDMsIGJpdGFuZ2VudFNjcmF0Y2gsIHRhbmdlbnRTY3JhdGNoLCBwb3NpdGlvblNjcmF0Y2gsIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ1LCBzY3JhdGNoT3B0aW9uczExLCB1bml0Q3lsaW5kZXJHZW9tZXRyeSwgQ3lsaW5kZXJHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X0N5bGluZGVyR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0N5bGluZGVyR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0N5bGluZGVyR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIHJhZGl1c1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIG5vcm1hbFNjcmF0Y2gzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBiaXRhbmdlbnRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0YW5nZW50U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcG9zaXRpb25TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBDeWxpbmRlckdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDU7CiAgICAgIEN5bGluZGVyR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFjayh2YWx1ZS5fdmVydGV4Rm9ybWF0LCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl90b3BSYWRpdXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9ib3R0b21SYWRpdXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zbGljZXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDUgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE9wdGlvbnMxMSA9IHsKICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ1LAogICAgICAgIGxlbmd0aDogdm9pZCAwLAogICAgICAgIHRvcFJhZGl1czogdm9pZCAwLAogICAgICAgIGJvdHRvbVJhZGl1czogdm9pZCAwLAogICAgICAgIHNsaWNlczogdm9pZCAwLAogICAgICAgIG9mZnNldEF0dHJpYnV0ZTogdm9pZCAwCiAgICAgIH07CiAgICAgIEN5bGluZGVyR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDUKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgdG9wUmFkaXVzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBib3R0b21SYWRpdXMgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHNsaWNlcyA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgb2Zmc2V0QXR0cmlidXRlID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMS5sZW5ndGggPSBsZW5ndGg7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczExLnRvcFJhZGl1cyA9IHRvcFJhZGl1czsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTEuYm90dG9tUmFkaXVzID0gYm90dG9tUmFkaXVzOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMS5zbGljZXMgPSBzbGljZXM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczExLm9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgICByZXR1cm4gbmV3IEN5bGluZGVyR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnMxMSk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0LCByZXN1bHQuX3ZlcnRleEZvcm1hdCk7CiAgICAgICAgcmVzdWx0Ll9sZW5ndGggPSBsZW5ndGg7CiAgICAgICAgcmVzdWx0Ll90b3BSYWRpdXMgPSB0b3BSYWRpdXM7CiAgICAgICAgcmVzdWx0Ll9ib3R0b21SYWRpdXMgPSBib3R0b21SYWRpdXM7CiAgICAgICAgcmVzdWx0Ll9zbGljZXMgPSBzbGljZXM7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEN5bGluZGVyR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihjeWxpbmRlckdlb21ldHJ5KSB7CiAgICAgICAgbGV0IGxlbmd0aCA9IGN5bGluZGVyR2VvbWV0cnkuX2xlbmd0aDsKICAgICAgICBjb25zdCB0b3BSYWRpdXMgPSBjeWxpbmRlckdlb21ldHJ5Ll90b3BSYWRpdXM7CiAgICAgICAgY29uc3QgYm90dG9tUmFkaXVzID0gY3lsaW5kZXJHZW9tZXRyeS5fYm90dG9tUmFkaXVzOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IGN5bGluZGVyR2VvbWV0cnkuX3ZlcnRleEZvcm1hdDsKICAgICAgICBjb25zdCBzbGljZXMgPSBjeWxpbmRlckdlb21ldHJ5Ll9zbGljZXM7CiAgICAgICAgaWYgKGxlbmd0aCA8PSAwIHx8IHRvcFJhZGl1cyA8IDAgfHwgYm90dG9tUmFkaXVzIDwgMCB8fCB0b3BSYWRpdXMgPT09IDAgJiYgYm90dG9tUmFkaXVzID09PSAwKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IHR3b1NsaWNlcyA9IHNsaWNlcyArIHNsaWNlczsKICAgICAgICBjb25zdCB0aHJlZVNsaWNlcyA9IHNsaWNlcyArIHR3b1NsaWNlczsKICAgICAgICBjb25zdCBudW1WZXJ0aWNlcyA9IHR3b1NsaWNlcyArIHR3b1NsaWNlczsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBDeWxpbmRlckdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMoCiAgICAgICAgICBsZW5ndGgsCiAgICAgICAgICB0b3BSYWRpdXMsCiAgICAgICAgICBib3R0b21SYWRpdXMsCiAgICAgICAgICBzbGljZXMsCiAgICAgICAgICB0cnVlCiAgICAgICAgKTsKICAgICAgICBjb25zdCBzdDIgPSB2ZXJ0ZXhGb3JtYXQuc3QgPyBuZXcgRmxvYXQzMkFycmF5KG51bVZlcnRpY2VzICogMikgOiB2b2lkIDA7CiAgICAgICAgY29uc3Qgbm9ybWFscyA9IHZlcnRleEZvcm1hdC5ub3JtYWwgPyBuZXcgRmxvYXQzMkFycmF5KG51bVZlcnRpY2VzICogMykgOiB2b2lkIDA7CiAgICAgICAgY29uc3QgdGFuZ2VudHMgPSB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkobnVtVmVydGljZXMgKiAzKSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkobnVtVmVydGljZXMgKiAzKSA6IHZvaWQgMDsKICAgICAgICBsZXQgaTI7CiAgICAgICAgY29uc3QgY29tcHV0ZU5vcm1hbCA9IHZlcnRleEZvcm1hdC5ub3JtYWwgfHwgdmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudDsKICAgICAgICBpZiAoY29tcHV0ZU5vcm1hbCkgewogICAgICAgICAgY29uc3QgY29tcHV0ZVRhbmdlbnQgPSB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50OwogICAgICAgICAgbGV0IG5vcm1hbEluZGV4ID0gMDsKICAgICAgICAgIGxldCB0YW5nZW50SW5kZXggPSAwOwogICAgICAgICAgbGV0IGJpdGFuZ2VudEluZGV4ID0gMDsKICAgICAgICAgIGNvbnN0IHRoZXRhID0gTWF0aC5hdGFuMihib3R0b21SYWRpdXMgLSB0b3BSYWRpdXMsIGxlbmd0aCk7CiAgICAgICAgICBjb25zdCBub3JtYWwyID0gbm9ybWFsU2NyYXRjaDM7CiAgICAgICAgICBub3JtYWwyLnogPSBNYXRoLnNpbih0aGV0YSk7CiAgICAgICAgICBjb25zdCBub3JtYWxTY2FsZTIgPSBNYXRoLmNvcyh0aGV0YSk7CiAgICAgICAgICBsZXQgdGFuZ2VudCA9IHRhbmdlbnRTY3JhdGNoOwogICAgICAgICAgbGV0IGJpdGFuZ2VudCA9IGJpdGFuZ2VudFNjcmF0Y2g7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzbGljZXM7IGkyKyspIHsKICAgICAgICAgICAgY29uc3QgYW5nbGUgPSBpMiAvIHNsaWNlcyAqIE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICAgIGNvbnN0IHgyID0gbm9ybWFsU2NhbGUyICogTWF0aC5jb3MoYW5nbGUpOwogICAgICAgICAgICBjb25zdCB5MiA9IG5vcm1hbFNjYWxlMiAqIE1hdGguc2luKGFuZ2xlKTsKICAgICAgICAgICAgaWYgKGNvbXB1dGVOb3JtYWwpIHsKICAgICAgICAgICAgICBub3JtYWwyLnggPSB4MjsKICAgICAgICAgICAgICBub3JtYWwyLnkgPSB5MjsKICAgICAgICAgICAgICBpZiAoY29tcHV0ZVRhbmdlbnQpIHsKICAgICAgICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwgbm9ybWFsMiwgdGFuZ2VudCksCiAgICAgICAgICAgICAgICAgIHRhbmdlbnQKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsKSB7CiAgICAgICAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi54OwogICAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIueTsKICAgICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLno7CiAgICAgICAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi54OwogICAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIueTsKICAgICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLno7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCkgewogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC54OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC55OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC56OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC54OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC55OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC56OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIHRhbmdlbnQsIGJpdGFuZ2VudCksCiAgICAgICAgICAgICAgICAgIGJpdGFuZ2VudAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueTsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQuejsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueTsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQuejsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHNsaWNlczsgaTIrKykgewogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSAwOwogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSAwOwogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSAtMTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSAxOwogICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IDA7CiAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSAwOwogICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSAtMTsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc2xpY2VzOyBpMisrKSB7CiAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsKSB7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IDA7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IDA7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IDE7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gMTsKICAgICAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSAwOwogICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gMDsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gMTsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBudW1JbmRpY2VzID0gMTIgKiBzbGljZXMgLSAxMjsKICAgICAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkobnVtVmVydGljZXMsIG51bUluZGljZXMpOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgbGV0IGoyID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzbGljZXMgLSAxOyBpMisrKSB7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gajI7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gajIgKyAyOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGoyICsgMzsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBqMjsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBqMiArIDM7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gajIgKyAxOwogICAgICAgICAgajIgKz0gMjsKICAgICAgICB9CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHR3b1NsaWNlcyAtIDI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IDA7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHR3b1NsaWNlcyAtIDI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHR3b1NsaWNlcyAtIDE7CiAgICAgICAgZm9yIChpMiA9IDE7IGkyIDwgc2xpY2VzIC0gMTsgaTIrKykgewogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHR3b1NsaWNlcyArIGkyICsgMTsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0d29TbGljZXMgKyBpMjsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0d29TbGljZXM7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IHNsaWNlcyAtIDE7IGkyKyspIHsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0aHJlZVNsaWNlczsKICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0aHJlZVNsaWNlcyArIGkyOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHRocmVlU2xpY2VzICsgaTIgKyAxOwogICAgICAgIH0KICAgICAgICBsZXQgdGV4dHVyZUNvb3JkSW5kZXggPSAwOwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIGNvbnN0IHJhZCA9IE1hdGgubWF4KHRvcFJhZGl1cywgYm90dG9tUmFkaXVzKTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bVZlcnRpY2VzOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkyICogMywgcG9zaXRpb25TY3JhdGNoKTsKICAgICAgICAgICAgc3QyW3RleHR1cmVDb29yZEluZGV4KytdID0gKHBvc2l0aW9uLnggKyByYWQpIC8gKDIgKiByYWQpOwogICAgICAgICAgICBzdDJbdGV4dHVyZUNvb3JkSW5kZXgrK10gPSAocG9zaXRpb24ueSArIHJhZCkgLyAoMiAqIHJhZCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgIGF0dHJpYnV0ZXMubm9ybWFsID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgdmFsdWVzOiBub3JtYWxzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLnRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHRhbmdlbnRzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgIHZhbHVlczogc3QyCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmFkaXVzU2NyYXRjaC54ID0gbGVuZ3RoICogMC41OwogICAgICAgIHJhZGl1c1NjcmF0Y2gueSA9IE1hdGgubWF4KGJvdHRvbVJhZGl1cywgdG9wUmFkaXVzKTsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sCiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQubWFnbml0dWRlKHJhZGl1c1NjcmF0Y2gpCiAgICAgICAgKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGN5bGluZGVyR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgIGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IGN5bGluZGVyR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5OT05FID8gMCA6IDE7CiAgICAgICAgICBjb25zdCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCAvIDMpLmZpbGwob2Zmc2V0VmFsdWUpOwogICAgICAgICAgYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogY3lsaW5kZXJHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEN5bGluZGVyR2VvbWV0cnkuZ2V0VW5pdEN5bGluZGVyID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodW5pdEN5bGluZGVyR2VvbWV0cnkpKSB7CiAgICAgICAgICB1bml0Q3lsaW5kZXJHZW9tZXRyeSA9IEN5bGluZGVyR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkoCiAgICAgICAgICAgIG5ldyBDeWxpbmRlckdlb21ldHJ5KHsKICAgICAgICAgICAgICB0b3BSYWRpdXM6IDEsCiAgICAgICAgICAgICAgYm90dG9tUmFkaXVzOiAxLAogICAgICAgICAgICAgIGxlbmd0aDogMSwKICAgICAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IFZlcnRleEZvcm1hdF9kZWZhdWx0LlBPU0lUSU9OX09OTFkKICAgICAgICAgICAgfSkKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB1bml0Q3lsaW5kZXJHZW9tZXRyeTsKICAgICAgfTsKICAgICAgQ3lsaW5kZXJHZW9tZXRyeV9kZWZhdWx0ID0gQ3lsaW5kZXJHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUN5bGluZGVyR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlQ3lsaW5kZXJHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlQ3lsaW5kZXJHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVDeWxpbmRlckdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVDeWxpbmRlckdlb21ldHJ5KGN5bGluZGVyR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGN5bGluZGVyR2VvbWV0cnkgPSBDeWxpbmRlckdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGN5bGluZGVyR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICByZXR1cm4gQ3lsaW5kZXJHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGN5bGluZGVyR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlQ3lsaW5kZXJHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUN5bGluZGVyR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUN5bGluZGVyR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0N5bGluZGVyR2VvbWV0cnkoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGNyZWF0ZUN5bGluZGVyR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZUN5bGluZGVyR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DeWxpbmRlck91dGxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEN5bGluZGVyT3V0bGluZUdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IGxlbmd0aCA9IG9wdGlvbnMubGVuZ3RoOwogICAgY29uc3QgdG9wUmFkaXVzID0gb3B0aW9ucy50b3BSYWRpdXM7CiAgICBjb25zdCBib3R0b21SYWRpdXMgPSBvcHRpb25zLmJvdHRvbVJhZGl1czsKICAgIGNvbnN0IHNsaWNlcyA9IG9wdGlvbnMuc2xpY2VzID8/IDEyODsKICAgIGNvbnN0IG51bWJlck9mVmVydGljYWxMaW5lcyA9IE1hdGgubWF4KAogICAgICBvcHRpb25zLm51bWJlck9mVmVydGljYWxMaW5lcyA/PyAxNiwKICAgICAgMAogICAgKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigib3B0aW9ucy5wb3NpdGlvbnMiLCBsZW5ndGgpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJvcHRpb25zLnRvcFJhZGl1cyIsIHRvcFJhZGl1cyk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIm9wdGlvbnMuYm90dG9tUmFkaXVzIiwgYm90dG9tUmFkaXVzKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJvcHRpb25zLnNsaWNlcyIsIHNsaWNlcywgMyk7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlKSAmJiBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5UT1ApIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIkdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlLlRPUCBpcyBub3QgYSBzdXBwb3J0ZWQgb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgZm9yIHRoaXMgZ2VvbWV0cnkuIgogICAgICApOwogICAgfQogICAgdGhpcy5fbGVuZ3RoID0gbGVuZ3RoOwogICAgdGhpcy5fdG9wUmFkaXVzID0gdG9wUmFkaXVzOwogICAgdGhpcy5fYm90dG9tUmFkaXVzID0gYm90dG9tUmFkaXVzOwogICAgdGhpcy5fc2xpY2VzID0gc2xpY2VzOwogICAgdGhpcy5fbnVtYmVyT2ZWZXJ0aWNhbExpbmVzID0gbnVtYmVyT2ZWZXJ0aWNhbExpbmVzOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5IjsKICB9CiAgdmFyIHJhZGl1c1NjcmF0Y2gyLCBzY3JhdGNoT3B0aW9uczEyLCBDeWxpbmRlck91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X0N5bGluZGVyT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DeWxpbmRlck91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9DeWxpbmRlckdlb21ldHJ5TGlicmFyeSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIHJhZGl1c1NjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBDeWxpbmRlck91dGxpbmVHZW9tZXRyeS5wYWNrZWRMZW5ndGggPSA2OwogICAgICBDeWxpbmRlck91dGxpbmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl90b3BSYWRpdXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9ib3R0b21SYWRpdXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zbGljZXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9udW1iZXJPZlZlcnRpY2FsTGluZXM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaE9wdGlvbnMxMiA9IHsKICAgICAgICBsZW5ndGg6IHZvaWQgMCwKICAgICAgICB0b3BSYWRpdXM6IHZvaWQgMCwKICAgICAgICBib3R0b21SYWRpdXM6IHZvaWQgMCwKICAgICAgICBzbGljZXM6IHZvaWQgMCwKICAgICAgICBudW1iZXJPZlZlcnRpY2FsTGluZXM6IHZvaWQgMCwKICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IHZvaWQgMAogICAgICB9OwogICAgICBDeWxpbmRlck91dGxpbmVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IGxlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgdG9wUmFkaXVzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBib3R0b21SYWRpdXMgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHNsaWNlcyA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNhbExpbmVzID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEyLmxlbmd0aCA9IGxlbmd0aDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTIudG9wUmFkaXVzID0gdG9wUmFkaXVzOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMi5ib3R0b21SYWRpdXMgPSBib3R0b21SYWRpdXM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEyLnNsaWNlcyA9IHNsaWNlczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTIubnVtYmVyT2ZWZXJ0aWNhbExpbmVzID0gbnVtYmVyT2ZWZXJ0aWNhbExpbmVzOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMi5vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgcmV0dXJuIG5ldyBDeWxpbmRlck91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczEyKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9sZW5ndGggPSBsZW5ndGg7CiAgICAgICAgcmVzdWx0Ll90b3BSYWRpdXMgPSB0b3BSYWRpdXM7CiAgICAgICAgcmVzdWx0Ll9ib3R0b21SYWRpdXMgPSBib3R0b21SYWRpdXM7CiAgICAgICAgcmVzdWx0Ll9zbGljZXMgPSBzbGljZXM7CiAgICAgICAgcmVzdWx0Ll9udW1iZXJPZlZlcnRpY2FsTGluZXMgPSBudW1iZXJPZlZlcnRpY2FsTGluZXM7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEN5bGluZGVyT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24oY3lsaW5kZXJHZW9tZXRyeSkgewogICAgICAgIGxldCBsZW5ndGggPSBjeWxpbmRlckdlb21ldHJ5Ll9sZW5ndGg7CiAgICAgICAgY29uc3QgdG9wUmFkaXVzID0gY3lsaW5kZXJHZW9tZXRyeS5fdG9wUmFkaXVzOwogICAgICAgIGNvbnN0IGJvdHRvbVJhZGl1cyA9IGN5bGluZGVyR2VvbWV0cnkuX2JvdHRvbVJhZGl1czsKICAgICAgICBjb25zdCBzbGljZXMgPSBjeWxpbmRlckdlb21ldHJ5Ll9zbGljZXM7CiAgICAgICAgY29uc3QgbnVtYmVyT2ZWZXJ0aWNhbExpbmVzID0gY3lsaW5kZXJHZW9tZXRyeS5fbnVtYmVyT2ZWZXJ0aWNhbExpbmVzOwogICAgICAgIGlmIChsZW5ndGggPD0gMCB8fCB0b3BSYWRpdXMgPCAwIHx8IGJvdHRvbVJhZGl1cyA8IDAgfHwgdG9wUmFkaXVzID09PSAwICYmIGJvdHRvbVJhZGl1cyA9PT0gMCkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBjb25zdCBudW1WZXJ0aWNlcyA9IHNsaWNlcyAqIDI7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gQ3lsaW5kZXJHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb25zKAogICAgICAgICAgbGVuZ3RoLAogICAgICAgICAgdG9wUmFkaXVzLAogICAgICAgICAgYm90dG9tUmFkaXVzLAogICAgICAgICAgc2xpY2VzLAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGxldCBudW1JbmRpY2VzID0gc2xpY2VzICogMjsKICAgICAgICBsZXQgbnVtU2lkZTsKICAgICAgICBpZiAobnVtYmVyT2ZWZXJ0aWNhbExpbmVzID4gMCkgewogICAgICAgICAgY29uc3QgbnVtU2lkZUxpbmVzID0gTWF0aC5taW4obnVtYmVyT2ZWZXJ0aWNhbExpbmVzLCBzbGljZXMpOwogICAgICAgICAgbnVtU2lkZSA9IE1hdGgucm91bmQoc2xpY2VzIC8gbnVtU2lkZUxpbmVzKTsKICAgICAgICAgIG51bUluZGljZXMgKz0gbnVtU2lkZUxpbmVzOwogICAgICAgIH0KICAgICAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkobnVtVmVydGljZXMsIG51bUluZGljZXMgKiAyKTsKICAgICAgICBsZXQgaW5kZXggPSAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzbGljZXMgLSAxOyBpMisrKSB7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaTI7CiAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaTIgKyAxOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgc2xpY2VzOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgMSArIHNsaWNlczsKICAgICAgICB9CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHNsaWNlcyAtIDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IDA7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHNsaWNlcyArIHNsaWNlcyAtIDE7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHNsaWNlczsKICAgICAgICBpZiAobnVtYmVyT2ZWZXJ0aWNhbExpbmVzID4gMCkgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc2xpY2VzOyBpMiArPSBudW1TaWRlKSB7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMjsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgc2xpY2VzOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgICAgIH0pOwogICAgICAgIHJhZGl1c1NjcmF0Y2gyLnggPSBsZW5ndGggKiAwLjU7CiAgICAgICAgcmFkaXVzU2NyYXRjaDIueSA9IE1hdGgubWF4KGJvdHRvbVJhZGl1cywgdG9wUmFkaXVzKTsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sCiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQubWFnbml0dWRlKHJhZGl1c1NjcmF0Y2gyKQogICAgICAgICk7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjeWxpbmRlckdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBjeWxpbmRlckdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgIGF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgIHZhbHVlczogYXBwbHlPZmZzZXQKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogY3lsaW5kZXJHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEN5bGluZGVyT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBDeWxpbmRlck91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVDeWxpbmRlck91dGxpbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVDeWxpbmRlck91dGxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlQ3lsaW5kZXJPdXRsaW5lR2VvbWV0cnkoY3lsaW5kZXJHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgY3lsaW5kZXJHZW9tZXRyeSA9IEN5bGluZGVyT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGN5bGluZGVyR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICByZXR1cm4gQ3lsaW5kZXJPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShjeWxpbmRlckdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlQ3lsaW5kZXJPdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9DeWxpbmRlck91dGxpbmVHZW9tZXRyeSgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgY3JlYXRlQ3lsaW5kZXJPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRWxsaXBzZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUVsbGlwc2VHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlRWxsaXBzZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZUVsbGlwc2VHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlRWxsaXBzZUdlb21ldHJ5KGVsbGlwc2VHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgZWxsaXBzZUdlb21ldHJ5ID0gRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGVsbGlwc2VHZW9tZXRyeSwgb2Zmc2V0KTsKICAgIH0KICAgIGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVsbGlwc2VHZW9tZXRyeS5fY2VudGVyKTsKICAgIGVsbGlwc2VHZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQpOwogICAgcmV0dXJuIEVsbGlwc2VHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGVsbGlwc2VHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVFbGxpcHNlR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVFbGxpcHNlR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUVsbGlwc2VHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNlR2VvbWV0cnkoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgY3JlYXRlRWxsaXBzZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVFbGxpcHNlR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlRWxsaXBzZU91dGxpbmVHZW9tZXRyeShlbGxpcHNlR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGVsbGlwc2VHZW9tZXRyeSA9IEVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2soZWxsaXBzZUdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoZWxsaXBzZUdlb21ldHJ5Ll9jZW50ZXIpOwogICAgZWxsaXBzZUdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNlR2VvbWV0cnkuX2VsbGlwc29pZCk7CiAgICByZXR1cm4gRWxsaXBzZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGVsbGlwc2VHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlRWxsaXBzZU91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRWxsaXBzZU91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNlT3V0bGluZUdlb21ldHJ5KCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEVsbGlwc29pZEdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgIGNvbnN0IHJhZGlpID0gb3B0aW9ucy5yYWRpaSA/PyBkZWZhdWx0UmFkaWk7CiAgICBjb25zdCBpbm5lclJhZGlpID0gb3B0aW9ucy5pbm5lclJhZGlpID8/IHJhZGlpOwogICAgY29uc3QgbWluaW11bUNsb2NrID0gb3B0aW9ucy5taW5pbXVtQ2xvY2sgPz8gMDsKICAgIGNvbnN0IG1heGltdW1DbG9jayA9IG9wdGlvbnMubWF4aW11bUNsb2NrID8/IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICBjb25zdCBtaW5pbXVtQ29uZSA9IG9wdGlvbnMubWluaW11bUNvbmUgPz8gMDsKICAgIGNvbnN0IG1heGltdW1Db25lID0gb3B0aW9ucy5tYXhpbXVtQ29uZSA/PyBNYXRoX2RlZmF1bHQuUEk7CiAgICBjb25zdCBzdGFja1BhcnRpdGlvbnMgPSBNYXRoLnJvdW5kKG9wdGlvbnMuc3RhY2tQYXJ0aXRpb25zID8/IDY0KTsKICAgIGNvbnN0IHNsaWNlUGFydGl0aW9ucyA9IE1hdGgucm91bmQob3B0aW9ucy5zbGljZVBhcnRpdGlvbnMgPz8gNjQpOwogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIGlmIChzbGljZVBhcnRpdGlvbnMgPCAzKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnNsaWNlUGFydGl0aW9ucyBjYW5ub3QgYmUgbGVzcyB0aGFuIHRocmVlLiIKICAgICAgKTsKICAgIH0KICAgIGlmIChzdGFja1BhcnRpdGlvbnMgPCAzKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnN0YWNrUGFydGl0aW9ucyBjYW5ub3QgYmUgbGVzcyB0aGFuIHRocmVlLiIKICAgICAgKTsKICAgIH0KICAgIHRoaXMuX3JhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHJhZGlpKTsKICAgIHRoaXMuX2lubmVyUmFkaWkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoaW5uZXJSYWRpaSk7CiAgICB0aGlzLl9taW5pbXVtQ2xvY2sgPSBtaW5pbXVtQ2xvY2s7CiAgICB0aGlzLl9tYXhpbXVtQ2xvY2sgPSBtYXhpbXVtQ2xvY2s7CiAgICB0aGlzLl9taW5pbXVtQ29uZSA9IG1pbmltdW1Db25lOwogICAgdGhpcy5fbWF4aW11bUNvbmUgPSBtYXhpbXVtQ29uZTsKICAgIHRoaXMuX3N0YWNrUGFydGl0aW9ucyA9IHN0YWNrUGFydGl0aW9uczsKICAgIHRoaXMuX3NsaWNlUGFydGl0aW9ucyA9IHNsaWNlUGFydGl0aW9uczsKICAgIHRoaXMuX3ZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKHZlcnRleEZvcm1hdCk7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlRWxsaXBzb2lkR2VvbWV0cnkiOwogIH0KICB2YXIgc2NyYXRjaFBvc2l0aW9uMiwgc2NyYXRjaE5vcm1hbDUsIHNjcmF0Y2hUYW5nZW50Mywgc2NyYXRjaEJpdGFuZ2VudDMsIHNjcmF0Y2hOb3JtYWxTVCwgZGVmYXVsdFJhZGlpLCBjb3MsIHNpbiwgc2NyYXRjaFJhZGlpLCBzY3JhdGNoSW5uZXJSYWRpaSwgc2NyYXRjaFZlcnRleEZvcm1hdDYsIHNjcmF0Y2hPcHRpb25zMTMsIHVuaXRFbGxpcHNvaWRHZW9tZXRyeSwgRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9FbGxpcHNvaWRHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRWxsaXBzb2lkR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1ZlcnRleEZvcm1hdCgpOwogICAgICBzY3JhdGNoUG9zaXRpb24yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsNSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRhbmdlbnQzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQml0YW5nZW50MyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5vcm1hbFNUID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBkZWZhdWx0UmFkaWkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KDEsIDEsIDEpOwogICAgICBjb3MgPSBNYXRoLmNvczsKICAgICAgc2luID0gTWF0aC5zaW47CiAgICAgIEVsbGlwc29pZEdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IDIgKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgNzsKICAgICAgRWxsaXBzb2lkR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sodmFsdWUuX3JhZGlpLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9pbm5lclJhZGlpLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2sodmFsdWUuX3ZlcnRleEZvcm1hdCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fbWluaW11bUNsb2NrOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fbWF4aW11bUNsb2NrOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fbWluaW11bUNvbmU7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9tYXhpbXVtQ29uZTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3N0YWNrUGFydGl0aW9uczsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3NsaWNlUGFydGl0aW9uczsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9vZmZzZXRBdHRyaWJ1dGUgPz8gLTE7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBzY3JhdGNoUmFkaWkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hJbm5lclJhZGlpID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0NiA9IG5ldyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczEzID0gewogICAgICAgIHJhZGlpOiBzY3JhdGNoUmFkaWksCiAgICAgICAgaW5uZXJSYWRpaTogc2NyYXRjaElubmVyUmFkaWksCiAgICAgICAgdmVydGV4Rm9ybWF0OiBzY3JhdGNoVmVydGV4Rm9ybWF0NiwKICAgICAgICBtaW5pbXVtQ2xvY2s6IHZvaWQgMCwKICAgICAgICBtYXhpbXVtQ2xvY2s6IHZvaWQgMCwKICAgICAgICBtaW5pbXVtQ29uZTogdm9pZCAwLAogICAgICAgIG1heGltdW1Db25lOiB2b2lkIDAsCiAgICAgICAgc3RhY2tQYXJ0aXRpb25zOiB2b2lkIDAsCiAgICAgICAgc2xpY2VQYXJ0aXRpb25zOiB2b2lkIDAsCiAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiB2b2lkIDAKICAgICAgfTsKICAgICAgRWxsaXBzb2lkR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgcmFkaWkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4LCBzY3JhdGNoUmFkaWkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBpbm5lclJhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaElubmVyUmFkaWkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0NgogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgbWluaW11bUNsb2NrID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBtYXhpbXVtQ2xvY2sgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG1pbmltdW1Db25lID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBtYXhpbXVtQ29uZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc3RhY2tQYXJ0aXRpb25zID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBzbGljZVBhcnRpdGlvbnMgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG9mZnNldEF0dHJpYnV0ZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTMubWluaW11bUNsb2NrID0gbWluaW11bUNsb2NrOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMy5tYXhpbXVtQ2xvY2sgPSBtYXhpbXVtQ2xvY2s7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEzLm1pbmltdW1Db25lID0gbWluaW11bUNvbmU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEzLm1heGltdW1Db25lID0gbWF4aW11bUNvbmU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczEzLnN0YWNrUGFydGl0aW9ucyA9IHN0YWNrUGFydGl0aW9uczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTMuc2xpY2VQYXJ0aXRpb25zID0gc2xpY2VQYXJ0aXRpb25zOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxMy5vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgcmV0dXJuIG5ldyBFbGxpcHNvaWRHZW9tZXRyeShzY3JhdGNoT3B0aW9uczEzKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9yYWRpaSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyYWRpaSwgcmVzdWx0Ll9yYWRpaSk7CiAgICAgICAgcmVzdWx0Ll9pbm5lclJhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGlubmVyUmFkaWksIHJlc3VsdC5faW5uZXJSYWRpaSk7CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXN1bHQuX21pbmltdW1DbG9jayA9IG1pbmltdW1DbG9jazsKICAgICAgICByZXN1bHQuX21heGltdW1DbG9jayA9IG1heGltdW1DbG9jazsKICAgICAgICByZXN1bHQuX21pbmltdW1Db25lID0gbWluaW11bUNvbmU7CiAgICAgICAgcmVzdWx0Ll9tYXhpbXVtQ29uZSA9IG1heGltdW1Db25lOwogICAgICAgIHJlc3VsdC5fc3RhY2tQYXJ0aXRpb25zID0gc3RhY2tQYXJ0aXRpb25zOwogICAgICAgIHJlc3VsdC5fc2xpY2VQYXJ0aXRpb25zID0gc2xpY2VQYXJ0aXRpb25zOwogICAgICAgIHJlc3VsdC5fb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBFbGxpcHNvaWRHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGVsbGlwc29pZEdlb21ldHJ5KSB7CiAgICAgICAgY29uc3QgcmFkaWkgPSBlbGxpcHNvaWRHZW9tZXRyeS5fcmFkaWk7CiAgICAgICAgaWYgKHJhZGlpLnggPD0gMCB8fCByYWRpaS55IDw9IDAgfHwgcmFkaWkueiA8PSAwKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IGlubmVyUmFkaWkgPSBlbGxpcHNvaWRHZW9tZXRyeS5faW5uZXJSYWRpaTsKICAgICAgICBpZiAoaW5uZXJSYWRpaS54IDw9IDAgfHwgaW5uZXJSYWRpaS55IDw9IDAgfHwgaW5uZXJSYWRpaS56IDw9IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgbWluaW11bUNsb2NrID0gZWxsaXBzb2lkR2VvbWV0cnkuX21pbmltdW1DbG9jazsKICAgICAgICBjb25zdCBtYXhpbXVtQ2xvY2sgPSBlbGxpcHNvaWRHZW9tZXRyeS5fbWF4aW11bUNsb2NrOwogICAgICAgIGNvbnN0IG1pbmltdW1Db25lID0gZWxsaXBzb2lkR2VvbWV0cnkuX21pbmltdW1Db25lOwogICAgICAgIGNvbnN0IG1heGltdW1Db25lID0gZWxsaXBzb2lkR2VvbWV0cnkuX21heGltdW1Db25lOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IGVsbGlwc29pZEdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgbGV0IHNsaWNlUGFydGl0aW9ucyA9IGVsbGlwc29pZEdlb21ldHJ5Ll9zbGljZVBhcnRpdGlvbnMgKyAxOwogICAgICAgIGxldCBzdGFja1BhcnRpdGlvbnMgPSBlbGxpcHNvaWRHZW9tZXRyeS5fc3RhY2tQYXJ0aXRpb25zICsgMTsKICAgICAgICBzbGljZVBhcnRpdGlvbnMgPSBNYXRoLnJvdW5kKAogICAgICAgICAgc2xpY2VQYXJ0aXRpb25zICogTWF0aC5hYnMobWF4aW11bUNsb2NrIC0gbWluaW11bUNsb2NrKSAvIE1hdGhfZGVmYXVsdC5UV09fUEkKICAgICAgICApOwogICAgICAgIHN0YWNrUGFydGl0aW9ucyA9IE1hdGgucm91bmQoCiAgICAgICAgICBzdGFja1BhcnRpdGlvbnMgKiBNYXRoLmFicyhtYXhpbXVtQ29uZSAtIG1pbmltdW1Db25lKSAvIE1hdGhfZGVmYXVsdC5QSQogICAgICAgICk7CiAgICAgICAgaWYgKHNsaWNlUGFydGl0aW9ucyA8IDIpIHsKICAgICAgICAgIHNsaWNlUGFydGl0aW9ucyA9IDI7CiAgICAgICAgfQogICAgICAgIGlmIChzdGFja1BhcnRpdGlvbnMgPCAyKSB7CiAgICAgICAgICBzdGFja1BhcnRpdGlvbnMgPSAyOwogICAgICAgIH0KICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IGoyOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgY29uc3QgcGhpcyA9IFttaW5pbXVtQ29uZV07CiAgICAgICAgY29uc3QgdGhldGFzID0gW21pbmltdW1DbG9ja107CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc3RhY2tQYXJ0aXRpb25zOyBpMisrKSB7CiAgICAgICAgICBwaGlzLnB1c2goCiAgICAgICAgICAgIG1pbmltdW1Db25lICsgaTIgKiAobWF4aW11bUNvbmUgLSBtaW5pbXVtQ29uZSkgLyAoc3RhY2tQYXJ0aXRpb25zIC0gMSkKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHBoaXMucHVzaChtYXhpbXVtQ29uZSk7CiAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc2xpY2VQYXJ0aXRpb25zOyBqMisrKSB7CiAgICAgICAgICB0aGV0YXMucHVzaCgKICAgICAgICAgICAgbWluaW11bUNsb2NrICsgajIgKiAobWF4aW11bUNsb2NrIC0gbWluaW11bUNsb2NrKSAvIChzbGljZVBhcnRpdGlvbnMgLSAxKQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgdGhldGFzLnB1c2gobWF4aW11bUNsb2NrKTsKICAgICAgICBjb25zdCBudW1QaGlzID0gcGhpcy5sZW5ndGg7CiAgICAgICAgY29uc3QgbnVtVGhldGFzID0gdGhldGFzLmxlbmd0aDsKICAgICAgICBsZXQgZXh0cmFJbmRpY2VzID0gMDsKICAgICAgICBsZXQgdmVydGV4TXVsdGlwbGllciA9IDE7CiAgICAgICAgY29uc3QgaGFzSW5uZXJTdXJmYWNlID0gaW5uZXJSYWRpaS54ICE9PSByYWRpaS54IHx8IGlubmVyUmFkaWkueSAhPT0gcmFkaWkueSB8fCBpbm5lclJhZGlpLnogIT09IHJhZGlpLno7CiAgICAgICAgbGV0IGlzVG9wT3BlbiA9IGZhbHNlOwogICAgICAgIGxldCBpc0JvdE9wZW4gPSBmYWxzZTsKICAgICAgICBsZXQgaXNDbG9ja09wZW4gPSBmYWxzZTsKICAgICAgICBpZiAoaGFzSW5uZXJTdXJmYWNlKSB7CiAgICAgICAgICB2ZXJ0ZXhNdWx0aXBsaWVyID0gMjsKICAgICAgICAgIGlmIChtaW5pbXVtQ29uZSA+IDApIHsKICAgICAgICAgICAgaXNUb3BPcGVuID0gdHJ1ZTsKICAgICAgICAgICAgZXh0cmFJbmRpY2VzICs9IHNsaWNlUGFydGl0aW9ucyAtIDE7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobWF4aW11bUNvbmUgPCBNYXRoLlBJKSB7CiAgICAgICAgICAgIGlzQm90T3BlbiA9IHRydWU7CiAgICAgICAgICAgIGV4dHJhSW5kaWNlcyArPSBzbGljZVBhcnRpdGlvbnMgLSAxOwogICAgICAgICAgfQogICAgICAgICAgaWYgKChtYXhpbXVtQ2xvY2sgLSBtaW5pbXVtQ2xvY2spICUgTWF0aF9kZWZhdWx0LlRXT19QSSkgewogICAgICAgICAgICBpc0Nsb2NrT3BlbiA9IHRydWU7CiAgICAgICAgICAgIGV4dHJhSW5kaWNlcyArPSAoc3RhY2tQYXJ0aXRpb25zIC0gMSkgKiAyICsgMTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGV4dHJhSW5kaWNlcyArPSAxOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCB2ZXJ0ZXhDb3VudCA9IG51bVRoZXRhcyAqIG51bVBoaXMgKiB2ZXJ0ZXhNdWx0aXBsaWVyOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkodmVydGV4Q291bnQgKiAzKTsKICAgICAgICBjb25zdCBpc0lubmVyID0gbmV3IEFycmF5KHZlcnRleENvdW50KS5maWxsKGZhbHNlKTsKICAgICAgICBjb25zdCBuZWdhdGVOb3JtYWwgPSBuZXcgQXJyYXkodmVydGV4Q291bnQpLmZpbGwoZmFsc2UpOwogICAgICAgIGNvbnN0IGluZGV4Q291bnQgPSBzbGljZVBhcnRpdGlvbnMgKiBzdGFja1BhcnRpdGlvbnMgKiB2ZXJ0ZXhNdWx0aXBsaWVyOwogICAgICAgIGNvbnN0IG51bUluZGljZXMgPSA2ICogKGluZGV4Q291bnQgKyBleHRyYUluZGljZXMgKyAxIC0gKHNsaWNlUGFydGl0aW9ucyArIHN0YWNrUGFydGl0aW9ucykgKiB2ZXJ0ZXhNdWx0aXBsaWVyKTsKICAgICAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoaW5kZXhDb3VudCwgbnVtSW5kaWNlcyk7CiAgICAgICAgY29uc3Qgbm9ybWFscyA9IHZlcnRleEZvcm1hdC5ub3JtYWwgPyBuZXcgRmxvYXQzMkFycmF5KHZlcnRleENvdW50ICogMykgOiB2b2lkIDA7CiAgICAgICAgY29uc3QgdGFuZ2VudHMgPSB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkodmVydGV4Q291bnQgKiAzKSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkodmVydGV4Q291bnQgKiAzKSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBzdDIgPSB2ZXJ0ZXhGb3JtYXQuc3QgPyBuZXcgRmxvYXQzMkFycmF5KHZlcnRleENvdW50ICogMikgOiB2b2lkIDA7CiAgICAgICAgY29uc3Qgc2luUGhpID0gbmV3IEFycmF5KG51bVBoaXMpOwogICAgICAgIGNvbnN0IGNvc1BoaSA9IG5ldyBBcnJheShudW1QaGlzKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1QaGlzOyBpMisrKSB7CiAgICAgICAgICBzaW5QaGlbaTJdID0gc2luKHBoaXNbaTJdKTsKICAgICAgICAgIGNvc1BoaVtpMl0gPSBjb3MocGhpc1tpMl0pOwogICAgICAgIH0KICAgICAgICBjb25zdCBzaW5UaGV0YSA9IG5ldyBBcnJheShudW1UaGV0YXMpOwogICAgICAgIGNvbnN0IGNvc1RoZXRhID0gbmV3IEFycmF5KG51bVRoZXRhcyk7CiAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgbnVtVGhldGFzOyBqMisrKSB7CiAgICAgICAgICBjb3NUaGV0YVtqMl0gPSBjb3ModGhldGFzW2oyXSk7CiAgICAgICAgICBzaW5UaGV0YVtqMl0gPSBzaW4odGhldGFzW2oyXSk7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bVBoaXM7IGkyKyspIHsKICAgICAgICAgIGZvciAoajIgPSAwOyBqMiA8IG51bVRoZXRhczsgajIrKykgewogICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSByYWRpaS54ICogc2luUGhpW2kyXSAqIGNvc1RoZXRhW2oyXTsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gcmFkaWkueSAqIHNpblBoaVtpMl0gKiBzaW5UaGV0YVtqMl07CiAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHJhZGlpLnogKiBjb3NQaGlbaTJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBsZXQgdmVydGV4SW5kZXggPSB2ZXJ0ZXhDb3VudCAvIDI7CiAgICAgICAgaWYgKGhhc0lubmVyU3VyZmFjZSkgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtUGhpczsgaTIrKykgewogICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBudW1UaGV0YXM7IGoyKyspIHsKICAgICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBpbm5lclJhZGlpLnggKiBzaW5QaGlbaTJdICogY29zVGhldGFbajJdOwogICAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGlubmVyUmFkaWkueSAqIHNpblBoaVtpMl0gKiBzaW5UaGV0YVtqMl07CiAgICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gaW5uZXJSYWRpaS56ICogY29zUGhpW2kyXTsKICAgICAgICAgICAgICBpc0lubmVyW3ZlcnRleEluZGV4XSA9IHRydWU7CiAgICAgICAgICAgICAgaWYgKGkyID4gMCAmJiBpMiAhPT0gbnVtUGhpcyAtIDEgJiYgajIgIT09IDAgJiYgajIgIT09IG51bVRoZXRhcyAtIDEpIHsKICAgICAgICAgICAgICAgIG5lZ2F0ZU5vcm1hbFt2ZXJ0ZXhJbmRleF0gPSB0cnVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2ZXJ0ZXhJbmRleCsrOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGluZGV4ID0gMDsKICAgICAgICBsZXQgdG9wT2Zmc2V0OwogICAgICAgIGxldCBib3R0b21PZmZzZXQ7CiAgICAgICAgZm9yIChpMiA9IDE7IGkyIDwgbnVtUGhpcyAtIDI7IGkyKyspIHsKICAgICAgICAgIHRvcE9mZnNldCA9IGkyICogbnVtVGhldGFzOwogICAgICAgICAgYm90dG9tT2Zmc2V0ID0gKGkyICsgMSkgKiBudW1UaGV0YXM7CiAgICAgICAgICBmb3IgKGoyID0gMTsgajIgPCBudW1UaGV0YXMgLSAyOyBqMisrKSB7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBib3R0b21PZmZzZXQgKyBqMjsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGJvdHRvbU9mZnNldCArIGoyICsgMTsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHRvcE9mZnNldCArIGoyICsgMTsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGJvdHRvbU9mZnNldCArIGoyOwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gdG9wT2Zmc2V0ICsgajIgKyAxOwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gdG9wT2Zmc2V0ICsgajI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChoYXNJbm5lclN1cmZhY2UpIHsKICAgICAgICAgIGNvbnN0IG9mZnNldCA9IG51bVBoaXMgKiBudW1UaGV0YXM7CiAgICAgICAgICBmb3IgKGkyID0gMTsgaTIgPCBudW1QaGlzIC0gMjsgaTIrKykgewogICAgICAgICAgICB0b3BPZmZzZXQgPSBvZmZzZXQgKyBpMiAqIG51bVRoZXRhczsKICAgICAgICAgICAgYm90dG9tT2Zmc2V0ID0gb2Zmc2V0ICsgKGkyICsgMSkgKiBudW1UaGV0YXM7CiAgICAgICAgICAgIGZvciAoajIgPSAxOyBqMiA8IG51bVRoZXRhcyAtIDI7IGoyKyspIHsKICAgICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gYm90dG9tT2Zmc2V0ICsgajI7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHRvcE9mZnNldCArIGoyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0b3BPZmZzZXQgKyBqMiArIDE7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGJvdHRvbU9mZnNldCArIGoyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0b3BPZmZzZXQgKyBqMiArIDE7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGJvdHRvbU9mZnNldCArIGoyICsgMTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBsZXQgb3V0ZXJPZmZzZXQ7CiAgICAgICAgbGV0IGlubmVyT2Zmc2V0OwogICAgICAgIGlmIChoYXNJbm5lclN1cmZhY2UpIHsKICAgICAgICAgIGlmIChpc1RvcE9wZW4pIHsKICAgICAgICAgICAgaW5uZXJPZmZzZXQgPSBudW1QaGlzICogbnVtVGhldGFzOwogICAgICAgICAgICBmb3IgKGkyID0gMTsgaTIgPCBudW1UaGV0YXMgLSAyOyBpMisrKSB7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMiArIDE7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0ICsgaTIgKyAxOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMjsKICAgICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaW5uZXJPZmZzZXQgKyBpMiArIDE7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0ICsgaTI7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChpc0JvdE9wZW4pIHsKICAgICAgICAgICAgb3V0ZXJPZmZzZXQgPSBudW1QaGlzICogbnVtVGhldGFzIC0gbnVtVGhldGFzOwogICAgICAgICAgICBpbm5lck9mZnNldCA9IG51bVBoaXMgKiBudW1UaGV0YXMgKiB2ZXJ0ZXhNdWx0aXBsaWVyIC0gbnVtVGhldGFzOwogICAgICAgICAgICBmb3IgKGkyID0gMTsgaTIgPCBudW1UaGV0YXMgLSAyOyBpMisrKSB7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IG91dGVyT2Zmc2V0ICsgaTIgKyAxOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIGkyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpbm5lck9mZnNldCArIGkyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIGkyICsgMTsKICAgICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaW5uZXJPZmZzZXQgKyBpMjsKICAgICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaW5uZXJPZmZzZXQgKyBpMiArIDE7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGlzQ2xvY2tPcGVuKSB7CiAgICAgICAgICBmb3IgKGkyID0gMTsgaTIgPCBudW1QaGlzIC0gMjsgaTIrKykgewogICAgICAgICAgICBpbm5lck9mZnNldCA9IG51bVRoZXRhcyAqIG51bVBoaXMgKyBudW1UaGV0YXMgKiBpMjsKICAgICAgICAgICAgb3V0ZXJPZmZzZXQgPSBudW1UaGV0YXMgKiBpMjsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0OwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gb3V0ZXJPZmZzZXQgKyBudW1UaGV0YXM7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldDsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0OwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaW5uZXJPZmZzZXQgKyBudW1UaGV0YXM7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIG51bVRoZXRhczsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IG51bVBoaXMgLSAyOyBpMisrKSB7CiAgICAgICAgICAgIGlubmVyT2Zmc2V0ID0gbnVtVGhldGFzICogbnVtUGhpcyArIG51bVRoZXRhcyAqIChpMiArIDEpIC0gMTsKICAgICAgICAgICAgb3V0ZXJPZmZzZXQgPSBudW1UaGV0YXMgKiAoaTIgKyAxKSAtIDE7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIG51bVRoZXRhczsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0OwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gb3V0ZXJPZmZzZXQ7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIG51bVRoZXRhczsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0ICsgbnVtVGhldGFzOwogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gaW5uZXJPZmZzZXQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgbGV0IHN0SW5kZXggPSAwOwogICAgICAgIGxldCBub3JtYWxJbmRleCA9IDA7CiAgICAgICAgbGV0IHRhbmdlbnRJbmRleCA9IDA7CiAgICAgICAgbGV0IGJpdGFuZ2VudEluZGV4ID0gMDsKICAgICAgICBjb25zdCB2ZXJ0ZXhDb3VudEhhbGYgPSB2ZXJ0ZXhDb3VudCAvIDI7CiAgICAgICAgbGV0IGVsbGlwc29pZDsKICAgICAgICBjb25zdCBlbGxpcHNvaWRPdXRlciA9IEVsbGlwc29pZF9kZWZhdWx0LmZyb21DYXJ0ZXNpYW4zKHJhZGlpKTsKICAgICAgICBjb25zdCBlbGxpcHNvaWRJbm5lciA9IEVsbGlwc29pZF9kZWZhdWx0LmZyb21DYXJ0ZXNpYW4zKGlubmVyUmFkaWkpOwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QgfHwgdmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudDsgaTIrKykgewogICAgICAgICAgICBlbGxpcHNvaWQgPSBpc0lubmVyW2kyXSA/IGVsbGlwc29pZElubmVyIDogZWxsaXBzb2lkT3V0ZXI7CiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkyICogMywgc2NyYXRjaFBvc2l0aW9uMik7CiAgICAgICAgICAgIGNvbnN0IG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBzY3JhdGNoTm9ybWFsNSk7CiAgICAgICAgICAgIGlmIChuZWdhdGVOb3JtYWxbaTJdKSB7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgICAgICAgICAgY29uc3Qgbm9ybWFsU1QgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQubmVnYXRlKG5vcm1hbDIsIHNjcmF0Y2hOb3JtYWxTVCk7CiAgICAgICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSBNYXRoLmF0YW4yKG5vcm1hbFNULnksIG5vcm1hbFNULngpIC8gTWF0aF9kZWZhdWx0LlRXT19QSSArIDAuNTsKICAgICAgICAgICAgICBzdDJbc3RJbmRleCsrXSA9IE1hdGguYXNpbihub3JtYWwyLnopIC8gTWF0aC5QSSArIDAuNTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLng7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIueTsKICAgICAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi56OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICAgICAgY29uc3QgdGFuZ2VudCA9IHNjcmF0Y2hUYW5nZW50MzsKICAgICAgICAgICAgICBsZXQgdGFuZ2V0T2Zmc2V0ID0gMDsKICAgICAgICAgICAgICBsZXQgdW5pdDsKICAgICAgICAgICAgICBpZiAoaXNJbm5lcltpMl0pIHsKICAgICAgICAgICAgICAgIHRhbmdldE9mZnNldCA9IHZlcnRleENvdW50SGFsZjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKCFpc1RvcE9wZW4gJiYgaTIgPj0gdGFuZ2V0T2Zmc2V0ICYmIGkyIDwgdGFuZ2V0T2Zmc2V0ICsgbnVtVGhldGFzICogMikgewogICAgICAgICAgICAgICAgdW5pdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1g7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHVuaXQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9aOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3ModW5pdCwgbm9ybWFsMiwgdGFuZ2VudCk7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSh0YW5nZW50LCB0YW5nZW50KTsKICAgICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQueDsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQueTsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQuejsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgICAgIGNvbnN0IGJpdGFuZ2VudCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhub3JtYWwyLCB0YW5nZW50LCBzY3JhdGNoQml0YW5nZW50Myk7CiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGJpdGFuZ2VudCwgYml0YW5nZW50KTsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueTsKICAgICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQuejsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICAgIHZhbHVlczogc3QyCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgYXR0cmlidXRlcy50YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiB0YW5nZW50cwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGVsbGlwc29pZEdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBlbGxpcHNvaWRHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgIGNvbnN0IGFwcGx5T2Zmc2V0ID0gbmV3IFVpbnQ4QXJyYXkobGVuZ3RoIC8gMykuZmlsbChvZmZzZXRWYWx1ZSk7CiAgICAgICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAxLAogICAgICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUywKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlOiBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21FbGxpcHNvaWQoZWxsaXBzb2lkT3V0ZXIpLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBlbGxpcHNvaWRHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZEdlb21ldHJ5LmdldFVuaXRFbGxpcHNvaWQgPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1bml0RWxsaXBzb2lkR2VvbWV0cnkpKSB7CiAgICAgICAgICB1bml0RWxsaXBzb2lkR2VvbWV0cnkgPSBFbGxpcHNvaWRHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSgKICAgICAgICAgICAgbmV3IEVsbGlwc29pZEdlb21ldHJ5KHsKICAgICAgICAgICAgICByYWRpaTogbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgxLCAxLCAxKSwKICAgICAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IFZlcnRleEZvcm1hdF9kZWZhdWx0LlBPU0lUSU9OX09OTFkKICAgICAgICAgICAgfSkKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB1bml0RWxsaXBzb2lkR2VvbWV0cnk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZEdlb21ldHJ5X2RlZmF1bHQgPSBFbGxpcHNvaWRHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUVsbGlwc29pZEdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUVsbGlwc29pZEdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVFbGxpcHNvaWRHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVFbGxpcHNvaWRHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlRWxsaXBzb2lkR2VvbWV0cnkoZWxsaXBzb2lkR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGVsbGlwc29pZEdlb21ldHJ5ID0gRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdC51bnBhY2soZWxsaXBzb2lkR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICByZXR1cm4gRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShlbGxpcHNvaWRHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVFbGxpcHNvaWRHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUVsbGlwc29pZEdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVFbGxpcHNvaWRHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZEdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZUVsbGlwc29pZEdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVFbGxpcHNvaWRHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0VsbGlwc29pZE91dGxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICBjb25zdCByYWRpaSA9IG9wdGlvbnMucmFkaWkgPz8gZGVmYXVsdFJhZGlpMjsKICAgIGNvbnN0IGlubmVyUmFkaWkgPSBvcHRpb25zLmlubmVyUmFkaWkgPz8gcmFkaWk7CiAgICBjb25zdCBtaW5pbXVtQ2xvY2sgPSBvcHRpb25zLm1pbmltdW1DbG9jayA/PyAwOwogICAgY29uc3QgbWF4aW11bUNsb2NrID0gb3B0aW9ucy5tYXhpbXVtQ2xvY2sgPz8gTWF0aF9kZWZhdWx0LlRXT19QSTsKICAgIGNvbnN0IG1pbmltdW1Db25lID0gb3B0aW9ucy5taW5pbXVtQ29uZSA/PyAwOwogICAgY29uc3QgbWF4aW11bUNvbmUgPSBvcHRpb25zLm1heGltdW1Db25lID8/IE1hdGhfZGVmYXVsdC5QSTsKICAgIGNvbnN0IHN0YWNrUGFydGl0aW9ucyA9IE1hdGgucm91bmQob3B0aW9ucy5zdGFja1BhcnRpdGlvbnMgPz8gMTApOwogICAgY29uc3Qgc2xpY2VQYXJ0aXRpb25zID0gTWF0aC5yb3VuZChvcHRpb25zLnNsaWNlUGFydGl0aW9ucyA/PyA4KTsKICAgIGNvbnN0IHN1YmRpdmlzaW9ucyA9IE1hdGgucm91bmQob3B0aW9ucy5zdWJkaXZpc2lvbnMgPz8gMTI4KTsKICAgIGlmIChzdGFja1BhcnRpdGlvbnMgPCAxKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcHRpb25zLnN0YWNrUGFydGl0aW9ucyBjYW5ub3QgYmUgbGVzcyB0aGFuIDEiKTsKICAgIH0KICAgIGlmIChzbGljZVBhcnRpdGlvbnMgPCAwKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcHRpb25zLnNsaWNlUGFydGl0aW9ucyBjYW5ub3QgYmUgbGVzcyB0aGFuIDAiKTsKICAgIH0KICAgIGlmIChzdWJkaXZpc2lvbnMgPCAwKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnN1YmRpdmlzaW9ucyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB6ZXJvLiIKICAgICAgKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpICYmIG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUuVE9QIGlzIG5vdCBhIHN1cHBvcnRlZCBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSBmb3IgdGhpcyBnZW9tZXRyeS4iCiAgICAgICk7CiAgICB9CiAgICB0aGlzLl9yYWRpaSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShyYWRpaSk7CiAgICB0aGlzLl9pbm5lclJhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGlubmVyUmFkaWkpOwogICAgdGhpcy5fbWluaW11bUNsb2NrID0gbWluaW11bUNsb2NrOwogICAgdGhpcy5fbWF4aW11bUNsb2NrID0gbWF4aW11bUNsb2NrOwogICAgdGhpcy5fbWluaW11bUNvbmUgPSBtaW5pbXVtQ29uZTsKICAgIHRoaXMuX21heGltdW1Db25lID0gbWF4aW11bUNvbmU7CiAgICB0aGlzLl9zdGFja1BhcnRpdGlvbnMgPSBzdGFja1BhcnRpdGlvbnM7CiAgICB0aGlzLl9zbGljZVBhcnRpdGlvbnMgPSBzbGljZVBhcnRpdGlvbnM7CiAgICB0aGlzLl9zdWJkaXZpc2lvbnMgPSBzdWJkaXZpc2lvbnM7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5IjsKICB9CiAgdmFyIGRlZmF1bHRSYWRpaTIsIGNvczIsIHNpbjIsIHNjcmF0Y2hSYWRpaTIsIHNjcmF0Y2hJbm5lclJhZGlpMiwgc2NyYXRjaE9wdGlvbnMxNCwgRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGRlZmF1bHRSYWRpaTIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KDEsIDEsIDEpOwogICAgICBjb3MyID0gTWF0aC5jb3M7CiAgICAgIHNpbjIgPSBNYXRoLnNpbjsKICAgICAgRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IDIgKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgODsKICAgICAgRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2YWx1ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ2YWx1ZSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZhbHVlLl9yYWRpaSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayh2YWx1ZS5faW5uZXJSYWRpaSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX21pbmltdW1DbG9jazsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX21heGltdW1DbG9jazsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX21pbmltdW1Db25lOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fbWF4aW11bUNvbmU7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zdGFja1BhcnRpdGlvbnM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zbGljZVBhcnRpdGlvbnM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9zdWJkaXZpc2lvbnM7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaFJhZGlpMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaElubmVyUmFkaWkyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczE0ID0gewogICAgICAgIHJhZGlpOiBzY3JhdGNoUmFkaWkyLAogICAgICAgIGlubmVyUmFkaWk6IHNjcmF0Y2hJbm5lclJhZGlpMiwKICAgICAgICBtaW5pbXVtQ2xvY2s6IHZvaWQgMCwKICAgICAgICBtYXhpbXVtQ2xvY2s6IHZvaWQgMCwKICAgICAgICBtaW5pbXVtQ29uZTogdm9pZCAwLAogICAgICAgIG1heGltdW1Db25lOiB2b2lkIDAsCiAgICAgICAgc3RhY2tQYXJ0aXRpb25zOiB2b2lkIDAsCiAgICAgICAgc2xpY2VQYXJ0aXRpb25zOiB2b2lkIDAsCiAgICAgICAgc3ViZGl2aXNpb25zOiB2b2lkIDAsCiAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiB2b2lkIDAKICAgICAgfTsKICAgICAgRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IHJhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaFJhZGlpMik7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGlubmVyUmFkaWkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4LCBzY3JhdGNoSW5uZXJSYWRpaTIpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBtaW5pbXVtQ2xvY2sgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG1heGltdW1DbG9jayA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgbWluaW11bUNvbmUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IG1heGltdW1Db25lID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBzdGFja1BhcnRpdGlvbnMgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHNsaWNlUGFydGl0aW9ucyA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc3ViZGl2aXNpb25zID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE0Lm1pbmltdW1DbG9jayA9IG1pbmltdW1DbG9jazsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTQubWF4aW11bUNsb2NrID0gbWF4aW11bUNsb2NrOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNC5taW5pbXVtQ29uZSA9IG1pbmltdW1Db25lOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNC5tYXhpbXVtQ29uZSA9IG1heGltdW1Db25lOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNC5zdGFja1BhcnRpdGlvbnMgPSBzdGFja1BhcnRpdGlvbnM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE0LnNsaWNlUGFydGl0aW9ucyA9IHNsaWNlUGFydGl0aW9uczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTQuc3ViZGl2aXNpb25zID0gc3ViZGl2aXNpb25zOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNC5vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgcmV0dXJuIG5ldyBFbGxpcHNvaWRPdXRsaW5lR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnMxNCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fcmFkaWkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocmFkaWksIHJlc3VsdC5fcmFkaWkpOwogICAgICAgIHJlc3VsdC5faW5uZXJSYWRpaSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShpbm5lclJhZGlpLCByZXN1bHQuX2lubmVyUmFkaWkpOwogICAgICAgIHJlc3VsdC5fbWluaW11bUNsb2NrID0gbWluaW11bUNsb2NrOwogICAgICAgIHJlc3VsdC5fbWF4aW11bUNsb2NrID0gbWF4aW11bUNsb2NrOwogICAgICAgIHJlc3VsdC5fbWluaW11bUNvbmUgPSBtaW5pbXVtQ29uZTsKICAgICAgICByZXN1bHQuX21heGltdW1Db25lID0gbWF4aW11bUNvbmU7CiAgICAgICAgcmVzdWx0Ll9zdGFja1BhcnRpdGlvbnMgPSBzdGFja1BhcnRpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9zbGljZVBhcnRpdGlvbnMgPSBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9zdWJkaXZpc2lvbnMgPSBzdWJkaXZpc2lvbnM7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKGVsbGlwc29pZEdlb21ldHJ5KSB7CiAgICAgICAgY29uc3QgcmFkaWkgPSBlbGxpcHNvaWRHZW9tZXRyeS5fcmFkaWk7CiAgICAgICAgaWYgKHJhZGlpLnggPD0gMCB8fCByYWRpaS55IDw9IDAgfHwgcmFkaWkueiA8PSAwKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IGlubmVyUmFkaWkgPSBlbGxpcHNvaWRHZW9tZXRyeS5faW5uZXJSYWRpaTsKICAgICAgICBpZiAoaW5uZXJSYWRpaS54IDw9IDAgfHwgaW5uZXJSYWRpaS55IDw9IDAgfHwgaW5uZXJSYWRpaS56IDw9IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgbWluaW11bUNsb2NrID0gZWxsaXBzb2lkR2VvbWV0cnkuX21pbmltdW1DbG9jazsKICAgICAgICBjb25zdCBtYXhpbXVtQ2xvY2sgPSBlbGxpcHNvaWRHZW9tZXRyeS5fbWF4aW11bUNsb2NrOwogICAgICAgIGNvbnN0IG1pbmltdW1Db25lID0gZWxsaXBzb2lkR2VvbWV0cnkuX21pbmltdW1Db25lOwogICAgICAgIGNvbnN0IG1heGltdW1Db25lID0gZWxsaXBzb2lkR2VvbWV0cnkuX21heGltdW1Db25lOwogICAgICAgIGNvbnN0IHN1YmRpdmlzaW9ucyA9IGVsbGlwc29pZEdlb21ldHJ5Ll9zdWJkaXZpc2lvbnM7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZnJvbUNhcnRlc2lhbjMocmFkaWkpOwogICAgICAgIGxldCBzbGljZVBhcnRpdGlvbnMgPSBlbGxpcHNvaWRHZW9tZXRyeS5fc2xpY2VQYXJ0aXRpb25zICsgMTsKICAgICAgICBsZXQgc3RhY2tQYXJ0aXRpb25zID0gZWxsaXBzb2lkR2VvbWV0cnkuX3N0YWNrUGFydGl0aW9ucyArIDE7CiAgICAgICAgc2xpY2VQYXJ0aXRpb25zID0gTWF0aC5yb3VuZCgKICAgICAgICAgIHNsaWNlUGFydGl0aW9ucyAqIE1hdGguYWJzKG1heGltdW1DbG9jayAtIG1pbmltdW1DbG9jaykgLyBNYXRoX2RlZmF1bHQuVFdPX1BJCiAgICAgICAgKTsKICAgICAgICBzdGFja1BhcnRpdGlvbnMgPSBNYXRoLnJvdW5kKAogICAgICAgICAgc3RhY2tQYXJ0aXRpb25zICogTWF0aC5hYnMobWF4aW11bUNvbmUgLSBtaW5pbXVtQ29uZSkgLyBNYXRoX2RlZmF1bHQuUEkKICAgICAgICApOwogICAgICAgIGlmIChzbGljZVBhcnRpdGlvbnMgPCAyKSB7CiAgICAgICAgICBzbGljZVBhcnRpdGlvbnMgPSAyOwogICAgICAgIH0KICAgICAgICBpZiAoc3RhY2tQYXJ0aXRpb25zIDwgMikgewogICAgICAgICAgc3RhY2tQYXJ0aXRpb25zID0gMjsKICAgICAgICB9CiAgICAgICAgbGV0IGV4dHJhSW5kaWNlcyA9IDA7CiAgICAgICAgbGV0IHZlcnRleE11bHRpcGxpZXIgPSAxOwogICAgICAgIGNvbnN0IGhhc0lubmVyU3VyZmFjZSA9IGlubmVyUmFkaWkueCAhPT0gcmFkaWkueCB8fCBpbm5lclJhZGlpLnkgIT09IHJhZGlpLnkgfHwgaW5uZXJSYWRpaS56ICE9PSByYWRpaS56OwogICAgICAgIGxldCBpc1RvcE9wZW4gPSBmYWxzZTsKICAgICAgICBsZXQgaXNCb3RPcGVuID0gZmFsc2U7CiAgICAgICAgaWYgKGhhc0lubmVyU3VyZmFjZSkgewogICAgICAgICAgdmVydGV4TXVsdGlwbGllciA9IDI7CiAgICAgICAgICBpZiAobWluaW11bUNvbmUgPiAwKSB7CiAgICAgICAgICAgIGlzVG9wT3BlbiA9IHRydWU7CiAgICAgICAgICAgIGV4dHJhSW5kaWNlcyArPSBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobWF4aW11bUNvbmUgPCBNYXRoLlBJKSB7CiAgICAgICAgICAgIGlzQm90T3BlbiA9IHRydWU7CiAgICAgICAgICAgIGV4dHJhSW5kaWNlcyArPSBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IHZlcnRleENvdW50ID0gc3ViZGl2aXNpb25zICogdmVydGV4TXVsdGlwbGllciAqIChzdGFja1BhcnRpdGlvbnMgKyBzbGljZVBhcnRpdGlvbnMpOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkodmVydGV4Q291bnQgKiAzKTsKICAgICAgICBjb25zdCBudW1JbmRpY2VzID0gMiAqICh2ZXJ0ZXhDb3VudCArIGV4dHJhSW5kaWNlcyAtIChzbGljZVBhcnRpdGlvbnMgKyBzdGFja1BhcnRpdGlvbnMpICogdmVydGV4TXVsdGlwbGllcik7CiAgICAgICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KHZlcnRleENvdW50LCBudW1JbmRpY2VzKTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IGoyOwogICAgICAgIGxldCB0aGV0YTsKICAgICAgICBsZXQgcGhpOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgY29uc3Qgc2luUGhpID0gbmV3IEFycmF5KHN0YWNrUGFydGl0aW9ucyk7CiAgICAgICAgY29uc3QgY29zUGhpID0gbmV3IEFycmF5KHN0YWNrUGFydGl0aW9ucyk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc3RhY2tQYXJ0aXRpb25zOyBpMisrKSB7CiAgICAgICAgICBwaGkgPSBtaW5pbXVtQ29uZSArIGkyICogKG1heGltdW1Db25lIC0gbWluaW11bUNvbmUpIC8gKHN0YWNrUGFydGl0aW9ucyAtIDEpOwogICAgICAgICAgc2luUGhpW2kyXSA9IHNpbjIocGhpKTsKICAgICAgICAgIGNvc1BoaVtpMl0gPSBjb3MyKHBoaSk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHNpblRoZXRhID0gbmV3IEFycmF5KHN1YmRpdmlzaW9ucyk7CiAgICAgICAgY29uc3QgY29zVGhldGEgPSBuZXcgQXJyYXkoc3ViZGl2aXNpb25zKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzdWJkaXZpc2lvbnM7IGkyKyspIHsKICAgICAgICAgIHRoZXRhID0gbWluaW11bUNsb2NrICsgaTIgKiAobWF4aW11bUNsb2NrIC0gbWluaW11bUNsb2NrKSAvIChzdWJkaXZpc2lvbnMgLSAxKTsKICAgICAgICAgIHNpblRoZXRhW2kyXSA9IHNpbjIodGhldGEpOwogICAgICAgICAgY29zVGhldGFbaTJdID0gY29zMih0aGV0YSk7CiAgICAgICAgfQogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHN0YWNrUGFydGl0aW9uczsgaTIrKykgewogICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc3ViZGl2aXNpb25zOyBqMisrKSB7CiAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHJhZGlpLnggKiBzaW5QaGlbaTJdICogY29zVGhldGFbajJdOwogICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSByYWRpaS55ICogc2luUGhpW2kyXSAqIHNpblRoZXRhW2oyXTsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gcmFkaWkueiAqIGNvc1BoaVtpMl07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChoYXNJbm5lclN1cmZhY2UpIHsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHN0YWNrUGFydGl0aW9uczsgaTIrKykgewogICAgICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBzdWJkaXZpc2lvbnM7IGoyKyspIHsKICAgICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBpbm5lclJhZGlpLnggKiBzaW5QaGlbaTJdICogY29zVGhldGFbajJdOwogICAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGlubmVyUmFkaWkueSAqIHNpblBoaVtpMl0gKiBzaW5UaGV0YVtqMl07CiAgICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gaW5uZXJSYWRpaS56ICogY29zUGhpW2kyXTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBzaW5QaGkubGVuZ3RoID0gc3ViZGl2aXNpb25zOwogICAgICAgIGNvc1BoaS5sZW5ndGggPSBzdWJkaXZpc2lvbnM7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc3ViZGl2aXNpb25zOyBpMisrKSB7CiAgICAgICAgICBwaGkgPSBtaW5pbXVtQ29uZSArIGkyICogKG1heGltdW1Db25lIC0gbWluaW11bUNvbmUpIC8gKHN1YmRpdmlzaW9ucyAtIDEpOwogICAgICAgICAgc2luUGhpW2kyXSA9IHNpbjIocGhpKTsKICAgICAgICAgIGNvc1BoaVtpMl0gPSBjb3MyKHBoaSk7CiAgICAgICAgfQogICAgICAgIHNpblRoZXRhLmxlbmd0aCA9IHNsaWNlUGFydGl0aW9uczsKICAgICAgICBjb3NUaGV0YS5sZW5ndGggPSBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc2xpY2VQYXJ0aXRpb25zOyBpMisrKSB7CiAgICAgICAgICB0aGV0YSA9IG1pbmltdW1DbG9jayArIGkyICogKG1heGltdW1DbG9jayAtIG1pbmltdW1DbG9jaykgLyAoc2xpY2VQYXJ0aXRpb25zIC0gMSk7CiAgICAgICAgICBzaW5UaGV0YVtpMl0gPSBzaW4yKHRoZXRhKTsKICAgICAgICAgIGNvc1RoZXRhW2kyXSA9IGNvczIodGhldGEpOwogICAgICAgIH0KICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzdWJkaXZpc2lvbnM7IGkyKyspIHsKICAgICAgICAgIGZvciAoajIgPSAwOyBqMiA8IHNsaWNlUGFydGl0aW9uczsgajIrKykgewogICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSByYWRpaS54ICogc2luUGhpW2kyXSAqIGNvc1RoZXRhW2oyXTsKICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gcmFkaWkueSAqIHNpblBoaVtpMl0gKiBzaW5UaGV0YVtqMl07CiAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHJhZGlpLnogKiBjb3NQaGlbaTJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoaGFzSW5uZXJTdXJmYWNlKSB7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzdWJkaXZpc2lvbnM7IGkyKyspIHsKICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc2xpY2VQYXJ0aXRpb25zOyBqMisrKSB7CiAgICAgICAgICAgICAgcG9zaXRpb25zW2luZGV4KytdID0gaW5uZXJSYWRpaS54ICogc2luUGhpW2kyXSAqIGNvc1RoZXRhW2oyXTsKICAgICAgICAgICAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBpbm5lclJhZGlpLnkgKiBzaW5QaGlbaTJdICogc2luVGhldGFbajJdOwogICAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGlubmVyUmFkaWkueiAqIGNvc1BoaVtpMl07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaW5kZXggPSAwOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHN0YWNrUGFydGl0aW9ucyAqIHZlcnRleE11bHRpcGxpZXI7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHRvcE9mZnNldCA9IGkyICogc3ViZGl2aXNpb25zOwogICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc3ViZGl2aXNpb25zIC0gMTsgajIrKykgewogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gdG9wT2Zmc2V0ICsgajI7CiAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0b3BPZmZzZXQgKyBqMiArIDE7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGxldCBvZmZzZXQgPSBzdGFja1BhcnRpdGlvbnMgKiBzdWJkaXZpc2lvbnMgKiB2ZXJ0ZXhNdWx0aXBsaWVyOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHNsaWNlUGFydGl0aW9uczsgaTIrKykgewogICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc3ViZGl2aXNpb25zIC0gMTsgajIrKykgewogICAgICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gb2Zmc2V0ICsgaTIgKyBqMiAqIHNsaWNlUGFydGl0aW9uczsKICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IG9mZnNldCArIGkyICsgKGoyICsgMSkgKiBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChoYXNJbm5lclN1cmZhY2UpIHsKICAgICAgICAgIG9mZnNldCA9IHN0YWNrUGFydGl0aW9ucyAqIHN1YmRpdmlzaW9ucyAqIHZlcnRleE11bHRpcGxpZXIgKyBzbGljZVBhcnRpdGlvbnMgKiBzdWJkaXZpc2lvbnM7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBzbGljZVBhcnRpdGlvbnM7IGkyKyspIHsKICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc3ViZGl2aXNpb25zIC0gMTsgajIrKykgewogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvZmZzZXQgKyBpMiArIGoyICogc2xpY2VQYXJ0aXRpb25zOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvZmZzZXQgKyBpMiArIChqMiArIDEpICogc2xpY2VQYXJ0aXRpb25zOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChoYXNJbm5lclN1cmZhY2UpIHsKICAgICAgICAgIGxldCBvdXRlck9mZnNldCA9IHN0YWNrUGFydGl0aW9ucyAqIHN1YmRpdmlzaW9ucyAqIHZlcnRleE11bHRpcGxpZXI7CiAgICAgICAgICBsZXQgaW5uZXJPZmZzZXQgPSBvdXRlck9mZnNldCArIHN1YmRpdmlzaW9ucyAqIHNsaWNlUGFydGl0aW9uczsKICAgICAgICAgIGlmIChpc1RvcE9wZW4pIHsKICAgICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgc2xpY2VQYXJ0aXRpb25zOyBpMisrKSB7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IG91dGVyT2Zmc2V0ICsgaTI7CiAgICAgICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGlubmVyT2Zmc2V0ICsgaTI7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGlmIChpc0JvdE9wZW4pIHsKICAgICAgICAgICAgb3V0ZXJPZmZzZXQgKz0gc3ViZGl2aXNpb25zICogc2xpY2VQYXJ0aXRpb25zIC0gc2xpY2VQYXJ0aXRpb25zOwogICAgICAgICAgICBpbm5lck9mZnNldCArPSBzdWJkaXZpc2lvbnMgKiBzbGljZVBhcnRpdGlvbnMgLSBzbGljZVBhcnRpdGlvbnM7CiAgICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHNsaWNlUGFydGl0aW9uczsgaTIrKykgewogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBvdXRlck9mZnNldCArIGkyOwogICAgICAgICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpbm5lck9mZnNldCArIGkyOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoewogICAgICAgICAgcG9zaXRpb246IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgICAgICAgfSkKICAgICAgICB9KTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGVsbGlwc29pZEdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBlbGxpcHNvaWRHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgIGNvbnN0IGFwcGx5T2Zmc2V0ID0gbmV3IFVpbnQ4QXJyYXkobGVuZ3RoIC8gMykuZmlsbChvZmZzZXRWYWx1ZSk7CiAgICAgICAgICBhdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAxLAogICAgICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbUVsbGlwc29pZChlbGxpcHNvaWQpLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBlbGxpcHNvaWRHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5KGVsbGlwc29pZEdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkR2VvbWV0cnkuYnVmZmVyLCBvZmZzZXQpKSB7CiAgICAgIGVsbGlwc29pZEdlb21ldHJ5ID0gRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgIGVsbGlwc29pZEdlb21ldHJ5LAogICAgICAgIG9mZnNldAogICAgICApOwogICAgfQogICAgcmV0dXJuIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KGVsbGlwc29pZEdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ3VsbGluZ1ZvbHVtZS5qcwogIGZ1bmN0aW9uIEN1bGxpbmdWb2x1bWUocGxhbmVzKSB7CiAgICB0aGlzLnBsYW5lcyA9IHBsYW5lcyA/PyBbXTsKICB9CiAgdmFyIGZhY2VzLCBzY3JhdGNoUGxhbmVDZW50ZXIsIHNjcmF0Y2hQbGFuZU5vcm1hbDIsIHNjcmF0Y2hQbGFuZTIsIEN1bGxpbmdWb2x1bWVfZGVmYXVsdDsKICB2YXIgaW5pdF9DdWxsaW5nVm9sdW1lID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DdWxsaW5nVm9sdW1lLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuNCgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0ludGVyc2VjdCgpOwogICAgICBpbml0X1BsYW5lKCk7CiAgICAgIGZhY2VzID0gW25ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCldOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWCwgZmFjZXNbMF0pOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWSwgZmFjZXNbMV0pOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWiwgZmFjZXNbMl0pOwogICAgICBzY3JhdGNoUGxhbmVDZW50ZXIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQbGFuZU5vcm1hbDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQbGFuZTIgPSBuZXcgUGxhbmVfZGVmYXVsdChuZXcgQ2FydGVzaWFuM19kZWZhdWx0KDEsIDAsIDApLCAwKTsKICAgICAgQ3VsbGluZ1ZvbHVtZS5mcm9tQm91bmRpbmdTcGhlcmUgPSBmdW5jdGlvbihib3VuZGluZ1NwaGVyZSwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm91bmRpbmdTcGhlcmUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYm91bmRpbmdTcGhlcmUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDdWxsaW5nVm9sdW1lKCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGxlbmd0aCA9IGZhY2VzLmxlbmd0aDsKICAgICAgICBjb25zdCBwbGFuZXMgPSByZXN1bHQucGxhbmVzOwogICAgICAgIHBsYW5lcy5sZW5ndGggPSAyICogbGVuZ3RoOwogICAgICAgIGNvbnN0IGNlbnRlciA9IGJvdW5kaW5nU3BoZXJlLmNlbnRlcjsKICAgICAgICBjb25zdCByYWRpdXMgPSBib3VuZGluZ1NwaGVyZS5yYWRpdXM7CiAgICAgICAgbGV0IHBsYW5lSW5kZXggPSAwOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgIGNvbnN0IGZhY2VOb3JtYWwgPSBmYWNlc1tpMl07CiAgICAgICAgICBsZXQgcGxhbmUwID0gcGxhbmVzW3BsYW5lSW5kZXhdOwogICAgICAgICAgbGV0IHBsYW5lMSA9IHBsYW5lc1twbGFuZUluZGV4ICsgMV07CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZTApKSB7CiAgICAgICAgICAgIHBsYW5lMCA9IHBsYW5lc1twbGFuZUluZGV4XSA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBsYW5lMSkpIHsKICAgICAgICAgICAgcGxhbmUxID0gcGxhbmVzW3BsYW5lSW5kZXggKyAxXSA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGZhY2VOb3JtYWwsIC1yYWRpdXMsIHNjcmF0Y2hQbGFuZUNlbnRlcik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGNlbnRlciwgc2NyYXRjaFBsYW5lQ2VudGVyLCBzY3JhdGNoUGxhbmVDZW50ZXIpOwogICAgICAgICAgcGxhbmUwLnggPSBmYWNlTm9ybWFsLng7CiAgICAgICAgICBwbGFuZTAueSA9IGZhY2VOb3JtYWwueTsKICAgICAgICAgIHBsYW5lMC56ID0gZmFjZU5vcm1hbC56OwogICAgICAgICAgcGxhbmUwLncgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdChmYWNlTm9ybWFsLCBzY3JhdGNoUGxhbmVDZW50ZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZmFjZU5vcm1hbCwgcmFkaXVzLCBzY3JhdGNoUGxhbmVDZW50ZXIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjZW50ZXIsIHNjcmF0Y2hQbGFuZUNlbnRlciwgc2NyYXRjaFBsYW5lQ2VudGVyKTsKICAgICAgICAgIHBsYW5lMS54ID0gLWZhY2VOb3JtYWwueDsKICAgICAgICAgIHBsYW5lMS55ID0gLWZhY2VOb3JtYWwueTsKICAgICAgICAgIHBsYW5lMS56ID0gLWZhY2VOb3JtYWwuejsKICAgICAgICAgIHBsYW5lMS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3QoCiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoZmFjZU5vcm1hbCwgc2NyYXRjaFBsYW5lTm9ybWFsMiksCiAgICAgICAgICAgIHNjcmF0Y2hQbGFuZUNlbnRlcgogICAgICAgICAgKTsKICAgICAgICAgIHBsYW5lSW5kZXggKz0gMjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgQ3VsbGluZ1ZvbHVtZS5wcm90b3R5cGUuY29tcHV0ZVZpc2liaWxpdHkgPSBmdW5jdGlvbihib3VuZGluZ1ZvbHVtZSkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJvdW5kaW5nVm9sdW1lKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImJvdW5kaW5nVm9sdW1lIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lczsKICAgICAgICBsZXQgaW50ZXJzZWN0aW5nID0gZmFsc2U7CiAgICAgICAgZm9yIChsZXQgazIgPSAwLCBsZW4gPSBwbGFuZXMubGVuZ3RoOyBrMiA8IGxlbjsgKytrMikgewogICAgICAgICAgY29uc3QgcmVzdWx0ID0gYm91bmRpbmdWb2x1bWUuaW50ZXJzZWN0UGxhbmUoCiAgICAgICAgICAgIFBsYW5lX2RlZmF1bHQuZnJvbUNhcnRlc2lhbjQocGxhbmVzW2syXSwgc2NyYXRjaFBsYW5lMikKICAgICAgICAgICk7CiAgICAgICAgICBpZiAocmVzdWx0ID09PSBJbnRlcnNlY3RfZGVmYXVsdC5PVVRTSURFKSB7CiAgICAgICAgICAgIHJldHVybiBJbnRlcnNlY3RfZGVmYXVsdC5PVVRTSURFOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQgPT09IEludGVyc2VjdF9kZWZhdWx0LklOVEVSU0VDVElORykgewogICAgICAgICAgICBpbnRlcnNlY3RpbmcgPSB0cnVlOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gaW50ZXJzZWN0aW5nID8gSW50ZXJzZWN0X2RlZmF1bHQuSU5URVJTRUNUSU5HIDogSW50ZXJzZWN0X2RlZmF1bHQuSU5TSURFOwogICAgICB9OwogICAgICBDdWxsaW5nVm9sdW1lLnByb3RvdHlwZS5jb21wdXRlVmlzaWJpbGl0eVdpdGhQbGFuZU1hc2sgPSBmdW5jdGlvbihib3VuZGluZ1ZvbHVtZSwgcGFyZW50UGxhbmVNYXNrKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYm91bmRpbmdWb2x1bWUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYm91bmRpbmdWb2x1bWUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBhcmVudFBsYW5lTWFzaykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwYXJlbnRQbGFuZU1hc2sgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmIChwYXJlbnRQbGFuZU1hc2sgPT09IEN1bGxpbmdWb2x1bWUuTUFTS19PVVRTSURFIHx8IHBhcmVudFBsYW5lTWFzayA9PT0gQ3VsbGluZ1ZvbHVtZS5NQVNLX0lOU0lERSkgewogICAgICAgICAgcmV0dXJuIHBhcmVudFBsYW5lTWFzazsKICAgICAgICB9CiAgICAgICAgbGV0IG1hc2sgPSBDdWxsaW5nVm9sdW1lLk1BU0tfSU5TSURFOwogICAgICAgIGNvbnN0IHBsYW5lcyA9IHRoaXMucGxhbmVzOwogICAgICAgIGZvciAobGV0IGsyID0gMCwgbGVuID0gcGxhbmVzLmxlbmd0aDsgazIgPCBsZW47ICsrazIpIHsKICAgICAgICAgIGNvbnN0IGZsYWcgPSBrMiA8IDMxID8gMSA8PCBrMiA6IDA7CiAgICAgICAgICBpZiAoazIgPCAzMSAmJiAocGFyZW50UGxhbmVNYXNrICYgZmxhZykgPT09IDApIHsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCByZXN1bHQgPSBib3VuZGluZ1ZvbHVtZS5pbnRlcnNlY3RQbGFuZSgKICAgICAgICAgICAgUGxhbmVfZGVmYXVsdC5mcm9tQ2FydGVzaWFuNChwbGFuZXNbazJdLCBzY3JhdGNoUGxhbmUyKQogICAgICAgICAgKTsKICAgICAgICAgIGlmIChyZXN1bHQgPT09IEludGVyc2VjdF9kZWZhdWx0Lk9VVFNJREUpIHsKICAgICAgICAgICAgcmV0dXJuIEN1bGxpbmdWb2x1bWUuTUFTS19PVVRTSURFOwogICAgICAgICAgfSBlbHNlIGlmIChyZXN1bHQgPT09IEludGVyc2VjdF9kZWZhdWx0LklOVEVSU0VDVElORykgewogICAgICAgICAgICBtYXNrIHw9IGZsYWc7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBtYXNrOwogICAgICB9OwogICAgICBDdWxsaW5nVm9sdW1lLk1BU0tfT1VUU0lERSA9IDQyOTQ5NjcyOTU7CiAgICAgIEN1bGxpbmdWb2x1bWUuTUFTS19JTlNJREUgPSAwOwogICAgICBDdWxsaW5nVm9sdW1lLk1BU0tfSU5ERVRFUk1JTkFURSA9IDIxNDc0ODM2NDc7CiAgICAgIEN1bGxpbmdWb2x1bWVfZGVmYXVsdCA9IEN1bGxpbmdWb2x1bWU7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9PcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtLmpzCiAgZnVuY3Rpb24gT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICB0aGlzLmxlZnQgPSBvcHRpb25zLmxlZnQ7CiAgICB0aGlzLl9sZWZ0ID0gdm9pZCAwOwogICAgdGhpcy5yaWdodCA9IG9wdGlvbnMucmlnaHQ7CiAgICB0aGlzLl9yaWdodCA9IHZvaWQgMDsKICAgIHRoaXMudG9wID0gb3B0aW9ucy50b3A7CiAgICB0aGlzLl90b3AgPSB2b2lkIDA7CiAgICB0aGlzLmJvdHRvbSA9IG9wdGlvbnMuYm90dG9tOwogICAgdGhpcy5fYm90dG9tID0gdm9pZCAwOwogICAgdGhpcy5uZWFyID0gb3B0aW9ucy5uZWFyID8/IDE7CiAgICB0aGlzLl9uZWFyID0gdGhpcy5uZWFyOwogICAgdGhpcy5mYXIgPSBvcHRpb25zLmZhciA/PyA1ZTg7CiAgICB0aGlzLl9mYXIgPSB0aGlzLmZhcjsKICAgIHRoaXMuX2N1bGxpbmdWb2x1bWUgPSBuZXcgQ3VsbGluZ1ZvbHVtZV9kZWZhdWx0KCk7CiAgICB0aGlzLl9vcnRob2dyYXBoaWNNYXRyaXggPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgfQogIGZ1bmN0aW9uIHVwZGF0ZShmcnVzdHVtKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLnJpZ2h0KSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0ubGVmdCkgfHwgIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLnRvcCkgfHwgIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLmJvdHRvbSkgfHwgIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLm5lYXIpIHx8ICFkZWZpbmVkX2RlZmF1bHQoZnJ1c3R1bS5mYXIpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJyaWdodCwgbGVmdCwgdG9wLCBib3R0b20sIG5lYXIsIG9yIGZhciBwYXJhbWV0ZXJzIGFyZSBub3Qgc2V0LiIKICAgICAgKTsKICAgIH0KICAgIGlmIChmcnVzdHVtLnRvcCAhPT0gZnJ1c3R1bS5fdG9wIHx8IGZydXN0dW0uYm90dG9tICE9PSBmcnVzdHVtLl9ib3R0b20gfHwgZnJ1c3R1bS5sZWZ0ICE9PSBmcnVzdHVtLl9sZWZ0IHx8IGZydXN0dW0ucmlnaHQgIT09IGZydXN0dW0uX3JpZ2h0IHx8IGZydXN0dW0ubmVhciAhPT0gZnJ1c3R1bS5fbmVhciB8fCBmcnVzdHVtLmZhciAhPT0gZnJ1c3R1bS5fZmFyKSB7CiAgICAgIGlmIChmcnVzdHVtLmxlZnQgPiBmcnVzdHVtLnJpZ2h0KSB7CiAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJpZ2h0IG11c3QgYmUgZ3JlYXRlciB0aGFuIGxlZnQuIik7CiAgICAgIH0KICAgICAgaWYgKGZydXN0dW0uYm90dG9tID4gZnJ1c3R1bS50b3ApIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidG9wIG11c3QgYmUgZ3JlYXRlciB0aGFuIGJvdHRvbS4iKTsKICAgICAgfQogICAgICBpZiAoZnJ1c3R1bS5uZWFyIDw9IDAgfHwgZnJ1c3R1bS5uZWFyID4gZnJ1c3R1bS5mYXIpIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICJuZWFyIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8gYW5kIGxlc3MgdGhhbiBmYXIuIgogICAgICAgICk7CiAgICAgIH0KICAgICAgZnJ1c3R1bS5fbGVmdCA9IGZydXN0dW0ubGVmdDsKICAgICAgZnJ1c3R1bS5fcmlnaHQgPSBmcnVzdHVtLnJpZ2h0OwogICAgICBmcnVzdHVtLl90b3AgPSBmcnVzdHVtLnRvcDsKICAgICAgZnJ1c3R1bS5fYm90dG9tID0gZnJ1c3R1bS5ib3R0b207CiAgICAgIGZydXN0dW0uX25lYXIgPSBmcnVzdHVtLm5lYXI7CiAgICAgIGZydXN0dW0uX2ZhciA9IGZydXN0dW0uZmFyOwogICAgICBmcnVzdHVtLl9vcnRob2dyYXBoaWNNYXRyaXggPSBNYXRyaXg0X2RlZmF1bHQuY29tcHV0ZU9ydGhvZ3JhcGhpY09mZkNlbnRlcigKICAgICAgICBmcnVzdHVtLmxlZnQsCiAgICAgICAgZnJ1c3R1bS5yaWdodCwKICAgICAgICBmcnVzdHVtLmJvdHRvbSwKICAgICAgICBmcnVzdHVtLnRvcCwKICAgICAgICBmcnVzdHVtLm5lYXIsCiAgICAgICAgZnJ1c3R1bS5mYXIsCiAgICAgICAgZnJ1c3R1bS5fb3J0aG9ncmFwaGljTWF0cml4CiAgICAgICk7CiAgICB9CiAgfQogIHZhciBnZXRQbGFuZXNSaWdodCwgZ2V0UGxhbmVzTmVhckNlbnRlciwgZ2V0UGxhbmVzUG9pbnQsIG5lZ2F0ZVNjcmF0Y2gsIE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW1fZGVmYXVsdDsKICB2YXIgaW5pdF9PcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9PcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuNCgpOwogICAgICBpbml0X0N1bGxpbmdWb2x1bWUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhPcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtLnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIG9ydGhvZ3JhcGhpYyBwcm9qZWN0aW9uIG1hdHJpeCBjb21wdXRlZCBmcm9tIHRoZSB2aWV3IGZydXN0dW0uCiAgICAgICAgICogQG1lbWJlcm9mIE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge01hdHJpeDR9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgcHJvamVjdGlvbk1hdHJpeDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgdXBkYXRlKHRoaXMpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5fb3J0aG9ncmFwaGljTWF0cml4OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIGdldFBsYW5lc1JpZ2h0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBnZXRQbGFuZXNOZWFyQ2VudGVyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBnZXRQbGFuZXNQb2ludCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgbmVnYXRlU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bS5wcm90b3R5cGUuY29tcHV0ZUN1bGxpbmdWb2x1bWUgPSBmdW5jdGlvbihwb3NpdGlvbiwgZGlyZWN0aW9uMiwgdXApIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwb3NpdGlvbiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZGlyZWN0aW9uMikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkaXJlY3Rpb24gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHVwKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInVwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBwbGFuZXMgPSB0aGlzLl9jdWxsaW5nVm9sdW1lLnBsYW5lczsKICAgICAgICBjb25zdCB0MiA9IHRoaXMudG9wOwogICAgICAgIGNvbnN0IGIyID0gdGhpcy5ib3R0b207CiAgICAgICAgY29uc3QgcjIgPSB0aGlzLnJpZ2h0OwogICAgICAgIGNvbnN0IGwyID0gdGhpcy5sZWZ0OwogICAgICAgIGNvbnN0IG4yID0gdGhpcy5uZWFyOwogICAgICAgIGNvbnN0IGYyID0gdGhpcy5mYXI7CiAgICAgICAgY29uc3QgcmlnaHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoZGlyZWN0aW9uMiwgdXAsIGdldFBsYW5lc1JpZ2h0KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHJpZ2h0LCByaWdodCk7CiAgICAgICAgY29uc3QgbmVhckNlbnRlciA9IGdldFBsYW5lc05lYXJDZW50ZXI7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZGlyZWN0aW9uMiwgbjIsIG5lYXJDZW50ZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIG5lYXJDZW50ZXIsIG5lYXJDZW50ZXIpOwogICAgICAgIGNvbnN0IHBvaW50ID0gZ2V0UGxhbmVzUG9pbnQ7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIocmlnaHQsIGwyLCBwb2ludCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBwb2ludCwgcG9pbnQpOwogICAgICAgIGxldCBwbGFuZSA9IHBsYW5lc1swXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzBdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gcmlnaHQueDsKICAgICAgICBwbGFuZS55ID0gcmlnaHQueTsKICAgICAgICBwbGFuZS56ID0gcmlnaHQuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3QocmlnaHQsIHBvaW50KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihyaWdodCwgcjIsIHBvaW50KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKG5lYXJDZW50ZXIsIHBvaW50LCBwb2ludCk7CiAgICAgICAgcGxhbmUgPSBwbGFuZXNbMV07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocGxhbmUpKSB7CiAgICAgICAgICBwbGFuZSA9IHBsYW5lc1sxXSA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgcGxhbmUueCA9IC1yaWdodC54OwogICAgICAgIHBsYW5lLnkgPSAtcmlnaHQueTsKICAgICAgICBwbGFuZS56ID0gLXJpZ2h0Lno7CiAgICAgICAgcGxhbmUudyA9IC1DYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUocmlnaHQsIG5lZ2F0ZVNjcmF0Y2gpLCBwb2ludCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIodXAsIGIyLCBwb2ludCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBwb2ludCwgcG9pbnQpOwogICAgICAgIHBsYW5lID0gcGxhbmVzWzJdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBsYW5lKSkgewogICAgICAgICAgcGxhbmUgPSBwbGFuZXNbMl0gPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIHBsYW5lLnggPSB1cC54OwogICAgICAgIHBsYW5lLnkgPSB1cC55OwogICAgICAgIHBsYW5lLnogPSB1cC56OwogICAgICAgIHBsYW5lLncgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh1cCwgcG9pbnQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHVwLCB0MiwgcG9pbnQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobmVhckNlbnRlciwgcG9pbnQsIHBvaW50KTsKICAgICAgICBwbGFuZSA9IHBsYW5lc1szXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzNdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gLXVwLng7CiAgICAgICAgcGxhbmUueSA9IC11cC55OwogICAgICAgIHBsYW5lLnogPSAtdXAuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3QoQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZSh1cCwgbmVnYXRlU2NyYXRjaCksIHBvaW50KTsKICAgICAgICBwbGFuZSA9IHBsYW5lc1s0XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzRdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gZGlyZWN0aW9uMi54OwogICAgICAgIHBsYW5lLnkgPSBkaXJlY3Rpb24yLnk7CiAgICAgICAgcGxhbmUueiA9IGRpcmVjdGlvbjIuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3QoZGlyZWN0aW9uMiwgbmVhckNlbnRlcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoZGlyZWN0aW9uMiwgZjIsIHBvaW50KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHBvc2l0aW9uLCBwb2ludCwgcG9pbnQpOwogICAgICAgIHBsYW5lID0gcGxhbmVzWzVdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBsYW5lKSkgewogICAgICAgICAgcGxhbmUgPSBwbGFuZXNbNV0gPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIHBsYW5lLnggPSAtZGlyZWN0aW9uMi54OwogICAgICAgIHBsYW5lLnkgPSAtZGlyZWN0aW9uMi55OwogICAgICAgIHBsYW5lLnogPSAtZGlyZWN0aW9uMi56OwogICAgICAgIHBsYW5lLncgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdChDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGRpcmVjdGlvbjIsIG5lZ2F0ZVNjcmF0Y2gpLCBwb2ludCk7CiAgICAgICAgcmV0dXJuIHRoaXMuX2N1bGxpbmdWb2x1bWU7CiAgICAgIH07CiAgICAgIE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmdldFBpeGVsRGltZW5zaW9ucyA9IGZ1bmN0aW9uKGRyYXdpbmdCdWZmZXJXaWR0aCwgZHJhd2luZ0J1ZmZlckhlaWdodCwgZGlzdGFuY2UsIHBpeGVsUmF0aW8sIHJlc3VsdCkgewogICAgICAgIHVwZGF0ZSh0aGlzKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkcmF3aW5nQnVmZmVyV2lkdGgpIHx8ICFkZWZpbmVkX2RlZmF1bHQoZHJhd2luZ0J1ZmZlckhlaWdodCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiQm90aCBkcmF3aW5nQnVmZmVyV2lkdGggYW5kIGRyYXdpbmdCdWZmZXJIZWlnaHQgYXJlIHJlcXVpcmVkLiIKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGlmIChkcmF3aW5nQnVmZmVyV2lkdGggPD0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRyYXdpbmdCdWZmZXJXaWR0aCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoZHJhd2luZ0J1ZmZlckhlaWdodCA8PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZHJhd2luZ0J1ZmZlckhlaWdodCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkaXN0YW5jZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkaXN0YW5jZSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocGl4ZWxSYXRpbykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJwaXhlbFJhdGlvIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAocGl4ZWxSYXRpbyA8PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicGl4ZWxSYXRpbyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiQSByZXN1bHQgb2JqZWN0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBmcnVzdHVtV2lkdGggPSB0aGlzLnJpZ2h0IC0gdGhpcy5sZWZ0OwogICAgICAgIGNvbnN0IGZydXN0dW1IZWlnaHQgPSB0aGlzLnRvcCAtIHRoaXMuYm90dG9tOwogICAgICAgIGNvbnN0IHBpeGVsV2lkdGggPSBwaXhlbFJhdGlvICogZnJ1c3R1bVdpZHRoIC8gZHJhd2luZ0J1ZmZlcldpZHRoOwogICAgICAgIGNvbnN0IHBpeGVsSGVpZ2h0ID0gcGl4ZWxSYXRpbyAqIGZydXN0dW1IZWlnaHQgLyBkcmF3aW5nQnVmZmVySGVpZ2h0OwogICAgICAgIHJlc3VsdC54ID0gcGl4ZWxXaWR0aDsKICAgICAgICByZXN1bHQueSA9IHBpeGVsSGVpZ2h0OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0oKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LmxlZnQgPSB0aGlzLmxlZnQ7CiAgICAgICAgcmVzdWx0LnJpZ2h0ID0gdGhpcy5yaWdodDsKICAgICAgICByZXN1bHQudG9wID0gdGhpcy50b3A7CiAgICAgICAgcmVzdWx0LmJvdHRvbSA9IHRoaXMuYm90dG9tOwogICAgICAgIHJlc3VsdC5uZWFyID0gdGhpcy5uZWFyOwogICAgICAgIHJlc3VsdC5mYXIgPSB0aGlzLmZhcjsKICAgICAgICByZXN1bHQuX2xlZnQgPSB2b2lkIDA7CiAgICAgICAgcmVzdWx0Ll9yaWdodCA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX3RvcCA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX2JvdHRvbSA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX25lYXIgPSB2b2lkIDA7CiAgICAgICAgcmVzdWx0Ll9mYXIgPSB2b2lkIDA7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bS5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24ob3RoZXIpIHsKICAgICAgICByZXR1cm4gZGVmaW5lZF9kZWZhdWx0KG90aGVyKSAmJiBvdGhlciBpbnN0YW5jZW9mIE9ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0gJiYgdGhpcy5yaWdodCA9PT0gb3RoZXIucmlnaHQgJiYgdGhpcy5sZWZ0ID09PSBvdGhlci5sZWZ0ICYmIHRoaXMudG9wID09PSBvdGhlci50b3AgJiYgdGhpcy5ib3R0b20gPT09IG90aGVyLmJvdHRvbSAmJiB0aGlzLm5lYXIgPT09IG90aGVyLm5lYXIgJiYgdGhpcy5mYXIgPT09IG90aGVyLmZhcjsKICAgICAgfTsKICAgICAgT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bS5wcm90b3R5cGUuZXF1YWxzRXBzaWxvbiA9IGZ1bmN0aW9uKG90aGVyLCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgIHJldHVybiBvdGhlciA9PT0gdGhpcyB8fCBkZWZpbmVkX2RlZmF1bHQob3RoZXIpICYmIG90aGVyIGluc3RhbmNlb2YgT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMucmlnaHQsCiAgICAgICAgICBvdGhlci5yaWdodCwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLmxlZnQsCiAgICAgICAgICBvdGhlci5sZWZ0LAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMudG9wLAogICAgICAgICAgb3RoZXIudG9wLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMuYm90dG9tLAogICAgICAgICAgb3RoZXIuYm90dG9tLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMubmVhciwKICAgICAgICAgIG90aGVyLm5lYXIsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgdGhpcy5mYXIsCiAgICAgICAgICBvdGhlci5mYXIsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApOwogICAgICB9OwogICAgICBPcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtX2RlZmF1bHQgPSBPcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvT3J0aG9ncmFwaGljRnJ1c3R1bS5qcwogIGZ1bmN0aW9uIE9ydGhvZ3JhcGhpY0ZydXN0dW0ob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bSA9IG5ldyBPcnRob2dyYXBoaWNPZmZDZW50ZXJGcnVzdHVtX2RlZmF1bHQoKTsKICAgIHRoaXMud2lkdGggPSBvcHRpb25zLndpZHRoOwogICAgdGhpcy5fd2lkdGggPSB2b2lkIDA7CiAgICB0aGlzLmFzcGVjdFJhdGlvID0gb3B0aW9ucy5hc3BlY3RSYXRpbzsKICAgIHRoaXMuX2FzcGVjdFJhdGlvID0gdm9pZCAwOwogICAgdGhpcy5uZWFyID0gb3B0aW9ucy5uZWFyID8/IDE7CiAgICB0aGlzLl9uZWFyID0gdGhpcy5uZWFyOwogICAgdGhpcy5mYXIgPSBvcHRpb25zLmZhciA/PyA1ZTg7CiAgICB0aGlzLl9mYXIgPSB0aGlzLmZhcjsKICB9CiAgZnVuY3Rpb24gdXBkYXRlMihmcnVzdHVtKSB7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLndpZHRoKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uYXNwZWN0UmF0aW8pIHx8ICFkZWZpbmVkX2RlZmF1bHQoZnJ1c3R1bS5uZWFyKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uZmFyKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAid2lkdGgsIGFzcGVjdFJhdGlvLCBuZWFyLCBvciBmYXIgcGFyYW1ldGVycyBhcmUgbm90IHNldC4iCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBmMiA9IGZydXN0dW0uX29mZkNlbnRlckZydXN0dW07CiAgICBpZiAoZnJ1c3R1bS53aWR0aCAhPT0gZnJ1c3R1bS5fd2lkdGggfHwgZnJ1c3R1bS5hc3BlY3RSYXRpbyAhPT0gZnJ1c3R1bS5fYXNwZWN0UmF0aW8gfHwgZnJ1c3R1bS5uZWFyICE9PSBmcnVzdHVtLl9uZWFyIHx8IGZydXN0dW0uZmFyICE9PSBmcnVzdHVtLl9mYXIpIHsKICAgICAgaWYgKGZydXN0dW0uYXNwZWN0UmF0aW8gPCAwKSB7CiAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFzcGVjdFJhdGlvIG11c3QgYmUgcG9zaXRpdmUuIik7CiAgICAgIH0KICAgICAgaWYgKGZydXN0dW0ubmVhciA8IDAgfHwgZnJ1c3R1bS5uZWFyID4gZnJ1c3R1bS5mYXIpIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICJuZWFyIG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8gYW5kIGxlc3MgdGhhbiBmYXIuIgogICAgICAgICk7CiAgICAgIH0KICAgICAgZnJ1c3R1bS5fYXNwZWN0UmF0aW8gPSBmcnVzdHVtLmFzcGVjdFJhdGlvOwogICAgICBmcnVzdHVtLl93aWR0aCA9IGZydXN0dW0ud2lkdGg7CiAgICAgIGZydXN0dW0uX25lYXIgPSBmcnVzdHVtLm5lYXI7CiAgICAgIGZydXN0dW0uX2ZhciA9IGZydXN0dW0uZmFyOwogICAgICBjb25zdCByYXRpbyA9IDEgLyBmcnVzdHVtLmFzcGVjdFJhdGlvOwogICAgICBmMi5yaWdodCA9IGZydXN0dW0ud2lkdGggKiAwLjU7CiAgICAgIGYyLmxlZnQgPSAtZjIucmlnaHQ7CiAgICAgIGYyLnRvcCA9IHJhdGlvICogZjIucmlnaHQ7CiAgICAgIGYyLmJvdHRvbSA9IC1mMi50b3A7CiAgICAgIGYyLm5lYXIgPSBmcnVzdHVtLm5lYXI7CiAgICAgIGYyLmZhciA9IGZydXN0dW0uZmFyOwogICAgfQogIH0KICB2YXIgT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0OwogIHZhciBpbml0X09ydGhvZ3JhcGhpY0ZydXN0dW0gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL09ydGhvZ3JhcGhpY0ZydXN0dW0uanMiKCkgewogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X09ydGhvZ3JhcGhpY09mZkNlbnRlckZydXN0dW0oKTsKICAgICAgT3J0aG9ncmFwaGljRnJ1c3R1bS5wYWNrZWRMZW5ndGggPSA0OwogICAgICBPcnRob2dyYXBoaWNGcnVzdHVtLnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUud2lkdGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLmFzcGVjdFJhdGlvOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5uZWFyOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWUuZmFyOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgT3J0aG9ncmFwaGljRnJ1c3R1bS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBPcnRob2dyYXBoaWNGcnVzdHVtKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC53aWR0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgcmVzdWx0LmFzcGVjdFJhdGlvID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQubmVhciA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgcmVzdWx0LmZhciA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKE9ydGhvZ3JhcGhpY0ZydXN0dW0ucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgb3J0aG9ncmFwaGljIHByb2plY3Rpb24gbWF0cml4IGNvbXB1dGVkIGZyb20gdGhlIHZpZXcgZnJ1c3R1bS4KICAgICAgICAgKiBAbWVtYmVyb2YgT3J0aG9ncmFwaGljRnJ1c3R1bS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7TWF0cml4NH0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBwcm9qZWN0aW9uTWF0cml4OiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICB1cGRhdGUyKHRoaXMpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bS5wcm9qZWN0aW9uTWF0cml4OwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdW5kZXJseWluZyB7QGxpbmsgT3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bX0KICAgICAgICAgKiBAbWVtYmVyb2YgT3J0aG9ncmFwaGljRnJ1c3R1bS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7T3J0aG9ncmFwaGljT2ZmQ2VudGVyRnJ1c3R1bX0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIG9mZkNlbnRlckZydXN0dW06IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHVwZGF0ZTIodGhpcyk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIE9ydGhvZ3JhcGhpY0ZydXN0dW0ucHJvdG90eXBlLmNvbXB1dGVDdWxsaW5nVm9sdW1lID0gZnVuY3Rpb24ocG9zaXRpb24sIGRpcmVjdGlvbjIsIHVwKSB7CiAgICAgICAgdXBkYXRlMih0aGlzKTsKICAgICAgICByZXR1cm4gdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bS5jb21wdXRlQ3VsbGluZ1ZvbHVtZShwb3NpdGlvbiwgZGlyZWN0aW9uMiwgdXApOwogICAgICB9OwogICAgICBPcnRob2dyYXBoaWNGcnVzdHVtLnByb3RvdHlwZS5nZXRQaXhlbERpbWVuc2lvbnMgPSBmdW5jdGlvbihkcmF3aW5nQnVmZmVyV2lkdGgsIGRyYXdpbmdCdWZmZXJIZWlnaHQsIGRpc3RhbmNlLCBwaXhlbFJhdGlvLCByZXN1bHQpIHsKICAgICAgICB1cGRhdGUyKHRoaXMpOwogICAgICAgIHJldHVybiB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLmdldFBpeGVsRGltZW5zaW9ucygKICAgICAgICAgIGRyYXdpbmdCdWZmZXJXaWR0aCwKICAgICAgICAgIGRyYXdpbmdCdWZmZXJIZWlnaHQsCiAgICAgICAgICBkaXN0YW5jZSwKICAgICAgICAgIHBpeGVsUmF0aW8sCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBPcnRob2dyYXBoaWNGcnVzdHVtLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uKHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBPcnRob2dyYXBoaWNGcnVzdHVtKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5hc3BlY3RSYXRpbyA9IHRoaXMuYXNwZWN0UmF0aW87CiAgICAgICAgcmVzdWx0LndpZHRoID0gdGhpcy53aWR0aDsKICAgICAgICByZXN1bHQubmVhciA9IHRoaXMubmVhcjsKICAgICAgICByZXN1bHQuZmFyID0gdGhpcy5mYXI7CiAgICAgICAgcmVzdWx0Ll9hc3BlY3RSYXRpbyA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX3dpZHRoID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fbmVhciA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX2ZhciA9IHZvaWQgMDsKICAgICAgICB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLmNsb25lKHJlc3VsdC5fb2ZmQ2VudGVyRnJ1c3R1bSk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgT3J0aG9ncmFwaGljRnJ1c3R1bS5wcm90b3R5cGUuZXF1YWxzID0gZnVuY3Rpb24ob3RoZXIpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvdGhlcikgfHwgIShvdGhlciBpbnN0YW5jZW9mIE9ydGhvZ3JhcGhpY0ZydXN0dW0pKSB7CiAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIHVwZGF0ZTIodGhpcyk7CiAgICAgICAgdXBkYXRlMihvdGhlcik7CiAgICAgICAgcmV0dXJuIHRoaXMud2lkdGggPT09IG90aGVyLndpZHRoICYmIHRoaXMuYXNwZWN0UmF0aW8gPT09IG90aGVyLmFzcGVjdFJhdGlvICYmIHRoaXMuX29mZkNlbnRlckZydXN0dW0uZXF1YWxzKG90aGVyLl9vZmZDZW50ZXJGcnVzdHVtKTsKICAgICAgfTsKICAgICAgT3J0aG9ncmFwaGljRnJ1c3R1bS5wcm90b3R5cGUuZXF1YWxzRXBzaWxvbiA9IGZ1bmN0aW9uKG90aGVyLCByZWxhdGl2ZUVwc2lsb24sIGFic29sdXRlRXBzaWxvbikgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG90aGVyKSB8fCAhKG90aGVyIGluc3RhbmNlb2YgT3J0aG9ncmFwaGljRnJ1c3R1bSkpIHsKICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgdXBkYXRlMih0aGlzKTsKICAgICAgICB1cGRhdGUyKG90aGVyKTsKICAgICAgICByZXR1cm4gTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLndpZHRoLAogICAgICAgICAgb3RoZXIud2lkdGgsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgdGhpcy5hc3BlY3RSYXRpbywKICAgICAgICAgIG90aGVyLmFzcGVjdFJhdGlvLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBvdGhlci5fb2ZmQ2VudGVyRnJ1c3R1bSwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICk7CiAgICAgIH07CiAgICAgIE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdCA9IE9ydGhvZ3JhcGhpY0ZydXN0dW07CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0uanMKICBmdW5jdGlvbiBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgdGhpcy5sZWZ0ID0gb3B0aW9ucy5sZWZ0OwogICAgdGhpcy5fbGVmdCA9IHZvaWQgMDsKICAgIHRoaXMucmlnaHQgPSBvcHRpb25zLnJpZ2h0OwogICAgdGhpcy5fcmlnaHQgPSB2b2lkIDA7CiAgICB0aGlzLnRvcCA9IG9wdGlvbnMudG9wOwogICAgdGhpcy5fdG9wID0gdm9pZCAwOwogICAgdGhpcy5ib3R0b20gPSBvcHRpb25zLmJvdHRvbTsKICAgIHRoaXMuX2JvdHRvbSA9IHZvaWQgMDsKICAgIHRoaXMubmVhciA9IG9wdGlvbnMubmVhciA/PyAxOwogICAgdGhpcy5fbmVhciA9IHRoaXMubmVhcjsKICAgIHRoaXMuZmFyID0gb3B0aW9ucy5mYXIgPz8gNWU4OwogICAgdGhpcy5fZmFyID0gdGhpcy5mYXI7CiAgICB0aGlzLl9jdWxsaW5nVm9sdW1lID0gbmV3IEN1bGxpbmdWb2x1bWVfZGVmYXVsdCgpOwogICAgdGhpcy5fcGVyc3BlY3RpdmVNYXRyaXggPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICB0aGlzLl9pbmZpbml0ZVBlcnNwZWN0aXZlID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogIH0KICBmdW5jdGlvbiB1cGRhdGUzKGZydXN0dW0pIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0ucmlnaHQpIHx8ICFkZWZpbmVkX2RlZmF1bHQoZnJ1c3R1bS5sZWZ0KSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0udG9wKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uYm90dG9tKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0ubmVhcikgfHwgIWRlZmluZWRfZGVmYXVsdChmcnVzdHVtLmZhcikpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgInJpZ2h0LCBsZWZ0LCB0b3AsIGJvdHRvbSwgbmVhciwgb3IgZmFyIHBhcmFtZXRlcnMgYXJlIG5vdCBzZXQuIgogICAgICApOwogICAgfQogICAgY29uc3QgeyB0b3AsIGJvdHRvbSwgcmlnaHQsIGxlZnQsIG5lYXIsIGZhciB9ID0gZnJ1c3R1bTsKICAgIGNvbnN0IGNoYW5nZWQgPSB0b3AgIT09IGZydXN0dW0uX3RvcCB8fCBib3R0b20gIT09IGZydXN0dW0uX2JvdHRvbSB8fCBsZWZ0ICE9PSBmcnVzdHVtLl9sZWZ0IHx8IHJpZ2h0ICE9PSBmcnVzdHVtLl9yaWdodCB8fCBuZWFyICE9PSBmcnVzdHVtLl9uZWFyIHx8IGZhciAhPT0gZnJ1c3R1bS5fZmFyOwogICAgaWYgKCFjaGFuZ2VkKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGlmIChmcnVzdHVtLm5lYXIgPD0gMCB8fCBmcnVzdHVtLm5lYXIgPiBmcnVzdHVtLmZhcikgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAibmVhciBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvIGFuZCBsZXNzIHRoYW4gZmFyLiIKICAgICAgKTsKICAgIH0KICAgIGZydXN0dW0uX2xlZnQgPSBsZWZ0OwogICAgZnJ1c3R1bS5fcmlnaHQgPSByaWdodDsKICAgIGZydXN0dW0uX3RvcCA9IHRvcDsKICAgIGZydXN0dW0uX2JvdHRvbSA9IGJvdHRvbTsKICAgIGZydXN0dW0uX25lYXIgPSBuZWFyOwogICAgZnJ1c3R1bS5fZmFyID0gZmFyOwogICAgZnJ1c3R1bS5fcGVyc3BlY3RpdmVNYXRyaXggPSBNYXRyaXg0X2RlZmF1bHQuY29tcHV0ZVBlcnNwZWN0aXZlT2ZmQ2VudGVyKAogICAgICBsZWZ0LAogICAgICByaWdodCwKICAgICAgYm90dG9tLAogICAgICB0b3AsCiAgICAgIG5lYXIsCiAgICAgIGZhciwKICAgICAgZnJ1c3R1bS5fcGVyc3BlY3RpdmVNYXRyaXgKICAgICk7CiAgICBmcnVzdHVtLl9pbmZpbml0ZVBlcnNwZWN0aXZlID0gTWF0cml4NF9kZWZhdWx0LmNvbXB1dGVJbmZpbml0ZVBlcnNwZWN0aXZlT2ZmQ2VudGVyKAogICAgICBsZWZ0LAogICAgICByaWdodCwKICAgICAgYm90dG9tLAogICAgICB0b3AsCiAgICAgIG5lYXIsCiAgICAgIGZydXN0dW0uX2luZmluaXRlUGVyc3BlY3RpdmUKICAgICk7CiAgfQogIHZhciBnZXRQbGFuZXNSaWdodDIsIGdldFBsYW5lc05lYXJDZW50ZXIyLCBnZXRQbGFuZXNGYXJDZW50ZXIsIGdldFBsYW5lc05vcm1hbCwgUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtX2RlZmF1bHQ7CiAgdmFyIGluaXRfUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0uanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW40KCk7CiAgICAgIGluaXRfQ3VsbGluZ1ZvbHVtZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFBlcnNwZWN0aXZlT2ZmQ2VudGVyRnJ1c3R1bS5wcm90b3R5cGUsIHsKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBwZXJzcGVjdGl2ZSBwcm9qZWN0aW9uIG1hdHJpeCBjb21wdXRlZCBmcm9tIHRoZSB2aWV3IGZydXN0dW0uCiAgICAgICAgICogVGhlIHByb2plY3Rpb24gbWF0cml4IHdpbGwgYmUgcmVjb21wdXRlZCBpZiBhbnkgZnJ1c3R1bSBwYXJhbWV0ZXJzIGhhdmUgY2hhbmdlZC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge01hdHJpeDR9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIFBlcnNwZWN0aXZlT2ZmQ2VudGVyRnJ1c3R1bSNpbmZpbml0ZVByb2plY3Rpb25NYXRyaXgKICAgICAgICAgKi8KICAgICAgICBwcm9qZWN0aW9uTWF0cml4OiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICB1cGRhdGUzKHRoaXMpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5fcGVyc3BlY3RpdmVNYXRyaXg7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBwZXJzcGVjdGl2ZSBwcm9qZWN0aW9uIG1hdHJpeCBjb21wdXRlZCBmcm9tIHRoZSB2aWV3IGZydXN0dW0gd2l0aCBhbiBpbmZpbml0ZSBmYXIgcGxhbmUuCiAgICAgICAgICogQG1lbWJlcm9mIFBlcnNwZWN0aXZlT2ZmQ2VudGVyRnJ1c3R1bS5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7TWF0cml4NH0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKgogICAgICAgICAqIEBzZWUgUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtI3Byb2plY3Rpb25NYXRyaXgKICAgICAgICAgKi8KICAgICAgICBpbmZpbml0ZVByb2plY3Rpb25NYXRyaXg6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHVwZGF0ZTModGhpcyk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9pbmZpbml0ZVBlcnNwZWN0aXZlOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSk7CiAgICAgIGdldFBsYW5lc1JpZ2h0MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZ2V0UGxhbmVzTmVhckNlbnRlcjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGdldFBsYW5lc0ZhckNlbnRlciA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZ2V0UGxhbmVzTm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmNvbXB1dGVDdWxsaW5nVm9sdW1lID0gZnVuY3Rpb24ocG9zaXRpb24sIGRpcmVjdGlvbjIsIHVwKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb24pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicG9zaXRpb24gaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGRpcmVjdGlvbjIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGlyZWN0aW9uIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1cCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ1cCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgcGxhbmVzID0gdGhpcy5fY3VsbGluZ1ZvbHVtZS5wbGFuZXM7CiAgICAgICAgY29uc3QgdDIgPSB0aGlzLnRvcDsKICAgICAgICBjb25zdCBiMiA9IHRoaXMuYm90dG9tOwogICAgICAgIGNvbnN0IHIyID0gdGhpcy5yaWdodDsKICAgICAgICBjb25zdCBsMiA9IHRoaXMubGVmdDsKICAgICAgICBjb25zdCBuMiA9IHRoaXMubmVhcjsKICAgICAgICBjb25zdCBmMiA9IHRoaXMuZmFyOwogICAgICAgIGNvbnN0IHJpZ2h0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGRpcmVjdGlvbjIsIHVwLCBnZXRQbGFuZXNSaWdodDIpOwogICAgICAgIGNvbnN0IG5lYXJDZW50ZXIgPSBnZXRQbGFuZXNOZWFyQ2VudGVyMjsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihkaXJlY3Rpb24yLCBuMiwgbmVhckNlbnRlcik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwb3NpdGlvbiwgbmVhckNlbnRlciwgbmVhckNlbnRlcik7CiAgICAgICAgY29uc3QgZmFyQ2VudGVyID0gZ2V0UGxhbmVzRmFyQ2VudGVyOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGRpcmVjdGlvbjIsIGYyLCBmYXJDZW50ZXIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb24sIGZhckNlbnRlciwgZmFyQ2VudGVyKTsKICAgICAgICBjb25zdCBub3JtYWwyID0gZ2V0UGxhbmVzTm9ybWFsOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHJpZ2h0LCBsMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qobm9ybWFsMiwgcG9zaXRpb24sIG5vcm1hbDIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUobm9ybWFsMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIHVwLCBub3JtYWwyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG5vcm1hbDIsIG5vcm1hbDIpOwogICAgICAgIGxldCBwbGFuZSA9IHBsYW5lc1swXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzBdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gbm9ybWFsMi54OwogICAgICAgIHBsYW5lLnkgPSBub3JtYWwyLnk7CiAgICAgICAgcGxhbmUueiA9IG5vcm1hbDIuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgcG9zaXRpb24pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHJpZ2h0LCByMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qobm9ybWFsMiwgcG9zaXRpb24sIG5vcm1hbDIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyh1cCwgbm9ybWFsMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBwbGFuZSA9IHBsYW5lc1sxXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzFdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gbm9ybWFsMi54OwogICAgICAgIHBsYW5lLnkgPSBub3JtYWwyLnk7CiAgICAgICAgcGxhbmUueiA9IG5vcm1hbDIuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgcG9zaXRpb24pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHVwLCBiMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qobm9ybWFsMiwgcG9zaXRpb24sIG5vcm1hbDIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhyaWdodCwgbm9ybWFsMiwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBwbGFuZSA9IHBsYW5lc1syXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzJdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gbm9ybWFsMi54OwogICAgICAgIHBsYW5lLnkgPSBub3JtYWwyLnk7CiAgICAgICAgcGxhbmUueiA9IG5vcm1hbDIuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgcG9zaXRpb24pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHVwLCB0Miwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChuZWFyQ2VudGVyLCBub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3Qobm9ybWFsMiwgcG9zaXRpb24sIG5vcm1hbDIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhub3JtYWwyLCByaWdodCwgbm9ybWFsMik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShub3JtYWwyLCBub3JtYWwyKTsKICAgICAgICBwbGFuZSA9IHBsYW5lc1szXTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwbGFuZSkpIHsKICAgICAgICAgIHBsYW5lID0gcGxhbmVzWzNdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICAgIH0KICAgICAgICBwbGFuZS54ID0gbm9ybWFsMi54OwogICAgICAgIHBsYW5lLnkgPSBub3JtYWwyLnk7CiAgICAgICAgcGxhbmUueiA9IG5vcm1hbDIuejsKICAgICAgICBwbGFuZS53ID0gLUNhcnRlc2lhbjNfZGVmYXVsdC5kb3Qobm9ybWFsMiwgcG9zaXRpb24pOwogICAgICAgIHBsYW5lID0gcGxhbmVzWzRdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBsYW5lKSkgewogICAgICAgICAgcGxhbmUgPSBwbGFuZXNbNF0gPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIHBsYW5lLnggPSBkaXJlY3Rpb24yLng7CiAgICAgICAgcGxhbmUueSA9IGRpcmVjdGlvbjIueTsKICAgICAgICBwbGFuZS56ID0gZGlyZWN0aW9uMi56OwogICAgICAgIHBsYW5lLncgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yLCBuZWFyQ2VudGVyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKGRpcmVjdGlvbjIsIG5vcm1hbDIpOwogICAgICAgIHBsYW5lID0gcGxhbmVzWzVdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBsYW5lKSkgewogICAgICAgICAgcGxhbmUgPSBwbGFuZXNbNV0gPSBuZXcgQ2FydGVzaWFuNF9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIHBsYW5lLnggPSBub3JtYWwyLng7CiAgICAgICAgcGxhbmUueSA9IG5vcm1hbDIueTsKICAgICAgICBwbGFuZS56ID0gbm9ybWFsMi56OwogICAgICAgIHBsYW5lLncgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdChub3JtYWwyLCBmYXJDZW50ZXIpOwogICAgICAgIHJldHVybiB0aGlzLl9jdWxsaW5nVm9sdW1lOwogICAgICB9OwogICAgICBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmdldFBpeGVsRGltZW5zaW9ucyA9IGZ1bmN0aW9uKGRyYXdpbmdCdWZmZXJXaWR0aCwgZHJhd2luZ0J1ZmZlckhlaWdodCwgZGlzdGFuY2UsIHBpeGVsUmF0aW8sIHJlc3VsdCkgewogICAgICAgIHVwZGF0ZTModGhpcyk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZHJhd2luZ0J1ZmZlcldpZHRoKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGRyYXdpbmdCdWZmZXJIZWlnaHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAgICAgIkJvdGggZHJhd2luZ0J1ZmZlcldpZHRoIGFuZCBkcmF3aW5nQnVmZmVySGVpZ2h0IGFyZSByZXF1aXJlZC4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBpZiAoZHJhd2luZ0J1ZmZlcldpZHRoIDw9IDApIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJkcmF3aW5nQnVmZmVyV2lkdGggbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKGRyYXdpbmdCdWZmZXJIZWlnaHQgPD0gMCkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImRyYXdpbmdCdWZmZXJIZWlnaHQgbXVzdCBiZSBncmVhdGVyIHRoYW4gemVyby4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZGlzdGFuY2UpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiZGlzdGFuY2UgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBpeGVsUmF0aW8pKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicGl4ZWxSYXRpbyBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAocGl4ZWxSYXRpbyA8PSAwKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicGl4ZWxSYXRpbyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiQSByZXN1bHQgb2JqZWN0IGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBpbnZlcnNlTmVhciA9IDEgLyB0aGlzLm5lYXI7CiAgICAgICAgbGV0IHRhblRoZXRhID0gdGhpcy50b3AgKiBpbnZlcnNlTmVhcjsKICAgICAgICBjb25zdCBwaXhlbEhlaWdodCA9IDIgKiBwaXhlbFJhdGlvICogZGlzdGFuY2UgKiB0YW5UaGV0YSAvIGRyYXdpbmdCdWZmZXJIZWlnaHQ7CiAgICAgICAgdGFuVGhldGEgPSB0aGlzLnJpZ2h0ICogaW52ZXJzZU5lYXI7CiAgICAgICAgY29uc3QgcGl4ZWxXaWR0aCA9IDIgKiBwaXhlbFJhdGlvICogZGlzdGFuY2UgKiB0YW5UaGV0YSAvIGRyYXdpbmdCdWZmZXJXaWR0aDsKICAgICAgICByZXN1bHQueCA9IHBpeGVsV2lkdGg7CiAgICAgICAgcmVzdWx0LnkgPSBwaXhlbEhlaWdodDsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFBlcnNwZWN0aXZlT2ZmQ2VudGVyRnJ1c3R1bSgpOwogICAgICAgIH0KICAgICAgICByZXN1bHQucmlnaHQgPSB0aGlzLnJpZ2h0OwogICAgICAgIHJlc3VsdC5sZWZ0ID0gdGhpcy5sZWZ0OwogICAgICAgIHJlc3VsdC50b3AgPSB0aGlzLnRvcDsKICAgICAgICByZXN1bHQuYm90dG9tID0gdGhpcy5ib3R0b207CiAgICAgICAgcmVzdWx0Lm5lYXIgPSB0aGlzLm5lYXI7CiAgICAgICAgcmVzdWx0LmZhciA9IHRoaXMuZmFyOwogICAgICAgIHJlc3VsdC5fbGVmdCA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX3JpZ2h0ID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fdG9wID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fYm90dG9tID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fbmVhciA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX2ZhciA9IHZvaWQgMDsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0ucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uKG90aGVyKSB7CiAgICAgICAgcmV0dXJuIGRlZmluZWRfZGVmYXVsdChvdGhlcikgJiYgb3RoZXIgaW5zdGFuY2VvZiBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0gJiYgdGhpcy5yaWdodCA9PT0gb3RoZXIucmlnaHQgJiYgdGhpcy5sZWZ0ID09PSBvdGhlci5sZWZ0ICYmIHRoaXMudG9wID09PSBvdGhlci50b3AgJiYgdGhpcy5ib3R0b20gPT09IG90aGVyLmJvdHRvbSAmJiB0aGlzLm5lYXIgPT09IG90aGVyLm5lYXIgJiYgdGhpcy5mYXIgPT09IG90aGVyLmZhcjsKICAgICAgfTsKICAgICAgUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtLnByb3RvdHlwZS5lcXVhbHNFcHNpbG9uID0gZnVuY3Rpb24ob3RoZXIsIHJlbGF0aXZlRXBzaWxvbiwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgcmV0dXJuIG90aGVyID09PSB0aGlzIHx8IGRlZmluZWRfZGVmYXVsdChvdGhlcikgJiYgb3RoZXIgaW5zdGFuY2VvZiBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW0gJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLnJpZ2h0LAogICAgICAgICAgb3RoZXIucmlnaHQsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgdGhpcy5sZWZ0LAogICAgICAgICAgb3RoZXIubGVmdCwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLnRvcCwKICAgICAgICAgIG90aGVyLnRvcCwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLmJvdHRvbSwKICAgICAgICAgIG90aGVyLmJvdHRvbSwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICkgJiYgTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICB0aGlzLm5lYXIsCiAgICAgICAgICBvdGhlci5uZWFyLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHRoaXMuZmFyLAogICAgICAgICAgb3RoZXIuZmFyLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKTsKICAgICAgfTsKICAgICAgUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtX2RlZmF1bHQgPSBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW07CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QZXJzcGVjdGl2ZUZydXN0dW0uanMKICBmdW5jdGlvbiBQZXJzcGVjdGl2ZUZydXN0dW0ob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bSA9IG5ldyBQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW1fZGVmYXVsdCgpOwogICAgdGhpcy5mb3YgPSBvcHRpb25zLmZvdjsKICAgIHRoaXMuX2ZvdiA9IHZvaWQgMDsKICAgIHRoaXMuX2ZvdnkgPSB2b2lkIDA7CiAgICB0aGlzLl9zc2VEZW5vbWluYXRvciA9IHZvaWQgMDsKICAgIHRoaXMuYXNwZWN0UmF0aW8gPSBvcHRpb25zLmFzcGVjdFJhdGlvOwogICAgdGhpcy5fYXNwZWN0UmF0aW8gPSB2b2lkIDA7CiAgICB0aGlzLm5lYXIgPSBvcHRpb25zLm5lYXIgPz8gMTsKICAgIHRoaXMuX25lYXIgPSB0aGlzLm5lYXI7CiAgICB0aGlzLmZhciA9IG9wdGlvbnMuZmFyID8/IDVlODsKICAgIHRoaXMuX2ZhciA9IHRoaXMuZmFyOwogICAgdGhpcy54T2Zmc2V0ID0gb3B0aW9ucy54T2Zmc2V0ID8/IDA7CiAgICB0aGlzLl94T2Zmc2V0ID0gdGhpcy54T2Zmc2V0OwogICAgdGhpcy55T2Zmc2V0ID0gb3B0aW9ucy55T2Zmc2V0ID8/IDA7CiAgICB0aGlzLl95T2Zmc2V0ID0gdGhpcy55T2Zmc2V0OwogIH0KICBmdW5jdGlvbiB1cGRhdGU0KGZydXN0dW0pIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uZm92KSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uYXNwZWN0UmF0aW8pIHx8ICFkZWZpbmVkX2RlZmF1bHQoZnJ1c3R1bS5uZWFyKSB8fCAhZGVmaW5lZF9kZWZhdWx0KGZydXN0dW0uZmFyKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiZm92LCBhc3BlY3RSYXRpbywgbmVhciwgb3IgZmFyIHBhcmFtZXRlcnMgYXJlIG5vdCBzZXQuIgogICAgICApOwogICAgfQogICAgY29uc3QgY2hhbmdlZCA9IGZydXN0dW0uZm92ICE9PSBmcnVzdHVtLl9mb3YgfHwgZnJ1c3R1bS5hc3BlY3RSYXRpbyAhPT0gZnJ1c3R1bS5fYXNwZWN0UmF0aW8gfHwgZnJ1c3R1bS5uZWFyICE9PSBmcnVzdHVtLl9uZWFyIHx8IGZydXN0dW0uZmFyICE9PSBmcnVzdHVtLl9mYXIgfHwgZnJ1c3R1bS54T2Zmc2V0ICE9PSBmcnVzdHVtLl94T2Zmc2V0IHx8IGZydXN0dW0ueU9mZnNldCAhPT0gZnJ1c3R1bS5feU9mZnNldDsKICAgIGlmICghY2hhbmdlZCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygiZm92IiwgZnJ1c3R1bS5mb3YsIDApOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuKCJmb3YiLCBmcnVzdHVtLmZvdiwgTWF0aC5QSSk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIuZ3JlYXRlclRoYW5PckVxdWFscygKICAgICAgImFzcGVjdFJhdGlvIiwKICAgICAgZnJ1c3R1bS5hc3BlY3RSYXRpbywKICAgICAgMAogICAgKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJuZWFyIiwgZnJ1c3R1bS5uZWFyLCAwKTsKICAgIGlmIChmcnVzdHVtLm5lYXIgPiBmcnVzdHVtLmZhcikgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgibmVhciBtdXN0IGJlIGxlc3MgdGhhbiBmYXIuIik7CiAgICB9CiAgICBmcnVzdHVtLl9hc3BlY3RSYXRpbyA9IGZydXN0dW0uYXNwZWN0UmF0aW87CiAgICBmcnVzdHVtLl9mb3YgPSBmcnVzdHVtLmZvdjsKICAgIGZydXN0dW0uX2ZvdnkgPSBmcnVzdHVtLmFzcGVjdFJhdGlvIDw9IDEgPyBmcnVzdHVtLmZvdiA6IE1hdGguYXRhbihNYXRoLnRhbihmcnVzdHVtLmZvdiAqIDAuNSkgLyBmcnVzdHVtLmFzcGVjdFJhdGlvKSAqIDI7CiAgICBmcnVzdHVtLl9uZWFyID0gZnJ1c3R1bS5uZWFyOwogICAgZnJ1c3R1bS5fZmFyID0gZnJ1c3R1bS5mYXI7CiAgICBmcnVzdHVtLl9zc2VEZW5vbWluYXRvciA9IDIgKiBNYXRoLnRhbigwLjUgKiBmcnVzdHVtLl9mb3Z5KTsKICAgIGZydXN0dW0uX3hPZmZzZXQgPSBmcnVzdHVtLnhPZmZzZXQ7CiAgICBmcnVzdHVtLl95T2Zmc2V0ID0gZnJ1c3R1bS55T2Zmc2V0OwogICAgY29uc3QgZjIgPSBmcnVzdHVtLl9vZmZDZW50ZXJGcnVzdHVtOwogICAgZjIudG9wID0gZnJ1c3R1bS5uZWFyICogTWF0aC50YW4oMC41ICogZnJ1c3R1bS5fZm92eSk7CiAgICBmMi5ib3R0b20gPSAtZjIudG9wOwogICAgZjIucmlnaHQgPSBmcnVzdHVtLmFzcGVjdFJhdGlvICogZjIudG9wOwogICAgZjIubGVmdCA9IC1mMi5yaWdodDsKICAgIGYyLm5lYXIgPSBmcnVzdHVtLm5lYXI7CiAgICBmMi5mYXIgPSBmcnVzdHVtLmZhcjsKICAgIGYyLnJpZ2h0ICs9IGZydXN0dW0ueE9mZnNldDsKICAgIGYyLmxlZnQgKz0gZnJ1c3R1bS54T2Zmc2V0OwogICAgZjIudG9wICs9IGZydXN0dW0ueU9mZnNldDsKICAgIGYyLmJvdHRvbSArPSBmcnVzdHVtLnlPZmZzZXQ7CiAgfQogIHZhciBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdDsKICB2YXIgaW5pdF9QZXJzcGVjdGl2ZUZydXN0dW0gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BlcnNwZWN0aXZlRnJ1c3R1bS5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtKCk7CiAgICAgIFBlcnNwZWN0aXZlRnJ1c3R1bS5wYWNrZWRMZW5ndGggPSA2OwogICAgICBQZXJzcGVjdGl2ZUZydXN0dW0ucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5mb3Y7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLmFzcGVjdFJhdGlvOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5uZWFyOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5mYXI7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLnhPZmZzZXQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS55T2Zmc2V0OwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgUGVyc3BlY3RpdmVGcnVzdHVtLnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFBlcnNwZWN0aXZlRnJ1c3R1bSgpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuZm92ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQuYXNwZWN0UmF0aW8gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIHJlc3VsdC5uZWFyID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQuZmFyID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICByZXN1bHQueE9mZnNldCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgcmVzdWx0LnlPZmZzZXQgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhQZXJzcGVjdGl2ZUZydXN0dW0ucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgcGVyc3BlY3RpdmUgcHJvamVjdGlvbiBtYXRyaXggY29tcHV0ZWQgZnJvbSB0aGUgdmlldyBmcnVzdHVtLgogICAgICAgICAqIElmIG5lY2Vzc2FyeSwgdGhlIHByb2plY3Rpb24gbWF0cml4IHdpbGwgYmUgcmVjb21wdXRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBtZW1iZXJvZiBQZXJzcGVjdGl2ZUZydXN0dW0ucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge01hdHJpeDR9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIFBlcnNwZWN0aXZlT2ZmQ2VudGVyRnJ1c3R1bSNwcm9qZWN0aW9uTWF0cml4LgogICAgICAgICAqIEBzZWUgUGVyc3BlY3RpdmVGcnVzdHVtI2luZmluaXRlUHJvamVjdGlvbk1hdHJpeAogICAgICAgICAqLwogICAgICAgIHByb2plY3Rpb25NYXRyaXg6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHVwZGF0ZTQodGhpcyk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLnByb2plY3Rpb25NYXRyaXg7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBUaGUgcGVyc3BlY3RpdmUgcHJvamVjdGlvbiBtYXRyaXggY29tcHV0ZWQgZnJvbSB0aGUgdmlldyBmcnVzdHVtIHdpdGggYW4gaW5maW5pdGUgZmFyIHBsYW5lLgogICAgICAgICAqIEBtZW1iZXJvZiBQZXJzcGVjdGl2ZUZydXN0dW0ucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge01hdHJpeDR9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIFBlcnNwZWN0aXZlRnJ1c3R1bSNwcm9qZWN0aW9uTWF0cml4CiAgICAgICAgICovCiAgICAgICAgaW5maW5pdGVQcm9qZWN0aW9uTWF0cml4OiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICB1cGRhdGU0KHRoaXMpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bS5pbmZpbml0ZVByb2plY3Rpb25NYXRyaXg7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIHRoZSBhbmdsZSBvZiB0aGUgdmVydGljYWwgZmllbGQgb2YgdmlldywgaW4gcmFkaWFucy4KICAgICAgICAgKiBAbWVtYmVyb2YgUGVyc3BlY3RpdmVGcnVzdHVtLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ8dW5kZWZpbmVkfQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqIEBkZWZhdWx0IHVuZGVmaW5lZAogICAgICAgICAqLwogICAgICAgIGZvdnk6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHVwZGF0ZTQodGhpcyk7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9mb3Z5OwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBzc2VEZW5vbWluYXRvcjogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgdXBkYXRlNCh0aGlzKTsKICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3NzZURlbm9taW5hdG9yOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdW5kZXJseWluZyB7QGxpbmsgUGVyc3BlY3RpdmVPZmZDZW50ZXJGcnVzdHVtfS4KICAgICAgICAgKiBAbWVtYmVyb2YgUGVyc3BlY3RpdmVGcnVzdHVtLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtQZXJzcGVjdGl2ZU9mZkNlbnRlckZydXN0dW19CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBvZmZDZW50ZXJGcnVzdHVtOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICB1cGRhdGU0KHRoaXMpOwogICAgICAgICAgICByZXR1cm4gdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBQZXJzcGVjdGl2ZUZydXN0dW0ucHJvdG90eXBlLmNvbXB1dGVDdWxsaW5nVm9sdW1lID0gZnVuY3Rpb24ocG9zaXRpb24sIGRpcmVjdGlvbjIsIHVwKSB7CiAgICAgICAgdXBkYXRlNCh0aGlzKTsKICAgICAgICByZXR1cm4gdGhpcy5fb2ZmQ2VudGVyRnJ1c3R1bS5jb21wdXRlQ3VsbGluZ1ZvbHVtZShwb3NpdGlvbiwgZGlyZWN0aW9uMiwgdXApOwogICAgICB9OwogICAgICBQZXJzcGVjdGl2ZUZydXN0dW0ucHJvdG90eXBlLmdldFBpeGVsRGltZW5zaW9ucyA9IGZ1bmN0aW9uKGRyYXdpbmdCdWZmZXJXaWR0aCwgZHJhd2luZ0J1ZmZlckhlaWdodCwgZGlzdGFuY2UsIHBpeGVsUmF0aW8sIHJlc3VsdCkgewogICAgICAgIHVwZGF0ZTQodGhpcyk7CiAgICAgICAgcmV0dXJuIHRoaXMuX29mZkNlbnRlckZydXN0dW0uZ2V0UGl4ZWxEaW1lbnNpb25zKAogICAgICAgICAgZHJhd2luZ0J1ZmZlcldpZHRoLAogICAgICAgICAgZHJhd2luZ0J1ZmZlckhlaWdodCwKICAgICAgICAgIGRpc3RhbmNlLAogICAgICAgICAgcGl4ZWxSYXRpbywKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgIH07CiAgICAgIFBlcnNwZWN0aXZlRnJ1c3R1bS5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgUGVyc3BlY3RpdmVGcnVzdHVtKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5hc3BlY3RSYXRpbyA9IHRoaXMuYXNwZWN0UmF0aW87CiAgICAgICAgcmVzdWx0LmZvdiA9IHRoaXMuZm92OwogICAgICAgIHJlc3VsdC5uZWFyID0gdGhpcy5uZWFyOwogICAgICAgIHJlc3VsdC5mYXIgPSB0aGlzLmZhcjsKICAgICAgICByZXN1bHQuX2FzcGVjdFJhdGlvID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fZm92ID0gdm9pZCAwOwogICAgICAgIHJlc3VsdC5fbmVhciA9IHZvaWQgMDsKICAgICAgICByZXN1bHQuX2ZhciA9IHZvaWQgMDsKICAgICAgICB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLmNsb25lKHJlc3VsdC5fb2ZmQ2VudGVyRnJ1c3R1bSk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgUGVyc3BlY3RpdmVGcnVzdHVtLnByb3RvdHlwZS5lcXVhbHMgPSBmdW5jdGlvbihvdGhlcikgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG90aGVyKSB8fCAhKG90aGVyIGluc3RhbmNlb2YgUGVyc3BlY3RpdmVGcnVzdHVtKSkgewogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICB1cGRhdGU0KHRoaXMpOwogICAgICAgIHVwZGF0ZTQob3RoZXIpOwogICAgICAgIHJldHVybiB0aGlzLmZvdiA9PT0gb3RoZXIuZm92ICYmIHRoaXMuYXNwZWN0UmF0aW8gPT09IG90aGVyLmFzcGVjdFJhdGlvICYmIHRoaXMuX29mZkNlbnRlckZydXN0dW0uZXF1YWxzKG90aGVyLl9vZmZDZW50ZXJGcnVzdHVtKTsKICAgICAgfTsKICAgICAgUGVyc3BlY3RpdmVGcnVzdHVtLnByb3RvdHlwZS5lcXVhbHNFcHNpbG9uID0gZnVuY3Rpb24ob3RoZXIsIHJlbGF0aXZlRXBzaWxvbiwgYWJzb2x1dGVFcHNpbG9uKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQob3RoZXIpIHx8ICEob3RoZXIgaW5zdGFuY2VvZiBQZXJzcGVjdGl2ZUZydXN0dW0pKSB7CiAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfQogICAgICAgIHVwZGF0ZTQodGhpcyk7CiAgICAgICAgdXBkYXRlNChvdGhlcik7CiAgICAgICAgcmV0dXJuIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgdGhpcy5mb3YsCiAgICAgICAgICBvdGhlci5mb3YsCiAgICAgICAgICByZWxhdGl2ZUVwc2lsb24sCiAgICAgICAgICBhYnNvbHV0ZUVwc2lsb24KICAgICAgICApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgdGhpcy5hc3BlY3RSYXRpbywKICAgICAgICAgIG90aGVyLmFzcGVjdFJhdGlvLAogICAgICAgICAgcmVsYXRpdmVFcHNpbG9uLAogICAgICAgICAgYWJzb2x1dGVFcHNpbG9uCiAgICAgICAgKSAmJiB0aGlzLl9vZmZDZW50ZXJGcnVzdHVtLmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBvdGhlci5fb2ZmQ2VudGVyRnJ1c3R1bSwKICAgICAgICAgIHJlbGF0aXZlRXBzaWxvbiwKICAgICAgICAgIGFic29sdXRlRXBzaWxvbgogICAgICAgICk7CiAgICAgIH07CiAgICAgIFBlcnNwZWN0aXZlRnJ1c3R1bV9kZWZhdWx0ID0gUGVyc3BlY3RpdmVGcnVzdHVtOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRnJ1c3R1bUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gRnJ1c3R1bUdlb21ldHJ5KG9wdGlvbnMpIHsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucyIsIG9wdGlvbnMpOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zLmZydXN0dW0iLCBvcHRpb25zLmZydXN0dW0pOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zLm9yaWdpbiIsIG9wdGlvbnMub3JpZ2luKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5vcmllbnRhdGlvbiIsIG9wdGlvbnMub3JpZW50YXRpb24pOwogICAgY29uc3QgZnJ1c3R1bSA9IG9wdGlvbnMuZnJ1c3R1bTsKICAgIGNvbnN0IG9yaWVudGF0aW9uID0gb3B0aW9ucy5vcmllbnRhdGlvbjsKICAgIGNvbnN0IG9yaWdpbiA9IG9wdGlvbnMub3JpZ2luOwogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIGNvbnN0IGRyYXdOZWFyUGxhbmUgPSBvcHRpb25zLl9kcmF3TmVhclBsYW5lID8/IHRydWU7CiAgICBsZXQgZnJ1c3R1bVR5cGU7CiAgICBsZXQgZnJ1c3R1bVBhY2tlZExlbmd0aDsKICAgIGlmIChmcnVzdHVtIGluc3RhbmNlb2YgUGVyc3BlY3RpdmVGcnVzdHVtX2RlZmF1bHQpIHsKICAgICAgZnJ1c3R1bVR5cGUgPSBQRVJTUEVDVElWRTsKICAgICAgZnJ1c3R1bVBhY2tlZExlbmd0aCA9IFBlcnNwZWN0aXZlRnJ1c3R1bV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIH0gZWxzZSBpZiAoZnJ1c3R1bSBpbnN0YW5jZW9mIE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdCkgewogICAgICBmcnVzdHVtVHlwZSA9IE9SVEhPR1JBUEhJQzsKICAgICAgZnJ1c3R1bVBhY2tlZExlbmd0aCA9IE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICB9CiAgICB0aGlzLl9mcnVzdHVtVHlwZSA9IGZydXN0dW1UeXBlOwogICAgdGhpcy5fZnJ1c3R1bSA9IGZydXN0dW0uY2xvbmUoKTsKICAgIHRoaXMuX29yaWdpbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShvcmlnaW4pOwogICAgdGhpcy5fb3JpZW50YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuY2xvbmUob3JpZW50YXRpb24pOwogICAgdGhpcy5fZHJhd05lYXJQbGFuZSA9IGRyYXdOZWFyUGxhbmU7CiAgICB0aGlzLl92ZXJ0ZXhGb3JtYXQgPSB2ZXJ0ZXhGb3JtYXQ7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUZydXN0dW1HZW9tZXRyeSI7CiAgICB0aGlzLnBhY2tlZExlbmd0aCA9IDIgKyBmcnVzdHVtUGFja2VkTGVuZ3RoICsgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIFF1YXRlcm5pb25fZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgfQogIGZ1bmN0aW9uIGdldEF0dHJpYnV0ZXMob2Zmc2V0LCBub3JtYWxzLCB0YW5nZW50cywgYml0YW5nZW50cywgc3QyLCBub3JtYWwyLCB0YW5nZW50LCBiaXRhbmdlbnQpIHsKICAgIGNvbnN0IHN0T2Zmc2V0ID0gb2Zmc2V0IC8gMyAqIDI7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgNDsgKytpMikgewogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHMpKSB7CiAgICAgICAgbm9ybWFsc1tvZmZzZXRdID0gbm9ybWFsMi54OwogICAgICAgIG5vcm1hbHNbb2Zmc2V0ICsgMV0gPSBub3JtYWwyLnk7CiAgICAgICAgbm9ybWFsc1tvZmZzZXQgKyAyXSA9IG5vcm1hbDIuejsKICAgICAgfQogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRhbmdlbnRzKSkgewogICAgICAgIHRhbmdlbnRzW29mZnNldF0gPSB0YW5nZW50Lng7CiAgICAgICAgdGFuZ2VudHNbb2Zmc2V0ICsgMV0gPSB0YW5nZW50Lnk7CiAgICAgICAgdGFuZ2VudHNbb2Zmc2V0ICsgMl0gPSB0YW5nZW50Lno7CiAgICAgIH0KICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChiaXRhbmdlbnRzKSkgewogICAgICAgIGJpdGFuZ2VudHNbb2Zmc2V0XSA9IGJpdGFuZ2VudC54OwogICAgICAgIGJpdGFuZ2VudHNbb2Zmc2V0ICsgMV0gPSBiaXRhbmdlbnQueTsKICAgICAgICBiaXRhbmdlbnRzW29mZnNldCArIDJdID0gYml0YW5nZW50Lno7CiAgICAgIH0KICAgICAgb2Zmc2V0ICs9IDM7CiAgICB9CiAgICBzdDJbc3RPZmZzZXRdID0gMDsKICAgIHN0MltzdE9mZnNldCArIDFdID0gMDsKICAgIHN0MltzdE9mZnNldCArIDJdID0gMTsKICAgIHN0MltzdE9mZnNldCArIDNdID0gMDsKICAgIHN0MltzdE9mZnNldCArIDRdID0gMTsKICAgIHN0MltzdE9mZnNldCArIDVdID0gMTsKICAgIHN0MltzdE9mZnNldCArIDZdID0gMDsKICAgIHN0MltzdE9mZnNldCArIDddID0gMTsKICB9CiAgdmFyIFBFUlNQRUNUSVZFLCBPUlRIT0dSQVBISUMsIHNjcmF0Y2hQYWNrUGVyc3BlY3RpdmUsIHNjcmF0Y2hQYWNrT3J0aG9ncmFwaGljLCBzY3JhdGNoUGFja1F1YXRlcm5pb24sIHNjcmF0Y2hQYWNrb3JpZ2luLCBzY3JhdGNoVmVydGV4Rm9ybWF0Nywgc2NyYXRjaFJvdGF0aW9uTWF0cml4Miwgc2NyYXRjaFZpZXdNYXRyaXgsIHNjcmF0Y2hJbnZlcnNlTWF0cml4LCBzY3JhdGNoWERpcmVjdGlvbiwgc2NyYXRjaFlEaXJlY3Rpb24sIHNjcmF0Y2haRGlyZWN0aW9uLCBzY3JhdGNoTmVnYXRpdmVYLCBzY3JhdGNoTmVnYXRpdmVZLCBzY3JhdGNoTmVnYXRpdmVaLCBmcnVzdHVtU3BsaXRzLCBmcnVzdHVtQ29ybmVyc05EQywgc2NyYXRjaEZydXN0dW1Db3JuZXJzLCBGcnVzdHVtR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9GcnVzdHVtR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0ZydXN0dW1HZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuNCgpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfT3J0aG9ncmFwaGljRnJ1c3R1bSgpOwogICAgICBpbml0X1BlcnNwZWN0aXZlRnJ1c3R1bSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9RdWF0ZXJuaW9uKCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIFBFUlNQRUNUSVZFID0gMDsKICAgICAgT1JUSE9HUkFQSElDID0gMTsKICAgICAgRnJ1c3R1bUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCBmcnVzdHVtVHlwZSA9IHZhbHVlLl9mcnVzdHVtVHlwZTsKICAgICAgICBjb25zdCBmcnVzdHVtID0gdmFsdWUuX2ZydXN0dW07CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGZydXN0dW1UeXBlOwogICAgICAgIGlmIChmcnVzdHVtVHlwZSA9PT0gUEVSU1BFQ1RJVkUpIHsKICAgICAgICAgIFBlcnNwZWN0aXZlRnJ1c3R1bV9kZWZhdWx0LnBhY2soZnJ1c3R1bSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCArPSBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdC5wYWNrKGZydXN0dW0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sodmFsdWUuX29yaWdpbiwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBRdWF0ZXJuaW9uX2RlZmF1bHQucGFjayh2YWx1ZS5fb3JpZW50YXRpb24sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFF1YXRlcm5pb25fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFjayh2YWx1ZS5fdmVydGV4Rm9ybWF0LCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fZHJhd05lYXJQbGFuZSA/IDEgOiAwOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaFBhY2tQZXJzcGVjdGl2ZSA9IG5ldyBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGFja09ydGhvZ3JhcGhpYyA9IG5ldyBPcnRob2dyYXBoaWNGcnVzdHVtX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBhY2tRdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGFja29yaWdpbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDcgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgRnJ1c3R1bUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgZnJ1c3R1bVR5cGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGxldCBmcnVzdHVtOwogICAgICAgIGlmIChmcnVzdHVtVHlwZSA9PT0gUEVSU1BFQ1RJVkUpIHsKICAgICAgICAgIGZydXN0dW0gPSBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgIGFycmF5LAogICAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgICBzY3JhdGNoUGFja1BlcnNwZWN0aXZlCiAgICAgICAgICApOwogICAgICAgICAgc3RhcnRpbmdJbmRleCArPSBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGZydXN0dW0gPSBPcnRob2dyYXBoaWNGcnVzdHVtX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgICBhcnJheSwKICAgICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgICAgc2NyYXRjaFBhY2tPcnRob2dyYXBoaWMKICAgICAgICAgICk7CiAgICAgICAgICBzdGFydGluZ0luZGV4ICs9IE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG9yaWdpbiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hQYWNrb3JpZ2luKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3Qgb3JpZW50YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFBhY2tRdWF0ZXJuaW9uCiAgICAgICAgKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFF1YXRlcm5pb25fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDcKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGRyYXdOZWFyUGxhbmUgPSBhcnJheVtzdGFydGluZ0luZGV4XSA9PT0gMTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IEZydXN0dW1HZW9tZXRyeSh7CiAgICAgICAgICAgIGZydXN0dW0sCiAgICAgICAgICAgIG9yaWdpbiwKICAgICAgICAgICAgb3JpZW50YXRpb24sCiAgICAgICAgICAgIHZlcnRleEZvcm1hdCwKICAgICAgICAgICAgX2RyYXdOZWFyUGxhbmU6IGRyYXdOZWFyUGxhbmUKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBjb25zdCBmcnVzdHVtUmVzdWx0ID0gZnJ1c3R1bVR5cGUgPT09IHJlc3VsdC5fZnJ1c3R1bVR5cGUgPyByZXN1bHQuX2ZydXN0dW0gOiB2b2lkIDA7CiAgICAgICAgcmVzdWx0Ll9mcnVzdHVtID0gZnJ1c3R1bS5jbG9uZShmcnVzdHVtUmVzdWx0KTsKICAgICAgICByZXN1bHQuX2ZydXN0dW1UeXBlID0gZnJ1c3R1bVR5cGU7CiAgICAgICAgcmVzdWx0Ll9vcmlnaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUob3JpZ2luLCByZXN1bHQuX29yaWdpbik7CiAgICAgICAgcmVzdWx0Ll9vcmllbnRhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5jbG9uZShvcmllbnRhdGlvbiwgcmVzdWx0Ll9vcmllbnRhdGlvbik7CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXN1bHQuX2RyYXdOZWFyUGxhbmUgPSBkcmF3TmVhclBsYW5lOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hSb3RhdGlvbk1hdHJpeDIgPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hWaWV3TWF0cml4ID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoSW52ZXJzZU1hdHJpeCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFhEaXJlY3Rpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hZRGlyZWN0aW9uID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoWkRpcmVjdGlvbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5lZ2F0aXZlWCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5lZ2F0aXZlWSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5lZ2F0aXZlWiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZnJ1c3R1bVNwbGl0cyA9IG5ldyBBcnJheSgzKTsKICAgICAgZnJ1c3R1bUNvcm5lcnNOREMgPSBuZXcgQXJyYXkoNCk7CiAgICAgIGZydXN0dW1Db3JuZXJzTkRDWzBdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgtMSwgLTEsIDEsIDEpOwogICAgICBmcnVzdHVtQ29ybmVyc05EQ1sxXSA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoMSwgLTEsIDEsIDEpOwogICAgICBmcnVzdHVtQ29ybmVyc05EQ1syXSA9IG5ldyBDYXJ0ZXNpYW40X2RlZmF1bHQoMSwgMSwgMSwgMSk7CiAgICAgIGZydXN0dW1Db3JuZXJzTkRDWzNdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgtMSwgMSwgMSwgMSk7CiAgICAgIHNjcmF0Y2hGcnVzdHVtQ29ybmVycyA9IG5ldyBBcnJheSg0KTsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IDQ7ICsraTIpIHsKICAgICAgICBzY3JhdGNoRnJ1c3R1bUNvcm5lcnNbaTJdID0gbmV3IENhcnRlc2lhbjRfZGVmYXVsdCgpOwogICAgICB9CiAgICAgIEZydXN0dW1HZW9tZXRyeS5fY29tcHV0ZU5lYXJGYXJQbGFuZXMgPSBmdW5jdGlvbihvcmlnaW4sIG9yaWVudGF0aW9uLCBmcnVzdHVtVHlwZSwgZnJ1c3R1bSwgcG9zaXRpb25zLCB4RGlyZWN0aW9uLCB5RGlyZWN0aW9uLCB6RGlyZWN0aW9uKSB7CiAgICAgICAgY29uc3Qgcm90YXRpb25NYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24oCiAgICAgICAgICBvcmllbnRhdGlvbiwKICAgICAgICAgIHNjcmF0Y2hSb3RhdGlvbk1hdHJpeDIKICAgICAgICApOwogICAgICAgIGxldCB4MiA9IHhEaXJlY3Rpb24gPz8gc2NyYXRjaFhEaXJlY3Rpb247CiAgICAgICAgbGV0IHkyID0geURpcmVjdGlvbiA/PyBzY3JhdGNoWURpcmVjdGlvbjsKICAgICAgICBsZXQgejIgPSB6RGlyZWN0aW9uID8/IHNjcmF0Y2haRGlyZWN0aW9uOwogICAgICAgIHgyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihyb3RhdGlvbk1hdHJpeCwgMCwgeDIpOwogICAgICAgIHkyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihyb3RhdGlvbk1hdHJpeCwgMSwgeTIpOwogICAgICAgIHoyID0gTWF0cml4M19kZWZhdWx0LmdldENvbHVtbihyb3RhdGlvbk1hdHJpeCwgMiwgejIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoeDIsIHgyKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHkyLCB5Mik7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSh6MiwgejIpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoeDIsIHgyKTsKICAgICAgICBjb25zdCB2aWV3ID0gTWF0cml4NF9kZWZhdWx0LmNvbXB1dGVWaWV3KG9yaWdpbiwgejIsIHkyLCB4Miwgc2NyYXRjaFZpZXdNYXRyaXgpOwogICAgICAgIGxldCBpbnZlcnNlVmlldzsKICAgICAgICBsZXQgaW52ZXJzZVZpZXdQcm9qZWN0aW9uOwogICAgICAgIGNvbnN0IHByb2plY3Rpb24gPSBmcnVzdHVtLnByb2plY3Rpb25NYXRyaXg7CiAgICAgICAgaWYgKGZydXN0dW1UeXBlID09PSBQRVJTUEVDVElWRSkgewogICAgICAgICAgY29uc3Qgdmlld1Byb2plY3Rpb24gPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkoCiAgICAgICAgICAgIHByb2plY3Rpb24sCiAgICAgICAgICAgIHZpZXcsCiAgICAgICAgICAgIHNjcmF0Y2hJbnZlcnNlTWF0cml4CiAgICAgICAgICApOwogICAgICAgICAgaW52ZXJzZVZpZXdQcm9qZWN0aW9uID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2UoCiAgICAgICAgICAgIHZpZXdQcm9qZWN0aW9uLAogICAgICAgICAgICBzY3JhdGNoSW52ZXJzZU1hdHJpeAogICAgICAgICAgKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaW52ZXJzZVZpZXcgPSBNYXRyaXg0X2RlZmF1bHQuaW52ZXJzZVRyYW5zZm9ybWF0aW9uKHZpZXcsIHNjcmF0Y2hJbnZlcnNlTWF0cml4KTsKICAgICAgICB9CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnZlcnNlVmlld1Byb2plY3Rpb24pKSB7CiAgICAgICAgICBmcnVzdHVtU3BsaXRzWzBdID0gZnJ1c3R1bS5uZWFyOwogICAgICAgICAgZnJ1c3R1bVNwbGl0c1sxXSA9IGZydXN0dW0uZmFyOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBmcnVzdHVtU3BsaXRzWzBdID0gMDsKICAgICAgICAgIGZydXN0dW1TcGxpdHNbMV0gPSBmcnVzdHVtLm5lYXI7CiAgICAgICAgICBmcnVzdHVtU3BsaXRzWzJdID0gZnJ1c3R1bS5mYXI7CiAgICAgICAgfQogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCAyOyArK2kyKSB7CiAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgNDsgKytqMikgewogICAgICAgICAgICBsZXQgY29ybmVyID0gQ2FydGVzaWFuNF9kZWZhdWx0LmNsb25lKAogICAgICAgICAgICAgIGZydXN0dW1Db3JuZXJzTkRDW2oyXSwKICAgICAgICAgICAgICBzY3JhdGNoRnJ1c3R1bUNvcm5lcnNbajJdCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGludmVyc2VWaWV3UHJvamVjdGlvbikpIHsKICAgICAgICAgICAgICBjb25zdCBvZmZDZW50ZXJGcnVzdHVtID0gZnJ1c3R1bS5vZmZDZW50ZXJGcnVzdHVtOwogICAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2ZmQ2VudGVyRnJ1c3R1bSkpIHsKICAgICAgICAgICAgICAgIGZydXN0dW0gPSBvZmZDZW50ZXJGcnVzdHVtOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBjb25zdCBuZWFyID0gZnJ1c3R1bVNwbGl0c1tpMl07CiAgICAgICAgICAgICAgY29uc3QgZmFyID0gZnJ1c3R1bVNwbGl0c1tpMiArIDFdOwogICAgICAgICAgICAgIGNvcm5lci54ID0gKGNvcm5lci54ICogKGZydXN0dW0ucmlnaHQgLSBmcnVzdHVtLmxlZnQpICsgZnJ1c3R1bS5sZWZ0ICsgZnJ1c3R1bS5yaWdodCkgKiAwLjU7CiAgICAgICAgICAgICAgY29ybmVyLnkgPSAoY29ybmVyLnkgKiAoZnJ1c3R1bS50b3AgLSBmcnVzdHVtLmJvdHRvbSkgKyBmcnVzdHVtLmJvdHRvbSArIGZydXN0dW0udG9wKSAqIDAuNTsKICAgICAgICAgICAgICBjb3JuZXIueiA9IChjb3JuZXIueiAqIChuZWFyIC0gZmFyKSAtIG5lYXIgLSBmYXIpICogMC41OwogICAgICAgICAgICAgIGNvcm5lci53ID0gMTsKICAgICAgICAgICAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcihpbnZlcnNlVmlldywgY29ybmVyLCBjb3JuZXIpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIGNvcm5lciA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKAogICAgICAgICAgICAgICAgaW52ZXJzZVZpZXdQcm9qZWN0aW9uLAogICAgICAgICAgICAgICAgY29ybmVyLAogICAgICAgICAgICAgICAgY29ybmVyCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBjb25zdCB3MiA9IDEgLyBjb3JuZXIudzsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcihjb3JuZXIsIHcyLCBjb3JuZXIpOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjb3JuZXIsIG9yaWdpbiwgY29ybmVyKTsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGNvcm5lciwgY29ybmVyKTsKICAgICAgICAgICAgICBjb25zdCBmYWMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHoyLCBjb3JuZXIpOwogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKGNvcm5lciwgZnJ1c3R1bVNwbGl0c1tpMl0gLyBmYWMsIGNvcm5lcik7CiAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChjb3JuZXIsIG9yaWdpbiwgY29ybmVyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBwb3NpdGlvbnNbMTIgKiBpMiArIGoyICogM10gPSBjb3JuZXIueDsKICAgICAgICAgICAgcG9zaXRpb25zWzEyICogaTIgKyBqMiAqIDMgKyAxXSA9IGNvcm5lci55OwogICAgICAgICAgICBwb3NpdGlvbnNbMTIgKiBpMiArIGoyICogMyArIDJdID0gY29ybmVyLno7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9OwogICAgICBGcnVzdHVtR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihmcnVzdHVtR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBmcnVzdHVtVHlwZSA9IGZydXN0dW1HZW9tZXRyeS5fZnJ1c3R1bVR5cGU7CiAgICAgICAgY29uc3QgZnJ1c3R1bSA9IGZydXN0dW1HZW9tZXRyeS5fZnJ1c3R1bTsKICAgICAgICBjb25zdCBvcmlnaW4gPSBmcnVzdHVtR2VvbWV0cnkuX29yaWdpbjsKICAgICAgICBjb25zdCBvcmllbnRhdGlvbiA9IGZydXN0dW1HZW9tZXRyeS5fb3JpZW50YXRpb247CiAgICAgICAgY29uc3QgZHJhd05lYXJQbGFuZSA9IGZydXN0dW1HZW9tZXRyeS5fZHJhd05lYXJQbGFuZTsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBmcnVzdHVtR2VvbWV0cnkuX3ZlcnRleEZvcm1hdDsKICAgICAgICBjb25zdCBudW1iZXJPZlBsYW5lcyA9IGRyYXdOZWFyUGxhbmUgPyA2IDogNTsKICAgICAgICBsZXQgcG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSgzICogNCAqIDYpOwogICAgICAgIEZydXN0dW1HZW9tZXRyeS5fY29tcHV0ZU5lYXJGYXJQbGFuZXMoCiAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICBvcmllbnRhdGlvbiwKICAgICAgICAgIGZydXN0dW1UeXBlLAogICAgICAgICAgZnJ1c3R1bSwKICAgICAgICAgIHBvc2l0aW9ucwogICAgICAgICk7CiAgICAgICAgbGV0IG9mZnNldCA9IDMgKiA0ICogMjsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0XSA9IHBvc2l0aW9uc1szICogNF07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDFdID0gcG9zaXRpb25zWzMgKiA0ICsgMV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDJdID0gcG9zaXRpb25zWzMgKiA0ICsgMl07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDNdID0gcG9zaXRpb25zWzBdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA0XSA9IHBvc2l0aW9uc1sxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgNV0gPSBwb3NpdGlvbnNbMl07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDZdID0gcG9zaXRpb25zWzMgKiAzXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgN10gPSBwb3NpdGlvbnNbMyAqIDMgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgOF0gPSBwb3NpdGlvbnNbMyAqIDMgKyAyXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgOV0gPSBwb3NpdGlvbnNbMyAqIDddOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyAxMF0gPSBwb3NpdGlvbnNbMyAqIDcgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMTFdID0gcG9zaXRpb25zWzMgKiA3ICsgMl07CiAgICAgICAgb2Zmc2V0ICs9IDMgKiA0OwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXRdID0gcG9zaXRpb25zWzMgKiA1XTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMV0gPSBwb3NpdGlvbnNbMyAqIDUgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMl0gPSBwb3NpdGlvbnNbMyAqIDUgKyAyXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgM10gPSBwb3NpdGlvbnNbM107CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDRdID0gcG9zaXRpb25zWzMgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgNV0gPSBwb3NpdGlvbnNbMyArIDJdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA2XSA9IHBvc2l0aW9uc1swXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgN10gPSBwb3NpdGlvbnNbMV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDhdID0gcG9zaXRpb25zWzJdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA5XSA9IHBvc2l0aW9uc1szICogNF07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDEwXSA9IHBvc2l0aW9uc1szICogNCArIDFdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyAxMV0gPSBwb3NpdGlvbnNbMyAqIDQgKyAyXTsKICAgICAgICBvZmZzZXQgKz0gMyAqIDQ7CiAgICAgICAgcG9zaXRpb25zW29mZnNldF0gPSBwb3NpdGlvbnNbM107CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDFdID0gcG9zaXRpb25zWzMgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMl0gPSBwb3NpdGlvbnNbMyArIDJdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyAzXSA9IHBvc2l0aW9uc1szICogNV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDRdID0gcG9zaXRpb25zWzMgKiA1ICsgMV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDVdID0gcG9zaXRpb25zWzMgKiA1ICsgMl07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDZdID0gcG9zaXRpb25zWzMgKiA2XTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgN10gPSBwb3NpdGlvbnNbMyAqIDYgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgOF0gPSBwb3NpdGlvbnNbMyAqIDYgKyAyXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgOV0gPSBwb3NpdGlvbnNbMyAqIDJdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyAxMF0gPSBwb3NpdGlvbnNbMyAqIDIgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMTFdID0gcG9zaXRpb25zWzMgKiAyICsgMl07CiAgICAgICAgb2Zmc2V0ICs9IDMgKiA0OwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXRdID0gcG9zaXRpb25zWzMgKiAyXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMV0gPSBwb3NpdGlvbnNbMyAqIDIgKyAxXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMl0gPSBwb3NpdGlvbnNbMyAqIDIgKyAyXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgM10gPSBwb3NpdGlvbnNbMyAqIDZdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA0XSA9IHBvc2l0aW9uc1szICogNiArIDFdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA1XSA9IHBvc2l0aW9uc1szICogNiArIDJdOwogICAgICAgIHBvc2l0aW9uc1tvZmZzZXQgKyA2XSA9IHBvc2l0aW9uc1szICogN107CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDddID0gcG9zaXRpb25zWzMgKiA3ICsgMV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDhdID0gcG9zaXRpb25zWzMgKiA3ICsgMl07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDldID0gcG9zaXRpb25zWzMgKiAzXTsKICAgICAgICBwb3NpdGlvbnNbb2Zmc2V0ICsgMTBdID0gcG9zaXRpb25zWzMgKiAzICsgMV07CiAgICAgICAgcG9zaXRpb25zW29mZnNldCArIDExXSA9IHBvc2l0aW9uc1szICogMyArIDJdOwogICAgICAgIGlmICghZHJhd05lYXJQbGFuZSkgewogICAgICAgICAgcG9zaXRpb25zID0gcG9zaXRpb25zLnN1YmFycmF5KDMgKiA0KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCh7CiAgICAgICAgICBwb3NpdGlvbjogbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICAgICAgICB9KQogICAgICAgIH0pOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodmVydGV4Rm9ybWF0Lm5vcm1hbCkgfHwgZGVmaW5lZF9kZWZhdWx0KHZlcnRleEZvcm1hdC50YW5nZW50KSB8fCBkZWZpbmVkX2RlZmF1bHQodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgfHwgZGVmaW5lZF9kZWZhdWx0KHZlcnRleEZvcm1hdC5zdCkpIHsKICAgICAgICAgIGNvbnN0IG5vcm1hbHMgPSBkZWZpbmVkX2RlZmF1bHQodmVydGV4Rm9ybWF0Lm5vcm1hbCkgPyBuZXcgRmxvYXQzMkFycmF5KDMgKiA0ICogbnVtYmVyT2ZQbGFuZXMpIDogdm9pZCAwOwogICAgICAgICAgY29uc3QgdGFuZ2VudHMgPSBkZWZpbmVkX2RlZmF1bHQodmVydGV4Rm9ybWF0LnRhbmdlbnQpID8gbmV3IEZsb2F0MzJBcnJheSgzICogNCAqIG51bWJlck9mUGxhbmVzKSA6IHZvaWQgMDsKICAgICAgICAgIGNvbnN0IGJpdGFuZ2VudHMgPSBkZWZpbmVkX2RlZmF1bHQodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgPyBuZXcgRmxvYXQzMkFycmF5KDMgKiA0ICogbnVtYmVyT2ZQbGFuZXMpIDogdm9pZCAwOwogICAgICAgICAgY29uc3Qgc3QyID0gZGVmaW5lZF9kZWZhdWx0KHZlcnRleEZvcm1hdC5zdCkgPyBuZXcgRmxvYXQzMkFycmF5KDIgKiA0ICogbnVtYmVyT2ZQbGFuZXMpIDogdm9pZCAwOwogICAgICAgICAgY29uc3QgeDIgPSBzY3JhdGNoWERpcmVjdGlvbjsKICAgICAgICAgIGNvbnN0IHkyID0gc2NyYXRjaFlEaXJlY3Rpb247CiAgICAgICAgICBjb25zdCB6MiA9IHNjcmF0Y2haRGlyZWN0aW9uOwogICAgICAgICAgY29uc3QgbmVnYXRpdmVYMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUoeDIsIHNjcmF0Y2hOZWdhdGl2ZVgpOwogICAgICAgICAgY29uc3QgbmVnYXRpdmVZID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZSh5Miwgc2NyYXRjaE5lZ2F0aXZlWSk7CiAgICAgICAgICBjb25zdCBuZWdhdGl2ZVogPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKHoyLCBzY3JhdGNoTmVnYXRpdmVaKTsKICAgICAgICAgIG9mZnNldCA9IDA7CiAgICAgICAgICBpZiAoZHJhd05lYXJQbGFuZSkgewogICAgICAgICAgICBnZXRBdHRyaWJ1dGVzKG9mZnNldCwgbm9ybWFscywgdGFuZ2VudHMsIGJpdGFuZ2VudHMsIHN0MiwgbmVnYXRpdmVaLCB4MiwgeTIpOwogICAgICAgICAgICBvZmZzZXQgKz0gMyAqIDQ7CiAgICAgICAgICB9CiAgICAgICAgICBnZXRBdHRyaWJ1dGVzKG9mZnNldCwgbm9ybWFscywgdGFuZ2VudHMsIGJpdGFuZ2VudHMsIHN0MiwgejIsIG5lZ2F0aXZlWDIsIHkyKTsKICAgICAgICAgIG9mZnNldCArPSAzICogNDsKICAgICAgICAgIGdldEF0dHJpYnV0ZXMoCiAgICAgICAgICAgIG9mZnNldCwKICAgICAgICAgICAgbm9ybWFscywKICAgICAgICAgICAgdGFuZ2VudHMsCiAgICAgICAgICAgIGJpdGFuZ2VudHMsCiAgICAgICAgICAgIHN0MiwKICAgICAgICAgICAgbmVnYXRpdmVYMiwKICAgICAgICAgICAgbmVnYXRpdmVaLAogICAgICAgICAgICB5MgogICAgICAgICAgKTsKICAgICAgICAgIG9mZnNldCArPSAzICogNDsKICAgICAgICAgIGdldEF0dHJpYnV0ZXMoCiAgICAgICAgICAgIG9mZnNldCwKICAgICAgICAgICAgbm9ybWFscywKICAgICAgICAgICAgdGFuZ2VudHMsCiAgICAgICAgICAgIGJpdGFuZ2VudHMsCiAgICAgICAgICAgIHN0MiwKICAgICAgICAgICAgbmVnYXRpdmVZLAogICAgICAgICAgICBuZWdhdGl2ZVosCiAgICAgICAgICAgIG5lZ2F0aXZlWDIKICAgICAgICAgICk7CiAgICAgICAgICBvZmZzZXQgKz0gMyAqIDQ7CiAgICAgICAgICBnZXRBdHRyaWJ1dGVzKG9mZnNldCwgbm9ybWFscywgdGFuZ2VudHMsIGJpdGFuZ2VudHMsIHN0MiwgeDIsIHoyLCB5Mik7CiAgICAgICAgICBvZmZzZXQgKz0gMyAqIDQ7CiAgICAgICAgICBnZXRBdHRyaWJ1dGVzKG9mZnNldCwgbm9ybWFscywgdGFuZ2VudHMsIGJpdGFuZ2VudHMsIHN0MiwgeTIsIHoyLCBuZWdhdGl2ZVgyKTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobm9ybWFscykpIHsKICAgICAgICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRhbmdlbnRzKSkgewogICAgICAgICAgICBhdHRyaWJ1dGVzLnRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgICB2YWx1ZXM6IHRhbmdlbnRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChiaXRhbmdlbnRzKSkgewogICAgICAgICAgICBhdHRyaWJ1dGVzLmJpdGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICAgIHZhbHVlczogYml0YW5nZW50cwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoc3QyKSkgewogICAgICAgICAgICBhdHRyaWJ1dGVzLnN0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgICAgdmFsdWVzOiBzdDIKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkoNiAqIG51bWJlck9mUGxhbmVzKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtYmVyT2ZQbGFuZXM7ICsraTIpIHsKICAgICAgICAgIGNvbnN0IGluZGV4T2Zmc2V0ID0gaTIgKiA2OwogICAgICAgICAgY29uc3QgaW5kZXggPSBpMiAqIDQ7CiAgICAgICAgICBpbmRpY2VzW2luZGV4T2Zmc2V0XSA9IGluZGV4OwogICAgICAgICAgaW5kaWNlc1tpbmRleE9mZnNldCArIDFdID0gaW5kZXggKyAxOwogICAgICAgICAgaW5kaWNlc1tpbmRleE9mZnNldCArIDJdID0gaW5kZXggKyAyOwogICAgICAgICAgaW5kaWNlc1tpbmRleE9mZnNldCArIDNdID0gaW5kZXg7CiAgICAgICAgICBpbmRpY2VzW2luZGV4T2Zmc2V0ICsgNF0gPSBpbmRleCArIDI7CiAgICAgICAgICBpbmRpY2VzW2luZGV4T2Zmc2V0ICsgNV0gPSBpbmRleCArIDM7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZTogQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tVmVydGljZXMocG9zaXRpb25zKQogICAgICAgIH0pOwogICAgICB9OwogICAgICBGcnVzdHVtR2VvbWV0cnlfZGVmYXVsdCA9IEZydXN0dW1HZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUZydXN0dW1HZW9tZXRyeS5qcwogIHZhciBjcmVhdGVGcnVzdHVtR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZUZydXN0dW1HZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVGcnVzdHVtR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUZydXN0dW1HZW9tZXRyeShmcnVzdHVtR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIGZydXN0dW1HZW9tZXRyeSA9IEZydXN0dW1HZW9tZXRyeV9kZWZhdWx0LnVucGFjayhmcnVzdHVtR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICByZXR1cm4gRnJ1c3R1bUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoZnJ1c3R1bUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUZydXN0dW1HZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUZydXN0dW1HZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRnJ1c3R1bUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRnJ1c3R1bUdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZUZydXN0dW1HZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlRnJ1c3R1bUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvRnJ1c3R1bU91dGxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEZydXN0dW1PdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zIiwgb3B0aW9ucyk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMuZnJ1c3R1bSIsIG9wdGlvbnMuZnJ1c3R1bSk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMub3JpZ2luIiwgb3B0aW9ucy5vcmlnaW4pOwogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zLm9yaWVudGF0aW9uIiwgb3B0aW9ucy5vcmllbnRhdGlvbik7CiAgICBjb25zdCBmcnVzdHVtID0gb3B0aW9ucy5mcnVzdHVtOwogICAgY29uc3Qgb3JpZW50YXRpb24gPSBvcHRpb25zLm9yaWVudGF0aW9uOwogICAgY29uc3Qgb3JpZ2luID0gb3B0aW9ucy5vcmlnaW47CiAgICBjb25zdCBkcmF3TmVhclBsYW5lID0gb3B0aW9ucy5fZHJhd05lYXJQbGFuZSA/PyB0cnVlOwogICAgbGV0IGZydXN0dW1UeXBlOwogICAgbGV0IGZydXN0dW1QYWNrZWRMZW5ndGg7CiAgICBpZiAoZnJ1c3R1bSBpbnN0YW5jZW9mIFBlcnNwZWN0aXZlRnJ1c3R1bV9kZWZhdWx0KSB7CiAgICAgIGZydXN0dW1UeXBlID0gUEVSU1BFQ1RJVkUyOwogICAgICBmcnVzdHVtUGFja2VkTGVuZ3RoID0gUGVyc3BlY3RpdmVGcnVzdHVtX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgfSBlbHNlIGlmIChmcnVzdHVtIGluc3RhbmNlb2YgT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0KSB7CiAgICAgIGZydXN0dW1UeXBlID0gT1JUSE9HUkFQSElDMjsKICAgICAgZnJ1c3R1bVBhY2tlZExlbmd0aCA9IE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICB9CiAgICB0aGlzLl9mcnVzdHVtVHlwZSA9IGZydXN0dW1UeXBlOwogICAgdGhpcy5fZnJ1c3R1bSA9IGZydXN0dW0uY2xvbmUoKTsKICAgIHRoaXMuX29yaWdpbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShvcmlnaW4pOwogICAgdGhpcy5fb3JpZW50YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuY2xvbmUob3JpZW50YXRpb24pOwogICAgdGhpcy5fZHJhd05lYXJQbGFuZSA9IGRyYXdOZWFyUGxhbmU7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnkiOwogICAgdGhpcy5wYWNrZWRMZW5ndGggPSAyICsgZnJ1c3R1bVBhY2tlZExlbmd0aCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBRdWF0ZXJuaW9uX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogIH0KICB2YXIgUEVSU1BFQ1RJVkUyLCBPUlRIT0dSQVBISUMyLCBzY3JhdGNoUGFja1BlcnNwZWN0aXZlMiwgc2NyYXRjaFBhY2tPcnRob2dyYXBoaWMyLCBzY3JhdGNoUGFja1F1YXRlcm5pb24yLCBzY3JhdGNoUGFja29yaWdpbjIsIEZydXN0dW1PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9GcnVzdHVtT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9GcnVzdHVtT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0ZydXN0dW1HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9PcnRob2dyYXBoaWNGcnVzdHVtKCk7CiAgICAgIGluaXRfUGVyc3BlY3RpdmVGcnVzdHVtKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBpbml0X1F1YXRlcm5pb24oKTsKICAgICAgUEVSU1BFQ1RJVkUyID0gMDsKICAgICAgT1JUSE9HUkFQSElDMiA9IDE7CiAgICAgIEZydXN0dW1PdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IGZydXN0dW1UeXBlID0gdmFsdWUuX2ZydXN0dW1UeXBlOwogICAgICAgIGNvbnN0IGZydXN0dW0gPSB2YWx1ZS5fZnJ1c3R1bTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gZnJ1c3R1bVR5cGU7CiAgICAgICAgaWYgKGZydXN0dW1UeXBlID09PSBQRVJTUEVDVElWRTIpIHsKICAgICAgICAgIFBlcnNwZWN0aXZlRnJ1c3R1bV9kZWZhdWx0LnBhY2soZnJ1c3R1bSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCArPSBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdC5wYWNrKGZydXN0dW0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sodmFsdWUuX29yaWdpbiwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBRdWF0ZXJuaW9uX2RlZmF1bHQucGFjayh2YWx1ZS5fb3JpZW50YXRpb24sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFF1YXRlcm5pb25fZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fZHJhd05lYXJQbGFuZSA/IDEgOiAwOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaFBhY2tQZXJzcGVjdGl2ZTIgPSBuZXcgUGVyc3BlY3RpdmVGcnVzdHVtX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBhY2tPcnRob2dyYXBoaWMyID0gbmV3IE9ydGhvZ3JhcGhpY0ZydXN0dW1fZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGFja1F1YXRlcm5pb24yID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGFja29yaWdpbjIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEZydXN0dW1PdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCBmcnVzdHVtVHlwZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgbGV0IGZydXN0dW07CiAgICAgICAgaWYgKGZydXN0dW1UeXBlID09PSBQRVJTUEVDVElWRTIpIHsKICAgICAgICAgIGZydXN0dW0gPSBQZXJzcGVjdGl2ZUZydXN0dW1fZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgIGFycmF5LAogICAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgICBzY3JhdGNoUGFja1BlcnNwZWN0aXZlMgogICAgICAgICAgKTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gUGVyc3BlY3RpdmVGcnVzdHVtX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBmcnVzdHVtID0gT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgYXJyYXksCiAgICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICAgIHNjcmF0Y2hQYWNrT3J0aG9ncmFwaGljMgogICAgICAgICAgKTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gT3J0aG9ncmFwaGljRnJ1c3R1bV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb3JpZ2luID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaFBhY2tvcmlnaW4yKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3Qgb3JpZW50YXRpb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFBhY2tRdWF0ZXJuaW9uMgogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBRdWF0ZXJuaW9uX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGRyYXdOZWFyUGxhbmUgPSBhcnJheVtzdGFydGluZ0luZGV4XSA9PT0gMTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXR1cm4gbmV3IEZydXN0dW1PdXRsaW5lR2VvbWV0cnkoewogICAgICAgICAgICBmcnVzdHVtLAogICAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICAgIG9yaWVudGF0aW9uLAogICAgICAgICAgICBfZHJhd05lYXJQbGFuZTogZHJhd05lYXJQbGFuZQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGZydXN0dW1SZXN1bHQgPSBmcnVzdHVtVHlwZSA9PT0gcmVzdWx0Ll9mcnVzdHVtVHlwZSA/IHJlc3VsdC5fZnJ1c3R1bSA6IHZvaWQgMDsKICAgICAgICByZXN1bHQuX2ZydXN0dW0gPSBmcnVzdHVtLmNsb25lKGZydXN0dW1SZXN1bHQpOwogICAgICAgIHJlc3VsdC5fZnJ1c3R1bVR5cGUgPSBmcnVzdHVtVHlwZTsKICAgICAgICByZXN1bHQuX29yaWdpbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShvcmlnaW4sIHJlc3VsdC5fb3JpZ2luKTsKICAgICAgICByZXN1bHQuX29yaWVudGF0aW9uID0gUXVhdGVybmlvbl9kZWZhdWx0LmNsb25lKG9yaWVudGF0aW9uLCByZXN1bHQuX29yaWVudGF0aW9uKTsKICAgICAgICByZXN1bHQuX2RyYXdOZWFyUGxhbmUgPSBkcmF3TmVhclBsYW5lOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIEZydXN0dW1PdXRsaW5lR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihmcnVzdHVtR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBmcnVzdHVtVHlwZSA9IGZydXN0dW1HZW9tZXRyeS5fZnJ1c3R1bVR5cGU7CiAgICAgICAgY29uc3QgZnJ1c3R1bSA9IGZydXN0dW1HZW9tZXRyeS5fZnJ1c3R1bTsKICAgICAgICBjb25zdCBvcmlnaW4gPSBmcnVzdHVtR2VvbWV0cnkuX29yaWdpbjsKICAgICAgICBjb25zdCBvcmllbnRhdGlvbiA9IGZydXN0dW1HZW9tZXRyeS5fb3JpZW50YXRpb247CiAgICAgICAgY29uc3QgZHJhd05lYXJQbGFuZSA9IGZydXN0dW1HZW9tZXRyeS5fZHJhd05lYXJQbGFuZTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KDMgKiA0ICogMik7CiAgICAgICAgRnJ1c3R1bUdlb21ldHJ5X2RlZmF1bHQuX2NvbXB1dGVOZWFyRmFyUGxhbmVzKAogICAgICAgICAgb3JpZ2luLAogICAgICAgICAgb3JpZW50YXRpb24sCiAgICAgICAgICBmcnVzdHVtVHlwZSwKICAgICAgICAgIGZydXN0dW0sCiAgICAgICAgICBwb3NpdGlvbnMKICAgICAgICApOwogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoewogICAgICAgICAgcG9zaXRpb246IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgICAgICAgfSkKICAgICAgICB9KTsKICAgICAgICBsZXQgb2Zmc2V0OwogICAgICAgIGxldCBpbmRleDsKICAgICAgICBjb25zdCBudW1iZXJPZlBsYW5lcyA9IGRyYXdOZWFyUGxhbmUgPyAyIDogMTsKICAgICAgICBjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KDggKiAobnVtYmVyT2ZQbGFuZXMgKyAxKSk7CiAgICAgICAgbGV0IGkyID0gZHJhd05lYXJQbGFuZSA/IDAgOiAxOwogICAgICAgIGZvciAoOyBpMiA8IDI7ICsraTIpIHsKICAgICAgICAgIG9mZnNldCA9IGRyYXdOZWFyUGxhbmUgPyBpMiAqIDggOiAwOwogICAgICAgICAgaW5kZXggPSBpMiAqIDQ7CiAgICAgICAgICBpbmRpY2VzW29mZnNldF0gPSBpbmRleDsKICAgICAgICAgIGluZGljZXNbb2Zmc2V0ICsgMV0gPSBpbmRleCArIDE7CiAgICAgICAgICBpbmRpY2VzW29mZnNldCArIDJdID0gaW5kZXggKyAxOwogICAgICAgICAgaW5kaWNlc1tvZmZzZXQgKyAzXSA9IGluZGV4ICsgMjsKICAgICAgICAgIGluZGljZXNbb2Zmc2V0ICsgNF0gPSBpbmRleCArIDI7CiAgICAgICAgICBpbmRpY2VzW29mZnNldCArIDVdID0gaW5kZXggKyAzOwogICAgICAgICAgaW5kaWNlc1tvZmZzZXQgKyA2XSA9IGluZGV4ICsgMzsKICAgICAgICAgIGluZGljZXNbb2Zmc2V0ICsgN10gPSBpbmRleDsKICAgICAgICB9CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgMjsgKytpMikgewogICAgICAgICAgb2Zmc2V0ID0gKG51bWJlck9mUGxhbmVzICsgaTIpICogODsKICAgICAgICAgIGluZGV4ID0gaTIgKiA0OwogICAgICAgICAgaW5kaWNlc1tvZmZzZXRdID0gaW5kZXg7CiAgICAgICAgICBpbmRpY2VzW29mZnNldCArIDFdID0gaW5kZXggKyA0OwogICAgICAgICAgaW5kaWNlc1tvZmZzZXQgKyAyXSA9IGluZGV4ICsgMTsKICAgICAgICAgIGluZGljZXNbb2Zmc2V0ICsgM10gPSBpbmRleCArIDU7CiAgICAgICAgICBpbmRpY2VzW29mZnNldCArIDRdID0gaW5kZXggKyAyOwogICAgICAgICAgaW5kaWNlc1tvZmZzZXQgKyA1XSA9IGluZGV4ICsgNjsKICAgICAgICAgIGluZGljZXNbb2Zmc2V0ICsgNl0gPSBpbmRleCArIDM7CiAgICAgICAgICBpbmRpY2VzW29mZnNldCArIDddID0gaW5kZXggKyA3OwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZTogQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tVmVydGljZXMocG9zaXRpb25zKQogICAgICAgIH0pOwogICAgICB9OwogICAgICBGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBGcnVzdHVtT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlRnJ1c3R1bU91dGxpbmVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnkoZnJ1c3R1bUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBmcnVzdHVtR2VvbWV0cnkgPSBGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKGZydXN0dW1HZW9tZXRyeSwgb2Zmc2V0KTsKICAgIH0KICAgIHJldHVybiBGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoZnJ1c3R1bUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRnJ1c3R1bU91dGxpbmVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvZ3JhcGhpY1RpbGluZ1NjaGVtZS5qcwogIHZhciBHZW9ncmFwaGljVGlsaW5nU2NoZW1lLCBHZW9ncmFwaGljVGlsaW5nU2NoZW1lX2RlZmF1bHQ7CiAgdmFyIGluaXRfR2VvZ3JhcGhpY1RpbGluZ1NjaGVtZSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR2VvZ3JhcGhpY1RpbGluZ1NjaGVtZS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb2dyYXBoaWNQcm9qZWN0aW9uKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBHZW9ncmFwaGljVGlsaW5nU2NoZW1lID0gY2xhc3MgewogICAgICAgIC8qKgogICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gT2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOgogICAgICAgICAqIEBwYXJhbSB7RWxsaXBzb2lkfSBbb3B0aW9ucy5lbGxpcHNvaWQ9RWxsaXBzb2lkLmRlZmF1bHRdIFRoZSBlbGxpcHNvaWQgd2hvc2Ugc3VyZmFjZSBpcyBiZWluZyB0aWxlZC4gRGVmYXVsdHMgdG8KICAgICAgICAgKiB0aGUgZGVmYXVsdCBlbGxpcHNvaWQuCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtvcHRpb25zLnJlY3RhbmdsZT1SZWN0YW5nbGUuTUFYX1ZBTFVFXSBUaGUgcmVjdGFuZ2xlLCBpbiByYWRpYW5zLCBjb3ZlcmVkIGJ5IHRoZSB0aWxpbmcgc2NoZW1lLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5udW1iZXJPZkxldmVsWmVyb1RpbGVzWD0yXSBUaGUgbnVtYmVyIG9mIHRpbGVzIGluIHRoZSBYIGRpcmVjdGlvbiBhdCBsZXZlbCB6ZXJvIG9mCiAgICAgICAgICogdGhlIHRpbGUgdHJlZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubnVtYmVyT2ZMZXZlbFplcm9UaWxlc1k9MV0gVGhlIG51bWJlciBvZiB0aWxlcyBpbiB0aGUgWSBkaXJlY3Rpb24gYXQgbGV2ZWwgemVybyBvZgogICAgICAgICAqIHRoZSB0aWxlIHRyZWUuCiAgICAgICAgICovCiAgICAgICAgY29uc3RydWN0b3Iob3B0aW9ucykgewogICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgICAgdGhpcy5fZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICAgIHRoaXMuX3JlY3RhbmdsZSA9IG9wdGlvbnMucmVjdGFuZ2xlID8/IFJlY3RhbmdsZV9kZWZhdWx0Lk1BWF9WQUxVRTsKICAgICAgICAgIHRoaXMuX3Byb2plY3Rpb24gPSBuZXcgR2VvZ3JhcGhpY1Byb2plY3Rpb25fZGVmYXVsdCh0aGlzLl9lbGxpcHNvaWQpOwogICAgICAgICAgdGhpcy5fbnVtYmVyT2ZMZXZlbFplcm9UaWxlc1ggPSBvcHRpb25zLm51bWJlck9mTGV2ZWxaZXJvVGlsZXNYID8/IDI7CiAgICAgICAgICB0aGlzLl9udW1iZXJPZkxldmVsWmVyb1RpbGVzWSA9IG9wdGlvbnMubnVtYmVyT2ZMZXZlbFplcm9UaWxlc1kgPz8gMTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgZWxsaXBzb2lkIHRoYXQgaXMgdGlsZWQgYnkgdGhpcyB0aWxpbmcgc2NoZW1lLgogICAgICAgICAqIEB0eXBlIHtFbGxpcHNvaWR9CiAgICAgICAgICovCiAgICAgICAgZ2V0IGVsbGlwc29pZCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9lbGxpcHNvaWQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHJlY3RhbmdsZSwgaW4gcmFkaWFucywgY292ZXJlZCBieSB0aGlzIHRpbGluZyBzY2hlbWUuCiAgICAgICAgICogQHR5cGUge1JlY3RhbmdsZX0KICAgICAgICAgKi8KICAgICAgICBnZXQgcmVjdGFuZ2xlKCkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX3JlY3RhbmdsZTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgbWFwIHByb2plY3Rpb24gdXNlZCBieSB0aGlzIHRpbGluZyBzY2hlbWUuCiAgICAgICAgICogQHR5cGUge01hcFByb2plY3Rpb259CiAgICAgICAgICovCiAgICAgICAgZ2V0IHByb2plY3Rpb24oKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fcHJvamVjdGlvbjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdG90YWwgbnVtYmVyIG9mIHRpbGVzIGluIHRoZSBYIGRpcmVjdGlvbiBhdCBhIHNwZWNpZmllZCBsZXZlbC1vZi1kZXRhaWwuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgVGhlIGxldmVsLW9mLWRldGFpbC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgbnVtYmVyIG9mIHRpbGVzIGluIHRoZSBYIGRpcmVjdGlvbiBhdCB0aGUgZ2l2ZW4gbGV2ZWwuCiAgICAgICAgICovCiAgICAgICAgZ2V0TnVtYmVyT2ZYVGlsZXNBdExldmVsKGxldmVsKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fbnVtYmVyT2ZMZXZlbFplcm9UaWxlc1ggPDwgbGV2ZWw7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHRvdGFsIG51bWJlciBvZiB0aWxlcyBpbiB0aGUgWSBkaXJlY3Rpb24gYXQgYSBzcGVjaWZpZWQgbGV2ZWwtb2YtZGV0YWlsLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIFRoZSBsZXZlbC1vZi1kZXRhaWwuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIG51bWJlciBvZiB0aWxlcyBpbiB0aGUgWSBkaXJlY3Rpb24gYXQgdGhlIGdpdmVuIGxldmVsLgogICAgICAgICAqLwogICAgICAgIGdldE51bWJlck9mWVRpbGVzQXRMZXZlbChsZXZlbCkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX251bWJlck9mTGV2ZWxaZXJvVGlsZXNZIDw8IGxldmVsOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBUcmFuc2Zvcm1zIGEgcmVjdGFuZ2xlIHNwZWNpZmllZCBpbiBnZW9kZXRpYyByYWRpYW5zIHRvIHRoZSBuYXRpdmUgY29vcmRpbmF0ZSBzeXN0ZW0KICAgICAgICAgKiBvZiB0aGlzIHRpbGluZyBzY2hlbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gcmVjdGFuZ2xlIFRoZSByZWN0YW5nbGUgdG8gdHJhbnNmb3JtLgogICAgICAgICAqIEBwYXJhbSB7UmVjdGFuZ2xlfSBbcmVzdWx0XSBUaGUgaW5zdGFuY2UgdG8gd2hpY2ggdG8gY29weSB0aGUgcmVzdWx0LCBvciB1bmRlZmluZWQgaWYgYSBuZXcgaW5zdGFuY2UKICAgICAgICAgKiAgICAgICAgc2hvdWxkIGJlIGNyZWF0ZWQuCiAgICAgICAgICogQHJldHVybnMge1JlY3RhbmdsZX0gVGhlIHNwZWNpZmllZCAncmVzdWx0Jywgb3IgYSBuZXcgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIG5hdGl2ZSByZWN0YW5nbGUgaWYgJ3Jlc3VsdCcKICAgICAgICAgKiAgICAgICAgICBpcyB1bmRlZmluZWQuCiAgICAgICAgICovCiAgICAgICAgcmVjdGFuZ2xlVG9OYXRpdmVSZWN0YW5nbGUocmVjdGFuZ2xlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICAgIGNvbnN0IHdlc3QgPSBNYXRoX2RlZmF1bHQudG9EZWdyZWVzKHJlY3RhbmdsZS53ZXN0KTsKICAgICAgICAgIGNvbnN0IHNvdXRoID0gTWF0aF9kZWZhdWx0LnRvRGVncmVlcyhyZWN0YW5nbGUuc291dGgpOwogICAgICAgICAgY29uc3QgZWFzdCA9IE1hdGhfZGVmYXVsdC50b0RlZ3JlZXMocmVjdGFuZ2xlLmVhc3QpOwogICAgICAgICAgY29uc3Qgbm9ydGggPSBNYXRoX2RlZmF1bHQudG9EZWdyZWVzKHJlY3RhbmdsZS5ub3J0aCk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQod2VzdCwgc291dGgsIGVhc3QsIG5vcnRoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC53ZXN0ID0gd2VzdDsKICAgICAgICAgIHJlc3VsdC5zb3V0aCA9IHNvdXRoOwogICAgICAgICAgcmVzdWx0LmVhc3QgPSBlYXN0OwogICAgICAgICAgcmVzdWx0Lm5vcnRoID0gbm9ydGg7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aWxlIHgsIHkgY29vcmRpbmF0ZXMgYW5kIGxldmVsIHRvIGEgcmVjdGFuZ2xlIGV4cHJlc3NlZCBpbiB0aGUgbmF0aXZlIGNvb3JkaW5hdGVzCiAgICAgICAgICogb2YgdGhlIHRpbGluZyBzY2hlbWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0geCBUaGUgaW50ZWdlciB4IGNvb3JkaW5hdGUgb2YgdGhlIHRpbGUuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHkgVGhlIGludGVnZXIgeSBjb29yZGluYXRlIG9mIHRoZSB0aWxlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCBUaGUgdGlsZSBsZXZlbC1vZi1kZXRhaWwuICBaZXJvIGlzIHRoZSBsZWFzdCBkZXRhaWxlZC4KICAgICAgICAgKiBAcGFyYW0ge1JlY3RhbmdsZX0gW3Jlc3VsdF0gVGhlIGluc3RhbmNlIHRvIHdoaWNoIHRvIGNvcHkgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEgbmV3IGluc3RhbmNlCiAgICAgICAgICogICAgICAgIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtSZWN0YW5nbGV9IFRoZSBzcGVjaWZpZWQgJ3Jlc3VsdCcsIG9yIGEgbmV3IG9iamVjdCBjb250YWluaW5nIHRoZSByZWN0YW5nbGUKICAgICAgICAgKiAgICAgICAgICBpZiAncmVzdWx0JyBpcyB1bmRlZmluZWQuCiAgICAgICAgICovCiAgICAgICAgdGlsZVhZVG9OYXRpdmVSZWN0YW5nbGUoeDIsIHkyLCBsZXZlbCwgcmVzdWx0KSB7CiAgICAgICAgICBjb25zdCByZWN0YW5nbGVSYWRpYW5zID0gdGhpcy50aWxlWFlUb1JlY3RhbmdsZSh4MiwgeTIsIGxldmVsLCByZXN1bHQpOwogICAgICAgICAgcmVjdGFuZ2xlUmFkaWFucy53ZXN0ID0gTWF0aF9kZWZhdWx0LnRvRGVncmVlcyhyZWN0YW5nbGVSYWRpYW5zLndlc3QpOwogICAgICAgICAgcmVjdGFuZ2xlUmFkaWFucy5zb3V0aCA9IE1hdGhfZGVmYXVsdC50b0RlZ3JlZXMocmVjdGFuZ2xlUmFkaWFucy5zb3V0aCk7CiAgICAgICAgICByZWN0YW5nbGVSYWRpYW5zLmVhc3QgPSBNYXRoX2RlZmF1bHQudG9EZWdyZWVzKHJlY3RhbmdsZVJhZGlhbnMuZWFzdCk7CiAgICAgICAgICByZWN0YW5nbGVSYWRpYW5zLm5vcnRoID0gTWF0aF9kZWZhdWx0LnRvRGVncmVlcyhyZWN0YW5nbGVSYWRpYW5zLm5vcnRoKTsKICAgICAgICAgIHJldHVybiByZWN0YW5nbGVSYWRpYW5zOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aWxlIHgsIHkgY29vcmRpbmF0ZXMgYW5kIGxldmVsIHRvIGEgY2FydG9ncmFwaGljIHJlY3RhbmdsZSBpbiByYWRpYW5zLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHggVGhlIGludGVnZXIgeCBjb29yZGluYXRlIG9mIHRoZSB0aWxlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IFRoZSBpbnRlZ2VyIHkgY29vcmRpbmF0ZSBvZiB0aGUgdGlsZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgVGhlIHRpbGUgbGV2ZWwtb2YtZGV0YWlsLiAgWmVybyBpcyB0aGUgbGVhc3QgZGV0YWlsZWQuCiAgICAgICAgICogQHBhcmFtIHtSZWN0YW5nbGV9IFtyZXN1bHRdIFRoZSBpbnN0YW5jZSB0byB3aGljaCB0byBjb3B5IHRoZSByZXN1bHQsIG9yIHVuZGVmaW5lZCBpZiBhIG5ldyBpbnN0YW5jZQogICAgICAgICAqICAgICAgICBzaG91bGQgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7UmVjdGFuZ2xlfSBUaGUgc3BlY2lmaWVkICdyZXN1bHQnLCBvciBhIG5ldyBvYmplY3QgY29udGFpbmluZyB0aGUgcmVjdGFuZ2xlCiAgICAgICAgICogICAgICAgICAgaWYgJ3Jlc3VsdCcgaXMgdW5kZWZpbmVkLgogICAgICAgICAqLwogICAgICAgIHRpbGVYWVRvUmVjdGFuZ2xlKHgyLCB5MiwgbGV2ZWwsIHJlc3VsdCkgewogICAgICAgICAgY29uc3QgcmVjdGFuZ2xlID0gdGhpcy5fcmVjdGFuZ2xlOwogICAgICAgICAgY29uc3QgeFRpbGVzID0gdGhpcy5nZXROdW1iZXJPZlhUaWxlc0F0TGV2ZWwobGV2ZWwpOwogICAgICAgICAgY29uc3QgeVRpbGVzID0gdGhpcy5nZXROdW1iZXJPZllUaWxlc0F0TGV2ZWwobGV2ZWwpOwogICAgICAgICAgY29uc3QgeFRpbGVXaWR0aCA9IHJlY3RhbmdsZS53aWR0aCAvIHhUaWxlczsKICAgICAgICAgIGNvbnN0IHdlc3QgPSB4MiAqIHhUaWxlV2lkdGggKyByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGNvbnN0IGVhc3QgPSAoeDIgKyAxKSAqIHhUaWxlV2lkdGggKyByZWN0YW5nbGUud2VzdDsKICAgICAgICAgIGNvbnN0IHlUaWxlSGVpZ2h0ID0gcmVjdGFuZ2xlLmhlaWdodCAvIHlUaWxlczsKICAgICAgICAgIGNvbnN0IG5vcnRoID0gcmVjdGFuZ2xlLm5vcnRoIC0geTIgKiB5VGlsZUhlaWdodDsKICAgICAgICAgIGNvbnN0IHNvdXRoID0gcmVjdGFuZ2xlLm5vcnRoIC0gKHkyICsgMSkgKiB5VGlsZUhlaWdodDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KHdlc3QsIHNvdXRoLCBlYXN0LCBub3J0aCk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQud2VzdCA9IHdlc3Q7CiAgICAgICAgICByZXN1bHQuc291dGggPSBzb3V0aDsKICAgICAgICAgIHJlc3VsdC5lYXN0ID0gZWFzdDsKICAgICAgICAgIHJlc3VsdC5ub3J0aCA9IG5vcnRoOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ2FsY3VsYXRlcyB0aGUgdGlsZSB4LCB5IGNvb3JkaW5hdGVzIG9mIHRoZSB0aWxlIGNvbnRhaW5pbmcKICAgICAgICAgKiBhIGdpdmVuIGNhcnRvZ3JhcGhpYyBwb3NpdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q2FydG9ncmFwaGljfSBwb3NpdGlvbiBUaGUgcG9zaXRpb24uCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIFRoZSB0aWxlIGxldmVsLW9mLWRldGFpbC4gIFplcm8gaXMgdGhlIGxlYXN0IGRldGFpbGVkLgogICAgICAgICAqIEBwYXJhbSB7Q2FydGVzaWFuMn0gW3Jlc3VsdF0gVGhlIGluc3RhbmNlIHRvIHdoaWNoIHRvIGNvcHkgdGhlIHJlc3VsdCwgb3IgdW5kZWZpbmVkIGlmIGEgbmV3IGluc3RhbmNlCiAgICAgICAgICogICAgICAgIHNob3VsZCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4yfSBUaGUgc3BlY2lmaWVkICdyZXN1bHQnLCBvciBhIG5ldyBvYmplY3QgY29udGFpbmluZyB0aGUgdGlsZSB4LCB5IGNvb3JkaW5hdGVzCiAgICAgICAgICogICAgICAgICAgaWYgJ3Jlc3VsdCcgaXMgdW5kZWZpbmVkLgogICAgICAgICAqLwogICAgICAgIHBvc2l0aW9uVG9UaWxlWFkocG9zaXRpb24sIGxldmVsLCByZXN1bHQpIHsKICAgICAgICAgIGNvbnN0IHJlY3RhbmdsZSA9IHRoaXMuX3JlY3RhbmdsZTsKICAgICAgICAgIGlmICghUmVjdGFuZ2xlX2RlZmF1bHQuY29udGFpbnMocmVjdGFuZ2xlLCBwb3NpdGlvbikpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHhUaWxlcyA9IHRoaXMuZ2V0TnVtYmVyT2ZYVGlsZXNBdExldmVsKGxldmVsKTsKICAgICAgICAgIGNvbnN0IHlUaWxlcyA9IHRoaXMuZ2V0TnVtYmVyT2ZZVGlsZXNBdExldmVsKGxldmVsKTsKICAgICAgICAgIGNvbnN0IHhUaWxlV2lkdGggPSByZWN0YW5nbGUud2lkdGggLyB4VGlsZXM7CiAgICAgICAgICBjb25zdCB5VGlsZUhlaWdodCA9IHJlY3RhbmdsZS5oZWlnaHQgLyB5VGlsZXM7CiAgICAgICAgICBsZXQgbG9uZ2l0dWRlID0gcG9zaXRpb24ubG9uZ2l0dWRlOwogICAgICAgICAgaWYgKHJlY3RhbmdsZS5lYXN0IDwgcmVjdGFuZ2xlLndlc3QpIHsKICAgICAgICAgICAgbG9uZ2l0dWRlICs9IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgeFRpbGVDb29yZGluYXRlID0gKGxvbmdpdHVkZSAtIHJlY3RhbmdsZS53ZXN0KSAvIHhUaWxlV2lkdGggfCAwOwogICAgICAgICAgaWYgKHhUaWxlQ29vcmRpbmF0ZSA+PSB4VGlsZXMpIHsKICAgICAgICAgICAgeFRpbGVDb29yZGluYXRlID0geFRpbGVzIC0gMTsKICAgICAgICAgIH0KICAgICAgICAgIGxldCB5VGlsZUNvb3JkaW5hdGUgPSAocmVjdGFuZ2xlLm5vcnRoIC0gcG9zaXRpb24ubGF0aXR1ZGUpIC8geVRpbGVIZWlnaHQgfCAwOwogICAgICAgICAgaWYgKHlUaWxlQ29vcmRpbmF0ZSA+PSB5VGlsZXMpIHsKICAgICAgICAgICAgeVRpbGVDb29yZGluYXRlID0geVRpbGVzIC0gMTsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoeFRpbGVDb29yZGluYXRlLCB5VGlsZUNvb3JkaW5hdGUpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSB4VGlsZUNvb3JkaW5hdGU7CiAgICAgICAgICByZXN1bHQueSA9IHlUaWxlQ29vcmRpbmF0ZTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICB9OwogICAgICBHZW9ncmFwaGljVGlsaW5nU2NoZW1lX2RlZmF1bHQgPSBHZW9ncmFwaGljVGlsaW5nU2NoZW1lOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5qcwogIGZ1bmN0aW9uIGdldFRpbGVYWUxldmVsKHJlY3RhbmdsZSkgewogICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgIHJlY3RhbmdsZS5lYXN0LAogICAgICByZWN0YW5nbGUubm9ydGgsCiAgICAgIDAsCiAgICAgIHNjcmF0Y2hDb3JuZXJzWzBdCiAgICApOwogICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgIHJlY3RhbmdsZS53ZXN0LAogICAgICByZWN0YW5nbGUubm9ydGgsCiAgICAgIDAsCiAgICAgIHNjcmF0Y2hDb3JuZXJzWzFdCiAgICApOwogICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgIHJlY3RhbmdsZS5lYXN0LAogICAgICByZWN0YW5nbGUuc291dGgsCiAgICAgIDAsCiAgICAgIHNjcmF0Y2hDb3JuZXJzWzJdCiAgICApOwogICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgIHJlY3RhbmdsZS53ZXN0LAogICAgICByZWN0YW5nbGUuc291dGgsCiAgICAgIDAsCiAgICAgIHNjcmF0Y2hDb3JuZXJzWzNdCiAgICApOwogICAgbGV0IGxhc3RMZXZlbFggPSAwLCBsYXN0TGV2ZWxZID0gMDsKICAgIGxldCBjdXJyZW50WCA9IDAsIGN1cnJlbnRZID0gMDsKICAgIGNvbnN0IG1heExldmVsID0gQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fdGVycmFpbkhlaWdodHNNYXhMZXZlbDsKICAgIGxldCBpMjsKICAgIGZvciAoaTIgPSAwOyBpMiA8PSBtYXhMZXZlbDsgKytpMikgewogICAgICBsZXQgZmFpbGVkID0gZmFsc2U7CiAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCA0OyArK2oyKSB7CiAgICAgICAgY29uc3QgY29ybmVyID0gc2NyYXRjaENvcm5lcnNbajJdOwogICAgICAgIHRpbGluZ1NjaGVtZS5wb3NpdGlvblRvVGlsZVhZKGNvcm5lciwgaTIsIHNjcmF0Y2hUaWxlWFkpOwogICAgICAgIGlmIChqMiA9PT0gMCkgewogICAgICAgICAgY3VycmVudFggPSBzY3JhdGNoVGlsZVhZLng7CiAgICAgICAgICBjdXJyZW50WSA9IHNjcmF0Y2hUaWxlWFkueTsKICAgICAgICB9IGVsc2UgaWYgKGN1cnJlbnRYICE9PSBzY3JhdGNoVGlsZVhZLnggfHwgY3VycmVudFkgIT09IHNjcmF0Y2hUaWxlWFkueSkgewogICAgICAgICAgZmFpbGVkID0gdHJ1ZTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgICBpZiAoZmFpbGVkKSB7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgbGFzdExldmVsWCA9IGN1cnJlbnRYOwogICAgICBsYXN0TGV2ZWxZID0gY3VycmVudFk7CiAgICB9CiAgICBpZiAoaTIgPT09IDApIHsKICAgICAgcmV0dXJuIHZvaWQgMDsKICAgIH0KICAgIHJldHVybiB7CiAgICAgIHg6IGxhc3RMZXZlbFgsCiAgICAgIHk6IGxhc3RMZXZlbFksCiAgICAgIGxldmVsOiBpMiA+IG1heExldmVsID8gbWF4TGV2ZWwgOiBpMiAtIDEKICAgIH07CiAgfQogIHZhciBzY3JhdGNoRGlhZ29uYWxDYXJ0ZXNpYW5ORSwgc2NyYXRjaERpYWdvbmFsQ2FydGVzaWFuU1csIHNjcmF0Y2hEaWFnb25hbENhcnRvZ3JhcGhpYywgc2NyYXRjaENlbnRlckNhcnRlc2lhbiwgc2NyYXRjaFN1cmZhY2VDYXJ0ZXNpYW4sIHNjcmF0Y2hCb3VuZGluZ1NwaGVyZTIsIHRpbGluZ1NjaGVtZSwgc2NyYXRjaENvcm5lcnMsIHNjcmF0Y2hUaWxlWFksIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMsIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHNfZGVmYXVsdDsKICB2YXIgaW5pdF9BcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9BcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X2J1aWxkTW9kdWxlVXJsKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb2dyYXBoaWNUaWxpbmdTY2hlbWUoKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgaW5pdF9SZXNvdXJjZSgpOwogICAgICBzY3JhdGNoRGlhZ29uYWxDYXJ0ZXNpYW5ORSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaERpYWdvbmFsQ2FydGVzaWFuU1cgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hEaWFnb25hbENhcnRvZ3JhcGhpYyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoU3VyZmFjZUNhcnRlc2lhbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEJvdW5kaW5nU3BoZXJlMiA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHRpbGluZ1NjaGVtZSA9IG5ldyBHZW9ncmFwaGljVGlsaW5nU2NoZW1lX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENvcm5lcnMgPSBbCiAgICAgICAgbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCkKICAgICAgXTsKICAgICAgc2NyYXRjaFRpbGVYWSA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cyA9IHt9OwogICAgICBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLmluaXRpYWxpemUgPSBmdW5jdGlvbigpIHsKICAgICAgICBsZXQgaW5pdFByb21pc2UgPSBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl9pbml0UHJvbWlzZTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluaXRQcm9taXNlKSkgewogICAgICAgICAgcmV0dXJuIGluaXRQcm9taXNlOwogICAgICAgIH0KICAgICAgICBpbml0UHJvbWlzZSA9IFJlc291cmNlX2RlZmF1bHQuZmV0Y2hKc29uKAogICAgICAgICAgYnVpbGRNb2R1bGVVcmxfZGVmYXVsdCgiQXNzZXRzL2FwcHJveGltYXRlVGVycmFpbkhlaWdodHMuanNvbiIpCiAgICAgICAgKS50aGVuKGZ1bmN0aW9uKGpzb24pIHsKICAgICAgICAgIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX3RlcnJhaW5IZWlnaHRzID0ganNvbjsKICAgICAgICB9KTsKICAgICAgICBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl9pbml0UHJvbWlzZSA9IGluaXRQcm9taXNlOwogICAgICAgIHJldHVybiBpbml0UHJvbWlzZTsKICAgICAgfTsKICAgICAgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5nZXRNaW5pbXVtTWF4aW11bUhlaWdodHMgPSBmdW5jdGlvbihyZWN0YW5nbGUsIGVsbGlwc29pZCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl90ZXJyYWluSGVpZ2h0cykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiWW91IG11c3QgY2FsbCBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLmluaXRpYWxpemUgYW5kIHdhaXQgZm9yIHRoZSBwcm9taXNlIHRvIHJlc29sdmUgYmVmb3JlIHVzaW5nIHRoaXMgZnVuY3Rpb24iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBlbGxpcHNvaWQgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCB4eUxldmVsID0gZ2V0VGlsZVhZTGV2ZWwocmVjdGFuZ2xlKTsKICAgICAgICBsZXQgbWluVGVycmFpbkhlaWdodCA9IEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX2RlZmF1bHRNaW5UZXJyYWluSGVpZ2h0OwogICAgICAgIGxldCBtYXhUZXJyYWluSGVpZ2h0ID0gQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fZGVmYXVsdE1heFRlcnJhaW5IZWlnaHQ7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh4eUxldmVsKSkgewogICAgICAgICAgY29uc3Qga2V5ID0gYCR7eHlMZXZlbC5sZXZlbH0tJHt4eUxldmVsLnh9LSR7eHlMZXZlbC55fWA7CiAgICAgICAgICBjb25zdCBoZWlnaHRzID0gQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fdGVycmFpbkhlaWdodHNba2V5XTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaGVpZ2h0cykpIHsKICAgICAgICAgICAgbWluVGVycmFpbkhlaWdodCA9IGhlaWdodHNbMF07CiAgICAgICAgICAgIG1heFRlcnJhaW5IZWlnaHQgPSBoZWlnaHRzWzFdOwogICAgICAgICAgfQogICAgICAgICAgZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgICAgICBSZWN0YW5nbGVfZGVmYXVsdC5ub3J0aGVhc3QocmVjdGFuZ2xlLCBzY3JhdGNoRGlhZ29uYWxDYXJ0b2dyYXBoaWMpLAogICAgICAgICAgICBzY3JhdGNoRGlhZ29uYWxDYXJ0ZXNpYW5ORQogICAgICAgICAgKTsKICAgICAgICAgIGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICAgICAgUmVjdGFuZ2xlX2RlZmF1bHQuc291dGh3ZXN0KHJlY3RhbmdsZSwgc2NyYXRjaERpYWdvbmFsQ2FydG9ncmFwaGljKSwKICAgICAgICAgICAgc2NyYXRjaERpYWdvbmFsQ2FydGVzaWFuU1cKICAgICAgICAgICk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWlkcG9pbnQoCiAgICAgICAgICAgIHNjcmF0Y2hEaWFnb25hbENhcnRlc2lhblNXLAogICAgICAgICAgICBzY3JhdGNoRGlhZ29uYWxDYXJ0ZXNpYW5ORSwKICAgICAgICAgICAgc2NyYXRjaENlbnRlckNhcnRlc2lhbgogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHN1cmZhY2VQb3NpdGlvbiA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKAogICAgICAgICAgICBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuLAogICAgICAgICAgICBzY3JhdGNoU3VyZmFjZUNhcnRlc2lhbgogICAgICAgICAgKTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoc3VyZmFjZVBvc2l0aW9uKSkgewogICAgICAgICAgICBjb25zdCBkaXN0YW5jZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5kaXN0YW5jZSgKICAgICAgICAgICAgICBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuLAogICAgICAgICAgICAgIHN1cmZhY2VQb3NpdGlvbgogICAgICAgICAgICApOwogICAgICAgICAgICBtaW5UZXJyYWluSGVpZ2h0ID0gTWF0aC5taW4obWluVGVycmFpbkhlaWdodCwgLWRpc3RhbmNlKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIG1pblRlcnJhaW5IZWlnaHQgPSBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl9kZWZhdWx0TWluVGVycmFpbkhlaWdodDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbWluVGVycmFpbkhlaWdodCA9IE1hdGgubWF4KAogICAgICAgICAgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fZGVmYXVsdE1pblRlcnJhaW5IZWlnaHQsCiAgICAgICAgICBtaW5UZXJyYWluSGVpZ2h0CiAgICAgICAgKTsKICAgICAgICByZXR1cm4gewogICAgICAgICAgbWluaW11bVRlcnJhaW5IZWlnaHQ6IG1pblRlcnJhaW5IZWlnaHQsCiAgICAgICAgICBtYXhpbXVtVGVycmFpbkhlaWdodDogbWF4VGVycmFpbkhlaWdodAogICAgICAgIH07CiAgICAgIH07CiAgICAgIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuZ2V0Qm91bmRpbmdTcGhlcmUgPSBmdW5jdGlvbihyZWN0YW5nbGUsIGVsbGlwc29pZCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl90ZXJyYWluSGVpZ2h0cykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiWW91IG11c3QgY2FsbCBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLmluaXRpYWxpemUgYW5kIHdhaXQgZm9yIHRoZSBwcm9taXNlIHRvIHJlc29sdmUgYmVmb3JlIHVzaW5nIHRoaXMgZnVuY3Rpb24iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBlbGxpcHNvaWQgPSBlbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCB4eUxldmVsID0gZ2V0VGlsZVhZTGV2ZWwocmVjdGFuZ2xlKTsKICAgICAgICBsZXQgbWF4VGVycmFpbkhlaWdodCA9IEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX2RlZmF1bHRNYXhUZXJyYWluSGVpZ2h0OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoeHlMZXZlbCkpIHsKICAgICAgICAgIGNvbnN0IGtleSA9IGAke3h5TGV2ZWwubGV2ZWx9LSR7eHlMZXZlbC54fS0ke3h5TGV2ZWwueX1gOwogICAgICAgICAgY29uc3QgaGVpZ2h0cyA9IEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX3RlcnJhaW5IZWlnaHRzW2tleV07CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGhlaWdodHMpKSB7CiAgICAgICAgICAgIG1heFRlcnJhaW5IZWlnaHQgPSBoZWlnaHRzWzFdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCByZXN1bHQgPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21SZWN0YW5nbGUzRChyZWN0YW5nbGUsIGVsbGlwc29pZCwgMCk7CiAgICAgICAgQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlM0QoCiAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBtYXhUZXJyYWluSGVpZ2h0LAogICAgICAgICAgc2NyYXRjaEJvdW5kaW5nU3BoZXJlMgogICAgICAgICk7CiAgICAgICAgcmV0dXJuIEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQudW5pb24ocmVzdWx0LCBzY3JhdGNoQm91bmRpbmdTcGhlcmUyLCByZXN1bHQpOwogICAgICB9OwogICAgICBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLl90ZXJyYWluSGVpZ2h0c01heExldmVsID0gNjsKICAgICAgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fZGVmYXVsdE1heFRlcnJhaW5IZWlnaHQgPSA5ZTM7CiAgICAgIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX2RlZmF1bHRNaW5UZXJyYWluSGVpZ2h0ID0gLTFlNTsKICAgICAgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cy5fdGVycmFpbkhlaWdodHMgPSB2b2lkIDA7CiAgICAgIEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX2luaXRQcm9taXNlID0gdm9pZCAwOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogRGV0ZXJtaW5lcyBpZiB0aGUgdGVycmFpbiBoZWlnaHRzIGFyZSBpbml0aWFsaXplZCBhbmQgcmVhZHkgdG8gdXNlLiBUbyBpbml0aWFsaXplIHRoZSB0ZXJyYWluIGhlaWdodHMsCiAgICAgICAgICogY2FsbCB7QGxpbmsgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cyNpbml0aWFsaXplfSBhbmQgd2FpdCBmb3IgdGhlIHJldHVybmVkIHByb21pc2UgdG8gcmVzb2x2ZS4KICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKiBAbWVtYmVyb2YgQXBwcm94aW1hdGVUZXJyYWluSGVpZ2h0cwogICAgICAgICAqLwogICAgICAgIGluaXRpYWxpemVkOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gZGVmaW5lZF9kZWZhdWx0KEFwcHJveGltYXRlVGVycmFpbkhlaWdodHMuX3RlcnJhaW5IZWlnaHRzKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzX2RlZmF1bHQgPSBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvR3JvdW5kUG9seWxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIEdyb3VuZFBvbHlsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpIHx8IHBvc2l0aW9ucy5sZW5ndGggPCAyKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJBdCBsZWFzdCB0d28gcG9zaXRpb25zIGFyZSByZXF1aXJlZC4iKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5hcmNUeXBlKSAmJiBvcHRpb25zLmFyY1R5cGUgIT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQyAmJiBvcHRpb25zLmFyY1R5cGUgIT09IEFyY1R5cGVfZGVmYXVsdC5SSFVNQikgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAiVmFsaWQgb3B0aW9ucyBmb3IgYXJjVHlwZSBhcmUgQXJjVHlwZS5HRU9ERVNJQyBhbmQgQXJjVHlwZS5SSFVNQi4iCiAgICAgICk7CiAgICB9CiAgICB0aGlzLndpZHRoID0gb3B0aW9ucy53aWR0aCA/PyAxOwogICAgdGhpcy5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgdGhpcy5ncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gOTk5OTsKICAgIHRoaXMubG9vcCA9IG9wdGlvbnMubG9vcCA/PyBmYWxzZTsKICAgIHRoaXMuYXJjVHlwZSA9IG9wdGlvbnMuYXJjVHlwZSA/PyBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUM7CiAgICB0aGlzLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgdGhpcy5fcHJvamVjdGlvbkluZGV4ID0gMDsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlR3JvdW5kUG9seWxpbmVHZW9tZXRyeSI7CiAgICB0aGlzLl9zY2VuZTNET25seSA9IGZhbHNlOwogIH0KICBmdW5jdGlvbiBjb21wdXRlUmlnaHROb3JtYWwoc3RhcnQsIGVuZCwgbWF4SGVpZ2h0LCBlbGxpcHNvaWQsIHJlc3VsdCkgewogICAgY29uc3Qgc3RhcnRCb3R0b20gPSBnZXRQb3NpdGlvbihlbGxpcHNvaWQsIHN0YXJ0LCAwLCBjYXJ0M1NjcmF0Y2gxKTsKICAgIGNvbnN0IHN0YXJ0VG9wID0gZ2V0UG9zaXRpb24oZWxsaXBzb2lkLCBzdGFydCwgbWF4SGVpZ2h0LCBjYXJ0M1NjcmF0Y2gyKTsKICAgIGNvbnN0IGVuZEJvdHRvbSA9IGdldFBvc2l0aW9uKGVsbGlwc29pZCwgZW5kLCAwLCBjYXJ0M1NjcmF0Y2gzKTsKICAgIGNvbnN0IHVwID0gZGlyZWN0aW9uKHN0YXJ0VG9wLCBzdGFydEJvdHRvbSwgY2FydDNTY3JhdGNoMik7CiAgICBjb25zdCBmb3J3YXJkID0gZGlyZWN0aW9uKGVuZEJvdHRvbSwgc3RhcnRCb3R0b20sIGNhcnQzU2NyYXRjaDMpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGZvcndhcmQsIHVwLCByZXN1bHQpOwogICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmVzdWx0LCByZXN1bHQpOwogIH0KICBmdW5jdGlvbiBpbnRlcnBvbGF0ZVNlZ21lbnQoc3RhcnQsIGVuZCwgbWluSGVpZ2h0LCBtYXhIZWlnaHQsIGdyYW51bGFyaXR5LCBhcmNUeXBlLCBlbGxpcHNvaWQsIG5vcm1hbHNBcnJheSwgYm90dG9tUG9zaXRpb25zQXJyYXksIHRvcFBvc2l0aW9uc0FycmF5LCBjYXJ0b2dyYXBoaWNzQXJyYXkpIHsKICAgIGlmIChncmFudWxhcml0eSA9PT0gMCkgewogICAgICByZXR1cm47CiAgICB9CiAgICBsZXQgZWxsaXBzb2lkTGluZTsKICAgIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMpIHsKICAgICAgZWxsaXBzb2lkTGluZSA9IG5ldyBFbGxpcHNvaWRHZW9kZXNpY19kZWZhdWx0KHN0YXJ0LCBlbmQsIGVsbGlwc29pZCk7CiAgICB9IGVsc2UgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5SSFVNQikgewogICAgICBlbGxpcHNvaWRMaW5lID0gbmV3IEVsbGlwc29pZFJodW1iTGluZV9kZWZhdWx0KHN0YXJ0LCBlbmQsIGVsbGlwc29pZCk7CiAgICB9CiAgICBjb25zdCBzdXJmYWNlRGlzdGFuY2UgPSBlbGxpcHNvaWRMaW5lLnN1cmZhY2VEaXN0YW5jZTsKICAgIGlmIChzdXJmYWNlRGlzdGFuY2UgPCBncmFudWxhcml0eSkgewogICAgICByZXR1cm47CiAgICB9CiAgICBjb25zdCBpbnRlcnBvbGF0ZWROb3JtYWwgPSBjb21wdXRlUmlnaHROb3JtYWwoCiAgICAgIHN0YXJ0LAogICAgICBlbmQsCiAgICAgIG1heEhlaWdodCwKICAgICAgZWxsaXBzb2lkLAogICAgICBpbnRlcnBvbGF0ZWROb3JtYWxTY3JhdGNoCiAgICApOwogICAgY29uc3Qgc2VnbWVudHMgPSBNYXRoLmNlaWwoc3VyZmFjZURpc3RhbmNlIC8gZ3JhbnVsYXJpdHkpOwogICAgY29uc3QgaW50ZXJwb2ludERpc3RhbmNlID0gc3VyZmFjZURpc3RhbmNlIC8gc2VnbWVudHM7CiAgICBsZXQgZGlzdGFuY2VGcm9tU3RhcnQgPSBpbnRlcnBvaW50RGlzdGFuY2U7CiAgICBjb25zdCBwb2ludHNUb0FkZCA9IHNlZ21lbnRzIC0gMTsKICAgIGxldCBwYWNrSW5kZXggPSBub3JtYWxzQXJyYXkubGVuZ3RoOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvaW50c1RvQWRkOyBpMisrKSB7CiAgICAgIGNvbnN0IGludGVycG9sYXRlZENhcnRvZ3JhcGhpYyA9IGVsbGlwc29pZExpbmUuaW50ZXJwb2xhdGVVc2luZ1N1cmZhY2VEaXN0YW5jZSgKICAgICAgICBkaXN0YW5jZUZyb21TdGFydCwKICAgICAgICBpbnRlcnBvbGF0ZWRDYXJ0b2dyYXBoaWNTY3JhdGNoCiAgICAgICk7CiAgICAgIGNvbnN0IGludGVycG9sYXRlZEJvdHRvbSA9IGdldFBvc2l0aW9uKAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICBpbnRlcnBvbGF0ZWRDYXJ0b2dyYXBoaWMsCiAgICAgICAgbWluSGVpZ2h0LAogICAgICAgIGludGVycG9sYXRlZEJvdHRvbVNjcmF0Y2gKICAgICAgKTsKICAgICAgY29uc3QgaW50ZXJwb2xhdGVkVG9wID0gZ2V0UG9zaXRpb24oCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIGludGVycG9sYXRlZENhcnRvZ3JhcGhpYywKICAgICAgICBtYXhIZWlnaHQsCiAgICAgICAgaW50ZXJwb2xhdGVkVG9wU2NyYXRjaAogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhpbnRlcnBvbGF0ZWROb3JtYWwsIG5vcm1hbHNBcnJheSwgcGFja0luZGV4KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soaW50ZXJwb2xhdGVkQm90dG9tLCBib3R0b21Qb3NpdGlvbnNBcnJheSwgcGFja0luZGV4KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soaW50ZXJwb2xhdGVkVG9wLCB0b3BQb3NpdGlvbnNBcnJheSwgcGFja0luZGV4KTsKICAgICAgY2FydG9ncmFwaGljc0FycmF5LnB1c2goaW50ZXJwb2xhdGVkQ2FydG9ncmFwaGljLmxhdGl0dWRlKTsKICAgICAgY2FydG9ncmFwaGljc0FycmF5LnB1c2goaW50ZXJwb2xhdGVkQ2FydG9ncmFwaGljLmxvbmdpdHVkZSk7CiAgICAgIHBhY2tJbmRleCArPSAzOwogICAgICBkaXN0YW5jZUZyb21TdGFydCArPSBpbnRlcnBvaW50RGlzdGFuY2U7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGdldFBvc2l0aW9uKGVsbGlwc29pZCwgY2FydG9ncmFwaGljMiwgaGVpZ2h0LCByZXN1bHQpIHsKICAgIENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKGNhcnRvZ3JhcGhpYzIsIGhlaWdodGxlc3NDYXJ0b2dyYXBoaWNTY3JhdGNoKTsKICAgIGhlaWdodGxlc3NDYXJ0b2dyYXBoaWNTY3JhdGNoLmhlaWdodCA9IGhlaWdodDsKICAgIHJldHVybiBDYXJ0b2dyYXBoaWNfZGVmYXVsdC50b0NhcnRlc2lhbigKICAgICAgaGVpZ2h0bGVzc0NhcnRvZ3JhcGhpY1NjcmF0Y2gsCiAgICAgIGVsbGlwc29pZCwKICAgICAgcmVzdWx0CiAgICApOwogIH0KICBmdW5jdGlvbiBkaXJlY3Rpb24odGFyZ2V0LCBvcmlnaW4sIHJlc3VsdCkgewogICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHRhcmdldCwgb3JpZ2luLCByZXN1bHQpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShyZXN1bHQsIHJlc3VsdCk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiB0YW5nZW50RGlyZWN0aW9uKHRhcmdldCwgb3JpZ2luLCB1cCwgcmVzdWx0KSB7CiAgICByZXN1bHQgPSBkaXJlY3Rpb24odGFyZ2V0LCBvcmlnaW4sIHJlc3VsdCk7CiAgICByZXN1bHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MocmVzdWx0LCB1cCwgcmVzdWx0KTsKICAgIHJlc3VsdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmVzdWx0LCByZXN1bHQpOwogICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHVwLCByZXN1bHQsIHJlc3VsdCk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBjb21wdXRlVmVydGV4TWl0ZXJOb3JtYWwocHJldmlvdXNCb3R0b20sIHZlcnRleEJvdHRvbSwgdmVydGV4VG9wLCBuZXh0Qm90dG9tLCByZXN1bHQpIHsKICAgIGNvbnN0IHVwID0gZGlyZWN0aW9uKHZlcnRleFRvcCwgdmVydGV4Qm90dG9tLCB2ZXJ0ZXhVcFNjcmF0Y2gpOwogICAgY29uc3QgdG9QcmV2aW91cyA9IHRhbmdlbnREaXJlY3Rpb24oCiAgICAgIHByZXZpb3VzQm90dG9tLAogICAgICB2ZXJ0ZXhCb3R0b20sCiAgICAgIHVwLAogICAgICB0b1ByZXZpb3VzU2NyYXRjaAogICAgKTsKICAgIGNvbnN0IHRvTmV4dCA9IHRhbmdlbnREaXJlY3Rpb24obmV4dEJvdHRvbSwgdmVydGV4Qm90dG9tLCB1cCwgdG9OZXh0U2NyYXRjaCk7CiAgICBpZiAoTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodG9QcmV2aW91cywgdG9OZXh0KSwKICAgICAgY29zaW5lMTgwLAogICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjUKICAgICkpIHsKICAgICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHVwLCB0b1ByZXZpb3VzLCByZXN1bHQpOwogICAgICByZXN1bHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHJlc3VsdCwgcmVzdWx0KTsKICAgICAgcmV0dXJuIHJlc3VsdDsKICAgIH0KICAgIHJlc3VsdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQodG9OZXh0LCB0b1ByZXZpb3VzLCByZXN1bHQpOwogICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShyZXN1bHQsIHJlc3VsdCk7CiAgICBjb25zdCBmb3J3YXJkID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKHVwLCByZXN1bHQsIGZvcndhcmRTY3JhdGNoKTsKICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KHRvTmV4dCwgZm9yd2FyZCkgPCBjb3NpbmU5MCkgewogICAgICByZXN1bHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKHJlc3VsdCwgcmVzdWx0KTsKICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGJyZWFrTWl0ZXIoZW5kR2VvbWV0cnlOb3JtYWwsIHN0YXJ0Qm90dG9tLCBlbmRCb3R0b20sIGVuZFRvcCkgewogICAgY29uc3QgbGluZURpcmVjdGlvbiA9IGRpcmVjdGlvbihlbmRCb3R0b20sIHN0YXJ0Qm90dG9tLCBsaW5lRGlyZWN0aW9uU2NyYXRjaCk7CiAgICBjb25zdCBkb3QgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGxpbmVEaXJlY3Rpb24sIGVuZEdlb21ldHJ5Tm9ybWFsKTsKICAgIGlmIChkb3QgPiBNSVRFUl9CUkVBS19TTUFMTCB8fCBkb3QgPCBNSVRFUl9CUkVBS19MQVJHRSkgewogICAgICBjb25zdCB2ZXJ0ZXhVcCA9IGRpcmVjdGlvbihlbmRUb3AsIGVuZEJvdHRvbSwgdmVydGV4VXBTY3JhdGNoKTsKICAgICAgY29uc3QgYW5nbGUgPSBkb3QgPCBNSVRFUl9CUkVBS19MQVJHRSA/IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyA6IC1NYXRoX2RlZmF1bHQuUElfT1ZFUl9UV087CiAgICAgIGNvbnN0IHF1YXRlcm5pb24gPSBRdWF0ZXJuaW9uX2RlZmF1bHQuZnJvbUF4aXNBbmdsZSgKICAgICAgICB2ZXJ0ZXhVcCwKICAgICAgICBhbmdsZSwKICAgICAgICBxdWF0ZXJuaW9uU2NyYXRjaDMKICAgICAgKTsKICAgICAgY29uc3Qgcm90YXRpb25NYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24ocXVhdGVybmlvbiwgbWF0cml4M1NjcmF0Y2gpOwogICAgICBNYXRyaXgzX2RlZmF1bHQubXVsdGlwbHlCeVZlY3RvcigKICAgICAgICByb3RhdGlvbk1hdHJpeCwKICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbCwKICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbAogICAgICApOwogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHJldHVybiBmYWxzZTsKICB9CiAgZnVuY3Rpb24gcHJvamVjdE5vcm1hbChwcm9qZWN0aW9uLCBjYXJ0b2dyYXBoaWMyLCBub3JtYWwyLCBwcm9qZWN0ZWRQb3NpdGlvbiwgcmVzdWx0KSB7CiAgICBjb25zdCBwb3NpdGlvbiA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LnRvQ2FydGVzaWFuKAogICAgICBjYXJ0b2dyYXBoaWMyLAogICAgICBwcm9qZWN0aW9uLl9lbGxpcHNvaWQsCiAgICAgIG5vcm1hbFN0YXJ0cG9pbnRTY3JhdGNoCiAgICApOwogICAgbGV0IG5vcm1hbEVuZHBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwb3NpdGlvbiwgbm9ybWFsMiwgbm9ybWFsRW5kcG9pbnRTY3JhdGNoKTsKICAgIGxldCBmbGlwTm9ybWFsID0gZmFsc2U7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBwcm9qZWN0aW9uLl9lbGxpcHNvaWQ7CiAgICBsZXQgbm9ybWFsRW5kcG9pbnRDYXJ0b2dyYXBoaWMgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgIG5vcm1hbEVuZHBvaW50LAogICAgICBlbmRQb3NDYXJ0b2dyYXBoaWNTY3JhdGNoCiAgICApOwogICAgaWYgKE1hdGguYWJzKGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlIC0gbm9ybWFsRW5kcG9pbnRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlKSA+IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTykgewogICAgICBmbGlwTm9ybWFsID0gdHJ1ZTsKICAgICAgbm9ybWFsRW5kcG9pbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgbm9ybWFsMiwKICAgICAgICBub3JtYWxFbmRwb2ludFNjcmF0Y2gKICAgICAgKTsKICAgICAgbm9ybWFsRW5kcG9pbnRDYXJ0b2dyYXBoaWMgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgICAgbm9ybWFsRW5kcG9pbnQsCiAgICAgICAgZW5kUG9zQ2FydG9ncmFwaGljU2NyYXRjaAogICAgICApOwogICAgfQogICAgbm9ybWFsRW5kcG9pbnRDYXJ0b2dyYXBoaWMuaGVpZ2h0ID0gMDsKICAgIGNvbnN0IG5vcm1hbEVuZHBvaW50UHJvamVjdGVkID0gcHJvamVjdGlvbi5wcm9qZWN0KAogICAgICBub3JtYWxFbmRwb2ludENhcnRvZ3JhcGhpYywKICAgICAgcmVzdWx0CiAgICApOwogICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICBub3JtYWxFbmRwb2ludFByb2plY3RlZCwKICAgICAgcHJvamVjdGVkUG9zaXRpb24sCiAgICAgIHJlc3VsdAogICAgKTsKICAgIHJlc3VsdC56ID0gMDsKICAgIHJlc3VsdCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmVzdWx0LCByZXN1bHQpOwogICAgaWYgKGZsaXBOb3JtYWwpIHsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5lZ2F0ZShyZXN1bHQsIHJlc3VsdCk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBhZGp1c3RIZWlnaHRzKGJvdHRvbSwgdG9wLCBtaW5IZWlnaHQsIG1heEhlaWdodCwgYWRqdXN0SGVpZ2h0Qm90dG9tLCBhZGp1c3RIZWlnaHRUb3ApIHsKICAgIGNvbnN0IGFkanVzdEhlaWdodE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgdG9wLAogICAgICBib3R0b20sCiAgICAgIGFkanVzdEhlaWdodE5vcm1hbFNjcmF0Y2gKICAgICk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGFkanVzdEhlaWdodE5vcm1hbCwgYWRqdXN0SGVpZ2h0Tm9ybWFsKTsKICAgIGNvbnN0IGRpc3RhbmNlRm9yQm90dG9tID0gbWluSGVpZ2h0IC0gV0FMTF9JTklUSUFMX01JTl9IRUlHSFQ7CiAgICBsZXQgYWRqdXN0SGVpZ2h0T2Zmc2V0ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgIGFkanVzdEhlaWdodE5vcm1hbCwKICAgICAgZGlzdGFuY2VGb3JCb3R0b20sCiAgICAgIGFkanVzdEhlaWdodE9mZnNldFNjcmF0Y2gKICAgICk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGJvdHRvbSwgYWRqdXN0SGVpZ2h0T2Zmc2V0LCBhZGp1c3RIZWlnaHRCb3R0b20pOwogICAgY29uc3QgZGlzdGFuY2VGb3JUb3AgPSBtYXhIZWlnaHQgLSBXQUxMX0lOSVRJQUxfTUFYX0hFSUdIVDsKICAgIGFkanVzdEhlaWdodE9mZnNldCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICBhZGp1c3RIZWlnaHROb3JtYWwsCiAgICAgIGRpc3RhbmNlRm9yVG9wLAogICAgICBhZGp1c3RIZWlnaHRPZmZzZXRTY3JhdGNoCiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZCh0b3AsIGFkanVzdEhlaWdodE9mZnNldCwgYWRqdXN0SGVpZ2h0VG9wKTsKICB9CiAgZnVuY3Rpb24gbnVkZ2VYWihzdGFydCwgZW5kKSB7CiAgICBjb25zdCBzdGFydFRvWFpkaXN0YW5jZSA9IFBsYW5lX2RlZmF1bHQuZ2V0UG9pbnREaXN0YW5jZShYWl9QTEFORSwgc3RhcnQpOwogICAgY29uc3QgZW5kVG9YWmRpc3RhbmNlID0gUGxhbmVfZGVmYXVsdC5nZXRQb2ludERpc3RhbmNlKFhaX1BMQU5FLCBlbmQpOwogICAgbGV0IG9mZnNldCA9IG51ZGdlRGlyZWN0aW9uU2NyYXRjaDsKICAgIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihzdGFydFRvWFpkaXN0YW5jZSwgMCwgTWF0aF9kZWZhdWx0LkVQU0lMT04yKSkgewogICAgICBvZmZzZXQgPSBkaXJlY3Rpb24oZW5kLCBzdGFydCwgb2Zmc2V0KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIob2Zmc2V0LCBNYXRoX2RlZmF1bHQuRVBTSUxPTjIsIG9mZnNldCk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoc3RhcnQsIG9mZnNldCwgc3RhcnQpOwogICAgfSBlbHNlIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihlbmRUb1haZGlzdGFuY2UsIDAsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMikpIHsKICAgICAgb2Zmc2V0ID0gZGlyZWN0aW9uKHN0YXJ0LCBlbmQsIG9mZnNldCk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKG9mZnNldCwgTWF0aF9kZWZhdWx0LkVQU0lMT04yLCBvZmZzZXQpOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGVuZCwgb2Zmc2V0LCBlbmQpOwogICAgfQogIH0KICBmdW5jdGlvbiBudWRnZUNhcnRvZ3JhcGhpYyhzdGFydCwgZW5kKSB7CiAgICBjb25zdCBhYnNTdGFydExvbiA9IE1hdGguYWJzKHN0YXJ0LmxvbmdpdHVkZSk7CiAgICBjb25zdCBhYnNFbmRMb24gPSBNYXRoLmFicyhlbmQubG9uZ2l0dWRlKTsKICAgIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihhYnNTdGFydExvbiwgTWF0aF9kZWZhdWx0LlBJLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjExKSkgewogICAgICBjb25zdCBlbmRTaWduID0gTWF0aF9kZWZhdWx0LnNpZ24oZW5kLmxvbmdpdHVkZSk7CiAgICAgIHN0YXJ0LmxvbmdpdHVkZSA9IGVuZFNpZ24gKiAoYWJzU3RhcnRMb24gLSBNYXRoX2RlZmF1bHQuRVBTSUxPTjExKTsKICAgICAgcmV0dXJuIDE7CiAgICB9IGVsc2UgaWYgKE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKGFic0VuZExvbiwgTWF0aF9kZWZhdWx0LlBJLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjExKSkgewogICAgICBjb25zdCBzdGFydFNpZ24gPSBNYXRoX2RlZmF1bHQuc2lnbihzdGFydC5sb25naXR1ZGUpOwogICAgICBlbmQubG9uZ2l0dWRlID0gc3RhcnRTaWduICogKGFic0VuZExvbiAtIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTEpOwogICAgICByZXR1cm4gMjsKICAgIH0KICAgIHJldHVybiAwOwogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZUdlb21ldHJ5QXR0cmlidXRlcyhsb29wLCBwcm9qZWN0aW9uLCBib3R0b21Qb3NpdGlvbnNBcnJheSwgdG9wUG9zaXRpb25zQXJyYXksIG5vcm1hbHNBcnJheSwgY2FydG9ncmFwaGljc0FycmF5LCBjb21wdXRlMmRBdHRyaWJ1dGVzKSB7CiAgICBsZXQgaTI7CiAgICBsZXQgaW5kZXg7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBwcm9qZWN0aW9uLl9lbGxpcHNvaWQ7CiAgICBjb25zdCBzZWdtZW50Q291bnQgPSBib3R0b21Qb3NpdGlvbnNBcnJheS5sZW5ndGggLyAzIC0gMTsKICAgIGNvbnN0IHZlcnRleENvdW50ID0gc2VnbWVudENvdW50ICogODsKICAgIGNvbnN0IGFycmF5U2l6ZVZlYzQgPSB2ZXJ0ZXhDb3VudCAqIDQ7CiAgICBjb25zdCBpbmRleENvdW50ID0gc2VnbWVudENvdW50ICogMzY7CiAgICBjb25zdCBpbmRpY2VzID0gdmVydGV4Q291bnQgPiA2NTUzNSA/IG5ldyBVaW50MzJBcnJheShpbmRleENvdW50KSA6IG5ldyBVaW50MTZBcnJheShpbmRleENvdW50KTsKICAgIGNvbnN0IHBvc2l0aW9uc0FycmF5ID0gbmV3IEZsb2F0NjRBcnJheSh2ZXJ0ZXhDb3VudCAqIDMpOwogICAgY29uc3Qgc3RhcnRIaUFuZEZvcndhcmRPZmZzZXRYID0gbmV3IEZsb2F0MzJBcnJheShhcnJheVNpemVWZWM0KTsKICAgIGNvbnN0IHN0YXJ0TG9BbmRGb3J3YXJkT2Zmc2V0WSA9IG5ldyBGbG9hdDMyQXJyYXkoYXJyYXlTaXplVmVjNCk7CiAgICBjb25zdCBzdGFydE5vcm1hbEFuZEZvcndhcmRPZmZzZXRaID0gbmV3IEZsb2F0MzJBcnJheShhcnJheVNpemVWZWM0KTsKICAgIGNvbnN0IGVuZE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblggPSBuZXcgRmxvYXQzMkFycmF5KAogICAgICBhcnJheVNpemVWZWM0CiAgICApOwogICAgY29uc3QgcmlnaHROb3JtYWxBbmRUZXh0dXJlQ29vcmRpbmF0ZU5vcm1hbGl6YXRpb25ZID0gbmV3IEZsb2F0MzJBcnJheSgKICAgICAgYXJyYXlTaXplVmVjNAogICAgKTsKICAgIGxldCBzdGFydEhpTG8yRDsKICAgIGxldCBvZmZzZXRBbmRSaWdodDJEOwogICAgbGV0IHN0YXJ0RW5kTm9ybWFsczJEOwogICAgbGV0IHRleGNvb3JkTm9ybWFsaXphdGlvbjJEOwogICAgaWYgKGNvbXB1dGUyZEF0dHJpYnV0ZXMpIHsKICAgICAgc3RhcnRIaUxvMkQgPSBuZXcgRmxvYXQzMkFycmF5KGFycmF5U2l6ZVZlYzQpOwogICAgICBvZmZzZXRBbmRSaWdodDJEID0gbmV3IEZsb2F0MzJBcnJheShhcnJheVNpemVWZWM0KTsKICAgICAgc3RhcnRFbmROb3JtYWxzMkQgPSBuZXcgRmxvYXQzMkFycmF5KGFycmF5U2l6ZVZlYzQpOwogICAgICB0ZXhjb29yZE5vcm1hbGl6YXRpb24yRCA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGV4Q291bnQgKiAyKTsKICAgIH0KICAgIGNvbnN0IGNhcnRvZ3JhcGhpY3NMZW5ndGggPSBjYXJ0b2dyYXBoaWNzQXJyYXkubGVuZ3RoIC8gMjsKICAgIGxldCBsZW5ndGgyRCA9IDA7CiAgICBjb25zdCBzdGFydENhcnRvZ3JhcGhpYyA9IHN0YXJ0Q2FydG9ncmFwaGljU2NyYXRjaDsKICAgIHN0YXJ0Q2FydG9ncmFwaGljLmhlaWdodCA9IDA7CiAgICBjb25zdCBlbmRDYXJ0b2dyYXBoaWMgPSBlbmRDYXJ0b2dyYXBoaWNTY3JhdGNoOwogICAgZW5kQ2FydG9ncmFwaGljLmhlaWdodCA9IDA7CiAgICBsZXQgc2VnbWVudFN0YXJ0Q2FydGVzaWFuID0gc2VnbWVudFN0YXJ0VG9wU2NyYXRjaDsKICAgIGxldCBzZWdtZW50RW5kQ2FydGVzaWFuID0gc2VnbWVudEVuZFRvcFNjcmF0Y2g7CiAgICBpZiAoY29tcHV0ZTJkQXR0cmlidXRlcykgewogICAgICBpbmRleCA9IDA7CiAgICAgIGZvciAoaTIgPSAxOyBpMiA8IGNhcnRvZ3JhcGhpY3NMZW5ndGg7IGkyKyspIHsKICAgICAgICBzdGFydENhcnRvZ3JhcGhpYy5sYXRpdHVkZSA9IGNhcnRvZ3JhcGhpY3NBcnJheVtpbmRleF07CiAgICAgICAgc3RhcnRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlID0gY2FydG9ncmFwaGljc0FycmF5W2luZGV4ICsgMV07CiAgICAgICAgZW5kQ2FydG9ncmFwaGljLmxhdGl0dWRlID0gY2FydG9ncmFwaGljc0FycmF5W2luZGV4ICsgMl07CiAgICAgICAgZW5kQ2FydG9ncmFwaGljLmxvbmdpdHVkZSA9IGNhcnRvZ3JhcGhpY3NBcnJheVtpbmRleCArIDNdOwogICAgICAgIHNlZ21lbnRTdGFydENhcnRlc2lhbiA9IHByb2plY3Rpb24ucHJvamVjdCgKICAgICAgICAgIHN0YXJ0Q2FydG9ncmFwaGljLAogICAgICAgICAgc2VnbWVudFN0YXJ0Q2FydGVzaWFuCiAgICAgICAgKTsKICAgICAgICBzZWdtZW50RW5kQ2FydGVzaWFuID0gcHJvamVjdGlvbi5wcm9qZWN0KAogICAgICAgICAgZW5kQ2FydG9ncmFwaGljLAogICAgICAgICAgc2VnbWVudEVuZENhcnRlc2lhbgogICAgICAgICk7CiAgICAgICAgbGVuZ3RoMkQgKz0gQ2FydGVzaWFuM19kZWZhdWx0LmRpc3RhbmNlKAogICAgICAgICAgc2VnbWVudFN0YXJ0Q2FydGVzaWFuLAogICAgICAgICAgc2VnbWVudEVuZENhcnRlc2lhbgogICAgICAgICk7CiAgICAgICAgaW5kZXggKz0gMjsKICAgICAgfQogICAgfQogICAgY29uc3QgcG9zaXRpb25zTGVuZ3RoID0gdG9wUG9zaXRpb25zQXJyYXkubGVuZ3RoIC8gMzsKICAgIHNlZ21lbnRFbmRDYXJ0ZXNpYW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICB0b3BQb3NpdGlvbnNBcnJheSwKICAgICAgMCwKICAgICAgc2VnbWVudEVuZENhcnRlc2lhbgogICAgKTsKICAgIGxldCBsZW5ndGgzRCA9IDA7CiAgICBpbmRleCA9IDM7CiAgICBmb3IgKGkyID0gMTsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7IGkyKyspIHsKICAgICAgc2VnbWVudFN0YXJ0Q2FydGVzaWFuID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKAogICAgICAgIHNlZ21lbnRFbmRDYXJ0ZXNpYW4sCiAgICAgICAgc2VnbWVudFN0YXJ0Q2FydGVzaWFuCiAgICAgICk7CiAgICAgIHNlZ21lbnRFbmRDYXJ0ZXNpYW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICAgIHRvcFBvc2l0aW9uc0FycmF5LAogICAgICAgIGluZGV4LAogICAgICAgIHNlZ21lbnRFbmRDYXJ0ZXNpYW4KICAgICAgKTsKICAgICAgbGVuZ3RoM0QgKz0gQ2FydGVzaWFuM19kZWZhdWx0LmRpc3RhbmNlKHNlZ21lbnRTdGFydENhcnRlc2lhbiwgc2VnbWVudEVuZENhcnRlc2lhbik7CiAgICAgIGluZGV4ICs9IDM7CiAgICB9CiAgICBsZXQgajI7CiAgICBpbmRleCA9IDM7CiAgICBsZXQgY2FydG9ncmFwaGljc0luZGV4ID0gMDsKICAgIGxldCB2ZWMyc1dyaXRlSW5kZXggPSAwOwogICAgbGV0IHZlYzNzV3JpdGVJbmRleCA9IDA7CiAgICBsZXQgdmVjNHNXcml0ZUluZGV4ID0gMDsKICAgIGxldCBtaXRlckJyb2tlbiA9IGZhbHNlOwogICAgbGV0IGVuZEJvdHRvbSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgIGJvdHRvbVBvc2l0aW9uc0FycmF5LAogICAgICAwLAogICAgICBzZWdtZW50RW5kQm90dG9tU2NyYXRjaAogICAgKTsKICAgIGxldCBlbmRUb3AgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHRvcFBvc2l0aW9uc0FycmF5LCAwLCBzZWdtZW50RW5kVG9wU2NyYXRjaCk7CiAgICBsZXQgZW5kR2VvbWV0cnlOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICBub3JtYWxzQXJyYXksCiAgICAgIDAsCiAgICAgIHNlZ21lbnRFbmROb3JtYWxTY3JhdGNoCiAgICApOwogICAgaWYgKGxvb3ApIHsKICAgICAgY29uc3QgcHJlRW5kQm90dG9tID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICBib3R0b21Qb3NpdGlvbnNBcnJheSwKICAgICAgICBib3R0b21Qb3NpdGlvbnNBcnJheS5sZW5ndGggLSA2LAogICAgICAgIHNlZ21lbnRTdGFydEJvdHRvbVNjcmF0Y2gKICAgICAgKTsKICAgICAgaWYgKGJyZWFrTWl0ZXIoZW5kR2VvbWV0cnlOb3JtYWwsIHByZUVuZEJvdHRvbSwgZW5kQm90dG9tLCBlbmRUb3ApKSB7CiAgICAgICAgZW5kR2VvbWV0cnlOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKAogICAgICAgICAgZW5kR2VvbWV0cnlOb3JtYWwsCiAgICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbAogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIGxldCBsZW5ndGhTb0ZhcjNEID0gMDsKICAgIGxldCBsZW5ndGhTb0ZhcjJEID0gMDsKICAgIGxldCBzdW1IZWlnaHRzID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IHNlZ21lbnRDb3VudDsgaTIrKykgewogICAgICBjb25zdCBzdGFydEJvdHRvbSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShlbmRCb3R0b20sIHNlZ21lbnRTdGFydEJvdHRvbVNjcmF0Y2gpOwogICAgICBjb25zdCBzdGFydFRvcCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShlbmRUb3AsIHNlZ21lbnRTdGFydFRvcFNjcmF0Y2gpOwogICAgICBsZXQgc3RhcnRHZW9tZXRyeU5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSgKICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbCwKICAgICAgICBzZWdtZW50U3RhcnROb3JtYWxTY3JhdGNoCiAgICAgICk7CiAgICAgIGlmIChtaXRlckJyb2tlbikgewogICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubmVnYXRlKAogICAgICAgICAgc3RhcnRHZW9tZXRyeU5vcm1hbCwKICAgICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwKICAgICAgICApOwogICAgICB9CiAgICAgIGVuZEJvdHRvbSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgYm90dG9tUG9zaXRpb25zQXJyYXksCiAgICAgICAgaW5kZXgsCiAgICAgICAgc2VnbWVudEVuZEJvdHRvbVNjcmF0Y2gKICAgICAgKTsKICAgICAgZW5kVG9wID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayh0b3BQb3NpdGlvbnNBcnJheSwgaW5kZXgsIHNlZ21lbnRFbmRUb3BTY3JhdGNoKTsKICAgICAgZW5kR2VvbWV0cnlOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICAgIG5vcm1hbHNBcnJheSwKICAgICAgICBpbmRleCwKICAgICAgICBzZWdtZW50RW5kTm9ybWFsU2NyYXRjaAogICAgICApOwogICAgICBtaXRlckJyb2tlbiA9IGJyZWFrTWl0ZXIoZW5kR2VvbWV0cnlOb3JtYWwsIHN0YXJ0Qm90dG9tLCBlbmRCb3R0b20sIGVuZFRvcCk7CiAgICAgIHN0YXJ0Q2FydG9ncmFwaGljLmxhdGl0dWRlID0gY2FydG9ncmFwaGljc0FycmF5W2NhcnRvZ3JhcGhpY3NJbmRleF07CiAgICAgIHN0YXJ0Q2FydG9ncmFwaGljLmxvbmdpdHVkZSA9IGNhcnRvZ3JhcGhpY3NBcnJheVtjYXJ0b2dyYXBoaWNzSW5kZXggKyAxXTsKICAgICAgZW5kQ2FydG9ncmFwaGljLmxhdGl0dWRlID0gY2FydG9ncmFwaGljc0FycmF5W2NhcnRvZ3JhcGhpY3NJbmRleCArIDJdOwogICAgICBlbmRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlID0gY2FydG9ncmFwaGljc0FycmF5W2NhcnRvZ3JhcGhpY3NJbmRleCArIDNdOwogICAgICBsZXQgc3RhcnQyRDsKICAgICAgbGV0IGVuZDJEOwogICAgICBsZXQgc3RhcnRHZW9tZXRyeU5vcm1hbDJEOwogICAgICBsZXQgZW5kR2VvbWV0cnlOb3JtYWwyRDsKICAgICAgaWYgKGNvbXB1dGUyZEF0dHJpYnV0ZXMpIHsKICAgICAgICBjb25zdCBudWRnZVJlc3VsdCA9IG51ZGdlQ2FydG9ncmFwaGljKHN0YXJ0Q2FydG9ncmFwaGljLCBlbmRDYXJ0b2dyYXBoaWMpOwogICAgICAgIHN0YXJ0MkQgPSBwcm9qZWN0aW9uLnByb2plY3Qoc3RhcnRDYXJ0b2dyYXBoaWMsIHNlZ21lbnRTdGFydDJEU2NyYXRjaCk7CiAgICAgICAgZW5kMkQgPSBwcm9qZWN0aW9uLnByb2plY3QoZW5kQ2FydG9ncmFwaGljLCBzZWdtZW50RW5kMkRTY3JhdGNoKTsKICAgICAgICBjb25zdCBkaXJlY3Rpb24yRCA9IGRpcmVjdGlvbihlbmQyRCwgc3RhcnQyRCwgZm9yd2FyZE9mZnNldDJEU2NyYXRjaCk7CiAgICAgICAgZGlyZWN0aW9uMkQueSA9IE1hdGguYWJzKGRpcmVjdGlvbjJELnkpOwogICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwyRCA9IHNlZ21lbnRTdGFydE5vcm1hbDJEU2NyYXRjaDsKICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbDJEID0gc2VnbWVudEVuZE5vcm1hbDJEU2NyYXRjaDsKICAgICAgICBpZiAobnVkZ2VSZXN1bHQgPT09IDAgfHwgQ2FydGVzaWFuM19kZWZhdWx0LmRvdChkaXJlY3Rpb24yRCwgQ2FydGVzaWFuM19kZWZhdWx0LlVOSVRfWSkgPiBNSVRFUl9CUkVBS19TTUFMTCkgewogICAgICAgICAgc3RhcnRHZW9tZXRyeU5vcm1hbDJEID0gcHJvamVjdE5vcm1hbCgKICAgICAgICAgICAgcHJvamVjdGlvbiwKICAgICAgICAgICAgc3RhcnRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwsCiAgICAgICAgICAgIHN0YXJ0MkQsCiAgICAgICAgICAgIHNlZ21lbnRTdGFydE5vcm1hbDJEU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGVuZEdlb21ldHJ5Tm9ybWFsMkQgPSBwcm9qZWN0Tm9ybWFsKAogICAgICAgICAgICBwcm9qZWN0aW9uLAogICAgICAgICAgICBlbmRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIGVuZEdlb21ldHJ5Tm9ybWFsLAogICAgICAgICAgICBlbmQyRCwKICAgICAgICAgICAgc2VnbWVudEVuZE5vcm1hbDJEU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICB9IGVsc2UgaWYgKG51ZGdlUmVzdWx0ID09PSAxKSB7CiAgICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbDJEID0gcHJvamVjdE5vcm1hbCgKICAgICAgICAgICAgcHJvamVjdGlvbiwKICAgICAgICAgICAgZW5kQ2FydG9ncmFwaGljLAogICAgICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbCwKICAgICAgICAgICAgZW5kMkQsCiAgICAgICAgICAgIHNlZ21lbnRFbmROb3JtYWwyRFNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBzdGFydEdlb21ldHJ5Tm9ybWFsMkQueCA9IDA7CiAgICAgICAgICBzdGFydEdlb21ldHJ5Tm9ybWFsMkQueSA9IE1hdGhfZGVmYXVsdC5zaWduKAogICAgICAgICAgICBzdGFydENhcnRvZ3JhcGhpYy5sb25naXR1ZGUgLSBNYXRoLmFicyhlbmRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlKQogICAgICAgICAgKTsKICAgICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwyRC56ID0gMDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgc3RhcnRHZW9tZXRyeU5vcm1hbDJEID0gcHJvamVjdE5vcm1hbCgKICAgICAgICAgICAgcHJvamVjdGlvbiwKICAgICAgICAgICAgc3RhcnRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIHN0YXJ0R2VvbWV0cnlOb3JtYWwsCiAgICAgICAgICAgIHN0YXJ0MkQsCiAgICAgICAgICAgIHNlZ21lbnRTdGFydE5vcm1hbDJEU2NyYXRjaAogICAgICAgICAgKTsKICAgICAgICAgIGVuZEdlb21ldHJ5Tm9ybWFsMkQueCA9IDA7CiAgICAgICAgICBlbmRHZW9tZXRyeU5vcm1hbDJELnkgPSBNYXRoX2RlZmF1bHQuc2lnbigKICAgICAgICAgICAgc3RhcnRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlIC0gZW5kQ2FydG9ncmFwaGljLmxvbmdpdHVkZQogICAgICAgICAgKTsKICAgICAgICAgIGVuZEdlb21ldHJ5Tm9ybWFsMkQueiA9IDA7CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IHNlZ21lbnRMZW5ndGgzRCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kaXN0YW5jZShzdGFydFRvcCwgZW5kVG9wKTsKICAgICAgY29uc3QgZW5jb2RlZFN0YXJ0ID0gRW5jb2RlZENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQ2FydGVzaWFuKAogICAgICAgIHN0YXJ0Qm90dG9tLAogICAgICAgIGVuY29kZVNjcmF0Y2gKICAgICAgKTsKICAgICAgY29uc3QgZm9yd2FyZE9mZnNldCA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICBlbmRCb3R0b20sCiAgICAgICAgc3RhcnRCb3R0b20sCiAgICAgICAgb2Zmc2V0U2NyYXRjaDIKICAgICAgKTsKICAgICAgY29uc3QgZm9yd2FyZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoZm9yd2FyZE9mZnNldCwgcmlnaHRTY3JhdGNoMik7CiAgICAgIGxldCBzdGFydFVwID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHN0YXJ0VG9wLCBzdGFydEJvdHRvbSwgc3RhcnRVcFNjcmF0Y2gpOwogICAgICBzdGFydFVwID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShzdGFydFVwLCBzdGFydFVwKTsKICAgICAgbGV0IHJpZ2h0Tm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKGZvcndhcmQsIHN0YXJ0VXAsIHJpZ2h0U2NyYXRjaDIpOwogICAgICByaWdodE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUocmlnaHROb3JtYWwsIHJpZ2h0Tm9ybWFsKTsKICAgICAgbGV0IHN0YXJ0UGxhbmVOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoCiAgICAgICAgc3RhcnRVcCwKICAgICAgICBzdGFydEdlb21ldHJ5Tm9ybWFsLAogICAgICAgIHN0YXJ0UGxhbmVOb3JtYWxTY3JhdGNoCiAgICAgICk7CiAgICAgIHN0YXJ0UGxhbmVOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHN0YXJ0UGxhbmVOb3JtYWwsIHN0YXJ0UGxhbmVOb3JtYWwpOwogICAgICBsZXQgZW5kVXAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoZW5kVG9wLCBlbmRCb3R0b20sIGVuZFVwU2NyYXRjaCk7CiAgICAgIGVuZFVwID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShlbmRVcCwgZW5kVXApOwogICAgICBsZXQgZW5kUGxhbmVOb3JtYWwgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoCiAgICAgICAgZW5kR2VvbWV0cnlOb3JtYWwsCiAgICAgICAgZW5kVXAsCiAgICAgICAgZW5kUGxhbmVOb3JtYWxTY3JhdGNoCiAgICAgICk7CiAgICAgIGVuZFBsYW5lTm9ybWFsID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShlbmRQbGFuZU5vcm1hbCwgZW5kUGxhbmVOb3JtYWwpOwogICAgICBjb25zdCB0ZXhjb29yZE5vcm1hbGl6YXRpb24zRFggPSBzZWdtZW50TGVuZ3RoM0QgLyBsZW5ndGgzRDsKICAgICAgY29uc3QgdGV4Y29vcmROb3JtYWxpemF0aW9uM0RZID0gbGVuZ3RoU29GYXIzRCAvIGxlbmd0aDNEOwogICAgICBsZXQgc2VnbWVudExlbmd0aDJEID0gMDsKICAgICAgbGV0IGVuY29kZWRTdGFydDJEOwogICAgICBsZXQgZm9yd2FyZE9mZnNldDJEOwogICAgICBsZXQgcmlnaHQyRDsKICAgICAgbGV0IHRleGNvb3JkTm9ybWFsaXphdGlvbjJEWCA9IDA7CiAgICAgIGxldCB0ZXhjb29yZE5vcm1hbGl6YXRpb24yRFkgPSAwOwogICAgICBpZiAoY29tcHV0ZTJkQXR0cmlidXRlcykgewogICAgICAgIHNlZ21lbnRMZW5ndGgyRCA9IENhcnRlc2lhbjNfZGVmYXVsdC5kaXN0YW5jZShzdGFydDJELCBlbmQyRCk7CiAgICAgICAgZW5jb2RlZFN0YXJ0MkQgPSBFbmNvZGVkQ2FydGVzaWFuM19kZWZhdWx0LmZyb21DYXJ0ZXNpYW4oCiAgICAgICAgICBzdGFydDJELAogICAgICAgICAgZW5jb2RlU2NyYXRjaDJECiAgICAgICAgKTsKICAgICAgICBmb3J3YXJkT2Zmc2V0MkQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICBlbmQyRCwKICAgICAgICAgIHN0YXJ0MkQsCiAgICAgICAgICBmb3J3YXJkT2Zmc2V0MkRTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICByaWdodDJEID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShmb3J3YXJkT2Zmc2V0MkQsIHJpZ2h0MkRTY3JhdGNoKTsKICAgICAgICBjb25zdCBzd2FwMiA9IHJpZ2h0MkQueDsKICAgICAgICByaWdodDJELnggPSByaWdodDJELnk7CiAgICAgICAgcmlnaHQyRC55ID0gLXN3YXAyOwogICAgICAgIHRleGNvb3JkTm9ybWFsaXphdGlvbjJEWCA9IHNlZ21lbnRMZW5ndGgyRCAvIGxlbmd0aDJEOwogICAgICAgIHRleGNvb3JkTm9ybWFsaXphdGlvbjJEWSA9IGxlbmd0aFNvRmFyMkQgLyBsZW5ndGgyRDsKICAgICAgfQogICAgICBmb3IgKGoyID0gMDsgajIgPCA4OyBqMisrKSB7CiAgICAgICAgY29uc3QgdmVjNEluZGV4ID0gdmVjNHNXcml0ZUluZGV4ICsgajIgKiA0OwogICAgICAgIGNvbnN0IHZlYzJJbmRleCA9IHZlYzJzV3JpdGVJbmRleCArIGoyICogMjsKICAgICAgICBjb25zdCB3SW5kZXggPSB2ZWM0SW5kZXggKyAzOwogICAgICAgIGNvbnN0IHJpZ2h0UGxhbmVTaWRlID0gajIgPCA0ID8gMSA6IC0xOwogICAgICAgIGNvbnN0IHRvcEJvdHRvbVNpZGUgPSBqMiA9PT0gMiB8fCBqMiA9PT0gMyB8fCBqMiA9PT0gNiB8fCBqMiA9PT0gNyA/IDEgOiAtMTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhlbmNvZGVkU3RhcnQuaGlnaCwgc3RhcnRIaUFuZEZvcndhcmRPZmZzZXRYLCB2ZWM0SW5kZXgpOwogICAgICAgIHN0YXJ0SGlBbmRGb3J3YXJkT2Zmc2V0WFt3SW5kZXhdID0gZm9yd2FyZE9mZnNldC54OwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGVuY29kZWRTdGFydC5sb3csIHN0YXJ0TG9BbmRGb3J3YXJkT2Zmc2V0WSwgdmVjNEluZGV4KTsKICAgICAgICBzdGFydExvQW5kRm9yd2FyZE9mZnNldFlbd0luZGV4XSA9IGZvcndhcmRPZmZzZXQueTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjaygKICAgICAgICAgIHN0YXJ0UGxhbmVOb3JtYWwsCiAgICAgICAgICBzdGFydE5vcm1hbEFuZEZvcndhcmRPZmZzZXRaLAogICAgICAgICAgdmVjNEluZGV4CiAgICAgICAgKTsKICAgICAgICBzdGFydE5vcm1hbEFuZEZvcndhcmRPZmZzZXRaW3dJbmRleF0gPSBmb3J3YXJkT2Zmc2V0Lno7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soCiAgICAgICAgICBlbmRQbGFuZU5vcm1hbCwKICAgICAgICAgIGVuZE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblgsCiAgICAgICAgICB2ZWM0SW5kZXgKICAgICAgICApOwogICAgICAgIGVuZE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblhbd0luZGV4XSA9IHRleGNvb3JkTm9ybWFsaXphdGlvbjNEWCAqIHJpZ2h0UGxhbmVTaWRlOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKAogICAgICAgICAgcmlnaHROb3JtYWwsCiAgICAgICAgICByaWdodE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblksCiAgICAgICAgICB2ZWM0SW5kZXgKICAgICAgICApOwogICAgICAgIGxldCB0ZXhjb29yZE5vcm1hbGl6YXRpb24gPSB0ZXhjb29yZE5vcm1hbGl6YXRpb24zRFkgKiB0b3BCb3R0b21TaWRlOwogICAgICAgIGlmICh0ZXhjb29yZE5vcm1hbGl6YXRpb24gPT09IDAgJiYgdG9wQm90dG9tU2lkZSA8IDApIHsKICAgICAgICAgIHRleGNvb3JkTm9ybWFsaXphdGlvbiA9IDk7CiAgICAgICAgfQogICAgICAgIHJpZ2h0Tm9ybWFsQW5kVGV4dHVyZUNvb3JkaW5hdGVOb3JtYWxpemF0aW9uWVt3SW5kZXhdID0gdGV4Y29vcmROb3JtYWxpemF0aW9uOwogICAgICAgIGlmIChjb21wdXRlMmRBdHRyaWJ1dGVzKSB7CiAgICAgICAgICBzdGFydEhpTG8yRFt2ZWM0SW5kZXhdID0gZW5jb2RlZFN0YXJ0MkQuaGlnaC54OwogICAgICAgICAgc3RhcnRIaUxvMkRbdmVjNEluZGV4ICsgMV0gPSBlbmNvZGVkU3RhcnQyRC5oaWdoLnk7CiAgICAgICAgICBzdGFydEhpTG8yRFt2ZWM0SW5kZXggKyAyXSA9IGVuY29kZWRTdGFydDJELmxvdy54OwogICAgICAgICAgc3RhcnRIaUxvMkRbdmVjNEluZGV4ICsgM10gPSBlbmNvZGVkU3RhcnQyRC5sb3cueTsKICAgICAgICAgIHN0YXJ0RW5kTm9ybWFsczJEW3ZlYzRJbmRleF0gPSAtc3RhcnRHZW9tZXRyeU5vcm1hbDJELnk7CiAgICAgICAgICBzdGFydEVuZE5vcm1hbHMyRFt2ZWM0SW5kZXggKyAxXSA9IHN0YXJ0R2VvbWV0cnlOb3JtYWwyRC54OwogICAgICAgICAgc3RhcnRFbmROb3JtYWxzMkRbdmVjNEluZGV4ICsgMl0gPSBlbmRHZW9tZXRyeU5vcm1hbDJELnk7CiAgICAgICAgICBzdGFydEVuZE5vcm1hbHMyRFt2ZWM0SW5kZXggKyAzXSA9IC1lbmRHZW9tZXRyeU5vcm1hbDJELng7CiAgICAgICAgICBvZmZzZXRBbmRSaWdodDJEW3ZlYzRJbmRleF0gPSBmb3J3YXJkT2Zmc2V0MkQueDsKICAgICAgICAgIG9mZnNldEFuZFJpZ2h0MkRbdmVjNEluZGV4ICsgMV0gPSBmb3J3YXJkT2Zmc2V0MkQueTsKICAgICAgICAgIG9mZnNldEFuZFJpZ2h0MkRbdmVjNEluZGV4ICsgMl0gPSByaWdodDJELng7CiAgICAgICAgICBvZmZzZXRBbmRSaWdodDJEW3ZlYzRJbmRleCArIDNdID0gcmlnaHQyRC55OwogICAgICAgICAgdGV4Y29vcmROb3JtYWxpemF0aW9uMkRbdmVjMkluZGV4XSA9IHRleGNvb3JkTm9ybWFsaXphdGlvbjJEWCAqIHJpZ2h0UGxhbmVTaWRlOwogICAgICAgICAgdGV4Y29vcmROb3JtYWxpemF0aW9uID0gdGV4Y29vcmROb3JtYWxpemF0aW9uMkRZICogdG9wQm90dG9tU2lkZTsKICAgICAgICAgIGlmICh0ZXhjb29yZE5vcm1hbGl6YXRpb24gPT09IDAgJiYgdG9wQm90dG9tU2lkZSA8IDApIHsKICAgICAgICAgICAgdGV4Y29vcmROb3JtYWxpemF0aW9uID0gOTsKICAgICAgICAgIH0KICAgICAgICAgIHRleGNvb3JkTm9ybWFsaXphdGlvbjJEW3ZlYzJJbmRleCArIDFdID0gdGV4Y29vcmROb3JtYWxpemF0aW9uOwogICAgICAgIH0KICAgICAgfQogICAgICBjb25zdCBhZGp1c3RIZWlnaHRTdGFydEJvdHRvbSA9IGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tU2NyYXRjaDsKICAgICAgY29uc3QgYWRqdXN0SGVpZ2h0RW5kQm90dG9tID0gYWRqdXN0SGVpZ2h0RW5kQm90dG9tU2NyYXRjaDsKICAgICAgY29uc3QgYWRqdXN0SGVpZ2h0U3RhcnRUb3AgPSBhZGp1c3RIZWlnaHRTdGFydFRvcFNjcmF0Y2g7CiAgICAgIGNvbnN0IGFkanVzdEhlaWdodEVuZFRvcCA9IGFkanVzdEhlaWdodEVuZFRvcFNjcmF0Y2g7CiAgICAgIGNvbnN0IGdldEhlaWdodHNSZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5mcm9tQ2FydG9ncmFwaGljQXJyYXkoCiAgICAgICAgZ2V0SGVpZ2h0Q2FydG9ncmFwaGljcywKICAgICAgICBnZXRIZWlnaHRSZWN0YW5nbGVTY3JhdGNoCiAgICAgICk7CiAgICAgIGNvbnN0IG1pbk1heEhlaWdodHMgPSBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzX2RlZmF1bHQuZ2V0TWluaW11bU1heGltdW1IZWlnaHRzKAogICAgICAgIGdldEhlaWdodHNSZWN0YW5nbGUsCiAgICAgICAgZWxsaXBzb2lkCiAgICAgICk7CiAgICAgIGNvbnN0IG1pbkhlaWdodCA9IG1pbk1heEhlaWdodHMubWluaW11bVRlcnJhaW5IZWlnaHQ7CiAgICAgIGNvbnN0IG1heEhlaWdodCA9IG1pbk1heEhlaWdodHMubWF4aW11bVRlcnJhaW5IZWlnaHQ7CiAgICAgIHN1bUhlaWdodHMgKz0gTWF0aC5hYnMobWluSGVpZ2h0KTsKICAgICAgc3VtSGVpZ2h0cyArPSBNYXRoLmFicyhtYXhIZWlnaHQpOwogICAgICBhZGp1c3RIZWlnaHRzKAogICAgICAgIHN0YXJ0Qm90dG9tLAogICAgICAgIHN0YXJ0VG9wLAogICAgICAgIG1pbkhlaWdodCwKICAgICAgICBtYXhIZWlnaHQsCiAgICAgICAgYWRqdXN0SGVpZ2h0U3RhcnRCb3R0b20sCiAgICAgICAgYWRqdXN0SGVpZ2h0U3RhcnRUb3AKICAgICAgKTsKICAgICAgYWRqdXN0SGVpZ2h0cygKICAgICAgICBlbmRCb3R0b20sCiAgICAgICAgZW5kVG9wLAogICAgICAgIG1pbkhlaWdodCwKICAgICAgICBtYXhIZWlnaHQsCiAgICAgICAgYWRqdXN0SGVpZ2h0RW5kQm90dG9tLAogICAgICAgIGFkanVzdEhlaWdodEVuZFRvcAogICAgICApOwogICAgICBsZXQgbm9ybWFsTnVkZ2UgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubXVsdGlwbHlCeVNjYWxhcigKICAgICAgICByaWdodE5vcm1hbCwKICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjUsCiAgICAgICAgbm9ybWFsTnVkZ2VTY3JhdGNoCiAgICAgICk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgYWRqdXN0SGVpZ2h0U3RhcnRCb3R0b20sCiAgICAgICAgbm9ybWFsTnVkZ2UsCiAgICAgICAgYWRqdXN0SGVpZ2h0U3RhcnRCb3R0b20KICAgICAgKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChhZGp1c3RIZWlnaHRFbmRCb3R0b20sIG5vcm1hbE51ZGdlLCBhZGp1c3RIZWlnaHRFbmRCb3R0b20pOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGFkanVzdEhlaWdodFN0YXJ0VG9wLCBub3JtYWxOdWRnZSwgYWRqdXN0SGVpZ2h0U3RhcnRUb3ApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKGFkanVzdEhlaWdodEVuZFRvcCwgbm9ybWFsTnVkZ2UsIGFkanVzdEhlaWdodEVuZFRvcCk7CiAgICAgIG51ZGdlWFooYWRqdXN0SGVpZ2h0U3RhcnRCb3R0b20sIGFkanVzdEhlaWdodEVuZEJvdHRvbSk7CiAgICAgIG51ZGdlWFooYWRqdXN0SGVpZ2h0U3RhcnRUb3AsIGFkanVzdEhlaWdodEVuZFRvcCk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tLCBwb3NpdGlvbnNBcnJheSwgdmVjM3NXcml0ZUluZGV4KTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soYWRqdXN0SGVpZ2h0RW5kQm90dG9tLCBwb3NpdGlvbnNBcnJheSwgdmVjM3NXcml0ZUluZGV4ICsgMyk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGFkanVzdEhlaWdodEVuZFRvcCwgcG9zaXRpb25zQXJyYXksIHZlYzNzV3JpdGVJbmRleCArIDYpOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhhZGp1c3RIZWlnaHRTdGFydFRvcCwgcG9zaXRpb25zQXJyYXksIHZlYzNzV3JpdGVJbmRleCArIDkpOwogICAgICBub3JtYWxOdWRnZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgIHJpZ2h0Tm9ybWFsLAogICAgICAgIC0yICogTWF0aF9kZWZhdWx0LkVQU0lMT041LAogICAgICAgIG5vcm1hbE51ZGdlU2NyYXRjaAogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgIGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tLAogICAgICAgIG5vcm1hbE51ZGdlLAogICAgICAgIGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tCiAgICAgICk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoYWRqdXN0SGVpZ2h0RW5kQm90dG9tLCBub3JtYWxOdWRnZSwgYWRqdXN0SGVpZ2h0RW5kQm90dG9tKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChhZGp1c3RIZWlnaHRTdGFydFRvcCwgbm9ybWFsTnVkZ2UsIGFkanVzdEhlaWdodFN0YXJ0VG9wKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChhZGp1c3RIZWlnaHRFbmRUb3AsIG5vcm1hbE51ZGdlLCBhZGp1c3RIZWlnaHRFbmRUb3ApOwogICAgICBudWRnZVhaKGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tLCBhZGp1c3RIZWlnaHRFbmRCb3R0b20pOwogICAgICBudWRnZVhaKGFkanVzdEhlaWdodFN0YXJ0VG9wLCBhZGp1c3RIZWlnaHRFbmRUb3ApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjaygKICAgICAgICBhZGp1c3RIZWlnaHRTdGFydEJvdHRvbSwKICAgICAgICBwb3NpdGlvbnNBcnJheSwKICAgICAgICB2ZWMzc1dyaXRlSW5kZXggKyAxMgogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjaygKICAgICAgICBhZGp1c3RIZWlnaHRFbmRCb3R0b20sCiAgICAgICAgcG9zaXRpb25zQXJyYXksCiAgICAgICAgdmVjM3NXcml0ZUluZGV4ICsgMTUKICAgICAgKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soYWRqdXN0SGVpZ2h0RW5kVG9wLCBwb3NpdGlvbnNBcnJheSwgdmVjM3NXcml0ZUluZGV4ICsgMTgpOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhhZGp1c3RIZWlnaHRTdGFydFRvcCwgcG9zaXRpb25zQXJyYXksIHZlYzNzV3JpdGVJbmRleCArIDIxKTsKICAgICAgY2FydG9ncmFwaGljc0luZGV4ICs9IDI7CiAgICAgIGluZGV4ICs9IDM7CiAgICAgIHZlYzJzV3JpdGVJbmRleCArPSAxNjsKICAgICAgdmVjM3NXcml0ZUluZGV4ICs9IDI0OwogICAgICB2ZWM0c1dyaXRlSW5kZXggKz0gMzI7CiAgICAgIGxlbmd0aFNvRmFyM0QgKz0gc2VnbWVudExlbmd0aDNEOwogICAgICBsZW5ndGhTb0ZhcjJEICs9IHNlZ21lbnRMZW5ndGgyRDsKICAgIH0KICAgIGluZGV4ID0gMDsKICAgIGxldCBpbmRleE9mZnNldCA9IDA7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBzZWdtZW50Q291bnQ7IGkyKyspIHsKICAgICAgZm9yIChqMiA9IDA7IGoyIDwgUkVGRVJFTkNFX0lORElDRVNfTEVOR1RIOyBqMisrKSB7CiAgICAgICAgaW5kaWNlc1tpbmRleCArIGoyXSA9IFJFRkVSRU5DRV9JTkRJQ0VTW2oyXSArIGluZGV4T2Zmc2V0OwogICAgICB9CiAgICAgIGluZGV4T2Zmc2V0ICs9IDg7CiAgICAgIGluZGV4ICs9IFJFRkVSRU5DRV9JTkRJQ0VTX0xFTkdUSDsKICAgIH0KICAgIGNvbnN0IGJvdW5kaW5nU3BoZXJlcyA9IHNjcmF0Y2hCb3VuZGluZ1NwaGVyZXM7CiAgICBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcygKICAgICAgYm90dG9tUG9zaXRpb25zQXJyYXksCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLAogICAgICAzLAogICAgICBib3VuZGluZ1NwaGVyZXNbMF0KICAgICk7CiAgICBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcygKICAgICAgdG9wUG9zaXRpb25zQXJyYXksCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLAogICAgICAzLAogICAgICBib3VuZGluZ1NwaGVyZXNbMV0KICAgICk7CiAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbUJvdW5kaW5nU3BoZXJlcyhib3VuZGluZ1NwaGVyZXMpOwogICAgYm91bmRpbmdTcGhlcmUucmFkaXVzICs9IHN1bUhlaWdodHMgLyAoc2VnbWVudENvdW50ICogMik7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gewogICAgICBwb3NpdGlvbjogbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgIG5vcm1hbGl6ZTogZmFsc2UsCiAgICAgICAgdmFsdWVzOiBwb3NpdGlvbnNBcnJheQogICAgICB9KSwKICAgICAgc3RhcnRIaUFuZEZvcndhcmRPZmZzZXRYOiBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUoCiAgICAgICAgc3RhcnRIaUFuZEZvcndhcmRPZmZzZXRYCiAgICAgICksCiAgICAgIHN0YXJ0TG9BbmRGb3J3YXJkT2Zmc2V0WTogZ2V0VmVjNEdlb21ldHJ5QXR0cmlidXRlKAogICAgICAgIHN0YXJ0TG9BbmRGb3J3YXJkT2Zmc2V0WQogICAgICApLAogICAgICBzdGFydE5vcm1hbEFuZEZvcndhcmRPZmZzZXRaOiBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUoCiAgICAgICAgc3RhcnROb3JtYWxBbmRGb3J3YXJkT2Zmc2V0WgogICAgICApLAogICAgICBlbmROb3JtYWxBbmRUZXh0dXJlQ29vcmRpbmF0ZU5vcm1hbGl6YXRpb25YOiBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUoCiAgICAgICAgZW5kTm9ybWFsQW5kVGV4dHVyZUNvb3JkaW5hdGVOb3JtYWxpemF0aW9uWAogICAgICApLAogICAgICByaWdodE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblk6IGdldFZlYzRHZW9tZXRyeUF0dHJpYnV0ZSgKICAgICAgICByaWdodE5vcm1hbEFuZFRleHR1cmVDb29yZGluYXRlTm9ybWFsaXphdGlvblkKICAgICAgKQogICAgfTsKICAgIGlmIChjb21wdXRlMmRBdHRyaWJ1dGVzKSB7CiAgICAgIGF0dHJpYnV0ZXMuc3RhcnRIaUxvMkQgPSBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUoc3RhcnRIaUxvMkQpOwogICAgICBhdHRyaWJ1dGVzLm9mZnNldEFuZFJpZ2h0MkQgPSBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUob2Zmc2V0QW5kUmlnaHQyRCk7CiAgICAgIGF0dHJpYnV0ZXMuc3RhcnRFbmROb3JtYWxzMkQgPSBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUoc3RhcnRFbmROb3JtYWxzMkQpOwogICAgICBhdHRyaWJ1dGVzLnRleGNvb3JkTm9ybWFsaXphdGlvbjJEID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgbm9ybWFsaXplOiBmYWxzZSwKICAgICAgICB2YWx1ZXM6IHRleGNvb3JkTm9ybWFsaXphdGlvbjJECiAgICAgIH0pOwogICAgfQogICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlcywKICAgICAgYm91bmRpbmdTcGhlcmUKICAgIH0pOwogIH0KICBmdW5jdGlvbiBnZXRWZWM0R2VvbWV0cnlBdHRyaWJ1dGUodHlwZWRBcnJheSkgewogICAgcmV0dXJuIG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDQsCiAgICAgIG5vcm1hbGl6ZTogZmFsc2UsCiAgICAgIHZhbHVlczogdHlwZWRBcnJheQogICAgfSk7CiAgfQogIHZhciBQUk9KRUNUSU9OUywgUFJPSkVDVElPTl9DT1VOVCwgTUlURVJfQlJFQUtfU01BTEwsIE1JVEVSX0JSRUFLX0xBUkdFLCBXQUxMX0lOSVRJQUxfTUlOX0hFSUdIVCwgV0FMTF9JTklUSUFMX01BWF9IRUlHSFQsIGNhcnQzU2NyYXRjaDEsIGNhcnQzU2NyYXRjaDIsIGNhcnQzU2NyYXRjaDMsIGludGVycG9sYXRlZENhcnRvZ3JhcGhpY1NjcmF0Y2gsIGludGVycG9sYXRlZEJvdHRvbVNjcmF0Y2gsIGludGVycG9sYXRlZFRvcFNjcmF0Y2gsIGludGVycG9sYXRlZE5vcm1hbFNjcmF0Y2gsIGhlaWdodGxlc3NDYXJ0b2dyYXBoaWNTY3JhdGNoLCB0b1ByZXZpb3VzU2NyYXRjaCwgdG9OZXh0U2NyYXRjaCwgZm9yd2FyZFNjcmF0Y2gsIHZlcnRleFVwU2NyYXRjaCwgY29zaW5lOTAsIGNvc2luZTE4MCwgWFpfUExBTkUsIHByZXZpb3VzQm90dG9tU2NyYXRjaCwgdmVydGV4Qm90dG9tU2NyYXRjaCwgdmVydGV4VG9wU2NyYXRjaCwgbmV4dEJvdHRvbVNjcmF0Y2gsIHZlcnRleE5vcm1hbFNjcmF0Y2gsIGludGVyc2VjdGlvblNjcmF0Y2gsIGNhcnRvZ3JhcGhpY1NjcmF0Y2gwLCBjYXJ0b2dyYXBoaWNTY3JhdGNoMSwgY2FydG9ncmFwaGljSW50ZXJzZWN0aW9uU2NyYXRjaCwgbGluZURpcmVjdGlvblNjcmF0Y2gsIG1hdHJpeDNTY3JhdGNoLCBxdWF0ZXJuaW9uU2NyYXRjaDMsIGVuZFBvc0NhcnRvZ3JhcGhpY1NjcmF0Y2gsIG5vcm1hbFN0YXJ0cG9pbnRTY3JhdGNoLCBub3JtYWxFbmRwb2ludFNjcmF0Y2gsIGFkanVzdEhlaWdodE5vcm1hbFNjcmF0Y2gsIGFkanVzdEhlaWdodE9mZnNldFNjcmF0Y2gsIG51ZGdlRGlyZWN0aW9uU2NyYXRjaCwgc3RhcnRDYXJ0b2dyYXBoaWNTY3JhdGNoLCBlbmRDYXJ0b2dyYXBoaWNTY3JhdGNoLCBzZWdtZW50U3RhcnRUb3BTY3JhdGNoLCBzZWdtZW50RW5kVG9wU2NyYXRjaCwgc2VnbWVudFN0YXJ0Qm90dG9tU2NyYXRjaCwgc2VnbWVudEVuZEJvdHRvbVNjcmF0Y2gsIHNlZ21lbnRTdGFydE5vcm1hbFNjcmF0Y2gsIHNlZ21lbnRFbmROb3JtYWxTY3JhdGNoLCBnZXRIZWlnaHRDYXJ0b2dyYXBoaWNzLCBnZXRIZWlnaHRSZWN0YW5nbGVTY3JhdGNoLCBhZGp1c3RIZWlnaHRTdGFydFRvcFNjcmF0Y2gsIGFkanVzdEhlaWdodEVuZFRvcFNjcmF0Y2gsIGFkanVzdEhlaWdodFN0YXJ0Qm90dG9tU2NyYXRjaCwgYWRqdXN0SGVpZ2h0RW5kQm90dG9tU2NyYXRjaCwgc2VnbWVudFN0YXJ0MkRTY3JhdGNoLCBzZWdtZW50RW5kMkRTY3JhdGNoLCBzZWdtZW50U3RhcnROb3JtYWwyRFNjcmF0Y2gsIHNlZ21lbnRFbmROb3JtYWwyRFNjcmF0Y2gsIG9mZnNldFNjcmF0Y2gyLCBzdGFydFVwU2NyYXRjaCwgZW5kVXBTY3JhdGNoLCByaWdodFNjcmF0Y2gyLCBzdGFydFBsYW5lTm9ybWFsU2NyYXRjaCwgZW5kUGxhbmVOb3JtYWxTY3JhdGNoLCBlbmNvZGVTY3JhdGNoLCBlbmNvZGVTY3JhdGNoMkQsIGZvcndhcmRPZmZzZXQyRFNjcmF0Y2gsIHJpZ2h0MkRTY3JhdGNoLCBub3JtYWxOdWRnZVNjcmF0Y2gsIHNjcmF0Y2hCb3VuZGluZ1NwaGVyZXMsIFJFRkVSRU5DRV9JTkRJQ0VTLCBSRUZFUkVOQ0VfSU5ESUNFU19MRU5HVEgsIEdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9Hcm91bmRQb2x5bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Hcm91bmRQb2x5bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9BcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzKCk7CiAgICAgIGluaXRfQXJjVHlwZSgpOwogICAgICBpbml0X2FycmF5UmVtb3ZlRHVwbGljYXRlcygpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWRHZW9kZXNpYygpOwogICAgICBpbml0X0VsbGlwc29pZFJodW1iTGluZSgpOwogICAgICBpbml0X0VuY29kZWRDYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfR2VvZ3JhcGhpY1Byb2plY3Rpb24oKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0aW9uVGVzdHMoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X1BsYW5lKCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1dlYk1lcmNhdG9yUHJvamVjdGlvbigpOwogICAgICBQUk9KRUNUSU9OUyA9IFtHZW9ncmFwaGljUHJvamVjdGlvbl9kZWZhdWx0LCBXZWJNZXJjYXRvclByb2plY3Rpb25fZGVmYXVsdF07CiAgICAgIFBST0pFQ1RJT05fQ09VTlQgPSBQUk9KRUNUSU9OUy5sZW5ndGg7CiAgICAgIE1JVEVSX0JSRUFLX1NNQUxMID0gTWF0aC5jb3MoTWF0aF9kZWZhdWx0LnRvUmFkaWFucygzMCkpOwogICAgICBNSVRFUl9CUkVBS19MQVJHRSA9IE1hdGguY29zKE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoMTUwKSk7CiAgICAgIFdBTExfSU5JVElBTF9NSU5fSEVJR0hUID0gMDsKICAgICAgV0FMTF9JTklUSUFMX01BWF9IRUlHSFQgPSAxZTM7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEdyb3VuZFBvbHlsaW5lR2VvbWV0cnkucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIG51bWJlciBvZiBlbGVtZW50cyB1c2VkIHRvIHBhY2sgdGhlIG9iamVjdCBpbnRvIGFuIGFycmF5LgogICAgICAgICAqIEBtZW1iZXJvZiBHcm91bmRQb2x5bGluZUdlb21ldHJ5LnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICBwYWNrZWRMZW5ndGg6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAxICsgdGhpcy5fcG9zaXRpb25zLmxlbmd0aCAqIDMgKyAxICsgMSArIDEgKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAxICsgMTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBHcm91bmRQb2x5bGluZUdlb21ldHJ5LnNldFByb2plY3Rpb25BbmRFbGxpcHNvaWQgPSBmdW5jdGlvbihncm91bmRQb2x5bGluZUdlb21ldHJ5LCBtYXBQcm9qZWN0aW9uKSB7CiAgICAgICAgbGV0IHByb2plY3Rpb25JbmRleCA9IDA7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IFBST0pFQ1RJT05fQ09VTlQ7IGkyKyspIHsKICAgICAgICAgIGlmIChtYXBQcm9qZWN0aW9uIGluc3RhbmNlb2YgUFJPSkVDVElPTlNbaTJdKSB7CiAgICAgICAgICAgIHByb2plY3Rpb25JbmRleCA9IGkyOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5fcHJvamVjdGlvbkluZGV4ID0gcHJvamVjdGlvbkluZGV4OwogICAgICAgIGdyb3VuZFBvbHlsaW5lR2VvbWV0cnkuX2VsbGlwc29pZCA9IG1hcFByb2plY3Rpb24uZWxsaXBzb2lkOwogICAgICB9OwogICAgICBjYXJ0M1NjcmF0Y2gxID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0M1NjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0M1NjcmF0Y2gzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBpbnRlcnBvbGF0ZWRDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIGludGVycG9sYXRlZEJvdHRvbVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGludGVycG9sYXRlZFRvcFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGludGVycG9sYXRlZE5vcm1hbFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGhlaWdodGxlc3NDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIEdyb3VuZFBvbHlsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBsZXQgaW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gdmFsdWUuX3Bvc2l0aW9uczsKICAgICAgICBjb25zdCBwb3NpdGlvbnNMZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGFycmF5W2luZGV4KytdID0gcG9zaXRpb25zTGVuZ3RoOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7ICsraTIpIHsKICAgICAgICAgIGNvbnN0IGNhcnRlc2lhbjExID0gcG9zaXRpb25zW2kyXTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGNhcnRlc2lhbjExLCBhcnJheSwgaW5kZXgpOwogICAgICAgICAgaW5kZXggKz0gMzsKICAgICAgICB9CiAgICAgICAgYXJyYXlbaW5kZXgrK10gPSB2YWx1ZS5ncmFudWxhcml0eTsKICAgICAgICBhcnJheVtpbmRleCsrXSA9IHZhbHVlLmxvb3AgPyAxIDogMDsKICAgICAgICBhcnJheVtpbmRleCsrXSA9IHZhbHVlLmFyY1R5cGU7CiAgICAgICAgRWxsaXBzb2lkX2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzb2lkLCBhcnJheSwgaW5kZXgpOwogICAgICAgIGluZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtpbmRleCsrXSA9IHZhbHVlLl9wcm9qZWN0aW9uSW5kZXg7CiAgICAgICAgYXJyYXlbaW5kZXhdID0gdmFsdWUuX3NjZW5lM0RPbmx5ID8gMSA6IDA7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBHcm91bmRQb2x5bGluZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIGxldCBpbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCBwb3NpdGlvbnNMZW5ndGggPSBhcnJheVtpbmRleCsrXTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgQXJyYXkocG9zaXRpb25zTGVuZ3RoKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zTGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBwb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgaW5kZXgpOwogICAgICAgICAgaW5kZXggKz0gMzsKICAgICAgICB9CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBhcnJheVtpbmRleCsrXTsKICAgICAgICBjb25zdCBsb29wID0gYXJyYXlbaW5kZXgrK10gPT09IDE7CiAgICAgICAgY29uc3QgYXJjVHlwZSA9IGFycmF5W2luZGV4KytdOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LnVucGFjayhhcnJheSwgaW5kZXgpOwogICAgICAgIGluZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBwcm9qZWN0aW9uSW5kZXggPSBhcnJheVtpbmRleCsrXTsKICAgICAgICBjb25zdCBzY2VuZTNET25seSA9IGFycmF5W2luZGV4XSA9PT0gMTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgR3JvdW5kUG9seWxpbmVHZW9tZXRyeSh7CiAgICAgICAgICAgIHBvc2l0aW9ucwogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgIHJlc3VsdC5ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgIHJlc3VsdC5sb29wID0gbG9vcDsKICAgICAgICByZXN1bHQuYXJjVHlwZSA9IGFyY1R5cGU7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNvaWQgPSBlbGxpcHNvaWQ7CiAgICAgICAgcmVzdWx0Ll9wcm9qZWN0aW9uSW5kZXggPSBwcm9qZWN0aW9uSW5kZXg7CiAgICAgICAgcmVzdWx0Ll9zY2VuZTNET25seSA9IHNjZW5lM0RPbmx5OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIHRvUHJldmlvdXNTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0b05leHRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmb3J3YXJkU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdmVydGV4VXBTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjb3NpbmU5MCA9IDA7CiAgICAgIGNvc2luZTE4MCA9IC0xOwogICAgICBYWl9QTEFORSA9IFBsYW5lX2RlZmF1bHQuZnJvbVBvaW50Tm9ybWFsKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9ZKTsKICAgICAgcHJldmlvdXNCb3R0b21TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB2ZXJ0ZXhCb3R0b21TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB2ZXJ0ZXhUb3BTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBuZXh0Qm90dG9tU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdmVydGV4Tm9ybWFsU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgaW50ZXJzZWN0aW9uU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FydG9ncmFwaGljU2NyYXRjaDAgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgY2FydG9ncmFwaGljU2NyYXRjaDEgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgY2FydG9ncmFwaGljSW50ZXJzZWN0aW9uU2NyYXRjaCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBHcm91bmRQb2x5bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24oZ3JvdW5kUG9seWxpbmVHZW9tZXRyeSkgewogICAgICAgIGNvbnN0IGNvbXB1dGUyZEF0dHJpYnV0ZXMgPSAhZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5fc2NlbmUzRE9ubHk7CiAgICAgICAgbGV0IGxvb3AgPSBncm91bmRQb2x5bGluZUdlb21ldHJ5Lmxvb3A7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5ncmFudWxhcml0eTsKICAgICAgICBjb25zdCBhcmNUeXBlID0gZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5hcmNUeXBlOwogICAgICAgIGNvbnN0IHByb2plY3Rpb24gPSBuZXcgUFJPSkVDVElPTlNbZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5fcHJvamVjdGlvbkluZGV4XSgKICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICk7CiAgICAgICAgY29uc3QgbWluSGVpZ2h0ID0gV0FMTF9JTklUSUFMX01JTl9IRUlHSFQ7CiAgICAgICAgY29uc3QgbWF4SGVpZ2h0ID0gV0FMTF9JTklUSUFMX01BWF9IRUlHSFQ7CiAgICAgICAgbGV0IGluZGV4OwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBncm91bmRQb2x5bGluZUdlb21ldHJ5Ll9wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgcG9zaXRpb25zTGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBpZiAocG9zaXRpb25zTGVuZ3RoID09PSAyKSB7CiAgICAgICAgICBsb29wID0gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGxldCBwMDsKICAgICAgICBsZXQgcDE7CiAgICAgICAgbGV0IGMwOwogICAgICAgIGxldCBjMTsKICAgICAgICBjb25zdCByaHVtYkxpbmUgPSBuZXcgRWxsaXBzb2lkUmh1bWJMaW5lX2RlZmF1bHQodm9pZCAwLCB2b2lkIDAsIGVsbGlwc29pZCk7CiAgICAgICAgbGV0IGludGVyc2VjdGlvbjsKICAgICAgICBsZXQgaW50ZXJzZWN0aW9uQ2FydG9ncmFwaGljOwogICAgICAgIGxldCBpbnRlcnNlY3Rpb25Mb25naXR1ZGU7CiAgICAgICAgY29uc3Qgc3BsaXRQb3NpdGlvbnMgPSBbcG9zaXRpb25zWzBdXTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGggLSAxOyBpMisrKSB7CiAgICAgICAgICBwMCA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICBwMSA9IHBvc2l0aW9uc1tpMiArIDFdOwogICAgICAgICAgaW50ZXJzZWN0aW9uID0gSW50ZXJzZWN0aW9uVGVzdHNfZGVmYXVsdC5saW5lU2VnbWVudFBsYW5lKAogICAgICAgICAgICBwMCwKICAgICAgICAgICAgcDEsCiAgICAgICAgICAgIFhaX1BMQU5FLAogICAgICAgICAgICBpbnRlcnNlY3Rpb25TY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb24pICYmICFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihpbnRlcnNlY3Rpb24sIHAwLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjcpICYmICFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihpbnRlcnNlY3Rpb24sIHAxLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjcpKSB7CiAgICAgICAgICAgIGlmIChncm91bmRQb2x5bGluZUdlb21ldHJ5LmFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQykgewogICAgICAgICAgICAgIHNwbGl0UG9zaXRpb25zLnB1c2goQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGludGVyc2VjdGlvbikpOwogICAgICAgICAgICB9IGVsc2UgaWYgKGdyb3VuZFBvbHlsaW5lR2VvbWV0cnkuYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uTG9uZ2l0dWRlID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uLAogICAgICAgICAgICAgICAgY2FydG9ncmFwaGljU2NyYXRjaDAKICAgICAgICAgICAgICApLmxvbmdpdHVkZTsKICAgICAgICAgICAgICBjMCA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMCwgY2FydG9ncmFwaGljU2NyYXRjaDApOwogICAgICAgICAgICAgIGMxID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKHAxLCBjYXJ0b2dyYXBoaWNTY3JhdGNoMSk7CiAgICAgICAgICAgICAgcmh1bWJMaW5lLnNldEVuZFBvaW50cyhjMCwgYzEpOwogICAgICAgICAgICAgIGludGVyc2VjdGlvbkNhcnRvZ3JhcGhpYyA9IHJodW1iTGluZS5maW5kSW50ZXJzZWN0aW9uV2l0aExvbmdpdHVkZSgKICAgICAgICAgICAgICAgIGludGVyc2VjdGlvbkxvbmdpdHVkZSwKICAgICAgICAgICAgICAgIGNhcnRvZ3JhcGhpY0ludGVyc2VjdGlvblNjcmF0Y2gKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGludGVyc2VjdGlvbiA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICAgICAgICAgIGludGVyc2VjdGlvbkNhcnRvZ3JhcGhpYywKICAgICAgICAgICAgICAgIGludGVyc2VjdGlvblNjcmF0Y2gKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoaW50ZXJzZWN0aW9uKSAmJiAhQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24oaW50ZXJzZWN0aW9uLCBwMCwgTWF0aF9kZWZhdWx0LkVQU0lMT043KSAmJiAhQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24oaW50ZXJzZWN0aW9uLCBwMSwgTWF0aF9kZWZhdWx0LkVQU0lMT043KSkgewogICAgICAgICAgICAgICAgc3BsaXRQb3NpdGlvbnMucHVzaChDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoaW50ZXJzZWN0aW9uKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBzcGxpdFBvc2l0aW9ucy5wdXNoKHAxKTsKICAgICAgICB9CiAgICAgICAgaWYgKGxvb3ApIHsKICAgICAgICAgIHAwID0gcG9zaXRpb25zW3Bvc2l0aW9uc0xlbmd0aCAtIDFdOwogICAgICAgICAgcDEgPSBwb3NpdGlvbnNbMF07CiAgICAgICAgICBpbnRlcnNlY3Rpb24gPSBJbnRlcnNlY3Rpb25UZXN0c19kZWZhdWx0LmxpbmVTZWdtZW50UGxhbmUoCiAgICAgICAgICAgIHAwLAogICAgICAgICAgICBwMSwKICAgICAgICAgICAgWFpfUExBTkUsCiAgICAgICAgICAgIGludGVyc2VjdGlvblNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGludGVyc2VjdGlvbikgJiYgIUNhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKGludGVyc2VjdGlvbiwgcDAsIE1hdGhfZGVmYXVsdC5FUFNJTE9ONykgJiYgIUNhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKGludGVyc2VjdGlvbiwgcDEsIE1hdGhfZGVmYXVsdC5FUFNJTE9ONykpIHsKICAgICAgICAgICAgaWYgKGdyb3VuZFBvbHlsaW5lR2VvbWV0cnkuYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDKSB7CiAgICAgICAgICAgICAgc3BsaXRQb3NpdGlvbnMucHVzaChDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoaW50ZXJzZWN0aW9uKSk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZ3JvdW5kUG9seWxpbmVHZW9tZXRyeS5hcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgICAgICAgICBpbnRlcnNlY3Rpb25Mb25naXR1ZGUgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgICAgICAgICAgICBpbnRlcnNlY3Rpb24sCiAgICAgICAgICAgICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoMAogICAgICAgICAgICAgICkubG9uZ2l0dWRlOwogICAgICAgICAgICAgIGMwID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKHAwLCBjYXJ0b2dyYXBoaWNTY3JhdGNoMCk7CiAgICAgICAgICAgICAgYzEgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocDEsIGNhcnRvZ3JhcGhpY1NjcmF0Y2gxKTsKICAgICAgICAgICAgICByaHVtYkxpbmUuc2V0RW5kUG9pbnRzKGMwLCBjMSk7CiAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uQ2FydG9ncmFwaGljID0gcmh1bWJMaW5lLmZpbmRJbnRlcnNlY3Rpb25XaXRoTG9uZ2l0dWRlKAogICAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uTG9uZ2l0dWRlLAogICAgICAgICAgICAgICAgY2FydG9ncmFwaGljSW50ZXJzZWN0aW9uU2NyYXRjaAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uQ2FydG9ncmFwaGljLAogICAgICAgICAgICAgICAgaW50ZXJzZWN0aW9uU2NyYXRjaAogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChpbnRlcnNlY3Rpb24pICYmICFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihpbnRlcnNlY3Rpb24sIHAwLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjcpICYmICFDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihpbnRlcnNlY3Rpb24sIHAxLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjcpKSB7CiAgICAgICAgICAgICAgICBzcGxpdFBvc2l0aW9ucy5wdXNoKENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShpbnRlcnNlY3Rpb24pKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgbGV0IGNhcnRvZ3JhcGhpY3NMZW5ndGggPSBzcGxpdFBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgbGV0IGNhcnRvZ3JhcGhpY3MgPSBuZXcgQXJyYXkoY2FydG9ncmFwaGljc0xlbmd0aCk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgY2FydG9ncmFwaGljc0xlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21DYXJ0ZXNpYW4oCiAgICAgICAgICAgIHNwbGl0UG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgZWxsaXBzb2lkCiAgICAgICAgICApOwogICAgICAgICAgY2FydG9ncmFwaGljMi5oZWlnaHQgPSAwOwogICAgICAgICAgY2FydG9ncmFwaGljc1tpMl0gPSBjYXJ0b2dyYXBoaWMyOwogICAgICAgIH0KICAgICAgICBjYXJ0b2dyYXBoaWNzID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICBjYXJ0b2dyYXBoaWNzLAogICAgICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZXF1YWxzRXBzaWxvbgogICAgICAgICk7CiAgICAgICAgY2FydG9ncmFwaGljc0xlbmd0aCA9IGNhcnRvZ3JhcGhpY3MubGVuZ3RoOwogICAgICAgIGlmIChjYXJ0b2dyYXBoaWNzTGVuZ3RoIDwgMikgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgY29uc3QgY2FydG9ncmFwaGljc0FycmF5ID0gW107CiAgICAgICAgY29uc3Qgbm9ybWFsc0FycmF5ID0gW107CiAgICAgICAgY29uc3QgYm90dG9tUG9zaXRpb25zQXJyYXkgPSBbXTsKICAgICAgICBjb25zdCB0b3BQb3NpdGlvbnNBcnJheSA9IFtdOwogICAgICAgIGxldCBwcmV2aW91c0JvdHRvbSA9IHByZXZpb3VzQm90dG9tU2NyYXRjaDsKICAgICAgICBsZXQgdmVydGV4Qm90dG9tID0gdmVydGV4Qm90dG9tU2NyYXRjaDsKICAgICAgICBsZXQgdmVydGV4VG9wID0gdmVydGV4VG9wU2NyYXRjaDsKICAgICAgICBsZXQgbmV4dEJvdHRvbSA9IG5leHRCb3R0b21TY3JhdGNoOwogICAgICAgIGxldCB2ZXJ0ZXhOb3JtYWwgPSB2ZXJ0ZXhOb3JtYWxTY3JhdGNoOwogICAgICAgIGNvbnN0IHN0YXJ0Q2FydG9ncmFwaGljID0gY2FydG9ncmFwaGljc1swXTsKICAgICAgICBjb25zdCBuZXh0Q2FydG9ncmFwaGljID0gY2FydG9ncmFwaGljc1sxXTsKICAgICAgICBjb25zdCBwcmVzdGFydENhcnRvZ3JhcGhpYyA9IGNhcnRvZ3JhcGhpY3NbY2FydG9ncmFwaGljc0xlbmd0aCAtIDFdOwogICAgICAgIHByZXZpb3VzQm90dG9tID0gZ2V0UG9zaXRpb24oCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBwcmVzdGFydENhcnRvZ3JhcGhpYywKICAgICAgICAgIG1pbkhlaWdodCwKICAgICAgICAgIHByZXZpb3VzQm90dG9tCiAgICAgICAgKTsKICAgICAgICBuZXh0Qm90dG9tID0gZ2V0UG9zaXRpb24oZWxsaXBzb2lkLCBuZXh0Q2FydG9ncmFwaGljLCBtaW5IZWlnaHQsIG5leHRCb3R0b20pOwogICAgICAgIHZlcnRleEJvdHRvbSA9IGdldFBvc2l0aW9uKAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc3RhcnRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICBtaW5IZWlnaHQsCiAgICAgICAgICB2ZXJ0ZXhCb3R0b20KICAgICAgICApOwogICAgICAgIHZlcnRleFRvcCA9IGdldFBvc2l0aW9uKGVsbGlwc29pZCwgc3RhcnRDYXJ0b2dyYXBoaWMsIG1heEhlaWdodCwgdmVydGV4VG9wKTsKICAgICAgICBpZiAobG9vcCkgewogICAgICAgICAgdmVydGV4Tm9ybWFsID0gY29tcHV0ZVZlcnRleE1pdGVyTm9ybWFsKAogICAgICAgICAgICBwcmV2aW91c0JvdHRvbSwKICAgICAgICAgICAgdmVydGV4Qm90dG9tLAogICAgICAgICAgICB2ZXJ0ZXhUb3AsCiAgICAgICAgICAgIG5leHRCb3R0b20sCiAgICAgICAgICAgIHZlcnRleE5vcm1hbAogICAgICAgICAgKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdmVydGV4Tm9ybWFsID0gY29tcHV0ZVJpZ2h0Tm9ybWFsKAogICAgICAgICAgICBzdGFydENhcnRvZ3JhcGhpYywKICAgICAgICAgICAgbmV4dENhcnRvZ3JhcGhpYywKICAgICAgICAgICAgbWF4SGVpZ2h0LAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHZlcnRleE5vcm1hbAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sodmVydGV4Tm9ybWFsLCBub3JtYWxzQXJyYXksIDApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZlcnRleEJvdHRvbSwgYm90dG9tUG9zaXRpb25zQXJyYXksIDApOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZlcnRleFRvcCwgdG9wUG9zaXRpb25zQXJyYXksIDApOwogICAgICAgIGNhcnRvZ3JhcGhpY3NBcnJheS5wdXNoKHN0YXJ0Q2FydG9ncmFwaGljLmxhdGl0dWRlKTsKICAgICAgICBjYXJ0b2dyYXBoaWNzQXJyYXkucHVzaChzdGFydENhcnRvZ3JhcGhpYy5sb25naXR1ZGUpOwogICAgICAgIGludGVycG9sYXRlU2VnbWVudCgKICAgICAgICAgIHN0YXJ0Q2FydG9ncmFwaGljLAogICAgICAgICAgbmV4dENhcnRvZ3JhcGhpYywKICAgICAgICAgIG1pbkhlaWdodCwKICAgICAgICAgIG1heEhlaWdodCwKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgYXJjVHlwZSwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIG5vcm1hbHNBcnJheSwKICAgICAgICAgIGJvdHRvbVBvc2l0aW9uc0FycmF5LAogICAgICAgICAgdG9wUG9zaXRpb25zQXJyYXksCiAgICAgICAgICBjYXJ0b2dyYXBoaWNzQXJyYXkKICAgICAgICApOwogICAgICAgIGZvciAoaTIgPSAxOyBpMiA8IGNhcnRvZ3JhcGhpY3NMZW5ndGggLSAxOyArK2kyKSB7CiAgICAgICAgICBwcmV2aW91c0JvdHRvbSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhCb3R0b20sIHByZXZpb3VzQm90dG9tKTsKICAgICAgICAgIHZlcnRleEJvdHRvbSA9IENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShuZXh0Qm90dG9tLCB2ZXJ0ZXhCb3R0b20pOwogICAgICAgICAgY29uc3QgdmVydGV4Q2FydG9ncmFwaGljID0gY2FydG9ncmFwaGljc1tpMl07CiAgICAgICAgICBnZXRQb3NpdGlvbihlbGxpcHNvaWQsIHZlcnRleENhcnRvZ3JhcGhpYywgbWF4SGVpZ2h0LCB2ZXJ0ZXhUb3ApOwogICAgICAgICAgZ2V0UG9zaXRpb24oZWxsaXBzb2lkLCBjYXJ0b2dyYXBoaWNzW2kyICsgMV0sIG1pbkhlaWdodCwgbmV4dEJvdHRvbSk7CiAgICAgICAgICBjb21wdXRlVmVydGV4TWl0ZXJOb3JtYWwoCiAgICAgICAgICAgIHByZXZpb3VzQm90dG9tLAogICAgICAgICAgICB2ZXJ0ZXhCb3R0b20sCiAgICAgICAgICAgIHZlcnRleFRvcCwKICAgICAgICAgICAgbmV4dEJvdHRvbSwKICAgICAgICAgICAgdmVydGV4Tm9ybWFsCiAgICAgICAgICApOwogICAgICAgICAgaW5kZXggPSBub3JtYWxzQXJyYXkubGVuZ3RoOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sodmVydGV4Tm9ybWFsLCBub3JtYWxzQXJyYXksIGluZGV4KTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZlcnRleEJvdHRvbSwgYm90dG9tUG9zaXRpb25zQXJyYXksIGluZGV4KTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZlcnRleFRvcCwgdG9wUG9zaXRpb25zQXJyYXksIGluZGV4KTsKICAgICAgICAgIGNhcnRvZ3JhcGhpY3NBcnJheS5wdXNoKHZlcnRleENhcnRvZ3JhcGhpYy5sYXRpdHVkZSk7CiAgICAgICAgICBjYXJ0b2dyYXBoaWNzQXJyYXkucHVzaCh2ZXJ0ZXhDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlKTsKICAgICAgICAgIGludGVycG9sYXRlU2VnbWVudCgKICAgICAgICAgICAgY2FydG9ncmFwaGljc1tpMl0sCiAgICAgICAgICAgIGNhcnRvZ3JhcGhpY3NbaTIgKyAxXSwKICAgICAgICAgICAgbWluSGVpZ2h0LAogICAgICAgICAgICBtYXhIZWlnaHQsCiAgICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgICBhcmNUeXBlLAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIG5vcm1hbHNBcnJheSwKICAgICAgICAgICAgYm90dG9tUG9zaXRpb25zQXJyYXksCiAgICAgICAgICAgIHRvcFBvc2l0aW9uc0FycmF5LAogICAgICAgICAgICBjYXJ0b2dyYXBoaWNzQXJyYXkKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGVuZENhcnRvZ3JhcGhpYyA9IGNhcnRvZ3JhcGhpY3NbY2FydG9ncmFwaGljc0xlbmd0aCAtIDFdOwogICAgICAgIGNvbnN0IHByZUVuZENhcnRvZ3JhcGhpYyA9IGNhcnRvZ3JhcGhpY3NbY2FydG9ncmFwaGljc0xlbmd0aCAtIDJdOwogICAgICAgIHZlcnRleEJvdHRvbSA9IGdldFBvc2l0aW9uKAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZW5kQ2FydG9ncmFwaGljLAogICAgICAgICAgbWluSGVpZ2h0LAogICAgICAgICAgdmVydGV4Qm90dG9tCiAgICAgICAgKTsKICAgICAgICB2ZXJ0ZXhUb3AgPSBnZXRQb3NpdGlvbihlbGxpcHNvaWQsIGVuZENhcnRvZ3JhcGhpYywgbWF4SGVpZ2h0LCB2ZXJ0ZXhUb3ApOwogICAgICAgIGlmIChsb29wKSB7CiAgICAgICAgICBjb25zdCBwb3N0RW5kQ2FydG9ncmFwaGljID0gY2FydG9ncmFwaGljc1swXTsKICAgICAgICAgIHByZXZpb3VzQm90dG9tID0gZ2V0UG9zaXRpb24oCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgcHJlRW5kQ2FydG9ncmFwaGljLAogICAgICAgICAgICBtaW5IZWlnaHQsCiAgICAgICAgICAgIHByZXZpb3VzQm90dG9tCiAgICAgICAgICApOwogICAgICAgICAgbmV4dEJvdHRvbSA9IGdldFBvc2l0aW9uKAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHBvc3RFbmRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIG1pbkhlaWdodCwKICAgICAgICAgICAgbmV4dEJvdHRvbQogICAgICAgICAgKTsKICAgICAgICAgIHZlcnRleE5vcm1hbCA9IGNvbXB1dGVWZXJ0ZXhNaXRlck5vcm1hbCgKICAgICAgICAgICAgcHJldmlvdXNCb3R0b20sCiAgICAgICAgICAgIHZlcnRleEJvdHRvbSwKICAgICAgICAgICAgdmVydGV4VG9wLAogICAgICAgICAgICBuZXh0Qm90dG9tLAogICAgICAgICAgICB2ZXJ0ZXhOb3JtYWwKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZlcnRleE5vcm1hbCA9IGNvbXB1dGVSaWdodE5vcm1hbCgKICAgICAgICAgICAgcHJlRW5kQ2FydG9ncmFwaGljLAogICAgICAgICAgICBlbmRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIG1heEhlaWdodCwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICB2ZXJ0ZXhOb3JtYWwKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGluZGV4ID0gbm9ybWFsc0FycmF5Lmxlbmd0aDsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayh2ZXJ0ZXhOb3JtYWwsIG5vcm1hbHNBcnJheSwgaW5kZXgpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHZlcnRleEJvdHRvbSwgYm90dG9tUG9zaXRpb25zQXJyYXksIGluZGV4KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayh2ZXJ0ZXhUb3AsIHRvcFBvc2l0aW9uc0FycmF5LCBpbmRleCk7CiAgICAgICAgY2FydG9ncmFwaGljc0FycmF5LnB1c2goZW5kQ2FydG9ncmFwaGljLmxhdGl0dWRlKTsKICAgICAgICBjYXJ0b2dyYXBoaWNzQXJyYXkucHVzaChlbmRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlKTsKICAgICAgICBpZiAobG9vcCkgewogICAgICAgICAgaW50ZXJwb2xhdGVTZWdtZW50KAogICAgICAgICAgICBlbmRDYXJ0b2dyYXBoaWMsCiAgICAgICAgICAgIHN0YXJ0Q2FydG9ncmFwaGljLAogICAgICAgICAgICBtaW5IZWlnaHQsCiAgICAgICAgICAgIG1heEhlaWdodCwKICAgICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICAgIGFyY1R5cGUsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgbm9ybWFsc0FycmF5LAogICAgICAgICAgICBib3R0b21Qb3NpdGlvbnNBcnJheSwKICAgICAgICAgICAgdG9wUG9zaXRpb25zQXJyYXksCiAgICAgICAgICAgIGNhcnRvZ3JhcGhpY3NBcnJheQogICAgICAgICAgKTsKICAgICAgICAgIGluZGV4ID0gbm9ybWFsc0FycmF5Lmxlbmd0aDsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IDM7ICsraTIpIHsKICAgICAgICAgICAgbm9ybWFsc0FycmF5W2luZGV4ICsgaTJdID0gbm9ybWFsc0FycmF5W2kyXTsKICAgICAgICAgICAgYm90dG9tUG9zaXRpb25zQXJyYXlbaW5kZXggKyBpMl0gPSBib3R0b21Qb3NpdGlvbnNBcnJheVtpMl07CiAgICAgICAgICAgIHRvcFBvc2l0aW9uc0FycmF5W2luZGV4ICsgaTJdID0gdG9wUG9zaXRpb25zQXJyYXlbaTJdOwogICAgICAgICAgfQogICAgICAgICAgY2FydG9ncmFwaGljc0FycmF5LnB1c2goc3RhcnRDYXJ0b2dyYXBoaWMubGF0aXR1ZGUpOwogICAgICAgICAgY2FydG9ncmFwaGljc0FycmF5LnB1c2goc3RhcnRDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGdlbmVyYXRlR2VvbWV0cnlBdHRyaWJ1dGVzKAogICAgICAgICAgbG9vcCwKICAgICAgICAgIHByb2plY3Rpb24sCiAgICAgICAgICBib3R0b21Qb3NpdGlvbnNBcnJheSwKICAgICAgICAgIHRvcFBvc2l0aW9uc0FycmF5LAogICAgICAgICAgbm9ybWFsc0FycmF5LAogICAgICAgICAgY2FydG9ncmFwaGljc0FycmF5LAogICAgICAgICAgY29tcHV0ZTJkQXR0cmlidXRlcwogICAgICAgICk7CiAgICAgIH07CiAgICAgIGxpbmVEaXJlY3Rpb25TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBtYXRyaXgzU2NyYXRjaCA9IG5ldyBNYXRyaXgzX2RlZmF1bHQoKTsKICAgICAgcXVhdGVybmlvblNjcmF0Y2gzID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBlbmRQb3NDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIG5vcm1hbFN0YXJ0cG9pbnRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBub3JtYWxFbmRwb2ludFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGFkanVzdEhlaWdodE5vcm1hbFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGFkanVzdEhlaWdodE9mZnNldFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIG51ZGdlRGlyZWN0aW9uU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc3RhcnRDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIGVuZENhcnRvZ3JhcGhpY1NjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2VnbWVudFN0YXJ0VG9wU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2VnbWVudEVuZFRvcFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNlZ21lbnRTdGFydEJvdHRvbVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNlZ21lbnRFbmRCb3R0b21TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzZWdtZW50U3RhcnROb3JtYWxTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzZWdtZW50RW5kTm9ybWFsU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgZ2V0SGVpZ2h0Q2FydG9ncmFwaGljcyA9IFsKICAgICAgICBzdGFydENhcnRvZ3JhcGhpY1NjcmF0Y2gsCiAgICAgICAgZW5kQ2FydG9ncmFwaGljU2NyYXRjaAogICAgICBdOwogICAgICBnZXRIZWlnaHRSZWN0YW5nbGVTY3JhdGNoID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIGFkanVzdEhlaWdodFN0YXJ0VG9wU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYWRqdXN0SGVpZ2h0RW5kVG9wU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYWRqdXN0SGVpZ2h0U3RhcnRCb3R0b21TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBhZGp1c3RIZWlnaHRFbmRCb3R0b21TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzZWdtZW50U3RhcnQyRFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNlZ21lbnRFbmQyRFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNlZ21lbnRTdGFydE5vcm1hbDJEU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2VnbWVudEVuZE5vcm1hbDJEU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgb2Zmc2V0U2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN0YXJ0VXBTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBlbmRVcFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHJpZ2h0U2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHN0YXJ0UGxhbmVOb3JtYWxTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBlbmRQbGFuZU5vcm1hbFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGVuY29kZVNjcmF0Y2ggPSBuZXcgRW5jb2RlZENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBlbmNvZGVTY3JhdGNoMkQgPSBuZXcgRW5jb2RlZENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBmb3J3YXJkT2Zmc2V0MkRTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICByaWdodDJEU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgbm9ybWFsTnVkZ2VTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQm91bmRpbmdTcGhlcmVzID0gW25ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCksIG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCldOwogICAgICBSRUZFUkVOQ0VfSU5ESUNFUyA9IFsKICAgICAgICAwLAogICAgICAgIDIsCiAgICAgICAgMSwKICAgICAgICAwLAogICAgICAgIDMsCiAgICAgICAgMiwKICAgICAgICAvLyByaWdodAogICAgICAgIDAsCiAgICAgICAgNywKICAgICAgICAzLAogICAgICAgIDAsCiAgICAgICAgNCwKICAgICAgICA3LAogICAgICAgIC8vIHN0YXJ0CiAgICAgICAgMCwKICAgICAgICA1LAogICAgICAgIDQsCiAgICAgICAgMCwKICAgICAgICAxLAogICAgICAgIDUsCiAgICAgICAgLy8gYm90dG9tCiAgICAgICAgNSwKICAgICAgICA3LAogICAgICAgIDQsCiAgICAgICAgNSwKICAgICAgICA2LAogICAgICAgIDcsCiAgICAgICAgLy8gbGVmdAogICAgICAgIDUsCiAgICAgICAgMiwKICAgICAgICA2LAogICAgICAgIDUsCiAgICAgICAgMSwKICAgICAgICAyLAogICAgICAgIC8vIGVuZAogICAgICAgIDMsCiAgICAgICAgNiwKICAgICAgICAyLAogICAgICAgIDMsCiAgICAgICAgNywKICAgICAgICA2CiAgICAgICAgLy8gdG9wCiAgICAgIF07CiAgICAgIFJFRkVSRU5DRV9JTkRJQ0VTX0xFTkdUSCA9IFJFRkVSRU5DRV9JTkRJQ0VTLmxlbmd0aDsKICAgICAgR3JvdW5kUG9seWxpbmVHZW9tZXRyeS5fcHJvamVjdE5vcm1hbCA9IHByb2plY3ROb3JtYWw7CiAgICAgIEdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IEdyb3VuZFBvbHlsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlR3JvdW5kUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlR3JvdW5kUG9seWxpbmVHZW9tZXRyeShncm91bmRQb2x5bGluZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIHJldHVybiBBcHByb3hpbWF0ZVRlcnJhaW5IZWlnaHRzX2RlZmF1bHQuaW5pdGlhbGl6ZSgpLnRoZW4oZnVuY3Rpb24oKSB7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICAgIGdyb3VuZFBvbHlsaW5lR2VvbWV0cnkgPSBHcm91bmRQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgZ3JvdW5kUG9seWxpbmVHZW9tZXRyeSwKICAgICAgICAgIG9mZnNldAogICAgICAgICk7CiAgICAgIH0KICAgICAgcmV0dXJuIEdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShncm91bmRQb2x5bGluZUdlb21ldHJ5KTsKICAgIH0pOwogIH0KICB2YXIgY3JlYXRlR3JvdW5kUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0FwcHJveGltYXRlVGVycmFpbkhlaWdodHMoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfR3JvdW5kUG9seWxpbmVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUGxhbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIFBsYW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIHRoaXMuX3ZlcnRleEZvcm1hdCA9IHZlcnRleEZvcm1hdDsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlUGxhbmVHZW9tZXRyeSI7CiAgfQogIHZhciBzY3JhdGNoVmVydGV4Rm9ybWF0OCwgc2NyYXRjaE9wdGlvbnMxNSwgbWluLCBtYXgsIFBsYW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9QbGFuZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QbGFuZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIFBsYW5lR2VvbWV0cnkucGFja2VkTGVuZ3RoID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICBQbGFuZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrKHZhbHVlLl92ZXJ0ZXhGb3JtYXQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ4ID0gbmV3IFZlcnRleEZvcm1hdF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hPcHRpb25zMTUgPSB7CiAgICAgICAgdmVydGV4Rm9ybWF0OiBzY3JhdGNoVmVydGV4Rm9ybWF0OAogICAgICB9OwogICAgICBQbGFuZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDgKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJldHVybiBuZXcgUGxhbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczE1KTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBtaW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KC0wLjUsIC0wLjUsIDApOwogICAgICBtYXggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KDAuNSwgMC41LCAwKTsKICAgICAgUGxhbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKHBsYW5lR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBwbGFuZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCgpOwogICAgICAgIGxldCBpbmRpY2VzOwogICAgICAgIGxldCBwb3NpdGlvbnM7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5wb3NpdGlvbikgewogICAgICAgICAgcG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSg0ICogMyk7CiAgICAgICAgICBwb3NpdGlvbnNbMF0gPSBtaW4ueDsKICAgICAgICAgIHBvc2l0aW9uc1sxXSA9IG1pbi55OwogICAgICAgICAgcG9zaXRpb25zWzJdID0gMDsKICAgICAgICAgIHBvc2l0aW9uc1szXSA9IG1heC54OwogICAgICAgICAgcG9zaXRpb25zWzRdID0gbWluLnk7CiAgICAgICAgICBwb3NpdGlvbnNbNV0gPSAwOwogICAgICAgICAgcG9zaXRpb25zWzZdID0gbWF4Lng7CiAgICAgICAgICBwb3NpdGlvbnNbN10gPSBtYXgueTsKICAgICAgICAgIHBvc2l0aW9uc1s4XSA9IDA7CiAgICAgICAgICBwb3NpdGlvbnNbOV0gPSBtaW4ueDsKICAgICAgICAgIHBvc2l0aW9uc1sxMF0gPSBtYXgueTsKICAgICAgICAgIHBvc2l0aW9uc1sxMV0gPSAwOwogICAgICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgICAgICAgfSk7CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgICBjb25zdCBub3JtYWxzID0gbmV3IEZsb2F0MzJBcnJheSg0ICogMyk7CiAgICAgICAgICAgIG5vcm1hbHNbMF0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzFdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1syXSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbM10gPSAwOwogICAgICAgICAgICBub3JtYWxzWzRdID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s1XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbNl0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzddID0gMDsKICAgICAgICAgICAgbm9ybWFsc1s4XSA9IDE7CiAgICAgICAgICAgIG5vcm1hbHNbOV0gPSAwOwogICAgICAgICAgICBub3JtYWxzWzEwXSA9IDA7CiAgICAgICAgICAgIG5vcm1hbHNbMTFdID0gMTsKICAgICAgICAgICAgYXR0cmlidXRlcy5ub3JtYWwgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgICB2YWx1ZXM6IG5vcm1hbHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgICAgICAgIGNvbnN0IHRleENvb3JkcyA9IG5ldyBGbG9hdDMyQXJyYXkoNCAqIDIpOwogICAgICAgICAgICB0ZXhDb29yZHNbMF0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMV0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbMl0gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbM10gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbNF0gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbNV0gPSAxOwogICAgICAgICAgICB0ZXhDb29yZHNbNl0gPSAwOwogICAgICAgICAgICB0ZXhDb29yZHNbN10gPSAxOwogICAgICAgICAgICBhdHRyaWJ1dGVzLnN0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgICAgdmFsdWVzOiB0ZXhDb29yZHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgY29uc3QgdGFuZ2VudHMgPSBuZXcgRmxvYXQzMkFycmF5KDQgKiAzKTsKICAgICAgICAgICAgdGFuZ2VudHNbMF0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1sxXSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzJdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbM10gPSAxOwogICAgICAgICAgICB0YW5nZW50c1s0XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzVdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbNl0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1s3XSA9IDA7CiAgICAgICAgICAgIHRhbmdlbnRzWzhdID0gMDsKICAgICAgICAgICAgdGFuZ2VudHNbOV0gPSAxOwogICAgICAgICAgICB0YW5nZW50c1sxMF0gPSAwOwogICAgICAgICAgICB0YW5nZW50c1sxMV0gPSAwOwogICAgICAgICAgICBhdHRyaWJ1dGVzLnRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgICB2YWx1ZXM6IHRhbmdlbnRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgY29uc3QgYml0YW5nZW50cyA9IG5ldyBGbG9hdDMyQXJyYXkoNCAqIDMpOwogICAgICAgICAgICBiaXRhbmdlbnRzWzBdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxXSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbMl0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzNdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s0XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbNV0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzZdID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1s3XSA9IDE7CiAgICAgICAgICAgIGJpdGFuZ2VudHNbOF0gPSAwOwogICAgICAgICAgICBiaXRhbmdlbnRzWzldID0gMDsKICAgICAgICAgICAgYml0YW5nZW50c1sxMF0gPSAxOwogICAgICAgICAgICBiaXRhbmdlbnRzWzExXSA9IDA7CiAgICAgICAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgaW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSgyICogMyk7CiAgICAgICAgICBpbmRpY2VzWzBdID0gMDsKICAgICAgICAgIGluZGljZXNbMV0gPSAxOwogICAgICAgICAgaW5kaWNlc1syXSA9IDI7CiAgICAgICAgICBpbmRpY2VzWzNdID0gMDsKICAgICAgICAgIGluZGljZXNbNF0gPSAyOwogICAgICAgICAgaW5kaWNlc1s1XSA9IDM7CiAgICAgICAgfQogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZTogbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIE1hdGguc3FydCgyKSkKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUGxhbmVHZW9tZXRyeV9kZWZhdWx0ID0gUGxhbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBsYW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUGxhbmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlUGxhbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVQbGFuZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVQbGFuZUdlb21ldHJ5KHBsYW5lR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIHBsYW5lR2VvbWV0cnkgPSBQbGFuZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKHBsYW5lR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICByZXR1cm4gUGxhbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHBsYW5lR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlUGxhbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZVBsYW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBsYW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9QbGFuZUdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZVBsYW5lR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZVBsYW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QbGFuZU91dGxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIFBsYW5lT3V0bGluZUdlb21ldHJ5KCkgewogICAgdGhpcy5fd29ya2VyTmFtZSA9ICJjcmVhdGVQbGFuZU91dGxpbmVHZW9tZXRyeSI7CiAgfQogIHZhciBtaW4yLCBtYXgyLCBQbGFuZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X1BsYW5lT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QbGFuZU91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQm91bmRpbmdTcGhlcmUoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBQbGFuZU91dGxpbmVHZW9tZXRyeS5wYWNrZWRMZW5ndGggPSAwOwogICAgICBQbGFuZU91dGxpbmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgUGxhbmVPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBQbGFuZU91dGxpbmVHZW9tZXRyeSgpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBtaW4yID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgtMC41LCAtMC41LCAwKTsKICAgICAgbWF4MiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoMC41LCAwLjUsIDApOwogICAgICBQbGFuZU91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKCkgewogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgICAgICBjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KDQgKiAyKTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KDQgKiAzKTsKICAgICAgICBwb3NpdGlvbnNbMF0gPSBtaW4yLng7CiAgICAgICAgcG9zaXRpb25zWzFdID0gbWluMi55OwogICAgICAgIHBvc2l0aW9uc1syXSA9IG1pbjIuejsKICAgICAgICBwb3NpdGlvbnNbM10gPSBtYXgyLng7CiAgICAgICAgcG9zaXRpb25zWzRdID0gbWluMi55OwogICAgICAgIHBvc2l0aW9uc1s1XSA9IG1pbjIuejsKICAgICAgICBwb3NpdGlvbnNbNl0gPSBtYXgyLng7CiAgICAgICAgcG9zaXRpb25zWzddID0gbWF4Mi55OwogICAgICAgIHBvc2l0aW9uc1s4XSA9IG1pbjIuejsKICAgICAgICBwb3NpdGlvbnNbOV0gPSBtaW4yLng7CiAgICAgICAgcG9zaXRpb25zWzEwXSA9IG1heDIueTsKICAgICAgICBwb3NpdGlvbnNbMTFdID0gbWluMi56OwogICAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgdmFsdWVzOiBwb3NpdGlvbnMKICAgICAgICB9KTsKICAgICAgICBpbmRpY2VzWzBdID0gMDsKICAgICAgICBpbmRpY2VzWzFdID0gMTsKICAgICAgICBpbmRpY2VzWzJdID0gMTsKICAgICAgICBpbmRpY2VzWzNdID0gMjsKICAgICAgICBpbmRpY2VzWzRdID0gMjsKICAgICAgICBpbmRpY2VzWzVdID0gMzsKICAgICAgICBpbmRpY2VzWzZdID0gMzsKICAgICAgICBpbmRpY2VzWzddID0gMDsKICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZTogbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIE1hdGguc3FydCgyKSkKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUGxhbmVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFBsYW5lT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVBsYW5lT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVBsYW5lT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVQbGFuZU91dGxpbmVHZW9tZXRyeShwbGFuZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBwbGFuZUdlb21ldHJ5ID0gUGxhbmVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2socGxhbmVHZW9tZXRyeSwgb2Zmc2V0KTsKICAgIH0KICAgIHJldHVybiBQbGFuZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHBsYW5lR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVQbGFuZU91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9QbGFuZU91dGxpbmVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVQbGFuZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9TdGVyZW9ncmFwaGljLmpzCiAgZnVuY3Rpb24gU3RlcmVvZ3JhcGhpYyhwb3NpdGlvbiwgdGFuZ2VudFBsYW5lKSB7CiAgICB0aGlzLnBvc2l0aW9uID0gcG9zaXRpb247CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLnBvc2l0aW9uKSkgewogICAgICB0aGlzLnBvc2l0aW9uID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgfQogICAgdGhpcy50YW5nZW50UGxhbmUgPSB0YW5nZW50UGxhbmU7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLnRhbmdlbnRQbGFuZSkpIHsKICAgICAgdGhpcy50YW5nZW50UGxhbmUgPSBTdGVyZW9ncmFwaGljLk5PUlRIX1BPTEVfVEFOR0VOVF9QTEFORTsKICAgIH0KICB9CiAgdmFyIHNjcmF0Y2hDYXJ0b2dyYXBoaWM1LCBzY3JhdGNoQ2FydGVzaWFuMTAsIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVSYXkyLCBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lUmF5RGlyZWN0aW9uLCBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lQ2FydGVzaWFuMzIsIFN0ZXJlb2dyYXBoaWNfZGVmYXVsdDsKICB2YXIgaW5pdF9TdGVyZW9ncmFwaGljID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9TdGVyZW9ncmFwaGljLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZFRhbmdlbnRQbGFuZSgpOwogICAgICBpbml0X0ludGVyc2VjdGlvblRlc3RzKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1JheSgpOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhTdGVyZW9ncmFwaGljLnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIGVsbGlwc29pZC4KICAgICAgICAgKiBAbWVtYmVyb2YgU3RlcmVvZ3JhcGhpYy5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7RWxsaXBzb2lkfQogICAgICAgICAqLwogICAgICAgIGVsbGlwc29pZDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFuZ2VudFBsYW5lLmVsbGlwc29pZDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHggY29vcmRpbmF0ZQogICAgICAgICAqIEBtZW1iZXJvZiBTdGVyZW9ncmFwaGljLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgeDogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucG9zaXRpb24ueDsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIHkgY29vcmRpbmF0ZQogICAgICAgICAqIEBtZW1iZXJvZiBTdGVyZW9ncmFwaGljLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgeTogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHRoaXMucG9zaXRpb24ueTsKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb25mb3JtYWwgbGF0aXR1ZGUsIG9yIHRoZSBlbGxpcHNvaWRhbCBsYXRpdHVkZSBwcm9qZWN0ZWQgb250byBhbiBhcmJpdHJhcnkgc3BoZXJlLgogICAgICAgICAqIEBtZW1iZXJvZiBTdGVyZW9ncmFwaGljLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgY29uZm9ybWFsTGF0aXR1ZGU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGNvbnN0IHIyID0gQ2FydGVzaWFuMl9kZWZhdWx0Lm1hZ25pdHVkZSh0aGlzLnBvc2l0aW9uKTsKICAgICAgICAgICAgY29uc3QgZDIgPSAyICogdGhpcy5lbGxpcHNvaWQubWF4aW11bVJhZGl1czsKICAgICAgICAgICAgY29uc3Qgc2lnbjMgPSB0aGlzLnRhbmdlbnRQbGFuZS5wbGFuZS5ub3JtYWwuejsKICAgICAgICAgICAgcmV0dXJuIHNpZ24zICogKE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTyAtIDIgKiBNYXRoLmF0YW4yKHIyLCBkMikpOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGxvbmdpdHVkZQogICAgICAgICAqIEBtZW1iZXJvZiBTdGVyZW9ncmFwaGljLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgbG9uZ2l0dWRlOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBsZXQgbG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPICsgTWF0aC5hdGFuMih0aGlzLnksIHRoaXMueCk7CiAgICAgICAgICAgIGlmIChsb25naXR1ZGUgPiBNYXRoLlBJKSB7CiAgICAgICAgICAgICAgbG9uZ2l0dWRlIC09IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGxvbmdpdHVkZTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljNSA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMTAgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFN0ZXJlb2dyYXBoaWMucHJvdG90eXBlLmdldExhdGl0dWRlID0gZnVuY3Rpb24oZWxsaXBzb2lkKSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkKSkgewogICAgICAgICAgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICB9CiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzUubGF0aXR1ZGUgPSB0aGlzLmNvbmZvcm1hbExhdGl0dWRlOwogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM1LmxvbmdpdHVkZSA9IHRoaXMubG9uZ2l0dWRlOwogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM1LmhlaWdodCA9IDA7CiAgICAgICAgY29uc3QgY2FydGVzaWFuMTEgPSB0aGlzLmVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM1LAogICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjEwCiAgICAgICAgKTsKICAgICAgICBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoY2FydGVzaWFuMTEsIHNjcmF0Y2hDYXJ0b2dyYXBoaWM1KTsKICAgICAgICByZXR1cm4gc2NyYXRjaENhcnRvZ3JhcGhpYzUubGF0aXR1ZGU7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVSYXkyID0gbmV3IFJheV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVSYXlEaXJlY3Rpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQcm9qZWN0UG9pbnRPbnRvUGxhbmVDYXJ0ZXNpYW4zMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgU3RlcmVvZ3JhcGhpYy5mcm9tQ2FydGVzaWFuID0gZnVuY3Rpb24oY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiY2FydGVzaWFuIiwgY2FydGVzaWFuMTEpOwogICAgICAgIGNvbnN0IHNpZ24zID0gTWF0aF9kZWZhdWx0LnNpZ25Ob3RaZXJvKGNhcnRlc2lhbjExLnopOwogICAgICAgIGxldCB0YW5nZW50UGxhbmUgPSBTdGVyZW9ncmFwaGljLk5PUlRIX1BPTEVfVEFOR0VOVF9QTEFORTsKICAgICAgICBsZXQgb3JpZ2luID0gU3RlcmVvZ3JhcGhpYy5TT1VUSF9QT0xFOwogICAgICAgIGlmIChzaWduMyA8IDApIHsKICAgICAgICAgIHRhbmdlbnRQbGFuZSA9IFN0ZXJlb2dyYXBoaWMuU09VVEhfUE9MRV9UQU5HRU5UX1BMQU5FOwogICAgICAgICAgb3JpZ2luID0gU3RlcmVvZ3JhcGhpYy5OT1JUSF9QT0xFOwogICAgICAgIH0KICAgICAgICBjb25zdCByYXkgPSBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lUmF5MjsKICAgICAgICByYXkub3JpZ2luID0gdGFuZ2VudFBsYW5lLmVsbGlwc29pZC5zY2FsZVRvR2VvY2VudHJpY1N1cmZhY2UoCiAgICAgICAgICBjYXJ0ZXNpYW4xMSwKICAgICAgICAgIHJheS5vcmlnaW4KICAgICAgICApOwogICAgICAgIHJheS5kaXJlY3Rpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgICByYXkub3JpZ2luLAogICAgICAgICAgb3JpZ2luLAogICAgICAgICAgc2NyYXRjaFByb2plY3RQb2ludE9udG9QbGFuZVJheURpcmVjdGlvbgogICAgICAgICk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShyYXkuZGlyZWN0aW9uLCByYXkuZGlyZWN0aW9uKTsKICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb25Qb2ludCA9IEludGVyc2VjdGlvblRlc3RzX2RlZmF1bHQucmF5UGxhbmUoCiAgICAgICAgICByYXksCiAgICAgICAgICB0YW5nZW50UGxhbmUucGxhbmUsCiAgICAgICAgICBzY3JhdGNoUHJvamVjdFBvaW50T250b1BsYW5lQ2FydGVzaWFuMzIKICAgICAgICApOwogICAgICAgIGNvbnN0IHY0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KGludGVyc2VjdGlvblBvaW50LCBvcmlnaW4sIGludGVyc2VjdGlvblBvaW50KTsKICAgICAgICBjb25zdCB4MiA9IENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodGFuZ2VudFBsYW5lLnhBeGlzLCB2NCk7CiAgICAgICAgY29uc3QgeTIgPSBzaWduMyAqIENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodGFuZ2VudFBsYW5lLnlBeGlzLCB2NCk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBTdGVyZW9ncmFwaGljKG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoeDIsIHkyKSwgdGFuZ2VudFBsYW5lKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnBvc2l0aW9uID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCh4MiwgeTIpOwogICAgICAgIHJlc3VsdC50YW5nZW50UGxhbmUgPSB0YW5nZW50UGxhbmU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgU3RlcmVvZ3JhcGhpYy5mcm9tQ2FydGVzaWFuQXJyYXkgPSBmdW5jdGlvbihjYXJ0ZXNpYW5zLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImNhcnRlc2lhbnMiLCBjYXJ0ZXNpYW5zKTsKICAgICAgICBjb25zdCBsZW5ndGggPSBjYXJ0ZXNpYW5zLmxlbmd0aDsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmVzdWx0Lmxlbmd0aCA9IGxlbmd0aDsKICAgICAgICB9CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgcmVzdWx0W2kyXSA9IFN0ZXJlb2dyYXBoaWMuZnJvbUNhcnRlc2lhbihjYXJ0ZXNpYW5zW2kyXSwgcmVzdWx0W2kyXSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFN0ZXJlb2dyYXBoaWMuY2xvbmUgPSBmdW5jdGlvbihzdGVyZW9ncmFwaGljLCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzdGVyZW9ncmFwaGljKSkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBTdGVyZW9ncmFwaGljKAogICAgICAgICAgICBzdGVyZW9ncmFwaGljLnBvc2l0aW9uLAogICAgICAgICAgICBzdGVyZW9ncmFwaGljLnRhbmdlbnRQbGFuZQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LnBvc2l0aW9uID0gc3RlcmVvZ3JhcGhpYy5wb3NpdGlvbjsKICAgICAgICByZXN1bHQudGFuZ2VudFBsYW5lID0gc3RlcmVvZ3JhcGhpYy50YW5nZW50UGxhbmU7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgU3RlcmVvZ3JhcGhpYy5IQUxGX1VOSVRfU1BIRVJFID0gT2JqZWN0LmZyZWV6ZShuZXcgRWxsaXBzb2lkX2RlZmF1bHQoMC41LCAwLjUsIDAuNSkpOwogICAgICBTdGVyZW9ncmFwaGljLk5PUlRIX1BPTEUgPSBPYmplY3QuZnJlZXplKG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoMCwgMCwgMC41KSk7CiAgICAgIFN0ZXJlb2dyYXBoaWMuU09VVEhfUE9MRSA9IE9iamVjdC5mcmVlemUobmV3IENhcnRlc2lhbjNfZGVmYXVsdCgwLCAwLCAtMC41KSk7CiAgICAgIFN0ZXJlb2dyYXBoaWMuTk9SVEhfUE9MRV9UQU5HRU5UX1BMQU5FID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgRWxsaXBzb2lkVGFuZ2VudFBsYW5lX2RlZmF1bHQoCiAgICAgICAgICBTdGVyZW9ncmFwaGljLk5PUlRIX1BPTEUsCiAgICAgICAgICBTdGVyZW9ncmFwaGljLkhBTEZfVU5JVF9TUEhFUkUKICAgICAgICApCiAgICAgICk7CiAgICAgIFN0ZXJlb2dyYXBoaWMuU09VVEhfUE9MRV9UQU5HRU5UX1BMQU5FID0gT2JqZWN0LmZyZWV6ZSgKICAgICAgICBuZXcgRWxsaXBzb2lkVGFuZ2VudFBsYW5lX2RlZmF1bHQoCiAgICAgICAgICBTdGVyZW9ncmFwaGljLlNPVVRIX1BPTEUsCiAgICAgICAgICBTdGVyZW9ncmFwaGljLkhBTEZfVU5JVF9TUEhFUkUKICAgICAgICApCiAgICAgICk7CiAgICAgIFN0ZXJlb2dyYXBoaWNfZGVmYXVsdCA9IFN0ZXJlb2dyYXBoaWM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Qb2x5Z29uR2VvbWV0cnkuanMKICBmdW5jdGlvbiBhZGp1c3RQb3NIZWlnaHRzRm9yTm9ybWFsKHBvc2l0aW9uLCBwMSwgcDIsIGVsbGlwc29pZCkgewogICAgY29uc3QgY2FydG8xMiA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwb3NpdGlvbiwgc2NyYXRjaENhcnRvMSk7CiAgICBjb25zdCBoZWlnaHQgPSBjYXJ0bzEyLmhlaWdodDsKICAgIGNvbnN0IHAxQ2FydG8gPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMocDEsIHNjcmF0Y2hDYXJ0bzIpOwogICAgcDFDYXJ0by5oZWlnaHQgPSBoZWlnaHQ7CiAgICBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4ocDFDYXJ0bywgcDEpOwogICAgY29uc3QgcDJDYXJ0byA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyhwMiwgc2NyYXRjaENhcnRvMik7CiAgICBwMkNhcnRvLmhlaWdodCA9IGhlaWdodCAtIDEwMDsKICAgIGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbihwMkNhcnRvLCBwMik7CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVBdHRyaWJ1dGVzKG9wdGlvbnMpIHsKICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IG9wdGlvbnMudmVydGV4Rm9ybWF0OwogICAgY29uc3QgZ2VvbWV0cnkgPSBvcHRpb25zLmdlb21ldHJ5OwogICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gb3B0aW9ucy5zaGFkb3dWb2x1bWU7CiAgICBjb25zdCBmbGF0UG9zaXRpb25zID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXM7CiAgICBjb25zdCBmbGF0VGV4Y29vcmRzID0gZGVmaW5lZF9kZWZhdWx0KGdlb21ldHJ5LmF0dHJpYnV0ZXMuc3QpID8gZ2VvbWV0cnkuYXR0cmlidXRlcy5zdC52YWx1ZXMgOiB2b2lkIDA7CiAgICBsZXQgbGVuZ3RoID0gZmxhdFBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCB3YWxsID0gb3B0aW9ucy53YWxsOwogICAgY29uc3QgdG9wID0gb3B0aW9ucy50b3AgfHwgd2FsbDsKICAgIGNvbnN0IGJvdHRvbSA9IG9wdGlvbnMuYm90dG9tIHx8IHdhbGw7CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0IHx8IHZlcnRleEZvcm1hdC5ub3JtYWwgfHwgdmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCB8fCBzaGFkb3dWb2x1bWUpIHsKICAgICAgY29uc3QgYm91bmRpbmdSZWN0YW5nbGUgPSBvcHRpb25zLmJvdW5kaW5nUmVjdGFuZ2xlOwogICAgICBjb25zdCByb3RhdGlvbkF4aXMgPSBvcHRpb25zLnJvdGF0aW9uQXhpczsKICAgICAgY29uc3QgcHJvamVjdFRvMmQgPSBvcHRpb25zLnByb2plY3RUbzJkOwogICAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZDsKICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IG9wdGlvbnMuc3RSb3RhdGlvbjsKICAgICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHQgPSBvcHRpb25zLnBlclBvc2l0aW9uSGVpZ2h0OwogICAgICBjb25zdCBvcmlnaW4gPSBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNPcmlnaW47CiAgICAgIG9yaWdpbi54ID0gYm91bmRpbmdSZWN0YW5nbGUueDsKICAgICAgb3JpZ2luLnkgPSBib3VuZGluZ1JlY3RhbmdsZS55OwogICAgICBjb25zdCB0ZXh0dXJlQ29vcmRpbmF0ZXMgPSB2ZXJ0ZXhGb3JtYXQuc3QgPyBuZXcgRmxvYXQzMkFycmF5KDIgKiAobGVuZ3RoIC8gMykpIDogdm9pZCAwOwogICAgICBsZXQgbm9ybWFsczsKICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICBpZiAocGVyUG9zaXRpb25IZWlnaHQgJiYgdG9wICYmICF3YWxsKSB7CiAgICAgICAgICBub3JtYWxzID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBub3JtYWxzID0gbmV3IEZsb2F0MzJBcnJheShsZW5ndGgpOwogICAgICAgIH0KICAgICAgfQogICAgICBjb25zdCB0YW5nZW50cyA9IHZlcnRleEZvcm1hdC50YW5nZW50ID8gbmV3IEZsb2F0MzJBcnJheShsZW5ndGgpIDogdm9pZCAwOwogICAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgICAgY29uc3QgZXh0cnVkZU5vcm1hbHMgPSBzaGFkb3dWb2x1bWUgPyBuZXcgRmxvYXQzMkFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICAgIGxldCB0ZXh0dXJlQ29vcmRJbmRleCA9IDA7CiAgICAgIGxldCBhdHRySW5kZXggPSAwOwogICAgICBsZXQgbm9ybWFsMiA9IHNjcmF0Y2hOb3JtYWw2OwogICAgICBsZXQgdGFuZ2VudCA9IHNjcmF0Y2hUYW5nZW50NDsKICAgICAgbGV0IGJpdGFuZ2VudCA9IHNjcmF0Y2hCaXRhbmdlbnQ0OwogICAgICBsZXQgcmVjb21wdXRlTm9ybWFsID0gdHJ1ZTsKICAgICAgbGV0IHRleHR1cmVNYXRyaXggPSBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNNYXRyaXgzOwogICAgICBsZXQgdGFuZ2VudFJvdGF0aW9uTWF0cml4ID0gdGFuZ2VudE1hdHJpeFNjcmF0Y2gyOwogICAgICBpZiAoc3RSb3RhdGlvbiAhPT0gMCkgewogICAgICAgIGxldCByb3RhdGlvbiA9IFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKAogICAgICAgICAgcm90YXRpb25BeGlzLAogICAgICAgICAgc3RSb3RhdGlvbiwKICAgICAgICAgIGFwcGVuZFRleHR1cmVDb29yZGluYXRlc1F1YXRlcm5pb24KICAgICAgICApOwogICAgICAgIHRleHR1cmVNYXRyaXggPSBNYXRyaXgzX2RlZmF1bHQuZnJvbVF1YXRlcm5pb24ocm90YXRpb24sIHRleHR1cmVNYXRyaXgpOwogICAgICAgIHJvdGF0aW9uID0gUXVhdGVybmlvbl9kZWZhdWx0LmZyb21BeGlzQW5nbGUoCiAgICAgICAgICByb3RhdGlvbkF4aXMsCiAgICAgICAgICAtc3RSb3RhdGlvbiwKICAgICAgICAgIGFwcGVuZFRleHR1cmVDb29yZGluYXRlc1F1YXRlcm5pb24KICAgICAgICApOwogICAgICAgIHRhbmdlbnRSb3RhdGlvbk1hdHJpeCA9IE1hdHJpeDNfZGVmYXVsdC5mcm9tUXVhdGVybmlvbigKICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgdGFuZ2VudFJvdGF0aW9uTWF0cml4CiAgICAgICAgKTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0ZXh0dXJlTWF0cml4ID0gTWF0cml4M19kZWZhdWx0LmNsb25lKE1hdHJpeDNfZGVmYXVsdC5JREVOVElUWSwgdGV4dHVyZU1hdHJpeCk7CiAgICAgICAgdGFuZ2VudFJvdGF0aW9uTWF0cml4ID0gTWF0cml4M19kZWZhdWx0LmNsb25lKAogICAgICAgICAgTWF0cml4M19kZWZhdWx0LklERU5USVRZLAogICAgICAgICAgdGFuZ2VudFJvdGF0aW9uTWF0cml4CiAgICAgICAgKTsKICAgICAgfQogICAgICBsZXQgYm90dG9tT2Zmc2V0ID0gMDsKICAgICAgbGV0IGJvdHRvbU9mZnNldDIgPSAwOwogICAgICBpZiAodG9wICYmIGJvdHRvbSkgewogICAgICAgIGJvdHRvbU9mZnNldCA9IGxlbmd0aCAvIDI7CiAgICAgICAgYm90dG9tT2Zmc2V0MiA9IGxlbmd0aCAvIDM7CiAgICAgICAgbGVuZ3RoIC89IDI7CiAgICAgIH0KICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgIGNvbnN0IHBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgIGZsYXRQb3NpdGlvbnMsCiAgICAgICAgICBpMiwKICAgICAgICAgIGFwcGVuZFRleHR1cmVDb29yZGluYXRlc0NhcnRlc2lhbjMKICAgICAgICApOwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGZsYXRUZXhjb29yZHMpKSB7CiAgICAgICAgICAgIGxldCBwMiA9IE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKAogICAgICAgICAgICAgIHRleHR1cmVNYXRyaXgsCiAgICAgICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICAgICAgc2NyYXRjaFBvc2l0aW9uMwogICAgICAgICAgICApOwogICAgICAgICAgICBwMiA9IGVsbGlwc29pZC5zY2FsZVRvR2VvZGV0aWNTdXJmYWNlKHAyLCBwMik7CiAgICAgICAgICAgIGNvbnN0IHN0MiA9IHByb2plY3RUbzJkKFtwMl0sIGFwcGVuZFRleHR1cmVDb29yZGluYXRlc0NhcnRlc2lhbjIpWzBdOwogICAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQuc3VidHJhY3Qoc3QyLCBvcmlnaW4sIHN0Mik7CiAgICAgICAgICAgIGNvbnN0IHN0eCA9IE1hdGhfZGVmYXVsdC5jbGFtcChzdDIueCAvIGJvdW5kaW5nUmVjdGFuZ2xlLndpZHRoLCAwLCAxKTsKICAgICAgICAgICAgY29uc3Qgc3R5ID0gTWF0aF9kZWZhdWx0LmNsYW1wKHN0Mi55IC8gYm91bmRpbmdSZWN0YW5nbGUuaGVpZ2h0LCAwLCAxKTsKICAgICAgICAgICAgaWYgKGJvdHRvbSkgewogICAgICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlc1t0ZXh0dXJlQ29vcmRJbmRleCArIGJvdHRvbU9mZnNldDJdID0gc3R4OwogICAgICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlc1t0ZXh0dXJlQ29vcmRJbmRleCArIDEgKyBib3R0b21PZmZzZXQyXSA9IHN0eTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodG9wKSB7CiAgICAgICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3RleHR1cmVDb29yZEluZGV4XSA9IHN0eDsKICAgICAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbdGV4dHVyZUNvb3JkSW5kZXggKyAxXSA9IHN0eTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0ZXh0dXJlQ29vcmRJbmRleCArPSAyOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50IHx8IHNoYWRvd1ZvbHVtZSkgewogICAgICAgICAgY29uc3QgYXR0ckluZGV4MSA9IGF0dHJJbmRleCArIDE7CiAgICAgICAgICBjb25zdCBhdHRySW5kZXgyID0gYXR0ckluZGV4ICsgMjsKICAgICAgICAgIGlmICh3YWxsKSB7CiAgICAgICAgICAgIGlmIChpMiArIDMgPCBsZW5ndGgpIHsKICAgICAgICAgICAgICBjb25zdCBwMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoZmxhdFBvc2l0aW9ucywgaTIgKyAzLCBwMVNjcmF0Y2gzKTsKICAgICAgICAgICAgICBpZiAocmVjb21wdXRlTm9ybWFsKSB7CiAgICAgICAgICAgICAgICBjb25zdCBwMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgICAgICAgIGZsYXRQb3NpdGlvbnMsCiAgICAgICAgICAgICAgICAgIGkyICsgbGVuZ3RoLAogICAgICAgICAgICAgICAgICBwMlNjcmF0Y2gzCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgaWYgKHBlclBvc2l0aW9uSGVpZ2h0KSB7CiAgICAgICAgICAgICAgICAgIGFkanVzdFBvc0hlaWdodHNGb3JOb3JtYWwocG9zaXRpb24sIHAxLCBwMiwgZWxsaXBzb2lkKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwMSwgcG9zaXRpb24sIHAxKTsKICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChwMiwgcG9zaXRpb24sIHAyKTsKICAgICAgICAgICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MocDIsIHAxLCBub3JtYWwyKSwKICAgICAgICAgICAgICAgICAgbm9ybWFsMgogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHJlY29tcHV0ZU5vcm1hbCA9IGZhbHNlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24ocDEsIHBvc2l0aW9uLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjEwKSkgewogICAgICAgICAgICAgICAgcmVjb21wdXRlTm9ybWFsID0gdHJ1ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50IHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgICBiaXRhbmdlbnQgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBiaXRhbmdlbnQpOwogICAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCkgewogICAgICAgICAgICAgICAgdGFuZ2VudCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhiaXRhbmdlbnQsIG5vcm1hbDIsIHRhbmdlbnQpLAogICAgICAgICAgICAgICAgICB0YW5nZW50CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgbm9ybWFsMiA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocG9zaXRpb24sIG5vcm1hbDIpOwogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICAgIGlmIChwZXJQb3NpdGlvbkhlaWdodCkgewogICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc05vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgICAgICAgIG5vcm1hbHMsCiAgICAgICAgICAgICAgICAgIGF0dHJJbmRleCwKICAgICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc05vcm1hbAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9aLAogICAgICAgICAgICAgICAgICBzY3JhdGNoUGVyUG9zTm9ybWFsLAogICAgICAgICAgICAgICAgICBzY3JhdGNoUGVyUG9zVGFuZ2VudAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICAgICAgTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IoCiAgICAgICAgICAgICAgICAgICAgdGFuZ2VudFJvdGF0aW9uTWF0cml4LAogICAgICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50LAogICAgICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50CiAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc0JpdGFuZ2VudCA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKAogICAgICAgICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc05vcm1hbCwKICAgICAgICAgICAgICAgICAgICAgIHNjcmF0Y2hQZXJQb3NUYW5nZW50LAogICAgICAgICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc0JpdGFuZ2VudAogICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgc2NyYXRjaFBlclBvc0JpdGFuZ2VudAogICAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKENhcnRlc2lhbjNfZGVmYXVsdC5VTklUX1osIG5vcm1hbDIsIHRhbmdlbnQpOwogICAgICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IodGFuZ2VudFJvdGF0aW9uTWF0cml4LCB0YW5nZW50LCB0YW5nZW50KSwKICAgICAgICAgICAgICAgIHRhbmdlbnQKICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICAgICAgICBiaXRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Mobm9ybWFsMiwgdGFuZ2VudCwgYml0YW5nZW50KSwKICAgICAgICAgICAgICAgICAgYml0YW5nZW50CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgICAgaWYgKG9wdGlvbnMud2FsbCkgewogICAgICAgICAgICAgIG5vcm1hbHNbYXR0ckluZGV4ICsgYm90dG9tT2Zmc2V0XSA9IG5vcm1hbDIueDsKICAgICAgICAgICAgICBub3JtYWxzW2F0dHJJbmRleDEgKyBib3R0b21PZmZzZXRdID0gbm9ybWFsMi55OwogICAgICAgICAgICAgIG5vcm1hbHNbYXR0ckluZGV4MiArIGJvdHRvbU9mZnNldF0gPSBub3JtYWwyLno7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoYm90dG9tKSB7CiAgICAgICAgICAgICAgbm9ybWFsc1thdHRySW5kZXggKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIueDsKICAgICAgICAgICAgICBub3JtYWxzW2F0dHJJbmRleDEgKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIueTsKICAgICAgICAgICAgICBub3JtYWxzW2F0dHJJbmRleDIgKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIuejsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodG9wICYmICFwZXJQb3NpdGlvbkhlaWdodCB8fCB3YWxsKSB7CiAgICAgICAgICAgICAgbm9ybWFsc1thdHRySW5kZXhdID0gbm9ybWFsMi54OwogICAgICAgICAgICAgIG5vcm1hbHNbYXR0ckluZGV4MV0gPSBub3JtYWwyLnk7CiAgICAgICAgICAgICAgbm9ybWFsc1thdHRySW5kZXgyXSA9IG5vcm1hbDIuejsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICAgICAgICBpZiAod2FsbCkgewogICAgICAgICAgICAgIG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBub3JtYWwyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBleHRydWRlTm9ybWFsc1thdHRySW5kZXggKyBib3R0b21PZmZzZXRdID0gLW5vcm1hbDIueDsKICAgICAgICAgICAgZXh0cnVkZU5vcm1hbHNbYXR0ckluZGV4MSArIGJvdHRvbU9mZnNldF0gPSAtbm9ybWFsMi55OwogICAgICAgICAgICBleHRydWRlTm9ybWFsc1thdHRySW5kZXgyICsgYm90dG9tT2Zmc2V0XSA9IC1ub3JtYWwyLno7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgaWYgKG9wdGlvbnMud2FsbCkgewogICAgICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleCArIGJvdHRvbU9mZnNldF0gPSB0YW5nZW50Lng7CiAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4MSArIGJvdHRvbU9mZnNldF0gPSB0YW5nZW50Lnk7CiAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4MiArIGJvdHRvbU9mZnNldF0gPSB0YW5nZW50Lno7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoYm90dG9tKSB7CiAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4ICsgYm90dG9tT2Zmc2V0XSA9IC10YW5nZW50Lng7CiAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4MSArIGJvdHRvbU9mZnNldF0gPSAtdGFuZ2VudC55OwogICAgICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleDIgKyBib3R0b21PZmZzZXRdID0gLXRhbmdlbnQuejsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodG9wKSB7CiAgICAgICAgICAgICAgaWYgKHBlclBvc2l0aW9uSGVpZ2h0KSB7CiAgICAgICAgICAgICAgICB0YW5nZW50c1thdHRySW5kZXhdID0gc2NyYXRjaFBlclBvc1RhbmdlbnQueDsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleDFdID0gc2NyYXRjaFBlclBvc1RhbmdlbnQueTsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleDJdID0gc2NyYXRjaFBlclBvc1RhbmdlbnQuejsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4XSA9IHRhbmdlbnQueDsKICAgICAgICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleDFdID0gdGFuZ2VudC55OwogICAgICAgICAgICAgICAgdGFuZ2VudHNbYXR0ckluZGV4Ml0gPSB0YW5nZW50Lno7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICBpZiAoYm90dG9tKSB7CiAgICAgICAgICAgICAgYml0YW5nZW50c1thdHRySW5kZXggKyBib3R0b21PZmZzZXRdID0gYml0YW5nZW50Lng7CiAgICAgICAgICAgICAgYml0YW5nZW50c1thdHRySW5kZXgxICsgYm90dG9tT2Zmc2V0XSA9IGJpdGFuZ2VudC55OwogICAgICAgICAgICAgIGJpdGFuZ2VudHNbYXR0ckluZGV4MiArIGJvdHRvbU9mZnNldF0gPSBiaXRhbmdlbnQuejsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodG9wKSB7CiAgICAgICAgICAgICAgaWYgKHBlclBvc2l0aW9uSGVpZ2h0KSB7CiAgICAgICAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleF0gPSBzY3JhdGNoUGVyUG9zQml0YW5nZW50Lng7CiAgICAgICAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleDFdID0gc2NyYXRjaFBlclBvc0JpdGFuZ2VudC55OwogICAgICAgICAgICAgICAgYml0YW5nZW50c1thdHRySW5kZXgyXSA9IHNjcmF0Y2hQZXJQb3NCaXRhbmdlbnQuejsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgYml0YW5nZW50c1thdHRySW5kZXhdID0gYml0YW5nZW50Lng7CiAgICAgICAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleDFdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleDJdID0gYml0YW5nZW50Lno7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBhdHRySW5kZXggKz0gMzsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCAmJiAhZGVmaW5lZF9kZWZhdWx0KGZsYXRUZXhjb29yZHMpKSB7CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMiwKICAgICAgICAgIHZhbHVlczogdGV4dHVyZUNvb3JkaW5hdGVzCiAgICAgICAgfSk7CiAgICAgIH0KICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLm5vcm1hbCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgIHZhbHVlczogbm9ybWFscwogICAgICAgIH0pOwogICAgICB9CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCkgewogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMudGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgIHZhbHVlczogdGFuZ2VudHMKICAgICAgICB9KTsKICAgICAgfQogICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgfSk7CiAgICAgIH0KICAgICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMuZXh0cnVkZURpcmVjdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgIHZhbHVlczogZXh0cnVkZU5vcm1hbHMKICAgICAgICB9KTsKICAgICAgfQogICAgfQogICAgaWYgKG9wdGlvbnMuZXh0cnVkZSAmJiBkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgIGNvbnN0IHNpemUgPSBmbGF0UG9zaXRpb25zLmxlbmd0aCAvIDM7CiAgICAgIGxldCBvZmZzZXRBdHRyaWJ1dGUgPSBuZXcgVWludDhBcnJheShzaXplKTsKICAgICAgaWYgKG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICAgIGlmICh0b3AgJiYgYm90dG9tIHx8IHdhbGwpIHsKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKDEsIDAsIHNpemUgLyAyKTsKICAgICAgICB9IGVsc2UgaWYgKHRvcCkgewogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlLmZpbGwoMSk7CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIGNvbnN0IG9mZnNldFZhbHVlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICB2YWx1ZXM6IG9mZnNldEF0dHJpYnV0ZQogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBnZW9tZXRyeTsKICB9CiAgZnVuY3Rpb24gY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zRXh0cnVkZWQoZWxsaXBzb2lkLCBwb2x5Z29uMiwgdGV4dHVyZUNvb3JkaW5hdGVzLCBncmFudWxhcml0eSwgaGllcmFyY2h5LCBwZXJQb3NpdGlvbkhlaWdodCwgY2xvc2VUb3AsIGNsb3NlQm90dG9tLCB2ZXJ0ZXhGb3JtYXQsIGFyY1R5cGUpIHsKICAgIGNvbnN0IGdlb3MgPSB7CiAgICAgIHdhbGxzOiBbXQogICAgfTsKICAgIGxldCBpMjsKICAgIGlmIChjbG9zZVRvcCB8fCBjbG9zZUJvdHRvbSkgewogICAgICBjb25zdCB0b3BHZW8gPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zKAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICBwb2x5Z29uMiwKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXMsCiAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgdmVydGV4Rm9ybWF0LAogICAgICAgIGFyY1R5cGUKICAgICAgKTsKICAgICAgY29uc3QgZWRnZVBvaW50cyA9IHRvcEdlby5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgICAgY29uc3QgaW5kaWNlcyA9IHRvcEdlby5pbmRpY2VzOwogICAgICBsZXQgbnVtUG9zaXRpb25zOwogICAgICBsZXQgbmV3SW5kaWNlczsKICAgICAgaWYgKGNsb3NlVG9wICYmIGNsb3NlQm90dG9tKSB7CiAgICAgICAgY29uc3QgdG9wQm90dG9tUG9zaXRpb25zID0gZWRnZVBvaW50cy5jb25jYXQoZWRnZVBvaW50cyk7CiAgICAgICAgbnVtUG9zaXRpb25zID0gdG9wQm90dG9tUG9zaXRpb25zLmxlbmd0aCAvIDM7CiAgICAgICAgbmV3SW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICAgICAgbnVtUG9zaXRpb25zLAogICAgICAgICAgaW5kaWNlcy5sZW5ndGggKiAyCiAgICAgICAgKTsKICAgICAgICBuZXdJbmRpY2VzLnNldChpbmRpY2VzKTsKICAgICAgICBjb25zdCBpbGVuZ3RoID0gaW5kaWNlcy5sZW5ndGg7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gbnVtUG9zaXRpb25zIC8gMjsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBpbGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgICAgICBjb25zdCBpMCA9IG5ld0luZGljZXNbaTJdICsgbGVuZ3RoOwogICAgICAgICAgY29uc3QgaTEgPSBuZXdJbmRpY2VzW2kyICsgMV0gKyBsZW5ndGg7CiAgICAgICAgICBjb25zdCBpMjIgPSBuZXdJbmRpY2VzW2kyICsgMl0gKyBsZW5ndGg7CiAgICAgICAgICBuZXdJbmRpY2VzW2kyICsgaWxlbmd0aF0gPSBpMjI7CiAgICAgICAgICBuZXdJbmRpY2VzW2kyICsgMSArIGlsZW5ndGhdID0gaTE7CiAgICAgICAgICBuZXdJbmRpY2VzW2kyICsgMiArIGlsZW5ndGhdID0gaTA7CiAgICAgICAgfQogICAgICAgIHRvcEdlby5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IHRvcEJvdHRvbVBvc2l0aW9uczsKICAgICAgICBpZiAocGVyUG9zaXRpb25IZWlnaHQgJiYgdmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICAgICAgY29uc3Qgbm9ybWFscyA9IHRvcEdlby5hdHRyaWJ1dGVzLm5vcm1hbC52YWx1ZXM7CiAgICAgICAgICB0b3BHZW8uYXR0cmlidXRlcy5ub3JtYWwudmFsdWVzID0gbmV3IEZsb2F0MzJBcnJheSgKICAgICAgICAgICAgdG9wQm90dG9tUG9zaXRpb25zLmxlbmd0aAogICAgICAgICAgKTsKICAgICAgICAgIHRvcEdlby5hdHRyaWJ1dGVzLm5vcm1hbC52YWx1ZXMuc2V0KG5vcm1hbHMpOwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnN0ICYmIGRlZmluZWRfZGVmYXVsdCh0ZXh0dXJlQ29vcmRpbmF0ZXMpKSB7CiAgICAgICAgICBjb25zdCB0ZXhjb29yZHMgPSB0b3BHZW8uYXR0cmlidXRlcy5zdC52YWx1ZXM7CiAgICAgICAgICB0b3BHZW8uYXR0cmlidXRlcy5zdC52YWx1ZXMgPSBuZXcgRmxvYXQzMkFycmF5KG51bVBvc2l0aW9ucyAqIDIpOwogICAgICAgICAgdG9wR2VvLmF0dHJpYnV0ZXMuc3QudmFsdWVzID0gdGV4Y29vcmRzLmNvbmNhdCh0ZXhjb29yZHMpOwogICAgICAgIH0KICAgICAgICB0b3BHZW8uaW5kaWNlcyA9IG5ld0luZGljZXM7CiAgICAgIH0gZWxzZSBpZiAoY2xvc2VCb3R0b20pIHsKICAgICAgICBudW1Qb3NpdGlvbnMgPSBlZGdlUG9pbnRzLmxlbmd0aCAvIDM7CiAgICAgICAgbmV3SW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KG51bVBvc2l0aW9ucywgaW5kaWNlcy5sZW5ndGgpOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGluZGljZXMubGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgICAgICBuZXdJbmRpY2VzW2kyXSA9IGluZGljZXNbaTIgKyAyXTsKICAgICAgICAgIG5ld0luZGljZXNbaTIgKyAxXSA9IGluZGljZXNbaTIgKyAxXTsKICAgICAgICAgIG5ld0luZGljZXNbaTIgKyAyXSA9IGluZGljZXNbaTJdOwogICAgICAgIH0KICAgICAgICB0b3BHZW8uaW5kaWNlcyA9IG5ld0luZGljZXM7CiAgICAgIH0KICAgICAgZ2Vvcy50b3BBbmRCb3R0b20gPSBuZXcgR2VvbWV0cnlJbnN0YW5jZV9kZWZhdWx0KHsKICAgICAgICBnZW9tZXRyeTogdG9wR2VvCiAgICAgIH0pOwogICAgfQogICAgbGV0IG91dGVyUmluZyA9IGhpZXJhcmNoeS5vdXRlclJpbmc7CiAgICBjb25zdCB0YW5nZW50UGxhbmUgPSBFbGxpcHNvaWRUYW5nZW50UGxhbmVfZGVmYXVsdC5mcm9tUG9pbnRzKG91dGVyUmluZywgZWxsaXBzb2lkKTsKICAgIGxldCBwb3NpdGlvbnMyRCA9IHRhbmdlbnRQbGFuZS5wcm9qZWN0UG9pbnRzT250b1BsYW5lKAogICAgICBvdXRlclJpbmcsCiAgICAgIGNyZWF0ZUdlb21ldHJ5RnJvbVBvc2l0aW9uc0V4dHJ1ZGVkUG9zaXRpb25zCiAgICApOwogICAgbGV0IHdpbmRpbmdPcmRlciA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LmNvbXB1dGVXaW5kaW5nT3JkZXIyRChwb3NpdGlvbnMyRCk7CiAgICBpZiAod2luZGluZ09yZGVyID09PSBXaW5kaW5nT3JkZXJfZGVmYXVsdC5DTE9DS1dJU0UpIHsKICAgICAgb3V0ZXJSaW5nID0gb3V0ZXJSaW5nLnNsaWNlKCkucmV2ZXJzZSgpOwogICAgfQogICAgbGV0IHdhbGxHZW8gPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVdhbGxHZW9tZXRyeSgKICAgICAgb3V0ZXJSaW5nLAogICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXMsCiAgICAgIGVsbGlwc29pZCwKICAgICAgZ3JhbnVsYXJpdHksCiAgICAgIHBlclBvc2l0aW9uSGVpZ2h0LAogICAgICBhcmNUeXBlCiAgICApOwogICAgZ2Vvcy53YWxscy5wdXNoKAogICAgICBuZXcgR2VvbWV0cnlJbnN0YW5jZV9kZWZhdWx0KHsKICAgICAgICBnZW9tZXRyeTogd2FsbEdlbwogICAgICB9KQogICAgKTsKICAgIGNvbnN0IGhvbGVzID0gaGllcmFyY2h5LmhvbGVzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgaG9sZXMubGVuZ3RoOyBpMisrKSB7CiAgICAgIGxldCBob2xlID0gaG9sZXNbaTJdOwogICAgICBwb3NpdGlvbnMyRCA9IHRhbmdlbnRQbGFuZS5wcm9qZWN0UG9pbnRzT250b1BsYW5lKAogICAgICAgIGhvbGUsCiAgICAgICAgY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zRXh0cnVkZWRQb3NpdGlvbnMKICAgICAgKTsKICAgICAgd2luZGluZ09yZGVyID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuY29tcHV0ZVdpbmRpbmdPcmRlcjJEKHBvc2l0aW9uczJEKTsKICAgICAgaWYgKHdpbmRpbmdPcmRlciA9PT0gV2luZGluZ09yZGVyX2RlZmF1bHQuQ09VTlRFUl9DTE9DS1dJU0UpIHsKICAgICAgICBob2xlID0gaG9sZS5zbGljZSgpLnJldmVyc2UoKTsKICAgICAgfQogICAgICB3YWxsR2VvID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVXYWxsR2VvbWV0cnkoCiAgICAgICAgaG9sZSwKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXMsCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgIHBlclBvc2l0aW9uSGVpZ2h0LAogICAgICAgIGFyY1R5cGUKICAgICAgKTsKICAgICAgZ2Vvcy53YWxscy5wdXNoKAogICAgICAgIG5ldyBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQoewogICAgICAgICAgZ2VvbWV0cnk6IHdhbGxHZW8KICAgICAgICB9KQogICAgICApOwogICAgfQogICAgcmV0dXJuIGdlb3M7CiAgfQogIGZ1bmN0aW9uIFBvbHlnb25HZW9tZXRyeShvcHRpb25zKSB7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMiLCBvcHRpb25zKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5wb2x5Z29uSGllcmFyY2h5Iiwgb3B0aW9ucy5wb2x5Z29uSGllcmFyY2h5KTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5wZXJQb3NpdGlvbkhlaWdodCkgJiYgb3B0aW9ucy5wZXJQb3NpdGlvbkhlaWdodCAmJiBkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5oZWlnaHQpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJDYW5ub3QgdXNlIGJvdGggb3B0aW9ucy5wZXJQb3NpdGlvbkhlaWdodCBhbmQgb3B0aW9ucy5oZWlnaHQiCiAgICAgICk7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuYXJjVHlwZSkgJiYgb3B0aW9ucy5hcmNUeXBlICE9PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMgJiYgb3B0aW9ucy5hcmNUeXBlICE9PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIkludmFsaWQgYXJjVHlwZS4gVmFsaWQgb3B0aW9ucyBhcmUgQXJjVHlwZS5HRU9ERVNJQyBhbmQgQXJjVHlwZS5SSFVNQi4iCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gb3B0aW9ucy5wb2x5Z29uSGllcmFyY2h5OwogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIGNvbnN0IGVsbGlwc29pZCA9IG9wdGlvbnMuZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgIGNvbnN0IHN0Um90YXRpb24gPSBvcHRpb25zLnN0Um90YXRpb24gPz8gMDsKICAgIGNvbnN0IHRleHR1cmVDb29yZGluYXRlcyA9IG9wdGlvbnMudGV4dHVyZUNvb3JkaW5hdGVzOwogICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHQgPSBvcHRpb25zLnBlclBvc2l0aW9uSGVpZ2h0ID8/IGZhbHNlOwogICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlID0gcGVyUG9zaXRpb25IZWlnaHQgJiYgZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQpOwogICAgbGV0IGhlaWdodCA9IG9wdGlvbnMuaGVpZ2h0ID8/IDA7CiAgICBsZXQgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0ID8/IGhlaWdodDsKICAgIGlmICghcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlKSB7CiAgICAgIGNvbnN0IGgyID0gTWF0aC5tYXgoaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICAgIGV4dHJ1ZGVkSGVpZ2h0ID0gTWF0aC5taW4oaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICAgIGhlaWdodCA9IGgyOwogICAgfQogICAgdGhpcy5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0KTsKICAgIHRoaXMuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgdGhpcy5fc3RSb3RhdGlvbiA9IHN0Um90YXRpb247CiAgICB0aGlzLl9oZWlnaHQgPSBoZWlnaHQ7CiAgICB0aGlzLl9leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgdGhpcy5fY2xvc2VUb3AgPSBvcHRpb25zLmNsb3NlVG9wID8/IHRydWU7CiAgICB0aGlzLl9jbG9zZUJvdHRvbSA9IG9wdGlvbnMuY2xvc2VCb3R0b20gPz8gdHJ1ZTsKICAgIHRoaXMuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgdGhpcy5fcGVyUG9zaXRpb25IZWlnaHQgPSBwZXJQb3NpdGlvbkhlaWdodDsKICAgIHRoaXMuX3BlclBvc2l0aW9uSGVpZ2h0RXh0cnVkZSA9IHBlclBvc2l0aW9uSGVpZ2h0RXh0cnVkZTsKICAgIHRoaXMuX3NoYWRvd1ZvbHVtZSA9IG9wdGlvbnMuc2hhZG93Vm9sdW1lID8/IGZhbHNlOwogICAgdGhpcy5fd29ya2VyTmFtZSA9ICJjcmVhdGVQb2x5Z29uR2VvbWV0cnkiOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl9hcmNUeXBlID0gb3B0aW9ucy5hcmNUeXBlID8/IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQzsKICAgIHRoaXMuX3JlY3RhbmdsZSA9IHZvaWQgMDsKICAgIHRoaXMuX3RleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHMgPSB2b2lkIDA7CiAgICB0aGlzLl90ZXh0dXJlQ29vcmRpbmF0ZXMgPSB0ZXh0dXJlQ29vcmRpbmF0ZXM7CiAgICB0aGlzLnBhY2tlZExlbmd0aCA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlSGllcmFyY2h5UGFja2VkTGVuZ3RoKAogICAgICBwb2x5Z29uSGllcmFyY2h5LAogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQKICAgICkgKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAodGV4dHVyZUNvb3JkaW5hdGVzID8gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVIaWVyYXJjaHlQYWNrZWRMZW5ndGgoCiAgICAgIHRleHR1cmVDb29yZGluYXRlcywKICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0CiAgICApIDogMSkgKyAxMjsKICB9CiAgZnVuY3Rpb24gZXhwYW5kUmVjdGFuZ2xlKHBvbGFyLCBsYXN0UG9sYXIsIGVsbGlwc29pZCwgYXJjVHlwZSwgcG9seWdvbjIsIHJlc3VsdCkgewogICAgY29uc3QgbG9uZ2l0dWRlID0gcG9sYXIubG9uZ2l0dWRlOwogICAgY29uc3QgbG9uQWRqdXN0ZWQgPSBsb25naXR1ZGUgPj0gMCA/IGxvbmdpdHVkZSA6IGxvbmdpdHVkZSArIE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICBwb2x5Z29uMi53ZXN0T3ZlcklkbCA9IE1hdGgubWluKHBvbHlnb24yLndlc3RPdmVySWRsLCBsb25BZGp1c3RlZCk7CiAgICBwb2x5Z29uMi5lYXN0T3ZlcklkbCA9IE1hdGgubWF4KHBvbHlnb24yLmVhc3RPdmVySWRsLCBsb25BZGp1c3RlZCk7CiAgICByZXN1bHQud2VzdCA9IE1hdGgubWluKHJlc3VsdC53ZXN0LCBsb25naXR1ZGUpOwogICAgcmVzdWx0LmVhc3QgPSBNYXRoLm1heChyZXN1bHQuZWFzdCwgbG9uZ2l0dWRlKTsKICAgIGNvbnN0IGxhdGl0dWRlID0gcG9sYXIuZ2V0TGF0aXR1ZGUoZWxsaXBzb2lkKTsKICAgIGxldCBzZWdtZW50TGF0aXR1ZGUgPSBsYXRpdHVkZTsKICAgIHJlc3VsdC5zb3V0aCA9IE1hdGgubWluKHJlc3VsdC5zb3V0aCwgbGF0aXR1ZGUpOwogICAgcmVzdWx0Lm5vcnRoID0gTWF0aC5tYXgocmVzdWx0Lm5vcnRoLCBsYXRpdHVkZSk7CiAgICBpZiAoYXJjVHlwZSAhPT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgIGNvbnN0IHNlZ21lbnQgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgICAgbGFzdFBvbGFyLnBvc2l0aW9uLAogICAgICAgIHBvbGFyLnBvc2l0aW9uLAogICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4wMgogICAgICApOwogICAgICBjb25zdCB0MiA9IENhcnRlc2lhbjJfZGVmYXVsdC5kb3QobGFzdFBvbGFyLnBvc2l0aW9uLCBzZWdtZW50KSAvIENhcnRlc2lhbjJfZGVmYXVsdC5kb3Qoc2VnbWVudCwgc2VnbWVudCk7CiAgICAgIGlmICh0MiA+IDAgJiYgdDIgPCAxKSB7CiAgICAgICAgY29uc3QgcHJvamVjdGVkID0gQ2FydGVzaWFuMl9kZWZhdWx0LmFkZCgKICAgICAgICAgIGxhc3RQb2xhci5wb3NpdGlvbiwKICAgICAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKHNlZ21lbnQsIC10Miwgc2VnbWVudCksCiAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuMTgKICAgICAgICApOwogICAgICAgIGNvbnN0IGNsb3Nlc3RQb2xhciA9IFN0ZXJlb2dyYXBoaWNfZGVmYXVsdC5jbG9uZShsYXN0UG9sYXIsIHNjcmF0Y2hQb2xhckNsb3Nlc3QpOwogICAgICAgIGNsb3Nlc3RQb2xhci5wb3NpdGlvbiA9IHByb2plY3RlZDsKICAgICAgICBjb25zdCBhZGp1c3RlZExhdGl0dWRlID0gY2xvc2VzdFBvbGFyLmdldExhdGl0dWRlKGVsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0LnNvdXRoID0gTWF0aC5taW4ocmVzdWx0LnNvdXRoLCBhZGp1c3RlZExhdGl0dWRlKTsKICAgICAgICByZXN1bHQubm9ydGggPSBNYXRoLm1heChyZXN1bHQubm9ydGgsIGFkanVzdGVkTGF0aXR1ZGUpOwogICAgICAgIGlmIChNYXRoLmFicyhsYXRpdHVkZSkgPiBNYXRoLmFicyhhZGp1c3RlZExhdGl0dWRlKSkgewogICAgICAgICAgc2VnbWVudExhdGl0dWRlID0gYWRqdXN0ZWRMYXRpdHVkZTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IGRpcmVjdGlvbjIgPSBsYXN0UG9sYXIueCAqIHBvbGFyLnkgLSBwb2xhci54ICogbGFzdFBvbGFyLnk7CiAgICBsZXQgYW5nbGUgPSBNYXRoLnNpZ24oZGlyZWN0aW9uMik7CiAgICBpZiAoYW5nbGUgIT09IDApIHsKICAgICAgYW5nbGUgKj0gQ2FydGVzaWFuMl9kZWZhdWx0LmFuZ2xlQmV0d2VlbihsYXN0UG9sYXIucG9zaXRpb24sIHBvbGFyLnBvc2l0aW9uKTsKICAgIH0KICAgIGlmIChzZWdtZW50TGF0aXR1ZGUgPj0gMCkgewogICAgICBwb2x5Z29uMi5ub3J0aEFuZ2xlICs9IGFuZ2xlOwogICAgfQogICAgaWYgKHNlZ21lbnRMYXRpdHVkZSA8PSAwKSB7CiAgICAgIHBvbHlnb24yLnNvdXRoQW5nbGUgKz0gYW5nbGU7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGdldFRhbmdlbnRQbGFuZShyZWN0YW5nbGUsIHBvc2l0aW9ucywgZWxsaXBzb2lkKSB7CiAgICBpZiAocmVjdGFuZ2xlLmhlaWdodCA+PSBNYXRoX2RlZmF1bHQuUEkgfHwgcmVjdGFuZ2xlLndpZHRoID49IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICBjb25zdCBwb2xhciA9IFN0ZXJlb2dyYXBoaWNfZGVmYXVsdC5mcm9tQ2FydGVzaWFuKAogICAgICAgIHBvc2l0aW9uc1swXSwKICAgICAgICBzY3JhdGNoUG9sYXJGb3JQbGFuZQogICAgICApOwogICAgICByZXR1cm4gcG9sYXIudGFuZ2VudFBsYW5lOwogICAgfQogICAgcmV0dXJuIEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0LmZyb21Qb2ludHMocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogIH0KICBmdW5jdGlvbiBjcmVhdGVQcm9qZWN0VG8yZChyZWN0YW5nbGUsIG91dGVyUG9zaXRpb25zLCBlbGxpcHNvaWQpIHsKICAgIHJldHVybiAocG9zaXRpb25zLCByZXN1bHRzKSA9PiB7CiAgICAgIGlmIChyZWN0YW5nbGUuaGVpZ2h0ID49IE1hdGhfZGVmYXVsdC5QSSB8fCByZWN0YW5nbGUud2lkdGggPj0gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgaWYgKHJlY3RhbmdsZS5zb3V0aCA8IDAgJiYgcmVjdGFuZ2xlLm5vcnRoID4gMCkgewogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0cykpIHsKICAgICAgICAgICAgcmVzdWx0cyA9IFtdOwogICAgICAgICAgfQogICAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvc2l0aW9ucy5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNDeWxsaW5kcmljYWwKICAgICAgICAgICAgKTsKICAgICAgICAgICAgcmVzdWx0c1tpMl0gPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KAogICAgICAgICAgICAgIGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlIC8gTWF0aF9kZWZhdWx0LlBJLAogICAgICAgICAgICAgIGNhcnRvZ3JhcGhpYzIubGF0aXR1ZGUgLyBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08KICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdHMubGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgIHJldHVybiByZXN1bHRzOwogICAgICAgIH0KICAgICAgICByZXR1cm4gU3RlcmVvZ3JhcGhpY19kZWZhdWx0LmZyb21DYXJ0ZXNpYW5BcnJheShwb3NpdGlvbnMsIHJlc3VsdHMpOwogICAgICB9CiAgICAgIGNvbnN0IHRhbmdlbnRQbGFuZSA9IEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0LmZyb21Qb2ludHMoCiAgICAgICAgb3V0ZXJQb3NpdGlvbnMsCiAgICAgICAgZWxsaXBzb2lkCiAgICAgICk7CiAgICAgIHJldHVybiB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50c09udG9QbGFuZShwb3NpdGlvbnMsIHJlc3VsdHMpOwogICAgfTsKICB9CiAgZnVuY3Rpb24gY3JlYXRlUHJvamVjdFBvc2l0aW9uVG8yZChyZWN0YW5nbGUsIG91dGVyUmluZywgZWxsaXBzb2lkKSB7CiAgICBpZiAocmVjdGFuZ2xlLmhlaWdodCA+PSBNYXRoX2RlZmF1bHQuUEkgfHwgcmVjdGFuZ2xlLndpZHRoID49IE1hdGhfZGVmYXVsdC5QSSkgewogICAgICByZXR1cm4gKHBvc2l0aW9uLCByZXN1bHQpID0+IHsKICAgICAgICBpZiAocmVjdGFuZ2xlLnNvdXRoIDwgMCAmJiByZWN0YW5nbGUubm9ydGggPiAwKSB7CiAgICAgICAgICBjb25zdCBjYXJ0b2dyYXBoaWMyID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY0N5bGxpbmRyaWNhbAogICAgICAgICAgKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnggPSBjYXJ0b2dyYXBoaWMyLmxvbmdpdHVkZSAvIE1hdGhfZGVmYXVsdC5QSTsKICAgICAgICAgIHJlc3VsdC55ID0gY2FydG9ncmFwaGljMi5sYXRpdHVkZSAvIE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIHJldHVybiBTdGVyZW9ncmFwaGljX2RlZmF1bHQuZnJvbUNhcnRlc2lhbihwb3NpdGlvbiwgcmVzdWx0KTsKICAgICAgfTsKICAgIH0KICAgIGNvbnN0IHRhbmdlbnRQbGFuZSA9IEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0LmZyb21Qb2ludHMob3V0ZXJSaW5nLCBlbGxpcHNvaWQpOwogICAgcmV0dXJuIChwb3NpdGlvbiwgcmVzdWx0KSA9PiB7CiAgICAgIHJldHVybiB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50c09udG9QbGFuZShwb3NpdGlvbiwgcmVzdWx0KTsKICAgIH07CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZVNwbGl0UG9seWdvbnMocmVjdGFuZ2xlLCBlbGxpcHNvaWQsIGFyY1R5cGUsIHBlclBvc2l0aW9uSGVpZ2h0KSB7CiAgICByZXR1cm4gKHBvbHlnb25zLCByZXN1bHRzKSA9PiB7CiAgICAgIGlmICghcGVyUG9zaXRpb25IZWlnaHQgJiYgKHJlY3RhbmdsZS5oZWlnaHQgPj0gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIHx8IHJlY3RhbmdsZS53aWR0aCA+PSAyICogTWF0aF9kZWZhdWx0LlBJX09WRVJfVEhSRUUpKSB7CiAgICAgICAgcmV0dXJuIFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5zcGxpdFBvbHlnb25zT25FcXVhdG9yKAogICAgICAgICAgcG9seWdvbnMsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBhcmNUeXBlLAogICAgICAgICAgcmVzdWx0cwogICAgICAgICk7CiAgICAgIH0KICAgICAgcmV0dXJuIHBvbHlnb25zOwogICAgfTsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZUJvdW5kaW5nUmVjdGFuZ2xlKG91dGVyUmluZywgcmVjdGFuZ2xlLCBlbGxpcHNvaWQsIHN0Um90YXRpb24pIHsKICAgIGlmIChyZWN0YW5nbGUuaGVpZ2h0ID49IE1hdGhfZGVmYXVsdC5QSSB8fCByZWN0YW5nbGUud2lkdGggPj0gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgIHJldHVybiBCb3VuZGluZ1JlY3RhbmdsZV9kZWZhdWx0LmZyb21SZWN0YW5nbGUoCiAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgIHZvaWQgMCwKICAgICAgICBzY3JhdGNoQm91bmRpbmdSZWN0YW5nbGUKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IG91dGVyUG9zaXRpb25zID0gb3V0ZXJSaW5nOwogICAgY29uc3QgdGFuZ2VudFBsYW5lID0gRWxsaXBzb2lkVGFuZ2VudFBsYW5lX2RlZmF1bHQuZnJvbVBvaW50cygKICAgICAgb3V0ZXJQb3NpdGlvbnMsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIHJldHVybiBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZUJvdW5kaW5nUmVjdGFuZ2xlKAogICAgICB0YW5nZW50UGxhbmUucGxhbmUubm9ybWFsLAogICAgICB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50T250b1BsYW5lLmJpbmQodGFuZ2VudFBsYW5lKSwKICAgICAgb3V0ZXJQb3NpdGlvbnMsCiAgICAgIHN0Um90YXRpb24sCiAgICAgIHNjcmF0Y2hCb3VuZGluZ1JlY3RhbmdsZQogICAgKTsKICB9CiAgZnVuY3Rpb24gdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czIocG9seWdvbkdlb21ldHJ5KSB7CiAgICBjb25zdCBzdFJvdGF0aW9uID0gLXBvbHlnb25HZW9tZXRyeS5fc3RSb3RhdGlvbjsKICAgIGlmIChzdFJvdGF0aW9uID09PSAwKSB7CiAgICAgIHJldHVybiBbMCwgMCwgMCwgMSwgMSwgMF07CiAgICB9CiAgICBjb25zdCBlbGxpcHNvaWQgPSBwb2x5Z29uR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IHBvbHlnb25HZW9tZXRyeS5fcG9seWdvbkhpZXJhcmNoeS5wb3NpdGlvbnM7CiAgICBjb25zdCBib3VuZGluZ1JlY3RhbmdsZSA9IHBvbHlnb25HZW9tZXRyeS5yZWN0YW5nbGU7CiAgICByZXR1cm4gR2VvbWV0cnlfZGVmYXVsdC5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cygKICAgICAgcG9zaXRpb25zLAogICAgICBzdFJvdGF0aW9uLAogICAgICBlbGxpcHNvaWQsCiAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlCiAgICApOwogIH0KICB2YXIgc2NyYXRjaENhcnRvMSwgc2NyYXRjaENhcnRvMiwgc2NyYXRjaEJvdW5kaW5nUmVjdGFuZ2xlLCBzY3JhdGNoUG9zaXRpb24zLCBzY3JhdGNoTm9ybWFsNiwgc2NyYXRjaFRhbmdlbnQ0LCBzY3JhdGNoQml0YW5nZW50NCwgcDFTY3JhdGNoMywgcDJTY3JhdGNoMywgc2NyYXRjaFBlclBvc05vcm1hbCwgc2NyYXRjaFBlclBvc1RhbmdlbnQsIHNjcmF0Y2hQZXJQb3NCaXRhbmdlbnQsIGFwcGVuZFRleHR1cmVDb29yZGluYXRlc09yaWdpbiwgYXBwZW5kVGV4dHVyZUNvb3JkaW5hdGVzQ2FydGVzaWFuMiwgYXBwZW5kVGV4dHVyZUNvb3JkaW5hdGVzQ2FydGVzaWFuMywgYXBwZW5kVGV4dHVyZUNvb3JkaW5hdGVzUXVhdGVybmlvbiwgYXBwZW5kVGV4dHVyZUNvb3JkaW5hdGVzTWF0cml4MywgdGFuZ2VudE1hdHJpeFNjcmF0Y2gyLCBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNFeHRydWRlZFBvc2l0aW9ucywgc2NyYXRjaEVsbGlwc29pZDYsIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ5LCBkdW1teU9wdGlvbnMsIHNjcmF0Y2hDYXJ0ZXNpYW4wMiwgc2NyYXRjaENhcnRlc2lhbjE4LCBzY3JhdGNoUG9sYXJDbG9zZXN0LCBzY3JhdGNoUG9sYXIsIHNjcmF0Y2hQb2xhclByZXZpb3VzLCBwb2x5Z29uLCBzY3JhdGNoUG9sYXJGb3JQbGFuZSwgc2NyYXRjaENhcnRvZ3JhcGhpY0N5bGxpbmRyaWNhbCwgUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWdvbkdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Qb2x5Z29uR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0FyY1R5cGUoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1JlY3RhbmdsZSgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkVGFuZ2VudFBsYW5lKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5SW5zdGFuY2UoKTsKICAgICAgaW5pdF9HZW9tZXRyeU9mZnNldEF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5UGlwZWxpbmUoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDMoKTsKICAgICAgaW5pdF9Qb2x5Z29uR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfUG9seWdvblBpcGVsaW5lKCk7CiAgICAgIGluaXRfUXVhdGVybmlvbigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1N0ZXJlb2dyYXBoaWMoKTsKICAgICAgaW5pdF9WZXJ0ZXhGb3JtYXQoKTsKICAgICAgaW5pdF9XaW5kaW5nT3JkZXIoKTsKICAgICAgc2NyYXRjaENhcnRvMSA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydG8yID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCb3VuZGluZ1JlY3RhbmdsZSA9IG5ldyBCb3VuZGluZ1JlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQb3NpdGlvbjMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOb3JtYWw2ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVGFuZ2VudDQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCaXRhbmdlbnQ0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwMVNjcmF0Y2gzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwMlNjcmF0Y2gzID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyUG9zTm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUGVyUG9zVGFuZ2VudCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBlclBvc0JpdGFuZ2VudCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYXBwZW5kVGV4dHVyZUNvb3JkaW5hdGVzT3JpZ2luID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNDYXJ0ZXNpYW4yID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNDYXJ0ZXNpYW4zID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNRdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb25fZGVmYXVsdCgpOwogICAgICBhcHBlbmRUZXh0dXJlQ29vcmRpbmF0ZXNNYXRyaXgzID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICB0YW5nZW50TWF0cml4U2NyYXRjaDIgPSBuZXcgTWF0cml4M19kZWZhdWx0KCk7CiAgICAgIGNyZWF0ZUdlb21ldHJ5RnJvbVBvc2l0aW9uc0V4dHJ1ZGVkUG9zaXRpb25zID0gW107CiAgICAgIFBvbHlnb25HZW9tZXRyeS5mcm9tUG9zaXRpb25zID0gZnVuY3Rpb24ob3B0aW9ucykgewogICAgICAgIG9wdGlvbnMgPSBvcHRpb25zID8/IEZyb3plbl9kZWZhdWx0LkVNUFRZX09CSkVDVDsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoIm9wdGlvbnMucG9zaXRpb25zIiwgb3B0aW9ucy5wb3NpdGlvbnMpOwogICAgICAgIGNvbnN0IG5ld09wdGlvbnMgPSB7CiAgICAgICAgICBwb2x5Z29uSGllcmFyY2h5OiB7CiAgICAgICAgICAgIHBvc2l0aW9uczogb3B0aW9ucy5wb3NpdGlvbnMKICAgICAgICAgIH0sCiAgICAgICAgICBoZWlnaHQ6IG9wdGlvbnMuaGVpZ2h0LAogICAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IG9wdGlvbnMudmVydGV4Rm9ybWF0LAogICAgICAgICAgc3RSb3RhdGlvbjogb3B0aW9ucy5zdFJvdGF0aW9uLAogICAgICAgICAgZWxsaXBzb2lkOiBvcHRpb25zLmVsbGlwc29pZCwKICAgICAgICAgIGdyYW51bGFyaXR5OiBvcHRpb25zLmdyYW51bGFyaXR5LAogICAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQ6IG9wdGlvbnMucGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICBjbG9zZVRvcDogb3B0aW9ucy5jbG9zZVRvcCwKICAgICAgICAgIGNsb3NlQm90dG9tOiBvcHRpb25zLmNsb3NlQm90dG9tLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSwKICAgICAgICAgIGFyY1R5cGU6IG9wdGlvbnMuYXJjVHlwZSwKICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlczogb3B0aW9ucy50ZXh0dXJlQ29vcmRpbmF0ZXMKICAgICAgICB9OwogICAgICAgIHJldHVybiBuZXcgUG9seWdvbkdlb21ldHJ5KG5ld09wdGlvbnMpOwogICAgICB9OwogICAgICBQb2x5Z29uR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICB2YWx1ZS5fcG9seWdvbkhpZXJhcmNoeSwKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdAogICAgICAgICk7CiAgICAgICAgRWxsaXBzb2lkX2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzb2lkLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFjayh2YWx1ZS5fdmVydGV4Rm9ybWF0LCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9oZWlnaHQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9leHRydWRlZEhlaWdodDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2dyYW51bGFyaXR5OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc3RSb3RhdGlvbjsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3BlclBvc2l0aW9uSGVpZ2h0RXh0cnVkZSA/IDEgOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fcGVyUG9zaXRpb25IZWlnaHQgPyAxIDogMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2Nsb3NlVG9wID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9jbG9zZUJvdHRvbSA/IDEgOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc2hhZG93Vm9sdW1lID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9vZmZzZXRBdHRyaWJ1dGUgPz8gLTE7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9hcmNUeXBlOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodmFsdWUuX3RleHR1cmVDb29yZGluYXRlcykpIHsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICAgIHZhbHVlLl90ZXh0dXJlQ29vcmRpbmF0ZXMsCiAgICAgICAgICAgIGFycmF5LAogICAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSAtMTsKICAgICAgICB9CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5wYWNrZWRMZW5ndGg7CiAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICB9OwogICAgICBzY3JhdGNoRWxsaXBzb2lkNiA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDkgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgZHVtbXlPcHRpb25zID0gewogICAgICAgIHBvbHlnb25IaWVyYXJjaHk6IHt9CiAgICAgIH07CiAgICAgIFBvbHlnb25HZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IHBvbHlnb25IaWVyYXJjaHkgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQudW5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdAogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHBvbHlnb25IaWVyYXJjaHkuc3RhcnRpbmdJbmRleDsKICAgICAgICBkZWxldGUgcG9seWdvbkhpZXJhcmNoeS5zdGFydGluZ0luZGV4OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaEVsbGlwc29pZDYpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQ5CiAgICAgICAgKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBoZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICBjb25zdCBwZXJQb3NpdGlvbkhlaWdodCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPT09IDE7CiAgICAgICAgY29uc3QgY2xvc2VUb3AgPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIGNvbnN0IGNsb3NlQm90dG9tID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICBjb25zdCBzaGFkb3dWb2x1bWUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIGNvbnN0IG9mZnNldEF0dHJpYnV0ZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgYXJjVHlwZSA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gYXJyYXlbc3RhcnRpbmdJbmRleF0gPT09IC0xID8gdm9pZCAwIDogUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnVucGFja1BvbHlnb25IaWVyYXJjaHkoCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQKICAgICAgICApOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGV4dHVyZUNvb3JkaW5hdGVzKSkgewogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHRleHR1cmVDb29yZGluYXRlcy5zdGFydGluZ0luZGV4OwogICAgICAgICAgZGVsZXRlIHRleHR1cmVDb29yZGluYXRlcy5zdGFydGluZ0luZGV4OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBzdGFydGluZ0luZGV4Kys7CiAgICAgICAgfQogICAgICAgIGNvbnN0IHBhY2tlZExlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBQb2x5Z29uR2VvbWV0cnkoZHVtbXlPcHRpb25zKTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9wb2x5Z29uSGllcmFyY2h5ID0gcG9seWdvbkhpZXJhcmNoeTsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCwgcmVzdWx0Ll9lbGxpcHNvaWQpOwogICAgICAgIHJlc3VsdC5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0LCByZXN1bHQuX3ZlcnRleEZvcm1hdCk7CiAgICAgICAgcmVzdWx0Ll9oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXN1bHQuX3N0Um90YXRpb24gPSBzdFJvdGF0aW9uOwogICAgICAgIHJlc3VsdC5fcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlID0gcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlOwogICAgICAgIHJlc3VsdC5fcGVyUG9zaXRpb25IZWlnaHQgPSBwZXJQb3NpdGlvbkhlaWdodDsKICAgICAgICByZXN1bHQuX2Nsb3NlVG9wID0gY2xvc2VUb3A7CiAgICAgICAgcmVzdWx0Ll9jbG9zZUJvdHRvbSA9IGNsb3NlQm90dG9tOwogICAgICAgIHJlc3VsdC5fc2hhZG93Vm9sdW1lID0gc2hhZG93Vm9sdW1lOwogICAgICAgIHJlc3VsdC5fb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICByZXN1bHQuX2FyY1R5cGUgPSBhcmNUeXBlOwogICAgICAgIHJlc3VsdC5fdGV4dHVyZUNvb3JkaW5hdGVzID0gdGV4dHVyZUNvb3JkaW5hdGVzOwogICAgICAgIHJlc3VsdC5wYWNrZWRMZW5ndGggPSBwYWNrZWRMZW5ndGg7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjAyID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuMTggPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQb2xhckNsb3Nlc3QgPSBuZXcgU3RlcmVvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQb2xhciA9IG5ldyBTdGVyZW9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBvbGFyUHJldmlvdXMgPSBuZXcgU3RlcmVvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHBvbHlnb24gPSB7CiAgICAgICAgbm9ydGhBbmdsZTogMCwKICAgICAgICBzb3V0aEFuZ2xlOiAwLAogICAgICAgIHdlc3RPdmVySWRsOiAwLAogICAgICAgIGVhc3RPdmVySWRsOiAwCiAgICAgIH07CiAgICAgIFBvbHlnb25HZW9tZXRyeS5jb21wdXRlUmVjdGFuZ2xlRnJvbVBvc2l0aW9ucyA9IGZ1bmN0aW9uKHBvc2l0aW9ucywgZWxsaXBzb2lkLCBhcmNUeXBlLCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIGlmIChwb3NpdGlvbnMubGVuZ3RoIDwgMykgewogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Lndlc3QgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgcmVzdWx0LmVhc3QgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgcmVzdWx0LnNvdXRoID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgIHJlc3VsdC5ub3J0aCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgICAgICBwb2x5Z29uLm5vcnRoQW5nbGUgPSAwOwogICAgICAgIHBvbHlnb24uc291dGhBbmdsZSA9IDA7CiAgICAgICAgcG9seWdvbi53ZXN0T3ZlcklkbCA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgICAgICBwb2x5Z29uLmVhc3RPdmVySWRsID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgbGV0IGxhc3RQb2xhclBvc2l0aW9uID0gU3RlcmVvZ3JhcGhpY19kZWZhdWx0LmZyb21DYXJ0ZXNpYW4oCiAgICAgICAgICBwb3NpdGlvbnNbMF0sCiAgICAgICAgICBzY3JhdGNoUG9sYXJQcmV2aW91cwogICAgICAgICk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IHBvc2l0aW9uc0xlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgcG9sYXJQb3NpdGlvbiA9IFN0ZXJlb2dyYXBoaWNfZGVmYXVsdC5mcm9tQ2FydGVzaWFuKAogICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICBzY3JhdGNoUG9sYXIKICAgICAgICAgICk7CiAgICAgICAgICBleHBhbmRSZWN0YW5nbGUoCiAgICAgICAgICAgIHBvbGFyUG9zaXRpb24sCiAgICAgICAgICAgIGxhc3RQb2xhclBvc2l0aW9uLAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIGFyY1R5cGUsCiAgICAgICAgICAgIHBvbHlnb24sCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICAgIGxhc3RQb2xhclBvc2l0aW9uID0gU3RlcmVvZ3JhcGhpY19kZWZhdWx0LmNsb25lKHBvbGFyUG9zaXRpb24sIGxhc3RQb2xhclBvc2l0aW9uKTsKICAgICAgICB9CiAgICAgICAgZXhwYW5kUmVjdGFuZ2xlKAogICAgICAgICAgU3RlcmVvZ3JhcGhpY19kZWZhdWx0LmZyb21DYXJ0ZXNpYW4ocG9zaXRpb25zWzBdLCBzY3JhdGNoUG9sYXIpLAogICAgICAgICAgbGFzdFBvbGFyUG9zaXRpb24sCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBhcmNUeXBlLAogICAgICAgICAgcG9seWdvbiwKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgICAgaWYgKHJlc3VsdC5lYXN0IC0gcmVzdWx0Lndlc3QgPiBwb2x5Z29uLmVhc3RPdmVySWRsIC0gcG9seWdvbi53ZXN0T3ZlcklkbCkgewogICAgICAgICAgcmVzdWx0Lndlc3QgPSBwb2x5Z29uLndlc3RPdmVySWRsOwogICAgICAgICAgcmVzdWx0LmVhc3QgPSBwb2x5Z29uLmVhc3RPdmVySWRsOwogICAgICAgICAgaWYgKHJlc3VsdC5lYXN0ID4gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICAgIHJlc3VsdC5lYXN0ID0gcmVzdWx0LmVhc3QgLSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJlc3VsdC53ZXN0ID4gTWF0aF9kZWZhdWx0LlBJKSB7CiAgICAgICAgICAgIHJlc3VsdC53ZXN0ID0gcmVzdWx0Lndlc3QgLSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBNYXRoLmFicyhwb2x5Z29uLm5vcnRoQW5nbGUpLAogICAgICAgICAgTWF0aF9kZWZhdWx0LlRXT19QSSwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAKICAgICAgICApKSB7CiAgICAgICAgICByZXN1bHQubm9ydGggPSBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV087CiAgICAgICAgICByZXN1bHQuZWFzdCA9IE1hdGhfZGVmYXVsdC5QSTsKICAgICAgICAgIHJlc3VsdC53ZXN0ID0gLU1hdGhfZGVmYXVsdC5QSTsKICAgICAgICB9CiAgICAgICAgaWYgKE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgTWF0aC5hYnMocG9seWdvbi5zb3V0aEFuZ2xlKSwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5UV09fUEksCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjEwCiAgICAgICAgKSkgewogICAgICAgICAgcmVzdWx0LnNvdXRoID0gLU1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICAgIHJlc3VsdC5lYXN0ID0gTWF0aF9kZWZhdWx0LlBJOwogICAgICAgICAgcmVzdWx0Lndlc3QgPSAtTWF0aF9kZWZhdWx0LlBJOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoUG9sYXJGb3JQbGFuZSA9IG5ldyBTdGVyZW9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY0N5bGxpbmRyaWNhbCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBQb2x5Z29uR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihwb2x5Z29uR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBwb2x5Z29uR2VvbWV0cnkuX3ZlcnRleEZvcm1hdDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBwb2x5Z29uR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IHBvbHlnb25HZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IHBvbHlnb25HZW9tZXRyeS5fc3RSb3RhdGlvbjsKICAgICAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gcG9seWdvbkdlb21ldHJ5Ll9wb2x5Z29uSGllcmFyY2h5OwogICAgICAgIGNvbnN0IHBlclBvc2l0aW9uSGVpZ2h0ID0gcG9seWdvbkdlb21ldHJ5Ll9wZXJQb3NpdGlvbkhlaWdodDsKICAgICAgICBjb25zdCBjbG9zZVRvcCA9IHBvbHlnb25HZW9tZXRyeS5fY2xvc2VUb3A7CiAgICAgICAgY29uc3QgY2xvc2VCb3R0b20gPSBwb2x5Z29uR2VvbWV0cnkuX2Nsb3NlQm90dG9tOwogICAgICAgIGNvbnN0IGFyY1R5cGUgPSBwb2x5Z29uR2VvbWV0cnkuX2FyY1R5cGU7CiAgICAgICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gcG9seWdvbkdlb21ldHJ5Ll90ZXh0dXJlQ29vcmRpbmF0ZXM7CiAgICAgICAgY29uc3QgaGFzVGV4dHVyZUNvb3JkaW5hdGVzID0gZGVmaW5lZF9kZWZhdWx0KHRleHR1cmVDb29yZGluYXRlcyk7CiAgICAgICAgY29uc3Qgb3V0ZXJQb3NpdGlvbnMgPSBwb2x5Z29uSGllcmFyY2h5LnBvc2l0aW9uczsKICAgICAgICBpZiAob3V0ZXJQb3NpdGlvbnMubGVuZ3RoIDwgMykgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBjb25zdCByZWN0YW5nbGUgPSBwb2x5Z29uR2VvbWV0cnkucmVjdGFuZ2xlOwogICAgICAgIGNvbnN0IHJlc3VsdHMgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucG9seWdvbnNGcm9tSGllcmFyY2h5KAogICAgICAgICAgcG9seWdvbkhpZXJhcmNoeSwKICAgICAgICAgIGhhc1RleHR1cmVDb29yZGluYXRlcywKICAgICAgICAgIGNyZWF0ZVByb2plY3RUbzJkKHJlY3RhbmdsZSwgb3V0ZXJQb3NpdGlvbnMsIGVsbGlwc29pZCksCiAgICAgICAgICAhcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBjcmVhdGVTcGxpdFBvbHlnb25zKHJlY3RhbmdsZSwgZWxsaXBzb2lkLCBhcmNUeXBlLCBwZXJQb3NpdGlvbkhlaWdodCkKICAgICAgICApOwogICAgICAgIGNvbnN0IGhpZXJhcmNoeSA9IHJlc3VsdHMuaGllcmFyY2h5OwogICAgICAgIGNvbnN0IHBvbHlnb25zID0gcmVzdWx0cy5wb2x5Z29uczsKICAgICAgICBjb25zdCBkdW1teUZ1bmN0aW9uID0gZnVuY3Rpb24oaWRlbnRpdHkpIHsKICAgICAgICAgIHJldHVybiBpZGVudGl0eTsKICAgICAgICB9OwogICAgICAgIGNvbnN0IHRleHR1cmVDb29yZGluYXRlUG9seWdvbnMgPSBoYXNUZXh0dXJlQ29vcmRpbmF0ZXMgPyBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucG9seWdvbnNGcm9tSGllcmFyY2h5KAogICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzLAogICAgICAgICAgdHJ1ZSwKICAgICAgICAgIGR1bW15RnVuY3Rpb24sCiAgICAgICAgICBmYWxzZSwKICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICkucG9seWdvbnMgOiB2b2lkIDA7CiAgICAgICAgaWYgKGhpZXJhcmNoeS5sZW5ndGggPT09IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb3V0ZXJSaW5nID0gaGllcmFyY2h5WzBdLm91dGVyUmluZzsKICAgICAgICBjb25zdCBib3VuZGluZ1JlY3RhbmdsZSA9IGNvbXB1dGVCb3VuZGluZ1JlY3RhbmdsZSgKICAgICAgICAgIG91dGVyUmluZywKICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHN0Um90YXRpb24KICAgICAgICApOwogICAgICAgIGNvbnN0IGdlb21ldHJpZXMgPSBbXTsKICAgICAgICBjb25zdCBoZWlnaHQgPSBwb2x5Z29uR2VvbWV0cnkuX2hlaWdodDsKICAgICAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IHBvbHlnb25HZW9tZXRyeS5fZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZSA9IHBvbHlnb25HZW9tZXRyeS5fcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlIHx8ICFNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihoZWlnaHQsIGV4dHJ1ZGVkSGVpZ2h0LCAwLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjIpOwogICAgICAgIGNvbnN0IG9wdGlvbnMgPSB7CiAgICAgICAgICBwZXJQb3NpdGlvbkhlaWdodCwKICAgICAgICAgIHZlcnRleEZvcm1hdCwKICAgICAgICAgIGdlb21ldHJ5OiB2b2lkIDAsCiAgICAgICAgICByb3RhdGlvbkF4aXM6IGdldFRhbmdlbnRQbGFuZShyZWN0YW5nbGUsIG91dGVyUmluZywgZWxsaXBzb2lkKS5wbGFuZS5ub3JtYWwsCiAgICAgICAgICBwcm9qZWN0VG8yZDogY3JlYXRlUHJvamVjdFBvc2l0aW9uVG8yZChyZWN0YW5nbGUsIG91dGVyUmluZywgZWxsaXBzb2lkKSwKICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc3RSb3RhdGlvbiwKICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlczogdm9pZCAwLAogICAgICAgICAgYm90dG9tOiBmYWxzZSwKICAgICAgICAgIHRvcDogdHJ1ZSwKICAgICAgICAgIHdhbGw6IGZhbHNlLAogICAgICAgICAgZXh0cnVkZTogZmFsc2UsCiAgICAgICAgICBhcmNUeXBlCiAgICAgICAgfTsKICAgICAgICBsZXQgaTI7CiAgICAgICAgaWYgKGV4dHJ1ZGUpIHsKICAgICAgICAgIG9wdGlvbnMuZXh0cnVkZSA9IHRydWU7CiAgICAgICAgICBvcHRpb25zLnRvcCA9IGNsb3NlVG9wOwogICAgICAgICAgb3B0aW9ucy5ib3R0b20gPSBjbG9zZUJvdHRvbTsKICAgICAgICAgIG9wdGlvbnMuc2hhZG93Vm9sdW1lID0gcG9seWdvbkdlb21ldHJ5Ll9zaGFkb3dWb2x1bWU7CiAgICAgICAgICBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZSA9IHBvbHlnb25HZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlOwogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgcG9seWdvbnMubGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIGNvbnN0IHNwbGl0R2VvbWV0cnkgPSBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNFeHRydWRlZCgKICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgcG9seWdvbnNbaTJdLAogICAgICAgICAgICAgIGhhc1RleHR1cmVDb29yZGluYXRlcyA/IHRleHR1cmVDb29yZGluYXRlUG9seWdvbnNbaTJdIDogdm9pZCAwLAogICAgICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgICAgIGhpZXJhcmNoeVtpMl0sCiAgICAgICAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICAgICAgY2xvc2VUb3AsCiAgICAgICAgICAgICAgY2xvc2VCb3R0b20sCiAgICAgICAgICAgICAgdmVydGV4Rm9ybWF0LAogICAgICAgICAgICAgIGFyY1R5cGUKICAgICAgICAgICAgKTsKICAgICAgICAgICAgbGV0IHRvcEFuZEJvdHRvbTsKICAgICAgICAgICAgaWYgKGNsb3NlVG9wICYmIGNsb3NlQm90dG9tKSB7CiAgICAgICAgICAgICAgdG9wQW5kQm90dG9tID0gc3BsaXRHZW9tZXRyeS50b3BBbmRCb3R0b207CiAgICAgICAgICAgICAgb3B0aW9ucy5nZW9tZXRyeSA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5zY2FsZVRvR2VvZGV0aWNIZWlnaHRFeHRydWRlZCgKICAgICAgICAgICAgICAgIHRvcEFuZEJvdHRvbS5nZW9tZXRyeSwKICAgICAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgICAgIGV4dHJ1ZGVkSGVpZ2h0LAogICAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQKICAgICAgICAgICAgICApOwogICAgICAgICAgICB9IGVsc2UgaWYgKGNsb3NlVG9wKSB7CiAgICAgICAgICAgICAgdG9wQW5kQm90dG9tID0gc3BsaXRHZW9tZXRyeS50b3BBbmRCb3R0b207CiAgICAgICAgICAgICAgdG9wQW5kQm90dG9tLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICAgICAgICAgICAgdG9wQW5kQm90dG9tLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgICAgIXBlclBvc2l0aW9uSGVpZ2h0CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBvcHRpb25zLmdlb21ldHJ5ID0gdG9wQW5kQm90dG9tLmdlb21ldHJ5OwogICAgICAgICAgICB9IGVsc2UgaWYgKGNsb3NlQm90dG9tKSB7CiAgICAgICAgICAgICAgdG9wQW5kQm90dG9tID0gc3BsaXRHZW9tZXRyeS50b3BBbmRCb3R0b207CiAgICAgICAgICAgICAgdG9wQW5kQm90dG9tLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICAgICAgICAgICAgdG9wQW5kQm90dG9tLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICAgICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICB0cnVlCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBvcHRpb25zLmdlb21ldHJ5ID0gdG9wQW5kQm90dG9tLmdlb21ldHJ5OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChjbG9zZVRvcCB8fCBjbG9zZUJvdHRvbSkgewogICAgICAgICAgICAgIG9wdGlvbnMud2FsbCA9IGZhbHNlOwogICAgICAgICAgICAgIHRvcEFuZEJvdHRvbS5nZW9tZXRyeSA9IGNvbXB1dGVBdHRyaWJ1dGVzKG9wdGlvbnMpOwogICAgICAgICAgICAgIGdlb21ldHJpZXMucHVzaCh0b3BBbmRCb3R0b20pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHdhbGxzID0gc3BsaXRHZW9tZXRyeS53YWxsczsKICAgICAgICAgICAgb3B0aW9ucy53YWxsID0gdHJ1ZTsKICAgICAgICAgICAgZm9yIChsZXQgazIgPSAwOyBrMiA8IHdhbGxzLmxlbmd0aDsgazIrKykgewogICAgICAgICAgICAgIGNvbnN0IHdhbGwgPSB3YWxsc1trMl07CiAgICAgICAgICAgICAgb3B0aW9ucy5nZW9tZXRyeSA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5zY2FsZVRvR2VvZGV0aWNIZWlnaHRFeHRydWRlZCgKICAgICAgICAgICAgICAgIHdhbGwuZ2VvbWV0cnksCiAgICAgICAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICAgICAgICBleHRydWRlZEhlaWdodCwKICAgICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAgIHBlclBvc2l0aW9uSGVpZ2h0CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB3YWxsLmdlb21ldHJ5ID0gY29tcHV0ZUF0dHJpYnV0ZXMob3B0aW9ucyk7CiAgICAgICAgICAgICAgZ2VvbWV0cmllcy5wdXNoKHdhbGwpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHBvbHlnb25zLmxlbmd0aDsgaTIrKykgewogICAgICAgICAgICBjb25zdCBnZW9tZXRyeUluc3RhbmNlID0gbmV3IEdlb21ldHJ5SW5zdGFuY2VfZGVmYXVsdCh7CiAgICAgICAgICAgICAgZ2VvbWV0cnk6IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnMoCiAgICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgICBwb2x5Z29uc1tpMl0sCiAgICAgICAgICAgICAgICBoYXNUZXh0dXJlQ29vcmRpbmF0ZXMgPyB0ZXh0dXJlQ29vcmRpbmF0ZVBvbHlnb25zW2kyXSA6IHZvaWQgMCwKICAgICAgICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICAgICAgICB2ZXJ0ZXhGb3JtYXQsCiAgICAgICAgICAgICAgICBhcmNUeXBlCiAgICAgICAgICAgICAgKQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgZ2VvbWV0cnlJbnN0YW5jZS5nZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgICAgICAgICBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgIXBlclBvc2l0aW9uSGVpZ2h0CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG9wdGlvbnMuZ2VvbWV0cnkgPSBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5OwogICAgICAgICAgICBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5ID0gY29tcHV0ZUF0dHJpYnV0ZXMob3B0aW9ucyk7CiAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocG9seWdvbkdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gZ2VvbWV0cnlJbnN0YW5jZS5nZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGg7CiAgICAgICAgICAgICAgY29uc3Qgb2Zmc2V0VmFsdWUgPSBwb2x5Z29uR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSA9PT0gR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGVfZGVmYXVsdC5OT05FID8gMCA6IDE7CiAgICAgICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgICBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5LmF0dHJpYnV0ZXMuYXBwbHlPZmZzZXQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICAgICAgICAgIHZhbHVlczogYXBwbHlPZmZzZXQKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnZW9tZXRyaWVzLnB1c2goZ2VvbWV0cnlJbnN0YW5jZSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdlb21ldHJ5ID0gR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmNvbWJpbmVJbnN0YW5jZXMoZ2VvbWV0cmllcylbMF07CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMgPSBuZXcgRmxvYXQ2NEFycmF5KAogICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMKICAgICAgICApOwogICAgICAgIGdlb21ldHJ5LmluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aCAvIDMsCiAgICAgICAgICBnZW9tZXRyeS5pbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gZ2VvbWV0cnkuYXR0cmlidXRlczsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMKICAgICAgICApOwogICAgICAgIGlmICghdmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgICAgICBkZWxldGUgYXR0cmlidXRlcy5wb3NpdGlvbjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBnZW9tZXRyeS5pbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSwKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBwb2x5Z29uR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBQb2x5Z29uR2VvbWV0cnkuY3JlYXRlU2hhZG93Vm9sdW1lID0gZnVuY3Rpb24ocG9seWdvbkdlb21ldHJ5LCBtaW5IZWlnaHRGdW5jLCBtYXhIZWlnaHRGdW5jKSB7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBwb2x5Z29uR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHBvbHlnb25HZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IG1pbkhlaWdodCA9IG1pbkhlaWdodEZ1bmMoZ3JhbnVsYXJpdHksIGVsbGlwc29pZCk7CiAgICAgICAgY29uc3QgbWF4SGVpZ2h0ID0gbWF4SGVpZ2h0RnVuYyhncmFudWxhcml0eSwgZWxsaXBzb2lkKTsKICAgICAgICByZXR1cm4gbmV3IFBvbHlnb25HZW9tZXRyeSh7CiAgICAgICAgICBwb2x5Z29uSGllcmFyY2h5OiBwb2x5Z29uR2VvbWV0cnkuX3BvbHlnb25IaWVyYXJjaHksCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzdFJvdGF0aW9uOiBwb2x5Z29uR2VvbWV0cnkuX3N0Um90YXRpb24sCiAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgIHBlclBvc2l0aW9uSGVpZ2h0OiBmYWxzZSwKICAgICAgICAgIGV4dHJ1ZGVkSGVpZ2h0OiBtaW5IZWlnaHQsCiAgICAgICAgICBoZWlnaHQ6IG1heEhlaWdodCwKICAgICAgICAgIHZlcnRleEZvcm1hdDogVmVydGV4Rm9ybWF0X2RlZmF1bHQuUE9TSVRJT05fT05MWSwKICAgICAgICAgIHNoYWRvd1ZvbHVtZTogdHJ1ZSwKICAgICAgICAgIGFyY1R5cGU6IHBvbHlnb25HZW9tZXRyeS5fYXJjVHlwZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhQb2x5Z29uR2VvbWV0cnkucHJvdG90eXBlLCB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICByZWN0YW5nbGU6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXMuX3JlY3RhbmdsZSkpIHsKICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB0aGlzLl9wb2x5Z29uSGllcmFyY2h5LnBvc2l0aW9uczsKICAgICAgICAgICAgICB0aGlzLl9yZWN0YW5nbGUgPSBQb2x5Z29uR2VvbWV0cnkuY29tcHV0ZVJlY3RhbmdsZUZyb21Qb3NpdGlvbnMoCiAgICAgICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgICAgICB0aGlzLl9lbGxpcHNvaWQsCiAgICAgICAgICAgICAgICB0aGlzLl9hcmNUeXBlCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVjdGFuZ2xlOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogRm9yIHJlbWFwcGluZyB0ZXh0dXJlIGNvb3JkaW5hdGVzIHdoZW4gcmVuZGVyaW5nIFBvbHlnb25HZW9tZXRyaWVzIGFzIEdyb3VuZFByaW1pdGl2ZXMuCiAgICAgICAgICogQHByaXZhdGUKICAgICAgICAgKi8KICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLl90ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzKSkgewogICAgICAgICAgICAgIHRoaXMuX3RleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHMgPSB0ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzMih0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0pOwogICAgICBQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdCA9IFBvbHlnb25HZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBvbHlnb25HZW9tZXRyeS5qcwogIHZhciBjcmVhdGVQb2x5Z29uR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVBvbHlnb25HZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZVBvbHlnb25HZW9tZXRyeShwb2x5Z29uR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIHBvbHlnb25HZW9tZXRyeSA9IFBvbHlnb25HZW9tZXRyeV9kZWZhdWx0LnVucGFjayhwb2x5Z29uR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICBwb2x5Z29uR2VvbWV0cnkuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKHBvbHlnb25HZW9tZXRyeS5fZWxsaXBzb2lkKTsKICAgIHJldHVybiBQb2x5Z29uR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShwb2x5Z29uR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlUG9seWdvbkdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVQb2x5Z29uR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9Qb2x5Z29uR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlUG9seWdvbkdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVQb2x5Z29uR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Qb2x5Z29uT3V0bGluZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zMihlbGxpcHNvaWQsIHBvc2l0aW9ucywgbWluRGlzdGFuY2UsIHBlclBvc2l0aW9uSGVpZ2h0LCBhcmNUeXBlKSB7CiAgICBjb25zdCB0YW5nZW50UGxhbmUgPSBFbGxpcHNvaWRUYW5nZW50UGxhbmVfZGVmYXVsdC5mcm9tUG9pbnRzKHBvc2l0aW9ucywgZWxsaXBzb2lkKTsKICAgIGNvbnN0IHBvc2l0aW9uczJEID0gdGFuZ2VudFBsYW5lLnByb2plY3RQb2ludHNPbnRvUGxhbmUoCiAgICAgIHBvc2l0aW9ucywKICAgICAgY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zUG9zaXRpb25zCiAgICApOwogICAgY29uc3Qgb3JpZ2luYWxXaW5kaW5nT3JkZXIgPSBQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5jb21wdXRlV2luZGluZ09yZGVyMkQocG9zaXRpb25zMkQpOwogICAgaWYgKG9yaWdpbmFsV2luZGluZ09yZGVyID09PSBXaW5kaW5nT3JkZXJfZGVmYXVsdC5DTE9DS1dJU0UpIHsKICAgICAgcG9zaXRpb25zMkQucmV2ZXJzZSgpOwogICAgICBwb3NpdGlvbnMgPSBwb3NpdGlvbnMuc2xpY2UoKS5yZXZlcnNlKCk7CiAgICB9CiAgICBsZXQgc3ViZGl2aWRlZFBvc2l0aW9uczsKICAgIGxldCBpMjsKICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGlmICghcGVyUG9zaXRpb25IZWlnaHQpIHsKICAgICAgbGV0IG51bVZlcnRpY2VzID0gMDsKICAgICAgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQykgewogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgbnVtVmVydGljZXMgKz0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZUxpbmVDb3VudCgKICAgICAgICAgICAgcG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgcG9zaXRpb25zWyhpMiArIDEpICUgbGVuZ3RoXSwKICAgICAgICAgICAgbWluRGlzdGFuY2UKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9IGVsc2UgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5SSFVNQikgewogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgICAgbnVtVmVydGljZXMgKz0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZVJodW1iTGluZUNvdW50KAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0sCiAgICAgICAgICAgIHBvc2l0aW9uc1soaTIgKyAxKSAlIGxlbmd0aF0sCiAgICAgICAgICAgIG1pbkRpc3RhbmNlCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgfQogICAgICBzdWJkaXZpZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShudW1WZXJ0aWNlcyAqIDMpOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICBsZXQgdGVtcFBvc2l0aW9uczsKICAgICAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDKSB7CiAgICAgICAgICB0ZW1wUG9zaXRpb25zID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZUxpbmUoCiAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0sCiAgICAgICAgICAgIHBvc2l0aW9uc1soaTIgKyAxKSAlIGxlbmd0aF0sCiAgICAgICAgICAgIG1pbkRpc3RhbmNlLAogICAgICAgICAgICBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNTdWJkaXZpZGVkCiAgICAgICAgICApOwogICAgICAgIH0gZWxzZSBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgICAgICB0ZW1wUG9zaXRpb25zID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZVJodW1iTGluZSgKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdLAogICAgICAgICAgICBtaW5EaXN0YW5jZSwKICAgICAgICAgICAgY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zU3ViZGl2aWRlZAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdGVtcFBvc2l0aW9uc0xlbmd0aCA9IHRlbXBQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCB0ZW1wUG9zaXRpb25zTGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zW2luZGV4KytdID0gdGVtcFBvc2l0aW9uc1tqMl07CiAgICAgICAgfQogICAgICB9CiAgICB9IGVsc2UgewogICAgICBzdWJkaXZpZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGggKiAyICogMyk7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgIGNvbnN0IHAwID0gcG9zaXRpb25zW2kyXTsKICAgICAgICBjb25zdCBwMSA9IHBvc2l0aW9uc1soaTIgKyAxKSAlIGxlbmd0aF07CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAwLng7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAwLnk7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAwLno7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAxLng7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAxLnk7CiAgICAgICAgc3ViZGl2aWRlZFBvc2l0aW9uc1tpbmRleCsrXSA9IHAxLno7CiAgICAgIH0KICAgIH0KICAgIGxlbmd0aCA9IHN1YmRpdmlkZWRQb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IGluZGljZXNTaXplID0gbGVuZ3RoICogMjsKICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShsZW5ndGgsIGluZGljZXNTaXplKTsKICAgIGluZGV4ID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gaTIgKyAxOwogICAgfQogICAgaW5kaWNlc1tpbmRleCsrXSA9IGxlbmd0aCAtIDE7CiAgICBpbmRpY2VzW2luZGV4XSA9IDA7CiAgICByZXR1cm4gbmV3IEdlb21ldHJ5SW5zdGFuY2VfZGVmYXVsdCh7CiAgICAgIGdlb21ldHJ5OiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgYXR0cmlidXRlczogbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KHsKICAgICAgICAgIHBvc2l0aW9uOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgdmFsdWVzOiBzdWJkaXZpZGVkUG9zaXRpb25zCiAgICAgICAgICB9KQogICAgICAgIH0pLAogICAgICAgIGluZGljZXMsCiAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTCiAgICAgIH0pCiAgICB9KTsKICB9CiAgZnVuY3Rpb24gY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zRXh0cnVkZWQyKGVsbGlwc29pZCwgcG9zaXRpb25zLCBtaW5EaXN0YW5jZSwgcGVyUG9zaXRpb25IZWlnaHQsIGFyY1R5cGUpIHsKICAgIGNvbnN0IHRhbmdlbnRQbGFuZSA9IEVsbGlwc29pZFRhbmdlbnRQbGFuZV9kZWZhdWx0LmZyb21Qb2ludHMocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgY29uc3QgcG9zaXRpb25zMkQgPSB0YW5nZW50UGxhbmUucHJvamVjdFBvaW50c09udG9QbGFuZSgKICAgICAgcG9zaXRpb25zLAogICAgICBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNQb3NpdGlvbnMKICAgICk7CiAgICBjb25zdCBvcmlnaW5hbFdpbmRpbmdPcmRlciA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LmNvbXB1dGVXaW5kaW5nT3JkZXIyRChwb3NpdGlvbnMyRCk7CiAgICBpZiAob3JpZ2luYWxXaW5kaW5nT3JkZXIgPT09IFdpbmRpbmdPcmRlcl9kZWZhdWx0LkNMT0NLV0lTRSkgewogICAgICBwb3NpdGlvbnMyRC5yZXZlcnNlKCk7CiAgICAgIHBvc2l0aW9ucyA9IHBvc2l0aW9ucy5zbGljZSgpLnJldmVyc2UoKTsKICAgIH0KICAgIGxldCBzdWJkaXZpZGVkUG9zaXRpb25zOwogICAgbGV0IGkyOwogICAgbGV0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCBjb3JuZXJzID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgaWYgKCFwZXJQb3NpdGlvbkhlaWdodCkgewogICAgICBsZXQgbnVtVmVydGljZXMgPSAwOwogICAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDKSB7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBudW1WZXJ0aWNlcyArPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuc3ViZGl2aWRlTGluZUNvdW50KAogICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdLAogICAgICAgICAgICBtaW5EaXN0YW5jZQogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICBudW1WZXJ0aWNlcyArPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuc3ViZGl2aWRlUmh1bWJMaW5lQ291bnQoCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgcG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgcG9zaXRpb25zWyhpMiArIDEpICUgbGVuZ3RoXSwKICAgICAgICAgICAgbWluRGlzdGFuY2UKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9CiAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KG51bVZlcnRpY2VzICogMyAqIDIpOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICBjb3JuZXJzW2kyXSA9IGluZGV4IC8gMzsKICAgICAgICBsZXQgdGVtcFBvc2l0aW9uczsKICAgICAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDKSB7CiAgICAgICAgICB0ZW1wUG9zaXRpb25zID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZUxpbmUoCiAgICAgICAgICAgIHBvc2l0aW9uc1tpMl0sCiAgICAgICAgICAgIHBvc2l0aW9uc1soaTIgKyAxKSAlIGxlbmd0aF0sCiAgICAgICAgICAgIG1pbkRpc3RhbmNlLAogICAgICAgICAgICBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNTdWJkaXZpZGVkCiAgICAgICAgICApOwogICAgICAgIH0gZWxzZSBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LlJIVU1CKSB7CiAgICAgICAgICB0ZW1wUG9zaXRpb25zID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnN1YmRpdmlkZVJodW1iTGluZSgKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdLAogICAgICAgICAgICBtaW5EaXN0YW5jZSwKICAgICAgICAgICAgY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zU3ViZGl2aWRlZAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgdGVtcFBvc2l0aW9uc0xlbmd0aCA9IHRlbXBQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCB0ZW1wUG9zaXRpb25zTGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICBzdWJkaXZpZGVkUG9zaXRpb25zW2luZGV4KytdID0gdGVtcFBvc2l0aW9uc1tqMl07CiAgICAgICAgfQogICAgICB9CiAgICB9IGVsc2UgewogICAgICBzdWJkaXZpZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGggKiAyICogMyAqIDIpOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICBjb3JuZXJzW2kyXSA9IGluZGV4IC8gMzsKICAgICAgICBjb25zdCBwMCA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgY29uc3QgcDEgPSBwb3NpdGlvbnNbKGkyICsgMSkgJSBsZW5ndGhdOwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMC54OwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMC55OwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMC56OwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMS54OwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMS55OwogICAgICAgIHN1YmRpdmlkZWRQb3NpdGlvbnNbaW5kZXgrK10gPSBwMS56OwogICAgICB9CiAgICB9CiAgICBsZW5ndGggPSBzdWJkaXZpZGVkUG9zaXRpb25zLmxlbmd0aCAvICgzICogMik7CiAgICBjb25zdCBjb3JuZXJzTGVuZ3RoID0gY29ybmVycy5sZW5ndGg7CiAgICBjb25zdCBpbmRpY2VzU2l6ZSA9IChsZW5ndGggKiAyICsgY29ybmVyc0xlbmd0aCkgKiAyOwogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBsZW5ndGggKyBjb3JuZXJzTGVuZ3RoLAogICAgICBpbmRpY2VzU2l6ZQogICAgKTsKICAgIGluZGV4ID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBpbmRpY2VzW2luZGV4KytdID0gaTI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSAoaTIgKyAxKSAlIGxlbmd0aDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgbGVuZ3RoOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gKGkyICsgMSkgJSBsZW5ndGggKyBsZW5ndGg7CiAgICB9CiAgICBmb3IgKGkyID0gMDsgaTIgPCBjb3JuZXJzTGVuZ3RoOyBpMisrKSB7CiAgICAgIGNvbnN0IGNvcm5lciA9IGNvcm5lcnNbaTJdOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gY29ybmVyOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gY29ybmVyICsgbGVuZ3RoOwogICAgfQogICAgcmV0dXJuIG5ldyBHZW9tZXRyeUluc3RhbmNlX2RlZmF1bHQoewogICAgICBnZW9tZXRyeTogbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgIGF0dHJpYnV0ZXM6IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCh7CiAgICAgICAgICBwb3NpdGlvbjogbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogc3ViZGl2aWRlZFBvc2l0aW9ucwogICAgICAgICAgfSkKICAgICAgICB9KSwKICAgICAgICBpbmRpY2VzLAogICAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5MSU5FUwogICAgICB9KQogICAgfSk7CiAgfQogIGZ1bmN0aW9uIFBvbHlnb25PdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJvcHRpb25zIiwgb3B0aW9ucyk7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMucG9seWdvbkhpZXJhcmNoeSIsIG9wdGlvbnMucG9seWdvbkhpZXJhcmNoeSk7CiAgICBpZiAob3B0aW9ucy5wZXJQb3NpdGlvbkhlaWdodCAmJiBkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5oZWlnaHQpKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJDYW5ub3QgdXNlIGJvdGggb3B0aW9ucy5wZXJQb3NpdGlvbkhlaWdodCBhbmQgb3B0aW9ucy5oZWlnaHQiCiAgICAgICk7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuYXJjVHlwZSkgJiYgb3B0aW9ucy5hcmNUeXBlICE9PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMgJiYgb3B0aW9ucy5hcmNUeXBlICE9PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIkludmFsaWQgYXJjVHlwZS4gVmFsaWQgb3B0aW9ucyBhcmUgQXJjVHlwZS5HRU9ERVNJQyBhbmQgQXJjVHlwZS5SSFVNQi4iCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBwb2x5Z29uSGllcmFyY2h5ID0gb3B0aW9ucy5wb2x5Z29uSGllcmFyY2h5OwogICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHQgPSBvcHRpb25zLnBlclBvc2l0aW9uSGVpZ2h0ID8/IGZhbHNlOwogICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHRFeHRydWRlID0gcGVyUG9zaXRpb25IZWlnaHQgJiYgZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQpOwogICAgY29uc3QgYXJjVHlwZSA9IG9wdGlvbnMuYXJjVHlwZSA/PyBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUM7CiAgICBsZXQgaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQgPz8gMDsKICAgIGxldCBleHRydWRlZEhlaWdodCA9IG9wdGlvbnMuZXh0cnVkZWRIZWlnaHQgPz8gaGVpZ2h0OwogICAgaWYgKCFwZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGUpIHsKICAgICAgY29uc3QgaDIgPSBNYXRoLm1heChoZWlnaHQsIGV4dHJ1ZGVkSGVpZ2h0KTsKICAgICAgZXh0cnVkZWRIZWlnaHQgPSBNYXRoLm1pbihoZWlnaHQsIGV4dHJ1ZGVkSGVpZ2h0KTsKICAgICAgaGVpZ2h0ID0gaDI7CiAgICB9CiAgICB0aGlzLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNvaWQpOwogICAgdGhpcy5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgIHRoaXMuX2hlaWdodCA9IGhlaWdodDsKICAgIHRoaXMuX2V4dHJ1ZGVkSGVpZ2h0ID0gZXh0cnVkZWRIZWlnaHQ7CiAgICB0aGlzLl9hcmNUeXBlID0gYXJjVHlwZTsKICAgIHRoaXMuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgdGhpcy5fcGVyUG9zaXRpb25IZWlnaHQgPSBwZXJQb3NpdGlvbkhlaWdodDsKICAgIHRoaXMuX3BlclBvc2l0aW9uSGVpZ2h0RXh0cnVkZSA9IHBlclBvc2l0aW9uSGVpZ2h0RXh0cnVkZTsKICAgIHRoaXMuX29mZnNldEF0dHJpYnV0ZSA9IG9wdGlvbnMub2Zmc2V0QXR0cmlidXRlOwogICAgdGhpcy5fd29ya2VyTmFtZSA9ICJjcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5IjsKICAgIHRoaXMucGFja2VkTGVuZ3RoID0gUG9seWdvbkdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVIaWVyYXJjaHlQYWNrZWRMZW5ndGgoCiAgICAgIHBvbHlnb25IaWVyYXJjaHksCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdAogICAgKSArIEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDg7CiAgfQogIHZhciBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNQb3NpdGlvbnMsIGNyZWF0ZUdlb21ldHJ5RnJvbVBvc2l0aW9uc1N1YmRpdmlkZWQsIHNjcmF0Y2hFbGxpcHNvaWQ3LCBkdW1teU9wdGlvbnMyLCBQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWdvbk91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWdvbk91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQXJjVHlwZSgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWRUYW5nZW50UGxhbmUoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfR2VvbWV0cnlJbnN0YW5jZSgpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlQaXBlbGluZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUG9seWdvbkdlb21ldHJ5TGlicmFyeSgpOwogICAgICBpbml0X1BvbHlnb25QaXBlbGluZSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9XaW5kaW5nT3JkZXIoKTsKICAgICAgY3JlYXRlR2VvbWV0cnlGcm9tUG9zaXRpb25zUG9zaXRpb25zID0gW107CiAgICAgIGNyZWF0ZUdlb21ldHJ5RnJvbVBvc2l0aW9uc1N1YmRpdmlkZWQgPSBbXTsKICAgICAgUG9seWdvbk91dGxpbmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IFBvbHlnb25HZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgIHZhbHVlLl9wb2x5Z29uSGllcmFyY2h5LAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0CiAgICAgICAgKTsKICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2hlaWdodDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9wZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGUgPyAxIDogMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3BlclBvc2l0aW9uSGVpZ2h0ID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9hcmNUeXBlOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWUucGFja2VkTGVuZ3RoOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDcgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShFbGxpcHNvaWRfZGVmYXVsdC5VTklUX1NQSEVSRSk7CiAgICAgIGR1bW15T3B0aW9uczIgPSB7CiAgICAgICAgcG9seWdvbkhpZXJhcmNoeToge30KICAgICAgfTsKICAgICAgUG9seWdvbk91dGxpbmVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IHBvbHlnb25IaWVyYXJjaHkgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQudW5wYWNrUG9seWdvbkhpZXJhcmNoeSgKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdAogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHBvbHlnb25IaWVyYXJjaHkuc3RhcnRpbmdJbmRleDsKICAgICAgICBkZWxldGUgcG9seWdvbkhpZXJhcmNoeS5zdGFydGluZ0luZGV4OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaEVsbGlwc29pZDcpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGhlaWdodCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBwZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIGNvbnN0IHBlclBvc2l0aW9uSGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICBjb25zdCBhcmNUeXBlID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHBhY2tlZExlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBQb2x5Z29uT3V0bGluZUdlb21ldHJ5KGR1bW15T3B0aW9uczIpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3BvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uSGllcmFyY2h5OwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll9oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXN1bHQuX3BlclBvc2l0aW9uSGVpZ2h0ID0gcGVyUG9zaXRpb25IZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9wZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGUgPSBwZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGU7CiAgICAgICAgcmVzdWx0Ll9hcmNUeXBlID0gYXJjVHlwZTsKICAgICAgICByZXN1bHQuX29mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgcmVzdWx0LnBhY2tlZExlbmd0aCA9IHBhY2tlZExlbmd0aDsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmZyb21Qb3NpdGlvbnMgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgib3B0aW9ucy5wb3NpdGlvbnMiLCBvcHRpb25zLnBvc2l0aW9ucyk7CiAgICAgICAgY29uc3QgbmV3T3B0aW9ucyA9IHsKICAgICAgICAgIHBvbHlnb25IaWVyYXJjaHk6IHsKICAgICAgICAgICAgcG9zaXRpb25zOiBvcHRpb25zLnBvc2l0aW9ucwogICAgICAgICAgfSwKICAgICAgICAgIGhlaWdodDogb3B0aW9ucy5oZWlnaHQsCiAgICAgICAgICBleHRydWRlZEhlaWdodDogb3B0aW9ucy5leHRydWRlZEhlaWdodCwKICAgICAgICAgIGVsbGlwc29pZDogb3B0aW9ucy5lbGxpcHNvaWQsCiAgICAgICAgICBncmFudWxhcml0eTogb3B0aW9ucy5ncmFudWxhcml0eSwKICAgICAgICAgIHBlclBvc2l0aW9uSGVpZ2h0OiBvcHRpb25zLnBlclBvc2l0aW9uSGVpZ2h0LAogICAgICAgICAgYXJjVHlwZTogb3B0aW9ucy5hcmNUeXBlLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZQogICAgICAgIH07CiAgICAgICAgcmV0dXJuIG5ldyBQb2x5Z29uT3V0bGluZUdlb21ldHJ5KG5ld09wdGlvbnMpOwogICAgICB9OwogICAgICBQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24ocG9seWdvbkdlb21ldHJ5KSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gcG9seWdvbkdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBwb2x5Z29uR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IHBvbHlnb25IaWVyYXJjaHkgPSBwb2x5Z29uR2VvbWV0cnkuX3BvbHlnb25IaWVyYXJjaHk7CiAgICAgICAgY29uc3QgcGVyUG9zaXRpb25IZWlnaHQgPSBwb2x5Z29uR2VvbWV0cnkuX3BlclBvc2l0aW9uSGVpZ2h0OwogICAgICAgIGNvbnN0IGFyY1R5cGUgPSBwb2x5Z29uR2VvbWV0cnkuX2FyY1R5cGU7CiAgICAgICAgY29uc3QgcG9seWdvbnMgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucG9seWdvbk91dGxpbmVzRnJvbUhpZXJhcmNoeSgKICAgICAgICAgIHBvbHlnb25IaWVyYXJjaHksCiAgICAgICAgICAhcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICBlbGxpcHNvaWQKICAgICAgICApOwogICAgICAgIGlmIChwb2x5Z29ucy5sZW5ndGggPT09IDApIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGxldCBnZW9tZXRyeUluc3RhbmNlOwogICAgICAgIGNvbnN0IGdlb21ldHJpZXMgPSBbXTsKICAgICAgICBjb25zdCBtaW5EaXN0YW5jZSA9IE1hdGhfZGVmYXVsdC5jaG9yZExlbmd0aCgKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZWxsaXBzb2lkLm1heGltdW1SYWRpdXMKICAgICAgICApOwogICAgICAgIGNvbnN0IGhlaWdodCA9IHBvbHlnb25HZW9tZXRyeS5faGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gcG9seWdvbkdlb21ldHJ5Ll9leHRydWRlZEhlaWdodDsKICAgICAgICBjb25zdCBleHRydWRlID0gcG9seWdvbkdlb21ldHJ5Ll9wZXJQb3NpdGlvbkhlaWdodEV4dHJ1ZGUgfHwgIU1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKGhlaWdodCwgZXh0cnVkZWRIZWlnaHQsIDAsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMik7CiAgICAgICAgbGV0IG9mZnNldFZhbHVlOwogICAgICAgIGxldCBpMjsKICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgcG9seWdvbnMubGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIGdlb21ldHJ5SW5zdGFuY2UgPSBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnNFeHRydWRlZDIoCiAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgIHBvbHlnb25zW2kyXSwKICAgICAgICAgICAgICBtaW5EaXN0YW5jZSwKICAgICAgICAgICAgICBwZXJQb3NpdGlvbkhlaWdodCwKICAgICAgICAgICAgICBhcmNUeXBlCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGdlb21ldHJ5SW5zdGFuY2UuZ2VvbWV0cnkgPSBQb2x5Z29uR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0RXh0cnVkZWQoCiAgICAgICAgICAgICAgZ2VvbWV0cnlJbnN0YW5jZS5nZW9tZXRyeSwKICAgICAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICAgIHBlclBvc2l0aW9uSGVpZ2h0CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocG9seWdvbkdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICAgICAgY29uc3Qgc2l6ZSA9IGdlb21ldHJ5SW5zdGFuY2UuZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoIC8gMzsKICAgICAgICAgICAgICBsZXQgb2Zmc2V0QXR0cmlidXRlID0gbmV3IFVpbnQ4QXJyYXkoc2l6ZSk7CiAgICAgICAgICAgICAgaWYgKHBvbHlnb25HZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICAgICAgICAgICAgb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlLmZpbGwoMSwgMCwgc2l6ZSAvIDIpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBvZmZzZXRWYWx1ZSA9IHBvbHlnb25HZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZ2VvbWV0cnlJbnN0YW5jZS5nZW9tZXRyeS5hdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgICAgICB2YWx1ZXM6IG9mZnNldEF0dHJpYnV0ZQogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdlb21ldHJpZXMucHVzaChnZW9tZXRyeUluc3RhbmNlKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgcG9seWdvbnMubGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgIGdlb21ldHJ5SW5zdGFuY2UgPSBjcmVhdGVHZW9tZXRyeUZyb21Qb3NpdGlvbnMyKAogICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICBwb2x5Z29uc1tpMl0sCiAgICAgICAgICAgICAgbWluRGlzdGFuY2UsCiAgICAgICAgICAgICAgcGVyUG9zaXRpb25IZWlnaHQsCiAgICAgICAgICAgICAgYXJjVHlwZQogICAgICAgICAgICApOwogICAgICAgICAgICBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICAgICAgICAgIGdlb21ldHJ5SW5zdGFuY2UuZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMsCiAgICAgICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICAhcGVyUG9zaXRpb25IZWlnaHQKICAgICAgICAgICAgKTsKICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChwb2x5Z29uR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgICAgICBjb25zdCBsZW5ndGggPSBnZW9tZXRyeUluc3RhbmNlLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aDsKICAgICAgICAgICAgICBvZmZzZXRWYWx1ZSA9IHBvbHlnb25HZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgICAgICBjb25zdCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCAvIDMpLmZpbGwob2Zmc2V0VmFsdWUpOwogICAgICAgICAgICAgIGdlb21ldHJ5SW5zdGFuY2UuZ2VvbWV0cnkuYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAxLAogICAgICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGdlb21ldHJpZXMucHVzaChnZW9tZXRyeUluc3RhbmNlKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uc3QgZ2VvbWV0cnkgPSBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQuY29tYmluZUluc3RhbmNlcyhnZW9tZXRyaWVzKVswXTsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMKICAgICAgICApOwogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzOiBnZW9tZXRyeS5hdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlczogZ2VvbWV0cnkuaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IGdlb21ldHJ5LnByaW1pdGl2ZVR5cGUsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogcG9seWdvbkdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgUG9seWdvbk91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gUG9seWdvbk91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUG9seWdvbk91dGxpbmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlUG9seWdvbk91dGxpbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5KHBvbHlnb25HZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcG9seWdvbkdlb21ldHJ5ID0gUG9seWdvbk91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LnVucGFjayhwb2x5Z29uR2VvbWV0cnksIG9mZnNldCk7CiAgICB9CiAgICBwb2x5Z29uR2VvbWV0cnkuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKHBvbHlnb25HZW9tZXRyeS5fZWxsaXBzb2lkKTsKICAgIHJldHVybiBQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkocG9seWdvbkdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfUG9seWdvbk91dGxpbmVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVQb2x5Z29uT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29sb3IuanMKICBmdW5jdGlvbiBodWUycmdiKG0xLCBtMiwgaDIpIHsKICAgIGlmIChoMiA8IDApIHsKICAgICAgaDIgKz0gMTsKICAgIH0KICAgIGlmIChoMiA+IDEpIHsKICAgICAgaDIgLT0gMTsKICAgIH0KICAgIGlmIChoMiAqIDYgPCAxKSB7CiAgICAgIHJldHVybiBtMSArIChtMiAtIG0xKSAqIDYgKiBoMjsKICAgIH0KICAgIGlmIChoMiAqIDIgPCAxKSB7CiAgICAgIHJldHVybiBtMjsKICAgIH0KICAgIGlmIChoMiAqIDMgPCAyKSB7CiAgICAgIHJldHVybiBtMSArIChtMiAtIG0xKSAqICgyIC8gMyAtIGgyKSAqIDY7CiAgICB9CiAgICByZXR1cm4gbTE7CiAgfQogIHZhciBDb2xvciwgc2NyYXRjaEFycmF5QnVmZmVyLCBzY3JhdGNoVWludDMyQXJyYXksIHNjcmF0Y2hVaW50OEFycmF5LCByZ2JhTWF0Y2hlciwgcnJnZ2JiYWFNYXRjaGVyLCByZ2JQYXJlbnRoZXNlc01hdGNoZXIsIGhzbFBhcmVudGhlc2VzTWF0Y2hlciwgQ29sb3JfZGVmYXVsdDsKICB2YXIgaW5pdF9Db2xvciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvQ29sb3IuanMiKCkgewogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0ZlYXR1cmVEZXRlY3Rpb24oKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIENvbG9yID0gY2xhc3MgX0NvbG9yIHsKICAgICAgICAvKioKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3JlZD0xLjBdIFRoZSByZWQgY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZ3JlZW49MS4wXSBUaGUgZ3JlZW4gY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYmx1ZT0xLjBdIFRoZSBibHVlIGNvbXBvbmVudC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2FscGhhPTEuMF0gVGhlIGFscGhhIGNvbXBvbmVudC4KICAgICAgICAgKi8KICAgICAgICBjb25zdHJ1Y3RvcihyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSkgewogICAgICAgICAgdGhpcy5yZWQgPSByZWQgPz8gMTsKICAgICAgICAgIHRoaXMuZ3JlZW4gPSBncmVlbiA/PyAxOwogICAgICAgICAgdGhpcy5ibHVlID0gYmx1ZSA/PyAxOwogICAgICAgICAgdGhpcy5hbHBoYSA9IGFscGhhID8/IDE7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBDb2xvciBpbnN0YW5jZSBmcm9tIGEge0BsaW5rIENhcnRlc2lhbjR9LiA8Y29kZT54PC9jb2RlPiwgPGNvZGU+eTwvY29kZT4sIDxjb2RlPno8L2NvZGU+LAogICAgICAgICAqIGFuZCA8Y29kZT53PC9jb2RlPiBtYXAgdG8gPGNvZGU+cmVkPC9jb2RlPiwgPGNvZGU+Z3JlZW48L2NvZGU+LCA8Y29kZT5ibHVlPC9jb2RlPiwgYW5kIDxjb2RlPmFscGhhPC9jb2RlPiwgcmVzcGVjdGl2ZWx5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDYXJ0ZXNpYW40fSBjYXJ0ZXNpYW4gVGhlIHNvdXJjZSBjYXJ0ZXNpYW4uCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NvbG9yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDb2xvciBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUNhcnRlc2lhbjQoY2FydGVzaWFuMTEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjYXJ0ZXNpYW4iLCBjYXJ0ZXNpYW4xMSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NvbG9yKGNhcnRlc2lhbjExLngsIGNhcnRlc2lhbjExLnksIGNhcnRlc2lhbjExLnosIGNhcnRlc2lhbjExLncpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnJlZCA9IGNhcnRlc2lhbjExLng7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBjYXJ0ZXNpYW4xMS55OwogICAgICAgICAgcmVzdWx0LmJsdWUgPSBjYXJ0ZXNpYW4xMS56OwogICAgICAgICAgcmVzdWx0LmFscGhhID0gY2FydGVzaWFuMTEudzsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgQ29sb3Igc3BlY2lmaWVkIHVzaW5nIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSB2YWx1ZXMKICAgICAgICAgKiB0aGF0IGFyZSBpbiB0aGUgcmFuZ2Ugb2YgMCB0byAyNTUsIGNvbnZlcnRpbmcgdGhlbSBpbnRlcm5hbGx5IHRvIGEgcmFuZ2Ugb2YgMC4wIHRvIDEuMC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbcmVkPTI1NV0gVGhlIHJlZCBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtncmVlbj0yNTVdIFRoZSBncmVlbiBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtibHVlPTI1NV0gVGhlIGJsdWUgY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYWxwaGE9MjU1XSBUaGUgYWxwaGEgY29tcG9uZW50LgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IFtyZXN1bHRdIFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ29sb3IgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21CeXRlcyhyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSwgcmVzdWx0KSB7CiAgICAgICAgICByZWQgPSBfQ29sb3IuYnl0ZVRvRmxvYXQocmVkID8/IDI1NSk7CiAgICAgICAgICBncmVlbiA9IF9Db2xvci5ieXRlVG9GbG9hdChncmVlbiA/PyAyNTUpOwogICAgICAgICAgYmx1ZSA9IF9Db2xvci5ieXRlVG9GbG9hdChibHVlID8/IDI1NSk7CiAgICAgICAgICBhbHBoYSA9IF9Db2xvci5ieXRlVG9GbG9hdChhbHBoYSA/PyAyNTUpOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9Db2xvcihyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQucmVkID0gcmVkOwogICAgICAgICAgcmVzdWx0LmdyZWVuID0gZ3JlZW47CiAgICAgICAgICByZXN1bHQuYmx1ZSA9IGJsdWU7CiAgICAgICAgICByZXN1bHQuYWxwaGEgPSBhbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgQ29sb3IgdGhhdCBoYXMgdGhlIHNhbWUgcmVkLCBncmVlbiwgYW5kIGJsdWUgY29tcG9uZW50cwogICAgICAgICAqIG9mIHRoZSBzcGVjaWZpZWQgY29sb3IsIGJ1dCB3aXRoIHRoZSBzcGVjaWZpZWQgYWxwaGEgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBjb2xvciBUaGUgYmFzZSBjb2xvcgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhbHBoYSBUaGUgbmV3IGFscGhhIGNvbXBvbmVudC4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBbcmVzdWx0XSBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IENvbG9yIGluc3RhbmNlIGlmIG9uZSB3YXMgbm90IHByb3ZpZGVkLgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUgY29uc3QgdHJhbnNsdWNlbnRSZWQgPSBDZXNpdW0uQ29sb3IuZnJvbUFscGhhKENlc2l1bS5Db2xvci5SRUQsIDAuOSk7CiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGZyb21BbHBoYShjb2xvciwgYWxwaGEsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjb2xvciIsIGNvbG9yKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiYWxwaGEiLCBhbHBoYSk7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NvbG9yKGNvbG9yLnJlZCwgY29sb3IuZ3JlZW4sIGNvbG9yLmJsdWUsIGFscGhhKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC5yZWQgPSBjb2xvci5yZWQ7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBjb2xvci5ncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gY29sb3IuYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGFscGhhOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIG5ldyBDb2xvciBmcm9tIGEgc2luZ2xlIG51bWVyaWMgdW5zaWduZWQgMzItYml0IFJHQkEgdmFsdWUsIHVzaW5nIHRoZSBlbmRpYW5uZXNzCiAgICAgICAgICogb2YgdGhlIHN5c3RlbS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSByZ2JhIEEgc2luZ2xlIG51bWVyaWMgdW5zaWduZWQgMzItYml0IFJHQkEgdmFsdWUuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW3Jlc3VsdF0gVGhlIG9iamVjdCB0byBzdG9yZSB0aGUgcmVzdWx0IGluLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIGNvbG9yIG9iamVjdC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgY29sb3IgPSBDZXNpdW0uQ29sb3IuZnJvbVJnYmEoMHg2N0FEREZGRik7CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIENvbG9yI3RvUmdiYQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUmdiYShyZ2JhLCByZXN1bHQpIHsKICAgICAgICAgIHNjcmF0Y2hVaW50MzJBcnJheVswXSA9IHJnYmE7CiAgICAgICAgICByZXR1cm4gX0NvbG9yLmZyb21CeXRlcygKICAgICAgICAgICAgc2NyYXRjaFVpbnQ4QXJyYXlbMF0sCiAgICAgICAgICAgIHNjcmF0Y2hVaW50OEFycmF5WzFdLAogICAgICAgICAgICBzY3JhdGNoVWludDhBcnJheVsyXSwKICAgICAgICAgICAgc2NyYXRjaFVpbnQ4QXJyYXlbM10sCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIENvbG9yIGluc3RhbmNlIGZyb20gaHVlLCBzYXR1cmF0aW9uLCBhbmQgbGlnaHRuZXNzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtodWU9MF0gVGhlIGh1ZSBhbmdsZSAwLi4uMQogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc2F0dXJhdGlvbj0wXSBUaGUgc2F0dXJhdGlvbiB2YWx1ZSAwLi4uMQogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbbGlnaHRuZXNzPTBdIFRoZSBsaWdodG5lc3MgdmFsdWUgMC4uLjEKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2FscGhhPTEuMF0gVGhlIGFscGhhIGNvbXBvbmVudCAwLi4uMQogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IFtyZXN1bHRdIFRoZSBvYmplY3QgdG8gc3RvcmUgdGhlIHJlc3VsdCBpbiwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBjb2xvciBvYmplY3QuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwOi8vd3d3LnczLm9yZy9UUi9jc3MzLWNvbG9yLyNoc2wtY29sb3J8Q1NTIGNvbG9yIHZhbHVlc30KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUhzbChodWUsIHNhdHVyYXRpb24sIGxpZ2h0bmVzcywgYWxwaGEsIHJlc3VsdCkgewogICAgICAgICAgaHVlID0gKGh1ZSA/PyAwKSAlIDE7CiAgICAgICAgICBzYXR1cmF0aW9uID0gc2F0dXJhdGlvbiA/PyAwOwogICAgICAgICAgbGlnaHRuZXNzID0gbGlnaHRuZXNzID8/IDA7CiAgICAgICAgICBhbHBoYSA9IGFscGhhID8/IDE7CiAgICAgICAgICBsZXQgcmVkID0gbGlnaHRuZXNzOwogICAgICAgICAgbGV0IGdyZWVuID0gbGlnaHRuZXNzOwogICAgICAgICAgbGV0IGJsdWUgPSBsaWdodG5lc3M7CiAgICAgICAgICBpZiAoc2F0dXJhdGlvbiAhPT0gMCkgewogICAgICAgICAgICBsZXQgbTI7CiAgICAgICAgICAgIGlmIChsaWdodG5lc3MgPCAwLjUpIHsKICAgICAgICAgICAgICBtMiA9IGxpZ2h0bmVzcyAqICgxICsgc2F0dXJhdGlvbik7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgbTIgPSBsaWdodG5lc3MgKyBzYXR1cmF0aW9uIC0gbGlnaHRuZXNzICogc2F0dXJhdGlvbjsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBtMSA9IDIgKiBsaWdodG5lc3MgLSBtMjsKICAgICAgICAgICAgcmVkID0gaHVlMnJnYihtMSwgbTIsIGh1ZSArIDEgLyAzKTsKICAgICAgICAgICAgZ3JlZW4gPSBodWUycmdiKG0xLCBtMiwgaHVlKTsKICAgICAgICAgICAgYmx1ZSA9IGh1ZTJyZ2IobTEsIG0yLCBodWUgLSAxIC8gMyk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgX0NvbG9yKHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC5yZWQgPSByZWQ7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGFscGhhOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlcyBhIHJhbmRvbSBjb2xvciB1c2luZyB0aGUgcHJvdmlkZWQgb3B0aW9ucy4gRm9yIHJlcHJvZHVjaWJsZSByYW5kb20gY29sb3JzLCB5b3Ugc2hvdWxkCiAgICAgICAgICogY2FsbCB7QGxpbmsgQ2VzaXVtTWF0aCNzZXRSYW5kb21OdW1iZXJTZWVkfSBvbmNlIGF0IHRoZSBiZWdpbm5pbmcgb2YgeW91ciBhcHBsaWNhdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gT2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5yZWRdIElmIHNwZWNpZmllZCwgdGhlIHJlZCBjb21wb25lbnQgdG8gdXNlIGluc3RlYWQgb2YgYSByYW5kb21pemVkIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5taW5pbXVtUmVkPTAuMF0gVGhlIG1heGltdW0gcmVkIHZhbHVlIHRvIGdlbmVyYXRlIGlmIG5vbmUgd2FzIHNwZWNpZmllZC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWF4aW11bVJlZD0xLjBdIFRoZSBtaW5pbXVtIHJlZCB2YWx1ZSB0byBnZW5lcmF0ZSBpZiBub25lIHdhcyBzcGVjaWZpZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmdyZWVuXSBJZiBzcGVjaWZpZWQsIHRoZSBncmVlbiBjb21wb25lbnQgdG8gdXNlIGluc3RlYWQgb2YgYSByYW5kb21pemVkIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5taW5pbXVtR3JlZW49MC4wXSBUaGUgbWF4aW11bSBncmVlbiB2YWx1ZSB0byBnZW5lcmF0ZSBpZiBub25lIHdhcyBzcGVjaWZpZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heGltdW1HcmVlbj0xLjBdIFRoZSBtaW5pbXVtIGdyZWVuIHZhbHVlIHRvIGdlbmVyYXRlIGlmIG5vbmUgd2FzIHNwZWNpZmllZC4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMuYmx1ZV0gSWYgc3BlY2lmaWVkLCB0aGUgYmx1ZSBjb21wb25lbnQgdG8gdXNlIGluc3RlYWQgb2YgYSByYW5kb21pemVkIHZhbHVlLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5taW5pbXVtQmx1ZT0wLjBdIFRoZSBtYXhpbXVtIGJsdWUgdmFsdWUgdG8gZ2VuZXJhdGUgaWYgbm9uZSB3YXMgc3BlY2lmaWVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5tYXhpbXVtQmx1ZT0xLjBdIFRoZSBtaW5pbXVtIGJsdWUgdmFsdWUgdG8gZ2VuZXJhdGUgaWYgbm9uZSB3YXMgc3BlY2lmaWVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5hbHBoYV0gSWYgc3BlY2lmaWVkLCB0aGUgYWxwaGEgY29tcG9uZW50IHRvIHVzZSBpbnN0ZWFkIG9mIGEgcmFuZG9taXplZCB2YWx1ZS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubWluaW11bUFscGhhPTAuMF0gVGhlIG1heGltdW0gYWxwaGEgdmFsdWUgdG8gZ2VuZXJhdGUgaWYgbm9uZSB3YXMgc3BlY2lmaWVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5tYXhpbXVtQWxwaGE9MS4wXSBUaGUgbWluaW11bSBhbHBoYSB2YWx1ZSB0byBnZW5lcmF0ZSBpZiBub25lIHdhcyBzcGVjaWZpZWQuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW3Jlc3VsdF0gVGhlIG9iamVjdCB0byBzdG9yZSB0aGUgcmVzdWx0IGluLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgaW5zdGFuY2UgaWYgcmVzdWx0IHdhcyB1bmRlZmluZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gbWluaW11bVJlZCBtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byBtYXhpbXVtUmVkLgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBtaW5pbXVtR3JlZW4gbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gbWF4aW11bUdyZWVuLgogICAgICAgICAqIEBleGNlcHRpb24ge0RldmVsb3BlckVycm9yfSBtaW5pbXVtQmx1ZSBtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byBtYXhpbXVtQmx1ZS4KICAgICAgICAgKiBAZXhjZXB0aW9uIHtEZXZlbG9wZXJFcnJvcn0gbWluaW11bUFscGhhIG11c3QgYmUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIG1heGltdW1BbHBoYS4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogLy9DcmVhdGUgYSBjb21wbGV0ZWx5IHJhbmRvbSBjb2xvcgogICAgICAgICAqIGNvbnN0IGNvbG9yID0gQ2VzaXVtLkNvbG9yLmZyb21SYW5kb20oKTsKICAgICAgICAgKgogICAgICAgICAqIC8vQ3JlYXRlIGEgcmFuZG9tIHNoYWRlIG9mIHllbGxvdy4KICAgICAgICAgKiBjb25zdCBjb2xvcjEgPSBDZXNpdW0uQ29sb3IuZnJvbVJhbmRvbSh7CiAgICAgICAgICogICAgIHJlZCA6IDEuMCwKICAgICAgICAgKiAgICAgZ3JlZW4gOiAxLjAsCiAgICAgICAgICogICAgIGFscGhhIDogMS4wCiAgICAgICAgICogfSk7CiAgICAgICAgICoKICAgICAgICAgKiAvL0NyZWF0ZSBhIHJhbmRvbSBicmlnaHQgY29sb3IuCiAgICAgICAgICogY29uc3QgY29sb3IyID0gQ2VzaXVtLkNvbG9yLmZyb21SYW5kb20oewogICAgICAgICAqICAgICBtaW5pbXVtUmVkIDogMC43NSwKICAgICAgICAgKiAgICAgbWluaW11bUdyZWVuIDogMC43NSwKICAgICAgICAgKiAgICAgbWluaW11bUJsdWUgOiAwLjc1LAogICAgICAgICAqICAgICBhbHBoYSA6IDEuMAogICAgICAgICAqIH0pOwogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmcm9tUmFuZG9tKG9wdGlvbnMsIHJlc3VsdCkgewogICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgICAgbGV0IHJlZCA9IG9wdGlvbnMucmVkOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVkKSkgewogICAgICAgICAgICBjb25zdCBtaW5pbXVtUmVkID0gb3B0aW9ucy5taW5pbXVtUmVkID8/IDA7CiAgICAgICAgICAgIGNvbnN0IG1heGltdW1SZWQgPSBvcHRpb25zLm1heGltdW1SZWQgPz8gMTsKICAgICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoCiAgICAgICAgICAgICAgIm1pbmltdW1SZWQiLAogICAgICAgICAgICAgIG1pbmltdW1SZWQsCiAgICAgICAgICAgICAgbWF4aW11bVJlZAogICAgICAgICAgICApOwogICAgICAgICAgICByZWQgPSBtaW5pbXVtUmVkICsgTWF0aF9kZWZhdWx0Lm5leHRSYW5kb21OdW1iZXIoKSAqIChtYXhpbXVtUmVkIC0gbWluaW11bVJlZCk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgZ3JlZW4gPSBvcHRpb25zLmdyZWVuOwogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZ3JlZW4pKSB7CiAgICAgICAgICAgIGNvbnN0IG1pbmltdW1HcmVlbiA9IG9wdGlvbnMubWluaW11bUdyZWVuID8/IDA7CiAgICAgICAgICAgIGNvbnN0IG1heGltdW1HcmVlbiA9IG9wdGlvbnMubWF4aW11bUdyZWVuID8/IDE7CiAgICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5sZXNzVGhhbk9yRXF1YWxzKAogICAgICAgICAgICAgICJtaW5pbXVtR3JlZW4iLAogICAgICAgICAgICAgIG1pbmltdW1HcmVlbiwKICAgICAgICAgICAgICBtYXhpbXVtR3JlZW4KICAgICAgICAgICAgKTsKICAgICAgICAgICAgZ3JlZW4gPSBtaW5pbXVtR3JlZW4gKyBNYXRoX2RlZmF1bHQubmV4dFJhbmRvbU51bWJlcigpICogKG1heGltdW1HcmVlbiAtIG1pbmltdW1HcmVlbik7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgYmx1ZSA9IG9wdGlvbnMuYmx1ZTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGJsdWUpKSB7CiAgICAgICAgICAgIGNvbnN0IG1pbmltdW1CbHVlID0gb3B0aW9ucy5taW5pbXVtQmx1ZSA/PyAwOwogICAgICAgICAgICBjb25zdCBtYXhpbXVtQmx1ZSA9IG9wdGlvbnMubWF4aW11bUJsdWUgPz8gMTsKICAgICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmxlc3NUaGFuT3JFcXVhbHMoCiAgICAgICAgICAgICAgIm1pbmltdW1CbHVlIiwKICAgICAgICAgICAgICBtaW5pbXVtQmx1ZSwKICAgICAgICAgICAgICBtYXhpbXVtQmx1ZQogICAgICAgICAgICApOwogICAgICAgICAgICBibHVlID0gbWluaW11bUJsdWUgKyBNYXRoX2RlZmF1bHQubmV4dFJhbmRvbU51bWJlcigpICogKG1heGltdW1CbHVlIC0gbWluaW11bUJsdWUpOwogICAgICAgICAgfQogICAgICAgICAgbGV0IGFscGhhID0gb3B0aW9ucy5hbHBoYTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFscGhhKSkgewogICAgICAgICAgICBjb25zdCBtaW5pbXVtQWxwaGEgPSBvcHRpb25zLm1pbmltdW1BbHBoYSA/PyAwOwogICAgICAgICAgICBjb25zdCBtYXhpbXVtQWxwaGEgPSBvcHRpb25zLm1heGltdW1BbHBoYSA/PyAxOwogICAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIubGVzc1RoYW5PckVxdWFscygKICAgICAgICAgICAgICAibWluaW11bUFscGhhIiwKICAgICAgICAgICAgICBtaW5pbXVtQWxwaGEsCiAgICAgICAgICAgICAgbWF4aW11bUFscGhhCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGFscGhhID0gbWluaW11bUFscGhhICsgTWF0aF9kZWZhdWx0Lm5leHRSYW5kb21OdW1iZXIoKSAqIChtYXhpbXVtQWxwaGEgLSBtaW5pbXVtQWxwaGEpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgICByZXR1cm4gbmV3IF9Db2xvcihyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQucmVkID0gcmVkOwogICAgICAgICAgcmVzdWx0LmdyZWVuID0gZ3JlZW47CiAgICAgICAgICByZXN1bHQuYmx1ZSA9IGJsdWU7CiAgICAgICAgICByZXN1bHQuYWxwaGEgPSBhbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBDb2xvciBpbnN0YW5jZSBmcm9tIGEgQ1NTIGNvbG9yIHZhbHVlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGNvbG9yIFRoZSBDU1MgY29sb3IgdmFsdWUgaW4gI3JnYiwgI3JnYmEsICNycmdnYmIsICNycmdnYmJhYSwgcmdiKCksIHJnYmEoKSwgaHNsKCksIG9yIGhzbGEoKSBmb3JtYXQuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW3Jlc3VsdF0gVGhlIG9iamVjdCB0byBzdG9yZSB0aGUgcmVzdWx0IGluLCBpZiB1bmRlZmluZWQgYSBuZXcgaW5zdGFuY2Ugd2lsbCBiZSBjcmVhdGVkLgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIGNvbG9yIG9iamVjdCwgb3IgdW5kZWZpbmVkIGlmIHRoZSBzdHJpbmcgd2FzIG5vdCBhIHZhbGlkIENTUyBjb2xvci4KICAgICAgICAgKgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiBjb25zdCBjZXNpdW1CbHVlID0gQ2VzaXVtLkNvbG9yLmZyb21Dc3NDb2xvclN0cmluZygnIzY3QURERicpOwogICAgICAgICAqIGNvbnN0IGdyZWVuID0gQ2VzaXVtLkNvbG9yLmZyb21Dc3NDb2xvclN0cmluZygnZ3JlZW4nKTsKICAgICAgICAgKgogICAgICAgICAqIEBzZWUge0BsaW5rIGh0dHA6Ly93d3cudzMub3JnL1RSL2NzczMtY29sb3J8Q1NTIGNvbG9yIHZhbHVlc30KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZnJvbUNzc0NvbG9yU3RyaW5nKGNvbG9yLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLnN0cmluZygiY29sb3IiLCBjb2xvcik7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBfQ29sb3IoKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbG9yID0gY29sb3IudHJpbSgpOwogICAgICAgICAgY29uc3QgbmFtZWRDb2xvciA9IF9Db2xvcltjb2xvci50b1VwcGVyQ2FzZSgpXTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobmFtZWRDb2xvcikpIHsKICAgICAgICAgICAgX0NvbG9yLmNsb25lKG5hbWVkQ29sb3IsIHJlc3VsdCk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgbWF0Y2hlcyA9IHJnYmFNYXRjaGVyLmV4ZWMoY29sb3IpOwogICAgICAgICAgaWYgKG1hdGNoZXMgIT09IG51bGwpIHsKICAgICAgICAgICAgcmVzdWx0LnJlZCA9IHBhcnNlSW50KG1hdGNoZXNbMV0sIDE2KSAvIDE1OwogICAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBwYXJzZUludChtYXRjaGVzWzJdLCAxNikgLyAxNTsKICAgICAgICAgICAgcmVzdWx0LmJsdWUgPSBwYXJzZUludChtYXRjaGVzWzNdLCAxNikgLyAxNTsKICAgICAgICAgICAgcmVzdWx0LmFscGhhID0gcGFyc2VJbnQobWF0Y2hlc1s0XSA/PyAiZiIsIDE2KSAvIDE1OwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgbWF0Y2hlcyA9IHJyZ2diYmFhTWF0Y2hlci5leGVjKGNvbG9yKTsKICAgICAgICAgIGlmIChtYXRjaGVzICE9PSBudWxsKSB7CiAgICAgICAgICAgIHJlc3VsdC5yZWQgPSBwYXJzZUludChtYXRjaGVzWzFdLCAxNikgLyAyNTU7CiAgICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IHBhcnNlSW50KG1hdGNoZXNbMl0sIDE2KSAvIDI1NTsKICAgICAgICAgICAgcmVzdWx0LmJsdWUgPSBwYXJzZUludChtYXRjaGVzWzNdLCAxNikgLyAyNTU7CiAgICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IHBhcnNlSW50KG1hdGNoZXNbNF0gPz8gImZmIiwgMTYpIC8gMjU1OwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgbWF0Y2hlcyA9IHJnYlBhcmVudGhlc2VzTWF0Y2hlci5leGVjKGNvbG9yKTsKICAgICAgICAgIGlmIChtYXRjaGVzICE9PSBudWxsKSB7CiAgICAgICAgICAgIHJlc3VsdC5yZWQgPSBwYXJzZUZsb2F0KG1hdGNoZXNbMV0pIC8gKCIlIiA9PT0gbWF0Y2hlc1sxXS5zdWJzdHIoLTEpID8gMTAwIDogMjU1KTsKICAgICAgICAgICAgcmVzdWx0LmdyZWVuID0gcGFyc2VGbG9hdChtYXRjaGVzWzJdKSAvICgiJSIgPT09IG1hdGNoZXNbMl0uc3Vic3RyKC0xKSA/IDEwMCA6IDI1NSk7CiAgICAgICAgICAgIHJlc3VsdC5ibHVlID0gcGFyc2VGbG9hdChtYXRjaGVzWzNdKSAvICgiJSIgPT09IG1hdGNoZXNbM10uc3Vic3RyKC0xKSA/IDEwMCA6IDI1NSk7CiAgICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IHBhcnNlRmxvYXQobWF0Y2hlc1s0XSA/PyAiMS4wIik7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9CiAgICAgICAgICBtYXRjaGVzID0gaHNsUGFyZW50aGVzZXNNYXRjaGVyLmV4ZWMoY29sb3IpOwogICAgICAgICAgaWYgKG1hdGNoZXMgIT09IG51bGwpIHsKICAgICAgICAgICAgcmV0dXJuIF9Db2xvci5mcm9tSHNsKAogICAgICAgICAgICAgIHBhcnNlRmxvYXQobWF0Y2hlc1sxXSkgLyAzNjAsCiAgICAgICAgICAgICAgcGFyc2VGbG9hdChtYXRjaGVzWzJdKSAvIDEwMCwKICAgICAgICAgICAgICBwYXJzZUZsb2F0KG1hdGNoZXNbM10pIC8gMTAwLAogICAgICAgICAgICAgIHBhcnNlRmxvYXQobWF0Y2hlc1s0XSA/PyAiMS4wIiksCiAgICAgICAgICAgICAgcmVzdWx0CiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHQgPSB2b2lkIDA7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBTdG9yZXMgdGhlIHByb3ZpZGVkIGluc3RhbmNlIGludG8gdGhlIHByb3ZpZGVkIGFycmF5LgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gdmFsdWUgVGhlIHZhbHVlIHRvIHBhY2suCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJbXXxUeXBlZEFycmF5fSBhcnJheSBUaGUgYXJyYXkgdG8gcGFjayBpbnRvLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRpbmdJbmRleD0wXSBUaGUgaW5kZXggaW50byB0aGUgYXJyYXkgYXQgd2hpY2ggdG8gc3RhcnQgcGFja2luZyB0aGUgZWxlbWVudHMuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW118VHlwZWRBcnJheX0gVGhlIGFycmF5IHRoYXQgd2FzIHBhY2tlZCBpbnRvCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHBhY2sodmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUucmVkOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLmdyZWVuOwogICAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLmJsdWU7CiAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLmFscGhhOwogICAgICAgICAgcmV0dXJuIGFycmF5OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXRyaWV2ZXMgYW4gaW5zdGFuY2UgZnJvbSBhIHBhY2tlZCBhcnJheS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyW118VHlwZWRBcnJheX0gYXJyYXkgVGhlIHBhY2tlZCBhcnJheS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0aW5nSW5kZXg9MF0gVGhlIHN0YXJ0aW5nIGluZGV4IG9mIHRoZSBlbGVtZW50IHRvIGJlIHVucGFja2VkLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IFtyZXN1bHRdIFRoZSBvYmplY3QgaW50byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIgb3IgYSBuZXcgQ29sb3IgaW5zdGFuY2UgaWYgb25lIHdhcyBub3QgcHJvdmlkZWQuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoImFycmF5IiwgYXJyYXkpOwogICAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmVzdWx0ID0gbmV3IF9Db2xvcigpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnJlZCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0LmJsdWUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgcmVzdWx0LmFscGhhID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyBhICdieXRlJyBjb2xvciBjb21wb25lbnQgaW4gdGhlIHJhbmdlIG9mIDAgdG8gMjU1IGludG8KICAgICAgICAgKiBhICdmbG9hdCcgY29sb3IgY29tcG9uZW50IGluIHRoZSByYW5nZSBvZiAwIHRvIDEuMC4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBudW1iZXIgVGhlIG51bWJlciB0byBiZSBjb252ZXJ0ZWQuCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gVGhlIGNvbnZlcnRlZCBudW1iZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGJ5dGVUb0Zsb2F0KG51bWJlcikgewogICAgICAgICAgcmV0dXJuIG51bWJlciAvIDI1NTsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydHMgYSAnZmxvYXQnIGNvbG9yIGNvbXBvbmVudCBpbiB0aGUgcmFuZ2Ugb2YgMCB0byAxLjAgaW50bwogICAgICAgICAqIGEgJ2J5dGUnIGNvbG9yIGNvbXBvbmVudCBpbiB0aGUgcmFuZ2Ugb2YgMCB0byAyNTUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbnVtYmVyIFRoZSBudW1iZXIgdG8gYmUgY29udmVydGVkLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBjb252ZXJ0ZWQgbnVtYmVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBmbG9hdFRvQnl0ZShudW1iZXIpIHsKICAgICAgICAgIHJldHVybiBudW1iZXIgPT09IDEgPyAyNTUgOiBudW1iZXIgKiAyNTYgfCAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEdXBsaWNhdGVzIGEgQ29sb3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBjb2xvciBUaGUgQ29sb3IgdG8gZHVwbGljYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IFtyZXN1bHRdIFRoZSBvYmplY3QgdG8gc3RvcmUgdGhlIHJlc3VsdCBpbiwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IGluc3RhbmNlIGlmIHJlc3VsdCB3YXMgdW5kZWZpbmVkLiAoUmV0dXJucyB1bmRlZmluZWQgaWYgY29sb3IgaXMgdW5kZWZpbmVkKQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBjbG9uZShjb2xvciwgcmVzdWx0KSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb2xvcikpIHsKICAgICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBfQ29sb3IoY29sb3IucmVkLCBjb2xvci5ncmVlbiwgY29sb3IuYmx1ZSwgY29sb3IuYWxwaGEpOwogICAgICAgICAgfQogICAgICAgICAgcmVzdWx0LnJlZCA9IGNvbG9yLnJlZDsKICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IGNvbG9yLmdyZWVuOwogICAgICAgICAgcmVzdWx0LmJsdWUgPSBjb2xvci5ibHVlOwogICAgICAgICAgcmVzdWx0LmFscGhhID0gY29sb3IuYWxwaGE7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIGZpcnN0IENvbG9yIGVxdWFscyB0aGUgc2Vjb25kIGNvbG9yLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW2xlZnRdIFRoZSBmaXJzdCBDb2xvciB0byBjb21wYXJlIGZvciBlcXVhbGl0eS4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBbcmlnaHRdIFRoZSBzZWNvbmQgQ29sb3IgdG8gY29tcGFyZSBmb3IgZXF1YWxpdHkuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBDb2xvcnMgYXJlIGVxdWFsOyBvdGhlcndpc2UsIDxjb2RlPmZhbHNlPC9jb2RlPi4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgZXF1YWxzKGxlZnQsIHJpZ2h0KSB7CiAgICAgICAgICByZXR1cm4gbGVmdCA9PT0gcmlnaHQgfHwgLy8KICAgICAgICAgIGRlZmluZWRfZGVmYXVsdChsZWZ0KSAmJiAvLwogICAgICAgICAgZGVmaW5lZF9kZWZhdWx0KHJpZ2h0KSAmJiAvLwogICAgICAgICAgbGVmdC5yZWQgPT09IHJpZ2h0LnJlZCAmJiAvLwogICAgICAgICAgbGVmdC5ncmVlbiA9PT0gcmlnaHQuZ3JlZW4gJiYgLy8KICAgICAgICAgIGxlZnQuYmx1ZSA9PT0gcmlnaHQuYmx1ZSAmJiAvLwogICAgICAgICAgbGVmdC5hbHBoYSA9PT0gcmlnaHQuYWxwaGE7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIGVxdWFsc0FycmF5KGNvbG9yLCBhcnJheSwgb2Zmc2V0KSB7CiAgICAgICAgICByZXR1cm4gY29sb3IucmVkID09PSBhcnJheVtvZmZzZXRdICYmIGNvbG9yLmdyZWVuID09PSBhcnJheVtvZmZzZXQgKyAxXSAmJiBjb2xvci5ibHVlID09PSBhcnJheVtvZmZzZXQgKyAyXSAmJiBjb2xvci5hbHBoYSA9PT0gYXJyYXlbb2Zmc2V0ICsgM107CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIFJldHVybnMgYSBkdXBsaWNhdGUgb2YgYSBDb2xvciBpbnN0YW5jZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IFtyZXN1bHRdIFRoZSBvYmplY3QgdG8gc3RvcmUgdGhlIHJlc3VsdCBpbiwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IGluc3RhbmNlIGlmIHJlc3VsdCB3YXMgdW5kZWZpbmVkLgogICAgICAgICAqLwogICAgICAgIGNsb25lKHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIF9Db2xvci5jbG9uZSh0aGlzLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBDb2xvciBlcXVhbHMgb3RoZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBbb3RoZXJdIFRoZSBDb2xvciB0byBjb21wYXJlIGZvciBlcXVhbGl0eS4KICAgICAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIENvbG9ycyBhcmUgZXF1YWw7IG90aGVyd2lzZSwgPGNvZGU+ZmFsc2U8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIGVxdWFscyhvdGhlcikgewogICAgICAgICAgcmV0dXJuIF9Db2xvci5lcXVhbHModGhpcywgb3RoZXIpOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBSZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoaXMgQ29sb3IgZXF1YWxzIG90aGVyIGNvbXBvbmVudHdpc2Ugd2l0aGluIHRoZSBzcGVjaWZpZWQgZXBzaWxvbi4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IG90aGVyIFRoZSBDb2xvciB0byBjb21wYXJlIGZvciBlcXVhbGl0eS4KICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW2Vwc2lsb249MC4wXSBUaGUgZXBzaWxvbiB0byB1c2UgZm9yIGVxdWFsaXR5IHRlc3RpbmcuCiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59IDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBDb2xvcnMgYXJlIGVxdWFsIHdpdGhpbiB0aGUgc3BlY2lmaWVkIGVwc2lsb247IG90aGVyd2lzZSwgPGNvZGU+ZmFsc2U8L2NvZGU+LgogICAgICAgICAqLwogICAgICAgIGVxdWFsc0Vwc2lsb24ob3RoZXIsIGVwc2lsb24pIHsKICAgICAgICAgIHJldHVybiB0aGlzID09PSBvdGhlciB8fCAvLwogICAgICAgICAgZGVmaW5lZF9kZWZhdWx0KG90aGVyKSAmJiAvLwogICAgICAgICAgTWF0aC5hYnModGhpcy5yZWQgLSBvdGhlci5yZWQpIDw9IGVwc2lsb24gJiYgLy8KICAgICAgICAgIE1hdGguYWJzKHRoaXMuZ3JlZW4gLSBvdGhlci5ncmVlbikgPD0gZXBzaWxvbiAmJiAvLwogICAgICAgICAgTWF0aC5hYnModGhpcy5ibHVlIC0gb3RoZXIuYmx1ZSkgPD0gZXBzaWxvbiAmJiAvLwogICAgICAgICAgTWF0aC5hYnModGhpcy5hbHBoYSAtIG90aGVyLmFscGhhKSA8PSBlcHNpbG9uOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGlzIENvbG9yIGluIHRoZSBmb3JtYXQgJyhyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSknLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge3N0cmluZ30gQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoaXMgQ29sb3IgaW4gdGhlIGZvcm1hdCAnKHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhKScuCiAgICAgICAgICovCiAgICAgICAgdG9TdHJpbmcoKSB7CiAgICAgICAgICByZXR1cm4gYCgke3RoaXMucmVkfSwgJHt0aGlzLmdyZWVufSwgJHt0aGlzLmJsdWV9LCAke3RoaXMuYWxwaGF9KWA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBzdHJpbmcgY29udGFpbmluZyB0aGUgQ1NTIGNvbG9yIHZhbHVlIGZvciB0aGlzIGNvbG9yLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIENTUyBlcXVpdmFsZW50IG9mIHRoaXMgY29sb3IuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwOi8vd3d3LnczLm9yZy9UUi9jc3MzLWNvbG9yLyNyZ2JhLWNvbG9yfENTUyBSR0Igb3IgUkdCQSBjb2xvciB2YWx1ZXN9CiAgICAgICAgICovCiAgICAgICAgdG9Dc3NDb2xvclN0cmluZygpIHsKICAgICAgICAgIGNvbnN0IHJlZCA9IF9Db2xvci5mbG9hdFRvQnl0ZSh0aGlzLnJlZCk7CiAgICAgICAgICBjb25zdCBncmVlbiA9IF9Db2xvci5mbG9hdFRvQnl0ZSh0aGlzLmdyZWVuKTsKICAgICAgICAgIGNvbnN0IGJsdWUgPSBfQ29sb3IuZmxvYXRUb0J5dGUodGhpcy5ibHVlKTsKICAgICAgICAgIGlmICh0aGlzLmFscGhhID09PSAxKSB7CiAgICAgICAgICAgIHJldHVybiBgcmdiKCR7cmVkfSwke2dyZWVufSwke2JsdWV9KWA7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gYHJnYmEoJHtyZWR9LCR7Z3JlZW59LCR7Ymx1ZX0sJHt0aGlzLmFscGhhfSlgOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDcmVhdGVzIGEgc3RyaW5nIGNvbnRhaW5pbmcgQ1NTIGhleCBzdHJpbmcgY29sb3IgdmFsdWUgZm9yIHRoaXMgY29sb3IuCiAgICAgICAgICoKICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQ1NTIGhleCBzdHJpbmcgZXF1aXZhbGVudCBvZiB0aGlzIGNvbG9yLgogICAgICAgICAqLwogICAgICAgIHRvQ3NzSGV4U3RyaW5nKCkgewogICAgICAgICAgbGV0IHIyID0gX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMucmVkKS50b1N0cmluZygxNik7CiAgICAgICAgICBpZiAocjIubGVuZ3RoIDwgMikgewogICAgICAgICAgICByMiA9IGAwJHtyMn1gOwogICAgICAgICAgfQogICAgICAgICAgbGV0IGcyID0gX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMuZ3JlZW4pLnRvU3RyaW5nKDE2KTsKICAgICAgICAgIGlmIChnMi5sZW5ndGggPCAyKSB7CiAgICAgICAgICAgIGcyID0gYDAke2cyfWA7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgYjIgPSBfQ29sb3IuZmxvYXRUb0J5dGUodGhpcy5ibHVlKS50b1N0cmluZygxNik7CiAgICAgICAgICBpZiAoYjIubGVuZ3RoIDwgMikgewogICAgICAgICAgICBiMiA9IGAwJHtiMn1gOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHRoaXMuYWxwaGEgPCAxKSB7CiAgICAgICAgICAgIGxldCBoZXhBbHBoYSA9IF9Db2xvci5mbG9hdFRvQnl0ZSh0aGlzLmFscGhhKS50b1N0cmluZygxNik7CiAgICAgICAgICAgIGlmIChoZXhBbHBoYS5sZW5ndGggPCAyKSB7CiAgICAgICAgICAgICAgaGV4QWxwaGEgPSBgMCR7aGV4QWxwaGF9YDsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gYCMke3IyfSR7ZzJ9JHtiMn0ke2hleEFscGhhfWA7CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gYCMke3IyfSR7ZzJ9JHtiMn1gOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIGNvbG9yIHRvIGFuIGFycmF5IG9mIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSB2YWx1ZXMKICAgICAgICAgKiB0aGF0IGFyZSBpbiB0aGUgcmFuZ2Ugb2YgMCB0byAyNTUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcltdfSBbcmVzdWx0XSBUaGUgYXJyYXkgdG8gc3RvcmUgdGhlIHJlc3VsdCBpbiwgaWYgdW5kZWZpbmVkIGEgbmV3IGluc3RhbmNlIHdpbGwgYmUgY3JlYXRlZC4KICAgICAgICAgKiBAcmV0dXJucyB7bnVtYmVyW119IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyIG9yIGEgbmV3IGluc3RhbmNlIGlmIHJlc3VsdCB3YXMgdW5kZWZpbmVkLgogICAgICAgICAqLwogICAgICAgIHRvQnl0ZXMocmVzdWx0KSB7CiAgICAgICAgICBjb25zdCByZWQgPSBfQ29sb3IuZmxvYXRUb0J5dGUodGhpcy5yZWQpOwogICAgICAgICAgY29uc3QgZ3JlZW4gPSBfQ29sb3IuZmxvYXRUb0J5dGUodGhpcy5ncmVlbik7CiAgICAgICAgICBjb25zdCBibHVlID0gX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMuYmx1ZSk7CiAgICAgICAgICBjb25zdCBhbHBoYSA9IF9Db2xvci5mbG9hdFRvQnl0ZSh0aGlzLmFscGhhKTsKICAgICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgICAgcmV0dXJuIFtyZWQsIGdyZWVuLCBibHVlLCBhbHBoYV07CiAgICAgICAgICB9CiAgICAgICAgICByZXN1bHRbMF0gPSByZWQ7CiAgICAgICAgICByZXN1bHRbMV0gPSBncmVlbjsKICAgICAgICAgIHJlc3VsdFsyXSA9IGJsdWU7CiAgICAgICAgICByZXN1bHRbM10gPSBhbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIFJHQkEgdmFsdWVzIGluIGJ5dGVzIHRvIGEgc2luZ2xlIG51bWVyaWMgdW5zaWduZWQgMzItYml0IFJHQkEgdmFsdWUsIHVzaW5nIHRoZSBlbmRpYW5uZXNzCiAgICAgICAgICogb2YgdGhlIHN5c3RlbS4KICAgICAgICAgKgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IEEgc2luZ2xlIG51bWVyaWMgdW5zaWduZWQgMzItYml0IFJHQkEgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIENvbG9yLnRvUmdiYQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBieXRlc1RvUmdiYShyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSkgewogICAgICAgICAgc2NyYXRjaFVpbnQ4QXJyYXlbMF0gPSByZWQ7CiAgICAgICAgICBzY3JhdGNoVWludDhBcnJheVsxXSA9IGdyZWVuOwogICAgICAgICAgc2NyYXRjaFVpbnQ4QXJyYXlbMl0gPSBibHVlOwogICAgICAgICAgc2NyYXRjaFVpbnQ4QXJyYXlbM10gPSBhbHBoYTsKICAgICAgICAgIHJldHVybiBzY3JhdGNoVWludDMyQXJyYXlbMF07CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbnZlcnRzIHRoaXMgY29sb3IgdG8gYSBzaW5nbGUgbnVtZXJpYyB1bnNpZ25lZCAzMi1iaXQgUkdCQSB2YWx1ZSwgdXNpbmcgdGhlIGVuZGlhbm5lc3MKICAgICAgICAgKiBvZiB0aGUgc3lzdGVtLgogICAgICAgICAqCiAgICAgICAgICogQHJldHVybnMge251bWJlcn0gQSBzaW5nbGUgbnVtZXJpYyB1bnNpZ25lZCAzMi1iaXQgUkdCQSB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqCiAgICAgICAgICogQGV4YW1wbGUKICAgICAgICAgKiBjb25zdCByZ2JhID0gQ2VzaXVtLkNvbG9yLkJMVUUudG9SZ2JhKCk7CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIENvbG9yLmZyb21SZ2JhCiAgICAgICAgICovCiAgICAgICAgdG9SZ2JhKCkgewogICAgICAgICAgcmV0dXJuIF9Db2xvci5ieXRlc1RvUmdiYSgKICAgICAgICAgICAgX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMucmVkKSwKICAgICAgICAgICAgX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMuZ3JlZW4pLAogICAgICAgICAgICBfQ29sb3IuZmxvYXRUb0J5dGUodGhpcy5ibHVlKSwKICAgICAgICAgICAgX0NvbG9yLmZsb2F0VG9CeXRlKHRoaXMuYWxwaGEpCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBCcmlnaHRlbnMgdGhpcyBjb2xvciBieSB0aGUgcHJvdmlkZWQgbWFnbml0dWRlLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG1hZ25pdHVkZSBBIHBvc2l0aXZlIG51bWJlciBpbmRpY2F0aW5nIHRoZSBhbW91bnQgdG8gYnJpZ2h0ZW4uCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICoKICAgICAgICAgKiBAZXhhbXBsZQogICAgICAgICAqIGNvbnN0IGJyaWdodEJsdWUgPSBDZXNpdW0uQ29sb3IuQkxVRS5icmlnaHRlbigwLjUsIG5ldyBDZXNpdW0uQ29sb3IoKSk7CiAgICAgICAgICovCiAgICAgICAgYnJpZ2h0ZW4obWFnbml0dWRlLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigibWFnbml0dWRlIiwgbWFnbml0dWRlKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlci5ncmVhdGVyVGhhbk9yRXF1YWxzKCJtYWduaXR1ZGUiLCBtYWduaXR1ZGUsIDApOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgbWFnbml0dWRlID0gMSAtIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSAxIC0gKDEgLSB0aGlzLnJlZCkgKiBtYWduaXR1ZGU7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSAxIC0gKDEgLSB0aGlzLmdyZWVuKSAqIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gMSAtICgxIC0gdGhpcy5ibHVlKSAqIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IHRoaXMuYWxwaGE7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEYXJrZW5zIHRoaXMgY29sb3IgYnkgdGhlIHByb3ZpZGVkIG1hZ25pdHVkZS4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtYWduaXR1ZGUgQSBwb3NpdGl2ZSBudW1iZXIgaW5kaWNhdGluZyB0aGUgYW1vdW50IHRvIGRhcmtlbi4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NvbG9yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlCiAgICAgICAgICogY29uc3QgZGFya0JsdWUgPSBDZXNpdW0uQ29sb3IuQkxVRS5kYXJrZW4oMC41LCBuZXcgQ2VzaXVtLkNvbG9yKCkpOwogICAgICAgICAqLwogICAgICAgIGRhcmtlbihtYWduaXR1ZGUsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJtYWduaXR1ZGUiLCBtYWduaXR1ZGUpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyLmdyZWF0ZXJUaGFuT3JFcXVhbHMoIm1hZ25pdHVkZSIsIG1hZ25pdHVkZSwgMCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICBtYWduaXR1ZGUgPSAxIC0gbWFnbml0dWRlOwogICAgICAgICAgcmVzdWx0LnJlZCA9IHRoaXMucmVkICogbWFnbml0dWRlOwogICAgICAgICAgcmVzdWx0LmdyZWVuID0gdGhpcy5ncmVlbiAqIG1hZ25pdHVkZTsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gdGhpcy5ibHVlICogbWFnbml0dWRlOwogICAgICAgICAgcmVzdWx0LmFscGhhID0gdGhpcy5hbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgQ29sb3IgdGhhdCBoYXMgdGhlIHNhbWUgcmVkLCBncmVlbiwgYW5kIGJsdWUgY29tcG9uZW50cwogICAgICAgICAqIGFzIHRoaXMgQ29sb3IsIGJ1dCB3aXRoIHRoZSBzcGVjaWZpZWQgYWxwaGEgdmFsdWUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gYWxwaGEgVGhlIG5ldyBhbHBoYSBjb21wb25lbnQuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gW3Jlc3VsdF0gVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NvbG9yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlciBvciBhIG5ldyBDb2xvciBpbnN0YW5jZSBpZiBvbmUgd2FzIG5vdCBwcm92aWRlZC4KICAgICAgICAgKgogICAgICAgICAqIEBleGFtcGxlIGNvbnN0IHRyYW5zbHVjZW50UmVkID0gQ2VzaXVtLkNvbG9yLlJFRC53aXRoQWxwaGEoMC45KTsKICAgICAgICAgKi8KICAgICAgICB3aXRoQWxwaGEoYWxwaGEsIHJlc3VsdCkgewogICAgICAgICAgcmV0dXJuIF9Db2xvci5mcm9tQWxwaGEodGhpcywgYWxwaGEsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHN1bSBvZiB0d28gQ29sb3JzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gbGVmdCBUaGUgZmlyc3QgQ29sb3IuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gcmlnaHQgVGhlIHNlY29uZCBDb2xvci4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NvbG9yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgYWRkKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSBsZWZ0LnJlZCArIHJpZ2h0LnJlZDsKICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IGxlZnQuZ3JlZW4gKyByaWdodC5ncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gbGVmdC5ibHVlICsgcmlnaHQuYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGxlZnQuYWxwaGEgKyByaWdodC5hbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIGRpZmZlcmVuY2Ugb2YgdHdvIENvbG9ycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IGxlZnQgVGhlIGZpcnN0IENvbG9yLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJpZ2h0IFRoZSBzZWNvbmQgQ29sb3IuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIHN1YnRyYWN0KGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSBsZWZ0LnJlZCAtIHJpZ2h0LnJlZDsKICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IGxlZnQuZ3JlZW4gLSByaWdodC5ncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gbGVmdC5ibHVlIC0gcmlnaHQuYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGxlZnQuYWxwaGEgLSByaWdodC5hbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHByb2R1Y3Qgb2YgdHdvIENvbG9ycy4KICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IGxlZnQgVGhlIGZpcnN0IENvbG9yLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJpZ2h0IFRoZSBzZWNvbmQgQ29sb3IuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gcmVzdWx0IFRoZSBvYmplY3Qgb250byB3aGljaCB0byBzdG9yZSB0aGUgcmVzdWx0LgogICAgICAgICAqIEByZXR1cm5zIHtDb2xvcn0gVGhlIG1vZGlmaWVkIHJlc3VsdCBwYXJhbWV0ZXIuCiAgICAgICAgICovCiAgICAgICAgc3RhdGljIG11bHRpcGx5KGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSBsZWZ0LnJlZCAqIHJpZ2h0LnJlZDsKICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IGxlZnQuZ3JlZW4gKiByaWdodC5ncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gbGVmdC5ibHVlICogcmlnaHQuYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGxlZnQuYWxwaGEgKiByaWdodC5hbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBjb21wb25lbnR3aXNlIHF1b3RpZW50IG9mIHR3byBDb2xvcnMuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBsZWZ0IFRoZSBmaXJzdCBDb2xvci4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSByaWdodCBUaGUgc2Vjb25kIENvbG9yLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGUobGVmdCwgcmlnaHQsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJsZWZ0IiwgbGVmdCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJpZ2h0IiwgcmlnaHQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgICAgcmVzdWx0LnJlZCA9IGxlZnQucmVkIC8gcmlnaHQucmVkOwogICAgICAgICAgcmVzdWx0LmdyZWVuID0gbGVmdC5ncmVlbiAvIHJpZ2h0LmdyZWVuOwogICAgICAgICAgcmVzdWx0LmJsdWUgPSBsZWZ0LmJsdWUgLyByaWdodC5ibHVlOwogICAgICAgICAgcmVzdWx0LmFscGhhID0gbGVmdC5hbHBoYSAvIHJpZ2h0LmFscGhhOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogQ29tcHV0ZXMgdGhlIGNvbXBvbmVudHdpc2UgbW9kdWx1cyBvZiB0d28gQ29sb3JzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gbGVmdCBUaGUgZmlyc3QgQ29sb3IuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gcmlnaHQgVGhlIHNlY29uZCBDb2xvci4KICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSByZXN1bHQgVGhlIG9iamVjdCBvbnRvIHdoaWNoIHRvIHN0b3JlIHRoZSByZXN1bHQuCiAgICAgICAgICogQHJldHVybnMge0NvbG9yfSBUaGUgbW9kaWZpZWQgcmVzdWx0IHBhcmFtZXRlci4KICAgICAgICAgKi8KICAgICAgICBzdGF0aWMgbW9kKGxlZnQsIHJpZ2h0LCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgibGVmdCIsIGxlZnQpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyaWdodCIsIHJpZ2h0KTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSBsZWZ0LnJlZCAlIHJpZ2h0LnJlZDsKICAgICAgICAgIHJlc3VsdC5ncmVlbiA9IGxlZnQuZ3JlZW4gJSByaWdodC5ncmVlbjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gbGVmdC5ibHVlICUgcmlnaHQuYmx1ZTsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGxlZnQuYWxwaGEgJSByaWdodC5hbHBoYTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENvbXB1dGVzIHRoZSBsaW5lYXIgaW50ZXJwb2xhdGlvbiBvciBleHRyYXBvbGF0aW9uIGF0IHQgYmV0d2VlbiB0aGUgcHJvdmlkZWQgY29sb3JzLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gc3RhcnQgVGhlIGNvbG9yIGNvcnJlc3BvbmRpbmcgdG8gdCBhdCAwLjAuCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gZW5kIFRoZSBjb2xvciBjb3JyZXNwb25kaW5nIHRvIHQgYXQgMS4wLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0IFRoZSBwb2ludCBhbG9uZyB0IGF0IHdoaWNoIHRvIGludGVycG9sYXRlLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBsZXJwKHN0YXJ0LCBlbmQsIHQyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgic3RhcnQiLCBzdGFydCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImVuZCIsIGVuZCk7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInQiLCB0Mik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQucmVkID0gTWF0aF9kZWZhdWx0LmxlcnAoc3RhcnQucmVkLCBlbmQucmVkLCB0Mik7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBNYXRoX2RlZmF1bHQubGVycChzdGFydC5ncmVlbiwgZW5kLmdyZWVuLCB0Mik7CiAgICAgICAgICByZXN1bHQuYmx1ZSA9IE1hdGhfZGVmYXVsdC5sZXJwKHN0YXJ0LmJsdWUsIGVuZC5ibHVlLCB0Mik7CiAgICAgICAgICByZXN1bHQuYWxwaGEgPSBNYXRoX2RlZmF1bHQubGVycChzdGFydC5hbHBoYSwgZW5kLmFscGhhLCB0Mik7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBNdWx0aXBsaWVzIHRoZSBwcm92aWRlZCBDb2xvciBjb21wb25lbnR3aXNlIGJ5IHRoZSBwcm92aWRlZCBzY2FsYXIuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge0NvbG9yfSBjb2xvciBUaGUgQ29sb3IgdG8gYmUgc2NhbGVkLgogICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXIgVGhlIHNjYWxhciB0byBtdWx0aXBseSB3aXRoLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBtdWx0aXBseUJ5U2NhbGFyKGNvbG9yLCBzY2FsYXIsIHJlc3VsdCkgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJjb2xvciIsIGNvbG9yKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic2NhbGFyIiwgc2NhbGFyKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVzdWx0IiwgcmVzdWx0KTsKICAgICAgICAgIHJlc3VsdC5yZWQgPSBjb2xvci5yZWQgKiBzY2FsYXI7CiAgICAgICAgICByZXN1bHQuZ3JlZW4gPSBjb2xvci5ncmVlbiAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdC5ibHVlID0gY29sb3IuYmx1ZSAqIHNjYWxhcjsKICAgICAgICAgIHJlc3VsdC5hbHBoYSA9IGNvbG9yLmFscGhhICogc2NhbGFyOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogRGl2aWRlcyB0aGUgcHJvdmlkZWQgQ29sb3IgY29tcG9uZW50d2lzZSBieSB0aGUgcHJvdmlkZWQgc2NhbGFyLgogICAgICAgICAqCiAgICAgICAgICogQHBhcmFtIHtDb2xvcn0gY29sb3IgVGhlIENvbG9yIHRvIGJlIGRpdmlkZWQuCiAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxhciBUaGUgc2NhbGFyIHRvIGRpdmlkZSB3aXRoLgogICAgICAgICAqIEBwYXJhbSB7Q29sb3J9IHJlc3VsdCBUaGUgb2JqZWN0IG9udG8gd2hpY2ggdG8gc3RvcmUgdGhlIHJlc3VsdC4KICAgICAgICAgKiBAcmV0dXJucyB7Q29sb3J9IFRoZSBtb2RpZmllZCByZXN1bHQgcGFyYW1ldGVyLgogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBkaXZpZGVCeVNjYWxhcihjb2xvciwgc2NhbGFyLCByZXN1bHQpIHsKICAgICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiY29sb3IiLCBjb2xvcik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInNjYWxhciIsIHNjYWxhcik7CiAgICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgICByZXN1bHQucmVkID0gY29sb3IucmVkIC8gc2NhbGFyOwogICAgICAgICAgcmVzdWx0LmdyZWVuID0gY29sb3IuZ3JlZW4gLyBzY2FsYXI7CiAgICAgICAgICByZXN1bHQuYmx1ZSA9IGNvbG9yLmJsdWUgLyBzY2FsYXI7CiAgICAgICAgICByZXN1bHQuYWxwaGEgPSBjb2xvci5hbHBoYSAvIHNjYWxhcjsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICB9OwogICAgICBpZiAoRmVhdHVyZURldGVjdGlvbl9kZWZhdWx0LnN1cHBvcnRzVHlwZWRBcnJheXMoKSkgewogICAgICAgIHNjcmF0Y2hBcnJheUJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZlcig0KTsKICAgICAgICBzY3JhdGNoVWludDMyQXJyYXkgPSBuZXcgVWludDMyQXJyYXkoc2NyYXRjaEFycmF5QnVmZmVyKTsKICAgICAgICBzY3JhdGNoVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KHNjcmF0Y2hBcnJheUJ1ZmZlcik7CiAgICAgIH0KICAgICAgcmdiYU1hdGNoZXIgPSAvXiMoWzAtOWEtZl0pKFswLTlhLWZdKShbMC05YS1mXSkoWzAtOWEtZl0pPyQvaTsKICAgICAgcnJnZ2JiYWFNYXRjaGVyID0gL14jKFswLTlhLWZdezJ9KShbMC05YS1mXXsyfSkoWzAtOWEtZl17Mn0pKFswLTlhLWZdezJ9KT8kL2k7CiAgICAgIHJnYlBhcmVudGhlc2VzTWF0Y2hlciA9IC9ecmdiYT9ccypcKFxzKihbMC05Ll0rJT8pXHMqWyxcc10rXHMqKFswLTkuXSslPylccypbLFxzXStccyooWzAtOS5dKyU/KSg/OlxzKlssXHMvXStccyooWzAtOS5dKykpP1xzKlwpJC9pOwogICAgICBoc2xQYXJlbnRoZXNlc01hdGNoZXIgPSAvXmhzbGE/XHMqXChccyooWzAtOS5dKylccypbLFxzXStccyooWzAtOS5dKyUpXHMqWyxcc10rXHMqKFswLTkuXSslKSg/OlxzKlssXHMvXStccyooWzAtOS5dKykpP1xzKlwpJC9pOwogICAgICBDb2xvci5wYWNrZWRMZW5ndGggPSA0OwogICAgICBDb2xvci5BTElDRUJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0YwRjhGRiIpKTsKICAgICAgQ29sb3IuQU5USVFVRVdISVRFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGQUVCRDciKSk7CiAgICAgIENvbG9yLkFRVUEgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwRkZGRiIpKTsKICAgICAgQ29sb3IuQVFVQU1BUklORSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjN0ZGRkQ0IikpOwogICAgICBDb2xvci5BWlVSRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRjBGRkZGIikpOwogICAgICBDb2xvci5CRUlHRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRjVGNURDIikpOwogICAgICBDb2xvci5CSVNRVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRTRDNCIpKTsKICAgICAgQ29sb3IuQkxBQ0sgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwMDAwMCIpKTsKICAgICAgQ29sb3IuQkxBTkNIRURBTE1PTkQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRUJDRCIpKTsKICAgICAgQ29sb3IuQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjMDAwMEZGIikpOwogICAgICBDb2xvci5CTFVFVklPTEVUID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM4QTJCRTIiKSk7CiAgICAgIENvbG9yLkJST1dOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNBNTJBMkEiKSk7CiAgICAgIENvbG9yLkJVUkxZV09PRCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjREVCODg3IikpOwogICAgICBDb2xvci5DQURFVEJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzVGOUVBMCIpKTsKICAgICAgQ29sb3IuQ0hBUlRSRVVTRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjN0ZGRjAwIikpOwogICAgICBDb2xvci5DSE9DT0xBVEUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0QyNjkxRSIpKTsKICAgICAgQ29sb3IuQ09SQUwgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGN0Y1MCIpKTsKICAgICAgQ29sb3IuQ09STkZMT1dFUkJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzY0OTVFRCIpKTsKICAgICAgQ29sb3IuQ09STlNJTEsgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRjhEQyIpKTsKICAgICAgQ29sb3IuQ1JJTVNPTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjREMxNDNDIikpOwogICAgICBDb2xvci5DWUFOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMEZGRkYiKSk7CiAgICAgIENvbG9yLkRBUktCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMDAwOEIiKSk7CiAgICAgIENvbG9yLkRBUktDWUFOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMDhCOEIiKSk7CiAgICAgIENvbG9yLkRBUktHT0xERU5ST0QgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0I4ODYwQiIpKTsKICAgICAgQ29sb3IuREFSS0dSQVkgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0E5QTlBOSIpKTsKICAgICAgQ29sb3IuREFSS0dSRUVOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMDY0MDAiKSk7CiAgICAgIENvbG9yLkRBUktHUkVZID0gQ29sb3IuREFSS0dSQVk7CiAgICAgIENvbG9yLkRBUktLSEFLSSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjQkRCNzZCIikpOwogICAgICBDb2xvci5EQVJLTUFHRU5UQSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOEIwMDhCIikpOwogICAgICBDb2xvci5EQVJLT0xJVkVHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNTU2QjJGIikpOwogICAgICBDb2xvci5EQVJLT1JBTkdFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRjhDMDAiKSk7CiAgICAgIENvbG9yLkRBUktPUkNISUQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzk5MzJDQyIpKTsKICAgICAgQ29sb3IuREFSS1JFRCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOEIwMDAwIikpOwogICAgICBDb2xvci5EQVJLU0FMTU9OID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNFOTk2N0EiKSk7CiAgICAgIENvbG9yLkRBUktTRUFHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOEZCQzhGIikpOwogICAgICBDb2xvci5EQVJLU0xBVEVCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM0ODNEOEIiKSk7CiAgICAgIENvbG9yLkRBUktTTEFURUdSQVkgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzJGNEY0RiIpKTsKICAgICAgQ29sb3IuREFSS1NMQVRFR1JFWSA9IENvbG9yLkRBUktTTEFURUdSQVk7CiAgICAgIENvbG9yLkRBUktUVVJRVU9JU0UgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwQ0VEMSIpKTsKICAgICAgQ29sb3IuREFSS1ZJT0xFVCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOTQwMEQzIikpOwogICAgICBDb2xvci5ERUVQUElOSyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkYxNDkzIikpOwogICAgICBDb2xvci5ERUVQU0tZQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjMDBCRkZGIikpOwogICAgICBDb2xvci5ESU1HUkFZID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM2OTY5NjkiKSk7CiAgICAgIENvbG9yLkRJTUdSRVkgPSBDb2xvci5ESU1HUkFZOwogICAgICBDb2xvci5ET0RHRVJCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMxRTkwRkYiKSk7CiAgICAgIENvbG9yLkZJUkVCUklDSyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjQjIyMjIyIikpOwogICAgICBDb2xvci5GTE9SQUxXSElURSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZGQUYwIikpOwogICAgICBDb2xvci5GT1JFU1RHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjMjI4QjIyIikpOwogICAgICBDb2xvci5GVUNIU0lBID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRjAwRkYiKSk7CiAgICAgIENvbG9yLkdBSU5TQk9STyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRENEQ0RDIikpOwogICAgICBDb2xvci5HSE9TVFdISVRFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGOEY4RkYiKSk7CiAgICAgIENvbG9yLkdPTEQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRDcwMCIpKTsKICAgICAgQ29sb3IuR09MREVOUk9EID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNEQUE1MjAiKSk7CiAgICAgIENvbG9yLkdSQVkgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzgwODA4MCIpKTsKICAgICAgQ29sb3IuR1JFRU4gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwODAwMCIpKTsKICAgICAgQ29sb3IuR1JFRU5ZRUxMT1cgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0FERkYyRiIpKTsKICAgICAgQ29sb3IuR1JFWSA9IENvbG9yLkdSQVk7CiAgICAgIENvbG9yLkhPTkVZREVXID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGMEZGRjAiKSk7CiAgICAgIENvbG9yLkhPVFBJTksgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGNjlCNCIpKTsKICAgICAgQ29sb3IuSU5ESUFOUkVEID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNDRDVDNUMiKSk7CiAgICAgIENvbG9yLklORElHTyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNEIwMDgyIikpOwogICAgICBDb2xvci5JVk9SWSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZGRkYwIikpOwogICAgICBDb2xvci5LSEFLSSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRjBFNjhDIikpOwogICAgICBDb2xvci5MQVZFTkRFUiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRTZFNkZBIikpOwogICAgICBDb2xvci5MQVZFTkRBUl9CTFVTSCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZGMEY1IikpOwogICAgICBDb2xvci5MQVdOR1JFRU4gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzdDRkMwMCIpKTsKICAgICAgQ29sb3IuTEVNT05DSElGRk9OID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRkZBQ0QiKSk7CiAgICAgIENvbG9yLkxJR0hUQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjQUREOEU2IikpOwogICAgICBDb2xvci5MSUdIVENPUkFMID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGMDgwODAiKSk7CiAgICAgIENvbG9yLkxJR0hUQ1lBTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRTBGRkZGIikpOwogICAgICBDb2xvci5MSUdIVEdPTERFTlJPRFlFTExPVyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkFGQUQyIikpOwogICAgICBDb2xvci5MSUdIVEdSQVkgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0QzRDNEMyIpKTsKICAgICAgQ29sb3IuTElHSFRHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOTBFRTkwIikpOwogICAgICBDb2xvci5MSUdIVEdSRVkgPSBDb2xvci5MSUdIVEdSQVk7CiAgICAgIENvbG9yLkxJR0hUUElOSyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZCNkMxIikpOwogICAgICBDb2xvci5MSUdIVFNFQUdSRUVOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMyMEIyQUEiKSk7CiAgICAgIENvbG9yLkxJR0hUU0tZQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjODdDRUZBIikpOwogICAgICBDb2xvci5MSUdIVFNMQVRFR1JBWSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNzc4ODk5IikpOwogICAgICBDb2xvci5MSUdIVFNMQVRFR1JFWSA9IENvbG9yLkxJR0hUU0xBVEVHUkFZOwogICAgICBDb2xvci5MSUdIVFNURUVMQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjQjBDNERFIikpOwogICAgICBDb2xvci5MSUdIVFlFTExPVyA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZGRkUwIikpOwogICAgICBDb2xvci5MSU1FID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMEZGMDAiKSk7CiAgICAgIENvbG9yLkxJTUVHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjMzJDRDMyIikpOwogICAgICBDb2xvci5MSU5FTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkFGMEU2IikpOwogICAgICBDb2xvci5NQUdFTlRBID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRjAwRkYiKSk7CiAgICAgIENvbG9yLk1BUk9PTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjODAwMDAwIikpOwogICAgICBDb2xvci5NRURJVU1BUVVBTUFSSU5FID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM2NkNEQUEiKSk7CiAgICAgIENvbG9yLk1FRElVTUJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwMDBDRCIpKTsKICAgICAgQ29sb3IuTUVESVVNT1JDSElEID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNCQTU1RDMiKSk7CiAgICAgIENvbG9yLk1FRElVTVBVUlBMRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOTM3MERCIikpOwogICAgICBDb2xvci5NRURJVU1TRUFHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjM0NCMzcxIikpOwogICAgICBDb2xvci5NRURJVU1TTEFURUJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzdCNjhFRSIpKTsKICAgICAgQ29sb3IuTUVESVVNU1BSSU5HR1JFRU4gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwRkE5QSIpKTsKICAgICAgQ29sb3IuTUVESVVNVFVSUVVPSVNFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM0OEQxQ0MiKSk7CiAgICAgIENvbG9yLk1FRElVTVZJT0xFVFJFRCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjQzcxNTg1IikpOwogICAgICBDb2xvci5NSUROSUdIVEJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzE5MTk3MCIpKTsKICAgICAgQ29sb3IuTUlOVENSRUFNID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGNUZGRkEiKSk7CiAgICAgIENvbG9yLk1JU1RZUk9TRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZFNEUxIikpOwogICAgICBDb2xvci5NT0NDQVNJTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZFNEI1IikpOwogICAgICBDb2xvci5OQVZBSk9XSElURSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZERUFEIikpOwogICAgICBDb2xvci5OQVZZID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMDAwODAiKSk7CiAgICAgIENvbG9yLk9MRExBQ0UgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZERjVFNiIpKTsKICAgICAgQ29sb3IuT0xJVkUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzgwODAwMCIpKTsKICAgICAgQ29sb3IuT0xJVkVEUkFCID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM2QjhFMjMiKSk7CiAgICAgIENvbG9yLk9SQU5HRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZBNTAwIikpOwogICAgICBDb2xvci5PUkFOR0VSRUQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGNDUwMCIpKTsKICAgICAgQ29sb3IuT1JDSElEID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNEQTcwRDYiKSk7CiAgICAgIENvbG9yLlBBTEVHT0xERU5ST0QgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0VFRThBQSIpKTsKICAgICAgQ29sb3IuUEFMRUdSRUVOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM5OEZCOTgiKSk7CiAgICAgIENvbG9yLlBBTEVUVVJRVU9JU0UgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0FGRUVFRSIpKTsKICAgICAgQ29sb3IuUEFMRVZJT0xFVFJFRCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjREI3MDkzIikpOwogICAgICBDb2xvci5QQVBBWUFXSElQID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRkVGRDUiKSk7CiAgICAgIENvbG9yLlBFQUNIUFVGRiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZEQUI5IikpOwogICAgICBDb2xvci5QRVJVID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNDRDg1M0YiKSk7CiAgICAgIENvbG9yLlBJTksgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGQzBDQiIpKTsKICAgICAgQ29sb3IuUExVTSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRERBMEREIikpOwogICAgICBDb2xvci5QT1dERVJCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNCMEUwRTYiKSk7CiAgICAgIENvbG9yLlBVUlBMRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjODAwMDgwIikpOwogICAgICBDb2xvci5SRUQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGMDAwMCIpKTsKICAgICAgQ29sb3IuUk9TWUJST1dOID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNCQzhGOEYiKSk7CiAgICAgIENvbG9yLlJPWUFMQkxVRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNDE2OUUxIikpOwogICAgICBDb2xvci5TQURETEVCUk9XTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjOEI0NTEzIikpOwogICAgICBDb2xvci5TQUxNT04gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZBODA3MiIpKTsKICAgICAgQ29sb3IuU0FORFlCUk9XTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRjRBNDYwIikpOwogICAgICBDb2xvci5TRUFHUkVFTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjMkU4QjU3IikpOwogICAgICBDb2xvci5TRUFTSEVMTCA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRkZGNUVFIikpOwogICAgICBDb2xvci5TSUVOTkEgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0EwNTIyRCIpKTsKICAgICAgQ29sb3IuU0lMVkVSID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNDMEMwQzAiKSk7CiAgICAgIENvbG9yLlNLWUJMVUUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzg3Q0VFQiIpKTsKICAgICAgQ29sb3IuU0xBVEVCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM2QTVBQ0QiKSk7CiAgICAgIENvbG9yLlNMQVRFR1JBWSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNzA4MDkwIikpOwogICAgICBDb2xvci5TTEFURUdSRVkgPSBDb2xvci5TTEFURUdSQVk7CiAgICAgIENvbG9yLlNOT1cgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRkFGQSIpKTsKICAgICAgQ29sb3IuU1BSSU5HR1JFRU4gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzAwRkY3RiIpKTsKICAgICAgQ29sb3IuU1RFRUxCTFVFID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiM0NjgyQjQiKSk7CiAgICAgIENvbG9yLlRBTiA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRDJCNDhDIikpOwogICAgICBDb2xvci5URUFMID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiMwMDgwODAiKSk7CiAgICAgIENvbG9yLlRISVNUTEUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0Q4QkZEOCIpKTsKICAgICAgQ29sb3IuVE9NQVRPID0gT2JqZWN0LmZyZWV6ZShDb2xvci5mcm9tQ3NzQ29sb3JTdHJpbmcoIiNGRjYzNDciKSk7CiAgICAgIENvbG9yLlRVUlFVT0lTRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjNDBFMEQwIikpOwogICAgICBDb2xvci5WSU9MRVQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0VFODJFRSIpKTsKICAgICAgQ29sb3IuV0hFQVQgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0Y1REVCMyIpKTsKICAgICAgQ29sb3IuV0hJVEUgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRkZGRiIpKTsKICAgICAgQ29sb3IuV0hJVEVTTU9LRSA9IE9iamVjdC5mcmVlemUoQ29sb3IuZnJvbUNzc0NvbG9yU3RyaW5nKCIjRjVGNUY1IikpOwogICAgICBDb2xvci5ZRUxMT1cgPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiI0ZGRkYwMCIpKTsKICAgICAgQ29sb3IuWUVMTE9XR1JFRU4gPSBPYmplY3QuZnJlZXplKENvbG9yLmZyb21Dc3NDb2xvclN0cmluZygiIzlBQ0QzMiIpKTsKICAgICAgQ29sb3IuVFJBTlNQQVJFTlQgPSBPYmplY3QuZnJlZXplKG5ldyBDb2xvcigwLCAwLCAwLCAwKSk7CiAgICAgIENvbG9yX2RlZmF1bHQgPSBDb2xvcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBpbnRlcnBvbGF0ZUNvbG9ycyhwMCwgcDEsIGNvbG9yMCwgY29sb3IxLCBudW1Qb2ludHMpIHsKICAgIGNvbnN0IGNvbG9ycyA9IHNjcmF0Y2hJbnRlcnBvbGF0ZUNvbG9yc0FycmF5OwogICAgY29sb3JzLmxlbmd0aCA9IG51bVBvaW50czsKICAgIGxldCBpMjsKICAgIGNvbnN0IHIwID0gY29sb3IwLnJlZDsKICAgIGNvbnN0IGcwID0gY29sb3IwLmdyZWVuOwogICAgY29uc3QgYjAgPSBjb2xvcjAuYmx1ZTsKICAgIGNvbnN0IGEwID0gY29sb3IwLmFscGhhOwogICAgY29uc3QgcjEgPSBjb2xvcjEucmVkOwogICAgY29uc3QgZzEgPSBjb2xvcjEuZ3JlZW47CiAgICBjb25zdCBiMSA9IGNvbG9yMS5ibHVlOwogICAgY29uc3QgYTEgPSBjb2xvcjEuYWxwaGE7CiAgICBpZiAoQ29sb3JfZGVmYXVsdC5lcXVhbHMoY29sb3IwLCBjb2xvcjEpKSB7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bVBvaW50czsgaTIrKykgewogICAgICAgIGNvbG9yc1tpMl0gPSBDb2xvcl9kZWZhdWx0LmNsb25lKGNvbG9yMCk7CiAgICAgIH0KICAgICAgcmV0dXJuIGNvbG9yczsKICAgIH0KICAgIGNvbnN0IHJlZFBlclZlcnRleCA9IChyMSAtIHIwKSAvIG51bVBvaW50czsKICAgIGNvbnN0IGdyZWVuUGVyVmVydGV4ID0gKGcxIC0gZzApIC8gbnVtUG9pbnRzOwogICAgY29uc3QgYmx1ZVBlclZlcnRleCA9IChiMSAtIGIwKSAvIG51bVBvaW50czsKICAgIGNvbnN0IGFscGhhUGVyVmVydGV4ID0gKGExIC0gYTApIC8gbnVtUG9pbnRzOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtUG9pbnRzOyBpMisrKSB7CiAgICAgIGNvbG9yc1tpMl0gPSBuZXcgQ29sb3JfZGVmYXVsdCgKICAgICAgICByMCArIGkyICogcmVkUGVyVmVydGV4LAogICAgICAgIGcwICsgaTIgKiBncmVlblBlclZlcnRleCwKICAgICAgICBiMCArIGkyICogYmx1ZVBlclZlcnRleCwKICAgICAgICBhMCArIGkyICogYWxwaGFQZXJWZXJ0ZXgKICAgICAgKTsKICAgIH0KICAgIHJldHVybiBjb2xvcnM7CiAgfQogIGZ1bmN0aW9uIFBvbHlsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICBjb25zdCBjb2xvcnMgPSBvcHRpb25zLmNvbG9yczsKICAgIGNvbnN0IHdpZHRoID0gb3B0aW9ucy53aWR0aCA/PyAxOwogICAgY29uc3QgY29sb3JzUGVyVmVydGV4ID0gb3B0aW9ucy5jb2xvcnNQZXJWZXJ0ZXggPz8gZmFsc2U7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpIHx8IHBvc2l0aW9ucy5sZW5ndGggPCAyKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJBdCBsZWFzdCB0d28gcG9zaXRpb25zIGFyZSByZXF1aXJlZC4iKTsKICAgIH0KICAgIGlmICh0eXBlb2Ygd2lkdGggIT09ICJudW1iZXIiKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ3aWR0aCBtdXN0IGJlIGEgbnVtYmVyIik7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykgJiYgKGNvbG9yc1BlclZlcnRleCAmJiBjb2xvcnMubGVuZ3RoIDwgcG9zaXRpb25zLmxlbmd0aCB8fCAhY29sb3JzUGVyVmVydGV4ICYmIGNvbG9ycy5sZW5ndGggPCBwb3NpdGlvbnMubGVuZ3RoIC0gMSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNvbG9ycyBoYXMgYW4gaW52YWxpZCBsZW5ndGguIik7CiAgICB9CiAgICB0aGlzLl9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICB0aGlzLl9jb2xvcnMgPSBjb2xvcnM7CiAgICB0aGlzLl93aWR0aCA9IHdpZHRoOwogICAgdGhpcy5fY29sb3JzUGVyVmVydGV4ID0gY29sb3JzUGVyVmVydGV4OwogICAgdGhpcy5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUoCiAgICAgIG9wdGlvbnMudmVydGV4Rm9ybWF0ID8/IFZlcnRleEZvcm1hdF9kZWZhdWx0LkRFRkFVTFQKICAgICk7CiAgICB0aGlzLl9hcmNUeXBlID0gb3B0aW9ucy5hcmNUeXBlID8/IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQzsKICAgIHRoaXMuX2dyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCk7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZVBvbHlsaW5lR2VvbWV0cnkiOwogICAgbGV0IG51bUNvbXBvbmVudHMgPSAxICsgcG9zaXRpb25zLmxlbmd0aCAqIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICBudW1Db21wb25lbnRzICs9IGRlZmluZWRfZGVmYXVsdChjb2xvcnMpID8gMSArIGNvbG9ycy5sZW5ndGggKiBDb2xvcl9kZWZhdWx0LnBhY2tlZExlbmd0aCA6IDE7CiAgICB0aGlzLnBhY2tlZExlbmd0aCA9IG51bUNvbXBvbmVudHMgKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyA0OwogIH0KICB2YXIgc2NyYXRjaEludGVycG9sYXRlQ29sb3JzQXJyYXksIHNjcmF0Y2hFbGxpcHNvaWQ4LCBzY3JhdGNoVmVydGV4Rm9ybWF0MTAsIHNjcmF0Y2hPcHRpb25zMTYsIHNjcmF0Y2hDYXJ0ZXNpYW4zOCwgc2NyYXRjaFBvc2l0aW9uNCwgc2NyYXRjaFByZXZQb3NpdGlvbiwgc2NyYXRjaE5leHRQb3NpdGlvbiwgUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X1BvbHlsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0FyY1R5cGUoKTsKICAgICAgaW5pdF9hcnJheVJlbW92ZUR1cGxpY2F0ZXMoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db2xvcigpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5VHlwZSgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfUG9seWxpbmVQaXBlbGluZSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9WZXJ0ZXhGb3JtYXQoKTsKICAgICAgc2NyYXRjaEludGVycG9sYXRlQ29sb3JzQXJyYXkgPSBbXTsKICAgICAgUG9seWxpbmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodmFsdWUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidmFsdWUgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXJyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBsZXQgaTI7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gdmFsdWUuX3Bvc2l0aW9uczsKICAgICAgICBsZXQgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gbGVuZ3RoOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhwb3NpdGlvbnNbaTJdLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGNvbG9ycyA9IHZhbHVlLl9jb2xvcnM7CiAgICAgICAgbGVuZ3RoID0gZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykgPyBjb2xvcnMubGVuZ3RoIDogMDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gbGVuZ3RoOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDb2xvcl9kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ29sb3JfZGVmYXVsdC5wYWNrKGNvbG9yc1tpMl0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgRWxsaXBzb2lkX2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzb2lkLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFjayh2YWx1ZS5fdmVydGV4Rm9ybWF0LCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl93aWR0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2NvbG9yc1BlclZlcnRleCA/IDEgOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fYXJjVHlwZTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQ4ID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoRWxsaXBzb2lkX2RlZmF1bHQuVU5JVF9TUEhFUkUpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTAgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE9wdGlvbnMxNiA9IHsKICAgICAgICBwb3NpdGlvbnM6IHZvaWQgMCwKICAgICAgICBjb2xvcnM6IHZvaWQgMCwKICAgICAgICBlbGxpcHNvaWQ6IHNjcmF0Y2hFbGxpcHNvaWQ4LAogICAgICAgIHZlcnRleEZvcm1hdDogc2NyYXRjaFZlcnRleEZvcm1hdDEwLAogICAgICAgIHdpZHRoOiB2b2lkIDAsCiAgICAgICAgY29sb3JzUGVyVmVydGV4OiB2b2lkIDAsCiAgICAgICAgYXJjVHlwZTogdm9pZCAwLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAKICAgICAgfTsKICAgICAgUG9seWxpbmVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXJyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IGxlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIHBvc2l0aW9uc1tpMl0gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgbGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBjb2xvcnMgPSBsZW5ndGggPiAwID8gbmV3IEFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENvbG9yX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBjb2xvcnNbaTJdID0gQ29sb3JfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQ4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTAKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IHdpZHRoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBjb2xvcnNQZXJWZXJ0ZXggPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIGNvbnN0IGFyY1R5cGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNi5wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE2LmNvbG9ycyA9IGNvbG9yczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTYud2lkdGggPSB3aWR0aDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTYuY29sb3JzUGVyVmVydGV4ID0gY29sb3JzUGVyVmVydGV4OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNi5hcmNUeXBlID0gYXJjVHlwZTsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTYuZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICAgIHJldHVybiBuZXcgUG9seWxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczE2KTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9jb2xvcnMgPSBjb2xvcnM7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNvaWQsIHJlc3VsdC5fZWxsaXBzb2lkKTsKICAgICAgICByZXN1bHQuX3ZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKHZlcnRleEZvcm1hdCwgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQpOwogICAgICAgIHJlc3VsdC5fd2lkdGggPSB3aWR0aDsKICAgICAgICByZXN1bHQuX2NvbG9yc1BlclZlcnRleCA9IGNvbG9yc1BlclZlcnRleDsKICAgICAgICByZXN1bHQuX2FyY1R5cGUgPSBhcmNUeXBlOwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBzY3JhdGNoQ2FydGVzaWFuMzggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQb3NpdGlvbjQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQcmV2UG9zaXRpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOZXh0UG9zaXRpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIFBvbHlsaW5lR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbihwb2x5bGluZUdlb21ldHJ5KSB7CiAgICAgICAgY29uc3Qgd2lkdGggPSBwb2x5bGluZUdlb21ldHJ5Ll93aWR0aDsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBwb2x5bGluZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgbGV0IGNvbG9ycyA9IHBvbHlsaW5lR2VvbWV0cnkuX2NvbG9yczsKICAgICAgICBjb25zdCBjb2xvcnNQZXJWZXJ0ZXggPSBwb2x5bGluZUdlb21ldHJ5Ll9jb2xvcnNQZXJWZXJ0ZXg7CiAgICAgICAgY29uc3QgYXJjVHlwZSA9IHBvbHlsaW5lR2VvbWV0cnkuX2FyY1R5cGU7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBwb2x5bGluZUdlb21ldHJ5Ll9ncmFudWxhcml0eTsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBwb2x5bGluZUdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGxldCBqMjsKICAgICAgICBsZXQgazI7CiAgICAgICAgY29uc3QgcmVtb3ZlZEluZGljZXMgPSBbXTsKICAgICAgICBsZXQgcG9zaXRpb25zID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICBwb2x5bGluZUdlb21ldHJ5Ll9wb3NpdGlvbnMsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbiwKICAgICAgICAgIGZhbHNlLAogICAgICAgICAgcmVtb3ZlZEluZGljZXMKICAgICAgICApOwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSAmJiByZW1vdmVkSW5kaWNlcy5sZW5ndGggPiAwKSB7CiAgICAgICAgICBsZXQgcmVtb3ZlZEFycmF5SW5kZXggPSAwOwogICAgICAgICAgbGV0IG5leHRSZW1vdmVkSW5kZXggPSByZW1vdmVkSW5kaWNlc1swXTsKICAgICAgICAgIGNvbG9ycyA9IGNvbG9ycy5maWx0ZXIoZnVuY3Rpb24oY29sb3IsIGluZGV4MikgewogICAgICAgICAgICBsZXQgcmVtb3ZlOwogICAgICAgICAgICBpZiAoY29sb3JzUGVyVmVydGV4KSB7CiAgICAgICAgICAgICAgcmVtb3ZlID0gaW5kZXgyID09PSBuZXh0UmVtb3ZlZEluZGV4IHx8IGluZGV4MiA9PT0gMCAmJiBuZXh0UmVtb3ZlZEluZGV4ID09PSAxOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHJlbW92ZSA9IGluZGV4MiArIDEgPT09IG5leHRSZW1vdmVkSW5kZXg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHJlbW92ZSkgewogICAgICAgICAgICAgIHJlbW92ZWRBcnJheUluZGV4Kys7CiAgICAgICAgICAgICAgbmV4dFJlbW92ZWRJbmRleCA9IHJlbW92ZWRJbmRpY2VzW3JlbW92ZWRBcnJheUluZGV4XTsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgbGV0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgaWYgKHBvc2l0aW9uc0xlbmd0aCA8IDIgfHwgd2lkdGggPD0gMCkgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgaWYgKGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQyB8fCBhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuUkhVTUIpIHsKICAgICAgICAgIGxldCBzdWJkaXZpc2lvblNpemU7CiAgICAgICAgICBsZXQgbnVtYmVyT2ZQb2ludHNGdW5jdGlvbjsKICAgICAgICAgIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMpIHsKICAgICAgICAgICAgc3ViZGl2aXNpb25TaXplID0gTWF0aF9kZWZhdWx0LmNob3JkTGVuZ3RoKAogICAgICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgICAgIGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG51bWJlck9mUG9pbnRzRnVuY3Rpb24gPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQubnVtYmVyT2ZQb2ludHM7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBzdWJkaXZpc2lvblNpemUgPSBncmFudWxhcml0eTsKICAgICAgICAgICAgbnVtYmVyT2ZQb2ludHNGdW5jdGlvbiA9IFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdC5udW1iZXJPZlBvaW50c1JodW1iTGluZTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhlaWdodHMgPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQuZXh0cmFjdEhlaWdodHMocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjb2xvcnMpKSB7CiAgICAgICAgICAgIGxldCBjb2xvckxlbmd0aCA9IDE7CiAgICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHBvc2l0aW9uc0xlbmd0aCAtIDE7ICsraTIpIHsKICAgICAgICAgICAgICBjb2xvckxlbmd0aCArPSBudW1iZXJPZlBvaW50c0Z1bmN0aW9uKAogICAgICAgICAgICAgICAgcG9zaXRpb25zW2kyXSwKICAgICAgICAgICAgICAgIHBvc2l0aW9uc1tpMiArIDFdLAogICAgICAgICAgICAgICAgc3ViZGl2aXNpb25TaXplCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBuZXdDb2xvcnMgPSBuZXcgQXJyYXkoY29sb3JMZW5ndGgpOwogICAgICAgICAgICBsZXQgbmV3Q29sb3JJbmRleCA9IDA7CiAgICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IHBvc2l0aW9uc0xlbmd0aCAtIDE7ICsraTIpIHsKICAgICAgICAgICAgICBjb25zdCBwMCA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICAgICAgY29uc3QgcDEgPSBwb3NpdGlvbnNbaTIgKyAxXTsKICAgICAgICAgICAgICBjb25zdCBjMCA9IGNvbG9yc1tpMl07CiAgICAgICAgICAgICAgY29uc3QgbnVtQ29sb3JzID0gbnVtYmVyT2ZQb2ludHNGdW5jdGlvbihwMCwgcDEsIHN1YmRpdmlzaW9uU2l6ZSk7CiAgICAgICAgICAgICAgaWYgKGNvbG9yc1BlclZlcnRleCAmJiBpMiA8IGNvbG9yTGVuZ3RoKSB7CiAgICAgICAgICAgICAgICBjb25zdCBjMSA9IGNvbG9yc1tpMiArIDFdOwogICAgICAgICAgICAgICAgY29uc3QgaW50ZXJwb2xhdGVkQ29sb3JzID0gaW50ZXJwb2xhdGVDb2xvcnMoCiAgICAgICAgICAgICAgICAgIHAwLAogICAgICAgICAgICAgICAgICBwMSwKICAgICAgICAgICAgICAgICAgYzAsCiAgICAgICAgICAgICAgICAgIGMxLAogICAgICAgICAgICAgICAgICBudW1Db2xvcnMKICAgICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgICBjb25zdCBpbnRlcnBvbGF0ZWRDb2xvcnNMZW5ndGggPSBpbnRlcnBvbGF0ZWRDb2xvcnMubGVuZ3RoOwogICAgICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgaW50ZXJwb2xhdGVkQ29sb3JzTGVuZ3RoOyArK2oyKSB7CiAgICAgICAgICAgICAgICAgIG5ld0NvbG9yc1tuZXdDb2xvckluZGV4KytdID0gaW50ZXJwb2xhdGVkQ29sb3JzW2oyXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgbnVtQ29sb3JzOyArK2oyKSB7CiAgICAgICAgICAgICAgICAgIG5ld0NvbG9yc1tuZXdDb2xvckluZGV4KytdID0gQ29sb3JfZGVmYXVsdC5jbG9uZShjMCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIG5ld0NvbG9yc1tuZXdDb2xvckluZGV4XSA9IENvbG9yX2RlZmF1bHQuY2xvbmUoY29sb3JzW2NvbG9ycy5sZW5ndGggLSAxXSk7CiAgICAgICAgICAgIGNvbG9ycyA9IG5ld0NvbG9yczsKICAgICAgICAgICAgc2NyYXRjaEludGVycG9sYXRlQ29sb3JzQXJyYXkubGVuZ3RoID0gMDsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMpIHsKICAgICAgICAgICAgcG9zaXRpb25zID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQ2FydGVzaWFuQXJjKHsKICAgICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgICAgbWluRGlzdGFuY2U6IHN1YmRpdmlzaW9uU2l6ZSwKICAgICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgICAgaGVpZ2h0OiBoZWlnaHRzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcG9zaXRpb25zID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQ2FydGVzaWFuUmh1bWJBcmMoewogICAgICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgICAgICBncmFudWxhcml0eTogc3ViZGl2aXNpb25TaXplLAogICAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgICBoZWlnaHQ6IGhlaWdodHMKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3Qgc2l6ZSA9IHBvc2l0aW9uc0xlbmd0aCAqIDQgLSA0OwogICAgICAgIGNvbnN0IGZpbmFsUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShzaXplICogMyk7CiAgICAgICAgY29uc3QgcHJldlBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoc2l6ZSAqIDMpOwogICAgICAgIGNvbnN0IG5leHRQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KHNpemUgKiAzKTsKICAgICAgICBjb25zdCBleHBhbmRBbmRXaWR0aCA9IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIDIpOwogICAgICAgIGNvbnN0IHN0MiA9IHZlcnRleEZvcm1hdC5zdCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIDIpIDogdm9pZCAwOwogICAgICAgIGNvbnN0IGZpbmFsQ29sb3JzID0gZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykgPyBuZXcgVWludDhBcnJheShzaXplICogNCkgOiB2b2lkIDA7CiAgICAgICAgbGV0IHBvc2l0aW9uSW5kZXggPSAwOwogICAgICAgIGxldCBleHBhbmRBbmRXaWR0aEluZGV4ID0gMDsKICAgICAgICBsZXQgc3RJbmRleCA9IDA7CiAgICAgICAgbGV0IGNvbG9ySW5kZXggPSAwOwogICAgICAgIGxldCBwb3NpdGlvbjsKICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBwb3NpdGlvbnNMZW5ndGg7ICsrajIpIHsKICAgICAgICAgIGlmIChqMiA9PT0gMCkgewogICAgICAgICAgICBwb3NpdGlvbiA9IHNjcmF0Y2hDYXJ0ZXNpYW4zODsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHBvc2l0aW9uc1swXSwgcG9zaXRpb25zWzFdLCBwb3NpdGlvbik7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb25zWzBdLCBwb3NpdGlvbiwgcG9zaXRpb24pOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbnNbajIgLSAxXTsKICAgICAgICAgIH0KICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgc2NyYXRjaFByZXZQb3NpdGlvbik7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUocG9zaXRpb25zW2oyXSwgc2NyYXRjaFBvc2l0aW9uNCk7CiAgICAgICAgICBpZiAoajIgPT09IHBvc2l0aW9uc0xlbmd0aCAtIDEpIHsKICAgICAgICAgICAgcG9zaXRpb24gPSBzY3JhdGNoQ2FydGVzaWFuMzg7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25zTGVuZ3RoIC0gMV0sCiAgICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uc0xlbmd0aCAtIDJdLAogICAgICAgICAgICAgIHBvc2l0aW9uCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocG9zaXRpb25zW3Bvc2l0aW9uc0xlbmd0aCAtIDFdLCBwb3NpdGlvbiwgcG9zaXRpb24pOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbnNbajIgKyAxXTsKICAgICAgICAgIH0KICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShwb3NpdGlvbiwgc2NyYXRjaE5leHRQb3NpdGlvbik7CiAgICAgICAgICBsZXQgY29sb3IwLCBjb2xvcjE7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGZpbmFsQ29sb3JzKSkgewogICAgICAgICAgICBpZiAoajIgIT09IDAgJiYgIWNvbG9yc1BlclZlcnRleCkgewogICAgICAgICAgICAgIGNvbG9yMCA9IGNvbG9yc1tqMiAtIDFdOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIGNvbG9yMCA9IGNvbG9yc1tqMl07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGoyICE9PSBwb3NpdGlvbnNMZW5ndGggLSAxKSB7CiAgICAgICAgICAgICAgY29sb3IxID0gY29sb3JzW2oyXTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgY29uc3Qgc3RhcnRLID0gajIgPT09IDAgPyAyIDogMDsKICAgICAgICAgIGNvbnN0IGVuZEsgPSBqMiA9PT0gcG9zaXRpb25zTGVuZ3RoIC0gMSA/IDIgOiA0OwogICAgICAgICAgZm9yIChrMiA9IHN0YXJ0SzsgazIgPCBlbmRLOyArK2syKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHNjcmF0Y2hQb3NpdGlvbjQsIGZpbmFsUG9zaXRpb25zLCBwb3NpdGlvbkluZGV4KTsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soc2NyYXRjaFByZXZQb3NpdGlvbiwgcHJldlBvc2l0aW9ucywgcG9zaXRpb25JbmRleCk7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHNjcmF0Y2hOZXh0UG9zaXRpb24sIG5leHRQb3NpdGlvbnMsIHBvc2l0aW9uSW5kZXgpOwogICAgICAgICAgICBwb3NpdGlvbkluZGV4ICs9IDM7CiAgICAgICAgICAgIGNvbnN0IGRpcmVjdGlvbjIgPSBrMiAtIDIgPCAwID8gLTEgOiAxOwogICAgICAgICAgICBleHBhbmRBbmRXaWR0aFtleHBhbmRBbmRXaWR0aEluZGV4KytdID0gMiAqIChrMiAlIDIpIC0gMTsKICAgICAgICAgICAgZXhwYW5kQW5kV2lkdGhbZXhwYW5kQW5kV2lkdGhJbmRleCsrXSA9IGRpcmVjdGlvbjIgKiB3aWR0aDsKICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgICAgIHN0MltzdEluZGV4KytdID0gajIgLyAocG9zaXRpb25zTGVuZ3RoIC0gMSk7CiAgICAgICAgICAgICAgc3QyW3N0SW5kZXgrK10gPSBNYXRoLm1heChleHBhbmRBbmRXaWR0aFtleHBhbmRBbmRXaWR0aEluZGV4IC0gMl0sIDApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZmluYWxDb2xvcnMpKSB7CiAgICAgICAgICAgICAgY29uc3QgY29sb3IgPSBrMiA8IDIgPyBjb2xvcjAgOiBjb2xvcjE7CiAgICAgICAgICAgICAgZmluYWxDb2xvcnNbY29sb3JJbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IucmVkKTsKICAgICAgICAgICAgICBmaW5hbENvbG9yc1tjb2xvckluZGV4KytdID0gQ29sb3JfZGVmYXVsdC5mbG9hdFRvQnl0ZShjb2xvci5ncmVlbik7CiAgICAgICAgICAgICAgZmluYWxDb2xvcnNbY29sb3JJbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IuYmx1ZSk7CiAgICAgICAgICAgICAgZmluYWxDb2xvcnNbY29sb3JJbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IuYWxwaGEpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgICAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgIHZhbHVlczogZmluYWxQb3NpdGlvbnMKICAgICAgICB9KTsKICAgICAgICBhdHRyaWJ1dGVzLnByZXZQb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IHByZXZQb3NpdGlvbnMKICAgICAgICB9KTsKICAgICAgICBhdHRyaWJ1dGVzLm5leHRQb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IG5leHRQb3NpdGlvbnMKICAgICAgICB9KTsKICAgICAgICBhdHRyaWJ1dGVzLmV4cGFuZEFuZFdpZHRoID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgdmFsdWVzOiBleHBhbmRBbmRXaWR0aAogICAgICAgIH0pOwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIGF0dHJpYnV0ZXMuc3QgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgICAgICB2YWx1ZXM6IHN0MgogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZmluYWxDb2xvcnMpKSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLmNvbG9yID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiA0LAogICAgICAgICAgICB2YWx1ZXM6IGZpbmFsQ29sb3JzLAogICAgICAgICAgICBub3JtYWxpemU6IHRydWUKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoc2l6ZSwgcG9zaXRpb25zTGVuZ3RoICogNiAtIDYpOwogICAgICAgIGxldCBpbmRleCA9IDA7CiAgICAgICAgbGV0IGluZGljZXNJbmRleCA9IDA7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zTGVuZ3RoIC0gMTsKICAgICAgICBmb3IgKGoyID0gMDsgajIgPCBsZW5ndGg7ICsrajIpIHsKICAgICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXg7CiAgICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGluZGV4ICsgMjsKICAgICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXggKyAxOwogICAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpbmRleCArIDE7CiAgICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGluZGV4ICsgMjsKICAgICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXggKyAzOwogICAgICAgICAgaW5kZXggKz0gNDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LlRSSUFOR0xFUywKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlOiBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21Qb2ludHMocG9zaXRpb25zKSwKICAgICAgICAgIGdlb21ldHJ5VHlwZTogR2VvbWV0cnlUeXBlX2RlZmF1bHQuUE9MWUxJTkVTCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFBvbHlsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFBvbHlsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVQb2x5bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZVBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlUG9seWxpbmVHZW9tZXRyeShwb2x5bGluZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBwb2x5bGluZUdlb21ldHJ5ID0gUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0LnVucGFjayhwb2x5bGluZUdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcG9seWxpbmVHZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUocG9seWxpbmVHZW9tZXRyeS5fZWxsaXBzb2lkKTsKICAgIHJldHVybiBQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkocG9seWxpbmVHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlUG9seWxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlUG9seWxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X1BvbHlsaW5lR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlUG9seWxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lVm9sdW1lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBjb21wdXRlQXR0cmlidXRlczIoY29tYmluZWRQb3NpdGlvbnMsIHNoYXBlLCBib3VuZGluZ1JlY3RhbmdsZSwgdmVydGV4Rm9ybWF0KSB7CiAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgIGF0dHJpYnV0ZXMucG9zaXRpb24gPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBjb21iaW5lZFBvc2l0aW9ucwogICAgICB9KTsKICAgIH0KICAgIGNvbnN0IHNoYXBlTGVuZ3RoID0gc2hhcGUubGVuZ3RoOwogICAgY29uc3QgdmVydGV4Q291bnQgPSBjb21iaW5lZFBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3QgbGVuZ3RoID0gKHZlcnRleENvdW50IC0gc2hhcGVMZW5ndGggKiAyKSAvIChzaGFwZUxlbmd0aCAqIDIpOwogICAgY29uc3QgZmlyc3RFbmRJbmRpY2VzID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQudHJpYW5ndWxhdGUoc2hhcGUpOwogICAgY29uc3QgaW5kaWNlc0NvdW50ID0gKGxlbmd0aCAtIDEpICogc2hhcGVMZW5ndGggKiA2ICsgZmlyc3RFbmRJbmRpY2VzLmxlbmd0aCAqIDI7CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkodmVydGV4Q291bnQsIGluZGljZXNDb3VudCk7CiAgICBsZXQgaTIsIGoyOwogICAgbGV0IGxsLCB1bCwgdXIsIGxyOwogICAgY29uc3Qgb2Zmc2V0ID0gc2hhcGVMZW5ndGggKiAyOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgZm9yIChqMiA9IDA7IGoyIDwgc2hhcGVMZW5ndGggLSAxOyBqMisrKSB7CiAgICAgICAgbGwgPSBqMiAqIDIgKyBpMiAqIHNoYXBlTGVuZ3RoICogMjsKICAgICAgICBsciA9IGxsICsgb2Zmc2V0OwogICAgICAgIHVsID0gbGwgKyAxOwogICAgICAgIHVyID0gdWwgKyBvZmZzZXQ7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHVsOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBsbDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gdXI7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHVyOwogICAgICAgIGluZGljZXNbaW5kZXgrK10gPSBsbDsKICAgICAgICBpbmRpY2VzW2luZGV4KytdID0gbHI7CiAgICAgIH0KICAgICAgbGwgPSBzaGFwZUxlbmd0aCAqIDIgLSAyICsgaTIgKiBzaGFwZUxlbmd0aCAqIDI7CiAgICAgIHVsID0gbGwgKyAxOwogICAgICB1ciA9IHVsICsgb2Zmc2V0OwogICAgICBsciA9IGxsICsgb2Zmc2V0OwogICAgICBpbmRpY2VzW2luZGV4KytdID0gdWw7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBsbDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHVyOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gdXI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBsbDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGxyOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5zdCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgIGNvbnN0IHN0MiA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGV4Q291bnQgKiAyKTsKICAgICAgY29uc3QgbGVuZ3RoU3QgPSAxIC8gKGxlbmd0aCAtIDEpOwogICAgICBjb25zdCBoZWlnaHRTdCA9IDEgLyBib3VuZGluZ1JlY3RhbmdsZS5oZWlnaHQ7CiAgICAgIGNvbnN0IGhlaWdodE9mZnNldCA9IGJvdW5kaW5nUmVjdGFuZ2xlLmhlaWdodCAvIDI7CiAgICAgIGxldCBzMiwgdDI7CiAgICAgIGxldCBzdGluZGV4ID0gMDsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgczIgPSBpMiAqIGxlbmd0aFN0OwogICAgICAgIHQyID0gaGVpZ2h0U3QgKiAoc2hhcGVbMF0ueSArIGhlaWdodE9mZnNldCk7CiAgICAgICAgc3QyW3N0aW5kZXgrK10gPSBzMjsKICAgICAgICBzdDJbc3RpbmRleCsrXSA9IHQyOwogICAgICAgIGZvciAoajIgPSAxOyBqMiA8IHNoYXBlTGVuZ3RoOyBqMisrKSB7CiAgICAgICAgICB0MiA9IGhlaWdodFN0ICogKHNoYXBlW2oyXS55ICsgaGVpZ2h0T2Zmc2V0KTsKICAgICAgICAgIHN0MltzdGluZGV4KytdID0gczI7CiAgICAgICAgICBzdDJbc3RpbmRleCsrXSA9IHQyOwogICAgICAgICAgc3QyW3N0aW5kZXgrK10gPSBzMjsKICAgICAgICAgIHN0MltzdGluZGV4KytdID0gdDI7CiAgICAgICAgfQogICAgICAgIHQyID0gaGVpZ2h0U3QgKiAoc2hhcGVbMF0ueSArIGhlaWdodE9mZnNldCk7CiAgICAgICAgc3QyW3N0aW5kZXgrK10gPSBzMjsKICAgICAgICBzdDJbc3RpbmRleCsrXSA9IHQyOwogICAgICB9CiAgICAgIGZvciAoajIgPSAwOyBqMiA8IHNoYXBlTGVuZ3RoOyBqMisrKSB7CiAgICAgICAgczIgPSAwOwogICAgICAgIHQyID0gaGVpZ2h0U3QgKiAoc2hhcGVbajJdLnkgKyBoZWlnaHRPZmZzZXQpOwogICAgICAgIHN0MltzdGluZGV4KytdID0gczI7CiAgICAgICAgc3QyW3N0aW5kZXgrK10gPSB0MjsKICAgICAgfQogICAgICBmb3IgKGoyID0gMDsgajIgPCBzaGFwZUxlbmd0aDsgajIrKykgewogICAgICAgIHMyID0gKGxlbmd0aCAtIDEpICogbGVuZ3RoU3Q7CiAgICAgICAgdDIgPSBoZWlnaHRTdCAqIChzaGFwZVtqMl0ueSArIGhlaWdodE9mZnNldCk7CiAgICAgICAgc3QyW3N0aW5kZXgrK10gPSBzMjsKICAgICAgICBzdDJbc3RpbmRleCsrXSA9IHQyOwogICAgICB9CiAgICAgIGF0dHJpYnV0ZXMuc3QgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMiwKICAgICAgICB2YWx1ZXM6IG5ldyBGbG9hdDMyQXJyYXkoc3QyKQogICAgICB9KTsKICAgIH0KICAgIGNvbnN0IGVuZE9mZnNldCA9IHZlcnRleENvdW50IC0gc2hhcGVMZW5ndGggKiAyOwogICAgZm9yIChpMiA9IDA7IGkyIDwgZmlyc3RFbmRJbmRpY2VzLmxlbmd0aDsgaTIgKz0gMykgewogICAgICBjb25zdCB2MDIgPSBmaXJzdEVuZEluZGljZXNbaTJdICsgZW5kT2Zmc2V0OwogICAgICBjb25zdCB2MTIgPSBmaXJzdEVuZEluZGljZXNbaTIgKyAxXSArIGVuZE9mZnNldDsKICAgICAgY29uc3QgdjIyID0gZmlyc3RFbmRJbmRpY2VzW2kyICsgMl0gKyBlbmRPZmZzZXQ7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSB2MDI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSB2MTI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSB2MjI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSB2MjIgKyBzaGFwZUxlbmd0aDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IHYxMiArIHNoYXBlTGVuZ3RoOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gdjAyICsgc2hhcGVMZW5ndGg7CiAgICB9CiAgICBsZXQgZ2VvbWV0cnkgPSBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgIGF0dHJpYnV0ZXMsCiAgICAgIGluZGljZXMsCiAgICAgIGJvdW5kaW5nU3BoZXJlOiBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcyhjb21iaW5lZFBvc2l0aW9ucyksCiAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5UUklBTkdMRVMKICAgIH0pOwogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgZ2VvbWV0cnkgPSBHZW9tZXRyeVBpcGVsaW5lX2RlZmF1bHQuY29tcHV0ZU5vcm1hbChnZW9tZXRyeSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQgfHwgdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICB0cnkgewogICAgICAgIGdlb21ldHJ5ID0gR2VvbWV0cnlQaXBlbGluZV9kZWZhdWx0LmNvbXB1dGVUYW5nZW50QW5kQml0YW5nZW50KGdlb21ldHJ5KTsKICAgICAgfSBjYXRjaCAoZTIpIHsKICAgICAgICBvbmVUaW1lV2FybmluZ19kZWZhdWx0KAogICAgICAgICAgInBvbHlsaW5lLXZvbHVtZS10YW5nZW50LWJpdGFuZ2VudCIsCiAgICAgICAgICAiVW5hYmxlIHRvIGNvbXB1dGUgdGFuZ2VudHMgYW5kIGJpdGFuZ2VudHMgZm9yIHBvbHlsaW5lIHZvbHVtZSBnZW9tZXRyeSIKICAgICAgICApOwogICAgICB9CiAgICAgIGlmICghdmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQgPSB2b2lkIDA7CiAgICAgIH0KICAgICAgaWYgKCF2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5iaXRhbmdlbnQgPSB2b2lkIDA7CiAgICAgIH0KICAgICAgaWYgKCF2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLnN0ID0gdm9pZCAwOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gZ2VvbWV0cnk7CiAgfQogIGZ1bmN0aW9uIFBvbHlsaW5lVm9sdW1lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb2x5bGluZVBvc2l0aW9uczsKICAgIGNvbnN0IHNoYXBlID0gb3B0aW9ucy5zaGFwZVBvc2l0aW9uczsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMucG9seWxpbmVQb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzaGFwZSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMuc2hhcGVQb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICB0aGlzLl9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICB0aGlzLl9zaGFwZSA9IHNoYXBlOwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCk7CiAgICB0aGlzLl9jb3JuZXJUeXBlID0gb3B0aW9ucy5jb3JuZXJUeXBlID8/IENvcm5lclR5cGVfZGVmYXVsdC5ST1VOREVEOwogICAgdGhpcy5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUoCiAgICAgIG9wdGlvbnMudmVydGV4Rm9ybWF0ID8/IFZlcnRleEZvcm1hdF9kZWZhdWx0LkRFRkFVTFQKICAgICk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlUG9seWxpbmVWb2x1bWVHZW9tZXRyeSI7CiAgICBsZXQgbnVtQ29tcG9uZW50cyA9IDEgKyBwb3NpdGlvbnMubGVuZ3RoICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIG51bUNvbXBvbmVudHMgKz0gMSArIHNoYXBlLmxlbmd0aCAqIENhcnRlc2lhbjJfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICB0aGlzLnBhY2tlZExlbmd0aCA9IG51bUNvbXBvbmVudHMgKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAyOwogIH0KICB2YXIgc2NyYXRjaEVsbGlwc29pZDksIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQxMSwgc2NyYXRjaE9wdGlvbnMxNywgYnJTY3JhdGNoLCBQb2x5bGluZVZvbHVtZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWxpbmVWb2x1bWVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWxpbmVWb2x1bWVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfYXJyYXlSZW1vdmVEdXBsaWNhdGVzKCk7CiAgICAgIGluaXRfQm91bmRpbmdSZWN0YW5nbGUoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Db3JuZXJUeXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5UGlwZWxpbmUoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X29uZVRpbWVXYXJuaW5nKCk7CiAgICAgIGluaXRfUG9seWdvblBpcGVsaW5lKCk7CiAgICAgIGluaXRfUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnkoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIGluaXRfV2luZGluZ09yZGVyKCk7CiAgICAgIFBvbHlsaW5lVm9sdW1lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHZhbHVlLl9wb3NpdGlvbnM7CiAgICAgICAgbGV0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2socG9zaXRpb25zW2kyXSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBzaGFwZSA9IHZhbHVlLl9zaGFwZTsKICAgICAgICBsZW5ndGggPSBzaGFwZS5sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2soc2hhcGVbaTJdLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIEVsbGlwc29pZF9kZWZhdWx0LnBhY2sodmFsdWUuX2VsbGlwc29pZCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2sodmFsdWUuX3ZlcnRleEZvcm1hdCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fY29ybmVyVHlwZTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQ5ID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoRWxsaXBzb2lkX2RlZmF1bHQuVU5JVF9TUEhFUkUpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTEgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE9wdGlvbnMxNyA9IHsKICAgICAgICBwb2x5bGluZVBvc2l0aW9uczogdm9pZCAwLAogICAgICAgIHNoYXBlUG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkOSwKICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IHNjcmF0Y2hWZXJ0ZXhGb3JtYXQxMSwKICAgICAgICBjb3JuZXJUeXBlOiB2b2lkIDAsCiAgICAgICAgZ3JhbnVsYXJpdHk6IHZvaWQgMAogICAgICB9OwogICAgICBQb2x5bGluZVZvbHVtZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgbGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgcG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHNoYXBlID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjJfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIHNoYXBlW2kyXSA9IENhcnRlc2lhbjJfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQ5KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgsCiAgICAgICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTEKICAgICAgICApOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IGNvcm5lclR5cGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxNy5wb2x5bGluZVBvc2l0aW9ucyA9IHBvc2l0aW9uczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTcuc2hhcGVQb3NpdGlvbnMgPSBzaGFwZTsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTcuY29ybmVyVHlwZSA9IGNvcm5lclR5cGU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE3LmdyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICByZXR1cm4gbmV3IFBvbHlsaW5lVm9sdW1lR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnMxNyk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgIHJlc3VsdC5fc2hhcGUgPSBzaGFwZTsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCwgcmVzdWx0Ll9lbGxpcHNvaWQpOwogICAgICAgIHJlc3VsdC5fdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQuY2xvbmUodmVydGV4Rm9ybWF0LCByZXN1bHQuX3ZlcnRleEZvcm1hdCk7CiAgICAgICAgcmVzdWx0Ll9jb3JuZXJUeXBlID0gY29ybmVyVHlwZTsKICAgICAgICByZXN1bHQuX2dyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgYnJTY3JhdGNoID0gbmV3IEJvdW5kaW5nUmVjdGFuZ2xlX2RlZmF1bHQoKTsKICAgICAgUG9seWxpbmVWb2x1bWVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKHBvbHlsaW5lVm9sdW1lR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBwb2x5bGluZVZvbHVtZUdlb21ldHJ5Ll9wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgY2xlYW5Qb3NpdGlvbnMgPSBhcnJheVJlbW92ZUR1cGxpY2F0ZXNfZGVmYXVsdCgKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uCiAgICAgICAgKTsKICAgICAgICBsZXQgc2hhcGUyRCA9IHBvbHlsaW5lVm9sdW1lR2VvbWV0cnkuX3NoYXBlOwogICAgICAgIHNoYXBlMkQgPSBQb2x5bGluZVZvbHVtZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LnJlbW92ZUR1cGxpY2F0ZXNGcm9tU2hhcGUoc2hhcGUyRCk7CiAgICAgICAgaWYgKGNsZWFuUG9zaXRpb25zLmxlbmd0aCA8IDIgfHwgc2hhcGUyRC5sZW5ndGggPCAzKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuY29tcHV0ZVdpbmRpbmdPcmRlcjJEKHNoYXBlMkQpID09PSBXaW5kaW5nT3JkZXJfZGVmYXVsdC5DTE9DS1dJU0UpIHsKICAgICAgICAgIHNoYXBlMkQucmV2ZXJzZSgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBib3VuZGluZ1JlY3RhbmdsZSA9IEJvdW5kaW5nUmVjdGFuZ2xlX2RlZmF1bHQuZnJvbVBvaW50cyhzaGFwZTJELCBiclNjcmF0Y2gpOwogICAgICAgIGNvbnN0IGNvbXB1dGVkUG9zaXRpb25zID0gUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb25zKAogICAgICAgICAgY2xlYW5Qb3NpdGlvbnMsCiAgICAgICAgICBzaGFwZTJELAogICAgICAgICAgYm91bmRpbmdSZWN0YW5nbGUsCiAgICAgICAgICBwb2x5bGluZVZvbHVtZUdlb21ldHJ5LAogICAgICAgICAgdHJ1ZQogICAgICAgICk7CiAgICAgICAgcmV0dXJuIGNvbXB1dGVBdHRyaWJ1dGVzMigKICAgICAgICAgIGNvbXB1dGVkUG9zaXRpb25zLAogICAgICAgICAgc2hhcGUyRCwKICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLAogICAgICAgICAgcG9seWxpbmVWb2x1bWVHZW9tZXRyeS5fdmVydGV4Rm9ybWF0CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgUG9seWxpbmVWb2x1bWVHZW9tZXRyeV9kZWZhdWx0ID0gUG9seWxpbmVWb2x1bWVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBvbHlsaW5lVm9sdW1lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUG9seWxpbmVWb2x1bWVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlUG9seWxpbmVWb2x1bWVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5KHBvbHlsaW5lVm9sdW1lR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIHBvbHlsaW5lVm9sdW1lR2VvbWV0cnkgPSBQb2x5bGluZVZvbHVtZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgIHBvbHlsaW5lVm9sdW1lR2VvbWV0cnksCiAgICAgICAgb2Zmc2V0CiAgICAgICk7CiAgICB9CiAgICBwb2x5bGluZVZvbHVtZUdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZSgKICAgICAgcG9seWxpbmVWb2x1bWVHZW9tZXRyeS5fZWxsaXBzb2lkCiAgICApOwogICAgcmV0dXJuIFBvbHlsaW5lVm9sdW1lR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShwb2x5bGluZVZvbHVtZUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZVBvbHlsaW5lVm9sdW1lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfUG9seWxpbmVWb2x1bWVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBjb21wdXRlQXR0cmlidXRlczMocG9zaXRpb25zLCBzaGFwZSkgewogICAgY29uc3QgYXR0cmlidXRlcyA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCgpOwogICAgYXR0cmlidXRlcy5wb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgfSk7CiAgICBjb25zdCBzaGFwZUxlbmd0aCA9IHNoYXBlLmxlbmd0aDsKICAgIGNvbnN0IHZlcnRleENvdW50ID0gYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IHBvc2l0aW9uTGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aCAvIDM7CiAgICBjb25zdCBzaGFwZUNvdW50ID0gcG9zaXRpb25MZW5ndGggLyBzaGFwZUxlbmd0aDsKICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgdmVydGV4Q291bnQsCiAgICAgIDIgKiBzaGFwZUxlbmd0aCAqIChzaGFwZUNvdW50ICsgMSkKICAgICk7CiAgICBsZXQgaTIsIGoyOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGkyID0gMDsKICAgIGxldCBvZmZzZXQgPSBpMiAqIHNoYXBlTGVuZ3RoOwogICAgZm9yIChqMiA9IDA7IGoyIDwgc2hhcGVMZW5ndGggLSAxOyBqMisrKSB7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBqMiArIG9mZnNldDsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGoyICsgb2Zmc2V0ICsgMTsKICAgIH0KICAgIGluZGljZXNbaW5kZXgrK10gPSBzaGFwZUxlbmd0aCAtIDEgKyBvZmZzZXQ7CiAgICBpbmRpY2VzW2luZGV4KytdID0gb2Zmc2V0OwogICAgaTIgPSBzaGFwZUNvdW50IC0gMTsKICAgIG9mZnNldCA9IGkyICogc2hhcGVMZW5ndGg7CiAgICBmb3IgKGoyID0gMDsgajIgPCBzaGFwZUxlbmd0aCAtIDE7IGoyKyspIHsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGoyICsgb2Zmc2V0OwogICAgICBpbmRpY2VzW2luZGV4KytdID0gajIgKyBvZmZzZXQgKyAxOwogICAgfQogICAgaW5kaWNlc1tpbmRleCsrXSA9IHNoYXBlTGVuZ3RoIC0gMSArIG9mZnNldDsKICAgIGluZGljZXNbaW5kZXgrK10gPSBvZmZzZXQ7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBzaGFwZUNvdW50IC0gMTsgaTIrKykgewogICAgICBjb25zdCBmaXJzdE9mZnNldCA9IHNoYXBlTGVuZ3RoICogaTI7CiAgICAgIGNvbnN0IHNlY29uZE9mZnNldCA9IGZpcnN0T2Zmc2V0ICsgc2hhcGVMZW5ndGg7CiAgICAgIGZvciAoajIgPSAwOyBqMiA8IHNoYXBlTGVuZ3RoOyBqMisrKSB7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGoyICsgZmlyc3RPZmZzZXQ7CiAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGoyICsgc2Vjb25kT2Zmc2V0OwogICAgICB9CiAgICB9CiAgICBjb25zdCBnZW9tZXRyeSA9IG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgYXR0cmlidXRlcywKICAgICAgaW5kaWNlczogSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkodmVydGV4Q291bnQsIGluZGljZXMpLAogICAgICBib3VuZGluZ1NwaGVyZTogQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tVmVydGljZXMocG9zaXRpb25zKSwKICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTCiAgICB9KTsKICAgIHJldHVybiBnZW9tZXRyeTsKICB9CiAgZnVuY3Rpb24gUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb2x5bGluZVBvc2l0aW9uczsKICAgIGNvbnN0IHNoYXBlID0gb3B0aW9ucy5zaGFwZVBvc2l0aW9uczsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMucG9seWxpbmVQb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChzaGFwZSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMuc2hhcGVQb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICB0aGlzLl9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICB0aGlzLl9zaGFwZSA9IHNoYXBlOwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCk7CiAgICB0aGlzLl9jb3JuZXJUeXBlID0gb3B0aW9ucy5jb3JuZXJUeXBlID8/IENvcm5lclR5cGVfZGVmYXVsdC5ST1VOREVEOwogICAgdGhpcy5fZ3JhbnVsYXJpdHkgPSBvcHRpb25zLmdyYW51bGFyaXR5ID8/IE1hdGhfZGVmYXVsdC5SQURJQU5TX1BFUl9ERUdSRUU7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5IjsKICAgIGxldCBudW1Db21wb25lbnRzID0gMSArIHBvc2l0aW9ucy5sZW5ndGggKiBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgbnVtQ29tcG9uZW50cyArPSAxICsgc2hhcGUubGVuZ3RoICogQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIHRoaXMucGFja2VkTGVuZ3RoID0gbnVtQ29tcG9uZW50cyArIEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDI7CiAgfQogIHZhciBzY3JhdGNoRWxsaXBzb2lkMTAsIHNjcmF0Y2hPcHRpb25zMTgsIGJyU2NyYXRjaDIsIFBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9hcnJheVJlbW92ZUR1cGxpY2F0ZXMoKTsKICAgICAgaW5pdF9Cb3VuZGluZ1JlY3RhbmdsZSgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Nvcm5lclR5cGUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9Qb2x5Z29uUGlwZWxpbmUoKTsKICAgICAgaW5pdF9Qb2x5bGluZVZvbHVtZUdlb21ldHJ5TGlicmFyeSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9XaW5kaW5nT3JkZXIoKTsKICAgICAgUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IHZhbHVlLl9wb3NpdGlvbnM7CiAgICAgICAgbGV0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2socG9zaXRpb25zW2kyXSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBjb25zdCBzaGFwZSA9IHZhbHVlLl9zaGFwZTsKICAgICAgICBsZW5ndGggPSBzaGFwZS5sZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2soc2hhcGVbaTJdLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIEVsbGlwc29pZF9kZWZhdWx0LnBhY2sodmFsdWUuX2VsbGlwc29pZCwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fY29ybmVyVHlwZTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQxMCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgc2NyYXRjaE9wdGlvbnMxOCA9IHsKICAgICAgICBwb2x5bGluZVBvc2l0aW9uczogdm9pZCAwLAogICAgICAgIHNoYXBlUG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkMTAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgY29ybmVyVHlwZTogdm9pZCAwLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAKICAgICAgfTsKICAgICAgUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGxldCBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBwb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIGxlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc2hhcGUgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgc2hhcGVbaTJdID0gQ2FydGVzaWFuMl9kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaEVsbGlwc29pZDEwKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBjb3JuZXJUeXBlID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMTgucG9seWxpbmVQb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE4LnNoYXBlUG9zaXRpb25zID0gc2hhcGU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE4LmNvcm5lclR5cGUgPSBjb3JuZXJUeXBlOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxOC5ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgICAgcmV0dXJuIG5ldyBQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczE4KTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9zaGFwZSA9IHNoYXBlOwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll9jb3JuZXJUeXBlID0gY29ybmVyVHlwZTsKICAgICAgICByZXN1bHQuX2dyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgYnJTY3JhdGNoMiA9IG5ldyBCb3VuZGluZ1JlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIFBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24ocG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeS5fcG9zaXRpb25zOwogICAgICAgIGNvbnN0IGNsZWFuUG9zaXRpb25zID0gYXJyYXlSZW1vdmVEdXBsaWNhdGVzX2RlZmF1bHQoCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbgogICAgICAgICk7CiAgICAgICAgbGV0IHNoYXBlMkQgPSBwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeS5fc2hhcGU7CiAgICAgICAgc2hhcGUyRCA9IFBvbHlsaW5lVm9sdW1lR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQucmVtb3ZlRHVwbGljYXRlc0Zyb21TaGFwZShzaGFwZTJEKTsKICAgICAgICBpZiAoY2xlYW5Qb3NpdGlvbnMubGVuZ3RoIDwgMiB8fCBzaGFwZTJELmxlbmd0aCA8IDMpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGlmIChQb2x5Z29uUGlwZWxpbmVfZGVmYXVsdC5jb21wdXRlV2luZGluZ09yZGVyMkQoc2hhcGUyRCkgPT09IFdpbmRpbmdPcmRlcl9kZWZhdWx0LkNMT0NLV0lTRSkgewogICAgICAgICAgc2hhcGUyRC5yZXZlcnNlKCk7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGJvdW5kaW5nUmVjdGFuZ2xlID0gQm91bmRpbmdSZWN0YW5nbGVfZGVmYXVsdC5mcm9tUG9pbnRzKHNoYXBlMkQsIGJyU2NyYXRjaDIpOwogICAgICAgIGNvbnN0IGNvbXB1dGVkUG9zaXRpb25zID0gUG9seWxpbmVWb2x1bWVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb25zKAogICAgICAgICAgY2xlYW5Qb3NpdGlvbnMsCiAgICAgICAgICBzaGFwZTJELAogICAgICAgICAgYm91bmRpbmdSZWN0YW5nbGUsCiAgICAgICAgICBwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeSwKICAgICAgICAgIGZhbHNlCiAgICAgICAgKTsKICAgICAgICByZXR1cm4gY29tcHV0ZUF0dHJpYnV0ZXMzKGNvbXB1dGVkUG9zaXRpb25zLCBzaGFwZTJEKTsKICAgICAgfTsKICAgICAgUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeShwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkgPSBQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LnVucGFjaygKICAgICAgICBwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeSwKICAgICAgICBvZmZzZXQKICAgICAgKTsKICAgIH0KICAgIHBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZSgKICAgICAgcG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkuX2VsbGlwc29pZAogICAgKTsKICAgIHJldHVybiBQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KAogICAgICBwb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeQogICAgKTsKICB9CiAgdmFyIGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5LmpzCiAgZnVuY3Rpb24gZ2V0Um90YXRpb25PcHRpb25zKG53Q29ybmVyLCByb3RhdGlvbiwgZ3JhbnVsYXJpdHlYLCBncmFudWxhcml0eVksIGNlbnRlciwgd2lkdGgsIGhlaWdodCkgewogICAgY29uc3QgY29zUm90YXRpb24gPSBNYXRoLmNvcyhyb3RhdGlvbik7CiAgICBjb25zdCBncmFuWUNvcyA9IGdyYW51bGFyaXR5WSAqIGNvc1JvdGF0aW9uOwogICAgY29uc3QgZ3JhblhDb3MgPSBncmFudWxhcml0eVggKiBjb3NSb3RhdGlvbjsKICAgIGNvbnN0IHNpblJvdGF0aW9uID0gTWF0aC5zaW4ocm90YXRpb24pOwogICAgY29uc3QgZ3JhbllTaW4gPSBncmFudWxhcml0eVkgKiBzaW5Sb3RhdGlvbjsKICAgIGNvbnN0IGdyYW5YU2luID0gZ3JhbnVsYXJpdHlYICogc2luUm90YXRpb247CiAgICBwcm9qLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgbndDYXJ0ZXNpYW4gPSBwcm9qLnByb2plY3QobndDb3JuZXIsIG53Q2FydGVzaWFuKTsKICAgIG53Q2FydGVzaWFuID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KG53Q2FydGVzaWFuLCBjZW50ZXJDYXJ0ZXNpYW4sIG53Q2FydGVzaWFuKTsKICAgIGNvbnN0IHJvdGF0aW9uTWF0cml4ID0gTWF0cml4Ml9kZWZhdWx0LmZyb21Sb3RhdGlvbihyb3RhdGlvbiwgcm90YXRpb25NYXRyaXhTY3JhdGNoKTsKICAgIG53Q2FydGVzaWFuID0gTWF0cml4Ml9kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IoCiAgICAgIHJvdGF0aW9uTWF0cml4LAogICAgICBud0NhcnRlc2lhbiwKICAgICAgbndDYXJ0ZXNpYW4KICAgICk7CiAgICBud0NhcnRlc2lhbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQobndDYXJ0ZXNpYW4sIGNlbnRlckNhcnRlc2lhbiwgbndDYXJ0ZXNpYW4pOwogICAgbndDb3JuZXIgPSBwcm9qLnVucHJvamVjdChud0NhcnRlc2lhbiwgbndDb3JuZXIpOwogICAgd2lkdGggLT0gMTsKICAgIGhlaWdodCAtPSAxOwogICAgY29uc3QgbGF0aXR1ZGUgPSBud0Nvcm5lci5sYXRpdHVkZTsKICAgIGNvbnN0IGxhdGl0dWRlMCA9IGxhdGl0dWRlICsgd2lkdGggKiBncmFuWFNpbjsKICAgIGNvbnN0IGxhdGl0dWRlMSA9IGxhdGl0dWRlIC0gZ3JhbllDb3MgKiBoZWlnaHQ7CiAgICBjb25zdCBsYXRpdHVkZTIgPSBsYXRpdHVkZSAtIGdyYW5ZQ29zICogaGVpZ2h0ICsgd2lkdGggKiBncmFuWFNpbjsKICAgIGNvbnN0IG5vcnRoID0gTWF0aC5tYXgobGF0aXR1ZGUsIGxhdGl0dWRlMCwgbGF0aXR1ZGUxLCBsYXRpdHVkZTIpOwogICAgY29uc3Qgc291dGggPSBNYXRoLm1pbihsYXRpdHVkZSwgbGF0aXR1ZGUwLCBsYXRpdHVkZTEsIGxhdGl0dWRlMik7CiAgICBjb25zdCBsb25naXR1ZGUgPSBud0Nvcm5lci5sb25naXR1ZGU7CiAgICBjb25zdCBsb25naXR1ZGUwID0gbG9uZ2l0dWRlICsgd2lkdGggKiBncmFuWENvczsKICAgIGNvbnN0IGxvbmdpdHVkZTEgPSBsb25naXR1ZGUgKyBoZWlnaHQgKiBncmFuWVNpbjsKICAgIGNvbnN0IGxvbmdpdHVkZTIgPSBsb25naXR1ZGUgKyBoZWlnaHQgKiBncmFuWVNpbiArIHdpZHRoICogZ3JhblhDb3M7CiAgICBjb25zdCBlYXN0ID0gTWF0aC5tYXgobG9uZ2l0dWRlLCBsb25naXR1ZGUwLCBsb25naXR1ZGUxLCBsb25naXR1ZGUyKTsKICAgIGNvbnN0IHdlc3QgPSBNYXRoLm1pbihsb25naXR1ZGUsIGxvbmdpdHVkZTAsIGxvbmdpdHVkZTEsIGxvbmdpdHVkZTIpOwogICAgcmV0dXJuIHsKICAgICAgbm9ydGgsCiAgICAgIHNvdXRoLAogICAgICBlYXN0LAogICAgICB3ZXN0LAogICAgICBncmFuWUNvcywKICAgICAgZ3JhbllTaW4sCiAgICAgIGdyYW5YQ29zLAogICAgICBncmFuWFNpbiwKICAgICAgbndDb3JuZXIKICAgIH07CiAgfQogIHZhciBjb3MzLCBzaW4zLCBzcXJ0LCBSZWN0YW5nbGVHZW9tZXRyeUxpYnJhcnksIHJvdGF0aW9uTWF0cml4U2NyYXRjaCwgbndDYXJ0ZXNpYW4sIGNlbnRlclNjcmF0Y2gzLCBjZW50ZXJDYXJ0ZXNpYW4sIHByb2osIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0OwogIHZhciBpbml0X1JlY3RhbmdsZUdlb21ldHJ5TGlicmFyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5LmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvZ3JhcGhpY1Byb2plY3Rpb24oKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4MigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBjb3MzID0gTWF0aC5jb3M7CiAgICAgIHNpbjMgPSBNYXRoLnNpbjsKICAgICAgc3FydCA9IE1hdGguc3FydDsKICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5ID0ge307CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeS5jb21wdXRlUG9zaXRpb24gPSBmdW5jdGlvbihjb21wdXRlZE9wdGlvbnMsIGVsbGlwc29pZCwgY29tcHV0ZVNULCByb3csIGNvbCwgcG9zaXRpb24sIHN0MikgewogICAgICAgIGNvbnN0IHJhZGlpU3F1YXJlZCA9IGVsbGlwc29pZC5yYWRpaVNxdWFyZWQ7CiAgICAgICAgY29uc3QgbndDb3JuZXIgPSBjb21wdXRlZE9wdGlvbnMubndDb3JuZXI7CiAgICAgICAgY29uc3QgcmVjdGFuZ2xlID0gY29tcHV0ZWRPcHRpb25zLmJvdW5kaW5nUmVjdGFuZ2xlOwogICAgICAgIGxldCBzdExhdGl0dWRlID0gbndDb3JuZXIubGF0aXR1ZGUgLSBjb21wdXRlZE9wdGlvbnMuZ3JhbllDb3MgKiByb3cgKyBjb2wgKiBjb21wdXRlZE9wdGlvbnMuZ3JhblhTaW47CiAgICAgICAgY29uc3QgY29zTGF0aXR1ZGUgPSBjb3MzKHN0TGF0aXR1ZGUpOwogICAgICAgIGNvbnN0IG5aID0gc2luMyhzdExhdGl0dWRlKTsKICAgICAgICBjb25zdCBrWiA9IHJhZGlpU3F1YXJlZC56ICogblo7CiAgICAgICAgbGV0IHN0TG9uZ2l0dWRlID0gbndDb3JuZXIubG9uZ2l0dWRlICsgcm93ICogY29tcHV0ZWRPcHRpb25zLmdyYW5ZU2luICsgY29sICogY29tcHV0ZWRPcHRpb25zLmdyYW5YQ29zOwogICAgICAgIGNvbnN0IG5YID0gY29zTGF0aXR1ZGUgKiBjb3MzKHN0TG9uZ2l0dWRlKTsKICAgICAgICBjb25zdCBuWSA9IGNvc0xhdGl0dWRlICogc2luMyhzdExvbmdpdHVkZSk7CiAgICAgICAgY29uc3Qga1ggPSByYWRpaVNxdWFyZWQueCAqIG5YOwogICAgICAgIGNvbnN0IGtZID0gcmFkaWlTcXVhcmVkLnkgKiBuWTsKICAgICAgICBjb25zdCBnYW1tYSA9IHNxcnQoa1ggKiBuWCArIGtZICogblkgKyBrWiAqIG5aKTsKICAgICAgICBwb3NpdGlvbi54ID0ga1ggLyBnYW1tYTsKICAgICAgICBwb3NpdGlvbi55ID0ga1kgLyBnYW1tYTsKICAgICAgICBwb3NpdGlvbi56ID0ga1ogLyBnYW1tYTsKICAgICAgICBpZiAoY29tcHV0ZVNUKSB7CiAgICAgICAgICBjb25zdCBzdE53Q29ybmVyID0gY29tcHV0ZWRPcHRpb25zLnN0TndDb3JuZXI7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHN0TndDb3JuZXIpKSB7CiAgICAgICAgICAgIHN0TGF0aXR1ZGUgPSBzdE53Q29ybmVyLmxhdGl0dWRlIC0gY29tcHV0ZWRPcHRpb25zLnN0R3JhbllDb3MgKiByb3cgKyBjb2wgKiBjb21wdXRlZE9wdGlvbnMuc3RHcmFuWFNpbjsKICAgICAgICAgICAgc3RMb25naXR1ZGUgPSBzdE53Q29ybmVyLmxvbmdpdHVkZSArIHJvdyAqIGNvbXB1dGVkT3B0aW9ucy5zdEdyYW5ZU2luICsgY29sICogY29tcHV0ZWRPcHRpb25zLnN0R3JhblhDb3M7CiAgICAgICAgICAgIHN0Mi54ID0gKHN0TG9uZ2l0dWRlIC0gY29tcHV0ZWRPcHRpb25zLnN0V2VzdCkgKiBjb21wdXRlZE9wdGlvbnMubG9uU2NhbGFyOwogICAgICAgICAgICBzdDIueSA9IChzdExhdGl0dWRlIC0gY29tcHV0ZWRPcHRpb25zLnN0U291dGgpICogY29tcHV0ZWRPcHRpb25zLmxhdFNjYWxhcjsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHN0Mi54ID0gKHN0TG9uZ2l0dWRlIC0gcmVjdGFuZ2xlLndlc3QpICogY29tcHV0ZWRPcHRpb25zLmxvblNjYWxhcjsKICAgICAgICAgICAgc3QyLnkgPSAoc3RMYXRpdHVkZSAtIHJlY3RhbmdsZS5zb3V0aCkgKiBjb21wdXRlZE9wdGlvbnMubGF0U2NhbGFyOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfTsKICAgICAgcm90YXRpb25NYXRyaXhTY3JhdGNoID0gbmV3IE1hdHJpeDJfZGVmYXVsdCgpOwogICAgICBud0NhcnRlc2lhbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2VudGVyU2NyYXRjaDMgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgY2VudGVyQ2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwcm9qID0gbmV3IEdlb2dyYXBoaWNQcm9qZWN0aW9uX2RlZmF1bHQoKTsKICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5LmNvbXB1dGVPcHRpb25zID0gZnVuY3Rpb24ocmVjdGFuZ2xlLCBncmFudWxhcml0eSwgcm90YXRpb24sIHN0Um90YXRpb24sIGJvdW5kaW5nUmVjdGFuZ2xlU2NyYXRjaCwgbndDb3JuZXJSZXN1bHQsIHN0TndDb3JuZXJSZXN1bHQpIHsKICAgICAgICBsZXQgZWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgIGxldCB3ZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgbGV0IG5vcnRoID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICAgIGxldCBzb3V0aCA9IHJlY3RhbmdsZS5zb3V0aDsKICAgICAgICBsZXQgbm9ydGhDYXAgPSBmYWxzZTsKICAgICAgICBsZXQgc291dGhDYXAgPSBmYWxzZTsKICAgICAgICBpZiAobm9ydGggPT09IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTykgewogICAgICAgICAgbm9ydGhDYXAgPSB0cnVlOwogICAgICAgIH0KICAgICAgICBpZiAoc291dGggPT09IC1NYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08pIHsKICAgICAgICAgIHNvdXRoQ2FwID0gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgbGV0IGR4OwogICAgICAgIGNvbnN0IGR5ID0gbm9ydGggLSBzb3V0aDsKICAgICAgICBpZiAod2VzdCA+IGVhc3QpIHsKICAgICAgICAgIGR4ID0gTWF0aF9kZWZhdWx0LlRXT19QSSAtIHdlc3QgKyBlYXN0OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBkeCA9IGVhc3QgLSB3ZXN0OwogICAgICAgIH0KICAgICAgICBjb25zdCB3aWR0aCA9IE1hdGguY2VpbChkeCAvIGdyYW51bGFyaXR5KSArIDE7CiAgICAgICAgY29uc3QgaGVpZ2h0ID0gTWF0aC5jZWlsKGR5IC8gZ3JhbnVsYXJpdHkpICsgMTsKICAgICAgICBjb25zdCBncmFudWxhcml0eVggPSBkeCAvICh3aWR0aCAtIDEpOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5WSA9IGR5IC8gKGhlaWdodCAtIDEpOwogICAgICAgIGNvbnN0IG53Q29ybmVyID0gUmVjdGFuZ2xlX2RlZmF1bHQubm9ydGh3ZXN0KHJlY3RhbmdsZSwgbndDb3JuZXJSZXN1bHQpOwogICAgICAgIGNvbnN0IGNlbnRlciA9IFJlY3RhbmdsZV9kZWZhdWx0LmNlbnRlcihyZWN0YW5nbGUsIGNlbnRlclNjcmF0Y2gzKTsKICAgICAgICBpZiAocm90YXRpb24gIT09IDAgfHwgc3RSb3RhdGlvbiAhPT0gMCkgewogICAgICAgICAgaWYgKGNlbnRlci5sb25naXR1ZGUgPCBud0Nvcm5lci5sb25naXR1ZGUpIHsKICAgICAgICAgICAgY2VudGVyLmxvbmdpdHVkZSArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgICAgICAgfQogICAgICAgICAgcHJvai5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICAgIGNlbnRlckNhcnRlc2lhbiA9IHByb2oucHJvamVjdChjZW50ZXIsIGNlbnRlckNhcnRlc2lhbik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGdyYW5ZQ29zID0gZ3JhbnVsYXJpdHlZOwogICAgICAgIGNvbnN0IGdyYW5YQ29zID0gZ3JhbnVsYXJpdHlYOwogICAgICAgIGNvbnN0IGdyYW5ZU2luID0gMDsKICAgICAgICBjb25zdCBncmFuWFNpbiA9IDA7CiAgICAgICAgY29uc3QgYm91bmRpbmdSZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5jbG9uZSgKICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlU2NyYXRjaAogICAgICAgICk7CiAgICAgICAgY29uc3QgY29tcHV0ZWRPcHRpb25zID0gewogICAgICAgICAgZ3JhbllDb3MsCiAgICAgICAgICBncmFuWVNpbiwKICAgICAgICAgIGdyYW5YQ29zLAogICAgICAgICAgZ3JhblhTaW4sCiAgICAgICAgICBud0Nvcm5lciwKICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLAogICAgICAgICAgd2lkdGgsCiAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICBub3J0aENhcCwKICAgICAgICAgIHNvdXRoQ2FwCiAgICAgICAgfTsKICAgICAgICBpZiAocm90YXRpb24gIT09IDApIHsKICAgICAgICAgIGNvbnN0IHJvdGF0aW9uT3B0aW9ucyA9IGdldFJvdGF0aW9uT3B0aW9ucygKICAgICAgICAgICAgbndDb3JuZXIsCiAgICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgICBncmFudWxhcml0eVgsCiAgICAgICAgICAgIGdyYW51bGFyaXR5WSwKICAgICAgICAgICAgY2VudGVyLAogICAgICAgICAgICB3aWR0aCwKICAgICAgICAgICAgaGVpZ2h0CiAgICAgICAgICApOwogICAgICAgICAgbm9ydGggPSByb3RhdGlvbk9wdGlvbnMubm9ydGg7CiAgICAgICAgICBzb3V0aCA9IHJvdGF0aW9uT3B0aW9ucy5zb3V0aDsKICAgICAgICAgIGVhc3QgPSByb3RhdGlvbk9wdGlvbnMuZWFzdDsKICAgICAgICAgIHdlc3QgPSByb3RhdGlvbk9wdGlvbnMud2VzdDsKICAgICAgICAgIGlmIChub3J0aCA8IC1NYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gfHwgbm9ydGggPiBNYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08gfHwgc291dGggPCAtTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPIHx8IHNvdXRoID4gTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJSb3RhdGVkIHJlY3RhbmdsZSBpcyBpbnZhbGlkLiAgSXQgY3Jvc3NlcyBvdmVyIGVpdGhlciB0aGUgbm9ydGggb3Igc291dGggcG9sZS4iCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBjb21wdXRlZE9wdGlvbnMuZ3JhbllDb3MgPSByb3RhdGlvbk9wdGlvbnMuZ3JhbllDb3M7CiAgICAgICAgICBjb21wdXRlZE9wdGlvbnMuZ3JhbllTaW4gPSByb3RhdGlvbk9wdGlvbnMuZ3JhbllTaW47CiAgICAgICAgICBjb21wdXRlZE9wdGlvbnMuZ3JhblhDb3MgPSByb3RhdGlvbk9wdGlvbnMuZ3JhblhDb3M7CiAgICAgICAgICBjb21wdXRlZE9wdGlvbnMuZ3JhblhTaW4gPSByb3RhdGlvbk9wdGlvbnMuZ3JhblhTaW47CiAgICAgICAgICBib3VuZGluZ1JlY3RhbmdsZS5ub3J0aCA9IG5vcnRoOwogICAgICAgICAgYm91bmRpbmdSZWN0YW5nbGUuc291dGggPSBzb3V0aDsKICAgICAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLmVhc3QgPSBlYXN0OwogICAgICAgICAgYm91bmRpbmdSZWN0YW5nbGUud2VzdCA9IHdlc3Q7CiAgICAgICAgfQogICAgICAgIGlmIChzdFJvdGF0aW9uICE9PSAwKSB7CiAgICAgICAgICByb3RhdGlvbiA9IHJvdGF0aW9uIC0gc3RSb3RhdGlvbjsKICAgICAgICAgIGNvbnN0IHN0TndDb3JuZXIgPSBSZWN0YW5nbGVfZGVmYXVsdC5ub3J0aHdlc3QoYm91bmRpbmdSZWN0YW5nbGUsIHN0TndDb3JuZXJSZXN1bHQpOwogICAgICAgICAgY29uc3Qgc3RSb3RhdGlvbk9wdGlvbnMgPSBnZXRSb3RhdGlvbk9wdGlvbnMoCiAgICAgICAgICAgIHN0TndDb3JuZXIsCiAgICAgICAgICAgIHJvdGF0aW9uLAogICAgICAgICAgICBncmFudWxhcml0eVgsCiAgICAgICAgICAgIGdyYW51bGFyaXR5WSwKICAgICAgICAgICAgY2VudGVyLAogICAgICAgICAgICB3aWR0aCwKICAgICAgICAgICAgaGVpZ2h0CiAgICAgICAgICApOwogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLnN0R3JhbllDb3MgPSBzdFJvdGF0aW9uT3B0aW9ucy5ncmFuWUNvczsKICAgICAgICAgIGNvbXB1dGVkT3B0aW9ucy5zdEdyYW5YQ29zID0gc3RSb3RhdGlvbk9wdGlvbnMuZ3JhblhDb3M7CiAgICAgICAgICBjb21wdXRlZE9wdGlvbnMuc3RHcmFuWVNpbiA9IHN0Um90YXRpb25PcHRpb25zLmdyYW5ZU2luOwogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLnN0R3JhblhTaW4gPSBzdFJvdGF0aW9uT3B0aW9ucy5ncmFuWFNpbjsKICAgICAgICAgIGNvbXB1dGVkT3B0aW9ucy5zdE53Q29ybmVyID0gc3ROd0Nvcm5lcjsKICAgICAgICAgIGNvbXB1dGVkT3B0aW9ucy5zdFdlc3QgPSBzdFJvdGF0aW9uT3B0aW9ucy53ZXN0OwogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLnN0U291dGggPSBzdFJvdGF0aW9uT3B0aW9ucy5zb3V0aDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNvbXB1dGVkT3B0aW9uczsKICAgICAgfTsKICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQgPSBSZWN0YW5nbGVHZW9tZXRyeUxpYnJhcnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZWN0YW5nbGVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIGNyZWF0ZUF0dHJpYnV0ZXModmVydGV4Rm9ybWF0LCBhdHRyaWJ1dGVzKSB7CiAgICBjb25zdCBnZW8gPSBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgIGF0dHJpYnV0ZXM6IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZXNfZGVmYXVsdCgpLAogICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTCiAgICB9KTsKICAgIGdlby5hdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgIHZhbHVlczogYXR0cmlidXRlcy5wb3NpdGlvbnMKICAgIH0pOwogICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgZ2VvLmF0dHJpYnV0ZXMubm9ybWFsID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiBhdHRyaWJ1dGVzLm5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgZ2VvLmF0dHJpYnV0ZXMudGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgIHZhbHVlczogYXR0cmlidXRlcy50YW5nZW50cwogICAgICB9KTsKICAgIH0KICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgIGdlby5hdHRyaWJ1dGVzLmJpdGFuZ2VudCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgIHZhbHVlczogYXR0cmlidXRlcy5iaXRhbmdlbnRzCiAgICAgIH0pOwogICAgfQogICAgcmV0dXJuIGdlbzsKICB9CiAgZnVuY3Rpb24gY2FsY3VsYXRlQXR0cmlidXRlcyhwb3NpdGlvbnMsIHZlcnRleEZvcm1hdCwgZWxsaXBzb2lkLCB0YW5nZW50Um90YXRpb25NYXRyaXgpIHsKICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCBub3JtYWxzID0gdmVydGV4Rm9ybWF0Lm5vcm1hbCA/IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgIGNvbnN0IHRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LnRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgIGxldCBhdHRySW5kZXggPSAwOwogICAgY29uc3QgYml0YW5nZW50ID0gYml0YW5nZW50U2NyYXRjaDI7CiAgICBjb25zdCB0YW5nZW50ID0gdGFuZ2VudFNjcmF0Y2gyOwogICAgbGV0IG5vcm1hbDIgPSBub3JtYWxTY3JhdGNoNDsKICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsIHx8IHZlcnRleEZvcm1hdC50YW5nZW50IHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gMykgewogICAgICAgIGNvbnN0IHAyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkyLCBwb3NpdGlvblNjcmF0Y2gyKTsKICAgICAgICBjb25zdCBhdHRySW5kZXgxID0gYXR0ckluZGV4ICsgMTsKICAgICAgICBjb25zdCBhdHRySW5kZXgyID0gYXR0ckluZGV4ICsgMjsKICAgICAgICBub3JtYWwyID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChwMiwgbm9ybWFsMik7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50IHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhDYXJ0ZXNpYW4zX2RlZmF1bHQuVU5JVF9aLCBub3JtYWwyLCB0YW5nZW50KTsKICAgICAgICAgIE1hdHJpeDNfZGVmYXVsdC5tdWx0aXBseUJ5VmVjdG9yKHRhbmdlbnRSb3RhdGlvbk1hdHJpeCwgdGFuZ2VudCwgdGFuZ2VudCk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHRhbmdlbnQsIHRhbmdlbnQpOwogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Mobm9ybWFsMiwgdGFuZ2VudCwgYml0YW5nZW50KSwKICAgICAgICAgICAgICBiaXRhbmdlbnQKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgIG5vcm1hbHNbYXR0ckluZGV4XSA9IG5vcm1hbDIueDsKICAgICAgICAgIG5vcm1hbHNbYXR0ckluZGV4MV0gPSBub3JtYWwyLnk7CiAgICAgICAgICBub3JtYWxzW2F0dHJJbmRleDJdID0gbm9ybWFsMi56OwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleF0gPSB0YW5nZW50Lng7CiAgICAgICAgICB0YW5nZW50c1thdHRySW5kZXgxXSA9IHRhbmdlbnQueTsKICAgICAgICAgIHRhbmdlbnRzW2F0dHJJbmRleDJdID0gdGFuZ2VudC56OwogICAgICAgIH0KICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgYml0YW5nZW50c1thdHRySW5kZXhdID0gYml0YW5nZW50Lng7CiAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleDFdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICBiaXRhbmdlbnRzW2F0dHJJbmRleDJdID0gYml0YW5nZW50Lno7CiAgICAgICAgfQogICAgICAgIGF0dHJJbmRleCArPSAzOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gY3JlYXRlQXR0cmlidXRlcyh2ZXJ0ZXhGb3JtYXQsIHsKICAgICAgcG9zaXRpb25zLAogICAgICBub3JtYWxzLAogICAgICB0YW5nZW50cywKICAgICAgYml0YW5nZW50cwogICAgfSk7CiAgfQogIGZ1bmN0aW9uIGNhbGN1bGF0ZUF0dHJpYnV0ZXNXYWxsKHBvc2l0aW9ucywgdmVydGV4Rm9ybWF0LCBlbGxpcHNvaWQpIHsKICAgIGNvbnN0IGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCBub3JtYWxzID0gdmVydGV4Rm9ybWF0Lm5vcm1hbCA/IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgIGNvbnN0IHRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LnRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICBjb25zdCBiaXRhbmdlbnRzID0gdmVydGV4Rm9ybWF0LmJpdGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgIGxldCBub3JtYWxJbmRleCA9IDA7CiAgICBsZXQgdGFuZ2VudEluZGV4ID0gMDsKICAgIGxldCBiaXRhbmdlbnRJbmRleCA9IDA7CiAgICBsZXQgcmVjb21wdXRlTm9ybWFsID0gdHJ1ZTsKICAgIGxldCBiaXRhbmdlbnQgPSBiaXRhbmdlbnRTY3JhdGNoMjsKICAgIGxldCB0YW5nZW50ID0gdGFuZ2VudFNjcmF0Y2gyOwogICAgbGV0IG5vcm1hbDIgPSBub3JtYWxTY3JhdGNoNDsKICAgIGlmICh2ZXJ0ZXhGb3JtYXQubm9ybWFsIHx8IHZlcnRleEZvcm1hdC50YW5nZW50IHx8IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIgKz0gNikgewogICAgICAgIGNvbnN0IHAyID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIGkyLCBwb3NpdGlvblNjcmF0Y2gyKTsKICAgICAgICBjb25zdCBwMSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCAoaTIgKyA2KSAlIGxlbmd0aCwgdjFTY3JhdGNoKTsKICAgICAgICBpZiAocmVjb21wdXRlTm9ybWFsKSB7CiAgICAgICAgICBjb25zdCBwMjIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgKGkyICsgMykgJSBsZW5ndGgsIHYyU2NyYXRjaCk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocDEsIHAyLCBwMSk7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocDIyLCBwMiwgcDIyKTsKICAgICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhwMjIsIHAxLCBub3JtYWwyKSwgbm9ybWFsMik7CiAgICAgICAgICByZWNvbXB1dGVOb3JtYWwgPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKHAxLCBwMiwgTWF0aF9kZWZhdWx0LkVQU0lMT04xMCkpIHsKICAgICAgICAgIHJlY29tcHV0ZU5vcm1hbCA9IHRydWU7CiAgICAgICAgfQogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICBiaXRhbmdlbnQgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHAyLCBiaXRhbmdlbnQpOwogICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhiaXRhbmdlbnQsIG5vcm1hbDIsIHRhbmdlbnQpLAogICAgICAgICAgICAgIHRhbmdlbnQKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLng7CiAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi55OwogICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIuejsKICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLng7CiAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi55OwogICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIuejsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lng7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lnk7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lno7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lng7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lnk7CiAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lno7CiAgICAgICAgfQogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lng7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lno7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lng7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lno7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICByZXR1cm4gY3JlYXRlQXR0cmlidXRlcyh2ZXJ0ZXhGb3JtYXQsIHsKICAgICAgcG9zaXRpb25zLAogICAgICBub3JtYWxzLAogICAgICB0YW5nZW50cywKICAgICAgYml0YW5nZW50cwogICAgfSk7CiAgfQogIGZ1bmN0aW9uIGNvbnN0cnVjdFJlY3RhbmdsZShyZWN0YW5nbGVHZW9tZXRyeSwgY29tcHV0ZWRPcHRpb25zKSB7CiAgICBjb25zdCB2ZXJ0ZXhGb3JtYXQgPSByZWN0YW5nbGVHZW9tZXRyeS5fdmVydGV4Rm9ybWF0OwogICAgY29uc3QgZWxsaXBzb2lkID0gcmVjdGFuZ2xlR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgIGNvbnN0IGhlaWdodCA9IGNvbXB1dGVkT3B0aW9ucy5oZWlnaHQ7CiAgICBjb25zdCB3aWR0aCA9IGNvbXB1dGVkT3B0aW9ucy53aWR0aDsKICAgIGNvbnN0IG5vcnRoQ2FwID0gY29tcHV0ZWRPcHRpb25zLm5vcnRoQ2FwOwogICAgY29uc3Qgc291dGhDYXAgPSBjb21wdXRlZE9wdGlvbnMuc291dGhDYXA7CiAgICBsZXQgcm93U3RhcnQgPSAwOwogICAgbGV0IHJvd0VuZCA9IGhlaWdodDsKICAgIGxldCByb3dIZWlnaHQgPSBoZWlnaHQ7CiAgICBsZXQgc2l6ZSA9IDA7CiAgICBpZiAobm9ydGhDYXApIHsKICAgICAgcm93U3RhcnQgPSAxOwogICAgICByb3dIZWlnaHQgLT0gMTsKICAgICAgc2l6ZSArPSAxOwogICAgfQogICAgaWYgKHNvdXRoQ2FwKSB7CiAgICAgIHJvd0VuZCAtPSAxOwogICAgICByb3dIZWlnaHQgLT0gMTsKICAgICAgc2l6ZSArPSAxOwogICAgfQogICAgc2l6ZSArPSB3aWR0aCAqIHJvd0hlaWdodDsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IHZlcnRleEZvcm1hdC5wb3NpdGlvbiA/IG5ldyBGbG9hdDY0QXJyYXkoc2l6ZSAqIDMpIDogdm9pZCAwOwogICAgY29uc3QgdGV4dHVyZUNvb3JkaW5hdGVzID0gdmVydGV4Rm9ybWF0LnN0ID8gbmV3IEZsb2F0MzJBcnJheShzaXplICogMikgOiB2b2lkIDA7CiAgICBsZXQgcG9zSW5kZXggPSAwOwogICAgbGV0IHN0SW5kZXggPSAwOwogICAgY29uc3QgcG9zaXRpb24gPSBwb3NpdGlvblNjcmF0Y2gyOwogICAgY29uc3Qgc3QyID0gc3RTY3JhdGNoMjsKICAgIGxldCBtaW5YID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgIGxldCBtaW5ZID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgIGxldCBtYXhYID0gLU51bWJlci5NQVhfVkFMVUU7CiAgICBsZXQgbWF4WSA9IC1OdW1iZXIuTUFYX1ZBTFVFOwogICAgZm9yIChsZXQgcm93ID0gcm93U3RhcnQ7IHJvdyA8IHJvd0VuZDsgKytyb3cpIHsKICAgICAgZm9yIChsZXQgY29sID0gMDsgY29sIDwgd2lkdGg7ICsrY29sKSB7CiAgICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVBvc2l0aW9uKAogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgdmVydGV4Rm9ybWF0LnN0LAogICAgICAgICAgcm93LAogICAgICAgICAgY29sLAogICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICBzdDIKICAgICAgICApOwogICAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLng7CiAgICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi56OwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIHRleHR1cmVDb29yZGluYXRlc1tzdEluZGV4KytdID0gc3QyLng7CiAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IHN0Mi55OwogICAgICAgICAgbWluWCA9IE1hdGgubWluKG1pblgsIHN0Mi54KTsKICAgICAgICAgIG1pblkgPSBNYXRoLm1pbihtaW5ZLCBzdDIueSk7CiAgICAgICAgICBtYXhYID0gTWF0aC5tYXgobWF4WCwgc3QyLngpOwogICAgICAgICAgbWF4WSA9IE1hdGgubWF4KG1heFksIHN0Mi55KTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmIChub3J0aENhcCkgewogICAgICBSZWN0YW5nbGVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb24oCiAgICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICB2ZXJ0ZXhGb3JtYXQuc3QsCiAgICAgICAgMCwKICAgICAgICAwLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHN0MgogICAgICApOwogICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi54OwogICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi55OwogICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi56OwogICAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3N0SW5kZXgrK10gPSBzdDIueDsKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IHN0Mi55OwogICAgICAgIG1pblggPSBzdDIueDsKICAgICAgICBtaW5ZID0gc3QyLnk7CiAgICAgICAgbWF4WCA9IHN0Mi54OwogICAgICAgIG1heFkgPSBzdDIueTsKICAgICAgfQogICAgfQogICAgaWYgKHNvdXRoQ2FwKSB7CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbigKICAgICAgICBjb21wdXRlZE9wdGlvbnMsCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIHZlcnRleEZvcm1hdC5zdCwKICAgICAgICBoZWlnaHQgLSAxLAogICAgICAgIDAsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgc3QyCiAgICAgICk7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLng7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLnk7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleF0gPSBwb3NpdGlvbi56OwogICAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3N0SW5kZXgrK10gPSBzdDIueDsKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleF0gPSBzdDIueTsKICAgICAgICBtaW5YID0gTWF0aC5taW4obWluWCwgc3QyLngpOwogICAgICAgIG1pblkgPSBNYXRoLm1pbihtaW5ZLCBzdDIueSk7CiAgICAgICAgbWF4WCA9IE1hdGgubWF4KG1heFgsIHN0Mi54KTsKICAgICAgICBtYXhZID0gTWF0aC5tYXgobWF4WSwgc3QyLnkpOwogICAgICB9CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0ICYmIChtaW5YIDwgMCB8fCBtaW5ZIDwgMCB8fCBtYXhYID4gMSB8fCBtYXhZID4gMSkpIHsKICAgICAgZm9yIChsZXQgazIgPSAwOyBrMiA8IHRleHR1cmVDb29yZGluYXRlcy5sZW5ndGg7IGsyICs9IDIpIHsKICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbazJdID0gKHRleHR1cmVDb29yZGluYXRlc1trMl0gLSBtaW5YKSAvIChtYXhYIC0gbWluWCk7CiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW2syICsgMV0gPSAodGV4dHVyZUNvb3JkaW5hdGVzW2syICsgMV0gLSBtaW5ZKSAvIChtYXhZIC0gbWluWSk7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IGdlbyA9IGNhbGN1bGF0ZUF0dHJpYnV0ZXMoCiAgICAgIHBvc2l0aW9ucywKICAgICAgdmVydGV4Rm9ybWF0LAogICAgICBlbGxpcHNvaWQsCiAgICAgIGNvbXB1dGVkT3B0aW9ucy50YW5nZW50Um90YXRpb25NYXRyaXgKICAgICk7CiAgICBsZXQgaW5kaWNlc1NpemUgPSA2ICogKHdpZHRoIC0gMSkgKiAocm93SGVpZ2h0IC0gMSk7CiAgICBpZiAobm9ydGhDYXApIHsKICAgICAgaW5kaWNlc1NpemUgKz0gMyAqICh3aWR0aCAtIDEpOwogICAgfQogICAgaWYgKHNvdXRoQ2FwKSB7CiAgICAgIGluZGljZXNTaXplICs9IDMgKiAod2lkdGggLSAxKTsKICAgIH0KICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShzaXplLCBpbmRpY2VzU2l6ZSk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgbGV0IGluZGljZXNJbmRleCA9IDA7CiAgICBsZXQgaTI7CiAgICBmb3IgKGkyID0gMDsgaTIgPCByb3dIZWlnaHQgLSAxOyArK2kyKSB7CiAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCB3aWR0aCAtIDE7ICsrajIpIHsKICAgICAgICBjb25zdCB1cHBlckxlZnQgPSBpbmRleDsKICAgICAgICBjb25zdCBsb3dlckxlZnQgPSB1cHBlckxlZnQgKyB3aWR0aDsKICAgICAgICBjb25zdCBsb3dlclJpZ2h0ID0gbG93ZXJMZWZ0ICsgMTsKICAgICAgICBjb25zdCB1cHBlclJpZ2h0ID0gdXBwZXJMZWZ0ICsgMTsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHVwcGVyTGVmdDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGxvd2VyTGVmdDsKICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHVwcGVyUmlnaHQ7CiAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSB1cHBlclJpZ2h0OwogICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gbG93ZXJMZWZ0OwogICAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gbG93ZXJSaWdodDsKICAgICAgICArK2luZGV4OwogICAgICB9CiAgICAgICsraW5kZXg7CiAgICB9CiAgICBpZiAobm9ydGhDYXAgfHwgc291dGhDYXApIHsKICAgICAgbGV0IG5vcnRoSW5kZXggPSBzaXplIC0gMTsKICAgICAgY29uc3Qgc291dGhJbmRleCA9IHNpemUgLSAxOwogICAgICBpZiAobm9ydGhDYXAgJiYgc291dGhDYXApIHsKICAgICAgICBub3J0aEluZGV4ID0gc2l6ZSAtIDI7CiAgICAgIH0KICAgICAgbGV0IHAxOwogICAgICBsZXQgcDI7CiAgICAgIGluZGV4ID0gMDsKICAgICAgaWYgKG5vcnRoQ2FwKSB7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgd2lkdGggLSAxOyBpMisrKSB7CiAgICAgICAgICBwMSA9IGluZGV4OwogICAgICAgICAgcDIgPSBwMSArIDE7CiAgICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IG5vcnRoSW5kZXg7CiAgICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHAxOwogICAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwMjsKICAgICAgICAgICsraW5kZXg7CiAgICAgICAgfQogICAgICB9CiAgICAgIGlmIChzb3V0aENhcCkgewogICAgICAgIGluZGV4ID0gKHJvd0hlaWdodCAtIDEpICogd2lkdGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgd2lkdGggLSAxOyBpMisrKSB7CiAgICAgICAgICBwMSA9IGluZGV4OwogICAgICAgICAgcDIgPSBwMSArIDE7CiAgICAgICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHAxOwogICAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBzb3V0aEluZGV4OwogICAgICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBwMjsKICAgICAgICAgICsraW5kZXg7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBnZW8uaW5kaWNlcyA9IGluZGljZXM7CiAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgIGdlby5hdHRyaWJ1dGVzLnN0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgdmFsdWVzOiB0ZXh0dXJlQ29vcmRpbmF0ZXMKICAgICAgfSk7CiAgICB9CiAgICByZXR1cm4gZ2VvOwogIH0KICBmdW5jdGlvbiBhZGRXYWxsUG9zaXRpb25zMih3YWxsUG9zaXRpb25zLCBwb3NJbmRleCwgaTIsIHRvcFBvc2l0aW9ucywgYm90dG9tUG9zaXRpb25zKSB7CiAgICB3YWxsUG9zaXRpb25zW3Bvc0luZGV4KytdID0gdG9wUG9zaXRpb25zW2kyXTsKICAgIHdhbGxQb3NpdGlvbnNbcG9zSW5kZXgrK10gPSB0b3BQb3NpdGlvbnNbaTIgKyAxXTsKICAgIHdhbGxQb3NpdGlvbnNbcG9zSW5kZXgrK10gPSB0b3BQb3NpdGlvbnNbaTIgKyAyXTsKICAgIHdhbGxQb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBib3R0b21Qb3NpdGlvbnNbaTJdOwogICAgd2FsbFBvc2l0aW9uc1twb3NJbmRleCsrXSA9IGJvdHRvbVBvc2l0aW9uc1tpMiArIDFdOwogICAgd2FsbFBvc2l0aW9uc1twb3NJbmRleF0gPSBib3R0b21Qb3NpdGlvbnNbaTIgKyAyXTsKICAgIHJldHVybiB3YWxsUG9zaXRpb25zOwogIH0KICBmdW5jdGlvbiBhZGRXYWxsVGV4dHVyZUNvb3JkaW5hdGVzKHdhbGxUZXh0dXJlcywgc3RJbmRleCwgaTIsIHN0MikgewogICAgd2FsbFRleHR1cmVzW3N0SW5kZXgrK10gPSBzdDJbaTJdOwogICAgd2FsbFRleHR1cmVzW3N0SW5kZXgrK10gPSBzdDJbaTIgKyAxXTsKICAgIHdhbGxUZXh0dXJlc1tzdEluZGV4KytdID0gc3QyW2kyXTsKICAgIHdhbGxUZXh0dXJlc1tzdEluZGV4XSA9IHN0MltpMiArIDFdOwogICAgcmV0dXJuIHdhbGxUZXh0dXJlczsKICB9CiAgZnVuY3Rpb24gY29uc3RydWN0RXh0cnVkZWRSZWN0YW5nbGUocmVjdGFuZ2xlR2VvbWV0cnksIGNvbXB1dGVkT3B0aW9ucykgewogICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gcmVjdGFuZ2xlR2VvbWV0cnkuX3NoYWRvd1ZvbHVtZTsKICAgIGNvbnN0IG9mZnNldEF0dHJpYnV0ZVZhbHVlID0gcmVjdGFuZ2xlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZTsKICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICBjb25zdCBtaW5IZWlnaHQgPSByZWN0YW5nbGVHZW9tZXRyeS5fZXh0cnVkZWRIZWlnaHQ7CiAgICBjb25zdCBtYXhIZWlnaHQgPSByZWN0YW5nbGVHZW9tZXRyeS5fc3VyZmFjZUhlaWdodDsKICAgIGNvbnN0IGVsbGlwc29pZCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICBjb25zdCBoZWlnaHQgPSBjb21wdXRlZE9wdGlvbnMuaGVpZ2h0OwogICAgY29uc3Qgd2lkdGggPSBjb21wdXRlZE9wdGlvbnMud2lkdGg7CiAgICBsZXQgaTI7CiAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgIGNvbnN0IG5ld1ZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKAogICAgICAgIHZlcnRleEZvcm1hdCwKICAgICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTIKICAgICAgKTsKICAgICAgbmV3VmVydGV4Rm9ybWF0Lm5vcm1hbCA9IHRydWU7CiAgICAgIHJlY3RhbmdsZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQgPSBuZXdWZXJ0ZXhGb3JtYXQ7CiAgICB9CiAgICBjb25zdCB0b3BCb3R0b21HZW8gPSBjb25zdHJ1Y3RSZWN0YW5nbGUocmVjdGFuZ2xlR2VvbWV0cnksIGNvbXB1dGVkT3B0aW9ucyk7CiAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgIHJlY3RhbmdsZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQgPSB2ZXJ0ZXhGb3JtYXQ7CiAgICB9CiAgICBsZXQgdG9wUG9zaXRpb25zID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICB0b3BCb3R0b21HZW8uYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMsCiAgICAgIG1heEhlaWdodCwKICAgICAgZWxsaXBzb2lkLAogICAgICBmYWxzZQogICAgKTsKICAgIHRvcFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkodG9wUG9zaXRpb25zKTsKICAgIGxldCBsZW5ndGggPSB0b3BQb3NpdGlvbnMubGVuZ3RoOwogICAgY29uc3QgbmV3TGVuZ3RoID0gbGVuZ3RoICogMjsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkobmV3TGVuZ3RoKTsKICAgIHBvc2l0aW9ucy5zZXQodG9wUG9zaXRpb25zKTsKICAgIGNvbnN0IGJvdHRvbVBvc2l0aW9ucyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICBtaW5IZWlnaHQsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIHBvc2l0aW9ucy5zZXQoYm90dG9tUG9zaXRpb25zLCBsZW5ndGgpOwogICAgdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gcG9zaXRpb25zOwogICAgY29uc3Qgbm9ybWFscyA9IHZlcnRleEZvcm1hdC5ub3JtYWwgPyBuZXcgRmxvYXQzMkFycmF5KG5ld0xlbmd0aCkgOiB2b2lkIDA7CiAgICBjb25zdCB0YW5nZW50cyA9IHZlcnRleEZvcm1hdC50YW5nZW50ID8gbmV3IEZsb2F0MzJBcnJheShuZXdMZW5ndGgpIDogdm9pZCAwOwogICAgY29uc3QgYml0YW5nZW50cyA9IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KG5ld0xlbmd0aCkgOiB2b2lkIDA7CiAgICBjb25zdCB0ZXh0dXJlcyA9IHZlcnRleEZvcm1hdC5zdCA/IG5ldyBGbG9hdDMyQXJyYXkobmV3TGVuZ3RoIC8gMyAqIDIpIDogdm9pZCAwOwogICAgbGV0IHRvcFN0OwogICAgbGV0IHRvcE5vcm1hbHM7CiAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCkgewogICAgICB0b3BOb3JtYWxzID0gdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMubm9ybWFsLnZhbHVlczsKICAgICAgbm9ybWFscy5zZXQodG9wTm9ybWFscyk7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgaTIrKykgewogICAgICAgIHRvcE5vcm1hbHNbaTJdID0gLXRvcE5vcm1hbHNbaTJdOwogICAgICB9CiAgICAgIG5vcm1hbHMuc2V0KHRvcE5vcm1hbHMsIGxlbmd0aCk7CiAgICAgIHRvcEJvdHRvbUdlby5hdHRyaWJ1dGVzLm5vcm1hbC52YWx1ZXMgPSBub3JtYWxzOwogICAgfQogICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICB0b3BOb3JtYWxzID0gdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMubm9ybWFsLnZhbHVlczsKICAgICAgaWYgKCF2ZXJ0ZXhGb3JtYXQubm9ybWFsKSB7CiAgICAgICAgdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMubm9ybWFsID0gdm9pZCAwOwogICAgICB9CiAgICAgIGNvbnN0IGV4dHJ1ZGVOb3JtYWxzID0gbmV3IEZsb2F0MzJBcnJheShuZXdMZW5ndGgpOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7IGkyKyspIHsKICAgICAgICB0b3BOb3JtYWxzW2kyXSA9IC10b3BOb3JtYWxzW2kyXTsKICAgICAgfQogICAgICBleHRydWRlTm9ybWFscy5zZXQodG9wTm9ybWFscywgbGVuZ3RoKTsKICAgICAgdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMuZXh0cnVkZURpcmVjdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgIHZhbHVlczogZXh0cnVkZU5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBsZXQgb2Zmc2V0VmFsdWU7CiAgICBjb25zdCBoYXNPZmZzZXRzID0gZGVmaW5lZF9kZWZhdWx0KG9mZnNldEF0dHJpYnV0ZVZhbHVlKTsKICAgIGlmIChoYXNPZmZzZXRzKSB7CiAgICAgIGNvbnN0IHNpemUgPSBsZW5ndGggLyAzICogMjsKICAgICAgbGV0IG9mZnNldEF0dHJpYnV0ZSA9IG5ldyBVaW50OEFycmF5KHNpemUpOwogICAgICBpZiAob2Zmc2V0QXR0cmlidXRlVmFsdWUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuVE9QKSB7CiAgICAgICAgb2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlLmZpbGwoMSwgMCwgc2l6ZSAvIDIpOwogICAgICB9IGVsc2UgewogICAgICAgIG9mZnNldFZhbHVlID0gb2Zmc2V0QXR0cmlidXRlVmFsdWUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgfQogICAgICB0b3BCb3R0b21HZW8uYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgdmFsdWVzOiBvZmZzZXRBdHRyaWJ1dGUKICAgICAgfSk7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgY29uc3QgdG9wVGFuZ2VudHMgPSB0b3BCb3R0b21HZW8uYXR0cmlidXRlcy50YW5nZW50LnZhbHVlczsKICAgICAgdGFuZ2VudHMuc2V0KHRvcFRhbmdlbnRzKTsKICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgICAgdG9wVGFuZ2VudHNbaTJdID0gLXRvcFRhbmdlbnRzW2kyXTsKICAgICAgfQogICAgICB0YW5nZW50cy5zZXQodG9wVGFuZ2VudHMsIGxlbmd0aCk7CiAgICAgIHRvcEJvdHRvbUdlby5hdHRyaWJ1dGVzLnRhbmdlbnQudmFsdWVzID0gdGFuZ2VudHM7CiAgICB9CiAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICBjb25zdCB0b3BCaXRhbmdlbnRzID0gdG9wQm90dG9tR2VvLmF0dHJpYnV0ZXMuYml0YW5nZW50LnZhbHVlczsKICAgICAgYml0YW5nZW50cy5zZXQodG9wQml0YW5nZW50cyk7CiAgICAgIGJpdGFuZ2VudHMuc2V0KHRvcEJpdGFuZ2VudHMsIGxlbmd0aCk7CiAgICAgIHRvcEJvdHRvbUdlby5hdHRyaWJ1dGVzLmJpdGFuZ2VudC52YWx1ZXMgPSBiaXRhbmdlbnRzOwogICAgfQogICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICB0b3BTdCA9IHRvcEJvdHRvbUdlby5hdHRyaWJ1dGVzLnN0LnZhbHVlczsKICAgICAgdGV4dHVyZXMuc2V0KHRvcFN0KTsKICAgICAgdGV4dHVyZXMuc2V0KHRvcFN0LCBsZW5ndGggLyAzICogMik7CiAgICAgIHRvcEJvdHRvbUdlby5hdHRyaWJ1dGVzLnN0LnZhbHVlcyA9IHRleHR1cmVzOwogICAgfQogICAgY29uc3QgaW5kaWNlcyA9IHRvcEJvdHRvbUdlby5pbmRpY2VzOwogICAgY29uc3QgaW5kaWNlc0xlbmd0aCA9IGluZGljZXMubGVuZ3RoOwogICAgY29uc3QgcG9zTGVuZ3RoID0gbGVuZ3RoIC8gMzsKICAgIGNvbnN0IG5ld0luZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgbmV3TGVuZ3RoIC8gMywKICAgICAgaW5kaWNlc0xlbmd0aCAqIDIKICAgICk7CiAgICBuZXdJbmRpY2VzLnNldChpbmRpY2VzKTsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGluZGljZXNMZW5ndGg7IGkyICs9IDMpIHsKICAgICAgbmV3SW5kaWNlc1tpMiArIGluZGljZXNMZW5ndGhdID0gaW5kaWNlc1tpMiArIDJdICsgcG9zTGVuZ3RoOwogICAgICBuZXdJbmRpY2VzW2kyICsgMSArIGluZGljZXNMZW5ndGhdID0gaW5kaWNlc1tpMiArIDFdICsgcG9zTGVuZ3RoOwogICAgICBuZXdJbmRpY2VzW2kyICsgMiArIGluZGljZXNMZW5ndGhdID0gaW5kaWNlc1tpMl0gKyBwb3NMZW5ndGg7CiAgICB9CiAgICB0b3BCb3R0b21HZW8uaW5kaWNlcyA9IG5ld0luZGljZXM7CiAgICBjb25zdCBub3J0aENhcCA9IGNvbXB1dGVkT3B0aW9ucy5ub3J0aENhcDsKICAgIGNvbnN0IHNvdXRoQ2FwID0gY29tcHV0ZWRPcHRpb25zLnNvdXRoQ2FwOwogICAgbGV0IHJvd0hlaWdodCA9IGhlaWdodDsKICAgIGxldCB3aWR0aE11bHRpcGxpZXIgPSAyOwogICAgbGV0IHBlcmltZXRlclBvc2l0aW9ucyA9IDA7CiAgICBsZXQgY29ybmVycyA9IDQ7CiAgICBsZXQgZHVwbGlhdGVDb3JuZXJzID0gNDsKICAgIGlmIChub3J0aENhcCkgewogICAgICB3aWR0aE11bHRpcGxpZXIgLT0gMTsKICAgICAgcm93SGVpZ2h0IC09IDE7CiAgICAgIHBlcmltZXRlclBvc2l0aW9ucyArPSAxOwogICAgICBjb3JuZXJzIC09IDI7CiAgICAgIGR1cGxpYXRlQ29ybmVycyAtPSAxOwogICAgfQogICAgaWYgKHNvdXRoQ2FwKSB7CiAgICAgIHdpZHRoTXVsdGlwbGllciAtPSAxOwogICAgICByb3dIZWlnaHQgLT0gMTsKICAgICAgcGVyaW1ldGVyUG9zaXRpb25zICs9IDE7CiAgICAgIGNvcm5lcnMgLT0gMjsKICAgICAgZHVwbGlhdGVDb3JuZXJzIC09IDE7CiAgICB9CiAgICBwZXJpbWV0ZXJQb3NpdGlvbnMgKz0gd2lkdGhNdWx0aXBsaWVyICogd2lkdGggKyAyICogcm93SGVpZ2h0IC0gY29ybmVyczsKICAgIGNvbnN0IHdhbGxDb3VudCA9IChwZXJpbWV0ZXJQb3NpdGlvbnMgKyBkdXBsaWF0ZUNvcm5lcnMpICogMjsKICAgIGxldCB3YWxsUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSh3YWxsQ291bnQgKiAzKTsKICAgIGNvbnN0IHdhbGxFeHRydWRlTm9ybWFscyA9IHNoYWRvd1ZvbHVtZSA/IG5ldyBGbG9hdDMyQXJyYXkod2FsbENvdW50ICogMykgOiB2b2lkIDA7CiAgICBsZXQgd2FsbE9mZnNldEF0dHJpYnV0ZSA9IGhhc09mZnNldHMgPyBuZXcgVWludDhBcnJheSh3YWxsQ291bnQpIDogdm9pZCAwOwogICAgbGV0IHdhbGxUZXh0dXJlcyA9IHZlcnRleEZvcm1hdC5zdCA/IG5ldyBGbG9hdDMyQXJyYXkod2FsbENvdW50ICogMikgOiB2b2lkIDA7CiAgICBjb25zdCBjb21wdXRlVG9wT2Zmc2V0cyA9IG9mZnNldEF0dHJpYnV0ZVZhbHVlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUDsKICAgIGlmIChoYXNPZmZzZXRzICYmICFjb21wdXRlVG9wT2Zmc2V0cykgewogICAgICBvZmZzZXRWYWx1ZSA9IG9mZnNldEF0dHJpYnV0ZVZhbHVlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LkFMTCA/IDEgOiAwOwogICAgICB3YWxsT2Zmc2V0QXR0cmlidXRlID0gd2FsbE9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgIH0KICAgIGxldCBwb3NJbmRleCA9IDA7CiAgICBsZXQgc3RJbmRleCA9IDA7CiAgICBsZXQgZXh0cnVkZU5vcm1hbEluZGV4ID0gMDsKICAgIGxldCB3YWxsT2Zmc2V0SW5kZXggPSAwOwogICAgY29uc3QgYXJlYTIgPSB3aWR0aCAqIHJvd0hlaWdodDsKICAgIGxldCB0aHJlZUk7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBhcmVhMjsgaTIgKz0gd2lkdGgpIHsKICAgICAgdGhyZWVJID0gaTIgKiAzOwogICAgICB3YWxsUG9zaXRpb25zID0gYWRkV2FsbFBvc2l0aW9uczIoCiAgICAgICAgd2FsbFBvc2l0aW9ucywKICAgICAgICBwb3NJbmRleCwKICAgICAgICB0aHJlZUksCiAgICAgICAgdG9wUG9zaXRpb25zLAogICAgICAgIGJvdHRvbVBvc2l0aW9ucwogICAgICApOwogICAgICBwb3NJbmRleCArPSA2OwogICAgICBpZiAodmVydGV4Rm9ybWF0LnN0KSB7CiAgICAgICAgd2FsbFRleHR1cmVzID0gYWRkV2FsbFRleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgIHdhbGxUZXh0dXJlcywKICAgICAgICAgIHN0SW5kZXgsCiAgICAgICAgICBpMiAqIDIsCiAgICAgICAgICB0b3BTdAogICAgICAgICk7CiAgICAgICAgc3RJbmRleCArPSA0OwogICAgICB9CiAgICAgIGlmIChzaGFkb3dWb2x1bWUpIHsKICAgICAgICBleHRydWRlTm9ybWFsSW5kZXggKz0gMzsKICAgICAgICB3YWxsRXh0cnVkZU5vcm1hbHNbZXh0cnVkZU5vcm1hbEluZGV4KytdID0gdG9wTm9ybWFsc1t0aHJlZUldOwogICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSSArIDFdOwogICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSSArIDJdOwogICAgICB9CiAgICAgIGlmIChjb21wdXRlVG9wT2Zmc2V0cykgewogICAgICAgIHdhbGxPZmZzZXRBdHRyaWJ1dGVbd2FsbE9mZnNldEluZGV4KytdID0gMTsKICAgICAgICB3YWxsT2Zmc2V0SW5kZXggKz0gMTsKICAgICAgfQogICAgfQogICAgaWYgKCFzb3V0aENhcCkgewogICAgICBmb3IgKGkyID0gYXJlYTIgLSB3aWR0aDsgaTIgPCBhcmVhMjsgaTIrKykgewogICAgICAgIHRocmVlSSA9IGkyICogMzsKICAgICAgICB3YWxsUG9zaXRpb25zID0gYWRkV2FsbFBvc2l0aW9uczIoCiAgICAgICAgICB3YWxsUG9zaXRpb25zLAogICAgICAgICAgcG9zSW5kZXgsCiAgICAgICAgICB0aHJlZUksCiAgICAgICAgICB0b3BQb3NpdGlvbnMsCiAgICAgICAgICBib3R0b21Qb3NpdGlvbnMKICAgICAgICApOwogICAgICAgIHBvc0luZGV4ICs9IDY7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgd2FsbFRleHR1cmVzID0gYWRkV2FsbFRleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgd2FsbFRleHR1cmVzLAogICAgICAgICAgICBzdEluZGV4LAogICAgICAgICAgICBpMiAqIDIsCiAgICAgICAgICAgIHRvcFN0CiAgICAgICAgICApOwogICAgICAgICAgc3RJbmRleCArPSA0OwogICAgICAgIH0KICAgICAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgICAgICBleHRydWRlTm9ybWFsSW5kZXggKz0gMzsKICAgICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSV07CiAgICAgICAgICB3YWxsRXh0cnVkZU5vcm1hbHNbZXh0cnVkZU5vcm1hbEluZGV4KytdID0gdG9wTm9ybWFsc1t0aHJlZUkgKyAxXTsKICAgICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSSArIDJdOwogICAgICAgIH0KICAgICAgICBpZiAoY29tcHV0ZVRvcE9mZnNldHMpIHsKICAgICAgICAgIHdhbGxPZmZzZXRBdHRyaWJ1dGVbd2FsbE9mZnNldEluZGV4KytdID0gMTsKICAgICAgICAgIHdhbGxPZmZzZXRJbmRleCArPSAxOwogICAgICAgIH0KICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgY29uc3Qgc291dGhJbmRleCA9IG5vcnRoQ2FwID8gYXJlYTIgKyAxIDogYXJlYTI7CiAgICAgIHRocmVlSSA9IHNvdXRoSW5kZXggKiAzOwogICAgICBmb3IgKGkyID0gMDsgaTIgPCAyOyBpMisrKSB7CiAgICAgICAgd2FsbFBvc2l0aW9ucyA9IGFkZFdhbGxQb3NpdGlvbnMyKAogICAgICAgICAgd2FsbFBvc2l0aW9ucywKICAgICAgICAgIHBvc0luZGV4LAogICAgICAgICAgdGhyZWVJLAogICAgICAgICAgdG9wUG9zaXRpb25zLAogICAgICAgICAgYm90dG9tUG9zaXRpb25zCiAgICAgICAgKTsKICAgICAgICBwb3NJbmRleCArPSA2OwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIHdhbGxUZXh0dXJlcyA9IGFkZFdhbGxUZXh0dXJlQ29vcmRpbmF0ZXMoCiAgICAgICAgICAgIHdhbGxUZXh0dXJlcywKICAgICAgICAgICAgc3RJbmRleCwKICAgICAgICAgICAgc291dGhJbmRleCAqIDIsCiAgICAgICAgICAgIHRvcFN0CiAgICAgICAgICApOwogICAgICAgICAgc3RJbmRleCArPSA0OwogICAgICAgIH0KICAgICAgICBpZiAoc2hhZG93Vm9sdW1lKSB7CiAgICAgICAgICBleHRydWRlTm9ybWFsSW5kZXggKz0gMzsKICAgICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSV07CiAgICAgICAgICB3YWxsRXh0cnVkZU5vcm1hbHNbZXh0cnVkZU5vcm1hbEluZGV4KytdID0gdG9wTm9ybWFsc1t0aHJlZUkgKyAxXTsKICAgICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSSArIDJdOwogICAgICAgIH0KICAgICAgICBpZiAoY29tcHV0ZVRvcE9mZnNldHMpIHsKICAgICAgICAgIHdhbGxPZmZzZXRBdHRyaWJ1dGVbd2FsbE9mZnNldEluZGV4KytdID0gMTsKICAgICAgICAgIHdhbGxPZmZzZXRJbmRleCArPSAxOwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgZm9yIChpMiA9IGFyZWEyIC0gMTsgaTIgPiAwOyBpMiAtPSB3aWR0aCkgewogICAgICB0aHJlZUkgPSBpMiAqIDM7CiAgICAgIHdhbGxQb3NpdGlvbnMgPSBhZGRXYWxsUG9zaXRpb25zMigKICAgICAgICB3YWxsUG9zaXRpb25zLAogICAgICAgIHBvc0luZGV4LAogICAgICAgIHRocmVlSSwKICAgICAgICB0b3BQb3NpdGlvbnMsCiAgICAgICAgYm90dG9tUG9zaXRpb25zCiAgICAgICk7CiAgICAgIHBvc0luZGV4ICs9IDY7CiAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICB3YWxsVGV4dHVyZXMgPSBhZGRXYWxsVGV4dHVyZUNvb3JkaW5hdGVzKAogICAgICAgICAgd2FsbFRleHR1cmVzLAogICAgICAgICAgc3RJbmRleCwKICAgICAgICAgIGkyICogMiwKICAgICAgICAgIHRvcFN0CiAgICAgICAgKTsKICAgICAgICBzdEluZGV4ICs9IDQ7CiAgICAgIH0KICAgICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICAgIGV4dHJ1ZGVOb3JtYWxJbmRleCArPSAzOwogICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSV07CiAgICAgICAgd2FsbEV4dHJ1ZGVOb3JtYWxzW2V4dHJ1ZGVOb3JtYWxJbmRleCsrXSA9IHRvcE5vcm1hbHNbdGhyZWVJICsgMV07CiAgICAgICAgd2FsbEV4dHJ1ZGVOb3JtYWxzW2V4dHJ1ZGVOb3JtYWxJbmRleCsrXSA9IHRvcE5vcm1hbHNbdGhyZWVJICsgMl07CiAgICAgIH0KICAgICAgaWYgKGNvbXB1dGVUb3BPZmZzZXRzKSB7CiAgICAgICAgd2FsbE9mZnNldEF0dHJpYnV0ZVt3YWxsT2Zmc2V0SW5kZXgrK10gPSAxOwogICAgICAgIHdhbGxPZmZzZXRJbmRleCArPSAxOwogICAgICB9CiAgICB9CiAgICBpZiAoIW5vcnRoQ2FwKSB7CiAgICAgIGZvciAoaTIgPSB3aWR0aCAtIDE7IGkyID49IDA7IGkyLS0pIHsKICAgICAgICB0aHJlZUkgPSBpMiAqIDM7CiAgICAgICAgd2FsbFBvc2l0aW9ucyA9IGFkZFdhbGxQb3NpdGlvbnMyKAogICAgICAgICAgd2FsbFBvc2l0aW9ucywKICAgICAgICAgIHBvc0luZGV4LAogICAgICAgICAgdGhyZWVJLAogICAgICAgICAgdG9wUG9zaXRpb25zLAogICAgICAgICAgYm90dG9tUG9zaXRpb25zCiAgICAgICAgKTsKICAgICAgICBwb3NJbmRleCArPSA2OwogICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgIHdhbGxUZXh0dXJlcyA9IGFkZFdhbGxUZXh0dXJlQ29vcmRpbmF0ZXMoCiAgICAgICAgICAgIHdhbGxUZXh0dXJlcywKICAgICAgICAgICAgc3RJbmRleCwKICAgICAgICAgICAgaTIgKiAyLAogICAgICAgICAgICB0b3BTdAogICAgICAgICAgKTsKICAgICAgICAgIHN0SW5kZXggKz0gNDsKICAgICAgICB9CiAgICAgICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICAgICAgZXh0cnVkZU5vcm1hbEluZGV4ICs9IDM7CiAgICAgICAgICB3YWxsRXh0cnVkZU5vcm1hbHNbZXh0cnVkZU5vcm1hbEluZGV4KytdID0gdG9wTm9ybWFsc1t0aHJlZUldOwogICAgICAgICAgd2FsbEV4dHJ1ZGVOb3JtYWxzW2V4dHJ1ZGVOb3JtYWxJbmRleCsrXSA9IHRvcE5vcm1hbHNbdGhyZWVJICsgMV07CiAgICAgICAgICB3YWxsRXh0cnVkZU5vcm1hbHNbZXh0cnVkZU5vcm1hbEluZGV4KytdID0gdG9wTm9ybWFsc1t0aHJlZUkgKyAyXTsKICAgICAgICB9CiAgICAgICAgaWYgKGNvbXB1dGVUb3BPZmZzZXRzKSB7CiAgICAgICAgICB3YWxsT2Zmc2V0QXR0cmlidXRlW3dhbGxPZmZzZXRJbmRleCsrXSA9IDE7CiAgICAgICAgICB3YWxsT2Zmc2V0SW5kZXggKz0gMTsKICAgICAgICB9CiAgICAgIH0KICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IG5vcnRoSW5kZXggPSBhcmVhMjsKICAgICAgdGhyZWVJID0gbm9ydGhJbmRleCAqIDM7CiAgICAgIGZvciAoaTIgPSAwOyBpMiA8IDI7IGkyKyspIHsKICAgICAgICB3YWxsUG9zaXRpb25zID0gYWRkV2FsbFBvc2l0aW9uczIoCiAgICAgICAgICB3YWxsUG9zaXRpb25zLAogICAgICAgICAgcG9zSW5kZXgsCiAgICAgICAgICB0aHJlZUksCiAgICAgICAgICB0b3BQb3NpdGlvbnMsCiAgICAgICAgICBib3R0b21Qb3NpdGlvbnMKICAgICAgICApOwogICAgICAgIHBvc0luZGV4ICs9IDY7CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgd2FsbFRleHR1cmVzID0gYWRkV2FsbFRleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgd2FsbFRleHR1cmVzLAogICAgICAgICAgICBzdEluZGV4LAogICAgICAgICAgICBub3J0aEluZGV4ICogMiwKICAgICAgICAgICAgdG9wU3QKICAgICAgICAgICk7CiAgICAgICAgICBzdEluZGV4ICs9IDQ7CiAgICAgICAgfQogICAgICAgIGlmIChzaGFkb3dWb2x1bWUpIHsKICAgICAgICAgIGV4dHJ1ZGVOb3JtYWxJbmRleCArPSAzOwogICAgICAgICAgd2FsbEV4dHJ1ZGVOb3JtYWxzW2V4dHJ1ZGVOb3JtYWxJbmRleCsrXSA9IHRvcE5vcm1hbHNbdGhyZWVJXTsKICAgICAgICAgIHdhbGxFeHRydWRlTm9ybWFsc1tleHRydWRlTm9ybWFsSW5kZXgrK10gPSB0b3BOb3JtYWxzW3RocmVlSSArIDFdOwogICAgICAgICAgd2FsbEV4dHJ1ZGVOb3JtYWxzW2V4dHJ1ZGVOb3JtYWxJbmRleCsrXSA9IHRvcE5vcm1hbHNbdGhyZWVJICsgMl07CiAgICAgICAgfQogICAgICAgIGlmIChjb21wdXRlVG9wT2Zmc2V0cykgewogICAgICAgICAgd2FsbE9mZnNldEF0dHJpYnV0ZVt3YWxsT2Zmc2V0SW5kZXgrK10gPSAxOwogICAgICAgICAgd2FsbE9mZnNldEluZGV4ICs9IDE7CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBsZXQgZ2VvID0gY2FsY3VsYXRlQXR0cmlidXRlc1dhbGwod2FsbFBvc2l0aW9ucywgdmVydGV4Rm9ybWF0LCBlbGxpcHNvaWQpOwogICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICBnZW8uYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAyLAogICAgICAgIHZhbHVlczogd2FsbFRleHR1cmVzCiAgICAgIH0pOwogICAgfQogICAgaWYgKHNoYWRvd1ZvbHVtZSkgewogICAgICBnZW8uYXR0cmlidXRlcy5leHRydWRlRGlyZWN0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgdmFsdWVzOiB3YWxsRXh0cnVkZU5vcm1hbHMKICAgICAgfSk7CiAgICB9CiAgICBpZiAoaGFzT2Zmc2V0cykgewogICAgICBnZW8uYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgdmFsdWVzOiB3YWxsT2Zmc2V0QXR0cmlidXRlCiAgICAgIH0pOwogICAgfQogICAgY29uc3Qgd2FsbEluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgd2FsbENvdW50LAogICAgICBwZXJpbWV0ZXJQb3NpdGlvbnMgKiA2CiAgICApOwogICAgbGV0IHVwcGVyTGVmdDsKICAgIGxldCBsb3dlckxlZnQ7CiAgICBsZXQgbG93ZXJSaWdodDsKICAgIGxldCB1cHBlclJpZ2h0OwogICAgbGVuZ3RoID0gd2FsbFBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgbGV0IGluZGV4ID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyICs9IDIpIHsKICAgICAgdXBwZXJMZWZ0ID0gaTI7CiAgICAgIHVwcGVyUmlnaHQgPSAodXBwZXJMZWZ0ICsgMikgJSBsZW5ndGg7CiAgICAgIGNvbnN0IHAxID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSh3YWxsUG9zaXRpb25zLCB1cHBlckxlZnQgKiAzLCB2MVNjcmF0Y2gpOwogICAgICBjb25zdCBwMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkod2FsbFBvc2l0aW9ucywgdXBwZXJSaWdodCAqIDMsIHYyU2NyYXRjaCk7CiAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihwMSwgcDIsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgbG93ZXJMZWZ0ID0gKHVwcGVyTGVmdCArIDEpICUgbGVuZ3RoOwogICAgICBsb3dlclJpZ2h0ID0gKGxvd2VyTGVmdCArIDIpICUgbGVuZ3RoOwogICAgICB3YWxsSW5kaWNlc1tpbmRleCsrXSA9IHVwcGVyTGVmdDsKICAgICAgd2FsbEluZGljZXNbaW5kZXgrK10gPSBsb3dlckxlZnQ7CiAgICAgIHdhbGxJbmRpY2VzW2luZGV4KytdID0gdXBwZXJSaWdodDsKICAgICAgd2FsbEluZGljZXNbaW5kZXgrK10gPSB1cHBlclJpZ2h0OwogICAgICB3YWxsSW5kaWNlc1tpbmRleCsrXSA9IGxvd2VyTGVmdDsKICAgICAgd2FsbEluZGljZXNbaW5kZXgrK10gPSBsb3dlclJpZ2h0OwogICAgfQogICAgZ2VvLmluZGljZXMgPSB3YWxsSW5kaWNlczsKICAgIGdlbyA9IEdlb21ldHJ5UGlwZWxpbmVfZGVmYXVsdC5jb21iaW5lSW5zdGFuY2VzKFsKICAgICAgbmV3IEdlb21ldHJ5SW5zdGFuY2VfZGVmYXVsdCh7CiAgICAgICAgZ2VvbWV0cnk6IHRvcEJvdHRvbUdlbwogICAgICB9KSwKICAgICAgbmV3IEdlb21ldHJ5SW5zdGFuY2VfZGVmYXVsdCh7CiAgICAgICAgZ2VvbWV0cnk6IGdlbwogICAgICB9KQogICAgXSk7CiAgICByZXR1cm4gZ2VvWzBdOwogIH0KICBmdW5jdGlvbiBjb21wdXRlUmVjdGFuZ2xlMyhyZWN0YW5nbGUsIGdyYW51bGFyaXR5LCByb3RhdGlvbiwgZWxsaXBzb2lkLCByZXN1bHQpIHsKICAgIGlmIChyb3RhdGlvbiA9PT0gMCkgewogICAgICByZXR1cm4gUmVjdGFuZ2xlX2RlZmF1bHQuY2xvbmUocmVjdGFuZ2xlLCByZXN1bHQpOwogICAgfQogICAgY29uc3QgY29tcHV0ZWRPcHRpb25zID0gUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZU9wdGlvbnMoCiAgICAgIHJlY3RhbmdsZSwKICAgICAgZ3JhbnVsYXJpdHksCiAgICAgIHJvdGF0aW9uLAogICAgICAwLAogICAgICByZWN0YW5nbGVTY3JhdGNoLAogICAgICBud1NjcmF0Y2gKICAgICk7CiAgICBjb25zdCBoZWlnaHQgPSBjb21wdXRlZE9wdGlvbnMuaGVpZ2h0OwogICAgY29uc3Qgd2lkdGggPSBjb21wdXRlZE9wdGlvbnMud2lkdGg7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBzY3JhdGNoUmVjdGFuZ2xlUG9pbnRzOwogICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVBvc2l0aW9uKAogICAgICBjb21wdXRlZE9wdGlvbnMsCiAgICAgIGVsbGlwc29pZCwKICAgICAgZmFsc2UsCiAgICAgIDAsCiAgICAgIDAsCiAgICAgIHBvc2l0aW9uc1swXQogICAgKTsKICAgIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbigKICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICBlbGxpcHNvaWQsCiAgICAgIGZhbHNlLAogICAgICAwLAogICAgICB3aWR0aCAtIDEsCiAgICAgIHBvc2l0aW9uc1sxXQogICAgKTsKICAgIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbigKICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICBlbGxpcHNvaWQsCiAgICAgIGZhbHNlLAogICAgICBoZWlnaHQgLSAxLAogICAgICAwLAogICAgICBwb3NpdGlvbnNbMl0KICAgICk7CiAgICBSZWN0YW5nbGVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb24oCiAgICAgIGNvbXB1dGVkT3B0aW9ucywKICAgICAgZWxsaXBzb2lkLAogICAgICBmYWxzZSwKICAgICAgaGVpZ2h0IC0gMSwKICAgICAgd2lkdGggLSAxLAogICAgICBwb3NpdGlvbnNbM10KICAgICk7CiAgICByZXR1cm4gUmVjdGFuZ2xlX2RlZmF1bHQuZnJvbUNhcnRlc2lhbkFycmF5KHBvc2l0aW9ucywgZWxsaXBzb2lkLCByZXN1bHQpOwogIH0KICBmdW5jdGlvbiBSZWN0YW5nbGVHZW9tZXRyeShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICBjb25zdCByZWN0YW5nbGUgPSBvcHRpb25zLnJlY3RhbmdsZTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicmVjdGFuZ2xlIiwgcmVjdGFuZ2xlKTsKICAgIFJlY3RhbmdsZV9kZWZhdWx0Ll92YWxpZGF0ZShyZWN0YW5nbGUpOwogICAgaWYgKHJlY3RhbmdsZS5ub3J0aCA8IHJlY3RhbmdsZS5zb3V0aCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAib3B0aW9ucy5yZWN0YW5nbGUubm9ydGggbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gb3B0aW9ucy5yZWN0YW5nbGUuc291dGgiCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodCA/PyAwOwogICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0ID8/IGhlaWdodDsKICAgIHRoaXMuX3JlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHJlY3RhbmdsZSk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgIHRoaXMuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKG9wdGlvbnMuZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQpOwogICAgdGhpcy5fc3VyZmFjZUhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgZXh0cnVkZWRIZWlnaHQpOwogICAgdGhpcy5fcm90YXRpb24gPSBvcHRpb25zLnJvdGF0aW9uID8/IDA7CiAgICB0aGlzLl9zdFJvdGF0aW9uID0gb3B0aW9ucy5zdFJvdGF0aW9uID8/IDA7CiAgICB0aGlzLl92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSgKICAgICAgb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVAogICAgKTsKICAgIHRoaXMuX2V4dHJ1ZGVkSGVpZ2h0ID0gTWF0aC5taW4oaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICB0aGlzLl9zaGFkb3dWb2x1bWUgPSBvcHRpb25zLnNoYWRvd1ZvbHVtZSA/PyBmYWxzZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnkiOwogICAgdGhpcy5fb2Zmc2V0QXR0cmlidXRlID0gb3B0aW9ucy5vZmZzZXRBdHRyaWJ1dGU7CiAgICB0aGlzLl9yb3RhdGVkUmVjdGFuZ2xlID0gdm9pZCAwOwogICAgdGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cyA9IHZvaWQgMDsKICB9CiAgZnVuY3Rpb24gdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czMocmVjdGFuZ2xlR2VvbWV0cnkpIHsKICAgIGlmIChyZWN0YW5nbGVHZW9tZXRyeS5fc3RSb3RhdGlvbiA9PT0gMCkgewogICAgICByZXR1cm4gWzAsIDAsIDAsIDEsIDEsIDBdOwogICAgfQogICAgY29uc3QgcmVjdGFuZ2xlID0gUmVjdGFuZ2xlX2RlZmF1bHQuY2xvbmUoCiAgICAgIHJlY3RhbmdsZUdlb21ldHJ5Ll9yZWN0YW5nbGUsCiAgICAgIHVucm90YXRlZFRleHR1cmVSZWN0YW5nbGVTY3JhdGNoCiAgICApOwogICAgY29uc3QgZ3JhbnVsYXJpdHkgPSByZWN0YW5nbGVHZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICBjb25zdCBlbGxpcHNvaWQgPSByZWN0YW5nbGVHZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgY29uc3Qgcm90YXRpb24gPSByZWN0YW5nbGVHZW9tZXRyeS5fcm90YXRpb24gLSByZWN0YW5nbGVHZW9tZXRyeS5fc3RSb3RhdGlvbjsKICAgIGNvbnN0IHVucm90YXRlZFRleHR1cmVSZWN0YW5nbGUgPSBjb21wdXRlUmVjdGFuZ2xlMygKICAgICAgcmVjdGFuZ2xlLAogICAgICBncmFudWxhcml0eSwKICAgICAgcm90YXRpb24sCiAgICAgIGVsbGlwc29pZCwKICAgICAgdW5yb3RhdGVkVGV4dHVyZVJlY3RhbmdsZVNjcmF0Y2gKICAgICk7CiAgICBjb25zdCBwb2ludHMyRCA9IHBvaW50czJEU2NyYXRjaDI7CiAgICBwb2ludHMyRFswXS54ID0gdW5yb3RhdGVkVGV4dHVyZVJlY3RhbmdsZS53ZXN0OwogICAgcG9pbnRzMkRbMF0ueSA9IHVucm90YXRlZFRleHR1cmVSZWN0YW5nbGUuc291dGg7CiAgICBwb2ludHMyRFsxXS54ID0gdW5yb3RhdGVkVGV4dHVyZVJlY3RhbmdsZS53ZXN0OwogICAgcG9pbnRzMkRbMV0ueSA9IHVucm90YXRlZFRleHR1cmVSZWN0YW5nbGUubm9ydGg7CiAgICBwb2ludHMyRFsyXS54ID0gdW5yb3RhdGVkVGV4dHVyZVJlY3RhbmdsZS5lYXN0OwogICAgcG9pbnRzMkRbMl0ueSA9IHVucm90YXRlZFRleHR1cmVSZWN0YW5nbGUuc291dGg7CiAgICBjb25zdCBib3VuZGluZ1JlY3RhbmdsZSA9IHJlY3RhbmdsZUdlb21ldHJ5LnJlY3RhbmdsZTsKICAgIGNvbnN0IHRvRGVzaXJlZEluQ29tcHV0ZWQgPSBNYXRyaXgyX2RlZmF1bHQuZnJvbVJvdGF0aW9uKAogICAgICByZWN0YW5nbGVHZW9tZXRyeS5fc3RSb3RhdGlvbiwKICAgICAgcm90YXRpb24yRFNjcmF0Y2gyCiAgICApOwogICAgY29uc3QgYm91bmRpbmdSZWN0YW5nbGVDZW50ZXIgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgIGJvdW5kaW5nUmVjdGFuZ2xlLAogICAgICByZWN0YW5nbGVDZW50ZXJTY3JhdGNoMgogICAgKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCAzOyArK2kyKSB7CiAgICAgIGNvbnN0IHBvaW50MkQgPSBwb2ludHMyRFtpMl07CiAgICAgIHBvaW50MkQueCAtPSBib3VuZGluZ1JlY3RhbmdsZUNlbnRlci5sb25naXR1ZGU7CiAgICAgIHBvaW50MkQueSAtPSBib3VuZGluZ1JlY3RhbmdsZUNlbnRlci5sYXRpdHVkZTsKICAgICAgTWF0cml4Ml9kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IodG9EZXNpcmVkSW5Db21wdXRlZCwgcG9pbnQyRCwgcG9pbnQyRCk7CiAgICAgIHBvaW50MkQueCArPSBib3VuZGluZ1JlY3RhbmdsZUNlbnRlci5sb25naXR1ZGU7CiAgICAgIHBvaW50MkQueSArPSBib3VuZGluZ1JlY3RhbmdsZUNlbnRlci5sYXRpdHVkZTsKICAgICAgcG9pbnQyRC54ID0gKHBvaW50MkQueCAtIGJvdW5kaW5nUmVjdGFuZ2xlLndlc3QpIC8gYm91bmRpbmdSZWN0YW5nbGUud2lkdGg7CiAgICAgIHBvaW50MkQueSA9IChwb2ludDJELnkgLSBib3VuZGluZ1JlY3RhbmdsZS5zb3V0aCkgLyBib3VuZGluZ1JlY3RhbmdsZS5oZWlnaHQ7CiAgICB9CiAgICBjb25zdCBtaW5YWUNvcm5lciA9IHBvaW50czJEWzBdOwogICAgY29uc3QgbWF4WUNvcm5lciA9IHBvaW50czJEWzFdOwogICAgY29uc3QgbWF4WENvcm5lciA9IHBvaW50czJEWzJdOwogICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5KDYpOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2sobWluWFlDb3JuZXIsIHJlc3VsdCk7CiAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQucGFjayhtYXhZQ29ybmVyLCByZXN1bHQsIDIpOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0LnBhY2sobWF4WENvcm5lciwgcmVzdWx0LCA0KTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciBwb3NpdGlvblNjcmF0Y2gyLCBub3JtYWxTY3JhdGNoNCwgdGFuZ2VudFNjcmF0Y2gyLCBiaXRhbmdlbnRTY3JhdGNoMiwgcmVjdGFuZ2xlU2NyYXRjaCwgc3RTY3JhdGNoMiwgYm90dG9tQm91bmRpbmdTcGhlcmUzLCB0b3BCb3VuZGluZ1NwaGVyZTMsIHYxU2NyYXRjaCwgdjJTY3JhdGNoLCBzY3JhdGNoVmVydGV4Rm9ybWF0MTIsIHNjcmF0Y2hSZWN0YW5nbGVQb2ludHMsIG53U2NyYXRjaCwgc3ROd1NjcmF0Y2gsIHNjcmF0Y2hSZWN0YW5nbGUsIHNjcmF0Y2hFbGxpcHNvaWQxMSwgc2NyYXRjaE9wdGlvbnMxOSwgdGFuZ2VudFJvdGF0aW9uTWF0cml4U2NyYXRjaCwgcXVhdGVybmlvblNjcmF0Y2g0LCBjZW50ZXJTY3JhdGNoNCwgdW5yb3RhdGVkVGV4dHVyZVJlY3RhbmdsZVNjcmF0Y2gsIHBvaW50czJEU2NyYXRjaDIsIHJvdGF0aW9uMkRTY3JhdGNoMiwgcmVjdGFuZ2xlQ2VudGVyU2NyYXRjaDIsIFJlY3RhbmdsZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUmVjdGFuZ2xlR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1JlY3RhbmdsZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9HZW9tZXRyeUluc3RhbmNlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlPZmZzZXRBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeVBpcGVsaW5lKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXgyKCk7CiAgICAgIGluaXRfTWF0cml4MygpOwogICAgICBpbml0X1BvbHlnb25QaXBlbGluZSgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9RdWF0ZXJuaW9uKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIHBvc2l0aW9uU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIG5vcm1hbFNjcmF0Y2g0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0YW5nZW50U2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGJpdGFuZ2VudFNjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICByZWN0YW5nbGVTY3JhdGNoID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIHN0U2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlMyA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHRvcEJvdW5kaW5nU3BoZXJlMyA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHYxU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgdjJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVmVydGV4Rm9ybWF0MTIgPSBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFJlY3RhbmdsZVBvaW50cyA9IFsKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkKICAgICAgXTsKICAgICAgbndTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHN0TndTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IFJlY3RhbmdsZV9kZWZhdWx0LnBhY2tlZExlbmd0aCArIEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDc7CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInZhbHVlIiwgdmFsdWUpOwogICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiYXJyYXkiLCBhcnJheSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBSZWN0YW5nbGVfZGVmYXVsdC5wYWNrKHZhbHVlLl9yZWN0YW5nbGUsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFJlY3RhbmdsZV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrKHZhbHVlLl92ZXJ0ZXhGb3JtYXQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2dyYW51bGFyaXR5OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc3VyZmFjZUhlaWdodDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3JvdGF0aW9uOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc3RSb3RhdGlvbjsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fc2hhZG93Vm9sdW1lID8gMSA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleF0gPSB2YWx1ZS5fb2Zmc2V0QXR0cmlidXRlID8/IC0xOwogICAgICAgIHJldHVybiBhcnJheTsKICAgICAgfTsKICAgICAgc2NyYXRjaFJlY3RhbmdsZSA9IG5ldyBSZWN0YW5nbGVfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRWxsaXBzb2lkMTEgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShFbGxpcHNvaWRfZGVmYXVsdC5VTklUX1NQSEVSRSk7CiAgICAgIHNjcmF0Y2hPcHRpb25zMTkgPSB7CiAgICAgICAgcmVjdGFuZ2xlOiBzY3JhdGNoUmVjdGFuZ2xlLAogICAgICAgIGVsbGlwc29pZDogc2NyYXRjaEVsbGlwc29pZDExLAogICAgICAgIHZlcnRleEZvcm1hdDogc2NyYXRjaFZlcnRleEZvcm1hdDEyLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgcm90YXRpb246IHZvaWQgMCwKICAgICAgICBzdFJvdGF0aW9uOiB2b2lkIDAsCiAgICAgICAgZXh0cnVkZWRIZWlnaHQ6IHZvaWQgMCwKICAgICAgICBzaGFkb3dWb2x1bWU6IHZvaWQgMCwKICAgICAgICBvZmZzZXRBdHRyaWJ1dGU6IHZvaWQgMAogICAgICB9OwogICAgICBSZWN0YW5nbGVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJhcnJheSIsIGFycmF5KTsKICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGNvbnN0IHJlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCwgc2NyYXRjaFJlY3RhbmdsZSk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBSZWN0YW5nbGVfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4LCBzY3JhdGNoRWxsaXBzb2lkMTEpOwogICAgICAgIHN0YXJ0aW5nSW5kZXggKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIHNjcmF0Y2hWZXJ0ZXhGb3JtYXQxMgogICAgICAgICk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHN1cmZhY2VIZWlnaHQgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHJvdGF0aW9uID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBzdFJvdGF0aW9uID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBleHRydWRlZEhlaWdodCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgc2hhZG93Vm9sdW1lID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9PT0gMTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE5LmdyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE5LmhlaWdodCA9IHN1cmZhY2VIZWlnaHQ7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE5LnJvdGF0aW9uID0gcm90YXRpb247CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE5LnN0Um90YXRpb24gPSBzdFJvdGF0aW9uOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxOS5leHRydWRlZEhlaWdodCA9IGV4dHJ1ZGVkSGVpZ2h0OwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMxOS5zaGFkb3dWb2x1bWUgPSBzaGFkb3dWb2x1bWU7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczE5Lm9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZSA9PT0gLTEgPyB2b2lkIDAgOiBvZmZzZXRBdHRyaWJ1dGU7CiAgICAgICAgICByZXR1cm4gbmV3IFJlY3RhbmdsZUdlb21ldHJ5KHNjcmF0Y2hPcHRpb25zMTkpOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3JlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHJlY3RhbmdsZSwgcmVzdWx0Ll9yZWN0YW5nbGUpOwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSh2ZXJ0ZXhGb3JtYXQsIHJlc3VsdC5fdmVydGV4Rm9ybWF0KTsKICAgICAgICByZXN1bHQuX2dyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgcmVzdWx0Ll9zdXJmYWNlSGVpZ2h0ID0gc3VyZmFjZUhlaWdodDsKICAgICAgICByZXN1bHQuX3JvdGF0aW9uID0gcm90YXRpb247CiAgICAgICAgcmVzdWx0Ll9zdFJvdGF0aW9uID0gc3RSb3RhdGlvbjsKICAgICAgICByZXN1bHQuX2V4dHJ1ZGVkSGVpZ2h0ID0gZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9zaGFkb3dWb2x1bWUgPSBzaGFkb3dWb2x1bWU7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5LmNvbXB1dGVSZWN0YW5nbGUgPSBmdW5jdGlvbihvcHRpb25zLCByZXN1bHQpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgY29uc3QgcmVjdGFuZ2xlID0gb3B0aW9ucy5yZWN0YW5nbGU7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgIFJlY3RhbmdsZV9kZWZhdWx0Ll92YWxpZGF0ZShyZWN0YW5nbGUpOwogICAgICAgIGlmIChyZWN0YW5nbGUubm9ydGggPCByZWN0YW5nbGUuc291dGgpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAib3B0aW9ucy5yZWN0YW5nbGUubm9ydGggbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gb3B0aW9ucy5yZWN0YW5nbGUuc291dGgiCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBvcHRpb25zLmVsbGlwc29pZCA/PyBFbGxpcHNvaWRfZGVmYXVsdC5kZWZhdWx0OwogICAgICAgIGNvbnN0IHJvdGF0aW9uID0gb3B0aW9ucy5yb3RhdGlvbiA/PyAwOwogICAgICAgIHJldHVybiBjb21wdXRlUmVjdGFuZ2xlMyhyZWN0YW5nbGUsIGdyYW51bGFyaXR5LCByb3RhdGlvbiwgZWxsaXBzb2lkLCByZXN1bHQpOwogICAgICB9OwogICAgICB0YW5nZW50Um90YXRpb25NYXRyaXhTY3JhdGNoID0gbmV3IE1hdHJpeDNfZGVmYXVsdCgpOwogICAgICBxdWF0ZXJuaW9uU2NyYXRjaDQgPSBuZXcgUXVhdGVybmlvbl9kZWZhdWx0KCk7CiAgICAgIGNlbnRlclNjcmF0Y2g0ID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24ocmVjdGFuZ2xlR2VvbWV0cnkpIHsKICAgICAgICBpZiAoTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICByZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlLm5vcnRoLAogICAgICAgICAgcmVjdGFuZ2xlR2VvbWV0cnkuX3JlY3RhbmdsZS5zb3V0aCwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAKICAgICAgICApIHx8IE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgcmVjdGFuZ2xlR2VvbWV0cnkuX3JlY3RhbmdsZS5lYXN0LAogICAgICAgICAgcmVjdGFuZ2xlR2VvbWV0cnkuX3JlY3RhbmdsZS53ZXN0LAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04xMAogICAgICAgICkpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIGxldCByZWN0YW5nbGUgPSByZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICAgICAgY29uc3Qgcm90YXRpb24gPSByZWN0YW5nbGVHZW9tZXRyeS5fcm90YXRpb247CiAgICAgICAgY29uc3Qgc3RSb3RhdGlvbiA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9zdFJvdGF0aW9uOwogICAgICAgIGNvbnN0IHZlcnRleEZvcm1hdCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgY29uc3QgY29tcHV0ZWRPcHRpb25zID0gUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZU9wdGlvbnMoCiAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICByZWN0YW5nbGVHZW9tZXRyeS5fZ3JhbnVsYXJpdHksCiAgICAgICAgICByb3RhdGlvbiwKICAgICAgICAgIHN0Um90YXRpb24sCiAgICAgICAgICByZWN0YW5nbGVTY3JhdGNoLAogICAgICAgICAgbndTY3JhdGNoLAogICAgICAgICAgc3ROd1NjcmF0Y2gKICAgICAgICApOwogICAgICAgIGNvbnN0IHRhbmdlbnRSb3RhdGlvbk1hdHJpeCA9IHRhbmdlbnRSb3RhdGlvbk1hdHJpeFNjcmF0Y2g7CiAgICAgICAgaWYgKHN0Um90YXRpb24gIT09IDAgfHwgcm90YXRpb24gIT09IDApIHsKICAgICAgICAgIGNvbnN0IGNlbnRlciA9IFJlY3RhbmdsZV9kZWZhdWx0LmNlbnRlcihyZWN0YW5nbGUsIGNlbnRlclNjcmF0Y2g0KTsKICAgICAgICAgIGNvbnN0IGF4aXMgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsQ2FydG9ncmFwaGljKGNlbnRlciwgdjFTY3JhdGNoKTsKICAgICAgICAgIFF1YXRlcm5pb25fZGVmYXVsdC5mcm9tQXhpc0FuZ2xlKGF4aXMsIC1zdFJvdGF0aW9uLCBxdWF0ZXJuaW9uU2NyYXRjaDQpOwogICAgICAgICAgTWF0cml4M19kZWZhdWx0LmZyb21RdWF0ZXJuaW9uKHF1YXRlcm5pb25TY3JhdGNoNCwgdGFuZ2VudFJvdGF0aW9uTWF0cml4KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgTWF0cml4M19kZWZhdWx0LmNsb25lKE1hdHJpeDNfZGVmYXVsdC5JREVOVElUWSwgdGFuZ2VudFJvdGF0aW9uTWF0cml4KTsKICAgICAgICB9CiAgICAgICAgY29uc3Qgc3VyZmFjZUhlaWdodCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9zdXJmYWNlSGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gcmVjdGFuZ2xlR2VvbWV0cnkuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGNvbnN0IGV4dHJ1ZGUgPSAhTWF0aF9kZWZhdWx0LmVxdWFsc0Vwc2lsb24oCiAgICAgICAgICBzdXJmYWNlSGVpZ2h0LAogICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAwLAogICAgICAgICAgTWF0aF9kZWZhdWx0LkVQU0lMT04yCiAgICAgICAgKTsKICAgICAgICBjb21wdXRlZE9wdGlvbnMubG9uU2NhbGFyID0gMSAvIHJlY3RhbmdsZUdlb21ldHJ5Ll9yZWN0YW5nbGUud2lkdGg7CiAgICAgICAgY29tcHV0ZWRPcHRpb25zLmxhdFNjYWxhciA9IDEgLyByZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlLmhlaWdodDsKICAgICAgICBjb21wdXRlZE9wdGlvbnMudGFuZ2VudFJvdGF0aW9uTWF0cml4ID0gdGFuZ2VudFJvdGF0aW9uTWF0cml4OwogICAgICAgIGxldCBnZW9tZXRyeTsKICAgICAgICBsZXQgYm91bmRpbmdTcGhlcmU7CiAgICAgICAgcmVjdGFuZ2xlID0gcmVjdGFuZ2xlR2VvbWV0cnkuX3JlY3RhbmdsZTsKICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgZ2VvbWV0cnkgPSBjb25zdHJ1Y3RFeHRydWRlZFJlY3RhbmdsZShyZWN0YW5nbGVHZW9tZXRyeSwgY29tcHV0ZWRPcHRpb25zKTsKICAgICAgICAgIGNvbnN0IHRvcEJTID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlM0QoCiAgICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBzdXJmYWNlSGVpZ2h0LAogICAgICAgICAgICB0b3BCb3VuZGluZ1NwaGVyZTMKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBib3R0b21CUyA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVJlY3RhbmdsZTNEKAogICAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlMwogICAgICAgICAgKTsKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC51bmlvbih0b3BCUywgYm90dG9tQlMpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBnZW9tZXRyeSA9IGNvbnN0cnVjdFJlY3RhbmdsZShyZWN0YW5nbGVHZW9tZXRyeSwgY29tcHV0ZWRPcHRpb25zKTsKICAgICAgICAgIGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcywKICAgICAgICAgICAgc3VyZmFjZUhlaWdodCwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBmYWxzZQogICAgICAgICAgKTsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocmVjdGFuZ2xlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZSkpIHsKICAgICAgICAgICAgY29uc3QgbGVuZ3RoID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMubGVuZ3RoOwogICAgICAgICAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgICBjb25zdCBhcHBseU9mZnNldCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aCAvIDMpLmZpbGwob2Zmc2V0VmFsdWUpOwogICAgICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICAgICAgICB2YWx1ZXM6IGFwcGx5T2Zmc2V0CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgYm91bmRpbmdTcGhlcmUgPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21SZWN0YW5nbGUzRCgKICAgICAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHN1cmZhY2VIZWlnaHQKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGlmICghdmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgICAgICBkZWxldGUgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXM6IGdlb21ldHJ5LmF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzOiBnZW9tZXRyeS5pbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogZ2VvbWV0cnkucHJpbWl0aXZlVHlwZSwKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgb2Zmc2V0QXR0cmlidXRlOiByZWN0YW5nbGVHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5LmNyZWF0ZVNoYWRvd1ZvbHVtZSA9IGZ1bmN0aW9uKHJlY3RhbmdsZUdlb21ldHJ5LCBtaW5IZWlnaHRGdW5jLCBtYXhIZWlnaHRGdW5jKSB7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSByZWN0YW5nbGVHZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gcmVjdGFuZ2xlR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBtaW5IZWlnaHQgPSBtaW5IZWlnaHRGdW5jKGdyYW51bGFyaXR5LCBlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IG1heEhlaWdodCA9IG1heEhlaWdodEZ1bmMoZ3JhbnVsYXJpdHksIGVsbGlwc29pZCk7CiAgICAgICAgcmV0dXJuIG5ldyBSZWN0YW5nbGVHZW9tZXRyeSh7CiAgICAgICAgICByZWN0YW5nbGU6IHJlY3RhbmdsZUdlb21ldHJ5Ll9yZWN0YW5nbGUsCiAgICAgICAgICByb3RhdGlvbjogcmVjdGFuZ2xlR2VvbWV0cnkuX3JvdGF0aW9uLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc3RSb3RhdGlvbjogcmVjdGFuZ2xlR2VvbWV0cnkuX3N0Um90YXRpb24sCiAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgIGV4dHJ1ZGVkSGVpZ2h0OiBtYXhIZWlnaHQsCiAgICAgICAgICBoZWlnaHQ6IG1pbkhlaWdodCwKICAgICAgICAgIHZlcnRleEZvcm1hdDogVmVydGV4Rm9ybWF0X2RlZmF1bHQuUE9TSVRJT05fT05MWSwKICAgICAgICAgIHNoYWRvd1ZvbHVtZTogdHJ1ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICB1bnJvdGF0ZWRUZXh0dXJlUmVjdGFuZ2xlU2NyYXRjaCA9IG5ldyBSZWN0YW5nbGVfZGVmYXVsdCgpOwogICAgICBwb2ludHMyRFNjcmF0Y2gyID0gW25ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKSwgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLCBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCldOwogICAgICByb3RhdGlvbjJEU2NyYXRjaDIgPSBuZXcgTWF0cml4Ml9kZWZhdWx0KCk7CiAgICAgIHJlY3RhbmdsZUNlbnRlclNjcmF0Y2gyID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFJlY3RhbmdsZUdlb21ldHJ5LnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgcmVjdGFuZ2xlOiB7CiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh0aGlzLl9yb3RhdGVkUmVjdGFuZ2xlKSkgewogICAgICAgICAgICAgIHRoaXMuX3JvdGF0ZWRSZWN0YW5nbGUgPSBjb21wdXRlUmVjdGFuZ2xlMygKICAgICAgICAgICAgICAgIHRoaXMuX3JlY3RhbmdsZSwKICAgICAgICAgICAgICAgIHRoaXMuX2dyYW51bGFyaXR5LAogICAgICAgICAgICAgICAgdGhpcy5fcm90YXRpb24sCiAgICAgICAgICAgICAgICB0aGlzLl9lbGxpcHNvaWQKICAgICAgICAgICAgICApOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9yb3RhdGVkUmVjdGFuZ2xlOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogRm9yIHJlbWFwcGluZyB0ZXh0dXJlIGNvb3JkaW5hdGVzIHdoZW4gcmVuZGVyaW5nIFJlY3RhbmdsZUdlb21ldHJpZXMgYXMgR3JvdW5kUHJpbWl0aXZlcy4KICAgICAgICAgKiBUaGlzIHZlcnNpb24gcGVybWl0cyBza2V3IGluIHRleHR1cmVzIGJ5IGNvbXB1dGluZyBvZmZzZXRzIGRpcmVjdGx5IGluIGNhcnRvZ3JhcGhpYyBzcGFjZSBhbmQKICAgICAgICAgKiBtb3JlIGFjY3VyYXRlbHkgYXBwcm94aW1hdGVzIHJlbmRlcmluZyBSZWN0YW5nbGVHZW9tZXRyaWVzIHdpdGggaGVpZ2h0IGFzIHN0YW5kYXJkIFByaW1pdGl2ZXMuCiAgICAgICAgICogQHNlZSBHZW9tZXRyeSNfdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cwogICAgICAgICAqIEBwcml2YXRlCiAgICAgICAgICovCiAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czogewogICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodGhpcy5fdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50cykpIHsKICAgICAgICAgICAgICB0aGlzLl90ZXh0dXJlQ29vcmRpbmF0ZVJvdGF0aW9uUG9pbnRzID0gdGV4dHVyZUNvb3JkaW5hdGVSb3RhdGlvblBvaW50czModGhpcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3RleHR1cmVDb29yZGluYXRlUm90YXRpb25Qb2ludHM7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlfZGVmYXVsdCA9IFJlY3RhbmdsZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5X2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVSZWN0YW5nbGVHZW9tZXRyeShyZWN0YW5nbGVHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcmVjdGFuZ2xlR2VvbWV0cnkgPSBSZWN0YW5nbGVHZW9tZXRyeV9kZWZhdWx0LnVucGFjayhyZWN0YW5nbGVHZW9tZXRyeSwgb2Zmc2V0KTsKICAgIH0KICAgIHJlY3RhbmdsZUdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShyZWN0YW5nbGVHZW9tZXRyeS5fZWxsaXBzb2lkKTsKICAgIHJlY3RhbmdsZUdlb21ldHJ5Ll9yZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5jbG9uZShyZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlKTsKICAgIHJldHVybiBSZWN0YW5nbGVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHJlY3RhbmdsZUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gY29uc3RydWN0UmVjdGFuZ2xlMihnZW9tZXRyeSwgY29tcHV0ZWRPcHRpb25zKSB7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBnZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgY29uc3QgaGVpZ2h0ID0gY29tcHV0ZWRPcHRpb25zLmhlaWdodDsKICAgIGNvbnN0IHdpZHRoID0gY29tcHV0ZWRPcHRpb25zLndpZHRoOwogICAgY29uc3Qgbm9ydGhDYXAgPSBjb21wdXRlZE9wdGlvbnMubm9ydGhDYXA7CiAgICBjb25zdCBzb3V0aENhcCA9IGNvbXB1dGVkT3B0aW9ucy5zb3V0aENhcDsKICAgIGxldCByb3dIZWlnaHQgPSBoZWlnaHQ7CiAgICBsZXQgd2lkdGhNdWx0aXBsaWVyID0gMjsKICAgIGxldCBzaXplID0gMDsKICAgIGxldCBjb3JuZXJzID0gNDsKICAgIGlmIChub3J0aENhcCkgewogICAgICB3aWR0aE11bHRpcGxpZXIgLT0gMTsKICAgICAgcm93SGVpZ2h0IC09IDE7CiAgICAgIHNpemUgKz0gMTsKICAgICAgY29ybmVycyAtPSAyOwogICAgfQogICAgaWYgKHNvdXRoQ2FwKSB7CiAgICAgIHdpZHRoTXVsdGlwbGllciAtPSAxOwogICAgICByb3dIZWlnaHQgLT0gMTsKICAgICAgc2l6ZSArPSAxOwogICAgICBjb3JuZXJzIC09IDI7CiAgICB9CiAgICBzaXplICs9IHdpZHRoTXVsdGlwbGllciAqIHdpZHRoICsgMiAqIHJvd0hlaWdodCAtIGNvcm5lcnM7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KHNpemUgKiAzKTsKICAgIGxldCBwb3NJbmRleCA9IDA7CiAgICBsZXQgcm93ID0gMDsKICAgIGxldCBjb2w7CiAgICBjb25zdCBwb3NpdGlvbiA9IHBvc2l0aW9uU2NyYXRjaDM7CiAgICBpZiAobm9ydGhDYXApIHsKICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVBvc2l0aW9uKAogICAgICAgIGNvbXB1dGVkT3B0aW9ucywKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgZmFsc2UsCiAgICAgICAgcm93LAogICAgICAgIDAsCiAgICAgICAgcG9zaXRpb24KICAgICAgKTsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24uejsKICAgIH0gZWxzZSB7CiAgICAgIGZvciAoY29sID0gMDsgY29sIDwgd2lkdGg7IGNvbCsrKSB7CiAgICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVBvc2l0aW9uKAogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZmFsc2UsCiAgICAgICAgICByb3csCiAgICAgICAgICBjb2wsCiAgICAgICAgICBwb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi55OwogICAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLno7CiAgICAgIH0KICAgIH0KICAgIGNvbCA9IHdpZHRoIC0gMTsKICAgIGZvciAocm93ID0gMTsgcm93IDwgaGVpZ2h0OyByb3crKykgewogICAgICBSZWN0YW5nbGVHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb24oCiAgICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICBmYWxzZSwKICAgICAgICByb3csCiAgICAgICAgY29sLAogICAgICAgIHBvc2l0aW9uCiAgICAgICk7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLng7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLnk7CiAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLno7CiAgICB9CiAgICByb3cgPSBoZWlnaHQgLSAxOwogICAgaWYgKCFzb3V0aENhcCkgewogICAgICBmb3IgKGNvbCA9IHdpZHRoIC0gMjsgY29sID49IDA7IGNvbC0tKSB7CiAgICAgICAgUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZVBvc2l0aW9uKAogICAgICAgICAgY29tcHV0ZWRPcHRpb25zLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgZmFsc2UsCiAgICAgICAgICByb3csCiAgICAgICAgICBjb2wsCiAgICAgICAgICBwb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgICBwb3NpdGlvbnNbcG9zSW5kZXgrK10gPSBwb3NpdGlvbi55OwogICAgICAgIHBvc2l0aW9uc1twb3NJbmRleCsrXSA9IHBvc2l0aW9uLno7CiAgICAgIH0KICAgIH0KICAgIGNvbCA9IDA7CiAgICBmb3IgKHJvdyA9IGhlaWdodCAtIDI7IHJvdyA+IDA7IHJvdy0tKSB7CiAgICAgIFJlY3RhbmdsZUdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbigKICAgICAgICBjb21wdXRlZE9wdGlvbnMsCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIGZhbHNlLAogICAgICAgIHJvdywKICAgICAgICBjb2wsCiAgICAgICAgcG9zaXRpb24KICAgICAgKTsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueDsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24ueTsKICAgICAgcG9zaXRpb25zW3Bvc0luZGV4KytdID0gcG9zaXRpb24uejsKICAgIH0KICAgIGNvbnN0IGluZGljZXNTaXplID0gcG9zaXRpb25zLmxlbmd0aCAvIDMgKiAyOwogICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICBwb3NpdGlvbnMubGVuZ3RoIC8gMywKICAgICAgaW5kaWNlc1NpemUKICAgICk7CiAgICBsZXQgaW5kZXggPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvc2l0aW9ucy5sZW5ndGggLyAzIC0gMTsgaTIrKykgewogICAgICBpbmRpY2VzW2luZGV4KytdID0gaTI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMiArIDE7CiAgICB9CiAgICBpbmRpY2VzW2luZGV4KytdID0gcG9zaXRpb25zLmxlbmd0aCAvIDMgLSAxOwogICAgaW5kaWNlc1tpbmRleF0gPSAwOwogICAgY29uc3QgZ2VvID0gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICBhdHRyaWJ1dGVzOiBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKSwKICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTCiAgICB9KTsKICAgIGdlby5hdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICB9KTsKICAgIGdlby5pbmRpY2VzID0gaW5kaWNlczsKICAgIHJldHVybiBnZW87CiAgfQogIGZ1bmN0aW9uIGNvbnN0cnVjdEV4dHJ1ZGVkUmVjdGFuZ2xlMihyZWN0YW5nbGVHZW9tZXRyeSwgY29tcHV0ZWRPcHRpb25zKSB7CiAgICBjb25zdCBtYXhIZWlnaHQgPSByZWN0YW5nbGVHZW9tZXRyeS5fc3VyZmFjZUhlaWdodDsKICAgIGNvbnN0IG1pbkhlaWdodCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9leHRydWRlZEhlaWdodDsKICAgIGNvbnN0IGVsbGlwc29pZCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICBjb25zdCBnZW8gPSBjb25zdHJ1Y3RSZWN0YW5nbGUyKHJlY3RhbmdsZUdlb21ldHJ5LCBjb21wdXRlZE9wdGlvbnMpOwogICAgY29uc3QgaGVpZ2h0ID0gY29tcHV0ZWRPcHRpb25zLmhlaWdodDsKICAgIGNvbnN0IHdpZHRoID0gY29tcHV0ZWRPcHRpb25zLndpZHRoOwogICAgY29uc3QgdG9wUG9zaXRpb25zID0gUG9seWdvblBpcGVsaW5lX2RlZmF1bHQuc2NhbGVUb0dlb2RldGljSGVpZ2h0KAogICAgICBnZW8uYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMsCiAgICAgIG1heEhlaWdodCwKICAgICAgZWxsaXBzb2lkLAogICAgICBmYWxzZQogICAgKTsKICAgIGxldCBsZW5ndGggPSB0b3BQb3NpdGlvbnMubGVuZ3RoOwogICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGggKiAyKTsKICAgIHBvc2l0aW9ucy5zZXQodG9wUG9zaXRpb25zKTsKICAgIGNvbnN0IGJvdHRvbVBvc2l0aW9ucyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgZ2VvLmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLAogICAgICBtaW5IZWlnaHQsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIHBvc2l0aW9ucy5zZXQoYm90dG9tUG9zaXRpb25zLCBsZW5ndGgpOwogICAgZ2VvLmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzID0gcG9zaXRpb25zOwogICAgY29uc3Qgbm9ydGhDYXAgPSBjb21wdXRlZE9wdGlvbnMubm9ydGhDYXA7CiAgICBjb25zdCBzb3V0aENhcCA9IGNvbXB1dGVkT3B0aW9ucy5zb3V0aENhcDsKICAgIGxldCBjb3JuZXJzID0gNDsKICAgIGlmIChub3J0aENhcCkgewogICAgICBjb3JuZXJzIC09IDE7CiAgICB9CiAgICBpZiAoc291dGhDYXApIHsKICAgICAgY29ybmVycyAtPSAxOwogICAgfQogICAgY29uc3QgaW5kaWNlc1NpemUgPSAocG9zaXRpb25zLmxlbmd0aCAvIDMgKyBjb3JuZXJzKSAqIDI7CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIHBvc2l0aW9ucy5sZW5ndGggLyAzLAogICAgICBpbmRpY2VzU2l6ZQogICAgKTsKICAgIGxlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyA2OwogICAgbGV0IGluZGV4ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGggLSAxOyBpMisrKSB7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBpMjsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgMTsKICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgbGVuZ3RoOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gaTIgKyBsZW5ndGggKyAxOwogICAgfQogICAgaW5kaWNlc1tpbmRleCsrXSA9IGxlbmd0aCAtIDE7CiAgICBpbmRpY2VzW2luZGV4KytdID0gMDsKICAgIGluZGljZXNbaW5kZXgrK10gPSBsZW5ndGggKyBsZW5ndGggLSAxOwogICAgaW5kaWNlc1tpbmRleCsrXSA9IGxlbmd0aDsKICAgIGluZGljZXNbaW5kZXgrK10gPSAwOwogICAgaW5kaWNlc1tpbmRleCsrXSA9IGxlbmd0aDsKICAgIGxldCBib3R0b21Db3JuZXI7CiAgICBpZiAobm9ydGhDYXApIHsKICAgICAgYm90dG9tQ29ybmVyID0gaGVpZ2h0IC0gMTsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IHRvcFJpZ2h0Q29ybmVyID0gd2lkdGggLSAxOwogICAgICBpbmRpY2VzW2luZGV4KytdID0gdG9wUmlnaHRDb3JuZXI7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSB0b3BSaWdodENvcm5lciArIGxlbmd0aDsKICAgICAgYm90dG9tQ29ybmVyID0gd2lkdGggKyBoZWlnaHQgLSAyOwogICAgfQogICAgaW5kaWNlc1tpbmRleCsrXSA9IGJvdHRvbUNvcm5lcjsKICAgIGluZGljZXNbaW5kZXgrK10gPSBib3R0b21Db3JuZXIgKyBsZW5ndGg7CiAgICBpZiAoIXNvdXRoQ2FwKSB7CiAgICAgIGNvbnN0IGJvdHRvbUxlZnRDb3JuZXIgPSB3aWR0aCArIGJvdHRvbUNvcm5lciAtIDE7CiAgICAgIGluZGljZXNbaW5kZXgrK10gPSBib3R0b21MZWZ0Q29ybmVyOwogICAgICBpbmRpY2VzW2luZGV4XSA9IGJvdHRvbUxlZnRDb3JuZXIgKyBsZW5ndGg7CiAgICB9CiAgICBnZW8uaW5kaWNlcyA9IGluZGljZXM7CiAgICByZXR1cm4gZ2VvOwogIH0KICBmdW5jdGlvbiBSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcmVjdGFuZ2xlID0gb3B0aW9ucy5yZWN0YW5nbGU7CiAgICBjb25zdCBncmFudWxhcml0eSA9IG9wdGlvbnMuZ3JhbnVsYXJpdHkgPz8gTWF0aF9kZWZhdWx0LlJBRElBTlNfUEVSX0RFR1JFRTsKICAgIGNvbnN0IGVsbGlwc29pZCA9IG9wdGlvbnMuZWxsaXBzb2lkID8/IEVsbGlwc29pZF9kZWZhdWx0LmRlZmF1bHQ7CiAgICBjb25zdCByb3RhdGlvbiA9IG9wdGlvbnMucm90YXRpb24gPz8gMDsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlY3RhbmdsZSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInJlY3RhbmdsZSBpcyByZXF1aXJlZC4iKTsKICAgIH0KICAgIFJlY3RhbmdsZV9kZWZhdWx0Ll92YWxpZGF0ZShyZWN0YW5nbGUpOwogICAgaWYgKHJlY3RhbmdsZS5ub3J0aCA8IHJlY3RhbmdsZS5zb3V0aCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAib3B0aW9ucy5yZWN0YW5nbGUubm9ydGggbXVzdCBiZSBncmVhdGVyIHRoYW4gb3B0aW9ucy5yZWN0YW5nbGUuc291dGgiCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodCA/PyAwOwogICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSBvcHRpb25zLmV4dHJ1ZGVkSGVpZ2h0ID8/IGhlaWdodDsKICAgIHRoaXMuX3JlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHJlY3RhbmdsZSk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgdGhpcy5fZWxsaXBzb2lkID0gZWxsaXBzb2lkOwogICAgdGhpcy5fc3VyZmFjZUhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgZXh0cnVkZWRIZWlnaHQpOwogICAgdGhpcy5fcm90YXRpb24gPSByb3RhdGlvbjsKICAgIHRoaXMuX2V4dHJ1ZGVkSGVpZ2h0ID0gTWF0aC5taW4oaGVpZ2h0LCBleHRydWRlZEhlaWdodCk7CiAgICB0aGlzLl9vZmZzZXRBdHRyaWJ1dGUgPSBvcHRpb25zLm9mZnNldEF0dHJpYnV0ZTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5IjsKICB9CiAgdmFyIGJvdHRvbUJvdW5kaW5nU3BoZXJlNCwgdG9wQm91bmRpbmdTcGhlcmU0LCBwb3NpdGlvblNjcmF0Y2gzLCByZWN0YW5nbGVTY3JhdGNoMiwgc2NyYXRjaFJlY3RhbmdsZTIsIHNjcmF0Y2hFbGxpcHNvaWQxMiwgc2NyYXRjaE9wdGlvbnMyMCwgbndTY3JhdGNoMiwgUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9SZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NvbXBvbmVudERhdGF0eXBlKCk7CiAgICAgIGluaXRfRnJvemVuKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfR2VvbWV0cnkoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlcygpOwogICAgICBpbml0X0dlb21ldHJ5T2Zmc2V0QXR0cmlidXRlKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9Qb2x5Z29uUGlwZWxpbmUoKTsKICAgICAgaW5pdF9QcmltaXRpdmVUeXBlKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlKCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlNCA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHRvcEJvdW5kaW5nU3BoZXJlNCA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHBvc2l0aW9uU2NyYXRjaDMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHJlY3RhbmdsZVNjcmF0Y2gyID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIFJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeS5wYWNrZWRMZW5ndGggPSBSZWN0YW5nbGVfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyA1OwogICAgICBSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHZhbHVlKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInZhbHVlIGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgUmVjdGFuZ2xlX2RlZmF1bHQucGFjayh2YWx1ZS5fcmVjdGFuZ2xlLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBSZWN0YW5nbGVfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgRWxsaXBzb2lkX2RlZmF1bHQucGFjayh2YWx1ZS5fZWxsaXBzb2lkLCBhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX3N1cmZhY2VIZWlnaHQ7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IHZhbHVlLl9yb3RhdGlvbjsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2V4dHJ1ZGVkSGVpZ2h0OwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXhdID0gdmFsdWUuX29mZnNldEF0dHJpYnV0ZSA/PyAtMTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hSZWN0YW5nbGUyID0gbmV3IFJlY3RhbmdsZV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQxMiA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgc2NyYXRjaE9wdGlvbnMyMCA9IHsKICAgICAgICByZWN0YW5nbGU6IHNjcmF0Y2hSZWN0YW5nbGUyLAogICAgICAgIGVsbGlwc29pZDogc2NyYXRjaEVsbGlwc29pZDEyLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgcm90YXRpb246IHZvaWQgMCwKICAgICAgICBleHRydWRlZEhlaWdodDogdm9pZCAwLAogICAgICAgIG9mZnNldEF0dHJpYnV0ZTogdm9pZCAwCiAgICAgIH07CiAgICAgIFJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYXJyYXkpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiYXJyYXkgaXMgcmVxdWlyZWQiKTsKICAgICAgICB9CiAgICAgICAgc3RhcnRpbmdJbmRleCA9IHN0YXJ0aW5nSW5kZXggPz8gMDsKICAgICAgICBjb25zdCByZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hSZWN0YW5nbGUyKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFJlY3RhbmdsZV9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQxMik7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGhlaWdodCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3Qgcm90YXRpb24gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGV4dHJ1ZGVkSGVpZ2h0ID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBvZmZzZXRBdHRyaWJ1dGUgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczIwLmdyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczIwLmhlaWdodCA9IGhlaWdodDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjAucm90YXRpb24gPSByb3RhdGlvbjsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjAuZXh0cnVkZWRIZWlnaHQgPSBleHRydWRlZEhlaWdodDsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjAub2Zmc2V0QXR0cmlidXRlID0gb2Zmc2V0QXR0cmlidXRlID09PSAtMSA/IHZvaWQgMCA6IG9mZnNldEF0dHJpYnV0ZTsKICAgICAgICAgIHJldHVybiBuZXcgUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5KHNjcmF0Y2hPcHRpb25zMjApOwogICAgICAgIH0KICAgICAgICByZXN1bHQuX3JlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHJlY3RhbmdsZSwgcmVzdWx0Ll9yZWN0YW5nbGUpOwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkLCByZXN1bHQuX2VsbGlwc29pZCk7CiAgICAgICAgcmVzdWx0Ll9zdXJmYWNlSGVpZ2h0ID0gaGVpZ2h0OwogICAgICAgIHJlc3VsdC5fcm90YXRpb24gPSByb3RhdGlvbjsKICAgICAgICByZXN1bHQuX2V4dHJ1ZGVkSGVpZ2h0ID0gZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9vZmZzZXRBdHRyaWJ1dGUgPSBvZmZzZXRBdHRyaWJ1dGUgPT09IC0xID8gdm9pZCAwIDogb2Zmc2V0QXR0cmlidXRlOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIG53U2NyYXRjaDIgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24ocmVjdGFuZ2xlR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCByZWN0YW5nbGUgPSByZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICAgICAgY29uc3QgY29tcHV0ZWRPcHRpb25zID0gUmVjdGFuZ2xlR2VvbWV0cnlMaWJyYXJ5X2RlZmF1bHQuY29tcHV0ZU9wdGlvbnMoCiAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICByZWN0YW5nbGVHZW9tZXRyeS5fZ3JhbnVsYXJpdHksCiAgICAgICAgICByZWN0YW5nbGVHZW9tZXRyeS5fcm90YXRpb24sCiAgICAgICAgICAwLAogICAgICAgICAgcmVjdGFuZ2xlU2NyYXRjaDIsCiAgICAgICAgICBud1NjcmF0Y2gyCiAgICAgICAgKTsKICAgICAgICBsZXQgZ2VvbWV0cnk7CiAgICAgICAgbGV0IGJvdW5kaW5nU3BoZXJlOwogICAgICAgIGlmIChNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHJlY3RhbmdsZS5ub3J0aCwKICAgICAgICAgIHJlY3RhbmdsZS5zb3V0aCwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAKICAgICAgICApIHx8IE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKAogICAgICAgICAgcmVjdGFuZ2xlLmVhc3QsCiAgICAgICAgICByZWN0YW5nbGUud2VzdCwKICAgICAgICAgIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTAKICAgICAgICApKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBjb25zdCBzdXJmYWNlSGVpZ2h0ID0gcmVjdGFuZ2xlR2VvbWV0cnkuX3N1cmZhY2VIZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZWRIZWlnaHQgPSByZWN0YW5nbGVHZW9tZXRyeS5fZXh0cnVkZWRIZWlnaHQ7CiAgICAgICAgY29uc3QgZXh0cnVkZSA9ICFNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbigKICAgICAgICAgIHN1cmZhY2VIZWlnaHQsCiAgICAgICAgICBleHRydWRlZEhlaWdodCwKICAgICAgICAgIDAsCiAgICAgICAgICBNYXRoX2RlZmF1bHQuRVBTSUxPTjIKICAgICAgICApOwogICAgICAgIGxldCBvZmZzZXRWYWx1ZTsKICAgICAgICBpZiAoZXh0cnVkZSkgewogICAgICAgICAgZ2VvbWV0cnkgPSBjb25zdHJ1Y3RFeHRydWRlZFJlY3RhbmdsZTIocmVjdGFuZ2xlR2VvbWV0cnksIGNvbXB1dGVkT3B0aW9ucyk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlY3RhbmdsZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICAgIGNvbnN0IHNpemUgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcy5sZW5ndGggLyAzOwogICAgICAgICAgICBsZXQgb2Zmc2V0QXR0cmlidXRlID0gbmV3IFVpbnQ4QXJyYXkoc2l6ZSk7CiAgICAgICAgICAgIGlmIChyZWN0YW5nbGVHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0LlRPUCkgewogICAgICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKDEsIDAsIHNpemUgLyAyKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBvZmZzZXRWYWx1ZSA9IHJlY3RhbmdsZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUgPT09IEdlb21ldHJ5T2Zmc2V0QXR0cmlidXRlX2RlZmF1bHQuTk9ORSA/IDAgOiAxOwogICAgICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZSA9IG9mZnNldEF0dHJpYnV0ZS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLmFwcGx5T2Zmc2V0ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUsCiAgICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMSwKICAgICAgICAgICAgICB2YWx1ZXM6IG9mZnNldEF0dHJpYnV0ZQogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHRvcEJTID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlM0QoCiAgICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBzdXJmYWNlSGVpZ2h0LAogICAgICAgICAgICB0b3BCb3VuZGluZ1NwaGVyZTQKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBib3R0b21CUyA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVJlY3RhbmdsZTNEKAogICAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgZXh0cnVkZWRIZWlnaHQsCiAgICAgICAgICAgIGJvdHRvbUJvdW5kaW5nU3BoZXJlNAogICAgICAgICAgKTsKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC51bmlvbih0b3BCUywgYm90dG9tQlMpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBnZW9tZXRyeSA9IGNvbnN0cnVjdFJlY3RhbmdsZTIocmVjdGFuZ2xlR2VvbWV0cnksIGNvbXB1dGVkT3B0aW9ucyk7CiAgICAgICAgICBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlcyA9IFBvbHlnb25QaXBlbGluZV9kZWZhdWx0LnNjYWxlVG9HZW9kZXRpY0hlaWdodCgKICAgICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXMsCiAgICAgICAgICAgIHN1cmZhY2VIZWlnaHQsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgZmFsc2UKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlY3RhbmdsZUdlb21ldHJ5Ll9vZmZzZXRBdHRyaWJ1dGUpKSB7CiAgICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzLmxlbmd0aDsKICAgICAgICAgICAgb2Zmc2V0VmFsdWUgPSByZWN0YW5nbGVHZW9tZXRyeS5fb2Zmc2V0QXR0cmlidXRlID09PSBHZW9tZXRyeU9mZnNldEF0dHJpYnV0ZV9kZWZhdWx0Lk5PTkUgPyAwIDogMTsKICAgICAgICAgICAgY29uc3QgYXBwbHlPZmZzZXQgPSBuZXcgVWludDhBcnJheShsZW5ndGggLyAzKS5maWxsKG9mZnNldFZhbHVlKTsKICAgICAgICAgICAgZ2VvbWV0cnkuYXR0cmlidXRlcy5hcHBseU9mZnNldCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDEsCiAgICAgICAgICAgICAgdmFsdWVzOiBhcHBseU9mZnNldAogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGJvdW5kaW5nU3BoZXJlID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlM0QoCiAgICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBzdXJmYWNlSGVpZ2h0CiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlczogZ2VvbWV0cnkuYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXM6IGdlb21ldHJ5LmluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuTElORVMsCiAgICAgICAgICBib3VuZGluZ1NwaGVyZSwKICAgICAgICAgIG9mZnNldEF0dHJpYnV0ZTogcmVjdGFuZ2xlR2VvbWV0cnkuX29mZnNldEF0dHJpYnV0ZQogICAgICAgIH0pOwogICAgICB9OwogICAgICBSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeV9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZVJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeShyZWN0YW5nbGVHZW9tZXRyeSwgb2Zmc2V0KSB7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG9mZnNldCkpIHsKICAgICAgcmVjdGFuZ2xlR2VvbWV0cnkgPSBSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2soCiAgICAgICAgcmVjdGFuZ2xlR2VvbWV0cnksCiAgICAgICAgb2Zmc2V0CiAgICAgICk7CiAgICB9CiAgICByZWN0YW5nbGVHZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUocmVjdGFuZ2xlR2VvbWV0cnkuX2VsbGlwc29pZCk7CiAgICByZWN0YW5nbGVHZW9tZXRyeS5fcmVjdGFuZ2xlID0gUmVjdGFuZ2xlX2RlZmF1bHQuY2xvbmUocmVjdGFuZ2xlR2VvbWV0cnkuX3JlY3RhbmdsZSk7CiAgICByZXR1cm4gUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkocmVjdGFuZ2xlR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgaW5pdF9SZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBjcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9TaW1wbGVQb2x5bGluZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gaW50ZXJwb2xhdGVDb2xvcnMyKHAwLCBwMSwgY29sb3IwLCBjb2xvcjEsIG1pbkRpc3RhbmNlLCBhcnJheSwgb2Zmc2V0KSB7CiAgICBjb25zdCBudW1Qb2ludHMgPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQubnVtYmVyT2ZQb2ludHMocDAsIHAxLCBtaW5EaXN0YW5jZSk7CiAgICBsZXQgaTI7CiAgICBjb25zdCByMCA9IGNvbG9yMC5yZWQ7CiAgICBjb25zdCBnMCA9IGNvbG9yMC5ncmVlbjsKICAgIGNvbnN0IGIwID0gY29sb3IwLmJsdWU7CiAgICBjb25zdCBhMCA9IGNvbG9yMC5hbHBoYTsKICAgIGNvbnN0IHIxID0gY29sb3IxLnJlZDsKICAgIGNvbnN0IGcxID0gY29sb3IxLmdyZWVuOwogICAgY29uc3QgYjEgPSBjb2xvcjEuYmx1ZTsKICAgIGNvbnN0IGExID0gY29sb3IxLmFscGhhOwogICAgaWYgKENvbG9yX2RlZmF1bHQuZXF1YWxzKGNvbG9yMCwgY29sb3IxKSkgewogICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1Qb2ludHM7IGkyKyspIHsKICAgICAgICBhcnJheVtvZmZzZXQrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKHIwKTsKICAgICAgICBhcnJheVtvZmZzZXQrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGcwKTsKICAgICAgICBhcnJheVtvZmZzZXQrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGIwKTsKICAgICAgICBhcnJheVtvZmZzZXQrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGEwKTsKICAgICAgfQogICAgICByZXR1cm4gb2Zmc2V0OwogICAgfQogICAgY29uc3QgcmVkUGVyVmVydGV4ID0gKHIxIC0gcjApIC8gbnVtUG9pbnRzOwogICAgY29uc3QgZ3JlZW5QZXJWZXJ0ZXggPSAoZzEgLSBnMCkgLyBudW1Qb2ludHM7CiAgICBjb25zdCBibHVlUGVyVmVydGV4ID0gKGIxIC0gYjApIC8gbnVtUG9pbnRzOwogICAgY29uc3QgYWxwaGFQZXJWZXJ0ZXggPSAoYTEgLSBhMCkgLyBudW1Qb2ludHM7CiAgICBsZXQgaW5kZXggPSBvZmZzZXQ7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1Qb2ludHM7IGkyKyspIHsKICAgICAgYXJyYXlbaW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKHIwICsgaTIgKiByZWRQZXJWZXJ0ZXgpOwogICAgICBhcnJheVtpbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoZzAgKyBpMiAqIGdyZWVuUGVyVmVydGV4KTsKICAgICAgYXJyYXlbaW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGIwICsgaTIgKiBibHVlUGVyVmVydGV4KTsKICAgICAgYXJyYXlbaW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGEwICsgaTIgKiBhbHBoYVBlclZlcnRleCk7CiAgICB9CiAgICByZXR1cm4gaW5kZXg7CiAgfQogIGZ1bmN0aW9uIFNpbXBsZVBvbHlsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICBjb25zdCBjb2xvcnMgPSBvcHRpb25zLmNvbG9yczsKICAgIGNvbnN0IGNvbG9yc1BlclZlcnRleCA9IG9wdGlvbnMuY29sb3JzUGVyVmVydGV4ID8/IGZhbHNlOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSB8fCBwb3NpdGlvbnMubGVuZ3RoIDwgMikgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiQXQgbGVhc3QgdHdvIHBvc2l0aW9ucyBhcmUgcmVxdWlyZWQuIik7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykgJiYgKGNvbG9yc1BlclZlcnRleCAmJiBjb2xvcnMubGVuZ3RoIDwgcG9zaXRpb25zLmxlbmd0aCB8fCAhY29sb3JzUGVyVmVydGV4ICYmIGNvbG9ycy5sZW5ndGggPCBwb3NpdGlvbnMubGVuZ3RoIC0gMSkpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImNvbG9ycyBoYXMgYW4gaW52YWxpZCBsZW5ndGguIik7CiAgICB9CiAgICB0aGlzLl9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICB0aGlzLl9jb2xvcnMgPSBjb2xvcnM7CiAgICB0aGlzLl9jb2xvcnNQZXJWZXJ0ZXggPSBjb2xvcnNQZXJWZXJ0ZXg7CiAgICB0aGlzLl9hcmNUeXBlID0gb3B0aW9ucy5hcmNUeXBlID8/IEFyY1R5cGVfZGVmYXVsdC5HRU9ERVNJQzsKICAgIHRoaXMuX2dyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgdGhpcy5fZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeSI7CiAgICBsZXQgbnVtQ29tcG9uZW50cyA9IDEgKyBwb3NpdGlvbnMubGVuZ3RoICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIG51bUNvbXBvbmVudHMgKz0gZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykgPyAxICsgY29sb3JzLmxlbmd0aCAqIENvbG9yX2RlZmF1bHQucGFja2VkTGVuZ3RoIDogMTsKICAgIHRoaXMucGFja2VkTGVuZ3RoID0gbnVtQ29tcG9uZW50cyArIEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDM7CiAgfQogIHZhciBzY3JhdGNoQXJyYXkxLCBzY3JhdGNoQXJyYXkyLCBnZW5lcmF0ZUFyY09wdGlvbnNTY3JhdGNoLCBTaW1wbGVQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfU2ltcGxlUG9seWxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvU2ltcGxlUG9seWxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQXJjVHlwZSgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NvbG9yKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9HZW9tZXRyeSgpOwogICAgICBpbml0X0dlb21ldHJ5QXR0cmlidXRlKCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGVzKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9Qb2x5bGluZVBpcGVsaW5lKCk7CiAgICAgIGluaXRfUHJpbWl0aXZlVHlwZSgpOwogICAgICBTaW1wbGVQb2x5bGluZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2YWx1ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ2YWx1ZSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB2YWx1ZS5fcG9zaXRpb25zOwogICAgICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHBvc2l0aW9uc1tpMl0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY29sb3JzID0gdmFsdWUuX2NvbG9yczsKICAgICAgICBsZW5ndGggPSBkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSA/IGNvbG9ycy5sZW5ndGggOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENvbG9yX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBDb2xvcl9kZWZhdWx0LnBhY2soY29sb3JzW2kyXSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gdmFsdWUuX2NvbG9yc1BlclZlcnRleCA/IDEgOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSB2YWx1ZS5fYXJjVHlwZTsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIFNpbXBsZVBvbHlsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGFycmF5KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoImFycmF5IGlzIHJlcXVpcmVkIik7CiAgICAgICAgfQogICAgICAgIHN0YXJ0aW5nSW5kZXggPSBzdGFydGluZ0luZGV4ID8/IDA7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGxldCBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoKSB7CiAgICAgICAgICBwb3NpdGlvbnNbaTJdID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhhcnJheSwgc3RhcnRpbmdJbmRleCk7CiAgICAgICAgfQogICAgICAgIGxlbmd0aCA9IGFycmF5W3N0YXJ0aW5nSW5kZXgrK107CiAgICAgICAgY29uc3QgY29sb3JzID0gbGVuZ3RoID4gMCA/IG5ldyBBcnJheShsZW5ndGgpIDogdm9pZCAwOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMiwgc3RhcnRpbmdJbmRleCArPSBDb2xvcl9kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgY29sb3JzW2kyXSA9IENvbG9yX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQudW5wYWNrKGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBjb2xvcnNQZXJWZXJ0ZXggPSBhcnJheVtzdGFydGluZ0luZGV4KytdID09PSAxOwogICAgICAgIGNvbnN0IGFyY1R5cGUgPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gYXJyYXlbc3RhcnRpbmdJbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmV0dXJuIG5ldyBTaW1wbGVQb2x5bGluZUdlb21ldHJ5KHsKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICBjb2xvcnMsCiAgICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgICAgY29sb3JzUGVyVmVydGV4LAogICAgICAgICAgICBhcmNUeXBlLAogICAgICAgICAgICBncmFudWxhcml0eQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgIHJlc3VsdC5fY29sb3JzID0gY29sb3JzOwogICAgICAgIHJlc3VsdC5fZWxsaXBzb2lkID0gZWxsaXBzb2lkOwogICAgICAgIHJlc3VsdC5fY29sb3JzUGVyVmVydGV4ID0gY29sb3JzUGVyVmVydGV4OwogICAgICAgIHJlc3VsdC5fYXJjVHlwZSA9IGFyY1R5cGU7CiAgICAgICAgcmVzdWx0Ll9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hBcnJheTEgPSBuZXcgQXJyYXkoMik7CiAgICAgIHNjcmF0Y2hBcnJheTIgPSBuZXcgQXJyYXkoMik7CiAgICAgIGdlbmVyYXRlQXJjT3B0aW9uc1NjcmF0Y2ggPSB7CiAgICAgICAgcG9zaXRpb25zOiBzY3JhdGNoQXJyYXkxLAogICAgICAgIGhlaWdodDogc2NyYXRjaEFycmF5MiwKICAgICAgICBlbGxpcHNvaWQ6IHZvaWQgMCwKICAgICAgICBtaW5EaXN0YW5jZTogdm9pZCAwLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAKICAgICAgfTsKICAgICAgU2ltcGxlUG9seWxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKHNpbXBsZVBvbHlsaW5lR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBzaW1wbGVQb2x5bGluZUdlb21ldHJ5Ll9wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgY29sb3JzID0gc2ltcGxlUG9seWxpbmVHZW9tZXRyeS5fY29sb3JzOwogICAgICAgIGNvbnN0IGNvbG9yc1BlclZlcnRleCA9IHNpbXBsZVBvbHlsaW5lR2VvbWV0cnkuX2NvbG9yc1BlclZlcnRleDsKICAgICAgICBjb25zdCBhcmNUeXBlID0gc2ltcGxlUG9seWxpbmVHZW9tZXRyeS5fYXJjVHlwZTsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IHNpbXBsZVBvbHlsaW5lR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHNpbXBsZVBvbHlsaW5lR2VvbWV0cnkuX2VsbGlwc29pZDsKICAgICAgICBjb25zdCBtaW5EaXN0YW5jZSA9IE1hdGhfZGVmYXVsdC5jaG9yZExlbmd0aCgKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZWxsaXBzb2lkLm1heGltdW1SYWRpdXMKICAgICAgICApOwogICAgICAgIGNvbnN0IHBlclNlZ21lbnRDb2xvcnMgPSBkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSAmJiAhY29sb3JzUGVyVmVydGV4OwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGxldCBwb3NpdGlvblZhbHVlczsKICAgICAgICBsZXQgbnVtYmVyT2ZQb3NpdGlvbnM7CiAgICAgICAgbGV0IGNvbG9yVmFsdWVzOwogICAgICAgIGxldCBjb2xvcjsKICAgICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDIHx8IGFyY1R5cGUgPT09IEFyY1R5cGVfZGVmYXVsdC5SSFVNQikgewogICAgICAgICAgbGV0IHN1YmRpdmlzaW9uU2l6ZTsKICAgICAgICAgIGxldCBudW1iZXJPZlBvaW50c0Z1bmN0aW9uOwogICAgICAgICAgbGV0IGdlbmVyYXRlQXJjRnVuY3Rpb247CiAgICAgICAgICBpZiAoYXJjVHlwZSA9PT0gQXJjVHlwZV9kZWZhdWx0LkdFT0RFU0lDKSB7CiAgICAgICAgICAgIHN1YmRpdmlzaW9uU2l6ZSA9IE1hdGhfZGVmYXVsdC5jaG9yZExlbmd0aCgKICAgICAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgICAgICBlbGxpcHNvaWQubWF4aW11bVJhZGl1cwogICAgICAgICAgICApOwogICAgICAgICAgICBudW1iZXJPZlBvaW50c0Z1bmN0aW9uID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0Lm51bWJlck9mUG9pbnRzOwogICAgICAgICAgICBnZW5lcmF0ZUFyY0Z1bmN0aW9uID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgc3ViZGl2aXNpb25TaXplID0gZ3JhbnVsYXJpdHk7CiAgICAgICAgICAgIG51bWJlck9mUG9pbnRzRnVuY3Rpb24gPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQubnVtYmVyT2ZQb2ludHNSaHVtYkxpbmU7CiAgICAgICAgICAgIGdlbmVyYXRlQXJjRnVuY3Rpb24gPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQuZ2VuZXJhdGVSaHVtYkFyYzsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGhlaWdodHMgPSBQb2x5bGluZVBpcGVsaW5lX2RlZmF1bHQuZXh0cmFjdEhlaWdodHMocG9zaXRpb25zLCBlbGxpcHNvaWQpOwogICAgICAgICAgY29uc3QgZ2VuZXJhdGVBcmNPcHRpb25zID0gZ2VuZXJhdGVBcmNPcHRpb25zU2NyYXRjaDsKICAgICAgICAgIGlmIChhcmNUeXBlID09PSBBcmNUeXBlX2RlZmF1bHQuR0VPREVTSUMpIHsKICAgICAgICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zLm1pbkRpc3RhbmNlID0gbWluRGlzdGFuY2U7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnZW5lcmF0ZUFyY09wdGlvbnMuZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICAgIH0KICAgICAgICAgIGdlbmVyYXRlQXJjT3B0aW9ucy5lbGxpcHNvaWQgPSBlbGxpcHNvaWQ7CiAgICAgICAgICBpZiAocGVyU2VnbWVudENvbG9ycykgewogICAgICAgICAgICBsZXQgcG9zaXRpb25Db3VudCA9IDA7CiAgICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgICAgICAgICBwb3NpdGlvbkNvdW50ICs9IG51bWJlck9mUG9pbnRzRnVuY3Rpb24oCiAgICAgICAgICAgICAgICBwb3NpdGlvbnNbaTJdLAogICAgICAgICAgICAgICAgcG9zaXRpb25zW2kyICsgMV0sCiAgICAgICAgICAgICAgICBzdWJkaXZpc2lvblNpemUKICAgICAgICAgICAgICApICsgMTsKICAgICAgICAgICAgfQogICAgICAgICAgICBwb3NpdGlvblZhbHVlcyA9IG5ldyBGbG9hdDY0QXJyYXkocG9zaXRpb25Db3VudCAqIDMpOwogICAgICAgICAgICBjb2xvclZhbHVlcyA9IG5ldyBVaW50OEFycmF5KHBvc2l0aW9uQ291bnQgKiA0KTsKICAgICAgICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zLnBvc2l0aW9ucyA9IHNjcmF0Y2hBcnJheTE7CiAgICAgICAgICAgIGdlbmVyYXRlQXJjT3B0aW9ucy5oZWlnaHQgPSBzY3JhdGNoQXJyYXkyOwogICAgICAgICAgICBsZXQgY2kgPSAwOwogICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGggLSAxOyArK2kyKSB7CiAgICAgICAgICAgICAgc2NyYXRjaEFycmF5MVswXSA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICAgICAgc2NyYXRjaEFycmF5MVsxXSA9IHBvc2l0aW9uc1tpMiArIDFdOwogICAgICAgICAgICAgIHNjcmF0Y2hBcnJheTJbMF0gPSBoZWlnaHRzW2kyXTsKICAgICAgICAgICAgICBzY3JhdGNoQXJyYXkyWzFdID0gaGVpZ2h0c1tpMiArIDFdOwogICAgICAgICAgICAgIGNvbnN0IHBvcyA9IGdlbmVyYXRlQXJjRnVuY3Rpb24oZ2VuZXJhdGVBcmNPcHRpb25zKTsKICAgICAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHNlZ0xlbiA9IHBvcy5sZW5ndGggLyAzOwogICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcnNbaTJdOwogICAgICAgICAgICAgICAgZm9yIChsZXQgazIgPSAwOyBrMiA8IHNlZ0xlbjsgKytrMikgewogICAgICAgICAgICAgICAgICBjb2xvclZhbHVlc1tjaSsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IucmVkKTsKICAgICAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbY2krK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmdyZWVuKTsKICAgICAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbY2krK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmJsdWUpOwogICAgICAgICAgICAgICAgICBjb2xvclZhbHVlc1tjaSsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IuYWxwaGEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBwb3NpdGlvblZhbHVlcy5zZXQocG9zLCBvZmZzZXQpOwogICAgICAgICAgICAgIG9mZnNldCArPSBwb3MubGVuZ3RoOwogICAgICAgICAgICB9CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBnZW5lcmF0ZUFyY09wdGlvbnMucG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgICAgICBnZW5lcmF0ZUFyY09wdGlvbnMuaGVpZ2h0ID0gaGVpZ2h0czsKICAgICAgICAgICAgcG9zaXRpb25WYWx1ZXMgPSBuZXcgRmxvYXQ2NEFycmF5KAogICAgICAgICAgICAgIGdlbmVyYXRlQXJjRnVuY3Rpb24oZ2VuZXJhdGVBcmNPcHRpb25zKQogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykpIHsKICAgICAgICAgICAgICBjb2xvclZhbHVlcyA9IG5ldyBVaW50OEFycmF5KHBvc2l0aW9uVmFsdWVzLmxlbmd0aCAvIDMgKiA0KTsKICAgICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGggLSAxOyArK2kyKSB7CiAgICAgICAgICAgICAgICBjb25zdCBwMCA9IHBvc2l0aW9uc1tpMl07CiAgICAgICAgICAgICAgICBjb25zdCBwMSA9IHBvc2l0aW9uc1tpMiArIDFdOwogICAgICAgICAgICAgICAgY29uc3QgYzAgPSBjb2xvcnNbaTJdOwogICAgICAgICAgICAgICAgY29uc3QgYzEgPSBjb2xvcnNbaTIgKyAxXTsKICAgICAgICAgICAgICAgIG9mZnNldCA9IGludGVycG9sYXRlQ29sb3JzMigKICAgICAgICAgICAgICAgICAgcDAsCiAgICAgICAgICAgICAgICAgIHAxLAogICAgICAgICAgICAgICAgICBjMCwKICAgICAgICAgICAgICAgICAgYzEsCiAgICAgICAgICAgICAgICAgIG1pbkRpc3RhbmNlLAogICAgICAgICAgICAgICAgICBjb2xvclZhbHVlcywKICAgICAgICAgICAgICAgICAgb2Zmc2V0CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBjb25zdCBsYXN0Q29sb3IgPSBjb2xvcnNbbGVuZ3RoIC0gMV07CiAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbb2Zmc2V0KytdID0gQ29sb3JfZGVmYXVsdC5mbG9hdFRvQnl0ZShsYXN0Q29sb3IucmVkKTsKICAgICAgICAgICAgICBjb2xvclZhbHVlc1tvZmZzZXQrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGxhc3RDb2xvci5ncmVlbik7CiAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbb2Zmc2V0KytdID0gQ29sb3JfZGVmYXVsdC5mbG9hdFRvQnl0ZShsYXN0Q29sb3IuYmx1ZSk7CiAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbb2Zmc2V0XSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUobGFzdENvbG9yLmFscGhhKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBudW1iZXJPZlBvc2l0aW9ucyA9IHBlclNlZ21lbnRDb2xvcnMgPyBsZW5ndGggKiAyIC0gMiA6IGxlbmd0aDsKICAgICAgICAgIHBvc2l0aW9uVmFsdWVzID0gbmV3IEZsb2F0NjRBcnJheShudW1iZXJPZlBvc2l0aW9ucyAqIDMpOwogICAgICAgICAgY29sb3JWYWx1ZXMgPSBkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSA/IG5ldyBVaW50OEFycmF5KG51bWJlck9mUG9zaXRpb25zICogNCkgOiB2b2lkIDA7CiAgICAgICAgICBsZXQgcG9zaXRpb25JbmRleCA9IDA7CiAgICAgICAgICBsZXQgY29sb3JJbmRleCA9IDA7CiAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgY29uc3QgcDIgPSBwb3NpdGlvbnNbaTJdOwogICAgICAgICAgICBpZiAocGVyU2VnbWVudENvbG9ycyAmJiBpMiA+IDApIHsKICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhwMiwgcG9zaXRpb25WYWx1ZXMsIHBvc2l0aW9uSW5kZXgpOwogICAgICAgICAgICAgIHBvc2l0aW9uSW5kZXggKz0gMzsKICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yc1tpMiAtIDFdOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLnJlZCk7CiAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbY29sb3JJbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IuZ3JlZW4pOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmJsdWUpOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmFscGhhKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAocGVyU2VnbWVudENvbG9ycyAmJiBpMiA9PT0gbGVuZ3RoIC0gMSkgewogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHAyLCBwb3NpdGlvblZhbHVlcywgcG9zaXRpb25JbmRleCk7CiAgICAgICAgICAgIHBvc2l0aW9uSW5kZXggKz0gMzsKICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjb2xvcnMpKSB7CiAgICAgICAgICAgICAgY29sb3IgPSBjb2xvcnNbaTJdOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLnJlZCk7CiAgICAgICAgICAgICAgY29sb3JWYWx1ZXNbY29sb3JJbmRleCsrXSA9IENvbG9yX2RlZmF1bHQuZmxvYXRUb0J5dGUoY29sb3IuZ3JlZW4pOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmJsdWUpOwogICAgICAgICAgICAgIGNvbG9yVmFsdWVzW2NvbG9ySW5kZXgrK10gPSBDb2xvcl9kZWZhdWx0LmZsb2F0VG9CeXRlKGNvbG9yLmFscGhhKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVzID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlc19kZWZhdWx0KCk7CiAgICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbiA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkRPVUJMRSwKICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9uVmFsdWVzCiAgICAgICAgfSk7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChjb2xvcnMpKSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLmNvbG9yID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9CWVRFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiA0LAogICAgICAgICAgICB2YWx1ZXM6IGNvbG9yVmFsdWVzLAogICAgICAgICAgICBub3JtYWxpemU6IHRydWUKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBudW1iZXJPZlBvc2l0aW9ucyA9IHBvc2l0aW9uVmFsdWVzLmxlbmd0aCAvIDM7CiAgICAgICAgY29uc3QgbnVtYmVyT2ZJbmRpY2VzID0gKG51bWJlck9mUG9zaXRpb25zIC0gMSkgKiAyOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgIG51bWJlck9mUG9zaXRpb25zLAogICAgICAgICAgbnVtYmVyT2ZJbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBsZXQgaW5kZXggPSAwOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IG51bWJlck9mUG9zaXRpb25zIC0gMTsgKytpMikgewogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyOwogICAgICAgICAgaW5kaWNlc1tpbmRleCsrXSA9IGkyICsgMTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5ldyBHZW9tZXRyeV9kZWZhdWx0KHsKICAgICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0aXZlVHlwZV9kZWZhdWx0LkxJTkVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVBvaW50cyhwb3NpdGlvbnMpCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFNpbXBsZVBvbHlsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFNpbXBsZVBvbHlsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVTaW1wbGVQb2x5bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZVNpbXBsZVBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVNpbXBsZVBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeShzaW1wbGVQb2x5bGluZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBzaW1wbGVQb2x5bGluZUdlb21ldHJ5ID0gU2ltcGxlUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0LnVucGFjaygKICAgICAgICBzaW1wbGVQb2x5bGluZUdlb21ldHJ5LAogICAgICAgIG9mZnNldAogICAgICApOwogICAgfQogICAgc2ltcGxlUG9seWxpbmVHZW9tZXRyeS5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoCiAgICAgIHNpbXBsZVBvbHlsaW5lR2VvbWV0cnkuX2VsbGlwc29pZAogICAgKTsKICAgIHJldHVybiBTaW1wbGVQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoc2ltcGxlUG9seWxpbmVHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVTaW1wbGVQb2x5bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X1NpbXBsZVBvbHlsaW5lR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1NwaGVyZUdlb21ldHJ5LmpzCiAgZnVuY3Rpb24gU3BoZXJlR2VvbWV0cnkob3B0aW9ucykgewogICAgY29uc3QgcmFkaXVzID0gb3B0aW9ucy5yYWRpdXMgPz8gMTsKICAgIGNvbnN0IHJhZGlpID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdChyYWRpdXMsIHJhZGl1cywgcmFkaXVzKTsKICAgIGNvbnN0IGVsbGlwc29pZE9wdGlvbnMgPSB7CiAgICAgIHJhZGlpLAogICAgICBzdGFja1BhcnRpdGlvbnM6IG9wdGlvbnMuc3RhY2tQYXJ0aXRpb25zLAogICAgICBzbGljZVBhcnRpdGlvbnM6IG9wdGlvbnMuc2xpY2VQYXJ0aXRpb25zLAogICAgICB2ZXJ0ZXhGb3JtYXQ6IG9wdGlvbnMudmVydGV4Rm9ybWF0CiAgICB9OwogICAgdGhpcy5fZWxsaXBzb2lkR2VvbWV0cnkgPSBuZXcgRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdChlbGxpcHNvaWRPcHRpb25zKTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlU3BoZXJlR2VvbWV0cnkiOwogIH0KICB2YXIgc2NyYXRjaEVsbGlwc29pZEdlb21ldHJ5LCBzY3JhdGNoT3B0aW9uczIxLCBTcGhlcmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X1NwaGVyZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9TcGhlcmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZEdlb21ldHJ5KCk7CiAgICAgIGluaXRfVmVydGV4Rm9ybWF0KCk7CiAgICAgIFNwaGVyZUdlb21ldHJ5LnBhY2tlZExlbmd0aCA9IEVsbGlwc29pZEdlb21ldHJ5X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICBTcGhlcmVHZW9tZXRyeS5wYWNrID0gZnVuY3Rpb24odmFsdWUsIGFycmF5LCBzdGFydGluZ0luZGV4KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ2YWx1ZSIsIHZhbHVlKTsKICAgICAgICByZXR1cm4gRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWRHZW9tZXRyeSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICB9OwogICAgICBzY3JhdGNoRWxsaXBzb2lkR2VvbWV0cnkgPSBuZXcgRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoT3B0aW9uczIxID0gewogICAgICAgIHJhZGl1czogdm9pZCAwLAogICAgICAgIHJhZGlpOiBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgdmVydGV4Rm9ybWF0OiBuZXcgVmVydGV4Rm9ybWF0X2RlZmF1bHQoKSwKICAgICAgICBzdGFja1BhcnRpdGlvbnM6IHZvaWQgMCwKICAgICAgICBzbGljZVBhcnRpdGlvbnM6IHZvaWQgMAogICAgICB9OwogICAgICBTcGhlcmVHZW9tZXRyeS51bnBhY2sgPSBmdW5jdGlvbihhcnJheSwgc3RhcnRpbmdJbmRleCwgcmVzdWx0KSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkR2VvbWV0cnkgPSBFbGxpcHNvaWRHZW9tZXRyeV9kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGFycmF5LAogICAgICAgICAgc3RhcnRpbmdJbmRleCwKICAgICAgICAgIHNjcmF0Y2hFbGxpcHNvaWRHZW9tZXRyeQogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnMyMS52ZXJ0ZXhGb3JtYXQgPSBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5jbG9uZSgKICAgICAgICAgIGVsbGlwc29pZEdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQsCiAgICAgICAgICBzY3JhdGNoT3B0aW9uczIxLnZlcnRleEZvcm1hdAogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnMyMS5zdGFja1BhcnRpdGlvbnMgPSBlbGxpcHNvaWRHZW9tZXRyeS5fc3RhY2tQYXJ0aXRpb25zOwogICAgICAgIHNjcmF0Y2hPcHRpb25zMjEuc2xpY2VQYXJ0aXRpb25zID0gZWxsaXBzb2lkR2VvbWV0cnkuX3NsaWNlUGFydGl0aW9uczsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczIxLnJhZGl1cyA9IGVsbGlwc29pZEdlb21ldHJ5Ll9yYWRpaS54OwogICAgICAgICAgcmV0dXJuIG5ldyBTcGhlcmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczIxKTsKICAgICAgICB9CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVsbGlwc29pZEdlb21ldHJ5Ll9yYWRpaSwgc2NyYXRjaE9wdGlvbnMyMS5yYWRpaSk7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNvaWRHZW9tZXRyeSA9IG5ldyBFbGxpcHNvaWRHZW9tZXRyeV9kZWZhdWx0KHNjcmF0Y2hPcHRpb25zMjEpOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFNwaGVyZUdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24oc3BoZXJlR2VvbWV0cnkpIHsKICAgICAgICByZXR1cm4gRWxsaXBzb2lkR2VvbWV0cnlfZGVmYXVsdC5jcmVhdGVHZW9tZXRyeShzcGhlcmVHZW9tZXRyeS5fZWxsaXBzb2lkR2VvbWV0cnkpOwogICAgICB9OwogICAgICBTcGhlcmVHZW9tZXRyeV9kZWZhdWx0ID0gU3BoZXJlR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVTcGhlcmVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVTcGhlcmVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlU3BoZXJlR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlU3BoZXJlR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGNyZWF0ZVNwaGVyZUdlb21ldHJ5KHNwaGVyZUdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICBzcGhlcmVHZW9tZXRyeSA9IFNwaGVyZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKHNwaGVyZUdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcmV0dXJuIFNwaGVyZUdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkoc3BoZXJlR2VvbWV0cnkpOwogIH0KICB2YXIgY3JlYXRlU3BoZXJlR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVTcGhlcmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlU3BoZXJlR2VvbWV0cnkuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9TcGhlcmVHZW9tZXRyeSgpOwogICAgICBjcmVhdGVTcGhlcmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlU3BoZXJlR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9TcGhlcmVPdXRsaW5lR2VvbWV0cnkuanMKICBmdW5jdGlvbiBTcGhlcmVPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgY29uc3QgcmFkaXVzID0gb3B0aW9ucy5yYWRpdXMgPz8gMTsKICAgIGNvbnN0IHJhZGlpID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdChyYWRpdXMsIHJhZGl1cywgcmFkaXVzKTsKICAgIGNvbnN0IGVsbGlwc29pZE9wdGlvbnMgPSB7CiAgICAgIHJhZGlpLAogICAgICBzdGFja1BhcnRpdGlvbnM6IG9wdGlvbnMuc3RhY2tQYXJ0aXRpb25zLAogICAgICBzbGljZVBhcnRpdGlvbnM6IG9wdGlvbnMuc2xpY2VQYXJ0aXRpb25zLAogICAgICBzdWJkaXZpc2lvbnM6IG9wdGlvbnMuc3ViZGl2aXNpb25zCiAgICB9OwogICAgdGhpcy5fZWxsaXBzb2lkR2VvbWV0cnkgPSBuZXcgRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQoZWxsaXBzb2lkT3B0aW9ucyk7CiAgICB0aGlzLl93b3JrZXJOYW1lID0gImNyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeSI7CiAgfQogIHZhciBzY3JhdGNoRWxsaXBzb2lkR2VvbWV0cnkyLCBzY3JhdGNoT3B0aW9uczIyLCBTcGhlcmVPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9TcGhlcmVPdXRsaW5lR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1NwaGVyZU91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZE91dGxpbmVHZW9tZXRyeSgpOwogICAgICBTcGhlcmVPdXRsaW5lR2VvbWV0cnkucGFja2VkTGVuZ3RoID0gRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICBTcGhlcmVPdXRsaW5lR2VvbWV0cnkucGFjayA9IGZ1bmN0aW9uKHZhbHVlLCBhcnJheSwgc3RhcnRpbmdJbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmFsdWUiLCB2YWx1ZSk7CiAgICAgICAgcmV0dXJuIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LnBhY2soCiAgICAgICAgICB2YWx1ZS5fZWxsaXBzb2lkR2VvbWV0cnksCiAgICAgICAgICBhcnJheSwKICAgICAgICAgIHN0YXJ0aW5nSW5kZXgKICAgICAgICApOwogICAgICB9OwogICAgICBzY3JhdGNoRWxsaXBzb2lkR2VvbWV0cnkyID0gbmV3IEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hPcHRpb25zMjIgPSB7CiAgICAgICAgcmFkaXVzOiB2b2lkIDAsCiAgICAgICAgcmFkaWk6IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBzdGFja1BhcnRpdGlvbnM6IHZvaWQgMCwKICAgICAgICBzbGljZVBhcnRpdGlvbnM6IHZvaWQgMCwKICAgICAgICBzdWJkaXZpc2lvbnM6IHZvaWQgMAogICAgICB9OwogICAgICBTcGhlcmVPdXRsaW5lR2VvbWV0cnkudW5wYWNrID0gZnVuY3Rpb24oYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHJlc3VsdCkgewogICAgICAgIGNvbnN0IGVsbGlwc29pZEdlb21ldHJ5ID0gRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaEVsbGlwc29pZEdlb21ldHJ5MgogICAgICAgICk7CiAgICAgICAgc2NyYXRjaE9wdGlvbnMyMi5zdGFja1BhcnRpdGlvbnMgPSBlbGxpcHNvaWRHZW9tZXRyeS5fc3RhY2tQYXJ0aXRpb25zOwogICAgICAgIHNjcmF0Y2hPcHRpb25zMjIuc2xpY2VQYXJ0aXRpb25zID0gZWxsaXBzb2lkR2VvbWV0cnkuX3NsaWNlUGFydGl0aW9uczsKICAgICAgICBzY3JhdGNoT3B0aW9uczIyLnN1YmRpdmlzaW9ucyA9IGVsbGlwc29pZEdlb21ldHJ5Ll9zdWJkaXZpc2lvbnM7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgc2NyYXRjaE9wdGlvbnMyMi5yYWRpdXMgPSBlbGxpcHNvaWRHZW9tZXRyeS5fcmFkaWkueDsKICAgICAgICAgIHJldHVybiBuZXcgU3BoZXJlT3V0bGluZUdlb21ldHJ5KHNjcmF0Y2hPcHRpb25zMjIpOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkR2VvbWV0cnkuX3JhZGlpLCBzY3JhdGNoT3B0aW9uczIyLnJhZGlpKTsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZEdlb21ldHJ5ID0gbmV3IEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0KHNjcmF0Y2hPcHRpb25zMjIpOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFNwaGVyZU91dGxpbmVHZW9tZXRyeS5jcmVhdGVHZW9tZXRyeSA9IGZ1bmN0aW9uKHNwaGVyZUdlb21ldHJ5KSB7CiAgICAgICAgcmV0dXJuIEVsbGlwc29pZE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KAogICAgICAgICAgc3BoZXJlR2VvbWV0cnkuX2VsbGlwc29pZEdlb21ldHJ5CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgU3BoZXJlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQgPSBTcGhlcmVPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlU3BoZXJlT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlU3BoZXJlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnkoc3BoZXJlR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIHNwaGVyZUdlb21ldHJ5ID0gU3BoZXJlT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQudW5wYWNrKHNwaGVyZUdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgcmV0dXJuIFNwaGVyZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHNwaGVyZUdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlU3BoZXJlT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfU3BoZXJlT3V0bGluZUdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlU3BoZXJlT3V0bGluZUdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXMuanMKICB2YXIgY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXNfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBkZWNvZGVQb3NpdGlvbnModUJ1ZmZlciwgdkJ1ZmZlciwgaGVpZ2h0QnVmZmVyLCByZWN0YW5nbGUsIG1pbmltdW1IZWlnaHQsIG1heGltdW1IZWlnaHQsIGVsbGlwc29pZCkgewogICAgY29uc3QgcG9zaXRpb25zTGVuZ3RoID0gdUJ1ZmZlci5sZW5ndGg7CiAgICBjb25zdCBkZWNvZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShwb3NpdGlvbnNMZW5ndGggKiAzKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7ICsraTIpIHsKICAgICAgY29uc3QgdTQgPSB1QnVmZmVyW2kyXTsKICAgICAgY29uc3QgdjQgPSB2QnVmZmVyW2kyXTsKICAgICAgY29uc3QgaDIgPSBoZWlnaHRCdWZmZXJbaTJdOwogICAgICBjb25zdCBsb24gPSBNYXRoX2RlZmF1bHQubGVycChyZWN0YW5nbGUud2VzdCwgcmVjdGFuZ2xlLmVhc3QsIHU0IC8gTUFYX1NIT1JUKTsKICAgICAgY29uc3QgbGF0ID0gTWF0aF9kZWZhdWx0LmxlcnAoCiAgICAgICAgcmVjdGFuZ2xlLnNvdXRoLAogICAgICAgIHJlY3RhbmdsZS5ub3J0aCwKICAgICAgICB2NCAvIE1BWF9TSE9SVAogICAgICApOwogICAgICBjb25zdCBhbHQgPSBNYXRoX2RlZmF1bHQubGVycChtaW5pbXVtSGVpZ2h0LCBtYXhpbXVtSGVpZ2h0LCBoMiAvIE1BWF9TSE9SVCk7CiAgICAgIGNvbnN0IGNhcnRvZ3JhcGhpYzIgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICBsb24sCiAgICAgICAgbGF0LAogICAgICAgIGFsdCwKICAgICAgICBzY3JhdGNoQlZDYXJ0b2dyYXBoaWMKICAgICAgKTsKICAgICAgY29uc3QgZGVjb2RlZFBvc2l0aW9uID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgIGNhcnRvZ3JhcGhpYzIsCiAgICAgICAgc2NyYXRjaEVuY29kZWRQb3NpdGlvbgogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhkZWNvZGVkUG9zaXRpb24sIGRlY29kZWRQb3NpdGlvbnMsIGkyICogMyk7CiAgICB9CiAgICByZXR1cm4gZGVjb2RlZFBvc2l0aW9uczsKICB9CiAgZnVuY3Rpb24gZ2V0UG9zaXRpb25PZmZzZXRzKGNvdW50cykgewogICAgY29uc3QgY291bnRzTGVuZ3RoID0gY291bnRzLmxlbmd0aDsKICAgIGNvbnN0IHBvc2l0aW9uT2Zmc2V0cyA9IG5ldyBVaW50MzJBcnJheShjb3VudHNMZW5ndGggKyAxKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGNvdW50c0xlbmd0aDsgKytpMikgewogICAgICBwb3NpdGlvbk9mZnNldHNbaTJdID0gb2Zmc2V0OwogICAgICBvZmZzZXQgKz0gY291bnRzW2kyXTsKICAgIH0KICAgIHBvc2l0aW9uT2Zmc2V0c1tjb3VudHNMZW5ndGhdID0gb2Zmc2V0OwogICAgcmV0dXJuIHBvc2l0aW9uT2Zmc2V0czsKICB9CiAgZnVuY3Rpb24gcmVtb3ZlRHVwbGljYXRlcyh1QnVmZmVyLCB2QnVmZmVyLCBoZWlnaHRCdWZmZXIsIGNvdW50cykgewogICAgY29uc3QgY291bnRzTGVuZ3RoID0gY291bnRzLmxlbmd0aDsKICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHVCdWZmZXIubGVuZ3RoOwogICAgY29uc3QgbWFya1JlbW92YWwgPSBuZXcgVWludDhBcnJheShwb3NpdGlvbnNMZW5ndGgpOwogICAgY29uc3QgcHJldmlvdXMgPSBwcmV2aW91c0NvbXByZXNzZWRDYXJ0b2dyYXBoaWNTY3JhdGNoOwogICAgY29uc3QgY3VycmVudCA9IGN1cnJlbnRDb21wcmVzc2VkQ2FydG9ncmFwaGljU2NyYXRjaDsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGNvdW50c0xlbmd0aDsgaTIrKykgewogICAgICBjb25zdCBjb3VudCA9IGNvdW50c1tpMl07CiAgICAgIGxldCB1cGRhdGVkQ291bnQgPSBjb3VudDsKICAgICAgZm9yIChsZXQgajIgPSAxOyBqMiA8IGNvdW50OyBqMisrKSB7CiAgICAgICAgY29uc3QgaW5kZXggPSBvZmZzZXQgKyBqMjsKICAgICAgICBjb25zdCBwcmV2aW91c0luZGV4ID0gaW5kZXggLSAxOwogICAgICAgIGN1cnJlbnQubG9uZ2l0dWRlID0gdUJ1ZmZlcltpbmRleF07CiAgICAgICAgY3VycmVudC5sYXRpdHVkZSA9IHZCdWZmZXJbaW5kZXhdOwogICAgICAgIHByZXZpb3VzLmxvbmdpdHVkZSA9IHVCdWZmZXJbcHJldmlvdXNJbmRleF07CiAgICAgICAgcHJldmlvdXMubGF0aXR1ZGUgPSB2QnVmZmVyW3ByZXZpb3VzSW5kZXhdOwogICAgICAgIGlmIChDYXJ0b2dyYXBoaWNfZGVmYXVsdC5lcXVhbHMoY3VycmVudCwgcHJldmlvdXMpKSB7CiAgICAgICAgICB1cGRhdGVkQ291bnQtLTsKICAgICAgICAgIG1hcmtSZW1vdmFsW3ByZXZpb3VzSW5kZXhdID0gMTsKICAgICAgICB9CiAgICAgIH0KICAgICAgY291bnRzW2kyXSA9IHVwZGF0ZWRDb3VudDsKICAgICAgb2Zmc2V0ICs9IGNvdW50OwogICAgfQogICAgbGV0IG5leHRBdmFpbGFibGVJbmRleCA9IDA7CiAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgcG9zaXRpb25zTGVuZ3RoOyBrMisrKSB7CiAgICAgIGlmIChtYXJrUmVtb3ZhbFtrMl0gIT09IDEpIHsKICAgICAgICB1QnVmZmVyW25leHRBdmFpbGFibGVJbmRleF0gPSB1QnVmZmVyW2syXTsKICAgICAgICB2QnVmZmVyW25leHRBdmFpbGFibGVJbmRleF0gPSB2QnVmZmVyW2syXTsKICAgICAgICBoZWlnaHRCdWZmZXJbbmV4dEF2YWlsYWJsZUluZGV4XSA9IGhlaWdodEJ1ZmZlcltrMl07CiAgICAgICAgbmV4dEF2YWlsYWJsZUluZGV4Kys7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gVmVydGV4QXR0cmlidXRlc0FuZEluZGljZXModm9sdW1lc0NvdW50KSB7CiAgICBjb25zdCB2ZXJ0ZXhDb3VudCA9IHZvbHVtZXNDb3VudCAqIDg7CiAgICBjb25zdCB2ZWMzRmxvYXRzID0gdmVydGV4Q291bnQgKiAzOwogICAgY29uc3QgdmVjNEZsb2F0cyA9IHZlcnRleENvdW50ICogNDsKICAgIHRoaXMuc3RhcnRFbGxpcHNvaWROb3JtYWxzID0gbmV3IEZsb2F0MzJBcnJheSh2ZWMzRmxvYXRzKTsKICAgIHRoaXMuZW5kRWxsaXBzb2lkTm9ybWFscyA9IG5ldyBGbG9hdDMyQXJyYXkodmVjM0Zsb2F0cyk7CiAgICB0aGlzLnN0YXJ0UG9zaXRpb25BbmRIZWlnaHRzID0gbmV3IEZsb2F0MzJBcnJheSh2ZWM0RmxvYXRzKTsKICAgIHRoaXMuc3RhcnRGYWNlTm9ybWFsQW5kVmVydGV4Q29ybmVySWRzID0gbmV3IEZsb2F0MzJBcnJheSh2ZWM0RmxvYXRzKTsKICAgIHRoaXMuZW5kUG9zaXRpb25BbmRIZWlnaHRzID0gbmV3IEZsb2F0MzJBcnJheSh2ZWM0RmxvYXRzKTsKICAgIHRoaXMuZW5kRmFjZU5vcm1hbEFuZEhhbGZXaWR0aHMgPSBuZXcgRmxvYXQzMkFycmF5KHZlYzRGbG9hdHMpOwogICAgdGhpcy52ZXJ0ZXhCYXRjaElkcyA9IG5ldyBVaW50MTZBcnJheSh2ZXJ0ZXhDb3VudCk7CiAgICB0aGlzLmluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSh2ZXJ0ZXhDb3VudCwgMzYgKiB2b2x1bWVzQ291bnQpOwogICAgdGhpcy52ZWMzT2Zmc2V0ID0gMDsKICAgIHRoaXMudmVjNE9mZnNldCA9IDA7CiAgICB0aGlzLmJhdGNoSWRPZmZzZXQgPSAwOwogICAgdGhpcy5pbmRleE9mZnNldCA9IDA7CiAgICB0aGlzLnZvbHVtZVN0YXJ0SW5kZXggPSAwOwogIH0KICBmdW5jdGlvbiBjb21wdXRlTWl0ZXJlZE5vcm1hbChwcmV2aW91c1Bvc2l0aW9uLCBwb3NpdGlvbiwgbmV4dFBvc2l0aW9uLCBlbGxpcHNvaWRTdXJmYWNlTm9ybWFsLCByZXN1bHQpIHsKICAgIGNvbnN0IHRvd2FyZE5leHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgIG5leHRQb3NpdGlvbiwKICAgICAgcG9zaXRpb24sCiAgICAgIHRvd2FyZE5leHRTY3JhdGNoCiAgICApOwogICAgbGV0IHRvd2FyZEN1cnIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgIHBvc2l0aW9uLAogICAgICBwcmV2aW91c1Bvc2l0aW9uLAogICAgICB0b3dhcmRDdXJyU2NyYXRjaAogICAgKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUodG93YXJkTmV4dCwgdG93YXJkTmV4dCk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKHRvd2FyZEN1cnIsIHRvd2FyZEN1cnIpOwogICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5kb3QodG93YXJkTmV4dCwgdG93YXJkQ3VycikgPCBNSVRFUl9CUkVBSykgewogICAgICB0b3dhcmRDdXJyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgICAgdG93YXJkQ3VyciwKICAgICAgICAtMSwKICAgICAgICB0b3dhcmRDdXJyU2NyYXRjaAogICAgICApOwogICAgfQogICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZCh0b3dhcmROZXh0LCB0b3dhcmRDdXJyLCByZXN1bHQpOwogICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHMocmVzdWx0LCBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTykpIHsKICAgICAgcmVzdWx0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHByZXZpb3VzUG9zaXRpb24sIHBvc2l0aW9uKTsKICAgIH0KICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhyZXN1bHQsIGVsbGlwc29pZFN1cmZhY2VOb3JtYWwsIHJlc3VsdCk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3MoZWxsaXBzb2lkU3VyZmFjZU5vcm1hbCwgcmVzdWx0LCByZXN1bHQpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShyZXN1bHQsIHJlc3VsdCk7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBjcmVhdGVWZWN0b3JUaWxlQ2xhbXBlZFBvbHlsaW5lcyhwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBlbmNvZGVkUG9zaXRpb25zID0gbmV3IFVpbnQxNkFycmF5KHBhcmFtZXRlcnMucG9zaXRpb25zKTsKICAgIGNvbnN0IHdpZHRocyA9IG5ldyBVaW50MTZBcnJheShwYXJhbWV0ZXJzLndpZHRocyk7CiAgICBjb25zdCBjb3VudHMgPSBuZXcgVWludDMyQXJyYXkocGFyYW1ldGVycy5jb3VudHMpOwogICAgY29uc3QgYmF0Y2hJZHMgPSBuZXcgVWludDE2QXJyYXkocGFyYW1ldGVycy5iYXRjaElkcyk7CiAgICBjb25zdCByZWN0YW5nbGUgPSBzY3JhdGNoUmVjdGFuZ2xlMzsKICAgIGNvbnN0IGVsbGlwc29pZCA9IHNjcmF0Y2hFbGxpcHNvaWQxMzsKICAgIGNvbnN0IGNlbnRlciA9IHNjcmF0Y2hDZW50ZXI0OwogICAgY29uc3QgcGFja2VkQnVmZmVyID0gbmV3IEZsb2F0NjRBcnJheShwYXJhbWV0ZXJzLnBhY2tlZEJ1ZmZlcik7CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIGNvbnN0IG1pbmltdW1IZWlnaHQgPSBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdOwogICAgY29uc3QgbWF4aW11bUhlaWdodCA9IHBhY2tlZEJ1ZmZlcltvZmZzZXQrK107CiAgICBSZWN0YW5nbGVfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHJlY3RhbmdsZSk7CiAgICBvZmZzZXQgKz0gUmVjdGFuZ2xlX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgRWxsaXBzb2lkX2RlZmF1bHQudW5wYWNrKHBhY2tlZEJ1ZmZlciwgb2Zmc2V0LCBlbGxpcHNvaWQpOwogICAgb2Zmc2V0ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIGNlbnRlcik7CiAgICBsZXQgaTI7CiAgICBsZXQgcG9zaXRpb25zTGVuZ3RoID0gZW5jb2RlZFBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3QgdUJ1ZmZlciA9IGVuY29kZWRQb3NpdGlvbnMuc3ViYXJyYXkoMCwgcG9zaXRpb25zTGVuZ3RoKTsKICAgIGNvbnN0IHZCdWZmZXIgPSBlbmNvZGVkUG9zaXRpb25zLnN1YmFycmF5KAogICAgICBwb3NpdGlvbnNMZW5ndGgsCiAgICAgIDIgKiBwb3NpdGlvbnNMZW5ndGgKICAgICk7CiAgICBjb25zdCBoZWlnaHRCdWZmZXIgPSBlbmNvZGVkUG9zaXRpb25zLnN1YmFycmF5KAogICAgICAyICogcG9zaXRpb25zTGVuZ3RoLAogICAgICAzICogcG9zaXRpb25zTGVuZ3RoCiAgICApOwogICAgQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC56aWdaYWdEZWx0YURlY29kZSh1QnVmZmVyLCB2QnVmZmVyLCBoZWlnaHRCdWZmZXIpOwogICAgcmVtb3ZlRHVwbGljYXRlcyh1QnVmZmVyLCB2QnVmZmVyLCBoZWlnaHRCdWZmZXIsIGNvdW50cyk7CiAgICBjb25zdCBjb3VudHNMZW5ndGggPSBjb3VudHMubGVuZ3RoOwogICAgbGV0IHZvbHVtZXNDb3VudCA9IDA7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBjb3VudHNMZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgcG9seWxpbmVQb3NpdGlvbkNvdW50ID0gY291bnRzW2kyXTsKICAgICAgdm9sdW1lc0NvdW50ICs9IHBvbHlsaW5lUG9zaXRpb25Db3VudCAtIDE7CiAgICB9CiAgICBjb25zdCBhdHRyaWJzQW5kSW5kaWNlcyA9IG5ldyBWZXJ0ZXhBdHRyaWJ1dGVzQW5kSW5kaWNlcyh2b2x1bWVzQ291bnQpOwogICAgY29uc3QgcG9zaXRpb25zID0gZGVjb2RlUG9zaXRpb25zKAogICAgICB1QnVmZmVyLAogICAgICB2QnVmZmVyLAogICAgICBoZWlnaHRCdWZmZXIsCiAgICAgIHJlY3RhbmdsZSwKICAgICAgbWluaW11bUhlaWdodCwKICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgZWxsaXBzb2lkLAogICAgICBjZW50ZXIKICAgICk7CiAgICBwb3NpdGlvbnNMZW5ndGggPSB1QnVmZmVyLmxlbmd0aDsKICAgIGNvbnN0IHBvc2l0aW9uc1JUQyA9IG5ldyBGbG9hdDMyQXJyYXkocG9zaXRpb25zTGVuZ3RoICogMyk7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBwb3NpdGlvbnNMZW5ndGg7ICsraTIpIHsKICAgICAgcG9zaXRpb25zUlRDW2kyICogM10gPSBwb3NpdGlvbnNbaTIgKiAzXSAtIGNlbnRlci54OwogICAgICBwb3NpdGlvbnNSVENbaTIgKiAzICsgMV0gPSBwb3NpdGlvbnNbaTIgKiAzICsgMV0gLSBjZW50ZXIueTsKICAgICAgcG9zaXRpb25zUlRDW2kyICogMyArIDJdID0gcG9zaXRpb25zW2kyICogMyArIDJdIC0gY2VudGVyLno7CiAgICB9CiAgICBsZXQgY3VycmVudFBvc2l0aW9uSW5kZXggPSAwOwogICAgbGV0IGN1cnJlbnRIZWlnaHRJbmRleCA9IDA7CiAgICBmb3IgKGkyID0gMDsgaTIgPCBjb3VudHNMZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgcG9seWxpbmVWb2x1bWVDb3VudCA9IGNvdW50c1tpMl0gLSAxOwogICAgICBjb25zdCBoYWxmV2lkdGggPSB3aWR0aHNbaTJdICogMC41OwogICAgICBjb25zdCBiYXRjaElkID0gYmF0Y2hJZHNbaTJdOwogICAgICBjb25zdCB2b2x1bWVGaXJzdFBvc2l0aW9uSW5kZXggPSBjdXJyZW50UG9zaXRpb25JbmRleDsKICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IHBvbHlsaW5lVm9sdW1lQ291bnQ7IGoyKyspIHsKICAgICAgICBjb25zdCB2b2x1bWVTdGFydCA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBwb3NpdGlvbnNSVEMsCiAgICAgICAgICBjdXJyZW50UG9zaXRpb25JbmRleCwKICAgICAgICAgIHNjcmF0Y2hQMAogICAgICAgICk7CiAgICAgICAgY29uc3Qgdm9sdW1lRW5kID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgIHBvc2l0aW9uc1JUQywKICAgICAgICAgIGN1cnJlbnRQb3NpdGlvbkluZGV4ICsgMywKICAgICAgICAgIHNjcmF0Y2hQMQogICAgICAgICk7CiAgICAgICAgbGV0IHN0YXJ0SGVpZ2h0ID0gaGVpZ2h0QnVmZmVyW2N1cnJlbnRIZWlnaHRJbmRleF07CiAgICAgICAgbGV0IGVuZEhlaWdodCA9IGhlaWdodEJ1ZmZlcltjdXJyZW50SGVpZ2h0SW5kZXggKyAxXTsKICAgICAgICBzdGFydEhlaWdodCA9IE1hdGhfZGVmYXVsdC5sZXJwKAogICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgICBzdGFydEhlaWdodCAvIE1BWF9TSE9SVAogICAgICAgICk7CiAgICAgICAgZW5kSGVpZ2h0ID0gTWF0aF9kZWZhdWx0LmxlcnAoCiAgICAgICAgICBtaW5pbXVtSGVpZ2h0LAogICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgIGVuZEhlaWdodCAvIE1BWF9TSE9SVAogICAgICAgICk7CiAgICAgICAgY3VycmVudEhlaWdodEluZGV4Kys7CiAgICAgICAgbGV0IHByZVN0YXJ0ID0gc2NyYXRjaFByZXY7CiAgICAgICAgbGV0IHBvc3RFbmQgPSBzY3JhdGNoTmV4dDsKICAgICAgICBpZiAoajIgPT09IDApIHsKICAgICAgICAgIGNvbnN0IGZpbmFsUG9zaXRpb25JbmRleCA9IHZvbHVtZUZpcnN0UG9zaXRpb25JbmRleCArIHBvbHlsaW5lVm9sdW1lQ291bnQgKiAzOwogICAgICAgICAgY29uc3QgZmluYWxQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgIHBvc2l0aW9uc1JUQywKICAgICAgICAgICAgZmluYWxQb3NpdGlvbkluZGV4LAogICAgICAgICAgICBzY3JhdGNoUHJldgogICAgICAgICAgKTsKICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzKGZpbmFsUG9zaXRpb24sIHZvbHVtZVN0YXJ0KSkgewogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHBvc2l0aW9uc1JUQywgZmluYWxQb3NpdGlvbkluZGV4IC0gMywgcHJlU3RhcnQpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0UGFzdFN0YXJ0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgICAgIHZvbHVtZVN0YXJ0LAogICAgICAgICAgICAgIHZvbHVtZUVuZCwKICAgICAgICAgICAgICBzY3JhdGNoUHJldgogICAgICAgICAgICApOwogICAgICAgICAgICBwcmVTdGFydCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQob2Zmc2V0UGFzdFN0YXJ0LCB2b2x1bWVTdGFydCwgc2NyYXRjaFByZXYpOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHBvc2l0aW9uc1JUQywgY3VycmVudFBvc2l0aW9uSW5kZXggLSAzLCBwcmVTdGFydCk7CiAgICAgICAgfQogICAgICAgIGlmIChqMiA9PT0gcG9seWxpbmVWb2x1bWVDb3VudCAtIDEpIHsKICAgICAgICAgIGNvbnN0IGZpcnN0UG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgICBwb3NpdGlvbnNSVEMsCiAgICAgICAgICAgIHZvbHVtZUZpcnN0UG9zaXRpb25JbmRleCwKICAgICAgICAgICAgc2NyYXRjaE5leHQKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhmaXJzdFBvc2l0aW9uLCB2b2x1bWVFbmQpKSB7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgICAgcG9zaXRpb25zUlRDLAogICAgICAgICAgICAgIHZvbHVtZUZpcnN0UG9zaXRpb25JbmRleCArIDMsCiAgICAgICAgICAgICAgcG9zdEVuZAogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgY29uc3Qgb2Zmc2V0UGFzdEVuZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICAgICAgICB2b2x1bWVFbmQsCiAgICAgICAgICAgICAgdm9sdW1lU3RhcnQsCiAgICAgICAgICAgICAgc2NyYXRjaE5leHQKICAgICAgICAgICAgKTsKICAgICAgICAgICAgcG9zdEVuZCA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQob2Zmc2V0UGFzdEVuZCwgdm9sdW1lRW5kLCBzY3JhdGNoTmV4dCk7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socG9zaXRpb25zUlRDLCBjdXJyZW50UG9zaXRpb25JbmRleCArIDYsIHBvc3RFbmQpOwogICAgICAgIH0KICAgICAgICBhdHRyaWJzQW5kSW5kaWNlcy5hZGRWb2x1bWUoCiAgICAgICAgICBwcmVTdGFydCwKICAgICAgICAgIHZvbHVtZVN0YXJ0LAogICAgICAgICAgdm9sdW1lRW5kLAogICAgICAgICAgcG9zdEVuZCwKICAgICAgICAgIHN0YXJ0SGVpZ2h0LAogICAgICAgICAgZW5kSGVpZ2h0LAogICAgICAgICAgaGFsZldpZHRoLAogICAgICAgICAgYmF0Y2hJZCwKICAgICAgICAgIGNlbnRlciwKICAgICAgICAgIGVsbGlwc29pZAogICAgICAgICk7CiAgICAgICAgY3VycmVudFBvc2l0aW9uSW5kZXggKz0gMzsKICAgICAgfQogICAgICBjdXJyZW50UG9zaXRpb25JbmRleCArPSAzOwogICAgICBjdXJyZW50SGVpZ2h0SW5kZXgrKzsKICAgIH0KICAgIGNvbnN0IGluZGljZXMgPSBhdHRyaWJzQW5kSW5kaWNlcy5pbmRpY2VzOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGF0dHJpYnNBbmRJbmRpY2VzLnN0YXJ0RWxsaXBzb2lkTm9ybWFscy5idWZmZXIpOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGF0dHJpYnNBbmRJbmRpY2VzLmVuZEVsbGlwc29pZE5vcm1hbHMuYnVmZmVyKTsKICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChhdHRyaWJzQW5kSW5kaWNlcy5zdGFydFBvc2l0aW9uQW5kSGVpZ2h0cy5idWZmZXIpOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICBhdHRyaWJzQW5kSW5kaWNlcy5zdGFydEZhY2VOb3JtYWxBbmRWZXJ0ZXhDb3JuZXJJZHMuYnVmZmVyCiAgICApOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGF0dHJpYnNBbmRJbmRpY2VzLmVuZFBvc2l0aW9uQW5kSGVpZ2h0cy5idWZmZXIpOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGF0dHJpYnNBbmRJbmRpY2VzLmVuZEZhY2VOb3JtYWxBbmRIYWxmV2lkdGhzLmJ1ZmZlcik7CiAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goYXR0cmlic0FuZEluZGljZXMudmVydGV4QmF0Y2hJZHMuYnVmZmVyKTsKICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChpbmRpY2VzLmJ1ZmZlcik7CiAgICBsZXQgcmVzdWx0cyA9IHsKICAgICAgaW5kZXhEYXRhdHlwZTogaW5kaWNlcy5CWVRFU19QRVJfRUxFTUVOVCA9PT0gMiA/IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9TSE9SVCA6IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9JTlQsCiAgICAgIHN0YXJ0RWxsaXBzb2lkTm9ybWFsczogYXR0cmlic0FuZEluZGljZXMuc3RhcnRFbGxpcHNvaWROb3JtYWxzLmJ1ZmZlciwKICAgICAgZW5kRWxsaXBzb2lkTm9ybWFsczogYXR0cmlic0FuZEluZGljZXMuZW5kRWxsaXBzb2lkTm9ybWFscy5idWZmZXIsCiAgICAgIHN0YXJ0UG9zaXRpb25BbmRIZWlnaHRzOiBhdHRyaWJzQW5kSW5kaWNlcy5zdGFydFBvc2l0aW9uQW5kSGVpZ2h0cy5idWZmZXIsCiAgICAgIHN0YXJ0RmFjZU5vcm1hbEFuZFZlcnRleENvcm5lcklkczogYXR0cmlic0FuZEluZGljZXMuc3RhcnRGYWNlTm9ybWFsQW5kVmVydGV4Q29ybmVySWRzLmJ1ZmZlciwKICAgICAgZW5kUG9zaXRpb25BbmRIZWlnaHRzOiBhdHRyaWJzQW5kSW5kaWNlcy5lbmRQb3NpdGlvbkFuZEhlaWdodHMuYnVmZmVyLAogICAgICBlbmRGYWNlTm9ybWFsQW5kSGFsZldpZHRoczogYXR0cmlic0FuZEluZGljZXMuZW5kRmFjZU5vcm1hbEFuZEhhbGZXaWR0aHMuYnVmZmVyLAogICAgICB2ZXJ0ZXhCYXRjaElkczogYXR0cmlic0FuZEluZGljZXMudmVydGV4QmF0Y2hJZHMuYnVmZmVyLAogICAgICBpbmRpY2VzOiBpbmRpY2VzLmJ1ZmZlcgogICAgfTsKICAgIGlmIChwYXJhbWV0ZXJzLmtlZXBEZWNvZGVkUG9zaXRpb25zKSB7CiAgICAgIGNvbnN0IHBvc2l0aW9uT2Zmc2V0cyA9IGdldFBvc2l0aW9uT2Zmc2V0cyhjb3VudHMpOwogICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2gocG9zaXRpb25zLmJ1ZmZlciwgcG9zaXRpb25PZmZzZXRzLmJ1ZmZlcik7CiAgICAgIHJlc3VsdHMgPSBjb21iaW5lX2RlZmF1bHQocmVzdWx0cywgewogICAgICAgIGRlY29kZWRQb3NpdGlvbnM6IHBvc2l0aW9ucy5idWZmZXIsCiAgICAgICAgZGVjb2RlZFBvc2l0aW9uT2Zmc2V0czogcG9zaXRpb25PZmZzZXRzLmJ1ZmZlcgogICAgICB9KTsKICAgIH0KICAgIHJldHVybiByZXN1bHRzOwogIH0KICB2YXIgTUFYX1NIT1JULCBNSVRFUl9CUkVBSywgc2NyYXRjaEJWQ2FydG9ncmFwaGljLCBzY3JhdGNoRW5jb2RlZFBvc2l0aW9uLCBwcmV2aW91c0NvbXByZXNzZWRDYXJ0b2dyYXBoaWNTY3JhdGNoLCBjdXJyZW50Q29tcHJlc3NlZENhcnRvZ3JhcGhpY1NjcmF0Y2gsIHRvd2FyZEN1cnJTY3JhdGNoLCB0b3dhcmROZXh0U2NyYXRjaCwgUkVGRVJFTkNFX0lORElDRVMyLCBSRUZFUkVOQ0VfSU5ESUNFU19MRU5HVEgyLCBwb3NpdGlvblNjcmF0Y2g0LCBzY3JhdGNoU3RhcnRFbGxpcHNvaWROb3JtYWwsIHNjcmF0Y2hTdGFydEZhY2VOb3JtYWwsIHNjcmF0Y2hFbmRFbGxpcHNvaWROb3JtYWwsIHNjcmF0Y2hFbmRGYWNlTm9ybWFsLCBzY3JhdGNoUmVjdGFuZ2xlMywgc2NyYXRjaEVsbGlwc29pZDEzLCBzY3JhdGNoQ2VudGVyNCwgc2NyYXRjaFByZXYsIHNjcmF0Y2hQMCwgc2NyYXRjaFAxLCBzY3JhdGNoTmV4dCwgY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXNfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVWZWN0b3JUaWxlQ2xhbXBlZFBvbHlsaW5lcyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXMuanMiKCkgewogICAgICBpbml0X0F0dHJpYnV0ZUNvbXByZXNzaW9uKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X2NvbWJpbmUoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgTUFYX1NIT1JUID0gMzI3Njc7CiAgICAgIE1JVEVSX0JSRUFLID0gTWF0aC5jb3MoTWF0aF9kZWZhdWx0LnRvUmFkaWFucygxNTApKTsKICAgICAgc2NyYXRjaEJWQ2FydG9ncmFwaGljID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbmNvZGVkUG9zaXRpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHByZXZpb3VzQ29tcHJlc3NlZENhcnRvZ3JhcGhpY1NjcmF0Y2ggPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgY3VycmVudENvbXByZXNzZWRDYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHRvd2FyZEN1cnJTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICB0b3dhcmROZXh0U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgUkVGRVJFTkNFX0lORElDRVMyID0gWwogICAgICAgIDAsCiAgICAgICAgMiwKICAgICAgICA2LAogICAgICAgIDAsCiAgICAgICAgNiwKICAgICAgICA0LAogICAgICAgIC8vIHJpZ2h0CiAgICAgICAgMCwKICAgICAgICAxLAogICAgICAgIDMsCiAgICAgICAgMCwKICAgICAgICAzLAogICAgICAgIDIsCiAgICAgICAgLy8gc3RhcnQgZmFjZQogICAgICAgIDAsCiAgICAgICAgNCwKICAgICAgICA1LAogICAgICAgIDAsCiAgICAgICAgNSwKICAgICAgICAxLAogICAgICAgIC8vIGJvdHRvbQogICAgICAgIDUsCiAgICAgICAgMywKICAgICAgICAxLAogICAgICAgIDUsCiAgICAgICAgNywKICAgICAgICAzLAogICAgICAgIC8vIGxlZnQKICAgICAgICA3LAogICAgICAgIDUsCiAgICAgICAgNCwKICAgICAgICA3LAogICAgICAgIDQsCiAgICAgICAgNiwKICAgICAgICAvLyBlbmQgZmFjZQogICAgICAgIDcsCiAgICAgICAgNiwKICAgICAgICAyLAogICAgICAgIDcsCiAgICAgICAgMiwKICAgICAgICAzCiAgICAgICAgLy8gdG9wCiAgICAgIF07CiAgICAgIFJFRkVSRU5DRV9JTkRJQ0VTX0xFTkdUSDIgPSBSRUZFUkVOQ0VfSU5ESUNFUzIubGVuZ3RoOwogICAgICBwb3NpdGlvblNjcmF0Y2g0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoU3RhcnRFbGxpcHNvaWROb3JtYWwgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hTdGFydEZhY2VOb3JtYWwgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbmRFbGxpcHNvaWROb3JtYWwgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbmRGYWNlTm9ybWFsID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBWZXJ0ZXhBdHRyaWJ1dGVzQW5kSW5kaWNlcy5wcm90b3R5cGUuYWRkVm9sdW1lID0gZnVuY3Rpb24ocHJlU3RhcnRSVEMsIHN0YXJ0UlRDLCBlbmRSVEMsIHBvc3RFbmRSVEMsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIGhhbGZXaWR0aCwgYmF0Y2hJZCwgY2VudGVyLCBlbGxpcHNvaWQpIHsKICAgICAgICBsZXQgcG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKHN0YXJ0UlRDLCBjZW50ZXIsIHBvc2l0aW9uU2NyYXRjaDQpOwogICAgICAgIGNvbnN0IHN0YXJ0RWxsaXBzb2lkTm9ybWFsID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbCgKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgc2NyYXRjaFN0YXJ0RWxsaXBzb2lkTm9ybWFsCiAgICAgICAgKTsKICAgICAgICBwb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoZW5kUlRDLCBjZW50ZXIsIHBvc2l0aW9uU2NyYXRjaDQpOwogICAgICAgIGNvbnN0IGVuZEVsbGlwc29pZE5vcm1hbCA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoCiAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgIHNjcmF0Y2hFbmRFbGxpcHNvaWROb3JtYWwKICAgICAgICApOwogICAgICAgIGNvbnN0IHN0YXJ0RmFjZU5vcm1hbCA9IGNvbXB1dGVNaXRlcmVkTm9ybWFsKAogICAgICAgICAgcHJlU3RhcnRSVEMsCiAgICAgICAgICBzdGFydFJUQywKICAgICAgICAgIGVuZFJUQywKICAgICAgICAgIHN0YXJ0RWxsaXBzb2lkTm9ybWFsLAogICAgICAgICAgc2NyYXRjaFN0YXJ0RmFjZU5vcm1hbAogICAgICAgICk7CiAgICAgICAgY29uc3QgZW5kRmFjZU5vcm1hbCA9IGNvbXB1dGVNaXRlcmVkTm9ybWFsKAogICAgICAgICAgcG9zdEVuZFJUQywKICAgICAgICAgIGVuZFJUQywKICAgICAgICAgIHN0YXJ0UlRDLAogICAgICAgICAgZW5kRWxsaXBzb2lkTm9ybWFsLAogICAgICAgICAgc2NyYXRjaEVuZEZhY2VOb3JtYWwKICAgICAgICApOwogICAgICAgIGNvbnN0IHN0YXJ0RWxsaXBzb2lkTm9ybWFscyA9IHRoaXMuc3RhcnRFbGxpcHNvaWROb3JtYWxzOwogICAgICAgIGNvbnN0IGVuZEVsbGlwc29pZE5vcm1hbHMgPSB0aGlzLmVuZEVsbGlwc29pZE5vcm1hbHM7CiAgICAgICAgY29uc3Qgc3RhcnRQb3NpdGlvbkFuZEhlaWdodHMgPSB0aGlzLnN0YXJ0UG9zaXRpb25BbmRIZWlnaHRzOwogICAgICAgIGNvbnN0IHN0YXJ0RmFjZU5vcm1hbEFuZFZlcnRleENvcm5lcklkcyA9IHRoaXMuc3RhcnRGYWNlTm9ybWFsQW5kVmVydGV4Q29ybmVySWRzOwogICAgICAgIGNvbnN0IGVuZFBvc2l0aW9uQW5kSGVpZ2h0cyA9IHRoaXMuZW5kUG9zaXRpb25BbmRIZWlnaHRzOwogICAgICAgIGNvbnN0IGVuZEZhY2VOb3JtYWxBbmRIYWxmV2lkdGhzID0gdGhpcy5lbmRGYWNlTm9ybWFsQW5kSGFsZldpZHRoczsKICAgICAgICBjb25zdCB2ZXJ0ZXhCYXRjaElkcyA9IHRoaXMudmVydGV4QmF0Y2hJZHM7CiAgICAgICAgbGV0IGJhdGNoSWRPZmZzZXQgPSB0aGlzLmJhdGNoSWRPZmZzZXQ7CiAgICAgICAgbGV0IHZlYzNPZmZzZXQgPSB0aGlzLnZlYzNPZmZzZXQ7CiAgICAgICAgbGV0IHZlYzRPZmZzZXQgPSB0aGlzLnZlYzRPZmZzZXQ7CiAgICAgICAgbGV0IGkyOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IDg7IGkyKyspIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHN0YXJ0RWxsaXBzb2lkTm9ybWFsLCBzdGFydEVsbGlwc29pZE5vcm1hbHMsIHZlYzNPZmZzZXQpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soZW5kRWxsaXBzb2lkTm9ybWFsLCBlbmRFbGxpcHNvaWROb3JtYWxzLCB2ZWMzT2Zmc2V0KTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHN0YXJ0UlRDLCBzdGFydFBvc2l0aW9uQW5kSGVpZ2h0cywgdmVjNE9mZnNldCk7CiAgICAgICAgICBzdGFydFBvc2l0aW9uQW5kSGVpZ2h0c1t2ZWM0T2Zmc2V0ICsgM10gPSBzdGFydEhlaWdodDsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGVuZFJUQywgZW5kUG9zaXRpb25BbmRIZWlnaHRzLCB2ZWM0T2Zmc2V0KTsKICAgICAgICAgIGVuZFBvc2l0aW9uQW5kSGVpZ2h0c1t2ZWM0T2Zmc2V0ICsgM10gPSBlbmRIZWlnaHQ7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjaygKICAgICAgICAgICAgc3RhcnRGYWNlTm9ybWFsLAogICAgICAgICAgICBzdGFydEZhY2VOb3JtYWxBbmRWZXJ0ZXhDb3JuZXJJZHMsCiAgICAgICAgICAgIHZlYzRPZmZzZXQKICAgICAgICAgICk7CiAgICAgICAgICBzdGFydEZhY2VOb3JtYWxBbmRWZXJ0ZXhDb3JuZXJJZHNbdmVjNE9mZnNldCArIDNdID0gaTI7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhlbmRGYWNlTm9ybWFsLCBlbmRGYWNlTm9ybWFsQW5kSGFsZldpZHRocywgdmVjNE9mZnNldCk7CiAgICAgICAgICBlbmRGYWNlTm9ybWFsQW5kSGFsZldpZHRoc1t2ZWM0T2Zmc2V0ICsgM10gPSBoYWxmV2lkdGg7CiAgICAgICAgICB2ZXJ0ZXhCYXRjaElkc1tiYXRjaElkT2Zmc2V0KytdID0gYmF0Y2hJZDsKICAgICAgICAgIHZlYzNPZmZzZXQgKz0gMzsKICAgICAgICAgIHZlYzRPZmZzZXQgKz0gNDsKICAgICAgICB9CiAgICAgICAgdGhpcy5iYXRjaElkT2Zmc2V0ID0gYmF0Y2hJZE9mZnNldDsKICAgICAgICB0aGlzLnZlYzNPZmZzZXQgPSB2ZWMzT2Zmc2V0OwogICAgICAgIHRoaXMudmVjNE9mZnNldCA9IHZlYzRPZmZzZXQ7CiAgICAgICAgY29uc3QgaW5kaWNlcyA9IHRoaXMuaW5kaWNlczsKICAgICAgICBjb25zdCB2b2x1bWVTdGFydEluZGV4ID0gdGhpcy52b2x1bWVTdGFydEluZGV4OwogICAgICAgIGNvbnN0IGluZGV4T2Zmc2V0ID0gdGhpcy5pbmRleE9mZnNldDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBSRUZFUkVOQ0VfSU5ESUNFU19MRU5HVEgyOyBpMisrKSB7CiAgICAgICAgICBpbmRpY2VzW2luZGV4T2Zmc2V0ICsgaTJdID0gUkVGRVJFTkNFX0lORElDRVMyW2kyXSArIHZvbHVtZVN0YXJ0SW5kZXg7CiAgICAgICAgfQogICAgICAgIHRoaXMudm9sdW1lU3RhcnRJbmRleCArPSA4OwogICAgICAgIHRoaXMuaW5kZXhPZmZzZXQgKz0gUkVGRVJFTkNFX0lORElDRVNfTEVOR1RIMjsKICAgICAgfTsKICAgICAgc2NyYXRjaFJlY3RhbmdsZTMgPSBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDEzID0gbmV3IEVsbGlwc29pZF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDZW50ZXI0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUHJldiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFAwID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUDEgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOZXh0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjcmVhdGVWZWN0b3JUaWxlQ2xhbXBlZFBvbHlsaW5lc19kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KGNyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzKTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9TY2VuZS9WZWN0b3IzRFRpbGVCYXRjaC5qcwogIGZ1bmN0aW9uIFZlY3RvcjNEVGlsZUJhdGNoKG9wdGlvbnMpIHsKICAgIHRoaXMub2Zmc2V0ID0gb3B0aW9ucy5vZmZzZXQ7CiAgICB0aGlzLmNvdW50ID0gb3B0aW9ucy5jb3VudDsKICAgIHRoaXMuY29sb3IgPSBvcHRpb25zLmNvbG9yOwogICAgdGhpcy5iYXRjaElkcyA9IG9wdGlvbnMuYmF0Y2hJZHM7CiAgfQogIHZhciBWZWN0b3IzRFRpbGVCYXRjaF9kZWZhdWx0OwogIHZhciBpbml0X1ZlY3RvcjNEVGlsZUJhdGNoID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvU2NlbmUvVmVjdG9yM0RUaWxlQmF0Y2guanMiKCkgewogICAgICBWZWN0b3IzRFRpbGVCYXRjaF9kZWZhdWx0ID0gVmVjdG9yM0RUaWxlQmF0Y2g7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllcy5qcwogIHZhciBjcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllc19leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXNfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXNfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGJveE1vZGVsTWF0cml4QW5kQm91bmRpbmdWb2x1bWUoYm94ZXMsIGluZGV4KSB7CiAgICBsZXQgYm94SW5kZXggPSBpbmRleCAqIHBhY2tlZEJveExlbmd0aDsKICAgIGNvbnN0IGRpbWVuc2lvbnMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGJveGVzLCBib3hJbmRleCwgc2NyYXRjaENhcnRlc2lhbjExKTsKICAgIGJveEluZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICBjb25zdCBib3hNb2RlbE1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC51bnBhY2soCiAgICAgIGJveGVzLAogICAgICBib3hJbmRleCwKICAgICAgc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYubW9kZWxNYXRyaXgKICAgICk7CiAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVNjYWxlKGJveE1vZGVsTWF0cml4LCBkaW1lbnNpb25zLCBib3hNb2RlbE1hdHJpeCk7CiAgICBjb25zdCBib3VuZGluZ1ZvbHVtZSA9IHNjcmF0Y2hNb2RlbE1hdHJpeEFuZEJWLmJvdW5kaW5nVm9sdW1lOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLCBib3VuZGluZ1ZvbHVtZS5jZW50ZXIpOwogICAgYm91bmRpbmdWb2x1bWUucmFkaXVzID0gTWF0aC5zcXJ0KDMpOwogICAgcmV0dXJuIHNjcmF0Y2hNb2RlbE1hdHJpeEFuZEJWOwogIH0KICBmdW5jdGlvbiBjeWxpbmRlck1vZGVsTWF0cml4QW5kQm91bmRpbmdWb2x1bWUoY3lsaW5kZXJzLCBpbmRleCkgewogICAgbGV0IGN5bGluZGVySW5kZXggPSBpbmRleCAqIHBhY2tlZEN5bGluZGVyTGVuZ3RoOwogICAgY29uc3QgY3lsaW5kZXJSYWRpdXMgPSBjeWxpbmRlcnNbY3lsaW5kZXJJbmRleCsrXTsKICAgIGNvbnN0IGxlbmd0aCA9IGN5bGluZGVyc1tjeWxpbmRlckluZGV4KytdOwogICAgY29uc3Qgc2NhbGUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICBjeWxpbmRlclJhZGl1cywKICAgICAgY3lsaW5kZXJSYWRpdXMsCiAgICAgIGxlbmd0aCwKICAgICAgc2NyYXRjaENhcnRlc2lhbjExCiAgICApOwogICAgY29uc3QgY3lsaW5kZXJNb2RlbE1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC51bnBhY2soCiAgICAgIGN5bGluZGVycywKICAgICAgY3lsaW5kZXJJbmRleCwKICAgICAgc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYubW9kZWxNYXRyaXgKICAgICk7CiAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVNjYWxlKGN5bGluZGVyTW9kZWxNYXRyaXgsIHNjYWxlLCBjeWxpbmRlck1vZGVsTWF0cml4KTsKICAgIGNvbnN0IGJvdW5kaW5nVm9sdW1lID0gc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYuYm91bmRpbmdWb2x1bWU7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIGJvdW5kaW5nVm9sdW1lLmNlbnRlcik7CiAgICBib3VuZGluZ1ZvbHVtZS5yYWRpdXMgPSBNYXRoLnNxcnQoMik7CiAgICByZXR1cm4gc2NyYXRjaE1vZGVsTWF0cml4QW5kQlY7CiAgfQogIGZ1bmN0aW9uIGVsbGlwc29pZE1vZGVsTWF0cml4QW5kQm91bmRpbmdWb2x1bWUoZWxsaXBzb2lkcywgaW5kZXgpIHsKICAgIGxldCBlbGxpcHNvaWRJbmRleCA9IGluZGV4ICogcGFja2VkRWxsaXBzb2lkTGVuZ3RoOwogICAgY29uc3QgcmFkaWkgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGVsbGlwc29pZHMsIGVsbGlwc29pZEluZGV4LCBzY3JhdGNoQ2FydGVzaWFuMTEpOwogICAgZWxsaXBzb2lkSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIGNvbnN0IGVsbGlwc29pZE1vZGVsTWF0cml4ID0gTWF0cml4NF9kZWZhdWx0LnVucGFjaygKICAgICAgZWxsaXBzb2lkcywKICAgICAgZWxsaXBzb2lkSW5kZXgsCiAgICAgIHNjcmF0Y2hNb2RlbE1hdHJpeEFuZEJWLm1vZGVsTWF0cml4CiAgICApOwogICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlTY2FsZShlbGxpcHNvaWRNb2RlbE1hdHJpeCwgcmFkaWksIGVsbGlwc29pZE1vZGVsTWF0cml4KTsKICAgIGNvbnN0IGJvdW5kaW5nVm9sdW1lID0gc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYuYm91bmRpbmdWb2x1bWU7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIGJvdW5kaW5nVm9sdW1lLmNlbnRlcik7CiAgICBib3VuZGluZ1ZvbHVtZS5yYWRpdXMgPSAxOwogICAgcmV0dXJuIHNjcmF0Y2hNb2RlbE1hdHJpeEFuZEJWOwogIH0KICBmdW5jdGlvbiBzcGhlcmVNb2RlbE1hdHJpeEFuZEJvdW5kaW5nVm9sdW1lKHNwaGVyZXMsIGluZGV4KSB7CiAgICBsZXQgc3BoZXJlSW5kZXggPSBpbmRleCAqIHBhY2tlZFNwaGVyZUxlbmd0aDsKICAgIGNvbnN0IHNwaGVyZVJhZGl1cyA9IHNwaGVyZXNbc3BoZXJlSW5kZXgrK107CiAgICBjb25zdCBzcGhlcmVUcmFuc2xhdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgIHNwaGVyZXMsCiAgICAgIHNwaGVyZUluZGV4LAogICAgICBzY3JhdGNoQ2FydGVzaWFuMTEKICAgICk7CiAgICBjb25zdCBzcGhlcmVNb2RlbE1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC5mcm9tVHJhbnNsYXRpb24oCiAgICAgIHNwaGVyZVRyYW5zbGF0aW9uLAogICAgICBzY3JhdGNoTW9kZWxNYXRyaXhBbmRCVi5tb2RlbE1hdHJpeAogICAgKTsKICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5VW5pZm9ybVNjYWxlKAogICAgICBzcGhlcmVNb2RlbE1hdHJpeCwKICAgICAgc3BoZXJlUmFkaXVzLAogICAgICBzcGhlcmVNb2RlbE1hdHJpeAogICAgKTsKICAgIGNvbnN0IGJvdW5kaW5nVm9sdW1lID0gc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYuYm91bmRpbmdWb2x1bWU7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoQ2FydGVzaWFuM19kZWZhdWx0LlpFUk8sIGJvdW5kaW5nVm9sdW1lLmNlbnRlcik7CiAgICBib3VuZGluZ1ZvbHVtZS5yYWRpdXMgPSAxOwogICAgcmV0dXJuIHNjcmF0Y2hNb2RlbE1hdHJpeEFuZEJWOwogIH0KICBmdW5jdGlvbiBjcmVhdGVQcmltaXRpdmUob3B0aW9ucywgcHJpbWl0aXZlLCBwcmltaXRpdmVCYXRjaElkcywgZ2VvbWV0cnksIGdldE1vZGVsTWF0cml4QW5kQm91bmRpbmdWb2x1bWUpIHsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHByaW1pdGl2ZSkpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3QgbnVtYmVyT2ZQcmltaXRpdmVzID0gcHJpbWl0aXZlQmF0Y2hJZHMubGVuZ3RoOwogICAgY29uc3QgZ2VvbWV0cnlQb3NpdGlvbnMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uLnZhbHVlczsKICAgIGNvbnN0IGdlb21ldHJ5SW5kaWNlcyA9IGdlb21ldHJ5LmluZGljZXM7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBvcHRpb25zLnBvc2l0aW9uczsKICAgIGNvbnN0IHZlcnRleEJhdGNoSWRzID0gb3B0aW9ucy52ZXJ0ZXhCYXRjaElkczsKICAgIGNvbnN0IGluZGljZXMgPSBvcHRpb25zLmluZGljZXM7CiAgICBjb25zdCBiYXRjaElkcyA9IG9wdGlvbnMuYmF0Y2hJZHM7CiAgICBjb25zdCBiYXRjaFRhYmxlQ29sb3JzID0gb3B0aW9ucy5iYXRjaFRhYmxlQ29sb3JzOwogICAgY29uc3QgYmF0Y2hlZEluZGljZXMgPSBvcHRpb25zLmJhdGNoZWRJbmRpY2VzOwogICAgY29uc3QgaW5kZXhPZmZzZXRzID0gb3B0aW9ucy5pbmRleE9mZnNldHM7CiAgICBjb25zdCBpbmRleENvdW50cyA9IG9wdGlvbnMuaW5kZXhDb3VudHM7CiAgICBjb25zdCBib3VuZGluZ1ZvbHVtZXMgPSBvcHRpb25zLmJvdW5kaW5nVm9sdW1lczsKICAgIGNvbnN0IG1vZGVsTWF0cml4ID0gb3B0aW9ucy5tb2RlbE1hdHJpeDsKICAgIGNvbnN0IGNlbnRlciA9IG9wdGlvbnMuY2VudGVyOwogICAgbGV0IHBvc2l0aW9uT2Zmc2V0ID0gb3B0aW9ucy5wb3NpdGlvbk9mZnNldDsKICAgIGxldCBiYXRjaElkSW5kZXggPSBvcHRpb25zLmJhdGNoSWRJbmRleDsKICAgIGxldCBpbmRleE9mZnNldCA9IG9wdGlvbnMuaW5kZXhPZmZzZXQ7CiAgICBjb25zdCBiYXRjaGVkSW5kaWNlc09mZnNldCA9IG9wdGlvbnMuYmF0Y2hlZEluZGljZXNPZmZzZXQ7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtYmVyT2ZQcmltaXRpdmVzOyArK2kyKSB7CiAgICAgIGNvbnN0IHByaW1pdGl2ZU1vZGVsTWF0cml4QW5kQlYgPSBnZXRNb2RlbE1hdHJpeEFuZEJvdW5kaW5nVm9sdW1lKAogICAgICAgIHByaW1pdGl2ZSwKICAgICAgICBpMgogICAgICApOwogICAgICBjb25zdCBwcmltaXRpdmVNb2RlbE1hdHJpeCA9IHByaW1pdGl2ZU1vZGVsTWF0cml4QW5kQlYubW9kZWxNYXRyaXg7CiAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseShtb2RlbE1hdHJpeCwgcHJpbWl0aXZlTW9kZWxNYXRyaXgsIHByaW1pdGl2ZU1vZGVsTWF0cml4KTsKICAgICAgY29uc3QgYmF0Y2hJZCA9IHByaW1pdGl2ZUJhdGNoSWRzW2kyXTsKICAgICAgY29uc3QgcG9zaXRpb25zTGVuZ3RoID0gZ2VvbWV0cnlQb3NpdGlvbnMubGVuZ3RoOwogICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgcG9zaXRpb25zTGVuZ3RoOyBqMiArPSAzKSB7CiAgICAgICAgY29uc3QgcG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGdlb21ldHJ5UG9zaXRpb25zLCBqMiwgc2NyYXRjaFBvc2l0aW9uNSk7CiAgICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludChwcmltaXRpdmVNb2RlbE1hdHJpeCwgcG9zaXRpb24sIHBvc2l0aW9uKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocG9zaXRpb24sIGNlbnRlciwgcG9zaXRpb24pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHBvc2l0aW9uLCBwb3NpdGlvbnMsIHBvc2l0aW9uT2Zmc2V0ICogMyArIGoyKTsKICAgICAgICB2ZXJ0ZXhCYXRjaElkc1tiYXRjaElkSW5kZXgrK10gPSBiYXRjaElkOwogICAgICB9CiAgICAgIGNvbnN0IGluZGljZXNMZW5ndGggPSBnZW9tZXRyeUluZGljZXMubGVuZ3RoOwogICAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgaW5kaWNlc0xlbmd0aDsgKytrMikgewogICAgICAgIGluZGljZXNbaW5kZXhPZmZzZXQgKyBrMl0gPSBnZW9tZXRyeUluZGljZXNbazJdICsgcG9zaXRpb25PZmZzZXQ7CiAgICAgIH0KICAgICAgY29uc3Qgb2Zmc2V0ID0gaTIgKyBiYXRjaGVkSW5kaWNlc09mZnNldDsKICAgICAgYmF0Y2hlZEluZGljZXNbb2Zmc2V0XSA9IG5ldyBWZWN0b3IzRFRpbGVCYXRjaF9kZWZhdWx0KHsKICAgICAgICBvZmZzZXQ6IGluZGV4T2Zmc2V0LAogICAgICAgIGNvdW50OiBpbmRpY2VzTGVuZ3RoLAogICAgICAgIGNvbG9yOiBDb2xvcl9kZWZhdWx0LmZyb21SZ2JhKGJhdGNoVGFibGVDb2xvcnNbYmF0Y2hJZF0pLAogICAgICAgIGJhdGNoSWRzOiBbYmF0Y2hJZF0KICAgICAgfSk7CiAgICAgIGJhdGNoSWRzW29mZnNldF0gPSBiYXRjaElkOwogICAgICBpbmRleE9mZnNldHNbb2Zmc2V0XSA9IGluZGV4T2Zmc2V0OwogICAgICBpbmRleENvdW50c1tvZmZzZXRdID0gaW5kaWNlc0xlbmd0aDsKICAgICAgYm91bmRpbmdWb2x1bWVzW29mZnNldF0gPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnRyYW5zZm9ybSgKICAgICAgICBwcmltaXRpdmVNb2RlbE1hdHJpeEFuZEJWLmJvdW5kaW5nVm9sdW1lLAogICAgICAgIHByaW1pdGl2ZU1vZGVsTWF0cml4CiAgICAgICk7CiAgICAgIHBvc2l0aW9uT2Zmc2V0ICs9IHBvc2l0aW9uc0xlbmd0aCAvIDM7CiAgICAgIGluZGV4T2Zmc2V0ICs9IGluZGljZXNMZW5ndGg7CiAgICB9CiAgICBvcHRpb25zLnBvc2l0aW9uT2Zmc2V0ID0gcG9zaXRpb25PZmZzZXQ7CiAgICBvcHRpb25zLmJhdGNoSWRJbmRleCA9IGJhdGNoSWRJbmRleDsKICAgIG9wdGlvbnMuaW5kZXhPZmZzZXQgPSBpbmRleE9mZnNldDsKICAgIG9wdGlvbnMuYmF0Y2hlZEluZGljZXNPZmZzZXQgKz0gbnVtYmVyT2ZQcmltaXRpdmVzOwogIH0KICBmdW5jdGlvbiB1bnBhY2tCdWZmZXIoYnVmZmVyKSB7CiAgICBjb25zdCBwYWNrZWRCdWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KGJ1ZmZlcik7CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHNjcmF0Y2hDZW50ZXI1KTsKICAgIG9mZnNldCArPSBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgTWF0cml4NF9kZWZhdWx0LnVucGFjayhwYWNrZWRCdWZmZXIsIG9mZnNldCwgc2NyYXRjaE1hdHJpeDQpOwogIH0KICBmdW5jdGlvbiBwYWNrZWRCYXRjaGVkSW5kaWNlc0xlbmd0aChiYXRjaGVkSW5kaWNlcykgewogICAgY29uc3QgbGVuZ3RoID0gYmF0Y2hlZEluZGljZXMubGVuZ3RoOwogICAgbGV0IGNvdW50ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgY291bnQgKz0gQ29sb3JfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAzICsgYmF0Y2hlZEluZGljZXNbaTJdLmJhdGNoSWRzLmxlbmd0aDsKICAgIH0KICAgIHJldHVybiBjb3VudDsKICB9CiAgZnVuY3Rpb24gcGFja0J1ZmZlcihpbmRpY2VzQnl0ZXNQZXJFbGVtZW50LCBiYXRjaGVkSW5kaWNlcywgYm91bmRpbmdWb2x1bWVzKSB7CiAgICBjb25zdCBudW1CVnMgPSBib3VuZGluZ1ZvbHVtZXMubGVuZ3RoOwogICAgY29uc3QgbGVuZ3RoID0gMSArIDEgKyBudW1CVnMgKiBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDEgKyBwYWNrZWRCYXRjaGVkSW5kaWNlc0xlbmd0aChiYXRjaGVkSW5kaWNlcyk7CiAgICBjb25zdCBwYWNrZWRCdWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KGxlbmd0aCk7CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIHBhY2tlZEJ1ZmZlcltvZmZzZXQrK10gPSBpbmRpY2VzQnl0ZXNQZXJFbGVtZW50OwogICAgcGFja2VkQnVmZmVyW29mZnNldCsrXSA9IG51bUJWczsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBudW1CVnM7ICsraTIpIHsKICAgICAgQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5wYWNrKGJvdW5kaW5nVm9sdW1lc1tpMl0sIHBhY2tlZEJ1ZmZlciwgb2Zmc2V0KTsKICAgICAgb2Zmc2V0ICs9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgfQogICAgY29uc3QgaW5kaWNlc0xlbmd0aCA9IGJhdGNoZWRJbmRpY2VzLmxlbmd0aDsKICAgIHBhY2tlZEJ1ZmZlcltvZmZzZXQrK10gPSBpbmRpY2VzTGVuZ3RoOwogICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGluZGljZXNMZW5ndGg7ICsrajIpIHsKICAgICAgY29uc3QgYmF0Y2hlZEluZGV4ID0gYmF0Y2hlZEluZGljZXNbajJdOwogICAgICBDb2xvcl9kZWZhdWx0LnBhY2soYmF0Y2hlZEluZGV4LmNvbG9yLCBwYWNrZWRCdWZmZXIsIG9mZnNldCk7CiAgICAgIG9mZnNldCArPSBDb2xvcl9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgcGFja2VkQnVmZmVyW29mZnNldCsrXSA9IGJhdGNoZWRJbmRleC5vZmZzZXQ7CiAgICAgIHBhY2tlZEJ1ZmZlcltvZmZzZXQrK10gPSBiYXRjaGVkSW5kZXguY291bnQ7CiAgICAgIGNvbnN0IGJhdGNoSWRzID0gYmF0Y2hlZEluZGV4LmJhdGNoSWRzOwogICAgICBjb25zdCBiYXRjaElkc0xlbmd0aCA9IGJhdGNoSWRzLmxlbmd0aDsKICAgICAgcGFja2VkQnVmZmVyW29mZnNldCsrXSA9IGJhdGNoSWRzTGVuZ3RoOwogICAgICBmb3IgKGxldCBrMiA9IDA7IGsyIDwgYmF0Y2hJZHNMZW5ndGg7ICsrazIpIHsKICAgICAgICBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdID0gYmF0Y2hJZHNbazJdOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gcGFja2VkQnVmZmVyOwogIH0KICBmdW5jdGlvbiBjcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllcyhwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBib3hlcyA9IGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLmJveGVzKSA/IG5ldyBGbG9hdDMyQXJyYXkocGFyYW1ldGVycy5ib3hlcykgOiB2b2lkIDA7CiAgICBjb25zdCBib3hCYXRjaElkcyA9IGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLmJveEJhdGNoSWRzKSA/IG5ldyBVaW50MTZBcnJheShwYXJhbWV0ZXJzLmJveEJhdGNoSWRzKSA6IHZvaWQgMDsKICAgIGNvbnN0IGN5bGluZGVycyA9IGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLmN5bGluZGVycykgPyBuZXcgRmxvYXQzMkFycmF5KHBhcmFtZXRlcnMuY3lsaW5kZXJzKSA6IHZvaWQgMDsKICAgIGNvbnN0IGN5bGluZGVyQmF0Y2hJZHMgPSBkZWZpbmVkX2RlZmF1bHQocGFyYW1ldGVycy5jeWxpbmRlckJhdGNoSWRzKSA/IG5ldyBVaW50MTZBcnJheShwYXJhbWV0ZXJzLmN5bGluZGVyQmF0Y2hJZHMpIDogdm9pZCAwOwogICAgY29uc3QgZWxsaXBzb2lkcyA9IGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLmVsbGlwc29pZHMpID8gbmV3IEZsb2F0MzJBcnJheShwYXJhbWV0ZXJzLmVsbGlwc29pZHMpIDogdm9pZCAwOwogICAgY29uc3QgZWxsaXBzb2lkQmF0Y2hJZHMgPSBkZWZpbmVkX2RlZmF1bHQocGFyYW1ldGVycy5lbGxpcHNvaWRCYXRjaElkcykgPyBuZXcgVWludDE2QXJyYXkocGFyYW1ldGVycy5lbGxpcHNvaWRCYXRjaElkcykgOiB2b2lkIDA7CiAgICBjb25zdCBzcGhlcmVzID0gZGVmaW5lZF9kZWZhdWx0KHBhcmFtZXRlcnMuc3BoZXJlcykgPyBuZXcgRmxvYXQzMkFycmF5KHBhcmFtZXRlcnMuc3BoZXJlcykgOiB2b2lkIDA7CiAgICBjb25zdCBzcGhlcmVCYXRjaElkcyA9IGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLnNwaGVyZUJhdGNoSWRzKSA/IG5ldyBVaW50MTZBcnJheShwYXJhbWV0ZXJzLnNwaGVyZUJhdGNoSWRzKSA6IHZvaWQgMDsKICAgIGNvbnN0IG51bWJlck9mQm94ZXMgPSBkZWZpbmVkX2RlZmF1bHQoYm94ZXMpID8gYm94QmF0Y2hJZHMubGVuZ3RoIDogMDsKICAgIGNvbnN0IG51bWJlck9mQ3lsaW5kZXJzID0gZGVmaW5lZF9kZWZhdWx0KGN5bGluZGVycykgPyBjeWxpbmRlckJhdGNoSWRzLmxlbmd0aCA6IDA7CiAgICBjb25zdCBudW1iZXJPZkVsbGlwc29pZHMgPSBkZWZpbmVkX2RlZmF1bHQoZWxsaXBzb2lkcykgPyBlbGxpcHNvaWRCYXRjaElkcy5sZW5ndGggOiAwOwogICAgY29uc3QgbnVtYmVyT2ZTcGhlcmVzID0gZGVmaW5lZF9kZWZhdWx0KHNwaGVyZXMpID8gc3BoZXJlQmF0Y2hJZHMubGVuZ3RoIDogMDsKICAgIGNvbnN0IGJveEdlb21ldHJ5ID0gQm94R2VvbWV0cnlfZGVmYXVsdC5nZXRVbml0Qm94KCk7CiAgICBjb25zdCBjeWxpbmRlckdlb21ldHJ5ID0gQ3lsaW5kZXJHZW9tZXRyeV9kZWZhdWx0LmdldFVuaXRDeWxpbmRlcigpOwogICAgY29uc3QgZWxsaXBzb2lkR2VvbWV0cnkgPSBFbGxpcHNvaWRHZW9tZXRyeV9kZWZhdWx0LmdldFVuaXRFbGxpcHNvaWQoKTsKICAgIGNvbnN0IGJveFBvc2l0aW9ucyA9IGJveEdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgY29uc3QgY3lsaW5kZXJQb3NpdGlvbnMgPSBjeWxpbmRlckdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24udmFsdWVzOwogICAgY29uc3QgZWxsaXBzb2lkUG9zaXRpb25zID0gZWxsaXBzb2lkR2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi52YWx1ZXM7CiAgICBsZXQgbnVtYmVyT2ZQb3NpdGlvbnMgPSBib3hQb3NpdGlvbnMubGVuZ3RoICogbnVtYmVyT2ZCb3hlczsKICAgIG51bWJlck9mUG9zaXRpb25zICs9IGN5bGluZGVyUG9zaXRpb25zLmxlbmd0aCAqIG51bWJlck9mQ3lsaW5kZXJzOwogICAgbnVtYmVyT2ZQb3NpdGlvbnMgKz0gZWxsaXBzb2lkUG9zaXRpb25zLmxlbmd0aCAqIChudW1iZXJPZkVsbGlwc29pZHMgKyBudW1iZXJPZlNwaGVyZXMpOwogICAgY29uc3QgYm94SW5kaWNlcyA9IGJveEdlb21ldHJ5LmluZGljZXM7CiAgICBjb25zdCBjeWxpbmRlckluZGljZXMgPSBjeWxpbmRlckdlb21ldHJ5LmluZGljZXM7CiAgICBjb25zdCBlbGxpcHNvaWRJbmRpY2VzID0gZWxsaXBzb2lkR2VvbWV0cnkuaW5kaWNlczsKICAgIGxldCBudW1iZXJPZkluZGljZXMgPSBib3hJbmRpY2VzLmxlbmd0aCAqIG51bWJlck9mQm94ZXM7CiAgICBudW1iZXJPZkluZGljZXMgKz0gY3lsaW5kZXJJbmRpY2VzLmxlbmd0aCAqIG51bWJlck9mQ3lsaW5kZXJzOwogICAgbnVtYmVyT2ZJbmRpY2VzICs9IGVsbGlwc29pZEluZGljZXMubGVuZ3RoICogKG51bWJlck9mRWxsaXBzb2lkcyArIG51bWJlck9mU3BoZXJlcyk7CiAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KG51bWJlck9mUG9zaXRpb25zKTsKICAgIGNvbnN0IHZlcnRleEJhdGNoSWRzID0gbmV3IFVpbnQxNkFycmF5KG51bWJlck9mUG9zaXRpb25zIC8gMyk7CiAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkoCiAgICAgIG51bWJlck9mUG9zaXRpb25zIC8gMywKICAgICAgbnVtYmVyT2ZJbmRpY2VzCiAgICApOwogICAgY29uc3QgbnVtYmVyT2ZHZW9tZXRyaWVzID0gbnVtYmVyT2ZCb3hlcyArIG51bWJlck9mQ3lsaW5kZXJzICsgbnVtYmVyT2ZFbGxpcHNvaWRzICsgbnVtYmVyT2ZTcGhlcmVzOwogICAgY29uc3QgYmF0Y2hJZHMgPSBuZXcgVWludDE2QXJyYXkobnVtYmVyT2ZHZW9tZXRyaWVzKTsKICAgIGNvbnN0IGJhdGNoZWRJbmRpY2VzID0gbmV3IEFycmF5KG51bWJlck9mR2VvbWV0cmllcyk7CiAgICBjb25zdCBpbmRleE9mZnNldHMgPSBuZXcgVWludDMyQXJyYXkobnVtYmVyT2ZHZW9tZXRyaWVzKTsKICAgIGNvbnN0IGluZGV4Q291bnRzID0gbmV3IFVpbnQzMkFycmF5KG51bWJlck9mR2VvbWV0cmllcyk7CiAgICBjb25zdCBib3VuZGluZ1ZvbHVtZXMgPSBuZXcgQXJyYXkobnVtYmVyT2ZHZW9tZXRyaWVzKTsKICAgIHVucGFja0J1ZmZlcihwYXJhbWV0ZXJzLnBhY2tlZEJ1ZmZlcik7CiAgICBjb25zdCBvcHRpb25zID0gewogICAgICBiYXRjaFRhYmxlQ29sb3JzOiBuZXcgVWludDMyQXJyYXkocGFyYW1ldGVycy5iYXRjaFRhYmxlQ29sb3JzKSwKICAgICAgcG9zaXRpb25zLAogICAgICB2ZXJ0ZXhCYXRjaElkcywKICAgICAgaW5kaWNlcywKICAgICAgYmF0Y2hJZHMsCiAgICAgIGJhdGNoZWRJbmRpY2VzLAogICAgICBpbmRleE9mZnNldHMsCiAgICAgIGluZGV4Q291bnRzLAogICAgICBib3VuZGluZ1ZvbHVtZXMsCiAgICAgIHBvc2l0aW9uT2Zmc2V0OiAwLAogICAgICBiYXRjaElkSW5kZXg6IDAsCiAgICAgIGluZGV4T2Zmc2V0OiAwLAogICAgICBiYXRjaGVkSW5kaWNlc09mZnNldDogMCwKICAgICAgbW9kZWxNYXRyaXg6IHNjcmF0Y2hNYXRyaXg0LAogICAgICBjZW50ZXI6IHNjcmF0Y2hDZW50ZXI1CiAgICB9OwogICAgY3JlYXRlUHJpbWl0aXZlKAogICAgICBvcHRpb25zLAogICAgICBib3hlcywKICAgICAgYm94QmF0Y2hJZHMsCiAgICAgIGJveEdlb21ldHJ5LAogICAgICBib3hNb2RlbE1hdHJpeEFuZEJvdW5kaW5nVm9sdW1lCiAgICApOwogICAgY3JlYXRlUHJpbWl0aXZlKAogICAgICBvcHRpb25zLAogICAgICBjeWxpbmRlcnMsCiAgICAgIGN5bGluZGVyQmF0Y2hJZHMsCiAgICAgIGN5bGluZGVyR2VvbWV0cnksCiAgICAgIGN5bGluZGVyTW9kZWxNYXRyaXhBbmRCb3VuZGluZ1ZvbHVtZQogICAgKTsKICAgIGNyZWF0ZVByaW1pdGl2ZSgKICAgICAgb3B0aW9ucywKICAgICAgZWxsaXBzb2lkcywKICAgICAgZWxsaXBzb2lkQmF0Y2hJZHMsCiAgICAgIGVsbGlwc29pZEdlb21ldHJ5LAogICAgICBlbGxpcHNvaWRNb2RlbE1hdHJpeEFuZEJvdW5kaW5nVm9sdW1lCiAgICApOwogICAgY3JlYXRlUHJpbWl0aXZlKAogICAgICBvcHRpb25zLAogICAgICBzcGhlcmVzLAogICAgICBzcGhlcmVCYXRjaElkcywKICAgICAgZWxsaXBzb2lkR2VvbWV0cnksCiAgICAgIHNwaGVyZU1vZGVsTWF0cml4QW5kQm91bmRpbmdWb2x1bWUKICAgICk7CiAgICBjb25zdCBwYWNrZWRCdWZmZXIgPSBwYWNrQnVmZmVyKAogICAgICBpbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5ULAogICAgICBiYXRjaGVkSW5kaWNlcywKICAgICAgYm91bmRpbmdWb2x1bWVzCiAgICApOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICBwb3NpdGlvbnMuYnVmZmVyLAogICAgICB2ZXJ0ZXhCYXRjaElkcy5idWZmZXIsCiAgICAgIGluZGljZXMuYnVmZmVyCiAgICApOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICBiYXRjaElkcy5idWZmZXIsCiAgICAgIGluZGV4T2Zmc2V0cy5idWZmZXIsCiAgICAgIGluZGV4Q291bnRzLmJ1ZmZlcgogICAgKTsKICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChwYWNrZWRCdWZmZXIuYnVmZmVyKTsKICAgIHJldHVybiB7CiAgICAgIHBvc2l0aW9uczogcG9zaXRpb25zLmJ1ZmZlciwKICAgICAgdmVydGV4QmF0Y2hJZHM6IHZlcnRleEJhdGNoSWRzLmJ1ZmZlciwKICAgICAgaW5kaWNlczogaW5kaWNlcy5idWZmZXIsCiAgICAgIGluZGV4T2Zmc2V0czogaW5kZXhPZmZzZXRzLmJ1ZmZlciwKICAgICAgaW5kZXhDb3VudHM6IGluZGV4Q291bnRzLmJ1ZmZlciwKICAgICAgYmF0Y2hJZHM6IGJhdGNoSWRzLmJ1ZmZlciwKICAgICAgcGFja2VkQnVmZmVyOiBwYWNrZWRCdWZmZXIuYnVmZmVyCiAgICB9OwogIH0KICB2YXIgc2NyYXRjaENhcnRlc2lhbjExLCBwYWNrZWRCb3hMZW5ndGgsIHBhY2tlZEN5bGluZGVyTGVuZ3RoLCBwYWNrZWRFbGxpcHNvaWRMZW5ndGgsIHBhY2tlZFNwaGVyZUxlbmd0aCwgc2NyYXRjaE1vZGVsTWF0cml4QW5kQlYsIHNjcmF0Y2hQb3NpdGlvbjUsIHNjcmF0Y2hDZW50ZXI1LCBzY3JhdGNoTWF0cml4NCwgY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXNfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllcyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXMuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQm94R2VvbWV0cnkoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ29sb3IoKTsKICAgICAgaW5pdF9DeWxpbmRlckdlb21ldHJ5KCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZEdlb21ldHJ5KCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9WZWN0b3IzRFRpbGVCYXRjaCgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjExID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBwYWNrZWRCb3hMZW5ndGggPSBNYXRyaXg0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgcGFja2VkQ3lsaW5kZXJMZW5ndGggPSBNYXRyaXg0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgMjsKICAgICAgcGFja2VkRWxsaXBzb2lkTGVuZ3RoID0gTWF0cml4NF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgIHBhY2tlZFNwaGVyZUxlbmd0aCA9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAxOwogICAgICBzY3JhdGNoTW9kZWxNYXRyaXhBbmRCViA9IHsKICAgICAgICBtb2RlbE1hdHJpeDogbmV3IE1hdHJpeDRfZGVmYXVsdCgpLAogICAgICAgIGJvdW5kaW5nVm9sdW1lOiBuZXcgQm91bmRpbmdTcGhlcmVfZGVmYXVsdCgpCiAgICAgIH07CiAgICAgIHNjcmF0Y2hQb3NpdGlvbjUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDZW50ZXI1ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTWF0cml4NCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXNfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChjcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllcyk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZWN0b3JUaWxlUG9pbnRzLmpzCiAgdmFyIGNyZWF0ZVZlY3RvclRpbGVQb2ludHNfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVZlY3RvclRpbGVQb2ludHNfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlVmVjdG9yVGlsZVBvaW50c19kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gdW5wYWNrQnVmZmVyMihwYWNrZWRCdWZmZXIpIHsKICAgIHBhY2tlZEJ1ZmZlciA9IG5ldyBGbG9hdDY0QXJyYXkocGFja2VkQnVmZmVyKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgc2NyYXRjaE1pbk1heEhlaWdodHMubWluID0gcGFja2VkQnVmZmVyW29mZnNldCsrXTsKICAgIHNjcmF0Y2hNaW5NYXhIZWlnaHRzLm1heCA9IHBhY2tlZEJ1ZmZlcltvZmZzZXQrK107CiAgICBSZWN0YW5nbGVfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHNjcmF0Y2hSZWN0YW5nbGU0KTsKICAgIG9mZnNldCArPSBSZWN0YW5nbGVfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHNjcmF0Y2hFbGxpcHNvaWQxNCk7CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZVZlY3RvclRpbGVQb2ludHMocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgcG9zaXRpb25zID0gbmV3IFVpbnQxNkFycmF5KHBhcmFtZXRlcnMucG9zaXRpb25zKTsKICAgIHVucGFja0J1ZmZlcjIocGFyYW1ldGVycy5wYWNrZWRCdWZmZXIpOwogICAgY29uc3QgcmVjdGFuZ2xlID0gc2NyYXRjaFJlY3RhbmdsZTQ7CiAgICBjb25zdCBlbGxpcHNvaWQgPSBzY3JhdGNoRWxsaXBzb2lkMTQ7CiAgICBjb25zdCBtaW5pbXVtSGVpZ2h0ID0gc2NyYXRjaE1pbk1heEhlaWdodHMubWluOwogICAgY29uc3QgbWF4aW11bUhlaWdodCA9IHNjcmF0Y2hNaW5NYXhIZWlnaHRzLm1heDsKICAgIGNvbnN0IHBvc2l0aW9uc0xlbmd0aCA9IHBvc2l0aW9ucy5sZW5ndGggLyAzOwogICAgY29uc3QgdUJ1ZmZlciA9IHBvc2l0aW9ucy5zdWJhcnJheSgwLCBwb3NpdGlvbnNMZW5ndGgpOwogICAgY29uc3QgdkJ1ZmZlciA9IHBvc2l0aW9ucy5zdWJhcnJheShwb3NpdGlvbnNMZW5ndGgsIDIgKiBwb3NpdGlvbnNMZW5ndGgpOwogICAgY29uc3QgaGVpZ2h0QnVmZmVyID0gcG9zaXRpb25zLnN1YmFycmF5KAogICAgICAyICogcG9zaXRpb25zTGVuZ3RoLAogICAgICAzICogcG9zaXRpb25zTGVuZ3RoCiAgICApOwogICAgQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC56aWdaYWdEZWx0YURlY29kZSh1QnVmZmVyLCB2QnVmZmVyLCBoZWlnaHRCdWZmZXIpOwogICAgY29uc3QgZGVjb2RlZCA9IG5ldyBGbG9hdDY0QXJyYXkocG9zaXRpb25zLmxlbmd0aCk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcG9zaXRpb25zTGVuZ3RoOyArK2kyKSB7CiAgICAgIGNvbnN0IHU0ID0gdUJ1ZmZlcltpMl07CiAgICAgIGNvbnN0IHY0ID0gdkJ1ZmZlcltpMl07CiAgICAgIGNvbnN0IGgyID0gaGVpZ2h0QnVmZmVyW2kyXTsKICAgICAgY29uc3QgbG9uID0gTWF0aF9kZWZhdWx0LmxlcnAocmVjdGFuZ2xlLndlc3QsIHJlY3RhbmdsZS5lYXN0LCB1NCAvIG1heFNob3J0KTsKICAgICAgY29uc3QgbGF0ID0gTWF0aF9kZWZhdWx0LmxlcnAocmVjdGFuZ2xlLnNvdXRoLCByZWN0YW5nbGUubm9ydGgsIHY0IC8gbWF4U2hvcnQpOwogICAgICBjb25zdCBhbHQgPSBNYXRoX2RlZmF1bHQubGVycChtaW5pbXVtSGVpZ2h0LCBtYXhpbXVtSGVpZ2h0LCBoMiAvIG1heFNob3J0KTsKICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21SYWRpYW5zKAogICAgICAgIGxvbiwKICAgICAgICBsYXQsCiAgICAgICAgYWx0LAogICAgICAgIHNjcmF0Y2hCVkNhcnRvZ3JhcGhpYzIKICAgICAgKTsKICAgICAgY29uc3QgZGVjb2RlZFBvc2l0aW9uID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKAogICAgICAgIGNhcnRvZ3JhcGhpYzIsCiAgICAgICAgc2NyYXRjaEVuY29kZWRQb3NpdGlvbjIKICAgICAgKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soZGVjb2RlZFBvc2l0aW9uLCBkZWNvZGVkLCBpMiAqIDMpOwogICAgfQogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGRlY29kZWQuYnVmZmVyKTsKICAgIHJldHVybiB7CiAgICAgIHBvc2l0aW9uczogZGVjb2RlZC5idWZmZXIKICAgIH07CiAgfQogIHZhciBtYXhTaG9ydCwgc2NyYXRjaEJWQ2FydG9ncmFwaGljMiwgc2NyYXRjaEVuY29kZWRQb3NpdGlvbjIsIHNjcmF0Y2hSZWN0YW5nbGU0LCBzY3JhdGNoRWxsaXBzb2lkMTQsIHNjcmF0Y2hNaW5NYXhIZWlnaHRzLCBjcmVhdGVWZWN0b3JUaWxlUG9pbnRzX2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlVmVjdG9yVGlsZVBvaW50cyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVjdG9yVGlsZVBvaW50cy5qcyIoKSB7CiAgICAgIGluaXRfQXR0cmlidXRlQ29tcHJlc3Npb24oKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgbWF4U2hvcnQgPSAzMjc2NzsKICAgICAgc2NyYXRjaEJWQ2FydG9ncmFwaGljMiA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRW5jb2RlZFBvc2l0aW9uMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFJlY3RhbmdsZTQgPSBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDE0ID0gbmV3IEVsbGlwc29pZF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5NYXhIZWlnaHRzID0gewogICAgICAgIG1pbjogdm9pZCAwLAogICAgICAgIG1heDogdm9pZCAwCiAgICAgIH07CiAgICAgIGNyZWF0ZVZlY3RvclRpbGVQb2ludHNfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChjcmVhdGVWZWN0b3JUaWxlUG9pbnRzKTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVZlY3RvclRpbGVQb2x5Z29ucy5qcwogIHZhciBjcmVhdGVWZWN0b3JUaWxlUG9seWdvbnNfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVZlY3RvclRpbGVQb2x5Z29uc19leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVWZWN0b3JUaWxlUG9seWdvbnNfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIHVucGFja0J1ZmZlcjMoYnVmZmVyKSB7CiAgICBjb25zdCBwYWNrZWRCdWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KGJ1ZmZlcik7CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIHNjcmF0Y2hTY2FsYXJzLmluZGV4Qnl0ZXNQZXJFbGVtZW50ID0gcGFja2VkQnVmZmVyW29mZnNldCsrXTsKICAgIHNjcmF0Y2hTY2FsYXJzLm1pbiA9IHBhY2tlZEJ1ZmZlcltvZmZzZXQrK107CiAgICBzY3JhdGNoU2NhbGFycy5tYXggPSBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjayhwYWNrZWRCdWZmZXIsIG9mZnNldCwgc2NyYXRjaENlbnRlcjYpOwogICAgb2Zmc2V0ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHNjcmF0Y2hFbGxpcHNvaWQxNSk7CiAgICBvZmZzZXQgKz0gRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgUmVjdGFuZ2xlX2RlZmF1bHQudW5wYWNrKHBhY2tlZEJ1ZmZlciwgb2Zmc2V0LCBzY3JhdGNoUmVjdGFuZ2xlNSk7CiAgfQogIGZ1bmN0aW9uIHBhY2tlZEJhdGNoZWRJbmRpY2VzTGVuZ3RoMihiYXRjaGVkSW5kaWNlcykgewogICAgY29uc3QgbGVuZ3RoID0gYmF0Y2hlZEluZGljZXMubGVuZ3RoOwogICAgbGV0IGNvdW50ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgY291bnQgKz0gQ29sb3JfZGVmYXVsdC5wYWNrZWRMZW5ndGggKyAzICsgYmF0Y2hlZEluZGljZXNbaTJdLmJhdGNoSWRzLmxlbmd0aDsKICAgIH0KICAgIHJldHVybiBjb3VudDsKICB9CiAgZnVuY3Rpb24gcGFja0J1ZmZlcjIoaW5kZXhEYXRhdHlwZSwgYm91bmRpbmdWb2x1bWVzLCBiYXRjaGVkSW5kaWNlcykgewogICAgY29uc3QgbnVtQlZzID0gYm91bmRpbmdWb2x1bWVzLmxlbmd0aDsKICAgIGNvbnN0IGxlbmd0aCA9IDEgKyAxICsgbnVtQlZzICogT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LnBhY2tlZExlbmd0aCArIDEgKyBwYWNrZWRCYXRjaGVkSW5kaWNlc0xlbmd0aDIoYmF0Y2hlZEluZGljZXMpOwogICAgY29uc3QgcGFja2VkQnVmZmVyID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGgpOwogICAgbGV0IG9mZnNldCA9IDA7CiAgICBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdID0gaW5kZXhEYXRhdHlwZTsKICAgIHBhY2tlZEJ1ZmZlcltvZmZzZXQrK10gPSBudW1CVnM7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtQlZzOyArK2kyKSB7CiAgICAgIE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdC5wYWNrKGJvdW5kaW5nVm9sdW1lc1tpMl0sIHBhY2tlZEJ1ZmZlciwgb2Zmc2V0KTsKICAgICAgb2Zmc2V0ICs9IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICB9CiAgICBjb25zdCBpbmRpY2VzTGVuZ3RoID0gYmF0Y2hlZEluZGljZXMubGVuZ3RoOwogICAgcGFja2VkQnVmZmVyW29mZnNldCsrXSA9IGluZGljZXNMZW5ndGg7CiAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgaW5kaWNlc0xlbmd0aDsgKytqMikgewogICAgICBjb25zdCBiYXRjaGVkSW5kZXggPSBiYXRjaGVkSW5kaWNlc1tqMl07CiAgICAgIENvbG9yX2RlZmF1bHQucGFjayhiYXRjaGVkSW5kZXguY29sb3IsIHBhY2tlZEJ1ZmZlciwgb2Zmc2V0KTsKICAgICAgb2Zmc2V0ICs9IENvbG9yX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgICBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdID0gYmF0Y2hlZEluZGV4Lm9mZnNldDsKICAgICAgcGFja2VkQnVmZmVyW29mZnNldCsrXSA9IGJhdGNoZWRJbmRleC5jb3VudDsKICAgICAgY29uc3QgYmF0Y2hJZHMgPSBiYXRjaGVkSW5kZXguYmF0Y2hJZHM7CiAgICAgIGNvbnN0IGJhdGNoSWRzTGVuZ3RoID0gYmF0Y2hJZHMubGVuZ3RoOwogICAgICBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdID0gYmF0Y2hJZHNMZW5ndGg7CiAgICAgIGZvciAobGV0IGsyID0gMDsgazIgPCBiYXRjaElkc0xlbmd0aDsgKytrMikgewogICAgICAgIHBhY2tlZEJ1ZmZlcltvZmZzZXQrK10gPSBiYXRjaElkc1trMl07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBwYWNrZWRCdWZmZXI7CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZVZlY3RvclRpbGVQb2x5Z29ucyhwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICB1bnBhY2tCdWZmZXIzKHBhcmFtZXRlcnMucGFja2VkQnVmZmVyKTsKICAgIGxldCBpbmRpY2VzOwogICAgY29uc3QgaW5kZXhCeXRlc1BlckVsZW1lbnQgPSBzY3JhdGNoU2NhbGFycy5pbmRleEJ5dGVzUGVyRWxlbWVudDsKICAgIGlmIChpbmRleEJ5dGVzUGVyRWxlbWVudCA9PT0gMikgewogICAgICBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KHBhcmFtZXRlcnMuaW5kaWNlcyk7CiAgICB9IGVsc2UgewogICAgICBpbmRpY2VzID0gbmV3IFVpbnQzMkFycmF5KHBhcmFtZXRlcnMuaW5kaWNlcyk7CiAgICB9CiAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgVWludDE2QXJyYXkocGFyYW1ldGVycy5wb3NpdGlvbnMpOwogICAgY29uc3QgY291bnRzID0gbmV3IFVpbnQzMkFycmF5KHBhcmFtZXRlcnMuY291bnRzKTsKICAgIGNvbnN0IGluZGV4Q291bnRzID0gbmV3IFVpbnQzMkFycmF5KHBhcmFtZXRlcnMuaW5kZXhDb3VudHMpOwogICAgY29uc3QgYmF0Y2hJZHMgPSBuZXcgVWludDMyQXJyYXkocGFyYW1ldGVycy5iYXRjaElkcyk7CiAgICBjb25zdCBiYXRjaFRhYmxlQ29sb3JzID0gbmV3IFVpbnQzMkFycmF5KHBhcmFtZXRlcnMuYmF0Y2hUYWJsZUNvbG9ycyk7CiAgICBjb25zdCBib3VuZGluZ1ZvbHVtZXMgPSBuZXcgQXJyYXkoY291bnRzLmxlbmd0aCk7CiAgICBjb25zdCBjZW50ZXIgPSBzY3JhdGNoQ2VudGVyNjsKICAgIGNvbnN0IGVsbGlwc29pZCA9IHNjcmF0Y2hFbGxpcHNvaWQxNTsKICAgIGxldCByZWN0YW5nbGUgPSBzY3JhdGNoUmVjdGFuZ2xlNTsKICAgIGNvbnN0IG1pbkhlaWdodCA9IHNjcmF0Y2hTY2FsYXJzLm1pbjsKICAgIGNvbnN0IG1heEhlaWdodCA9IHNjcmF0Y2hTY2FsYXJzLm1heDsKICAgIGxldCBtaW5pbXVtSGVpZ2h0cyA9IHBhcmFtZXRlcnMubWluaW11bUhlaWdodHM7CiAgICBsZXQgbWF4aW11bUhlaWdodHMgPSBwYXJhbWV0ZXJzLm1heGltdW1IZWlnaHRzOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChtaW5pbXVtSGVpZ2h0cykgJiYgZGVmaW5lZF9kZWZhdWx0KG1heGltdW1IZWlnaHRzKSkgewogICAgICBtaW5pbXVtSGVpZ2h0cyA9IG5ldyBGbG9hdDMyQXJyYXkobWluaW11bUhlaWdodHMpOwogICAgICBtYXhpbXVtSGVpZ2h0cyA9IG5ldyBGbG9hdDMyQXJyYXkobWF4aW11bUhlaWdodHMpOwogICAgfQogICAgbGV0IGkyOwogICAgbGV0IGoyOwogICAgbGV0IHJnYmE7CiAgICBjb25zdCBwb3NpdGlvbnNMZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMjsKICAgIGNvbnN0IHVCdWZmZXIgPSBwb3NpdGlvbnMuc3ViYXJyYXkoMCwgcG9zaXRpb25zTGVuZ3RoKTsKICAgIGNvbnN0IHZCdWZmZXIgPSBwb3NpdGlvbnMuc3ViYXJyYXkocG9zaXRpb25zTGVuZ3RoLCAyICogcG9zaXRpb25zTGVuZ3RoKTsKICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuemlnWmFnRGVsdGFEZWNvZGUodUJ1ZmZlciwgdkJ1ZmZlcik7CiAgICBjb25zdCBkZWNvZGVkUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheShwb3NpdGlvbnNMZW5ndGggKiAzKTsKICAgIGZvciAoaTIgPSAwOyBpMiA8IHBvc2l0aW9uc0xlbmd0aDsgKytpMikgewogICAgICBjb25zdCB1NCA9IHVCdWZmZXJbaTJdOwogICAgICBjb25zdCB2NCA9IHZCdWZmZXJbaTJdOwogICAgICBjb25zdCB4MiA9IE1hdGhfZGVmYXVsdC5sZXJwKHJlY3RhbmdsZS53ZXN0LCByZWN0YW5nbGUuZWFzdCwgdTQgLyBtYXhTaG9ydDIpOwogICAgICBjb25zdCB5MiA9IE1hdGhfZGVmYXVsdC5sZXJwKHJlY3RhbmdsZS5zb3V0aCwgcmVjdGFuZ2xlLm5vcnRoLCB2NCAvIG1heFNob3J0Mik7CiAgICAgIGNvbnN0IGNhcnQgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucyh4MiwgeTIsIDAsIHNjcmF0Y2hCVkNhcnRvZ3JhcGhpYzMpOwogICAgICBjb25zdCBkZWNvZGVkUG9zaXRpb24gPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgY2FydCwKICAgICAgICBzY3JhdGNoRW5jb2RlZFBvc2l0aW9uMwogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhkZWNvZGVkUG9zaXRpb24sIGRlY29kZWRQb3NpdGlvbnMsIGkyICogMyk7CiAgICB9CiAgICBjb25zdCBjb3VudHNMZW5ndGggPSBjb3VudHMubGVuZ3RoOwogICAgY29uc3Qgb2Zmc2V0cyA9IG5ldyBBcnJheShjb3VudHNMZW5ndGgpOwogICAgY29uc3QgaW5kZXhPZmZzZXRzID0gbmV3IEFycmF5KGNvdW50c0xlbmd0aCk7CiAgICBsZXQgY3VycmVudE9mZnNldCA9IDA7CiAgICBsZXQgY3VycmVudEluZGV4T2Zmc2V0ID0gMDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGNvdW50c0xlbmd0aDsgKytpMikgewogICAgICBvZmZzZXRzW2kyXSA9IGN1cnJlbnRPZmZzZXQ7CiAgICAgIGluZGV4T2Zmc2V0c1tpMl0gPSBjdXJyZW50SW5kZXhPZmZzZXQ7CiAgICAgIGN1cnJlbnRPZmZzZXQgKz0gY291bnRzW2kyXTsKICAgICAgY3VycmVudEluZGV4T2Zmc2V0ICs9IGluZGV4Q291bnRzW2kyXTsKICAgIH0KICAgIGNvbnN0IGJhdGNoZWRQb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KHBvc2l0aW9uc0xlbmd0aCAqIDMgKiAyKTsKICAgIGNvbnN0IGJhdGNoZWRJZHMgPSBuZXcgVWludDE2QXJyYXkocG9zaXRpb25zTGVuZ3RoICogMik7CiAgICBjb25zdCBiYXRjaGVkSW5kZXhPZmZzZXRzID0gbmV3IFVpbnQzMkFycmF5KGluZGV4T2Zmc2V0cy5sZW5ndGgpOwogICAgY29uc3QgYmF0Y2hlZEluZGV4Q291bnRzID0gbmV3IFVpbnQzMkFycmF5KGluZGV4Q291bnRzLmxlbmd0aCk7CiAgICBsZXQgYmF0Y2hlZEluZGljZXMgPSBbXTsKICAgIGNvbnN0IGNvbG9yVG9CdWZmZXJzID0ge307CiAgICBmb3IgKGkyID0gMDsgaTIgPCBjb3VudHNMZW5ndGg7ICsraTIpIHsKICAgICAgcmdiYSA9IGJhdGNoVGFibGVDb2xvcnNbaTJdOwogICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb2xvclRvQnVmZmVyc1tyZ2JhXSkpIHsKICAgICAgICBjb2xvclRvQnVmZmVyc1tyZ2JhXSA9IHsKICAgICAgICAgIHBvc2l0aW9uTGVuZ3RoOiBjb3VudHNbaTJdLAogICAgICAgICAgaW5kZXhMZW5ndGg6IGluZGV4Q291bnRzW2kyXSwKICAgICAgICAgIG9mZnNldDogMCwKICAgICAgICAgIGluZGV4T2Zmc2V0OiAwLAogICAgICAgICAgYmF0Y2hJZHM6IFtpMl0KICAgICAgICB9OwogICAgICB9IGVsc2UgewogICAgICAgIGNvbG9yVG9CdWZmZXJzW3JnYmFdLnBvc2l0aW9uTGVuZ3RoICs9IGNvdW50c1tpMl07CiAgICAgICAgY29sb3JUb0J1ZmZlcnNbcmdiYV0uaW5kZXhMZW5ndGggKz0gaW5kZXhDb3VudHNbaTJdOwogICAgICAgIGNvbG9yVG9CdWZmZXJzW3JnYmFdLmJhdGNoSWRzLnB1c2goaTIpOwogICAgICB9CiAgICB9CiAgICBsZXQgYnVmZmVyOwogICAgbGV0IGJ5Q29sb3JQb3NpdGlvbk9mZnNldCA9IDA7CiAgICBsZXQgYnlDb2xvckluZGV4T2Zmc2V0ID0gMDsKICAgIGZvciAocmdiYSBpbiBjb2xvclRvQnVmZmVycykgewogICAgICBpZiAoY29sb3JUb0J1ZmZlcnMuaGFzT3duUHJvcGVydHkocmdiYSkpIHsKICAgICAgICBidWZmZXIgPSBjb2xvclRvQnVmZmVyc1tyZ2JhXTsKICAgICAgICBidWZmZXIub2Zmc2V0ID0gYnlDb2xvclBvc2l0aW9uT2Zmc2V0OwogICAgICAgIGJ1ZmZlci5pbmRleE9mZnNldCA9IGJ5Q29sb3JJbmRleE9mZnNldDsKICAgICAgICBjb25zdCBwb3NpdGlvbkxlbmd0aCA9IGJ1ZmZlci5wb3NpdGlvbkxlbmd0aCAqIDI7CiAgICAgICAgY29uc3QgaW5kZXhMZW5ndGggPSBidWZmZXIuaW5kZXhMZW5ndGggKiAyICsgYnVmZmVyLnBvc2l0aW9uTGVuZ3RoICogNjsKICAgICAgICBieUNvbG9yUG9zaXRpb25PZmZzZXQgKz0gcG9zaXRpb25MZW5ndGg7CiAgICAgICAgYnlDb2xvckluZGV4T2Zmc2V0ICs9IGluZGV4TGVuZ3RoOwogICAgICAgIGJ1ZmZlci5pbmRleExlbmd0aCA9IGluZGV4TGVuZ3RoOwogICAgICB9CiAgICB9CiAgICBjb25zdCBiYXRjaGVkRHJhd0NhbGxzID0gW107CiAgICBmb3IgKHJnYmEgaW4gY29sb3JUb0J1ZmZlcnMpIHsKICAgICAgaWYgKGNvbG9yVG9CdWZmZXJzLmhhc093blByb3BlcnR5KHJnYmEpKSB7CiAgICAgICAgYnVmZmVyID0gY29sb3JUb0J1ZmZlcnNbcmdiYV07CiAgICAgICAgYmF0Y2hlZERyYXdDYWxscy5wdXNoKHsKICAgICAgICAgIGNvbG9yOiBDb2xvcl9kZWZhdWx0LmZyb21SZ2JhKHBhcnNlSW50KHJnYmEpKSwKICAgICAgICAgIG9mZnNldDogYnVmZmVyLmluZGV4T2Zmc2V0LAogICAgICAgICAgY291bnQ6IGJ1ZmZlci5pbmRleExlbmd0aCwKICAgICAgICAgIGJhdGNoSWRzOiBidWZmZXIuYmF0Y2hJZHMKICAgICAgICB9KTsKICAgICAgfQogICAgfQogICAgZm9yIChpMiA9IDA7IGkyIDwgY291bnRzTGVuZ3RoOyArK2kyKSB7CiAgICAgIHJnYmEgPSBiYXRjaFRhYmxlQ29sb3JzW2kyXTsKICAgICAgYnVmZmVyID0gY29sb3JUb0J1ZmZlcnNbcmdiYV07CiAgICAgIGNvbnN0IHBvc2l0aW9uT2Zmc2V0ID0gYnVmZmVyLm9mZnNldDsKICAgICAgbGV0IHBvc2l0aW9uSW5kZXggPSBwb3NpdGlvbk9mZnNldCAqIDM7CiAgICAgIGxldCBiYXRjaElkSW5kZXggPSBwb3NpdGlvbk9mZnNldDsKICAgICAgY29uc3QgcG9seWdvbk9mZnNldCA9IG9mZnNldHNbaTJdOwogICAgICBjb25zdCBwb2x5Z29uQ291bnQgPSBjb3VudHNbaTJdOwogICAgICBjb25zdCBiYXRjaElkID0gYmF0Y2hJZHNbaTJdOwogICAgICBsZXQgcG9seWdvbk1pbmltdW1IZWlnaHQgPSBtaW5IZWlnaHQ7CiAgICAgIGxldCBwb2x5Z29uTWF4aW11bUhlaWdodCA9IG1heEhlaWdodDsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChtaW5pbXVtSGVpZ2h0cykgJiYgZGVmaW5lZF9kZWZhdWx0KG1heGltdW1IZWlnaHRzKSkgewogICAgICAgIHBvbHlnb25NaW5pbXVtSGVpZ2h0ID0gbWluaW11bUhlaWdodHNbaTJdOwogICAgICAgIHBvbHlnb25NYXhpbXVtSGVpZ2h0ID0gbWF4aW11bUhlaWdodHNbaTJdOwogICAgICB9CiAgICAgIGxldCBtaW5MYXQgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgIGxldCBtYXhMYXQgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgIGxldCBtaW5Mb24gPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgIGxldCBtYXhMb24gPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgIGZvciAoajIgPSAwOyBqMiA8IHBvbHlnb25Db3VudDsgKytqMikgewogICAgICAgIGNvbnN0IHBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgIGRlY29kZWRQb3NpdGlvbnMsCiAgICAgICAgICBwb2x5Z29uT2Zmc2V0ICogMyArIGoyICogMywKICAgICAgICAgIHNjcmF0Y2hFbmNvZGVkUG9zaXRpb24zCiAgICAgICAgKTsKICAgICAgICBlbGxpcHNvaWQuc2NhbGVUb0dlb2RldGljU3VyZmFjZShwb3NpdGlvbiwgcG9zaXRpb24pOwogICAgICAgIGNvbnN0IGNhcnRvID0gZWxsaXBzb2lkLmNhcnRlc2lhblRvQ2FydG9ncmFwaGljKAogICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICBzY3JhdGNoQlZDYXJ0b2dyYXBoaWMzCiAgICAgICAgKTsKICAgICAgICBjb25zdCBsYXQgPSBjYXJ0by5sYXRpdHVkZTsKICAgICAgICBjb25zdCBsb24gPSBjYXJ0by5sb25naXR1ZGU7CiAgICAgICAgbWluTGF0ID0gTWF0aC5taW4obGF0LCBtaW5MYXQpOwogICAgICAgIG1heExhdCA9IE1hdGgubWF4KGxhdCwgbWF4TGF0KTsKICAgICAgICBtaW5Mb24gPSBNYXRoLm1pbihsb24sIG1pbkxvbik7CiAgICAgICAgbWF4TG9uID0gTWF0aC5tYXgobG9uLCBtYXhMb24pOwogICAgICAgIGNvbnN0IG5vcm1hbDIgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uLCBzY3JhdGNoTm9ybWFsNyk7CiAgICAgICAgbGV0IHNjYWxlZE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgbm9ybWFsMiwKICAgICAgICAgIHBvbHlnb25NaW5pbXVtSGVpZ2h0LAogICAgICAgICAgc2NyYXRjaFNjYWxlZE5vcm1hbAogICAgICAgICk7CiAgICAgICAgY29uc3QgbWluSGVpZ2h0UG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuYWRkKAogICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICBzY2FsZWROb3JtYWwsCiAgICAgICAgICBzY3JhdGNoTWluSGVpZ2h0UG9zaXRpb24KICAgICAgICApOwogICAgICAgIHNjYWxlZE5vcm1hbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5tdWx0aXBseUJ5U2NhbGFyKAogICAgICAgICAgbm9ybWFsMiwKICAgICAgICAgIHBvbHlnb25NYXhpbXVtSGVpZ2h0LAogICAgICAgICAgc2NhbGVkTm9ybWFsCiAgICAgICAgKTsKICAgICAgICBjb25zdCBtYXhIZWlnaHRQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5hZGQoCiAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgIHNjYWxlZE5vcm1hbCwKICAgICAgICAgIHNjcmF0Y2hNYXhIZWlnaHRQb3NpdGlvbgogICAgICAgICk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KG1heEhlaWdodFBvc2l0aW9uLCBjZW50ZXIsIG1heEhlaWdodFBvc2l0aW9uKTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobWluSGVpZ2h0UG9zaXRpb24sIGNlbnRlciwgbWluSGVpZ2h0UG9zaXRpb24pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKG1heEhlaWdodFBvc2l0aW9uLCBiYXRjaGVkUG9zaXRpb25zLCBwb3NpdGlvbkluZGV4KTsKICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhtaW5IZWlnaHRQb3NpdGlvbiwgYmF0Y2hlZFBvc2l0aW9ucywgcG9zaXRpb25JbmRleCArIDMpOwogICAgICAgIGJhdGNoZWRJZHNbYmF0Y2hJZEluZGV4XSA9IGJhdGNoSWQ7CiAgICAgICAgYmF0Y2hlZElkc1tiYXRjaElkSW5kZXggKyAxXSA9IGJhdGNoSWQ7CiAgICAgICAgcG9zaXRpb25JbmRleCArPSA2OwogICAgICAgIGJhdGNoSWRJbmRleCArPSAyOwogICAgICB9CiAgICAgIHJlY3RhbmdsZSA9IHNjcmF0Y2hCVlJlY3RhbmdsZTsKICAgICAgcmVjdGFuZ2xlLndlc3QgPSBtaW5Mb247CiAgICAgIHJlY3RhbmdsZS5lYXN0ID0gbWF4TG9uOwogICAgICByZWN0YW5nbGUuc291dGggPSBtaW5MYXQ7CiAgICAgIHJlY3RhbmdsZS5ub3J0aCA9IG1heExhdDsKICAgICAgYm91bmRpbmdWb2x1bWVzW2kyXSA9IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlKAogICAgICAgIHJlY3RhbmdsZSwKICAgICAgICBtaW5IZWlnaHQsCiAgICAgICAgbWF4SGVpZ2h0LAogICAgICAgIGVsbGlwc29pZAogICAgICApOwogICAgICBsZXQgaW5kaWNlc0luZGV4ID0gYnVmZmVyLmluZGV4T2Zmc2V0OwogICAgICBjb25zdCBpbmRleE9mZnNldCA9IGluZGV4T2Zmc2V0c1tpMl07CiAgICAgIGNvbnN0IGluZGV4Q291bnQgPSBpbmRleENvdW50c1tpMl07CiAgICAgIGJhdGNoZWRJbmRleE9mZnNldHNbaTJdID0gaW5kaWNlc0luZGV4OwogICAgICBmb3IgKGoyID0gMDsgajIgPCBpbmRleENvdW50OyBqMiArPSAzKSB7CiAgICAgICAgY29uc3QgaTAgPSBpbmRpY2VzW2luZGV4T2Zmc2V0ICsgajJdIC0gcG9seWdvbk9mZnNldDsKICAgICAgICBjb25zdCBpMSA9IGluZGljZXNbaW5kZXhPZmZzZXQgKyBqMiArIDFdIC0gcG9seWdvbk9mZnNldDsKICAgICAgICBjb25zdCBpMjIgPSBpbmRpY2VzW2luZGV4T2Zmc2V0ICsgajIgKyAyXSAtIHBvbHlnb25PZmZzZXQ7CiAgICAgICAgYmF0Y2hlZEluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTAgKiAyICsgcG9zaXRpb25PZmZzZXQ7CiAgICAgICAgYmF0Y2hlZEluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTEgKiAyICsgcG9zaXRpb25PZmZzZXQ7CiAgICAgICAgYmF0Y2hlZEluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTIyICogMiArIHBvc2l0aW9uT2Zmc2V0OwogICAgICAgIGJhdGNoZWRJbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGkyMiAqIDIgKyAxICsgcG9zaXRpb25PZmZzZXQ7CiAgICAgICAgYmF0Y2hlZEluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaTEgKiAyICsgMSArIHBvc2l0aW9uT2Zmc2V0OwogICAgICAgIGJhdGNoZWRJbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGkwICogMiArIDEgKyBwb3NpdGlvbk9mZnNldDsKICAgICAgfQogICAgICBmb3IgKGoyID0gMDsgajIgPCBwb2x5Z29uQ291bnQ7ICsrajIpIHsKICAgICAgICBjb25zdCB2MDIgPSBqMjsKICAgICAgICBjb25zdCB2MTIgPSAoajIgKyAxKSAlIHBvbHlnb25Db3VudDsKICAgICAgICBiYXRjaGVkSW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSB2MDIgKiAyICsgMSArIHBvc2l0aW9uT2Zmc2V0OwogICAgICAgIGJhdGNoZWRJbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHYxMiAqIDIgKyBwb3NpdGlvbk9mZnNldDsKICAgICAgICBiYXRjaGVkSW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSB2MDIgKiAyICsgcG9zaXRpb25PZmZzZXQ7CiAgICAgICAgYmF0Y2hlZEluZGljZXNbaW5kaWNlc0luZGV4KytdID0gdjAyICogMiArIDEgKyBwb3NpdGlvbk9mZnNldDsKICAgICAgICBiYXRjaGVkSW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSB2MTIgKiAyICsgMSArIHBvc2l0aW9uT2Zmc2V0OwogICAgICAgIGJhdGNoZWRJbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IHYxMiAqIDIgKyBwb3NpdGlvbk9mZnNldDsKICAgICAgfQogICAgICBidWZmZXIub2Zmc2V0ICs9IHBvbHlnb25Db3VudCAqIDI7CiAgICAgIGJ1ZmZlci5pbmRleE9mZnNldCA9IGluZGljZXNJbmRleDsKICAgICAgYmF0Y2hlZEluZGV4Q291bnRzW2kyXSA9IGluZGljZXNJbmRleCAtIGJhdGNoZWRJbmRleE9mZnNldHNbaTJdOwogICAgfQogICAgYmF0Y2hlZEluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgYmF0Y2hlZFBvc2l0aW9ucy5sZW5ndGggLyAzLAogICAgICBiYXRjaGVkSW5kaWNlcwogICAgKTsKICAgIGNvbnN0IGJhdGNoZWRJbmRpY2VzTGVuZ3RoID0gYmF0Y2hlZERyYXdDYWxscy5sZW5ndGg7CiAgICBmb3IgKGxldCBtMiA9IDA7IG0yIDwgYmF0Y2hlZEluZGljZXNMZW5ndGg7ICsrbTIpIHsKICAgICAgY29uc3QgdGVtcElkcyA9IGJhdGNoZWREcmF3Q2FsbHNbbTJdLmJhdGNoSWRzOwogICAgICBsZXQgY291bnQgPSAwOwogICAgICBjb25zdCB0ZW1wSWRzTGVuZ3RoID0gdGVtcElkcy5sZW5ndGg7CiAgICAgIGZvciAobGV0IG4yID0gMDsgbjIgPCB0ZW1wSWRzTGVuZ3RoOyArK24yKSB7CiAgICAgICAgY291bnQgKz0gYmF0Y2hlZEluZGV4Q291bnRzW3RlbXBJZHNbbjJdXTsKICAgICAgfQogICAgICBiYXRjaGVkRHJhd0NhbGxzW20yXS5jb3VudCA9IGNvdW50OwogICAgfQogICAgY29uc3QgaW5kZXhEYXRhdHlwZSA9IGJhdGNoZWRJbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5UID09PSAyID8gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX1NIT1JUIDogSW5kZXhEYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0lOVDsKICAgIGNvbnN0IHBhY2tlZEJ1ZmZlciA9IHBhY2tCdWZmZXIyKAogICAgICBpbmRleERhdGF0eXBlLAogICAgICBib3VuZGluZ1ZvbHVtZXMsCiAgICAgIGJhdGNoZWREcmF3Q2FsbHMKICAgICk7CiAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goCiAgICAgIGJhdGNoZWRQb3NpdGlvbnMuYnVmZmVyLAogICAgICBiYXRjaGVkSW5kaWNlcy5idWZmZXIsCiAgICAgIGJhdGNoZWRJbmRleE9mZnNldHMuYnVmZmVyLAogICAgICBiYXRjaGVkSW5kZXhDb3VudHMuYnVmZmVyLAogICAgICBiYXRjaGVkSWRzLmJ1ZmZlciwKICAgICAgcGFja2VkQnVmZmVyLmJ1ZmZlcgogICAgKTsKICAgIHJldHVybiB7CiAgICAgIHBvc2l0aW9uczogYmF0Y2hlZFBvc2l0aW9ucy5idWZmZXIsCiAgICAgIGluZGljZXM6IGJhdGNoZWRJbmRpY2VzLmJ1ZmZlciwKICAgICAgaW5kZXhPZmZzZXRzOiBiYXRjaGVkSW5kZXhPZmZzZXRzLmJ1ZmZlciwKICAgICAgaW5kZXhDb3VudHM6IGJhdGNoZWRJbmRleENvdW50cy5idWZmZXIsCiAgICAgIGJhdGNoSWRzOiBiYXRjaGVkSWRzLmJ1ZmZlciwKICAgICAgcGFja2VkQnVmZmVyOiBwYWNrZWRCdWZmZXIuYnVmZmVyCiAgICB9OwogIH0KICB2YXIgc2NyYXRjaENlbnRlcjYsIHNjcmF0Y2hFbGxpcHNvaWQxNSwgc2NyYXRjaFJlY3RhbmdsZTUsIHNjcmF0Y2hTY2FsYXJzLCBtYXhTaG9ydDIsIHNjcmF0Y2hFbmNvZGVkUG9zaXRpb24zLCBzY3JhdGNoTm9ybWFsNywgc2NyYXRjaFNjYWxlZE5vcm1hbCwgc2NyYXRjaE1pbkhlaWdodFBvc2l0aW9uLCBzY3JhdGNoTWF4SGVpZ2h0UG9zaXRpb24sIHNjcmF0Y2hCVkNhcnRvZ3JhcGhpYzMsIHNjcmF0Y2hCVlJlY3RhbmdsZSwgY3JlYXRlVmVjdG9yVGlsZVBvbHlnb25zX2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlVmVjdG9yVGlsZVBvbHlnb25zID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZWN0b3JUaWxlUG9seWdvbnMuanMiKCkgewogICAgICBpbml0X0F0dHJpYnV0ZUNvbXByZXNzaW9uKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X0NvbG9yKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0luZGV4RGF0YXR5cGUoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfT3JpZW50ZWRCb3VuZGluZ0JveCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgc2NyYXRjaENlbnRlcjYgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQxNSA9IG5ldyBFbGxpcHNvaWRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUmVjdGFuZ2xlNSA9IG5ldyBSZWN0YW5nbGVfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoU2NhbGFycyA9IHsKICAgICAgICBtaW46IHZvaWQgMCwKICAgICAgICBtYXg6IHZvaWQgMCwKICAgICAgICBpbmRleEJ5dGVzUGVyRWxlbWVudDogdm9pZCAwCiAgICAgIH07CiAgICAgIG1heFNob3J0MiA9IDMyNzY3OwogICAgICBzY3JhdGNoRW5jb2RlZFBvc2l0aW9uMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5vcm1hbDcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hTY2FsZWROb3JtYWwgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5IZWlnaHRQb3NpdGlvbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heEhlaWdodFBvc2l0aW9uID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQlZDYXJ0b2dyYXBoaWMzID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hCVlJlY3RhbmdsZSA9IG5ldyBSZWN0YW5nbGVfZGVmYXVsdCgpOwogICAgICBjcmVhdGVWZWN0b3JUaWxlUG9seWdvbnNfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChjcmVhdGVWZWN0b3JUaWxlUG9seWdvbnMpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZGVjb2RlVmVjdG9yUG9seWxpbmVQb3NpdGlvbnMuanMKICBmdW5jdGlvbiBkZWNvZGVWZWN0b3JQb2x5bGluZVBvc2l0aW9ucyhwb3NpdGlvbnMsIHJlY3RhbmdsZSwgbWluaW11bUhlaWdodCwgbWF4aW11bUhlaWdodCwgZWxsaXBzb2lkKSB7CiAgICBjb25zdCBwb3NpdGlvbnNMZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IHVCdWZmZXIgPSBwb3NpdGlvbnMuc3ViYXJyYXkoMCwgcG9zaXRpb25zTGVuZ3RoKTsKICAgIGNvbnN0IHZCdWZmZXIgPSBwb3NpdGlvbnMuc3ViYXJyYXkocG9zaXRpb25zTGVuZ3RoLCAyICogcG9zaXRpb25zTGVuZ3RoKTsKICAgIGNvbnN0IGhlaWdodEJ1ZmZlciA9IHBvc2l0aW9ucy5zdWJhcnJheSgKICAgICAgMiAqIHBvc2l0aW9uc0xlbmd0aCwKICAgICAgMyAqIHBvc2l0aW9uc0xlbmd0aAogICAgKTsKICAgIEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuemlnWmFnRGVsdGFEZWNvZGUodUJ1ZmZlciwgdkJ1ZmZlciwgaGVpZ2h0QnVmZmVyKTsKICAgIGNvbnN0IGRlY29kZWQgPSBuZXcgRmxvYXQ2NEFycmF5KHBvc2l0aW9ucy5sZW5ndGgpOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHBvc2l0aW9uc0xlbmd0aDsgKytpMikgewogICAgICBjb25zdCB1NCA9IHVCdWZmZXJbaTJdOwogICAgICBjb25zdCB2NCA9IHZCdWZmZXJbaTJdOwogICAgICBjb25zdCBoMiA9IGhlaWdodEJ1ZmZlcltpMl07CiAgICAgIGNvbnN0IGxvbiA9IE1hdGhfZGVmYXVsdC5sZXJwKHJlY3RhbmdsZS53ZXN0LCByZWN0YW5nbGUuZWFzdCwgdTQgLyBtYXhTaG9ydDMpOwogICAgICBjb25zdCBsYXQgPSBNYXRoX2RlZmF1bHQubGVycChyZWN0YW5nbGUuc291dGgsIHJlY3RhbmdsZS5ub3J0aCwgdjQgLyBtYXhTaG9ydDMpOwogICAgICBjb25zdCBhbHQgPSBNYXRoX2RlZmF1bHQubGVycChtaW5pbXVtSGVpZ2h0LCBtYXhpbXVtSGVpZ2h0LCBoMiAvIG1heFNob3J0Myk7CiAgICAgIGNvbnN0IGNhcnRvZ3JhcGhpYzIgPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICBsb24sCiAgICAgICAgbGF0LAogICAgICAgIGFsdCwKICAgICAgICBzY3JhdGNoQlZDYXJ0b2dyYXBoaWM0CiAgICAgICk7CiAgICAgIGNvbnN0IGRlY29kZWRQb3NpdGlvbiA9IGVsbGlwc29pZC5jYXJ0b2dyYXBoaWNUb0NhcnRlc2lhbigKICAgICAgICBjYXJ0b2dyYXBoaWMyLAogICAgICAgIHNjcmF0Y2hFbmNvZGVkUG9zaXRpb240CiAgICAgICk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGRlY29kZWRQb3NpdGlvbiwgZGVjb2RlZCwgaTIgKiAzKTsKICAgIH0KICAgIHJldHVybiBkZWNvZGVkOwogIH0KICB2YXIgbWF4U2hvcnQzLCBzY3JhdGNoQlZDYXJ0b2dyYXBoaWM0LCBzY3JhdGNoRW5jb2RlZFBvc2l0aW9uNCwgZGVjb2RlVmVjdG9yUG9seWxpbmVQb3NpdGlvbnNfZGVmYXVsdDsKICB2YXIgaW5pdF9kZWNvZGVWZWN0b3JQb2x5bGluZVBvc2l0aW9ucyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZGVjb2RlVmVjdG9yUG9seWxpbmVQb3NpdGlvbnMuanMiKCkgewogICAgICBpbml0X0F0dHJpYnV0ZUNvbXByZXNzaW9uKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgbWF4U2hvcnQzID0gMzI3Njc7CiAgICAgIHNjcmF0Y2hCVkNhcnRvZ3JhcGhpYzQgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVuY29kZWRQb3NpdGlvbjQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGRlY29kZVZlY3RvclBvbHlsaW5lUG9zaXRpb25zX2RlZmF1bHQgPSBkZWNvZGVWZWN0b3JQb2x5bGluZVBvc2l0aW9uczsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVZlY3RvclRpbGVQb2x5bGluZXMuanMKICB2YXIgY3JlYXRlVmVjdG9yVGlsZVBvbHlsaW5lc19leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlVmVjdG9yVGlsZVBvbHlsaW5lc19leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiB1bnBhY2tCdWZmZXI0KHBhY2tlZEJ1ZmZlcikgewogICAgcGFja2VkQnVmZmVyID0gbmV3IEZsb2F0NjRBcnJheShwYWNrZWRCdWZmZXIpOwogICAgbGV0IG9mZnNldCA9IDA7CiAgICBzY3JhdGNoTWluTWF4SGVpZ2h0czIubWluID0gcGFja2VkQnVmZmVyW29mZnNldCsrXTsKICAgIHNjcmF0Y2hNaW5NYXhIZWlnaHRzMi5tYXggPSBwYWNrZWRCdWZmZXJbb2Zmc2V0KytdOwogICAgUmVjdGFuZ2xlX2RlZmF1bHQudW5wYWNrKHBhY2tlZEJ1ZmZlciwgb2Zmc2V0LCBzY3JhdGNoUmVjdGFuZ2xlNik7CiAgICBvZmZzZXQgKz0gUmVjdGFuZ2xlX2RlZmF1bHQucGFja2VkTGVuZ3RoOwogICAgRWxsaXBzb2lkX2RlZmF1bHQudW5wYWNrKHBhY2tlZEJ1ZmZlciwgb2Zmc2V0LCBzY3JhdGNoRWxsaXBzb2lkMTYpOwogICAgb2Zmc2V0ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socGFja2VkQnVmZmVyLCBvZmZzZXQsIHNjcmF0Y2hDZW50ZXI3KTsKICB9CiAgZnVuY3Rpb24gZ2V0UG9zaXRpb25PZmZzZXRzMihjb3VudHMpIHsKICAgIGNvbnN0IGNvdW50c0xlbmd0aCA9IGNvdW50cy5sZW5ndGg7CiAgICBjb25zdCBwb3NpdGlvbk9mZnNldHMgPSBuZXcgVWludDMyQXJyYXkoY291bnRzTGVuZ3RoICsgMSk7CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBjb3VudHNMZW5ndGg7ICsraTIpIHsKICAgICAgcG9zaXRpb25PZmZzZXRzW2kyXSA9IG9mZnNldDsKICAgICAgb2Zmc2V0ICs9IGNvdW50c1tpMl07CiAgICB9CiAgICBwb3NpdGlvbk9mZnNldHNbY291bnRzTGVuZ3RoXSA9IG9mZnNldDsKICAgIHJldHVybiBwb3NpdGlvbk9mZnNldHM7CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZVZlY3RvclRpbGVQb2x5bGluZXMocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgZW5jb2RlZFBvc2l0aW9ucyA9IG5ldyBVaW50MTZBcnJheShwYXJhbWV0ZXJzLnBvc2l0aW9ucyk7CiAgICBjb25zdCB3aWR0aHMgPSBuZXcgVWludDE2QXJyYXkocGFyYW1ldGVycy53aWR0aHMpOwogICAgY29uc3QgY291bnRzID0gbmV3IFVpbnQzMkFycmF5KHBhcmFtZXRlcnMuY291bnRzKTsKICAgIGNvbnN0IGJhdGNoSWRzID0gbmV3IFVpbnQxNkFycmF5KHBhcmFtZXRlcnMuYmF0Y2hJZHMpOwogICAgdW5wYWNrQnVmZmVyNChwYXJhbWV0ZXJzLnBhY2tlZEJ1ZmZlcik7CiAgICBjb25zdCByZWN0YW5nbGUgPSBzY3JhdGNoUmVjdGFuZ2xlNjsKICAgIGNvbnN0IGVsbGlwc29pZCA9IHNjcmF0Y2hFbGxpcHNvaWQxNjsKICAgIGNvbnN0IGNlbnRlciA9IHNjcmF0Y2hDZW50ZXI3OwogICAgY29uc3QgbWluaW11bUhlaWdodCA9IHNjcmF0Y2hNaW5NYXhIZWlnaHRzMi5taW47CiAgICBjb25zdCBtYXhpbXVtSGVpZ2h0ID0gc2NyYXRjaE1pbk1heEhlaWdodHMyLm1heDsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IGRlY29kZVZlY3RvclBvbHlsaW5lUG9zaXRpb25zX2RlZmF1bHQoCiAgICAgIGVuY29kZWRQb3NpdGlvbnMsCiAgICAgIHJlY3RhbmdsZSwKICAgICAgbWluaW11bUhlaWdodCwKICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgZWxsaXBzb2lkCiAgICApOwogICAgY29uc3QgcG9zaXRpb25zTGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aCAvIDM7CiAgICBjb25zdCBzaXplID0gcG9zaXRpb25zTGVuZ3RoICogNCAtIDQ7CiAgICBjb25zdCBjdXJQb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAzKTsKICAgIGNvbnN0IHByZXZQb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAzKTsKICAgIGNvbnN0IG5leHRQb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiAzKTsKICAgIGNvbnN0IGV4cGFuZEFuZFdpZHRoID0gbmV3IEZsb2F0MzJBcnJheShzaXplICogMik7CiAgICBjb25zdCB2ZXJ0ZXhCYXRjaElkcyA9IG5ldyBVaW50MTZBcnJheShzaXplKTsKICAgIGxldCBwb3NpdGlvbkluZGV4ID0gMDsKICAgIGxldCBleHBhbmRBbmRXaWR0aEluZGV4ID0gMDsKICAgIGxldCBiYXRjaElkSW5kZXggPSAwOwogICAgbGV0IGkyOwogICAgbGV0IG9mZnNldCA9IDA7CiAgICBsZXQgbGVuZ3RoID0gY291bnRzLmxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBjb25zdCBjb3VudCA9IGNvdW50c1tpMl07CiAgICAgIGNvbnN0IHdpZHRoID0gd2lkdGhzW2kyXTsKICAgICAgY29uc3QgYmF0Y2hJZCA9IGJhdGNoSWRzW2kyXTsKICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGNvdW50OyArK2oyKSB7CiAgICAgICAgbGV0IHByZXZpb3VzOwogICAgICAgIGlmIChqMiA9PT0gMCkgewogICAgICAgICAgY29uc3QgcDAgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHBvc2l0aW9ucywgb2Zmc2V0ICogMywgc2NyYXRjaFAwMik7CiAgICAgICAgICBjb25zdCBwMSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2socG9zaXRpb25zLCAob2Zmc2V0ICsgMSkgKiAzLCBzY3JhdGNoUDEyKTsKICAgICAgICAgIHByZXZpb3VzID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHAwLCBwMSwgc2NyYXRjaFByZXYyKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocDAsIHByZXZpb3VzLCBwcmV2aW91cyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHByZXZpb3VzID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICAob2Zmc2V0ICsgajIgLSAxKSAqIDMsCiAgICAgICAgICAgIHNjcmF0Y2hQcmV2MgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY3VycmVudCA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAob2Zmc2V0ICsgajIpICogMywKICAgICAgICAgIHNjcmF0Y2hDdXIKICAgICAgICApOwogICAgICAgIGxldCBuZXh0OwogICAgICAgIGlmIChqMiA9PT0gY291bnQgLSAxKSB7CiAgICAgICAgICBjb25zdCBwMiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgICAgKG9mZnNldCArIGNvdW50IC0gMSkgKiAzLAogICAgICAgICAgICBzY3JhdGNoUDAyCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcDMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICAgIChvZmZzZXQgKyBjb3VudCAtIDIpICogMywKICAgICAgICAgICAgc2NyYXRjaFAxMgogICAgICAgICAgKTsKICAgICAgICAgIG5leHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocDIsIHAzLCBzY3JhdGNoTmV4dDIpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmFkZChwMiwgbmV4dCwgbmV4dCk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIG5leHQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHBvc2l0aW9ucywgKG9mZnNldCArIGoyICsgMSkgKiAzLCBzY3JhdGNoTmV4dDIpOwogICAgICAgIH0KICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QocHJldmlvdXMsIGNlbnRlciwgcHJldmlvdXMpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChjdXJyZW50LCBjZW50ZXIsIGN1cnJlbnQpOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdChuZXh0LCBjZW50ZXIsIG5leHQpOwogICAgICAgIGNvbnN0IHN0YXJ0SyA9IGoyID09PSAwID8gMiA6IDA7CiAgICAgICAgY29uc3QgZW5kSyA9IGoyID09PSBjb3VudCAtIDEgPyAyIDogNDsKICAgICAgICBmb3IgKGxldCBrMiA9IHN0YXJ0SzsgazIgPCBlbmRLOyArK2syKSB7CiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhjdXJyZW50LCBjdXJQb3NpdGlvbnMsIHBvc2l0aW9uSW5kZXgpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2socHJldmlvdXMsIHByZXZQb3NpdGlvbnMsIHBvc2l0aW9uSW5kZXgpOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sobmV4dCwgbmV4dFBvc2l0aW9ucywgcG9zaXRpb25JbmRleCk7CiAgICAgICAgICBwb3NpdGlvbkluZGV4ICs9IDM7CiAgICAgICAgICBjb25zdCBkaXJlY3Rpb24yID0gazIgLSAyIDwgMCA/IC0xIDogMTsKICAgICAgICAgIGV4cGFuZEFuZFdpZHRoW2V4cGFuZEFuZFdpZHRoSW5kZXgrK10gPSAyICogKGsyICUgMikgLSAxOwogICAgICAgICAgZXhwYW5kQW5kV2lkdGhbZXhwYW5kQW5kV2lkdGhJbmRleCsrXSA9IGRpcmVjdGlvbjIgKiB3aWR0aDsKICAgICAgICAgIHZlcnRleEJhdGNoSWRzW2JhdGNoSWRJbmRleCsrXSA9IGJhdGNoSWQ7CiAgICAgICAgfQogICAgICB9CiAgICAgIG9mZnNldCArPSBjb3VudDsKICAgIH0KICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShzaXplLCBwb3NpdGlvbnNMZW5ndGggKiA2IC0gNik7CiAgICBsZXQgaW5kZXggPSAwOwogICAgbGV0IGluZGljZXNJbmRleCA9IDA7CiAgICBsZW5ndGggPSBwb3NpdGlvbnNMZW5ndGggLSAxOwogICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXg7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXggKyAyOwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGluZGV4ICsgMTsKICAgICAgaW5kaWNlc1tpbmRpY2VzSW5kZXgrK10gPSBpbmRleCArIDE7CiAgICAgIGluZGljZXNbaW5kaWNlc0luZGV4KytdID0gaW5kZXggKyAyOwogICAgICBpbmRpY2VzW2luZGljZXNJbmRleCsrXSA9IGluZGV4ICsgMzsKICAgICAgaW5kZXggKz0gNDsKICAgIH0KICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaCgKICAgICAgY3VyUG9zaXRpb25zLmJ1ZmZlciwKICAgICAgcHJldlBvc2l0aW9ucy5idWZmZXIsCiAgICAgIG5leHRQb3NpdGlvbnMuYnVmZmVyCiAgICApOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICBleHBhbmRBbmRXaWR0aC5idWZmZXIsCiAgICAgIHZlcnRleEJhdGNoSWRzLmJ1ZmZlciwKICAgICAgaW5kaWNlcy5idWZmZXIKICAgICk7CiAgICBsZXQgcmVzdWx0cyA9IHsKICAgICAgaW5kZXhEYXRhdHlwZTogaW5kaWNlcy5CWVRFU19QRVJfRUxFTUVOVCA9PT0gMiA/IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9TSE9SVCA6IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9JTlQsCiAgICAgIGN1cnJlbnRQb3NpdGlvbnM6IGN1clBvc2l0aW9ucy5idWZmZXIsCiAgICAgIHByZXZpb3VzUG9zaXRpb25zOiBwcmV2UG9zaXRpb25zLmJ1ZmZlciwKICAgICAgbmV4dFBvc2l0aW9uczogbmV4dFBvc2l0aW9ucy5idWZmZXIsCiAgICAgIGV4cGFuZEFuZFdpZHRoOiBleHBhbmRBbmRXaWR0aC5idWZmZXIsCiAgICAgIGJhdGNoSWRzOiB2ZXJ0ZXhCYXRjaElkcy5idWZmZXIsCiAgICAgIGluZGljZXM6IGluZGljZXMuYnVmZmVyCiAgICB9OwogICAgaWYgKHBhcmFtZXRlcnMua2VlcERlY29kZWRQb3NpdGlvbnMpIHsKICAgICAgY29uc3QgcG9zaXRpb25PZmZzZXRzID0gZ2V0UG9zaXRpb25PZmZzZXRzMihjb3VudHMpOwogICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2gocG9zaXRpb25zLmJ1ZmZlciwgcG9zaXRpb25PZmZzZXRzLmJ1ZmZlcik7CiAgICAgIHJlc3VsdHMgPSBjb21iaW5lX2RlZmF1bHQocmVzdWx0cywgewogICAgICAgIGRlY29kZWRQb3NpdGlvbnM6IHBvc2l0aW9ucy5idWZmZXIsCiAgICAgICAgZGVjb2RlZFBvc2l0aW9uT2Zmc2V0czogcG9zaXRpb25PZmZzZXRzLmJ1ZmZlcgogICAgICB9KTsKICAgIH0KICAgIHJldHVybiByZXN1bHRzOwogIH0KICB2YXIgc2NyYXRjaFJlY3RhbmdsZTYsIHNjcmF0Y2hFbGxpcHNvaWQxNiwgc2NyYXRjaENlbnRlcjcsIHNjcmF0Y2hNaW5NYXhIZWlnaHRzMiwgc2NyYXRjaFAwMiwgc2NyYXRjaFAxMiwgc2NyYXRjaFByZXYyLCBzY3JhdGNoQ3VyLCBzY3JhdGNoTmV4dDIsIGNyZWF0ZVZlY3RvclRpbGVQb2x5bGluZXNfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzLmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfY29tYmluZSgpOwogICAgICBpbml0X2RlY29kZVZlY3RvclBvbHlsaW5lUG9zaXRpb25zKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgc2NyYXRjaFJlY3RhbmdsZTYgPSBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVsbGlwc29pZDE2ID0gbmV3IEVsbGlwc29pZF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDZW50ZXI3ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTWluTWF4SGVpZ2h0czIgPSB7CiAgICAgICAgbWluOiB2b2lkIDAsCiAgICAgICAgbWF4OiB2b2lkIDAKICAgICAgfTsKICAgICAgc2NyYXRjaFAwMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFAxMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFByZXYyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ3VyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTmV4dDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNyZWF0ZVZlY3RvclRpbGVQb2x5bGluZXNfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChjcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzKTsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL21lc2hvcHRpbWl6ZXIvbWVzaG9wdF9lbmNvZGVyLmpzCiAgdmFyIE1lc2hvcHRFbmNvZGVyOwogIHZhciBpbml0X21lc2hvcHRfZW5jb2RlciA9IF9fZXNtKHsKICAgICJub2RlX21vZHVsZXMvbWVzaG9wdGltaXplci9tZXNob3B0X2VuY29kZXIuanMiKCkgewogICAgICBNZXNob3B0RW5jb2RlciA9IChmdW5jdGlvbigpIHsKICAgICAgICB2YXIgd2FzbTIgPSAiYjlINzlUZWJiYmU5b2s5R2V1ZXU5R2V1YjlHYmI5R3J1dXV1dXV1ZXU5R3Z1dXV1dWV1OUdkdXVldTlHbHV1dXVldTlHdnV1dXV1YjlHb3V1dXV1dWI5R2x1dXV1YjlHaXV1dWV1aUU4QWRpbHZlb3Zlb3ZycndycnJERG9EcmJxcWJlbHZlOVdlaWl2aWViZW93ZXVlY2o6R2RrcjpQbENvOVRXOVQ5VlY5NWRiSDlGOUY5MzlINzlUOUY5SjlIMjI5RjlKdDlWVjdiYjhGOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c5d1dWdFc5NDljOTE5TTlNV1Y5bVc0VzJiZThBOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c5d1dWdFc5NDljOTE5TTlNV1ZiZDhGOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c5d1dWdFc5NDljOTE5TTlNV1Y5YzlWOTE5VTlLYmlFOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c5d1dWdFc5NDl3V1Y3OVA5VjlVYmxZOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c2OVU5S1c5NDljOTE5TTlNV1ZidjhFOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1c2OVU5S1c5NDljOTE5TTlNV1Y5YzlWOTE5VTlLYm84QTlUVzc5TzlWOVd0OUZXOVU5SjlWOUtXNjlVOUtXOTQ5d1dWNzlQOVY5VWJyRTlUVzc5TzlWOVd0OUZXOVU5SjlWOUtXNjlVOUtXOTQ5dFdHOTFXOVU5Sldid2E5VFc3OU85VjlXdDlGVzlVOUo5VjlLVzY5VTlLVzk0OXRXRzkxVzlVOUpXOWM5VjkxOVU5S2JETDlUVzc5TzlWOVd0OUZXOVU5SjlWOUtXUzlQMnRXVjlwOUp0YnFLOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1dTOVAydFdWOXI5MTlIdGJrTDlUVzc5TzlWOVd0OUZXOVU5SjlWOUtXUzlQMnRXVlQ5NDlXYnhZOVRXNzlPOVY5V3Q5Rlc5VTlKOVY5S1dTOVAydFdWSjlWMjlWVmJtRTlUVzc5TzlWOVd0OUY5VjlXdDlQOVQ5UDk2Vzl3V1Z0Vzk0SjlIOUo5T1diemE5VFc3OU85VjlXdDlGOVY5V3Q5UDlUOVA5Nlc5d1dWdFc5NEo5SDlKOU9XOXR0VjlQOVdiSGE5VFc3OU85VjlXdDlGOVY5V3Q5UDlUOVA5Nlc5d1dWdFc5NFNXdDlKOU85c1c5VDlIOVdiT0s5VFc3OU85VjlXdDlGNzlXOUh0OVA5SDI5dDlWVnQ5c1c5VDlIOVdiQWw3OUlWOVJiWER3ZWJjZWtkS1lxOnpmOEFkYms7d2FkaHVkOTo4SmpqampiYztxdzlSZ3I4S2pqampiY2Jod2RuYWVUbWJhYmNieWQ7aTpJOmNqYmFvYW9jYjlpRWdEYzpHZVY4NmJiYXJjO2FkZmNiY2pkejp4ampqYjhBZG5haVRtYmFyYzthZGZhZGFsejp3ampqYjhBa2FyYzthYmZhbGZjYmNiY2pkYWw5UmFsY0ZlMEV6OnhqampiOEFhcmM7YWJmYXJjO2FkZmFsejp3ampqYjhBYXI5Y2I4M2lVYXI5Y2I4M2k4V2FyOWNiODNpeWFyOWNiODNpYWFyOWNiODNpS2FyOWNiODNpemFyOWNiODNpd2FyOWNiODNpYmNqO2FiYWw5VWM7V0ZiR2NqZGFsY2EwRWhxZG5haWNkNm1iYXZjZDlpbWJhRFRtYmFkY2VmaGthcWNpMmd4YWwyaG1hcmM7YWxmY2xmaFBhcmM7cWxmY2VWaHNhcmM7cW9mY2xWaHpjYmhIaW5jZGhPY2JoQWRuYXZjaTZtYmFyOWNiODNpO09vYXI5Y2I4M2k7R29hcjljYjgzaTt5b2FyOWNiODNpO3FvYWRhSGZnb3liYmhDY2JoWGluY2Jod2NiaFFkbmluYW9hbGZoTGFveWJiZ0thQzdhUVZoUWF3Y1AwbWVhTGhvYUtoQ2F3Y2VmZ3dhWGZhaTZtYmtrY2JoQ2FyYztxb2Zod2luY3doWWN3aDhBZG5hUWFDOTNnb2NGZUdnRWNzMG1iY2xoOEFhRWNpMG1iY2RjYmFFRWg4QWtkbmFvY3c0Y0ZlR2dFY3MwbWJjbGhZYUVjaTBtYmNkY2JhRUVoWWthWWE4QWZoRWF3eWRiaDNjd2hZY3doOEFkbmFvY3o0Y0ZlR2c1Y3MwbWJjbGg4QWE1Y2kwbWJjZGNiYTVFaDhBa2FFYTNmaEVkbmFvY0ZGRkZiMG1iY2xoWWFvY0ZGRjhGMG1iY2JjZGFvY2pqanc2RWhZa2F3YUVhOEFmYVlmQmRiYXdjbGZod2FDY2VmZ0NjdzlobWJrYUxob2FLaENhWGN6ZmdYYWk2bWJrY2Job2NlaHdhemhRaW5hd2FvYVF5ZGJhcmM7cW9mYW9jZHRmeWRiNkVob2FRY2xmaFFhd2NlZmd3Y3c5aG1ia2FvY2x0aEFjaWhPa2NiaEVhcmM7cWxmY2JjamR6OnhqampiOEFhcmNiQmQ7aWxhcjljYjgzaTthbGFkaDhFYXFoOEZha2gzaW5hcmM7cWxmYWRhRWFFY2I5aDlSYWwyZmFsejp3ampqYjhBYWlhOEZhaWE4RjZFaGFkbmFxYWlhRTlSYUVhcWZhaTZFZ0tjc2ZjOVdHZ29hSzlubWJhcmM7cW9mYUtmY2Jhb2FLOVJ6OnhqampiOEFrYWRhRWFsMmZoaGNiaGdpbmFnYUFWY2w0aFhhcmM7YWxmYWdjZHRmaDhKYUhoOEtjYmg4TGluYThMYUhmaHdkbmRuZG5kbmRuZG5kbmFnUGxiZWRpYmthS1RtdmFoYXdmaG9hcmM7cWxmYXdmUmJiaFFhcmM7cW9maHdhYWhDaW5hd2FvUmJiZ1lhUTlSZ1FjZXRhUWNLdGM4RjkxNzg2YmJhd2NlZmh3YW9hbGZob2FZaFFhRWFDY3VmZ0M5aG1ieHZra2FLVG1sYThLYzk6R2hvYThMY2l0Y3dHaDhBYXJjO3FsZmF3Y2VWZlJiYmN3dGFyYztxbGZhd2M5OkdmUmJiVmhRYXJjO3FvZmh3YWFoQ2luYXdhM2FvZlJiYmN3dGE4RWFvZlJiYlZnWWFROVJnUWNldGFRY3p0YzhGOTE3Y0ZGaUdhOEE0ODZiYmFvYWxmaG9hd2NlZmh3YVloUWFFYUNjdWZnQzlobWJ4bGtrYXNhOEtjOThHZ1FmaG9hM2FRZmhZYXJjO3FsZmF3Yzk4R2dRZlJiYmhDY3dod2luYW9SYmJhd3RhQ1ZoQ2FvY2VmaG9hd2N3Zmd3Y2E5aG1ieGRra2FLVG1keGVrYUtUbWVhOExjaXRoNWFoYVFmaDhBY2JoTGluYThBUmJiaFFjd2hvYVlod2luYXdSYmJhb3RhUVZoUWF3Y2VmaHdhb2N3ZmdvY2E5aG1ia2FyYztxb2ZhTGZhUWFDN2FYOTNhNTQ4NmJiYVlhbGZoWWE4QWFsZmg4QWFRaENhTGNlZmdMYUs5aG1ia2thOEp5ZGJoOEFjYmhMYXJjO3FvZmhvaW5jZGhRY2Jod2luYVFhb2F3ZlJiYmNiOWhmaFFhd2NlZmd3Y3o5aG1ia2NsaENjYmh3aW5hQ2FvYXdmUmJiY2QwZmhDYXdjZWZnd2N6OWhtYmtjd2hZY2Jod2luYVlhb2F3ZlJiYmNQMGZoWWF3Y2VmZ3djejlobWJrYVFhQ2FRYUM2RWd3YVlhd2FZNkVnd2N6YXdjejZFYThBZmg4QWFvY3pmaG9hTGN6ZmdMYUs2bWJrYThKYThBQmRia2E4S2NlZmg4S2E4TGNlZmc4TGNsOWhtYmthZ2NlZmdnYU85aG1ia2E4RWFtZmg4RWE4RmF4Zmg4RmEzYW1maDNhRWF4ZmdFYWk2bWJrY2Job2NlaHdhUGhRaW5hd2FvYVF5ZGJhcmM7YWxmYW9jZHRmeWRiNkVob2FRY2xmaFFhT2F3Y2VmZ3c5aG1ia2FyYUhjZDRmYUFjZFZhb2FvY2RTRTg2YmJhSGNsZmdIYWw2bWJra2FiYWVmaGdhYmNlZmhvYWxjZDRnOE1jYmFERWhrYWRjZWZoOE5hcmM7YWJmY2VWaGVjYmhtZG5kbmluYWlhbTlubWVhcmM7cW9mY2JjamR6OnhqampiOEFhZ2FvOVJhazZtZGFkYW1hbDJnd2ZoeGNiaEhhOE5hd2ZoemFvY2Jha3o6eGpqamJnOEZha2ZoM2FxYWlhbTlSYW1hcWZhaTZFZ3Njc2Znb2NsNGNpZmNkNGhPYW9jOVdHZzhKVGhQaW5kbmRuZG5kbmRuZG5kbmRuZG5kbmFEVG1iYXJhSGNkNGZSYmJnUWNpR1BsYmVkbGJrYXNUbWRheGFIZmhvYXJjO2FiZmFIZlJiYmhRYXJjO3FvZmh3YXNoQ2luYXdhb1JiYmdZYVE5UmdRY2V0YVFjS3RjOEY5MTc4NmJiYXdjZWZod2FvYWxmaG9hWWhRYUNjdWZnQ21ieGlra2FzVG1pYUhjaXRjd0doOEFhcmM7YWJmYUhjZVZmUmJiY3d0YXJjO2FiZmFIYzk6R2dvZlJiYlZoUWF4YW9maG9hcmM7cW9maHdhc2hDaW5hd2FvOFZiYmdZYVE5UmdRY2V0YVFjenRjOEY5MTdjRkZpR2E4QTQ4NmJiYXdjZWZod2FvYWxmaG9hWWhRYUNjdWZnQ21ieGlra2FlYUhjOThHZzhBZmhvYXphOEFmaFlhcmM7YWJmYThBZlJiYmhDY3dod2luYW9SYmJhd3RhQ1ZoQ2FvY2VmaG9hd2N3Zmd3Y2E5aG1ia2FzVG1kYVFjbDRoS2FIY2l0Y0tHaEVheGE4QWZoOEFjYmhMaW5hOEFSYmJoUWN3aG9hWWh3aW5hd1JiYmFvdGFRVmhRYXdjZWZod2FvY3dmZ29jYTlobWJrYXJjO3FvZmFMZmFRYUM3YUs5M2FFNDg2YmJhWWFsZmhZYThBYWxmaDhBYVFoQ2FMY2VmZ0xhczlobWJra2FEbWJjYmhveGxrYThKVG1iY2Job2RuaW5hcmM7cW9mYW9mZ3djd2Y4UGliYXc4UGliOmU5cVRtZWFvY3pmZ29hOEo5cG1keGJra2RuYXZtYmNlaG94aWtjYmg4QWFPaExhT2hLaW5hcmM7cW9mYThBZmdvY3dmOFBpYmh5YW84UGliaDhQY2RoUWNiaHdpbmFRYW9hd2ZSYmJjYjloZmhRYXdjZWZnd2N6OWhtYmtjbGhDY2Jod2luYUNhb2F3ZlJiYmNkMGZoQ2F3Y2VmZ3djejlobWJrY3doWWNiaHdpbmFZYW9hd2ZSYmJjUDBmaFlhd2NlZmd3Y3o5aG1ia2FRYUNhUWFDNkVnb2FZYW9hWTZFZ29jemFvY3o2RWFLZmhLYW9jdWNiYXlhOFA6ZTljYjlzRWd3YW9hdzZFYUxmaExhOEFjemZnOEFhOEo5cG1keGJra2E4RmFIY2Q0ZmdvYW9SYmJjZGFIY2V0Y29HdFY4NmJieGlrZG5hTGFzNm1iYUthczZtYmE4RmFIY2Q0ZmdvYW9SYmJjaWFIY2V0Y29HdFY4NmJiYWdhMzlSYXM2bXJhM2FyYztxb2Zhc3o6d2pqamJhc2ZoM3hpa2FMYUs5cGhva2E4RmFIY2Q0Zmd3YXdSYmJhb2FIY2V0Y29HdFY4NmJia2FnYTM5UmFPNm1sYTNjYmFPejp4ampqYmdhYU9maEtkbmRuYThKbWJhUGhveGVrZG5hZ2FLOVJjSzlwbWJhUGhveGVrYW9jZHRjOnE6RzpjamJmY2o6RzpjamJhREVnM3lkeGdoY2V0Yzs6RkZGZUdoQWN1aEVjdWFodGN1N2NGZUdoOEVjYmg4S2FyYztxb2ZoUWluYXJjO3FvZmE4S2ZoWGN6aDhBZG5kbmRuYWhQRGJlZWVlZWVlZGVrY3VjYmFYY3dmOFBpYmFYOFBpYjplOWNiOXNFaDhBeGVrY2Job2FBaDhBaW5hOEFhOEVhUWFvZlJiYjluZmg4QWFvY2VmZ29jejlobWJra2NpaDVjYmhZaW5jemh3ZG5kbmRuYTNhWWNkdGZ5ZGJnTFBEYmVlZWVlZWVkZWtjdWNiYVhjd2Y4UGliYVg4UGliOmU5Y2I5c0Vod3hla2FMY2V0Yzs6RkZGZUdod2N1YUx0Y3U3Y0ZlR2hDY2Job2luYXdhQ2FRYW9mUmJiOW5maHdhb2NlZmdvY3o5aG1ia2tkbmRuYXdhOEE2bWJhTGFFOWhtZWF3YThBOWhtZWEzYTVjZHRmeWRiY3dTbWVrYVloNWF3aDhBa2FZY2VmZ1ljaTlobWJrYWFhOEtjbzRmZ29hb1JiYmE1YThLY2k0Y29HdFY4NmJiZG5kbmRuYTNhNWNkdGZ5ZGJnRVBEZGJiYmJiYmJlYmtkbmN3YUU5VGc1VG1iY3VhRXRjdTdod2RuZG5hRWNlU21iY2JoOExhUWhYaW5hWGhvYTVoWWNiaENpbmFvUmJiZzhBYXdjRmVHZ0xhOEFhTDZFYUNhRXRWaENhb2NlZmhvYVljdWZnWW1ia2FLYUM4NmJiYVhhNWZoWGFLY2VmaEthOExhNWZnOExjejZtYnhka2tjYmg4TGFRaFhpbmFYaG9hNWhZY2JoQ2luYW9SYmJnOEFhd2NGZUdnTGE4QWFMNkVhQ2NldFZoQ2FvY2VmaG9hWWN1ZmdZbWJrYUthQzpUOWNGZTpkOWM6Yzpxajpidzk6OWM6cTtjMTpJMWU6ZDljOmI6YzplMXo5OjljYTE4OGJiYVhhNWZoWGFLY2VmaEthOExhNWZnOExjejZtYmtrY2Job2luYUthUWFvZlJiYmdDODZiYmFLYUNhd2NGZUc5cGZoS2FvY2VmZ29jejlobWJ4aWtrZG5hRWNlU21iaW5hS2NiODZiYmFLY2VmaEt4YmtraW5hS2NiODZiYmFLY2VmaEt4YmtrYUthWDhQYnc4M2J3YUthWDhQYmI4M2JiYUtjemZoS2thOEtjemZnOEthOEo5cGdvbWVhUWN6ZmhRYWdhSzlSY0s5cG1ia2thb1RtbGFLaDNhS1RtbGthSGNlZmdIYWw5aG1ia2FyYzthYmZheGFzY3VmYWwyZmFsejp3ampqYjhBYXNhbWZobWEzaG9hM21ia2NiaHd4ZGtkbmFnYW85UmFrYWxmZ3djS2NhYURFZ1Fhd2FRMEVnQzlwbWJjYmh3eGRrZG5hd2FROXBtYmFvY2JhQ2F3OVJnd3o6eGpqamJhd2Zob2thb2FyYzthZGZhbHo6d2pqamJhbGZob2RuYURUbWJhb2FyYThNejp3ampqYmE4TWZob2thb2FiOVJod3hla2NiaHdrYXJjO3F3ZjhLampqamJhd2s1YmFiYWVhZGFpYWxjZGNieWQ7aTpJOmNqYno6YmpqamJrOXJlZHVhZWNkNGdkYWVmZ2ljYWFpY2EwRWFiY2o7YWJhZTlVYztXRmJHY2pkYWVjYTBFZ2lmY3VmYWk5VWFlMmFpYWRmYWljbDRjaWZjZDRmMmZjZWZrbWJjYmFiQmQ7aTpJOmNqYms7SFBlTHU4SmpqampiYzthZTlSZ2w4S2pqampiY2JodmRuYWVhaWNpOVVnb2NIZjZtYmFiY2J5ZDttOkk6Y2piZ3JjO0dlVjg2YmJhbGM7YWJmY0ZlY2plejp4ampqYjhBYWw5Y3U4M2lVYWw5Y3U4M2k4V2FsOWN1ODNpeWFsOWN1ODNpYWFsOWN1ODNpS2FsOWN1ODNpemFsOWN1ODNpd2FsOWN1ODNpYmFiYWVmYzlXZmh3YWJjZWZnRGFvZmhlZG5haVRtYmNtY3NhcmNiOWtncUVoa2NiaHhjYmhtY2JoUGNiaHNjYmh6aW5kbmFlYXc5bm1iY2Jodnhpa2F6Y3VmaHZhZGFQY2R0ZmdIeWRiaE9hSGN3ZnlkYmhBYUhjbGZ5ZGJoQ2NiaFhkbmRuZG5pbmFsYzthYmZhdmNzR2NpdGZnb3lkbGhRZG5kbmRuYW95ZGJnb2FPOWhtYmFRYUNTbWVrZG5hb2FDOWhtYmFRYUE5aG1iYVhjZWZoWHhla2FvYUE5aG1lYVFhTzlobWVhWGNkZmhYa2FYYzg3MG1kYXNjdWZodmFIYVhjZHRnQWN4R2dveWQ6NDpHOmNqYmNkdGZ5ZGJoUWFIYW95ZDowOkc6Y2piY2R0ZnlkYmhDYUhhb3lkOlc6RzpjamJjZHRmeWRiaE9jYmhvZG5pbmRuYWxhdmNzR2NkdGZ5ZGJhUTlobWJhb2hYeGRrY3VoWGF2Y3VmaHZhb2NlZmdvY3o5aG1ia2theGFRYXhTZ3ZhWGNlOWlhWGFrOW9WZ29HZmh4ZG5kbmRuY2Jjc2F2RWFYYW9FZ3ZjczlobWJhcmNlOWltYmFRYVFhbWFRY2VmYW1TZ3ZFZ21jZWZTbWVjbWNzYXZFaHZrYURhdmFBYztXZUdWODZiYmF2Y3M5aG1lYVFhbTlSZ3ZjZXRhdmM4RjkxN2h2aW5hZWNiY2plYXZjamU2RWF2Y0ZiR1Y4NmJiYWVjZWZoZWF2Y3I0Z3ZtYmthUWhteHZrY1BodmFEYUFjUFY4NmJiYVFobWthdlRtaWF2YWs5b21pY2Rob2NlaFhhemhBeGxrYXZjdWZodmFYY2xmZ1hjO2FiOWhtYmtrZG5hSGNlY2RjYmFBYXhTRWFDYXhTRWNkdGd2eWQ6VzpHOmNqYmNkdGZ5ZGJnT1RhSGF2eWQ6MDpHOmNqYmNkdGZ5ZGJnQ2NlU0dhSGF2eWQ6NDpHOmNqYmNkdGZ5ZGJnUWNkU0dheGNiOWhHYXFHZ0xjZTlobWJhbDljdTgzaVVhbDljdTgzaThXYWw5Y3U4M2l5YWw5Y3U4M2lhYWw5Y3U4M2lLYWw5Y3U4M2l6YWw5Y3U4M2l3YWw5Y3U4M2liY2JoeGtjYmhYYXNjdWZndmhvZG5pbmRuYWxhb2NzR2NkdGZ5ZGJhQzlobWJhWGhBeGRrY3VoQWFvY3VmaG9hWGNlZmdYY3o5aG1ia2tjYmhvZG5pbmRuYWxhdmNzR2NkdGZ5ZGJhUTlobWJhb2hYeGRrY3VoWGF2Y3VmaHZhb2NlZmdvY3o5aG1ia2theGFPYXhTZ0tmaEhkbmRuYUFjbTBtYmFBY2VmaEF4ZWtjYmNzYUNhSFNndkVoQWFIYXZmaEhrZG5kbmFYY20wbWJhWGNlZmhYeGVrY2Jjc2FRYUhTZ3ZFaFhhSGF2ZmhIa2M5OmN1YUtFaFljYmh2YVhhQWNsdFZnOEFjRmVHaG9kbmRuZG5pbmF2YztxOkc6Y2piZlJiYmFvU21lYXZjZWZndmN6OWhtYnhka2thTGFPYXg5aGF2Y20wVlZtYmFEYXZjO1dlVjg2YmJ4ZWthRGFZODZiYmFlYThBODZiYmFlY2VmaGVrZG5hS21iYU9hbTlSZ3ZjZXRhdmM4RjkxN2h2aW5hZWNiY2plYXZjamU2RWF2Y0ZiR1Y4NmJiYWVjZWZoZWF2Y3I0Z3ZtYmthT2hta2RuYUFjczlobWJhQ2FtOVJndmNldGF2YzhGOTE3aHZpbmFlY2JjamVhdmNqZTZFYXZjRmJHVjg2YmJhZWNlZmhlYXZjcjRndm1ia2FDaG1rZG5hWGNzOWhtYmFRYW05Umd2Y2V0YXZjOEY5MTdodmluYWVjYmNqZWF2Y2plNkVhdmNGYkdWODZiYmFlY2VmaGVhdmNyNGd2bWJrYVFobWthbGFzY2R0ZmFPQmRiYXNjZWZjc0dodmRuZG5hQVB6YmVlZWVlZWVlZWVlZWVlYmVrYWxhdmNkdGZhQ0JkYmFzY2RmY3NHaHZrZG5kbmFYUHpiZWVlZWVlZWVlZWVlZWViZWthbGF2Y2R0ZmFRQmRiYXZjZWZjc0dodmtjaWhvYWxjO2FiZmF6Y2l0ZmdYYU9CZGxhWGFDQmRiYXpjZWZjc0doQWNkaFhhdmhzYUhoeHhla2NkaG9hbGFzY2R0ZmFRQmRiY2VoWGFzY2VmY3NHaHNhemhBa2FsYzthYmZhQWNpdGZndmFDQmRsYXZhUUJkYmFsYzthYmZhemFYZmNzR2NpdGZndmFRQmRsYXZhT0JkYmFEY2VmaERhemFvZmNzR2h6YVBjaWZnUGFpNm1ia2tkbmFlYXc5bm1iY2Jodnhla2NiaHZpbmFlYXZmYXZjO3E6RzpjamJmUmJiODZiYmF2Y2VmZ3ZjejlobWJrYWVhYjlSYXZmaHZrYWxjO2FlZjhLampqamJhdmtaZWV1Y2JoZGRuaW5hZGNlZmdkYzhGMG1lYWVjZWFkdDBtYmtrYWRjcmZjRmVHY3I5VWNpMmNkZmFiY2k5VTJjSGZrbWJjYmFiQmQ7bTpJOmNqYms6emRlcnU4SmpqampiY3o5UmhsY2JodmRuYWVhaWN2ZjZtYmFiY2JSYjttOkk6Y2piYztxZVY4NmJiYWw5Y2I4M2l3YWJjZWZodmFiYWVmYzk4ZmhvZG5haVRtYmNiaGVjYmhyY2Jod2luZG5hdmFvNm1iY2Jza2FkYXdjZHRmeWRiZ0RhbGN3ZmFyYURhZTlSZ2VhZWM4RjkxZ2U3YWU5UmM1MDdncmNkdGZncXlkYjlSZ2VjOEU5MWM5OkdhZWNkdDdhclZoZWluYXZjYmNqZWFlY2plNkVhZWNGYkdWODZiYmF2Y2VmaHZhZWNyNGdlbWJrYXFhREJkYmFEaGVhd2NlZmd3YWk5aG1ia2tkbmF2YW85bm1iY2Jza2F2Y2JCYmJhdmFiOVJjbGZodmthdmtCZWV1Y2JoZGRuaW5hZGNlZmdkYzhGMG1lYWVjZWFkdDBtYmtrYWJhZGN3ZmNGZUdjcjlVMmN2Zms6ZHZsaTk5ZHVpOTlsdWRuYWVUbWJjdWFkY2V0Y3VmdGN1NzpaaHZkbmRuY3VhaWN1ZnRjdTc6WmdvSmJiYlpNZ3I6bEpiYmI5cDlEVG1iYXI6T2h3eGVrY2pqamo5NGh3a2NiaGljYmhEaW5hbGNsZklkYmdySmJiYmJKYmJqWmFsSWRiZ3E6bGFyOmxNYWxjd2ZJZGJnazpsTWdyOnZhckpiYmJiOUJFZ3JOaHhhcWFyTmhyYWxjeGZJZGJocWRuZG5ha0piYmJiOUdUbWJheGhreGVrSmJialphcjpsOnRna2FrOm1heEpiYmJiOUdFaGtKYmJqWmF4Omw6dGd4YXg6bWFySmJiYmI5R0VocmtkbmRuYXFKYmJqOjthcUpiYmo6OzlHRWd4SmJialpheEpiYmpaOUZFYXZOSmJiYlpKYmJiOjthcUpiYmJiOUdFTWdxOmxKYmJiOXA5RFRtYmFxOk9obXhla2NqampqOTRobWtkbmRuYWtKYmJqOjtha0piYmo6OzlHRWdxSmJialphcUpiYmpaOUZFYW9OSmJiYlpKYmJiOjtha0piYmJiOUdFTWdxOmxKYmJiOXA5RFRtYmFxOk9oUHhla2NqampqOTRoUGtkbmRuYXJKYmJqOjthckpiYmo6OzlHRWdxSmJialphcUpiYmpaOUZFYW9OSmJiYlpKYmJiOjthckpiYmJiOUdFTWdyOmxKYmJiOXA5RFRtYmFyOk9oc3hla2NqampqOTRoc2tkbmRuYWRjbDlobWJhYmFEZmd6YXM4NmJiYXpjaWZhbTg2YmJhemNkZmF3ODZiYmF6Y2VmYVA4NmJieGVrYWJhaWZnemFzODdlYmF6Y29mYW04N2ViYXpjbGZhdzg3ZWJhemNkZmFQODdlYmthaWN3ZmhpYURjbGZoRGFsY3pmaGxhZWN1ZmdlbWJra2s7aGxsZDk5ZXVkOTlldWRuYWVUbWJkbmRuY3VhaWN1ZnRjdTc6Wmd2SmJiYlpNZ286bEpiYmI5cDlEVG1iYW86T2hpeGVrY2pqamo5NGhpa2FpYzs4RmlHaHJpbmFiY29mY2ljZGFsY2xmSWRiOmxhbElkYjpsOUVnaWFsY3dmSWRiOmxhbGFpY2R0ZklkYjpsOUVFZ2lhbGN4ZklkYjpsYWxhaWNkdGZJZGI6bDlFRWdpYXJWODdlYmRuZG5KYmJqOjtKYmJqWmFsYWljZHRmSWRiSmJiYmI5REVnb2FsYWljZDdjZHRmSWRiSjtabDoxWk5OZ3dKYmJqOjthd0piYmo6OzlHRWdESmJialphREpiYmpaOUZFYXZOSmJiYlpKYmJiOjthd0piYmJiOUdFTWd3OmxKYmJiOXA5RFRtYmF3Ok9ocXhla2NqampqOTRocWthYmNkZmFxODdlYmRuZG5hbGFpY2VmY2lHY2R0ZklkYko7Wmw6MVpOYW9OZ3dKYmJqOjthd0piYmo6OzlHRWdESmJialphREpiYmpaOUZFYXZOSmJiYlpKYmJiOjthd0piYmJiOUdFTWd3OmxKYmJiOXA5RFRtYmF3Ok9ocXhla2NqampqOTRocWthYmFxODdlYmRuZG5hb2FsYWljdWZjaUdjZHRmSWRiSjtabDoxWk5OZ29KYmJqOjthb0piYmo6OzlHRWd3SmJialphd0piYmpaOUZFYXZOSmJiYlpKYmJiOjthb0piYmJiOUdFTWdvOmxKYmJiOXA5RFRtYmFvOk9oaXhla2NqampqOTRoaWthYmNsZmFpODdlYmFiY3dmaGJhbGN6ZmhsYWVjdWZnZW1ia2trO2d2ZER1ZTk5OEpqampqYmNqZDlSZ284S2pqampiZG5kbmRuYWRjZDRnclRtYmM6Q3VjYmF2RWh3YW9oZGFyaERpbmFkYXdCZGJhZGNsZmhkYURjdWZnRG1ia2F2Y2Q5aG1iYWVUbWJhcmNkdGhxY2Joa2FsaHhpbmFvaGRheGhEYXJod2luYWRhZHlkYmdtYUR5ZGJjTDRjRmVHYzpjdWZnUGFtYVA5a0VCZGJhRGNsZmhEYWRjbGZoZGF3Y3VmZ3dtYmtheGFxZmh4YWtjZWZna2FlOWhtYnhka2thZVRtZWthcmNkdGh4YXZjZTloaHFjYmhraW5kbmRuZG5hcW1iYXJUbWRjOkN1aERhbGhkYXJod2luYURhZHlkYmNMNGNGZUdjOmN1ZmdtYURhbTlrRWhEYWRjbGZoZGF3Y3VmZ3dtYnhka2tkbmRuZG5kbmF2UGxlZGRiZGthclRtbGFvaGRhbGhEYXJod2luYWRjYmFEeWRiY0w0Y0ZlR2dtYzpjdWZnUGFQYW0wRUJkYmFkY2xmaGRhRGNsZmhEYXdjdWZnd21ieGlra2FyVG1pY2JoZGFyaERpbmRuYWxhZGZJZGJnc0piYmJiOUJtYmFvYWRmYXM6OGNMNGNGZUdnd2M4QWF3YzhBMEVjOmN1ZkJkYmthZGNsZmhkYURjdWZnRG1ieGRra2FyVG1ka2M6Q3VoRGtjYmhkYXJobWluYURod2RuYXZjZVNtYmFvYWRmeWRiaHdrZG5kbmFsYWRmSWRiZ3NjampqOzhpYXdhaTlSY2VmZ3djTHQ5Ujo6TkpiYmJaSmJiYjo7YXNKYmJiYjlHRU1nczpsSmJiYjlwOURUbWJhczpPaFB4ZWtjampqajk0aFBrYWJhZGZhUGNGRkZyR2F3Y0t0VkJkYmFkY2xmaGRhbWN1ZmdtbWJra2FiYXhmaGJhbGF4ZmhsYWtjZWZna2FlOWhtYmtrYW9jamRmOEtqampqYms6T2x2ZXVlOTlpdWU5OWl1ZG5hZVRtYmNlYWljdWZ0aHZjdWFpdGN1NzpaaG9jYmhyYWRjbDloaHdjYmhEaW5kbmRuYWxjd2ZJZGJncUpiYmJiYXFKYmJiYjlHRWdxSmJialphcUpiYmpaOUZFYW9OSmJiYlpNZ3E6bEpiYmI5cDlEVG1iYXE6T2hpeGVrY2pqamo5NGhpa2RuZG5hbElkYmdxSmJiYmJhcUpiYmJiOUdFZ3FKYmJqWmFxSmJialo5RkVhb05KYmJiWk1ncTpsSmJiYjlwOURUbWJhcTpPaGR4ZWtjampqajk0aGRrYWRhaTlSY2Q5VGdrYWlmaGlkbmRuYWxjbGZJZGJncUpiYmJiYXFKYmJiYjlHRWdxSmJialphcUpiYmpaOUZFYW9OSmJiYlpNZ3E6bEpiYmI5cDlEVG1iYXE6T2hkeGVrY2pqamo5NGhka2FkYWk5UmNkOVRoZGRuZG5hbGN4ZklkYmdxSmJiYmJhcUpiYmJiOUdFZ3FKYmJqWmFxSmJialo5RkVhb05KYmJiWk1ncTpsSmJiYjlwOURUbWJhcTpPaHh4ZWtjampqajk0aHhrYWRhaWZoaWF4Y2U5MWF2Vmh4ZG5kbmF3bWJhYmFEZmdtYWk4NmJiYW1jaWZheDg2YmJhbWNkZmFkODZiYmFtY2VmYWs4NmJieGVrYWJhcmZnbWFpODdlYmFtY29mYXg4N2ViYW1jbGZhZDg3ZWJhbWNkZmFrODdlYmthcmN3ZmhyYURjbGZoRGFsY3pmaGxhZWN1ZmdlbWJra2s7bXFkUXVpOTk4SmpqampiYzpxZDlSZ3Y4S2pqampiYXZjOlNlZmNiYztLYno6eGpqamI4QWRuYWRUbWJhaVRtYmRuZG5hYmFlU21iYWVob3hla2F2Y3VhZGNkdGdyYWRjRkZGRmkwRWNieWQ7cTpJOmNqYkhqampqYmJnb0JkOlNlYXZjZUJkOm1kYW9hZWFyejp3ampqYjhBa2F2Y2JCZDpPZWF2OWNiODNpOkdlYXZjOkdlZmFvYWRhaWF2YzpTZWZ6OnBqampiYXZ5ZDpHZWh3YWRjaTlVZ0RjYnlkO3E6STpjamJIampqamJiaGVhdmM6U2VmYXZ5ZDptZGdxY2R0ZmFlQmRiYXZhcWNlZmdyQmQ6bWRhZWNiYUR6OnhqampiaGthdmM6U2VmYXJjZHRmY3VhaWNkdGFpY0ZGRkZpMEVjYnlkO3E6STpjamJIampqamJiZ3hCZGJhdmFxY2RmZ21CZDptZGFsYztlYmZoUGF3aGVheGhyaW5hcmFsSWRiYVBhZXlkYmdzY3dhc2N3NkVjZHRmSWRiTVVkYmFlY2xmaGVhcmNsZmhyYWljdWZnaW1ia2F2YzpTZWZhbWNkdGZjdWFEY2R0YWRjRkZGRjk3MEVjYnlkO3E6STpjamJIampqamJiZ21CZGJkbmFkY2k2bWJhb2hlYW1ocmFEaGlpbmFyYXhhZXlkYmNkdGZJZGJheGFlY2xmeWRiY2R0ZklkYk1heGFlY3dmeWRiY2R0ZklkYk1VZGJhZWN4ZmhlYXJjbGZocmFpY3VmZ2ltYmtrYXFjaWZoemFsYztlYmZoSGF2YztxYmZoT2F2aGVhdnlkOktlaEFhdnlkOk9laENjYmhzY2JocmNiaFhjZWhRaW5hZWhMYW9hcmN4MmZnS3lkYmhQYUtjbGZ5ZGJoZGFiYVhjeDJmZ2Vjd2ZhS2N3ZnlkYmdZQmRiYWVjbGZhZEJkYmFlYVBCZGJha2FyZmNlODZiYmFPYVlCZHdhT2FkQmRsYU9hUEJkYmFtYXJjZHRmY2JCZGJjaWg4QWRuYXNUbWJhTGhpaW5hT2E4QWNkdGZhaXlkYmdlQmRiYThBYWVhWTloYWVhUDloYWVhZDloR0dmaDhBYWljbGZoaWFzY3VmZ3NtYmtrYVhjZWZoWGNiaHNpbmFDYUFhS2FzY2R0ZnlkYmNkdGdpZnlkYmNkdGZnWWhlYXdhaWZnZHlkYmdQaGlkbmFQVG1iZG5pbmFleWRiYXJTbWVhZWNsZmhlYWljdWZnaVRtZHhia2thZWFZYVBjZHRmYzk4ZnlkYkJkYmFkYWR5ZGJjdWZCZGJrYXNjZWZnc2NpOWhtYmtkbmRuZG5hOEFUbWJjdWhySmJiYmJoRWNiaGRhdnlkOktlaFlhdnlkOk9laEtpbmRuYXdhT2FkY2R0ZnlkYmNkdGdzZnlkYmdlVG1iYXhhc2ZnaUlkYmgzYWlhbGN1YWRhZGNzMEVjZHRmY2xmSWRiYUhhZWN3YWVjdzZFY2R0ZklkYk1nNVVkYmE1YTM6dGg1YWVjZHRoaWFLYVlhc2Z5ZGJjZHRmaGVpbmFtYWV5ZGJnc2NkdGZnUGE1YVBJZGJNZzNVZGJhM2FFYUVhMzlEZ1BFaEVhc2FyYVBFaHJhZWNsZmhlYWljOThmZ2ltYmtrYWRjZWZnZGE4QTlobWJrYXJjdTlobWVrYVFhRDlwbWVpbmRuYWthUWZSYmJtYmFRaHJ4ZGthRGFRY2VmZ1E5aG1ieGRra2E4QWN6YThBY3o2RWhzYU9oZWFMaE9hcmN1OWhtZWtrYXpUbWJhcWNkdGF2YzpTZWZmY3dmaGVpbmFleWRiY2J5ZDt1Okk6Y2piSDpiampqYmJhZWM5OGZoZWF6Y3VmZ3ptYmtrYXZjOnFkZjhLampqamJrOjBsZW91Y3VhaWNkdGd2YWljRkZGRmkwRWdvY2J5ZDtxOkk6Y2piSGpqampiYmhyYWxhbHlkOUdnd2NkdGZhckJkYmFsYXdjZWZCZDlHYWJhckJkYmFvY2J5ZDtxOkk6Y2piSGpqampiYmhyYWxhbHlkOUdnb2NkdGZhckJkYmFsYW9jZWZCZDlHYWJhckJkbGN1YWRjZHRhZGNGRkZGaTBFY2J5ZDtxOkk6Y2piSGpqampiYmhyYWxhbHlkOUdnb2NkdGZhckJkYmFsYW9jZWZCZDlHYWJhckJkd2FieWRiY2Jhdno6eGpqamI4QWFieWRiaHJhZWhsYWRodmluYXJhbHlkYmNkdGZnb2FveWRiY2VmQmRiYWxjbGZobGF2Y3VmZ3ZtYmtjYmh2YWJ5ZGxnbGhvYXJod2FpaERpbmFvYXZCZGJhb2NsZmhvYXd5ZGJhdmZodmF3Y2xmaHdhRGN1ZmdEbWJrYWRjaTlVaHFkbmFkY2Q5bm1iYWJ5ZHdob2NiaHZpbmFlY3dmeWRiaHdhZWNsZnlkYmhEYWxhZXlkYmNkdGZnYmFieWRiZ2JjZWZCZGJhb2FiY2R0ZmF2QmRiYWxhRGNkdGZnRGFEeWRiZ0RjZWZCZGJhb2FEY2R0ZmF2QmRiYWxhd2NkdGZnd2F3eWRiZ3djZWZCZGJhb2F3Y2R0ZmF2QmRiYWVjeGZoZWFxYXZjZWZndjlobWJra2luYWxhbHlkYmFyeWRiOVJCZGJhcmNsZmhyYWxjbGZobGFpY3VmZ2ltYmtrUWJhYmFlYWRhaWM7RzpHOmNqYno6b2pqamJrUWJhYmFlYWRhaWM7aTpIOmNqYno6b2pqamJrOURlZXVhYmNGZWFpY2R0ejp4ampqYmhsY2JoYmRuYWRUbWJpbmRuYWxhZXlkYmNkdGZnaXlkYmN1OWhtYmFpYWJCZGJhYmNlZmhia2FlY2xmaGVhZGN1ZmdkbWJra2FiazozdmlvdWQ5OmR1OEpqampqYmM7V2E5UmdsOEtqampqYmNiaHZhbGN4ZmNiYztLYno6eGpqamI4QWFsY3VhZGNpdGdvYWRjRkZGRmUwRWNieWQ7cTpJOmNqYkhqampqYmJnckJkeGFsY2VCZDJhcmFlYWRhaWNlek5qampiYWxjdWFvYWRjampqam9HRWNieWQ7cTpJOmNqYkhqampqYmJnd0JkemFkY2R0aGVkbmFkVG1iYWJoaWluYWlhdkJkYmFpY2xmaGlhZGF2Y2VmZ3Y5aG1ia2thd2FlZmhEYWxhYkJkd2FsYXdCZGw5Y2JocWluZG5hZFRtYmFxOWNxOTpoa2FyaHZhRGhpYWRoZWluYWlhdjhQaWJhazE6TmNGckc4N2ViYXZjd2ZodmFpY2RmaGlhZWN1ZmdlbWJra2FsY2xmYXE6TmNlR2NkdGZ5ZGJoeGFsY2xmYXE5Y2U5OGdxOk5jZUdjZHRmeWRiaG1hbGM7V2JmY2JjamF6OnhqampiOEFhRGh2YWRoaWRuYWRUbWJpbmFsYztXYmZhdjhWZWJjZHRmZ2VhZXlkYmNlZkJkYmF2Y2RmaHZhaWN1ZmdpbWJra2NiaHZjYmhpaW5hbGM7V2JmYXZmZ2V5ZGJob2FlYWlCZGJhb2FpZmhpYXZjbGZndmNqYTlobWJrYWRodmRuZG5hZFRtYmluYWxjO1diZmFEYW15ZGJnaWNldGY4VmViY2R0ZmdlYWV5ZGJnZWNlZkJkYmF4YWVjZHRmYWlCZGJhbWNsZmhtYXZjdWZndm1ia2FxOWN2OXNtZGNiaHZpbmFiYXd5ZGJjZHRmYXZCZGJhd2NsZmh3YWRhdmNlZmd2OWhtYnhka2thcTljdjlzbWVra2N3aHZjYmhpaW5hbGN4ZmF2ZmM5OGZ5ZGJjYnlkO3U6STpjamJIOmJqampiYmFpY2VHaGVjbGh2Y2VoaWFlVG1ia2FsYztXYWY4S2pqampiazpBd2xpdW85OWl1ZDk6Y2JodjhKampqamJjYTlSZ29jYnlkOjQ6STpjamJCZEthb2NiOFBkOlc6STpjamI4M2l6YW9jYnlkO2U6STpjamJCZHdhb2NiOFBkOjg6STpjamI4M2liYWljZDRocmRuZG5hZG1iSkZGdUZod0pGRnV1aERKRkZ1dWhxSkZGdUZoa0pGRnV1aHhKRkZ1RmhteGVrYXJjZHRoUGFlaHNpbmNiaGlpbmFvY3pmYWlmZ3phc2FpZklkYmd3YXpJZGJnRGFEYXc5RUVVZGJhb2FpZmd6YXdheklkYmdEYURhdzlERVVkYmFpY2xmZ2ljeDlobWJrYXNhUGZoc2F2Y2VmZ3ZhZDlobWJrYW9JZEtoRGFvSWR3aHdhb0lkQ2hxYW9JZGxoa2FvSWR6aHhhb0lkYmhta2RuYWRUbWJKYmJiYkpiRnU5aEpiYmJiYW1heDp0Z21hbUpiYmJiOURFZ21ha2FxOnRna2FrYW05REVna2F3YUQ6dGd3YXdhazlERWd3OnZhd0piYmJiOUJFaHdkbmFsbWJhcmNkdGhvaW5kbmRuYWVjbGZJZGJhcTp0YXdOSmJiYlpNZ2s6bEpiYmI5cDlEVG1iYWs6T2hpeGVrY2pqamo5NGhpa2FpOlM5Y0M6Z2hIZG5kbmFlSWRiYXg6dGF3TkpiYmJaTWdrOmxKYmJiOXA5RFRtYmFrOk9oaXhla2NqampqOTRoaWthSGFpOlM6ZWhIZG5kbmFlY3dmSWRiYUQ6dGF3TkpiYmJaTWdrOmxKYmJiOXA5RFRtYmFrOk9oaXhla2NqampqOTRoaWthYmFIYWk6VDljeTpnOmU4M2liYWVhb2ZoZWFiY3dmaGJhZGN1ZmdkbWJ4ZGtrYXJjZHRob2luZG5kbmFlSWRiYXg6dGF3TkpiYmJaTWdrOmxKYmJiOXA5RFRtYmFrOk9oaXhla2NqampqOTRoaWthaTpTZ0g5Y2E6Z2FIOWN6Omc5Y2pqajs0czpkOmVhSDljRmU6ZDplOWNGOmJqOzQ6cGo7YXI6ZDljOmJkOTo5YzpwO0c6ZDs0ajpFO2FyOmQ5Y0g5OjljO2Q7SDpXOnk6bTpnO2Q7SGI6ZDljdjk6OWM7ajpLTTtqOktNO2o6S2Q6ZGhPZG5kbmFlY2xmSWRiYXE6dGF3TkpiYmJaTWdrOmxKYmJiOXA5RFRtYmFrOk9oaXhla2NqampqOTRoaWthaTpTZ0g5Y2E6Z2FIOWN6Omc5Y2pqajs0czpkOmVhSDljRmU6ZDplOWNGOmJqOzQ6cGo7YXI6ZDljOmJkOTo5YzpwO0c6ZDs0ajpFO2FyOmQ5Y0g5OjljO2Q7SDpXOnk6bTpnO2Q7SGI6ZDljcTk6OWNNO2o6S007ajpLTTtqbDpkYU86ZWhPZG5kbmFlY3dmSWRiYUQ6dGF3TkpiYmJaTWdrOmxKYmJiOXA5RFRtYmFrOk9oaXhla2NqampqOTRoaWthYmFPYWk6U2dIOWNhOmdhSDljejpnOWNqamo7NHM6ZDplYUg5Y0ZlOmQ6ZTljRjpiajs0OnBqO2FyOmQ5YzpiZDk6OWM6cDtHOmQ7NGo6RTthcjpkOWNIOTo5YztkO0g6Vzp5Om06ZztkO0hiOmQ5Y0M5OjljOktNO2o6S007ajpLTUQ6ZDplODNpYmFlYW9maGVhYmN3ZmhiYWRjdWZnZG1ia2trOXRlaXVjYmNieWQ7eTpJOmNqYmdlYWJjaWZjOThHZmdiQmQ7eTpJOmNqYmRuZG5hYlpiY3p0Z2Q5bm1iY3VoaWFiYWQ5UmNGRmlmY3o0bmJjdVNtZWthZWhpa2FpaztMZWVldWRuZG5hZWFiVmNpR1RtYmFiaGl4ZWtkbmRuYWRjejlwbWJhYmhpeGVrYWJoaWluYWlhZXlkYkJkYmFpY2xmYWVjbGZ5ZGJCZGJhaWN3ZmFlY3dmeWRiQmRiYWljeGZhZWN4ZnlkYkJkYmFlY3pmaGVhaWN6ZmhpYWRjOVdmZ2RjczBtYmtrYWRjbDZtYmluYWlhZXlkYkJkYmFlY2xmaGVhaWNsZmhpYWRjOThmZ2RjaTBtYmtrZG5hZFRtYmluYWlhZVJiYjg2YmJhaWNlZmhpYWVjZWZoZWFkY3VmZ2RtYmtrYWJrO2FlZWR1ZG5kbmFiY2lHVG1iYWJoaXhla2FlY0ZlR2M6YjpjOmV3MmhsZG5kbmFkY3o5cG1iYWJoaXhla2FiaGlpbmFpYWxCZGJhaWN4ZmFsQmRiYWljd2ZhbEJkYmFpY2xmYWxCZGJhaWN6ZmhpYWRjOVdmZ2RjczBtYmtrYWRjbDZtYmluYWlhbEJkYmFpY2xmaGlhZGM5OGZnZGNpMG1ia2tkbmFkVG1iaW5haWFlODZiYmFpY2VmaGlhZGN1ZmdkbWJra2Fiazl0ZWl1Y2JjYnlkO3k6STpjamJnZWFiY3JmYzk0R2ZnYkJkO3k6STpjamJkbmRuYWJaYmN6dGdkOW5tYmN1aGlhYmFkOVJjRkZpZmN6NG5iY3VTbWVrYWVoaWthaWtUZWV1Y2JhYmNieWQ7eTpJOmNqYmdlOVJjaWZjOThHYWVmZ2JCZDt5Okk6Y2piZG5hYlpiY3p0Z2U5bm1iYWJhZTlSY0ZGaWZjejRuYjhBa2trO1NkZGJjajpHZGs7aWRiYmJiZGJiYmxiYmJ3YmJiYmJiYmViYmJkYmJibGJiYndiYmJiYmJiYmJiYmJiYmJiYmJiZWJiYmRiYmJiYmJiZWJiYmJiYmJiYmJiYmJiYmI0Omg5dzlOOTQ6UDpnVzpqOU86eWU5UGJiYmJiYjpsMjloWjs2OTo5a1o7Tjs3Nlo7cmc5N1o7ejtvOXhaOEo7Qjg1Wjs6O3U5eVo7YjtrOUhaOjI7WjlEWjllOmw5bVo1OUE4S1o6cjtUM1o6QTp6WVo3OU9IWjtqNDo6ODo6WTpEOVY4OmJiYmI5czo0OTpaOFI6aEJaOU05TTtNODpMO3o7bzg6Ozg6UEc4OXE7eDpKODc4UjpoUTg6Ok06QjtlODdiYmJiYmJqWmJialpiYmpaOkU7VjtOODo6WTpEc1o5aTtIOzY4OnhkO1I4OjtoMDgzODo7VzpOb1piYmJiOldWOU84OnVmODg4OjlpO0g7Njg6OWM5RztMODk7bjttOW04OTtEOEtvODpiYmJiZjo4dFo5bTgzNlpTOjJBWkw7elBaWjgxOEVaOWU6bHhaO1U5OEY4OjgxOUU7Njg6RkZ1dUZGdXVGRnV1RkZ1RkZGdUZGRnVGYmM7aTpJZGtDZWJiYmViYmJlYmJiZGJiYjlHOnJiYiI7CiAgICAgICAgdmFyIHdhc21wYWNrID0gbmV3IFVpbnQ4QXJyYXkoWwogICAgICAgICAgMzIsCiAgICAgICAgICAwLAogICAgICAgICAgNjUsCiAgICAgICAgICAyLAogICAgICAgICAgMSwKICAgICAgICAgIDEwNiwKICAgICAgICAgIDM0LAogICAgICAgICAgMzMsCiAgICAgICAgICAzLAogICAgICAgICAgMTI4LAogICAgICAgICAgMTEsCiAgICAgICAgICA0LAogICAgICAgICAgMTMsCiAgICAgICAgICA2NCwKICAgICAgICAgIDYsCiAgICAgICAgICAyNTMsCiAgICAgICAgICAxMCwKICAgICAgICAgIDcsCiAgICAgICAgICAxNSwKICAgICAgICAgIDExNiwKICAgICAgICAgIDEyNywKICAgICAgICAgIDUsCiAgICAgICAgICA4LAogICAgICAgICAgMTIsCiAgICAgICAgICA0MCwKICAgICAgICAgIDE2LAogICAgICAgICAgMTksCiAgICAgICAgICA1NCwKICAgICAgICAgIDIwLAogICAgICAgICAgOSwKICAgICAgICAgIDI3LAogICAgICAgICAgMjU1LAogICAgICAgICAgMTEzLAogICAgICAgICAgMTcsCiAgICAgICAgICA0MiwKICAgICAgICAgIDY3LAogICAgICAgICAgMjQsCiAgICAgICAgICAyMywKICAgICAgICAgIDE0NiwKICAgICAgICAgIDE0OCwKICAgICAgICAgIDE4LAogICAgICAgICAgMTQsCiAgICAgICAgICAyMiwKICAgICAgICAgIDQ1LAogICAgICAgICAgNzAsCiAgICAgICAgICA2OSwKICAgICAgICAgIDU2LAogICAgICAgICAgMTE0LAogICAgICAgICAgMTAxLAogICAgICAgICAgMjEsCiAgICAgICAgICAyNSwKICAgICAgICAgIDYzLAogICAgICAgICAgNzUsCiAgICAgICAgICAxMzYsCiAgICAgICAgICAxMDgsCiAgICAgICAgICAyOCwKICAgICAgICAgIDExOCwKICAgICAgICAgIDI5LAogICAgICAgICAgNzMsCiAgICAgICAgICAxMTUKICAgICAgICBdKTsKICAgICAgICBpZiAodHlwZW9mIFdlYkFzc2VtYmx5ICE9PSAib2JqZWN0IikgewogICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgc3VwcG9ydGVkOiBmYWxzZQogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgdmFyIGluc3RhbmNlOwogICAgICAgIHZhciByZWFkeSA9IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKHVucGFjayh3YXNtMiksIHt9KS50aGVuKGZ1bmN0aW9uKHJlc3VsdCkgewogICAgICAgICAgaW5zdGFuY2UgPSByZXN1bHQuaW5zdGFuY2U7CiAgICAgICAgICBpbnN0YW5jZS5leHBvcnRzLl9fd2FzbV9jYWxsX2N0b3JzKCk7CiAgICAgICAgICBpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfZW5jb2RlVmVydGV4VmVyc2lvbigxKTsKICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVJbmRleFZlcnNpb24oMSk7CiAgICAgICAgfSk7CiAgICAgICAgZnVuY3Rpb24gdW5wYWNrKGRhdGEpIHsKICAgICAgICAgIHZhciByZXN1bHQgPSBuZXcgVWludDhBcnJheShkYXRhLmxlbmd0aCk7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgZGF0YS5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgdmFyIGNoID0gZGF0YS5jaGFyQ29kZUF0KGkyKTsKICAgICAgICAgICAgcmVzdWx0W2kyXSA9IGNoID4gOTYgPyBjaCAtIDk3IDogY2ggPiA2NCA/IGNoIC0gMzkgOiBjaCArIDQ7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgd3JpdGUgPSAwOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGRhdGEubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIHJlc3VsdFt3cml0ZSsrXSA9IHJlc3VsdFtpMl0gPCA2MCA/IHdhc21wYWNrW3Jlc3VsdFtpMl1dIDogKHJlc3VsdFtpMl0gLSA2MCkgKiA2NCArIHJlc3VsdFsrK2kyXTsKICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiByZXN1bHQuYnVmZmVyLnNsaWNlKDAsIHdyaXRlKTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gYXNzZXJ0KGNvbmQpIHsKICAgICAgICAgIGlmICghY29uZCkgewogICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoIkFzc2VydGlvbiBmYWlsZWQiKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gYnl0ZXModmlldykgewogICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHZpZXcuYnVmZmVyLCB2aWV3LmJ5dGVPZmZzZXQsIHZpZXcuYnl0ZUxlbmd0aCk7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHJlb3JkZXIoZnVuLCBpbmRpY2VzLCB2ZXJ0aWNlcywgb3B0ZikgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgaXAgPSBzYnJrKGluZGljZXMubGVuZ3RoICogNCk7CiAgICAgICAgICB2YXIgcnAgPSBzYnJrKHZlcnRpY2VzICogNCk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICB2YXIgaW5kaWNlczggPSBieXRlcyhpbmRpY2VzKTsKICAgICAgICAgIGhlYXAuc2V0KGluZGljZXM4LCBpcCk7CiAgICAgICAgICBpZiAob3B0ZikgewogICAgICAgICAgICBvcHRmKGlwLCBpcCwgaW5kaWNlcy5sZW5ndGgsIHZlcnRpY2VzKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB1bmlxdWUgPSBmdW4ocnAsIGlwLCBpbmRpY2VzLmxlbmd0aCwgdmVydGljZXMpOwogICAgICAgICAgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICB2YXIgcmVtYXAgPSBuZXcgVWludDMyQXJyYXkodmVydGljZXMpOwogICAgICAgICAgbmV3IFVpbnQ4QXJyYXkocmVtYXAuYnVmZmVyKS5zZXQoaGVhcC5zdWJhcnJheShycCwgcnAgKyB2ZXJ0aWNlcyAqIDQpKTsKICAgICAgICAgIGluZGljZXM4LnNldChoZWFwLnN1YmFycmF5KGlwLCBpcCArIGluZGljZXMubGVuZ3RoICogNCkpOwogICAgICAgICAgc2JyayhpcCAtIHNicmsoMCkpOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGluZGljZXMubGVuZ3RoOyArK2kyKSBpbmRpY2VzW2kyXSA9IHJlbWFwW2luZGljZXNbaTJdXTsKICAgICAgICAgIHJldHVybiBbcmVtYXAsIHVuaXF1ZV07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHNwYXRpYWxzb3J0KGZ1biwgcG9zaXRpb25zLCBjb3VudCwgc3RyaWRlKSB7CiAgICAgICAgICB2YXIgc2JyayA9IGluc3RhbmNlLmV4cG9ydHMuc2JyazsKICAgICAgICAgIHZhciBpcCA9IHNicmsoY291bnQgKiA0KTsKICAgICAgICAgIHZhciBzcCA9IHNicmsoY291bnQgKiBzdHJpZGUpOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMocG9zaXRpb25zKSwgc3ApOwogICAgICAgICAgZnVuKGlwLCBzcCwgY291bnQsIHN0cmlkZSk7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciByZW1hcCA9IG5ldyBVaW50MzJBcnJheShjb3VudCk7CiAgICAgICAgICBuZXcgVWludDhBcnJheShyZW1hcC5idWZmZXIpLnNldChoZWFwLnN1YmFycmF5KGlwLCBpcCArIGNvdW50ICogNCkpOwogICAgICAgICAgc2JyayhpcCAtIHNicmsoMCkpOwogICAgICAgICAgcmV0dXJuIHJlbWFwOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBlbmNvZGUoZnVuLCBib3VuZCwgc291cmNlLCBjb3VudCwgc2l6ZSwgbGV2ZWwsIHZlcnNpb24pIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHRwID0gc2Jyayhib3VuZCk7CiAgICAgICAgICB2YXIgc3AgPSBzYnJrKGNvdW50ICogc2l6ZSk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhzb3VyY2UpLCBzcCk7CiAgICAgICAgICB2YXIgcmVzID0gZnVuKHRwLCBib3VuZCwgc3AsIGNvdW50LCBzaXplLCBsZXZlbCwgdmVyc2lvbik7CiAgICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3IFVpbnQ4QXJyYXkocmVzKTsKICAgICAgICAgIHRhcmdldC5zZXQoaGVhcC5zdWJhcnJheSh0cCwgdHAgKyByZXMpKTsKICAgICAgICAgIHNicmsodHAgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiB0YXJnZXQ7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIG1heGluZGV4KHNvdXJjZSkgewogICAgICAgICAgdmFyIHJlc3VsdCA9IDA7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgc291cmNlLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICB2YXIgaW5kZXggPSBzb3VyY2VbaTJdOwogICAgICAgICAgICByZXN1bHQgPSByZXN1bHQgPCBpbmRleCA/IGluZGV4IDogcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gaW5kZXgzMihzb3VyY2UsIHNpemUpIHsKICAgICAgICAgIGFzc2VydChzaXplID09IDIgfHwgc2l6ZSA9PSA0KTsKICAgICAgICAgIGlmIChzaXplID09IDQpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50MzJBcnJheShzb3VyY2UuYnVmZmVyLCBzb3VyY2UuYnl0ZU9mZnNldCwgc291cmNlLmJ5dGVMZW5ndGggLyA0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHZhciB2aWV3ID0gbmV3IFVpbnQxNkFycmF5KHNvdXJjZS5idWZmZXIsIHNvdXJjZS5ieXRlT2Zmc2V0LCBzb3VyY2UuYnl0ZUxlbmd0aCAvIDIpOwogICAgICAgICAgICByZXR1cm4gbmV3IFVpbnQzMkFycmF5KHZpZXcpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBmaWx0ZXIoZnVuLCBzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMsIGluc2l6ZSwgbW9kZSkgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgdHAgPSBzYnJrKGNvdW50ICogc3RyaWRlKTsKICAgICAgICAgIHZhciBzcCA9IHNicmsoY291bnQgKiBpbnNpemUpOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMoc291cmNlKSwgc3ApOwogICAgICAgICAgZnVuKHRwLCBjb3VudCwgc3RyaWRlLCBiaXRzLCBzcCwgbW9kZSk7CiAgICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3IFVpbnQ4QXJyYXkoY291bnQgKiBzdHJpZGUpOwogICAgICAgICAgdGFyZ2V0LnNldChoZWFwLnN1YmFycmF5KHRwLCB0cCArIGNvdW50ICogc3RyaWRlKSk7CiAgICAgICAgICBzYnJrKHRwIC0gc2JyaygwKSk7CiAgICAgICAgICByZXR1cm4gdGFyZ2V0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgcmVhZHksCiAgICAgICAgICBzdXBwb3J0ZWQ6IHRydWUsCiAgICAgICAgICByZW9yZGVyTWVzaDogZnVuY3Rpb24oaW5kaWNlcywgdHJpYW5nbGVzLCBvcHRzaXplKSB7CiAgICAgICAgICAgIGFzc2VydChpbmRpY2VzIGluc3RhbmNlb2YgVWludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQoIXRyaWFuZ2xlcyB8fCBpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIHZhciBvcHRmID0gdHJpYW5nbGVzID8gb3B0c2l6ZSA/IGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9vcHRpbWl6ZVZlcnRleENhY2hlU3RyaXAgOiBpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfb3B0aW1pemVWZXJ0ZXhDYWNoZSA6IHZvaWQgMDsKICAgICAgICAgICAgcmV0dXJuIHJlb3JkZXIoaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X29wdGltaXplVmVydGV4RmV0Y2hSZW1hcCwgaW5kaWNlcywgbWF4aW5kZXgoaW5kaWNlcykgKyAxLCBvcHRmKTsKICAgICAgICAgIH0sCiAgICAgICAgICByZW9yZGVyUG9pbnRzOiBmdW5jdGlvbihwb3NpdGlvbnMsIHBvc2l0aW9uc19zdHJpZGUpIHsKICAgICAgICAgICAgYXNzZXJ0KHBvc2l0aW9ucyBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSk7CiAgICAgICAgICAgIGFzc2VydChwb3NpdGlvbnMubGVuZ3RoICUgcG9zaXRpb25zX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHBvc2l0aW9uc19zdHJpZGUgPj0gMyk7CiAgICAgICAgICAgIHJldHVybiBzcGF0aWFsc29ydChpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfc3BhdGlhbFNvcnRSZW1hcCwgcG9zaXRpb25zLCBwb3NpdGlvbnMubGVuZ3RoIC8gcG9zaXRpb25zX3N0cmlkZSwgcG9zaXRpb25zX3N0cmlkZSAqIDQpOwogICAgICAgICAgfSwKICAgICAgICAgIGVuY29kZVZlcnRleEJ1ZmZlcjogZnVuY3Rpb24oc291cmNlLCBjb3VudCwgc2l6ZSkgewogICAgICAgICAgICBhc3NlcnQoc2l6ZSA+IDAgJiYgc2l6ZSA8PSAyNTYpOwogICAgICAgICAgICBhc3NlcnQoc2l6ZSAlIDQgPT0gMCk7CiAgICAgICAgICAgIHZhciBib3VuZCA9IGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVWZXJ0ZXhCdWZmZXJCb3VuZChjb3VudCwgc2l6ZSk7CiAgICAgICAgICAgIHJldHVybiBlbmNvZGUoaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2VuY29kZVZlcnRleEJ1ZmZlciwgYm91bmQsIHNvdXJjZSwgY291bnQsIHNpemUpOwogICAgICAgICAgfSwKICAgICAgICAgIGVuY29kZVZlcnRleEJ1ZmZlckxldmVsOiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzaXplLCBsZXZlbCwgdmVyc2lvbikgewogICAgICAgICAgICBhc3NlcnQoc2l6ZSA+IDAgJiYgc2l6ZSA8PSAyNTYpOwogICAgICAgICAgICBhc3NlcnQoc2l6ZSAlIDQgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydChsZXZlbCA+PSAwICYmIGxldmVsIDw9IDMpOwogICAgICAgICAgICBhc3NlcnQodmVyc2lvbiA9PT0gdm9pZCAwIHx8IHZlcnNpb24gPT0gMCB8fCB2ZXJzaW9uID09IDEpOwogICAgICAgICAgICB2YXIgYm91bmQgPSBpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfZW5jb2RlVmVydGV4QnVmZmVyQm91bmQoY291bnQsIHNpemUpOwogICAgICAgICAgICByZXR1cm4gZW5jb2RlKGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVWZXJ0ZXhCdWZmZXJMZXZlbCwgYm91bmQsIHNvdXJjZSwgY291bnQsIHNpemUsIGxldmVsLCB2ZXJzaW9uID09PSB2b2lkIDAgPyAtMSA6IHZlcnNpb24pOwogICAgICAgICAgfSwKICAgICAgICAgIGVuY29kZUluZGV4QnVmZmVyOiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzaXplKSB7CiAgICAgICAgICAgIGFzc2VydChzaXplID09IDIgfHwgc2l6ZSA9PSA0KTsKICAgICAgICAgICAgYXNzZXJ0KGNvdW50ICUgMyA9PSAwKTsKICAgICAgICAgICAgdmFyIGluZGljZXMgPSBpbmRleDMyKHNvdXJjZSwgc2l6ZSk7CiAgICAgICAgICAgIHZhciBib3VuZCA9IGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVJbmRleEJ1ZmZlckJvdW5kKGNvdW50LCBtYXhpbmRleChpbmRpY2VzKSArIDEpOwogICAgICAgICAgICByZXR1cm4gZW5jb2RlKGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVJbmRleEJ1ZmZlciwgYm91bmQsIGluZGljZXMsIGNvdW50LCA0KTsKICAgICAgICAgIH0sCiAgICAgICAgICBlbmNvZGVJbmRleFNlcXVlbmNlOiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzaXplKSB7CiAgICAgICAgICAgIGFzc2VydChzaXplID09IDIgfHwgc2l6ZSA9PSA0KTsKICAgICAgICAgICAgdmFyIGluZGljZXMgPSBpbmRleDMyKHNvdXJjZSwgc2l6ZSk7CiAgICAgICAgICAgIHZhciBib3VuZCA9IGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9lbmNvZGVJbmRleFNlcXVlbmNlQm91bmQoY291bnQsIG1heGluZGV4KGluZGljZXMpICsgMSk7CiAgICAgICAgICAgIHJldHVybiBlbmNvZGUoaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2VuY29kZUluZGV4U2VxdWVuY2UsIGJvdW5kLCBpbmRpY2VzLCBjb3VudCwgNCk7CiAgICAgICAgICB9LAogICAgICAgICAgZW5jb2RlR2x0ZkJ1ZmZlcjogZnVuY3Rpb24oc291cmNlLCBjb3VudCwgc2l6ZSwgbW9kZSwgdmVyc2lvbikgewogICAgICAgICAgICB2YXIgdGFibGUgPSB7CiAgICAgICAgICAgICAgQVRUUklCVVRFUzogdGhpcy5lbmNvZGVWZXJ0ZXhCdWZmZXJMZXZlbCwKICAgICAgICAgICAgICBUUklBTkdMRVM6IHRoaXMuZW5jb2RlSW5kZXhCdWZmZXIsCiAgICAgICAgICAgICAgSU5ESUNFUzogdGhpcy5lbmNvZGVJbmRleFNlcXVlbmNlCiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGFzc2VydCh0YWJsZVttb2RlXSk7CiAgICAgICAgICAgIHJldHVybiB0YWJsZVttb2RlXSgKICAgICAgICAgICAgICBzb3VyY2UsCiAgICAgICAgICAgICAgY291bnQsCiAgICAgICAgICAgICAgc2l6ZSwKICAgICAgICAgICAgICAvKiBsZXZlbD0gKi8KICAgICAgICAgICAgICAyLAogICAgICAgICAgICAgIHZlcnNpb24gPT09IHZvaWQgMCA/IDAgOiB2ZXJzaW9uCiAgICAgICAgICAgICk7CiAgICAgICAgICB9LAogICAgICAgICAgZW5jb2RlRmlsdGVyT2N0OiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMpIHsKICAgICAgICAgICAgYXNzZXJ0KHN0cmlkZSA9PSA0IHx8IHN0cmlkZSA9PSA4KTsKICAgICAgICAgICAgYXNzZXJ0KGJpdHMgPj0gMiAmJiBiaXRzIDw9IDE2KTsKICAgICAgICAgICAgcmV0dXJuIGZpbHRlcihpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfZW5jb2RlRmlsdGVyT2N0LCBzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMsIDE2KTsKICAgICAgICAgIH0sCiAgICAgICAgICBlbmNvZGVGaWx0ZXJRdWF0OiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMpIHsKICAgICAgICAgICAgYXNzZXJ0KHN0cmlkZSA9PSA4KTsKICAgICAgICAgICAgYXNzZXJ0KGJpdHMgPj0gNCAmJiBiaXRzIDw9IDE2KTsKICAgICAgICAgICAgcmV0dXJuIGZpbHRlcihpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfZW5jb2RlRmlsdGVyUXVhdCwgc291cmNlLCBjb3VudCwgc3RyaWRlLCBiaXRzLCAxNik7CiAgICAgICAgICB9LAogICAgICAgICAgZW5jb2RlRmlsdGVyRXhwOiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMsIG1vZGUpIHsKICAgICAgICAgICAgYXNzZXJ0KHN0cmlkZSA+IDAgJiYgc3RyaWRlICUgNCA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KGJpdHMgPj0gMSAmJiBiaXRzIDw9IDI0KTsKICAgICAgICAgICAgdmFyIHRhYmxlID0gewogICAgICAgICAgICAgIFNlcGFyYXRlOiAwLAogICAgICAgICAgICAgIFNoYXJlZFZlY3RvcjogMSwKICAgICAgICAgICAgICBTaGFyZWRDb21wb25lbnQ6IDIsCiAgICAgICAgICAgICAgQ2xhbXBlZDogMwogICAgICAgICAgICB9OwogICAgICAgICAgICBhc3NlcnQoIW1vZGUgfHwgbW9kZSBpbiB0YWJsZSk7CiAgICAgICAgICAgIHJldHVybiBmaWx0ZXIoaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2VuY29kZUZpbHRlckV4cCwgc291cmNlLCBjb3VudCwgc3RyaWRlLCBiaXRzLCBzdHJpZGUsIG1vZGUgPyB0YWJsZVttb2RlXSA6IDEpOwogICAgICAgICAgfSwKICAgICAgICAgIGVuY29kZUZpbHRlckNvbG9yOiBmdW5jdGlvbihzb3VyY2UsIGNvdW50LCBzdHJpZGUsIGJpdHMpIHsKICAgICAgICAgICAgYXNzZXJ0KHN0cmlkZSA9PSA0IHx8IHN0cmlkZSA9PSA4KTsKICAgICAgICAgICAgYXNzZXJ0KGJpdHMgPj0gMiAmJiBiaXRzIDw9IDE2KTsKICAgICAgICAgICAgcmV0dXJuIGZpbHRlcihpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfZW5jb2RlRmlsdGVyQ29sb3IsIHNvdXJjZSwgY291bnQsIHN0cmlkZSwgYml0cywgMTYpOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL21lc2hvcHRfZGVjb2Rlci5tanMKICB2YXIgTWVzaG9wdERlY29kZXI7CiAgdmFyIGluaXRfbWVzaG9wdF9kZWNvZGVyID0gX19lc20oewogICAgIm5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL21lc2hvcHRfZGVjb2Rlci5tanMiKCkgewogICAgICBNZXNob3B0RGVjb2RlciA9IChmdW5jdGlvbigpIHsKICAgICAgICB2YXIgd2FzbV9iYXNlID0gImI5SDc5VGViYmJlOEZ2OUdiYjlHdnV1dXV1ZXU5R2l1dXViOUdldWV1OUdpdXV1ZXVpeGtiZWVlZGRkZGlsbHZpZWJlb3dldWVjajpHZGtyO05lcW85VFc5VDlWVjk1ZGJIOUY5RjkzOUg3OVQ5RjlKOUgyMjlGOUp0OVZWN2JiOEE5VFc3OU85VjlXdDlGOUtXOUo5VjlLVzl3V1Z0Vzk0OWM5MTlNOU1XVmJlWTlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXNjlVOUtXOTQ5YzkxOU05TVdWYmRFOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1c2OVU5S1c5NDl0V0c5MVc5VTlKV2JpTDlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXUzlQMnRXVjlwOUp0YmxLOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1dTOVAydFdWOXI5MTlIdGJ2TDlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXUzlQMnRXVlQ5NDlXYm9ZOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1dTOVAydFdWSjlWMjlWVmJybDc5SVY5UmJ3cTFaa2RiazprWWk1dWQ5OmR1OEpqampqYmNqcTlSZ3Y4S2pqampiYzk6aG9kbmFsVG1iY3Vob2FpUmJiZ3JjO1dlR2M6R2U5aG1iYXJjc0dnd2NlMG1iYzk6aG9hbGN1ZmFkY2Q0Y2Jhd0VnRGFkZmdyY0tjYWF3RWdxYXJhcTBFZ2s2bWJhaWNlZmh4Y2o7YWJhZDlVYztXRmJHY2pkYWRjYTBFaG1haWFsZmdQYXI5UmdvYWRmaHNhdmFvYWR6OmpqampiZ3pjZVZoSGNiaE9kbmRuaW5hZWFPOW5tZWFQYXg5UmFENm1kYW1hZWFPOVJhT2FtZmdvYWU2RWdBY3NmZ2xjOVdHaENhQWNldGhYYXhhRGZoaWFPYWVhb2FlYW82RTlSaFFhbGNsNGNpZmNkNGhMYXpjamRmYUFmaEtjYmhZYWJhT2FkMmZnOEFoRWFIaDNpbmNiaDVkbmF3VG1iYXhhWWNkNGZSYmJoNWtjYmg4RWF6Y2pkZmhxaW5haWg4RmRuZG5kbmRuYTVhOEVjZXQ0Y2lHZ29jOTpmUGRlYmRrYVBhOEY5UmFBNm1yYXpjamRmYThFYUEyZmE4RmFBejpqampqYjhBYThGYUFmaGl4ZGthemNqZGZhOEVhQTJmY2JhQXo6a2pqamI4QWE4RmhpeGVrYVBhOEY5UmFMNm12YThGYUxmaGlkbmFDVG1iYVBhaTlSY0s2bWJhb2NkdGM6cTpHOmNqYmZjajpHOmNqYmF3RWhhY3pocmNiaGxpbmFyZ29jOVdmZ2hhcWZocmRuZG5kbmRuZG5kbmFhYThGYWhjbzRmUmJiYWxjb0c0Y2lHY2R0ZnlkYlBEYmVkdml2dnZsdmthcjljYjgzYndhcjljYjgzYmJ4bGthcmNiYWlSYmRhaThYYmI5YzpjOnFqOmJ3OTo5YzpxO2MxOkkxZTpkOWM6YjpjOmUxejk6Z2c5Y2pqampqejpkZzhKOXFFODZiYmFxYW9mZ3JjR2ZjYmFpY2RmYThKOWM4TjE6TmZnaFJiYmFnOWNqampqanc6ZGc4SjlxRTg2YmJhcmNWZmNiYWhhOEo5YzhNMTpOZmdoUmJiYWc5Y2pqampqbDpkZzhKOXFFODZiYmFyYzdmY2JhaGE4SjljOEwxOk5mZ2hSYmJhZzljampqampkOmRnOEo5cUU4NmJiYXJjdGZjYmFoYThKOWM4SzE6TmZnaFJiYmFnOWNqampqamU6ZGc4SjlxRTg2YmJhcmM5MWZjYmFoYThKOWM4SjE6TmZnaFJiYmFnOWNqampqO2FiOmRnOEo5cUU4NmJiYXJjNGZjYmFoYThKOWNnMTpOZmdoUmJiYWc5Y2pqamphOmRnOEo5cUU4NmJiYXJjOTNmY2JhaGE4SjljaDE6TmZnaFJiYmFnOWNqampqejpkZ2c5cUU4NmJiYXJjOTRmY2JhaGFnOWNhMTpOZmdoUmJiYWk4WGJlOWM6Yzpxajpidzk6OWM6cTtjMTpJMWU6ZDljOmI6YzplMXo5OmdnOWNqampqano6ZGc4SjlxRTg2YmJhcmM5NWZjYmFoYThKOWM4TjE6TmZnaVJiYmFnOWNqampqanc6ZGc4SjlxRTg2YmJhcmM5NmZjYmFpYThKOWM4TTE6TmZnaVJiYmFnOWNqampqamw6ZGc4SjlxRTg2YmJhcmM5N2ZjYmFpYThKOWM4TDE6TmZnaVJiYmFnOWNqampqamQ6ZGc4SjlxRTg2YmJhcmM5OGZjYmFpYThKOWM4SzE6TmZnaVJiYmFnOWNqampqamU6ZGc4SjlxRTg2YmJhcmM5OWZjYmFpYThKOWM4SjE6TmZnaVJiYmFnOWNqampqO2FiOmRnOEo5cUU4NmJiYXJjOTpmY2JhaWE4SjljZzE6TmZnaVJiYmFnOWNqampqYTpkZzhKOXFFODZiYmFyY3VmY2JhaWE4SjljaDE6TmZnaVJiYmFnOWNqampqejpkZ2c5cUU4NmJiYWlhZzljYTE6TmZoaXhpa2FyYWlSYmxhaVJiYmdoY280ZzhLYThLY2lTZzhLRTg2YmJhcWFvZmdyY0dmYWljbGZhOEtmZzhLUmJiYWhjbDRjaUdnOExhOExjaVNnOExFODZiYmFyY1ZmYThLYThMZmc4S1JiYmFoY2Q0Y2lHZzhMYThMY2lTZzhMRTg2YmJhcmM3ZmE4S2E4TGZnOEtSYmJhaGNpR2doYWhjaVNnaEU4NmJiYXJjdGZhOEthaGZnOEtSYmJhaVJiZWdoY280ZzhMYThMY2lTZzhMRTg2YmJhcmM5MWZhOEthOExmZzhLUmJiYWhjbDRjaUdnOExhOExjaVNnOExFODZiYmFyYzRmYThLYThMZmc4S1JiYmFoY2Q0Y2lHZzhMYThMY2lTZzhMRTg2YmJhcmM5M2ZhOEthOExmZzhLUmJiYWhjaUdnaGFoY2lTZ2hFODZiYmFyYzk0ZmE4S2FoZmc4S1JiYmFpUmJkZ2hjbzRnOExhOExjaVNnOExFODZiYmFyYzk1ZmE4S2E4TGZnOEtSYmJhaGNsNGNpR2c4TGE4TGNpU2c4TEU4NmJiYXJjOTZmYThLYThMZmc4S1JiYmFoY2Q0Y2lHZzhMYThMY2lTZzhMRTg2YmJhcmM5N2ZhOEthOExmZzhLUmJiYWhjaUdnaGFoY2lTZ2hFODZiYmFyYzk4ZmE4S2FoZmdoUmJiYWlSYmlnaWNvNGc4S2E4S2NpU2c4S0U4NmJiYXJjOTlmYWhhOEtmZ2hSYmJhaWNsNGNpR2c4S2E4S2NpU2c4S0U4NmJiYXJjOTpmYWhhOEtmZ2hSYmJhaWNkNGNpR2c4S2E4S2NpU2c4S0U4NmJiYXJjdWZhaGE4S2ZnclJiYmFpY2lHZ2lhaWNpU2dpRTg2YmJhcmFpZmhpeGRrYXJhaVJid2FpUmJiZ2hjbDRnOEthOEtjc1NnOEtFODZiYmFxYW9mZ3JjR2ZhaWN3ZmE4S2ZnOEtSYmJhaGNzR2doYWhjc1NnaEU4NmJiYXJjVmZhOEthaGZnaFJiYmFpUmJlZzhLY2w0ZzhMYThMY3NTZzhMRTg2YmJhcmM3ZmFoYThMZmdoUmJiYThLY3NHZzhLYThLY3NTZzhLRTg2YmJhcmN0ZmFoYThLZmdoUmJiYWlSYmRnOEtjbDRnOExhOExjc1NnOExFODZiYmFyYzkxZmFoYThMZmdoUmJiYThLY3NHZzhLYThLY3NTZzhLRTg2YmJhcmM0ZmFoYThLZmdoUmJiYWlSYmlnOEtjbDRnOExhOExjc1NnOExFODZiYmFyYzkzZmFoYThMZmdoUmJiYThLY3NHZzhLYThLY3NTZzhLRTg2YmJhcmM5NGZhaGE4S2ZnaFJiYmFpUmJsZzhLY2w0ZzhMYThMY3NTZzhMRTg2YmJhcmM5NWZhaGE4TGZnaFJiYmE4S2NzR2c4S2E4S2NzU2c4S0U4NmJiYXJjOTZmYWhhOEtmZ2hSYmJhaVJidmc4S2NsNGc4TGE4TGNzU2c4TEU4NmJiYXJjOTdmYWhhOExmZ2hSYmJhOEtjc0dnOEthOEtjc1NnOEtFODZiYmFyYzk4ZmFoYThLZmdoUmJiYWlSYm9nOEtjbDRnOExhOExjc1NnOExFODZiYmFyYzk5ZmFoYThMZmdoUmJiYThLY3NHZzhLYThLY3NTZzhLRTg2YmJhcmM5OmZhaGE4S2ZnaFJiYmFpUmJyZ2ljbDRnOEthOEtjc1NnOEtFODZiYmFyY3VmYWhhOEtmZ3JSYmJhaWNzR2dpYWljc1NnaUU4NmJiYXJhaWZoaXhla2FyYWk4UGJ3ODNid2FyYWk4UGJiODNiYmFpY3pmaGlrZG5hb2FDOXBtYmFsY2RmaGxhb2N6ZmhyYVBhaTlSY0wwbWVra2FvYUM2bW9haW1leG9rYUNtdmE4RlRtdmthcWFBZmhxYThFY2VmZzhFY2w5aG1ia2RuZG5kbmRuYXdUbWJhc2FZY2Q0ZlJiYmdvY2lHUGxiZWRyYmthQVRtZGF6YVlmaDhGYXpjamRmaGhjYmg4RWFFaGFpbmE4RlJiYmhyYWFob2NiaGxpbmFvYWhhbGZSYmJncWNlNGNiYXFjZUc5UjdhcmZncjg2YmJhb2FkZmhvYUFhbGNlZmdsOWhtYmthYWNlZmhhYThGY2VmaDhGYWhhQWZoaGE4RWNlZmc4RWNsOWhtYnhpa2thQVRtZWF6YVlmaGFhemNqZGZoaGNiaG9jZWg4RWFLaDhGaW5hRWFvZmhsYWE4VmJiaHJjYmhvaW5hbGE4RmFvZlJiYmN3dGFoYW9mUmJiZ3FWYzs6RmlHY2U0Y2JhcWNlRzlSN2FyZmdyODdiYmFsYWRmaGxhUWFvY2VmZ29mbWJrYThGYVhmaDhGY2Rob2FhY2RmaGFhaGFYZmhoYThFY2VHaGxjYmg4RWFsbWJ4ZGtrYUFUbWJhb2NsNGg4RWF6YVlmUmJiaHFjd2hvYTNobGluYWxSYmJhb3RhcVZocWFsY2VmaGxhb2N3ZmdvY2E5aG1ia2NiaGhhRWg4RmFLaGFpbmF6Y2pkZmFoZlJiYmhyY3dob2FhaGxpbmFsUmJiYW90YXJWaHJhbGFBZmhsYW9jd2Znb2NhOWhtYmthcmE4RTk0YXE3aHFjYmhvYThGaGxpbmFsYXFhbzQ4NmJiYWxjZWZobGFvY3dmZ29jYTlobWJrYThGYWRmaDhGYWFjZWZoYWFoY2VmZ2hhQTlobWJra2FFY2xmaEVhM2NsZmgzYVljbGZnWWFkNm1ia2F6YThBYUFjdWZhZDJmYWR6OmpqampiOEFhQWFPZmhPYWloeGFpbWJrYzk6aG94ZGtjYmM5OWFQYXg5UmFrU0Vob3hla2M5Omhva2F2Y2pxZjhLampqamJhb2s6eXNlenU4SmpqampiYzthZTlSZ3Y4S2pqampiYzk6aG9kbmFsYWVjaTlVZ3JjSGY2bWJjdWhvYWlSYmJnd2M7V2VHYztHZTlobWJhd2NzR2dEY2UwbWJhdmM7YWJmY0ZlY2plejprampqYjhBYXY5Y3U4M2lVYXY5Y3U4M2k4V2F2OWN1ODNpeWF2OWN1ODNpYWF2OWN1ODNpS2F2OWN1ODNpemF2OWN1ODNpd2F2OWN1ODNpYmFpYWxmYzlXZmhxYWljZWZnd2FyZmhsZG5hZVRtYmNtY3NhRGNlU0Voa2NiaHhjYmhtY2JocmNiaGljYmhvaW5kbmFsYXE5bm1iYzk6aG94aWtkbmRuYXdSYmJnRGM7VmUwbWJhdmM7YWJmYW9hRGN1N2dQY2w0ZmNzR2NpdGZnc3lkbGh6YXN5ZGJoSGRuZG5hRGNzR2dzYWs5cG1iYXZhaWFQZmNzR2NkdGZ5ZGJheGFzRWhEYXhhc1RnT2ZoeHhla2RuZG5hc2NzU21iY2VoT2FzYzk4N2FzYW1mZmNlZmhEeGVrYWxjZWZoRGFsOFNiYmdzY0ZlR2hQZG5kbmFzY3U5bW1iYURobHhla2FsY3ZmaGxhUGNGYkdoUGNyaHNkbmluYUQ4U2JiZ09jRmJHYXN0YVBWaFBhT2N1OWttZWFEY2VmaERhc2NyZmdzYzhKOWhtYnhka2thRGNlZmhsa2NlaE9hUGNlNGNiYVBjZUc5UjdhbWZoRGthRGhta2F2YzthYmZhb2NpdGZnc2FEQmRiYXNhekJkbGF2YWljZHRmYURCZGJhdmM7YWJmYW9jZWZjc0djaXRmZ3NhSEJkYmFzYURCZGxhb2NkZmhvYU9haWZoaWRuYWRjZDlobWJhYmFyY2V0ZmdzYUg4N2ViYXNjbGZhRDg3ZWJhc2NkZmF6ODdlYnhka2FiYXJjZHRmZ3NhSEJkYmFzY3dmYURCZGJhc2NsZmF6QmRieGVrZG5hRGNwZTBtYmF2YWlhcWFEY3NHZlJiYmdzY2w0Z1A5UmNzR2NkdGZ5ZGJheGNlZmdPYVBFaERhdmFpYXM5UmNzR2NkdGZ5ZGJhT2FQVGd6ZmdPYXNjc0dnUEVoc2FQVGhQZG5kbmFkY2Q5aG1iYWJhcmNldGZnSGF4ODdlYmFIY2xmYXM4N2ViYUhjZGZhRDg3ZWJ4ZWthYmFyY2R0ZmdIYXhCZGJhSGN3ZmFzQmRiYUhjbGZhREJkYmthdmFpY2R0ZmF4QmRiYXZjO2FiZmFvY2l0ZmdIYURCZGJhSGF4QmRsYXZhaWNlZmdpY3NHY2R0ZmFEQmRiYXZjO2FiZmFvY2VmY3NHY2l0ZmdIYXNCZGJhSGFEQmRsYXZhaWF6ZmdpY3NHY2R0ZmFzQmRiYXZjO2FiZmFvY2RmY3NHY2l0ZmdEYXhCZGJhRGFzQmRsYW9jaWZob2FpYVBmaGlhT2FQZmh4eGVrYXhjYmFsUmJiZ3NFZ0hhRGM7OmVTZ0RmaE9hc2NzR2hBZG5kbmFzY2w0Z0NtYmFPY2VmaHp4ZWthT2h6YXZhaWFDOVJjc0djZHRmeWRiaE9rZG5kbmFBbWJhemNlZmh4eGVrYXpoeGF2YWlhczlSY3NHY2R0ZnlkYmh6a2RuZG5hRFRtYmFsY2VmaER4ZWthbGNkZmhEYWw4U2JlZ1BjRmVHaHNkbmFQY3U5a21iYWxjb2ZoSGFzY0ZiR2hzY3JobGRuaW5hRDhTYmJnUGNGYkdhbHRhc1Zoc2FQY3U5a21lYURjZWZoRGFsY3JmZ2xjOEo5aG1ia2FIaER4ZWthRGNlZmhEa2FzY2U0Y2Jhc2NlRzlSN2FtZmdtaEhrZG5kbmFDY3NTbWJhRGhzeGVrYURjZWZoc2FEOFNiYmdsY0ZlR2hQZG5hbGN1OWttYmFEY3ZmaE9hUGNGYkdoUGNyaGxkbmluYXM4U2JiZ0RjRmJHYWx0YVBWaFBhRGN1OWttZWFzY2VmaHNhbGNyZmdsYzhKOWhtYmthT2hzeGVrYXNjZWZoc2thUGNlNGNiYVBjZUc5UjdhbWZnbWhPa2RuZG5hQWNzU21iYXNobHhla2FzY2VmaGxhczhTYmJnRGNGZUdoUGRuYURjdTlrbWJhc2N2Zmh6YVBjRmJHaFBjcmhEZG5pbmFsOFNiYmdzY0ZiR2FEdGFQVmhQYXNjdTlrbWVhbGNlZmhsYURjcmZnRGM4SjlobWJrYXpobHhla2FsY2VmaGxrYVBjZTRjYmFQY2VHOVI3YW1mZ21oemtkbmRuYWRjZDlobWJhYmFyY2V0ZmdEYUg4N2ViYURjbGZhejg3ZWJhRGNkZmFPODdlYnhla2FiYXJjZHRmZ0RhSEJkYmFEY3dmYXpCZGJhRGNsZmFPQmRia2F2YzthYmZhb2NpdGZnRGFPQmRiYURhSEJkbGF2YWljZHRmYUhCZGJhdmM7YWJmYW9jZWZjc0djaXRmZ0RhekJkYmFEYU9CZGxhdmFpY2VmZ2ljc0djZHRmYU9CZGJhdmM7YWJmYW9jZGZjc0djaXRmZ0RhSEJkYmFEYXpCZGxhdmFpYUNUYUNjc1NWZmdpY3NHY2R0ZmF6QmRiYWlhQVRhQWNzU1ZmaGlhb2NpZmhva2F3Y2VmaHdhb2NzR2hvYWljc0doaWFyY2lmZ3JhZTZtYmtrY2JjOTlhbGFxU0Vob2thdmM7YWVmOEtqampqYmFvazpjbGV2dThKampqamJjejlSaHZkbmFsYWVjdmY5cG1iYzk6c2tkbmFpUmJiYzs6ZUdjO3FlU21iY3Vza2F2OWNiODNpd2FpY2VmaG9haWFsZmM5OGZocmRuYWVUbWJkbmFkY2RTbWJjYmh3aW5kbmFvYXI2bWJjOTpza2FvY2VmaGxhbzhTYmJnaWNGZUdoZGRuZG5haWN1OW1tYmFsaG94ZWthb2N2ZmhvYWRjRmJHaGRjcmhpZG5pbmFsOFNiYmdEY0ZiR2FpdGFkVmhkYURjdTlrbWVhbGNlZmhsYWljcmZnaWM4SjlobWJ4ZGtrYWxjZWZob2thYmF3Y2R0ZmFkYzhFdGM4RjkxYWRjZDQ3YXZjd2ZhZGNlR2NkdFZnbHlkYmZnaUJkYmFsYWlCZGJhd2NlZmd3YWU5aG1ieGRra2NiaHdpbmRuYW9hcjZtYmM5OnNrYW9jZWZobGFvOFNiYmdpY0ZlR2hkZG5kbmFpY3U5bW1iYWxob3hla2FvY3ZmaG9hZGNGYkdoZGNyaGlkbmluYWw4U2JiZ0RjRmJHYWl0YWRWaGRhRGN1OWttZWFsY2VmaGxhaWNyZmdpYzhKOWhtYnhka2thbGNlZmhva2FiYXdjZXRmYWRjOEV0YzhGOTFhZGNkNDdhdmN3ZmFkY2VHY2R0VmdseWRiZmdpODdlYmFsYWlCZGJhd2NlZmd3YWU5aG1ia2tjYmM5OWFvYXJTRWs6THZvZXVlOTlkdWQ5OWV1ZDk5ZG5kbmFkY2w5aG1iYWVUbWVpbmRuZG5hYmNkZmdkOFNiYjpZYWI4U2JiZ2k6WWdsOmw6dGFiY2VmZ3Y4U2JiZ286WWdyOmw6dGd3SmJiOzo5Y2F3YXdOSmJiYmJhd2F3SmJiYmI5R2dERWdxOm1na2FxYWljYjlpRWFsTWd3YXdOYWthcWFvY2I5aUVhck1ncWFxTk1NOnI6dmdsTkpiYmJaSmJiYjo7YURFTWdyOmxKYmJiOXA5RFRtYmFyOk9oaXhla2NqampqOTRoaWthZGFpODZiYmRuZG5hcWFsTkpiYmJaSmJiYjo7YXFKYmJiYjlHRU1ncTpsSmJiYjlwOURUbWJhcTpPaGR4ZWtjampqajk0aGRrYXZhZDg2YmJkbmRuYXdhbE5KYmJiWkpiYmI6O2F3SmJiYmI5R0VNZ3c6bEpiYmI5cDlEVG1iYXc6T2hkeGVrY2pqamo5NGhka2FiYWQ4NmJiYWJjbGZoYmFlY3VmZ2VtYnhka2thZVRtYmluZG5kbmFiY2xmZ2Q4VWViOllhYjhVZWJnaTpZZ2w6bDp0YWJjZGZndjhVZWJnbzpZZ3I6bDp0Z3dKYjs6RlNhd2F3TkpiYmJiYXdhd0piYmJiOUdnREVncTptZ2thcWFpY2I5aUVhbE1nd2F3TmFrYXFhb2NiOWlFYXJNZ3FhcU5NTTpyOnZnbE5KYmJiWkpiYmI6O2FERU1ncjpsSmJiYjlwOURUbWJhcjpPaGl4ZWtjampqajk0aGlrYWRhaTg3ZWJkbmRuYXFhbE5KYmJiWkpiYmI6O2FxSmJiYmI5R0VNZ3E6bEpiYmI5cDlEVG1iYXE6T2hkeGVrY2pqamo5NGhka2F2YWQ4N2ViZG5kbmF3YWxOSmJiYlpKYmJiOjthd0piYmJiOUdFTWd3OmxKYmJiOXA5RFRtYmF3Ok9oZHhla2NqampqOTRoZGthYmFkODdlYmFiY3dmaGJhZWN1ZmdlbWJra2s6NGlvaXVlOTlkdWQ5OWR1ZDk5ZG5hZVRtYmNiaGlhYmhsaW5kbmRuYWw4VWViZ3Y6WWdvSjpqaToxU2FsY29mOFVlYmdyY2lWZ3c6WTp2Z0ROSmJiYlpKYmJiOjthdmN1OWtFTWdxOmxKYmJiOXA5RFRtYmFxOk9oa3hla2NqampqOTRoa2thbGNsZjhVZWJodmFsY2RmOFVlYmh4YWxhcmNlZmNpR2NldGZhazg3ZWJkbmRuYXg6WWdxYUROSmJiYlpKYmJiOjtheGN1OWtFTWdtOmxKYmJiOXA5RFRtYmFtOk9oeHhla2NqampqOTRoeGthYmFpYXJjaUdna2ZjZDdjZXRmYXg4N2ViZG5kbmF2OllnbWFETkpiYmJaSmJiYjo7YXZjdTlrRU1nUDpsSmJiYjlwOURUbWJhUDpPaHZ4ZWtjampqajk0aHZrYWxhcmN1ZmNpR2NldGZhdjg3ZWJkbmRuYXdhdzI6WmdQYVBNYW9hb046dGFxYXFOOnRhbWFtTjp0Z29KYmJiYmFvSmJiYmI5R0U6cmFETkpiYmJaTWdEOmxKYmJiOXA5RFRtYmFEOk9ocnhla2NqampqOTRocmthbGFrY2V0ZmFyODdlYmFsY3dmaGxhaWNsZmhpYWVjdWZnZW1ia2trOW1iZG5hZGNkNGFlMmdkVG1iaW5hYmFieWRiZ2Vjd3RjdzkxOllhZWNlOTFjampqOThHY2pqajs4aWY6Ok5VZGJhYmNsZmhiYWRjdWZnZG1ia2trOlR2aXJ1ZDk5ZXVkbmRuYWRjbDlobWJhZVRtZWluZG5kbmFiUmJiZ2lhYmNlZmdsOFNiYmd2YWJjZGZnbzhTYmJncmY5UjpZSmJidUphYmNpZmd3UmJiZ2RjZTRhZFZnRGNkNGFEVmdEY2w0YURWZ0Q6Wjp2Z3FOSmJiYlpNZ2s6bEpiYmI5cDlEVG1iYWs6T2h4eGVrY2pqamo5NGh4a2FvYXg4NmJiZG5kbmFyYWlmOllhcU5KYmJiWk1nazpsSmJiYjlwOURUbWJhazpPaG94ZWtjampqajk0aG9rYWxhbzg2YmJkbmRuYXZhaWZhcjlSOllhcU5KYmJiWk1nazpsSmJiYjlwOURUbWJhazpPaGl4ZWtjampqajk0aGlrYWJhaTg2YmJkbmRuYURhZGNldEdhZGNlR1Y6WmFxTkpiYmJaTWdxOmxKYmJiOXA5RFRtYmFxOk9oZHhla2NqampqOTRoZGthd2FkODZiYmFiY2xmaGJhZWN1ZmdlbWJ4ZGtrYWVUbWJpbmRuZG5hYjhWZWJnaWFiY2RmZ2w4VWViZ3ZhYmNsZmdvOFVlYmdyZjlSOllKYkZ1OWhhYmNvZmd3OFZlYmdkY2U0YWRWZ0RjZDRhRFZnRGNsNGFEVmdEY3c0YURWZ0Q6Wjp2Z3FOSmJiYlpNZ2s6bEpiYmI5cDlEVG1iYWs6T2h4eGVrY2pqamo5NGh4a2FvYXg4N2ViZG5kbmFyYWlmOllhcU5KYmJiWk1nazpsSmJiYjlwOURUbWJhazpPaG94ZWtjampqajk0aG9rYWxhbzg3ZWJkbmRuYXZhaWZhcjlSOllhcU5KYmJiWk1nazpsSmJiYjlwOURUbWJhazpPaGl4ZWtjampqajk0aGlrYWJhaTg3ZWJkbmRuYURhZGNldEdhZGNlR1Y6WmFxTkpiYmJaTWdxOmxKYmJiOXA5RFRtYmFxOk9oZHhla2NqampqOTRoZGthd2FkODdlYmFiY3dmaGJhZWN1ZmdlbWJra2s5dGVpdWNiY2J5ZDpLOkc6Y2piZ2VhYmNpZmM5OEdmZ2JCZDpLOkc6Y2piZG5kbmFiWmJjenRnZDlubWJjdWhpYWJhZDlSY0ZGaWZjejRuYmN1U21la2FlaGlrYWlrO0xlZWV1ZG5kbmFlYWJWY2lHVG1iYWJoaXhla2RuZG5hZGN6OXBtYmFiaGl4ZWthYmhpaW5haWFleWRiQmRiYWljbGZhZWNsZnlkYkJkYmFpY3dmYWVjd2Z5ZGJCZGJhaWN4ZmFlY3hmeWRiQmRiYWVjemZoZWFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFleWRiQmRiYWVjbGZoZWFpY2xmaGlhZGM5OGZnZGNpMG1ia2tkbmFkVG1iaW5haWFlUmJiODZiYmFpY2VmaGlhZWNlZmhlYWRjdWZnZG1ia2thYms7YWVlZHVkbmRuYWJjaUdUbWJhYmhpeGVrYWVjRmVHYzpiOmM6ZXcyaGxkbmRuYWRjejlwbWJhYmhpeGVrYWJoaWluYWlhbEJkYmFpY3hmYWxCZGJhaWN3ZmFsQmRiYWljbGZhbEJkYmFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFsQmRiYWljbGZoaWFkYzk4ZmdkY2kwbWJra2RuYWRUbWJpbmFpYWU4NmJiYWljZWZoaWFkY3VmZ2RtYmtrYWJrazgzZGJjajpHZGs4S2JiYmJkYmJibGJiYndiYmJiYmJiZWJiYmRiYmJsYmJid2JiYmJjOks6R2RrbDhXOnFiYiI7CiAgICAgICAgdmFyIHdhc21fc2ltZCA9ICJiOUg3OVRlYmJiZUtsOUdiYjlHdnV1dXV1ZXU5R2l1dXViOUdldWV1aXhrYmJlYmVlZGRkZGlsdmU5V2VlZXZpZWJlb3dldWVjajpHZGtyO05lcW85VFc5VDlWVjk1ZGJIOUY5RjkzOUg3OVQ5RjlKOUgyMjlGOUp0OVZWN2JiOEE5VFc3OU85VjlXdDlGOUtXOUo5VjlLVzl3V1Z0Vzk0OWM5MTlNOU1XVmJkWTlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXNjlVOUtXOTQ5YzkxOU05TVdWYmxFOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1c2OVU5S1c5NDl0V0c5MVc5VTlKV2J2TDlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXUzlQMnRXVjlwOUp0Ym9LOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1dTOVAydFdWOXI5MTlIdGJyTDlUVzc5TzlWOVd0OUY5S1c5SjlWOUtXUzlQMnRXVlQ5NDlXYndZOVRXNzlPOVY5V3Q5RjlLVzlKOVY5S1dTOVAydFdWSjlWMjlWVmJEbDc5SVY5UmJxcTo1OURrbGJ6aWs5NGV2dThKampqamJjejlSaGJjYmhlaW5jYmhkY2JoaWluYWJjd2ZhZGZhaWNqdWFlYWQ0Y2VHZ2xFODZiYmFpYWxmaGlhZGNlZmdkY3c5aG1ia2FlYWk4NmI6cTpXOmNqYmFlY2l0YWI4UGl3ODNpOnE6RzpjamJhZWNlZmdlY2pkOWhtYmtrOlNCbEV1ZDk3ZHVyOTc4SmpqampiY2o7a2I5Umd2OEtqampqYmM5OmhvZG5hbFRtYmN1aG9haVJiYmdyYztXZUdjOkdlOWhtYmFyY3NHZ3djZTBtYmM5OmhvYWxjdWZhZGNkNGNiYXdFZ0RhZGZncmNLY2Fhd0VncWFyYXEwRWdrNm1iYWlhbGZneGFyOVJob2RuYWRUZ21tYmF2YW9hZDs4cWJia2FpY2VmaFBjajthYmFkOVVjO1dGYkdjamRhZGNhMEVoc2RuZG5kbmFkVG1iYW9hZGZoemNiaEhpbmFlYUg5bm1kYXhhUDlSYUQ2bWlhYmFIYWQyZmdPYXZjamRmYXNhZWFIOVJhSGFzZmFlNkVnQWFBY3NmZ29jOVdHZ0NTRWhYYVBhRGZoUWFvY2w0Y2lmY2Q0aExhdmNqO2NiZmFDY2V0ZmhLYXZjajtjYmZhQ2NpMmZoWWF2Y2o7Y2JmYUNmaDhBY2JoRWFvYzthYjZoM2luY2JoNWRuYXdUbWJhUGFFY2Q0ZlJiYmg1a2NiaDhFYXZjajtjYmZoOEZpbmRuZG5kbmRuYTVhOEVjZXQ0Y2lHZ29jOTpmUGRlYmRrYXhhUTlSYUM2bXdkbmFDVG1iYXZjajtjYmZhOEVhQzJmYVFhQzs4cWJia2FRYUFmaFF4ZGthQ1RtZWF2Y2o7Y2JmYThFYUMyZmNiYUM7OGtieGVrYXhhUTlSYUw2bW9hb2NsVmNiYXdFaHJhUWFMZmhvY2JoaWRuYTNtYmF4YW85UmM7R2I2bWJjYmhsaW5hOEZhbGZoaWRuZG5kbmRuZG5kbmFRYWxjbzRmUmJiZ3FjaUdhcmZQRGJlZGlibGVkaWJrYWlweGJiYmJiYmJiYmJiYmJiYmJwa2xieGxrYWlhb3BiYmxhb3BiYmJnYWNscDptZWFhcG1iemVIZE9pQWxDdlhvUXJMZ2FjZHA6bWVhYXBtYnplSGRPaUFsQ3ZYb1FyTHB4aWlpaWlpaWlpaWlpaWlpaXA5b2docHhpaWlpaWlpaWlpaWlpaWlpcDhKZ2FwNWI5Y2pGOzg7NDtXO0c7YWI5OjljVTE6TmdnY2l0cGJpOnE6RzpjamJhZ1JiOnE6VzpjamJnZ3BzYWFwNWU5Y2pGOzg7NDtXO0c7YWI5OjljVTE6Tmc4SmNpdHBiaTpxOkc6Y2picDlVcG1iZWRpbHZvcnpIT0FDWFFMcFBhaGFhcDlzcGtsYmFnYW9jbGZmYThKUmI6cTpXOmNqYmZob3hpa2FpYW9wYmJ3YW9wYmJiZ2FjbHA6bWVhYXBtYnplSGRPaUFsQ3ZYb1FyTHB4c3Nzc3Nzc3Nzc3Nzc3Nzc3A5b2docHhzc3Nzc3Nzc3Nzc3Nzc3NzcDhKZ2FwNWI5Y2pGOzg7NDtXO0c7YWI5OjljVTE6TmdnY2l0cGJpOnE6RzpjamJhZ1JiOnE6VzpjamJnZ3BzYWFwNWU5Y2pGOzg7NDtXO0c7YWI5OjljVTE6Tmc4SmNpdHBiaTpxOkc6Y2picDlVcG1iZWRpbHZvcnpIT0FDWFFMcFBhaGFhcDlzcGtsYmFnYW9jd2ZmYThKUmI6cTpXOmNqYmZob3hka2FpYW9wYmJicGtsYmFvY3pmaG94ZWthaWFvcGJiZGFvUmJiZ2djaXRwYmk6cTpHOmNqYmFnUmI6cTpXOmNqYmdncHNhb1JiZWc4SmNpdHBiaTpxOkc6Y2picDlVcG1iZWRpbHZvcnpIT0FDWFFMcFBwa2xiYWdhb2NkZmZhOEpSYjpxOlc6Y2piZmhva2RuZG5kbmRuZG5kbmFxY2Q0Y2lHYXJmUERiZWRpYmxlZGlia2FpY3pmcHhiYmJiYmJiYmJiYmJiYmJicGtsYnhsa2FpY3pmYW9wYmJsYW9wYmJiZ2FjbHA6bWVhYXBtYnplSGRPaUFsQ3ZYb1FyTGdhY2RwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxweGlpaWlpaWlpaWlpaWlpaWlwOW9naHB4aWlpaWlpaWlpaWlpaWlpaXA4SmdhcDViOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5nZ2NpdHBiaTpxOkc6Y2piYWdSYjpxOlc6Y2piZ2dwc2FhcDVlOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5nOEpjaXRwYmk6cTpHOmNqYnA5VXBtYmVkaWx2b3J6SE9BQ1hRTHBQYWhhYXA5c3BrbGJhZ2FvY2xmZmE4SlJiOnE6VzpjamJmaG94aWthaWN6ZmFvcGJid2FvcGJiYmdhY2xwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxweHNzc3Nzc3Nzc3Nzc3Nzc3NwOW9naHB4c3Nzc3Nzc3Nzc3Nzc3Nzc3A4SmdhcDViOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5nZ2NpdHBiaTpxOkc6Y2piYWdSYjpxOlc6Y2piZ2dwc2FhcDVlOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5nOEpjaXRwYmk6cTpHOmNqYnA5VXBtYmVkaWx2b3J6SE9BQ1hRTHBQYWhhYXA5c3BrbGJhZ2FvY3dmZmE4SlJiOnE6VzpjamJmaG94ZGthaWN6ZmFvcGJiYnBrbGJhb2N6ZmhveGVrYWljemZhb3BiYmRhb1JiYmdnY2l0cGJpOnE6RzpjamJhZ1JiOnE6VzpjamJnZ3BzYW9SYmVnOEpjaXRwYmk6cTpHOmNqYnA5VXBtYmVkaWx2b3J6SE9BQ1hRTHBQcGtsYmFnYW9jZGZmYThKUmI6cTpXOmNqYmZob2tkbmRuZG5kbmRuZG5hcWNsNGNpR2FyZlBEYmVkaWJsZWRpYmthaWNhZnB4YmJiYmJiYmJiYmJiYmJiYnBrbGJ4bGthaWNhZmFvcGJibGFvcGJiYmdhY2xwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxnYWNkcDptZWFhcG1iemVIZE9pQWxDdlhvUXJMcHhpaWlpaWlpaWlpaWlpaWlpcDlvZ2hweGlpaWlpaWlpaWlpaWlpaWlwOEpnYXA1YjljakY7ODs0O1c7RzthYjk6OWNVMTpOZ2djaXRwYmk6cTpHOmNqYmFnUmI6cTpXOmNqYmdncHNhYXA1ZTljakY7ODs0O1c7RzthYjk6OWNVMTpOZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUGFoYWFwOXNwa2xiYWdhb2NsZmZhOEpSYjpxOlc6Y2piZmhveGlrYWljYWZhb3BiYndhb3BiYmJnYWNscDptZWFhcG1iemVIZE9pQWxDdlhvUXJMcHhzc3Nzc3Nzc3Nzc3Nzc3NzcDlvZ2hweHNzc3Nzc3Nzc3Nzc3Nzc3NwOEpnYXA1YjljakY7ODs0O1c7RzthYjk6OWNVMTpOZ2djaXRwYmk6cTpHOmNqYmFnUmI6cTpXOmNqYmdncHNhYXA1ZTljakY7ODs0O1c7RzthYjk6OWNVMTpOZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUGFoYWFwOXNwa2xiYWdhb2N3ZmZhOEpSYjpxOlc6Y2piZmhveGRrYWljYWZhb3BiYmJwa2xiYW9jemZob3hla2FpY2FmYW9wYmJkYW9SYmJnZ2NpdHBiaTpxOkc6Y2piYWdSYjpxOlc6Y2piZ2dwc2FvUmJlZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUHBrbGJhZ2FvY2RmZmE4SlJiOnE6VzpjamJmaG9rZG5kbmRuZG5kbmRuYXFjbzRhcmZQRGJlZGlibGVkaWJrYWljOFdmcHhiYmJiYmJiYmJiYmJiYmJicGtsYnhsa2FpYzhXZmFvcGJibGFvcGJiYmdhY2xwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxnYWNkcDptZWFhcG1iemVIZE9pQWxDdlhvUXJMcHhpaWlpaWlpaWlpaWlpaWlpcDlvZ2hweGlpaWlpaWlpaWlpaWlpaWlwOEpnYXA1YjljakY7ODs0O1c7RzthYjk6OWNVMTpOZ2ljaXRwYmk6cTpHOmNqYmFpUmI6cTpXOmNqYmdpcHNhYXA1ZTljakY7ODs0O1c7RzthYjk6OWNVMTpOZ3FjaXRwYmk6cTpHOmNqYnA5VXBtYmVkaWx2b3J6SE9BQ1hRTHBQYWhhYXA5c3BrbGJhaWFvY2xmZmFxUmI6cTpXOmNqYmZob3hpa2FpYzhXZmFvcGJid2FvcGJiYmdhY2xwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxweHNzc3Nzc3Nzc3Nzc3Nzc3NwOW9naHB4c3Nzc3Nzc3Nzc3Nzc3Nzc3A4SmdhcDViOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5naWNpdHBiaTpxOkc6Y2piYWlSYjpxOlc6Y2piZ2lwc2FhcDVlOWNqRjs4OzQ7VztHO2FiOTo5Y1UxOk5ncWNpdHBiaTpxOkc6Y2picDlVcG1iZWRpbHZvcnpIT0FDWFFMcFBhaGFhcDlzcGtsYmFpYW9jd2ZmYXFSYjpxOlc6Y2piZmhveGRrYWljOFdmYW9wYmJicGtsYmFvY3pmaG94ZWthaWM4V2Zhb3BiYmRhb1JiYmdpY2l0cGJpOnE6RzpjamJhaVJiOnE6VzpjamJnaXBzYW9SYmVncWNpdHBiaTpxOkc6Y2picDlVcG1iZWRpbHZvcnpIT0FDWFFMcFBwa2xiYWlhb2NkZmZhcVJiOnE6VzpjamJmaG9rYWxjO2FiZmhpYWxjamVmYUMwbWVhaWhsYXhhbzlSYztGYjBtYmtrZG5haWFDOXBtYmFpY2k0aGxpbmF4YW85UmNLNm13YThGYWlmaHFkbmRuZG5kbmRuZG5hUWFpY280ZlJiYmFsY29HNGNpR2FyZlBEYmVkaWJsZWRpYmthcXB4YmJiYmJiYmJiYmJiYmJiYnBrYmJ4bGthcWFvcGJibGFvcGJiYmdhY2xwOm1lYWFwbWJ6ZUhkT2lBbEN2WG9RckxnYWNkcDptZWFhcG1iemVIZE9pQWxDdlhvUXJMcHhpaWlpaWlpaWlpaWlpaWlpcDlvZ2hweGlpaWlpaWlpaWlpaWlpaWlwOEpnYXA1YjljakY7ODs0O1c7RzthYjk6OWNVMTpOZ2djaXRwYmk6cTpHOmNqYmFnUmI6cTpXOmNqYmdncHNhYXA1ZTljakY7ODs0O1c7RzthYjk6OWNVMTpOZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUGFoYWFwOXNwa2JiYWdhb2NsZmZhOEpSYjpxOlc6Y2piZmhveGlrYXFhb3BiYndhb3BiYmJnYWNscDptZWFhcG1iemVIZE9pQWxDdlhvUXJMcHhzc3Nzc3Nzc3Nzc3Nzc3NzcDlvZ2hweHNzc3Nzc3Nzc3Nzc3Nzc3NwOEpnYXA1YjljakY7ODs0O1c7RzthYjk6OWNVMTpOZ2djaXRwYmk6cTpHOmNqYmFnUmI6cTpXOmNqYmdncHNhYXA1ZTljakY7ODs0O1c7RzthYjk6OWNVMTpOZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUGFoYWFwOXNwa2JiYWdhb2N3ZmZhOEpSYjpxOlc6Y2piZmhveGRrYXFhb3BiYmJwa2JiYW9jemZob3hla2FxYW9wYmJkYW9SYmJnZ2NpdHBiaTpxOkc6Y2piYWdSYjpxOlc6Y2piZ2dwc2FvUmJlZzhKY2l0cGJpOnE6RzpjamJwOVVwbWJlZGlsdm9yekhPQUNYUUxwUHBrYmJhZ2FvY2RmZmE4SlJiOnE6VzpjamJmaG9rYWxjZGZobGFpY3pmZ2lhQzZtYmtrYW9oUWFvVG1va2E4RmFDZmg4RmE4RWNlZmc4RWNsOWhtYmtkbmRuZG5kbmF3VG1iYXphRWNkNGZSYmJnbGNpR1BsYmVkd2JrYUNUbWRhWGFFZmhsYXZhRWZwYmRiaDhLY2Job2luYWxhdmNqO2NiZmFvZnBibGJnOExhOEFhb2ZwYmxiZzhNcG1iemVIZE9pQWxDdlhvUXJMZzhOYUthb2ZwYmxiZ3lhWWFvZnBibGJnOFBwbWJ6ZUhkT2lBbEN2WG9RckxnSXBtYmV6SGRpT0FsdkNYb3JRTGdhY2VwOVRhYXB4ZWVlZWVlZWVlZWVlZWVlZWdocDlvcDlIcDlyZ2FhOEtwOVVnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBtbHZvcmx2b3Jsdm9ybHZvcnA5VWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDlVZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbXhtUHN4bVBzeG1Qc3htUHNwOVVnOEtwOUFiYmJhbGFkZmdsYThLYThOYUlwbXdES1lxazhBRXhtMzVQczhFOEZnYWNlcDlUYWFhaHA5b3A5SHA5cmdhcDlVZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbWx2b3Jsdm9ybHZvcmx2b3JwOVVnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBtd0Rxa3dEcWt3RHFrd0Rxa3A5VWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG14bVBzeG1Qc3htUHN4bVBzcDlVZzhLcDlBYmJiYWxhZGZnbGE4S2E4TGE4TXBtd0tEWXE4QWtFeDNtNVA4RXM4Rmc4TGF5YThQcG13S0RZcThBa0V4M201UDhFczhGZzhNcG1iZXpIZGlPQWx2Q1hvclFMZ2FjZXA5VGFhYWhwOW9wOUhwOXJnYXA5VWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG1sdm9ybHZvcmx2b3Jsdm9ycDlVZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbXdEcWt3RHFrd0Rxa3dEcWtwOVVnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBteG1Qc3htUHN4bVBzeG1Qc3A5VWc4S3A5QWJiYmFsYWRmZ2xhOEthOExhOE1wbXdES1lxazhBRXhtMzVQczhFOEZnYWNlcDlUYWFhaHA5b3A5SHA5cmdhcDlVZ2hwOUFiYmJhbGFkZmdsYWhhYWFhcG1sdm9ybHZvcmx2b3Jsdm9ycDlVZ2hwOUFiYmJhbGFkZmdsYWhhYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDlVZ2hwOUFiYmJhbGFkZmdsYWhhYWFhcG14bVBzeG1Qc3htUHN4bVBzcDlVZzhLcDlBYmJiYWxhZGZobGFvY3pmZ29hQzZtYnhpa2thQ1RtZWFYYUVmaGxhdmFFZnBiZGJoOEtjYmhvaW5hbGF2Y2o7Y2JmYW9mcGJsYmc4TGE4QWFvZnBibGJnOE1wbWJ6ZUhkT2lBbEN2WG9RckxnOE5hS2FvZnBibGJneWFZYW9mcGJsYmc4UHBtYnplSGRPaUFsQ3ZYb1FyTGdJcG1iZXpIZGlPQWx2Q1hvclFMZ2FjZXA6bmVhYXB4ZWJlYmViZWJlYmViZWJlYmdocDlvcDpiZXA5cmdhYThLcDpvZWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG1sdm9ybHZvcmx2b3Jsdm9ycDpvZWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDpvZWc4S3A5QWJiYmFsYWRmZ2xhOEthYWFhcG14bVBzeG1Qc3htUHN4bVBzcDpvZWc4S3A5QWJiYmFsYWRmZ2xhOEthOE5hSXBtd0RLWXFrOEFFeG0zNVBzOEU4RmdhY2VwOm5lYWFhaHA5b3A6YmVwOXJnYXA6b2VnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBtbHZvcmx2b3Jsdm9ybHZvcnA6b2VnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBtd0Rxa3dEcWt3RHFrd0Rxa3A6b2VnOEtwOUFiYmJhbGFkZmdsYThLYWFhYXBteG1Qc3htUHN4bVBzeG1Qc3A6b2VnOEtwOUFiYmJhbGFkZmdsYThLYThMYThNcG13S0RZcThBa0V4M201UDhFczhGZzhMYXlhOFBwbXdLRFlxOEFrRXgzbTVQOEVzOEZnOE1wbWJlekhkaU9BbHZDWG9yUUxnYWNlcDpuZWFhYWhwOW9wOmJlcDlyZ2FwOm9lZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbWx2b3Jsdm9ybHZvcmx2b3JwOm9lZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbXdEcWt3RHFrd0Rxa3dEcWtwOm9lZzhLcDlBYmJiYWxhZGZnbGE4S2FhYWFwbXhtUHN4bVBzeG1Qc3htUHNwOm9lZzhLcDlBYmJiYWxhZGZnbGE4S2E4TGE4TXBtd0RLWXFrOEFFeG0zNVBzOEU4RmdhY2VwOm5lYWFhaHA5b3A6YmVwOXJnYXA6b2VnaHA5QWJiYmFsYWRmZ2xhaGFhYWFwbWx2b3Jsdm9ybHZvcmx2b3JwOm9lZ2hwOUFiYmJhbGFkZmdsYWhhYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDpvZWdocDlBYmJiYWxhZGZnbGFoYWFhYXBteG1Qc3htUHN4bVBzeG1Qc3A6b2VnOEtwOUFiYmJhbGFkZmhsYW9jemZnb2FDNm1ieGRra2FDVG1iYVhhRWZocmNiaG9jYmFsY2w0Z2w5UmM4RkdoaWF2YUVmcGJkYmhoaW5hcmF2Y2o7Y2JmYW9mcGJsYmc4S2E4QWFvZnBibGJnOExwbWJ6ZUhkT2lBbEN2WG9RckxnOE1hS2FvZnBibGJnOE5hWWFvZnBibGJneXBtYnplSGRPaUFsQ3ZYb1FyTGc4UHBtYmV6SGRpT0FsdkNYb3JRTGdhYWlwOlJlYWFhbHA6VGVwOXFnYWFocDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG1sdm9ybHZvcmx2b3Jsdm9ycDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG14bVBzeG1Qc3htUHN4bVBzcDlyZ2hwOUFiYmJhcmFkZmdyYWhhOE1hOFBwbXdES1lxazhBRXhtMzVQczhFOEZnYWFpcDpSZWFhYWxwOlRlcDlxZ2FwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbWx2b3Jsdm9ybHZvcmx2b3JwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbXdEcWt3RHFrd0Rxa3dEcWtwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbXhtUHN4bVBzeG1Qc3htUHNwOXJnaHA5QWJiYmFyYWRmZ3JhaGE4S2E4THBtd0tEWXE4QWtFeDNtNVA4RXM4Rmc4S2E4TmF5cG13S0RZcThBa0V4M201UDhFczhGZzhMcG1iZXpIZGlPQWx2Q1hvclFMZ2FhaXA6UmVhYWFscDpUZXA5cWdhcDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG1sdm9ybHZvcmx2b3Jsdm9ycDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG13RHFrd0Rxa3dEcWt3RHFrcDlyZ2hwOUFiYmJhcmFkZmdyYWhhYWFhcG14bVBzeG1Qc3htUHN4bVBzcDlyZ2hwOUFiYmJhcmFkZmdyYWhhOEthOExwbXdES1lxazhBRXhtMzVQczhFOEZnYWFpcDpSZWFhYWxwOlRlcDlxZ2FwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbWx2b3Jsdm9ybHZvcmx2b3JwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbXdEcWt3RHFrd0Rxa3dEcWtwOXJnaHA5QWJiYmFyYWRmZ3JhaGFhYWFwbXhtUHN4bVBzeG1Qc3htUHNwOXJnaHA5QWJiYmFyYWRmaHJhb2N6ZmdvYUM2bWJra2FFY2xmZ0VhZDZtYmtkbmFYYXZjamRmOWhtYmFBYWQyZ29UbWJhT2F2Y2pkZmFvOzhxYmJrZG5hbW1iYXZhWGFBY3VmYWQyZmFkOzhxYmJrYUFhSGZoSGM5OmhvYVFoUGFRbWJ4bGtrYWVUbWJhRGFsZmhyY2Job2N1aGxpbmFyYWxhRDlSZ2xmYUQ2bWRhc2FlYW85UmFvYXNmYWU2RWFvZmdvYWU2bWJrYWlhbDlSaFBrY2JjOTlheGFQOVJha1NFaG94ZWtjOTpob2thdmNqO2tiZjhLampqamJhb2t3Yno6YmpqamJrTnNlenU4SmpqampiYzthZTlSZ3Y4S2pqampiYzk6aG9kbmFsYWVjaTlVZ3JjSGY2bWJjdWhvYWlSYmJnd2M7V2VHYztHZTlobWJhd2NzR2dEY2UwbWJhdmM7YWJmY0ZlY2plOzhrYmF2OWN1ODNpVWF2OWN1ODNpOFdhdjljdTgzaXlhdjljdTgzaWFhdjljdTgzaUthdjljdTgzaXphdjljdTgzaXdhdjljdTgzaWJhaWFsZmM5V2ZocWFpY2VmZ3dhcmZobGRuYWVUbWJjbWNzYURjZVNFaGtjYmh4Y2JobWNiaHJjYmhpY2Job2luZG5hbGFxOW5tYmM5OmhveGlrZG5kbmF3UmJiZ0RjO1ZlMG1iYXZjO2FiZmFvYURjdTdnUGNsNGZjc0djaXRmZ3N5ZGxoemFzeWRiaEhkbmRuYURjc0dnc2FrOXBtYmF2YWlhUGZjc0djZHRmeWRiYXhhc0VoRGF4YXNUZ09maHh4ZWtkbmRuYXNjc1NtYmNlaE9hc2M5ODdhc2FtZmZjZWZoRHhla2FsY2VmaERhbDhTYmJnc2NGZUdoUGRuZG5hc2N1OW1tYmFEaGx4ZWthbGN2ZmhsYVBjRmJHaFBjcmhzZG5pbmFEOFNiYmdPY0ZiR2FzdGFQVmhQYU9jdTlrbWVhRGNlZmhEYXNjcmZnc2M4SjlobWJ4ZGtrYURjZWZobGtjZWhPYVBjZTRjYmFQY2VHOVI3YW1maERrYURobWthdmM7YWJmYW9jaXRmZ3NhREJkYmFzYXpCZGxhdmFpY2R0ZmFEQmRiYXZjO2FiZmFvY2VmY3NHY2l0ZmdzYUhCZGJhc2FEQmRsYW9jZGZob2FPYWlmaGlkbmFkY2Q5aG1iYWJhcmNldGZnc2FIODdlYmFzY2xmYUQ4N2ViYXNjZGZhejg3ZWJ4ZGthYmFyY2R0ZmdzYUhCZGJhc2N3ZmFEQmRiYXNjbGZhekJkYnhla2RuYURjcGUwbWJhdmFpYXFhRGNzR2ZSYmJnc2NsNGdQOVJjc0djZHRmeWRiYXhjZWZnT2FQRWhEYXZhaWFzOVJjc0djZHRmeWRiYU9hUFRnemZnT2FzY3NHZ1BFaHNhUFRoUGRuZG5hZGNkOWhtYmFiYXJjZXRmZ0hheDg3ZWJhSGNsZmFzODdlYmFIY2RmYUQ4N2VieGVrYWJhcmNkdGZnSGF4QmRiYUhjd2Zhc0JkYmFIY2xmYURCZGJrYXZhaWNkdGZheEJkYmF2YzthYmZhb2NpdGZnSGFEQmRiYUhheEJkbGF2YWljZWZnaWNzR2NkdGZhREJkYmF2YzthYmZhb2NlZmNzR2NpdGZnSGFzQmRiYUhhREJkbGF2YWlhemZnaWNzR2NkdGZhc0JkYmF2YzthYmZhb2NkZmNzR2NpdGZnRGF4QmRiYURhc0JkbGFvY2lmaG9haWFQZmhpYU9hUGZoeHhla2F4Y2JhbFJiYmdzRWdIYURjOzplU2dEZmhPYXNjc0doQWRuZG5hc2NsNGdDbWJhT2NlZmh6eGVrYU9oemF2YWlhQzlSY3NHY2R0ZnlkYmhPa2RuZG5hQW1iYXpjZWZoeHhla2F6aHhhdmFpYXM5UmNzR2NkdGZ5ZGJoemtkbmRuYURUbWJhbGNlZmhEeGVrYWxjZGZoRGFsOFNiZWdQY0ZlR2hzZG5hUGN1OWttYmFsY29maEhhc2NGYkdoc2NyaGxkbmluYUQ4U2JiZ1BjRmJHYWx0YXNWaHNhUGN1OWttZWFEY2VmaERhbGNyZmdsYzhKOWhtYmthSGhEeGVrYURjZWZoRGthc2NlNGNiYXNjZUc5UjdhbWZnbWhIa2RuZG5hQ2NzU21iYURoc3hla2FEY2VmaHNhRDhTYmJnbGNGZUdoUGRuYWxjdTlrbWJhRGN2ZmhPYVBjRmJHaFBjcmhsZG5pbmFzOFNiYmdEY0ZiR2FsdGFQVmhQYURjdTlrbWVhc2NlZmhzYWxjcmZnbGM4SjlobWJrYU9oc3hla2FzY2VmaHNrYVBjZTRjYmFQY2VHOVI3YW1mZ21oT2tkbmRuYUFjc1NtYmFzaGx4ZWthc2NlZmhsYXM4U2JiZ0RjRmVHaFBkbmFEY3U5a21iYXNjdmZoemFQY0ZiR2hQY3JoRGRuaW5hbDhTYmJnc2NGYkdhRHRhUFZoUGFzY3U5a21lYWxjZWZobGFEY3JmZ0RjOEo5aG1ia2F6aGx4ZWthbGNlZmhsa2FQY2U0Y2JhUGNlRzlSN2FtZmdtaHprZG5kbmFkY2Q5aG1iYWJhcmNldGZnRGFIODdlYmFEY2xmYXo4N2ViYURjZGZhTzg3ZWJ4ZWthYmFyY2R0ZmdEYUhCZGJhRGN3ZmF6QmRiYURjbGZhT0JkYmthdmM7YWJmYW9jaXRmZ0RhT0JkYmFEYUhCZGxhdmFpY2R0ZmFIQmRiYXZjO2FiZmFvY2VmY3NHY2l0ZmdEYXpCZGJhRGFPQmRsYXZhaWNlZmdpY3NHY2R0ZmFPQmRiYXZjO2FiZmFvY2RmY3NHY2l0ZmdEYUhCZGJhRGF6QmRsYXZhaWFDVGFDY3NTVmZnaWNzR2NkdGZhekJkYmFpYUFUYUFjc1NWZmhpYW9jaWZob2thd2NlZmh3YW9jc0dob2FpY3NHaGlhcmNpZmdyYWU2bWJra2NiYzk5YWxhcVNFaG9rYXZjO2FlZjhLampqamJhb2s6Y2xldnU4SmpqampiY3o5Umh2ZG5hbGFlY3ZmOXBtYmM5OnNrZG5haVJiYmM7OmVHYztxZVNtYmN1c2thdjljYjgzaXdhaWNlZmhvYWlhbGZjOThmaHJkbmFlVG1iZG5hZGNkU21iY2Jod2luZG5hb2FyNm1iYzk6c2thb2NlZmhsYW84U2JiZ2ljRmVHaGRkbmRuYWljdTltbWJhbGhveGVrYW9jdmZob2FkY0ZiR2hkY3JoaWRuaW5hbDhTYmJnRGNGYkdhaXRhZFZoZGFEY3U5a21lYWxjZWZobGFpY3JmZ2ljOEo5aG1ieGRra2FsY2VmaG9rYWJhd2NkdGZhZGM4RXRjOEY5MWFkY2Q0N2F2Y3dmYWRjZUdjZHRWZ2x5ZGJmZ2lCZGJhbGFpQmRiYXdjZWZnd2FlOWhtYnhka2tjYmh3aW5kbmFvYXI2bWJjOTpza2FvY2VmaGxhbzhTYmJnaWNGZUdoZGRuZG5haWN1OW1tYmFsaG94ZWthb2N2ZmhvYWRjRmJHaGRjcmhpZG5pbmFsOFNiYmdEY0ZiR2FpdGFkVmhkYURjdTlrbWVhbGNlZmhsYWljcmZnaWM4SjlobWJ4ZGtrYWxjZWZob2thYmF3Y2V0ZmFkYzhFdGM4RjkxYWRjZDQ3YXZjd2ZhZGNlR2NkdFZnbHlkYmZnaTg3ZWJhbGFpQmRiYXdjZWZnd2FlOWhtYmtrY2JjOTlhb2FyU0VrO1RvaW85N2V1ZTk3YWVjOThHaGVkbmRuYWRjbDlobWJhZVRtZWNiaGRpbmFiYWJwYmJiZ2ljS3A6UmVjS3A6U2VwOzZlZ2xhaWN3cDpSZWNLcDpTZXA7NmVhbHA7R2VhaWN6cDpSZWNLcDpTZXA7NmVndnA7R2VwO0tlcDtMZWdvcHhiYmJiYmJiYmJiYmJiYmJicDoyZWdyYWxweGJiYmpiYmJqYmJiamJiYmpnd3A5b3A5cnA7S2VnbHB4YmI7OjljYmI7OjljYmI7OjljYmI7OjljYWxhbHA7TWVhb2FvcDtNZWF2YXJhdmF3cDlvcDlycDtLZWdsYWxwO01lcDtLZXA7S2VwO0plcDtOZWd2cDtNZXB4YmJuMGJibjBiYm4wYmJuMGdycDtLZXB4RmJiYkZiYmJGYmJiRmJiYnA5b2FpcHhiYmJGYmJiRmJiYkZiYmJGcDlvcDlxYWxhdnA7TWVhcnA7S2Vjd3A6UmVweGJGYmJiRmJiYkZiYmJGYmJwOW9wOXFhb2F2cDtNZWFycDtLZWN6cDpSZXB4YmJGYmJiRmJiYkZiYmJGYnA5b3A5cXBrYmJhYmN6ZmhiYWRjbGZnZGFlNm1ieGRra2FlVG1iY2JoZGluYWJjemZnRGFEcGJiYmdpcHhiYmJiYmJGRmJiYmJiYkZGZ3dwOW9hYnBiYmJnb2FpcG1iZWRpd0Rxa3pIT0FLWThBRWd2Y3pwOlJlY3pwOlNlcDs2ZWdsYW9haXBtbHZvcnhtUHNDWFFMMzU4RThGcHhGdWJiRnViYkZ1YmJGdWJicDlvcDs2ZWF2Y3pwOlNlcDs2ZWd2cDtHZWFscDtHZXA7S2VwO0xlZ2lweGJiYmJiYmJiYmJiYmJiYmJwOjJlZ3JhbHB4YmJiamJiYmpiYmJqYmJiamdxcDlvcDlycDtLZWdscHhiOzpGU2I7OkZTYjs6RlNiOzpGU2FsYWxwO01lYWlhaXA7TWVhdmFyYXZhcXA5b3A5cnA7S2VnbGFscDtNZXA7S2VwO0tlcDtKZXA7TmVndnA7TWVweGJibjBiYm4wYmJuMGJibjBncnA7S2VweEZGYmJGRmJiRkZiYkZGYmJwOW9haWF2cDtNZWFycDtLZWN6cDpSZXA5cWdpYWxhdnA7TWVhcnA7S2VweEZGYmJGRmJiRkZiYkZGYmJwOW9nbHBtd0RLWXFrOEFFeG0zNVBzOEU4RnA5cXBrYmJhYmFvYXdwOW9haWFscG1iZXpIZGlPQWx2Q1hvclFMcDlxcGtiYmFiY2FmaGJhZGNsZmdkYWU2bWJra2s7MmlsZXVlOTdldW85N2RuYWVjOThHZ2lUbWJjYmhlaW5hYmNLZnB4OmppOjFTOmppOjFTOmppOjFTOmppOjFTYWJwYmJiZ2xhYmN6Zmd2cGJiYmdvcG1sdm9yeG1Qc0NYUUwzNThFOEZncmN6cDpTZWd3cHhpYmJiaWJiYmliYmJpYmJicDlxcDs2ZWdEcDtOZWdxYURhRHA7TWVnRGFEcDtLZWFsYW9wbWJlZGl3RHFrekhPQUtZOEFFZ0RjenA6UmVjenA6U2VwOzZlZ2xhbHA7TWVhRGN6cDpTZXA7NmVnb2FvcDtNZWFyY3pwOlJlY3pwOlNlcDs2ZWdyYXJwO01lcDtLZXA7S2VwO0xlcHhiYmJiYmJiYmJiYmJiYmJicDo0ZXA7SmVwO01lcHhiYm4wYmJuMGJibjBiYm4wZ0RwO0tlcHhGRmJiRkZiYkZGYmJGRmJiZ2twOW9hcWFvcDtNZWFEcDtLZWN6cDpSZXA5cWdvYXFhbHA7TWVhRHA7S2Vha3A5b2FxYXJwO01lYURwO0tlY3pwOlJlcDlxZ0RwbXdES1lxazhBRXhtMzVQczhFOEZnbHA1ZWF3Y2xwOlJlZ3FwRWk6VDpqODNpYmF2YWxwNWJhcXBFZDpUOmo4M2liYWJjd2Zhb2FEcG1iZXpIZGlPQWx2Q1hvclFMZ0RwNWVhcXBFZTpUOmo4M2liYWJhRHA1YmFxcEViOlQ6ajgzaWJhYmNhZmhiYWVjbGZnZWFpNm1ia2trdWVlOTdkbmFkY2Q0YWUyYzk4R2dlVG1iY2JoZGluYWJhYnBiYmJnaWN3cDpSZWN3cDpTZXA7NmVhaWNlcDpTZXB4YmJqRmJiakZiYmpGYmJqRnA5b3B4YmJqWmJialpiYmpaYmJqWnA6VWVwO01lcGtiYmFiY3pmaGJhZGNsZmdkYWU2bWJra2s6U29kdzk3ZXVhZWM5OEdoZWRuZG5hZGNsOWhtYmFlVG1lY2JoZGluYWJweGJidUpiYnVKYmJ1SmJidUphYnBiYmJnaWNLcDpUZWdsYWljWXA6VGVwOXFndmNkcDpUZWF2cDlxZ3ZjbHA6VGVhdnA5cWdvcDs2ZXA7TmVndmFpY3dwOlJlY0twOlNlZ3JhaXB4RmJiYkZiYmJGYmJiRmJiYmd3cDlvZ0RwOlVlcDs2ZXA7TWVweGJibjBiYm4wYmJuMGJibjBncXA7S2Vjd3A6UmVweGJGYmJiRmJiYkZiYmJGYmJwOW9hdmFEYXJwOlhlYWljenA6UmVjS3A6U2VnaXA6VWVwOzZlcDtNZWFxcDtLZWF3cDlvcDlxYXZhRGFyYWlwOlVlcDpYZXA7NmVwO01lYXFwO0tlY3pwOlJlcHhiYkZiYmJGYmJiRmJiYkZicDlvcDlxYXZhb2FsY2VwOlJlcDlvYWxweGViYmJlYmJiZWJiYmViYmJwOW9wOXFwOzZlcDtNZWFxcDtLZWNLcDpSZXA5cXBrYmJhYmN6ZmhiYWRjbGZnZGFlNm1ieGRra2FlVG1iY2JoZGluYWJjemZna3B4YkZ1OWhiRnU5aGJGdTloYkZ1OWhhYnBiYmJnbGFrcGJiYmdycG1sdm9yeG1Qc0NYUUwzNThFOEZndmN6cDpUZWdxYXZjSHA6VGVwOXFnaWNkcDpUZWFpcDlxZ2ljbHA6VGVhaXA5cWdpY3dwOlRlYWlwOXFnb3A7NmVwO05lZ2lhbGFycG1iZWRpd0Rxa3pIT0FLWThBRWdEcHhGRmJiRkZiYkZGYmJGRmJiZ2xwOW9ncmFEY3pwOlNlZ3dwOlVlYXZjenA6UmVjenA6U2VnRHA6WGVwOzZlcDtNZXB4YmJuMGJibjBiYm4wYmJuMGd2cDtLZWFscDlvYWlhcmF3YURwOlVlcDpYZXA7NmVwO01lYXZwO0tlY3pwOlJlcDlxZ3dhaWFvYXFjZXA6UmVwOW9hcXB4ZWJiYmViYmJlYmJiZWJiYnA5b3A5cXA7NmVwO01lYXZwO0tlY3pwOlJlYWlhRGFycDpVZXA7NmVwO01lYXZwO0tlYWxwOW9wOXFnaXBtd0RLWXFrOEFFeG0zNVBzOEU4RnBrYmJhYmF3YWlwbWJlekhkaU9BbHZDWG9yUUxwa2JiYWJjYWZoYmFkY2xmZ2RhZTZtYmtrazl0ZWl1Y2JjYnlkajpHOmNqYmdlYWJjaWZjOThHZmdiQmRqOkc6Y2piZG5kbmFiWmJjenRnZDlubWJjdWhpYWJhZDlSY0ZGaWZjejRuYmN1U21la2FlaGlrYWlra3hlYmNqOkdka2x6OnpiYiI7CiAgICAgICAgdmFyIGRldGVjdG9yID0gbmV3IFVpbnQ4QXJyYXkoWwogICAgICAgICAgMCwKICAgICAgICAgIDk3LAogICAgICAgICAgMTE1LAogICAgICAgICAgMTA5LAogICAgICAgICAgMSwKICAgICAgICAgIDAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDEsCiAgICAgICAgICA0LAogICAgICAgICAgMSwKICAgICAgICAgIDk2LAogICAgICAgICAgMCwKICAgICAgICAgIDAsCiAgICAgICAgICAzLAogICAgICAgICAgMywKICAgICAgICAgIDIsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDUsCiAgICAgICAgICAzLAogICAgICAgICAgMSwKICAgICAgICAgIDAsCiAgICAgICAgICAxLAogICAgICAgICAgMTIsCiAgICAgICAgICAxLAogICAgICAgICAgMCwKICAgICAgICAgIDEwLAogICAgICAgICAgMjIsCiAgICAgICAgICAyLAogICAgICAgICAgMTIsCiAgICAgICAgICAwLAogICAgICAgICAgNjUsCiAgICAgICAgICAwLAogICAgICAgICAgNjUsCiAgICAgICAgICAwLAogICAgICAgICAgNjUsCiAgICAgICAgICAwLAogICAgICAgICAgMjUyLAogICAgICAgICAgMTAsCiAgICAgICAgICAwLAogICAgICAgICAgMCwKICAgICAgICAgIDExLAogICAgICAgICAgNywKICAgICAgICAgIDAsCiAgICAgICAgICA2NSwKICAgICAgICAgIDAsCiAgICAgICAgICAyNTMsCiAgICAgICAgICAxNSwKICAgICAgICAgIDI2LAogICAgICAgICAgMTEKICAgICAgICBdKTsKICAgICAgICB2YXIgd2FzbXBhY2sgPSBuZXcgVWludDhBcnJheShbCiAgICAgICAgICAzMiwKICAgICAgICAgIDAsCiAgICAgICAgICA2NSwKICAgICAgICAgIDIsCiAgICAgICAgICAxLAogICAgICAgICAgMTA2LAogICAgICAgICAgMzQsCiAgICAgICAgICAzMywKICAgICAgICAgIDMsCiAgICAgICAgICAxMjgsCiAgICAgICAgICAxMSwKICAgICAgICAgIDQsCiAgICAgICAgICAxMywKICAgICAgICAgIDY0LAogICAgICAgICAgNiwKICAgICAgICAgIDI1MywKICAgICAgICAgIDEwLAogICAgICAgICAgNywKICAgICAgICAgIDE1LAogICAgICAgICAgMTE2LAogICAgICAgICAgMTI3LAogICAgICAgICAgNSwKICAgICAgICAgIDgsCiAgICAgICAgICAxMiwKICAgICAgICAgIDQwLAogICAgICAgICAgMTYsCiAgICAgICAgICAxOSwKICAgICAgICAgIDU0LAogICAgICAgICAgMjAsCiAgICAgICAgICA5LAogICAgICAgICAgMjcsCiAgICAgICAgICAyNTUsCiAgICAgICAgICAxMTMsCiAgICAgICAgICAxNywKICAgICAgICAgIDQyLAogICAgICAgICAgNjcsCiAgICAgICAgICAyNCwKICAgICAgICAgIDIzLAogICAgICAgICAgMTQ2LAogICAgICAgICAgMTQ4LAogICAgICAgICAgMTgsCiAgICAgICAgICAxNCwKICAgICAgICAgIDIyLAogICAgICAgICAgNDUsCiAgICAgICAgICA3MCwKICAgICAgICAgIDY5LAogICAgICAgICAgNTYsCiAgICAgICAgICAxMTQsCiAgICAgICAgICAxMDEsCiAgICAgICAgICAyMSwKICAgICAgICAgIDI1LAogICAgICAgICAgNjMsCiAgICAgICAgICA3NSwKICAgICAgICAgIDEzNiwKICAgICAgICAgIDEwOCwKICAgICAgICAgIDI4LAogICAgICAgICAgMTE4LAogICAgICAgICAgMjksCiAgICAgICAgICA3MywKICAgICAgICAgIDExNQogICAgICAgIF0pOwogICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkgIT09ICJvYmplY3QiKSB7CiAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICBzdXBwb3J0ZWQ6IGZhbHNlCiAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICB2YXIgd2FzbTIgPSBXZWJBc3NlbWJseS52YWxpZGF0ZShkZXRlY3RvcikgPyB1bnBhY2sod2FzbV9zaW1kKSA6IHVucGFjayh3YXNtX2Jhc2UpOwogICAgICAgIHZhciBpbnN0YW5jZTsKICAgICAgICB2YXIgcmVhZHkgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZSh3YXNtMiwge30pLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgICBpbnN0YW5jZSA9IHJlc3VsdC5pbnN0YW5jZTsKICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMuX193YXNtX2NhbGxfY3RvcnMoKTsKICAgICAgICB9KTsKICAgICAgICBmdW5jdGlvbiB1bnBhY2soZGF0YSkgewogICAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KGRhdGEubGVuZ3RoKTsKICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBkYXRhLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICB2YXIgY2ggPSBkYXRhLmNoYXJDb2RlQXQoaTIpOwogICAgICAgICAgICByZXN1bHRbaTJdID0gY2ggPiA5NiA/IGNoIC0gOTcgOiBjaCA+IDY0ID8gY2ggLSAzOSA6IGNoICsgNDsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB3cml0ZSA9IDA7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgZGF0YS5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgcmVzdWx0W3dyaXRlKytdID0gcmVzdWx0W2kyXSA8IDYwID8gd2FzbXBhY2tbcmVzdWx0W2kyXV0gOiAocmVzdWx0W2kyXSAtIDYwKSAqIDY0ICsgcmVzdWx0WysraTJdOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdC5idWZmZXIuc2xpY2UoMCwgd3JpdGUpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBkZWNvZGUzKGluc3RhbmNlMiwgZnVuLCB0YXJnZXQsIGNvdW50LCBzaXplLCBzb3VyY2UsIGZpbHRlcikgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZTIuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIGNvdW50NCA9IGNvdW50ICsgMyAmIH4zOwogICAgICAgICAgdmFyIHRwID0gc2Jyayhjb3VudDQgKiBzaXplKTsKICAgICAgICAgIHZhciBzcCA9IHNicmsoc291cmNlLmxlbmd0aCk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlMi5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoc291cmNlLCBzcCk7CiAgICAgICAgICB2YXIgcmVzID0gZnVuKHRwLCBjb3VudCwgc2l6ZSwgc3AsIHNvdXJjZS5sZW5ndGgpOwogICAgICAgICAgaWYgKHJlcyA9PSAwICYmIGZpbHRlcikgewogICAgICAgICAgICBmaWx0ZXIodHAsIGNvdW50NCwgc2l6ZSk7CiAgICAgICAgICB9CiAgICAgICAgICB0YXJnZXQuc2V0KGhlYXAuc3ViYXJyYXkodHAsIHRwICsgY291bnQgKiBzaXplKSk7CiAgICAgICAgICBzYnJrKHRwIC0gc2JyaygwKSk7CiAgICAgICAgICBpZiAocmVzICE9IDApIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJNYWxmb3JtZWQgYnVmZmVyIGRhdGE6ICIgKyByZXMpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB2YXIgZmlsdGVycyA9IHsKICAgICAgICAgIE5PTkU6ICIiLAogICAgICAgICAgT0NUQUhFRFJBTDogIm1lc2hvcHRfZGVjb2RlRmlsdGVyT2N0IiwKICAgICAgICAgIFFVQVRFUk5JT046ICJtZXNob3B0X2RlY29kZUZpbHRlclF1YXQiLAogICAgICAgICAgRVhQT05FTlRJQUw6ICJtZXNob3B0X2RlY29kZUZpbHRlckV4cCIsCiAgICAgICAgICBDT0xPUjogIm1lc2hvcHRfZGVjb2RlRmlsdGVyQ29sb3IiCiAgICAgICAgfTsKICAgICAgICB2YXIgZGVjb2RlcnMgPSB7CiAgICAgICAgICBBVFRSSUJVVEVTOiAibWVzaG9wdF9kZWNvZGVWZXJ0ZXhCdWZmZXIiLAogICAgICAgICAgVFJJQU5HTEVTOiAibWVzaG9wdF9kZWNvZGVJbmRleEJ1ZmZlciIsCiAgICAgICAgICBJTkRJQ0VTOiAibWVzaG9wdF9kZWNvZGVJbmRleFNlcXVlbmNlIgogICAgICAgIH07CiAgICAgICAgdmFyIHdvcmtlcnMgPSBbXTsKICAgICAgICB2YXIgcmVxdWVzdElkID0gMDsKICAgICAgICBmdW5jdGlvbiBjcmVhdGVXb3JrZXIyKHVybCkgewogICAgICAgICAgdmFyIHdvcmtlciA9IHsKICAgICAgICAgICAgb2JqZWN0OiBuZXcgV29ya2VyKHVybCksCiAgICAgICAgICAgIHBlbmRpbmc6IDAsCiAgICAgICAgICAgIHJlcXVlc3RzOiB7fQogICAgICAgICAgfTsKICAgICAgICAgIHdvcmtlci5vYmplY3Qub25tZXNzYWdlID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgICAgICAgdmFyIGRhdGEgPSBldmVudC5kYXRhOwogICAgICAgICAgICB3b3JrZXIucGVuZGluZyAtPSBkYXRhLmNvdW50OwogICAgICAgICAgICB3b3JrZXIucmVxdWVzdHNbZGF0YS5pZF1bZGF0YS5hY3Rpb25dKGRhdGEudmFsdWUpOwogICAgICAgICAgICBkZWxldGUgd29ya2VyLnJlcXVlc3RzW2RhdGEuaWRdOwogICAgICAgICAgfTsKICAgICAgICAgIHJldHVybiB3b3JrZXI7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGluaXRXb3JrZXJzKGNvdW50KSB7CiAgICAgICAgICB2YXIgc291cmNlID0gInNlbGYucmVhZHkgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZShuZXcgVWludDhBcnJheShbIiArIG5ldyBVaW50OEFycmF5KHdhc20yKSArICJdKSwge30pLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7IHJlc3VsdC5pbnN0YW5jZS5leHBvcnRzLl9fd2FzbV9jYWxsX2N0b3JzKCk7IHJldHVybiByZXN1bHQuaW5zdGFuY2U7IH0pO3NlbGYub25tZXNzYWdlID0gIiArIHdvcmtlclByb2Nlc3MubmFtZSArICI7IiArIGRlY29kZTMudG9TdHJpbmcoKSArIHdvcmtlclByb2Nlc3MudG9TdHJpbmcoKTsKICAgICAgICAgIHZhciBibG9iID0gbmV3IEJsb2IoW3NvdXJjZV0sIHsgdHlwZTogInRleHQvamF2YXNjcmlwdCIgfSk7CiAgICAgICAgICB2YXIgdXJsID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTsKICAgICAgICAgIGZvciAodmFyIGkyID0gd29ya2Vycy5sZW5ndGg7IGkyIDwgY291bnQ7ICsraTIpIHsKICAgICAgICAgICAgd29ya2Vyc1tpMl0gPSBjcmVhdGVXb3JrZXIyKHVybCk7CiAgICAgICAgICB9CiAgICAgICAgICBmb3IgKHZhciBpMiA9IGNvdW50OyBpMiA8IHdvcmtlcnMubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIHdvcmtlcnNbaTJdLm9iamVjdC5wb3N0TWVzc2FnZSh7fSk7CiAgICAgICAgICB9CiAgICAgICAgICB3b3JrZXJzLmxlbmd0aCA9IGNvdW50OwogICAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh1cmwpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBkZWNvZGVXb3JrZXIoY291bnQsIHNpemUsIHNvdXJjZSwgbW9kZSwgZmlsdGVyKSB7CiAgICAgICAgICB2YXIgd29ya2VyID0gd29ya2Vyc1swXTsKICAgICAgICAgIGZvciAodmFyIGkyID0gMTsgaTIgPCB3b3JrZXJzLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICBpZiAod29ya2Vyc1tpMl0ucGVuZGluZyA8IHdvcmtlci5wZW5kaW5nKSB7CiAgICAgICAgICAgICAgd29ya2VyID0gd29ya2Vyc1tpMl07CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHsKICAgICAgICAgICAgdmFyIGRhdGEgPSBuZXcgVWludDhBcnJheShzb3VyY2UpOwogICAgICAgICAgICB2YXIgaWQgPSArK3JlcXVlc3RJZDsKICAgICAgICAgICAgd29ya2VyLnBlbmRpbmcgKz0gY291bnQ7CiAgICAgICAgICAgIHdvcmtlci5yZXF1ZXN0c1tpZF0gPSB7IHJlc29sdmUsIHJlamVjdCB9OwogICAgICAgICAgICB3b3JrZXIub2JqZWN0LnBvc3RNZXNzYWdlKHsgaWQsIGNvdW50LCBzaXplLCBzb3VyY2U6IGRhdGEsIG1vZGUsIGZpbHRlciB9LCBbZGF0YS5idWZmZXJdKTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiB3b3JrZXJQcm9jZXNzKGV2ZW50KSB7CiAgICAgICAgICB2YXIgZGF0YSA9IGV2ZW50LmRhdGE7CiAgICAgICAgICBzZWxmLnJlYWR5LnRoZW4oZnVuY3Rpb24oaW5zdGFuY2UyKSB7CiAgICAgICAgICAgIGlmICghZGF0YS5pZCkgewogICAgICAgICAgICAgIHJldHVybiBzZWxmLmNsb3NlKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5jb3VudCAqIGRhdGEuc2l6ZSk7CiAgICAgICAgICAgICAgZGVjb2RlMyhpbnN0YW5jZTIsIGluc3RhbmNlMi5leHBvcnRzW2RhdGEubW9kZV0sIHRhcmdldCwgZGF0YS5jb3VudCwgZGF0YS5zaXplLCBkYXRhLnNvdXJjZSwgaW5zdGFuY2UyLmV4cG9ydHNbZGF0YS5maWx0ZXJdKTsKICAgICAgICAgICAgICBzZWxmLnBvc3RNZXNzYWdlKHsgaWQ6IGRhdGEuaWQsIGNvdW50OiBkYXRhLmNvdW50LCBhY3Rpb246ICJyZXNvbHZlIiwgdmFsdWU6IHRhcmdldCB9LCBbdGFyZ2V0LmJ1ZmZlcl0pOwogICAgICAgICAgICB9IGNhdGNoIChlcnJvcikgewogICAgICAgICAgICAgIHNlbGYucG9zdE1lc3NhZ2UoeyBpZDogZGF0YS5pZCwgY291bnQ6IGRhdGEuY291bnQsIGFjdGlvbjogInJlamVjdCIsIHZhbHVlOiBlcnJvciB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB7CiAgICAgICAgICByZWFkeSwKICAgICAgICAgIHN1cHBvcnRlZDogdHJ1ZSwKICAgICAgICAgIHVzZVdvcmtlcnM6IGZ1bmN0aW9uKGNvdW50KSB7CiAgICAgICAgICAgIGluaXRXb3JrZXJzKGNvdW50KTsKICAgICAgICAgIH0sCiAgICAgICAgICBkZWNvZGVWZXJ0ZXhCdWZmZXI6IGZ1bmN0aW9uKHRhcmdldCwgY291bnQsIHNpemUsIHNvdXJjZSwgZmlsdGVyKSB7CiAgICAgICAgICAgIGRlY29kZTMoaW5zdGFuY2UsIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9kZWNvZGVWZXJ0ZXhCdWZmZXIsIHRhcmdldCwgY291bnQsIHNpemUsIHNvdXJjZSwgaW5zdGFuY2UuZXhwb3J0c1tmaWx0ZXJzW2ZpbHRlcl1dKTsKICAgICAgICAgIH0sCiAgICAgICAgICBkZWNvZGVJbmRleEJ1ZmZlcjogZnVuY3Rpb24odGFyZ2V0LCBjb3VudCwgc2l6ZSwgc291cmNlKSB7CiAgICAgICAgICAgIGRlY29kZTMoaW5zdGFuY2UsIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9kZWNvZGVJbmRleEJ1ZmZlciwgdGFyZ2V0LCBjb3VudCwgc2l6ZSwgc291cmNlKTsKICAgICAgICAgIH0sCiAgICAgICAgICBkZWNvZGVJbmRleFNlcXVlbmNlOiBmdW5jdGlvbih0YXJnZXQsIGNvdW50LCBzaXplLCBzb3VyY2UpIHsKICAgICAgICAgICAgZGVjb2RlMyhpbnN0YW5jZSwgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2RlY29kZUluZGV4U2VxdWVuY2UsIHRhcmdldCwgY291bnQsIHNpemUsIHNvdXJjZSk7CiAgICAgICAgICB9LAogICAgICAgICAgZGVjb2RlR2x0ZkJ1ZmZlcjogZnVuY3Rpb24odGFyZ2V0LCBjb3VudCwgc2l6ZSwgc291cmNlLCBtb2RlLCBmaWx0ZXIpIHsKICAgICAgICAgICAgZGVjb2RlMyhpbnN0YW5jZSwgaW5zdGFuY2UuZXhwb3J0c1tkZWNvZGVyc1ttb2RlXV0sIHRhcmdldCwgY291bnQsIHNpemUsIHNvdXJjZSwgaW5zdGFuY2UuZXhwb3J0c1tmaWx0ZXJzW2ZpbHRlcl1dKTsKICAgICAgICAgIH0sCiAgICAgICAgICBkZWNvZGVHbHRmQnVmZmVyQXN5bmM6IGZ1bmN0aW9uKGNvdW50LCBzaXplLCBzb3VyY2UsIG1vZGUsIGZpbHRlcikgewogICAgICAgICAgICBpZiAod29ya2Vycy5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuIGRlY29kZVdvcmtlcihjb3VudCwgc2l6ZSwgc291cmNlLCBkZWNvZGVyc1ttb2RlXSwgZmlsdGVyc1tmaWx0ZXJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmVhZHkudGhlbihmdW5jdGlvbigpIHsKICAgICAgICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3IFVpbnQ4QXJyYXkoY291bnQgKiBzaXplKTsKICAgICAgICAgICAgICBkZWNvZGUzKGluc3RhbmNlLCBpbnN0YW5jZS5leHBvcnRzW2RlY29kZXJzW21vZGVdXSwgdGFyZ2V0LCBjb3VudCwgc2l6ZSwgc291cmNlLCBpbnN0YW5jZS5leHBvcnRzW2ZpbHRlcnNbZmlsdGVyXV0pOwogICAgICAgICAgICAgIHJldHVybiB0YXJnZXQ7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL21lc2hvcHRfc2ltcGxpZmllci5qcwogIHZhciBNZXNob3B0U2ltcGxpZmllcjsKICB2YXIgaW5pdF9tZXNob3B0X3NpbXBsaWZpZXIgPSBfX2VzbSh7CiAgICAibm9kZV9tb2R1bGVzL21lc2hvcHRpbWl6ZXIvbWVzaG9wdF9zaW1wbGlmaWVyLmpzIigpIHsKICAgICAgTWVzaG9wdFNpbXBsaWZpZXIgPSAoZnVuY3Rpb24oKSB7CiAgICAgICAgdmFyIHdhc20yID0gImI5SDc5VGViYmJlOjZlTzlHZXVldTlHZXViOUdiYjlHc3V1dXV1dXV1dXV1dTk5dXVldTlHdnV1dXV1YjlHcnV1dXV1dXViOUdvdXV1dXV1ZTk5OUd2dXV1dXVldTlHenV1dXV1dXV1dXV1OTl1dXV1YjlHcXV1dXV1dXU5OXV1ZXU5R1B1dXV1dXV1dXV1dTk5dXVldTlHcXV1dXV1dXV1OTl1ZXU5R3J1dXV1dXU5OWV1OUd3dXV1dXV1OTl1ZXU5R2l1dXVlOTk5R2x1dXV1ZXU5R2x1dXV1YjlHaXV1dWV1aUxRZGlsdm9ybHdEaXFreG1Qc3piSEhiZWx2ZTlXZWlpdmllYmVvd2V1ZWNqOkdka3I6QmR4bzlUVzlUOVZWOTVkYkg5RjlGOTM5SDc5VDlGOUo5SDIyOUY5SnQ5VlY3YmJ6OVRXNzlPOVY5V3Q5Rjc5UDlUOVcyOVA5TTk1Ync4RTlUVzc5TzlWOVd0OUY3OVA5VDlXMjlQOU05NTl4OVB0OU9jdHRWOVA5STkxdFc3YkQ4QTlUVzc5TzlWOVd0OUY3OVA5VDlXMjlQOU05NTl4OVB0OU85djlXOUs5SHRXYnFROVRXNzlPOVY5V3Q5Rjc5UDlUOVcyOVA5TTk1OXQyOVY5VzlXOTVia1g5VFc3OU85VjlXdDlGNzlQOVQ5VzI5UDlNOTU5cVY5MTlVV2J4UTlUVzc5TzlWOVd0OUY3OVA5VDlXMjlQOU05NTlxOVY5UDlVdDdibVg5VFc3OU85VjlXdDlGNzlQOVQ5VzI5UDlNOTU5dDlKOUgyV2JQYTlUVzc5TzlWOVd0OUY5VjlXdDlQOVQ5UDk2Vzl3V1Z0Vzk0U1d0OUo5TzlzVzlUOUg5V2JzNTlUVzc5TzlWOVd0OUY5Tlc5VVdWOUh0VzlxOVY3OVB0OVA5VjlVOXNXOVQ5SDlXYnpsNzlJVjlSYkhEd2ViY2VrZENYcTt5O1dlUWRiaztyOmhlcll1ZTk5aXVZOTlYdWU5OkQ5OThKampqamJjajtzYjlSZ3M4S2pqampiY2JoemFzYzpDZWZjYmM7S2J6OnRqampiOEFkbmFiYWVTbWJhYmFlYWRjZHR6TWpqamI4QWtkbmFtY2RHVG1iYWxjcmZjaTRjYnlkMTpIOmNqYkhqampqYmJoSGFzYzpDZWZhc3lkOzhlZ2VjZHRmYUhCZGJhc2FlY2VmQmQ7OGVjYmhsY2JoZWRuYWRUbWJhYmhlYWRoT2luYUhhZXlkYmNpNGZjYjg2YmJhZWNsZmhlYU9jdWZnT21ia2NiaGxhYmhlYWRoT2luYUhhZXlkYmdBY2k0ZmdDYUNSYmJnQ2NlYUFjckdnQXRWODZiYmFDY3U3YUE0Y2VHYWxmaGxhZWNsZmhlYU9jdWZnT21ia2N1YWxjZHRhbGNGRkZGaTBFaGVrYWVjYnlkMTpIOmNqYkhqampqYmJoemFzYzpDZWZhc3lkOzhlZ2VjZHRmYXpCZGJhc2FlY2VmQmQ7OGVhbGNkNGFsZmhPY2VoSGluYUhnZWNldGhIYWVhTzZtYmtjYmhYY3VhZWNkdGdPYWVjRkZGRmkwRWNieWQxOkg6Y2piSGpqampiYmhIYXNjOkNlZmFzeWQ7OGVnQWNkdGZhSEJkYmFzYUFjZWZCZDs4ZWFIY0ZlYU96OnRqampiaFFkbmFkVG1iYWVjdWZoTGNiaEtpbmRuZG5hUWFiYUtjZHRmZ1l5ZGJnQWM6djt0O2g7RXYyYUxHZ09jZHRmZ0N5ZGJnSGN1U21iY2VoZWluYXphSGNkdGZ5ZGJhQVNtZGFPYWVmaEhhZWNlZmhlYVFhSGFMR2dPY2R0ZmdDeWRiZ0hjdTlobWJra2F6YVhjZHRmYUFCZGJhQ2FYQmRiYVhoSGFYY2VmaFhrYVlhSEJkYmFLY2VmZ0thZDlobWJra2FRY2J5ZDptOkg6Y2piSDpiampqYmJhc2FzeWQ7OGVjdWZCZDs4ZWtjYmg4QWN1YWxjZWZnZWNkdGFlY0ZGRkZpMEVjYnlkMTpIOmNqYkhqampqYmJoTGFzYzpDZWZhc3lkOzhlZ2VjZHRmYUxCZGJhc2FMQmROZWFzYWVjZWZCZDs4ZWN1YWRjaXRhZGNGRkZGZTBFY2J5ZDE6SDpjamJIampqamJiaEVhc2M6Q2VmYXN5ZDs4ZWdlY2R0ZmFFQmRiYXNhRUJkOnllYXNhZWNlZkJkOzhlYXNjTmVmYWJhZGFsY2J6OmNqampiY3VhbGNkdGdlYWxjRkZGRmkwRWczY2J5ZDE6SDpjamJIampqamJiaE9hc2M6Q2VmYXN5ZDs4ZWdIY2R0ZmFPQmRiYXNhSGNlZkJkOzhlYTNjYnlkMTpIOmNqYkhqampqYmJoUWFzYzpDZWZhc3lkOzhlZ0hjZHRmYVFCZGJhc2FIY2VmQmQ7OGVhT2FRYWlhbGF2YXphc2M6Q2VmejpkampqYmFsY2J5ZDE6SDpjamJIampqamJiaFlhc2M6Q2VmYXN5ZDs4ZWdIY2R0ZmFZQmRiYXNhSGNlZkJkOzhlYTNjYnlkMTpIOmNqYkhqampqYmJoSGFzYzpDZWZhc3lkOzhlZ0FjZHRmYUhCZGJhc2FBY2VmQmQ7OGVhM2NieWQxOkg6Y2piSGpqampiYmhBYXNjOkNlZmFzeWQ7OGVnQ2NkdGZhQUJkYmFzYUNjZWZCZDs4ZWFIY0ZlYWV6OnRqampiaDVhQWNGZWFlejp0ampqYmg4RWRuYWxUbWJpbmRuYUxhOEFnQWNlZmc4QWNkdGZ5ZGJnQ2FMYUFjZHRnZWZ5ZGJnSFNtYmFDYUg5Umg4RmFFYUhjaXRmaGFhOEVhZWZoaGE1YWVmaEtjYmhDaW5kbmRuYWFhQ2NpdGZ5ZGJnWGFBOWhtYmFLYUFCZGJhaGFBQmRieGVrZG5hTGFYY2R0Z2dmZ2VjbGZ5ZGJnSGFleWRiZ2VTbWJhSGFlOVJoSGFFYWVjaXRmaGVpbmFleWRiYUFTbWRhZWN3ZmhlYUhjdWZnSG1ia2thOEVhZ2ZnZWFBYVhhZXlkYmN1U0VCZGJhS2FYYUFhS3lkYmN1U0VCZGJrYUNjZWZnQ2E4RjlobWJra2E4QWFsOWhtYmthT2hIYVFoQWE1aFhhOEVoQ2NiaGVpbmRuZG5hZWFIeWRiZ0s5aG1iZG5hZWFBeWRiZ0s5aG1iYVh5ZGJoS2RuYUN5ZGJnOEZjdTlobWJhS2N1OWhtYmFZYWVmY2I4NmJieGlrZG5hOEZjdVNtYmFLY3VTbWJhZWE4RlNtYmFPYThGY2R0ZnlkYmFPYUtjZHRmeWRiOWhtYmFZYWVmY2Q4NmJieGlrYVlhZWZoYWRuYWVhOEZTbWJhZWFLU21iYWFjZTg2YmJ4aWthYWNsODZiYnhka2RuYWVhUWFLY2R0ZzhGZnlkYjlobWJkbmFDeWRiZ2FjdVNtYmFlYWFTbWJhWHlkYmdnY3VTbWJhZWFnU21iYThFYThGZnlkYmdoY3VTbWJhaGFLU21iYTVhOEZmeWRiZzhGY3VTbWJhOEZhS1NtYmRuYU9hYWNkdGZ5ZGJnS2FPYThGY2R0ZnlkYjlobWJhS2FPYWdjZHRmeWRiZzhGU21iYThGYU9haGNkdGZ5ZGI5aG1iYVlhZWZjZDg2YmJ4bGthWWFlZmNsODZiYnhpa2FZYWVmY2w4NmJieGRrYVlhZWZjbDg2YmJ4ZWthWWFlZmFZYUtmUmJiODZiYmthSGNsZmhIYUFjbGZoQWFYY2xmaFhhQ2NsZmhDYWxhZWNlZmdlOWhtYmtkbmFtY2FHVG1iY2JoOEppbmRuZG5hWWE4SmZnOEtSYmJnOExjOTpmUGliZWJla2RuZG5kbmFPYThKY2R0ZnlkYmdlYThKOWhtYmRuYXFtYmNiaDhGeGRrZG5helRtYmNiaDhGYThKaGVpbmFxYXphZWNkdGdlZnlkYmZSYmJjZTRhOEZWY2VHaDhGYVFhZWZ5ZGJnZWE4SjlobWJ4aWtrY2JoOEZhOEpoZWluYXFhZWZSYmJjZTRhOEZWY2VHaDhGYVFhZWNkdGZ5ZGJnZWE4SjlobWJ4ZGtrYVlhZWZSYmJoZXhla2E4SmhlaW5kbmFMYWVjZHRnOEFmZ2VjbGZ5ZGJnSGFleWRiZ2VTbWJhSGFlOVJoZ2FFYWVjaXRmaGhhT2E4QWZoYWNiaEtpbmFoYUtjaXRmeWRiZ1hoZWRuaW5kbmFMYWVjZHRnQ2ZnZWNsZnlkYmdIYWV5ZGJnZVNtYmFIYWU5UmhIYUVhZWNpdGZoZWFheWRiaEFkbmluYU9hZXlkYmNkdGZ5ZGJhQVNtZWFlY3dmaGVhSGN1ZmdIVG1keGJra2NiaGV4ZGthUWFDZnlkYmdlYVg5aG1ia2NlaGVrYThGYWVWaDhGYUtjZWZnS2FnOWhtYmtrYVFhOEFmeWRiZ2VhOEo5aG1ia2E4TGNpYThGY2VHRWhla2E4S2FlODZiYmthOEpjZWZnOEphbDlobWJra2RuYXFUbWJkbmRuYXpUbWJhemhlYU9oSGFsaEFpbmRuYXFhZXlkYmZSYmJjZUdUbWJhWWFIeWRiZmNsODZiYmthZWNsZmhlYUhjbGZoSGFBY3VmZ0FtYnhka2thcWhlYU9oSGFsaEFpbmRuYWVSYmJjZUdUbWJhWWFIeWRiZmNsODZiYmthZWNlZmhlYUhjbGZoSGFBY3VmZ0FtYmtrYU9oZWFsaEFhWWhIaW5kbmFZYWV5ZGJmUmJiY2w5aG1iYUhjbDg2YmJrYWVjbGZoZWFIY2VmaEhhQWN1ZmdBbWJra2FtY2VHVG1iYVloZWFsaEhpbmRuYWVSYmJjZTlobWJhZWNsODZiYmthZWNlZmhlYUhjdWZnSG1ia2tjYmg4TWN1YWxjeDJhbGM7djpRO3Y6UWUwRWNieWQxOkg6Y2piSGpqampiYmg4TmFzYzpDZWZhc3lkOzhlZ2VjZHRmYThOQmRiYXNhZWNlZkJkOzhlYXNjYkJkOnFlYXM5Y2I4M2kxZWE4TmFpYWxhdmF6YXNjMWVmejplampqYmh5ZG5kbmFEbWJjYmg4UGNiaEN4ZWtjYmhDYXdoZWNiaEhpbmRuYWVJZGJKYmJiYjlFVG1iYXNhQ2NkdGZhSEJkYmFDY2VmaENrYWVjbGZoZWFEYUhjZWZnSDlobWJrY3VhQ2FsMmdlY2R0YWVjRkZGRmkwRWNieWQxOkg6Y2piSGpqampiYmg4UGFzYzpDZWZhc3lkOzhlZ2VjZHRmYThQQmRiYXNhZWNlZkJkOzhlYWxUbWJkbmFDbWJjYmhDeGVrYXJjZDRoZ2RuYXpUbWJhQ2NkdGhoY2JoOEZhOFBoYWluYW9hemE4RmNkdGZ5ZGJhZzJjZHRmaEthc2hlYWFoSGFDaEFpbmFIYUthZXlkYmNkdGdYZklkYmF3YVhmSWRiTlVkYmFlY2xmaGVhSGNsZmhIYUFjdWZnQW1ia2FhYWhmaGFhOEZjZWZnOEZhbDlobWJ4ZGtrYUNjZHRoaGNiaDhGYThQaGFpbmFvYThGYWcyY2R0ZmhLYXNoZWFhaEhhQ2hBaW5hSGFLYWV5ZGJjZHRnWGZJZGJhd2FYZklkYk5VZGJhZWNsZmhlYUhjbGZoSGFBY3VmZ0FtYmthYWFoZmhhYThGY2VmZzhGYWw5aG1ia2tjdWFsYzhTMmdIYWxjO0Q7TztmOFUwRWdYY2J5ZDE6SDpjamJIampqamJiaGVhc2M6Q2VmYXN5ZDs4ZWdBY2R0ZmFlQmRiYXNhQWNlZkJkOzhlYWVjYmFIejp0ampqYmhJY2JoOFJjYmhnZG5hQ1RtYmNiaDhNYVhjYnlkMTpIOmNqYkhqampqYmJoZ2FzYzpDZWZhc3lkOzhlZ2VjZHRmYWdCZGJhc2FlY2VmQmQ7OGVhZ2NiYUh6OnRqampiOEFjdWFDYWwyZ2VjbHRnSGFlY0ZGRkZiMEVjYnlkMTpIOmNqYkhqampqYmJoOFJhc2M6Q2VmYXN5ZDs4ZWdlY2R0ZmE4UkJkYmFzYWVjZWZCZDs4ZWE4UmNiYUh6OnRqampiOEFhbWNqampqZEdUbWJjdWFsY2x0Z2VhbGNGRkZGYjBFY2J5ZDE6SDpjamJIampqamJiaDhNYXNjOkNlZmFzeWQ7OGVnSGNkdGZhOE1CZGJhc2FIY2VmQmQ7OGVhOE1jYmFlejp0ampqYjhBa2RuYWRUbWJjYmhLYWJoSGluYThOYUhjbGZ5ZGJnOEZjeDJmZ2VJZGJhOE5hSHlkYmdhY3gyZmdBSWRiZzhTOnRnUmE4TmFIY3dmeWRiZ2hjeDJmZ1hJZGxhQUlkbGc4VTp0ZzhWTmFlSWRsYThVOnRnOFdhWElkYmE4Uzp0ZzhYTjp0ZzhZYThZTmE4V2FYSWR3YUFJZHdnOFo6dGc4ME5hZUlkd2E4Wjp0ZzhXYThWTjp0ZzgxYTgxTmE4V2E4WE5hUmE4ME46dGc4MGE4ME5NTWc4VjpyaEJhOFloOFhhODBoOFdhODFoUmRuYThWSmJiYmI5RWdBVG1iYThZYUI6dmg4WGE4MGFCOnZoOFdhODFhQjp2aFJrYUlhT2FhY2R0ZnlkYmdYYzhTMmZnZWFSYUI6cmc4VmFSTk5nODNhZUlkYk1VZGJhZWE4V2E4VmE4V05nVU5nODVhZUlkbE1VZGxhZWE4WGE4VmE4WE5nODZOZzg3YWVJZHdNVWR3YWVhUmFVTmdVYWVJZHhNVWR4YWVhODZhUk5nODhhZUlkek1VZHphZWE4V2E4Nk5nODlhZUlkQ01VZENhZWFSYThWYThYYThaTmFSYThTTmE4VWE4V05NTTptZzg6Tmc4Nk5nUmFlSWRLTVVkS2FlYThXYTg2Tmc4V2FlSWQzTVVkM2FlYThYYTg2Tmc4WGFlSWRhTVVkYWFlYTg2YTg6Tmc4NmFlSWQ4S01VZDhLYWVhOFZhZUlkeU1VZHlhSWFPYThGY2R0ZnlkYmc4RmM4UzJmZ2VhODNhZUlkYk1VZGJhZWE4NWFlSWRsTVVkbGFlYTg3YWVJZHdNVWR3YWVhVWFlSWR4TVVkeGFlYTg4YWVJZHpNVWR6YWVhODlhZUlkQ01VZENhZWFSYWVJZEtNVWRLYWVhOFdhZUlkM01VZDNhZWE4WGFlSWRhTVVkYWFlYTg2YWVJZDhLTVVkOEthZWE4VmFlSWR5TVVkeWFJYU9haGNkdGZ5ZGJnYWM4UzJmZ2VhODNhZUlkYk1VZGJhZWE4NWFlSWRsTVVkbGFlYTg3YWVJZHdNVWR3YWVhVWFlSWR4TVVkeGFlYTg4YWVJZHpNVWR6YWVhODlhZUlkQ01VZENhZWFSYWVJZEtNVWRLYWVhOFdhZUlkM01VZDNhZWE4WGFlSWRhTVVkYWFlYTg2YWVJZDhLTVVkOEthZWE4VmFlSWR5TVVkeWRuYThNVG1iZG5hQVRtYmE4WWFCOnZoOFlhODBhQjp2aDgwYTgxYUI6dmg4MWthOE1hWGNsdGZnZWFCSmJiYlpOZ1JhODBOZzhWYWVJZGxNVWRsYWVhUmE4WU5nOFdhZUlkd01VZHdhZWFSYTgxTmc4WGFlSWRiTVVkYmFlYVJhOFM6bWE4MU5hOFVhODBOOnRhOFphOFlOOnROZ1JhZUlkeE1VZHhhOE1hOEZjbHRmZ2VhOFZhZUlkbE1VZGxhZWE4V2FlSWR3TVVkd2FlYThYYWVJZGJNVWRiYWVhUmFlSWR4TVVkeGE4TWFhY2x0ZmdlYThWYWVJZGxNVWRsYWVhOFdhZUlkd01VZHdhZWE4WGFlSWRiTVVkYmFlYVJhZUlkeE1VZHhrYUhjeGZoSGFLY2lmZ0thZDZtYmtrZG5hbFRtYkpxO3g4Sjg4SjtuO207bTg5Sjp2Ojs7dzhaYW1jekdFYW1jO2FiR0VoODBjYmhIYU9oWGF6aEthSWhlYThOaEFpbmRuYUhhWHlkYjlobWJhSGg4RmRuYXpUbWJhS3lkYmg4RmthODBoUmRuYXFUbWJKYmJqWmE4MGFxYThGZlJiYmNsR0VoUmthZWN4Zmc4RmE4RklkYkpiYmJiTVVkYmFlY3pmZzhGYThGSWRiSmJiYmJNVWRiYWVjQ2ZnOEZhOEZJZGJKYmJiYk1VZGJhZWFSYWVjeWZnOEZJZGJnOFlOZ1JhZUlkYk1VZGJhZWNsZmdhYVJhYUlkYk1VZGJhZWN3ZmdhYVJhYUlkYk1VZGJhZWNLZmdhYWFJZGJhQUlkYmc4V2FSTjp0VWRiYUFjd2ZJZGJoOFZhZWMzZmdhYWFJZGJhUmFBY2xmSWRiZzhYTjp0VWRiYWVjYWZnYWFhSWRiYVJhOFZOOnRVZGJhZWM4S2ZnYUlkYmg4MWE4RmE4WWFSTVVkYmFhYTgxYVJhOFZhOFZOYThXYThXTmE4WGE4WE5NTU5NVWRia2FYY2xmaFhhS2NsZmhLYWVjOFNmaGVhQWN4ZmhBYWxhSGNlZmdIOWhtYmtrZG5hZFRtYmNiaDhBYWJoYWluYWJhOEFjZHRmaDhGY2JoSGluYVlhOEZhSGM6RzpHOmNqYmZ5ZGJjZHRmeWRiZ0FmUmJiaGVkbmRuYVlhYWFIZnlkYmdYZlJiYmdLYzk5ZmNGZUdjcGUwbWJhZWM5OWZjRmVHYzs6ZTZtZWtkbmFLY3VmY0ZlR2NlMG1iYTVhWGNkdGZ5ZGJhQTlobWVrZG5hZWN1ZmNGZUdjZTBtYmE4RWFBY2R0ZnlkYmFYOWhtZWtKYmJhY0piYmFjSmJiYlphZWNGZUdjZVNFYUtjRmVHY2VTRWhVZG5hOE5hOEZhSGM6SzpHOmNqYmZ5ZGJjZHRmeWRiY3gyZmdlSWR3YThOYVhjeDJmZ0tJZHdnODY6dGc4U2E4TmFBY3gyZmdoSWR3YTg2OnRnOFhhOFhOYWhJZGJhS0lkYmc4VTp0ZzgwYTgwTmFoSWRsYUtJZGxnOFo6dGc4VmE4Vk5NTWc4MU5hOFhhOFNhOFhOYWVJZGJhOFU6dGc4M2E4ME5hOFZhZUlkbGE4Wjp0Zzg1Tk1NZzhXTjp0ZzhZYThZTmE4M2E4MU5hODBhOFdOOnRnUmFSTmE4NWE4MU5hOFZhOFdOOnRnOFdhOFdOTU1nQkpiYmJiOUVUbWJhOFlhQjpyZ0I6dmg4WWE4V2FCOnZoOFdhUmFCOnZoUmthVWE4MTpyTmdCYThZYTg2TmFSYThVTmE4WmE4V05NTTptZzgxTmc4N2E4MU5oODhhODBhODVOYThWYTgzTjp0ZzgxYTgxTmE4VmE4U05hOFhhODVOOnRnOFZhOFZOYThYYTgzTmE4MGE4U046dGc4WGE4WE5NTWc4MzpyaDgwYThZYTg3Tmg4NWE4V2E4N05oODlhUmE4N05oODdhOFdhQmE4WU5nOFNOaDg6YThTYVJOaFphUmFCYThXTmduTmhjYThZYThTTmg4WWE4V2FuTmg4V2FSYUJhUk5OaDhTZG5hODNKYmJiYjlFVG1iYTgxYTgwOnZoODFhOFhhODA6dmg4WGE4VmE4MDp2aDhWa2FJYU9hWGNkdGZ5ZGJjOFMyZmdlYWVJZGJhOFNhOFZhVWE4MDpyTmdSYThWTk5NZzgwTVVkYmFlYThXYThYYVJhOFhOZzhTTk1nODNhZUlkbE1VZGxhZWE4WWE4MWFSYTgxTmc4V05NZzhZYWVJZHdNVWR3YWVhY2E4VmE4U05NZzhTYWVJZHhNVWR4YWVhWmE4V2E4Vk5NZ1VhZUlkek1VZHphZWE4OmE4WGE4V05NZzhXYWVJZENNVWRDYWVhODdhOFZhUmE4MWE4Nk5hOFZhOFVOYThaYThYTk1NZzg2Om1OZ1JOTWc4VmFlSWRLTVVkS2FlYTg5YThYYVJOTWc4WGFlSWQzTVVkM2FlYTg1YTgxYVJOTWc4MWFlSWRhTVVkYWFlYTg4YTg2YVJOOnRnUmFlSWQ4S01VZDhLYWVhQmFlSWR5TVVkeWFJYU9hQWNkdGZ5ZGJjOFMyZmdlYTgwYWVJZGJNVWRiYWVhODNhZUlkbE1VZGxhZWE4WWFlSWR3TVVkd2FlYThTYWVJZHhNVWR4YWVhVWFlSWR6TVVkemFlYThXYWVJZENNVWRDYWVhOFZhZUlkS01VZEthZWE4WGFlSWQzTVVkM2FlYTgxYWVJZGFNVWRhYWVhUmFlSWQ4S01VZDhLYWVhQmFlSWR5TVVkeWthSGNsZmdIY3g5aG1ia2FhY3hmaGFhOEFjaWZnOEFhZDZtYmthQ1RtYmNiaGFpbkpiYmJiaDgwYThOYWJhYWNkdGZnZWNsZnlkYmc4RmN4MmZnSElkd2E4TmFleWRiZ2hjeDJmZ0FJZHdnOFo6dGc4VmE4Vk5hSElkYmFBSWRiZzgzOnRnOFdhOFdOYUhJZGxhQUlkbGc4NTp0ZzhYYThYTk1NZzhTYThOYWVjd2Z5ZGJnOEFjeDJmZ2VJZHdhOFo6dGc4WU5hOFZhOFlOYThXYWVJZGJhODM6dGc4MU5hOFhhZUlkbGE4NTp0Z0JOTU1nUmE4Vk46dEpiYmJiSmJialphOFNhOFlhOFlOYTgxYTgxTmFCYUJOTU1nOFVOYVJhUk46dGc4Njp2YTg2SmJiYmI5QkVnODZOaDg4YThVYThWTmFSYThZTjp0YTg2Tmg4OWE4U2FCTmFSYThYTjp0YTg2Tmg4OmE4VWE4WE5hUmFCTjp0YTg2TmhaYThTYTgxTmFSYThXTjp0YTg2TmhuYThVYThXTmFSYTgxTjp0YTg2TmhjYThXYUJOYThYYTgxTjp0Z1JhUk5hOFhhOFlOYThWYUJOOnRnUmFSTmE4VmE4MU5hOFdhOFlOOnRnUmFSTk1NOnJKYmJiWk5oUmE4UGFoYUMyZzhKY2R0ZmhIYThQYThBYUMyZ0RjZHRmaEFhOFBhOEZhQzJnOEtjZHRmaFhhOFo6bWg5Y2E4NTptaEphODM6bWg5ZWFzY2pkZmhlYUNoS0piYmJiaEJKYmJiYmg4NkpiYmJiaDhTSmJiYmJoOFVKYmJiYmg4WkpiYmJiaDgzSmJiYmJoODVKYmJiYmg4N0piYmJiaFVpbmFlY3dmYVJhODlhWElkYmFISWRiZzhZOnRnOFhOYTg4YUFJZGJhOFk6dGc4MU5NZzhWTlVkYmFlY2xmYVJhWmE4WE5hODphODFOTWc4V05VZGJhZWFSYWNhOFhOYW5hODFOTWc4WE5VZGJhZWN4ZmFSYTljYThWTmFKYThXTmE4WWE5ZWE4WE5NTU1nOFlOVWRiYVJhOFZhOFdOTmE4Wk1oOFphUmE4VmE4WE5OYThVTWg4VWFSYThXYThYTk5hOFNNaDhTYVJhOFlhOFlOTmFVTWhVYVJhOFZhOFlOTmE4N01oODdhUmE4V2E4WU5OYTg1TWg4NWFSYThYYThZTk5hODNNaDgzYVJhOFZhOFZOTmE4Nk1oODZhUmE4V2E4V05OYUJNaEJhUmE4WGE4WE5OYTgwTWg4MGFIY2xmaEhhWGNsZmhYYUFjbGZoQWFlY3pmaGVhS2N1ZmdLbWJrYWdhaGM4UzJmZ2VhODBhZUlkYk1VZGJhZWFCYWVJZGxNVWRsYWVhODZhZUlkd01VZHdhZWE4U2FlSWR4TVVkeGFlYThVYWVJZHpNVWR6YWVhOFphZUlkQ01VZENhZWE4M2FlSWRLTVVkS2FlYTg1YWVJZDNNVWQzYWVhODdhZUlkYU1VZGFhZWFVYWVJZDhLTVVkOEthZWFSYWVJZHlNVWR5YWdhOEZjOFMyZmdlYTgwYWVJZGJNVWRiYWVhQmFlSWRsTVVkbGFlYTg2YWVJZHdNVWR3YWVhOFNhZUlkeE1VZHhhZWE4VWFlSWR6TVVkemFlYThaYWVJZENNVWRDYWVhODNhZUlkS01VZEthZWE4NWFlSWQzTVVkM2FlYTg3YWVJZGFNVWRhYWVhVWFlSWQ4S01VZDhLYWVhUmFlSWR5TVVkeWFnYThBYzhTMmZnZWE4MGFlSWRiTVVkYmFlYUJhZUlkbE1VZGxhZWE4NmFlSWR3TVVkd2FlYThTYWVJZHhNVWR4YWVhOFVhZUlkek1VZHphZWE4WmFlSWRDTVVkQ2FlYTgzYWVJZEtNVWRLYWVhODVhZUlkM01VZDNhZWE4N2FlSWRhTVVkYWFlYVVhZUlkOEtNVWQ4S2FlYVJhZUlkeU1VZHlhOFJhOEpjbHRmaDhGY2JoSGFDaFhpbmE4RmFIZmdlYXNjamRmYUhmZ0FJZGJhZUlkYk1VZGJhZWNsZmdLYUFjbGZJZGJhS0lkYk1VZGJhZWN3ZmdLYUFjd2ZJZGJhS0lkYk1VZGJhZWN4ZmdlYUFjeGZJZGJhZUlkYk1VZGJhSGN6ZmhIYVhjdWZnWG1ia2E4UmE4S2NsdGZoOEZjYmhIYUNoWGluYThGYUhmZ2Vhc2NqZGZhSGZnQUlkYmFlSWRiTVVkYmFlY2xmZ0thQWNsZklkYmFLSWRiTVVkYmFlY3dmZ0thQWN3ZklkYmFLSWRiTVVkYmFlY3hmZ2VhQWN4ZklkYmFlSWRiTVVkYmFIY3pmaEhhWGN1ZmdYbWJrYThSYURjbHRmaDhGY2JoSGFDaFhpbmE4RmFIZmdlYXNjamRmYUhmZ0FJZGJhZUlkYk1VZGJhZWNsZmdLYUFjbGZJZGJhS0lkYk1VZGJhZWN3ZmdLYUFjd2ZJZGJhS0lkYk1VZGJhZWN4ZmdlYUFjeGZJZGJhZUlkYk1VZGJhSGN6ZmhIYVhjdWZnWG1ia2FhY2lmZ2FhZDZtYmtrY2JoQWRuZG5hbWN3R2dUbWJKYmJiYmg4U2NiaFNjYmg5aGNiaDlpeGVrY2JoU2EzY2J5ZDE6SDpjamJIampqamJiaDlpYXNjOkNlZmFzeWQ7OGVnZWNkdGZhOWlCZGJhc2FlY2VmQmQ7OGVjdWE5aWFsYWJhZGFPejpmampqYmdYY2x0YVhjampqamlHRWNieWQxOkg6Y2piSGpqampiYmg5aGFzYzpDZWZhc3lkOzhlZ2VjZHRmYTloQmRiYXNhZWNlZkJkOzhlYTloYVhhOWlhOE5hbHo6Z2pqamJKRkZ1dWg4U2FYVG1iYTloaGVhWGhIaW5hZUlkYmdSYThTYThTYVI5RUVoOFNhZWNsZmhlYUhjdWZnSG1ia2FYaFNrZG5hbFRtYmFMY2xmaGVhTHlkYmhYYVloSGFsaEtjYmhBaW5jYmFleWRiZzhGYVg5UmFIUmJiY3BlR0VhQWZoQWFIY2VmaEhhZWNsZmhlYThGaFhhS2N1ZmdLbWJrYUFjZTRoQWtjdWFkYUE5UmNpZmc2Y3gyYTZjO3Y6UTt2OlFlMEVjYnlkMTpIOmNqYkhqampqYmJoOWthc2M6Q2VmYXN5ZDs4ZWdlY2R0ZmE5a0JkYmFzYWVjZWZCZDs4ZWN1YTZjZHRhNmNGRkZGaTBFY2J5ZDE6SDpjamJIampqamJiaDBhc2M6Q2VmYXN5ZDs4ZWdlY2R0ZmEwQmRiYXNhZWNlZkJkOzhlYTNjYnlkMTpIOmNqYkhqampqYmJoOW1hc2M6Q2VmYXN5ZDs4ZWdlY2R0ZmE5bUJkYmFzYWVjZWZCZDs4ZWFsY2J5ZDE6SDpjamJIampqamJiaDluYXNjOkNlZmFzeWQ7OGVnZWNkdGZhOW5CZGJhc2FlY2VmQmQ7OGVheGF4TmF5SmJialphbWNsR0VnWmFaTjp2aDg3SmJiYmJoVWRuYWRhazlubWJkbmE2Y2k2bWJhQ2NsdGg5b2E5a2N3Zmg5cEpiYmJiaDg1SmJiYmJoVWluYXNjTmVmYWJhZGFsYU96OmNqampiYWJoOEFjYmg5cWNiaDlyaW5hYmE5cmNkdGZoRGNiaGVpbmRuYU9hOEFhZWZ5ZGJnQWNkdGdoZnlkYmdYYU9hRGFlYzpXOkc6Y2piZnlkYmNkdGZ5ZGJnSGNkdGc4SmZ5ZGJnS1NtYmFZYUhmUmJiZ2FjdjJhWWFBZlJiYmc4RmZSYjthOkc6Y2piZzhMYThGY3YyYWFmZzhLUmI7YTpHOmNqYmczVmNGZUdUbWJkbmFLYVg5bm1iYThLUmI7RzpHOmNqYmNGZUdtZWtkbmE4RmN1ZmNGZUdjZTBtYmFhVG1iYTVhaGZ5ZGJhSDlobWVrZG5hOEZUbWJhYWN1ZmNGZUdjZTBtYmE4RWE4SmZ5ZGJhQTlobWVrYTlrYTlxY3gyZmdYYUhhQWEzY0ZlR2dLRUJkbGFYYUFhSGFLRUJkYmFYYUthOExHY2I5aEJkd2E5cWNlZmg5cWthZWNsZmdlY3g5aG1ia2RuYTlyY2lmZzlyYWQ5cG1iYThBY3hmaDhBYTlxY2lmYTY5bm1la2thOXFUbWRjYmg4S2luYUlhT2E5a2E4S2N4MmZnaHlkYmdLY2R0Z1hmeWRiZzhBYzhTMmZnZUlkd2E4TmFoeWRsZzhGY3gyZmdISWR3ZzhXTmFlSWR6YUhJZGJnOFhOYWVJZGFNZ1JhUk1NYThXTmFlSWRsYUhJZGxnOFlOYWVJZENhOFdOYWVJZDNNZ1JhUk1NYThZTmFlSWRiYThYTmFlSWR4YThZTmFlSWRLTWdSYVJNTWE4WE5hZUlkOEtNTU06bGhSSmJiYmJKYmJqWmFlSWR5ZzhWOnZhOFZKYmJiYjlCRWg4VmRuZG5haHlkd2dEbWJKRkZ1dWg4Nnhla0piYmJiSmJialphSWFPYThGY2R0ZnlkYmM4UzJmZ2VJZHlnODE6dmE4MUpiYmJiOUJFYWVJZHdhOE5hS2N4MmZnSElkd2c4MU5hZUlkemFISWRiZzgwTmFlSWRhTWdCYUJNTWE4MU5hZUlkbGFISWRsZ0JOYWVJZENhODFOYWVJZDNNZzgxYTgxTU1hQk5hZUlkYmE4ME5hZUlkeGFCTmFlSWRLTWc4MWE4MU1NYTgwTmFlSWQ4S01NTTpsTmg4NmthOFZhUk5oQmRuYUNUbWJhZ2FLYzhTMmZnQUlkd2E4V05hQUlkemE4WE5hQUlkYU1nUmFSTU1hOFdOYUFJZGxhOFlOYUFJZENhOFdOYUFJZDNNZ1JhUk1NYThZTmFBSWRiYThYTmFBSWR4YThZTmFBSWRLTWdSYVJNTWE4WE5hQUlkOEtNTU1oUmE4UGE4RmFDMmdhY2R0ZmhIYThSYUthQzJnOEpjbHRmaGVhQUlkeWg4MWFDaEFpbmFISWRiZzhWYThWYTgxTmFlY3hmSWRiYThXYWVjd2ZJZGJOYThYYWVJZGJOYThZYWVjbGZJZGJOTU1NZzhWYThWTTp0TmFSTWhSYUhjbGZoSGFlY3pmaGVhQWN1ZmdBbWJrZG5kbmFEbWJKYmJiYmg4Vnhla2FnYThGYzhTMmZnQUlkd2E4TmFLY3gyZmdlSWR3ZzhYTmFBSWR6YWVJZGJnOFlOYUFJZGFNZzhWYThWTU1hOFhOYUFJZGxhZUlkbGc4MU5hQUlkQ2E4WE5hQUlkM01nOFZhOFZNTWE4MU5hQUlkYmE4WU5hQUlkeGE4MU5hQUlkS01nOFZhOFZNTWE4WU5hQUlkOEtNTU1oOFZhOFBhOEpjZHRmaEhhOFJhYWNsdGZoZWFBSWR5aDgwYUNoQWluYUhJZGJnOFdhOFdhODBOYWVjeGZJZGJhOFhhZWN3ZklkYk5hOFlhZUlkYk5hODFhZWNsZklkYk5NTU1nOFdhOFdNOnROYThWTWg4VmFIY2xmaEhhZWN6ZmhlYUFjdWZnQW1ia2E4VjpsaDhWa2FCYVI6bE1oQmE4NmE4Vk1oODZkbmRuZG5hWWFLZlJiYmM5OmZQZGRiZWthUWFYZnlkYmdYYUtTbWJhT2E4RmNkdGZ5ZGJoOEppbmRuZG5hNWFYY2R0Z2FmeWRiZ2VjdVNtYmFPYWVjZHRmeWRiYThKU21la2RuYThFYWFmeWRiZ2VjdVNtYmFPYWVjZHRmeWRiYThKU21la2E4Rmhla2FnYVhjOFMyZmdBSWR3YThOYWVjeDJmZ0hJZHdnOFdOYUFJZHphSElkYmc4WE5hQUlkYU1nUmFSTU1hOFdOYUFJZGxhSElkbGc4WU5hQUlkQ2E4V05hQUlkM01nUmFSTU1hOFlOYUFJZGJhOFhOYUFJZHhhOFlOYUFJZEtNZ1JhUk1NYThYTmFBSWQ4S01NTWhSYThQYWVhQzJjZHRmaEhhOFJhWGFDMmNsdGZoZWFBSWR5aDgxYUNoQWluYUhJZGJnOFZhOFZhODFOYWVjeGZJZGJhOFdhZWN3ZklkYk5hOFhhZUlkYk5hOFlhZWNsZklkYk5NTU1nOFZhOFZNOnROYVJNaFJhSGNsZmhIYWVjemZoZWFBY3VmZ0FtYmthQmFSOmxNaEJhUWFhZnlkYmdYYUs5aG1ia2thWWE4RmZSYmJjaTlobWVhRFRtZWFRYThGY2R0ZnlkYmdYYThGU21laW5kbmRuYTVhWGNkdGdhZnlkYmdlY3VTbWJhT2FlY2R0ZnlkYmE4QVNtZWtkbmE4RWFhZnlkYmdlY3VTbWJhT2FlY2R0ZnlkYmE4QVNtZWthS2hla2FnYVhjOFMyZmdBSWR3YThOYWVjeDJmZ0hJZHdnOFdOYUFJZHphSElkYmc4WE5hQUlkYU1nUmFSTU1hOFdOYUFJZGxhSElkbGc4WU5hQUlkQ2E4V05hQUlkM01nUmFSTU1hOFlOYUFJZGJhOFhOYUFJZHhhOFlOYUFJZEtNZ1JhUk1NYThYTmFBSWQ4S01NTWhSYThQYWVhQzJjZHRmaEhhOFJhWGFDMmNsdGZoZWFBSWR5aDgxYUNoQWluYUhJZGJnOFZhOFZhODFOYWVjeGZJZGJhOFdhZWN3ZklkYk5hOFhhZUlkYk5hOFlhZWNsZklkYk5NTU1nOFZhOFZNOnROYVJNaFJhSGNsZmhIYWVjemZoZWFBY3VmZ0FtYmthODZhUjpsTWg4NmFRYWFmeWRiZ1hhOEY5aG1ieGRra2RuYThFYTVhNWFYZnlkYmE4RlNFYVFhWGZ5ZGJnYWNkdGZ5ZGJnWGN1OWhtYmFRYThGY2R0ZnlkYmhYa2FnYWFjOFMyZmdBSWR3YThOYVhjeDJmZ2VJZHdnOFdOYUFJZHphZUlkYmc4WE5hQUlkYU1nUmFSTU1hOFdOYUFJZGxhZUlkbGc4WU5hQUlkQ2E4V05hQUlkM01nUmFSTU1hOFlOYUFJZGJhOFhOYUFJZHhhOFlOYUFJZEtNZ1JhUk1NYThYTmFBSWQ4S01NTWhSYThQYVhhQzJnOEFjZHRmaEhhOFJhYWFDMmc4SmNsdGZoZWFBSWR5aDgxYUNoQWluYUhJZGJnOFZhOFZhODFOYWVjeGZJZGJhOFdhZWN3ZklkYk5hOFhhZUlkYk5hOFlhZWNsZklkYk5NTU1nOFZhOFZNOnROYVJNaFJhSGNsZmhIYWVjemZoZWFBY3VmZ0FtYmtkbmRuYURtYkpiYmJiaDhWeGVrYWdhWGM4UzJmZ0FJZHdhOE5hYWN4MmZnZUlkd2c4WE5hQUlkemFlSWRiZzhZTmFBSWRhTWc4VmE4Vk1NYThYTmFBSWRsYWVJZGxnODFOYUFJZENhOFhOYUFJZDNNZzhWYThWTU1hODFOYUFJZGJhOFlOYUFJZHhhODFOYUFJZEtNZzhWYThWTU1hOFlOYUFJZDhLTU1NaDhWYThQYThKY2R0ZmhIYThSYThBY2x0ZmhlYUFJZHloODBhQ2hBaW5hSElkYmc4V2E4V2E4ME5hZWN4ZklkYmE4WGFlY3dmSWRiTmE4WWFlSWRiTmE4MWFlY2xmSWRiTk1NTWc4V2E4V006dE5hOFZNaDhWYUhjbGZoSGFlY3pmaGVhQWN1ZmdBbWJrYThWOmxoOFZrYUJhUjpsTWhCYTg2YThWTWg4NmthaGE4NmFCYTg2YUI5RGdlRVVkd2FoYUthOEZhZWFEY2I5aEdnZUVCZGxhaGE4RmFLYWVFQmRiYThLY2VmZzhLYTlxOWhtYmthc2NqZGZjYmNqO3Fiejp0ampqYjhBYTlwaGVhOXFoSGluYXNjamRmYWV5ZGJjQTRjRjhGR2dBY0ZBYUFjRkE2RWNkdGZnQWFBeWRiY2VmQmRiYWVjeGZoZWFIY3VmZ0htYmtjYmhlY2JoSGluYXNjamRmYWVmZ0F5ZGJoWGFBYUhCZGJhWGFIZmhIYWVjbGZnZWNqO3FiOWhtYmtjYmhlYTlwaEhpbmFzY2pkZmFIeWRiY0E0Y0Y4RkdnQWNGQWFBY0ZBNkVjZHRmZ0FhQXlkYmdBY2VmQmRiYTBhQWNkdGZhZUJkYmFIY3hmaEhhOXFhZWNlZmdlOWhtYmthZGFrOVJnQWNpOVVoOXNkbmFsVG1iY2JoZWE5bWhIaW5hSGFlQmRiYUhjbGZoSGFsYWVjZWZnZTlobWJra2NiaDl0YTluY2JhbHo6dGpqamJoM2FBY085VWg5dWE5c2NlNGg5cmNiaDhMY2JoOEtkbmluYTlrYTBhOEtjZHRmeWRiY3gyZmc4Sklkd2dSYTg3OUVtZWE4TGE5czlwbWVKRkZ1dWg4VmRuYTlyYTlxOXBtYmE5a2EwYTlyY2R0ZnlkYmN4MmZJZHdKYmI7YVpOaDhWa2RuYVJhOFY5RVRtYmFSYVU5RVRtYmE4TGE5dTBtZGtkbmEzYU9hOEp5ZGxnRGNkdGc5dmZnOEF5ZGJnQWZnOXdSYmJhM2FPYThKeWRiZ2hjZHRnOXhmeWRiZ2VmZzl5UmJiVm1iYVlhaGZSYmJoOXpkbmRuYUxhZWNkdGZnSGNsZnlkYmdYYUh5ZGJnSFNtYmFYYUg5UmhYYThOYUFjeDJmaDhGYThOYWVjeDJmaGFhRWFIY2l0ZmhlaW5kbmE5bWFleWRiY2R0ZnlkYmdIYUFTbWJhOW1hZWNsZnlkYmNkdGZ5ZGJnS2FBU21iYUhhS1NtYmE4TmFLY3gyZmdLSWRiYThOYUhjeDJmZ0hJZGJnOFc6dGdSYWFJZGxhSElkbGc4WDp0ZzgwTmFLSWRsYThYOnRnOFZhYUlkYmE4Vzp0Z0JOOnRnOFlhUmE4RklkbGE4WDp0Zzg2TmE4VmE4RklkYmE4Vzp0ZzhVTjp0ZzhYTmE4VmFhSWR3YUhJZHdnODE6dGc4Wk5hS0lkd2E4MTp0ZzhXYTgwTjp0ZzgwYThWYThGSWR3YTgxOnRnODNOYThXYTg2Tjp0ZzhWTmE4V2FCTmFSYThaTjp0ZzgxYThXYThVTmFSYTgzTjp0Z1JOTU1hOFlhOFlOYTgwYTgwTmE4MWE4MU5NTWE4WGE4WE5hOFZhOFZOYVJhUk5NTU46ckpiYmo4Ok45Rm1pa2FlY3dmaGVhWGN1ZmdYbWJra2RuZG5kbmRuYTl6Yzk6ZlBkZWJka2FoaGVpbmE4QXlkYmhBZG5kbmE1YWVjZHRnSGZ5ZGJnZWN1U21iYU9hZWNkdGZ5ZGJhQVNtZWtkbmE4RWFIZnlkYmdlY3VTbWJhT2FlY2R0ZnlkYmFBU21la2FEaGVrYTltYUhmYWVCZGJhUWFIZnlkYmdlYWg5aG1ieGlra2RuYThFYTVhNWE5eGZ5ZGJhRFNFYVFhOXhmeWRiZ2hjZHRmeWRiZ2VjdTlobWJhUWE5dmZ5ZGJoZWthOW1hOXhmYURCZGJhZWhEa2E5bWFoY2R0ZmFEQmRia2E5eWNlODZiYmE5d2NlODZiYmE4Sklkd2dSYVVhVWFSOURFaFVhOXRjZWZoOXRjZWNkYTl6Y2VTRWE4TGZoOEx4ZWthOXJjZWZoOXJrYThLY2VmZzhLYTlxOWhtYmtrYTl0VG1kZG5hbFRtYmNiaDhGY2JoaGluZG5hOW1haGNkdGdlZnlkYmdBYWhTbWJhT2FBY2R0ZnlkYmg4QWRuYWhhT2FlZnlkYjloZzhKbWJhSWE4QWM4UzJmZ2VhSWFoYzhTMmZnSElkYmFlSWRiTVVkYmFlYUhJZGxhZUlkbE1VZGxhZWFISWR3YWVJZHdNVWR3YWVhSElkeGFlSWR4TVVkeGFlYUhJZHphZUlkek1VZHphZWFISWRDYWVJZENNVWRDYWVhSElkS2FlSWRLTVVkS2FlYUhJZDNhZUlkM01VZDNhZWFISWRhYWVJZGFNVWRhYWVhSElkOEthZUlkOEtNVWQ4S2FlYUhJZHlhZUlkeU1VZHlhOE1UbWJhOE1hOEFjbHRmZ2VhOE1haGNsdGZnSElkYmFlSWRiTVVkYmFlYUhJZGxhZUlkbE1VZGxhZWFISWR3YWVJZHdNVWR3YWVhSElkeGFlSWR4TVVkeGthQ1RtYmFnYUFjOFMyZmdlYWdhaGM4UzJnRGZnSElkYmFlSWRiTVVkYmFlYUhJZGxhZUlkbE1VZGxhZWFISWR3YWVJZHdNVWR3YWVhSElkeGFlSWR4TVVkeGFlYUhJZHphZUlkek1VZHphZWFISWRDYWVJZENNVWRDYWVhSElkS2FlSWRLTVVkS2FlYUhJZDNhZUlkM01VZDNhZWFISWRhYWVJZGFNVWRhYWVhSElkOEthZUlkOEtNVWQ4S2FlYUhJZHlhZUlkeU1VZHlhOW9hQTJoYWE4UmhIYUNoWGluYUhhYWZnZWFIYThGZmdBSWRiYWVJZGJNVWRiYWVjbGZnS2FBY2xmSWRiYUtJZGJNVWRiYWVjd2ZnS2FBY3dmSWRiYUtJZGJNVWRiYWVjeGZnZWFBY3hmSWRiYWVJZGJNVWRiYUhjemZoSGFYY3VmZ1htYmthOEptYkpiYmJiSmJialphSWFEZmdlSWR5Z1I6dmFSSmJiYmI5QkVhZUlkd2E4TmE4QWN4MmZnSElkd2dSTmFlSWR6YUhJZGJnOFZOYWVJZGFNZzhXYThXTU1hUk5hZUlkbGFISWRsZzhXTmFlSWRDYVJOYWVJZDNNZ1JhUk1NYThXTmFlSWRiYThWTmFlSWR4YThXTmFlSWRLTWdSYVJNTWE4Vk5hZUlkOEtNTU06bE5nUmE4NWE4NWFSOURFaDg1a2E4RmE5b2ZoOEZhaGNlZmdoYWw5aG1ia2NiaEhhNWhlaW5kbmFleWRiZ0FjdVNtYmRuYUhhOW1hQWNkdGdYZnlkYmdBOWhtYmN1aEFhNWFYZnlkYmdYY3VTbWJhOW1hWGNkdGZ5ZGJoQWthZWFBQmRia2FlY2xmaGVhbGFIY2VmZ0g5aG1ia2NiaEhhOEVoZWluZG5hZXlkYmdBY3VTbWJkbmFIYTltYUFjZHRnWGZ5ZGJnQTlobWJjdWhBYThFYVhmeWRiZ1hjdVNtYmE5bWFYY2R0ZnlkYmhBa2FlYUFCZGJrYWVjbGZoZWFsYUhjZWZnSDlobWJra2E4NWFVYUNFaDg1Y2JoSGFiaGVjYmhBaW5kbmFPYTltYWV5ZGJjZHRmeWRiZzhGY2R0ZnlkYmdYYU9hOW1hZWNsZnlkYmNkdGZ5ZGJnYWNkdGZ5ZGJnS1NtYmFYYU9hOW1hZWN3ZnlkYmNkdGZ5ZGJnOEFjZHRmeWRiZ2hTbWJhS2FoU21iYWJhSGNkdGZnWGE4RkJkYmFYY3dmYThBQmRiYVhjbGZhYUJkYmFIY2lmaEhrYWVjeGZoZWFBY2lmZ0FhZDZtYmtkbmRuYVRtYmFIaGR4ZWtkbmFIYWswbWJhSGhkeGVrZG5hOFNhODU5Rm1iYUhoZHhla0pGRnV1aDhTY2JoZGFiaGVjYmhBaW5kbmE5aGE5aWFleWRiZ1hjZHRmeWRiY2R0ZklkYmdSYTg1OUVUbWJhZWNsZjhQZGJoOUFhYmFkY2R0ZmdLYVhCZGJhS2NsZmE5QTgzZGJhUmE4U2E4U2FSOUVFaDhTYWRjaWZoZGthZWN4ZmhlYUFjaWZnQWFINm1ia2thZGFrMG1ieGRra2FzY05lZmFiYWRhbGFPejpjampqYmtkbmRuYWRhazBtYmFkaGF4ZWtkbmFUbWJhZGhheGVrZG5hOFNhODc5Rm1iYWRoYXhla2NlaEtpbmE4U0piYjthWk5nUmE4N2FSYTg3OURFaDhXSmJiYmJoUmRuYVNUbWJhOWhoZWFTaEhpbmFlSWRiZzhWYVJhOFZhOFc5RkVhUmE4VmFSOUVFaFJhZWNsZmhlYUhjdWZnSG1ia2tKRkZ1dWg4U2NiaGFhYmhlY2JoSGluZG5hOWhhOWlhZXlkYmdBY2R0ZnlkYmNkdGZJZGJnOFZhOFc5RVRtYmFlY2xmOFBkYmg5QWFiYWFjZHRmZ1hhQUJkYmFYY2xmYTlBODNkYmE4VmE4U2E4U2E4VjlFRWg4U2FhY2lmaGFrYWVjeGZoZWFIY2lmZ0hhZDZtYmtkbmFLYWFhZDloVmNlR21iYWRoYXhka2FSYVVhVWFSOURFaFVhYWFrOW5tZWNiaEthYWhkYThTYTg3OUZtYmtrZG5hbWNqampqZEdUbWJhOW5jYmFsejp0ampqYmg4QWRuYWFUbWJhYmhlYWFoSGluYThBYWV5ZGJnQWZjZTg2YmJhOEFhT2FBY2R0ZnlkYmZjZTg2YmJhZWNsZmhlYUhjdWZnSG1ia2thc2NOZWZhYmFhYWxhT3o6Y2pqamJkbmRuYWxUbWJjYmhYaW5kbmE4QWFYZlJiYlRtYmRuYVlhWGZSYmJnZWNsMG1iY2VhZXRjUUdtZWtkbmFPYVhjZHRnOEZmeWRiZ2VhWFNtYmE4TmFYY3gyZmdIYThOYWVjeDJmZ2V5ZHdCZHdhSGFlOFBkYjgzZGJ4ZWthSWFYYzhTMmZnS0lkeWdjYWNKTDozO3JVTmdSTWg4N2FLSWR3ZzlCYVJNaDhTYUtJZGxnOUNhUk1oOFVhS0lkYmc5RGFSTWg4MWFLSWRhZzlFYVJhOE5hWGN4MmZnOEpJZHdnODhOOnRoOFphS0lkM2c5RmFSYThKSWRsZzg5Tjp0aDgzYUtJZEtnOUdhOEpJZGJnODphUk46dGg4MEpiYmJiaG5hS0lkQ2c5SEpiYmJiTWg4NWFLSWR6ZzlJSmJiYmJNaEJhS0lkeGc5SkpiYmJiTWg4NmRuZG5hQ1RtYmFYaEFpbkpiYmJiYTg3YWdhQWM4UzJmZ0hJZHlnUjp2YVJKYmJiYjlCRWhSYThSYUFhQzJjbHRmaGVhSElkYWE4N05hOFpNaDhaYUhJZDNhODdOYTgzTWg4M2FISWRLYTg3TmE4ME1oODBhSElkQ2E4N05hODVNaDg1YUhJZHphODdOYUJNaEJhSElkeGE4N05hODZNaDg2YUhJZHdhODdOYThTTWg4U2FISWRsYTg3TmE4VU1oOFVhSElkYmE4N05hODFNaDgxYUNoSGluYThaYWVjd2ZJZGJnOFZhZWN4ZklkYmc4WU5hUk46dGg4WmE4M2FlY2xmSWRiZzhXYThZTmFSTjp0aDgzYTg1YThXYThWTmFSTjp0aDg1YTgxYWVJZGJnOFhhOFhOYVJOOnRoODFhODBhOFhhOFlOYVJOOnRoODBhQmE4WGE4Vk5hUk46dGhCYTg2YThYYThXTmFSTjp0aDg2YThTYThWYThWTmFSTjp0aDhTYThVYThXYThXTmFSTjp0aDhVYWVjemZoZWFIY3VmZ0htYmthUWFBY2R0ZnlkYmdBYVg5aG1ia2E4TVRtYmE4TWFYY2x0ZmdlSWR4aHhhZUlkd2g5Y2FlSWRsaEphZUlkYmhSeGVrSmJiYmJoeEpiYmJiaDljSmJiYmJoSkpiYmJiaFJrYUJhODE6dmc4V2E4ME5hOFo6dGE4NWFCYTg2YTgxOnZnOFZOOnRnOFphOFVhODZhOFZOOnRnOFk6dmc4WGE4VmE4ME5hODM6dGc4VU46dGg4M2E5Y2FSYThXTjp0YUphUmE4Vk46dGc4NmE4WE46dGc4NWE4U2FCYThXTjp0YThaYThYTjp0Z0I6dmc4UzptaDhaYTg2YThZOnZnOWM6bWhKZG5KYmJiYmFSYVJhODE6dmc5ZU46dGE4NmE5Y046dGE4NWE4U046dGc4NjpsYTg3Sjo5ODM6ZzgxTmdSOUVUbWJhOFphODNOYUphOFVOYTllYTgwTmF4OnRNTWE4Njp2aG5rYTgxOmxhUjlFVG1iYThZOmxhUjlFVG1iYUI6bGFSOUVUbWJhOWU6bWFuTmE4VzptYThaYW5OYTgzYUI6dk1nQk5hOFY6bWFKYW5OYThYOm1hQk5hOFVhOFk6dk1NZzg1TmE4MDptYTgxOnZNTU1oODdhTGE4RmZnZWNsZnlkYmdIYWV5ZGJnZTlSaGhhRWFlY2l0Zmg4RkpiYmJiaFJkbmFIYWVTZ0RtYkpiYmJiaFJhOEZoZWFoaEFpbmE4TmFlY2xmeWRiY3gyZmdISWR3YTg4OnRnOFZhOFZOYUhJZGJhODo6dGc4VmE4Vk5hSElkbGE4OTp0ZzhWYThWTk1NZzhWYThOYWV5ZGJjeDJmZ0hJZHdhODg6dGc4V2E4V05hSElkYmE4Ojp0ZzhXYThXTmFISWRsYTg5OnRnOFdhOFdOTU1nOFdhUmFSYThXOURFZ1JhUmE4VjlERWhSYWVjd2ZoZWFBY3VmZ0FtYmthUjpyZ1JhUk5oUmthQmE4ODp0ZzhWYThWTmE4N2E4Ojp0ZzhWYThWTmE4NWE4OTp0ZzhWYThWTk1NYVI5RW1iYUtJZDhLaG5kbmFEbWJpbmE4TmE4RmNsZnlkYmN4MmZnZUlkYmE4TmE4RnlkYmN4MmZnSElkYmc4Vzp0Z1JhODlhSElkbGc4WDp0ZzgwTmFlSWRsYThYOnRnOFZhODphOFc6dGc4Nk46dGc4WWFSYTg1YThYOnRnOFNOYThWYTg3YThXOnRnOFVOOnRnOFhOYThWYTg4YUhJZHdnODE6dGc4Wk5hZUlkd2E4MTp0ZzhXYTgwTjp0ZzgwYThWYUJhODE6dGc4M05hOFdhOFNOOnRnOFZOYThXYTg2TmFSYThaTjp0ZzgxYThXYThVTmFSYTgzTjp0Z1JOTU1hOFlhOFlOYTgwYTgwTmE4MWE4MU5NTWE4WGE4WE5hOFZhOFZOYVJhUk5NTU46ckpiYmo4Ok45Rm1kYThGY3dmaDhGYWhjdWZnaG1ia2tKYmJiYkpiYmpaYWM6dmFjSmJiYmI5QkVnUmE5QmFCTmE5SWE4N05hOUVNZzhWYThWTU1hQk5hOUNhODVOYTlIYUJOYTlGTWc4VmE4Vk1NYTg1TmE5RGE4N05hOUphODVOYTlHTWc4VmE4Vk1NYTg3TmFuTU1NOmxOYVJhOUJhODhOYTlJYTg6TmE5RU1nOFZhOFZNTWE4OE5hOUNhODlOYTlIYTg4TmE5Rk1nOFZhOFZNTWE4OU5hOURhODpOYTlKYTg5TmE5R01nOFZhOFZNTWE4Ok5hbk1NTTpsTkpiYjthWk5KOjk4MzpnODFNOUVtYmE4SmFCVWR3YThKYTg1VWRsYThKYTg3VWRia2FYY2VmZ1hhbDlobWJrZG5hQ21iY2JoQ3hka2NiaFhpbmRuYThBYVhmUmJiVG1iYU9hWGNkdGdlZnlkYmFYOWhtYmFZYVhmaGhhUWFlZmg4SmE4TmFYY3gyZmhBYThQYVhhQzJjZHRmaERjYmhFaW5jdWhMZG5haFJiYmNpOWhtYmFYaExhOEp5ZGJnZWFYU21iYThQYUVjZHRnSGZoS2FEYUhmSWRiaFJhWGhMaW5hTGhIY3VoTGRuYUthZWFDMmNkdGZJZGJhUjlDbWJhSGN1U21iYUhoTGFnYWVjOFMyZklkeWFnYUhjOFMyZklkeTlFVG1iYWVoTGthUWFlY2R0ZnlkYmdlYVg5aG1ia2thOFBhRWNkdGZoS2E4UmFFY2x0Zmg4RmFYaGVpbmFLYWVhQzJjZHRmSmJiYmJKYmJqWmFnYWVhTGFMY3VTRWdIYzhTMmZJZHlnUjp2YVJKYmJiYjlCRWE4RmFIYUMyY2x0ZmdISWR3YUFJZHdOYUhJZGJhQUlkYk5hSElkbGFBSWRsTk1NYUhJZHhNTlVkYmFRYWVjZHRmeWRiZ2VhWDlobWJrYUVjZWZnRWFDOWhtYmtrYVhjZWZnWGFsOWhtYnhka2thQ21iY2JoQ2thaWF2YW9hcmF3YUNhbGE4TmE4UGF6YXNheWFzYzFlZmFZYThBYXF6Omhqampia2RuYW1jampqamxHVG1iYXptYmFhVG1iYWJoZWNiaExpbmFZYWV5ZGJnQWZSYmJjM3RoUWFlY3dmZ1h5ZGJoSGNqampqOTRoQ2RuYTVhQWNkdGdFZnlkYmFlY2xmZ0t5ZGJnT1NtYmNqampqOTRjYmE4RWFPY2R0ZnlkYmFBU0VoQ2thZWFRYUNWYUFWQmRiYVlhT2ZSYmJjM3RoOEZjampqajk0aENjampqajk0aFFkbmE1YU9jZHRmeWRiYUhTbWJjampqajk0Y2JhOEVhSGNkdGZ5ZGJhT1NFaFFrYUthOEZhUVZhT1ZCZGJhWWFIZlJiYmMzdGhPZG5hNWFIY2R0ZnlkYmFBU21iY2pqamo5NGNiYThFYUVmeWRiYUhTRWhDa2FYYU9hQ1ZhSFZCZGJhZWN4ZmhlYUxjaWZnTGFhNm1ia2tkbmF6VG1iYWFUbWJhYWhlaW5hYmF6YWJ5ZGJjZHRmeWRiQmRiYWJjbGZoYmFlY3VmZ2VtYmtrZG5hUFRtYmFQYVphVTpyTlVkYmtkbmFzeWQ7OGVnSFRtYmFIY2R0YXNjOkNlZmZjOThmaGVpbmFleWRiY2J5ZDptOkg6Y2piSDpiampqYmJhZWM5OGZoZWFIY3VmZ0htYmtrYXNjajtzYmY4S2pqampiYWFrO1lpZW91YWJ5ZGxodmFieWRiY2xmY2JhaWNkdHo6dGpqamJob2FkY2k5VWhyZG5hZFRtYmRuYWxUbWJhZWh3YWRoRGluYW9hbGF3eWRiY2R0ZnlkYmNkdGZncWFxeWRiY2VmQmRiYXdjbGZod2FEY3VmZ0RtYnhka2thZWh3YWRoRGluYW9hd3lkYmNkdGZncWFxeWRiY2VmQmRiYXdjbGZod2FEY3VmZ0RtYmtrZG5haVRtYmNiaERhb2h3aW5hd3lkYmhxYXdhREJkYmF3Y2xmaHdhcWFEZmhEYWljdWZnaW1ia2tkbmFkY2k2bWJpbmFlY3dmeWRiaHdhZWNsZnlkYmhEYWV5ZGJoaWRuYWxUbWJhbGF3Y2R0ZnlkYmh3YWxhRGNkdGZ5ZGJoRGFsYWljZHRmeWRiaGlrYXZhb2FpY2R0ZmdxeWRiY2l0ZmFEQmRiYXZhcXlkYmNpdGZhd0JkbGFxYXF5ZGJjZWZCZGJhdmFvYURjZHRmZ3F5ZGJjaXRmYXdCZGJhdmFxeWRiY2l0ZmFpQmRsYXFhcXlkYmNlZkJkYmF2YW9hd2NkdGZnd3lkYmNpdGZhaUJkYmF2YXd5ZGJjaXRmYURCZGxhd2F3eWRiY2VmQmRiYWVjeGZoZWFyY3VmZ3JtYmtrYWJ5ZGJjYkJkYms6dG9kRHVlOTlhaWNkNGFpZmhyY2Vod2luYXdnRGNldGh3YURhcjZtYmtjdWFEY2R0Z3JhRGNGRkZGaTBFY2J5ZDE6SDpjamJIampqamJiaHdhb2FveWQ5R2dxY2VmQmQ5R2FvYXFjZHRmYXdCZGJhd2NGZWFyejp0ampqYmhrZG5haVRtYmFsY2Q0aGxhRGN1Zmh4Y2JobWluYW1oRGRuYXZUbWJhdmFtY2R0ZnlkYmhEa2NiYWRhRGFsMmNkdGZnRHlkbGd3YXdjampqajk0U0Vnd2NINGF3N2M6RjpiOkREMmNiYUR5ZGJnd2F3Y2pqamo5NFNFZ3djSDRhdzdjO0Q7TzpCOEoyN2NiYUR5ZHdnRGFEY2pqamo5NFNFZ0RjSDRhRDdjOjNGO044TjI3YXhHaHdhbWNkdGhQZG5kbmRuYXZUbWJha2F3Y2R0ZmdyeWRiZ0RjdVNtZWFkYXZhUGZ5ZGJhbDJjZHRmZ3NJZGJoemNlaHFpbmFxaHJkbmFkYXZhRGNkdGZ5ZGJhbDJjZHRmZ3FJZGJhejlDbWJhcUlkbGFzSWRsOUNtYmFxSWR3YXNJZHc5Qm1sa2FyY2VmaHFha2F3YXJmYXhHZ3djZHRmZ3J5ZGJnRGN1OWhtYnhka2tha2F3Y2R0ZmdyeWRiZ0RjdVNtYmFkYW1hbDJjZHRmZ3NJZGJoemNlaHFpbmFxaHJkbmFkYURhbDJjZHRmZ3FJZGJhejlDbWJhcUlkbGFzSWRsOUNtYmFxSWR3YXNJZHc5Qm1pa2FyY2VmaHFha2F3YXJmYXhHZ3djZHRmZ3J5ZGJnRGN1OWhtYmtrYXJhbUJkYmFtaERrYWJhUGZhREJkYmFtY2VmZ21haTlobWJra2FrY2J5ZDptOkg6Y2piSDpiampqYmJhb2FveWQ5R2N1ZkJkOUdkbmFlVG1iYWlUbWJjYmhEYWVod2luYXdhREJkYmF3Y2xmaHdhaWFEY2VmZ0Q5aG1ia2NiaERhZWh3aW5kbmFEYWJ5ZGJnclNtYmF3YWVhcmNkdGZncnlkYkJkYmFyYURCZGJrYWJjbGZoYmF3Y2xmaHdhaWFEY2VmZ0Q5aG1ia2trOzpvZHZ1djk5OEpqampqYmNhOVJnb2NieWQxOkc6Y2piQmRLYW9jYjhQZGo6RzpjamI4M2l6YW9jYnlkTjpHOmNqYkJkd2FvY2I4UGQ6bTpHOmNqYjgzaWJkbmFkVG1iYWljZDRocmRuYWJtYmRuYWxUbWJjYmh3aW5hZWFsYXdjZHRmeWRiYXIyY2R0ZmhEY2JoaWluYW9jemZhaWZncWFEYWlmSWRiZ2thcUlkYmd4YXhhazlFRVVkYmFvYWlmZ3Fha2FxSWRiZ3hheGFrOURFVWRiYWljbGZnaWN4OWhtYmthd2NlZmd3YWQ5aG1ieGlra2FyY2R0aHdjYmhEaW5jYmhpaW5hb2N6ZmFpZmdxYWVhaWZJZGJna2FxSWRiZ3hheGFrOUVFVWRiYW9haWZncWFrYXFJZGJneGF4YWs5REVVZGJhaWNsZmdpY3g5aG1ia2FlYXdmaGVhRGNlZmdEYWQ5aG1ieGRra2RuYWxUbWJjYmh3aW5hYmF3Y3gyZmdpYWVhbGF3Y2R0ZnlkYmFyMmNkdGZnRElkYlVkYmFpYURJZGxVZGxhaWFESWR3VWR3Y2JoaWluYW9jemZhaWZncWFEYWlmSWRiZ2thcUlkYmd4YXhhazlFRVVkYmFvYWlmZ3Fha2FxSWRiZ3hheGFrOURFVWRiYWljbGZnaWN4OWhtYmthd2NlZmd3YWQ5aG1ieGRra2FyY2R0aGxjYmh3YWVoRGluYWJhd2N4MmZnaWFlYXdhcjJjZHRmZ3FJZGJVZGJhaWFxSWRsVWRsYWlhcUlkd1Vkd2NiaGlpbmFvY3pmYWlmZ3FhRGFpZklkYmdrYXFJZGJneGF4YWs5RUVVZGJhb2FpZmdxYWthcUlkYmd4YXhhazlERVVkYmFpY2xmZ2ljeDlobWJrYURhbGZoRGF3Y2VmZ3dhZDlobWJra0piYmJiYW9JZGJhb0lkemd4OnRna2FrSmJiYmI5REVna2FvSWRsYW9JZENnbTp0Z1BhUGFrOURFZ2thb0lkd2FvSWRLZ1A6dGdzYXNhazlERWhzZG5hYlRtYmFkVG1iSmJiYmJKYmJqWmFzOnZhc0piYmJiOUJFaGtpbmFiYWthYklkYmF4OnROVWRiYWJjbGZnb2FrYW9JZGJhbTp0TlVkYmFiY3dmZ29ha2FvSWRiYVA6dE5VZGJhYmN4ZmhiYWRjdWZnZG1ia2tkbmF2VG1iYXZhUFVkd2F2YW1VZGxhdmF4VWRia2FzazpXbGV3dWRuYWVUbWJjYmh2YWJob2luYW9hdkJkYmFvY2xmaG9hZWF2Y2VmZ3Y5aG1ia2tkbmFpVG1iY2JocmluYWRhcmNkdGZod2NiaERpbmFsYXdhRGNkdGd2eWQ6RzpHOmNqYmNkdGZ5ZGJjZHRmeWRiaG9kbmFsYXdhdmZ5ZGJjZHRmeWRiZ3FhYmFxY2R0ZmdreWRiZ3ZTbWJpbmFrYWJhdmdxY2R0Zmd4eWRiZ3ZCZGJheGhrYXFhdjlobWJra2RuYW9hYmFvY2R0ZmdreWRiZ3ZTbWJpbmFrYWJhdmdvY2R0Zmd4eWRiZ3ZCZGJheGhrYW9hdjlobWJra2RuYXFhb1NtYmFiYXFhb2FxYW8wRWNkdGZhcWFvYXFhbzZFQmRia2FEY2VmZ0RjaTlobWJrYXJjaWZncmFpNm1ia2tkbmFlbWJjYnNrY2JoeGluZG5hbGF4Y2R0Z3ZmeWRiYXg5aG1iYXhob2RuYXhhYmF2ZmdEeWRiZ3ZTbWJhRGhxaW5hcWFiYXZnb2NkdGZna3lkYmd2QmRiYWtocWFvYXY5aG1ia2thRGFvQmRia2F4Y2VmZ3hhZTlobWJrY2Joa2FiaHZjYmhvaW5kbmRuYW9hbHlkYmdxOWhtYmRuYW9hdnlkYmdxOWhtYmF2YWtCZGJha2NlZmhreGRrYXZhYmFxY2R0ZnlkYkJkYnhla2F2YWJhcWNkdGZ5ZGJCZGJrYWxjbGZobGF2Y2xmaHZhZWFvY2VmZ285aG1ia2FraztqaWlsdWQ5OWV1YWJjYmFlY2x0ejp0ampqYmh2ZG5hbFRtYmFkaG9haWhyYWxod2luYXJjd2ZJZGJoRGFyY2xmSWRiaHFhdmFveWRiY2x0ZmdrYXJJZGJha0lkYk1VZGJha2FxYWtJZGxNVWRsYWthRGFrSWR3TVVkd2FrYWtJZHhKYmJqWk1VZHhhb2NsZmhvYXJjeGZocmF3Y3VmZ3dtYmtrZG5hZVRtYmF2aGthZWhyaW5ha2N4ZmdvSWRiaERhb2NiQmRiYWtha0lkYkpiYmJiSmJialphRDp2YURKYmJiYjlCRWdETlVkYmFrY2xmZ29hRGFvSWRiTlVkYmFrY3dmZ29hRGFvSWRiTlVkYmFrY3pmaGthcmN1ZmdybWJra2RuYWxUbWJpbmF2YWR5ZGJjbHRmZ2thaWN3ZklkYmFrSWR3OnRnRGFETmFpSWRiYWtJZGI6dGdEYUROYWljbGZJZGJha0lkbDp0Z0RhRE5NTWdEYWtJZHhncWFxYUQ5REVVZHhhZGNsZmhkYWljeGZoaWFsY3VmZ2xtYmtrZG5hZVRtYmF2Y3hmaGtpbmFiYWtJZGJVZGJha2N6ZmhrYWJjbGZoYmFlY3VmZ2VtYmtrazptb2VydWRuYW9UbWJhZWNkNGh6ZG5hdlRtYmFpY2Q0aEhhdmNkdGhPY2JoQWluZG5hUGFBZlJiYlRtYmFBaGVkbmFEVG1iYURhQWNkdGZ5ZGJoZWtkbmFzVG1iYXNhZWZSYmJjZUdtZWtkbmFtYUFmUmJiY2xTbWJhYmFlYXoyY2R0ZmdpYXJhQWN4MmZnQ0lkYmFrTmF4SWRiTVVkYmFpYUNJZGxha05heElkbE1VZGxhaWFDSWR3YWtOYXhJZHdNVWR3a2FkYWVhSDJjZHRmaFhhcWhlYXdoaWF2aENpbmFYYWV5ZGJjZHRnUWZhaUlkYmFsYVFmSWRiOnZVZGJhZWNsZmhlYWljbGZoaWFDY3VmZ0NtYmtrYXdhT2Zod2FBY2VmZ0FhbzlobWJ4ZGtrZG5hc21iY2JoZWFEaGlpbmRuYVBhZWZSYmJUbWJhZWhDZG5hRFRtYmFpeWRiaENrYW1hZWZSYmJjbFNtYmFiYUNhejJjZHRmZ0NhcklkYmFrTmF4SWRiTVVkYmFDYXJjbGZJZGJha05heElkbE1VZGxhQ2FyY3dmSWRiYWtOYXhJZHdNVWR3a2FpY2xmaGlhcmN4ZmhyYW9hZWNlZmdlOWhtYnhka2tkbmFEVG1iaW5kbmFQUmJiVG1iYXNhRHlkYmdlZlJiYmNlR21iYW1SYmJjbFNtYmFiYWVhejJjZHRmZ2VhcklkYmFrTmF4SWRiTVVkYmFlYXJjbGZJZGJha05heElkbE1VZGxhZWFyY3dmSWRiYWtOYXhJZHdNVWR3a2FQY2VmaFBhRGNsZmhEYW1jZWZobWFyY3hmaHJhb2N1ZmdvbWJ4ZGtrYXpjZHRoaWNiaGVpbmRuYVBhZWZSYmJUbWJhc2FlZlJiYmNlR21iYW1hZWZSYmJjbFNtYmFiYXJJZGJha05heElkYk1VZGJhYmNsZmFyY2xmSWRiYWtOYXhJZGxNVWRiYWJjd2ZhcmN3ZklkYmFrTmF4SWR3TVVkYmthcmN4ZmhyYWJhaWZoYmFvYWVjZWZnZTlobWJra2s4TWJhYmFlYWRhaWFsYXZjYmNiY2JjYmNiYW9hcmF3YUR6OmJqampiazhNYmFiYWVhZGFpYWxhdmFvYXJhd2FEYXFha2F4YW1hUHo6YmpqamJrUmJhYmFiYWVhZGFpYWxhdmFvYXJhd2FEYXFha2F4Y2pqampkVmFtejpiampqYms6ZzhLb3F1ZTk5ZHVlOTlkdXE5OThKampqamJjO1diOVJncThLampqamJjYmhrYXFjeGZjYmM7S2J6OnRqampiOEFhcWN1YWxjeDJhbGM7djpRO3Y6UWUwRWNieWQxOkg6Y2piSGpqampiYmd4QmR4YXFjZUJkMmF4YWlhbGF2Y2JjYno6ZWpqamI4QWFxY3VhbGNkdGFsY0ZGRkZpMEVnbWNieWQxOkg6Y2piSGpqampiYmdpQmR6YXFjZEJkMmRuZG5KRkY5NTllSmJialphd0piYmpaYXdKYmJqWjlERTp2YXdKOVZPOmQ4NjlERWd3OmxKYmJiOXA5RFRtYmF3Ok9oUHhla2NqampqOTRoUGthZGNpOVVoc2FyY285VWh6ZG5kbmFvbWJhUGNkOWltZWtkbmFsVG1iYVBjdWY6WWh3ZG5hb1RtYmNiaHZhaWhIYXhoT2luZG5kbmFvYXZmUmJiY2VHVG1iYXZjampqamxWaEF4ZWtkbmRuYU9jbGZJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaEF4ZWtjampqajk0aEFrYUFjcXRoQWRuZG5hT2N3ZklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9oWHhla2NqampqOTRoWGthQWFYVmhBZG5kbmFPSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hYeGVrY2pqamo5NGhYa2FBYVhjQ3RWaEFrYUhhQUJkYmFIY2xmaEhhT2N4ZmhPYWxhdmNlZmd2OWhtYnhka2theGh2YWloT2FsaEhpbmRuZG5hdklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9oQXhla2NqampqOTRoQWthQWNDdGhBZG5kbmF2Y2xmSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hYeGVrY2pqamo5NGhYa2FYY3F0YUFWaEFkbmRuYXZjd2ZJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaFh4ZWtjampqajk0aFhrYU9hQWFYVkJkYmF2Y3hmaHZhT2NsZmhPYUhjdWZnSG1ia2thZFRtYmNiaGthZWh2Y2JoT2luYWthaWF2Y2xmeWRiY2R0ZnlkYmdIYWlhdmN3ZnlkYmNkdGZ5ZGJnQTloYWlhdnlkYmNkdGZ5ZGJnWGFIOWhhWGFBOWhHR2Zoa2F2Y3hmaHZhT2NpZmdPYWQ2bWJra2FyY2k5VWhRZG5kbmF6Olo6ckpiYmJaTWd3OmxKYmJiOXA5RFRtYmF3Ok9odnhla2NqampqOTRodmthUTpaaExjYmhLYzpid2h6ZG5pbmFrYVE5cG1lYXphUDlSY2Q5aW1lYXZhemN1ZmdPYXZhTzlpRWFQY2VmYXZhUDlrRWhZZG5hbFRtYmFZY3VmOllod2RuYW9UbWJjYmhPYWloSGF4aHZpbmRuZG5hb2FPZlJiYmNlR1RtYmFPY2pqampsVmhBeGVrZG5kbmF2Y2xmSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hBeGVrY2pqamo5NGhBa2FBY3F0aEFkbmRuYXZjd2ZJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaFh4ZWtjampqajk0aFhrYUFhWFZoQWRuZG5hdklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9oWHhla2NqampqOTRoWGthQWFYY0N0VmhBa2FIYUFCZGJhSGNsZmhIYXZjeGZodmFsYU9jZWZnTzlobWJ4ZGtrYXhodmFpaE9hbGhIaW5kbmRuYXZJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaEF4ZWtjampqajk0aEFrYUFjQ3RoQWRuZG5hdmNsZklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9oWHhla2NqampqOTRoWGthWGNxdGFBVmhBZG5kbmF2Y3dmSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hYeGVrY2pqamo5NGhYa2FPYUFhWFZCZGJhdmN4Zmh2YU9jbGZoT2FIY3VmZ0htYmtrY2JoT2RuYWRUbWJhZWh2Y2JoSGluYU9haWF2Y2xmeWRiY2R0ZnlkYmdBYWlhdmN3ZnlkYmNkdGZ5ZGJnWDloYWlhdnlkYmNkdGZ5ZGJncmFBOWhhcmFYOWhHR2ZoT2F2Y3hmaHZhSGNpZmdIYWQ2bWJra2RuYXM6WmdDYUw6dGFZOllnd2F6Olk6dGc4QU5hazpaZ0VhTzpaZzM6dE5hRWFMOnRhd2FQOlk6dGc1TmEzYUM6dE5NZzhFSmJiYmI5Qm1iYUNhRTp0YTVhOEFhM2FMOnROTk5hOEU6dmF3TWh3a2RuZG5hT2FRMG1iYU9oa2FZaFB4ZWthT2hzYVloemtkbmRuYUtjbDBtYmRuYXdKYmJiWk1ndzpsSmJiYjlwOURUbWJhdzpPaHZ4ZGtjampqajk0aHZ4ZWthUGF6ZmNkOVRodmthS2NlZmdLY3M5aG1ia2tkbmRuZG5ha21iSmJialpod2NiaE9jZGh2YURtZXhka2FsY2Q0YWxmaEhjZWhPaW5hT2d2Y2V0aE9hdmFINm1ia2NiaE9hcWN1YXZjZHRnWWF2Y0ZGRkZpMEVjYnlkMTpIOmNqYkhqampqYmJnS0JkQ2FxY2lCZDJhcWFtY2J5ZDE6SDpjamJIampqamJiZ3pCZEthcWNsQmQyZG5kbmRuZG5hbFRtYmFQY3VmOllod2FvVG1lY2JoT2FpaEFheGhIaW5kbmRuYW9hT2ZSYmJjZUdUbWJhT2NqampqbFZoWHhla2RuZG5hSGNsZklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9oWHhla2NqampqOTRoWGthWGNxdGhYZG5kbmFIY3dmSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hyeGVrY2pqamo5NGhya2FYYXJWaFhkbmRuYUhJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaHJ4ZWtjampqajk0aHJrYVhhcmNDdFZoWGthQWFYQmRiYUFjbGZoQWFIY3hmaEhhbGFPY2VmZ085aG1ieGlra2FLY0ZlYVl6OnRqampiOEFjYmhQY2Jodnhka2F4aE9haWhIYWxoQWluZG5kbmFPSWRiYXdOSmJiYlpNZ0M6bEpiYmI5cDlEVG1iYUM6T2hYeGVrY2pqamo5NGhYa2FYY0N0aFhkbmRuYU9jbGZJZGJhd05KYmJiWk1nQzpsSmJiYjlwOURUbWJhQzpPaHJ4ZWtjampqajk0aHJrYXJjcXRhWFZoWGRuZG5hT2N3ZklkYmF3TkpiYmJaTWdDOmxKYmJiOXA5RFRtYmFDOk9ocnhla2NqampqOTRocmthSGFYYXJWQmRiYU9jeGZoT2FIY2xmaEhhQWN1ZmdBbWJra2FLY0ZlYVl6OnRqampiaHJhdmN1ZmhvY2JoUGNiaFlpbmRuZG5kbmFyYWlhWWNkdGdLZnlkYmdBY200YUE3Yzp2O3Q7aDtFdjJndmNzNGF2N2FvR2dIY2R0ZmdYeWRiZ09jdVNtYmNlaHZpbmFpYU9jZHRnT2Z5ZGJhQVNtZGFIYXZmaE9hdmNlZmh2YXJhT2FvR2dIY2R0ZmdYeWRiZ09jdTlobWJra2FYYVlCZGJhUGh2YVBjZWZoUHhla2F6YU9meWRiaHZrYXphS2ZhdkJkYmFZY2VmZ1lhbDlobWJrY3VhUGM4UzJnT2FQYztEO087ZjhVMEVodmtjYmhYYXFhdmNieWQxOkg6Y2piSGpqampiYmd2QmQzYXFjdkJkMmF2Y2JhT3o6dGpqamJoT2RuYWRUbWJhZWhpaW5heGFpY2xmeWRiZ3JjeDJmZ3ZJZGJheGFpeWRiZ29jeDJmZ0hJZGJnMzp0Z0NheGFpY3dmeWRiZ1ljeDJmZ0FJZGxhSElkbGc4QTp0Z3dOYXZJZGxhOEE6dGdFYUFJZGJhMzp0ZzhFTjp0Z0xhTE5hRWFBSWR3YUhJZHdnNTp0ZzhGTmF2SWR3YTU6dGdFYXdOOnRnd2F3TmFFYThFTmFDYThGTjp0Z0NhQ05NTWc4RTpyaEVKYmJubkpiYmpaYXphb2NkdGZ5ZGJndmF6YXJjZHRmeWRiZ0FTYXZhemFZY2R0ZnlkYmdyU0dnSEVoOEZkbmE4RUpiYmJiOUVUbWJhTGFFOnZoTGFDYUU6dmhDYXdhRTp2aHdrYU9hdmM4UzJmZ3ZhdklkYmF3YThGYUU6ck5nRWF3Tk5nOEZNVWRiYXZhQ2FFYUNOZ2FOZ2hhdklkbE1VZGxhdmFMYUVhTE5nOEVOZ2dhdklkd01VZHdhdmF3YWFOZ2FhdklkeE1VZHhhdmE4RWF3Tmc4SmF2SWR6TVVkemF2YUNhOEVOZzhFYXZJZENNVWRDYXZhd2FFYUxhNU5hd2EzTmE4QWFDTk1NOm1nOEFOZzNOZ3dhdklkS01VZEthdmFDYTNOZ0NhdklkM01VZDNhdmFMYTNOZ0xhdklkYU1VZGFhdmEzYThBTmczYXZJZDhLTVVkOEthdmFFYXZJZHlNVWR5ZG5hSG1iYU9hQWM4UzJmZ3ZhOEZhdklkYk1VZGJhdmFoYXZJZGxNVWRsYXZhZ2F2SWR3TVVkd2F2YWFhdklkeE1VZHhhdmE4SmF2SWR6TVVkemF2YThFYXZJZENNVWRDYXZhd2F2SWRLTVVkS2F2YUNhdklkM01VZDNhdmFMYXZJZGFNVWRhYXZhM2F2SWQ4S01VZDhLYXZhRWF2SWR5TVVkeWFPYXJjOFMyZmd2YThGYXZJZGJNVWRiYXZhaGF2SWRsTVVkbGF2YWdhdklkd01VZHdhdmFhYXZJZHhNVWR4YXZhOEphdklkek1VZHphdmE4RWF2SWRDTVVkQ2F2YXdhdklkS01VZEthdmFDYXZJZDNNVWQzYXZhTGF2SWRhTVVkYWF2YTNhdklkOEtNVWQ4S2F2YUVhdklkeU1VZHlrYWljeGZoaWFYY2lmZ1hhZDZtYmtrY2JoQWFxY3VhUGNkdGd2YVBjRkZGRmkwRWdpY2J5ZDE6SDpjamJIampqamJiZ0hCZGFhcWNvQmQyYXFhaWNieWQxOkg6Y2piSGpqampiYmdpQmQ4S2FxY3JCZDJhSGNGZWF2ejp0ampqYmhZZG5hbFRtYmF6aEhpbkpiYmJiSmJialphT2FIeWRiZ1hjOFMyZmd2SWR5Z3c6dmF3SmJiYmI5QkVhdklkd2F4Y3dmSWRiZ3dOYXZJZHpheElkYmdDTmF2SWRhTWdMYUxNTWF3TmF2SWRsYXhjbGZJZGJnTE5hdklkQ2F3TmF2SWQzTWd3YXdNTWFMTmF2SWRiYUNOYXZJZHhhTE5hdklkS01nd2F3TU1hQ05hdklkOEtNTU06bE5od2RuZG5hWWFYY2R0Z3ZmZ1h5ZGJjdVNtYmFpYXZmSWRiYXc5RVRtZWthWGFBQmRiYWlhdmZhd1VkYmthSGNsZmhIYXhjeGZoeGFsYUFjZWZnQTlobWJra2RuZG5hUG1iSmJiYmJod3hla0piYmJiaHdpbmFpSWRiZ0Nhd2F3YUM5REVod2FpY2xmaGlhUGN1ZmdQbWJrYXc6cmh3a2FrY2Q0YWtmaE9jZWhpaW5haWd2Y2V0aGlhdmFPNm1ia2NiaE9hcWN1YXZjZHRnaWF2Y0ZGRkZpMEVjYnlkMTpIOmNqYkhqampqYmJnSEJkeWFIY0ZlYWl6OnRqampiaFhkbmFkVG1iYXZjdWZocmNiaFBjYmh4aW5kbmF6YWVheGNkdGZndnlkYmNkdGZ5ZGJnaWF6YXZjbGZ5ZGJjZHRmeWRiZ09TbWJhaWF6YXZjd2Z5ZGJjZHRmeWRiZ3ZTbWJhT2F2U21iYVlhdmNkdGZ5ZGJoQWRuZG5hWWFPY2R0ZnlkYmd2YVlhaWNkdGZ5ZGJnaTlwbWJhdmFBOXBtYmFBaGxhaWhvYXZoQXhla2RuYUFhaTlwbWJhQWF2OXBtYmFpaGxhdmhveGVrYXZobGFBaG9haWhBa2FiYVBjeDJmZ3ZhQUJkYmF2Y3dmYW9CZGJhdmNsZmFsQmRiZG5hWGFvYzozRjtOOE4yYWxjOkY6YjpERDI3YUFjO0Q7TzpCOEoyN2FyR2dPY2R0Zmd2eWRiZ2ljdVNtYmNlaEhpbmFIaHZkbmFiYWljeDJmZ2l5ZGJhQTlobWJhaXlkbGFsOWhtYmFpeWR3YW9TbWlrYXZjZWZoSGFYYU9hdmZhckdnT2NkdGZndnlkYmdpY3U5aG1ia2thdmFQQmRiYVBjZWZoUGtheGNpZmd4YWQ2bWJrYVBjaTJoT2tjd2h2YURUbWVrYURhd1VkYmthdmNkdGh2YXFjeGZjOThmaGlpbmFpYXZmeWRiY2J5ZDptOkg6Y2piSDpiampqYmJhdmM5OGZndm1ia2FxYztXYmY4S2pqampiYU9rOjNsZHJ1ZTk6OEpqampqYmM7V2I5UmdyOEtqampqYmNiaHdhcmN4ZmNiYztLYno6dGpqamI4QWRuYWJhZVNtYmFiYWVhZGNkdHpNampqYjhBa2FyY3VhbGNkdGFsY0ZGRkZpMEVnRGNieWQxOkg6Y2piSGpqampiYmdxQmR4YXJjZUJkMmFxY2JhaWFsYXZjYmFyY3hmejpkampqYmN1YWxjeDJhbGM7djpRO3Y6UWUwRWNieWQxOkg6Y2piSGpqampiYmhrYXJjeGZhcnlkMmd4Y2R0ZmFrQmRiYXJheGNlZmdtQmQyYWthaWFsYXZjYmNiejplampqYjhBYXJjeGZhbWNkdGZhRGNieWQxOkg6Y2piSGpqampiYmdpQmRiYXJheGNkZmd2QmQyYXJjeGZhdmNkdGZjdWFpYWxhZWFkYXF6OmZqampiZ2VjbHRhZWNqampqaUdFY2J5ZDE6SDpjamJIampqamJiZ3FCZGJhcWFlYWlha2FsejpnampqYmF4Y2lmaGtkbmFkVG1iYW9hb05ob2NiaHdhYmhsY2JoZWluZG5hcWFpYWx5ZGJndmNkdGZ5ZGJjZHRmSWRiYW85RVRtYmFsY2xmOFBkYmhQYWJhd2NkdGZnRGF2QmRiYURjbGZhUDgzZGJhd2NpZmh3a2FsY3hmaGxhZWNpZmdlYWQ2bWJra2RuYWtUbWJheGNkdGFyY3hmZmN3ZmhsaW5hbHlkYmNieWQ6bTpIOmNqYkg6YmpqamJiYWxjOThmaGxha2N1ZmdrbWJra2FyYztXYmY4S2pqampiYXdrOldDb0R1ZDk5dnVlOTl2dXY5OThKampqamJjO1diOVJndzhLampqamJkbmRuYXJtYmNiaER4ZWthd2N4ZmNiYztLYno6dGpqamI4QWF3Y3VhZGN4MmFkYzt2OlE7djpRZTBFY2J5ZDE6SDpjamJIampqamJiZ3FCZHhhd2NlQmQyYXFhZWFkYWljYmNiejplampqYjhBYXdjdWFkY2R0YWRjRkZGRmkwRWdrY2J5ZDE6SDpjamJIampqamJiZ3hCZHphd2NkQmQyYWRjZDRhZGZobWNlaGVpbmFlZ2ljZXRoZWFpYW02bWJrY2JoUGF3Y3VhaWNkdGdzYWljRkZGRmkwRWNieWQxOkg6Y2piSGpqampiYmd6QmRDYXdjaUJkMmRuZG5hcjpaZ0g6ckpiYmJaTWdPOmxKYmJiOXA5RFRtYmFPOk9oZXhla2NqampqOTRoZWthaWN1ZmhBYzpid2hDY2JoWGFkaFFjYmhMaW5hZWFDY3VmZ2lhZWFpOWlFYVBjZWZhZWFQOWtFaERkbmRuYWRUbWJhRGN1ZjpZaE9hcWhpYXhoZWFkaG1pbmRuZG5haUlkYmFPTkpiYmJaTWdLOmxKYmJiOXA5RFRtYmFLOk9oWXhla2NqampqOTRoWWthWWNDdGhZZG5kbmFpY2xmSWRiYU9OSmJiYlpNZ0s6bEpiYmI5cDlEVG1iYUs6T2g4QXhla2NqampqOTRoOEFrYThBY3F0YVlWaFlkbmRuYWljd2ZJZGJhT05KYmJiWk1nSzpsSmJiYjlwOURUbWJhSzpPaDhBeGVrY2pqamo5NGg4QWthZWFZYThBVkJkYmFpY3hmaGlhZWNsZmhlYW1jdWZnbW1ia2F6Y0ZlYXN6OnRqampiaEVjYmgzY2JoNWluZG5hRWF4YTVjZHRmeWRiZ1ljbTRhWTdjOnY7dDtoO0V2MmdpY3M0YWk3YUFHZ21jZHRmZzhBeWRiZ2VjdVNtYmFlYVlTbWJjZWhpaW5hRWFtYWlmYUFHZ21jZHRmZzhBeWRiZ2VjdVNtZWFpY2VmaGlhZWFZOWhtYmtrYThBYVlCZGJhM2FlY3VTZmgzYTVjZWZnNWFkOWhtYnhka2themNGZWFzejp0ampqYjhBY2JoM2tkbmFROlpnS2FIOnRhRDpZZ09hQzpZOnRnOEVOYVg6Wmc4RmEzOlpnYTp0TmE4RmFIOnRhT2FQOlk6dGdoTmFhYUs6dE5NZ2dKYmJiYjlCbWJhS2E4Rjp0YWhhOEVhYWFIOnROTk5hZzp2YU9NaE9rYVBhRGEzYXIwZ2lFaFBhWGEzYWlFaFhkbmEzYXJTbWJhRGFDYWlFZ0NhUDlSY2Q5aW1iZG5kbmFMY2wwbWJkbmFPSmJiYlpNZ086bEpiYmI5cDlEVG1iYU86T2hleGRrY2pqamo5NGhleGVrYVBhQ2ZjZDlUaGVrYTNhUWFpRWhRYUxjZWZnTGNzOWhtZWtrZG5kbmFYbWJjaWhpY2JoRHhla2NiaGlhd2FrY2J5ZDE6SDpjamJIampqamJiZzVCZEthd2NsQmQyYVBjdWY6WWhLZG5kbmFkVG1iYXFoaWF4aGVhZGhtaW5kbmRuYWlJZGJhS05KYmJiWk1nTzpsSmJiYjlwOURUbWJhTzpPaFl4ZWtjampqajk0aFlrYVljQ3RoWWRuZG5haWNsZklkYmFLTkpiYmJaTWdPOmxKYmJiOXA5RFRtYmFPOk9oOEF4ZWtjampqajk0aDhBa2E4QWNxdGFZVmhZZG5kbmFpY3dmSWRiYUtOSmJiYlpNZ086bEpiYmI5cDlEVG1iYU86T2g4QXhla2NqampqOTRoOEFrYWVhWWE4QVZCZGJhaWN4ZmhpYWVjbGZoZWFtY3VmZ21tYmthemNGZWFzejp0ampqYmhFY2JoRGNiaDNpbmRuZG5kbmFFYXhhM2NkdGdDZnlkYmdZY200YVk3Yzp2O3Q7aDtFdjJnaWNzNGFpN2FBR2dtY2R0Zmc4QXlkYmdlY3VTbWJjZWhpaW5heGFlY2R0Z2VmeWRiYVlTbWRhbWFpZmhlYWljZWZoaWFFYWVhQUdnbWNkdGZnOEF5ZGJnZWN1OWhtYmtrYThBYTNCZGJhRGhpYURjZWZoRHhla2E1YWVmeWRiaGlrYTVhQ2ZhaUJkYmEzY2VmZzNhZDlobWJrY3VhRGMzMmdpYURjO2o6S007amIwRWhleGVrYXpjRmVhc3o6dGpqamI4QWNiaERjYmhla2F3YWVjYnlkMTpIOmNqYkhqampqYmJnZUJkM2F3Y3ZCZDJhZWNiYWl6OnRqampiaDhBYXZjZDRoeGRuYWRUbWJkbmFsVG1iYXhjZHRoRWE1aFlhcWhlYWxobWFkaEFpbmE4QWFZeWRiYzMyZmdpYWVJZGJhaUlkYk1VZGJhaWFlY2xmSWRiYWlJZGxNVWRsYWlhZWN3ZklkYmFpSWR3TVVkd2FpYW1JZGJhaUlkeE1VZHhhaWFtY2xmSWRiYWlJZHpNVWR6YWlhbWN3ZklkYmFpSWRDTVVkQ2FpYWlJZEtKYmJqWk1VZEthWWNsZmhZYWVjeGZoZWFtYUVmaG1hQWN1ZmdBbWJ4ZGtrYTVobWFxaGVhZGhZaW5hOEFhbXlkYmMzMmZnaWFlSWRiYWlJZGJNVWRiYWlhZWNsZklkYmFpSWRsTVVkbGFpYWVjd2ZJZGJhaUlkd01VZHdhaWFpSWR4SmJiYmJNVWR4YWlhaUlkekpiYmJiTVVkemFpYWlJZENKYmJiYk1VZENhaWFpSWRLSmJialpNVWRLYW1jbGZobWFlY3hmaGVhWWN1ZmdZbWJra2RuYURUbWJhOEFoaWFEaGVpbmFpYWlJZGJKYmJiYkpiYmpaYWljS2ZJZGJnTzp2YU9KYmJiYjlCRWdPTlVkYmFpY2xmZ21hT2FtSWRiTlVkYmFpY3dmZ21hT2FtSWRiTlVkYmFpY3hmZ21hT2FtSWRiTlVkYmFpY3pmZ21hT2FtSWRiTlVkYmFpY0NmZ21hT2FtSWRiTlVkYmFpYzNmaGlhZWN1ZmdlbWJra2NiaFlhd2N1YURjZHRnQ2FEY0ZGRkZpMEVnaWNieWQxOkg6Y2piSGpqampiYmdlQmRhYXdjb0JkMmF3YWljYnlkMTpIOmNqYkhqampqYmJnRUJkOEthZWNGZWFDejp0ampqYmgzZG5hZFRtYmFvSmJialpKYmJqWmFLOnZhUGNlU0VOZ09hT05oS2F4Y2R0aHhhbGhlaW5hS2FlYzs4Okc6Y2piYWxFZ21JZHdhOEFhNXlkYmdBYzMyZmdpSWRDOnRnT2FPTmFtSWRiYWlJZHg6dGdPYU9OYW1JZGxhaUlkejp0Z09hT05NTU5hcWN3ZklkYmFpSWR3OnRnT2FPTmFxSWRiYWlJZGI6dGdPYU9OYXFjbGZJZGJhaUlkbDp0Z09hT05NTU1oT2RuZG5hM2FBY2R0Z2lmZ215ZGJjdVNtYmFFYWlmSWRiYU85RVRtZWthbWFZQmRiYUVhaWZhT1VkYmthNWNsZmg1YXFjeGZocWFlYXhmaGVhZGFZY2VmZ1k5aG1ia2thYmEzYUN6TWpqamI4QWNyaGlrYWljZHRoaWF3Y3hmYzk4ZmhlaW5hZWFpZnlkYmNieWQ6bTpIOmNqYkg6YmpqamJiYWljOThmZ2ltYmtrYXdjO1diZjhLampqamJhRGs6UGRpZHVpOTlkdWNiaGk4SmpqampiY2E5UmdsY2J5ZDE6RzpjamJCZEthbGNiOFBkajpHOmNqYjgzaXphbGNieWROOkc6Y2piQmR3YWxjYjhQZDptOkc6Y2piODNpYmRuZG5hZW1iSmJiakZodkpiYmpGaG9KYmJqRmhyeGVrYWRjZDRjZHRod2luY2JoZGluYWxjemZhZGZnRGFiYWRmSWRiZ3ZhRElkYmdvYW9hdjlFRVVkYmFsYWRmZ0RhdmFESWRiZ29hb2F2OURFVWRiYWRjbGZnZGN4OWhtYmthYmF3ZmhiYWljZWZnaWFlOWhtYmthbElkd2FsSWRLOnRocmFsSWRsYWxJZEM6dGhvYWxJZGJhbElkejp0aHZrSmJiYmJhdmF2SmJiYmI5REVndmFvYW9hdjlERWd2YXJhcmF2OURFazlEZWV1YWJjRmVhaWNkdHo6dGpqamJobGNiaGJkbmFkVG1iaW5kbmFsYWV5ZGJjZHRmZ2l5ZGJjdTlobWJhaWFiQmRiYWJjZWZoYmthZWNsZmhlYWRjdWZnZG1ia2thYms7QmlkcXVpOTk4SmpqampiYztXYjlSZ2w4S2pqampiYWxjeGZjYmM7S2J6OnRqampiOEFhZGNkNGFkZmh2Y2Vob2luYW9ncmNldGhvYXJhdjZtYmthbGN1YXJjZHRnb2FyY0ZGRkZpMEVjYnlkMTpIOmNqYkhqampqYmJndkJkeGF2Y0ZlYW96OnRqampiaHdkbmFkVG1iYWljZDRoRGFyY3VmaHFjYmhraW5kbmRuYXdjYmFlYWthRDJjZHRmZ3J5ZGxnaWFpY2pqamo5NFNFZ29jSDRhbzdjOkY6YjpERDJjYmFyeWRiZ3hheGNqampqOTRTRWdvY0g0YW83YztEO086QjhKMjdjYmFyeWR3Z21hbWNqampqOTRTRWdyY0g0YXI3YzozRjtOOE4yN2FxR2d2Y2R0ZmdyeWRiZ29jdVNtYmFtOjpoUGFpOjpoc2F4OjpoemNlaGlpbmFpaHJkbmFlYW9hRDJjZHRmZ2lJZGJhejlDbWJhaUlkbGFzOUNtYmFpSWR3YVA5Qm1pa2FyY2VmaGlhd2F2YXJmYXFHZ3ZjZHRmZ3J5ZGJnb2N1OWhtYmtrYXJha0JkYmFraG9rYWJha2NkdGZhb0JkYmFrY2VmZ2thZDlobWJra2FseWR4Y2J5ZDptOkg6Y2piSDpiampqYmJhbGM7V2JmOEtqampqYms5dGVpdWNiY2J5ZDpxOkg6Y2piZ2VhYmNpZmM5OEdmZ2JCZDpxOkg6Y2piZG5kbmFiWmJjenRnZDlubWJjdWhpYWJhZDlSY0ZGaWZjejRuYmN1U21la2FlaGlrYWlrO0xlZWV1ZG5kbmFlYWJWY2lHVG1iYWJoaXhla2RuZG5hZGN6OXBtYmFiaGl4ZWthYmhpaW5haWFleWRiQmRiYWljbGZhZWNsZnlkYkJkYmFpY3dmYWVjd2Z5ZGJCZGJhaWN4ZmFlY3hmeWRiQmRiYWVjemZoZWFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFleWRiQmRiYWVjbGZoZWFpY2xmaGlhZGM5OGZnZGNpMG1ia2tkbmFkVG1iaW5haWFlUmJiODZiYmFpY2VmaGlhZWNlZmhlYWRjdWZnZG1ia2thYms7YWVlZHVkbmRuYWJjaUdUbWJhYmhpeGVrYWVjRmVHYzpiOmM6ZXcyaGxkbmRuYWRjejlwbWJhYmhpeGVrYWJoaWluYWlhbEJkYmFpY3hmYWxCZGJhaWN3ZmFsQmRiYWljbGZhbEJkYmFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFsQmRiYWljbGZoaWFkYzk4ZmdkY2kwbWJra2RuYWRUbWJpbmFpYWU4NmJiYWljZWZoaWFkY3VmZ2RtYmtrYWJrOXRlaXVjYmNieWQ6cTpIOmNqYmdlYWJjcmZjOTRHZmdiQmQ6cTpIOmNqYmRuZG5hYlpiY3p0Z2Q5bm1iY3VoaWFiYWQ5UmNGRmlmY3o0bmJjdVNtZWthZWhpa2Fpa1RlZXVjYmFiY2J5ZDpxOkg6Y2piZ2U5UmNpZmM5OEdhZWZnYkJkOnE6SDpjamJkbmFiWmJjenRnZTlubWJhYmFlOVJjRkZpZmN6NG5iOEFra2s6S2VkYmNqOkdkazFlRkZ1dUZGdXVGRnV1RkZ1RkZGdUZGRnVGYmJiYmJiYmJlYmJiZGJiYmJiYmJlYmJiZWJiYmRiYmJiYmJiYmJiYmVlZWVlYmViYmViYmViZWJiYmVlYmJiYmJiYmJiYmJiZWVlZWVlYmViYmVlZWJlZWJiYmJlYmViYmJiYmJiYmJiYmJiYmJiYmJjMTpIZGt4ZWJiYmRiYmI6RzpxYmIiOwogICAgICAgIHZhciB3YXNtcGFjayA9IG5ldyBVaW50OEFycmF5KFsKICAgICAgICAgIDMyLAogICAgICAgICAgMCwKICAgICAgICAgIDY1LAogICAgICAgICAgMiwKICAgICAgICAgIDEsCiAgICAgICAgICAxMDYsCiAgICAgICAgICAzNCwKICAgICAgICAgIDMzLAogICAgICAgICAgMywKICAgICAgICAgIDEyOCwKICAgICAgICAgIDExLAogICAgICAgICAgNCwKICAgICAgICAgIDEzLAogICAgICAgICAgNjQsCiAgICAgICAgICA2LAogICAgICAgICAgMjUzLAogICAgICAgICAgMTAsCiAgICAgICAgICA3LAogICAgICAgICAgMTUsCiAgICAgICAgICAxMTYsCiAgICAgICAgICAxMjcsCiAgICAgICAgICA1LAogICAgICAgICAgOCwKICAgICAgICAgIDEyLAogICAgICAgICAgNDAsCiAgICAgICAgICAxNiwKICAgICAgICAgIDE5LAogICAgICAgICAgNTQsCiAgICAgICAgICAyMCwKICAgICAgICAgIDksCiAgICAgICAgICAyNywKICAgICAgICAgIDI1NSwKICAgICAgICAgIDExMywKICAgICAgICAgIDE3LAogICAgICAgICAgNDIsCiAgICAgICAgICA2NywKICAgICAgICAgIDI0LAogICAgICAgICAgMjMsCiAgICAgICAgICAxNDYsCiAgICAgICAgICAxNDgsCiAgICAgICAgICAxOCwKICAgICAgICAgIDE0LAogICAgICAgICAgMjIsCiAgICAgICAgICA0NSwKICAgICAgICAgIDcwLAogICAgICAgICAgNjksCiAgICAgICAgICA1NiwKICAgICAgICAgIDExNCwKICAgICAgICAgIDEwMSwKICAgICAgICAgIDIxLAogICAgICAgICAgMjUsCiAgICAgICAgICA2MywKICAgICAgICAgIDc1LAogICAgICAgICAgMTM2LAogICAgICAgICAgMTA4LAogICAgICAgICAgMjgsCiAgICAgICAgICAxMTgsCiAgICAgICAgICAyOSwKICAgICAgICAgIDczLAogICAgICAgICAgMTE1CiAgICAgICAgXSk7CiAgICAgICAgaWYgKHR5cGVvZiBXZWJBc3NlbWJseSAhPT0gIm9iamVjdCIpIHsKICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIHN1cHBvcnRlZDogZmFsc2UKICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIHZhciBpbnN0YW5jZTsKICAgICAgICB2YXIgcmVhZHkgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZSh1bnBhY2sod2FzbTIpLCB7fSkudGhlbihmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICAgIGluc3RhbmNlID0gcmVzdWx0Lmluc3RhbmNlOwogICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fX3dhc21fY2FsbF9jdG9ycygpOwogICAgICAgIH0pOwogICAgICAgIGZ1bmN0aW9uIHVucGFjayhkYXRhKSB7CiAgICAgICAgICB2YXIgcmVzdWx0ID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5sZW5ndGgpOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGRhdGEubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIHZhciBjaCA9IGRhdGEuY2hhckNvZGVBdChpMik7CiAgICAgICAgICAgIHJlc3VsdFtpMl0gPSBjaCA+IDk2ID8gY2ggLSA5NyA6IGNoID4gNjQgPyBjaCAtIDM5IDogY2ggKyA0OwogICAgICAgICAgfQogICAgICAgICAgdmFyIHdyaXRlID0gMDsKICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBkYXRhLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICByZXN1bHRbd3JpdGUrK10gPSByZXN1bHRbaTJdIDwgNjAgPyB3YXNtcGFja1tyZXN1bHRbaTJdXSA6IChyZXN1bHRbaTJdIC0gNjApICogNjQgKyByZXN1bHRbKytpMl07CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0LmJ1ZmZlci5zbGljZSgwLCB3cml0ZSk7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGFzc2VydChjb25kKSB7CiAgICAgICAgICBpZiAoIWNvbmQpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJBc3NlcnRpb24gZmFpbGVkIik7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGJ5dGVzKHZpZXcpIHsKICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheSh2aWV3LmJ1ZmZlciwgdmlldy5ieXRlT2Zmc2V0LCB2aWV3LmJ5dGVMZW5ndGgpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBnZW5yZW1hcChmdW4sIHBvc2l0aW9ucywgdmVydGljZXMsIHN0cmlkZSkgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgcnAgPSBzYnJrKHZlcnRpY2VzICogNCk7CiAgICAgICAgICB2YXIgc3AgPSBzYnJrKHZlcnRpY2VzICogc3RyaWRlICogNCk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhwb3NpdGlvbnMpLCBzcCk7CiAgICAgICAgICBmdW4ocnAsIHNwLCB2ZXJ0aWNlcywgc3RyaWRlICogNCk7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciByZW1hcCA9IG5ldyBVaW50MzJBcnJheSh2ZXJ0aWNlcyk7CiAgICAgICAgICBuZXcgVWludDhBcnJheShyZW1hcC5idWZmZXIpLnNldChoZWFwLnN1YmFycmF5KHJwLCBycCArIHZlcnRpY2VzICogNCkpOwogICAgICAgICAgc2JyayhycCAtIHNicmsoMCkpOwogICAgICAgICAgcmV0dXJuIHJlbWFwOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiByZW9yZGVyKGZ1biwgaW5kaWNlcywgdmVydGljZXMpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIGlwID0gc2JyayhpbmRpY2VzLmxlbmd0aCAqIDQpOwogICAgICAgICAgdmFyIHJwID0gc2Jyayh2ZXJ0aWNlcyAqIDQpOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgdmFyIGluZGljZXM4ID0gYnl0ZXMoaW5kaWNlcyk7CiAgICAgICAgICBoZWFwLnNldChpbmRpY2VzOCwgaXApOwogICAgICAgICAgdmFyIHVuaXF1ZSA9IGZ1bihycCwgaXAsIGluZGljZXMubGVuZ3RoLCB2ZXJ0aWNlcyk7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciByZW1hcCA9IG5ldyBVaW50MzJBcnJheSh2ZXJ0aWNlcyk7CiAgICAgICAgICBuZXcgVWludDhBcnJheShyZW1hcC5idWZmZXIpLnNldChoZWFwLnN1YmFycmF5KHJwLCBycCArIHZlcnRpY2VzICogNCkpOwogICAgICAgICAgc2JyayhpcCAtIHNicmsoMCkpOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGluZGljZXMubGVuZ3RoOyArK2kyKSBpbmRpY2VzW2kyXSA9IHJlbWFwW2luZGljZXNbaTJdXTsKICAgICAgICAgIHJldHVybiBbcmVtYXAsIHVuaXF1ZV07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIG1heGluZGV4KHNvdXJjZSkgewogICAgICAgICAgdmFyIHJlc3VsdCA9IDA7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgc291cmNlLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICB2YXIgaW5kZXggPSBzb3VyY2VbaTJdOwogICAgICAgICAgICByZXN1bHQgPSByZXN1bHQgPCBpbmRleCA/IGluZGV4IDogcmVzdWx0OwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gc2ltcGxpZnkoZnVuLCBpbmRpY2VzLCBpbmRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdGFyZ2V0X2luZGV4X2NvdW50LCB0YXJnZXRfZXJyb3IsIG9wdGlvbnMpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHRlMiA9IHNicmsoNCk7CiAgICAgICAgICB2YXIgdGkgPSBzYnJrKGluZGV4X2NvdW50ICogNCk7CiAgICAgICAgICB2YXIgc3AgPSBzYnJrKHZlcnRleF9jb3VudCAqIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKTsKICAgICAgICAgIHZhciBzaSA9IHNicmsoaW5kZXhfY291bnQgKiA0KTsKICAgICAgICAgIHZhciBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKHZlcnRleF9wb3NpdGlvbnMpLCBzcCk7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhpbmRpY2VzKSwgc2kpOwogICAgICAgICAgdmFyIHJlc3VsdCA9IGZ1bih0aSwgc2ksIGluZGV4X2NvdW50LCBzcCwgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdGFyZ2V0X2luZGV4X2NvdW50LCB0YXJnZXRfZXJyb3IsIG9wdGlvbnMsIHRlMik7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciB0YXJnZXQgPSBuZXcgVWludDMyQXJyYXkocmVzdWx0KTsKICAgICAgICAgIGJ5dGVzKHRhcmdldCkuc2V0KGhlYXAuc3ViYXJyYXkodGksIHRpICsgcmVzdWx0ICogNCkpOwogICAgICAgICAgdmFyIGVycm9yID0gbmV3IEZsb2F0MzJBcnJheSgxKTsKICAgICAgICAgIGJ5dGVzKGVycm9yKS5zZXQoaGVhcC5zdWJhcnJheSh0ZTIsIHRlMiArIDQpKTsKICAgICAgICAgIHNicmsodGUyIC0gc2JyaygwKSk7CiAgICAgICAgICByZXR1cm4gW3RhcmdldCwgZXJyb3JbMF1dOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBzaW1wbGlmeUF0dHIoZnVuLCBpbmRpY2VzLCBpbmRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdmVydGV4X2F0dHJpYnV0ZXMsIHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSwgYXR0cmlidXRlX3dlaWdodHMsIHZlcnRleF9sb2NrLCB0YXJnZXRfaW5kZXhfY291bnQsIHRhcmdldF9lcnJvciwgb3B0aW9ucykgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgdGUyID0gc2Jyayg0KTsKICAgICAgICAgIHZhciB0aSA9IHNicmsoaW5kZXhfY291bnQgKiA0KTsKICAgICAgICAgIHZhciBzcCA9IHNicmsodmVydGV4X2NvdW50ICogdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpOwogICAgICAgICAgdmFyIHNhID0gc2Jyayh2ZXJ0ZXhfY291bnQgKiB2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUpOwogICAgICAgICAgdmFyIHN3ID0gc2JyayhhdHRyaWJ1dGVfd2VpZ2h0cy5sZW5ndGggKiA0KTsKICAgICAgICAgIHZhciBzaSA9IHNicmsoaW5kZXhfY291bnQgKiA0KTsKICAgICAgICAgIHZhciB2bCA9IHZlcnRleF9sb2NrID8gc2Jyayh2ZXJ0ZXhfY291bnQpIDogMDsKICAgICAgICAgIHZhciBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKHZlcnRleF9wb3NpdGlvbnMpLCBzcCk7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfYXR0cmlidXRlcyksIHNhKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKGF0dHJpYnV0ZV93ZWlnaHRzKSwgc3cpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMoaW5kaWNlcyksIHNpKTsKICAgICAgICAgIGlmICh2ZXJ0ZXhfbG9jaykgewogICAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfbG9jayksIHZsKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciByZXN1bHQgPSBmdW4oCiAgICAgICAgICAgIHRpLAogICAgICAgICAgICBzaSwKICAgICAgICAgICAgaW5kZXhfY291bnQsCiAgICAgICAgICAgIHNwLAogICAgICAgICAgICB2ZXJ0ZXhfY291bnQsCiAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICBzYSwKICAgICAgICAgICAgdmVydGV4X2F0dHJpYnV0ZXNfc3RyaWRlLAogICAgICAgICAgICBzdywKICAgICAgICAgICAgYXR0cmlidXRlX3dlaWdodHMubGVuZ3RoLAogICAgICAgICAgICB2bCwKICAgICAgICAgICAgdGFyZ2V0X2luZGV4X2NvdW50LAogICAgICAgICAgICB0YXJnZXRfZXJyb3IsCiAgICAgICAgICAgIG9wdGlvbnMsCiAgICAgICAgICAgIHRlMgogICAgICAgICAgKTsKICAgICAgICAgIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgdmFyIHRhcmdldCA9IG5ldyBVaW50MzJBcnJheShyZXN1bHQpOwogICAgICAgICAgYnl0ZXModGFyZ2V0KS5zZXQoaGVhcC5zdWJhcnJheSh0aSwgdGkgKyByZXN1bHQgKiA0KSk7CiAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRmxvYXQzMkFycmF5KDEpOwogICAgICAgICAgYnl0ZXMoZXJyb3IpLnNldChoZWFwLnN1YmFycmF5KHRlMiwgdGUyICsgNCkpOwogICAgICAgICAgc2Jyayh0ZTIgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiBbdGFyZ2V0LCBlcnJvclswXV07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHNpbXBsaWZ5VXBkYXRlKGZ1biwgaW5kaWNlcywgaW5kZXhfY291bnQsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZlcnRleF9hdHRyaWJ1dGVzLCB2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUsIGF0dHJpYnV0ZV93ZWlnaHRzLCB2ZXJ0ZXhfbG9jaywgdGFyZ2V0X2luZGV4X2NvdW50LCB0YXJnZXRfZXJyb3IsIG9wdGlvbnMpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHRlMiA9IHNicmsoNCk7CiAgICAgICAgICB2YXIgc3AgPSBzYnJrKHZlcnRleF9jb3VudCAqIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKTsKICAgICAgICAgIHZhciBzYSA9IHNicmsodmVydGV4X2NvdW50ICogdmVydGV4X2F0dHJpYnV0ZXNfc3RyaWRlKTsKICAgICAgICAgIHZhciBzdyA9IHNicmsoYXR0cmlidXRlX3dlaWdodHMubGVuZ3RoICogNCk7CiAgICAgICAgICB2YXIgc2kgPSBzYnJrKGluZGV4X2NvdW50ICogNCk7CiAgICAgICAgICB2YXIgdmwgPSB2ZXJ0ZXhfbG9jayA/IHNicmsodmVydGV4X2NvdW50KSA6IDA7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfcG9zaXRpb25zKSwgc3ApOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X2F0dHJpYnV0ZXMpLCBzYSk7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhhdHRyaWJ1dGVfd2VpZ2h0cyksIHN3KTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKGluZGljZXMpLCBzaSk7CiAgICAgICAgICBpZiAodmVydGV4X2xvY2spIHsKICAgICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X2xvY2spLCB2bCk7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgcmVzdWx0ID0gZnVuKAogICAgICAgICAgICBzaSwKICAgICAgICAgICAgaW5kZXhfY291bnQsCiAgICAgICAgICAgIHNwLAogICAgICAgICAgICB2ZXJ0ZXhfY291bnQsCiAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICBzYSwKICAgICAgICAgICAgdmVydGV4X2F0dHJpYnV0ZXNfc3RyaWRlLAogICAgICAgICAgICBzdywKICAgICAgICAgICAgYXR0cmlidXRlX3dlaWdodHMubGVuZ3RoLAogICAgICAgICAgICB2bCwKICAgICAgICAgICAgdGFyZ2V0X2luZGV4X2NvdW50LAogICAgICAgICAgICB0YXJnZXRfZXJyb3IsCiAgICAgICAgICAgIG9wdGlvbnMsCiAgICAgICAgICAgIHRlMgogICAgICAgICAgKTsKICAgICAgICAgIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgYnl0ZXMoaW5kaWNlcykuc2V0KGhlYXAuc3ViYXJyYXkoc2ksIHNpICsgcmVzdWx0ICogNCkpOwogICAgICAgICAgYnl0ZXModmVydGV4X3Bvc2l0aW9ucykuc2V0KGhlYXAuc3ViYXJyYXkoc3AsIHNwICsgdmVydGV4X2NvdW50ICogdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpKTsKICAgICAgICAgIGJ5dGVzKHZlcnRleF9hdHRyaWJ1dGVzKS5zZXQoaGVhcC5zdWJhcnJheShzYSwgc2EgKyB2ZXJ0ZXhfY291bnQgKiB2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUpKTsKICAgICAgICAgIHZhciBlcnJvciA9IG5ldyBGbG9hdDMyQXJyYXkoMSk7CiAgICAgICAgICBieXRlcyhlcnJvcikuc2V0KGhlYXAuc3ViYXJyYXkodGUyLCB0ZTIgKyA0KSk7CiAgICAgICAgICBzYnJrKHRlMiAtIHNicmsoMCkpOwogICAgICAgICAgcmV0dXJuIFtyZXN1bHQsIGVycm9yWzBdXTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gc2ltcGxpZnlTY2FsZShmdW4sIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHNwID0gc2Jyayh2ZXJ0ZXhfY291bnQgKiB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfcG9zaXRpb25zKSwgc3ApOwogICAgICAgICAgdmFyIHJlc3VsdCA9IGZ1bihzcCwgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSk7CiAgICAgICAgICBzYnJrKHNwIC0gc2JyaygwKSk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBzaW1wbGlmeVBvaW50cyhmdW4sIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZlcnRleF9jb2xvcnMsIHZlcnRleF9jb2xvcnNfc3RyaWRlLCBjb2xvcl93ZWlnaHQsIHRhcmdldF92ZXJ0ZXhfY291bnQpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHRpID0gc2Jyayh0YXJnZXRfdmVydGV4X2NvdW50ICogNCk7CiAgICAgICAgICB2YXIgc3AgPSBzYnJrKHZlcnRleF9jb3VudCAqIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKTsKICAgICAgICAgIHZhciBzYyA9IHZlcnRleF9jb2xvcnMgPyBzYnJrKHZlcnRleF9jb3VudCAqIHZlcnRleF9jb2xvcnNfc3RyaWRlKSA6IDA7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfcG9zaXRpb25zKSwgc3ApOwogICAgICAgICAgaWYgKHZlcnRleF9jb2xvcnMpIHsKICAgICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X2NvbG9ycyksIHNjKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciByZXN1bHQgPSBmdW4odGksIHNwLCB2ZXJ0ZXhfY291bnQsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLCBzYywgdmVydGV4X2NvbG9yc19zdHJpZGUsIGNvbG9yX3dlaWdodCwgdGFyZ2V0X3ZlcnRleF9jb3VudCk7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciB0YXJnZXQgPSBuZXcgVWludDMyQXJyYXkocmVzdWx0KTsKICAgICAgICAgIGJ5dGVzKHRhcmdldCkuc2V0KGhlYXAuc3ViYXJyYXkodGksIHRpICsgcmVzdWx0ICogNCkpOwogICAgICAgICAgc2Jyayh0aSAtIHNicmsoMCkpOwogICAgICAgICAgcmV0dXJuIHRhcmdldDsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gc2ltcGxpZnlTbG9wcHkoZnVuLCBpbmRpY2VzLCBpbmRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdmVydGV4X2xvY2ssIHRhcmdldF9pbmRleF9jb3VudCwgdGFyZ2V0X2Vycm9yKSB7CiAgICAgICAgICB2YXIgc2JyayA9IGluc3RhbmNlLmV4cG9ydHMuc2JyazsKICAgICAgICAgIHZhciB0ZTIgPSBzYnJrKDQpOwogICAgICAgICAgdmFyIHRpID0gc2JyayhpbmRleF9jb3VudCAqIDQpOwogICAgICAgICAgdmFyIHNwID0gc2Jyayh2ZXJ0ZXhfY291bnQgKiB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSk7CiAgICAgICAgICB2YXIgc2kgPSBzYnJrKGluZGV4X2NvdW50ICogNCk7CiAgICAgICAgICB2YXIgdmwgPSB2ZXJ0ZXhfbG9jayA/IHNicmsodmVydGV4X2NvdW50KSA6IDA7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfcG9zaXRpb25zKSwgc3ApOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMoaW5kaWNlcyksIHNpKTsKICAgICAgICAgIGlmICh2ZXJ0ZXhfbG9jaykgewogICAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfbG9jayksIHZsKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciByZXN1bHQgPSBmdW4odGksIHNpLCBpbmRleF9jb3VudCwgc3AsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZsLCB0YXJnZXRfaW5kZXhfY291bnQsIHRhcmdldF9lcnJvciwgdGUyKTsKICAgICAgICAgIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgdmFyIHRhcmdldCA9IG5ldyBVaW50MzJBcnJheShyZXN1bHQpOwogICAgICAgICAgYnl0ZXModGFyZ2V0KS5zZXQoaGVhcC5zdWJhcnJheSh0aSwgdGkgKyByZXN1bHQgKiA0KSk7CiAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRmxvYXQzMkFycmF5KDEpOwogICAgICAgICAgYnl0ZXMoZXJyb3IpLnNldChoZWFwLnN1YmFycmF5KHRlMiwgdGUyICsgNCkpOwogICAgICAgICAgc2Jyayh0ZTIgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiBbdGFyZ2V0LCBlcnJvclswXV07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIHNpbXBsaWZ5UHJ1bmUoZnVuLCBpbmRpY2VzLCBpbmRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdGFyZ2V0X2Vycm9yKSB7CiAgICAgICAgICB2YXIgc2JyayA9IGluc3RhbmNlLmV4cG9ydHMuc2JyazsKICAgICAgICAgIHZhciB0aSA9IHNicmsoaW5kZXhfY291bnQgKiA0KTsKICAgICAgICAgIHZhciBzcCA9IHNicmsodmVydGV4X2NvdW50ICogdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpOwogICAgICAgICAgdmFyIHNpID0gc2JyayhpbmRleF9jb3VudCAqIDQpOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X3Bvc2l0aW9ucyksIHNwKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKGluZGljZXMpLCBzaSk7CiAgICAgICAgICB2YXIgcmVzdWx0ID0gZnVuKHRpLCBzaSwgaW5kZXhfY291bnQsIHNwLCB2ZXJ0ZXhfY291bnQsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLCB0YXJnZXRfZXJyb3IpOwogICAgICAgICAgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICB2YXIgdGFyZ2V0ID0gbmV3IFVpbnQzMkFycmF5KHJlc3VsdCk7CiAgICAgICAgICBieXRlcyh0YXJnZXQpLnNldChoZWFwLnN1YmFycmF5KHRpLCB0aSArIHJlc3VsdCAqIDQpKTsKICAgICAgICAgIHNicmsodGkgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiB0YXJnZXQ7CiAgICAgICAgfQogICAgICAgIHZhciBzaW1wbGlmeU9wdGlvbnMgPSB7CiAgICAgICAgICBMb2NrQm9yZGVyOiAxLAogICAgICAgICAgU3BhcnNlOiAyLAogICAgICAgICAgRXJyb3JBYnNvbHV0ZTogNCwKICAgICAgICAgIFBydW5lOiA4LAogICAgICAgICAgUmVndWxhcml6ZTogMTYsCiAgICAgICAgICBQZXJtaXNzaXZlOiAzMiwKICAgICAgICAgIFJlZ3VsYXJpemVMaWdodDogNjQsCiAgICAgICAgICBfSW50ZXJuYWxEZWJ1ZzogMSA8PCAzMAogICAgICAgICAgLy8gaW50ZXJuYWwsIGRvbid0IHVzZSEKICAgICAgICB9OwogICAgICAgIHJldHVybiB7CiAgICAgICAgICByZWFkeSwKICAgICAgICAgIHN1cHBvcnRlZDogdHJ1ZSwKICAgICAgICAgIGNvbXBhY3RNZXNoOiBmdW5jdGlvbihpbmRpY2VzKSB7CiAgICAgICAgICAgIGFzc2VydCgKICAgICAgICAgICAgICBpbmRpY2VzIGluc3RhbmNlb2YgVWludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQxNkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBJbnQxNkFycmF5CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGFzc2VydChpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIHZhciBpbmRpY2VzMzIgPSBpbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5UID09IDQgPyBpbmRpY2VzIDogbmV3IFVpbnQzMkFycmF5KGluZGljZXMpOwogICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmVvcmRlcihpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfb3B0aW1pemVWZXJ0ZXhGZXRjaFJlbWFwLCBpbmRpY2VzMzIsIG1heGluZGV4KGluZGljZXMpICsgMSk7CiAgICAgICAgICAgIGlmIChpbmRpY2VzICE9PSBpbmRpY2VzMzIpIHsKICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgaW5kaWNlczMyLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgICAgaW5kaWNlc1tpMl0gPSBpbmRpY2VzMzJbaTJdOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfSwKICAgICAgICAgIGdlbmVyYXRlUG9zaXRpb25SZW1hcDogZnVuY3Rpb24odmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpIHsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggJSB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID49IDMpOwogICAgICAgICAgICByZXR1cm4gZ2VucmVtYXAoCiAgICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2dlbmVyYXRlUG9zaXRpb25SZW1hcCwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUKICAgICAgICAgICAgKTsKICAgICAgICAgIH0sCiAgICAgICAgICBzaW1wbGlmeTogZnVuY3Rpb24oaW5kaWNlcywgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHRhcmdldF9pbmRleF9jb3VudCwgdGFyZ2V0X2Vycm9yLCBmbGFncykgewogICAgICAgICAgICBhc3NlcnQoCiAgICAgICAgICAgICAgaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQzMkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBJbnQzMkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBVaW50MTZBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgSW50MTZBcnJheQogICAgICAgICAgICApOwogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcy5sZW5ndGggJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucyBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAlIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPj0gMyk7CiAgICAgICAgICAgIGFzc2VydCh0YXJnZXRfaW5kZXhfY291bnQgPj0gMCAmJiB0YXJnZXRfaW5kZXhfY291bnQgPD0gaW5kaWNlcy5sZW5ndGgpOwogICAgICAgICAgICBhc3NlcnQodGFyZ2V0X2luZGV4X2NvdW50ICUgMyA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHRhcmdldF9lcnJvciA+PSAwKTsKICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAwOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgKGZsYWdzID8gZmxhZ3MubGVuZ3RoIDogMCk7ICsraTIpIHsKICAgICAgICAgICAgICBhc3NlcnQoZmxhZ3NbaTJdIGluIHNpbXBsaWZ5T3B0aW9ucyk7CiAgICAgICAgICAgICAgb3B0aW9ucyB8PSBzaW1wbGlmeU9wdGlvbnNbZmxhZ3NbaTJdXTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgaW5kaWNlczMyID0gaW5kaWNlcy5CWVRFU19QRVJfRUxFTUVOVCA9PSA0ID8gaW5kaWNlcyA6IG5ldyBVaW50MzJBcnJheShpbmRpY2VzKTsKICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHNpbXBsaWZ5KAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9zaW1wbGlmeSwKICAgICAgICAgICAgICBpbmRpY2VzMzIsCiAgICAgICAgICAgICAgaW5kaWNlcy5sZW5ndGgsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucywKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCwKICAgICAgICAgICAgICB0YXJnZXRfaW5kZXhfY291bnQsCiAgICAgICAgICAgICAgdGFyZ2V0X2Vycm9yLAogICAgICAgICAgICAgIG9wdGlvbnMKICAgICAgICAgICAgKTsKICAgICAgICAgICAgcmVzdWx0WzBdID0gaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQzMkFycmF5ID8gcmVzdWx0WzBdIDogbmV3IGluZGljZXMuY29uc3RydWN0b3IocmVzdWx0WzBdKTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0sCiAgICAgICAgICBzaW1wbGlmeVdpdGhBdHRyaWJ1dGVzOiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdmVydGV4X2F0dHJpYnV0ZXMsIHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSwgYXR0cmlidXRlX3dlaWdodHMsIHZlcnRleF9sb2NrLCB0YXJnZXRfaW5kZXhfY291bnQsIHRhcmdldF9lcnJvciwgZmxhZ3MpIHsKICAgICAgICAgICAgYXNzZXJ0KAogICAgICAgICAgICAgIGluZGljZXMgaW5zdGFuY2VvZiBVaW50MzJBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgSW50MzJBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgVWludDE2QXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDE2QXJyYXkKICAgICAgICAgICAgKTsKICAgICAgICAgICAgYXNzZXJ0KGluZGljZXMubGVuZ3RoICUgMyA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggJSB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID49IDMpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXMubGVuZ3RoID09IHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSAqICh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUgPj0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfbG9jayA9PSBudWxsIHx8IHZlcnRleF9sb2NrIGluc3RhbmNlb2YgVWludDhBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfbG9jayA9PSBudWxsIHx8IHZlcnRleF9sb2NrLmxlbmd0aCA9PSB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKTsKICAgICAgICAgICAgYXNzZXJ0KHRhcmdldF9pbmRleF9jb3VudCA+PSAwICYmIHRhcmdldF9pbmRleF9jb3VudCA8PSBpbmRpY2VzLmxlbmd0aCk7CiAgICAgICAgICAgIGFzc2VydCh0YXJnZXRfaW5kZXhfY291bnQgJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQodGFyZ2V0X2Vycm9yID49IDApOwogICAgICAgICAgICBhc3NlcnQoQXJyYXkuaXNBcnJheShhdHRyaWJ1dGVfd2VpZ2h0cykpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXNfc3RyaWRlID49IGF0dHJpYnV0ZV93ZWlnaHRzLmxlbmd0aCk7CiAgICAgICAgICAgIGFzc2VydChhdHRyaWJ1dGVfd2VpZ2h0cy5sZW5ndGggPD0gMzIpOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgYXR0cmlidXRlX3dlaWdodHMubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgYXNzZXJ0KGF0dHJpYnV0ZV93ZWlnaHRzW2kyXSA+PSAwKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgb3B0aW9ucyA9IDA7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCAoZmxhZ3MgPyBmbGFncy5sZW5ndGggOiAwKTsgKytpMikgewogICAgICAgICAgICAgIGFzc2VydChmbGFnc1tpMl0gaW4gc2ltcGxpZnlPcHRpb25zKTsKICAgICAgICAgICAgICBvcHRpb25zIHw9IHNpbXBsaWZ5T3B0aW9uc1tmbGFnc1tpMl1dOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBpbmRpY2VzMzIgPSBpbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5UID09IDQgPyBpbmRpY2VzIDogbmV3IFVpbnQzMkFycmF5KGluZGljZXMpOwogICAgICAgICAgICB2YXIgcmVzdWx0ID0gc2ltcGxpZnlBdHRyKAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9zaW1wbGlmeVdpdGhBdHRyaWJ1dGVzLAogICAgICAgICAgICAgIGluZGljZXMzMiwKICAgICAgICAgICAgICBpbmRpY2VzLmxlbmd0aCwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgIHZlcnRleF9hdHRyaWJ1dGVzLAogICAgICAgICAgICAgIHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSAqIDQsCiAgICAgICAgICAgICAgbmV3IEZsb2F0MzJBcnJheShhdHRyaWJ1dGVfd2VpZ2h0cyksCiAgICAgICAgICAgICAgdmVydGV4X2xvY2ssCiAgICAgICAgICAgICAgdGFyZ2V0X2luZGV4X2NvdW50LAogICAgICAgICAgICAgIHRhcmdldF9lcnJvciwKICAgICAgICAgICAgICBvcHRpb25zCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIHJlc3VsdFswXSA9IGluZGljZXMgaW5zdGFuY2VvZiBVaW50MzJBcnJheSA/IHJlc3VsdFswXSA6IG5ldyBpbmRpY2VzLmNvbnN0cnVjdG9yKHJlc3VsdFswXSk7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICB9LAogICAgICAgICAgc2ltcGxpZnlXaXRoVXBkYXRlOiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdmVydGV4X2F0dHJpYnV0ZXMsIHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSwgYXR0cmlidXRlX3dlaWdodHMsIHZlcnRleF9sb2NrLCB0YXJnZXRfaW5kZXhfY291bnQsIHRhcmdldF9lcnJvciwgZmxhZ3MpIHsKICAgICAgICAgICAgYXNzZXJ0KAogICAgICAgICAgICAgIGluZGljZXMgaW5zdGFuY2VvZiBVaW50MzJBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgSW50MzJBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgVWludDE2QXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDE2QXJyYXkKICAgICAgICAgICAgKTsKICAgICAgICAgICAgYXNzZXJ0KGluZGljZXMubGVuZ3RoICUgMyA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggJSB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID49IDMpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXMubGVuZ3RoID09IHZlcnRleF9hdHRyaWJ1dGVzX3N0cmlkZSAqICh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUgPj0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfbG9jayA9PSBudWxsIHx8IHZlcnRleF9sb2NrIGluc3RhbmNlb2YgVWludDhBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfbG9jayA9PSBudWxsIHx8IHZlcnRleF9sb2NrLmxlbmd0aCA9PSB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKTsKICAgICAgICAgICAgYXNzZXJ0KHRhcmdldF9pbmRleF9jb3VudCA+PSAwICYmIHRhcmdldF9pbmRleF9jb3VudCA8PSBpbmRpY2VzLmxlbmd0aCk7CiAgICAgICAgICAgIGFzc2VydCh0YXJnZXRfaW5kZXhfY291bnQgJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQodGFyZ2V0X2Vycm9yID49IDApOwogICAgICAgICAgICBhc3NlcnQoQXJyYXkuaXNBcnJheShhdHRyaWJ1dGVfd2VpZ2h0cykpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X2F0dHJpYnV0ZXNfc3RyaWRlID49IGF0dHJpYnV0ZV93ZWlnaHRzLmxlbmd0aCk7CiAgICAgICAgICAgIGFzc2VydChhdHRyaWJ1dGVfd2VpZ2h0cy5sZW5ndGggPD0gMzIpOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgYXR0cmlidXRlX3dlaWdodHMubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgYXNzZXJ0KGF0dHJpYnV0ZV93ZWlnaHRzW2kyXSA+PSAwKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgb3B0aW9ucyA9IDA7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCAoZmxhZ3MgPyBmbGFncy5sZW5ndGggOiAwKTsgKytpMikgewogICAgICAgICAgICAgIGFzc2VydChmbGFnc1tpMl0gaW4gc2ltcGxpZnlPcHRpb25zKTsKICAgICAgICAgICAgICBvcHRpb25zIHw9IHNpbXBsaWZ5T3B0aW9uc1tmbGFnc1tpMl1dOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBpbmRpY2VzMzIgPSBpbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5UID09IDQgPyBpbmRpY2VzIDogbmV3IFVpbnQzMkFycmF5KGluZGljZXMpOwogICAgICAgICAgICB2YXIgcmVzdWx0ID0gc2ltcGxpZnlVcGRhdGUoCiAgICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X3NpbXBsaWZ5V2l0aFVwZGF0ZSwKICAgICAgICAgICAgICBpbmRpY2VzMzIsCiAgICAgICAgICAgICAgaW5kaWNlcy5sZW5ndGgsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucywKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCwKICAgICAgICAgICAgICB2ZXJ0ZXhfYXR0cmlidXRlcywKICAgICAgICAgICAgICB2ZXJ0ZXhfYXR0cmlidXRlc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgIG5ldyBGbG9hdDMyQXJyYXkoYXR0cmlidXRlX3dlaWdodHMpLAogICAgICAgICAgICAgIHZlcnRleF9sb2NrLAogICAgICAgICAgICAgIHRhcmdldF9pbmRleF9jb3VudCwKICAgICAgICAgICAgICB0YXJnZXRfZXJyb3IsCiAgICAgICAgICAgICAgb3B0aW9ucwogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAoaW5kaWNlcyAhPT0gaW5kaWNlczMyKSB7CiAgICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IHJlc3VsdFswXTsgKytpMikgewogICAgICAgICAgICAgICAgaW5kaWNlc1tpMl0gPSBpbmRpY2VzMzJbaTJdOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfSwKICAgICAgICAgIGdldFNjYWxlOiBmdW5jdGlvbih2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSkgewogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucyBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAlIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPj0gMyk7CiAgICAgICAgICAgIHJldHVybiBzaW1wbGlmeVNjYWxlKAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9zaW1wbGlmeVNjYWxlLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSAqIDQKICAgICAgICAgICAgKTsKICAgICAgICAgIH0sCiAgICAgICAgICBzaW1wbGlmeVBvaW50czogZnVuY3Rpb24odmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHRhcmdldF92ZXJ0ZXhfY291bnQsIHZlcnRleF9jb2xvcnMsIHZlcnRleF9jb2xvcnNfc3RyaWRlLCBjb2xvcl93ZWlnaHQpIHsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggJSB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID49IDMpOwogICAgICAgICAgICBhc3NlcnQodGFyZ2V0X3ZlcnRleF9jb3VudCA+PSAwICYmIHRhcmdldF92ZXJ0ZXhfY291bnQgPD0gdmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSk7CiAgICAgICAgICAgIGlmICh2ZXJ0ZXhfY29sb3JzKSB7CiAgICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9jb2xvcnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfY29sb3JzLmxlbmd0aCAlIHZlcnRleF9jb2xvcnNfc3RyaWRlID09IDApOwogICAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfY29sb3JzX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSB2ZXJ0ZXhfY29sb3JzLmxlbmd0aCAvIHZlcnRleF9jb2xvcnNfc3RyaWRlKTsKICAgICAgICAgICAgICByZXR1cm4gc2ltcGxpZnlQb2ludHMoCiAgICAgICAgICAgICAgICBpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfc2ltcGxpZnlQb2ludHMsCiAgICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwKICAgICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCwKICAgICAgICAgICAgICAgIHZlcnRleF9jb2xvcnMsCiAgICAgICAgICAgICAgICB2ZXJ0ZXhfY29sb3JzX3N0cmlkZSAqIDQsCiAgICAgICAgICAgICAgICBjb2xvcl93ZWlnaHQgfHwgMCwKICAgICAgICAgICAgICAgIHRhcmdldF92ZXJ0ZXhfY291bnQKICAgICAgICAgICAgICApOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHJldHVybiBzaW1wbGlmeVBvaW50cygKICAgICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9zaW1wbGlmeVBvaW50cywKICAgICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMsCiAgICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgICAgdm9pZCAwLAogICAgICAgICAgICAgICAgMCwKICAgICAgICAgICAgICAgIDAsCiAgICAgICAgICAgICAgICB0YXJnZXRfdmVydGV4X2NvdW50CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIHNpbXBsaWZ5U2xvcHB5OiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdmVydGV4X2xvY2ssIHRhcmdldF9pbmRleF9jb3VudCwgdGFyZ2V0X2Vycm9yKSB7CiAgICAgICAgICAgIGFzc2VydCgKICAgICAgICAgICAgICBpbmRpY2VzIGluc3RhbmNlb2YgVWludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQxNkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBJbnQxNkFycmF5CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGFzc2VydChpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9sb2NrID09IG51bGwgfHwgdmVydGV4X2xvY2sgaW5zdGFuY2VvZiBVaW50OEFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9sb2NrID09IG51bGwgfHwgdmVydGV4X2xvY2subGVuZ3RoID09IHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpOwogICAgICAgICAgICBhc3NlcnQodGFyZ2V0X2luZGV4X2NvdW50ID49IDAgJiYgdGFyZ2V0X2luZGV4X2NvdW50IDw9IGluZGljZXMubGVuZ3RoKTsKICAgICAgICAgICAgYXNzZXJ0KHRhcmdldF9pbmRleF9jb3VudCAlIDMgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh0YXJnZXRfZXJyb3IgPj0gMCk7CiAgICAgICAgICAgIHZhciBpbmRpY2VzMzIgPSBpbmRpY2VzLkJZVEVTX1BFUl9FTEVNRU5UID09IDQgPyBpbmRpY2VzIDogbmV3IFVpbnQzMkFycmF5KGluZGljZXMpOwogICAgICAgICAgICB2YXIgcmVzdWx0ID0gc2ltcGxpZnlTbG9wcHkoCiAgICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X3NpbXBsaWZ5U2xvcHB5LAogICAgICAgICAgICAgIGluZGljZXMzMiwKICAgICAgICAgICAgICBpbmRpY2VzLmxlbmd0aCwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgIHZlcnRleF9sb2NrLAogICAgICAgICAgICAgIHRhcmdldF9pbmRleF9jb3VudCwKICAgICAgICAgICAgICB0YXJnZXRfZXJyb3IKICAgICAgICAgICAgKTsKICAgICAgICAgICAgcmVzdWx0WzBdID0gaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQzMkFycmF5ID8gcmVzdWx0WzBdIDogbmV3IGluZGljZXMuY29uc3RydWN0b3IocmVzdWx0WzBdKTsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH0sCiAgICAgICAgICBzaW1wbGlmeVBydW5lOiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgdGFyZ2V0X2Vycm9yKSB7CiAgICAgICAgICAgIGFzc2VydCgKICAgICAgICAgICAgICBpbmRpY2VzIGluc3RhbmNlb2YgVWludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIEludDMyQXJyYXkgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQxNkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBJbnQxNkFycmF5CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGFzc2VydChpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgYXNzZXJ0KHRhcmdldF9lcnJvciA+PSAwKTsKICAgICAgICAgICAgdmFyIGluZGljZXMzMiA9IGluZGljZXMuQllURVNfUEVSX0VMRU1FTlQgPT0gNCA/IGluZGljZXMgOiBuZXcgVWludDMyQXJyYXkoaW5kaWNlcyk7CiAgICAgICAgICAgIHZhciByZXN1bHQgPSBzaW1wbGlmeVBydW5lKAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9zaW1wbGlmeVBydW5lLAogICAgICAgICAgICAgIGluZGljZXMzMiwKICAgICAgICAgICAgICBpbmRpY2VzLmxlbmd0aCwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgIHRhcmdldF9lcnJvcgogICAgICAgICAgICApOwogICAgICAgICAgICByZXN1bHQgPSBpbmRpY2VzIGluc3RhbmNlb2YgVWludDMyQXJyYXkgPyByZXN1bHQgOiBuZXcgaW5kaWNlcy5jb25zdHJ1Y3RvcihyZXN1bHQpOwogICAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL21lc2hvcHRfY2x1c3Rlcml6ZXIuanMKICB2YXIgTWVzaG9wdENsdXN0ZXJpemVyOwogIHZhciBpbml0X21lc2hvcHRfY2x1c3Rlcml6ZXIgPSBfX2VzbSh7CiAgICAibm9kZV9tb2R1bGVzL21lc2hvcHRpbWl6ZXIvbWVzaG9wdF9jbHVzdGVyaXplci5qcyIoKSB7CiAgICAgIE1lc2hvcHRDbHVzdGVyaXplciA9IChmdW5jdGlvbigpIHsKICAgICAgICB2YXIgd2FzbTIgPSAiYjlINzlUZWJiYmU6bmVQOUdldWV1OUdldWI5R2JiOUdpdXV1ZXU5R211dXV1dXV1dXV1dTk5OTlldTlHb3V1dXV1dWV1OUdydXV1dXV1dWI5R3h1dXV1dXV1dXV1dXVldTlHeHV1dXV1dXV1dXV1OTlldTlHUHV1dXV1dXV1dXV1dXU5OWI5R291dXV1dXViOUd3dXV1dXV1dXViOUd2dXV1dXViOUdsdXV1dWJpUVhkaWx2b3J3RHFva29xeG1iaWliZWlsdmU5V2VpaXZpZWJlb3dldWVjajpHZGtyO1plcW85VFc5VDlWVjk1ZGJIOUY5RjkzOUg3OVQ5RjlKOUgyMjlGOUp0OVZWN2JiOEE5VFc3OU85VjlXdDlGOUk5MTlQMjlLOW5XNzlPMld0NzljOVY5MTlVOUtiZVk5VFc3OU85VjlXdDlGOUk5MTlQMjlLOW5XNzlPMld0N1MyVzk0YmQzOVRXNzlPOVY5V3Q5RjlJOTE5UDI5SzluVzc5TzJXdDc5dDlXOUh0OVA5SDJibzM5VFc3OU85VjlXdDlGOUo5VjlUOVc5MXRXSjI5MTd0V1Y5YzlWOTE5VTlLN2J3MzlUVzc5TzlWOVd0OUY5SjlWOVQ5VzkxdFc5blc3OU8yV3Q5YzlWOTE5VTlLN2JrRTlUVzc5TzlWOVd0OUY5SjlWOVQ5VzkxdFc5dDlXOU9XVlc5YzlWOTE5VTlLN2J4TDlUVzc5TzlWOVd0OUY5VjlXdDlQOVQ5UDk2VzluVzc5TzJXdGJQbDc5SVY5UmJzRHdlYmNla2RPQXE7VzpsZVhkYmtJYmFiYWVjOTpmZ2VmY3VmYWU5VWdlYWJjaTlVYWRmY3VmYWQ5VWdiYWVhYjBFazo4OEpEUHVlOTlldXg5OWR1ZTk5ZXVvOTlpdThKampqamJjOldEOVJnbThLampqamJkbmRuYWxtYmNiaFB4ZWthbWM6Q3dmY2JjO0tiejpyampqYjhBY3Vhb2NkdGdzYW9jRkZGRmkwRWh6Y2J5ZDswOkc6Y2piaEhkbmRuYWxjYjlpbWJhb2FsOW5tYmFtYXphSEhqampqYmJnSEJkOkN3YW1jZUJkOzh3YW1hemNieWQ7MDpHOmNqYkhqampqYmJnT0JkOkd3YW1jZEJkOzh3YW1jdWFsY2R0YWxjRkZGRmkwRWNieWQ7MDpHOmNqYkhqampqYmJnQUJkOkt3YW1jaUJkOzh3YWloemFsaHNpbmFIYXp5ZGJjZHRmY2JCZGJhemNsZmh6YXNjdWZnc21ia2FpaHphbGhzaW5hSGF6eWRiY2R0ZmdDYUN5ZGJjZWZCZGJhemNsZmh6YXNjdWZnc21ia2FpaHphbGhDY2JoWGluZG5hSGF6eWRiY2R0Z1FmZ3N5ZGJjYjlpbWJhT2FRZmFYQmRiYXNhc3lkYmdRY2pqamo5NFZCZGJhUWFYZmhYa2F6Y2xmaHphQ2N1ZmdDbWJrYWxjaTlVaExkbmFsY2k2bWJjYmh6YWloc2luYXNjd2Z5ZGJoQ2FzY2xmeWRiaFhhT2FzeWRiY2R0ZmdRYVF5ZGJnUWNlZkJkYmFBYVFjZHRmYXpCZGJhT2FYY2R0ZmdYYVh5ZGJnWGNlZkJkYmFBYVhjZHRmYXpCZGJhT2FDY2R0ZmdDYUN5ZGJnQ2NlZkJkYmFBYUNjZHRmYXpCZGJhc2N4ZmhzYUxhemNlZmd6OWhtYmtrYWloemFsaHNpbmRuYUhhenlkYmNkdGdDZmdYeWRiZ1FjdTlrbWJhWGFRY0ZGRkZyR2dRQmRiYU9hQ2ZnQ2FDeWRiYVE5UkJkYmthemNsZmh6YXNjdWZnc21ieGRra2FtYXphSEhqampqYmJnSEJkOkN3YW1jZUJkOzh3YW1hemNieWQ7MDpHOmNqYkhqampqYmJnT0JkOkd3YW1jZEJkOzh3YW1jdWFsY2R0YWxjRkZGRmkwRWNieWQ7MDpHOmNqYkhqampqYmJnQUJkOkt3YW1jaUJkOzh3YUhjYmFzejpyampqYmhYYWloemFsaHNpbmFYYXp5ZGJjZHRmZ0NhQ3lkYmNlZkJkYmF6Y2xmaHphc2N1ZmdzbWJrYWxjaTlVaExkbmFvVG1iY2JoemFPaHNhWGhDYW9oUWluYXNhekJkYmFzY2xmaHNhQ3lkYmF6Zmh6YUNjbGZoQ2FRY3VmZ1FtYmtrZG5hbGNpNm1iY2JoemFpaHNpbmFzY3dmeWRiaENhc2NsZnlkYmhRYU9hc3lkYmNkdGZnS2FLeWRiZ0tjZWZCZGJhQWFLY2R0ZmF6QmRiYU9hUWNkdGZnUWFReWRiZ1FjZWZCZGJhQWFRY2R0ZmF6QmRiYU9hQ2NkdGZnQ2FDeWRiZ0NjZWZCZGJhQWFDY2R0ZmF6QmRiYXNjeGZoc2FMYXpjZWZnejlobWJra2FvVG1iY2JoemFvaHNpbmFPYXpmZ0NhQ3lkYmFYYXpmeWRiOVJCZGJhemNsZmh6YXNjdWZnc21ia2thbWFMY2J5ZDswOkc6Y2piSGpqampiYmd6QmQ6T3dhbWNsQmQ7OHdhemNiYUx6OnJqampiaFlhbWN1YUxjSzJhbGNqampqZDBFY2J5ZDswOkc6Y2piSGpqampiYmc4QUJkOlN3YW1jdkJkOzh3SmJiYmJoRWRuYWxjaTZnM21iYXJjZDRoS2FpaHNhOEFoemFMaHJKYmJiYmg1aW5hdmFzY2xmeWRiYUsyY2R0ZmdDSWRsaDhFYXZhc3lkYmFLMmNkdGZnWElkbGhFYXZhc2N3ZnlkYmFLMmNkdGZnUUlkbGg4RmFDSWR3aGFhWElkd2hoYVFJZHdoZ2F6YUNJZGJnOEphWElkYmc4S01hUUlkYmc4TE1KYmJubjp2VWRiYXpjbGZhWElkbGFDSWRsTWFRSWRsTUpiYm5uOnZVZGJhUUlkd2g4TWFDSWR3aDhOYVhJZHdoeWF6Y3hmYThFYUU6dGc4RWFnYWg6dGdnTmFhYWg6dGdhYThGYUU6dGdoTjp0Z0VKYmJiYkpiYmpaYThKYThLOnRnOEZhaE5hOEVhOExhOEs6dGc4S046dGdoYWhOYUVhRU5hYWE4S05hOEZhZ046dGdFYUVOTU1nOEs6cmc4RTp2YThLSmJiYmI5QkVnOEtOVWRiYXpjemZhRWE4S05VZGJhemNDZmFoYThLTlVkYmF6Y3dmYThNYXlhOE5NTUpiYm5uOnZVZGJhNWE4RU1oNWFzY3hmaHNhemNLZmh6YXJjdWZncm1ia2E1YUw6Wjp2SmJiYlpOaEVrYW1jdWFMY2R0YWxjRkZGRjk3MEVjYnlkOzA6RzpjamJIampqamJiZ0NCZDpXd2FtY29CZDs4d2FxOlpoaGRuYTNtYmNiaHphQ2hzaW5hc2F6QmRiYXNjbGZoc2FMYXpjZWZnejlobWJra2FFYWhOaGhhbWN1YUxjbHRhbGNGRkZGZDBFY2J5ZDswOkc6Y2piSGpqampiYmc4UEJkOjB3YW1jckJkOzh3Y2JhOFBhOEFhQ2FMY2J6OmRqampiOEFKRkZ1dWg4TUpGRnV1aDhOSkZGdXVoeWRuYWxjaTZtYkpGRnV1aHlhOEFoemFMaHNKRkZ1dWg4TkpGRnV1aDhNaW5hemN3ZklkYmdFYThNYThNYUU5RUVoOE1hemNsZklkYmdFYThOYThOYUU5RUVoOE5heklkYmdFYXlheWFFOUVFaHlhemNLZmh6YXNjdWZnc21ia2thaDpyaEVhbWFvY2V0Z3pjdWFvY3U5a0VjYnlkOzA6RzpjamJIampqamJiZ0NCZDo0d2RuZG5hb2FsOW5tYmFpaHphbGhzaW5hQ2F6eWRiY2V0ZmNGRmk4N2ViYXpjbGZoemFzY3VmZ3NtYnhka2thQ2NGZWF6ejpyampqYjhBa2FFSmJiYlpOaDhKY3VoSWRuYWxjaTZtYmNiaHNKRkZ1dWhFYThBaHpjdWhJaW5hemN3ZklkYmE4TTp0Z2hhaE5heklkYmF5OnRnaGFoTmF6Y2xmSWRiYThOOnRnaGFoTk1NOnJnaGFFYUljdVNhaGFFOURWZ1hFaEVhc2FJYVhFaElhemNLZmh6YUxhc2NlZmdzOWhtYmtrYW1jemZjYmNqd3o6cmpqamI4QWFtOWNiODNpd2FtOWNiODNpYmF4YThKTmg4UkpiYmpaYWs6dGg4TGNiaDhTSmJiYmJoUkpiYmJiaDhVSmJiYmJoOFZKYmJiYmg4V0piYmJiaDhYSmJiYmJoOFljYmg4WmNiaFBpbkpiYmJiaEVkbmE4U1RtYkpiYmpaYThTOlo6dmhFa0piYmJiaGhkbmE4WWE4WU5hOFdhOFdOYThYYThYTk1NZzhLSmJiYmI5Qm1iSmJialphOEs6cjp2aGhrYThWYUVOaDhLYThVYUVOaDVhUmFFTmg4RWFJaExkbmRuZG5kbmRuYThTYVBWVG1iYW15ZHdnODBUbWVhOFlhaE5oOEZhOFhhaE5oYWE4V2FoTmhnYWVhbXlkYmNkdGZoODFjYmgzSkZGdXVoRWN2aFFjdWhMaW5kbmFIYTgxYTNjZHRmeWRiY2R0Z3pmeWRiZ3ZUbWJhQWFPYXpmeWRiY2R0ZmhzaW5kbmRuYUNhaWFzeWRiZ0tjeDJmZ3pjbGZ5ZGJncmNldGY4VmViY3M0YUNhenlkYmdYY2V0ZjhWZWJjczRmYUNhemN3ZnlkYmdsY2V0ZjhWZWJjczRmZ29tYmNiaHp4ZWtjZWh6YUhhWGNkdGZ5ZGJnWGNlU21iY2VoemFIYXJjZHRmeWRiZ3JjZVNtYmNlaHphSGFsY2R0ZnlkYmdsY2VTbWJkbmFyY2RTYVhjZFNmYWxjZFNmY2Q2bWJhb2NlZmh6eGVrYW9jZGZoemtkbmF6YVE5a21iYThBYUtjSzJmZ1hJZHdhOEs6dGdoYWhOYVhJZGJhOEU6dGdoYWhOYVhJZGxhNTp0Z2hhaE5NTTpyYThKOnZhOExOSmJialpNSjlWTzpkODZKYmJqWmFYSWRDYThGTmFYSWR4YWdOYWFhWElkek5NTWFrTjp0Z2hhaEo5Vk86ZDg2OURFTmdoYUVhemFRNmFoYUU5RFZnWEVoRWFLYUxhWEVoTGF6YVFhWEVoUWthc2NsZmhzYXZjdWZndm1ia2thM2NlZmczYTgwOWhtYmtrYUxjdTlobWVrYW1hOEtVZDpPRGFtYTVVZDpLRGFtYThFVWQ6R0RhbWN1QmQ6cURhbWNGRkY7N3JCZGpEYThQY2JhOEFhWWFtYzpHRGZhbWM6cURmYW1jakRmejplampqYmFteWQ6cURoTGRuZG5heEpiYmJiOUVUbWJhOFNhRDZtYmFMY3VTbWVjZWgzYW1JZGpEYThSOUVtaXhka2FMY3U5aG1la2RuYThTVG1iYWJhUGNsdGZnSGFtOFBpdzgzZHdhSGFtOFBpYjgzZGJhUGNlZmhQa2MzaEhpbmFtYzpDd2ZhSGZ5ZGJjYnlkOzQ6RzpjamJIOmJqampiYmFIYzk4ZmdIYzk4OWhtYnh2a2tjYmgzYThTYXE5cG1iYW15ZHdhQ2FpYUxjeDJmZ3p5ZGJjZXRmOFZlYmNzNGFDYXpjd2Z5ZGJjZXRmOFZlYmNzNGZhQ2F6Y2xmeWRiY2V0ZjhWZWJjczRmZmF3OW5tZWtjYmh6Y2Joc2RuYThaVG1iY2Joc2FtY3pmaFhpbmFtY3pmYXNjZHRmYVh5ZGJnUUJkYmFYY2xmaFhhc2FZYVFmUmJiVGZoc2E4WmN1Zmc4Wm1ia2thbXlkd2hsYW15ZGJoWGFtOWN1ODNpOkdEYW05Y3U4M2k6T0RhbTljdTgzaTpxRGFtOWN1ODNpOnlEaW5hbWNqRGZhemZjRkZGOzdyQmRiYXpjbGZnemN6OWhtYmthc2M7OGVhc2NsZmM6YmQ2RWc4WmNkdGg4MGRuYWxUbWJhZWFYY2R0ZmhvY2JocmluZG5hSGFvYXJjZHRmeWRiY2R0Z3pmeWRiZ3ZUbWJhQWFPYXpmeWRiY2R0ZmhzY3VoUWN1aHppbmFIYWlhc3lkYmdLY3gyZmdYY2xmeWRiY2R0ZnlkYmFIYVh5ZGJjZHRmeWRiZmFIYVhjd2Z5ZGJjZHRmeWRiZmdYYXphWGF6NmdYRWh6YUthUWFYRWhRYXNjbGZoc2F2Y3VmZ3ZtYmthUWN1U21iYThBYVFjSzJmZ3NJZHdhOE06dGdFYUVOYXNJZGJheTp0Z0VhRU5hc0lkbGE4Tjp0Z0VhRU5NTTpyaEVjYmhzaW5kbmRuYXphbWM6cURmYXNmZ3Z5ZGJnWDZtYmF6YVg5aG1lYUVhbWNqRGZhc2ZJZGI5RlRtZWthdmF6QmRiYW1jOkdEZmFzZmFRQmRiYW1jakRmYXNmYUVVZGJ4ZGthc2NsZmdzY3o5aG1ia2thcmNlZmdyYWw5aG1ia2thbWN6ZmE4MGZoUWNiaHpjYmhzaW5kbmFtYzpHRGZhemZ5ZGJnWGN1U21iYVFhc2NkdGZhWEJkYmFzY2VmaHNrYXpjbGZnemN6OWhtYmthc2E4WmZnOFpUbWJKRkZ1dWhoY3VoS2FtY3pmaHphOFpodmN1aFFpbmE4QWF6eWRiZ1hjSzJmZ3NJZHdhOE06dGdFYUVOYXNJZGJheTp0Z0VhRU5hc0lkbGE4Tjp0Z0VhRU5NTTpyaEVkbmRuYUhhaWFYY3gyZmdzY2xmeWRiY2R0ZnlkYmFIYXN5ZGJjZHRmeWRiZmFIYXNjd2Z5ZGJjZHRmeWRiZmdzYVE2bWJhc2FROWhtZWFFYWg5RFRtZWthRWhoYXNoUWFYaEtrYXpjbGZoemF2Y3VmZ3ZtYmthS2N1U21iYUtoTGtkbmFtYWlhTGN4MmZncnlkYmFyY2xmeWRiYXJjd2Z5ZGJhQ2FiYWVhZGFQYXdhcWEzejpmampqYlRtYmFQY2VmaFBKYmJiYmhSSmJiYmJoOFVKYmJiYmg4VkpiYmJiaDhXSmJiYmJoOFhKYmJiYmg4WWtjYmhYaW5hQWFPYXJhWGNkdGZ5ZGJjZHRnc2Z5ZGJjZHRmZ0toemFIYXNmZ3Z5ZGJnUWhzZG5hUVRtYmRuaW5henlkYmFMU21lYXpjbGZoemFzY3VmZ3NUbWR4YmtrYXphS2FRY2R0ZmM5OGZ5ZGJCZGJhdmF2eWRiY3VmQmRia2FYY2VmZ1hjaTlobWJrYThBYUxjSzJmZ3pJZGJoRWF6SWRsaGhheklkd2g4S2F6SWR4aDVheklkemg4RWF6SWRDaDhGYVlhTGZjZTg2YmJhOFlhOEZNaDhZYThYYThFTWg4WGE4V2E1TWg4V2E4VmE4S01oOFZhOFVhaE1oOFVhUmFFTWhSYW15ZHhoOFN4YmtrYW1jOldEZjhLampqamJhUGtqb2l2dXY5OWx1OEpqampqYmNhOVJnbzhLampqamJkbmRuYWxjdzBtYmFpeWRiaHJhZWFiY2l0Zmd3YWxjZHRjaVZCZGxhd2FyQmRiZG5hbGNkNm1iYWljbGZocmFsY3VmaERhd2N4Zmh3aW5hcnlkYmhxYXdjdUJkYmF3Yzk4ZmFxQmRiYXdjd2Zod2FyY2xmaHJhRGN1ZmdEbWJra2FsYWJmaHd4ZWtjYmhxYW9jYkJkS2FvOWNiODNpemFvY2JCZHdhbzljYjgzaWJKYmJqWmhrSmJialpoeGluYWRhaWFxY2R0ZnlkYmNLMmZoRGNiaHdpbmFvY3pmYXdmZ3JhRGF3ZklkYmdtYXJJZGJnUDp0Z3NheE5hUE1nUFVkYmFvYXdmZ3Jhc2FtYVA6dE5hcklkYk1VZGJhd2NsZmd3Y3g5aG1ia0piYmpaYWtKYmJqWk1nazp2aHhhcWNlZmdxYWw5aG1ia2NiaHJhZGNiY2VjZGFvSWRsZ21hb0lkd2dQOUdFZ3dhb0lkYmdzYVA5R0Vhd2FzYW05R0VnemNkdGd3ZmhIYW9jemZhd2ZJZGJobWFpaHdhbGhEaW5haWFyY2R0ZmdxeWRiaE9hcWF3eWRiZ0FCZGJhd2FPQmRiYXdjbGZod2FyYUhhQWNLMmZJZGJhbTlEZmhyYURjdWZnRG1ia2RuZG5hcmN2Nm1iYXZjOFg5a21iYXJhbGM5OGY2bWVrYWl5ZGJocmFlYWJjaXRmZ3dhbGNkdGNpVkJkbGF3YXJCZGJhaWNsZmhyYWxjdWZoRGF3Y3hmaHdpbmFyeWRiaHFhd2N1QmRiYXdjOThmYXFCZGJhd2N3Zmh3YXJjbGZocmFEY3VmZ0RtYmthbGFiZmh3eGVrYWVhYmNpdGZnd2FtVWRiYXdhd3lkbGM5OEdhelZCZGxhYmNlZmFlYWRhaWFyYXZjZWZncXo6ZGpqamJoRGF3YXd5ZGxjaUdhRGFiY3U3ZmNkdFZCZGxhRGFlYWRhaWFyY2R0ZmFsYXI5UmFxejpkampqYmh3a2FvY2FmOEtqampqYmF3aztPZGR2dWU5OWRuaW5hYmFlY2l0ZmdyeWRsZ3djZDRnRFRtZWRuYXdjaUdncWNpOWhtYmNpaHFkbmF3Y2w2bWJhYmFlY2l0ZmhiY2JoZWF3aHFjZWhraW5kbmFpYWJ5ZGJnRGZSYmJtYmNiaGthZGFEY0syZmd3SWR3YWxJZHc6dGd4YXhOYXdJZGJhbElkYjp0Z3hheE5hd0lkbGFsSWRsOnRneGF4Tk1NOnJneGFvSWRiOURUbWJhb2F4VWRiYXZhREJkYmFyeWRsaHFrYWJjd2ZoYmFlY2VmZ2VhcWNkNDZtYmtha2NlR1RtaWthcmFxY2lHQmRsc2tkbmFiY2JhRGFsYXFjZHRmSWRiYXJJZGI6dGd4SmJiYmI5RkVnd2FEN2FlY2VmZ0RmZ2VjaXRmeWRsYWJhd2FEZmdEY2l0ZnlkbFZjaTBtYmFyYXFCZGxrYWJhRGFkYWlhbGF2YW96OmVqampiYXg6bGFvSWRiOUZtYmtra2psZXZ1ZG5kbmFieWR3Z3hhbGFkY2V0ZmdtOFZlYmNzNGFsYWVjZXRmZ1A4VmViZ3NjczRmYWxhaWNldGZnejhWZWJjczRmZmFEMG1iYWttYmNiaERhYnlkeGFxNm1la2F2YXdjbHRmZ3hhYjhQZHc4M2R3YXhhYjhQZGI4M2RiYWJ5ZGJoRGRuYWJ5ZHdnd1RtYmFvYURjZHRmaHhhd2hzaW5hbGF4eWRiY2V0ZmNGRmk4N2ViYXhjbGZoeGFzY3VmZ3NtYmtrYWJhRGF3ZkJkYmFieWR4aHhhYjljYjgzZHdhYmFieWRsYXhjaTJmQmRsYVA4VmViaHNjZWhEY2JoeGtkbmFzY3p0Y3o5MWN1OWttYmFiYXhjZWZCZHdhUGF4ODdlYmFvYWJ5ZGJjZHRmYXhjZHRmYWVCZGJrZG5hbThVZWJjdTlrbWJhYmFieWR3Z3hjZWZCZHdhbWF4ODdlYmFvYWJ5ZGJjZHRmYXhjZHRmYWRCZGJrZG5hejhVZWJjdTlrbWJhYmFieWR3Z3hjZWZCZHdhemF4ODdlYmFvYWJ5ZGJjZHRmYXhjZHRmYWlCZGJrYXJhYnlkbGZhYnlkeGNpMmZhUFJiYjg2YmJhcmFieWRsZmFieWR4Y2kyZmNlZmFtUmJiODZiYmFyYWJ5ZGxmYWJ5ZHhjaTJmY2RmYXpSYmI4NmJiYWJhYnlkeGNlZkJkeGFEazptUHJIdWU5OWV1ZTk5ZXVlOTlpdThKampqamJjO1c7R2I5Umd4OEtqampqYmRuZG5hbG1iY2JobXhla2NiaFBheGM6bTtHYmZjYmM7S2J6OnJqampiOEFheGN1YWxjaTlVZ3NjbHRhc2NqampqaUdFY2J5ZDswOkc6Y2piSGpqampiYmd6QmQ6bTlHYXhjZUJkO1M5R2F4Y3Vhc2NLMmdIY0tmYWxjcEZGRmUwRWNieWQ7MDpHOmNqYkhqampqYmJnT0JkOnE5R2F4Y2RCZDtTOUdkbmFsY2k2Z0FtYmFyY2Q0aENhc2NkdGhYYU9oUWF6aExpbmF2YWlhUGN4MmZncnlkd2FDMmNkdGZoS2F2YXJ5ZGxhQzJjZHRmaFlhdmFyeWRiYUMyY2R0Zmg4QWNiaHJhTGhFaW5hUWFyZmdtYThBYXJmZzNJZGJnNWFZYXJmZzhFSWRiZzhGYTVhOEY5REVnNVVkYmFtYUthcmZnYUlkYmc4RmE1YThGYTU5REVnOEZVZGJhbWN4ZmdtYTNJZGJnNWE4RUlkYmdoYTVhaDlFRWc1VWRiYW1hYUlkYmdoYTVhaGE1OUVFZzVVZGJhRWE4RmE1TUpiYmJaTlVkYmFFYVhmaEVhcmNsZmdyY3g5aG1ia2FRY0tmaFFhTGNsZmhMYVBjZWZnUGFzOWhtYmtrYU9hSGZncjljYjgzZGJhcjljYjgzZHphcjljYjgzZHdheGN1YXNjeDJncmFsYzpiampqbDBFY2J5ZDswOkc6Y2piSGpqampiYmdIQmROOUdheGNpQmQ7UzlHYXNjZHRoZ2F6YXJmaHZheGN3VmhQYXhjbFZoQ2FIaDhKYXpoOEtjYmhMaW5heGNiY2o7R2J6OnJqampiaEVhTGFzMmNkdGhhZG5hQW1iYThLaHJhc2gzaW5hRWFyeWRiZ21jOEY5MWNqampqOTRWYW03Z21jUTRjeDJmZzhFYThFeWR3Y2VmQmR3YUVhbWNkNGNGckdjeDJmZzhFYThFeWRiY2VmQmRiYUVhbWN4NGNGckdjeDJmZ21hbXlkbGNlZkJkbGFyY2xmaHJhM2N1ZmczbWJra2F6YWFmaDhBYUhhYWZoWGNiaG1jYmgzY2JoOEVjYmhhaW5hRWFtZmdyeWRiaFFhcmEzQmRiYXJjd2ZnS3lkYmhZYUthYUJkYmFyY2xmZ3J5ZGJoS2FyYThFQmRiYVFhM2ZoM2FZYWFmaGFhS2E4RWZoOEVhbWN4ZmdtY2o7R2I5aG1ia2RuYUFtYmNiaHJhdmhtaW5hbWFyQmRiYW1jbGZobWFzYXJjZWZncjlobWJrYXZocmFzaG1pbmFFYThBYXJ5ZGJnM2NkdGZ5ZGJnOEVjOEY5MWE4RTdjZDRjRnJHY3gyZmc4RWE4RXlkYmc4RWNlZkJkYmFYYThFY2R0ZmEzQmRiYXJjbGZocmFtY3VmZ21tYmthOEpocmFzaG1pbmFDYThBYXJ5ZGJnM2NkdGZ5ZGJnOEVjOEY5MWE4RTdjeDRjRnJHY3gyZmc4RWE4RXlkYmc4RWNlZkJkYmF2YThFY2R0ZmEzQmRiYXJjbGZocmFtY3VmZ21tYmthdmhyYXNobWluYVBhOEFhcnlkYmczY2R0ZnlkYmc4RWM4RjkxY2pqamo5NFZhOEU3Y1E0Y3gyZmc4RWE4RXlkYmc4RWNlZkJkYmFYYThFY2R0ZmEzQmRiYXJjbGZocmFtY3VmZ21tYmtrYThKYWdmaDhKYThLYWdmaDhLYUxjZWZnTGNpOWhtYmthRWFvY2V0Z3JjdWFvY3U5a0VjYnlkOzA6RzpjamJIampqamJiZ0tCZDp5OUdhRWNsQmQ7UzlHZG5kbmFvYWw5bm1iYWlocmFsaG1pbmFLYXJ5ZGJjZXRmY0ZGaTg3ZWJhcmNsZmhyYW1jdWZnbW1ieGRra2FLY0ZlYXJ6OnJqampiOEFrY2JoOEVhRWFzY2J5ZDswOkc6Y2piSGpqampiYmc4QUJkOkM5R2FPYUhhSGFzY2R0ZmFIYXNjaXRmYThBYXNjYmF6YUthaWF3YURhcWFrejpoampqYmRuZG5hbGNpNm1iYThBaHJhc2htaW5hOEVhclJiYmZoOEVhcmNlZmhyYW1jdWZnbW1ia2FFOWNiODNpd2FFOWNiODNpYmFsYXdjOTpmZ3JmY3VmYXI5VWdyYXNhRGZjdWZhRDlVZ21hcmFtMEVoWWNiaG1jYmhyYThFaGFpbmNiaDNkbmFyVG1iYThBYXJmUmJiY2VTaDNrYW1hRWFpYUh5ZGJjeDJmZ1F5ZGJhUWNsZnlkYmFRY3dmeWRiYUthYmFlYWRhbWF3YXFhM2EzY2U3YThFYVk5blZhYWFtZmFZNlZHejpmampqYmZobWFIY2xmaEhhYWE4QWFyZlJiYjlSaGFhc2FyY2VmZ3I5aG1ia2FFeWR4VG1lYWJhbWNsdGZncmFFOFBpdzgzZHdhcmFFOFBpYjgzZGJhbWNlZmhteGVrYUU5Y2I4M2l3YUU5Y2I4M2liY2JobWtjemhyaW5hRWM6bTtHYmZhcmZ5ZGJjYnlkOzQ6RzpjamJIOmJqampiYmFyYzk4ZmdyYzk4OWhtYmtrYXhjO1c7R2JmOEtqampqYmFtazp3S0RRdWU5OWl1ZTk5aXVsOTpldXc5OWl1OEpqampqYmM7cWI5UmdQOEtqampqYmF4aHNheGh6ZG5kbmF2YXgwZ0htYmRuYXZUbWJjYmhPYWVoemF2aEFpbmF3YURhenlkYmN4MmZnQ2N3ZnlkYmNldGZnWDhWZWJoUWF3YUNjbGZ5ZGJjZXRmZ0w4VmViaEthd2FDeWRiY2V0ZmdDOFZlYmhZYVhjZTg3ZWJhTGNlODdlYmFDY2U4N2ViYU9hS2NzNGFZY3M0ZmFRY3M0ZmZoT2F6Y2xmaHphQWN1ZmdBbWJrYWVoemF2aEFpbmF3YURhenlkYmN4MmZnQ2N3ZnlkYmNldGZjRkZpODdlYmF3YUNjbGZ5ZGJjZXRmY0ZGaTg3ZWJhd2FDeWRiY2V0ZmNGRmk4N2ViYXpjbGZoemFBY3VmZ0FtYmtjZWh6YXFoc2FPYXEwbWVrYWxjZTg2YmJhbGNlZmNiYXZjdWZ6OnJqampiOEF4ZWthUGFpQmR4YVBhZEJkd2FQYWVCZGxhdmFrYXFjaTlVZzhBYWthOEFhazZFYUhFZ0s5UmhFYXhhSzlSaDNhS2N1Zmg1YUtjZXRoOEVhS2NkdGdDYzk4Zmg4RmF2Y2l0Z09hQzlSYXJmYzk4ZmhhYXNjdWZoaGF2Y3VmaGdhcmFPZmg4SkpiYmpaYXM6WTp2aDhLY2JhemNlYWtheFNFZzhMY2R0ZzhNOVJoOE5KRkZ1dWh5Y3VoOFBjYmhJY2JoOFJpbmFQY2xmYThSY2R0ZnlkYmhRYVBjYjhQZDp5Okc6Y2piZzhTODNpOWlhUGNiOFBkOnE6RzpjamJnUjgzaW5hUGNiOFBkMTpHOmNqYmc4VTgzaVVhUGNiOFBkajpHOmNqYmc4VjgzaThXYVBhOFM4M2l5YVBhUjgzaWFhUGE4VTgzaUthUGE4VjgzaXphUWF2Y2R0Z1lmaDhXY2JoWGluYWJhUWFYY2R0Z0xmeWRiY0syZmhBY2JoemluYVBjOFdmYXpmZ0NhQWF6ZmdPSWRiZzhYYUNJZGJnOFlhOFhhOFk5REVVZGJhQ2N6ZmdDYU9jeGZJZGJnOFhhQ0lkYmc4WWE4WGE4WTlFRVVkYmF6Y2xmZ3pjeDlobWJrYWJhOFdhWGN1N2NkdGZ5ZGJjSzJmaEFjYmh6YVBJZFVoOFphUElkOWloODBhUElkODBoODFhUElkOWVoQmFQSWQ4V2g4M2FQSWRuaFVpbmFQY3pmYXpmZ0NhQWF6ZmdPSWRiZzhYYUNJZGJnOFlhOFhhOFk5REVVZGJhQ2N6ZmdDYU9jeGZJZGJnOFhhQ0lkYmc4WWE4WGE4WTlFRVVkYmF6Y2xmZ3pjeDlobWJrYXJhTGZnemE4MGE4Wjp0ZzhYYVVhODM6dGc4WU5hOFlhQmE4MTp0ZzhaTmE4WmE4WE5NTVVkYmF6YVlmYVBJZHlhUElkSzp0ZzhYYVBJZGFhUElkejp0ZzhZTmE4WWFQSWQ4S2FQSWRDOnRnOFpOYThaYThYTk1NVWRiYVhjZWZnWGF2OWhtYmtjYmg4NWRuYUhtYmNiaEFhUWh6YThKaENhdmhYaW5hd2FEYXp5ZGJjeDJmZ09jd2Z5ZGJjZXRmZ0w4VmViaDhXYXdhT2NsZnlkYmNldGZnODU4VmViaDg2YXdhT3lkYmNldGZnTzhWZWJoODdhTGNlODdlYmE4NWNlODdlYmFPY2U4N2ViYUNhQWE4NmNzNGE4N2NzNGZhOFdjczRmZmdBQmRiYXpjbGZoemFDY2xmaENhWGN1ZmdYbWJrYXZoQ2luYXdhRGFReWRiY3gyZmd6Y3dmeWRiY2V0ZmNGRmk4N2ViYXdhemNsZnlkYmNldGZjRkZpODdlYmF3YXp5ZGJjZXRmY0ZGaTg3ZWJhUWNsZmhRYUNjdWZnQ21ia2E4Smg4NWtkbmRuZG5kbmRuZG5kbmRuZG5kbmRuYXZhOEU2bWJhOEVheDlubWVhdmF2YUs5VWd6YUsyOVJhemEzMjBtZGE1YUU5cG1xYTg1VGg4N2NlaDhXYUVoUXh3a2E1YWc5cG1EYThFYXg5bm1peG9rYXZhSzZtZWE1YUU5cG13Y2VoUWFFaFhhODVUbWl4bGthNWFnNm1seHJrYTVhZzlwbW9rY2JoUWFnaFhhODVtZWtKRkZ1dWg4WGNiaExhNWh6aW5kbmF6Y2VmZ0NhSzZtYmFRYXZhQzlSZ09hSzZHbWJhcmF6Y2R0ZklkYmc4WWFDOllOYXJhdmF6OVJjZHRmYVlmYzk0ZklkYmc4WmFPOllOTWc4MGE4WDlFbWJkbmRuYThLYU9haGY6WU5nODE6bEpiYmI5cDlEVG1iYTgxOk9oQXhla2NqampqOTRoQWthOFphc2FBMmFPOVI6WU5oOFpkbmRuYThLYXphc2Y6WU5nODE6bEpiYmI5cDlEVG1iYTgxOk9oT3hla2NqampqOTRoT2thbWFzYU8yYUM5UjpZYThZTmE4Wk1OYTgwTWc4WWE4WGE4WWE4WDlEZ09FaDhYYUNhTGFPRWhMa2F6YThMZmd6YVg2bWJ4bGtrSkZGdXVoOFhjYmhMYUVoQ2FhaEFhOEZoT2FLaHppbmRuYXphSzZtYmFRYUNhSzZHbWJhcmFPZklkYmc4WWF6OllOYUFJZGJnOFphQzpZTk1nODBhOFg5RW1iZG5kbmE4S2E4NWFPZnlkYmdZYWhmOllOZzgxOmxKYmJiOXA5RFRtYmE4MTpPaDhXeGVrY2pqamo5NGg4V2thbWFzYThXMmFZOVI6WWc4MWE4WU5hOFphODFOTU5hODBNZzhZYThYYThZYThYOURnWUVoOFhhemFMYVlFaExrYUNhOEw5UmhDYUFhOE5maEFhT2E4TWZoT2F6YThMZmd6Y3VmYVg2bWJ4aWtrYTg1VGg4N2NiaDhXYWdoUWtKRkZ1dWg4WGNiaExhRWhDYWFoQWE4RmhPYUtoemluZG5hemF6YUs5VWdYYUsyOVJhWGEzMjBtYmRuYThXVG1iYUNhQ2FLOVVnWGFLMjlSYVhhMzIwbWVrYXJhT2ZJZGJnOFlhejpZTmFBSWRiZzhaYUM6WU5NZzgwYThYOUVtYmF6aFhhQ2hZZG5hODdtYmE4NWFPZnlkYmdYaFlrZG5kbmE4S2FZYWhmOllOZzgxOmxKYmJiOXA5RFRtYmE4MTpPaDg2eGVrY2pqamo5NGg4NmthOFphc2E4NjJhWTlSOllOaDhaZG5kbmE4S2FYYWhmOllOZzgxOmxKYmJiOXA5RFRtYmE4MTpPaFl4ZWtjampqajk0aFlrYW1hc2FZMmFYOVI6WWE4WU5hOFpNTmE4ME1nOFlhOFhhOFlhOFg5RGdYRWg4WGF6YUxhWEVoTGthQ2E4TDlSaENhQWE4TmZoQWFPYThNZmhPYXphOExmZ3pjdWZhUTZtYmtrYUxUbWJhOFhheTlEVG1iYThYaHlhTGhJYThSaDhQa2E4UmNlZmc4UmNpOWhtYmtkbmRuYW9jOFg5a21iYThQY2I5b21la2E4QWN1Zmg4NWNiaFlpbmRuZG5kbmF2YVk5UmF4YVlheGZhdjBFZzhXVG1iY2JoQWFlYVljZHRmZ3poQ2E4V2hYaW5hd2FEYUN5ZGJjeDJmZ09jd2Z5ZGJjZXRmZ1E4VmViaGJhd2FPY2xmeWRiY2V0ZmdMOFZlYmhyYXdhT3lkYmNldGZnTzhWZWJoS2FRY2U4N2ViYUxjZTg3ZWJhT2NlODdlYmFBYXJjczRhS2NzNGZhYmNzNGZmaEFhQ2NsZmhDYVhjdWZnWG1ia2E4V2hPaW5hd2FEYXp5ZGJjeDJmZ0Njd2Z5ZGJjZXRmY0ZGaTg3ZWJhd2FDY2xmeWRiY2V0ZmNGRmk4N2ViYXdhQ3lkYmNldGZjRkZpODdlYmF6Y2xmaHphT2N1ZmdPbWJrYUFhcTBtZWthbGFZZmd6Y2U4NmJiYXpjZWZjYmE4V2N1Zno6cmpqamI4QXhla2FsYVlmZ3pjZTg2YmJhemNlZmNiYTg1ejpyampqYjhBYThBaDhXa2E4V2FZZmdZYXY5cG1keGJra2FyYXZjZHRnOFdmaExkbmFJVG1iYVBjbGZhOFBjZHRmeWRiaHphSWhDaW5hTGF6eWRiZmNiODZiYmF6Y2xmaHphQ2N1ZmdDbWJra2RuYXZhSTlubWJhUGNsZmE4UGNkdGZ5ZGJhSWNkdGZoemF2YUk5UmhDaW5hTGF6eWRiZmNlODZiYmF6Y2xmaHphQ2N1ZmdDbWJra2NiaFlpbmRuYVlhOFBTbWJjYmh6YXJhUGNsZmFZY2R0ZnlkYmdLYThXejpxampqYmhDYXZoWGFJaE9pbmFLYU9hemFMYUN5ZGJnUWZSYmJnQUVjZHRmYVFCZGJhQ2NsZmhDYU9hQWZoT2F6YUE5UmNlZmh6YVhjdWZnWG1ia2thWWNlZmdZY2k5aG1ia2FiYWVhZGFpYWxhSWFvY2VmZ0NhcmF3YURhcWFrYXhhbXo6aGpqamJhYmFlYUljZHRnemZhZGF6ZmFpYXpmYWxhSWZhdmFJOVJhQ2FyYXdhRGFxYWtheGFtejpoampqYmthUGM7cWJmOEtqampqYms6U2VlcnU4SmpqampiYzpxO2FiOVJnbzhLampqamJhb2M6cThXZmNGZWNqeno6cmpqamI4QWNiaHJkbmFkVG1iYWVod2FkaERpbmFvYXJjZHRmYXd5ZGJncUJkYmFvYzpxOFdmYXFjRmlHY2R0ZmdreWRiaHhha2FxQmRiYXdjbGZod2FyYXhhcTloZmhyYURjdWZnRG1ia2thYmFlYWRhb2FyYWlhdno6ampqamJhb2M6cTthYmY4S2pqampiaztTcWxvdWQ5OWV1RDk5OEpqampqYmM6VzthYjlSZ3I4S2pqampiZG5kbmFkVG1iYW9jZDRod2NiaERjYmhxaW5kbmF2YWVjbGZ5ZGJhdzJjZHRmZ2tJZGJhdmFleWRiYXcyY2R0Zmd4SWRiZ206dGdQYXZhZWN3ZnlkYmF3MmNkdGZnc0lkbGF4SWRsZ3o6dGdITmFrSWRsYXo6dGdPYXNJZGJhbTp0Z0FOOnRnQ2FDTmFPYXNJZHdheElkd2dYOnRnUU5ha0lkd2FYOnRnT2FITjp0Z0hhSE5hT2FBTmFQYVFOOnRnUGFQTk1NZ09KYmJiYjlCbWJhcmM4V2ZhRGNsdGZna2FDYU86cmdPOnZnQ1Vkd2FrYVBhTzp2Z1BVZGxha2FIYU86dmdIVWRiYWthQ2FYTmFIYW1OYXphUE5NTTptVWR4YURjZWZoRGthZWN4ZmhlYXFjaWZncWFkNm1ia2FiOWNiODNkeWFiOWNiODNkYWFiOWNiODNkS2FiOWNiODNkemFiOWNiODNkd2FiOWNiODNkYmFEVG1lYXJjYkJkOFNhcjljYjgzaUthcjljYjgzaXphcmN6ZmF2YWxhb2FyYzhTZmNiY3JhaXo6a2pqamJhcklkS2hRYXJJZENoTGFySWR6aEthcjljYjgzaXdhcjljYjgzaWJhcmFyYzhXZmFEY3phcmM4U2ZjYmNpY2J6OmtqampiSmJiYmJobWRuYXJJZHdnemF6TmFySWRiZ0hhSE5hcklkbGdYYVhOTU1nQ0piYmJiOUJtYkpiYmpaYUM6cjp2aG1rYXphbU5oQ2FYYW1OaFhhSGFtTmhISmJialpobWFyYzhXZmhlYURodmluYWVjd2ZJZGJhQ05hZUlkYmFITmFYYWVjbGZJZGJOTU1nemFtYXphbTlERWhtYWVjemZoZWF2Y3VmZ3ZtYmthYmFRVWR3YWJhTFVkbGFiYUtVZGJhYmFySWQzVWR4ZG5kbmFtSjtuO207bTg5OUZtYkpiYmJiaHphcmM4V2ZoZWluYWVjeGZJZGJhUWFlY3dmSWRiZ1BOYUthZUlkYmdPTmFMYWVjbGZJZGJnQU5NTU1hQ2FQTmFIYU9OYVhhQU5NTTp2Z1BhemFQYXo5RUVoemFlY3pmaGVhRGN1ZmdEbWJrYWJhQ1VkOEthYmFYVWRhYWJhSFVkM2FiYVFhQ2F6Tjp0VWRLYWJhTGFYYXpOOnRVZENhYmFLYUhhek46dFVkemFiSmJialphbWFtTjp0OnJnbVVkeWRuZG5hQ0piYmo6O2FDSmJiajo7OUdFZ3pKYmJqWmF6SmJialo5RkVKYmI7OjljTkpiYmJaSmJiYjo7YUNKYmJiYjlHRU1nejpsSmJiYjlwOURUbWJhejpPaGV4ZWtjampqajk0aGVrYWJhZTg2YjhVZG5kbmFYSmJiajo7YVhKYmJqOjs5R0VnekpiYmpaYXpKYmJqWjlGRUpiYjs6OWNOSmJiYlpKYmJiOjthWEpiYmJiOUdFTWd6OmxKYmJiOXA5RFRtYmF6Ok9odnhla2NqampqOTRodmthYmF2ODZiUmRuZG5hSEpiYmo6O2FISmJiajo7OUdFZ3pKYmJqWmF6SmJialo5RkVKYmI7OjljTkpiYmJaSmJiYjo7YUhKYmJiYjlHRU1nejpsSmJiYjlwOURUbWJhejpPaHd4ZWtjampqajk0aHdrYWJhdzg2YjhTZG5kbmFlY0t0Y0s5MTpZSmJiOzo5Yzp2YUM6dDpsYXZjS3RjSzkxOllKYmI7OjljOnZhWDp0Omxhd2NLdGNLOTE6WUpiYjs6OWM6dmFIOnQ6bGFtTU1NSmJiOzo5Y05KYmJqWk1nbTpsSmJiYjlwOURUbWJhbTpPaGV4ZWtjampqajk0aGVrYWVjRmJhZWNGYjlpRWhleGVrYWJjampqOzhpQmR5Y0ZiaGVrYWJhZTg2YjhWeGVrYWI5Y2I4M2R5YWI5Y2I4M2RhYWI5Y2I4M2RLYWI5Y2I4M2R6YWI5Y2I4M2R3YWI5Y2I4M2Ria2FyYzpXO2FiZjhLampqamJrOzd3b0R1bzk5ZXVlOTlldXY5OThKampqamJjamU5Umd3OEtqampqYmF3YzthYmZjYmFvY2R0Z0R6OnJqampiOEFhd2M7R2JmY2JhRHo6cmpqamI4QWF3Y2FmaERhd2hxYW9oa2luYXFjRkZGOTdCZGJhRGNGRkY7N3JCZGJhcWNsZmhxYURjbGZoRGFrY3VmZ2ttYmthdmNkNGh4YWljZDRobWRuYWRUbWJhb2N4MmhQY2Joc2luYXNoemRuYXJUbWJhcmFzY2R0ZnlkYmh6a2FlYXphbTJjZHRmZ0RJZHdoSGFESWRsaE9hRElkYmhBYWxhemF4MmNkdGZJZGJoQ2NiaERhd2NhZmhxYXdjO0diZmh2YXdoa2F3YzthYmZoaWluYUNhRGM6TzpHOmNqYmZJZGJhSE5hRGM6RzpHOmNqYmZJZGJhQU5hRGM6SzpHOmNqYmZJZGJhT05NTWdYTWhRYXpoTGRuYVhhQzp0Z1hhcUlkYmdLOURnWW1iYXZ5ZGJoTGthdmFMQmRiYXpoTGRuYVFha0lkYmc4QTlFbWJhaXlkYmhMYThBaFFrYWlhTEJkYmFrYVFVZGJhcWFYYUthWUVVZGJhaWNsZmhpYWtjbGZoa2F2Y2xmaHZhcWNsZmhxYVBhRGN4ZmdEOWhtYmthc2NlZmdzYWQ5aG1ia2tKYmJiYmhRY2JoTGF3YztHYmZoRGF3YzthYmZocWNiaGtpbmFsYXF5ZGJndmF4MmNkdGZJZGJhbGFEeWRiZ2lheDJjZHRmSWRiYWVhdmFtMmNkdGZndklkd2FlYWlhbTJjZHRmZ2lJZHc6dGdDYUNOYXZJZGJhaUlkYjp0Z0NhQ05hdklkbGFpSWRsOnRnQ2FDTk1NOnJNTWdDYVFhQ2FROUVndkVoUWFrYUxhdkVoTGFxY2xmaHFhRGNsZmhEYW9ha2NlZmdrOWhtYmtKYmJiYmhDZG5hZWF3YzthYmZhTGNkdGdxZnlkYmdrYW0yY2R0ZmdESWR3YWVhd2M7R2JmYXFmeWRiZ3ZhbTJjZHRmZ3FJZHdnSDp0Z1hhWE5hRElkYmFxSWRiZ0E6dGc4QWE4QU5hRElkbGFxSWRsZ0U6dGdPYU9OTU1nS0piYmJiOUVUbWJhSzpyZ0NhbGFrYXgyY2R0ZklkYk1hbGF2YXgyY2R0ZklkYjp0YUNhQ006dmhDa2FRSmJiYlpOaEthWGFDTmFITWhIYU9hQ05hRU1oT2E4QWFDTmFBTWhBZG5hZFRtYmNiaHFhcmhraW5hcWhEZG5hclRtYmFreWRiaERrZG5hbGFEYXgyY2R0ZklkYmczYWVhRGFtMmNkdGZnRElkd2FIOnRnUWFRTmFESWRiYUE6dGdDYUNOYURJZGxhTzp0Z1hhWE5NTWc1OnJnRU1nOEVhSzlFVG1iSmJiYmJoOEFkbmE1SmJiYmI5RVRtYmE4RWFLOnRhRWFFTTp2aDhBa2E4QWFRTmFITWhIYThBYVhOYU9NaE9hOEFhQ05hQU1oQWEzYUthRU1NSmJiYlpOaEtrYWtjbGZoa2FkYXFjZWZncTlobWJra2FiYUtVZHhhYmFIVWR3YWJhT1VkbGFiYUFVZGJhd2NqZWY4S2pqampiazpyZWV2dThKampqamJjajhXOVJncjhLampqamJhaWNpMmh3Y2JoRGRuYWlUbWJhcmhpYXdocWluYWlhZWFkUmJiZ2tjZHRmeWRiQmRiYURha2NlZmdrYURhazBFaERhaWNsZmhpYWRjZWZoZGFxY3VmZ3FtYmtrYWJhcmF3YWVhRGFsYW96OmpqampiYXJjajhXZjhLampqamJrOkVlZWV1OEpqampqYmNhOVJnbzhLampqamJhYjljYjgzZHlhYjljYjgzZGFhYjljYjgzZEthYjljYjgzZHphYjljYjgzZHdhYjljYjgzZGJkbmFkVG1iYW9jYkJkM2FvOWNiODNpd2FvOWNiODNpYmFvYWVhZGFpYWxhb2MzZmFsRWF2Y2JhbEVjcmNiejprampqYmFiYW84UGliODNkYmFiYW84UGl3ODNkd2thb2NhZjhLampqamJrOjptZVF1OEpqampqYmNqejlSZ3Y4S2pqampiY2Job2F2Y2pQZmNiYWV6OnJqampiOEFhdmNqeGZjYmFlejpyampqYjhBZG5haVRtYmFkaG9haWhyaW5hdmNqeGZhb1JiYmZnd2F3UmJiY2VmODZiYmF2Y2p4ZmFvY2VmUmJiZmd3YXdSYmJjZWY4NmJiYXZjanhmYW9jZGZSYmJmZ3dhd1JiYmNlZjg2YmJhb2NpZmhvYXJjdWZncm1ia2NiaERjamVob2FkaHFjZWhraW5kbmRuYWxUbWJjYmh4Y3VobWFxaHJha2h3Y3VoUGluYXdjdWZhbWFvYXZjalBmYXJjZWZSYmJnc2ZSYmI5UmNGZUdnemNpNmFvYXZjalBmYXJSYmJnSGZSYmI5UmNGZUdnT2NpNmZhb2F2Y2pQZmFyY2RmUmJiZ0FmUmJiOVJjRmVHZ0NjaTZmZ1hjT3RhT2NGcjdhemFDZjlSY3d0VmF2Y2p4ZmFBZlJiYmd6YXZjanhmYUhmUmJiZ0hhdmNqeGZhc2ZSYmJnc2FIYXM2RWdzYXphczZFY0ZlN1Znc2FQOWtnekVobWFYY2Q2Z0hheGNlZmdPYWw5aVZjZTlobWRhc2FQYXpFaFBheGFPYUhFaHhhcmNpZmhyYXdhaTZoc2F3Y2VmaHdhc21ieGRra2N1aG1hcWhyYWtod2N1aHhpbmF3Y3VmYW1hb2F2Y2pQZmFyY2VmUmJiZlJiYjlSY0ZlR2NpNmFvYXZjalBmYXJSYmJmUmJiOVJjRmVHY2k2ZmFvYXZjalBmYXJjZGZSYmJmUmJiOVJjRmVHY2k2ZmdQYXg5a2dzRWhtYVBjZTBtZWFQYXhhc0VoeGFyY2lmaHJhd2FpNmhQYXdjZWZod2FQbWJra2FkYW1jaTJmZ3JjZGZSYmJod2FyY2VmUmJiaHhhclJiYmhQYWRhRGNpMmZncmNpZmFyYW1hRDlSY2kyek5qampiOEFhUGF2Y2pQZmZhb2NlZmdvODZiYmFQYXZjanhmZmdtYW1SYmJjdWY4NmJiYXhhdmNqUGZmYW84NmJiYXhhdmNqeGZmZ21hbVJiYmN1Zjg2YmJhcmNkZmF3ODZiYmFyY2VmYXg4NmJiYXJhUDg2YmJhd2F2Y2pQZmZhbzg2YmJhd2F2Y2p4ZmZncmFyUmJiY3VmODZiYmFxY2lmaHFha2NlZmhrYURjZWZnRGFpOWhtYmtjYmh6ZG5hbGNiOW1tYmNiaHNhdmNqUGZjYmFlejpyampqYjhBYWRjdmZobGluYWRhc2NpMmZneGNlZmdEUmJiaG9heGNkZmdxUmJiaHJkbmRuYXZjalBmYXhSYmJnbWZSYmJtYmF2Y2pQZmFyZlJiYmh3ZG5kbmRuYXZjalBmYW9mUmJiVG1iYXdjRmVHVG1leGlrYXdjRmVHbWRhc2NlZmdBYWk5cG1kYXNjOTgwbWRhc2NpZmhRY2JoTGFyY0ZlR2hDYW1jRmVHaFhhbGh3Y2JoS2NiaFlpbmF3Y3VmUmJiaFBhd1JiYmhPY2Voa2RuZG5hd2M5OmZSYmJnSGFvOWhtYmFQY0ZlR2FtU21la2RuYVBjRmVHYW85aG1iYU9jRmVHYW1TbWVrYUhhbVNhT2NGZUdhb1NHaGtrY2VoOEFhWWNlR2hZZG5kbmFIYXI5aG1iYVBjRmVHYW9TbWVrZG5hUGNGZUdhcjlobWJhT2NGZUdhb1NtZWthSGFvU2FPY0ZlR2FyU0doOEFrYWthWVZoWWFMYUhjRmVHZ0hhWFNhUGNGZUdnUGFDU0dhUGFYU2FPY0ZlR2dQYUNTR1ZhSGFDU2FQYVhTR1ZWaExhOEFhS2NlR1ZoS2RuYUFjZWZnUGFpOXBtYmF3Y2lmaHdhQWFRNmhIYVBoQWFIbWVra2FZVG1lYUttZWthcmh3YW9oUGFvaEhhcmhPYW1ocnhka2RuYVlUYUxWY2VHVG1iYVlhS1RWYUxWY2VHbWVrYW1od2FyaFBhcmhIYW1oT2FvaHJ4ZWthb2h3YW1oUGFtaEhhb2hPa2F2Y2pQZmFyZmNlODZiYmF2Y2pQZmF3ZmNlODZiYmF4YUg4NmJiYXFhcjg2YmJhRGFPODZiYmF2Y2pQZmFQZmNlODZiYmFsY2lmaGxhc2NlZmdzYWk5aG1ia2thdmNGZWFlY2V0ejpyampqYmh3YWljaTJocmluZG5hd2FkUmJiZ21jZXRmZ3g4VWViZ29jdTlrbWJheGF6ODdlYmF3Y2psZmF6Y2R0ZmFiYW1jZHRmeWRiQmRiYXpob2F6Y2VmaHprYWRhbzg2YmJhZGNlZmhkYXJjdWZncm1ia2F6Y2R0aG9rYWJhdmNqbGZhb3o6cWpqamI4QWF2Y2p6ZjhLampqamJrT2JhYmFpYWVhZGNiejpuampqYms5dGVpdWNiY2J5ZDs4Okc6Y2piZ2VhYmNpZmM5OEdmZ2JCZDs4Okc6Y2piZG5kbmFiWmJjenRnZDlubWJjdWhpYWJhZDlSY0ZGaWZjejRuYmN1U21la2FlaGlrYWlrO0xlZWV1ZG5kbmFlYWJWY2lHVG1iYWJoaXhla2RuZG5hZGN6OXBtYmFiaGl4ZWthYmhpaW5haWFleWRiQmRiYWljbGZhZWNsZnlkYkJkYmFpY3dmYWVjd2Z5ZGJCZGJhaWN4ZmFlY3hmeWRiQmRiYWVjemZoZWFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFleWRiQmRiYWVjbGZoZWFpY2xmaGlhZGM5OGZnZGNpMG1ia2tkbmFkVG1iaW5haWFlUmJiODZiYmFpY2VmaGlhZWNlZmhlYWRjdWZnZG1ia2thYms7YWVlZHVkbmRuYWJjaUdUbWJhYmhpeGVrYWVjRmVHYzpiOmM6ZXcyaGxkbmRuYWRjejlwbWJhYmhpeGVrYWJoaWluYWlhbEJkYmFpY3hmYWxCZGJhaWN3ZmFsQmRiYWljbGZhbEJkYmFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFsQmRiYWljbGZoaWFkYzk4ZmdkY2kwbWJra2RuYWRUbWJpbmFpYWU4NmJiYWljZWZoaWFkY3VmZ2RtYmtrYWJrOXRlaXVjYmNieWQ7ODpHOmNqYmdlYWJjcmZjOTRHZmdiQmQ7ODpHOmNqYmRuZG5hYlpiY3p0Z2Q5bm1iY3VoaWFiYWQ5UmNGRmlmY3o0bmJjdVNtZWthZWhpa2Fpa1RlZXVjYmFiY2J5ZDs4Okc6Y2piZ2U5UmNpZmM5OEdhZWZnYkJkOzg6RzpjamJkbmFiWmJjenRnZTlubWJhYmFlOVJjRkZpZmN6NG5iOEFrazozcWVsdWRuZG5hZGNoNm1iYWRUbWVhYmFlYWQ7OHFiYmFic2thYmFlU21iZG5hZWFkYWJmZ2k5UmNiYWRjZXQ5UjBtYmFkVG1lYWJhZWFkOzhxYmJhYnNrYWVhYjdjaUdobGRuZG5kbmFiYWU5cG1iZG5hbFRtYmFkaHZhYmhpeGlrZG5hYmNpR21iYWRodmFiaGl4ZGthZFRtaWFiYWVSYmI4NmJiYWRjdWZodmRuYWJjZWZnaWNpR21iYWVjZWZoZXhka2F2VG1pYWJhZVJiZTg2YmVhZGM5OmZodmRuYWJjZGZnaWNpR21iYWVjZGZoZXhka2F2VG1pYWJhZVJiZDg2YmRhZGM5OWZodmRuYWJjaWZnaWNpR21iYWVjaWZoZXhka2F2VG1pYWJhZVJiaTg2YmlhYmNsZmhpYWVjbGZoZWFkYzk4Zmh2eGVrZG5hbG1iZG5haWNpR1RtYmFkVG1sYWJhZGN1ZmdpZmdsYWVhaWZSYmI4NmJiZG5hbGNpR21iYWloZHhla2FpVG1sYWJhZGM5OmZnaWZnbGFlYWlmUmJiODZiYmRuYWxjaUdtYmFpaGR4ZWthaVRtbGFiYWRjOTlmZ2lmZ2xhZWFpZlJiYjg2YmJkbmFsY2lHbWJhaWhkeGVrYWlUbWxhYmFkYzk4ZmdkZmFlYWRmUmJiODZiYmthZGNsNm1iZG5hZGM5OGZnb2N4R2N4U21iYW9jZDRjZWZjaUdoaWFlYzk4ZmhsYWJjOThmaHZpbmF2YWRmYWxhZGZ5ZGJCZGJhZGM5OGZoZGFpY3VmZ2ltYmtrYW9jeDZtYmFlYzlXZmh2YWJjOVdmaG9pbmFvYWRmZ2ljeGZhdmFkZmdsY3hmeWRiQmRiYWljd2ZhbGN3ZnlkYkJkYmFpY2xmYWxjbGZ5ZGJCZGJhaWFseWRiQmRiYWRjOVdmZ2RjaTBtYmtrYWRUbWRhZGhpZG5hZGNpR2dsVG1iYWVjdWZodmFiY3VmaG9hZGhpaW5hb2FpZmF2YWlmUmJiODZiYmFpY3VmaGlhbGN1ZmdsbWJra2FkY2w2bWRhZWM5OGZobGFiYzk4Zmh2aW5hdmFpZmdlY2lmYWxhaWZnZGNpZlJiYjg2YmJhZWNkZmFkY2RmUmJiODZiYmFlY2VmYWRjZWZSYmI4NmJiYWVhZFJiYjg2YmJhaWM5OGZnaW1ieGlra2F2Y2w2bWJkbmF2Yzk4ZmdsYzNHYzNTbWJhdmFsY2Q0Y2VmY3JHZ2RjZHQ5Umh2aW5haWFleWRiQmRiYWVjbGZoZWFpY2xmaGlhZGN1ZmdkbWJra2FsYzM2bWJpbmFpYWV5ZGJCZGJhaWNsZmFlY2xmeWRiQmRiYWljd2ZhZWN3ZnlkYkJkYmFpY3hmYWVjeGZ5ZGJCZGJhaWN6ZmFlY3pmeWRiQmRiYWljQ2ZhZWNDZnlkYkJkYmFpY0tmYWVjS2Z5ZGJCZGJhaWMzZmFlYzNmeWRiQmRiYWVjYWZoZWFpY2FmaGlhdmM5R2ZndmNpMG1ia2thdlRtYmRuZG5hdmNyR2dkbWJhdmhseGVrYXZjOTRHaGxpbmFpYWVSYmI4NmJiYWljZWZoaWFlY2VmaGVhZGN1ZmdkbWJra2F2Y3c2bWJpbmFpYWVSYmI4NmJiYWljZWZhZWNlZlJiYjg2YmJhaWNkZmFlY2RmUmJiODZiYmFpY2lmYWVjaWZSYmI4NmJiYWljbGZhZWNsZlJiYjg2YmJhaWN2ZmFlY3ZmUmJiODZiYmFpY29mYWVjb2ZSYmI4NmJiYWljcmZhZWNyZlJiYjg2YmJhaWN3ZmhpYWVjd2ZoZWFsYzk0ZmdsbWJra2Fia2s6cGVkYmNqOkdka3RGRnV1RkZ1dUZGdXViYmJiRkZ1RkZGdUZGRnVGYmJiYmJialpiYmJiYmJiYmJiYmJiYmpaYmJiYmJiYmJiYmJiYmJqWjg2O25BWjg2O25BWjg2O25BWjg2O25BOjs4NjtuQVo4NjtuQVo4NjtuQVo4NjtuQTo7ODY7bkFaODY7bkFaODY7bkFaODY7bkE6O2JjOzA6R2RreGViYmJkYmJiajpxYmIiOwogICAgICAgIHZhciB3YXNtcGFjayA9IG5ldyBVaW50OEFycmF5KFsKICAgICAgICAgIDMyLAogICAgICAgICAgMCwKICAgICAgICAgIDY1LAogICAgICAgICAgMiwKICAgICAgICAgIDEsCiAgICAgICAgICAxMDYsCiAgICAgICAgICAzNCwKICAgICAgICAgIDMzLAogICAgICAgICAgMywKICAgICAgICAgIDEyOCwKICAgICAgICAgIDExLAogICAgICAgICAgNCwKICAgICAgICAgIDEzLAogICAgICAgICAgNjQsCiAgICAgICAgICA2LAogICAgICAgICAgMjUzLAogICAgICAgICAgMTAsCiAgICAgICAgICA3LAogICAgICAgICAgMTUsCiAgICAgICAgICAxMTYsCiAgICAgICAgICAxMjcsCiAgICAgICAgICA1LAogICAgICAgICAgOCwKICAgICAgICAgIDEyLAogICAgICAgICAgNDAsCiAgICAgICAgICAxNiwKICAgICAgICAgIDE5LAogICAgICAgICAgNTQsCiAgICAgICAgICAyMCwKICAgICAgICAgIDksCiAgICAgICAgICAyNywKICAgICAgICAgIDI1NSwKICAgICAgICAgIDExMywKICAgICAgICAgIDE3LAogICAgICAgICAgNDIsCiAgICAgICAgICA2NywKICAgICAgICAgIDI0LAogICAgICAgICAgMjMsCiAgICAgICAgICAxNDYsCiAgICAgICAgICAxNDgsCiAgICAgICAgICAxOCwKICAgICAgICAgIDE0LAogICAgICAgICAgMjIsCiAgICAgICAgICA0NSwKICAgICAgICAgIDcwLAogICAgICAgICAgNjksCiAgICAgICAgICA1NiwKICAgICAgICAgIDExNCwKICAgICAgICAgIDEwMSwKICAgICAgICAgIDIxLAogICAgICAgICAgMjUsCiAgICAgICAgICA2MywKICAgICAgICAgIDc1LAogICAgICAgICAgMTM2LAogICAgICAgICAgMTA4LAogICAgICAgICAgMjgsCiAgICAgICAgICAxMTgsCiAgICAgICAgICAyOSwKICAgICAgICAgIDczLAogICAgICAgICAgMTE1CiAgICAgICAgXSk7CiAgICAgICAgaWYgKHR5cGVvZiBXZWJBc3NlbWJseSAhPT0gIm9iamVjdCIpIHsKICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIHN1cHBvcnRlZDogZmFsc2UKICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIHZhciBpbnN0YW5jZTsKICAgICAgICB2YXIgcmVhZHkgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZSh1bnBhY2sod2FzbTIpLCB7fSkudGhlbihmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICAgIGluc3RhbmNlID0gcmVzdWx0Lmluc3RhbmNlOwogICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5fX3dhc21fY2FsbF9jdG9ycygpOwogICAgICAgIH0pOwogICAgICAgIGZ1bmN0aW9uIHVucGFjayhkYXRhKSB7CiAgICAgICAgICB2YXIgcmVzdWx0ID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5sZW5ndGgpOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGRhdGEubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIHZhciBjaCA9IGRhdGEuY2hhckNvZGVBdChpMik7CiAgICAgICAgICAgIHJlc3VsdFtpMl0gPSBjaCA+IDk2ID8gY2ggLSA5NyA6IGNoID4gNjQgPyBjaCAtIDM5IDogY2ggKyA0OwogICAgICAgICAgfQogICAgICAgICAgdmFyIHdyaXRlID0gMDsKICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBkYXRhLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICByZXN1bHRbd3JpdGUrK10gPSByZXN1bHRbaTJdIDwgNjAgPyB3YXNtcGFja1tyZXN1bHRbaTJdXSA6IChyZXN1bHRbaTJdIC0gNjApICogNjQgKyByZXN1bHRbKytpMl07CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gcmVzdWx0LmJ1ZmZlci5zbGljZSgwLCB3cml0ZSk7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGFzc2VydChjb25kKSB7CiAgICAgICAgICBpZiAoIWNvbmQpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJBc3NlcnRpb24gZmFpbGVkIik7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGJ5dGVzKHZpZXcpIHsKICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheSh2aWV3LmJ1ZmZlciwgdmlldy5ieXRlT2Zmc2V0LCB2aWV3LmJ5dGVMZW5ndGgpOwogICAgICAgIH0KICAgICAgICB2YXIgQk9VTkRTX1NJWkUgPSA0ODsKICAgICAgICB2YXIgTUVTSExFVF9TSVpFID0gMTY7CiAgICAgICAgZnVuY3Rpb24gZXh0cmFjdE1lc2hsZXQoYnVmZmVycywgaW5kZXgpIHsKICAgICAgICAgIHZhciB2ZXJ0ZXhfb2Zmc2V0ID0gYnVmZmVycy5tZXNobGV0c1tpbmRleCAqIDQgKyAwXTsKICAgICAgICAgIHZhciB0cmlhbmdsZV9vZmZzZXQgPSBidWZmZXJzLm1lc2hsZXRzW2luZGV4ICogNCArIDFdOwogICAgICAgICAgdmFyIHZlcnRleF9jb3VudCA9IGJ1ZmZlcnMubWVzaGxldHNbaW5kZXggKiA0ICsgMl07CiAgICAgICAgICB2YXIgdHJpYW5nbGVfY291bnQgPSBidWZmZXJzLm1lc2hsZXRzW2luZGV4ICogNCArIDNdOwogICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgdmVydGljZXM6IGJ1ZmZlcnMudmVydGljZXMuc3ViYXJyYXkodmVydGV4X29mZnNldCwgdmVydGV4X29mZnNldCArIHZlcnRleF9jb3VudCksCiAgICAgICAgICAgIHRyaWFuZ2xlczogYnVmZmVycy50cmlhbmdsZXMuc3ViYXJyYXkodHJpYW5nbGVfb2Zmc2V0LCB0cmlhbmdsZV9vZmZzZXQgKyB0cmlhbmdsZV9jb3VudCAqIDMpCiAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBidWlsZE1lc2hsZXRzKGZ1biwgaW5kaWNlcywgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X2NvdW50LCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgbWF4X3ZlcnRpY2VzLCBtaW5fdHJpYW5nbGVzLCBtYXhfdHJpYW5nbGVzLCBwYXJhbWEsIHBhcmFtYikgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgbWF4X21lc2hsZXRzID0gaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2J1aWxkTWVzaGxldHNCb3VuZChpbmRpY2VzLmxlbmd0aCwgbWF4X3ZlcnRpY2VzLCBtaW5fdHJpYW5nbGVzKTsKICAgICAgICAgIHZhciBtZXNobGV0c3AgPSBzYnJrKG1heF9tZXNobGV0cyAqIE1FU0hMRVRfU0laRSk7CiAgICAgICAgICB2YXIgbWVzaGxldF92ZXJ0aWNlc3AgPSBzYnJrKGluZGljZXMubGVuZ3RoICogNCk7CiAgICAgICAgICB2YXIgbWVzaGxldF90cmlhbmdsZXNwID0gc2JyayhpbmRpY2VzLmxlbmd0aCk7CiAgICAgICAgICB2YXIgaW5kaWNlc3AgPSBzYnJrKGluZGljZXMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgdmVydGljZXNwID0gc2Jyayh2ZXJ0ZXhfcG9zaXRpb25zLmJ5dGVMZW5ndGgpOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMoaW5kaWNlcyksIGluZGljZXNwKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKHZlcnRleF9wb3NpdGlvbnMpLCB2ZXJ0aWNlc3ApOwogICAgICAgICAgdmFyIGNvdW50ID0gZnVuKAogICAgICAgICAgICBtZXNobGV0c3AsCiAgICAgICAgICAgIG1lc2hsZXRfdmVydGljZXNwLAogICAgICAgICAgICBtZXNobGV0X3RyaWFuZ2xlc3AsCiAgICAgICAgICAgIGluZGljZXNwLAogICAgICAgICAgICBpbmRpY2VzLmxlbmd0aCwKICAgICAgICAgICAgdmVydGljZXNwLAogICAgICAgICAgICB2ZXJ0ZXhfY291bnQsCiAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICBtYXhfdmVydGljZXMsCiAgICAgICAgICAgIG1pbl90cmlhbmdsZXMsCiAgICAgICAgICAgIG1heF90cmlhbmdsZXMsCiAgICAgICAgICAgIHBhcmFtYSwKICAgICAgICAgICAgcGFyYW1iCiAgICAgICAgICApOwogICAgICAgICAgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICB2YXIgbWVzaGxldEJ5dGVzID0gaGVhcC5zdWJhcnJheShtZXNobGV0c3AsIG1lc2hsZXRzcCArIGNvdW50ICogTUVTSExFVF9TSVpFKTsKICAgICAgICAgIHZhciBtZXNobGV0cyA9IG5ldyBVaW50MzJBcnJheShtZXNobGV0Qnl0ZXMuYnVmZmVyLCBtZXNobGV0Qnl0ZXMuYnl0ZU9mZnNldCwgbWVzaGxldEJ5dGVzLmJ5dGVMZW5ndGggLyA0KS5zbGljZSgpOwogICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGNvdW50OyArK2kyKSB7CiAgICAgICAgICAgIHZhciB2ZXJ0ZXhfb2Zmc2V0ID0gbWVzaGxldHNbaTIgKiA0ICsgMF07CiAgICAgICAgICAgIHZhciB0cmlhbmdsZV9vZmZzZXQgPSBtZXNobGV0c1tpMiAqIDQgKyAxXTsKICAgICAgICAgICAgdmFyIHZlcnRleF9jb3VudCA9IG1lc2hsZXRzW2kyICogNCArIDJdOwogICAgICAgICAgICB2YXIgdHJpYW5nbGVfY291bnQgPSBtZXNobGV0c1tpMiAqIDQgKyAzXTsKICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X29wdGltaXplTWVzaGxldCgKICAgICAgICAgICAgICBtZXNobGV0X3ZlcnRpY2VzcCArIHZlcnRleF9vZmZzZXQgKiA0LAogICAgICAgICAgICAgIG1lc2hsZXRfdHJpYW5nbGVzcCArIHRyaWFuZ2xlX29mZnNldCwKICAgICAgICAgICAgICB0cmlhbmdsZV9jb3VudCwKICAgICAgICAgICAgICB2ZXJ0ZXhfY291bnQKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB1c2VkX3ZlcnRpY2VzID0gY291bnQgPyBtZXNobGV0c1soY291bnQgLSAxKSAqIDQgKyAwXSArIG1lc2hsZXRzWyhjb3VudCAtIDEpICogNCArIDJdIDogMDsKICAgICAgICAgIHZhciB1c2VkX3RyaWFuZ2xlcyA9IGNvdW50ID8gbWVzaGxldHNbKGNvdW50IC0gMSkgKiA0ICsgMV0gKyBtZXNobGV0c1soY291bnQgLSAxKSAqIDQgKyAzXSAqIDMgOiAwOwogICAgICAgICAgdmFyIHJlc3VsdCA9IHsKICAgICAgICAgICAgbWVzaGxldHMsCiAgICAgICAgICAgIHZlcnRpY2VzOiBuZXcgVWludDMyQXJyYXkoaGVhcC5idWZmZXIsIG1lc2hsZXRfdmVydGljZXNwLCB1c2VkX3ZlcnRpY2VzKS5zbGljZSgpLAogICAgICAgICAgICB0cmlhbmdsZXM6IG5ldyBVaW50OEFycmF5KGhlYXAuYnVmZmVyLCBtZXNobGV0X3RyaWFuZ2xlc3AsIHVzZWRfdHJpYW5nbGVzKS5zbGljZSgpLAogICAgICAgICAgICBtZXNobGV0Q291bnQ6IGNvdW50CiAgICAgICAgICB9OwogICAgICAgICAgc2JyayhtZXNobGV0c3AgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGV4dHJhY3RCb3VuZHMoYm91bmRzcCkgewogICAgICAgICAgdmFyIGJvdW5kc19mbG9hdHMgPSBuZXcgRmxvYXQzMkFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlciwgYm91bmRzcCwgQk9VTkRTX1NJWkUgLyA0KTsKICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgIGNlbnRlclg6IGJvdW5kc19mbG9hdHNbMF0sCiAgICAgICAgICAgIGNlbnRlclk6IGJvdW5kc19mbG9hdHNbMV0sCiAgICAgICAgICAgIGNlbnRlclo6IGJvdW5kc19mbG9hdHNbMl0sCiAgICAgICAgICAgIHJhZGl1czogYm91bmRzX2Zsb2F0c1szXSwKICAgICAgICAgICAgY29uZUFwZXhYOiBib3VuZHNfZmxvYXRzWzRdLAogICAgICAgICAgICBjb25lQXBleFk6IGJvdW5kc19mbG9hdHNbNV0sCiAgICAgICAgICAgIGNvbmVBcGV4WjogYm91bmRzX2Zsb2F0c1s2XSwKICAgICAgICAgICAgY29uZUF4aXNYOiBib3VuZHNfZmxvYXRzWzddLAogICAgICAgICAgICBjb25lQXhpc1k6IGJvdW5kc19mbG9hdHNbOF0sCiAgICAgICAgICAgIGNvbmVBeGlzWjogYm91bmRzX2Zsb2F0c1s5XSwKICAgICAgICAgICAgY29uZUN1dG9mZjogYm91bmRzX2Zsb2F0c1sxMF0KICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVNZXNobGV0Qm91bmRzKGJ1ZmZlcnMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHJlc3VsdHMgPSBbXTsKICAgICAgICAgIHZhciB2ZXJ0aWNlc3AgPSBzYnJrKHZlcnRleF9wb3NpdGlvbnMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgbWVzaGxldF92ZXJ0aWNlc3AgPSBzYnJrKGJ1ZmZlcnMudmVydGljZXMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgbWVzaGxldF90cmlhbmdsZXNwID0gc2JyayhidWZmZXJzLnRyaWFuZ2xlcy5ieXRlTGVuZ3RoKTsKICAgICAgICAgIHZhciByZXN1bHRwID0gc2JyayhCT1VORFNfU0laRSk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyh2ZXJ0ZXhfcG9zaXRpb25zKSwgdmVydGljZXNwKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKGJ1ZmZlcnMudmVydGljZXMpLCBtZXNobGV0X3ZlcnRpY2VzcCk7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhidWZmZXJzLnRyaWFuZ2xlcyksIG1lc2hsZXRfdHJpYW5nbGVzcCk7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgYnVmZmVycy5tZXNobGV0Q291bnQ7ICsraTIpIHsKICAgICAgICAgICAgdmFyIHZlcnRleF9vZmZzZXQgPSBidWZmZXJzLm1lc2hsZXRzW2kyICogNCArIDBdOwogICAgICAgICAgICB2YXIgdHJpYW5nbGVfb2Zmc2V0ID0gYnVmZmVycy5tZXNobGV0c1tpMiAqIDQgKyAxXTsKICAgICAgICAgICAgdmFyIHRyaWFuZ2xlX2NvdW50ID0gYnVmZmVycy5tZXNobGV0c1tpMiAqIDQgKyAzXTsKICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2NvbXB1dGVNZXNobGV0Qm91bmRzKAogICAgICAgICAgICAgIHJlc3VsdHAsCiAgICAgICAgICAgICAgbWVzaGxldF92ZXJ0aWNlc3AgKyB2ZXJ0ZXhfb2Zmc2V0ICogNCwKICAgICAgICAgICAgICBtZXNobGV0X3RyaWFuZ2xlc3AgKyB0cmlhbmdsZV9vZmZzZXQsCiAgICAgICAgICAgICAgdHJpYW5nbGVfY291bnQsCiAgICAgICAgICAgICAgdmVydGljZXNwLAogICAgICAgICAgICAgIHZlcnRleF9jb3VudCwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZQogICAgICAgICAgICApOwogICAgICAgICAgICByZXN1bHRzLnB1c2goZXh0cmFjdEJvdW5kcyhyZXN1bHRwKSk7CiAgICAgICAgICB9CiAgICAgICAgICBzYnJrKHZlcnRpY2VzcCAtIHNicmsoMCkpOwogICAgICAgICAgcmV0dXJuIHJlc3VsdHM7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVDbHVzdGVyQm91bmRzKGluZGljZXMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpIHsKICAgICAgICAgIHZhciBzYnJrID0gaW5zdGFuY2UuZXhwb3J0cy5zYnJrOwogICAgICAgICAgdmFyIHJlc3VsdHAgPSBzYnJrKEJPVU5EU19TSVpFKTsKICAgICAgICAgIHZhciBpbmRpY2VzcCA9IHNicmsoaW5kaWNlcy5ieXRlTGVuZ3RoKTsKICAgICAgICAgIHZhciB2ZXJ0aWNlc3AgPSBzYnJrKHZlcnRleF9wb3NpdGlvbnMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBoZWFwLnNldChieXRlcyhpbmRpY2VzKSwgaW5kaWNlc3ApOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X3Bvc2l0aW9ucyksIHZlcnRpY2VzcCk7CiAgICAgICAgICBpbnN0YW5jZS5leHBvcnRzLm1lc2hvcHRfY29tcHV0ZUNsdXN0ZXJCb3VuZHMocmVzdWx0cCwgaW5kaWNlc3AsIGluZGljZXMubGVuZ3RoLCB2ZXJ0aWNlc3AsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUpOwogICAgICAgICAgdmFyIHJlc3VsdCA9IGV4dHJhY3RCb3VuZHMocmVzdWx0cCk7CiAgICAgICAgICBzYnJrKHJlc3VsdHAgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGNvbXB1dGVTcGhlcmVCb3VuZHMocG9zaXRpb25zLCBjb3VudCwgcG9zaXRpb25zX3N0cmlkZSwgcmFkaWksIHJhZGlpX3N0cmlkZSkgewogICAgICAgICAgdmFyIHNicmsgPSBpbnN0YW5jZS5leHBvcnRzLnNicms7CiAgICAgICAgICB2YXIgcmVzdWx0cCA9IHNicmsoQk9VTkRTX1NJWkUpOwogICAgICAgICAgdmFyIHBvc2l0aW9uc3AgPSBzYnJrKHBvc2l0aW9ucy5ieXRlTGVuZ3RoKTsKICAgICAgICAgIHZhciByYWRpaXAgPSByYWRpaSA/IHNicmsocmFkaWkuYnl0ZUxlbmd0aCkgOiAwOwogICAgICAgICAgdmFyIGhlYXAgPSBuZXcgVWludDhBcnJheShpbnN0YW5jZS5leHBvcnRzLm1lbW9yeS5idWZmZXIpOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXMocG9zaXRpb25zKSwgcG9zaXRpb25zcCk7CiAgICAgICAgICBpZiAocmFkaWkpIHsKICAgICAgICAgICAgaGVhcC5zZXQoYnl0ZXMocmFkaWkpLCByYWRpaXApOwogICAgICAgICAgfQogICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2NvbXB1dGVTcGhlcmVCb3VuZHMocmVzdWx0cCwgcG9zaXRpb25zcCwgY291bnQsIHBvc2l0aW9uc19zdHJpZGUsIHJhZGlpcCwgcmFkaWkgPyByYWRpaV9zdHJpZGUgOiAwKTsKICAgICAgICAgIHZhciByZXN1bHQgPSBleHRyYWN0Qm91bmRzKHJlc3VsdHApOwogICAgICAgICAgc2JyayhyZXN1bHRwIC0gc2JyaygwKSk7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgcmVhZHksCiAgICAgICAgICBzdXBwb3J0ZWQ6IHRydWUsCiAgICAgICAgICBidWlsZE1lc2hsZXRzOiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSwgbWF4X3ZlcnRpY2VzLCBtYXhfdHJpYW5nbGVzLCBjb25lX3dlaWdodCkgewogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcy5sZW5ndGggJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucyBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAlIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPj0gMyk7CiAgICAgICAgICAgIGFzc2VydChtYXhfdmVydGljZXMgPj0gMyAmJiBtYXhfdmVydGljZXMgPD0gMjU2KTsKICAgICAgICAgICAgYXNzZXJ0KG1heF90cmlhbmdsZXMgPj0gMSAmJiBtYXhfdHJpYW5nbGVzIDw9IDUxMik7CiAgICAgICAgICAgIGNvbmVfd2VpZ2h0ID0gY29uZV93ZWlnaHQgfHwgMDsKICAgICAgICAgICAgdmFyIGluZGljZXMzMiA9IGluZGljZXMuQllURVNfUEVSX0VMRU1FTlQgPT0gNCA/IGluZGljZXMgOiBuZXcgVWludDMyQXJyYXkoaW5kaWNlcyk7CiAgICAgICAgICAgIHJldHVybiBidWlsZE1lc2hsZXRzKAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9idWlsZE1lc2hsZXRzRmxleCwKICAgICAgICAgICAgICBpbmRpY2VzMzIsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucywKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCwKICAgICAgICAgICAgICBtYXhfdmVydGljZXMsCiAgICAgICAgICAgICAgbWF4X3RyaWFuZ2xlcywKICAgICAgICAgICAgICBtYXhfdHJpYW5nbGVzLAogICAgICAgICAgICAgIGNvbmVfd2VpZ2h0LAogICAgICAgICAgICAgIDAKICAgICAgICAgICAgKTsKICAgICAgICAgIH0sCiAgICAgICAgICBidWlsZE1lc2hsZXRzRmxleDogZnVuY3Rpb24oaW5kaWNlcywgdmVydGV4X3Bvc2l0aW9ucywgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIG1heF92ZXJ0aWNlcywgbWluX3RyaWFuZ2xlcywgbWF4X3RyaWFuZ2xlcywgY29uZV93ZWlnaHQsIHNwbGl0X2ZhY3RvcikgewogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcy5sZW5ndGggJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucyBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAlIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlID09IDApOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPj0gMyk7CiAgICAgICAgICAgIGFzc2VydChtYXhfdmVydGljZXMgPj0gMyAmJiBtYXhfdmVydGljZXMgPD0gMjU2KTsKICAgICAgICAgICAgYXNzZXJ0KG1pbl90cmlhbmdsZXMgPj0gMSAmJiBtYXhfdHJpYW5nbGVzIDw9IDUxMik7CiAgICAgICAgICAgIGFzc2VydChtaW5fdHJpYW5nbGVzIDw9IG1heF90cmlhbmdsZXMpOwogICAgICAgICAgICBjb25lX3dlaWdodCA9IGNvbmVfd2VpZ2h0IHx8IDA7CiAgICAgICAgICAgIHNwbGl0X2ZhY3RvciA9IHNwbGl0X2ZhY3RvciB8fCAwOwogICAgICAgICAgICB2YXIgaW5kaWNlczMyID0gaW5kaWNlcy5CWVRFU19QRVJfRUxFTUVOVCA9PSA0ID8gaW5kaWNlcyA6IG5ldyBVaW50MzJBcnJheShpbmRpY2VzKTsKICAgICAgICAgICAgcmV0dXJuIGJ1aWxkTWVzaGxldHMoCiAgICAgICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2J1aWxkTWVzaGxldHNGbGV4LAogICAgICAgICAgICAgIGluZGljZXMzMiwKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgKiA0LAogICAgICAgICAgICAgIG1heF92ZXJ0aWNlcywKICAgICAgICAgICAgICBtaW5fdHJpYW5nbGVzLAogICAgICAgICAgICAgIG1heF90cmlhbmdsZXMsCiAgICAgICAgICAgICAgY29uZV93ZWlnaHQsCiAgICAgICAgICAgICAgc3BsaXRfZmFjdG9yCiAgICAgICAgICAgICk7CiAgICAgICAgICB9LAogICAgICAgICAgYnVpbGRNZXNobGV0c1NwYXRpYWw6IGZ1bmN0aW9uKGluZGljZXMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLCBtYXhfdmVydGljZXMsIG1pbl90cmlhbmdsZXMsIG1heF90cmlhbmdsZXMsIGZpbGxfd2VpZ2h0KSB7CiAgICAgICAgICAgIGFzc2VydChpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgYXNzZXJ0KG1heF92ZXJ0aWNlcyA+PSAzICYmIG1heF92ZXJ0aWNlcyA8PSAyNTYpOwogICAgICAgICAgICBhc3NlcnQobWluX3RyaWFuZ2xlcyA+PSAxICYmIG1heF90cmlhbmdsZXMgPD0gNTEyKTsKICAgICAgICAgICAgYXNzZXJ0KG1pbl90cmlhbmdsZXMgPD0gbWF4X3RyaWFuZ2xlcyk7CiAgICAgICAgICAgIGZpbGxfd2VpZ2h0ID0gZmlsbF93ZWlnaHQgfHwgMDsKICAgICAgICAgICAgdmFyIGluZGljZXMzMiA9IGluZGljZXMuQllURVNfUEVSX0VMRU1FTlQgPT0gNCA/IGluZGljZXMgOiBuZXcgVWludDMyQXJyYXkoaW5kaWNlcyk7CiAgICAgICAgICAgIHJldHVybiBidWlsZE1lc2hsZXRzKAogICAgICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMubWVzaG9wdF9idWlsZE1lc2hsZXRzU3BhdGlhbCwKICAgICAgICAgICAgICBpbmRpY2VzMzIsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucywKICAgICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLAogICAgICAgICAgICAgIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCwKICAgICAgICAgICAgICBtYXhfdmVydGljZXMsCiAgICAgICAgICAgICAgbWluX3RyaWFuZ2xlcywKICAgICAgICAgICAgICBtYXhfdHJpYW5nbGVzLAogICAgICAgICAgICAgIGZpbGxfd2VpZ2h0CiAgICAgICAgICAgICk7CiAgICAgICAgICB9LAogICAgICAgICAgZXh0cmFjdE1lc2hsZXQ6IGZ1bmN0aW9uKGJ1ZmZlcnMsIGluZGV4KSB7CiAgICAgICAgICAgIGFzc2VydChpbmRleCA+PSAwICYmIGluZGV4IDwgYnVmZmVycy5tZXNobGV0Q291bnQpOwogICAgICAgICAgICByZXR1cm4gZXh0cmFjdE1lc2hsZXQoYnVmZmVycywgaW5kZXgpOwogICAgICAgICAgfSwKICAgICAgICAgIGNvbXB1dGVDbHVzdGVyQm91bmRzOiBmdW5jdGlvbihpbmRpY2VzLCB2ZXJ0ZXhfcG9zaXRpb25zLCB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSkgewogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcy5sZW5ndGggJSAzID09IDApOwogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcy5sZW5ndGggLyAzIDw9IDUxMik7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgdmFyIGluZGljZXMzMiA9IGluZGljZXMuQllURVNfUEVSX0VMRU1FTlQgPT0gNCA/IGluZGljZXMgOiBuZXcgVWludDMyQXJyYXkoaW5kaWNlcyk7CiAgICAgICAgICAgIHJldHVybiBjb21wdXRlQ2x1c3RlckJvdW5kcyhpbmRpY2VzMzIsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCk7CiAgICAgICAgICB9LAogICAgICAgICAgY29tcHV0ZU1lc2hsZXRCb3VuZHM6IGZ1bmN0aW9uKGJ1ZmZlcnMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlKSB7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgcmV0dXJuIGNvbXB1dGVNZXNobGV0Qm91bmRzKGJ1ZmZlcnMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoIC8gdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlICogNCk7CiAgICAgICAgICB9LAogICAgICAgICAgY29tcHV0ZVNwaGVyZUJvdW5kczogZnVuY3Rpb24ocG9zaXRpb25zLCBwb3NpdGlvbnNfc3RyaWRlLCByYWRpaSwgcmFkaWlfc3RyaWRlKSB7CiAgICAgICAgICAgIGFzc2VydChwb3NpdGlvbnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQocG9zaXRpb25zLmxlbmd0aCAlIHBvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydChwb3NpdGlvbnNfc3RyaWRlID49IDMpOwogICAgICAgICAgICBhc3NlcnQoIXJhZGlpIHx8IHJhZGlpIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KCFyYWRpaSB8fCByYWRpaS5sZW5ndGggJSByYWRpaV9zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCghcmFkaWkgfHwgcmFkaWlfc3RyaWRlID49IDEpOwogICAgICAgICAgICBhc3NlcnQoIXJhZGlpIHx8IHBvc2l0aW9ucy5sZW5ndGggLyBwb3NpdGlvbnNfc3RyaWRlID09IHJhZGlpLmxlbmd0aCAvIHJhZGlpX3N0cmlkZSk7CiAgICAgICAgICAgIHJhZGlpX3N0cmlkZSA9IHJhZGlpX3N0cmlkZSB8fCAwOwogICAgICAgICAgICByZXR1cm4gY29tcHV0ZVNwaGVyZUJvdW5kcyhwb3NpdGlvbnMsIHBvc2l0aW9ucy5sZW5ndGggLyBwb3NpdGlvbnNfc3RyaWRlLCBwb3NpdGlvbnNfc3RyaWRlICogNCwgcmFkaWksIHJhZGlpX3N0cmlkZSAqIDQpOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL21lc2hvcHRfdGFuZ2VudHMuanMKICB2YXIgTWVzaG9wdFRhbmdlbnRzOwogIHZhciBpbml0X21lc2hvcHRfdGFuZ2VudHMgPSBfX2VzbSh7CiAgICAibm9kZV9tb2R1bGVzL21lc2hvcHRpbWl6ZXIvbWVzaG9wdF90YW5nZW50cy5qcyIoKSB7CiAgICAgIE1lc2hvcHRUYW5nZW50cyA9IChmdW5jdGlvbigpIHsKICAgICAgICB2YXIgd2FzbTIgPSAiYjlINzlUZWJiYmVndjlHZXVldTlHZXViOUdiYjlHa3V1dXV1dXV1dXV1YjlHaXV1dWV1aXJvZGlibGJlbHZlOVdlaWl2aWViZW93ZXVlY2o6R2Rrcm5sbzlUVzlUOVZWOTVkYkg5RjlGOTM5SDc5VDlGOUo5SDIyOUY5SnQ5VlY3YmJLOVRXNzlPOVY5V3Q5RjlOVzlVV1Y5SHRXOXU5SDlVOU5XOVV0N2JlbDc5SVY5UmJkRHdlYmNla2RsdnE7bThMb2Riazp3Z3ZPdXc5OWl1djk5dnU4SmpqampiYztXYjlSZ2s4S2pqampiYWtjeGZjYmM7S2J6OmRqampiOEFha2N1YWxjZHRneGFsY0ZGRkZpMEVjYnlkOnE6RzpjamJIampqamJiZ21CZHhha2NlQmQyYWRjaTlVaFBhbGNkNGFsZmhzY2VoemluYXpnSGNldGh6YUhhczZtYmtha2N1YUhjZHRnemFIY0ZGRkZpMEVjYnlkOnE6RzpjamJIampqamJiZ3NCZHpha2NkQmQyYXNjRmVheno6ZGpqamJoT2FEY2Q0aEFhcmNkNGhDYXZjZDRoWGRuYWxUbWJhSGN1ZmhyY2JodmluZG5kbmFPY2JhaWF2YVgyY2R0ZmdIeWRsZ0RhRGNqampqOTRTRWdzY0g0Y2Jhb2F2YUMyY2R0Zmd6eWRsZ1FjczRhUWNqampqOTRTRTdhczdjOkY6YjpERDJjYmFIeWRiZ0xhTGNqampqOTRTRWdzY0g0Y2JhenlkYmdLY3M0YUtjampqajk0U0U3YXM3YztEO086QjhKMjdjYmFIeWR3Z1lhWWNqampqOTRTRWdIY0g0Y2Jhenlkd2c4QWNzNGE4QWNqampqOTRTRTdhSDdjOjNGO044TjI3YXdhdmFBMmNkdGZnSHlkbGdFYUh5ZGJnMzdjRkZGRnJHZ0hjbTRhSDdjOmZqaksyN2FyR2dzY2R0ZmdIeWRiZ3pjdVNtYmFFOjpoNWEzOjpoOEVhOEE6Omg4RmFROjpoYWFLOjpoaGFZOjpoZ2FEOjpoOEphTDo6aDhLY2VoRGluYURoSGRuYWlhemFYMmNkdGZnRElkYmE4SzlDbWJhRElkbGE4SjlDbWJhRElkd2FnOUNtYmFvYXphQzJjZHRmZ0RJZGJhaDlDbWJhRElkbGFhOUNtYmFESWR3YThGOUNtYmF3YXphQTJjZHRmZ0RJZGJhOEU5Q21iYURJZGxhNTlCbWlrYUhjZWZoRGFPYXNhSGZhckdnc2NkdGZnSHlkYmd6Y3U5aG1ia2thSGF2QmRiYXZoemthbWF2Y2R0ZmF6QmRiYXZjZWZndmFsOWhtYmtrYU9jYnlkTjpHOmNqYkg6YmpqamJiYWtjZUJkMmFrY3VhbGNlZmdIY2R0YUhjRkZGRmkwRWNieWQ6cTpHOmNqYkhqampqYmJnOExCZHpha2NkQmQyYWtjdWFkY2R0YWRjRkZGRmkwRWdZY2J5ZDpxOkc6Y2piSGpqampiYmc4TUJkQ2FrY2lCZDJhOExjbGZjYmF4ejpkampqYmh6ZG5hZFRtYmRuYWVUbWJhZWhIYWRoc2luYXphbWFIeWRiY2R0ZnlkYmNkdGZnRGFEeWRiY2VmQmRiYUhjbGZoSGFzY3VmZ3NtYnhka2thbWhIYWRoc2luYXphSHlkYmNkdGZnRGFEeWRiY2VmQmRiYUhjbGZoSGFzY3VmZ3NtYmtrZG5hbFRtYmNiaHNhemhIYWxoRGluYUh5ZGJoT2FIYXNCZGJhSGNsZmhIYU9hc2Zoc2FEY3VmZ0RtYmtrZG5hZGNpNmdRbWJjYmhzY2RoSGFQaE9pbmRuZG5hZVRtYmFtYWVhc2ZndnlkYmNkdGZoRGFtYXZjd2Z5ZGJjZHRmaHJhbWF2Y2xmeWRiY2R0Zmh2eGVrYW1hc2ZnRGN3ZmhyYURjbGZodmthcnlkYmhyYXZ5ZGJodmF6YUR5ZGJjZHRmZ0RhRHlkYmdEY2VmQmRiYThNYURjZHRmYUhjOTpmQmRiYXphdmNkdGZnRGFEeWRiZ0RjZWZCZGJhOE1hRGNkdGZhSGN1ZkJkYmF6YXJjZHRmZ0RhRHlkYmdEY2VmQmRiYThNYURjZHRmYUhCZGJhc2N4ZmhzYUhjbGZoSGFPY3VmZ09tYmtrY2Joc2E4TGNiQmRiYWtjdWFQY2x0YWRjRkZGRmQwRWNieWQ6cTpHOmNqYkhqampqYmJnOE5CZEtha2NsQmQyZG5hUW1iYWVoemE4TmhIYVBodmluZG5kbmFlVG1iYXpjd2Z5ZGJoRGF6Y2xmeWRiaE9henlkYmhyeGVrYXNjZGZoRGFzY2VmaE9hc2hya0piYmJiaDhLSmJiYmJKYmJiYkpiYmJiSmJiYmJKYmJqWkpiYmo6O2F3YU9hQTJjZHRmZ1FJZGJhd2FyYUEyY2R0ZmdMSWRiZ2g6dGF3YURhQTJjZHRmZ0tJZGxhTElkbGdnOnRnOEpOYVFJZGxhZzp0Z2dhS0lkYmFoOnROOnRnaEpiYmJiOUVFYWhKYmJiYjlCRWc4RWFpYXJhWDJjZHRmZ3JJZHdnaGFpYU9hWDJjZHRmZ09JZHdnNTlCRWE4RWFySWRsZ2FhT0lkbGd5OUJFYThFYXJJZGJnOEZhT0lkYmc4UDlCRWc4RWFoYWlhRGFYMmNkdGZnRElkd2dJOUJFYThFYWFhRElkbGc4UjlCRWE4RWE4RmFESWRiZzhTOUJFZzhFYTVhSTlCRWE4RWF5YThSOUJFYThFYThQYThTOUJFaDhFZG5hOEphNWFoOnROYWdhSWFoOnROOnRnaGFoTmE4SmE4UGE4Rjp0TmFnYThTYThGOnROOnRnOEZhOEZOYThKYXlhYTp0TmFnYThSYWE6dE46dGc4SmE4Sk5NTWdnSmJiYmI5Qm1iYThFYWc6cjp2aDhLa2FIY3hmYThFVWRiYUhjd2ZhaGE4S05VZGJhSGNsZmE4SmE4S05VZGJhSGE4RmE4S05VZGJhemN4Zmh6YUhjemZoSGFzY2lmaHNhdmN1Zmd2bWJra2NiaEhha2FZY2J5ZDpxOkc6Y2piSGpqampiYmdEQmQzYWtjdkJkMmRuYWRUbWJhRGh6aW5hemFIQmRiYXpjbGZoemFkYUhjZWZnSDlobWJra2FrY3VhUGNkdGFkY0ZGRkY5NzBFY2J5ZDpxOkc6Y2piSGpqampiYmd2QmRhYWtjb0JkMmFrYVBjYnlkOnE6RzpjamJIampqamJiZzhBQmQ4S2FrY3JCZDJkbmFkY2k2bWJhOE5jeGZoemF2aHNjYmhIaW5hc2FIQmRiYThBYUhmY2RjYmF6SWRiZzhLSmJiYmI5REVhOEtKYmJiYjlFVjg2YmJhc2NsZmhzYXpjemZoemFQYUhjZWZnSDlobWJra2RuYWxUbWJjYmhSaW5hUmNkdGhIZG5hOExhUmNlZmdSY2R0ZnlkYmd6YThMYUhmeWRiZ0hTbWJhemFIOVJoTGE4TWFIY2R0ZmhLY2JoOFVpbmFLYThVY2R0Zmc4VnlkYmdIY2Q0ZzhXY2kyZ3hhSGNpR2NkdGd6eWQ6ZTpHOmNqYmZoSGF4YXp5ZGo6RzpjamJmaHpkbmFlVG1iYWVhSGNkdGZ5ZGJoSGFlYXpjZHRmeWRiaHprZG5hOFVjZWZnOFVhTDlwbWJhbWFIY2R0ZnlkYmhZYW1hemNkdGZ5ZGJoM2E4QWE4V2ZoRWF2YThXY2R0Zmg4WGE4VWh3aW5hS2F3Y2R0ZmdReWRiZ0hjZDRnemNpMmdBYUhjaUdjZHRnSHlkOmU6RzpjamJmaHNhQWFIeWRqOkc6Y2piZmhIZG5hZVRtYmFlYXNjZHRmeWRiaHNhZWFIY2R0ZnlkYmhIa2RuZG5hbWFIY2R0ZnlkYmFZU21iYW1hc2NkdGZ5ZGJhMzlobWVrYThBYXpmUmJiZ0hhRVJiYmdzVmNpU21iZG5hSGFzR21iYThXaHNkbmE4V2E4WHlkYmdIU21iYThYaE9pbmFPYXZhSGdzY2R0ZmdyeWRiZ0hCZGJhcmhPYXNhSDlobWJra2RuYXphdmF6Y2R0ZmdPeWRiZ0hTbWJpbmFPYXZhSGd6Y2R0ZmdyeWRiZ0hCZGJhcmhPYXphSDlobWJra2FzYXpTbWJhOEFhemZnT1JiYmE4QWFzZmdIUmJiVmNpU21lYXZhemNkdGZhc0JkYmFIYUhSYmJhT1JiYlY4NmJia2RuYThWeWRiY2lHYXhmZ3phRGF6Y2R0ZmdzeWRiZ0hTbWJpbmFzYURhSGd6Y2R0ZmdPeWRiZ0hCZGJhT2hzYXphSDlobWJra2RuYVF5ZGJjaUdhQWZnc2FEYXNjZHRmZ095ZGJnSFNtYmluYU9hRGFIZ3NjZHRmZ3J5ZGJnSEJkYmFyaE9hc2FIOWhtYmtrYXphc1NtYmFEYXNjZHRmYXpCZGJrYXdjZWZnd2FMOWhtYmtrYThVYUw5aG1ia2thUmFsOWhtYmtrZG5hZFRtYmNiaHJpbmFyaHpkbmFyYURhcmNkdGZnd3lkYmdIU21iYXdoc2luYXNhRGFIZ3pjZHRmZ095ZGJnSEJkYmFPaHNhemFIOWhtYmtrYXdhekJkYmFyY2VmZ3JhZDlobWJrY2JoOFZhYmNiYWRjbHR6OmRqampiaEtkbmFkY2k2bWJhcWNlR2hFYURoWWFlaDNjYmg4V2luZG5hOE5hOFdjbHRmZ3NJZHhKYmJiYjlCbWJhbWE4V2N4MmdIZmh4YWVhSGZoTGNiaHphOFZod2luYUthWWF6ZnlkYmNsdGZoSGRuZG5hZVRtYmFtYUxhemM6ZTpHOmNqYmZ5ZGJjZHRmeWRiY2R0ZmhBYW1hTGF6Y2o6RzpjamJmeWRiY2R0ZnlkYmNkdGZocmEzYXpmeWRiaE94ZWtheGF6YzplOkc6Y2piZnlkYmNkdGZoQWF4YXpjajpHOmNqYmZ5ZGJjZHRmaHJhd2hPa2FIYXNJZGJnZ2FvYW1hT2NkdGZ5ZGJnUWFDMmNkdGZnT0lkYmc4S2FzSWR3ZzhGYU9JZHdnOEpOYWdhOEtOYXNJZGxnOEVhT0lkbGdnTk1NZ2hOOnRnYUpiYmJiSmJialphOEZhOEphaE46dGc4RmE4Rk5hYWFhTmE4RWFnYWhOOnRnaGFoTk1NZ2E6cjp2YWFKYmJiYjlCRUo7QXM2bkpiYmpaYWlhcnlkYmFYMmNkdGZnT0lkd2FpYVFhWDJjZHRmZ3JJZHdnNTp0Z2FhOEphYWE4Sk5hT0lkYmFySWRiZ3k6dGc4UGE4S05hZ2FPSWRsYXJJZGxnSTp0ZzhSTk1NZ2FOOnRnOEVhaWFBeWRiYVgyY2R0ZmdPSWR3YTU6dGc1YThKYTVhOEpOYU9JZGJheTp0ZzhTYThLTmFnYU9JZGxhSTp0Z0lOTU1nNU46dGc4Sk5hOFBhOEthYU46dGd5YThTYThLYTVOOnRnOEtOYThSYWdhYU46dGdhYUlhZ2E1Tjp0Z2dOTU1KYmJiYkpiYmpaYThFYThFTmF5YXlOYWFhYU5NTWE4SmE4Sk5hOEthOEtOYWdhZ05NTU5nOEs6cmc4Sjp2YThLSmJiYmI5QkVOZ2c6bGc4S2E4S0piYmpaOUVFZzhLYThLSjc7QTlzODlOSjpMOXQ5czo6TU5KO29iO2paTUpiYmpaYThLOnQ6ck5nOEs6dGE4S2FnSmJiYmI5REVOZzhLYThKYThLTmFFRWc4S05hSElkYk1VZGJhSGFoYThLTmFISWRsTVVkbGFIYThGYThLTmFISWR3TVVkd2F3Y2VmaHdhemNsZmd6Y3g5aG1ia2thWWN4ZmhZYTNjeGZoM2E4VmNpZmg4VmE4V2NlZmc4V2FQOWhtYmtjYmhyaW5hcmh6ZG5hcmF2YXJjZHRmZ3N5ZGJnSFNtYmluYXNhdmFIZ3pjZHRmZ095ZGJnSEJkYmFPaHNhemFIOWhtYmtrYUthcmM4VzJmZ0hjM2ZKYmJqWkpiYmo6O2E4QWF6ZlJiYmNlR0VnOEtVZGJhSGM4U2ZhOEtVZGJhSGE4S1VkeGFyY2VmZ3JhUDlobWJra2FxY2RHaHZjYmh6YURoc2FLaEhpbmRuYXphc3lkYjlobWJKYmJiYmg4S2RuYUhjd2ZnT0lkYmc4SmE4Sk5hSElkYmdnYWdOYUhjbGZncklkYmdoYWhOTU1nYUpiYmJiOUJtYkpiYmpaYWE6cjp2aDhLa2FPYThKYThLTlVkYmFyYWhhOEtOVWRiYUhhZ2E4S05nOEpVZGJhdm1iYUhKYmJqWmE4SmE4S0piYmJiOUJFVWRia2FzY2xmaHNhSGN6ZmhIYWRhemNlZmd6OWhtYmtjYmhIYUtoemluZG5hSGFEeWRiZ3NTbWJhemFLYXNjbHRmZ3N5ZHdCZHdhemFzOFBkYjgzZGJrYURjbGZoRGF6Y3pmaHphZGFIY2VmZ0g5aG1ia2tkbmFreWQyZ3pUbWJhemNkdGFrY3hmZmM5OGZoSGluYUh5ZGJjYnlkTjpHOmNqYkg6YmpqamJiYUhjOThmaEhhemN1Zmd6bWJra2FrYztXYmY4S2pqampiazl0ZWl1Y2JjYnlkOnk6RzpjamJnZWFiY2lmYzk4R2ZnYkJkOnk6RzpjamJkbmRuYWJaYmN6dGdkOW5tYmN1aGlhYmFkOVJjRkZpZmN6NG5iY3VTbWVrYWVoaWthaWs7YWVlZHVkbmRuYWJjaUdUbWJhYmhpeGVrYWVjRmVHYzpiOmM6ZXcyaGxkbmRuYWRjejlwbWJhYmhpeGVrYWJoaWluYWlhbEJkYmFpY3hmYWxCZGJhaWN3ZmFsQmRiYWljbGZhbEJkYmFpY3pmaGlhZGM5V2ZnZGNzMG1ia2thZGNsNm1iaW5haWFsQmRiYWljbGZoaWFkYzk4ZmdkY2kwbWJra2RuYWRUbWJpbmFpYWU4NmJiYWljZWZoaWFkY3VmZ2RtYmtrYWJrOXRlaXVjYmNieWQ6eTpHOmNqYmdlYWJjcmZjOTRHZmdiQmQ6eTpHOmNqYmRuZG5hYlpiY3p0Z2Q5bm1iY3VoaWFiYWQ5UmNGRmlmY3o0bmJjdVNtZWthZWhpa2Fpa1RlZXVjYmFiY2J5ZDp5Okc6Y2piZ2U5UmNpZmM5OEdhZWZnYkJkOnk6RzpjamJkbmFiWmJjenRnZTlubWJhYmFlOVJjRkZpZmN6NG5iOEFra2s4UmRiY2o6R2RremViYmJkYmJiYmJiYmViYmJiYzpxOkdka3hlYmJiZGJiYmE6cWJiIjsKICAgICAgICB2YXIgd2FzbXBhY2sgPSBuZXcgVWludDhBcnJheShbCiAgICAgICAgICAzMiwKICAgICAgICAgIDAsCiAgICAgICAgICA2NSwKICAgICAgICAgIDIsCiAgICAgICAgICAxLAogICAgICAgICAgMTA2LAogICAgICAgICAgMzQsCiAgICAgICAgICAzMywKICAgICAgICAgIDMsCiAgICAgICAgICAxMjgsCiAgICAgICAgICAxMSwKICAgICAgICAgIDQsCiAgICAgICAgICAxMywKICAgICAgICAgIDY0LAogICAgICAgICAgNiwKICAgICAgICAgIDI1MywKICAgICAgICAgIDEwLAogICAgICAgICAgNywKICAgICAgICAgIDE1LAogICAgICAgICAgMTE2LAogICAgICAgICAgMTI3LAogICAgICAgICAgNSwKICAgICAgICAgIDgsCiAgICAgICAgICAxMiwKICAgICAgICAgIDQwLAogICAgICAgICAgMTYsCiAgICAgICAgICAxOSwKICAgICAgICAgIDU0LAogICAgICAgICAgMjAsCiAgICAgICAgICA5LAogICAgICAgICAgMjcsCiAgICAgICAgICAyNTUsCiAgICAgICAgICAxMTMsCiAgICAgICAgICAxNywKICAgICAgICAgIDQyLAogICAgICAgICAgNjcsCiAgICAgICAgICAyNCwKICAgICAgICAgIDIzLAogICAgICAgICAgMTQ2LAogICAgICAgICAgMTQ4LAogICAgICAgICAgMTgsCiAgICAgICAgICAxNCwKICAgICAgICAgIDIyLAogICAgICAgICAgNDUsCiAgICAgICAgICA3MCwKICAgICAgICAgIDY5LAogICAgICAgICAgNTYsCiAgICAgICAgICAxMTQsCiAgICAgICAgICAxMDEsCiAgICAgICAgICAyMSwKICAgICAgICAgIDI1LAogICAgICAgICAgNjMsCiAgICAgICAgICA3NSwKICAgICAgICAgIDEzNiwKICAgICAgICAgIDEwOCwKICAgICAgICAgIDI4LAogICAgICAgICAgMTE4LAogICAgICAgICAgMjksCiAgICAgICAgICA3MywKICAgICAgICAgIDExNQogICAgICAgIF0pOwogICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkgIT09ICJvYmplY3QiKSB7CiAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICBzdXBwb3J0ZWQ6IGZhbHNlCiAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICB2YXIgaW5zdGFuY2U7CiAgICAgICAgdmFyIHJlYWR5ID0gV2ViQXNzZW1ibHkuaW5zdGFudGlhdGUodW5wYWNrKHdhc20yKSwge30pLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgICBpbnN0YW5jZSA9IHJlc3VsdC5pbnN0YW5jZTsKICAgICAgICAgIGluc3RhbmNlLmV4cG9ydHMuX193YXNtX2NhbGxfY3RvcnMoKTsKICAgICAgICB9KTsKICAgICAgICBmdW5jdGlvbiB1bnBhY2soZGF0YSkgewogICAgICAgICAgdmFyIHJlc3VsdCA9IG5ldyBVaW50OEFycmF5KGRhdGEubGVuZ3RoKTsKICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBkYXRhLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICB2YXIgY2ggPSBkYXRhLmNoYXJDb2RlQXQoaTIpOwogICAgICAgICAgICByZXN1bHRbaTJdID0gY2ggPiA5NiA/IGNoIC0gOTcgOiBjaCA+IDY0ID8gY2ggLSAzOSA6IGNoICsgNDsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB3cml0ZSA9IDA7CiAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgZGF0YS5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgcmVzdWx0W3dyaXRlKytdID0gcmVzdWx0W2kyXSA8IDYwID8gd2FzbXBhY2tbcmVzdWx0W2kyXV0gOiAocmVzdWx0W2kyXSAtIDYwKSAqIDY0ICsgcmVzdWx0WysraTJdOwogICAgICAgICAgfQogICAgICAgICAgcmV0dXJuIHJlc3VsdC5idWZmZXIuc2xpY2UoMCwgd3JpdGUpOwogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBhc3NlcnQoY29uZCkgewogICAgICAgICAgaWYgKCFjb25kKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiQXNzZXJ0aW9uIGZhaWxlZCIpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBmdW5jdGlvbiBieXRlcyh2aWV3KSB7CiAgICAgICAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkodmlldy5idWZmZXIsIHZpZXcuYnl0ZU9mZnNldCwgdmlldy5ieXRlTGVuZ3RoKTsKICAgICAgICB9CiAgICAgICAgZnVuY3Rpb24gZ2VuZXJhdGUoaW5kaWNlcywgaW5kZXhfY291bnQsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9jb3VudCwgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsIHZlcnRleF9ub3JtYWxzLCB2ZXJ0ZXhfbm9ybWFsc19zdHJpZGUsIHZlcnRleF91dnMsIHZlcnRleF91dnNfc3RyaWRlLCBvcHRpb25zKSB7CiAgICAgICAgICB2YXIgc2JyayA9IGluc3RhbmNlLmV4cG9ydHMuc2JyazsKICAgICAgICAgIHZhciByZXN1bHRwID0gc2JyayhpbmRleF9jb3VudCAqIDE2KTsKICAgICAgICAgIHZhciBpbmRpY2VzcCA9IGluZGljZXMgPyBzYnJrKGluZGljZXMuYnl0ZUxlbmd0aCkgOiAwOwogICAgICAgICAgdmFyIHBvc2l0aW9uc3AgPSBzYnJrKHZlcnRleF9wb3NpdGlvbnMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgbm9ybWFsc3AgPSBzYnJrKHZlcnRleF9ub3JtYWxzLmJ5dGVMZW5ndGgpOwogICAgICAgICAgdmFyIHV2c3AgPSBzYnJrKHZlcnRleF91dnMuYnl0ZUxlbmd0aCk7CiAgICAgICAgICB2YXIgaGVhcCA9IG5ldyBVaW50OEFycmF5KGluc3RhbmNlLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICBpZiAoaW5kaWNlcykgaGVhcC5zZXQoYnl0ZXMoaW5kaWNlcyksIGluZGljZXNwKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKHZlcnRleF9wb3NpdGlvbnMpLCBwb3NpdGlvbnNwKTsKICAgICAgICAgIGhlYXAuc2V0KGJ5dGVzKHZlcnRleF9ub3JtYWxzKSwgbm9ybWFsc3ApOwogICAgICAgICAgaGVhcC5zZXQoYnl0ZXModmVydGV4X3V2cyksIHV2c3ApOwogICAgICAgICAgaW5zdGFuY2UuZXhwb3J0cy5tZXNob3B0X2dlbmVyYXRlVGFuZ2VudHMoCiAgICAgICAgICAgIHJlc3VsdHAsCiAgICAgICAgICAgIGluZGljZXNwLAogICAgICAgICAgICBpbmRleF9jb3VudCwKICAgICAgICAgICAgcG9zaXRpb25zcCwKICAgICAgICAgICAgdmVydGV4X2NvdW50LAogICAgICAgICAgICB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSAqIDQsCiAgICAgICAgICAgIG5vcm1hbHNwLAogICAgICAgICAgICB2ZXJ0ZXhfbm9ybWFsc19zdHJpZGUgKiA0LAogICAgICAgICAgICB1dnNwLAogICAgICAgICAgICB2ZXJ0ZXhfdXZzX3N0cmlkZSAqIDQsCiAgICAgICAgICAgIG9wdGlvbnMKICAgICAgICAgICk7CiAgICAgICAgICBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoaW5zdGFuY2UuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKTsKICAgICAgICAgIHZhciByZXN1bHQgPSBuZXcgRmxvYXQzMkFycmF5KGhlYXAuYnVmZmVyLCByZXN1bHRwLCBpbmRleF9jb3VudCAqIDQpLnNsaWNlKCk7CiAgICAgICAgICBzYnJrKHJlc3VsdHAgLSBzYnJrKDApKTsKICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgfQogICAgICAgIHZhciB0YW5nZW50T3B0aW9ucyA9IHsKICAgICAgICAgIENvbXBhdGlibGU6IDEsCiAgICAgICAgICBaZXJvRmFsbGJhY2s6IDIKICAgICAgICB9OwogICAgICAgIHJldHVybiB7CiAgICAgICAgICByZWFkeSwKICAgICAgICAgIHN1cHBvcnRlZDogdHJ1ZSwKICAgICAgICAgIGdlbmVyYXRlVGFuZ2VudHM6IGZ1bmN0aW9uKGluZGljZXMsIHZlcnRleF9wb3NpdGlvbnMsIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlLCB2ZXJ0ZXhfbm9ybWFscywgdmVydGV4X25vcm1hbHNfc3RyaWRlLCB2ZXJ0ZXhfdXZzLCB2ZXJ0ZXhfdXZzX3N0cmlkZSwgZmxhZ3MpIHsKICAgICAgICAgICAgYXNzZXJ0KAogICAgICAgICAgICAgIGluZGljZXMgPT09IG51bGwgfHwgaW5kaWNlcyBpbnN0YW5jZW9mIFVpbnQzMkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBJbnQzMkFycmF5IHx8IGluZGljZXMgaW5zdGFuY2VvZiBVaW50MTZBcnJheSB8fCBpbmRpY2VzIGluc3RhbmNlb2YgSW50MTZBcnJheQogICAgICAgICAgICApOwogICAgICAgICAgICBhc3NlcnQoaW5kaWNlcyA9PT0gbnVsbCB8fCBpbmRpY2VzLmxlbmd0aCAlIDMgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9wb3NpdGlvbnMubGVuZ3RoICUgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUgPT0gMCk7CiAgICAgICAgICAgIGFzc2VydCh2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9ub3JtYWxzIGluc3RhbmNlb2YgRmxvYXQzMkFycmF5KTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9ub3JtYWxzLmxlbmd0aCAlIHZlcnRleF9ub3JtYWxzX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF9ub3JtYWxzX3N0cmlkZSA+PSAzKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF91dnMgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3V2cy5sZW5ndGggJSB2ZXJ0ZXhfdXZzX3N0cmlkZSA9PSAwKTsKICAgICAgICAgICAgYXNzZXJ0KHZlcnRleF91dnNfc3RyaWRlID49IDIpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSB2ZXJ0ZXhfbm9ybWFscy5sZW5ndGggLyB2ZXJ0ZXhfbm9ybWFsc19zdHJpZGUpOwogICAgICAgICAgICBhc3NlcnQodmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSA9PSB2ZXJ0ZXhfdXZzLmxlbmd0aCAvIHZlcnRleF91dnNfc3RyaWRlKTsKICAgICAgICAgICAgYXNzZXJ0KGluZGljZXMgIT09IG51bGwgfHwgdmVydGV4X3Bvc2l0aW9ucy5sZW5ndGggLyB2ZXJ0ZXhfcG9zaXRpb25zX3N0cmlkZSAlIDMgPT0gMCk7CiAgICAgICAgICAgIHZhciBvcHRpb25zID0gMDsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IChmbGFncyA/IGZsYWdzLmxlbmd0aCA6IDApOyArK2kyKSB7CiAgICAgICAgICAgICAgYXNzZXJ0KGZsYWdzW2kyXSBpbiB0YW5nZW50T3B0aW9ucyk7CiAgICAgICAgICAgICAgb3B0aW9ucyB8PSB0YW5nZW50T3B0aW9uc1tmbGFnc1tpMl1dOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciB2ZXJ0ZXhfY291bnQgPSB2ZXJ0ZXhfcG9zaXRpb25zLmxlbmd0aCAvIHZlcnRleF9wb3NpdGlvbnNfc3RyaWRlOwogICAgICAgICAgICB2YXIgaW5kZXhfY291bnQgPSBpbmRpY2VzID8gaW5kaWNlcy5sZW5ndGggOiB2ZXJ0ZXhfY291bnQ7CiAgICAgICAgICAgIHZhciBpbmRpY2VzMzIgPSBpbmRpY2VzID09PSBudWxsIHx8IGluZGljZXMuQllURVNfUEVSX0VMRU1FTlQgPT0gNCA/IGluZGljZXMgOiBuZXcgVWludDMyQXJyYXkoaW5kaWNlcyk7CiAgICAgICAgICAgIHJldHVybiBnZW5lcmF0ZSgKICAgICAgICAgICAgICBpbmRpY2VzMzIsCiAgICAgICAgICAgICAgaW5kZXhfY291bnQsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9ucywKICAgICAgICAgICAgICB2ZXJ0ZXhfY291bnQsCiAgICAgICAgICAgICAgdmVydGV4X3Bvc2l0aW9uc19zdHJpZGUsCiAgICAgICAgICAgICAgdmVydGV4X25vcm1hbHMsCiAgICAgICAgICAgICAgdmVydGV4X25vcm1hbHNfc3RyaWRlLAogICAgICAgICAgICAgIHZlcnRleF91dnMsCiAgICAgICAgICAgICAgdmVydGV4X3V2c19zdHJpZGUsCiAgICAgICAgICAgICAgb3B0aW9ucwogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9tZXNob3B0aW1pemVyL2luZGV4LmpzCiAgdmFyIGluaXRfbWVzaG9wdGltaXplciA9IF9fZXNtKHsKICAgICJub2RlX21vZHVsZXMvbWVzaG9wdGltaXplci9pbmRleC5qcyIoKSB7CiAgICAgIGluaXRfbWVzaG9wdF9lbmNvZGVyKCk7CiAgICAgIGluaXRfbWVzaG9wdF9kZWNvZGVyKCk7CiAgICAgIGluaXRfbWVzaG9wdF9zaW1wbGlmaWVyKCk7CiAgICAgIGluaXRfbWVzaG9wdF9jbHVzdGVyaXplcigpOwogICAgICBpbml0X21lc2hvcHRfdGFuZ2VudHMoKTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9TY2VuZS9BeGlzLmpzCiAgdmFyIEF4aXMsIEF4aXNfZGVmYXVsdDsKICB2YXIgaW5pdF9BeGlzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvU2NlbmUvQXhpcy5qcyIoKSB7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBBeGlzID0gewogICAgICAgIC8qKgogICAgICAgICAqIERlbm90ZXMgdGhlIHgtYXhpcy4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgWDogMCwKICAgICAgICAvKioKICAgICAgICAgKiBEZW5vdGVzIHRoZSB5LWF4aXMuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFk6IDEsCiAgICAgICAgLyoqCiAgICAgICAgICogRGVub3RlcyB0aGUgei1heGlzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBaOiAyCiAgICAgIH07CiAgICAgIEF4aXMuWV9VUF9UT19aX1VQID0gTWF0cml4NF9kZWZhdWx0LmZyb21Sb3RhdGlvblRyYW5zbGF0aW9uKAogICAgICAgIC8vIFJvdGF0aW9uIGFib3V0IFBJLzIgYXJvdW5kIHRoZSBYLWF4aXMKICAgICAgICBNYXRyaXgzX2RlZmF1bHQuZnJvbUFycmF5KFsxLCAwLCAwLCAwLCAwLCAxLCAwLCAtMSwgMF0pCiAgICAgICk7CiAgICAgIEF4aXMuWl9VUF9UT19ZX1VQID0gTWF0cml4NF9kZWZhdWx0LmZyb21Sb3RhdGlvblRyYW5zbGF0aW9uKAogICAgICAgIC8vIFJvdGF0aW9uIGFib3V0IC1QSS8yIGFyb3VuZCB0aGUgWC1heGlzCiAgICAgICAgTWF0cml4M19kZWZhdWx0LmZyb21BcnJheShbMSwgMCwgMCwgMCwgMCwgLTEsIDAsIDEsIDBdKQogICAgICApOwogICAgICBBeGlzLlhfVVBfVE9fWl9VUCA9IE1hdHJpeDRfZGVmYXVsdC5mcm9tUm90YXRpb25UcmFuc2xhdGlvbigKICAgICAgICAvLyBSb3RhdGlvbiBhYm91dCAtUEkvMiBhcm91bmQgdGhlIFktYXhpcwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5mcm9tQXJyYXkoWzAsIDAsIDEsIDAsIDEsIDAsIC0xLCAwLCAwXSkKICAgICAgKTsKICAgICAgQXhpcy5aX1VQX1RPX1hfVVAgPSBNYXRyaXg0X2RlZmF1bHQuZnJvbVJvdGF0aW9uVHJhbnNsYXRpb24oCiAgICAgICAgLy8gUm90YXRpb24gYWJvdXQgUEkvMiBhcm91bmQgdGhlIFktYXhpcwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5mcm9tQXJyYXkoWzAsIDAsIC0xLCAwLCAxLCAwLCAxLCAwLCAwXSkKICAgICAgKTsKICAgICAgQXhpcy5YX1VQX1RPX1lfVVAgPSBNYXRyaXg0X2RlZmF1bHQuZnJvbVJvdGF0aW9uVHJhbnNsYXRpb24oCiAgICAgICAgLy8gUm90YXRpb24gYWJvdXQgUEkvMiBhcm91bmQgdGhlIFotYXhpcwogICAgICAgIE1hdHJpeDNfZGVmYXVsdC5mcm9tQXJyYXkoWzAsIDEsIDAsIC0xLCAwLCAwLCAwLCAwLCAxXSkKICAgICAgKTsKICAgICAgQXhpcy5ZX1VQX1RPX1hfVVAgPSBNYXRyaXg0X2RlZmF1bHQuZnJvbVJvdGF0aW9uVHJhbnNsYXRpb24oCiAgICAgICAgLy8gUm90YXRpb24gYWJvdXQgLVBJLzIgYXJvdW5kIHRoZSBaLWF4aXMKICAgICAgICBNYXRyaXgzX2RlZmF1bHQuZnJvbUFycmF5KFswLCAtMSwgMCwgMSwgMCwgMCwgMCwgMCwgMV0pCiAgICAgICk7CiAgICAgIEF4aXMuZnJvbU5hbWUgPSBmdW5jdGlvbihuYW1lKSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yuc3RyaW5nKCJuYW1lIiwgbmFtZSk7CiAgICAgICAgcmV0dXJuIEF4aXNbbmFtZV07CiAgICAgIH07CiAgICAgIE9iamVjdC5mcmVlemUoQXhpcyk7CiAgICAgIEF4aXNfZGVmYXVsdCA9IEF4aXM7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9FbGxpcHNvaWRhbE9jY2x1ZGVyLmpzCiAgZnVuY3Rpb24gRWxsaXBzb2lkYWxPY2NsdWRlcihlbGxpcHNvaWQsIGNhbWVyYVBvc2l0aW9uKSB7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImVsbGlwc29pZCIsIGVsbGlwc29pZCk7CiAgICB0aGlzLl9lbGxpcHNvaWQgPSBlbGxpcHNvaWQ7CiAgICB0aGlzLl9jYW1lcmFQb3NpdGlvbiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgIHRoaXMuX2NhbWVyYVBvc2l0aW9uSW5TY2FsZWRTcGFjZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgIHRoaXMuX2Rpc3RhbmNlVG9MaW1iSW5TY2FsZWRTcGFjZVNxdWFyZWQgPSAwOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChjYW1lcmFQb3NpdGlvbikpIHsKICAgICAgdGhpcy5jYW1lcmFQb3NpdGlvbiA9IGNhbWVyYVBvc2l0aW9uOwogICAgfQogIH0KICBmdW5jdGlvbiBnZXRQb3NzaWJseVNocnVua0VsbGlwc29pZChlbGxpcHNvaWQsIG1pbmltdW1IZWlnaHQsIHJlc3VsdCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChtaW5pbXVtSGVpZ2h0KSAmJiBtaW5pbXVtSGVpZ2h0IDwgMCAmJiBlbGxpcHNvaWQubWluaW11bVJhZGl1cyA+IC1taW5pbXVtSGVpZ2h0KSB7CiAgICAgIGNvbnN0IGVsbGlwc29pZFNocnVua1JhZGlpID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygKICAgICAgICBlbGxpcHNvaWQucmFkaWkueCArIG1pbmltdW1IZWlnaHQsCiAgICAgICAgZWxsaXBzb2lkLnJhZGlpLnkgKyBtaW5pbXVtSGVpZ2h0LAogICAgICAgIGVsbGlwc29pZC5yYWRpaS56ICsgbWluaW11bUhlaWdodCwKICAgICAgICBzY3JhdGNoRWxsaXBzb2lkU2hydW5rUmFkaWkKICAgICAgKTsKICAgICAgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuZnJvbUNhcnRlc2lhbjMoZWxsaXBzb2lkU2hydW5rUmFkaWksIHJlc3VsdCk7CiAgICB9CiAgICByZXR1cm4gZWxsaXBzb2lkOwogIH0KICBmdW5jdGlvbiBjb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21Qb3NpdGlvbnMoZWxsaXBzb2lkLCBkaXJlY3Rpb25Ub1BvaW50LCBwb3NpdGlvbnMsIHJlc3VsdCkgewogICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJkaXJlY3Rpb25Ub1BvaW50IiwgZGlyZWN0aW9uVG9Qb2ludCk7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInBvc2l0aW9ucyIsIHBvc2l0aW9ucyk7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgIH0KICAgIGNvbnN0IHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludCA9IGNvbXB1dGVTY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQoCiAgICAgIGVsbGlwc29pZCwKICAgICAgZGlyZWN0aW9uVG9Qb2ludAogICAgKTsKICAgIGxldCByZXN1bHRNYWduaXR1ZGUgPSAwOwogICAgZm9yIChsZXQgaTIgPSAwLCBsZW4gPSBwb3NpdGlvbnMubGVuZ3RoOyBpMiA8IGxlbjsgKytpMikgewogICAgICBjb25zdCBwb3NpdGlvbiA9IHBvc2l0aW9uc1tpMl07CiAgICAgIGNvbnN0IGNhbmRpZGF0ZU1hZ25pdHVkZSA9IGNvbXB1dGVNYWduaXR1ZGUoCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludAogICAgICApOwogICAgICBpZiAoY2FuZGlkYXRlTWFnbml0dWRlIDwgMCkgewogICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgIH0KICAgICAgcmVzdWx0TWFnbml0dWRlID0gTWF0aC5tYXgocmVzdWx0TWFnbml0dWRlLCBjYW5kaWRhdGVNYWduaXR1ZGUpOwogICAgfQogICAgcmV0dXJuIG1hZ25pdHVkZVRvUG9pbnQoc2NhbGVkU3BhY2VEaXJlY3Rpb25Ub1BvaW50LCByZXN1bHRNYWduaXR1ZGUsIHJlc3VsdCk7CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVIb3Jpem9uQ3VsbGluZ1BvaW50RnJvbVZlcnRpY2VzKGVsbGlwc29pZCwgZGlyZWN0aW9uVG9Qb2ludCwgdmVydGljZXMsIHN0cmlkZSwgY2VudGVyLCByZXN1bHQpIHsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZGlyZWN0aW9uVG9Qb2ludCIsIGRpcmVjdGlvblRvUG9pbnQpOwogICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2ZXJ0aWNlcyIsIHZlcnRpY2VzKTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigic3RyaWRlIiwgc3RyaWRlKTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgcmVzdWx0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgfQogICAgc3RyaWRlID0gc3RyaWRlID8/IDM7CiAgICBjZW50ZXIgPSBjZW50ZXIgPz8gQ2FydGVzaWFuM19kZWZhdWx0LlpFUk87CiAgICBjb25zdCBzY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQgPSBjb21wdXRlU2NhbGVkU3BhY2VEaXJlY3Rpb25Ub1BvaW50KAogICAgICBlbGxpcHNvaWQsCiAgICAgIGRpcmVjdGlvblRvUG9pbnQKICAgICk7CiAgICBsZXQgcmVzdWx0TWFnbml0dWRlID0gMDsKICAgIGZvciAobGV0IGkyID0gMCwgbGVuID0gdmVydGljZXMubGVuZ3RoOyBpMiA8IGxlbjsgaTIgKz0gc3RyaWRlKSB7CiAgICAgIHBvc2l0aW9uU2NyYXRjaDUueCA9IHZlcnRpY2VzW2kyXSArIGNlbnRlci54OwogICAgICBwb3NpdGlvblNjcmF0Y2g1LnkgPSB2ZXJ0aWNlc1tpMiArIDFdICsgY2VudGVyLnk7CiAgICAgIHBvc2l0aW9uU2NyYXRjaDUueiA9IHZlcnRpY2VzW2kyICsgMl0gKyBjZW50ZXIuejsKICAgICAgY29uc3QgY2FuZGlkYXRlTWFnbml0dWRlID0gY29tcHV0ZU1hZ25pdHVkZSgKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgcG9zaXRpb25TY3JhdGNoNSwKICAgICAgICBzY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQKICAgICAgKTsKICAgICAgaWYgKGNhbmRpZGF0ZU1hZ25pdHVkZSA8IDApIHsKICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICB9CiAgICAgIHJlc3VsdE1hZ25pdHVkZSA9IE1hdGgubWF4KHJlc3VsdE1hZ25pdHVkZSwgY2FuZGlkYXRlTWFnbml0dWRlKTsKICAgIH0KICAgIHJldHVybiBtYWduaXR1ZGVUb1BvaW50KHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludCwgcmVzdWx0TWFnbml0dWRlLCByZXN1bHQpOwogIH0KICBmdW5jdGlvbiBpc1NjYWxlZFNwYWNlUG9pbnRWaXNpYmxlKG9jY2x1ZGVlU2NhbGVkU3BhY2VQb3NpdGlvbiwgY2FtZXJhUG9zaXRpb25JblNjYWxlZFNwYWNlLCBkaXN0YW5jZVRvTGltYkluU2NhbGVkU3BhY2VTcXVhcmVkKSB7CiAgICBjb25zdCBjdiA9IGNhbWVyYVBvc2l0aW9uSW5TY2FsZWRTcGFjZTsKICAgIGNvbnN0IHZoTWFnbml0dWRlU3F1YXJlZCA9IGRpc3RhbmNlVG9MaW1iSW5TY2FsZWRTcGFjZVNxdWFyZWQ7CiAgICBjb25zdCB2dDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QoCiAgICAgIG9jY2x1ZGVlU2NhbGVkU3BhY2VQb3NpdGlvbiwKICAgICAgY3YsCiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4xOQogICAgKTsKICAgIGNvbnN0IHZ0RG90VmMgPSAtQ2FydGVzaWFuM19kZWZhdWx0LmRvdCh2dDIsIGN2KTsKICAgIGNvbnN0IGlzT2NjbHVkZWQgPSB2aE1hZ25pdHVkZVNxdWFyZWQgPCAwID8gdnREb3RWYyA+IDAgOiB2dERvdFZjID4gdmhNYWduaXR1ZGVTcXVhcmVkICYmIHZ0RG90VmMgKiB2dERvdFZjIC8gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZVNxdWFyZWQodnQyKSA+IHZoTWFnbml0dWRlU3F1YXJlZDsKICAgIHJldHVybiAhaXNPY2NsdWRlZDsKICB9CiAgZnVuY3Rpb24gY29tcHV0ZU1hZ25pdHVkZShlbGxpcHNvaWQsIHBvc2l0aW9uLCBzY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQpIHsKICAgIGNvbnN0IHNjYWxlZFNwYWNlUG9zaXRpb24gPSBlbGxpcHNvaWQudHJhbnNmb3JtUG9zaXRpb25Ub1NjYWxlZFNwYWNlKAogICAgICBwb3NpdGlvbiwKICAgICAgc2NhbGVkU3BhY2VTY3JhdGNoCiAgICApOwogICAgbGV0IG1hZ25pdHVkZVNxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZChzY2FsZWRTcGFjZVBvc2l0aW9uKTsKICAgIGxldCBtYWduaXR1ZGUgPSBNYXRoLnNxcnQobWFnbml0dWRlU3F1YXJlZCk7CiAgICBjb25zdCBkaXJlY3Rpb24yID0gQ2FydGVzaWFuM19kZWZhdWx0LmRpdmlkZUJ5U2NhbGFyKAogICAgICBzY2FsZWRTcGFjZVBvc2l0aW9uLAogICAgICBtYWduaXR1ZGUsCiAgICAgIGRpcmVjdGlvblNjcmF0Y2gKICAgICk7CiAgICBtYWduaXR1ZGVTcXVhcmVkID0gTWF0aC5tYXgoMSwgbWFnbml0dWRlU3F1YXJlZCk7CiAgICBtYWduaXR1ZGUgPSBNYXRoLm1heCgxLCBtYWduaXR1ZGUpOwogICAgY29uc3QgY29zQWxwaGEgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGRpcmVjdGlvbjIsIHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludCk7CiAgICBjb25zdCBzaW5BbHBoYSA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhkaXJlY3Rpb24yLCBzY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQsIGRpcmVjdGlvbjIpCiAgICApOwogICAgY29uc3QgY29zQmV0YSA9IDEgLyBtYWduaXR1ZGU7CiAgICBjb25zdCBzaW5CZXRhID0gTWF0aC5zcXJ0KG1hZ25pdHVkZVNxdWFyZWQgLSAxKSAqIGNvc0JldGE7CiAgICByZXR1cm4gMSAvIChjb3NBbHBoYSAqIGNvc0JldGEgLSBzaW5BbHBoYSAqIHNpbkJldGEpOwogIH0KICBmdW5jdGlvbiBtYWduaXR1ZGVUb1BvaW50KHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludCwgcmVzdWx0TWFnbml0dWRlLCByZXN1bHQpIHsKICAgIGlmIChyZXN1bHRNYWduaXR1ZGUgPD0gMCB8fCByZXN1bHRNYWduaXR1ZGUgPT09IDEgLyAwIHx8IHJlc3VsdE1hZ25pdHVkZSAhPT0gcmVzdWx0TWFnbml0dWRlKSB7CiAgICAgIHJldHVybiB2b2lkIDA7CiAgICB9CiAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0Lm11bHRpcGx5QnlTY2FsYXIoCiAgICAgIHNjYWxlZFNwYWNlRGlyZWN0aW9uVG9Qb2ludCwKICAgICAgcmVzdWx0TWFnbml0dWRlLAogICAgICByZXN1bHQKICAgICk7CiAgfQogIGZ1bmN0aW9uIGNvbXB1dGVTY2FsZWRTcGFjZURpcmVjdGlvblRvUG9pbnQoZWxsaXBzb2lkLCBkaXJlY3Rpb25Ub1BvaW50KSB7CiAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFscyhkaXJlY3Rpb25Ub1BvaW50LCBDYXJ0ZXNpYW4zX2RlZmF1bHQuWkVSTykpIHsKICAgICAgcmV0dXJuIGRpcmVjdGlvblRvUG9pbnQ7CiAgICB9CiAgICBlbGxpcHNvaWQudHJhbnNmb3JtUG9zaXRpb25Ub1NjYWxlZFNwYWNlKAogICAgICBkaXJlY3Rpb25Ub1BvaW50LAogICAgICBkaXJlY3Rpb25Ub1BvaW50U2NyYXRjaAogICAgKTsKICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKGRpcmVjdGlvblRvUG9pbnRTY3JhdGNoLCBkaXJlY3Rpb25Ub1BvaW50U2NyYXRjaCk7CiAgfQogIHZhciBzY3JhdGNoQ2FydGVzaWFuMTksIHNjcmF0Y2hDYW1lcmFQb3NpdGlvbkluU2NhbGVkU3BhY2VTaHJ1bmssIHNjcmF0Y2hFbGxpcHNvaWRTaHJ1bmssIHN1YnNhbXBsZVNjcmF0Y2gsIHNjcmF0Y2hFbGxpcHNvaWRTaHJ1bmtSYWRpaSwgcG9zaXRpb25TY3JhdGNoNSwgc2NhbGVkU3BhY2VTY3JhdGNoLCBkaXJlY3Rpb25TY3JhdGNoLCBkaXJlY3Rpb25Ub1BvaW50U2NyYXRjaCwgRWxsaXBzb2lkYWxPY2NsdWRlcl9kZWZhdWx0OwogIHZhciBpbml0X0VsbGlwc29pZGFsT2NjbHVkZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0VsbGlwc29pZGFsT2NjbHVkZXIuanMiKCkgewogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhFbGxpcHNvaWRhbE9jY2x1ZGVyLnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgdGhlIG9jY2x1ZGluZyBlbGxpcHNvaWQuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZGFsT2NjbHVkZXIucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0VsbGlwc29pZH0KICAgICAgICAgKi8KICAgICAgICBlbGxpcHNvaWQ6IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbGxpcHNvaWQ7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIG9yIHNldHMgdGhlIHBvc2l0aW9uIG9mIHRoZSBjYW1lcmEuCiAgICAgICAgICogQG1lbWJlcm9mIEVsbGlwc29pZGFsT2NjbHVkZXIucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0NhcnRlc2lhbjN9CiAgICAgICAgICovCiAgICAgICAgY2FtZXJhUG9zaXRpb246IHsKICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB0aGlzLl9jYW1lcmFQb3NpdGlvbjsKICAgICAgICAgIH0sCiAgICAgICAgICBzZXQ6IGZ1bmN0aW9uKGNhbWVyYVBvc2l0aW9uKSB7CiAgICAgICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHRoaXMuX2VsbGlwc29pZDsKICAgICAgICAgICAgY29uc3QgY3YgPSBlbGxpcHNvaWQudHJhbnNmb3JtUG9zaXRpb25Ub1NjYWxlZFNwYWNlKAogICAgICAgICAgICAgIGNhbWVyYVBvc2l0aW9uLAogICAgICAgICAgICAgIHRoaXMuX2NhbWVyYVBvc2l0aW9uSW5TY2FsZWRTcGFjZQogICAgICAgICAgICApOwogICAgICAgICAgICBjb25zdCB2aE1hZ25pdHVkZVNxdWFyZWQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlU3F1YXJlZChjdikgLSAxOwogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoY2FtZXJhUG9zaXRpb24sIHRoaXMuX2NhbWVyYVBvc2l0aW9uKTsKICAgICAgICAgICAgdGhpcy5fY2FtZXJhUG9zaXRpb25JblNjYWxlZFNwYWNlID0gY3Y7CiAgICAgICAgICAgIHRoaXMuX2Rpc3RhbmNlVG9MaW1iSW5TY2FsZWRTcGFjZVNxdWFyZWQgPSB2aE1hZ25pdHVkZVNxdWFyZWQ7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9KTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjE5ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBFbGxpcHNvaWRhbE9jY2x1ZGVyLnByb3RvdHlwZS5pc1BvaW50VmlzaWJsZSA9IGZ1bmN0aW9uKG9jY2x1ZGVlKSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gdGhpcy5fZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IG9jY2x1ZGVlU2NhbGVkU3BhY2VQb3NpdGlvbiA9IGVsbGlwc29pZC50cmFuc2Zvcm1Qb3NpdGlvblRvU2NhbGVkU3BhY2UoCiAgICAgICAgICBvY2NsdWRlZSwKICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4xOQogICAgICAgICk7CiAgICAgICAgcmV0dXJuIGlzU2NhbGVkU3BhY2VQb2ludFZpc2libGUoCiAgICAgICAgICBvY2NsdWRlZVNjYWxlZFNwYWNlUG9zaXRpb24sCiAgICAgICAgICB0aGlzLl9jYW1lcmFQb3NpdGlvbkluU2NhbGVkU3BhY2UsCiAgICAgICAgICB0aGlzLl9kaXN0YW5jZVRvTGltYkluU2NhbGVkU3BhY2VTcXVhcmVkCiAgICAgICAgKTsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkYWxPY2NsdWRlci5wcm90b3R5cGUuaXNTY2FsZWRTcGFjZVBvaW50VmlzaWJsZSA9IGZ1bmN0aW9uKG9jY2x1ZGVlU2NhbGVkU3BhY2VQb3NpdGlvbikgewogICAgICAgIHJldHVybiBpc1NjYWxlZFNwYWNlUG9pbnRWaXNpYmxlKAogICAgICAgICAgb2NjbHVkZWVTY2FsZWRTcGFjZVBvc2l0aW9uLAogICAgICAgICAgdGhpcy5fY2FtZXJhUG9zaXRpb25JblNjYWxlZFNwYWNlLAogICAgICAgICAgdGhpcy5fZGlzdGFuY2VUb0xpbWJJblNjYWxlZFNwYWNlU3F1YXJlZAogICAgICAgICk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hDYW1lcmFQb3NpdGlvbkluU2NhbGVkU3BhY2VTaHJ1bmsgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEVsbGlwc29pZGFsT2NjbHVkZXIucHJvdG90eXBlLmlzU2NhbGVkU3BhY2VQb2ludFZpc2libGVQb3NzaWJseVVuZGVyRWxsaXBzb2lkID0gZnVuY3Rpb24ob2NjbHVkZWVTY2FsZWRTcGFjZVBvc2l0aW9uLCBtaW5pbXVtSGVpZ2h0KSB7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gdGhpcy5fZWxsaXBzb2lkOwogICAgICAgIGxldCB2aE1hZ25pdHVkZVNxdWFyZWQ7CiAgICAgICAgbGV0IGN2OwogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWluaW11bUhlaWdodCkgJiYgbWluaW11bUhlaWdodCA8IDAgJiYgZWxsaXBzb2lkLm1pbmltdW1SYWRpdXMgPiAtbWluaW11bUhlaWdodCkgewogICAgICAgICAgY3YgPSBzY3JhdGNoQ2FtZXJhUG9zaXRpb25JblNjYWxlZFNwYWNlU2hydW5rOwogICAgICAgICAgY3YueCA9IHRoaXMuX2NhbWVyYVBvc2l0aW9uLnggLyAoZWxsaXBzb2lkLnJhZGlpLnggKyBtaW5pbXVtSGVpZ2h0KTsKICAgICAgICAgIGN2LnkgPSB0aGlzLl9jYW1lcmFQb3NpdGlvbi55IC8gKGVsbGlwc29pZC5yYWRpaS55ICsgbWluaW11bUhlaWdodCk7CiAgICAgICAgICBjdi56ID0gdGhpcy5fY2FtZXJhUG9zaXRpb24ueiAvIChlbGxpcHNvaWQucmFkaWkueiArIG1pbmltdW1IZWlnaHQpOwogICAgICAgICAgdmhNYWduaXR1ZGVTcXVhcmVkID0gY3YueCAqIGN2LnggKyBjdi55ICogY3YueSArIGN2LnogKiBjdi56IC0gMTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgY3YgPSB0aGlzLl9jYW1lcmFQb3NpdGlvbkluU2NhbGVkU3BhY2U7CiAgICAgICAgICB2aE1hZ25pdHVkZVNxdWFyZWQgPSB0aGlzLl9kaXN0YW5jZVRvTGltYkluU2NhbGVkU3BhY2VTcXVhcmVkOwogICAgICAgIH0KICAgICAgICByZXR1cm4gaXNTY2FsZWRTcGFjZVBvaW50VmlzaWJsZSgKICAgICAgICAgIG9jY2x1ZGVlU2NhbGVkU3BhY2VQb3NpdGlvbiwKICAgICAgICAgIGN2LAogICAgICAgICAgdmhNYWduaXR1ZGVTcXVhcmVkCiAgICAgICAgKTsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkYWxPY2NsdWRlci5wcm90b3R5cGUuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnQgPSBmdW5jdGlvbihkaXJlY3Rpb25Ub1BvaW50LCBwb3NpdGlvbnMsIHJlc3VsdCkgewogICAgICAgIHJldHVybiBjb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21Qb3NpdGlvbnMoCiAgICAgICAgICB0aGlzLl9lbGxpcHNvaWQsCiAgICAgICAgICBkaXJlY3Rpb25Ub1BvaW50LAogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgcmVzdWx0CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgc2NyYXRjaEVsbGlwc29pZFNocnVuayA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgRWxsaXBzb2lkYWxPY2NsdWRlci5wcm90b3R5cGUuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnRQb3NzaWJseVVuZGVyRWxsaXBzb2lkID0gZnVuY3Rpb24oZGlyZWN0aW9uVG9Qb2ludCwgcG9zaXRpb25zLCBtaW5pbXVtSGVpZ2h0LCByZXN1bHQpIHsKICAgICAgICBjb25zdCBwb3NzaWJseVNocnVua0VsbGlwc29pZCA9IGdldFBvc3NpYmx5U2hydW5rRWxsaXBzb2lkKAogICAgICAgICAgdGhpcy5fZWxsaXBzb2lkLAogICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgIHNjcmF0Y2hFbGxpcHNvaWRTaHJ1bmsKICAgICAgICApOwogICAgICAgIHJldHVybiBjb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21Qb3NpdGlvbnMoCiAgICAgICAgICBwb3NzaWJseVNocnVua0VsbGlwc29pZCwKICAgICAgICAgIGRpcmVjdGlvblRvUG9pbnQsCiAgICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgICByZXN1bHQKICAgICAgICApOwogICAgICB9OwogICAgICBFbGxpcHNvaWRhbE9jY2x1ZGVyLnByb3RvdHlwZS5jb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21WZXJ0aWNlcyA9IGZ1bmN0aW9uKGRpcmVjdGlvblRvUG9pbnQsIHZlcnRpY2VzLCBzdHJpZGUsIGNlbnRlciwgcmVzdWx0KSB7CiAgICAgICAgcmV0dXJuIGNvbXB1dGVIb3Jpem9uQ3VsbGluZ1BvaW50RnJvbVZlcnRpY2VzKAogICAgICAgICAgdGhpcy5fZWxsaXBzb2lkLAogICAgICAgICAgZGlyZWN0aW9uVG9Qb2ludCwKICAgICAgICAgIHZlcnRpY2VzLAogICAgICAgICAgc3RyaWRlLAogICAgICAgICAgY2VudGVyLAogICAgICAgICAgcmVzdWx0CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgRWxsaXBzb2lkYWxPY2NsdWRlci5wcm90b3R5cGUuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnRGcm9tVmVydGljZXNQb3NzaWJseVVuZGVyRWxsaXBzb2lkID0gZnVuY3Rpb24oZGlyZWN0aW9uVG9Qb2ludCwgdmVydGljZXMsIHN0cmlkZSwgY2VudGVyLCBtaW5pbXVtSGVpZ2h0LCByZXN1bHQpIHsKICAgICAgICBjb25zdCBwb3NzaWJseVNocnVua0VsbGlwc29pZCA9IGdldFBvc3NpYmx5U2hydW5rRWxsaXBzb2lkKAogICAgICAgICAgdGhpcy5fZWxsaXBzb2lkLAogICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgIHNjcmF0Y2hFbGxpcHNvaWRTaHJ1bmsKICAgICAgICApOwogICAgICAgIHJldHVybiBjb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21WZXJ0aWNlcygKICAgICAgICAgIHBvc3NpYmx5U2hydW5rRWxsaXBzb2lkLAogICAgICAgICAgZGlyZWN0aW9uVG9Qb2ludCwKICAgICAgICAgIHZlcnRpY2VzLAogICAgICAgICAgc3RyaWRlLAogICAgICAgICAgY2VudGVyLAogICAgICAgICAgcmVzdWx0CiAgICAgICAgKTsKICAgICAgfTsKICAgICAgc3Vic2FtcGxlU2NyYXRjaCA9IFtdOwogICAgICBFbGxpcHNvaWRhbE9jY2x1ZGVyLnByb3RvdHlwZS5jb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludEZyb21SZWN0YW5nbGUgPSBmdW5jdGlvbihyZWN0YW5nbGUsIGVsbGlwc29pZCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZWN0YW5nbGUiLCByZWN0YW5nbGUpOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IFJlY3RhbmdsZV9kZWZhdWx0LnN1YnNhbXBsZSgKICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIDAsCiAgICAgICAgICBzdWJzYW1wbGVTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBjb25zdCBicyA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVBvaW50cyhwb3NpdGlvbnMpOwogICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQubWFnbml0dWRlKGJzLmNlbnRlcikgPCAwLjEgKiBlbGxpcHNvaWQubWluaW11bVJhZGl1cykgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnQoYnMuY2VudGVyLCBwb3NpdGlvbnMsIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWRTaHJ1bmtSYWRpaSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgcG9zaXRpb25TY3JhdGNoNSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NhbGVkU3BhY2VTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBkaXJlY3Rpb25TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBkaXJlY3Rpb25Ub1BvaW50U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgRWxsaXBzb2lkYWxPY2NsdWRlcl9kZWZhdWx0ID0gRWxsaXBzb2lkYWxPY2NsdWRlcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1ZlcnRpY2FsRXhhZ2dlcmF0aW9uLmpzCiAgdmFyIFZlcnRpY2FsRXhhZ2dlcmF0aW9uLCBzY3JhdGNoQ2FydG9ncmFwaGljNiwgVmVydGljYWxFeGFnZ2VyYXRpb25fZGVmYXVsdDsKICB2YXIgaW5pdF9WZXJ0aWNhbEV4YWdnZXJhdGlvbiA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVmVydGljYWxFeGFnZ2VyYXRpb24uanMiKCkgewogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgVmVydGljYWxFeGFnZ2VyYXRpb24gPSB7fTsKICAgICAgVmVydGljYWxFeGFnZ2VyYXRpb24uZ2V0SGVpZ2h0ID0gZnVuY3Rpb24oaGVpZ2h0LCBzY2FsZSwgcmVsYXRpdmVIZWlnaHQpIHsKICAgICAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShzY2FsZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJzY2FsZSBtdXN0IGJlIGEgZmluaXRlIG51bWJlci4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUocmVsYXRpdmVIZWlnaHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgicmVsYXRpdmVIZWlnaHQgbXVzdCBiZSBhIGZpbml0ZSBudW1iZXIuIik7CiAgICAgICAgfQogICAgICAgIHJldHVybiAoaGVpZ2h0IC0gcmVsYXRpdmVIZWlnaHQpICogc2NhbGUgKyByZWxhdGl2ZUhlaWdodDsKICAgICAgfTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzYgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgVmVydGljYWxFeGFnZ2VyYXRpb24uZ2V0UG9zaXRpb24gPSBmdW5jdGlvbihwb3NpdGlvbiwgZWxsaXBzb2lkLCB2ZXJ0aWNhbEV4YWdnZXJhdGlvbiwgdmVydGljYWxFeGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodCwgcmVzdWx0KSB7CiAgICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYygKICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzYKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNhcnRvZ3JhcGhpYzIpKSB7CiAgICAgICAgICByZXR1cm4gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKHBvc2l0aW9uLCByZXN1bHQpOwogICAgICAgIH0KICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSBWZXJ0aWNhbEV4YWdnZXJhdGlvbi5nZXRIZWlnaHQoCiAgICAgICAgICBjYXJ0b2dyYXBoaWMyLmhlaWdodCwKICAgICAgICAgIHZlcnRpY2FsRXhhZ2dlcmF0aW9uLAogICAgICAgICAgdmVydGljYWxFeGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgICAgICk7CiAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tUmFkaWFucygKICAgICAgICAgIGNhcnRvZ3JhcGhpYzIubG9uZ2l0dWRlLAogICAgICAgICAgY2FydG9ncmFwaGljMi5sYXRpdHVkZSwKICAgICAgICAgIG5ld0hlaWdodCwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHJlc3VsdAogICAgICAgICk7CiAgICAgIH07CiAgICAgIFZlcnRpY2FsRXhhZ2dlcmF0aW9uX2RlZmF1bHQgPSBWZXJ0aWNhbEV4YWdnZXJhdGlvbjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RlcnJhaW5RdWFudGl6YXRpb24uanMKICB2YXIgVGVycmFpblF1YW50aXphdGlvbiwgVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0OwogIHZhciBpbml0X1RlcnJhaW5RdWFudGl6YXRpb24gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RlcnJhaW5RdWFudGl6YXRpb24uanMiKCkgewogICAgICBUZXJyYWluUXVhbnRpemF0aW9uID0gewogICAgICAgIC8qKgogICAgICAgICAqIFRoZSB2ZXJ0aWNlcyBhcmUgbm90IGNvbXByZXNzZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIE5PTkU6IDAsCiAgICAgICAgLyoqCiAgICAgICAgICogVGhlIHZlcnRpY2VzIGFyZSBjb21wcmVzc2VkIHRvIDEyIGJpdHMuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIEJJVFMxMjogMQogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKFRlcnJhaW5RdWFudGl6YXRpb24pOwogICAgICBUZXJyYWluUXVhbnRpemF0aW9uX2RlZmF1bHQgPSBUZXJyYWluUXVhbnRpemF0aW9uOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVGVycmFpbkVuY29kaW5nLmpzCiAgZnVuY3Rpb24gVGVycmFpbkVuY29kaW5nKGNlbnRlciwgYXhpc0FsaWduZWRCb3VuZGluZ0JveCwgbWluaW11bUhlaWdodCwgbWF4aW11bUhlaWdodCwgZnJvbUVOVSwgaGFzVmVydGV4Tm9ybWFscywgaGFzV2ViTWVyY2F0b3JULCBoYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzLCBleGFnZ2VyYXRpb24sIGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0KSB7CiAgICBsZXQgcXVhbnRpemF0aW9uID0gVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0Lk5PTkU7CiAgICBsZXQgdG9FTlU7CiAgICBsZXQgbWF0cml4OwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChheGlzQWxpZ25lZEJvdW5kaW5nQm94KSAmJiBkZWZpbmVkX2RlZmF1bHQobWluaW11bUhlaWdodCkgJiYgZGVmaW5lZF9kZWZhdWx0KG1heGltdW1IZWlnaHQpICYmIGRlZmluZWRfZGVmYXVsdChmcm9tRU5VKSkgewogICAgICBjb25zdCBtaW5pbXVtID0gYXhpc0FsaWduZWRCb3VuZGluZ0JveC5taW5pbXVtOwogICAgICBjb25zdCBtYXhpbXVtID0gYXhpc0FsaWduZWRCb3VuZGluZ0JveC5tYXhpbXVtOwogICAgICBjb25zdCBkaW1lbnNpb25zID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgIG1heGltdW0sCiAgICAgICAgbWluaW11bSwKICAgICAgICBjYXJ0ZXNpYW4zRGltU2NyYXRjaAogICAgICApOwogICAgICBjb25zdCBoRGltID0gbWF4aW11bUhlaWdodCAtIG1pbmltdW1IZWlnaHQ7CiAgICAgIGNvbnN0IG1heERpbSA9IE1hdGgubWF4KENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQ29tcG9uZW50KGRpbWVuc2lvbnMpLCBoRGltKTsKICAgICAgaWYgKG1heERpbSA8IFNISUZUX0xFRlRfMTIgLSAxKSB7CiAgICAgICAgcXVhbnRpemF0aW9uID0gVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0LkJJVFMxMjsKICAgICAgfSBlbHNlIHsKICAgICAgICBxdWFudGl6YXRpb24gPSBUZXJyYWluUXVhbnRpemF0aW9uX2RlZmF1bHQuTk9ORTsKICAgICAgfQogICAgICBsZXQgc3QyID0gTWF0cml4NF9kZWZhdWx0LmZyb21TY2FsZShkaW1lbnNpb25zLCBtYXRyaXg0U2NyYXRjaCk7CiAgICAgIHN0MiA9IE1hdHJpeDRfZGVmYXVsdC5zZXRUcmFuc2xhdGlvbihzdDIsIG1pbmltdW0sIHN0Mik7CiAgICAgIGxldCBpbnZTdCA9IE1hdHJpeDRfZGVmYXVsdC5mcm9tU2NhbGUoCiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygKICAgICAgICAgIDEgLyBkaW1lbnNpb25zLngsCiAgICAgICAgICAxIC8gZGltZW5zaW9ucy55LAogICAgICAgICAgMSAvIGRpbWVuc2lvbnMueiwKICAgICAgICAgIGNhcnRlc2lhbjNTY3JhdGNoCiAgICAgICAgKSwKICAgICAgICBtYXRyaXg0U2NyYXRjaDIKICAgICAgKTsKICAgICAgaW52U3QgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVRyYW5zbGF0aW9uKAogICAgICAgIGludlN0LAogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5uZWdhdGUobWluaW11bSwgY2FydGVzaWFuM1NjcmF0Y2gpLAogICAgICAgIGludlN0CiAgICAgICk7CiAgICAgIG1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC5jbG9uZShmcm9tRU5VLCBuZXcgTWF0cml4NF9kZWZhdWx0KCkpOwogICAgICBsZXQgcnRjT2Zmc2V0ID0gTWF0cml4NF9kZWZhdWx0LmdldFRyYW5zbGF0aW9uKGZyb21FTlUsIGNhcnRlc2lhbjNTY3JhdGNoKTsKICAgICAgcnRjT2Zmc2V0ID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KHJ0Y09mZnNldCwgY2VudGVyLCBjYXJ0ZXNpYW4zU2NyYXRjaCk7CiAgICAgIG1hdHJpeCA9IE1hdHJpeDRfZGVmYXVsdC5zZXRUcmFuc2xhdGlvbihtYXRyaXgsIHJ0Y09mZnNldCwgbWF0cml4KTsKICAgICAgbWF0cml4ID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5KG1hdHJpeCwgc3QyLCBtYXRyaXgpOwogICAgICB0b0VOVSA9IE1hdHJpeDRfZGVmYXVsdC5pbnZlcnNlVHJhbnNmb3JtYXRpb24oZnJvbUVOVSwgbmV3IE1hdHJpeDRfZGVmYXVsdCgpKTsKICAgICAgdG9FTlUgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkoaW52U3QsIHRvRU5VLCB0b0VOVSk7CiAgICAgIGZyb21FTlUgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkoZnJvbUVOVSwgc3QyLCBuZXcgTWF0cml4NF9kZWZhdWx0KCkpOwogICAgfQogICAgdGhpcy5xdWFudGl6YXRpb24gPSBxdWFudGl6YXRpb247CiAgICB0aGlzLm1pbmltdW1IZWlnaHQgPSBtaW5pbXVtSGVpZ2h0OwogICAgdGhpcy5tYXhpbXVtSGVpZ2h0ID0gbWF4aW11bUhlaWdodDsKICAgIHRoaXMuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGNlbnRlcik7CiAgICB0aGlzLnRvU2NhbGVkRU5VID0gdG9FTlU7CiAgICB0aGlzLmZyb21TY2FsZWRFTlUgPSBmcm9tRU5VOwogICAgdGhpcy5tYXRyaXggPSBtYXRyaXg7CiAgICB0aGlzLmhhc1ZlcnRleE5vcm1hbHMgPSBoYXNWZXJ0ZXhOb3JtYWxzID8/IGZhbHNlOwogICAgdGhpcy5oYXNXZWJNZXJjYXRvclQgPSBoYXNXZWJNZXJjYXRvclQgPz8gZmFsc2U7CiAgICB0aGlzLmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBoYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID8/IGZhbHNlOwogICAgdGhpcy5leGFnZ2VyYXRpb24gPSBleGFnZ2VyYXRpb24gPz8gMTsKICAgIHRoaXMuZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQgPSBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodCA/PyAwOwogICAgdGhpcy5zdHJpZGUgPSAwOwogICAgdGhpcy5fb2Zmc2V0R2VvZGV0aWNTdXJmYWNlTm9ybWFsID0gMDsKICAgIHRoaXMuX29mZnNldFZlcnRleE5vcm1hbCA9IDA7CiAgICB0aGlzLl9jYWxjdWxhdGVTdHJpZGVBbmRPZmZzZXRzKCk7CiAgfQogIHZhciBjYXJ0ZXNpYW4zU2NyYXRjaCwgY2FydGVzaWFuM0RpbVNjcmF0Y2gsIGNhcnRlc2lhbjJTY3JhdGNoLCBtYXRyaXg0U2NyYXRjaCwgbWF0cml4NFNjcmF0Y2gyLCBTSElGVF9MRUZUXzEyLCBzY3JhdGNoUG9zaXRpb242LCBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsLCBhdHRyaWJ1dGVzSW5kaWNlc05vbmUsIGF0dHJpYnV0ZXNJbmRpY2VzQml0czEyLCBUZXJyYWluRW5jb2RpbmdfZGVmYXVsdDsKICB2YXIgaW5pdF9UZXJyYWluRW5jb2RpbmcgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RlcnJhaW5FbmNvZGluZy5qcyIoKSB7CiAgICAgIGluaXRfQXR0cmlidXRlQ29tcHJlc3Npb24oKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9WZXJ0aWNhbEV4YWdnZXJhdGlvbigpOwogICAgICBpbml0X1RlcnJhaW5RdWFudGl6YXRpb24oKTsKICAgICAgY2FydGVzaWFuM1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhcnRlc2lhbjNEaW1TY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4yU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgbWF0cml4NFNjcmF0Y2ggPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIG1hdHJpeDRTY3JhdGNoMiA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgU0hJRlRfTEVGVF8xMiA9IE1hdGgucG93KDIsIDEyKTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5lbmNvZGUgPSBmdW5jdGlvbih2ZXJ0ZXhCdWZmZXIsIGJ1ZmZlckluZGV4LCBwb3NpdGlvbiwgdXYsIGhlaWdodCwgbm9ybWFsVG9QYWNrLCB3ZWJNZXJjYXRvclQsIGdlb2RldGljU3VyZmFjZU5vcm1hbCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgidmVydGV4QnVmZmVyIiwgdmVydGV4QnVmZmVyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImJ1ZmZlckluZGV4IiwgYnVmZmVySW5kZXgpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgicG9zaXRpb24iLCBwb3NpdGlvbik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJ1diIsIHV2KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImhlaWdodCIsIGhlaWdodCk7CiAgICAgICAgY29uc3QgdTQgPSB1di54OwogICAgICAgIGNvbnN0IHY0ID0gdXYueTsKICAgICAgICBpZiAodGhpcy5xdWFudGl6YXRpb24gPT09IFRlcnJhaW5RdWFudGl6YXRpb25fZGVmYXVsdC5CSVRTMTIpIHsKICAgICAgICAgIHBvc2l0aW9uID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCgKICAgICAgICAgICAgdGhpcy50b1NjYWxlZEVOVSwKICAgICAgICAgICAgcG9zaXRpb24sCiAgICAgICAgICAgIGNhcnRlc2lhbjNTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgcG9zaXRpb24ueCA9IE1hdGhfZGVmYXVsdC5jbGFtcChwb3NpdGlvbi54LCAwLCAxKTsKICAgICAgICAgIHBvc2l0aW9uLnkgPSBNYXRoX2RlZmF1bHQuY2xhbXAocG9zaXRpb24ueSwgMCwgMSk7CiAgICAgICAgICBwb3NpdGlvbi56ID0gTWF0aF9kZWZhdWx0LmNsYW1wKHBvc2l0aW9uLnosIDAsIDEpOwogICAgICAgICAgY29uc3QgaERpbSA9IHRoaXMubWF4aW11bUhlaWdodCAtIHRoaXMubWluaW11bUhlaWdodDsKICAgICAgICAgIGNvbnN0IGgyID0gTWF0aF9kZWZhdWx0LmNsYW1wKChoZWlnaHQgLSB0aGlzLm1pbmltdW1IZWlnaHQpIC8gaERpbSwgMCwgMSk7CiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUVsZW1lbnRzKHBvc2l0aW9uLngsIHBvc2l0aW9uLnksIGNhcnRlc2lhbjJTY3JhdGNoKTsKICAgICAgICAgIGNvbnN0IGNvbXByZXNzZWQwID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5jb21wcmVzc1RleHR1cmVDb29yZGluYXRlcyhjYXJ0ZXNpYW4yU2NyYXRjaCk7CiAgICAgICAgICBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUVsZW1lbnRzKHBvc2l0aW9uLnosIGgyLCBjYXJ0ZXNpYW4yU2NyYXRjaCk7CiAgICAgICAgICBjb25zdCBjb21wcmVzc2VkMSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuY29tcHJlc3NUZXh0dXJlQ29vcmRpbmF0ZXMoY2FydGVzaWFuMlNjcmF0Y2gpOwogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21FbGVtZW50cyh1NCwgdjQsIGNhcnRlc2lhbjJTY3JhdGNoKTsKICAgICAgICAgIGNvbnN0IGNvbXByZXNzZWQyID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5jb21wcmVzc1RleHR1cmVDb29yZGluYXRlcyhjYXJ0ZXNpYW4yU2NyYXRjaCk7CiAgICAgICAgICB2ZXJ0ZXhCdWZmZXJbYnVmZmVySW5kZXgrK10gPSBjb21wcmVzc2VkMDsKICAgICAgICAgIHZlcnRleEJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IGNvbXByZXNzZWQxOwogICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gY29tcHJlc3NlZDI7CiAgICAgICAgICBpZiAodGhpcy5oYXNXZWJNZXJjYXRvclQpIHsKICAgICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21FbGVtZW50cyh3ZWJNZXJjYXRvclQsIDAsIGNhcnRlc2lhbjJTY3JhdGNoKTsKICAgICAgICAgICAgY29uc3QgY29tcHJlc3NlZDMgPSBBdHRyaWJ1dGVDb21wcmVzc2lvbl9kZWZhdWx0LmNvbXByZXNzVGV4dHVyZUNvb3JkaW5hdGVzKGNhcnRlc2lhbjJTY3JhdGNoKTsKICAgICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gY29tcHJlc3NlZDM7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZlcnRleEJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IHBvc2l0aW9uLnggLSB0aGlzLmNlbnRlci54OwogICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gcG9zaXRpb24ueSAtIHRoaXMuY2VudGVyLnk7CiAgICAgICAgICB2ZXJ0ZXhCdWZmZXJbYnVmZmVySW5kZXgrK10gPSBwb3NpdGlvbi56IC0gdGhpcy5jZW50ZXIuejsKICAgICAgICAgIHZlcnRleEJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IGhlaWdodDsKICAgICAgICAgIHZlcnRleEJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IHU0OwogICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gdjQ7CiAgICAgICAgICBpZiAodGhpcy5oYXNXZWJNZXJjYXRvclQpIHsKICAgICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gd2ViTWVyY2F0b3JUOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5oYXNWZXJ0ZXhOb3JtYWxzKSB7CiAgICAgICAgICB2ZXJ0ZXhCdWZmZXJbYnVmZmVySW5kZXgrK10gPSBBdHRyaWJ1dGVDb21wcmVzc2lvbl9kZWZhdWx0Lm9jdFBhY2tGbG9hdChub3JtYWxUb1BhY2spOwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5oYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzKSB7CiAgICAgICAgICB2ZXJ0ZXhCdWZmZXJbYnVmZmVySW5kZXgrK10gPSBnZW9kZXRpY1N1cmZhY2VOb3JtYWwueDsKICAgICAgICAgIHZlcnRleEJ1ZmZlcltidWZmZXJJbmRleCsrXSA9IGdlb2RldGljU3VyZmFjZU5vcm1hbC55OwogICAgICAgICAgdmVydGV4QnVmZmVyW2J1ZmZlckluZGV4KytdID0gZ2VvZGV0aWNTdXJmYWNlTm9ybWFsLno7CiAgICAgICAgfQogICAgICAgIHJldHVybiBidWZmZXJJbmRleDsKICAgICAgfTsKICAgICAgc2NyYXRjaFBvc2l0aW9uNiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEdlb2RldGljU3VyZmFjZU5vcm1hbCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5hZGRHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID0gZnVuY3Rpb24ob2xkQnVmZmVyLCBuZXdCdWZmZXIsIGVsbGlwc29pZCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib2xkQnVmZmVyIiwgb2xkQnVmZmVyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm5ld0J1ZmZlciIsIG5ld0J1ZmZlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJlbGxpcHNvaWQiLCBlbGxpcHNvaWQpOwogICAgICAgIGlmICh0aGlzLmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb2xkU3RyaWRlID0gdGhpcy5zdHJpZGU7CiAgICAgICAgY29uc3QgdmVydGV4Q291bnQgPSBvbGRCdWZmZXIubGVuZ3RoIC8gb2xkU3RyaWRlOwogICAgICAgIHRoaXMuaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscyA9IHRydWU7CiAgICAgICAgdGhpcy5fY2FsY3VsYXRlU3RyaWRlQW5kT2Zmc2V0cygpOwogICAgICAgIGNvbnN0IG5ld1N0cmlkZSA9IHRoaXMuc3RyaWRlOwogICAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB2ZXJ0ZXhDb3VudDsgaW5kZXgrKykgewogICAgICAgICAgZm9yIChsZXQgb2Zmc2V0ID0gMDsgb2Zmc2V0IDwgb2xkU3RyaWRlOyBvZmZzZXQrKykgewogICAgICAgICAgICBjb25zdCBvbGRJbmRleCA9IGluZGV4ICogb2xkU3RyaWRlICsgb2Zmc2V0OwogICAgICAgICAgICBjb25zdCBuZXdJbmRleCA9IGluZGV4ICogbmV3U3RyaWRlICsgb2Zmc2V0OwogICAgICAgICAgICBuZXdCdWZmZXJbbmV3SW5kZXhdID0gb2xkQnVmZmVyW29sZEluZGV4XTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gdGhpcy5kZWNvZGVQb3NpdGlvbihuZXdCdWZmZXIsIGluZGV4LCBzY3JhdGNoUG9zaXRpb242KTsKICAgICAgICAgIGNvbnN0IGdlb2RldGljU3VyZmFjZU5vcm1hbCA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoCiAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgYnVmZmVySW5kZXggPSBpbmRleCAqIG5ld1N0cmlkZSArIHRoaXMuX29mZnNldEdlb2RldGljU3VyZmFjZU5vcm1hbDsKICAgICAgICAgIG5ld0J1ZmZlcltidWZmZXJJbmRleF0gPSBnZW9kZXRpY1N1cmZhY2VOb3JtYWwueDsKICAgICAgICAgIG5ld0J1ZmZlcltidWZmZXJJbmRleCArIDFdID0gZ2VvZGV0aWNTdXJmYWNlTm9ybWFsLnk7CiAgICAgICAgICBuZXdCdWZmZXJbYnVmZmVySW5kZXggKyAyXSA9IGdlb2RldGljU3VyZmFjZU5vcm1hbC56OwogICAgICAgIH0KICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5yZW1vdmVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID0gZnVuY3Rpb24ob2xkQnVmZmVyLCBuZXdCdWZmZXIpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9sZEJ1ZmZlciIsIG9sZEJ1ZmZlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJuZXdCdWZmZXIiLCBuZXdCdWZmZXIpOwogICAgICAgIGlmICghdGhpcy5oYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzKSB7CiAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGNvbnN0IG9sZFN0cmlkZSA9IHRoaXMuc3RyaWRlOwogICAgICAgIGNvbnN0IHZlcnRleENvdW50ID0gb2xkQnVmZmVyLmxlbmd0aCAvIG9sZFN0cmlkZTsKICAgICAgICB0aGlzLmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBmYWxzZTsKICAgICAgICB0aGlzLl9jYWxjdWxhdGVTdHJpZGVBbmRPZmZzZXRzKCk7CiAgICAgICAgY29uc3QgbmV3U3RyaWRlID0gdGhpcy5zdHJpZGU7CiAgICAgICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHZlcnRleENvdW50OyBpbmRleCsrKSB7CiAgICAgICAgICBmb3IgKGxldCBvZmZzZXQgPSAwOyBvZmZzZXQgPCBuZXdTdHJpZGU7IG9mZnNldCsrKSB7CiAgICAgICAgICAgIGNvbnN0IG9sZEluZGV4ID0gaW5kZXggKiBvbGRTdHJpZGUgKyBvZmZzZXQ7CiAgICAgICAgICAgIGNvbnN0IG5ld0luZGV4ID0gaW5kZXggKiBuZXdTdHJpZGUgKyBvZmZzZXQ7CiAgICAgICAgICAgIG5ld0J1ZmZlcltuZXdJbmRleF0gPSBvbGRCdWZmZXJbb2xkSW5kZXhdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5kZWNvZGVQb3NpdGlvbiA9IGZ1bmN0aW9uKGJ1ZmZlciwgaW5kZXgsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiYnVmZmVyIiwgYnVmZmVyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImluZGV4IiwgaW5kZXgpOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgICB9CiAgICAgICAgaW5kZXggKj0gdGhpcy5zdHJpZGU7CiAgICAgICAgaWYgKHRoaXMucXVhbnRpemF0aW9uID09PSBUZXJyYWluUXVhbnRpemF0aW9uX2RlZmF1bHQuQklUUzEyKSB7CiAgICAgICAgICBjb25zdCB4eSA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuZGVjb21wcmVzc1RleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgYnVmZmVyW2luZGV4XSwKICAgICAgICAgICAgY2FydGVzaWFuMlNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICByZXN1bHQueCA9IHh5Lng7CiAgICAgICAgICByZXN1bHQueSA9IHh5Lnk7CiAgICAgICAgICBjb25zdCB6aCA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuZGVjb21wcmVzc1RleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgYnVmZmVyW2luZGV4ICsgMV0sCiAgICAgICAgICAgIGNhcnRlc2lhbjJTY3JhdGNoCiAgICAgICAgICApOwogICAgICAgICAgcmVzdWx0LnogPSB6aC54OwogICAgICAgICAgcmV0dXJuIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQodGhpcy5mcm9tU2NhbGVkRU5VLCByZXN1bHQsIHJlc3VsdCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC54ID0gYnVmZmVyW2luZGV4XTsKICAgICAgICByZXN1bHQueSA9IGJ1ZmZlcltpbmRleCArIDFdOwogICAgICAgIHJlc3VsdC56ID0gYnVmZmVyW2luZGV4ICsgMl07CiAgICAgICAgcmV0dXJuIENhcnRlc2lhbjNfZGVmYXVsdC5hZGQocmVzdWx0LCB0aGlzLmNlbnRlciwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5nZXRFeGFnZ2VyYXRlZFBvc2l0aW9uID0gZnVuY3Rpb24oYnVmZmVyLCBpbmRleCwgcmVzdWx0KSB7CiAgICAgICAgcmVzdWx0ID0gdGhpcy5kZWNvZGVQb3NpdGlvbihidWZmZXIsIGluZGV4LCByZXN1bHQpOwogICAgICAgIGNvbnN0IGV4YWdnZXJhdGlvbiA9IHRoaXMuZXhhZ2dlcmF0aW9uOwogICAgICAgIGNvbnN0IGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0ID0gdGhpcy5leGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodDsKICAgICAgICBjb25zdCBoYXNFeGFnZ2VyYXRpb24gPSBleGFnZ2VyYXRpb24gIT09IDE7CiAgICAgICAgaWYgKGhhc0V4YWdnZXJhdGlvbiAmJiB0aGlzLmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICAgIGNvbnN0IGdlb2RldGljU3VyZmFjZU5vcm1hbCA9IHRoaXMuZGVjb2RlR2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgICBidWZmZXIsCiAgICAgICAgICAgIGluZGV4LAogICAgICAgICAgICBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgcmF3SGVpZ2h0ID0gdGhpcy5kZWNvZGVIZWlnaHQoYnVmZmVyLCBpbmRleCk7CiAgICAgICAgICBjb25zdCBoZWlnaHREaWZmZXJlbmNlID0gVmVydGljYWxFeGFnZ2VyYXRpb25fZGVmYXVsdC5nZXRIZWlnaHQoCiAgICAgICAgICAgIHJhd0hlaWdodCwKICAgICAgICAgICAgZXhhZ2dlcmF0aW9uLAogICAgICAgICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgICAgICAgKSAtIHJhd0hlaWdodDsKICAgICAgICAgIHJlc3VsdC54ICs9IGdlb2RldGljU3VyZmFjZU5vcm1hbC54ICogaGVpZ2h0RGlmZmVyZW5jZTsKICAgICAgICAgIHJlc3VsdC55ICs9IGdlb2RldGljU3VyZmFjZU5vcm1hbC55ICogaGVpZ2h0RGlmZmVyZW5jZTsKICAgICAgICAgIHJlc3VsdC56ICs9IGdlb2RldGljU3VyZmFjZU5vcm1hbC56ICogaGVpZ2h0RGlmZmVyZW5jZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5kZWNvZGVUZXh0dXJlQ29vcmRpbmF0ZXMgPSBmdW5jdGlvbihidWZmZXIsIGluZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImJ1ZmZlciIsIGJ1ZmZlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJpbmRleCIsIGluZGV4KTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgICAgfQogICAgICAgIGluZGV4ICo9IHRoaXMuc3RyaWRlOwogICAgICAgIGlmICh0aGlzLnF1YW50aXphdGlvbiA9PT0gVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0LkJJVFMxMikgewogICAgICAgICAgcmV0dXJuIEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuZGVjb21wcmVzc1RleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgYnVmZmVyW2luZGV4ICsgMl0sCiAgICAgICAgICAgIHJlc3VsdAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIENhcnRlc2lhbjJfZGVmYXVsdC5mcm9tRWxlbWVudHMoYnVmZmVyW2luZGV4ICsgNF0sIGJ1ZmZlcltpbmRleCArIDVdLCByZXN1bHQpOwogICAgICB9OwogICAgICBUZXJyYWluRW5jb2RpbmcucHJvdG90eXBlLmRlY29kZUhlaWdodCA9IGZ1bmN0aW9uKGJ1ZmZlciwgaW5kZXgpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImJ1ZmZlciIsIGJ1ZmZlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJpbmRleCIsIGluZGV4KTsKICAgICAgICBpbmRleCAqPSB0aGlzLnN0cmlkZTsKICAgICAgICBpZiAodGhpcy5xdWFudGl6YXRpb24gPT09IFRlcnJhaW5RdWFudGl6YXRpb25fZGVmYXVsdC5CSVRTMTIpIHsKICAgICAgICAgIGNvbnN0IHpoID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5kZWNvbXByZXNzVGV4dHVyZUNvb3JkaW5hdGVzKAogICAgICAgICAgICBidWZmZXJbaW5kZXggKyAxXSwKICAgICAgICAgICAgY2FydGVzaWFuMlNjcmF0Y2gKICAgICAgICAgICk7CiAgICAgICAgICByZXR1cm4gemgueSAqICh0aGlzLm1heGltdW1IZWlnaHQgLSB0aGlzLm1pbmltdW1IZWlnaHQpICsgdGhpcy5taW5pbXVtSGVpZ2h0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gYnVmZmVyW2luZGV4ICsgM107CiAgICAgIH07CiAgICAgIFRlcnJhaW5FbmNvZGluZy5wcm90b3R5cGUuZGVjb2RlV2ViTWVyY2F0b3JUID0gZnVuY3Rpb24oYnVmZmVyLCBpbmRleCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiYnVmZmVyIiwgYnVmZmVyKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoImluZGV4IiwgaW5kZXgpOwogICAgICAgIGluZGV4ICo9IHRoaXMuc3RyaWRlOwogICAgICAgIGlmICh0aGlzLnF1YW50aXphdGlvbiA9PT0gVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0LkJJVFMxMikgewogICAgICAgICAgcmV0dXJuIEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQuZGVjb21wcmVzc1RleHR1cmVDb29yZGluYXRlcygKICAgICAgICAgICAgYnVmZmVyW2luZGV4ICsgM10sCiAgICAgICAgICAgIGNhcnRlc2lhbjJTY3JhdGNoCiAgICAgICAgICApLng7CiAgICAgICAgfQogICAgICAgIHJldHVybiBidWZmZXJbaW5kZXggKyA2XTsKICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5nZXRPY3RFbmNvZGVkTm9ybWFsID0gZnVuY3Rpb24oYnVmZmVyLCBpbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJidWZmZXIiLCBidWZmZXIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiaW5kZXgiLCBpbmRleCk7CiAgICAgICAgaW5kZXggPSBpbmRleCAqIHRoaXMuc3RyaWRlICsgdGhpcy5fb2Zmc2V0VmVydGV4Tm9ybWFsOwogICAgICAgIGNvbnN0IHRlbXAgPSBidWZmZXJbaW5kZXhdIC8gMjU2OwogICAgICAgIGNvbnN0IHgyID0gTWF0aC5mbG9vcih0ZW1wKTsKICAgICAgICBjb25zdCB5MiA9ICh0ZW1wIC0geDIpICogMjU2OwogICAgICAgIHJldHVybiBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUVsZW1lbnRzKHgyLCB5MiwgcmVzdWx0KTsKICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nLnByb3RvdHlwZS5kZWNvZGVOb3JtYWwgPSBmdW5jdGlvbihidWZmZXIsIGluZGV4LCByZXN1bHQpIHsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoImJ1ZmZlciIsIGJ1ZmZlcik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJpbmRleCIsIGluZGV4KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInJlc3VsdCIsIHJlc3VsdCk7CiAgICAgICAgY29uc3QgYnVmZmVySW5kZXggPSBpbmRleCAqIHRoaXMuc3RyaWRlICsgdGhpcy5fb2Zmc2V0VmVydGV4Tm9ybWFsOwogICAgICAgIHJldHVybiBBdHRyaWJ1dGVDb21wcmVzc2lvbl9kZWZhdWx0Lm9jdERlY29kZUZsb2F0KGJ1ZmZlcltidWZmZXJJbmRleF0sIHJlc3VsdCk7CiAgICAgIH07CiAgICAgIFRlcnJhaW5FbmNvZGluZy5wcm90b3R5cGUuZGVjb2RlR2VvZGV0aWNTdXJmYWNlTm9ybWFsID0gZnVuY3Rpb24oYnVmZmVyLCBpbmRleCwgcmVzdWx0KSB7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJidWZmZXIiLCBidWZmZXIpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigiaW5kZXgiLCBpbmRleCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2Yub2JqZWN0KCJyZXN1bHQiLCByZXN1bHQpOwogICAgICAgIGluZGV4ID0gaW5kZXggKiB0aGlzLnN0cmlkZSArIHRoaXMuX29mZnNldEdlb2RldGljU3VyZmFjZU5vcm1hbDsKICAgICAgICByZXN1bHQueCA9IGJ1ZmZlcltpbmRleF07CiAgICAgICAgcmVzdWx0LnkgPSBidWZmZXJbaW5kZXggKyAxXTsKICAgICAgICByZXN1bHQueiA9IGJ1ZmZlcltpbmRleCArIDJdOwogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgIH07CiAgICAgIFRlcnJhaW5FbmNvZGluZy5wcm90b3R5cGUuX2NhbGN1bGF0ZVN0cmlkZUFuZE9mZnNldHMgPSBmdW5jdGlvbigpIHsKICAgICAgICBsZXQgdmVydGV4U3RyaWRlID0gMDsKICAgICAgICBzd2l0Y2ggKHRoaXMucXVhbnRpemF0aW9uKSB7CiAgICAgICAgICBjYXNlIFRlcnJhaW5RdWFudGl6YXRpb25fZGVmYXVsdC5CSVRTMTI6CiAgICAgICAgICAgIHZlcnRleFN0cmlkZSArPSAzOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgIHZlcnRleFN0cmlkZSArPSA2OwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5oYXNXZWJNZXJjYXRvclQpIHsKICAgICAgICAgIHZlcnRleFN0cmlkZSArPSAxOwogICAgICAgIH0KICAgICAgICBpZiAodGhpcy5oYXNWZXJ0ZXhOb3JtYWxzKSB7CiAgICAgICAgICB0aGlzLl9vZmZzZXRWZXJ0ZXhOb3JtYWwgPSB2ZXJ0ZXhTdHJpZGU7CiAgICAgICAgICB2ZXJ0ZXhTdHJpZGUgKz0gMTsKICAgICAgICB9CiAgICAgICAgaWYgKHRoaXMuaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscykgewogICAgICAgICAgdGhpcy5fb2Zmc2V0R2VvZGV0aWNTdXJmYWNlTm9ybWFsID0gdmVydGV4U3RyaWRlOwogICAgICAgICAgdmVydGV4U3RyaWRlICs9IDM7CiAgICAgICAgfQogICAgICAgIHRoaXMuc3RyaWRlID0gdmVydGV4U3RyaWRlOwogICAgICB9OwogICAgICBhdHRyaWJ1dGVzSW5kaWNlc05vbmUgPSB7CiAgICAgICAgcG9zaXRpb24zREFuZEhlaWdodDogMCwKICAgICAgICB0ZXh0dXJlQ29vcmRBbmRFbmNvZGVkTm9ybWFsczogMSwKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWw6IDIKICAgICAgfTsKICAgICAgYXR0cmlidXRlc0luZGljZXNCaXRzMTIgPSB7CiAgICAgICAgY29tcHJlc3NlZDA6IDAsCiAgICAgICAgY29tcHJlc3NlZDE6IDEsCiAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsOiAyCiAgICAgIH07CiAgICAgIFRlcnJhaW5FbmNvZGluZy5wcm90b3R5cGUuZ2V0QXR0cmlidXRlcyA9IGZ1bmN0aW9uKGJ1ZmZlcikgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiYnVmZmVyIiwgYnVmZmVyKTsKICAgICAgICBjb25zdCBkYXRhdHlwZSA9IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQ7CiAgICAgICAgY29uc3Qgc2l6ZUluQnl0ZXMgPSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmdldFNpemVJbkJ5dGVzKGRhdGF0eXBlKTsKICAgICAgICBjb25zdCBzdHJpZGVJbkJ5dGVzID0gdGhpcy5zdHJpZGUgKiBzaXplSW5CeXRlczsKICAgICAgICBsZXQgb2Zmc2V0SW5CeXRlcyA9IDA7CiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IFtdOwogICAgICAgIGZ1bmN0aW9uIGFkZEF0dHJpYnV0ZShpbmRleCwgY29tcG9uZW50c1BlckF0dHJpYnV0ZSkgewogICAgICAgICAgYXR0cmlidXRlcy5wdXNoKHsKICAgICAgICAgICAgaW5kZXgsCiAgICAgICAgICAgIHZlcnRleEJ1ZmZlcjogYnVmZmVyLAogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogZGF0YXR5cGUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGUsCiAgICAgICAgICAgIG9mZnNldEluQnl0ZXMsCiAgICAgICAgICAgIHN0cmlkZUluQnl0ZXMKICAgICAgICAgIH0pOwogICAgICAgICAgb2Zmc2V0SW5CeXRlcyArPSBjb21wb25lbnRzUGVyQXR0cmlidXRlICogc2l6ZUluQnl0ZXM7CiAgICAgICAgfQogICAgICAgIGlmICh0aGlzLnF1YW50aXphdGlvbiA9PT0gVGVycmFpblF1YW50aXphdGlvbl9kZWZhdWx0Lk5PTkUpIHsKICAgICAgICAgIGFkZEF0dHJpYnV0ZShhdHRyaWJ1dGVzSW5kaWNlc05vbmUucG9zaXRpb24zREFuZEhlaWdodCwgNCk7CiAgICAgICAgICBsZXQgY29tcG9uZW50c1RleENvb3JkQW5kTm9ybWFscyA9IDI7CiAgICAgICAgICBjb21wb25lbnRzVGV4Q29vcmRBbmROb3JtYWxzICs9IHRoaXMuaGFzV2ViTWVyY2F0b3JUID8gMSA6IDA7CiAgICAgICAgICBjb21wb25lbnRzVGV4Q29vcmRBbmROb3JtYWxzICs9IHRoaXMuaGFzVmVydGV4Tm9ybWFscyA/IDEgOiAwOwogICAgICAgICAgYWRkQXR0cmlidXRlKAogICAgICAgICAgICBhdHRyaWJ1dGVzSW5kaWNlc05vbmUudGV4dHVyZUNvb3JkQW5kRW5jb2RlZE5vcm1hbHMsCiAgICAgICAgICAgIGNvbXBvbmVudHNUZXhDb29yZEFuZE5vcm1hbHMKICAgICAgICAgICk7CiAgICAgICAgICBpZiAodGhpcy5oYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzKSB7CiAgICAgICAgICAgIGFkZEF0dHJpYnV0ZShhdHRyaWJ1dGVzSW5kaWNlc05vbmUuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsLCAzKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgY29uc3QgdXNpbmdBdHRyaWJ1dGUwQ29tcG9uZW50NCA9IHRoaXMuaGFzV2ViTWVyY2F0b3JUIHx8IHRoaXMuaGFzVmVydGV4Tm9ybWFsczsKICAgICAgICAgIGNvbnN0IHVzaW5nQXR0cmlidXRlMUNvbXBvbmVudDEgPSB0aGlzLmhhc1dlYk1lcmNhdG9yVCAmJiB0aGlzLmhhc1ZlcnRleE5vcm1hbHM7CiAgICAgICAgICBhZGRBdHRyaWJ1dGUoCiAgICAgICAgICAgIGF0dHJpYnV0ZXNJbmRpY2VzQml0czEyLmNvbXByZXNzZWQwLAogICAgICAgICAgICB1c2luZ0F0dHJpYnV0ZTBDb21wb25lbnQ0ID8gNCA6IDMKICAgICAgICAgICk7CiAgICAgICAgICBpZiAodXNpbmdBdHRyaWJ1dGUxQ29tcG9uZW50MSkgewogICAgICAgICAgICBhZGRBdHRyaWJ1dGUoYXR0cmlidXRlc0luZGljZXNCaXRzMTIuY29tcHJlc3NlZDEsIDEpOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHRoaXMuaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscykgewogICAgICAgICAgICBhZGRBdHRyaWJ1dGUoYXR0cmlidXRlc0luZGljZXNCaXRzMTIuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsLCAzKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZXM7CiAgICAgIH07CiAgICAgIFRlcnJhaW5FbmNvZGluZy5wcm90b3R5cGUuZ2V0QXR0cmlidXRlTG9jYXRpb25zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKHRoaXMucXVhbnRpemF0aW9uID09PSBUZXJyYWluUXVhbnRpemF0aW9uX2RlZmF1bHQuTk9ORSkgewogICAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZXNJbmRpY2VzTm9uZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZXNJbmRpY2VzQml0czEyOwogICAgICB9OwogICAgICBUZXJyYWluRW5jb2RpbmcuY2xvbmUgPSBmdW5jdGlvbihlbmNvZGluZywgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoZW5jb2RpbmcpKSB7CiAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQgPSBuZXcgVGVycmFpbkVuY29kaW5nKCk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5xdWFudGl6YXRpb24gPSBlbmNvZGluZy5xdWFudGl6YXRpb247CiAgICAgICAgcmVzdWx0Lm1pbmltdW1IZWlnaHQgPSBlbmNvZGluZy5taW5pbXVtSGVpZ2h0OwogICAgICAgIHJlc3VsdC5tYXhpbXVtSGVpZ2h0ID0gZW5jb2RpbmcubWF4aW11bUhlaWdodDsKICAgICAgICByZXN1bHQuY2VudGVyID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGVuY29kaW5nLmNlbnRlcik7CiAgICAgICAgcmVzdWx0LnRvU2NhbGVkRU5VID0gTWF0cml4NF9kZWZhdWx0LmNsb25lKGVuY29kaW5nLnRvU2NhbGVkRU5VKTsKICAgICAgICByZXN1bHQuZnJvbVNjYWxlZEVOVSA9IE1hdHJpeDRfZGVmYXVsdC5jbG9uZShlbmNvZGluZy5mcm9tU2NhbGVkRU5VKTsKICAgICAgICByZXN1bHQubWF0cml4ID0gTWF0cml4NF9kZWZhdWx0LmNsb25lKGVuY29kaW5nLm1hdHJpeCk7CiAgICAgICAgcmVzdWx0Lmhhc1ZlcnRleE5vcm1hbHMgPSBlbmNvZGluZy5oYXNWZXJ0ZXhOb3JtYWxzOwogICAgICAgIHJlc3VsdC5oYXNXZWJNZXJjYXRvclQgPSBlbmNvZGluZy5oYXNXZWJNZXJjYXRvclQ7CiAgICAgICAgcmVzdWx0Lmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBlbmNvZGluZy5oYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzOwogICAgICAgIHJlc3VsdC5leGFnZ2VyYXRpb24gPSBlbmNvZGluZy5leGFnZ2VyYXRpb247CiAgICAgICAgcmVzdWx0LmV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0ID0gZW5jb2RpbmcuZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQ7CiAgICAgICAgcmVzdWx0Ll9jYWxjdWxhdGVTdHJpZGVBbmRPZmZzZXRzKCk7CiAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgfTsKICAgICAgVGVycmFpbkVuY29kaW5nX2RlZmF1bHQgPSBUZXJyYWluRW5jb2Rpbmc7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvU2NlbmUvU2NlbmVNb2RlLmpzCiAgdmFyIFNjZW5lTW9kZSwgU2NlbmVNb2RlX2RlZmF1bHQ7CiAgdmFyIGluaXRfU2NlbmVNb2RlID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvU2NlbmUvU2NlbmVNb2RlLmpzIigpIHsKICAgICAgU2NlbmVNb2RlID0gewogICAgICAgIC8qKgogICAgICAgICAqIE1vcnBoaW5nIGJldHdlZW4gbW9kZSwgZS5nLiwgM0QgdG8gMkQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIE1PUlBISU5HOiAwLAogICAgICAgIC8qKgogICAgICAgICAqIENvbHVtYnVzIFZpZXcgbW9kZS4gIEEgMi41RCBwZXJzcGVjdGl2ZSB2aWV3IHdoZXJlIHRoZSBtYXAgaXMgbGFpZCBvdXQKICAgICAgICAgKiBmbGF0IGFuZCBvYmplY3RzIHdpdGggbm9uLXplcm8gaGVpZ2h0IGFyZSBkcmF3biBhYm92ZSBpdC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgQ09MVU1CVVNfVklFVzogMSwKICAgICAgICAvKioKICAgICAgICAgKiAyRCBtb2RlLiAgVGhlIG1hcCBpcyB2aWV3ZWQgdG9wLWRvd24gd2l0aCBhbiBvcnRob2dyYXBoaWMgcHJvamVjdGlvbi4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgU0NFTkUyRDogMiwKICAgICAgICAvKioKICAgICAgICAgKiAzRCBtb2RlLiAgQSB0cmFkaXRpb25hbCAzRCBwZXJzcGVjdGl2ZSB2aWV3IG9mIHRoZSBnbG9iZS4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgU0NFTkUzRDogMwogICAgICB9OwogICAgICBTY2VuZU1vZGUuZ2V0TW9ycGhUaW1lID0gZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICBpZiAodmFsdWUgPT09IFNjZW5lTW9kZS5TQ0VORTNEKSB7CiAgICAgICAgICByZXR1cm4gMTsKICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBTY2VuZU1vZGUuTU9SUEhJTkcpIHsKICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgfQogICAgICAgIHJldHVybiAwOwogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKFNjZW5lTW9kZSk7CiAgICAgIFNjZW5lTW9kZV9kZWZhdWx0ID0gU2NlbmVNb2RlOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZGVzdHJveU9iamVjdC5qcwogIGZ1bmN0aW9uIHJldHVyblRydWUoKSB7CiAgICByZXR1cm4gdHJ1ZTsKICB9CiAgZnVuY3Rpb24gZGVzdHJveU9iamVjdChvYmplY3QsIG1lc3NhZ2UpIHsKICAgIG1lc3NhZ2UgPSBtZXNzYWdlID8/ICJUaGlzIG9iamVjdCB3YXMgZGVzdHJveWVkLCBpLmUuLCBkZXN0cm95KCkgd2FzIGNhbGxlZC4iOwogICAgZnVuY3Rpb24gdGhyb3dPbkRlc3Ryb3llZCgpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQobWVzc2FnZSk7CiAgICB9CiAgICBmb3IgKGNvbnN0IGtleSBpbiBvYmplY3QpIHsKICAgICAgaWYgKHR5cGVvZiBvYmplY3Rba2V5XSA9PT0gImZ1bmN0aW9uIikgewogICAgICAgIG9iamVjdFtrZXldID0gdGhyb3dPbkRlc3Ryb3llZDsKICAgICAgfQogICAgfQogICAgb2JqZWN0LmlzRGVzdHJveWVkID0gcmV0dXJuVHJ1ZTsKICAgIHJldHVybiB2b2lkIDA7CiAgfQogIHZhciBkZXN0cm95T2JqZWN0X2RlZmF1bHQ7CiAgdmFyIGluaXRfZGVzdHJveU9iamVjdCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvZGVzdHJveU9iamVjdC5qcyIoKSB7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgZGVzdHJveU9iamVjdF9kZWZhdWx0ID0gZGVzdHJveU9iamVjdDsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1Rhc2tQcm9jZXNzb3IuanMKICBmdW5jdGlvbiBjYW5UcmFuc2ZlckFycmF5QnVmZmVyKCkgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoVGFza1Byb2Nlc3Nvci5fY2FuVHJhbnNmZXJBcnJheUJ1ZmZlcikpIHsKICAgICAgY29uc3Qgd29ya2VyID0gY3JlYXRlV29ya2VyKCJ0cmFuc2ZlclR5cGVkQXJyYXlUZXN0Iik7CiAgICAgIHdvcmtlci5wb3N0TWVzc2FnZSA9IHdvcmtlci53ZWJraXRQb3N0TWVzc2FnZSA/PyB3b3JrZXIucG9zdE1lc3NhZ2U7CiAgICAgIGNvbnN0IHZhbHVlID0gOTk7CiAgICAgIGNvbnN0IGFycmF5ID0gbmV3IEludDhBcnJheShbdmFsdWVdKTsKICAgICAgdHJ5IHsKICAgICAgICB3b3JrZXIucG9zdE1lc3NhZ2UoCiAgICAgICAgICB7CiAgICAgICAgICAgIGFycmF5CiAgICAgICAgICB9LAogICAgICAgICAgW2FycmF5LmJ1ZmZlcl0KICAgICAgICApOwogICAgICB9IGNhdGNoIChlMikgewogICAgICAgIFRhc2tQcm9jZXNzb3IuX2NhblRyYW5zZmVyQXJyYXlCdWZmZXIgPSBmYWxzZTsKICAgICAgICByZXR1cm4gVGFza1Byb2Nlc3Nvci5fY2FuVHJhbnNmZXJBcnJheUJ1ZmZlcjsKICAgICAgfQogICAgICBUYXNrUHJvY2Vzc29yLl9jYW5UcmFuc2ZlckFycmF5QnVmZmVyID0gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHsKICAgICAgICB3b3JrZXIub25tZXNzYWdlID0gZnVuY3Rpb24oZXZlbnQpIHsKICAgICAgICAgIGNvbnN0IGFycmF5MiA9IGV2ZW50LmRhdGEuYXJyYXk7CiAgICAgICAgICBjb25zdCByZXN1bHQgPSBkZWZpbmVkX2RlZmF1bHQoYXJyYXkyKSAmJiBhcnJheTJbMF0gPT09IHZhbHVlOwogICAgICAgICAgcmVzb2x2ZShyZXN1bHQpOwogICAgICAgICAgd29ya2VyLnRlcm1pbmF0ZSgpOwogICAgICAgICAgVGFza1Byb2Nlc3Nvci5fY2FuVHJhbnNmZXJBcnJheUJ1ZmZlciA9IHJlc3VsdDsKICAgICAgICB9OwogICAgICB9KTsKICAgIH0KICAgIHJldHVybiBUYXNrUHJvY2Vzc29yLl9jYW5UcmFuc2ZlckFycmF5QnVmZmVyOwogIH0KICBmdW5jdGlvbiB1cmxGcm9tU2NyaXB0KHNjcmlwdCkgewogICAgbGV0IGJsb2I7CiAgICB0cnkgewogICAgICBibG9iID0gbmV3IEJsb2IoW3NjcmlwdF0sIHsKICAgICAgICB0eXBlOiAiYXBwbGljYXRpb24vamF2YXNjcmlwdCIKICAgICAgfSk7CiAgICB9IGNhdGNoIChlMikgewogICAgICBjb25zdCBCbG9iQnVpbGRlciA9IHdpbmRvdy5CbG9iQnVpbGRlciB8fCB3aW5kb3cuV2ViS2l0QmxvYkJ1aWxkZXIgfHwgd2luZG93Lk1vekJsb2JCdWlsZGVyIHx8IHdpbmRvdy5NU0Jsb2JCdWlsZGVyOwogICAgICBjb25zdCBibG9iQnVpbGRlciA9IG5ldyBCbG9iQnVpbGRlcigpOwogICAgICBibG9iQnVpbGRlci5hcHBlbmQoc2NyaXB0KTsKICAgICAgYmxvYiA9IGJsb2JCdWlsZGVyLmdldEJsb2IoImFwcGxpY2F0aW9uL2phdmFzY3JpcHQiKTsKICAgIH0KICAgIGNvbnN0IFVSTDIgPSB3aW5kb3cuVVJMIHx8IHdpbmRvdy53ZWJraXRVUkw7CiAgICByZXR1cm4gVVJMMi5jcmVhdGVPYmplY3RVUkwoYmxvYik7CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZVdvcmtlcih1cmwpIHsKICAgIGNvbnN0IHVyaSA9IG5ldyBpbXBvcnRfdXJpanM3LmRlZmF1bHQodXJsKTsKICAgIGNvbnN0IGlzVXJpID0gdXJpLnNjaGVtZSgpLmxlbmd0aCAhPT0gMCAmJiB1cmkuZnJhZ21lbnQoKS5sZW5ndGggPT09IDA7CiAgICBjb25zdCBtb2R1bGVJRCA9IHVybC5yZXBsYWNlKC9cLmpzJC8sICIiKTsKICAgIGNvbnN0IG9wdGlvbnMgPSB7fTsKICAgIGxldCB3b3JrZXJQYXRoOwogICAgbGV0IGNyb3NzT3JpZ2luVXJsOwogICAgaWYgKGlzQ3Jvc3NPcmlnaW5VcmxfZGVmYXVsdCh1cmwpKSB7CiAgICAgIGNyb3NzT3JpZ2luVXJsID0gdXJsOwogICAgfSBlbHNlIGlmICghaXNVcmkpIHsKICAgICAgY29uc3QgbW9kdWxlQWJzb2x1dGVVcmwgPSBidWlsZE1vZHVsZVVybF9kZWZhdWx0KAogICAgICAgIGAke1Rhc2tQcm9jZXNzb3IuX3dvcmtlck1vZHVsZVByZWZpeH0vJHttb2R1bGVJRH0uanNgCiAgICAgICk7CiAgICAgIGlmIChpc0Nyb3NzT3JpZ2luVXJsX2RlZmF1bHQobW9kdWxlQWJzb2x1dGVVcmwpKSB7CiAgICAgICAgY3Jvc3NPcmlnaW5VcmwgPSBtb2R1bGVBYnNvbHV0ZVVybDsKICAgICAgfQogICAgfQogICAgaWYgKGNyb3NzT3JpZ2luVXJsKSB7CiAgICAgIGNvbnN0IHNjcmlwdCA9IGBpbXBvcnQgIiR7Y3Jvc3NPcmlnaW5Vcmx9IjtgOwogICAgICB3b3JrZXJQYXRoID0gdXJsRnJvbVNjcmlwdChzY3JpcHQpOwogICAgICBvcHRpb25zLnR5cGUgPSAibW9kdWxlIjsKICAgICAgcmV0dXJuIG5ldyBXb3JrZXIod29ya2VyUGF0aCwgb3B0aW9ucyk7CiAgICB9CiAgICBpZiAoIWlzVXJpICYmIHR5cGVvZiBDRVNJVU1fV09SS0VSUyAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgY29uc3Qgc2NyaXB0ID0gYAogICAgICBpbXBvcnRTY3JpcHRzKCIke3VybEZyb21TY3JpcHQoQ0VTSVVNX1dPUktFUlMpfSIpOwogICAgICBDZXNpdW1Xb3JrZXJzWyIke21vZHVsZUlEfSJdKCk7CiAgICBgOwogICAgICB3b3JrZXJQYXRoID0gdXJsRnJvbVNjcmlwdChzY3JpcHQpOwogICAgICByZXR1cm4gbmV3IFdvcmtlcih3b3JrZXJQYXRoLCBvcHRpb25zKTsKICAgIH0KICAgIHdvcmtlclBhdGggPSB1cmw7CiAgICBpZiAoIWlzVXJpKSB7CiAgICAgIHdvcmtlclBhdGggPSBidWlsZE1vZHVsZVVybF9kZWZhdWx0KAogICAgICAgIGAke1Rhc2tQcm9jZXNzb3IuX3dvcmtlck1vZHVsZVByZWZpeCArIG1vZHVsZUlEfS5qc2AKICAgICAgKTsKICAgIH0KICAgIGlmICghRmVhdHVyZURldGVjdGlvbl9kZWZhdWx0LnN1cHBvcnRzRXNtV2ViV29ya2VycygpKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgKICAgICAgICAiVGhpcyBicm93c2VyIGlzIG5vdCBzdXBwb3J0ZWQuIFBsZWFzZSB1cGRhdGUgeW91ciBicm93c2VyIHRvIGNvbnRpbnVlLiIKICAgICAgKTsKICAgIH0KICAgIG9wdGlvbnMudHlwZSA9ICJtb2R1bGUiOwogICAgcmV0dXJuIG5ldyBXb3JrZXIod29ya2VyUGF0aCwgb3B0aW9ucyk7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIGdldFdlYkFzc2VtYmx5TG9hZGVyQ29uZmlnKHByb2Nlc3Nvciwgd2FzbU9wdGlvbnMpIHsKICAgIGNvbnN0IGNvbmZpZyA9IHsKICAgICAgbW9kdWxlUGF0aDogdm9pZCAwLAogICAgICB3YXNtQmluYXJ5RmlsZTogdm9pZCAwLAogICAgICB3YXNtQmluYXJ5OiB2b2lkIDAKICAgIH07CiAgICBpZiAoIUZlYXR1cmVEZXRlY3Rpb25fZGVmYXVsdC5zdXBwb3J0c1dlYkFzc2VtYmx5KCkpIHsKICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQod2FzbU9wdGlvbnMuZmFsbGJhY2tNb2R1bGVQYXRoKSkgewogICAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgKICAgICAgICAgIGBUaGlzIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBXZWIgQXNzZW1ibHksIGFuZCBubyBiYWNrdXAgbW9kdWxlIHdhcyBwcm92aWRlZCBmb3IgJHtwcm9jZXNzb3IuX3dvcmtlclBhdGh9YAogICAgICAgICk7CiAgICAgIH0KICAgICAgY29uZmlnLm1vZHVsZVBhdGggPSBidWlsZE1vZHVsZVVybF9kZWZhdWx0KHdhc21PcHRpb25zLmZhbGxiYWNrTW9kdWxlUGF0aCk7CiAgICAgIHJldHVybiBjb25maWc7CiAgICB9CiAgICBjb25maWcud2FzbUJpbmFyeUZpbGUgPSBidWlsZE1vZHVsZVVybF9kZWZhdWx0KHdhc21PcHRpb25zLndhc21CaW5hcnlGaWxlKTsKICAgIGNvbnN0IGFycmF5QnVmZmVyID0gYXdhaXQgUmVzb3VyY2VfZGVmYXVsdC5mZXRjaEFycmF5QnVmZmVyKHsKICAgICAgdXJsOiBjb25maWcud2FzbUJpbmFyeUZpbGUKICAgIH0pOwogICAgY29uZmlnLndhc21CaW5hcnkgPSBhcnJheUJ1ZmZlcjsKICAgIHJldHVybiBjb25maWc7CiAgfQogIGZ1bmN0aW9uIFRhc2tQcm9jZXNzb3Iod29ya2VyUGF0aCwgbWF4aW11bUFjdGl2ZVRhc2tzKSB7CiAgICB0aGlzLl93b3JrZXJQYXRoID0gd29ya2VyUGF0aDsKICAgIHRoaXMuX21heGltdW1BY3RpdmVUYXNrcyA9IG1heGltdW1BY3RpdmVUYXNrcyA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICB0aGlzLl9hY3RpdmVUYXNrcyA9IDA7CiAgICB0aGlzLl9uZXh0SUQgPSAwOwogICAgdGhpcy5fd2ViQXNzZW1ibHlQcm9taXNlID0gdm9pZCAwOwogIH0KICBhc3luYyBmdW5jdGlvbiBydW5UYXNrKHByb2Nlc3NvciwgcGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgY2FuVHJhbnNmZXIgPSBhd2FpdCBQcm9taXNlLnJlc29sdmUoY2FuVHJhbnNmZXJBcnJheUJ1ZmZlcigpKTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRyYW5zZmVyYWJsZU9iamVjdHMpKSB7CiAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMgPSBlbXB0eVRyYW5zZmVyYWJsZU9iamVjdEFycmF5OwogICAgfSBlbHNlIGlmICghY2FuVHJhbnNmZXIpIHsKICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5sZW5ndGggPSAwOwogICAgfQogICAgY29uc3QgaWQgPSBwcm9jZXNzb3IuX25leHRJRCsrOwogICAgY29uc3QgcHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHsKICAgICAgcHJvY2Vzc29yLl93b3JrZXIuYWRkRXZlbnRMaXN0ZW5lcigKICAgICAgICAibWVzc2FnZSIsCiAgICAgICAgY3JlYXRlT25tZXNzYWdlSGFuZGxlcihwcm9jZXNzb3IuX3dvcmtlciwgaWQsIHJlc29sdmUsIHJlamVjdCkKICAgICAgKTsKICAgIH0pOwogICAgcHJvY2Vzc29yLl93b3JrZXIucG9zdE1lc3NhZ2UoCiAgICAgIHsKICAgICAgICBpZCwKICAgICAgICBiYXNlVXJsOiBidWlsZE1vZHVsZVVybF9kZWZhdWx0LmdldENlc2l1bUJhc2VVcmwoKS51cmwsCiAgICAgICAgcGFyYW1ldGVycywKICAgICAgICBjYW5UcmFuc2ZlckFycmF5QnVmZmVyOiBjYW5UcmFuc2ZlcgogICAgICB9LAogICAgICB0cmFuc2ZlcmFibGVPYmplY3RzCiAgICApOwogICAgcmV0dXJuIHByb21pc2U7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIHNjaGVkdWxlVGFzayhwcm9jZXNzb3IsIHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgICsrcHJvY2Vzc29yLl9hY3RpdmVUYXNrczsKICAgIHRyeSB7CiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJ1blRhc2socHJvY2Vzc29yLCBwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgICAgLS1wcm9jZXNzb3IuX2FjdGl2ZVRhc2tzOwogICAgICByZXR1cm4gcmVzdWx0OwogICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgLS1wcm9jZXNzb3IuX2FjdGl2ZVRhc2tzOwogICAgICB0aHJvdyBlcnJvcjsKICAgIH0KICB9CiAgdmFyIGltcG9ydF91cmlqczcsIHRhc2tDb21wbGV0ZWRFdmVudCwgY3JlYXRlT25tZXNzYWdlSGFuZGxlciwgZW1wdHlUcmFuc2ZlcmFibGVPYmplY3RBcnJheSwgVGFza1Byb2Nlc3Nvcl9kZWZhdWx0OwogIHZhciBpbml0X1Rhc2tQcm9jZXNzb3IgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1Rhc2tQcm9jZXNzb3IuanMiKCkgewogICAgICBpbXBvcnRfdXJpanM3ID0gX190b0VTTShyZXF1aXJlX1VSSSgpLCAxKTsKICAgICAgaW5pdF9idWlsZE1vZHVsZVVybCgpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9kZXN0cm95T2JqZWN0KCk7CiAgICAgIGluaXRfRGV2ZWxvcGVyRXJyb3IoKTsKICAgICAgaW5pdF9FdmVudCgpOwogICAgICBpbml0X0ZlYXR1cmVEZXRlY3Rpb24oKTsKICAgICAgaW5pdF9pc0Nyb3NzT3JpZ2luVXJsKCk7CiAgICAgIGluaXRfUmVzb3VyY2UoKTsKICAgICAgaW5pdF9SdW50aW1lRXJyb3IoKTsKICAgICAgdGFza0NvbXBsZXRlZEV2ZW50ID0gbmV3IEV2ZW50X2RlZmF1bHQoKTsKICAgICAgY3JlYXRlT25tZXNzYWdlSGFuZGxlciA9ICh3b3JrZXIsIGlkLCByZXNvbHZlLCByZWplY3QpID0+IHsKICAgICAgICBjb25zdCBsaXN0ZW5lciA9ICh7IGRhdGEgfSkgPT4gewogICAgICAgICAgaWYgKGRhdGEuaWQgIT09IGlkKSB7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgIH0KICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZGF0YS5lcnJvcikpIHsKICAgICAgICAgICAgbGV0IGVycm9yID0gZGF0YS5lcnJvcjsKICAgICAgICAgICAgaWYgKGVycm9yLm5hbWUgPT09ICJSdW50aW1lRXJyb3IiKSB7CiAgICAgICAgICAgICAgZXJyb3IgPSBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoZGF0YS5lcnJvci5tZXNzYWdlKTsKICAgICAgICAgICAgICBlcnJvci5zdGFjayA9IGRhdGEuZXJyb3Iuc3RhY2s7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZXJyb3IubmFtZSA9PT0gIkRldmVsb3BlckVycm9yIikgewogICAgICAgICAgICAgIGVycm9yID0gbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoZGF0YS5lcnJvci5tZXNzYWdlKTsKICAgICAgICAgICAgICBlcnJvci5zdGFjayA9IGRhdGEuZXJyb3Iuc3RhY2s7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZXJyb3IubmFtZSA9PT0gIkVycm9yIikgewogICAgICAgICAgICAgIGVycm9yID0gbmV3IEVycm9yKGRhdGEuZXJyb3IubWVzc2FnZSk7CiAgICAgICAgICAgICAgZXJyb3Iuc3RhY2sgPSBkYXRhLmVycm9yLnN0YWNrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHRhc2tDb21wbGV0ZWRFdmVudC5yYWlzZUV2ZW50KGVycm9yKTsKICAgICAgICAgICAgcmVqZWN0KGVycm9yKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRhc2tDb21wbGV0ZWRFdmVudC5yYWlzZUV2ZW50KCk7CiAgICAgICAgICAgIHJlc29sdmUoZGF0YS5yZXN1bHQpOwogICAgICAgICAgfQogICAgICAgICAgd29ya2VyLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLCBsaXN0ZW5lcik7CiAgICAgICAgfTsKICAgICAgICByZXR1cm4gbGlzdGVuZXI7CiAgICAgIH07CiAgICAgIGVtcHR5VHJhbnNmZXJhYmxlT2JqZWN0QXJyYXkgPSBbXTsKICAgICAgVGFza1Byb2Nlc3Nvci5wcm90b3R5cGUuc2NoZWR1bGVUYXNrID0gZnVuY3Rpb24ocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRoaXMuX3dvcmtlcikpIHsKICAgICAgICAgIHRoaXMuX3dvcmtlciA9IGNyZWF0ZVdvcmtlcih0aGlzLl93b3JrZXJQYXRoKTsKICAgICAgICB9CiAgICAgICAgaWYgKHRoaXMuX2FjdGl2ZVRhc2tzID49IHRoaXMuX21heGltdW1BY3RpdmVUYXNrcykgewogICAgICAgICAgcmV0dXJuIHZvaWQgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHNjaGVkdWxlVGFzayh0aGlzLCBwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgICAgfTsKICAgICAgVGFza1Byb2Nlc3Nvci5wcm90b3R5cGUuaW5pdFdlYkFzc2VtYmx5TW9kdWxlID0gYXN5bmMgZnVuY3Rpb24od2ViQXNzZW1ibHlPcHRpb25zKSB7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh0aGlzLl93ZWJBc3NlbWJseVByb21pc2UpKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5fd2ViQXNzZW1ibHlQcm9taXNlOwogICAgICAgIH0KICAgICAgICBjb25zdCBpbml0ID0gYXN5bmMgKCkgPT4gewogICAgICAgICAgY29uc3Qgd29ya2VyID0gdGhpcy5fd29ya2VyID0gY3JlYXRlV29ya2VyKHRoaXMuX3dvcmtlclBhdGgpOwogICAgICAgICAgY29uc3Qgd2FzbUNvbmZpZyA9IGF3YWl0IGdldFdlYkFzc2VtYmx5TG9hZGVyQ29uZmlnKAogICAgICAgICAgICB0aGlzLAogICAgICAgICAgICB3ZWJBc3NlbWJseU9wdGlvbnMKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBjYW5UcmFuc2ZlciA9IGF3YWl0IFByb21pc2UucmVzb2x2ZShjYW5UcmFuc2ZlckFycmF5QnVmZmVyKCkpOwogICAgICAgICAgbGV0IHRyYW5zZmVyYWJsZU9iamVjdHM7CiAgICAgICAgICBjb25zdCBiaW5hcnkgPSB3YXNtQ29uZmlnLndhc21CaW5hcnk7CiAgICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGJpbmFyeSkgJiYgY2FuVHJhbnNmZXIpIHsKICAgICAgICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cyA9IFtiaW5hcnldOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgcHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHsKICAgICAgICAgICAgd29ya2VyLm9ubWVzc2FnZSA9IGZ1bmN0aW9uKHsgZGF0YSB9KSB7CiAgICAgICAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChkYXRhKSkgewogICAgICAgICAgICAgICAgcmVzb2x2ZShkYXRhLnJlc3VsdCk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJlamVjdChuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkNvdWxkIG5vdCBjb25maWd1cmUgd2FzbSBtb2R1bGUiKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9OwogICAgICAgICAgfSk7CiAgICAgICAgICB3b3JrZXIucG9zdE1lc3NhZ2UoCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICBjYW5UcmFuc2ZlckFycmF5QnVmZmVyOiBjYW5UcmFuc2ZlciwKICAgICAgICAgICAgICBwYXJhbWV0ZXJzOiB7IHdlYkFzc2VtYmx5Q29uZmlnOiB3YXNtQ29uZmlnIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cwogICAgICAgICAgKTsKICAgICAgICAgIHJldHVybiBwcm9taXNlOwogICAgICAgIH07CiAgICAgICAgdGhpcy5fd2ViQXNzZW1ibHlQcm9taXNlID0gaW5pdCgpOwogICAgICAgIHJldHVybiB0aGlzLl93ZWJBc3NlbWJseVByb21pc2U7CiAgICAgIH07CiAgICAgIFRhc2tQcm9jZXNzb3IucHJvdG90eXBlLmlzRGVzdHJveWVkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICB9OwogICAgICBUYXNrUHJvY2Vzc29yLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh0aGlzLl93b3JrZXIpKSB7CiAgICAgICAgICB0aGlzLl93b3JrZXIudGVybWluYXRlKCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBkZXN0cm95T2JqZWN0X2RlZmF1bHQodGhpcyk7CiAgICAgIH07CiAgICAgIFRhc2tQcm9jZXNzb3IudGFza0NvbXBsZXRlZEV2ZW50ID0gdGFza0NvbXBsZXRlZEV2ZW50OwogICAgICBUYXNrUHJvY2Vzc29yLl9kZWZhdWx0V29ya2VyTW9kdWxlUHJlZml4ID0gIldvcmtlcnMvIjsKICAgICAgVGFza1Byb2Nlc3Nvci5fd29ya2VyTW9kdWxlUHJlZml4ID0gVGFza1Byb2Nlc3Nvci5fZGVmYXVsdFdvcmtlck1vZHVsZVByZWZpeDsKICAgICAgVGFza1Byb2Nlc3Nvci5fY2FuVHJhbnNmZXJBcnJheUJ1ZmZlciA9IHZvaWQgMDsKICAgICAgVGFza1Byb2Nlc3Nvcl9kZWZhdWx0ID0gVGFza1Byb2Nlc3NvcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RlcnJhaW5QaWNrZXIuanMKICBmdW5jdGlvbiByZXNldCh0ZXJyYWluUGlja2VyLCB0aWxlVHJhbnNmb3JtKSB7CiAgICBNYXRyaXg0X2RlZmF1bHQuaW52ZXJzZSh0aWxlVHJhbnNmb3JtLCB0ZXJyYWluUGlja2VyLl9pbnZlcnNlVHJhbnNmb3JtKTsKICAgIHRlcnJhaW5QaWNrZXIuX25lZWRzUmVidWlsZCA9IGZhbHNlOwogICAgY29uc3QgdHJpYW5nbGVDb3VudCA9IHRlcnJhaW5QaWNrZXIuX2luZGljZXMubGVuZ3RoIC8gMzsKICAgIGNvbnN0IGludGVyc2VjdGluZ1RyaWFuZ2xlcyA9IG5ldyBVaW50MzJBcnJheSh0cmlhbmdsZUNvdW50KTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB0cmlhbmdsZUNvdW50OyArK2kyKSB7CiAgICAgIGludGVyc2VjdGluZ1RyaWFuZ2xlc1tpMl0gPSBpMjsKICAgIH0KICAgIHRlcnJhaW5QaWNrZXIuX3Jvb3ROb2RlLmludGVyc2VjdGluZ1RyaWFuZ2xlcyA9IGludGVyc2VjdGluZ1RyaWFuZ2xlczsKICAgIHRlcnJhaW5QaWNrZXIuX3Jvb3ROb2RlLmNoaWxkcmVuLmxlbmd0aCA9IDA7CiAgfQogIGZ1bmN0aW9uIGNyZWF0ZUFBQkJGb3JOb2RlKHgyLCB5MiwgbGV2ZWwpIHsKICAgIGNvbnN0IHNpemVBdExldmVsID0gMSAvIE1hdGgucG93KDIsIGxldmVsKTsKICAgIGNvbnN0IGFhYmJNaW4gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICB4MiAqIHNpemVBdExldmVsIC0gMC41LAogICAgICB5MiAqIHNpemVBdExldmVsIC0gMC41LAogICAgICAtMC41LAogICAgICBzY3JhdGNoQUFCQk1pbgogICAgKTsKICAgIGNvbnN0IGFhYmJNYXggPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICAoeDIgKyAxKSAqIHNpemVBdExldmVsIC0gMC41LAogICAgICAoeTIgKyAxKSAqIHNpemVBdExldmVsIC0gMC41LAogICAgICAwLjUsCiAgICAgIHNjcmF0Y2hBQUJCTWF4CiAgICApOwogICAgcmV0dXJuIEF4aXNBbGlnbmVkQm91bmRpbmdCb3hfZGVmYXVsdC5mcm9tQ29ybmVycyhhYWJiTWluLCBhYWJiTWF4KTsKICB9CiAgZnVuY3Rpb24gcGFja1RyaWFuZ2xlQnVmZmVycyh0cmlhbmdsZVBvc2l0aW9uc0J1ZmZlciwgdHJpYW5nbGVJbmRpY2VzQnVmZmVyLCB0cmlhbmdsZVBvc2l0aW9ucywgdHJpYW5nbGVJbmRleCwgYnVmZmVySW5kZXgpIHsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKAogICAgICB0cmlhbmdsZVBvc2l0aW9uc1swXSwKICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBodHRwczovL2dpdGh1Yi5jb20vQ2VzaXVtR1MvY2VzaXVtL3B1bGwvMTMzMDIKICAgICAgdHJpYW5nbGVQb3NpdGlvbnNCdWZmZXIsCiAgICAgIDkgKiBidWZmZXJJbmRleAogICAgKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKAogICAgICB0cmlhbmdsZVBvc2l0aW9uc1sxXSwKICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBodHRwczovL2dpdGh1Yi5jb20vQ2VzaXVtR1MvY2VzaXVtL3B1bGwvMTMzMDIKICAgICAgdHJpYW5nbGVQb3NpdGlvbnNCdWZmZXIsCiAgICAgIDkgKiBidWZmZXJJbmRleCArIDMKICAgICk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjaygKICAgICAgdHJpYW5nbGVQb3NpdGlvbnNbMl0sCiAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgaHR0cHM6Ly9naXRodWIuY29tL0Nlc2l1bUdTL2Nlc2l1bS9wdWxsLzEzMzAyCiAgICAgIHRyaWFuZ2xlUG9zaXRpb25zQnVmZmVyLAogICAgICA5ICogYnVmZmVySW5kZXggKyA2CiAgICApOwogICAgdHJpYW5nbGVJbmRpY2VzQnVmZmVyW2J1ZmZlckluZGV4XSA9IHRyaWFuZ2xlSW5kZXg7CiAgfQogIGZ1bmN0aW9uIGdldE5vZGVzSW50ZXJzZWN0aW5nUmF5KGN1cnJlbnROb2RlLCByYXksIGludGVyc2VjdGluZ05vZGVzKSB7CiAgICBjb25zdCBpbnRlcnZhbCA9IEludGVyc2VjdGlvblRlc3RzX2RlZmF1bHQucmF5QXhpc0FsaWduZWRCb3VuZGluZ0JveCgKICAgICAgcmF5LAogICAgICBjdXJyZW50Tm9kZS5hYWJiLAogICAgICBzY3JhdGNoSW50ZXJ2YWwKICAgICk7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbnRlcnZhbCkpIHsKICAgICAgcmV0dXJuOwogICAgfQogICAgY29uc3QgaXNMZWFmID0gIWN1cnJlbnROb2RlLmNoaWxkcmVuLmxlbmd0aCB8fCBjdXJyZW50Tm9kZS5idWlsZGluZ0NoaWxkcmVuOwogICAgaWYgKGlzTGVhZikgewogICAgICBpbnRlcnNlY3RpbmdOb2Rlcy5wdXNoKHsKICAgICAgICBub2RlOiBjdXJyZW50Tm9kZSwKICAgICAgICBpbnRlcnZhbDogbmV3IEludGVydmFsX2RlZmF1bHQoaW50ZXJ2YWwuc3RhcnQsIGludGVydmFsLnN0b3ApCiAgICAgIH0pOwogICAgICByZXR1cm47CiAgICB9CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgY3VycmVudE5vZGUuY2hpbGRyZW4ubGVuZ3RoOyBpMisrKSB7CiAgICAgIGdldE5vZGVzSW50ZXJzZWN0aW5nUmF5KGN1cnJlbnROb2RlLmNoaWxkcmVuW2kyXSwgcmF5LCBpbnRlcnNlY3RpbmdOb2Rlcyk7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGZpbmRDbG9zZXN0UG9pbnRJbkNsb3Nlc3ROb2RlKHRlcnJhaW5QaWNrZXIsIGludGVyc2VjdGlvbnMsIHJheSwgY3VsbEJhY2tGYWNlcywgbW9kZSwgcHJvamVjdGlvbikgewogICAgY29uc3Qgc29ydGVkSW50ZXJzZWN0aW9ucyA9IGludGVyc2VjdGlvbnMuc29ydChmdW5jdGlvbihhNCwgYjIpIHsKICAgICAgcmV0dXJuIGE0LmludGVydmFsLnN0YXJ0IC0gYjIuaW50ZXJ2YWwuc3RhcnQ7CiAgICB9KTsKICAgIGxldCBtaW5UID0gTnVtYmVyLk1BWF9WQUxVRTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBzb3J0ZWRJbnRlcnNlY3Rpb25zLmxlbmd0aDsgaTIrKykgewogICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSBzb3J0ZWRJbnRlcnNlY3Rpb25zW2kyXTsKICAgICAgY29uc3QgaW50ZXJzZWN0aW9uUmVzdWx0ID0gZ2V0Q2xvc2VzdFRyaWFuZ2xlSW5Ob2RlKAogICAgICAgIHRlcnJhaW5QaWNrZXIsCiAgICAgICAgcmF5LAogICAgICAgIGludGVyc2VjdGlvbi5ub2RlLAogICAgICAgIGN1bGxCYWNrRmFjZXMsCiAgICAgICAgbW9kZSwKICAgICAgICBwcm9qZWN0aW9uCiAgICAgICk7CiAgICAgIG1pblQgPSBNYXRoLm1pbihpbnRlcnNlY3Rpb25SZXN1bHQsIG1pblQpOwogICAgICBpZiAobWluVCAhPT0gTnVtYmVyLk1BWF9WQUxVRSkgewogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgICBpZiAobWluVCAhPT0gTnVtYmVyLk1BWF9WQUxVRSkgewogICAgICByZXR1cm4gUmF5X2RlZmF1bHQuZ2V0UG9pbnQocmF5LCBtaW5UKTsKICAgIH0KICAgIHJldHVybiB2b2lkIDA7CiAgfQogIGZ1bmN0aW9uIGdldENsb3Nlc3RUcmlhbmdsZUluTm9kZSh0ZXJyYWluUGlja2VyLCByYXksIG5vZGUsIGN1bGxCYWNrRmFjZXMsIG1vZGUsIHByb2plY3Rpb24pIHsKICAgIGxldCByZXN1bHQgPSBOdW1iZXIuTUFYX1ZBTFVFOwogICAgY29uc3QgZW5jb2RpbmcgPSB0ZXJyYWluUGlja2VyLl9lbmNvZGluZzsKICAgIGNvbnN0IGluZGljZXMgPSB0ZXJyYWluUGlja2VyLl9pbmRpY2VzOwogICAgY29uc3QgdmVydGljZXMgPSB0ZXJyYWluUGlja2VyLl92ZXJ0aWNlczsKICAgIGNvbnN0IHRyaWFuZ2xlQ291bnQgPSBub2RlLmludGVyc2VjdGluZ1RyaWFuZ2xlcy5sZW5ndGg7CiAgICBjb25zdCBpc01heExldmVsID0gbm9kZS5sZXZlbCA+PSBNQVhJTVVNX1RFUlJBSU5fUElDS0VSX0xFVkVMOwogICAgY29uc3Qgc2hvdWxkQnVpbGRDaGlsZHJlbiA9ICFpc01heExldmVsICYmICFub2RlLmJ1aWxkaW5nQ2hpbGRyZW47CiAgICBsZXQgdHJpYW5nbGVQb3NpdGlvbnM7CiAgICBsZXQgdHJpYW5nbGVJbmRpY2VzOwogICAgaWYgKHNob3VsZEJ1aWxkQ2hpbGRyZW4pIHsKICAgICAgdHJpYW5nbGVQb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KHRyaWFuZ2xlQ291bnQgKiA5KTsKICAgICAgdHJpYW5nbGVJbmRpY2VzID0gbmV3IFVpbnQzMkFycmF5KHRyaWFuZ2xlQ291bnQpOwogICAgfQogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHRyaWFuZ2xlQ291bnQ7IGkyKyspIHsKICAgICAgY29uc3QgdHJpSW5kZXggPSBub2RlLmludGVyc2VjdGluZ1RyaWFuZ2xlc1tpMl07CiAgICAgIGNvbnN0IHYwMiA9IGdldFZlcnRleFBvc2l0aW9uKAogICAgICAgIGVuY29kaW5nLAogICAgICAgIG1vZGUsCiAgICAgICAgcHJvamVjdGlvbiwKICAgICAgICByYXksCiAgICAgICAgdmVydGljZXMsCiAgICAgICAgaW5kaWNlc1szICogdHJpSW5kZXhdLAogICAgICAgIHNjcmF0Y2hUcmlhbmdsZVBvaW50c1swXQogICAgICApOwogICAgICBjb25zdCB2MTIgPSBnZXRWZXJ0ZXhQb3NpdGlvbigKICAgICAgICBlbmNvZGluZywKICAgICAgICBtb2RlLAogICAgICAgIHByb2plY3Rpb24sCiAgICAgICAgcmF5LAogICAgICAgIHZlcnRpY2VzLAogICAgICAgIGluZGljZXNbMyAqIHRyaUluZGV4ICsgMV0sCiAgICAgICAgc2NyYXRjaFRyaWFuZ2xlUG9pbnRzWzFdCiAgICAgICk7CiAgICAgIGNvbnN0IHYyMiA9IGdldFZlcnRleFBvc2l0aW9uKAogICAgICAgIGVuY29kaW5nLAogICAgICAgIG1vZGUsCiAgICAgICAgcHJvamVjdGlvbiwKICAgICAgICByYXksCiAgICAgICAgdmVydGljZXMsCiAgICAgICAgaW5kaWNlc1szICogdHJpSW5kZXggKyAyXSwKICAgICAgICBzY3JhdGNoVHJpYW5nbGVQb2ludHNbMl0KICAgICAgKTsKICAgICAgY29uc3QgdHJpVCA9IEludGVyc2VjdGlvblRlc3RzX2RlZmF1bHQucmF5VHJpYW5nbGVQYXJhbWV0cmljKAogICAgICAgIHJheSwKICAgICAgICB2MDIsCiAgICAgICAgdjEyLAogICAgICAgIHYyMiwKICAgICAgICBjdWxsQmFja0ZhY2VzCiAgICAgICk7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodHJpVCkgJiYgdHJpVCA8IHJlc3VsdCAmJiB0cmlUID49IDApIHsKICAgICAgICByZXN1bHQgPSB0cmlUOwogICAgICB9CiAgICAgIGlmIChzaG91bGRCdWlsZENoaWxkcmVuKSB7CiAgICAgICAgcGFja1RyaWFuZ2xlQnVmZmVycygKICAgICAgICAgIHRyaWFuZ2xlUG9zaXRpb25zLAogICAgICAgICAgdHJpYW5nbGVJbmRpY2VzLAogICAgICAgICAgc2NyYXRjaFRyaWFuZ2xlUG9pbnRzLAogICAgICAgICAgdHJpSW5kZXgsCiAgICAgICAgICBpMgogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIGlmIChzaG91bGRCdWlsZENoaWxkcmVuKSB7CiAgICAgIGZvciAobGV0IGNoaWxkSWR4ID0gMDsgY2hpbGRJZHggPCA0OyBjaGlsZElkeCsrKSB7CiAgICAgICAgbm9kZS5hZGRDaGlsZChjaGlsZElkeCk7CiAgICAgIH0KICAgICAgYWRkVHJpYW5nbGVzVG9DaGlsZHJlbk5vZGVzKAogICAgICAgIHRlcnJhaW5QaWNrZXIuX2ludmVyc2VUcmFuc2Zvcm0sCiAgICAgICAgbm9kZSwKICAgICAgICB0cmlhbmdsZUluZGljZXMsCiAgICAgICAgdHJpYW5nbGVQb3NpdGlvbnMKICAgICAgKTsKICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGdldFZlcnRleFBvc2l0aW9uKGVuY29kaW5nLCBtb2RlLCBwcm9qZWN0aW9uLCByYXksIHZlcnRpY2VzLCBpbmRleCwgcmVzdWx0KSB7CiAgICBsZXQgcG9zaXRpb24gPSBlbmNvZGluZy5nZXRFeGFnZ2VyYXRlZFBvc2l0aW9uKHZlcnRpY2VzLCBpbmRleCwgcmVzdWx0KTsKICAgIGlmIChtb2RlID09PSBTY2VuZU1vZGVfZGVmYXVsdC5TQ0VORTNEKSB7CiAgICAgIHJldHVybiBwb3NpdGlvbjsKICAgIH0KICAgIGNvbnN0IGVsbGlwc29pZCA9IHByb2plY3Rpb24uZWxsaXBzb2lkOwogICAgY29uc3QgcG9zaXRpb25DYXJ0b2dyYXBoaWMgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWMoCiAgICAgIHBvc2l0aW9uLAogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljNwogICAgKTsKICAgIHBvc2l0aW9uID0gcHJvamVjdGlvbi5wcm9qZWN0KHBvc2l0aW9uQ2FydG9ncmFwaGljLCByZXN1bHQpOwogICAgcG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICBwb3NpdGlvbi56LAogICAgICBwb3NpdGlvbi54LAogICAgICBwb3NpdGlvbi55LAogICAgICByZXN1bHQKICAgICk7CiAgICBjb25zdCB3b3JsZFdpZHRoID0gTWF0aF9kZWZhdWx0LlRXT19QSSAqIHByb2plY3Rpb24uZWxsaXBzb2lkLm1heGltdW1SYWRpdXM7CiAgICBjb25zdCBrMiA9IE1hdGgucm91bmQoKHJheS5vcmlnaW4ueSAtIHBvc2l0aW9uLnkpIC8gd29ybGRXaWR0aCk7CiAgICBwb3NpdGlvbi55ICs9IGsyICogd29ybGRXaWR0aDsKICAgIHJldHVybiBwb3NpdGlvbjsKICB9CiAgYXN5bmMgZnVuY3Rpb24gYWRkVHJpYW5nbGVzVG9DaGlsZHJlbk5vZGVzKGludmVyc2VUcmFuc2Zvcm0sIG5vZGUsIHRyaWFuZ2xlSW5kaWNlcywgdHJpYW5nbGVQb3NpdGlvbnMpIHsKICAgIG5vZGUuYnVpbGRpbmdDaGlsZHJlbiA9IHRydWU7CiAgICBjb25zdCBpbnZlcnNlVHJhbnNmb3JtUGFja2VkID0gbmV3IEZsb2F0NjRBcnJheSgxNik7CiAgICBNYXRyaXg0X2RlZmF1bHQucGFjayhpbnZlcnNlVHJhbnNmb3JtLCBpbnZlcnNlVHJhbnNmb3JtUGFja2VkLCAwKTsKICAgIGNvbnN0IGFhYmJBcnJheSA9IG5ldyBGbG9hdDY0QXJyYXkoNiAqIDQpOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IDQ7IGkyKyspIHsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2sobm9kZS5jaGlsZHJlbltpMl0uYWFiYi5taW5pbXVtLCBhYWJiQXJyYXksIGkyICogNik7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKG5vZGUuY2hpbGRyZW5baTJdLmFhYmIubWF4aW11bSwgYWFiYkFycmF5LCBpMiAqIDYgKyAzKTsKICAgIH0KICAgIGNvbnN0IHBhcmFtZXRlcnMgPSB7CiAgICAgIGFhYmJzOiBhYWJiQXJyYXksCiAgICAgIGludmVyc2VUcmFuc2Zvcm06IGludmVyc2VUcmFuc2Zvcm1QYWNrZWQsCiAgICAgIHRyaWFuZ2xlSW5kaWNlcywKICAgICAgdHJpYW5nbGVQb3NpdGlvbnMKICAgIH07CiAgICBjb25zdCB0cmFuc2ZlcmFibGVPYmplY3RzID0gWwogICAgICBhYWJiQXJyYXkuYnVmZmVyLAogICAgICBpbnZlcnNlVHJhbnNmb3JtUGFja2VkLmJ1ZmZlciwKICAgICAgdHJpYW5nbGVJbmRpY2VzLmJ1ZmZlciwKICAgICAgdHJpYW5nbGVQb3NpdGlvbnMuYnVmZmVyCiAgICBdOwogICAgY29uc3QgaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlclByb21pc2UgPSBpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyVGFza1Byb2Nlc3Nvci5zY2hlZHVsZVRhc2soCiAgICAgIHBhcmFtZXRlcnMsCiAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMKICAgICk7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyUHJvbWlzZSkpIHsKICAgICAgbm9kZS5idWlsZGluZ0NoaWxkcmVuID0gZmFsc2U7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNvbnN0IHJlc3VsdCA9ICgKICAgICAgLyoqIEB0eXBlIHt7aW50ZXJzZWN0aW5nVHJpYW5nbGVzQXJyYXlzOiBBcnJheUJ1ZmZlcltdfX0gKi8KICAgICAgYXdhaXQgaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlclByb21pc2UKICAgICk7CiAgICByZXN1bHQuaW50ZXJzZWN0aW5nVHJpYW5nbGVzQXJyYXlzLmZvckVhY2goKGJ1ZmZlciwgaW5kZXgpID0+IHsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChub2RlLmNoaWxkcmVuW2luZGV4XSkpIHsKICAgICAgICBub2RlLmNoaWxkcmVuW2luZGV4XS5pbnRlcnNlY3RpbmdUcmlhbmdsZXMgPSBuZXcgVWludDMyQXJyYXkoYnVmZmVyKTsKICAgICAgfQogICAgfSk7CiAgICBub2RlLmludGVyc2VjdGluZ1RyaWFuZ2xlcyA9IG5ldyBVaW50MzJBcnJheSgwKTsKICAgIG5vZGUuYnVpbGRpbmdDaGlsZHJlbiA9IGZhbHNlOwogIH0KICB2YXIgTUFYSU1VTV9URVJSQUlOX1BJQ0tFUl9MRVZFTCwgVGVycmFpblBpY2tlciwgaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlclRhc2tQcm9jZXNzb3IsIFRlcnJhaW5QaWNrZXJOb2RlLCBzY3JhdGNoVHJhbnNmb3JtZWRSYXksIHNjcmF0Y2hUcmlhbmdsZVBvaW50cywgc2NyYXRjaEFBQkJNaW4sIHNjcmF0Y2hBQUJCTWF4LCBzY3JhdGNoSW50ZXJ2YWwsIHNjcmF0Y2hDYXJ0b2dyYXBoaWM3LCBUZXJyYWluUGlja2VyX2RlZmF1bHQ7CiAgdmFyIGluaXRfVGVycmFpblBpY2tlciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVGVycmFpblBpY2tlci5qcyIoKSB7CiAgICAgIGluaXRfQXhpc0FsaWduZWRCb3VuZGluZ0JveCgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0aW9uVGVzdHMoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfUmF5KCk7CiAgICAgIGluaXRfVGFza1Byb2Nlc3NvcigpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X1NjZW5lTW9kZSgpOwogICAgICBpbml0X0ludGVydmFsKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgTUFYSU1VTV9URVJSQUlOX1BJQ0tFUl9MRVZFTCA9IDM7CiAgICAgIFRlcnJhaW5QaWNrZXIgPSBjbGFzcyB7CiAgICAgICAgLyoqCiAgICAgICAgICogQHBhcmFtIHtGbG9hdDY0QXJyYXl9IHZlcnRpY2VzIFRoZSB0ZXJyYWluIG1lc2gncyB2ZXJ0ZXggYnVmZmVyLgogICAgICAgICAqIEBwYXJhbSB7VWludDhBcnJheXxVaW50MTZBcnJheXxVaW50MzJBcnJheX0gaW5kaWNlcyBUaGUgdGVycmFpbiBtZXNoJ3MgaW5kZXggYnVmZmVyLgogICAgICAgICAqIEBwYXJhbSB7VGVycmFpbkVuY29kaW5nfSBlbmNvZGluZyBUaGUgdGVycmFpbiBtZXNoJ3MgdmVydGV4IGVuY29kaW5nLgogICAgICAgICAqLwogICAgICAgIGNvbnN0cnVjdG9yKHZlcnRpY2VzLCBpbmRpY2VzLCBlbmNvZGluZykgewogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJ2ZXJ0aWNlcyIsIHZlcnRpY2VzKTsKICAgICAgICAgIENoZWNrX2RlZmF1bHQuZGVmaW5lZCgiaW5kaWNlcyIsIGluZGljZXMpOwogICAgICAgICAgQ2hlY2tfZGVmYXVsdC5kZWZpbmVkKCJlbmNvZGluZyIsIGVuY29kaW5nKTsKICAgICAgICAgIHRoaXMuX3ZlcnRpY2VzID0gdmVydGljZXM7CiAgICAgICAgICB0aGlzLl9pbmRpY2VzID0gaW5kaWNlczsKICAgICAgICAgIHRoaXMuX2VuY29kaW5nID0gZW5jb2Rpbmc7CiAgICAgICAgICB0aGlzLl9pbnZlcnNlVHJhbnNmb3JtID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICAgICAgdGhpcy5fbmVlZHNSZWJ1aWxkID0gdHJ1ZTsKICAgICAgICAgIHRoaXMuX3Jvb3ROb2RlID0gbmV3IFRlcnJhaW5QaWNrZXJOb2RlKCk7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIEluZGljYXRlcyB3aGV0aGVyIHRoZSB0ZXJyYWluIHBpY2tlciBuZWVkcyB0byBiZSByZWJ1aWx0IGR1ZSB0byBjaGFuZ2VzIGluIHRoZSB1bmRlcmx5aW5nIHRlcnJhaW4gbWVzaCdzIHZlcnRpY2VzIG9yIGluZGljZXMuCiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59CiAgICAgICAgICovCiAgICAgICAgZ2V0IG5lZWRzUmVidWlsZCgpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9uZWVkc1JlYnVpbGQ7CiAgICAgICAgfQogICAgICAgIHNldCBuZWVkc1JlYnVpbGQodmFsdWUpIHsKICAgICAgICAgIHRoaXMuX25lZWRzUmVidWlsZCA9IHZhbHVlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBEZXRlcm1pbmVzIHRoZSBwb2ludCBvbiB0aGUgbWVzaCB3aGVyZSB0aGUgZ2l2ZW4gcmF5IGludGVyc2VjdHMuCiAgICAgICAgICogQHBhcmFtIHtSYXl9IHJheSBUaGUgcmF5IHRvIHRlc3QuCiAgICAgICAgICogQHBhcmFtIHtNYXRyaXg0fSB0aWxlVHJhbnNmb3JtIFRoZSB0ZXJyYWluIG1lc2ggdGlsZSdzIHRyYW5zZm9ybSBmcm9tIGxvY2FsIHNwYWNlIHRvIHdvcmxkIHNwYWNlLgogICAgICAgICAqIEBwYXJhbSB7Qm9vbGVhbn0gY3VsbEJhY2tGYWNlcyBXaGV0aGVyIHRvIGNvbnNpZGVyIGJhY2stZmFjaW5nIHRyaWFuZ2xlcyBhcyBpbnRlcnNlY3Rpb25zLgogICAgICAgICAqIEBwYXJhbSB7U2NlbmVNb2RlfSBtb2RlIFRoZSBzY2VuZSBtb2RlICgyRC8zRC9Db2x1bWJ1cyBWaWV3KS4KICAgICAgICAgKiBAcGFyYW0ge01hcFByb2plY3Rpb259IHByb2plY3Rpb24gVGhlIG1hcCBwcm9qZWN0aW9uLgogICAgICAgICAqIEByZXR1cm5zIHtDYXJ0ZXNpYW4zIHwgdW5kZWZpbmVkfSByZXN1bHQgVGhlIGludGVyc2VjdGlvbiBwb2ludCwgb3IgdW5kZWZpbmVkIGlmIHRoZXJlIGlzIG5vIGludGVyc2VjdGlvbi4KICAgICAgICAgKiBAcHJpdmF0ZQogICAgICAgICAqLwogICAgICAgIHJheUludGVyc2VjdChyYXksIHRpbGVUcmFuc2Zvcm0sIGN1bGxCYWNrRmFjZXMsIG1vZGUsIHByb2plY3Rpb24pIHsKICAgICAgICAgIGlmICh0aGlzLl9uZWVkc1JlYnVpbGQpIHsKICAgICAgICAgICAgcmVzZXQodGhpcywgdGlsZVRyYW5zZm9ybSk7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBpbnZUcmFuc2Zvcm0gPSB0aGlzLl9pbnZlcnNlVHJhbnNmb3JtOwogICAgICAgICAgY29uc3QgdHJhbnNmb3JtZWRSYXkgPSBzY3JhdGNoVHJhbnNmb3JtZWRSYXk7CiAgICAgICAgICB0cmFuc2Zvcm1lZFJheS5vcmlnaW4gPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICAgICAgICBpbnZUcmFuc2Zvcm0sCiAgICAgICAgICAgIHJheS5vcmlnaW4sCiAgICAgICAgICAgIHRyYW5zZm9ybWVkUmF5Lm9yaWdpbgogICAgICAgICAgKTsKICAgICAgICAgIHRyYW5zZm9ybWVkUmF5LmRpcmVjdGlvbiA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnRBc1ZlY3RvcigKICAgICAgICAgICAgaW52VHJhbnNmb3JtLAogICAgICAgICAgICByYXkuZGlyZWN0aW9uLAogICAgICAgICAgICB0cmFuc2Zvcm1lZFJheS5kaXJlY3Rpb24KICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb25zID0gW107CiAgICAgICAgICBnZXROb2Rlc0ludGVyc2VjdGluZ1JheSh0aGlzLl9yb290Tm9kZSwgdHJhbnNmb3JtZWRSYXksIGludGVyc2VjdGlvbnMpOwogICAgICAgICAgcmV0dXJuIGZpbmRDbG9zZXN0UG9pbnRJbkNsb3Nlc3ROb2RlKAogICAgICAgICAgICB0aGlzLAogICAgICAgICAgICBpbnRlcnNlY3Rpb25zLAogICAgICAgICAgICByYXksCiAgICAgICAgICAgIGN1bGxCYWNrRmFjZXMsCiAgICAgICAgICAgIG1vZGUsCiAgICAgICAgICAgIHByb2plY3Rpb24KICAgICAgICAgICk7CiAgICAgICAgfQogICAgICB9OwogICAgICBpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyVGFza1Byb2Nlc3NvciA9IG5ldyBUYXNrUHJvY2Vzc29yX2RlZmF1bHQoCiAgICAgICAgImluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIiCiAgICAgICk7CiAgICAgIFRlcnJhaW5QaWNrZXJOb2RlID0gY2xhc3MgX1RlcnJhaW5QaWNrZXJOb2RlIHsKICAgICAgICBjb25zdHJ1Y3RvcigpIHsKICAgICAgICAgIHRoaXMueCA9IDA7CiAgICAgICAgICB0aGlzLnkgPSAwOwogICAgICAgICAgdGhpcy5sZXZlbCA9IDA7CiAgICAgICAgICB0aGlzLmFhYmIgPSBjcmVhdGVBQUJCRm9yTm9kZSh0aGlzLngsIHRoaXMueSwgdGhpcy5sZXZlbCk7CiAgICAgICAgICB0aGlzLmludGVyc2VjdGluZ1RyaWFuZ2xlcyA9IG5ldyBVaW50MzJBcnJheSgwKTsKICAgICAgICAgIHRoaXMuY2hpbGRyZW4gPSBbXTsKICAgICAgICAgIHRoaXMuYnVpbGRpbmdDaGlsZHJlbiA9IGZhbHNlOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBBZGRzIGEgY2hpbGQgbm9kZSB0byB0aGlzIG5vZGUuCiAgICAgICAgICoKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gY2hpbGRJZHggVGhlIGluZGV4IG9mIHRoZSBjaGlsZCB0byBhZGQgKDAtMykuCiAgICAgICAgICovCiAgICAgICAgYWRkQ2hpbGQoY2hpbGRJZHgpIHsKICAgICAgICAgIGlmIChjaGlsZElkeCA8IDAgfHwgY2hpbGRJZHggPiAzKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAgICJUZXJyYWluUGlja2VyTm9kZSBjaGlsZCBpbmRleCBtdXN0IGJlIGJldHdlZW4gMCBhbmQgMywgaW5jbHVzaXZlLiIKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGNvbnN0IGNoaWxkTm9kZSA9IG5ldyBfVGVycmFpblBpY2tlck5vZGUoKTsKICAgICAgICAgIGNoaWxkTm9kZS54ID0gdGhpcy54ICogMiArIChjaGlsZElkeCAmIDEpOwogICAgICAgICAgY2hpbGROb2RlLnkgPSB0aGlzLnkgKiAyICsgKGNoaWxkSWR4ID4+IDEgJiAxKTsKICAgICAgICAgIGNoaWxkTm9kZS5sZXZlbCA9IHRoaXMubGV2ZWwgKyAxOwogICAgICAgICAgY2hpbGROb2RlLmFhYmIgPSBjcmVhdGVBQUJCRm9yTm9kZSgKICAgICAgICAgICAgY2hpbGROb2RlLngsCiAgICAgICAgICAgIGNoaWxkTm9kZS55LAogICAgICAgICAgICBjaGlsZE5vZGUubGV2ZWwKICAgICAgICAgICk7CiAgICAgICAgICB0aGlzLmNoaWxkcmVuW2NoaWxkSWR4XSA9IGNoaWxkTm9kZTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIHNjcmF0Y2hUcmFuc2Zvcm1lZFJheSA9IG5ldyBSYXlfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVHJpYW5nbGVQb2ludHMgPSBbCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkKICAgICAgXTsKICAgICAgc2NyYXRjaEFBQkJNaW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hBQUJCTWF4ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoSW50ZXJ2YWwgPSBuZXcgSW50ZXJ2YWxfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljNyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBUZXJyYWluUGlja2VyX2RlZmF1bHQgPSBUZXJyYWluUGlja2VyOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVGVycmFpbk1lc2guanMKICBmdW5jdGlvbiBUZXJyYWluTWVzaChjZW50ZXIsIHZlcnRpY2VzLCBpbmRpY2VzLCBpbmRleENvdW50V2l0aG91dFNraXJ0cywgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzLCBtaW5pbXVtSGVpZ2h0LCBtYXhpbXVtSGVpZ2h0LCByZWN0YW5nbGUsIGJvdW5kaW5nU3BoZXJlM0QsIG9jY2x1ZGVlUG9pbnRJblNjYWxlZFNwYWNlLCB2ZXJ0ZXhTdHJpZGUsIG9yaWVudGVkQm91bmRpbmdCb3gsIGVuY29kaW5nLCB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwgZWFzdEluZGljZXNOb3J0aFRvU291dGgsIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QpIHsKICAgIHRoaXMuY2VudGVyID0gY2VudGVyOwogICAgdGhpcy52ZXJ0aWNlcyA9IHZlcnRpY2VzOwogICAgdGhpcy5zdHJpZGUgPSB2ZXJ0ZXhTdHJpZGUgPz8gNjsKICAgIHRoaXMuaW5kaWNlcyA9IGluZGljZXM7CiAgICB0aGlzLmluZGV4Q291bnRXaXRob3V0U2tpcnRzID0gaW5kZXhDb3VudFdpdGhvdXRTa2lydHM7CiAgICB0aGlzLnZlcnRleENvdW50V2l0aG91dFNraXJ0cyA9IHZlcnRleENvdW50V2l0aG91dFNraXJ0czsKICAgIHRoaXMubWluaW11bUhlaWdodCA9IG1pbmltdW1IZWlnaHQ7CiAgICB0aGlzLm1heGltdW1IZWlnaHQgPSBtYXhpbXVtSGVpZ2h0OwogICAgdGhpcy5yZWN0YW5nbGUgPSByZWN0YW5nbGU7CiAgICB0aGlzLmJvdW5kaW5nU3BoZXJlM0QgPSBib3VuZGluZ1NwaGVyZTNEOwogICAgdGhpcy5vY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZSA9IG9jY2x1ZGVlUG9pbnRJblNjYWxlZFNwYWNlOwogICAgdGhpcy5vcmllbnRlZEJvdW5kaW5nQm94ID0gb3JpZW50ZWRCb3VuZGluZ0JveDsKICAgIHRoaXMuZW5jb2RpbmcgPSBlbmNvZGluZzsKICAgIHRoaXMud2VzdEluZGljZXNTb3V0aFRvTm9ydGggPSB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aDsKICAgIHRoaXMuc291dGhJbmRpY2VzRWFzdFRvV2VzdCA9IHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3Q7CiAgICB0aGlzLmVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoID0gZWFzdEluZGljZXNOb3J0aFRvU291dGg7CiAgICB0aGlzLm5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QgPSBub3J0aEluZGljZXNXZXN0VG9FYXN0OwogICAgdGhpcy5fdHJhbnNmb3JtID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgdGhpcy5fbGFzdFBpY2tTY2VuZU1vZGUgPSB2b2lkIDA7CiAgICB0aGlzLl90ZXJyYWluUGlja2VyID0gbmV3IFRlcnJhaW5QaWNrZXJfZGVmYXVsdCh2ZXJ0aWNlcywgaW5kaWNlcywgZW5jb2RpbmcpOwogIH0KICBmdW5jdGlvbiBjb21wdXRlVHJhbnNmb3JtKG1lc2gsIHJlc3VsdCkgewogICAgY29uc3QgZXhhZ2dlcmF0aW9uID0gbWVzaC5lbmNvZGluZy5leGFnZ2VyYXRpb247CiAgICBjb25zdCBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodCA9IG1lc2guZW5jb2RpbmcuZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQ7CiAgICBjb25zdCBleGFnZ2VyYXRlZE1pbkhlaWdodCA9IFZlcnRpY2FsRXhhZ2dlcmF0aW9uX2RlZmF1bHQuZ2V0SGVpZ2h0KAogICAgICBtZXNoLm1pbmltdW1IZWlnaHQsCiAgICAgIGV4YWdnZXJhdGlvbiwKICAgICAgZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQKICAgICk7CiAgICBjb25zdCBleGFnZ2VyYXRlZE1heEhlaWdodCA9IFZlcnRpY2FsRXhhZ2dlcmF0aW9uX2RlZmF1bHQuZ2V0SGVpZ2h0KAogICAgICBtZXNoLm1heGltdW1IZWlnaHQsCiAgICAgIGV4YWdnZXJhdGlvbiwKICAgICAgZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQKICAgICk7CiAgICBjb25zdCBvYmIgPSBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQuZnJvbVJlY3RhbmdsZSgKICAgICAgbWVzaC5yZWN0YW5nbGUsCiAgICAgIGV4YWdnZXJhdGVkTWluSGVpZ2h0LAogICAgICBleGFnZ2VyYXRlZE1heEhlaWdodCwKICAgICAgRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdCwKICAgICAgbWVzaC5vcmllbnRlZEJvdW5kaW5nQm94CiAgICApOwogICAgT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmNvbXB1dGVUcmFuc2Zvcm1hdGlvbihvYmIsIHJlc3VsdCk7CiAgICBjb25zdCB6U2NhbGUgPSBNYXRyaXg0X2RlZmF1bHQuZ2V0U2NhbGUocmVzdWx0LCBzY3JhdGNoU2NhbGUzKS56OwogICAgaWYgKHpTY2FsZSA8PSBNYXRoX2RlZmF1bHQuRVBTSUxPTjE2KSB7CiAgICAgIHNjcmF0Y2hTY2FsZTMueiA9IDE7CiAgICAgIE1hdHJpeDRfZGVmYXVsdC5zZXRTY2FsZShyZXN1bHQsIHNjcmF0Y2hTY2FsZTMsIHJlc3VsdCk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBjb21wdXRlVHJhbnNmb3JtMkQobWVzaCwgcHJvamVjdGlvbiwgcmVzdWx0KSB7CiAgICBjb25zdCBleGFnZ2VyYXRpb24gPSBtZXNoLmVuY29kaW5nLmV4YWdnZXJhdGlvbjsKICAgIGNvbnN0IGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0ID0gbWVzaC5lbmNvZGluZy5leGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodDsKICAgIGNvbnN0IGV4YWdnZXJhdGVkTWluSGVpZ2h0ID0gVmVydGljYWxFeGFnZ2VyYXRpb25fZGVmYXVsdC5nZXRIZWlnaHQoCiAgICAgIG1lc2gubWluaW11bUhlaWdodCwKICAgICAgZXhhZ2dlcmF0aW9uLAogICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgKTsKICAgIGNvbnN0IGV4YWdnZXJhdGVkTWF4SGVpZ2h0ID0gVmVydGljYWxFeGFnZ2VyYXRpb25fZGVmYXVsdC5nZXRIZWlnaHQoCiAgICAgIG1lc2gubWF4aW11bUhlaWdodCwKICAgICAgZXhhZ2dlcmF0aW9uLAogICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgKTsKICAgIGNvbnN0IHNvdXRod2VzdCA9IHByb2plY3Rpb24ucHJvamVjdCgKICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgbWVzaC5yZWN0YW5nbGUud2VzdCwKICAgICAgICBtZXNoLnJlY3RhbmdsZS5zb3V0aCwKICAgICAgICAwLAogICAgICAgIHNjcmF0Y2hTV0NhcnRvZ3JhcGhpYwogICAgICApLAogICAgICBzY3JhdGNoU1dDYXJ0ZXNpYW4KICAgICk7CiAgICBjb25zdCBub3J0aGVhc3QgPSBwcm9qZWN0aW9uLnByb2plY3QoCiAgICAgIENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21SYWRpYW5zKAogICAgICAgIG1lc2gucmVjdGFuZ2xlLmVhc3QsCiAgICAgICAgbWVzaC5yZWN0YW5nbGUubm9ydGgsCiAgICAgICAgMCwKICAgICAgICBzY3JhdGNoTkVDYXJ0b2dyYXBoaWMKICAgICAgKSwKICAgICAgc2NyYXRjaE5FQ2FydGVzaWFuCiAgICApOwogICAgY29uc3QgaGVpZ2h0UmFuZ2UgPSBleGFnZ2VyYXRlZE1heEhlaWdodCAtIGV4YWdnZXJhdGVkTWluSGVpZ2h0OwogICAgY29uc3Qgc2NhbGUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICBub3J0aGVhc3QueCAtIHNvdXRod2VzdC54LAogICAgICBub3J0aGVhc3QueSAtIHNvdXRod2VzdC55LAogICAgICBoZWlnaHRSYW5nZSA+IDAgPyBoZWlnaHRSYW5nZSA6IDEsCiAgICAgIC8vIEF2b2lkIHplcm8gc2NhbGUKICAgICAgc2NyYXRjaFNjYWxlMkQKICAgICk7CiAgICBjb25zdCBjZW50ZXIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICBzb3V0aHdlc3QueCArIHNjYWxlLnggKiAwLjUsCiAgICAgIHNvdXRod2VzdC55ICsgc2NhbGUueSAqIDAuNSwKICAgICAgZXhhZ2dlcmF0ZWRNaW5IZWlnaHQgKyBzY2FsZS56ICogMC41LAogICAgICBzY3JhdGNoQ2VudGVyMkQKICAgICk7CiAgICBNYXRyaXg0X2RlZmF1bHQuZnJvbVRyYW5zbGF0aW9uKGNlbnRlciwgcmVzdWx0KTsKICAgIE1hdHJpeDRfZGVmYXVsdC5zZXRTY2FsZShyZXN1bHQsIHNjYWxlLCByZXN1bHQpOwogICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5KFRyYW5zZm9ybXNfZGVmYXVsdC5TV0laWkxFXzNEX1RPXzJEX01BVFJJWCwgcmVzdWx0LCByZXN1bHQpOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgdmFyIHNjcmF0Y2hTV0NhcnRlc2lhbiwgc2NyYXRjaE5FQ2FydGVzaWFuLCBzY3JhdGNoU1dDYXJ0b2dyYXBoaWMsIHNjcmF0Y2hORUNhcnRvZ3JhcGhpYywgc2NyYXRjaFNjYWxlMkQsIHNjcmF0Y2hDZW50ZXIyRCwgc2NyYXRjaFNjYWxlMywgVGVycmFpbk1lc2hfZGVmYXVsdDsKICB2YXIgaW5pdF9UZXJyYWluTWVzaCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVGVycmFpbk1lc2guanMiKCkgewogICAgICBpbml0X1NjZW5lTW9kZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X01hdHJpeDQoKTsKICAgICAgaW5pdF9PcmllbnRlZEJvdW5kaW5nQm94KCk7CiAgICAgIGluaXRfVGVycmFpblBpY2tlcigpOwogICAgICBpbml0X1RyYW5zZm9ybXMoKTsKICAgICAgaW5pdF9WZXJ0aWNhbEV4YWdnZXJhdGlvbigpOwogICAgICBUZXJyYWluTWVzaC5wcm90b3R5cGUuZ2V0VHJhbnNmb3JtID0gZnVuY3Rpb24obW9kZSwgcHJvamVjdGlvbikgewogICAgICAgIGlmICh0aGlzLl9sYXN0UGlja1NjZW5lTW9kZSA9PT0gbW9kZSkgewogICAgICAgICAgcmV0dXJuIHRoaXMuX3RyYW5zZm9ybTsKICAgICAgICB9CiAgICAgICAgdGhpcy5fdGVycmFpblBpY2tlci5uZWVkc1JlYnVpbGQgPSB0cnVlOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG1vZGUpIHx8IG1vZGUgPT09IFNjZW5lTW9kZV9kZWZhdWx0LlNDRU5FM0QpIHsKICAgICAgICAgIHJldHVybiBjb21wdXRlVHJhbnNmb3JtKHRoaXMsIHRoaXMuX3RyYW5zZm9ybSk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBjb21wdXRlVHJhbnNmb3JtMkQodGhpcywgcHJvamVjdGlvbiwgdGhpcy5fdHJhbnNmb3JtKTsKICAgICAgfTsKICAgICAgc2NyYXRjaFNXQ2FydGVzaWFuID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTkVDYXJ0ZXNpYW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hTV0NhcnRvZ3JhcGhpYyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTkVDYXJ0b2dyYXBoaWMgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFNjYWxlMkQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDZW50ZXIyRCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFNjYWxlMyA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgVGVycmFpbk1lc2gucHJvdG90eXBlLnBpY2sgPSBmdW5jdGlvbihyYXksIGN1bGxCYWNrRmFjZXMsIG1vZGUsIHByb2plY3Rpb24pIHsKICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSB0aGlzLl90ZXJyYWluUGlja2VyLnJheUludGVyc2VjdCgKICAgICAgICAgIHJheSwKICAgICAgICAgIHRoaXMuZ2V0VHJhbnNmb3JtKG1vZGUsIHByb2plY3Rpb24pLAogICAgICAgICAgY3VsbEJhY2tGYWNlcywKICAgICAgICAgIG1vZGUsCiAgICAgICAgICBwcm9qZWN0aW9uCiAgICAgICAgKTsKICAgICAgICB0aGlzLl9sYXN0UGlja1NjZW5lTW9kZSA9IG1vZGU7CiAgICAgICAgcmV0dXJuIGludGVyc2VjdGlvbjsKICAgICAgfTsKICAgICAgVGVycmFpbk1lc2gucHJvdG90eXBlLnVwZGF0ZUV4YWdnZXJhdGlvbiA9IGZ1bmN0aW9uKGV4YWdnZXJhdGlvbiwgZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQpIHsKICAgICAgICB0aGlzLl90ZXJyYWluUGlja2VyLl92ZXJ0aWNlcyA9IHRoaXMudmVydGljZXM7CiAgICAgICAgdGhpcy5fdGVycmFpblBpY2tlci5uZWVkc1JlYnVpbGQgPSB0cnVlOwogICAgICAgIHRoaXMuX2xhc3RQaWNrU2NlbmVNb2RlID0gdm9pZCAwOwogICAgICB9OwogICAgICBUZXJyYWluTWVzaC5wcm90b3R5cGUudXBkYXRlU2NlbmVNb2RlID0gZnVuY3Rpb24obW9kZSkgewogICAgICAgIHRoaXMuX3RlcnJhaW5QaWNrZXIubmVlZHNSZWJ1aWxkID0gdHJ1ZTsKICAgICAgICB0aGlzLl9sYXN0UGlja1NjZW5lTW9kZSA9IHZvaWQgMDsKICAgICAgfTsKICAgICAgVGVycmFpbk1lc2hfZGVmYXVsdCA9IFRlcnJhaW5NZXNoOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVGVycmFpblByb3ZpZGVyLmpzCiAgZnVuY3Rpb24gVGVycmFpblByb3ZpZGVyKCkgewogICAgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdC50aHJvd0luc3RhbnRpYXRpb25FcnJvcigpOwogIH0KICBmdW5jdGlvbiBnZXRFZGdlSW5kaWNlcyh3aWR0aCwgaGVpZ2h0KSB7CiAgICBjb25zdCB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCA9IG5ldyBBcnJheShoZWlnaHQpOwogICAgY29uc3Qgc291dGhJbmRpY2VzRWFzdFRvV2VzdCA9IG5ldyBBcnJheSh3aWR0aCk7CiAgICBjb25zdCBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCA9IG5ldyBBcnJheShoZWlnaHQpOwogICAgY29uc3Qgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdCA9IG5ldyBBcnJheSh3aWR0aCk7CiAgICBsZXQgaTI7CiAgICBmb3IgKGkyID0gMDsgaTIgPCB3aWR0aDsgKytpMikgewogICAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0W2kyXSA9IGkyOwogICAgICBzb3V0aEluZGljZXNFYXN0VG9XZXN0W2kyXSA9IHdpZHRoICogaGVpZ2h0IC0gMSAtIGkyOwogICAgfQogICAgZm9yIChpMiA9IDA7IGkyIDwgaGVpZ2h0OyArK2kyKSB7CiAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoW2kyXSA9IChpMiArIDEpICogd2lkdGggLSAxOwogICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aFtpMl0gPSAoaGVpZ2h0IC0gaTIgLSAxKSAqIHdpZHRoOwogICAgfQogICAgcmV0dXJuIHsKICAgICAgd2VzdEluZGljZXNTb3V0aFRvTm9ydGgsCiAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLAogICAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0CiAgICB9OwogIH0KICBmdW5jdGlvbiBhZGRSZWd1bGFyR3JpZEluZGljZXMod2lkdGgsIGhlaWdodCwgaW5kaWNlcywgb2Zmc2V0KSB7CiAgICBsZXQgaW5kZXggPSAwOwogICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGhlaWdodCAtIDE7ICsrajIpIHsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHdpZHRoIC0gMTsgKytpMikgewogICAgICAgIGNvbnN0IHVwcGVyTGVmdCA9IGluZGV4OwogICAgICAgIGNvbnN0IGxvd2VyTGVmdCA9IHVwcGVyTGVmdCArIHdpZHRoOwogICAgICAgIGNvbnN0IGxvd2VyUmlnaHQgPSBsb3dlckxlZnQgKyAxOwogICAgICAgIGNvbnN0IHVwcGVyUmlnaHQgPSB1cHBlckxlZnQgKyAxOwogICAgICAgIGluZGljZXNbb2Zmc2V0KytdID0gdXBwZXJMZWZ0OwogICAgICAgIGluZGljZXNbb2Zmc2V0KytdID0gbG93ZXJMZWZ0OwogICAgICAgIGluZGljZXNbb2Zmc2V0KytdID0gdXBwZXJSaWdodDsKICAgICAgICBpbmRpY2VzW29mZnNldCsrXSA9IHVwcGVyUmlnaHQ7CiAgICAgICAgaW5kaWNlc1tvZmZzZXQrK10gPSBsb3dlckxlZnQ7CiAgICAgICAgaW5kaWNlc1tvZmZzZXQrK10gPSBsb3dlclJpZ2h0OwogICAgICAgICsraW5kZXg7CiAgICAgIH0KICAgICAgKytpbmRleDsKICAgIH0KICB9CiAgZnVuY3Rpb24gYWRkU2tpcnRJbmRpY2VzKGVkZ2VJbmRpY2VzLCB2ZXJ0ZXhJbmRleCwgaW5kaWNlcywgb2Zmc2V0KSB7CiAgICBsZXQgcHJldmlvdXNJbmRleCA9IGVkZ2VJbmRpY2VzWzBdOwogICAgY29uc3QgbGVuZ3RoID0gZWRnZUluZGljZXMubGVuZ3RoOwogICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBjb25zdCBpbmRleCA9IGVkZ2VJbmRpY2VzW2kyXTsKICAgICAgaW5kaWNlc1tvZmZzZXQrK10gPSBwcmV2aW91c0luZGV4OwogICAgICBpbmRpY2VzW29mZnNldCsrXSA9IGluZGV4OwogICAgICBpbmRpY2VzW29mZnNldCsrXSA9IHZlcnRleEluZGV4OwogICAgICBpbmRpY2VzW29mZnNldCsrXSA9IHZlcnRleEluZGV4OwogICAgICBpbmRpY2VzW29mZnNldCsrXSA9IGluZGV4OwogICAgICBpbmRpY2VzW29mZnNldCsrXSA9IHZlcnRleEluZGV4ICsgMTsKICAgICAgcHJldmlvdXNJbmRleCA9IGluZGV4OwogICAgICArK3ZlcnRleEluZGV4OwogICAgfQogICAgcmV0dXJuIG9mZnNldDsKICB9CiAgdmFyIHJlZ3VsYXJHcmlkSW5kaWNlc0NhY2hlLCByZWd1bGFyR3JpZEFuZEVkZ2VJbmRpY2VzQ2FjaGUsIHJlZ3VsYXJHcmlkQW5kU2tpcnRBbmRFZGdlSW5kaWNlc0NhY2hlLCBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdDsKICB2YXIgaW5pdF9UZXJyYWluUHJvdmlkZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1RlcnJhaW5Qcm92aWRlci5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVGVycmFpblByb3ZpZGVyLnByb3RvdHlwZSwgewogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgYW4gZXZlbnQgdGhhdCBpcyByYWlzZWQgd2hlbiB0aGUgdGVycmFpbiBwcm92aWRlciBlbmNvdW50ZXJzIGFuIGFzeW5jaHJvbm91cyBlcnJvci4gIEJ5IHN1YnNjcmliaW5nCiAgICAgICAgICogdG8gdGhlIGV2ZW50LCB5b3Ugd2lsbCBiZSBub3RpZmllZCBvZiB0aGUgZXJyb3IgYW5kIGNhbiBwb3RlbnRpYWxseSByZWNvdmVyIGZyb20gaXQuICBFdmVudCBsaXN0ZW5lcnMKICAgICAgICAgKiBhcmUgcGFzc2VkIGFuIGluc3RhbmNlIG9mIHtAbGluayBUaWxlUHJvdmlkZXJFcnJvcn0uCiAgICAgICAgICogQG1lbWJlcm9mIFRlcnJhaW5Qcm92aWRlci5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7RXZlbnQ8VGVycmFpblByb3ZpZGVyLkVycm9yRXZlbnQ+fQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGVycm9yRXZlbnQ6IHsKICAgICAgICAgIGdldDogRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdC50aHJvd0luc3RhbnRpYXRpb25FcnJvcgogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgY3JlZGl0IHRvIGRpc3BsYXkgd2hlbiB0aGlzIHRlcnJhaW4gcHJvdmlkZXIgaXMgYWN0aXZlLiAgVHlwaWNhbGx5IHRoaXMgaXMgdXNlZCB0byBjcmVkaXQKICAgICAgICAgKiB0aGUgc291cmNlIG9mIHRoZSB0ZXJyYWluLgogICAgICAgICAqIEBtZW1iZXJvZiBUZXJyYWluUHJvdmlkZXIucHJvdG90eXBlCiAgICAgICAgICogQHR5cGUge0NyZWRpdH0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBjcmVkaXQ6IHsKICAgICAgICAgIGdldDogRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdC50aHJvd0luc3RhbnRpYXRpb25FcnJvcgogICAgICAgIH0sCiAgICAgICAgLyoqCiAgICAgICAgICogR2V0cyB0aGUgdGlsaW5nIHNjaGVtZSB1c2VkIGJ5IHRoZSBwcm92aWRlci4KICAgICAgICAgKiBAbWVtYmVyb2YgVGVycmFpblByb3ZpZGVyLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtUaWxpbmdTY2hlbWV9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgdGlsaW5nU2NoZW1lOiB7CiAgICAgICAgICBnZXQ6IERldmVsb3BlckVycm9yX2RlZmF1bHQudGhyb3dJbnN0YW50aWF0aW9uRXJyb3IKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgYSB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgb3Igbm90IHRoZSBwcm92aWRlciBpbmNsdWRlcyBhIHdhdGVyIG1hc2suICBUaGUgd2F0ZXIgbWFzawogICAgICAgICAqIGluZGljYXRlcyB3aGljaCBhcmVhcyBvZiB0aGUgZ2xvYmUgYXJlIHdhdGVyIHJhdGhlciB0aGFuIGxhbmQsIHNvIHRoZXkgY2FuIGJlIHJlbmRlcmVkCiAgICAgICAgICogYXMgYSByZWZsZWN0aXZlIHN1cmZhY2Ugd2l0aCBhbmltYXRlZCB3YXZlcy4KICAgICAgICAgKiBAbWVtYmVyb2YgVGVycmFpblByb3ZpZGVyLnByb3RvdHlwZQogICAgICAgICAqIEB0eXBlIHtib29sZWFufQogICAgICAgICAqIEByZWFkb25seQogICAgICAgICAqLwogICAgICAgIGhhc1dhdGVyTWFzazogewogICAgICAgICAgZ2V0OiBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0LnRocm93SW5zdGFudGlhdGlvbkVycm9yCiAgICAgICAgfSwKICAgICAgICAvKioKICAgICAgICAgKiBHZXRzIGEgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIG9yIG5vdCB0aGUgcmVxdWVzdGVkIHRpbGVzIGluY2x1ZGUgdmVydGV4IG5vcm1hbHMuCiAgICAgICAgICogQG1lbWJlcm9mIFRlcnJhaW5Qcm92aWRlci5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn0KICAgICAgICAgKiBAcmVhZG9ubHkKICAgICAgICAgKi8KICAgICAgICBoYXNWZXJ0ZXhOb3JtYWxzOiB7CiAgICAgICAgICBnZXQ6IERldmVsb3BlckVycm9yX2RlZmF1bHQudGhyb3dJbnN0YW50aWF0aW9uRXJyb3IKICAgICAgICB9LAogICAgICAgIC8qKgogICAgICAgICAqIEdldHMgYW4gb2JqZWN0IHRoYXQgY2FuIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIGF2YWlsYWJpbGl0eSBvZiB0ZXJyYWluIGZyb20gdGhpcyBwcm92aWRlciwgc3VjaCBhcwogICAgICAgICAqIGF0IHBvaW50cyBhbmQgaW4gcmVjdGFuZ2xlcy4gVGhpcyBwcm9wZXJ0eSBtYXkgYmUgdW5kZWZpbmVkIGlmIGF2YWlsYWJpbGl0eQogICAgICAgICAqIGluZm9ybWF0aW9uIGlzIG5vdCBhdmFpbGFibGUuCiAgICAgICAgICogQG1lbWJlcm9mIFRlcnJhaW5Qcm92aWRlci5wcm90b3R5cGUKICAgICAgICAgKiBAdHlwZSB7VGlsZUF2YWlsYWJpbGl0eXx1bmRlZmluZWR9CiAgICAgICAgICogQHJlYWRvbmx5CiAgICAgICAgICovCiAgICAgICAgYXZhaWxhYmlsaXR5OiB7CiAgICAgICAgICBnZXQ6IERldmVsb3BlckVycm9yX2RlZmF1bHQudGhyb3dJbnN0YW50aWF0aW9uRXJyb3IKICAgICAgICB9CiAgICAgIH0pOwogICAgICByZWd1bGFyR3JpZEluZGljZXNDYWNoZSA9IFtdOwogICAgICBUZXJyYWluUHJvdmlkZXIuZ2V0UmVndWxhckdyaWRJbmRpY2VzID0gZnVuY3Rpb24od2lkdGgsIGhlaWdodCkgewogICAgICAgIGlmICh3aWR0aCAqIGhlaWdodCA+PSBNYXRoX2RlZmF1bHQuRk9VUl9HSUdBQllURVMpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiVGhlIHRvdGFsIG51bWJlciBvZiB2ZXJ0aWNlcyAod2lkdGggKiBoZWlnaHQpIG11c3QgYmUgbGVzcyB0aGFuIDQsMjk0LDk2NywyOTYuIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgbGV0IGJ5V2lkdGggPSByZWd1bGFyR3JpZEluZGljZXNDYWNoZVt3aWR0aF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYnlXaWR0aCkpIHsKICAgICAgICAgIHJlZ3VsYXJHcmlkSW5kaWNlc0NhY2hlW3dpZHRoXSA9IGJ5V2lkdGggPSBbXTsKICAgICAgICB9CiAgICAgICAgbGV0IGluZGljZXMgPSBieVdpZHRoW2hlaWdodF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5kaWNlcykpIHsKICAgICAgICAgIGlmICh3aWR0aCAqIGhlaWdodCA8IE1hdGhfZGVmYXVsdC5TSVhUWV9GT1VSX0tJTE9CWVRFUykgewogICAgICAgICAgICBpbmRpY2VzID0gYnlXaWR0aFtoZWlnaHRdID0gbmV3IFVpbnQxNkFycmF5KAogICAgICAgICAgICAgICh3aWR0aCAtIDEpICogKGhlaWdodCAtIDEpICogNgogICAgICAgICAgICApOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgaW5kaWNlcyA9IGJ5V2lkdGhbaGVpZ2h0XSA9IG5ldyBVaW50MzJBcnJheSgKICAgICAgICAgICAgICAod2lkdGggLSAxKSAqIChoZWlnaHQgLSAxKSAqIDYKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIGFkZFJlZ3VsYXJHcmlkSW5kaWNlcyh3aWR0aCwgaGVpZ2h0LCBpbmRpY2VzLCAwKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGluZGljZXM7CiAgICAgIH07CiAgICAgIHJlZ3VsYXJHcmlkQW5kRWRnZUluZGljZXNDYWNoZSA9IFtdOwogICAgICBUZXJyYWluUHJvdmlkZXIuZ2V0UmVndWxhckdyaWRJbmRpY2VzQW5kRWRnZUluZGljZXMgPSBmdW5jdGlvbih3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgaWYgKHdpZHRoICogaGVpZ2h0ID49IE1hdGhfZGVmYXVsdC5GT1VSX0dJR0FCWVRFUykgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgICAgICJUaGUgdG90YWwgbnVtYmVyIG9mIHZlcnRpY2VzICh3aWR0aCAqIGhlaWdodCkgbXVzdCBiZSBsZXNzIHRoYW4gNCwyOTQsOTY3LDI5Ni4iCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBsZXQgYnlXaWR0aCA9IHJlZ3VsYXJHcmlkQW5kRWRnZUluZGljZXNDYWNoZVt3aWR0aF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYnlXaWR0aCkpIHsKICAgICAgICAgIHJlZ3VsYXJHcmlkQW5kRWRnZUluZGljZXNDYWNoZVt3aWR0aF0gPSBieVdpZHRoID0gW107CiAgICAgICAgfQogICAgICAgIGxldCBpbmRpY2VzQW5kRWRnZXMgPSBieVdpZHRoW2hlaWdodF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5kaWNlc0FuZEVkZ2VzKSkgewogICAgICAgICAgY29uc3QgaW5kaWNlcyA9IFRlcnJhaW5Qcm92aWRlci5nZXRSZWd1bGFyR3JpZEluZGljZXMod2lkdGgsIGhlaWdodCk7CiAgICAgICAgICBjb25zdCBlZGdlSW5kaWNlcyA9IGdldEVkZ2VJbmRpY2VzKHdpZHRoLCBoZWlnaHQpOwogICAgICAgICAgY29uc3Qgd2VzdEluZGljZXNTb3V0aFRvTm9ydGggPSBlZGdlSW5kaWNlcy53ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aDsKICAgICAgICAgIGNvbnN0IHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QgPSBlZGdlSW5kaWNlcy5zb3V0aEluZGljZXNFYXN0VG9XZXN0OwogICAgICAgICAgY29uc3QgZWFzdEluZGljZXNOb3J0aFRvU291dGggPSBlZGdlSW5kaWNlcy5lYXN0SW5kaWNlc05vcnRoVG9Tb3V0aDsKICAgICAgICAgIGNvbnN0IG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QgPSBlZGdlSW5kaWNlcy5ub3J0aEluZGljZXNXZXN0VG9FYXN0OwogICAgICAgICAgaW5kaWNlc0FuZEVkZ2VzID0gYnlXaWR0aFtoZWlnaHRdID0gewogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwKICAgICAgICAgICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwKICAgICAgICAgICAgZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgICAgICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QKICAgICAgICAgIH07CiAgICAgICAgfQogICAgICAgIHJldHVybiBpbmRpY2VzQW5kRWRnZXM7CiAgICAgIH07CiAgICAgIHJlZ3VsYXJHcmlkQW5kU2tpcnRBbmRFZGdlSW5kaWNlc0NhY2hlID0gW107CiAgICAgIFRlcnJhaW5Qcm92aWRlci5nZXRSZWd1bGFyR3JpZEFuZFNraXJ0SW5kaWNlc0FuZEVkZ2VJbmRpY2VzID0gZnVuY3Rpb24od2lkdGgsIGhlaWdodCkgewogICAgICAgIGlmICh3aWR0aCAqIGhlaWdodCA+PSBNYXRoX2RlZmF1bHQuRk9VUl9HSUdBQllURVMpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICAgICAiVGhlIHRvdGFsIG51bWJlciBvZiB2ZXJ0aWNlcyAod2lkdGggKiBoZWlnaHQpIG11c3QgYmUgbGVzcyB0aGFuIDQsMjk0LDk2NywyOTYuIgogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgbGV0IGJ5V2lkdGggPSByZWd1bGFyR3JpZEFuZFNraXJ0QW5kRWRnZUluZGljZXNDYWNoZVt3aWR0aF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoYnlXaWR0aCkpIHsKICAgICAgICAgIHJlZ3VsYXJHcmlkQW5kU2tpcnRBbmRFZGdlSW5kaWNlc0NhY2hlW3dpZHRoXSA9IGJ5V2lkdGggPSBbXTsKICAgICAgICB9CiAgICAgICAgbGV0IGluZGljZXNBbmRFZGdlcyA9IGJ5V2lkdGhbaGVpZ2h0XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChpbmRpY2VzQW5kRWRnZXMpKSB7CiAgICAgICAgICBjb25zdCBncmlkVmVydGV4Q291bnQgPSB3aWR0aCAqIGhlaWdodDsKICAgICAgICAgIGNvbnN0IGdyaWRJbmRleENvdW50ID0gKHdpZHRoIC0gMSkgKiAoaGVpZ2h0IC0gMSkgKiA2OwogICAgICAgICAgY29uc3QgZWRnZVZlcnRleENvdW50ID0gd2lkdGggKiAyICsgaGVpZ2h0ICogMjsKICAgICAgICAgIGNvbnN0IGVkZ2VJbmRleENvdW50ID0gTWF0aC5tYXgoMCwgZWRnZVZlcnRleENvdW50IC0gNCkgKiA2OwogICAgICAgICAgY29uc3QgdmVydGV4Q291bnQgPSBncmlkVmVydGV4Q291bnQgKyBlZGdlVmVydGV4Q291bnQ7CiAgICAgICAgICBjb25zdCBpbmRleENvdW50ID0gZ3JpZEluZGV4Q291bnQgKyBlZGdlSW5kZXhDb3VudDsKICAgICAgICAgIGNvbnN0IGVkZ2VJbmRpY2VzID0gZ2V0RWRnZUluZGljZXMod2lkdGgsIGhlaWdodCk7CiAgICAgICAgICBjb25zdCB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCA9IGVkZ2VJbmRpY2VzLndlc3RJbmRpY2VzU291dGhUb05vcnRoOwogICAgICAgICAgY29uc3Qgc291dGhJbmRpY2VzRWFzdFRvV2VzdCA9IGVkZ2VJbmRpY2VzLnNvdXRoSW5kaWNlc0Vhc3RUb1dlc3Q7CiAgICAgICAgICBjb25zdCBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCA9IGVkZ2VJbmRpY2VzLmVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoOwogICAgICAgICAgY29uc3Qgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdCA9IGVkZ2VJbmRpY2VzLm5vcnRoSW5kaWNlc1dlc3RUb0Vhc3Q7CiAgICAgICAgICBjb25zdCBpbmRpY2VzID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkodmVydGV4Q291bnQsIGluZGV4Q291bnQpOwogICAgICAgICAgYWRkUmVndWxhckdyaWRJbmRpY2VzKHdpZHRoLCBoZWlnaHQsIGluZGljZXMsIDApOwogICAgICAgICAgVGVycmFpblByb3ZpZGVyLmFkZFNraXJ0SW5kaWNlcygKICAgICAgICAgICAgd2VzdEluZGljZXNTb3V0aFRvTm9ydGgsCiAgICAgICAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgICAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLAogICAgICAgICAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0LAogICAgICAgICAgICBncmlkVmVydGV4Q291bnQsCiAgICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICAgIGdyaWRJbmRleENvdW50CiAgICAgICAgICApOwogICAgICAgICAgaW5kaWNlc0FuZEVkZ2VzID0gYnlXaWR0aFtoZWlnaHRdID0gewogICAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwKICAgICAgICAgICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwKICAgICAgICAgICAgZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgICAgICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QsCiAgICAgICAgICAgIGluZGV4Q291bnRXaXRob3V0U2tpcnRzOiBncmlkSW5kZXhDb3VudAogICAgICAgICAgfTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGluZGljZXNBbmRFZGdlczsKICAgICAgfTsKICAgICAgVGVycmFpblByb3ZpZGVyLmdldFNraXJ0VmVydGV4Q291bnQgPSBmdW5jdGlvbih3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwgZWFzdEluZGljZXNOb3J0aFRvU291dGgsIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QpIHsKICAgICAgICByZXR1cm4gd2VzdEluZGljZXNTb3V0aFRvTm9ydGgubGVuZ3RoICsgc291dGhJbmRpY2VzRWFzdFRvV2VzdC5sZW5ndGggKyBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aC5sZW5ndGggKyBub3J0aEluZGljZXNXZXN0VG9FYXN0Lmxlbmd0aDsKICAgICAgfTsKICAgICAgVGVycmFpblByb3ZpZGVyLmdldFNraXJ0SW5kZXhDb3VudCA9IGZ1bmN0aW9uKHNraXJ0VmVydGV4Q291bnQpIHsKICAgICAgICByZXR1cm4gKHNraXJ0VmVydGV4Q291bnQgLSA0KSAqIDIgKiAzOwogICAgICB9OwogICAgICBUZXJyYWluUHJvdmlkZXIuZ2V0U2tpcnRJbmRleENvdW50V2l0aEZpbGxlZENvcm5lcnMgPSBmdW5jdGlvbihza2lydFZlcnRleENvdW50KSB7CiAgICAgICAgcmV0dXJuICgoc2tpcnRWZXJ0ZXhDb3VudCAtIDQpICogMiArIDQpICogMzsKICAgICAgfTsKICAgICAgVGVycmFpblByb3ZpZGVyLmFkZFNraXJ0SW5kaWNlcyA9IGZ1bmN0aW9uKHdlc3RJbmRpY2VzU291dGhUb05vcnRoLCBzb3V0aEluZGljZXNFYXN0VG9XZXN0LCBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCwgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdCwgdmVydGV4Q291bnQsIGluZGljZXMsIG9mZnNldCkgewogICAgICAgIGxldCB2ZXJ0ZXhJbmRleCA9IHZlcnRleENvdW50OwogICAgICAgIG9mZnNldCA9IGFkZFNraXJ0SW5kaWNlcygKICAgICAgICAgIHdlc3RJbmRpY2VzU291dGhUb05vcnRoLAogICAgICAgICAgdmVydGV4SW5kZXgsCiAgICAgICAgICBpbmRpY2VzLAogICAgICAgICAgb2Zmc2V0CiAgICAgICAgKTsKICAgICAgICB2ZXJ0ZXhJbmRleCArPSB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aC5sZW5ndGg7CiAgICAgICAgb2Zmc2V0ID0gYWRkU2tpcnRJbmRpY2VzKAogICAgICAgICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwKICAgICAgICAgIHZlcnRleEluZGV4LAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIG9mZnNldAogICAgICAgICk7CiAgICAgICAgdmVydGV4SW5kZXggKz0gc291dGhJbmRpY2VzRWFzdFRvV2VzdC5sZW5ndGg7CiAgICAgICAgb2Zmc2V0ID0gYWRkU2tpcnRJbmRpY2VzKAogICAgICAgICAgZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgICAgICB2ZXJ0ZXhJbmRleCwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBvZmZzZXQKICAgICAgICApOwogICAgICAgIHZlcnRleEluZGV4ICs9IGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLmxlbmd0aDsKICAgICAgICBhZGRTa2lydEluZGljZXMobm9ydGhJbmRpY2VzV2VzdFRvRWFzdCwgdmVydGV4SW5kZXgsIGluZGljZXMsIG9mZnNldCk7CiAgICAgIH07CiAgICAgIFRlcnJhaW5Qcm92aWRlci5hZGRTa2lydEluZGljZXNXaXRoRmlsbGVkQ29ybmVycyA9IGZ1bmN0aW9uKHdlc3RJbmRpY2VzU291dGhUb05vcnRoLCBzb3V0aEluZGljZXNFYXN0VG9XZXN0LCBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCwgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdCwgdmVydGV4Q291bnQsIGluZGljZXMsIG9mZnNldCkgewogICAgICAgIFRlcnJhaW5Qcm92aWRlci5hZGRTa2lydEluZGljZXMoCiAgICAgICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwKICAgICAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgICAgICBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCwKICAgICAgICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QsCiAgICAgICAgICB2ZXJ0ZXhDb3VudCwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBvZmZzZXQKICAgICAgICApOwogICAgICAgIGNvbnN0IHNraXJ0VmVydGV4Q291bnQgPSBUZXJyYWluUHJvdmlkZXIuZ2V0U2tpcnRWZXJ0ZXhDb3VudCgKICAgICAgICAgIHdlc3RJbmRpY2VzU291dGhUb05vcnRoLAogICAgICAgICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwKICAgICAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLAogICAgICAgICAgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdAogICAgICAgICk7CiAgICAgICAgY29uc3Qgc2tpcnRJbmRleENvdW50V2l0aG91dENhcHMgPSBUZXJyYWluUHJvdmlkZXIuZ2V0U2tpcnRJbmRleENvdW50KHNraXJ0VmVydGV4Q291bnQpOwogICAgICAgIGNvbnN0IGNvcm5lclN0YXJ0SWR4ID0gb2Zmc2V0ICsgc2tpcnRJbmRleENvdW50V2l0aG91dENhcHM7CiAgICAgICAgY29uc3QgY29ybmVyU1dJbmRleCA9IHdlc3RJbmRpY2VzU291dGhUb05vcnRoWzBdOwogICAgICAgIGNvbnN0IGNvcm5lck5XSW5kZXggPSBub3J0aEluZGljZXNXZXN0VG9FYXN0WzBdOwogICAgICAgIGNvbnN0IGNvcm5lck5FSW5kZXggPSBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aFswXTsKICAgICAgICBjb25zdCBjb3JuZXJTRUluZGV4ID0gc291dGhJbmRpY2VzRWFzdFRvV2VzdFswXTsKICAgICAgICBjb25zdCB3ZXN0U291dGhJbmRleCA9IHZlcnRleENvdW50OwogICAgICAgIGNvbnN0IHdlc3ROb3J0aEluZGV4ID0gd2VzdFNvdXRoSW5kZXggKyB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aC5sZW5ndGggLSAxOwogICAgICAgIGNvbnN0IHNvdXRoRWFzdEluZGV4ID0gd2VzdE5vcnRoSW5kZXggKyAxOwogICAgICAgIGNvbnN0IHNvdXRoV2VzdEluZGV4ID0gc291dGhFYXN0SW5kZXggKyBzb3V0aEluZGljZXNFYXN0VG9XZXN0Lmxlbmd0aCAtIDE7CiAgICAgICAgY29uc3QgZWFzdE5vcnRoSW5kZXggPSBzb3V0aFdlc3RJbmRleCArIDE7CiAgICAgICAgY29uc3QgZWFzdFNvdXRoSW5kZXggPSBlYXN0Tm9ydGhJbmRleCArIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLmxlbmd0aCAtIDE7CiAgICAgICAgY29uc3Qgbm9ydGhXZXN0SW5kZXggPSBlYXN0U291dGhJbmRleCArIDE7CiAgICAgICAgY29uc3Qgbm9ydGhFYXN0SW5kZXggPSBub3J0aFdlc3RJbmRleCArIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QubGVuZ3RoIC0gMTsKICAgICAgICBpbmRpY2VzW2Nvcm5lclN0YXJ0SWR4ICsgMF0gPSBjb3JuZXJTV0luZGV4OwogICAgICAgIGluZGljZXNbY29ybmVyU3RhcnRJZHggKyAxXSA9IHdlc3RTb3V0aEluZGV4OwogICAgICAgIGluZGljZXNbY29ybmVyU3RhcnRJZHggKyAyXSA9IHNvdXRoV2VzdEluZGV4OwogICAgICAgIGluZGljZXNbY29ybmVyU3RhcnRJZHggKyAzXSA9IGNvcm5lclNFSW5kZXg7CiAgICAgICAgaW5kaWNlc1tjb3JuZXJTdGFydElkeCArIDRdID0gc291dGhFYXN0SW5kZXg7CiAgICAgICAgaW5kaWNlc1tjb3JuZXJTdGFydElkeCArIDVdID0gZWFzdFNvdXRoSW5kZXg7CiAgICAgICAgaW5kaWNlc1tjb3JuZXJTdGFydElkeCArIDZdID0gY29ybmVyTkVJbmRleDsKICAgICAgICBpbmRpY2VzW2Nvcm5lclN0YXJ0SWR4ICsgN10gPSBlYXN0Tm9ydGhJbmRleDsKICAgICAgICBpbmRpY2VzW2Nvcm5lclN0YXJ0SWR4ICsgOF0gPSBub3J0aEVhc3RJbmRleDsKICAgICAgICBpbmRpY2VzW2Nvcm5lclN0YXJ0SWR4ICsgOV0gPSBjb3JuZXJOV0luZGV4OwogICAgICAgIGluZGljZXNbY29ybmVyU3RhcnRJZHggKyAxMF0gPSBub3J0aFdlc3RJbmRleDsKICAgICAgICBpbmRpY2VzW2Nvcm5lclN0YXJ0SWR4ICsgMTFdID0gd2VzdE5vcnRoSW5kZXg7CiAgICAgIH07CiAgICAgIFRlcnJhaW5Qcm92aWRlci5oZWlnaHRtYXBUZXJyYWluUXVhbGl0eSA9IDAuMjU7CiAgICAgIFRlcnJhaW5Qcm92aWRlci5nZXRFc3RpbWF0ZWRMZXZlbFplcm9HZW9tZXRyaWNFcnJvckZvckFIZWlnaHRtYXAgPSBmdW5jdGlvbihlbGxpcHNvaWQsIHRpbGVJbWFnZVdpZHRoLCBudW1iZXJPZlRpbGVzQXRMZXZlbFplcm8pIHsKICAgICAgICByZXR1cm4gZWxsaXBzb2lkLm1heGltdW1SYWRpdXMgKiAyICogTWF0aC5QSSAqIFRlcnJhaW5Qcm92aWRlci5oZWlnaHRtYXBUZXJyYWluUXVhbGl0eSAvICh0aWxlSW1hZ2VXaWR0aCAqIG51bWJlck9mVGlsZXNBdExldmVsWmVybyk7CiAgICAgIH07CiAgICAgIFRlcnJhaW5Qcm92aWRlci5wcm90b3R5cGUucmVxdWVzdFRpbGVHZW9tZXRyeSA9IERldmVsb3BlckVycm9yX2RlZmF1bHQudGhyb3dJbnN0YW50aWF0aW9uRXJyb3I7CiAgICAgIFRlcnJhaW5Qcm92aWRlci5wcm90b3R5cGUuZ2V0TGV2ZWxNYXhpbXVtR2VvbWV0cmljRXJyb3IgPSBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0LnRocm93SW5zdGFudGlhdGlvbkVycm9yOwogICAgICBUZXJyYWluUHJvdmlkZXIucHJvdG90eXBlLmdldFRpbGVEYXRhQXZhaWxhYmxlID0gRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdC50aHJvd0luc3RhbnRpYXRpb25FcnJvcjsKICAgICAgVGVycmFpblByb3ZpZGVyLnByb3RvdHlwZS5sb2FkVGlsZURhdGFBdmFpbGFiaWxpdHkgPSBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0LnRocm93SW5zdGFudGlhdGlvbkVycm9yOwogICAgICBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdCA9IFRlcnJhaW5Qcm92aWRlcjsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0Nlc2l1bTNEVGlsZXNUZXJyYWluR2VvbWV0cnlQcm9jZXNzb3IuanMKICBmdW5jdGlvbiBkZWNvZGVQb3NpdGlvbnMyKGdsdGYpIHsKICAgIGNvbnN0IHByaW1pdGl2ZSA9IGdsdGYubWVzaGVzWzBdLnByaW1pdGl2ZXNbMF07CiAgICBjb25zdCBhY2Nlc3NvciA9IGdsdGYuYWNjZXNzb3JzW3ByaW1pdGl2ZS5hdHRyaWJ1dGVzWyJQT1NJVElPTiJdXTsKICAgIGNvbnN0IGJ1ZmZlclZpZXcgPSBnbHRmLmJ1ZmZlclZpZXdzW2FjY2Vzc29yLmJ1ZmZlclZpZXddOwogICAgY29uc3QgcG9zaXRpb25Db3VudCA9IGFjY2Vzc29yLmNvdW50OwogICAgY29uc3QgYnVmZmVyVmlld01lc2hPcHQgPSBidWZmZXJWaWV3LmV4dGVuc2lvbnMgPyBidWZmZXJWaWV3LmV4dGVuc2lvbnNbIkVYVF9tZXNob3B0X2NvbXByZXNzaW9uIl0gOiB2b2lkIDA7CiAgICBpZiAoYnVmZmVyVmlld01lc2hPcHQgPT09IHZvaWQgMCkgewogICAgICBjb25zdCBidWZmZXIyID0gZ2x0Zi5idWZmZXJzW2J1ZmZlclZpZXcuYnVmZmVyXS5leHRyYXMuX3BpcGVsaW5lLnNvdXJjZTsKICAgICAgcmV0dXJuIG5ldyBGbG9hdDMyQXJyYXkoCiAgICAgICAgYnVmZmVyMi5idWZmZXIsCiAgICAgICAgYnVmZmVyMi5ieXRlT2Zmc2V0ICsgLy8gb2Zmc2V0IGZyb20gdGhlIHN0YXJ0IG9mIHRoZSBnbGIKICAgICAgICAoYnVmZmVyVmlldy5ieXRlT2Zmc2V0ID8/IDApICsgKGFjY2Vzc29yLmJ5dGVPZmZzZXQgPz8gMCksCiAgICAgICAgcG9zaXRpb25Db3VudCAqIDMKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IGJ1ZmZlciA9IGdsdGYuYnVmZmVyc1tidWZmZXJWaWV3TWVzaE9wdC5idWZmZXJdLmV4dHJhcy5fcGlwZWxpbmUuc291cmNlOwogICAgY29uc3QgY29tcHJlc3NlZEJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KAogICAgICBidWZmZXIuYnVmZmVyLAogICAgICBidWZmZXIuYnl0ZU9mZnNldCArIC8vIG9mZnNldCBmcm9tIHRoZSBzdGFydCBvZiB0aGUgZ2xiCiAgICAgIChidWZmZXJWaWV3TWVzaE9wdC5ieXRlT2Zmc2V0ID8/IDApICsgKGFjY2Vzc29yLmJ5dGVPZmZzZXQgPz8gMCksCiAgICAgIGJ1ZmZlclZpZXdNZXNoT3B0LmJ5dGVMZW5ndGgKICAgICk7CiAgICBjb25zdCBwb3NpdGlvbkJ5dGVMZW5ndGggPSBidWZmZXJWaWV3TWVzaE9wdC5ieXRlU3RyaWRlOwogICAgY29uc3QgUG9zaXRpb25UeXBlID0gcG9zaXRpb25CeXRlTGVuZ3RoID09PSA0ID8gVWludDhBcnJheSA6IFVpbnQxNkFycmF5OwogICAgY29uc3QgcG9zaXRpb25zUmVzdWx0ID0gbmV3IFBvc2l0aW9uVHlwZShwb3NpdGlvbkNvdW50ICogNCk7CiAgICBNZXNob3B0RGVjb2Rlci5kZWNvZGVWZXJ0ZXhCdWZmZXIoCiAgICAgIG5ldyBVaW50OEFycmF5KHBvc2l0aW9uc1Jlc3VsdC5idWZmZXIpLAogICAgICBwb3NpdGlvbkNvdW50LAogICAgICBwb3NpdGlvbkJ5dGVMZW5ndGgsCiAgICAgIGNvbXByZXNzZWRCdWZmZXIKICAgICk7CiAgICBjb25zdCBwb3NpdGlvblN0b3JhZ2VWYWx1ZU1heCA9ICgxIDw8IHBvc2l0aW9uc1Jlc3VsdC5CWVRFU19QRVJfRUxFTUVOVCAqIDgpIC0gMTsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBGbG9hdDMyQXJyYXkocG9zaXRpb25Db3VudCAqIDMpOwogICAgZm9yIChsZXQgcDIgPSAwOyBwMiA8IHBvc2l0aW9uQ291bnQ7IHAyKyspIHsKICAgICAgcG9zaXRpb25zW3AyICogMyArIDBdID0gcG9zaXRpb25zUmVzdWx0W3AyICogNCArIDBdIC8gcG9zaXRpb25TdG9yYWdlVmFsdWVNYXg7CiAgICAgIHBvc2l0aW9uc1twMiAqIDMgKyAxXSA9IHBvc2l0aW9uc1Jlc3VsdFtwMiAqIDQgKyAxXSAvIHBvc2l0aW9uU3RvcmFnZVZhbHVlTWF4OwogICAgICBwb3NpdGlvbnNbcDIgKiAzICsgMl0gPSBwb3NpdGlvbnNSZXN1bHRbcDIgKiA0ICsgMl0gLyBwb3NpdGlvblN0b3JhZ2VWYWx1ZU1heDsKICAgIH0KICAgIHJldHVybiBwb3NpdGlvbnM7CiAgfQogIGZ1bmN0aW9uIGRlY29kZU5vcm1hbHMoZ2x0ZikgewogICAgY29uc3QgcHJpbWl0aXZlID0gZ2x0Zi5tZXNoZXNbMF0ucHJpbWl0aXZlc1swXTsKICAgIGNvbnN0IGFjY2Vzc29yID0gZ2x0Zi5hY2Nlc3NvcnNbcHJpbWl0aXZlLmF0dHJpYnV0ZXNbIk5PUk1BTCJdXTsKICAgIGNvbnN0IGJ1ZmZlclZpZXcgPSBnbHRmLmJ1ZmZlclZpZXdzW2FjY2Vzc29yLmJ1ZmZlclZpZXddOwogICAgY29uc3Qgbm9ybWFsQ291bnQgPSBhY2Nlc3Nvci5jb3VudDsKICAgIGNvbnN0IGJ1ZmZlclZpZXdNZXNoT3B0ID0gYnVmZmVyVmlldy5leHRlbnNpb25zID8gYnVmZmVyVmlldy5leHRlbnNpb25zWyJFWFRfbWVzaG9wdF9jb21wcmVzc2lvbiJdIDogdm9pZCAwOwogICAgaWYgKGJ1ZmZlclZpZXdNZXNoT3B0ID09PSB2b2lkIDApIHsKICAgICAgY29uc3QgYnVmZmVyMiA9IGdsdGYuYnVmZmVyc1tidWZmZXJWaWV3LmJ1ZmZlcl0uZXh0cmFzLl9waXBlbGluZS5zb3VyY2U7CiAgICAgIHJldHVybiBuZXcgRmxvYXQzMkFycmF5KAogICAgICAgIGJ1ZmZlcjIuYnVmZmVyLAogICAgICAgIGJ1ZmZlcjIuYnl0ZU9mZnNldCArIC8vIG9mZnNldCBmcm9tIHRoZSBzdGFydCBvZiB0aGUgZ2xiCiAgICAgICAgKGJ1ZmZlclZpZXcuYnl0ZU9mZnNldCA/PyAwKSArIChhY2Nlc3Nvci5ieXRlT2Zmc2V0ID8/IDApLAogICAgICAgIG5vcm1hbENvdW50ICogMwogICAgICApOwogICAgfQogICAgY29uc3QgYnVmZmVyID0gZ2x0Zi5idWZmZXJzW2J1ZmZlclZpZXdNZXNoT3B0LmJ1ZmZlcl0uZXh0cmFzLl9waXBlbGluZS5zb3VyY2U7CiAgICBjb25zdCBjb21wcmVzc2VkQnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkoCiAgICAgIGJ1ZmZlci5idWZmZXIsCiAgICAgIGJ1ZmZlci5ieXRlT2Zmc2V0ICsgLy8gb2Zmc2V0IGZyb20gdGhlIHN0YXJ0IG9mIHRoZSBnbGIKICAgICAgKGJ1ZmZlclZpZXdNZXNoT3B0LmJ5dGVPZmZzZXQgPz8gMCkgKyAoYWNjZXNzb3IuYnl0ZU9mZnNldCA/PyAwKSwKICAgICAgYnVmZmVyVmlld01lc2hPcHQuYnl0ZUxlbmd0aAogICAgKTsKICAgIGNvbnN0IG5vcm1hbEJ5dGVMZW5ndGggPSBidWZmZXJWaWV3TWVzaE9wdC5ieXRlU3RyaWRlOwogICAgY29uc3Qgbm9ybWFsc1Jlc3VsdCA9IG5ldyBJbnQ4QXJyYXkobm9ybWFsQ291bnQgKiBub3JtYWxCeXRlTGVuZ3RoKTsKICAgIE1lc2hvcHREZWNvZGVyLmRlY29kZVZlcnRleEJ1ZmZlcigKICAgICAgbmV3IFVpbnQ4QXJyYXkobm9ybWFsc1Jlc3VsdC5idWZmZXIpLAogICAgICBub3JtYWxDb3VudCwKICAgICAgbm9ybWFsQnl0ZUxlbmd0aCwKICAgICAgY29tcHJlc3NlZEJ1ZmZlcgogICAgKTsKICAgIGNvbnN0IG5vcm1hbHMgPSBuZXcgRmxvYXQzMkFycmF5KG5vcm1hbENvdW50ICogMyk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbm9ybWFsQ291bnQ7IGkyKyspIHsKICAgICAgbGV0IG9jdFggPSBNYXRoLm1heChub3JtYWxzUmVzdWx0W2kyICogNCArIDBdIC8gMTI3LCAtMSk7CiAgICAgIGxldCBvY3RZID0gTWF0aC5tYXgobm9ybWFsc1Jlc3VsdFtpMiAqIDQgKyAxXSAvIDEyNywgLTEpOwogICAgICBjb25zdCBvY3RaID0gMSAtIChNYXRoLmFicyhvY3RYKSArIE1hdGguYWJzKG9jdFkpKTsKICAgICAgaWYgKG9jdFogPCAwKSB7CiAgICAgICAgY29uc3Qgb2xkWCA9IG9jdFg7CiAgICAgICAgY29uc3Qgb2xkWSA9IG9jdFk7CiAgICAgICAgb2N0WCA9ICgxIC0gTWF0aC5hYnMob2xkWSkpICogTWF0aF9kZWZhdWx0LnNpZ25Ob3RaZXJvKG9sZFgpOwogICAgICAgIG9jdFkgPSAoMSAtIE1hdGguYWJzKG9sZFgpKSAqIE1hdGhfZGVmYXVsdC5zaWduTm90WmVybyhvbGRZKTsKICAgICAgfQogICAgICBsZXQgbm9ybWFsMiA9IHNjcmF0Y2hOb3JtYWw4OwogICAgICBub3JtYWwyLnggPSBvY3RYOwogICAgICBub3JtYWwyLnkgPSBvY3RZOwogICAgICBub3JtYWwyLnogPSBvY3RaOwogICAgICBub3JtYWwyID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShub3JtYWwyLCBzY3JhdGNoTm9ybWFsOCk7CiAgICAgIG5vcm1hbHNbaTIgKiAzICsgMF0gPSBub3JtYWwyLng7CiAgICAgIG5vcm1hbHNbaTIgKiAzICsgMV0gPSBub3JtYWwyLnk7CiAgICAgIG5vcm1hbHNbaTIgKiAzICsgMl0gPSBub3JtYWwyLno7CiAgICB9CiAgICByZXR1cm4gbm9ybWFsczsKICB9CiAgZnVuY3Rpb24gZGVjb2RlSW5kaWNlcyhnbHRmKSB7CiAgICBjb25zdCBwcmltaXRpdmUgPSBnbHRmLm1lc2hlc1swXS5wcmltaXRpdmVzWzBdOwogICAgY29uc3QgYWNjZXNzb3IgPSBnbHRmLmFjY2Vzc29yc1twcmltaXRpdmUuaW5kaWNlc107CiAgICBjb25zdCBidWZmZXJWaWV3ID0gZ2x0Zi5idWZmZXJWaWV3c1thY2Nlc3Nvci5idWZmZXJWaWV3XTsKICAgIGNvbnN0IGluZGV4Q291bnQgPSBhY2Nlc3Nvci5jb3VudDsKICAgIGNvbnN0IFNpemVkSW5kZXhUeXBlID0gYWNjZXNzb3IuY29tcG9uZW50VHlwZSA9PT0gQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9TSE9SVCA/IFVpbnQxNkFycmF5IDogVWludDMyQXJyYXk7CiAgICBjb25zdCBidWZmZXJWaWV3TWVzaE9wdCA9IGJ1ZmZlclZpZXcuZXh0ZW5zaW9ucyA/IGJ1ZmZlclZpZXcuZXh0ZW5zaW9uc1siRVhUX21lc2hvcHRfY29tcHJlc3Npb24iXSA6IHZvaWQgMDsKICAgIGlmIChidWZmZXJWaWV3TWVzaE9wdCA9PT0gdm9pZCAwKSB7CiAgICAgIGNvbnN0IGJ1ZmZlcjIgPSBnbHRmLmJ1ZmZlcnNbYnVmZmVyVmlldy5idWZmZXJdLmV4dHJhcy5fcGlwZWxpbmUuc291cmNlOwogICAgICByZXR1cm4gbmV3IFNpemVkSW5kZXhUeXBlKAogICAgICAgIGJ1ZmZlcjIuYnVmZmVyLAogICAgICAgIGJ1ZmZlcjIuYnl0ZU9mZnNldCArIC8vIG9mZnNldCBmcm9tIHRoZSBnbGIKICAgICAgICAoYnVmZmVyVmlldy5ieXRlT2Zmc2V0ID8/IDApICsgKGFjY2Vzc29yLmJ5dGVPZmZzZXQgPz8gMCksCiAgICAgICAgaW5kZXhDb3VudAogICAgICApOwogICAgfQogICAgY29uc3QgYnVmZmVyID0gZ2x0Zi5idWZmZXJzW2J1ZmZlclZpZXdNZXNoT3B0LmJ1ZmZlcl0uZXh0cmFzLl9waXBlbGluZS5zb3VyY2U7CiAgICBjb25zdCBjb21wcmVzc2VkQnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkoCiAgICAgIGJ1ZmZlci5idWZmZXIsCiAgICAgIGJ1ZmZlci5ieXRlT2Zmc2V0ICsgLy8gb2Zmc2V0IGZyb20gdGhlIHN0YXJ0IG9mIHRoZSBnbGIKICAgICAgKGJ1ZmZlclZpZXdNZXNoT3B0LmJ5dGVPZmZzZXQgPz8gMCkgKyAoYWNjZXNzb3IuYnl0ZU9mZnNldCA/PyAwKSwKICAgICAgYnVmZmVyVmlld01lc2hPcHQuYnl0ZUxlbmd0aAogICAgKTsKICAgIGNvbnN0IGluZGljZXMgPSBuZXcgU2l6ZWRJbmRleFR5cGUoaW5kZXhDb3VudCk7CiAgICBNZXNob3B0RGVjb2Rlci5kZWNvZGVJbmRleEJ1ZmZlcigKICAgICAgbmV3IFVpbnQ4QXJyYXkoaW5kaWNlcy5idWZmZXIpLAogICAgICBpbmRleENvdW50LAogICAgICBidWZmZXJWaWV3TWVzaE9wdC5ieXRlU3RyaWRlLAogICAgICBjb21wcmVzc2VkQnVmZmVyCiAgICApOwogICAgcmV0dXJuIGluZGljZXM7CiAgfQogIGZ1bmN0aW9uIGRlY29kZUVkZ2VJbmRpY2VzKGdsdGYsIG5hbWUpIHsKICAgIGNvbnN0IHByaW1pdGl2ZSA9IGdsdGYubWVzaGVzWzBdLnByaW1pdGl2ZXNbMF07CiAgICBjb25zdCBhY2Nlc3NvciA9IGdsdGYuYWNjZXNzb3JzW3ByaW1pdGl2ZS5leHRlbnNpb25zLkNFU0lVTV90aWxlX2VkZ2VzW25hbWVdXTsKICAgIGNvbnN0IGJ1ZmZlclZpZXcgPSBnbHRmLmJ1ZmZlclZpZXdzW2FjY2Vzc29yLmJ1ZmZlclZpZXddOwogICAgY29uc3QgaW5kZXhDb3VudCA9IGFjY2Vzc29yLmNvdW50OwogICAgY29uc3QgU2l6ZWRJbmRleFR5cGUgPSBhY2Nlc3Nvci5jb21wb25lbnRUeXBlID09PSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX1NIT1JUID8gVWludDE2QXJyYXkgOiBVaW50MzJBcnJheTsKICAgIGNvbnN0IGJ1ZmZlclZpZXdNZXNoT3B0ID0gYnVmZmVyVmlldy5leHRlbnNpb25zID8gYnVmZmVyVmlldy5leHRlbnNpb25zWyJFWFRfbWVzaG9wdF9jb21wcmVzc2lvbiJdIDogdm9pZCAwOwogICAgaWYgKGJ1ZmZlclZpZXdNZXNoT3B0ID09PSB2b2lkIDApIHsKICAgICAgY29uc3QgYnVmZmVyMiA9IGdsdGYuYnVmZmVyc1tidWZmZXJWaWV3LmJ1ZmZlcl0uZXh0cmFzLl9waXBlbGluZS5zb3VyY2U7CiAgICAgIHJldHVybiBuZXcgU2l6ZWRJbmRleFR5cGUoCiAgICAgICAgYnVmZmVyMi5idWZmZXIsCiAgICAgICAgYnVmZmVyMi5ieXRlT2Zmc2V0ICsgLy8gb2Zmc2V0IGZyb20gdGhlIGdsYgogICAgICAgIChidWZmZXJWaWV3LmJ5dGVPZmZzZXQgPz8gMCkgKyAoYWNjZXNzb3IuYnl0ZU9mZnNldCA/PyAwKSwKICAgICAgICBpbmRleENvdW50CiAgICAgICk7CiAgICB9CiAgICBjb25zdCBidWZmZXIgPSBnbHRmLmJ1ZmZlcnNbYnVmZmVyVmlld01lc2hPcHQuYnVmZmVyXS5leHRyYXMuX3BpcGVsaW5lLnNvdXJjZTsKICAgIGNvbnN0IGNvbXByZXNzZWRCdWZmZXIgPSBuZXcgVWludDhBcnJheSgKICAgICAgYnVmZmVyLmJ1ZmZlciwKICAgICAgYnVmZmVyLmJ5dGVPZmZzZXQgKyAvLyBvZmZzZXQgZnJvbSB0aGUgc3RhcnQgb2YgdGhlIGdsYgogICAgICAoYnVmZmVyVmlld01lc2hPcHQuYnl0ZU9mZnNldCA/PyAwKSArIChhY2Nlc3Nvci5ieXRlT2Zmc2V0ID8/IDApLAogICAgICBidWZmZXJWaWV3TWVzaE9wdC5ieXRlTGVuZ3RoCiAgICApOwogICAgY29uc3QgaW5kaWNlcyA9IG5ldyBTaXplZEluZGV4VHlwZShpbmRleENvdW50KTsKICAgIGNvbnN0IGluZGV4Qnl0ZUxlbmd0aCA9IGJ1ZmZlclZpZXdNZXNoT3B0LmJ5dGVTdHJpZGU7CiAgICBNZXNob3B0RGVjb2Rlci5kZWNvZGVJbmRleFNlcXVlbmNlKAogICAgICBuZXcgVWludDhBcnJheShpbmRpY2VzLmJ1ZmZlciksCiAgICAgIGluZGV4Q291bnQsCiAgICAgIGluZGV4Qnl0ZUxlbmd0aCwKICAgICAgY29tcHJlc3NlZEJ1ZmZlcgogICAgKTsKICAgIHJldHVybiBpbmRpY2VzOwogIH0KICBmdW5jdGlvbiBkZWNvZGVHbHRmKGdsdGYsIGhhc05vcm1hbHMsIHJlc3VsdCkgewogICAgcmVzdWx0LnBvc2l0aW9ucyA9IGRlY29kZVBvc2l0aW9uczIoZ2x0Zik7CiAgICByZXN1bHQubm9ybWFscyA9IGhhc05vcm1hbHMgPyBkZWNvZGVOb3JtYWxzKGdsdGYpIDogdm9pZCAwOwogICAgcmVzdWx0LmluZGljZXMgPSBkZWNvZGVJbmRpY2VzKGdsdGYpOwogICAgcmVzdWx0LmVkZ2VJbmRpY2VzV2VzdCA9IGRlY29kZUVkZ2VJbmRpY2VzKGdsdGYsICJsZWZ0Iik7CiAgICByZXN1bHQuZWRnZUluZGljZXNTb3V0aCA9IGRlY29kZUVkZ2VJbmRpY2VzKGdsdGYsICJib3R0b20iKTsKICAgIHJlc3VsdC5lZGdlSW5kaWNlc0Vhc3QgPSBkZWNvZGVFZGdlSW5kaWNlcyhnbHRmLCAicmlnaHQiKTsKICAgIHJlc3VsdC5lZGdlSW5kaWNlc05vcnRoID0gZGVjb2RlRWRnZUluZGljZXMoZ2x0ZiwgInRvcCIpOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgZnVuY3Rpb24gYWRkU2tpcnRzVG9NZXNoKG1lc2gsIHJlY3RhbmdsZSwgZWxsaXBzb2lkLCBlbnVNaW5pbXVtLCBlbnVNYXhpbXVtLCBlbnVUb0VjZWYsIGVjZWZUb0VudSwgc2tpcnRIZWlnaHQpIHsKICAgIGNvbnN0IHsgZW5jb2RpbmcgfSA9IG1lc2g7CiAgICBjb25zdCB2ZXJ0ZXhTdHJpZGUgPSBlbmNvZGluZy5zdHJpZGU7CiAgICBjb25zdCB2ZXJ0ZXhCdWZmZXIgPSBtZXNoLnZlcnRpY2VzOwogICAgY29uc3QgewogICAgICBoYXNWZXJ0ZXhOb3JtYWxzLAogICAgICBoYXNXZWJNZXJjYXRvclQsCiAgICAgIGV4YWdnZXJhdGlvbiwKICAgICAgZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQKICAgIH0gPSBlbmNvZGluZzsKICAgIGNvbnN0IGhhc0V4YWdnZXJhdGlvbiA9IGV4YWdnZXJhdGlvbiAhPT0gMTsKICAgIGNvbnN0IGhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBoYXNFeGFnZ2VyYXRpb247CiAgICBjb25zdCB2ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMgPSBtZXNoLnZlcnRleENvdW50V2l0aG91dFNraXJ0czsKICAgIGxldCB2ZXJ0ZXhCdWZmZXJPZmZzZXQgPSB2ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMgKiB2ZXJ0ZXhTdHJpZGU7CiAgICBjb25zdCB2ZXJ0ZXhDb3VudFdpdGhTa2lydHMgPSB2ZXJ0ZXhCdWZmZXIubGVuZ3RoIC8gdmVydGV4U3RyaWRlOwogICAgY29uc3Qgc2tpcnRWZXJ0ZXhDb3VudCA9IHZlcnRleENvdW50V2l0aFNraXJ0cyAtIHZlcnRleENvdW50V2l0aG91dFNraXJ0czsKICAgIGNvbnN0IGluZGljZXMgPSBtZXNoLmluZGljZXM7CiAgICBjb25zdCBpbmRleENvdW50V2l0aG91dFNraXJ0cyA9IG1lc2guaW5kZXhDb3VudFdpdGhvdXRTa2lydHM7CiAgICBjb25zdCB3ZXN0SW5kaWNlcyA9IG1lc2gud2VzdEluZGljZXNTb3V0aFRvTm9ydGg7CiAgICBjb25zdCBzb3V0aEluZGljZXMgPSBtZXNoLnNvdXRoSW5kaWNlc0Vhc3RUb1dlc3Q7CiAgICBjb25zdCBlYXN0SW5kaWNlcyA9IG1lc2guZWFzdEluZGljZXNOb3J0aFRvU291dGg7CiAgICBjb25zdCBub3J0aEluZGljZXMgPSBtZXNoLm5vcnRoSW5kaWNlc1dlc3RUb0Vhc3Q7CiAgICBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdC5hZGRTa2lydEluZGljZXNXaXRoRmlsbGVkQ29ybmVycygKICAgICAgd2VzdEluZGljZXMsCiAgICAgIHNvdXRoSW5kaWNlcywKICAgICAgZWFzdEluZGljZXMsCiAgICAgIG5vcnRoSW5kaWNlcywKICAgICAgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzLAogICAgICBpbmRpY2VzLAogICAgICBpbmRleENvdW50V2l0aG91dFNraXJ0cwogICAgKTsKICAgIGNvbnN0IHdlc3RPZmZzZXQgPSAwOwogICAgY29uc3Qgc291dGhPZmZzZXQgPSB3ZXN0T2Zmc2V0ICsgd2VzdEluZGljZXMubGVuZ3RoOwogICAgY29uc3QgZWFzdE9mZnNldCA9IHNvdXRoT2Zmc2V0ICsgc291dGhJbmRpY2VzLmxlbmd0aDsKICAgIGNvbnN0IG5vcnRoT2Zmc2V0ID0gZWFzdE9mZnNldCArIGVhc3RJbmRpY2VzLmxlbmd0aDsKICAgIGNvbnN0IGVkZ2VzID0gW3dlc3RJbmRpY2VzLCBzb3V0aEluZGljZXMsIGVhc3RJbmRpY2VzLCBub3J0aEluZGljZXNdOwogICAgY29uc3QgZWRnZUluZGV4T2Zmc2V0ID0gW3dlc3RPZmZzZXQsIHNvdXRoT2Zmc2V0LCBlYXN0T2Zmc2V0LCBub3J0aE9mZnNldF07CiAgICBjb25zdCBlZGdlTG9uZ2l0dWRlU2lnbiA9IFstMSwgMCwgMSwgMF07CiAgICBjb25zdCBlZGdlTGF0aXR1ZGVTaWduID0gWzAsIC0xLCAwLCAxXTsKICAgIGNvbnN0IG1pbmltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgIGVudU1pbmltdW0sCiAgICAgIHNjcmF0Y2hNaW5pbXVtUG9zaXRpb25FTlVTa2lydAogICAgKTsKICAgIGNvbnN0IG1heGltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUoCiAgICAgIGVudU1heGltdW0sCiAgICAgIHNjcmF0Y2hNYXhpbXVtUG9zaXRpb25FTlVTa2lydAogICAgKTsKICAgIGNvbnN0IG1heGltdW1IZWlnaHQgPSBtZXNoLm1heGltdW1IZWlnaHQ7CiAgICBjb25zdCBtaW5pbXVtSGVpZ2h0V2l0aFNraXJ0cyA9IG1lc2gubWluaW11bUhlaWdodCAtIHNraXJ0SGVpZ2h0OwogICAgZm9yIChsZXQgc2tpcnRJZCA9IDA7IHNraXJ0SWQgPCBza2lydFZlcnRleENvdW50OyBza2lydElkKyspIHsKICAgICAgbGV0IHNpZGU7CiAgICAgIGZvciAoc2lkZSA9IDA7IHNpZGUgPCAzOyBzaWRlKyspIHsKICAgICAgICBpZiAoc2tpcnRJZCA8IGVkZ2VJbmRleE9mZnNldFtzaWRlICsgMV0pIHsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgICBjb25zdCB2ZXJ0ZXhJbmRleCA9IGVkZ2VzW3NpZGVdW3NraXJ0SWQgLSBlZGdlSW5kZXhPZmZzZXRbc2lkZV1dOwogICAgICBjb25zdCB1diA9IGVuY29kaW5nLmRlY29kZVRleHR1cmVDb29yZGluYXRlcygKICAgICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgICAgdmVydGV4SW5kZXgsCiAgICAgICAgc2NyYXRjaFVWU2tpcnQKICAgICAgKTsKICAgICAgY29uc3Qgc2tpcnRMb25MYXRPZmZzZXRQZXJjZW50ID0gMWUtNDsKICAgICAgY29uc3QgbG9uZ2l0dWRlVCA9IHV2LnggKyBlZGdlTG9uZ2l0dWRlU2lnbltzaWRlXSAqIHNraXJ0TG9uTGF0T2Zmc2V0UGVyY2VudDsKICAgICAgY29uc3QgbGF0aXR1ZGVUID0gdXYueSArIGVkZ2VMYXRpdHVkZVNpZ25bc2lkZV0gKiBza2lydExvbkxhdE9mZnNldFBlcmNlbnQ7CiAgICAgIGNvbnN0IGxvbmdpdHVkZSA9IE1hdGhfZGVmYXVsdC5sZXJwKAogICAgICAgIHJlY3RhbmdsZS53ZXN0LAogICAgICAgIHJlY3RhbmdsZS5lYXN0LAogICAgICAgIGxvbmdpdHVkZVQKICAgICAgKTsKICAgICAgY29uc3QgbGF0aXR1ZGUgPSBNYXRoX2RlZmF1bHQuY2xhbXAoCiAgICAgICAgTWF0aF9kZWZhdWx0LmxlcnAocmVjdGFuZ2xlLnNvdXRoLCByZWN0YW5nbGUubm9ydGgsIGxhdGl0dWRlVCksCiAgICAgICAgLU1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTywKICAgICAgICArTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPCiAgICAgICk7CiAgICAgIGNvbnN0IHZlcnRIZWlnaHQgPSBlbmNvZGluZy5kZWNvZGVIZWlnaHQodmVydGV4QnVmZmVyLCB2ZXJ0ZXhJbmRleCk7CiAgICAgIGNvbnN0IGhlaWdodCA9IHZlcnRIZWlnaHQgLSBza2lydEhlaWdodDsKICAgICAgY29uc3QgY2FydG9ncmFwaGljMiA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21SYWRpYW5zKAogICAgICAgIGxvbmdpdHVkZSwKICAgICAgICBsYXRpdHVkZSwKICAgICAgICBoZWlnaHQsCiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpY1NraXJ0CiAgICAgICk7CiAgICAgIGNvbnN0IHBvc2l0aW9uRWNlZiA9IENhcnRvZ3JhcGhpY19kZWZhdWx0LnRvQ2FydGVzaWFuKAogICAgICAgIGNhcnRvZ3JhcGhpYzIsCiAgICAgICAgZWxsaXBzb2lkLAogICAgICAgIHNjcmF0Y2hQb3NFY2VmU2tpcnQKICAgICAgKTsKICAgICAgbGV0IG5vcm1hbE9jdDsKICAgICAgaWYgKGhhc1ZlcnRleE5vcm1hbHMpIHsKICAgICAgICBub3JtYWxPY3QgPSBlbmNvZGluZy5nZXRPY3RFbmNvZGVkTm9ybWFsKAogICAgICAgICAgdmVydGV4QnVmZmVyLAogICAgICAgICAgdmVydGV4SW5kZXgsCiAgICAgICAgICBzY3JhdGNoTm9ybWFsT2N0U2tpcnQKICAgICAgICApOwogICAgICB9CiAgICAgIGxldCB3ZWJNZXJjYXRvclQ7CiAgICAgIGlmIChoYXNXZWJNZXJjYXRvclQpIHsKICAgICAgICB3ZWJNZXJjYXRvclQgPSBlbmNvZGluZy5kZWNvZGVXZWJNZXJjYXRvclQodmVydGV4QnVmZmVyLCB2ZXJ0ZXhJbmRleCk7CiAgICAgIH0KICAgICAgbGV0IGdlb2RldGljU3VyZmFjZU5vcm1hbDsKICAgICAgaWYgKGhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgcG9zaXRpb25FY2VmLAogICAgICAgICAgc2NyYXRjaEdlb2RldGljU3VyZmFjZU5vcm1hbFNraXJ0CiAgICAgICAgKTsKICAgICAgfQogICAgICB2ZXJ0ZXhCdWZmZXJPZmZzZXQgPSBlbmNvZGluZy5lbmNvZGUoCiAgICAgICAgdmVydGV4QnVmZmVyLAogICAgICAgIHZlcnRleEJ1ZmZlck9mZnNldCwKICAgICAgICBwb3NpdGlvbkVjZWYsCiAgICAgICAgdXYsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIG5vcm1hbE9jdCwKICAgICAgICB3ZWJNZXJjYXRvclQsCiAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsCiAgICAgICk7CiAgICAgIGNvbnN0IHBvc2l0aW9uRU5VID0gTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCgKICAgICAgICBlY2VmVG9FbnUsCiAgICAgICAgcG9zaXRpb25FY2VmLAogICAgICAgIHNjcmF0Y2hQb3NFbnVTa2lydAogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWluaW11bUJ5Q29tcG9uZW50KAogICAgICAgIHBvc2l0aW9uRU5VLAogICAgICAgIG1pbmltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMsCiAgICAgICAgbWluaW11bVBvc2l0aW9uRU5VV2l0aFNraXJ0cwogICAgICApOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWF4aW11bUJ5Q29tcG9uZW50KAogICAgICAgIHBvc2l0aW9uRU5VLAogICAgICAgIG1heGltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMsCiAgICAgICAgbWF4aW11bVBvc2l0aW9uRU5VV2l0aFNraXJ0cwogICAgICApOwogICAgfQogICAgY29uc3QgYWFiYkVudVdpdGhTa2lydHMgPSBBeGlzQWxpZ25lZEJvdW5kaW5nQm94X2RlZmF1bHQuZnJvbUNvcm5lcnMoCiAgICAgIG1pbmltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMsCiAgICAgIG1heGltdW1Qb3NpdGlvbkVOVVdpdGhTa2lydHMsCiAgICAgIHNjcmF0Y2hBQUJCRW51U2tpcnQKICAgICk7CiAgICBjb25zdCBlbmNvZGluZ1dpdGhTa2lydHMgPSBuZXcgVGVycmFpbkVuY29kaW5nX2RlZmF1bHQoCiAgICAgIGVuY29kaW5nLmNlbnRlciwKICAgICAgYWFiYkVudVdpdGhTa2lydHMsCiAgICAgIG1pbmltdW1IZWlnaHRXaXRoU2tpcnRzLAogICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICBlbnVUb0VjZWYsCiAgICAgIGVuY29kaW5nLmhhc1ZlcnRleE5vcm1hbHMsCiAgICAgIGVuY29kaW5nLmhhc1dlYk1lcmNhdG9yVCwKICAgICAgaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgZXhhZ2dlcmF0aW9uLAogICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgKTsKICAgIGlmIChlbmNvZGluZy5xdWFudGl6YXRpb24gIT09IGVuY29kaW5nV2l0aFNraXJ0cy5xdWFudGl6YXRpb24pIHsKICAgICAgY29uc3QgZmluYWxFbmNvZGluZyA9IGVuY29kaW5nV2l0aFNraXJ0czsKICAgICAgY29uc3QgZmluYWxWZXJ0ZXhTdHJpZGUgPSBmaW5hbEVuY29kaW5nLnN0cmlkZTsKICAgICAgY29uc3QgZmluYWxWZXJ0ZXhCdWZmZXIgPSBuZXcgRmxvYXQzMkFycmF5KAogICAgICAgIHZlcnRleENvdW50V2l0aFNraXJ0cyAqIGZpbmFsVmVydGV4U3RyaWRlCiAgICAgICk7CiAgICAgIGxldCBmaW5hbFZlcnRleEJ1ZmZlck9mZnNldCA9IDA7CiAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudFdpdGhTa2lydHM7IGkyKyspIHsKICAgICAgICBmaW5hbFZlcnRleEJ1ZmZlck9mZnNldCA9IGZpbmFsRW5jb2RpbmcuZW5jb2RlKAogICAgICAgICAgZmluYWxWZXJ0ZXhCdWZmZXIsCiAgICAgICAgICBmaW5hbFZlcnRleEJ1ZmZlck9mZnNldCwKICAgICAgICAgIGVuY29kaW5nLmRlY29kZVBvc2l0aW9uKHZlcnRleEJ1ZmZlciwgaTIsIHNjcmF0Y2hQb3NFY2VmU2tpcnQpLAogICAgICAgICAgZW5jb2RpbmcuZGVjb2RlVGV4dHVyZUNvb3JkaW5hdGVzKHZlcnRleEJ1ZmZlciwgaTIsIHNjcmF0Y2hVVlNraXJ0KSwKICAgICAgICAgIGVuY29kaW5nLmRlY29kZUhlaWdodCh2ZXJ0ZXhCdWZmZXIsIGkyKSwKICAgICAgICAgIGVuY29kaW5nLmhhc1ZlcnRleE5vcm1hbHMgPyBlbmNvZGluZy5nZXRPY3RFbmNvZGVkTm9ybWFsKHZlcnRleEJ1ZmZlciwgaTIsIHNjcmF0Y2hOb3JtYWxPY3RTa2lydCkgOiB2b2lkIDAsCiAgICAgICAgICBlbmNvZGluZy5oYXNXZWJNZXJjYXRvclQgPyBlbmNvZGluZy5kZWNvZGVXZWJNZXJjYXRvclQodmVydGV4QnVmZmVyLCBpMikgOiB2b2lkIDAsCiAgICAgICAgICBlbmNvZGluZy5oYXNHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID8gZW5jb2RpbmcuZGVjb2RlR2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgICAgICAgIGkyLAogICAgICAgICAgICBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsU2tpcnQKICAgICAgICAgICkgOiB2b2lkIDAKICAgICAgICApOwogICAgICB9CiAgICAgIG1lc2gudmVydGljZXMgPSBmaW5hbFZlcnRleEJ1ZmZlcjsKICAgICAgbWVzaC5zdHJpZGUgPSBmaW5hbFZlcnRleFN0cmlkZTsKICAgICAgbWVzaC5lbmNvZGluZyA9IGZpbmFsRW5jb2Rpbmc7CiAgICB9CiAgICByZXR1cm4gbWVzaDsKICB9CiAgZnVuY3Rpb24gaW5zaWRlKGJveE1pbmltdW0sIGJveE1heGltdW0sIGVkZ2VJZCwgcDIpIHsKICAgIHN3aXRjaCAoZWRnZUlkKSB7CiAgICAgIGNhc2UgRURHRV9JRF9MRUZUOgogICAgICAgIHJldHVybiBNYXRoX2RlZmF1bHQuc2lnbihwMi54IC0gYm94TWluaW11bS54KTsKICAgICAgY2FzZSBFREdFX0lEX1JJR0hUOgogICAgICAgIHJldHVybiBNYXRoX2RlZmF1bHQuc2lnbihib3hNYXhpbXVtLnggLSBwMi54KTsKICAgICAgY2FzZSBFREdFX0lEX0JPVFRPTToKICAgICAgICByZXR1cm4gTWF0aF9kZWZhdWx0LnNpZ24ocDIueSAtIGJveE1pbmltdW0ueSk7CiAgICAgIGRlZmF1bHQ6CiAgICAgICAgcmV0dXJuIE1hdGhfZGVmYXVsdC5zaWduKGJveE1heGltdW0ueSAtIHAyLnkpOwogICAgfQogIH0KICBmdW5jdGlvbiBpbnRlcnNlY3QoYm94TWluaW11bSwgYm94TWF4aW11bSwgZWRnZUlkLCBhNCwgYjIsIHJlc3VsdCkgewogICAgbGV0IHQyLCBpbnRlcnNlY3RYLCBpbnRlcnNlY3RZOwogICAgc3dpdGNoIChlZGdlSWQpIHsKICAgICAgY2FzZSBFREdFX0lEX0xFRlQ6CiAgICAgICAgdDIgPSAoYm94TWluaW11bS54IC0gYTQueCkgLyAoYjIueCAtIGE0LngpOwogICAgICAgIGludGVyc2VjdFggPSBib3hNaW5pbXVtLng7CiAgICAgICAgaW50ZXJzZWN0WSA9IGE0LnkgKyAoYjIueSAtIGE0LnkpICogdDI7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgRURHRV9JRF9SSUdIVDoKICAgICAgICB0MiA9IChib3hNYXhpbXVtLnggLSBhNC54KSAvIChiMi54IC0gYTQueCk7CiAgICAgICAgaW50ZXJzZWN0WCA9IGJveE1heGltdW0ueDsKICAgICAgICBpbnRlcnNlY3RZID0gYTQueSArIChiMi55IC0gYTQueSkgKiB0MjsKICAgICAgICBicmVhazsKICAgICAgY2FzZSBFREdFX0lEX0JPVFRPTToKICAgICAgICB0MiA9IChib3hNaW5pbXVtLnkgLSBhNC55KSAvIChiMi55IC0gYTQueSk7CiAgICAgICAgaW50ZXJzZWN0WCA9IGE0LnggKyAoYjIueCAtIGE0LngpICogdDI7CiAgICAgICAgaW50ZXJzZWN0WSA9IGJveE1pbmltdW0ueTsKICAgICAgICBicmVhazsKICAgICAgZGVmYXVsdDoKICAgICAgICB0MiA9IChib3hNYXhpbXVtLnkgLSBhNC55KSAvIChiMi55IC0gYTQueSk7CiAgICAgICAgaW50ZXJzZWN0WCA9IGE0LnggKyAoYjIueCAtIGE0LngpICogdDI7CiAgICAgICAgaW50ZXJzZWN0WSA9IGJveE1heGltdW0ueTsKICAgICAgICBicmVhazsKICAgIH0KICAgIHJldHVybiBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKGludGVyc2VjdFgsIGludGVyc2VjdFksIHQyLCByZXN1bHQpOwogIH0KICBmdW5jdGlvbiBjbGlwVHJpYW5nbGVBZ2FpbnN0Qm94RWRnZVJhbmdlKGVkZ2VTdGFydCwgZWRnZUNvdW50LCBib3hNaW5pbXVtLCBib3hNYXhpbXVtLCBwMCwgcDEsIHAyLCByZXN1bHQpIHsKICAgIGxldCBpbnB1dExlbmd0aDsKICAgIGxldCBpbnB1dFBvaW50cyA9IHNjcmF0Y2hJblBvaW50czsKICAgIGxldCBpbnB1dEJhcnlzID0gc2NyYXRjaEluQmFyeXM7CiAgICBsZXQgb3V0cHV0TGVuZ3RoID0gMzsKICAgIGxldCBvdXRwdXRQb2ludHMgPSBzY3JhdGNoT3V0UG9pbnRzOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0LmNsb25lKHAwLCBvdXRwdXRQb2ludHNbMF0pOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0LmNsb25lKHAxLCBvdXRwdXRQb2ludHNbMV0pOwogICAgQ2FydGVzaWFuMl9kZWZhdWx0LmNsb25lKHAyLCBvdXRwdXRQb2ludHNbMl0pOwogICAgbGV0IG91dHB1dEJhcnlzID0gc2NyYXRjaE91dEJhcnlzOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygxLCAwLCAwLCBvdXRwdXRCYXJ5c1swXSk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKDAsIDEsIDAsIG91dHB1dEJhcnlzWzFdKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMoMCwgMCwgMSwgb3V0cHV0QmFyeXNbMl0pOwogICAgZm9yIChsZXQgZTIgPSAwOyBlMiA8IGVkZ2VDb3VudDsgZTIrKykgewogICAgICBjb25zdCBlZGdlSWQgPSAoZWRnZVN0YXJ0ICsgZTIpICUgRURHRV9DT1VOVDsKICAgICAgY29uc3QgdGVtcFBvaW50cyA9IGlucHV0UG9pbnRzOwogICAgICBjb25zdCB0ZW1wQmFyeXMgPSBpbnB1dEJhcnlzOwogICAgICBpbnB1dFBvaW50cyA9IG91dHB1dFBvaW50czsKICAgICAgaW5wdXRCYXJ5cyA9IG91dHB1dEJhcnlzOwogICAgICBpbnB1dExlbmd0aCA9IG91dHB1dExlbmd0aDsKICAgICAgb3V0cHV0UG9pbnRzID0gdGVtcFBvaW50czsKICAgICAgb3V0cHV0QmFyeXMgPSB0ZW1wQmFyeXM7CiAgICAgIG91dHB1dExlbmd0aCA9IDA7CiAgICAgIGNvbnN0IHByZXZJZHggPSBpbnB1dExlbmd0aCAtIDE7CiAgICAgIGxldCBwcmV2UG9pbnQgPSBpbnB1dFBvaW50c1twcmV2SWR4XTsKICAgICAgbGV0IHByZXZCYXJ5ID0gaW5wdXRCYXJ5c1twcmV2SWR4XTsKICAgICAgbGV0IHByZXZJbnNpZGUgPSBpbnNpZGUoYm94TWluaW11bSwgYm94TWF4aW11bSwgZWRnZUlkLCBwcmV2UG9pbnQpOwogICAgICBmb3IgKGxldCBjdXJySWR4ID0gMDsgY3VycklkeCA8IGlucHV0TGVuZ3RoOyBjdXJySWR4KyspIHsKICAgICAgICBjb25zdCBjdXJyUG9pbnQgPSBpbnB1dFBvaW50c1tjdXJySWR4XTsKICAgICAgICBjb25zdCBjdXJyQmFyeSA9IGlucHV0QmFyeXNbY3VycklkeF07CiAgICAgICAgY29uc3QgY3Vyckluc2lkZSA9IGluc2lkZShib3hNaW5pbXVtLCBib3hNYXhpbXVtLCBlZGdlSWQsIGN1cnJQb2ludCk7CiAgICAgICAgaWYgKHByZXZJbnNpZGUgKiBjdXJySW5zaWRlID09PSAtMSkgewogICAgICAgICAgY29uc3QgaW50ZXJzZWN0aW9uID0gaW50ZXJzZWN0KAogICAgICAgICAgICBib3hNaW5pbXVtLAogICAgICAgICAgICBib3hNYXhpbXVtLAogICAgICAgICAgICBlZGdlSWQsCiAgICAgICAgICAgIHByZXZQb2ludCwKICAgICAgICAgICAgY3VyclBvaW50LAogICAgICAgICAgICBzY3JhdGNoSW50ZXJzZWN0aW9uCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgeyB4OiB4MiwgeTogeTIsIHo6IHQyIH0gPSBpbnRlcnNlY3Rpb247CiAgICAgICAgICBjb25zdCB0SW52ID0gMSAtIHQyOwogICAgICAgICAgY29uc3QgYmFyeUEgPSBwcmV2QmFyeS54ICogdEludiArIGN1cnJCYXJ5LnggKiB0MjsKICAgICAgICAgIGNvbnN0IGJhcnlCID0gcHJldkJhcnkueSAqIHRJbnYgKyBjdXJyQmFyeS55ICogdDI7CiAgICAgICAgICBjb25zdCBiYXJ5QyA9IHByZXZCYXJ5LnogKiB0SW52ICsgY3VyckJhcnkueiAqIHQyOwogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LmZyb21FbGVtZW50cyh4MiwgeTIsIG91dHB1dFBvaW50c1tvdXRwdXRMZW5ndGhdKTsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMoYmFyeUEsIGJhcnlCLCBiYXJ5Qywgb3V0cHV0QmFyeXNbb3V0cHV0TGVuZ3RoXSk7CiAgICAgICAgICBvdXRwdXRMZW5ndGgrKzsKICAgICAgICB9CiAgICAgICAgaWYgKGN1cnJJbnNpZGUgPj0gMCkgewogICAgICAgICAgQ2FydGVzaWFuMl9kZWZhdWx0LmNsb25lKGN1cnJQb2ludCwgb3V0cHV0UG9pbnRzW291dHB1dExlbmd0aF0pOwogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGN1cnJCYXJ5LCBvdXRwdXRCYXJ5c1tvdXRwdXRMZW5ndGhdKTsKICAgICAgICAgIG91dHB1dExlbmd0aCsrOwogICAgICAgIH0KICAgICAgICBwcmV2UG9pbnQgPSBjdXJyUG9pbnQ7CiAgICAgICAgcHJldkJhcnkgPSBjdXJyQmFyeTsKICAgICAgICBwcmV2SW5zaWRlID0gY3Vyckluc2lkZTsKICAgICAgfQogICAgICBpZiAob3V0cHV0TGVuZ3RoID09PSAwKSB7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH0KICAgIHJlc3VsdC5sZW5ndGggPSBvdXRwdXRMZW5ndGg7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgb3V0cHV0TGVuZ3RoOyBpMisrKSB7CiAgICAgIENhcnRlc2lhbjJfZGVmYXVsdC5jbG9uZShvdXRwdXRQb2ludHNbaTJdLCByZXN1bHQuY29vcmRpbmF0ZXNbaTJdKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKG91dHB1dEJhcnlzW2kyXSwgcmVzdWx0LmJhcnljZW50cmljQ29vcmRpbmF0ZXNbaTJdKTsKICAgIH0KICAgIHJldHVybiByZXN1bHQ7CiAgfQogIGZ1bmN0aW9uIGNsaXBUcmlhbmdsZUZyb21RdWFkcmFudChpc0Vhc3RDaGlsZCwgaXNOb3J0aENoaWxkLCBib3hNaW5pbXVtLCBib3hNYXhpbXVtLCBwMCwgcDEsIHAyLCByZXN1bHQpIHsKICAgIGNvbnN0IGVkZ2VTdGFydCA9IGlzRWFzdENoaWxkID8gaXNOb3J0aENoaWxkID8gRURHRV9JRF9CT1RUT00gOiBFREdFX0lEX0xFRlQgOiBpc05vcnRoQ2hpbGQgPyBFREdFX0lEX1JJR0hUIDogRURHRV9JRF9UT1A7CiAgICByZXR1cm4gY2xpcFRyaWFuZ2xlQWdhaW5zdEJveEVkZ2VSYW5nZSgKICAgICAgZWRnZVN0YXJ0LAogICAgICAyLAogICAgICBib3hNaW5pbXVtLAogICAgICBib3hNYXhpbXVtLAogICAgICBwMCwKICAgICAgcDEsCiAgICAgIHAyLAogICAgICByZXN1bHQKICAgICk7CiAgfQogIGZ1bmN0aW9uIGNsaXBUaWxlRnJvbVF1YWRyYW50KGlzRWFzdENoaWxkLCBpc05vcnRoQ2hpbGQsIGluZGV4Q291bnQsIGluZGljZXMsIHZlcnRleENvdW50LCB2ZXJ0aWNlcywgdmVydGV4RW5jb2RpbmcsIHJlc3VsdEluZGljZXMsIHJlc3VsdFdlc3RJbmRpY2VzLCByZXN1bHRTb3V0aEluZGljZXMsIHJlc3VsdEVhc3RJbmRpY2VzLCByZXN1bHROb3J0aEluZGljZXMsIHJlc3VsdFRyaUlkcywgcmVzdWx0QmFyeSwgcmVzdWx0VVZzKSB7CiAgICBjb25zdCB1cHNhbXBsZWRWZXJ0ZXhNYXAgPSB7fTsKICAgIGNvbnN0IG1pblUgPSBpc0Vhc3RDaGlsZCA/IDAuNSA6IDA7CiAgICBjb25zdCBtYXhVID0gaXNFYXN0Q2hpbGQgPyAxIDogMC41OwogICAgY29uc3QgbWluViA9IGlzTm9ydGhDaGlsZCA/IDAuNSA6IDA7CiAgICBjb25zdCBtYXhWID0gaXNOb3J0aENoaWxkID8gMSA6IDAuNTsKICAgIGNvbnN0IG1pblVWID0gc2NyYXRjaE1pblVWOwogICAgbWluVVYueCA9IG1pblU7CiAgICBtaW5VVi55ID0gbWluVjsKICAgIGNvbnN0IG1heFVWID0gc2NyYXRjaE1heFVWOwogICAgbWF4VVYueCA9IG1heFU7CiAgICBtYXhVVi55ID0gbWF4VjsKICAgIGxldCB1cHNhbXBsZWRWZXJ0ZXhDb3VudCA9IDA7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgaW5kZXhDb3VudDsgaTIgKz0gMykgewogICAgICBjb25zdCBpbmRleEEgPSBpbmRpY2VzW2kyICsgMF07CiAgICAgIGNvbnN0IGluZGV4QiA9IGluZGljZXNbaTIgKyAxXTsKICAgICAgY29uc3QgaW5kZXhDID0gaW5kaWNlc1tpMiArIDJdOwogICAgICBjb25zdCB1dkEgPSB2ZXJ0ZXhFbmNvZGluZy5kZWNvZGVUZXh0dXJlQ29vcmRpbmF0ZXMoCiAgICAgICAgdmVydGljZXMsCiAgICAgICAgaW5kZXhBLAogICAgICAgIHNjcmF0Y2hVdkEKICAgICAgKTsKICAgICAgY29uc3QgdXZCID0gdmVydGV4RW5jb2RpbmcuZGVjb2RlVGV4dHVyZUNvb3JkaW5hdGVzKAogICAgICAgIHZlcnRpY2VzLAogICAgICAgIGluZGV4QiwKICAgICAgICBzY3JhdGNoVXZCCiAgICAgICk7CiAgICAgIGNvbnN0IHV2QyA9IHZlcnRleEVuY29kaW5nLmRlY29kZVRleHR1cmVDb29yZGluYXRlcygKICAgICAgICB2ZXJ0aWNlcywKICAgICAgICBpbmRleEMsCiAgICAgICAgc2NyYXRjaFV2QwogICAgICApOwogICAgICBjb25zdCBjbGlwcGVkUG9seWdvbiA9IGNsaXBUcmlhbmdsZUZyb21RdWFkcmFudCgKICAgICAgICBpc0Vhc3RDaGlsZCwKICAgICAgICBpc05vcnRoQ2hpbGQsCiAgICAgICAgbWluVVYsCiAgICAgICAgbWF4VVYsCiAgICAgICAgdXZBLAogICAgICAgIHV2QiwKICAgICAgICB1dkMsCiAgICAgICAgc2NyYXRjaFBvbHlnb24KICAgICAgKTsKICAgICAgY29uc3QgY2xpcHBlZFBvbHlnb25MZW5ndGggPSBjbGlwcGVkUG9seWdvbi5sZW5ndGg7CiAgICAgIGlmIChjbGlwcGVkUG9seWdvbkxlbmd0aCA8IDMpIHsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBjb25zdCBwb2x5Z29uVXBzYW1wbGVkSW5kaWNlcyA9IHNjcmF0Y2hQb2x5Z29uSW5kaWNlczsKICAgICAgZm9yIChsZXQgcDIgPSAwOyBwMiA8IGNsaXBwZWRQb2x5Z29uTGVuZ3RoOyBwMisrKSB7CiAgICAgICAgY29uc3QgcG9seWdvbkJhcnkgPSBjbGlwcGVkUG9seWdvbi5iYXJ5Y2VudHJpY0Nvb3JkaW5hdGVzW3AyXTsKICAgICAgICBjb25zdCBiQSA9IHBvbHlnb25CYXJ5Lng7CiAgICAgICAgY29uc3QgYkIgPSBwb2x5Z29uQmFyeS55OwogICAgICAgIGNvbnN0IGJDID0gcG9seWdvbkJhcnkuejsKICAgICAgICBjb25zdCBiYXJ5SWQgPSBNYXRoLmNlaWwoYkEpIHwgTWF0aC5jZWlsKGJCKSA8PCAxIHwgTWF0aC5jZWlsKGJDKSA8PCAyOwogICAgICAgIGNvbnN0IHByaW1pdGl2ZUlkcyA9IGxvb2tVcFRhYmxlQmFyeVRvUHJpbVtiYXJ5SWRdOwogICAgICAgIGxldCB1cHNhbXBsZWRJbmRleDsKICAgICAgICBsZXQgaXNOZXdWZXJ0ZXggPSBmYWxzZTsKICAgICAgICBpZiAocHJpbWl0aXZlSWRzLmxlbmd0aCA9PT0gMSkgewogICAgICAgICAgY29uc3QgcG9pbnRQcmltaXRpdmVJZCA9IHByaW1pdGl2ZUlkc1swXTsKICAgICAgICAgIGNvbnN0IHBvaW50SW5kZXggPSBpbmRpY2VzW2kyICsgcG9pbnRQcmltaXRpdmVJZF07CiAgICAgICAgICBjb25zdCBwb2ludEtleSA9IHBvaW50SW5kZXg7CiAgICAgICAgICB1cHNhbXBsZWRJbmRleCA9IHVwc2FtcGxlZFZlcnRleE1hcFtwb2ludEtleV07CiAgICAgICAgICBpZiAodXBzYW1wbGVkSW5kZXggPT09IHZvaWQgMCkgewogICAgICAgICAgICBpc05ld1ZlcnRleCA9IHRydWU7CiAgICAgICAgICAgIHVwc2FtcGxlZEluZGV4ID0gdXBzYW1wbGVkVmVydGV4Q291bnQrKzsKICAgICAgICAgICAgdXBzYW1wbGVkVmVydGV4TWFwW3BvaW50S2V5XSA9IHVwc2FtcGxlZEluZGV4OwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSBpZiAocHJpbWl0aXZlSWRzLmxlbmd0aCA9PT0gMikgewogICAgICAgICAgY29uc3QgZWRnZVByaW1pdGl2ZUlkQSA9IHByaW1pdGl2ZUlkc1swXTsKICAgICAgICAgIGNvbnN0IGVkZ2VQcmltaXRpdmVJZEIgPSBwcmltaXRpdmVJZHNbMV07CiAgICAgICAgICBjb25zdCBlZGdlSW5kZXhBID0gaW5kaWNlc1tpMiArIGVkZ2VQcmltaXRpdmVJZEFdOwogICAgICAgICAgY29uc3QgZWRnZUluZGV4QiA9IGluZGljZXNbaTIgKyBlZGdlUHJpbWl0aXZlSWRCXTsKICAgICAgICAgIGNvbnN0IHByZXZCYXJ5ID0gY2xpcHBlZFBvbHlnb24uYmFyeWNlbnRyaWNDb29yZGluYXRlc1socDIgKyBjbGlwcGVkUG9seWdvbkxlbmd0aCAtIDEpICUgY2xpcHBlZFBvbHlnb25MZW5ndGhdOwogICAgICAgICAgY29uc3QgcHJldkJhcnlJZCA9IE1hdGguY2VpbChwcmV2QmFyeS54KSB8IE1hdGguY2VpbChwcmV2QmFyeS55KSA8PCAxIHwgTWF0aC5jZWlsKHByZXZCYXJ5LnopIDw8IDI7CiAgICAgICAgICBjb25zdCBzYW1lRWRnZSA9IGJhcnlJZCA9PT0gcHJldkJhcnlJZDsKICAgICAgICAgIGNvbnN0IG1pbkluZGV4ID0gTWF0aC5taW4oZWRnZUluZGV4QSwgZWRnZUluZGV4Qik7CiAgICAgICAgICBjb25zdCBtYXhJbmRleCA9IE1hdGgubWF4KGVkZ2VJbmRleEEsIGVkZ2VJbmRleEIpOwogICAgICAgICAgY29uc3QgYmFzZUtleSA9IHZlcnRleENvdW50ICsgMiAqIChtaW5JbmRleCAqIHZlcnRleENvdW50ICsgbWF4SW5kZXgpOwogICAgICAgICAgY29uc3QgZmlyc3RLZXkgPSBiYXNlS2V5ICsgMDsKICAgICAgICAgIGNvbnN0IHNlY29uZEtleSA9IGJhc2VLZXkgKyAxOwogICAgICAgICAgY29uc3QgZmlyc3RFbnRyeSA9IHVwc2FtcGxlZFZlcnRleE1hcFtmaXJzdEtleV07CiAgICAgICAgICBjb25zdCBzZWNvbmRFbnRyeSA9IHVwc2FtcGxlZFZlcnRleE1hcFtzZWNvbmRLZXldOwogICAgICAgICAgY29uc3QgdXNlRmlyc3QgPSAhc2FtZUVkZ2UgPT09IChmaXJzdEVudHJ5ID09PSB2b2lkIDAgfHwgc2Vjb25kRW50cnkgPT09IHZvaWQgMCk7CiAgICAgICAgICB1cHNhbXBsZWRJbmRleCA9IHVzZUZpcnN0ID8gZmlyc3RFbnRyeSA6IHNlY29uZEVudHJ5OwogICAgICAgICAgaWYgKHVwc2FtcGxlZEluZGV4ID09PSB2b2lkIDApIHsKICAgICAgICAgICAgaXNOZXdWZXJ0ZXggPSB0cnVlOwogICAgICAgICAgICB1cHNhbXBsZWRJbmRleCA9IHVwc2FtcGxlZFZlcnRleENvdW50Kys7CiAgICAgICAgICAgIGNvbnN0IGVkZ2VLZXkgPSB1c2VGaXJzdCA/IGZpcnN0S2V5IDogc2Vjb25kS2V5OwogICAgICAgICAgICB1cHNhbXBsZWRWZXJ0ZXhNYXBbZWRnZUtleV0gPSB1cHNhbXBsZWRJbmRleDsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgaXNOZXdWZXJ0ZXggPSB0cnVlOwogICAgICAgICAgdXBzYW1wbGVkSW5kZXggPSB1cHNhbXBsZWRWZXJ0ZXhDb3VudCsrOwogICAgICAgIH0KICAgICAgICBwb2x5Z29uVXBzYW1wbGVkSW5kaWNlc1twMl0gPSB1cHNhbXBsZWRJbmRleDsKICAgICAgICBpZiAoaXNOZXdWZXJ0ZXgpIHsKICAgICAgICAgIGNvbnN0IHRyaUlkID0gaTIgLyAzOwogICAgICAgICAgcmVzdWx0VHJpSWRzLnB1c2godHJpSWQpOwogICAgICAgICAgY29uc3QgcG9seWdvblVWID0gY2xpcHBlZFBvbHlnb24uY29vcmRpbmF0ZXNbcDJdOwogICAgICAgICAgY29uc3QgdTQgPSAocG9seWdvblVWLnggLSBtaW5VKSAvIChtYXhVIC0gbWluVSk7CiAgICAgICAgICBjb25zdCB2NCA9IChwb2x5Z29uVVYueSAtIG1pblYpIC8gKG1heFYgLSBtaW5WKTsKICAgICAgICAgIHJlc3VsdFVWcy5wdXNoKHU0LCB2NCk7CiAgICAgICAgICByZXN1bHRCYXJ5LnB1c2goYkEsIGJCKTsKICAgICAgICAgIGlmICh1NCA9PT0gMCkgewogICAgICAgICAgICByZXN1bHRXZXN0SW5kaWNlcy5wdXNoKHVwc2FtcGxlZEluZGV4KTsKICAgICAgICAgIH0gZWxzZSBpZiAodTQgPT09IDEpIHsKICAgICAgICAgICAgcmVzdWx0RWFzdEluZGljZXMucHVzaCh1cHNhbXBsZWRJbmRleCk7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodjQgPT09IDApIHsKICAgICAgICAgICAgcmVzdWx0U291dGhJbmRpY2VzLnB1c2godXBzYW1wbGVkSW5kZXgpOwogICAgICAgICAgfSBlbHNlIGlmICh2NCA9PT0gMSkgewogICAgICAgICAgICByZXN1bHROb3J0aEluZGljZXMucHVzaCh1cHNhbXBsZWRJbmRleCk7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IHVpMCA9IHBvbHlnb25VcHNhbXBsZWRJbmRpY2VzWzBdOwogICAgICBsZXQgdWkxID0gcG9seWdvblVwc2FtcGxlZEluZGljZXNbMV07CiAgICAgIGxldCB1aTIgPSBwb2x5Z29uVXBzYW1wbGVkSW5kaWNlc1syXTsKICAgICAgcmVzdWx0SW5kaWNlcy5wdXNoKHVpMCwgdWkxLCB1aTIpOwogICAgICBmb3IgKGxldCBqMiA9IDM7IGoyIDwgY2xpcHBlZFBvbHlnb25MZW5ndGg7IGoyKyspIHsKICAgICAgICB1aTEgPSB1aTI7CiAgICAgICAgdWkyID0gcG9seWdvblVwc2FtcGxlZEluZGljZXNbajJdOwogICAgICAgIHJlc3VsdEluZGljZXMucHVzaCh1aTAsIHVpMSwgdWkyKTsKICAgICAgfQogICAgfQogICAgcmVzdWx0V2VzdEluZGljZXMuc29ydChmdW5jdGlvbihhNCwgYjIpIHsKICAgICAgcmV0dXJuIHJlc3VsdFVWc1thNCAqIDIgKyAxXSAtIHJlc3VsdFVWc1tiMiAqIDIgKyAxXTsKICAgIH0pOwogICAgcmVzdWx0U291dGhJbmRpY2VzLnNvcnQoZnVuY3Rpb24oYTQsIGIyKSB7CiAgICAgIHJldHVybiByZXN1bHRVVnNbYjIgKiAyICsgMF0gLSByZXN1bHRVVnNbYTQgKiAyICsgMF07CiAgICB9KTsKICAgIHJlc3VsdEVhc3RJbmRpY2VzLnNvcnQoZnVuY3Rpb24oYTQsIGIyKSB7CiAgICAgIHJldHVybiByZXN1bHRVVnNbYjIgKiAyICsgMV0gLSByZXN1bHRVVnNbYTQgKiAyICsgMV07CiAgICB9KTsKICAgIHJlc3VsdE5vcnRoSW5kaWNlcy5zb3J0KGZ1bmN0aW9uKGE0LCBiMikgewogICAgICByZXR1cm4gcmVzdWx0VVZzW2E0ICogMiArIDBdIC0gcmVzdWx0VVZzW2IyICogMiArIDBdOwogICAgfSk7CiAgfQogIHZhciBDZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yLCBzY3JhdGNoR2x0ZkluZm8sIHNjcmF0Y2hDZW50ZXJDYXJ0b2dyYXBoaWMsIHNjcmF0Y2hDZW50ZXJDYXJ0ZXNpYW4yLCBzY3JhdGNoRW51VG9FY2VmLCBzY3JhdGNoRWNlZlRvRW51LCBzY3JhdGNoVGlsZXNldFRyYW5zZm9ybSwgc2NyYXRjaE1pbmltdW1Qb3NpdGlvbkVOVSwgc2NyYXRjaE1heGltdW1Qb3NpdGlvbkVOVSwgc2NyYXRjaFBvc0xvY2FsLCBzY3JhdGNoUG9zRWNlZiwgc2NyYXRjaENhcnRvZ3JhcGhpYzgsIHNjcmF0Y2hVViwgc2NyYXRjaE5vcm1hbDgsIHNjcmF0Y2hOb3JtYWxPY3QsIHNjcmF0Y2hHZW9kZXRpY1N1cmZhY2VOb3JtYWwyLCBzY3JhdGNoUG9zRW51LCBzb3J0ZWRFZGdlQ29tcGFyZSwgc2NyYXRjaE1pblVWLCBzY3JhdGNoTWF4VVYsIHNjcmF0Y2hQb2x5Z29uSW5kaWNlcywgc2NyYXRjaFV2QSwgc2NyYXRjaFV2Qiwgc2NyYXRjaFV2Qywgc2NyYXRjaE5vcm1hbEEsIHNjcmF0Y2hOb3JtYWxCLCBzY3JhdGNoTm9ybWFsQywgc2NyYXRjaENlbnRlckNhcnRvZ3JhcGhpY1Vwc2FtcGxlLCBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuVXBzYW1wbGUsIHNjcmF0Y2hDYXJ0b2dyYXBoaWNTa2lydCwgc2NyYXRjaENhcnRvZ3JhcGhpY1Vwc2FtcGxlLCBzY3JhdGNoUG9zRWNlZlNraXJ0LCBzY3JhdGNoUG9zRWNlZlVwc2FtcGxlLCBzY3JhdGNoUG9zRW51U2tpcnQsIHNjcmF0Y2hQb3NFbnVVcHNhbXBsZSwgc2NyYXRjaE1pbmltdW1Qb3NpdGlvbkVOVVNraXJ0LCBzY3JhdGNoTWF4aW11bVBvc2l0aW9uRU5VU2tpcnQsIHNjcmF0Y2hNaW5pbXVtUG9zaXRpb25FTlVVcHNhbXBsZSwgc2NyYXRjaE1heGltdW1Qb3NpdGlvbkVOVVVwc2FtcGxlLCBzY3JhdGNoRW51VG9FY2VmVXBzYW1wbGUsIHNjcmF0Y2hFY2VmVG9FbnVVcHNhbXBsZSwgc2NyYXRjaFVWU2tpcnQsIHNjcmF0Y2hVVlVwc2FtcGxlLCBzY3JhdGNoSG9yaXpvbk9jY2x1c2lvblBvaW50LCBzY3JhdGNoQm91bmRpbmdTcGhlcmUzLCBzY3JhdGNoT3JpZW50ZWRCb3VuZGluZ0JveCwgc2NyYXRjaEFBQkJFbnVTa2lydCwgc2NyYXRjaE5vcm1hbFVwc2FtcGxlLCBzY3JhdGNoTm9ybWFsT2N0U2tpcnQsIHNjcmF0Y2hOb3JtYWxPY3RVcHNhbXBsZSwgc2NyYXRjaEdlb2RldGljU3VyZmFjZU5vcm1hbFNraXJ0LCBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsVXBzYW1wbGUsIEVER0VfSURfTEVGVCwgRURHRV9JRF9UT1AsIEVER0VfSURfUklHSFQsIEVER0VfSURfQk9UVE9NLCBFREdFX0NPVU5ULCBzY3JhdGNoSW50ZXJzZWN0aW9uLCBzY3JhdGNoSW5CYXJ5cywgc2NyYXRjaEluUG9pbnRzLCBzY3JhdGNoT3V0QmFyeXMsIHNjcmF0Y2hPdXRQb2ludHMsIHNjcmF0Y2hQb2x5Z29uLCBsb29rVXBUYWJsZUJhcnlUb1ByaW0sIENlc2l1bTNEVGlsZXNUZXJyYWluR2VvbWV0cnlQcm9jZXNzb3JfZGVmYXVsdDsKICB2YXIgaW5pdF9DZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9DZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yLmpzIigpIHsKICAgICAgaW5pdF9tZXNob3B0aW1pemVyKCk7CiAgICAgIGluaXRfQXR0cmlidXRlQ29tcHJlc3Npb24oKTsKICAgICAgaW5pdF9BeGlzKCk7CiAgICAgIGluaXRfQXhpc0FsaWduZWRCb3VuZGluZ0JveCgpOwogICAgICBpbml0X2JpbmFyeVNlYXJjaCgpOwogICAgICBpbml0X0JvdW5kaW5nU3BoZXJlKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMigpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfQ2hlY2soKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZGFsT2NjbHVkZXIoKTsKICAgICAgaW5pdF9Gcm96ZW4oKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfT3JpZW50ZWRCb3VuZGluZ0JveCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1RlcnJhaW5FbmNvZGluZygpOwogICAgICBpbml0X1RlcnJhaW5NZXNoKCk7CiAgICAgIGluaXRfVGVycmFpblByb3ZpZGVyKCk7CiAgICAgIGluaXRfVHJhbnNmb3JtcygpOwogICAgICBpbml0X1dlYk1lcmNhdG9yUHJvamVjdGlvbigpOwogICAgICBDZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yID0ge307CiAgICAgIHNjcmF0Y2hHbHRmSW5mbyA9IHsKICAgICAgICBwb3NpdGlvbnM6IHZvaWQgMCwKICAgICAgICBub3JtYWxzOiB2b2lkIDAsCiAgICAgICAgaW5kaWNlczogdm9pZCAwLAogICAgICAgIGVkZ2VJbmRpY2VzV2VzdDogdm9pZCAwLAogICAgICAgIGVkZ2VJbmRpY2VzU291dGg6IHZvaWQgMCwKICAgICAgICBlZGdlSW5kaWNlc0Vhc3Q6IHZvaWQgMCwKICAgICAgICBlZGdlSW5kaWNlc05vcnRoOiB2b2lkIDAKICAgICAgfTsKICAgICAgc2NyYXRjaENlbnRlckNhcnRvZ3JhcGhpYyA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVudVRvRWNlZiA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVjZWZUb0VudSA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRpbGVzZXRUcmFuc2Zvcm0gPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5pbXVtUG9zaXRpb25FTlUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNYXhpbXVtUG9zaXRpb25FTlUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hQb3NMb2NhbCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBvc0VjZWYgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM4ID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hVViA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5vcm1hbDggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOb3JtYWxPY3QgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hHZW9kZXRpY1N1cmZhY2VOb3JtYWwyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUG9zRW51ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzb3J0ZWRFZGdlQ29tcGFyZSA9IGZ1bmN0aW9uKGE0LCBiMikgewogICAgICAgIHJldHVybiBhNCAtIGIyOwogICAgICB9OwogICAgICBDZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yLmNyZWF0ZU1lc2ggPSBhc3luYyBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHsKICAgICAgICAgIGV4YWdnZXJhdGlvbiA9IDEsCiAgICAgICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodCA9IDAsCiAgICAgICAgICBoYXNWZXJ0ZXhOb3JtYWxzLAogICAgICAgICAgaGFzV2ViTWVyY2F0b3JULAogICAgICAgICAgZ2x0ZiwKICAgICAgICAgIG1pbmltdW1IZWlnaHQsCiAgICAgICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICAgICAgc2tpcnRIZWlnaHQKICAgICAgICB9ID0gb3B0aW9uczsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMuZWxsaXBzb2lkIiwgb3B0aW9ucy5lbGxpcHNvaWQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5yZWN0YW5nbGUiLCBvcHRpb25zLnJlY3RhbmdsZSk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuYm9vbCgib3B0aW9ucy5oYXNWZXJ0ZXhOb3JtYWxzIiwgaGFzVmVydGV4Tm9ybWFscyk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuYm9vbCgib3B0aW9ucy5oYXNXZWJNZXJjYXRvclQiLCBoYXNXZWJNZXJjYXRvclQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5nbHRmIiwgZ2x0Zik7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJvcHRpb25zLm1pbmltdW1IZWlnaHQiLCBtaW5pbXVtSGVpZ2h0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIm9wdGlvbnMubWF4aW11bUhlaWdodCIsIG1heGltdW1IZWlnaHQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5ib3VuZGluZ1NwaGVyZSIsIG9wdGlvbnMuYm91bmRpbmdTcGhlcmUpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgKICAgICAgICAgICJvcHRpb25zLm9yaWVudGVkQm91bmRpbmdCb3giLAogICAgICAgICAgb3B0aW9ucy5vcmllbnRlZEJvdW5kaW5nQm94CiAgICAgICAgKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoCiAgICAgICAgICAib3B0aW9ucy5ob3Jpem9uT2NjbHVzaW9uUG9pbnQiLAogICAgICAgICAgb3B0aW9ucy5ob3Jpem9uT2NjbHVzaW9uUG9pbnQKICAgICAgICApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigib3B0aW9ucy5za2lydEhlaWdodCIsIHNraXJ0SGVpZ2h0KTsKICAgICAgICBjb25zdCBoYXNFeGFnZ2VyYXRpb24gPSBleGFnZ2VyYXRpb24gIT09IDE7CiAgICAgICAgY29uc3QgaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscyA9IGhhc0V4YWdnZXJhdGlvbjsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuY2xvbmUoCiAgICAgICAgICBvcHRpb25zLmJvdW5kaW5nU3BoZXJlLAogICAgICAgICAgbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoKQogICAgICAgICk7CiAgICAgICAgY29uc3Qgb3JpZW50ZWRCb3VuZGluZ0JveCA9IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdC5jbG9uZSgKICAgICAgICAgIG9wdGlvbnMub3JpZW50ZWRCb3VuZGluZ0JveCwKICAgICAgICAgIG5ldyBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQoKQogICAgICAgICk7CiAgICAgICAgY29uc3QgaG9yaXpvbk9jY2x1c2lvblBvaW50ID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKAogICAgICAgICAgb3B0aW9ucy5ob3Jpem9uT2NjbHVzaW9uUG9pbnQsCiAgICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkKICAgICAgICApOwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKG9wdGlvbnMuZWxsaXBzb2lkLCBuZXcgRWxsaXBzb2lkX2RlZmF1bHQoKSk7CiAgICAgICAgY29uc3QgcmVjdGFuZ2xlID0gUmVjdGFuZ2xlX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5yZWN0YW5nbGUsIG5ldyBSZWN0YW5nbGVfZGVmYXVsdCgpKTsKICAgICAgICBjb25zdCBoYXNNZXNoT3B0Q29tcHJlc3Npb24gPSBnbHRmLmV4dGVuc2lvbnNSZXF1aXJlZCAhPT0gdm9pZCAwICYmIGdsdGYuZXh0ZW5zaW9uc1JlcXVpcmVkLmluZGV4T2YoIkVYVF9tZXNob3B0X2NvbXByZXNzaW9uIikgIT09IC0xOwogICAgICAgIGNvbnN0IGRlY29kZXJQcm9taXNlID0gaGFzTWVzaE9wdENvbXByZXNzaW9uID8gTWVzaG9wdERlY29kZXIucmVhZHkgOiBQcm9taXNlLnJlc29sdmUodm9pZCAwKTsKICAgICAgICBhd2FpdCBkZWNvZGVyUHJvbWlzZTsKICAgICAgICBjb25zdCB0aWxlTWluTG9uZ2l0dWRlID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgY29uc3QgdGlsZU1pbkxhdGl0dWRlID0gcmVjdGFuZ2xlLnNvdXRoOwogICAgICAgIGNvbnN0IHRpbGVNYXhMYXRpdHVkZSA9IHJlY3RhbmdsZS5ub3J0aDsKICAgICAgICBjb25zdCB0aWxlTGVuZ3RoTG9uZ2l0dWRlID0gcmVjdGFuZ2xlLndpZHRoOwogICAgICAgIGNvbnN0IHRpbGVMZW5ndGhMYXRpdHVkZSA9IHJlY3RhbmdsZS5oZWlnaHQ7CiAgICAgICAgY29uc3QgYXBwcm94aW1hdGVDZW50ZXJDYXJ0b2dyYXBoaWMgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgICAgICByZWN0YW5nbGUsCiAgICAgICAgICBzY3JhdGNoQ2VudGVyQ2FydG9ncmFwaGljCiAgICAgICAgKTsKICAgICAgICBhcHByb3hpbWF0ZUNlbnRlckNhcnRvZ3JhcGhpYy5oZWlnaHQgPSAwLjUgKiAobWluaW11bUhlaWdodCArIG1heGltdW1IZWlnaHQpOwogICAgICAgIGNvbnN0IGFwcHJveGltYXRlQ2VudGVyUG9zaXRpb24gPSBDYXJ0b2dyYXBoaWNfZGVmYXVsdC50b0NhcnRlc2lhbigKICAgICAgICAgIGFwcHJveGltYXRlQ2VudGVyQ2FydG9ncmFwaGljLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgc2NyYXRjaENlbnRlckNhcnRlc2lhbjIKICAgICAgICApOwogICAgICAgIGNvbnN0IGVudVRvRWNlZiA9IFRyYW5zZm9ybXNfZGVmYXVsdC5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZSgKICAgICAgICAgIGFwcHJveGltYXRlQ2VudGVyUG9zaXRpb24sCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICBzY3JhdGNoRW51VG9FY2VmCiAgICAgICAgKTsKICAgICAgICBjb25zdCBlY2VmVG9FbnUgPSBNYXRyaXg0X2RlZmF1bHQuaW52ZXJzZVRyYW5zZm9ybWF0aW9uKGVudVRvRWNlZiwgc2NyYXRjaEVjZWZUb0VudSk7CiAgICAgICAgbGV0IHRpbGVzZXRUcmFuc2Zvcm0gPSBNYXRyaXg0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgZ2x0Zi5ub2Rlc1swXS5tYXRyaXgsCiAgICAgICAgICAwLAogICAgICAgICAgc2NyYXRjaFRpbGVzZXRUcmFuc2Zvcm0KICAgICAgICApOwogICAgICAgIHRpbGVzZXRUcmFuc2Zvcm0gPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHkoCiAgICAgICAgICBBeGlzX2RlZmF1bHQuWV9VUF9UT19aX1VQLAogICAgICAgICAgdGlsZXNldFRyYW5zZm9ybSwKICAgICAgICAgIHRpbGVzZXRUcmFuc2Zvcm0KICAgICAgICApOwogICAgICAgIGNvbnN0IGdsdGZJbmZvID0gZGVjb2RlR2x0ZihnbHRmLCBoYXNWZXJ0ZXhOb3JtYWxzLCBzY3JhdGNoR2x0ZkluZm8pOwogICAgICAgIGNvbnN0IHNraXJ0VmVydGV4Q291bnQgPSBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdC5nZXRTa2lydFZlcnRleENvdW50KAogICAgICAgICAgZ2x0ZkluZm8uZWRnZUluZGljZXNXZXN0LAogICAgICAgICAgZ2x0ZkluZm8uZWRnZUluZGljZXNTb3V0aCwKICAgICAgICAgIGdsdGZJbmZvLmVkZ2VJbmRpY2VzRWFzdCwKICAgICAgICAgIGdsdGZJbmZvLmVkZ2VJbmRpY2VzTm9ydGgKICAgICAgICApOwogICAgICAgIGNvbnN0IHBvc2l0aW9uc0xvY2FsV2l0aG91dFNraXJ0cyA9IGdsdGZJbmZvLnBvc2l0aW9uczsKICAgICAgICBjb25zdCBub3JtYWxzV2l0aG91dFNraXJ0cyA9IGdsdGZJbmZvLm5vcm1hbHM7CiAgICAgICAgY29uc3QgaW5kaWNlc1dpdGhvdXRTa2lydHMgPSBnbHRmSW5mby5pbmRpY2VzOwogICAgICAgIGNvbnN0IHZlcnRleENvdW50V2l0aG91dFNraXJ0cyA9IHBvc2l0aW9uc0xvY2FsV2l0aG91dFNraXJ0cy5sZW5ndGggLyAzOwogICAgICAgIGNvbnN0IHZlcnRleENvdW50V2l0aFNraXJ0cyA9IHZlcnRleENvdW50V2l0aG91dFNraXJ0cyArIHNraXJ0VmVydGV4Q291bnQ7CiAgICAgICAgY29uc3QgaW5kZXhDb3VudFdpdGhvdXRTa2lydHMgPSBpbmRpY2VzV2l0aG91dFNraXJ0cy5sZW5ndGg7CiAgICAgICAgY29uc3Qgc2tpcnRJbmRleENvdW50ID0gVGVycmFpblByb3ZpZGVyX2RlZmF1bHQuZ2V0U2tpcnRJbmRleENvdW50V2l0aEZpbGxlZENvcm5lcnMoc2tpcnRWZXJ0ZXhDb3VudCk7CiAgICAgICAgY29uc3QgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzID0gdmVydGV4Q291bnRXaXRoU2tpcnRzIDw9IDY1NTM1ID8gVWludDE2QXJyYXkgOiBVaW50MzJBcnJheTsKICAgICAgICBjb25zdCBpbmRleEJ1ZmZlcldpdGhTa2lydHMgPSBuZXcgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzKAogICAgICAgICAgaW5kZXhDb3VudFdpdGhvdXRTa2lydHMgKyBza2lydEluZGV4Q291bnQKICAgICAgICApOwogICAgICAgIGluZGV4QnVmZmVyV2l0aFNraXJ0cy5zZXQoaW5kaWNlc1dpdGhvdXRTa2lydHMpOwogICAgICAgIGNvbnN0IHdlc3RJbmRpY2VzID0gbmV3IFNpemVkSW5kZXhUeXBlV2l0aFNraXJ0cyhnbHRmSW5mby5lZGdlSW5kaWNlc1dlc3QpOwogICAgICAgIGNvbnN0IHNvdXRoSW5kaWNlcyA9IG5ldyBTaXplZEluZGV4VHlwZVdpdGhTa2lydHMoZ2x0ZkluZm8uZWRnZUluZGljZXNTb3V0aCk7CiAgICAgICAgY29uc3QgZWFzdEluZGljZXMgPSBuZXcgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzKGdsdGZJbmZvLmVkZ2VJbmRpY2VzRWFzdCk7CiAgICAgICAgY29uc3Qgbm9ydGhJbmRpY2VzID0gbmV3IFNpemVkSW5kZXhUeXBlV2l0aFNraXJ0cyhnbHRmSW5mby5lZGdlSW5kaWNlc05vcnRoKTsKICAgICAgICBjb25zdCBzb3J0ZWRXZXN0SW5kaWNlcyA9IG5ldyBTaXplZEluZGV4VHlwZVdpdGhTa2lydHMod2VzdEluZGljZXMpLnNvcnQoKTsKICAgICAgICBjb25zdCBzb3J0ZWRTb3V0aEluZGljZXMgPSBuZXcgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzKHNvdXRoSW5kaWNlcykuc29ydCgpOwogICAgICAgIGNvbnN0IHNvcnRlZEVhc3RJbmRpY2VzID0gbmV3IFNpemVkSW5kZXhUeXBlV2l0aFNraXJ0cyhlYXN0SW5kaWNlcykuc29ydCgpOwogICAgICAgIGNvbnN0IHNvcnRlZE5vcnRoSW5kaWNlcyA9IG5ldyBTaXplZEluZGV4VHlwZVdpdGhTa2lydHMobm9ydGhJbmRpY2VzKS5zb3J0KCk7CiAgICAgICAgY29uc3Qgc291dGhNZXJjYXRvckFuZ2xlID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZSh0aWxlTWluTGF0aXR1ZGUpOwogICAgICAgIGNvbnN0IG5vcnRoTWVyY2F0b3JBbmdsZSA9IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUodGlsZU1heExhdGl0dWRlKTsKICAgICAgICBjb25zdCBvbmVPdmVyTWVyY2F0b3JIZWlnaHQgPSAxIC8gKG5vcnRoTWVyY2F0b3JBbmdsZSAtIHNvdXRoTWVyY2F0b3JBbmdsZSk7CiAgICAgICAgbGV0IG1pblBvc0VudSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBzY3JhdGNoTWluaW11bVBvc2l0aW9uRU5VCiAgICAgICAgKTsKICAgICAgICBsZXQgbWF4UG9zRW51ID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21FbGVtZW50cygKICAgICAgICAgIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgICAgIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgICAgIE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwKICAgICAgICAgIHNjcmF0Y2hNYXhpbXVtUG9zaXRpb25FTlUKICAgICAgICApOwogICAgICAgIGNvbnN0IHRlbXBUZXJyYWluRW5jb2RpbmcgPSBuZXcgVGVycmFpbkVuY29kaW5nX2RlZmF1bHQoCiAgICAgICAgICBib3VuZGluZ1NwaGVyZS5jZW50ZXIsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICB2b2lkIDAsCiAgICAgICAgICBoYXNWZXJ0ZXhOb3JtYWxzLAogICAgICAgICAgaGFzV2ViTWVyY2F0b3JULAogICAgICAgICAgaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgICAgIGV4YWdnZXJhdGlvbiwKICAgICAgICAgIGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0CiAgICAgICAgKTsKICAgICAgICBjb25zdCB0ZW1wQnVmZmVyU3RyaWRlID0gdGVtcFRlcnJhaW5FbmNvZGluZy5zdHJpZGU7CiAgICAgICAgY29uc3QgdGVtcEJ1ZmZlciA9IG5ldyBGbG9hdDMyQXJyYXkodmVydGV4Q291bnRXaXRoU2tpcnRzICogdGVtcEJ1ZmZlclN0cmlkZSk7CiAgICAgICAgbGV0IHRlbXBCdWZmZXJPZmZzZXQgPSAwOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHM7IGkyKyspIHsKICAgICAgICAgIGNvbnN0IHBvc0xvY2FsID0gQ2FydGVzaWFuM19kZWZhdWx0LnVucGFjaygKICAgICAgICAgICAgcG9zaXRpb25zTG9jYWxXaXRob3V0U2tpcnRzLAogICAgICAgICAgICBpMiAqIDMsCiAgICAgICAgICAgIHNjcmF0Y2hQb3NMb2NhbAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBvc0VDRUYgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICAgICAgICB0aWxlc2V0VHJhbnNmb3JtLAogICAgICAgICAgICBwb3NMb2NhbCwKICAgICAgICAgICAgc2NyYXRjaFBvc0VjZWYKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBjYXJ0b2dyYXBoaWMyID0gQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbUNhcnRlc2lhbigKICAgICAgICAgICAgcG9zRUNFRiwKICAgICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHsgbG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0IH0gPSBjYXJ0b2dyYXBoaWMyOwogICAgICAgICAgbGV0IHU0ID0gKGxvbmdpdHVkZSAtIHRpbGVNaW5Mb25naXR1ZGUpIC8gdGlsZUxlbmd0aExvbmdpdHVkZTsKICAgICAgICAgIGxldCB2NCA9IChsYXRpdHVkZSAtIHRpbGVNaW5MYXRpdHVkZSkgLyB0aWxlTGVuZ3RoTGF0aXR1ZGU7CiAgICAgICAgICB1NCA9IE1hdGhfZGVmYXVsdC5jbGFtcCh1NCwgMCwgMSk7CiAgICAgICAgICB2NCA9IE1hdGhfZGVmYXVsdC5jbGFtcCh2NCwgMCwgMSk7CiAgICAgICAgICBpZiAoYmluYXJ5U2VhcmNoX2RlZmF1bHQoc29ydGVkV2VzdEluZGljZXMsIGkyLCBzb3J0ZWRFZGdlQ29tcGFyZSkgPj0gMCkgewogICAgICAgICAgICB1NCA9IDA7CiAgICAgICAgICB9IGVsc2UgaWYgKGJpbmFyeVNlYXJjaF9kZWZhdWx0KHNvcnRlZEVhc3RJbmRpY2VzLCBpMiwgc29ydGVkRWRnZUNvbXBhcmUpID49IDApIHsKICAgICAgICAgICAgdTQgPSAxOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGJpbmFyeVNlYXJjaF9kZWZhdWx0KHNvcnRlZFNvdXRoSW5kaWNlcywgaTIsIHNvcnRlZEVkZ2VDb21wYXJlKSA+PSAwKSB7CiAgICAgICAgICAgIHY0ID0gMDsKICAgICAgICAgIH0gZWxzZSBpZiAoYmluYXJ5U2VhcmNoX2RlZmF1bHQoc29ydGVkTm9ydGhJbmRpY2VzLCBpMiwgc29ydGVkRWRnZUNvbXBhcmUpID49IDApIHsKICAgICAgICAgICAgdjQgPSAxOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgdXYgPSBDYXJ0ZXNpYW4yX2RlZmF1bHQuZnJvbUVsZW1lbnRzKHU0LCB2NCwgc2NyYXRjaFVWKTsKICAgICAgICAgIGxldCBub3JtYWxPY3Q7CiAgICAgICAgICBpZiAoaGFzVmVydGV4Tm9ybWFscykgewogICAgICAgICAgICBsZXQgbm9ybWFsMiA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soCiAgICAgICAgICAgICAgbm9ybWFsc1dpdGhvdXRTa2lydHMsCiAgICAgICAgICAgICAgaTIgKiAzLAogICAgICAgICAgICAgIHNjcmF0Y2hOb3JtYWw4CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG5vcm1hbDIgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50QXNWZWN0b3IoCiAgICAgICAgICAgICAgdGlsZXNldFRyYW5zZm9ybSwKICAgICAgICAgICAgICBub3JtYWwyLAogICAgICAgICAgICAgIHNjcmF0Y2hOb3JtYWw4CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG5vcm1hbDIsIHNjcmF0Y2hOb3JtYWw4KTsKICAgICAgICAgICAgbm9ybWFsT2N0ID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5vY3RFbmNvZGUobm9ybWFsMiwgc2NyYXRjaE5vcm1hbE9jdCk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgd2ViTWVyY2F0b3JUOwogICAgICAgICAgaWYgKGhhc1dlYk1lcmNhdG9yVCkgewogICAgICAgICAgICBjb25zdCBtZXJjYXRvckFuZ2xlID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZShsYXRpdHVkZSk7CiAgICAgICAgICAgIHdlYk1lcmNhdG9yVCA9IChtZXJjYXRvckFuZ2xlIC0gc291dGhNZXJjYXRvckFuZ2xlKSAqIG9uZU92ZXJNZXJjYXRvckhlaWdodDsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBnZW9kZXRpY1N1cmZhY2VOb3JtYWw7CiAgICAgICAgICBpZiAoaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscykgewogICAgICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKAogICAgICAgICAgICAgIHBvc0VDRUYsCiAgICAgICAgICAgICAgc2NyYXRjaEdlb2RldGljU3VyZmFjZU5vcm1hbDIKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHRlbXBCdWZmZXJPZmZzZXQgPSB0ZW1wVGVycmFpbkVuY29kaW5nLmVuY29kZSgKICAgICAgICAgICAgdGVtcEJ1ZmZlciwKICAgICAgICAgICAgdGVtcEJ1ZmZlck9mZnNldCwKICAgICAgICAgICAgcG9zRUNFRiwKICAgICAgICAgICAgdXYsCiAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgbm9ybWFsT2N0LAogICAgICAgICAgICB3ZWJNZXJjYXRvclQsCiAgICAgICAgICAgIGdlb2RldGljU3VyZmFjZU5vcm1hbAogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBvc0VudSA9IE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQoZWNlZlRvRW51LCBwb3NFQ0VGLCBzY3JhdGNoUG9zRW51KTsKICAgICAgICAgIG1pblBvc0VudSA9IENhcnRlc2lhbjNfZGVmYXVsdC5taW5pbXVtQnlDb21wb25lbnQocG9zRW51LCBtaW5Qb3NFbnUsIG1pblBvc0VudSk7CiAgICAgICAgICBtYXhQb3NFbnUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWF4aW11bUJ5Q29tcG9uZW50KHBvc0VudSwgbWF4UG9zRW51LCBtYXhQb3NFbnUpOwogICAgICAgIH0KICAgICAgICBjb25zdCBtZXNoID0gbmV3IFRlcnJhaW5NZXNoX2RlZmF1bHQoCiAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY2xvbmUodGVtcFRlcnJhaW5FbmNvZGluZy5jZW50ZXIsIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSksCiAgICAgICAgICB0ZW1wQnVmZmVyLAogICAgICAgICAgaW5kZXhCdWZmZXJXaXRoU2tpcnRzLAogICAgICAgICAgaW5kZXhDb3VudFdpdGhvdXRTa2lydHMsCiAgICAgICAgICB2ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMsCiAgICAgICAgICBtaW5pbXVtSGVpZ2h0LAogICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgIEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuY2xvbmUoYm91bmRpbmdTcGhlcmUsIG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCkpLAogICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKGhvcml6b25PY2NsdXNpb25Qb2ludCwgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpKSwKICAgICAgICAgIHRlbXBCdWZmZXJTdHJpZGUsCiAgICAgICAgICBPcmllbnRlZEJvdW5kaW5nQm94X2RlZmF1bHQuY2xvbmUob3JpZW50ZWRCb3VuZGluZ0JveCwgbmV3IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdCgpKSwKICAgICAgICAgIHRlbXBUZXJyYWluRW5jb2RpbmcsCiAgICAgICAgICB3ZXN0SW5kaWNlcywKICAgICAgICAgIHNvdXRoSW5kaWNlcywKICAgICAgICAgIGVhc3RJbmRpY2VzLAogICAgICAgICAgbm9ydGhJbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBhZGRTa2lydHNUb01lc2goCiAgICAgICAgICBtZXNoLAogICAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgbWluUG9zRW51LAogICAgICAgICAgbWF4UG9zRW51LAogICAgICAgICAgZW51VG9FY2VmLAogICAgICAgICAgZWNlZlRvRW51LAogICAgICAgICAgc2tpcnRIZWlnaHQKICAgICAgICApOwogICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobWVzaCk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hNaW5VViA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heFVWID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUG9seWdvbkluZGljZXMgPSBuZXcgQXJyYXkoNik7CiAgICAgIHNjcmF0Y2hVdkEgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hVdkIgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hVdkMgPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOb3JtYWxBID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsQiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5vcm1hbEMgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDZW50ZXJDYXJ0b2dyYXBoaWNVcHNhbXBsZSA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2VudGVyQ2FydGVzaWFuVXBzYW1wbGUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNTa2lydCA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljVXBzYW1wbGUgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBvc0VjZWZTa2lydCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBvc0VjZWZVcHNhbXBsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFBvc0VudVNraXJ0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoUG9zRW51VXBzYW1wbGUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNaW5pbXVtUG9zaXRpb25FTlVTa2lydCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1heGltdW1Qb3NpdGlvbkVOVVNraXJ0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTWluaW11bVBvc2l0aW9uRU5VVXBzYW1wbGUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNYXhpbXVtUG9zaXRpb25FTlVVcHNhbXBsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEVudVRvRWNlZlVwc2FtcGxlID0gbmV3IE1hdHJpeDRfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoRWNlZlRvRW51VXBzYW1wbGUgPSBuZXcgTWF0cml4NF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hVVlNraXJ0ID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVVZVcHNhbXBsZSA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEhvcml6b25PY2NsdXNpb25Qb2ludCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaEJvdW5kaW5nU3BoZXJlMyA9IG5ldyBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hPcmllbnRlZEJvdW5kaW5nQm94ID0gbmV3IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQUFCQkVudVNraXJ0ID0gbmV3IEF4aXNBbGlnbmVkQm91bmRpbmdCb3hfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsVXBzYW1wbGUgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hOb3JtYWxPY3RTa2lydCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE5vcm1hbE9jdFVwc2FtcGxlID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsU2tpcnQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hHZW9kZXRpY1N1cmZhY2VOb3JtYWxVcHNhbXBsZSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgQ2VzaXVtM0RUaWxlc1RlcnJhaW5HZW9tZXRyeVByb2Nlc3Nvci51cHNhbXBsZU1lc2ggPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHsKICAgICAgICAgIGlzRWFzdENoaWxkLAogICAgICAgICAgaXNOb3J0aENoaWxkLAogICAgICAgICAgcGFyZW50TWluaW11bUhlaWdodCwKICAgICAgICAgIHBhcmVudE1heGltdW1IZWlnaHQsCiAgICAgICAgICBza2lydEhlaWdodAogICAgICAgIH0gPSBvcHRpb25zOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLmJvb2woIm9wdGlvbnMuaXNFYXN0Q2hpbGQiLCBpc0Vhc3RDaGlsZCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YuYm9vbCgib3B0aW9ucy5pc05vcnRoQ2hpbGQiLCBpc05vcnRoQ2hpbGQpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5wYXJlbnRWZXJ0aWNlcyIsIG9wdGlvbnMucGFyZW50VmVydGljZXMpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgib3B0aW9ucy5wYXJlbnRJbmRpY2VzIiwgb3B0aW9ucy5wYXJlbnRJbmRpY2VzKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoCiAgICAgICAgICAib3B0aW9ucy5wYXJlbnRWZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMiLAogICAgICAgICAgb3B0aW9ucy5wYXJlbnRWZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMKICAgICAgICApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigKICAgICAgICAgICJvcHRpb25zLnBhcmVudEluZGV4Q291bnRXaXRob3V0U2tpcnRzIiwKICAgICAgICAgIG9wdGlvbnMucGFyZW50SW5kZXhDb3VudFdpdGhvdXRTa2lydHMKICAgICAgICApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigib3B0aW9ucy5wYXJlbnRNaW5pbXVtSGVpZ2h0IiwgcGFyZW50TWluaW11bUhlaWdodCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJvcHRpb25zLnBhcmVudE1heGltdW1IZWlnaHQiLCBwYXJlbnRNYXhpbXVtSGVpZ2h0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMucGFyZW50RW5jb2RpbmciLCBvcHRpb25zLnBhcmVudEVuY29kaW5nKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMucmVjdGFuZ2xlIiwgb3B0aW9ucy5yZWN0YW5nbGUpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigib3B0aW9ucy5za2lydEhlaWdodCIsIHNraXJ0SGVpZ2h0KTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoIm9wdGlvbnMuZWxsaXBzb2lkIiwgb3B0aW9ucy5lbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IGluZGV4Q291bnQgPSBvcHRpb25zLnBhcmVudEluZGV4Q291bnRXaXRob3V0U2tpcnRzOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBvcHRpb25zLnBhcmVudEluZGljZXM7CiAgICAgICAgY29uc3QgdmVydGV4Q291bnQgPSBvcHRpb25zLnBhcmVudFZlcnRleENvdW50V2l0aG91dFNraXJ0czsKICAgICAgICBjb25zdCB2ZXJ0ZXhCdWZmZXIgPSBvcHRpb25zLnBhcmVudFZlcnRpY2VzOwogICAgICAgIGNvbnN0IGVuY29kaW5nID0gVGVycmFpbkVuY29kaW5nX2RlZmF1bHQuY2xvbmUoCiAgICAgICAgICBvcHRpb25zLnBhcmVudEVuY29kaW5nLAogICAgICAgICAgbmV3IFRlcnJhaW5FbmNvZGluZ19kZWZhdWx0KCkKICAgICAgICApOwogICAgICAgIGNvbnN0IGhhc1ZlcnRleE5vcm1hbHMgPSBlbmNvZGluZy5oYXNWZXJ0ZXhOb3JtYWxzOwogICAgICAgIGNvbnN0IGhhc1dlYk1lcmNhdG9yVCA9IGVuY29kaW5nLmhhc1dlYk1lcmNhdG9yVDsKICAgICAgICBjb25zdCBleGFnZ2VyYXRpb24gPSBlbmNvZGluZy5leGFnZ2VyYXRpb247CiAgICAgICAgY29uc3QgZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQgPSBlbmNvZGluZy5leGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodDsKICAgICAgICBjb25zdCBoYXNFeGFnZ2VyYXRpb24gPSBleGFnZ2VyYXRpb24gIT09IDE7CiAgICAgICAgY29uc3QgaGFzR2VvZGV0aWNTdXJmYWNlTm9ybWFscyA9IGhhc0V4YWdnZXJhdGlvbjsKICAgICAgICBjb25zdCB1cHNhbXBsZVJlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKG9wdGlvbnMucmVjdGFuZ2xlLCBuZXcgUmVjdGFuZ2xlX2RlZmF1bHQoKSk7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUob3B0aW9ucy5lbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZFRyaUlEcyA9IFtdOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZFVWcyA9IFtdOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZEJhcnlzID0gW107CiAgICAgICAgY29uc3QgdXBzYW1wbGVkSW5kaWNlcyA9IFtdOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZFdlc3RJbmRpY2VzID0gW107CiAgICAgICAgY29uc3QgdXBzYW1wbGVkU291dGhJbmRpY2VzID0gW107CiAgICAgICAgY29uc3QgdXBzYW1wbGVkRWFzdEluZGljZXMgPSBbXTsKICAgICAgICBjb25zdCB1cHNhbXBsZWROb3J0aEluZGljZXMgPSBbXTsKICAgICAgICBjbGlwVGlsZUZyb21RdWFkcmFudCgKICAgICAgICAgIGlzRWFzdENoaWxkLAogICAgICAgICAgaXNOb3J0aENoaWxkLAogICAgICAgICAgaW5kZXhDb3VudCwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICB2ZXJ0ZXhDb3VudCwKICAgICAgICAgIHZlcnRleEJ1ZmZlciwKICAgICAgICAgIGVuY29kaW5nLAogICAgICAgICAgdXBzYW1wbGVkSW5kaWNlcywKICAgICAgICAgIHVwc2FtcGxlZFdlc3RJbmRpY2VzLAogICAgICAgICAgdXBzYW1wbGVkU291dGhJbmRpY2VzLAogICAgICAgICAgdXBzYW1wbGVkRWFzdEluZGljZXMsCiAgICAgICAgICB1cHNhbXBsZWROb3J0aEluZGljZXMsCiAgICAgICAgICB1cHNhbXBsZWRUcmlJRHMsCiAgICAgICAgICB1cHNhbXBsZWRCYXJ5cywKICAgICAgICAgIHVwc2FtcGxlZFVWcwogICAgICAgICk7CiAgICAgICAgY29uc3QgYXBwcm94aW1hdGVDZW50ZXJDYXJ0b2dyYXBoaWMgPSBSZWN0YW5nbGVfZGVmYXVsdC5jZW50ZXIoCiAgICAgICAgICB1cHNhbXBsZVJlY3RhbmdsZSwKICAgICAgICAgIHNjcmF0Y2hDZW50ZXJDYXJ0b2dyYXBoaWNVcHNhbXBsZQogICAgICAgICk7CiAgICAgICAgYXBwcm94aW1hdGVDZW50ZXJDYXJ0b2dyYXBoaWMuaGVpZ2h0ID0gMC41ICogKHBhcmVudE1pbmltdW1IZWlnaHQgKyBwYXJlbnRNYXhpbXVtSGVpZ2h0KTsKICAgICAgICBjb25zdCBhcHByb3hpbWF0ZUNlbnRlclBvc2l0aW9uID0gQ2FydG9ncmFwaGljX2RlZmF1bHQudG9DYXJ0ZXNpYW4oCiAgICAgICAgICBhcHByb3hpbWF0ZUNlbnRlckNhcnRvZ3JhcGhpYywKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHNjcmF0Y2hDZW50ZXJDYXJ0ZXNpYW5VcHNhbXBsZQogICAgICAgICk7CiAgICAgICAgY29uc3QgdXBzYW1wbGVkVmVydGV4Q291bnRXaXRob3V0U2tpcnRzID0gdXBzYW1wbGVkVHJpSURzLmxlbmd0aDsKICAgICAgICBjb25zdCB1cHNhbXBsZWRUZXJyYWluRW5jb2RpbmcgPSBuZXcgVGVycmFpbkVuY29kaW5nX2RlZmF1bHQoCiAgICAgICAgICBhcHByb3hpbWF0ZUNlbnRlclBvc2l0aW9uLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgdm9pZCAwLAogICAgICAgICAgaGFzVmVydGV4Tm9ybWFscywKICAgICAgICAgIGhhc1dlYk1lcmNhdG9yVCwKICAgICAgICAgIGhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMsCiAgICAgICAgICBleGFnZ2VyYXRpb24sCiAgICAgICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgICAgICk7CiAgICAgICAgY29uc3QgdXBzYW1wbGVkVmVydGV4QnVmZmVyU3RyaWRlID0gdXBzYW1wbGVkVGVycmFpbkVuY29kaW5nLnN0cmlkZTsKICAgICAgICBjb25zdCB1cHNhbXBsZWRTa2lydFZlcnRleENvdW50ID0gVGVycmFpblByb3ZpZGVyX2RlZmF1bHQuZ2V0U2tpcnRWZXJ0ZXhDb3VudCgKICAgICAgICAgIHVwc2FtcGxlZFdlc3RJbmRpY2VzLAogICAgICAgICAgdXBzYW1wbGVkU291dGhJbmRpY2VzLAogICAgICAgICAgdXBzYW1wbGVkRWFzdEluZGljZXMsCiAgICAgICAgICB1cHNhbXBsZWROb3J0aEluZGljZXMKICAgICAgICApOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZFZlcnRleENvdW50V2l0aFNraXJ0cyA9IHVwc2FtcGxlZFZlcnRleENvdW50V2l0aG91dFNraXJ0cyArIHVwc2FtcGxlZFNraXJ0VmVydGV4Q291bnQ7CiAgICAgICAgY29uc3QgdXBzYW1wbGVkSW5kZXhDb3VudFdpdGhvdXRTa2lydHMgPSB1cHNhbXBsZWRJbmRpY2VzLmxlbmd0aDsKICAgICAgICBjb25zdCB1cHNhbXBsZWRTa2lydEluZGV4Q291bnQgPSBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdC5nZXRTa2lydEluZGV4Q291bnRXaXRoRmlsbGVkQ29ybmVycygKICAgICAgICAgIHVwc2FtcGxlZFNraXJ0VmVydGV4Q291bnQKICAgICAgICApOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZEluZGV4Q291bnRXaXRoU2tpcnRzID0gdXBzYW1wbGVkSW5kZXhDb3VudFdpdGhvdXRTa2lydHMgKyB1cHNhbXBsZWRTa2lydEluZGV4Q291bnQ7CiAgICAgICAgY29uc3QgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzID0gdXBzYW1wbGVkVmVydGV4Q291bnRXaXRoU2tpcnRzIDw9IDY1NTM1ID8gVWludDE2QXJyYXkgOiBVaW50MzJBcnJheTsKICAgICAgICBjb25zdCB1cHNhbXBsZWRJbmRleEJ1ZmZlciA9IG5ldyBTaXplZEluZGV4VHlwZVdpdGhTa2lydHMoCiAgICAgICAgICB1cHNhbXBsZWRJbmRleENvdW50V2l0aFNraXJ0cwogICAgICAgICk7CiAgICAgICAgdXBzYW1wbGVkSW5kZXhCdWZmZXIuc2V0KHVwc2FtcGxlZEluZGljZXMpOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZFdlc3RJbmRpY2VzQnVmZmVyID0gbmV3IFNpemVkSW5kZXhUeXBlV2l0aFNraXJ0cygKICAgICAgICAgIHVwc2FtcGxlZFdlc3RJbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBjb25zdCB1cHNhbXBsZWRTb3V0aEluZGljZXNCdWZmZXIgPSBuZXcgU2l6ZWRJbmRleFR5cGVXaXRoU2tpcnRzKAogICAgICAgICAgdXBzYW1wbGVkU291dGhJbmRpY2VzCiAgICAgICAgKTsKICAgICAgICBjb25zdCB1cHNhbXBsZWRFYXN0SW5kaWNlc0J1ZmZlciA9IG5ldyBTaXplZEluZGV4VHlwZVdpdGhTa2lydHMoCiAgICAgICAgICB1cHNhbXBsZWRFYXN0SW5kaWNlcwogICAgICAgICk7CiAgICAgICAgY29uc3QgdXBzYW1wbGVkTm9ydGhJbmRpY2VzQnVmZmVyID0gbmV3IFNpemVkSW5kZXhUeXBlV2l0aFNraXJ0cygKICAgICAgICAgIHVwc2FtcGxlZE5vcnRoSW5kaWNlcwogICAgICAgICk7CiAgICAgICAgY29uc3QgdXBzYW1wbGVkVmVydGV4QnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSgKICAgICAgICAgIHVwc2FtcGxlZFZlcnRleENvdW50V2l0aFNraXJ0cyAqIHVwc2FtcGxlZFZlcnRleEJ1ZmZlclN0cmlkZQogICAgICAgICk7CiAgICAgICAgbGV0IHVwc2FtcGxlZFZlcnRleEJ1ZmZlck9mZnNldCA9IDA7CiAgICAgICAgY29uc3QgZW51VG9FY2VmID0gVHJhbnNmb3Jtc19kZWZhdWx0LmVhc3ROb3J0aFVwVG9GaXhlZEZyYW1lKAogICAgICAgICAgYXBwcm94aW1hdGVDZW50ZXJQb3NpdGlvbiwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHNjcmF0Y2hFbnVUb0VjZWZVcHNhbXBsZQogICAgICAgICk7CiAgICAgICAgY29uc3QgZWNlZlRvRW51ID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2VUcmFuc2Zvcm1hdGlvbigKICAgICAgICAgIGVudVRvRWNlZiwKICAgICAgICAgIHNjcmF0Y2hFY2VmVG9FbnVVcHNhbXBsZQogICAgICAgICk7CiAgICAgICAgY29uc3QgbWluaW11bUxvbmdpdHVkZSA9IHVwc2FtcGxlUmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgY29uc3QgbWF4aW11bUxvbmdpdHVkZSA9IHVwc2FtcGxlUmVjdGFuZ2xlLmVhc3Q7CiAgICAgICAgY29uc3QgbWluaW11bUxhdGl0dWRlID0gdXBzYW1wbGVSZWN0YW5nbGUuc291dGg7CiAgICAgICAgY29uc3QgbWF4aW11bUxhdGl0dWRlID0gdXBzYW1wbGVSZWN0YW5nbGUubm9ydGg7CiAgICAgICAgY29uc3Qgc291dGhNZXJjYXRvckFuZ2xlID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZShtaW5pbXVtTGF0aXR1ZGUpOwogICAgICAgIGNvbnN0IG5vcnRoTWVyY2F0b3JBbmdsZSA9IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUobWF4aW11bUxhdGl0dWRlKTsKICAgICAgICBjb25zdCBvbmVPdmVyTWVyY2F0b3JIZWlnaHQgPSAxIC8gKG5vcnRoTWVyY2F0b3JBbmdsZSAtIHNvdXRoTWVyY2F0b3JBbmdsZSk7CiAgICAgICAgbGV0IG1pbmltdW1IZWlnaHQgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IG1heGltdW1IZWlnaHQgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IG1pblBvc0VudSA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksCiAgICAgICAgICBzY3JhdGNoTWluaW11bVBvc2l0aW9uRU5VVXBzYW1wbGUKICAgICAgICApOwogICAgICAgIGxldCBtYXhQb3NFbnUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUVsZW1lbnRzKAogICAgICAgICAgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgICAgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgICAgTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgICAgc2NyYXRjaE1heGltdW1Qb3NpdGlvbkVOVVVwc2FtcGxlCiAgICAgICAgKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgdXBzYW1wbGVkVmVydGV4Q291bnRXaXRob3V0U2tpcnRzOyBpMisrKSB7CiAgICAgICAgICBjb25zdCB0cmlJZCA9IHVwc2FtcGxlZFRyaUlEc1tpMl07CiAgICAgICAgICBjb25zdCBpbmRleEEgPSBpbmRpY2VzW3RyaUlkICogMyArIDBdOwogICAgICAgICAgY29uc3QgaW5kZXhCID0gaW5kaWNlc1t0cmlJZCAqIDMgKyAxXTsKICAgICAgICAgIGNvbnN0IGluZGV4QyA9IGluZGljZXNbdHJpSWQgKiAzICsgMl07CiAgICAgICAgICBjb25zdCB1diA9IHNjcmF0Y2hVVlVwc2FtcGxlOwogICAgICAgICAgdXYueCA9IHVwc2FtcGxlZFVWc1tpMiAqIDIgKyAwXTsKICAgICAgICAgIHV2LnkgPSB1cHNhbXBsZWRVVnNbaTIgKiAyICsgMV07CiAgICAgICAgICBjb25zdCB1NCA9IHV2Lng7CiAgICAgICAgICBjb25zdCB2NCA9IHV2Lnk7CiAgICAgICAgICBjb25zdCBiYXJ5QSA9IHVwc2FtcGxlZEJhcnlzW2kyICogMiArIDBdOwogICAgICAgICAgY29uc3QgYmFyeUIgPSB1cHNhbXBsZWRCYXJ5c1tpMiAqIDIgKyAxXTsKICAgICAgICAgIGNvbnN0IGJhcnlDID0gMSAtIGJhcnlBIC0gYmFyeUI7CiAgICAgICAgICBjb25zdCBoZWlnaHRBID0gZW5jb2RpbmcuZGVjb2RlSGVpZ2h0KHZlcnRleEJ1ZmZlciwgaW5kZXhBKTsKICAgICAgICAgIGNvbnN0IGhlaWdodEIgPSBlbmNvZGluZy5kZWNvZGVIZWlnaHQodmVydGV4QnVmZmVyLCBpbmRleEIpOwogICAgICAgICAgY29uc3QgaGVpZ2h0QyA9IGVuY29kaW5nLmRlY29kZUhlaWdodCh2ZXJ0ZXhCdWZmZXIsIGluZGV4Qyk7CiAgICAgICAgICBjb25zdCBoZWlnaHQgPSBoZWlnaHRBICogYmFyeUEgKyBoZWlnaHRCICogYmFyeUIgKyBoZWlnaHRDICogYmFyeUM7CiAgICAgICAgICBtaW5pbXVtSGVpZ2h0ID0gTWF0aC5taW4oaGVpZ2h0LCBtaW5pbXVtSGVpZ2h0KTsKICAgICAgICAgIG1heGltdW1IZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIG1heGltdW1IZWlnaHQpOwogICAgICAgICAgY29uc3QgbG9uID0gTWF0aF9kZWZhdWx0LmxlcnAobWluaW11bUxvbmdpdHVkZSwgbWF4aW11bUxvbmdpdHVkZSwgdTQpOwogICAgICAgICAgY29uc3QgbGF0ID0gTWF0aF9kZWZhdWx0LmxlcnAobWluaW11bUxhdGl0dWRlLCBtYXhpbXVtTGF0aXR1ZGUsIHY0KTsKICAgICAgICAgIGNvbnN0IGNhcnRvID0gQ2FydG9ncmFwaGljX2RlZmF1bHQuZnJvbVJhZGlhbnMoCiAgICAgICAgICAgIGxvbiwKICAgICAgICAgICAgbGF0LAogICAgICAgICAgICBoZWlnaHQsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWNVcHNhbXBsZQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gQ2FydG9ncmFwaGljX2RlZmF1bHQudG9DYXJ0ZXNpYW4oCiAgICAgICAgICAgIGNhcnRvLAogICAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICAgIHNjcmF0Y2hQb3NFY2VmVXBzYW1wbGUKICAgICAgICAgICk7CiAgICAgICAgICBjb25zdCBwb3NFbnUgPSBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICAgICAgICBlY2VmVG9FbnUsCiAgICAgICAgICAgIHBvc2l0aW9uLAogICAgICAgICAgICBzY3JhdGNoUG9zRW51VXBzYW1wbGUKICAgICAgICAgICk7CiAgICAgICAgICBtaW5Qb3NFbnUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubWluaW11bUJ5Q29tcG9uZW50KHBvc0VudSwgbWluUG9zRW51LCBtaW5Qb3NFbnUpOwogICAgICAgICAgbWF4UG9zRW51ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1heGltdW1CeUNvbXBvbmVudChwb3NFbnUsIG1heFBvc0VudSwgbWF4UG9zRW51KTsKICAgICAgICAgIGxldCBub3JtYWxPY3Q7CiAgICAgICAgICBpZiAoaGFzVmVydGV4Tm9ybWFscykgewogICAgICAgICAgICBjb25zdCBub3JtYWxBID0gZW5jb2RpbmcuZGVjb2RlTm9ybWFsKAogICAgICAgICAgICAgIHZlcnRleEJ1ZmZlciwKICAgICAgICAgICAgICBpbmRleEEsCiAgICAgICAgICAgICAgc2NyYXRjaE5vcm1hbEEKICAgICAgICAgICAgKTsKICAgICAgICAgICAgY29uc3Qgbm9ybWFsQiA9IGVuY29kaW5nLmRlY29kZU5vcm1hbCgKICAgICAgICAgICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgICAgICAgICAgaW5kZXhCLAogICAgICAgICAgICAgIHNjcmF0Y2hOb3JtYWxCCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGNvbnN0IG5vcm1hbEMgPSBlbmNvZGluZy5kZWNvZGVOb3JtYWwoCiAgICAgICAgICAgICAgdmVydGV4QnVmZmVyLAogICAgICAgICAgICAgIGluZGV4QywKICAgICAgICAgICAgICBzY3JhdGNoTm9ybWFsQwogICAgICAgICAgICApOwogICAgICAgICAgICBsZXQgbm9ybWFsMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tRWxlbWVudHMoCiAgICAgICAgICAgICAgbm9ybWFsQS54ICogYmFyeUEgKyBub3JtYWxCLnggKiBiYXJ5QiArIG5vcm1hbEMueCAqIGJhcnlDLAogICAgICAgICAgICAgIG5vcm1hbEEueSAqIGJhcnlBICsgbm9ybWFsQi55ICogYmFyeUIgKyBub3JtYWxDLnkgKiBiYXJ5QywKICAgICAgICAgICAgICBub3JtYWxBLnogKiBiYXJ5QSArIG5vcm1hbEIueiAqIGJhcnlCICsgbm9ybWFsQy56ICogYmFyeUMsCiAgICAgICAgICAgICAgc2NyYXRjaE5vcm1hbFVwc2FtcGxlCiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG5vcm1hbDIgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKG5vcm1hbDIsIHNjcmF0Y2hOb3JtYWxVcHNhbXBsZSk7CiAgICAgICAgICAgIG5vcm1hbE9jdCA9IEF0dHJpYnV0ZUNvbXByZXNzaW9uX2RlZmF1bHQub2N0RW5jb2RlKAogICAgICAgICAgICAgIG5vcm1hbDIsCiAgICAgICAgICAgICAgc2NyYXRjaE5vcm1hbE9jdFVwc2FtcGxlCiAgICAgICAgICAgICk7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgd2ViTWVyY2F0b3JUOwogICAgICAgICAgaWYgKGhhc1dlYk1lcmNhdG9yVCkgewogICAgICAgICAgICBjb25zdCBtZXJjYXRvckFuZ2xlID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZShsYXQpOwogICAgICAgICAgICB3ZWJNZXJjYXRvclQgPSAobWVyY2F0b3JBbmdsZSAtIHNvdXRoTWVyY2F0b3JBbmdsZSkgKiBvbmVPdmVyTWVyY2F0b3JIZWlnaHQ7CiAgICAgICAgICB9CiAgICAgICAgICBsZXQgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsOwogICAgICAgICAgaWYgKGhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbCgKICAgICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgICBzY3JhdGNoR2VvZGV0aWNTdXJmYWNlTm9ybWFsVXBzYW1wbGUKICAgICAgICAgICAgKTsKICAgICAgICAgIH0KICAgICAgICAgIHVwc2FtcGxlZFZlcnRleEJ1ZmZlck9mZnNldCA9IHVwc2FtcGxlZFRlcnJhaW5FbmNvZGluZy5lbmNvZGUoCiAgICAgICAgICAgIHVwc2FtcGxlZFZlcnRleEJ1ZmZlciwKICAgICAgICAgICAgdXBzYW1wbGVkVmVydGV4QnVmZmVyT2Zmc2V0LAogICAgICAgICAgICBwb3NpdGlvbiwKICAgICAgICAgICAgdXYsCiAgICAgICAgICAgIGhlaWdodCwKICAgICAgICAgICAgbm9ybWFsT2N0LAogICAgICAgICAgICB3ZWJNZXJjYXRvclQsCiAgICAgICAgICAgIGdlb2RldGljU3VyZmFjZU5vcm1hbAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3Qgb3JpZW50ZWRCb3VuZGluZ0JveCA9IE9yaWVudGVkQm91bmRpbmdCb3hfZGVmYXVsdC5mcm9tUmVjdGFuZ2xlKAogICAgICAgICAgdXBzYW1wbGVSZWN0YW5nbGUsCiAgICAgICAgICBtaW5pbXVtSGVpZ2h0LAogICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgIGVsbGlwc29pZCwKICAgICAgICAgIHNjcmF0Y2hPcmllbnRlZEJvdW5kaW5nQm94CiAgICAgICAgKTsKICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZSA9IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKAogICAgICAgICAgdXBzYW1wbGVkVmVydGV4QnVmZmVyLAogICAgICAgICAgdXBzYW1wbGVkVGVycmFpbkVuY29kaW5nLmNlbnRlciwKICAgICAgICAgIHVwc2FtcGxlZFZlcnRleEJ1ZmZlclN0cmlkZSwKICAgICAgICAgIHNjcmF0Y2hCb3VuZGluZ1NwaGVyZTMKICAgICAgICApOwogICAgICAgIGNvbnN0IG9jY2x1ZGVyID0gbmV3IEVsbGlwc29pZGFsT2NjbHVkZXJfZGVmYXVsdChlbGxpcHNvaWQpOwogICAgICAgIGNvbnN0IGhvcml6b25PY2NsdXNpb25Qb2ludCA9IG9jY2x1ZGVyLmNvbXB1dGVIb3Jpem9uQ3VsbGluZ1BvaW50RnJvbVZlcnRpY2VzUG9zc2libHlVbmRlckVsbGlwc29pZCgKICAgICAgICAgIHVwc2FtcGxlZFRlcnJhaW5FbmNvZGluZy5jZW50ZXIsCiAgICAgICAgICAvLyB2ZWN0b3IgZnJvbSBlbGxpcHNvaWQgY2VudGVyIHRvIGhvcml6b24gb2NjbHVzaW9uIHBvaW50CiAgICAgICAgICB1cHNhbXBsZWRWZXJ0ZXhCdWZmZXIsCiAgICAgICAgICB1cHNhbXBsZWRWZXJ0ZXhCdWZmZXJTdHJpZGUsCiAgICAgICAgICB1cHNhbXBsZWRUZXJyYWluRW5jb2RpbmcuY2VudGVyLAogICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgIHNjcmF0Y2hIb3Jpem9uT2NjbHVzaW9uUG9pbnQKICAgICAgICApOwogICAgICAgIGNvbnN0IHVwc2FtcGxlZE1lc2ggPSBuZXcgVGVycmFpbk1lc2hfZGVmYXVsdCgKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZSh1cHNhbXBsZWRUZXJyYWluRW5jb2RpbmcuY2VudGVyLCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCkpLAogICAgICAgICAgdXBzYW1wbGVkVmVydGV4QnVmZmVyLAogICAgICAgICAgdXBzYW1wbGVkSW5kZXhCdWZmZXIsCiAgICAgICAgICB1cHNhbXBsZWRJbmRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgICAgIHVwc2FtcGxlZFZlcnRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgICAgIG1pbmltdW1IZWlnaHQsCiAgICAgICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICAgICAgdXBzYW1wbGVSZWN0YW5nbGUsCiAgICAgICAgICBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmNsb25lKGJvdW5kaW5nU3BoZXJlKSwKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbG9uZShob3Jpem9uT2NjbHVzaW9uUG9pbnQpLAogICAgICAgICAgdXBzYW1wbGVkVmVydGV4QnVmZmVyU3RyaWRlLAogICAgICAgICAgT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmNsb25lKG9yaWVudGVkQm91bmRpbmdCb3gpLAogICAgICAgICAgdXBzYW1wbGVkVGVycmFpbkVuY29kaW5nLAogICAgICAgICAgdXBzYW1wbGVkV2VzdEluZGljZXNCdWZmZXIsCiAgICAgICAgICB1cHNhbXBsZWRTb3V0aEluZGljZXNCdWZmZXIsCiAgICAgICAgICB1cHNhbXBsZWRFYXN0SW5kaWNlc0J1ZmZlciwKICAgICAgICAgIHVwc2FtcGxlZE5vcnRoSW5kaWNlc0J1ZmZlcgogICAgICAgICk7CiAgICAgICAgYWRkU2tpcnRzVG9NZXNoKAogICAgICAgICAgdXBzYW1wbGVkTWVzaCwKICAgICAgICAgIHVwc2FtcGxlUmVjdGFuZ2xlLAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgbWluUG9zRW51LAogICAgICAgICAgbWF4UG9zRW51LAogICAgICAgICAgZW51VG9FY2VmLAogICAgICAgICAgZWNlZlRvRW51LAogICAgICAgICAgc2tpcnRIZWlnaHQKICAgICAgICApOwogICAgICAgIHJldHVybiB1cHNhbXBsZWRNZXNoOwogICAgICB9OwogICAgICBFREdFX0lEX0xFRlQgPSAwOwogICAgICBFREdFX0lEX1RPUCA9IDE7CiAgICAgIEVER0VfSURfUklHSFQgPSAyOwogICAgICBFREdFX0lEX0JPVFRPTSA9IDM7CiAgICAgIEVER0VfQ09VTlQgPSA0OwogICAgICBzY3JhdGNoSW50ZXJzZWN0aW9uID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoSW5CYXJ5cyA9IFsKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKQogICAgICBdOwogICAgICBzY3JhdGNoSW5Qb2ludHMgPSBbCiAgICAgICAgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCkKICAgICAgXTsKICAgICAgc2NyYXRjaE91dEJhcnlzID0gWwogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpCiAgICAgIF07CiAgICAgIHNjcmF0Y2hPdXRQb2ludHMgPSBbCiAgICAgICAgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjJfZGVmYXVsdCgpLAogICAgICAgIG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCkKICAgICAgXTsKICAgICAgc2NyYXRjaFBvbHlnb24gPSB7CiAgICAgICAgbGVuZ3RoOiAwLAogICAgICAgIGNvb3JkaW5hdGVzOiBbCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCksCiAgICAgICAgICBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCkKICAgICAgICBdLAogICAgICAgIGJhcnljZW50cmljQ29vcmRpbmF0ZXM6IFsKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKQogICAgICAgIF0KICAgICAgfTsKICAgICAgbG9va1VwVGFibGVCYXJ5VG9QcmltID0gWwogICAgICAgIFtdLAogICAgICAgIC8vIDAwMAogICAgICAgIFswXSwKICAgICAgICAvLyAwMDEKICAgICAgICBbMV0sCiAgICAgICAgLy8gMDEwCiAgICAgICAgWzAsIDFdLAogICAgICAgIC8vIDAxMQogICAgICAgIFsyXSwKICAgICAgICAvLyAxMDAKICAgICAgICBbMCwgMl0sCiAgICAgICAgLy8gMTAxCiAgICAgICAgWzEsIDJdLAogICAgICAgIC8vIDExMAogICAgICAgIFswLCAxLCAyXQogICAgICAgIC8vIDExMQogICAgICBdOwogICAgICBDZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yX2RlZmF1bHQgPSBDZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4uanMKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW5fZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGNyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbihvcHRpb25zLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCBtZXNoUHJvbWlzZSA9IENlc2l1bTNEVGlsZXNUZXJyYWluR2VvbWV0cnlQcm9jZXNzb3JfZGVmYXVsdC5jcmVhdGVNZXNoKG9wdGlvbnMpOwogICAgcmV0dXJuIG1lc2hQcm9taXNlLnRoZW4oZnVuY3Rpb24obWVzaCkgewogICAgICBjb25zdCB2ZXJ0aWNlc0J1ZmZlciA9IG1lc2gudmVydGljZXMuYnVmZmVyOwogICAgICBjb25zdCBpbmRpY2VzQnVmZmVyID0gbWVzaC5pbmRpY2VzLmJ1ZmZlcjsKICAgICAgY29uc3Qgd2VzdEluZGljZXNCdWZmZXIgPSBtZXNoLndlc3RJbmRpY2VzU291dGhUb05vcnRoLmJ1ZmZlcjsKICAgICAgY29uc3Qgc291dGhJbmRpY2VzQnVmZmVyID0gbWVzaC5zb3V0aEluZGljZXNFYXN0VG9XZXN0LmJ1ZmZlcjsKICAgICAgY29uc3QgZWFzdEluZGljZXNCdWZmZXIgPSBtZXNoLmVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLmJ1ZmZlcjsKICAgICAgY29uc3Qgbm9ydGhJbmRpY2VzQnVmZmVyID0gbWVzaC5ub3J0aEluZGljZXNXZXN0VG9FYXN0LmJ1ZmZlcjsKICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICAgIHZlcnRpY2VzQnVmZmVyLAogICAgICAgIGluZGljZXNCdWZmZXIsCiAgICAgICAgd2VzdEluZGljZXNCdWZmZXIsCiAgICAgICAgc291dGhJbmRpY2VzQnVmZmVyLAogICAgICAgIGVhc3RJbmRpY2VzQnVmZmVyLAogICAgICAgIG5vcnRoSW5kaWNlc0J1ZmZlcgogICAgICApOwogICAgICByZXR1cm4gewogICAgICAgIHZlcnRpY2VzQnVmZmVyLAogICAgICAgIGluZGljZXNCdWZmZXIsCiAgICAgICAgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzOiBtZXNoLnZlcnRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgICBpbmRleENvdW50V2l0aG91dFNraXJ0czogbWVzaC5pbmRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgICBlbmNvZGluZzogbWVzaC5lbmNvZGluZywKICAgICAgICB3ZXN0SW5kaWNlc0J1ZmZlciwKICAgICAgICBzb3V0aEluZGljZXNCdWZmZXIsCiAgICAgICAgZWFzdEluZGljZXNCdWZmZXIsCiAgICAgICAgbm9ydGhJbmRpY2VzQnVmZmVyCiAgICAgIH07CiAgICB9KTsKICB9CiAgdmFyIGNyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4gPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluLmpzIigpIHsKICAgICAgaW5pdF9DZXNpdW0zRFRpbGVzVGVycmFpbkdlb21ldHJ5UHJvY2Vzc29yKCk7CiAgICAgIGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcigpOwogICAgICBjcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbl9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KAogICAgICAgIGNyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluCiAgICAgICk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXIuanMKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXJfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBpbmRleE9mRXBzaWxvbihhcnIsIGVsZW0sIGVsZW1UeXBlKSB7CiAgICBlbGVtVHlwZSA9IGVsZW1UeXBlID8/IE1hdGhfZGVmYXVsdDsKICAgIGNvbnN0IGNvdW50ID0gYXJyLmxlbmd0aDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBjb3VudDsgKytpMikgewogICAgICBpZiAoZWxlbVR5cGUuZXF1YWxzRXBzaWxvbihhcnJbaTJdLCBlbGVtLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjEyKSkgewogICAgICAgIHJldHVybiBpMjsKICAgICAgfQogICAgfQogICAgcmV0dXJuIC0xOwogIH0KICBmdW5jdGlvbiBjcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXIocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgcGFyYW1ldGVycy5lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShwYXJhbWV0ZXJzLmVsbGlwc29pZCk7CiAgICBwYXJhbWV0ZXJzLnJlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHBhcmFtZXRlcnMucmVjdGFuZ2xlKTsKICAgIGNvbnN0IHN0YXRpc3RpY3MyID0gcHJvY2Vzc0J1ZmZlcigKICAgICAgcGFyYW1ldGVycy5idWZmZXIsCiAgICAgIHBhcmFtZXRlcnMucmVsYXRpdmVUb0NlbnRlciwKICAgICAgcGFyYW1ldGVycy5lbGxpcHNvaWQsCiAgICAgIHBhcmFtZXRlcnMucmVjdGFuZ2xlLAogICAgICBwYXJhbWV0ZXJzLm5hdGl2ZVJlY3RhbmdsZSwKICAgICAgcGFyYW1ldGVycy5leGFnZ2VyYXRpb24sCiAgICAgIHBhcmFtZXRlcnMuZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQsCiAgICAgIHBhcmFtZXRlcnMuc2tpcnRIZWlnaHQsCiAgICAgIHBhcmFtZXRlcnMuaW5jbHVkZVdlYk1lcmNhdG9yVCwKICAgICAgcGFyYW1ldGVycy5uZWdhdGl2ZUFsdGl0dWRlRXhwb25lbnRCaWFzLAogICAgICBwYXJhbWV0ZXJzLm5lZ2F0aXZlRWxldmF0aW9uVGhyZXNob2xkCiAgICApOwogICAgY29uc3QgdmVydGljZXMgPSBzdGF0aXN0aWNzMi52ZXJ0aWNlczsKICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaCh2ZXJ0aWNlcy5idWZmZXIpOwogICAgY29uc3QgaW5kaWNlcyA9IHN0YXRpc3RpY3MyLmluZGljZXM7CiAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goaW5kaWNlcy5idWZmZXIpOwogICAgcmV0dXJuIHsKICAgICAgdmVydGljZXM6IHZlcnRpY2VzLmJ1ZmZlciwKICAgICAgaW5kaWNlczogaW5kaWNlcy5idWZmZXIsCiAgICAgIG51bWJlck9mQXR0cmlidXRlczogc3RhdGlzdGljczIuZW5jb2Rpbmcuc3RyaWRlLAogICAgICBtaW5pbXVtSGVpZ2h0OiBzdGF0aXN0aWNzMi5taW5pbXVtSGVpZ2h0LAogICAgICBtYXhpbXVtSGVpZ2h0OiBzdGF0aXN0aWNzMi5tYXhpbXVtSGVpZ2h0LAogICAgICBib3VuZGluZ1NwaGVyZTNEOiBzdGF0aXN0aWNzMi5ib3VuZGluZ1NwaGVyZTNELAogICAgICBvcmllbnRlZEJvdW5kaW5nQm94OiBzdGF0aXN0aWNzMi5vcmllbnRlZEJvdW5kaW5nQm94LAogICAgICBvY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZTogc3RhdGlzdGljczIub2NjbHVkZWVQb2ludEluU2NhbGVkU3BhY2UsCiAgICAgIGVuY29kaW5nOiBzdGF0aXN0aWNzMi5lbmNvZGluZywKICAgICAgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzOiBzdGF0aXN0aWNzMi52ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMsCiAgICAgIGluZGV4Q291bnRXaXRob3V0U2tpcnRzOiBzdGF0aXN0aWNzMi5pbmRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgd2VzdEluZGljZXNTb3V0aFRvTm9ydGg6IHN0YXRpc3RpY3MyLndlc3RJbmRpY2VzU291dGhUb05vcnRoLAogICAgICBzb3V0aEluZGljZXNFYXN0VG9XZXN0OiBzdGF0aXN0aWNzMi5zb3V0aEluZGljZXNFYXN0VG9XZXN0LAogICAgICBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aDogc3RhdGlzdGljczIuZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3Q6IHN0YXRpc3RpY3MyLm5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QKICAgIH07CiAgfQogIGZ1bmN0aW9uIHByb2Nlc3NCdWZmZXIoYnVmZmVyLCByZWxhdGl2ZVRvQ2VudGVyLCBlbGxpcHNvaWQsIHJlY3RhbmdsZSwgbmF0aXZlUmVjdGFuZ2xlLCBleGFnZ2VyYXRpb24sIGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0LCBza2lydEhlaWdodCwgaW5jbHVkZVdlYk1lcmNhdG9yVCwgbmVnYXRpdmVBbHRpdHVkZUV4cG9uZW50QmlhcywgbmVnYXRpdmVFbGV2YXRpb25UaHJlc2hvbGQpIHsKICAgIGxldCBnZW9ncmFwaGljV2VzdDsKICAgIGxldCBnZW9ncmFwaGljU291dGg7CiAgICBsZXQgZ2VvZ3JhcGhpY0Vhc3Q7CiAgICBsZXQgZ2VvZ3JhcGhpY05vcnRoOwogICAgbGV0IHJlY3RhbmdsZVdpZHRoLCByZWN0YW5nbGVIZWlnaHQ7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgIGdlb2dyYXBoaWNXZXN0ID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUud2VzdCk7CiAgICAgIGdlb2dyYXBoaWNTb3V0aCA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMobmF0aXZlUmVjdGFuZ2xlLnNvdXRoKTsKICAgICAgZ2VvZ3JhcGhpY0Vhc3QgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKG5hdGl2ZVJlY3RhbmdsZS5lYXN0KTsKICAgICAgZ2VvZ3JhcGhpY05vcnRoID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUubm9ydGgpOwogICAgICByZWN0YW5nbGVXaWR0aCA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMocmVjdGFuZ2xlLndpZHRoKTsKICAgICAgcmVjdGFuZ2xlSGVpZ2h0ID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhyZWN0YW5nbGUuaGVpZ2h0KTsKICAgIH0gZWxzZSB7CiAgICAgIGdlb2dyYXBoaWNXZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgIGdlb2dyYXBoaWNTb3V0aCA9IHJlY3RhbmdsZS5zb3V0aDsKICAgICAgZ2VvZ3JhcGhpY0Vhc3QgPSByZWN0YW5nbGUuZWFzdDsKICAgICAgZ2VvZ3JhcGhpY05vcnRoID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICByZWN0YW5nbGVXaWR0aCA9IHJlY3RhbmdsZS53aWR0aDsKICAgICAgcmVjdGFuZ2xlSGVpZ2h0ID0gcmVjdGFuZ2xlLmhlaWdodDsKICAgIH0KICAgIGNvbnN0IHF1YWRCb3JkZXJMYXRpdHVkZXMgPSBbZ2VvZ3JhcGhpY1NvdXRoLCBnZW9ncmFwaGljTm9ydGhdOwogICAgY29uc3QgcXVhZEJvcmRlckxvbmdpdHVkZXMgPSBbZ2VvZ3JhcGhpY1dlc3QsIGdlb2dyYXBoaWNFYXN0XTsKICAgIGNvbnN0IGZyb21FTlUgPSBUcmFuc2Zvcm1zX2RlZmF1bHQuZWFzdE5vcnRoVXBUb0ZpeGVkRnJhbWUoCiAgICAgIHJlbGF0aXZlVG9DZW50ZXIsCiAgICAgIGVsbGlwc29pZAogICAgKTsKICAgIGNvbnN0IHRvRU5VID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2VUcmFuc2Zvcm1hdGlvbihmcm9tRU5VLCBtYXRyaXg0U2NyYXRjaDMpOwogICAgbGV0IHNvdXRoTWVyY2F0b3JZOwogICAgbGV0IG9uZU92ZXJNZXJjYXRvckhlaWdodDsKICAgIGlmIChpbmNsdWRlV2ViTWVyY2F0b3JUKSB7CiAgICAgIHNvdXRoTWVyY2F0b3JZID0gV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZShnZW9ncmFwaGljU291dGgpOwogICAgICBvbmVPdmVyTWVyY2F0b3JIZWlnaHQgPSAxIC8gKFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUoZ2VvZ3JhcGhpY05vcnRoKSAtIHNvdXRoTWVyY2F0b3JZKTsKICAgIH0KICAgIGNvbnN0IGhhc0V4YWdnZXJhdGlvbiA9IGV4YWdnZXJhdGlvbiAhPT0gMTsKICAgIGNvbnN0IGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID0gaGFzRXhhZ2dlcmF0aW9uOwogICAgY29uc3QgZHYgPSBuZXcgRGF0YVZpZXcoYnVmZmVyKTsKICAgIGxldCBtaW5IZWlnaHQgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBsZXQgbWF4SGVpZ2h0ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgY29uc3QgbWluaW11bSA9IG1pbmltdW1TY3JhdGNoOwogICAgbWluaW11bS54ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgbWluaW11bS55ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgbWluaW11bS56ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgY29uc3QgbWF4aW11bSA9IG1heGltdW1TY3JhdGNoOwogICAgbWF4aW11bS54ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbWF4aW11bS55ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbWF4aW11bS56ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbGV0IG9mZnNldCA9IDA7CiAgICBsZXQgc2l6ZSA9IDA7CiAgICBsZXQgaW5kaWNlc1NpemUgPSAwOwogICAgbGV0IHF1YWRTaXplOwogICAgbGV0IHF1YWQ7CiAgICBmb3IgKHF1YWQgPSAwOyBxdWFkIDwgNDsgKytxdWFkKSB7CiAgICAgIGxldCBvMiA9IG9mZnNldDsKICAgICAgcXVhZFNpemUgPSBkdi5nZXRVaW50MzIobzIsIHRydWUpOwogICAgICBvMiArPSBzaXplT2ZVaW50MzI7CiAgICAgIGNvbnN0IHgyID0gTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhkdi5nZXRGbG9hdDY0KG8yLCB0cnVlKSAqIDE4MCk7CiAgICAgIG8yICs9IHNpemVPZkRvdWJsZTsKICAgICAgaWYgKGluZGV4T2ZFcHNpbG9uKHF1YWRCb3JkZXJMb25naXR1ZGVzLCB4MikgPT09IC0xKSB7CiAgICAgICAgcXVhZEJvcmRlckxvbmdpdHVkZXMucHVzaCh4Mik7CiAgICAgIH0KICAgICAgY29uc3QgeTIgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKGR2LmdldEZsb2F0NjQobzIsIHRydWUpICogMTgwKTsKICAgICAgbzIgKz0gc2l6ZU9mRG91YmxlOwogICAgICBpZiAoaW5kZXhPZkVwc2lsb24ocXVhZEJvcmRlckxhdGl0dWRlcywgeTIpID09PSAtMSkgewogICAgICAgIHF1YWRCb3JkZXJMYXRpdHVkZXMucHVzaCh5Mik7CiAgICAgIH0KICAgICAgbzIgKz0gMiAqIHNpemVPZkRvdWJsZTsKICAgICAgbGV0IGMyID0gZHYuZ2V0SW50MzIobzIsIHRydWUpOwogICAgICBvMiArPSBzaXplT2ZJbnQzMjsKICAgICAgc2l6ZSArPSBjMjsKICAgICAgYzIgPSBkdi5nZXRJbnQzMihvMiwgdHJ1ZSk7CiAgICAgIGluZGljZXNTaXplICs9IGMyICogMzsKICAgICAgb2Zmc2V0ICs9IHF1YWRTaXplICsgc2l6ZU9mVWludDMyOwogICAgfQogICAgY29uc3QgcXVhZEJvcmRlclBvaW50cyA9IFtdOwogICAgY29uc3QgcXVhZEJvcmRlckluZGljZXMgPSBbXTsKICAgIGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBBcnJheShzaXplKTsKICAgIGNvbnN0IHV2cyA9IG5ldyBBcnJheShzaXplKTsKICAgIGNvbnN0IGhlaWdodHMgPSBuZXcgQXJyYXkoc2l6ZSk7CiAgICBjb25zdCB3ZWJNZXJjYXRvclRzID0gaW5jbHVkZVdlYk1lcmNhdG9yVCA/IG5ldyBBcnJheShzaXplKSA6IFtdOwogICAgY29uc3QgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscyA9IGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID8gbmV3IEFycmF5KHNpemUpIDogW107CiAgICBjb25zdCBpbmRpY2VzID0gbmV3IEFycmF5KGluZGljZXNTaXplKTsKICAgIGNvbnN0IHdlc3RCb3JkZXIgPSBbXTsKICAgIGNvbnN0IHNvdXRoQm9yZGVyID0gW107CiAgICBjb25zdCBlYXN0Qm9yZGVyID0gW107CiAgICBjb25zdCBub3J0aEJvcmRlciA9IFtdOwogICAgbGV0IHBvaW50T2Zmc2V0ID0gMDsKICAgIGxldCBpbmRpY2VzT2Zmc2V0ID0gMDsKICAgIG9mZnNldCA9IDA7CiAgICBmb3IgKHF1YWQgPSAwOyBxdWFkIDwgNDsgKytxdWFkKSB7CiAgICAgIHF1YWRTaXplID0gZHYuZ2V0VWludDMyKG9mZnNldCwgdHJ1ZSk7CiAgICAgIG9mZnNldCArPSBzaXplT2ZVaW50MzI7CiAgICAgIGNvbnN0IHN0YXJ0UXVhZCA9IG9mZnNldDsKICAgICAgY29uc3Qgb3JpZ2luWCA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoZHYuZ2V0RmxvYXQ2NChvZmZzZXQsIHRydWUpICogMTgwKTsKICAgICAgb2Zmc2V0ICs9IHNpemVPZkRvdWJsZTsKICAgICAgY29uc3Qgb3JpZ2luWSA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoZHYuZ2V0RmxvYXQ2NChvZmZzZXQsIHRydWUpICogMTgwKTsKICAgICAgb2Zmc2V0ICs9IHNpemVPZkRvdWJsZTsKICAgICAgY29uc3Qgc3RlcFggPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKGR2LmdldEZsb2F0NjQob2Zmc2V0LCB0cnVlKSAqIDE4MCk7CiAgICAgIGNvbnN0IGhhbGZTdGVwWCA9IHN0ZXBYICogMC41OwogICAgICBvZmZzZXQgKz0gc2l6ZU9mRG91YmxlOwogICAgICBjb25zdCBzdGVwWSA9IE1hdGhfZGVmYXVsdC50b1JhZGlhbnMoZHYuZ2V0RmxvYXQ2NChvZmZzZXQsIHRydWUpICogMTgwKTsKICAgICAgY29uc3QgaGFsZlN0ZXBZID0gc3RlcFkgKiAwLjU7CiAgICAgIG9mZnNldCArPSBzaXplT2ZEb3VibGU7CiAgICAgIGNvbnN0IG51bVBvaW50cyA9IGR2LmdldEludDMyKG9mZnNldCwgdHJ1ZSk7CiAgICAgIG9mZnNldCArPSBzaXplT2ZJbnQzMjsKICAgICAgY29uc3QgbnVtRmFjZXMgPSBkdi5nZXRJbnQzMihvZmZzZXQsIHRydWUpOwogICAgICBvZmZzZXQgKz0gc2l6ZU9mSW50MzI7CiAgICAgIG9mZnNldCArPSBzaXplT2ZJbnQzMjsKICAgICAgY29uc3QgaW5kaWNlc01hcHBpbmcgPSBuZXcgQXJyYXkobnVtUG9pbnRzKTsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG51bVBvaW50czsgKytpMikgewogICAgICAgIGNvbnN0IGxvbmdpdHVkZSA9IG9yaWdpblggKyBkdi5nZXRVaW50OChvZmZzZXQrKykgKiBzdGVwWDsKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOS5sb25naXR1ZGUgPSBsb25naXR1ZGU7CiAgICAgICAgY29uc3QgbGF0aXR1ZGUgPSBvcmlnaW5ZICsgZHYuZ2V0VWludDgob2Zmc2V0KyspICogc3RlcFk7CiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzkubGF0aXR1ZGUgPSBsYXRpdHVkZTsKICAgICAgICBsZXQgaGVpZ2h0ID0gZHYuZ2V0RmxvYXQzMihvZmZzZXQsIHRydWUpOwogICAgICAgIG9mZnNldCArPSBzaXplT2ZGbG9hdDsKICAgICAgICBpZiAoaGVpZ2h0ICE9PSAwICYmIGhlaWdodCA8IG5lZ2F0aXZlRWxldmF0aW9uVGhyZXNob2xkKSB7CiAgICAgICAgICBoZWlnaHQgKj0gLU1hdGgucG93KDIsIG5lZ2F0aXZlQWx0aXR1ZGVFeHBvbmVudEJpYXMpOwogICAgICAgIH0KICAgICAgICBoZWlnaHQgKj0gNjM3MTAxMDsKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOS5oZWlnaHQgPSBoZWlnaHQ7CiAgICAgICAgaWYgKGluZGV4T2ZFcHNpbG9uKHF1YWRCb3JkZXJMb25naXR1ZGVzLCBsb25naXR1ZGUpICE9PSAtMSB8fCBpbmRleE9mRXBzaWxvbihxdWFkQm9yZGVyTGF0aXR1ZGVzLCBsYXRpdHVkZSkgIT09IC0xKSB7CiAgICAgICAgICBjb25zdCBpbmRleCA9IGluZGV4T2ZFcHNpbG9uKAogICAgICAgICAgICBxdWFkQm9yZGVyUG9pbnRzLAogICAgICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOSwKICAgICAgICAgICAgQ2FydG9ncmFwaGljX2RlZmF1bHQKICAgICAgICAgICk7CiAgICAgICAgICBpZiAoaW5kZXggPT09IC0xKSB7CiAgICAgICAgICAgIHF1YWRCb3JkZXJQb2ludHMucHVzaChDYXJ0b2dyYXBoaWNfZGVmYXVsdC5jbG9uZShzY3JhdGNoQ2FydG9ncmFwaGljOSkpOwogICAgICAgICAgICBxdWFkQm9yZGVySW5kaWNlcy5wdXNoKHBvaW50T2Zmc2V0KTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGluZGljZXNNYXBwaW5nW2kyXSA9IHF1YWRCb3JkZXJJbmRpY2VzW2luZGV4XTsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGluZGljZXNNYXBwaW5nW2kyXSA9IHBvaW50T2Zmc2V0OwogICAgICAgIGlmIChNYXRoLmFicyhsb25naXR1ZGUgLSBnZW9ncmFwaGljV2VzdCkgPCBoYWxmU3RlcFgpIHsKICAgICAgICAgIHdlc3RCb3JkZXIucHVzaCh7CiAgICAgICAgICAgIGluZGV4OiBwb2ludE9mZnNldCwKICAgICAgICAgICAgY2FydG9ncmFwaGljOiBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5jbG9uZShzY3JhdGNoQ2FydG9ncmFwaGljOSkKICAgICAgICAgIH0pOwogICAgICAgIH0gZWxzZSBpZiAoTWF0aC5hYnMobG9uZ2l0dWRlIC0gZ2VvZ3JhcGhpY0Vhc3QpIDwgaGFsZlN0ZXBYKSB7CiAgICAgICAgICBlYXN0Qm9yZGVyLnB1c2goewogICAgICAgICAgICBpbmRleDogcG9pbnRPZmZzZXQsCiAgICAgICAgICAgIGNhcnRvZ3JhcGhpYzogQ2FydG9ncmFwaGljX2RlZmF1bHQuY2xvbmUoc2NyYXRjaENhcnRvZ3JhcGhpYzkpCiAgICAgICAgICB9KTsKICAgICAgICB9IGVsc2UgaWYgKE1hdGguYWJzKGxhdGl0dWRlIC0gZ2VvZ3JhcGhpY1NvdXRoKSA8IGhhbGZTdGVwWSkgewogICAgICAgICAgc291dGhCb3JkZXIucHVzaCh7CiAgICAgICAgICAgIGluZGV4OiBwb2ludE9mZnNldCwKICAgICAgICAgICAgY2FydG9ncmFwaGljOiBDYXJ0b2dyYXBoaWNfZGVmYXVsdC5jbG9uZShzY3JhdGNoQ2FydG9ncmFwaGljOSkKICAgICAgICAgIH0pOwogICAgICAgIH0gZWxzZSBpZiAoTWF0aC5hYnMobGF0aXR1ZGUgLSBnZW9ncmFwaGljTm9ydGgpIDwgaGFsZlN0ZXBZKSB7CiAgICAgICAgICBub3J0aEJvcmRlci5wdXNoKHsKICAgICAgICAgICAgaW5kZXg6IHBvaW50T2Zmc2V0LAogICAgICAgICAgICBjYXJ0b2dyYXBoaWM6IENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKHNjcmF0Y2hDYXJ0b2dyYXBoaWM5KQogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICAgIG1pbkhlaWdodCA9IE1hdGgubWluKGhlaWdodCwgbWluSGVpZ2h0KTsKICAgICAgICBtYXhIZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIG1heEhlaWdodCk7CiAgICAgICAgaGVpZ2h0c1twb2ludE9mZnNldF0gPSBoZWlnaHQ7CiAgICAgICAgY29uc3QgcG9zID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKHNjcmF0Y2hDYXJ0b2dyYXBoaWM5KTsKICAgICAgICBwb3NpdGlvbnNbcG9pbnRPZmZzZXRdID0gcG9zOwogICAgICAgIGlmIChpbmNsdWRlV2ViTWVyY2F0b3JUKSB7CiAgICAgICAgICB3ZWJNZXJjYXRvclRzW3BvaW50T2Zmc2V0XSA9IChXZWJNZXJjYXRvclByb2plY3Rpb25fZGVmYXVsdC5nZW9kZXRpY0xhdGl0dWRlVG9NZXJjYXRvckFuZ2xlKGxhdGl0dWRlKSAtIHNvdXRoTWVyY2F0b3JZKSAqIG9uZU92ZXJNZXJjYXRvckhlaWdodDsKICAgICAgICB9CiAgICAgICAgaWYgKGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzKSB7CiAgICAgICAgICBjb25zdCBub3JtYWwyID0gZWxsaXBzb2lkLmdlb2RldGljU3VyZmFjZU5vcm1hbChwb3MpOwogICAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsc1twb2ludE9mZnNldF0gPSBub3JtYWwyOwogICAgICAgIH0KICAgICAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KHRvRU5VLCBwb3MsIHNjcmF0Y2hDYXJ0ZXNpYW4yMCk7CiAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm1pbmltdW1CeUNvbXBvbmVudChzY3JhdGNoQ2FydGVzaWFuMjAsIG1pbmltdW0sIG1pbmltdW0pOwogICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQnlDb21wb25lbnQoc2NyYXRjaENhcnRlc2lhbjIwLCBtYXhpbXVtLCBtYXhpbXVtKTsKICAgICAgICBsZXQgdTQgPSAobG9uZ2l0dWRlIC0gZ2VvZ3JhcGhpY1dlc3QpIC8gKGdlb2dyYXBoaWNFYXN0IC0gZ2VvZ3JhcGhpY1dlc3QpOwogICAgICAgIHU0ID0gTWF0aF9kZWZhdWx0LmNsYW1wKHU0LCAwLCAxKTsKICAgICAgICBsZXQgdjQgPSAobGF0aXR1ZGUgLSBnZW9ncmFwaGljU291dGgpIC8gKGdlb2dyYXBoaWNOb3J0aCAtIGdlb2dyYXBoaWNTb3V0aCk7CiAgICAgICAgdjQgPSBNYXRoX2RlZmF1bHQuY2xhbXAodjQsIDAsIDEpOwogICAgICAgIHV2c1twb2ludE9mZnNldF0gPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KHU0LCB2NCk7CiAgICAgICAgKytwb2ludE9mZnNldDsKICAgICAgfQogICAgICBjb25zdCBmYWNlc0VsZW1lbnRDb3VudCA9IG51bUZhY2VzICogMzsKICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGZhY2VzRWxlbWVudENvdW50OyArK2oyLCArK2luZGljZXNPZmZzZXQpIHsKICAgICAgICBpbmRpY2VzW2luZGljZXNPZmZzZXRdID0gaW5kaWNlc01hcHBpbmdbZHYuZ2V0VWludDE2KG9mZnNldCwgdHJ1ZSldOwogICAgICAgIG9mZnNldCArPSBzaXplT2ZVaW50MTY7CiAgICAgIH0KICAgICAgaWYgKHF1YWRTaXplICE9PSBvZmZzZXQgLSBzdGFydFF1YWQpIHsKICAgICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkludmFsaWQgdGVycmFpbiB0aWxlLiIpOwogICAgICB9CiAgICB9CiAgICBwb3NpdGlvbnMubGVuZ3RoID0gcG9pbnRPZmZzZXQ7CiAgICB1dnMubGVuZ3RoID0gcG9pbnRPZmZzZXQ7CiAgICBoZWlnaHRzLmxlbmd0aCA9IHBvaW50T2Zmc2V0OwogICAgaWYgKGluY2x1ZGVXZWJNZXJjYXRvclQpIHsKICAgICAgd2ViTWVyY2F0b3JUcy5sZW5ndGggPSBwb2ludE9mZnNldDsKICAgIH0KICAgIGlmIChpbmNsdWRlR2VvZGV0aWNTdXJmYWNlTm9ybWFscykgewogICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWxzLmxlbmd0aCA9IHBvaW50T2Zmc2V0OwogICAgfQogICAgY29uc3QgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzID0gcG9pbnRPZmZzZXQ7CiAgICBjb25zdCBpbmRleENvdW50V2l0aG91dFNraXJ0cyA9IGluZGljZXNPZmZzZXQ7CiAgICBjb25zdCBza2lydE9wdGlvbnMgPSB7CiAgICAgIGhNaW46IG1pbkhlaWdodCwKICAgICAgbGFzdEJvcmRlclBvaW50OiB2b2lkIDAsCiAgICAgIHNraXJ0SGVpZ2h0LAogICAgICB0b0VOVSwKICAgICAgZWxsaXBzb2lkLAogICAgICBtaW5pbXVtLAogICAgICBtYXhpbXVtCiAgICB9OwogICAgd2VzdEJvcmRlci5zb3J0KGZ1bmN0aW9uKGE0LCBiMikgewogICAgICByZXR1cm4gYjIuY2FydG9ncmFwaGljLmxhdGl0dWRlIC0gYTQuY2FydG9ncmFwaGljLmxhdGl0dWRlOwogICAgfSk7CiAgICBzb3V0aEJvcmRlci5zb3J0KGZ1bmN0aW9uKGE0LCBiMikgewogICAgICByZXR1cm4gYTQuY2FydG9ncmFwaGljLmxvbmdpdHVkZSAtIGIyLmNhcnRvZ3JhcGhpYy5sb25naXR1ZGU7CiAgICB9KTsKICAgIGVhc3RCb3JkZXIuc29ydChmdW5jdGlvbihhNCwgYjIpIHsKICAgICAgcmV0dXJuIGE0LmNhcnRvZ3JhcGhpYy5sYXRpdHVkZSAtIGIyLmNhcnRvZ3JhcGhpYy5sYXRpdHVkZTsKICAgIH0pOwogICAgbm9ydGhCb3JkZXIuc29ydChmdW5jdGlvbihhNCwgYjIpIHsKICAgICAgcmV0dXJuIGIyLmNhcnRvZ3JhcGhpYy5sb25naXR1ZGUgLSBhNC5jYXJ0b2dyYXBoaWMubG9uZ2l0dWRlOwogICAgfSk7CiAgICBjb25zdCBwZXJjZW50YWdlID0gMWUtNTsKICAgIGFkZFNraXJ0KAogICAgICBwb3NpdGlvbnMsCiAgICAgIGhlaWdodHMsCiAgICAgIHV2cywKICAgICAgd2ViTWVyY2F0b3JUcywKICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgaW5kaWNlcywKICAgICAgc2tpcnRPcHRpb25zLAogICAgICB3ZXN0Qm9yZGVyLAogICAgICAtcGVyY2VudGFnZSAqIHJlY3RhbmdsZVdpZHRoLAogICAgICB0cnVlLAogICAgICAtcGVyY2VudGFnZSAqIHJlY3RhbmdsZUhlaWdodAogICAgKTsKICAgIGFkZFNraXJ0KAogICAgICBwb3NpdGlvbnMsCiAgICAgIGhlaWdodHMsCiAgICAgIHV2cywKICAgICAgd2ViTWVyY2F0b3JUcywKICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgaW5kaWNlcywKICAgICAgc2tpcnRPcHRpb25zLAogICAgICBzb3V0aEJvcmRlciwKICAgICAgLXBlcmNlbnRhZ2UgKiByZWN0YW5nbGVIZWlnaHQsCiAgICAgIGZhbHNlCiAgICApOwogICAgYWRkU2tpcnQoCiAgICAgIHBvc2l0aW9ucywKICAgICAgaGVpZ2h0cywKICAgICAgdXZzLAogICAgICB3ZWJNZXJjYXRvclRzLAogICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWxzLAogICAgICBpbmRpY2VzLAogICAgICBza2lydE9wdGlvbnMsCiAgICAgIGVhc3RCb3JkZXIsCiAgICAgIHBlcmNlbnRhZ2UgKiByZWN0YW5nbGVXaWR0aCwKICAgICAgdHJ1ZSwKICAgICAgcGVyY2VudGFnZSAqIHJlY3RhbmdsZUhlaWdodAogICAgKTsKICAgIGFkZFNraXJ0KAogICAgICBwb3NpdGlvbnMsCiAgICAgIGhlaWdodHMsCiAgICAgIHV2cywKICAgICAgd2ViTWVyY2F0b3JUcywKICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgaW5kaWNlcywKICAgICAgc2tpcnRPcHRpb25zLAogICAgICBub3J0aEJvcmRlciwKICAgICAgcGVyY2VudGFnZSAqIHJlY3RhbmdsZUhlaWdodCwKICAgICAgZmFsc2UKICAgICk7CiAgICBpZiAod2VzdEJvcmRlci5sZW5ndGggPiAwICYmIG5vcnRoQm9yZGVyLmxlbmd0aCA+IDApIHsKICAgICAgY29uc3QgZmlyc3RCb3JkZXJJbmRleCA9IHdlc3RCb3JkZXJbMF0uaW5kZXg7CiAgICAgIGNvbnN0IGZpcnN0U2tpcnRJbmRleCA9IHZlcnRleENvdW50V2l0aG91dFNraXJ0czsKICAgICAgY29uc3QgbGFzdEJvcmRlckluZGV4ID0gbm9ydGhCb3JkZXJbbm9ydGhCb3JkZXIubGVuZ3RoIC0gMV0uaW5kZXg7CiAgICAgIGNvbnN0IGxhc3RTa2lydEluZGV4ID0gcG9zaXRpb25zLmxlbmd0aCAtIDE7CiAgICAgIGluZGljZXMucHVzaCgKICAgICAgICBsYXN0Qm9yZGVySW5kZXgsCiAgICAgICAgbGFzdFNraXJ0SW5kZXgsCiAgICAgICAgZmlyc3RTa2lydEluZGV4LAogICAgICAgIGZpcnN0U2tpcnRJbmRleCwKICAgICAgICBmaXJzdEJvcmRlckluZGV4LAogICAgICAgIGxhc3RCb3JkZXJJbmRleAogICAgICApOwogICAgfQogICAgc2l6ZSA9IHBvc2l0aW9ucy5sZW5ndGg7CiAgICBjb25zdCBib3VuZGluZ1NwaGVyZTNEID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUG9pbnRzKHBvc2l0aW9ucyk7CiAgICBsZXQgb3JpZW50ZWRCb3VuZGluZ0JveDsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocmVjdGFuZ2xlKSkgewogICAgICBvcmllbnRlZEJvdW5kaW5nQm94ID0gT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21SZWN0YW5nbGUoCiAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgIG1pbkhlaWdodCwKICAgICAgICBtYXhIZWlnaHQsCiAgICAgICAgZWxsaXBzb2lkCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBvY2NsdWRlciA9IG5ldyBFbGxpcHNvaWRhbE9jY2x1ZGVyX2RlZmF1bHQoZWxsaXBzb2lkKTsKICAgIGNvbnN0IG9jY2x1ZGVlUG9pbnRJblNjYWxlZFNwYWNlID0gb2NjbHVkZXIuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnRQb3NzaWJseVVuZGVyRWxsaXBzb2lkKAogICAgICByZWxhdGl2ZVRvQ2VudGVyLAogICAgICBwb3NpdGlvbnMsCiAgICAgIG1pbkhlaWdodAogICAgKTsKICAgIGNvbnN0IGFhQm94ID0gbmV3IEF4aXNBbGlnbmVkQm91bmRpbmdCb3hfZGVmYXVsdChtaW5pbXVtLCBtYXhpbXVtLCByZWxhdGl2ZVRvQ2VudGVyKTsKICAgIGNvbnN0IGVuY29kaW5nID0gbmV3IFRlcnJhaW5FbmNvZGluZ19kZWZhdWx0KAogICAgICByZWxhdGl2ZVRvQ2VudGVyLAogICAgICBhYUJveCwKICAgICAgc2tpcnRPcHRpb25zLmhNaW4sCiAgICAgIG1heEhlaWdodCwKICAgICAgZnJvbUVOVSwKICAgICAgZmFsc2UsCiAgICAgIGluY2x1ZGVXZWJNZXJjYXRvclQsCiAgICAgIGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzLAogICAgICBleGFnZ2VyYXRpb24sCiAgICAgIGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0CiAgICApOwogICAgY29uc3QgdmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KHNpemUgKiBlbmNvZGluZy5zdHJpZGUpOwogICAgbGV0IGJ1ZmZlckluZGV4ID0gMDsKICAgIGZvciAobGV0IGsyID0gMDsgazIgPCBzaXplOyArK2syKSB7CiAgICAgIGJ1ZmZlckluZGV4ID0gZW5jb2RpbmcuZW5jb2RlKAogICAgICAgIHZlcnRpY2VzLAogICAgICAgIGJ1ZmZlckluZGV4LAogICAgICAgIHBvc2l0aW9uc1trMl0sCiAgICAgICAgdXZzW2syXSwKICAgICAgICBoZWlnaHRzW2syXSwKICAgICAgICB2b2lkIDAsCiAgICAgICAgd2ViTWVyY2F0b3JUc1trMl0sCiAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsc1trMl0KICAgICAgKTsKICAgIH0KICAgIGNvbnN0IHdlc3RJbmRpY2VzU291dGhUb05vcnRoID0gd2VzdEJvcmRlci5tYXAoZnVuY3Rpb24odmVydGV4KSB7CiAgICAgIHJldHVybiB2ZXJ0ZXguaW5kZXg7CiAgICB9KS5yZXZlcnNlKCk7CiAgICBjb25zdCBzb3V0aEluZGljZXNFYXN0VG9XZXN0ID0gc291dGhCb3JkZXIubWFwKGZ1bmN0aW9uKHZlcnRleCkgewogICAgICByZXR1cm4gdmVydGV4LmluZGV4OwogICAgfSkucmV2ZXJzZSgpOwogICAgY29uc3QgZWFzdEluZGljZXNOb3J0aFRvU291dGggPSBlYXN0Qm9yZGVyLm1hcChmdW5jdGlvbih2ZXJ0ZXgpIHsKICAgICAgcmV0dXJuIHZlcnRleC5pbmRleDsKICAgIH0pLnJldmVyc2UoKTsKICAgIGNvbnN0IG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QgPSBub3J0aEJvcmRlci5tYXAoZnVuY3Rpb24odmVydGV4KSB7CiAgICAgIHJldHVybiB2ZXJ0ZXguaW5kZXg7CiAgICB9KS5yZXZlcnNlKCk7CiAgICBzb3V0aEluZGljZXNFYXN0VG9XZXN0LnVuc2hpZnQoCiAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoW2Vhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLmxlbmd0aCAtIDFdCiAgICApOwogICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdC5wdXNoKHdlc3RJbmRpY2VzU291dGhUb05vcnRoWzBdKTsKICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QudW5zaGlmdCgKICAgICAgd2VzdEluZGljZXNTb3V0aFRvTm9ydGhbd2VzdEluZGljZXNTb3V0aFRvTm9ydGgubGVuZ3RoIC0gMV0KICAgICk7CiAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0LnB1c2goZWFzdEluZGljZXNOb3J0aFRvU291dGhbMF0pOwogICAgcmV0dXJuIHsKICAgICAgdmVydGljZXMsCiAgICAgIGluZGljZXM6IG5ldyBVaW50MTZBcnJheShpbmRpY2VzKSwKICAgICAgbWF4aW11bUhlaWdodDogbWF4SGVpZ2h0LAogICAgICBtaW5pbXVtSGVpZ2h0OiBtaW5IZWlnaHQsCiAgICAgIGVuY29kaW5nLAogICAgICBib3VuZGluZ1NwaGVyZTNELAogICAgICBvcmllbnRlZEJvdW5kaW5nQm94LAogICAgICBvY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZSwKICAgICAgdmVydGV4Q291bnRXaXRob3V0U2tpcnRzLAogICAgICBpbmRleENvdW50V2l0aG91dFNraXJ0cywKICAgICAgd2VzdEluZGljZXNTb3V0aFRvTm9ydGgsCiAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoLAogICAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0CiAgICB9OwogIH0KICBmdW5jdGlvbiBhZGRTa2lydChwb3NpdGlvbnMsIGhlaWdodHMsIHV2cywgd2ViTWVyY2F0b3JUcywgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscywgaW5kaWNlcywgc2tpcnRPcHRpb25zLCBib3JkZXJQb2ludHMsIGZ1ZGdlRmFjdG9yLCBlYXN0T3JXZXN0LCBjb3JuZXJGdWRnZSkgewogICAgY29uc3QgY291bnQgPSBib3JkZXJQb2ludHMubGVuZ3RoOwogICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGNvdW50OyArK2oyKSB7CiAgICAgIGNvbnN0IGJvcmRlclBvaW50ID0gYm9yZGVyUG9pbnRzW2oyXTsKICAgICAgY29uc3QgYm9yZGVyQ2FydG9ncmFwaGljID0gYm9yZGVyUG9pbnQuY2FydG9ncmFwaGljOwogICAgICBjb25zdCBib3JkZXJJbmRleCA9IGJvcmRlclBvaW50LmluZGV4OwogICAgICBjb25zdCBjdXJyZW50SW5kZXggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICBjb25zdCBsb25naXR1ZGUgPSBib3JkZXJDYXJ0b2dyYXBoaWMubG9uZ2l0dWRlOwogICAgICBsZXQgbGF0aXR1ZGUgPSBib3JkZXJDYXJ0b2dyYXBoaWMubGF0aXR1ZGU7CiAgICAgIGxhdGl0dWRlID0gTWF0aF9kZWZhdWx0LmNsYW1wKAogICAgICAgIGxhdGl0dWRlLAogICAgICAgIC1NYXRoX2RlZmF1bHQuUElfT1ZFUl9UV08sCiAgICAgICAgTWF0aF9kZWZhdWx0LlBJX09WRVJfVFdPCiAgICAgICk7CiAgICAgIGNvbnN0IGhlaWdodCA9IGJvcmRlckNhcnRvZ3JhcGhpYy5oZWlnaHQgLSBza2lydE9wdGlvbnMuc2tpcnRIZWlnaHQ7CiAgICAgIHNraXJ0T3B0aW9ucy5oTWluID0gTWF0aC5taW4oc2tpcnRPcHRpb25zLmhNaW4sIGhlaWdodCk7CiAgICAgIENhcnRvZ3JhcGhpY19kZWZhdWx0LmZyb21SYWRpYW5zKGxvbmdpdHVkZSwgbGF0aXR1ZGUsIGhlaWdodCwgc2NyYXRjaENhcnRvZ3JhcGhpYzkpOwogICAgICBpZiAoZWFzdE9yV2VzdCkgewogICAgICAgIHNjcmF0Y2hDYXJ0b2dyYXBoaWM5LmxvbmdpdHVkZSArPSBmdWRnZUZhY3RvcjsKICAgICAgfQogICAgICBpZiAoIWVhc3RPcldlc3QpIHsKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOS5sYXRpdHVkZSArPSBmdWRnZUZhY3RvcjsKICAgICAgfSBlbHNlIGlmIChqMiA9PT0gY291bnQgLSAxKSB7CiAgICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzkubGF0aXR1ZGUgKz0gY29ybmVyRnVkZ2U7CiAgICAgIH0gZWxzZSBpZiAoajIgPT09IDApIHsKICAgICAgICBzY3JhdGNoQ2FydG9ncmFwaGljOS5sYXRpdHVkZSAtPSBjb3JuZXJGdWRnZTsKICAgICAgfQogICAgICBjb25zdCBwb3MgPSBza2lydE9wdGlvbnMuZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKHNjcmF0Y2hDYXJ0b2dyYXBoaWM5KTsKICAgICAgcG9zaXRpb25zLnB1c2gocG9zKTsKICAgICAgaGVpZ2h0cy5wdXNoKGhlaWdodCk7CiAgICAgIHV2cy5wdXNoKENhcnRlc2lhbjJfZGVmYXVsdC5jbG9uZSh1dnNbYm9yZGVySW5kZXhdKSk7CiAgICAgIGlmICh3ZWJNZXJjYXRvclRzLmxlbmd0aCA+IDApIHsKICAgICAgICB3ZWJNZXJjYXRvclRzLnB1c2god2ViTWVyY2F0b3JUc1tib3JkZXJJbmRleF0pOwogICAgICB9CiAgICAgIGlmIChnZW9kZXRpY1N1cmZhY2VOb3JtYWxzLmxlbmd0aCA+IDApIHsKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWxzLnB1c2goZ2VvZGV0aWNTdXJmYWNlTm9ybWFsc1tib3JkZXJJbmRleF0pOwogICAgICB9CiAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQoc2tpcnRPcHRpb25zLnRvRU5VLCBwb3MsIHNjcmF0Y2hDYXJ0ZXNpYW4yMCk7CiAgICAgIGNvbnN0IG1pbmltdW0gPSBza2lydE9wdGlvbnMubWluaW11bTsKICAgICAgY29uc3QgbWF4aW11bSA9IHNraXJ0T3B0aW9ucy5tYXhpbXVtOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWluaW11bUJ5Q29tcG9uZW50KHNjcmF0Y2hDYXJ0ZXNpYW4yMCwgbWluaW11bSwgbWluaW11bSk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQnlDb21wb25lbnQoc2NyYXRjaENhcnRlc2lhbjIwLCBtYXhpbXVtLCBtYXhpbXVtKTsKICAgICAgY29uc3QgbGFzdEJvcmRlclBvaW50ID0gc2tpcnRPcHRpb25zLmxhc3RCb3JkZXJQb2ludDsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChsYXN0Qm9yZGVyUG9pbnQpKSB7CiAgICAgICAgY29uc3QgbGFzdEJvcmRlckluZGV4ID0gbGFzdEJvcmRlclBvaW50LmluZGV4OwogICAgICAgIGluZGljZXMucHVzaCgKICAgICAgICAgIGxhc3RCb3JkZXJJbmRleCwKICAgICAgICAgIGN1cnJlbnRJbmRleCAtIDEsCiAgICAgICAgICBjdXJyZW50SW5kZXgsCiAgICAgICAgICBjdXJyZW50SW5kZXgsCiAgICAgICAgICBib3JkZXJJbmRleCwKICAgICAgICAgIGxhc3RCb3JkZXJJbmRleAogICAgICAgICk7CiAgICAgIH0KICAgICAgc2tpcnRPcHRpb25zLmxhc3RCb3JkZXJQb2ludCA9IGJvcmRlclBvaW50OwogICAgfQogIH0KICB2YXIgc2l6ZU9mVWludDE2LCBzaXplT2ZJbnQzMiwgc2l6ZU9mVWludDMyLCBzaXplT2ZGbG9hdCwgc2l6ZU9mRG91YmxlLCBzY3JhdGNoQ2FydG9ncmFwaGljOSwgc2NyYXRjaENhcnRlc2lhbjIwLCBtaW5pbXVtU2NyYXRjaCwgbWF4aW11bVNjcmF0Y2gsIG1hdHJpeDRTY3JhdGNoMywgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyX2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXIuanMiKCkgewogICAgICBpbml0X0F4aXNBbGlnbmVkQm91bmRpbmdCb3goKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZGFsT2NjbHVkZXIoKTsKICAgICAgaW5pdF9NYXRoKCk7CiAgICAgIGluaXRfTWF0cml4NCgpOwogICAgICBpbml0X09yaWVudGVkQm91bmRpbmdCb3goKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgaW5pdF9SdW50aW1lRXJyb3IoKTsKICAgICAgaW5pdF9UZXJyYWluRW5jb2RpbmcoKTsKICAgICAgaW5pdF9UcmFuc2Zvcm1zKCk7CiAgICAgIGluaXRfV2ViTWVyY2F0b3JQcm9qZWN0aW9uKCk7CiAgICAgIGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcigpOwogICAgICBzaXplT2ZVaW50MTYgPSBVaW50MTZBcnJheS5CWVRFU19QRVJfRUxFTUVOVDsKICAgICAgc2l6ZU9mSW50MzIgPSBJbnQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICBzaXplT2ZVaW50MzIgPSBVaW50MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVDsKICAgICAgc2l6ZU9mRmxvYXQgPSBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgIHNpemVPZkRvdWJsZSA9IEZsb2F0NjRBcnJheS5CWVRFU19QRVJfRUxFTUVOVDsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzkgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjIwID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBtaW5pbXVtU2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgbWF4aW11bVNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIG1hdHJpeDRTY3JhdGNoMyA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyX2RlZmF1bHQgPSBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQoCiAgICAgICAgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyCiAgICAgICk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9IZWlnaHRtYXBFbmNvZGluZy5qcwogIHZhciBIZWlnaHRtYXBFbmNvZGluZywgSGVpZ2h0bWFwRW5jb2RpbmdfZGVmYXVsdDsKICB2YXIgaW5pdF9IZWlnaHRtYXBFbmNvZGluZyA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSGVpZ2h0bWFwRW5jb2RpbmcuanMiKCkgewogICAgICBIZWlnaHRtYXBFbmNvZGluZyA9IHsKICAgICAgICAvKioKICAgICAgICAgKiBObyBlbmNvZGluZwogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBOT05FOiAwLAogICAgICAgIC8qKgogICAgICAgICAqIExFUkMgZW5jb2RpbmcKICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICoKICAgICAgICAgKiBAc2VlIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vRXNyaS9sZXJjfFRoZSBMRVJDIHNwZWNpZmljYXRpb259CiAgICAgICAgICovCiAgICAgICAgTEVSQzogMQogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKEhlaWdodG1hcEVuY29kaW5nKTsKICAgICAgSGVpZ2h0bWFwRW5jb2RpbmdfZGVmYXVsdCA9IEhlaWdodG1hcEVuY29kaW5nOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSGVpZ2h0bWFwVGVzc2VsbGF0b3IuanMKICB2YXIgSGVpZ2h0bWFwVGVzc2VsbGF0b3IsIGNhcnRlc2lhbjNTY3JhdGNoNywgbWF0cml4NFNjcmF0Y2g0LCBtaW5pbXVtU2NyYXRjaDIsIG1heGltdW1TY3JhdGNoMiwgSGVpZ2h0bWFwVGVzc2VsbGF0b3JfZGVmYXVsdDsKICB2YXIgaW5pdF9IZWlnaHRtYXBUZXNzZWxsYXRvciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSGVpZ2h0bWFwVGVzc2VsbGF0b3IuanMiKCkgewogICAgICBpbml0X0F4aXNBbGlnbmVkQm91bmRpbmdCb3goKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkYWxPY2NsdWRlcigpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfT3JpZW50ZWRCb3VuZGluZ0JveCgpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1RlcnJhaW5FbmNvZGluZygpOwogICAgICBpbml0X1RyYW5zZm9ybXMoKTsKICAgICAgaW5pdF9XZWJNZXJjYXRvclByb2plY3Rpb24oKTsKICAgICAgSGVpZ2h0bWFwVGVzc2VsbGF0b3IgPSB7fTsKICAgICAgSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkUgPSBPYmplY3QuZnJlZXplKHsKICAgICAgICBoZWlnaHRTY2FsZTogMSwKICAgICAgICBoZWlnaHRPZmZzZXQ6IDAsCiAgICAgICAgZWxlbWVudHNQZXJIZWlnaHQ6IDEsCiAgICAgICAgc3RyaWRlOiAxLAogICAgICAgIGVsZW1lbnRNdWx0aXBsaWVyOiAyNTYsCiAgICAgICAgaXNCaWdFbmRpYW46IGZhbHNlCiAgICAgIH0pOwogICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDcgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIG1hdHJpeDRTY3JhdGNoNCA9IG5ldyBNYXRyaXg0X2RlZmF1bHQoKTsKICAgICAgbWluaW11bVNjcmF0Y2gyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBtYXhpbXVtU2NyYXRjaDIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIEhlaWdodG1hcFRlc3NlbGxhdG9yLmNvbXB1dGVWZXJ0aWNlcyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvcHRpb25zKSB8fCAhZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuaGVpZ2h0bWFwKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMuaGVpZ2h0bWFwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChvcHRpb25zLndpZHRoKSB8fCAhZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuaGVpZ2h0KSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMud2lkdGggYW5kIG9wdGlvbnMuaGVpZ2h0IGFyZSByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQob3B0aW9ucy5uYXRpdmVSZWN0YW5nbGUpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy5uYXRpdmVSZWN0YW5nbGUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG9wdGlvbnMuc2tpcnRIZWlnaHQpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy5za2lydEhlaWdodCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgY29zNCA9IE1hdGguY29zOwogICAgICAgIGNvbnN0IHNpbjQgPSBNYXRoLnNpbjsKICAgICAgICBjb25zdCBzcXJ0MiA9IE1hdGguc3FydDsKICAgICAgICBjb25zdCBhdGFuID0gTWF0aC5hdGFuOwogICAgICAgIGNvbnN0IGV4cCA9IE1hdGguZXhwOwogICAgICAgIGNvbnN0IHBpT3ZlclR3byA9IE1hdGhfZGVmYXVsdC5QSV9PVkVSX1RXTzsKICAgICAgICBjb25zdCB0b1JhZGlhbnMgPSBNYXRoX2RlZmF1bHQudG9SYWRpYW5zOwogICAgICAgIGNvbnN0IGhlaWdodG1hcCA9IG9wdGlvbnMuaGVpZ2h0bWFwOwogICAgICAgIGNvbnN0IHdpZHRoID0gb3B0aW9ucy53aWR0aDsKICAgICAgICBjb25zdCBoZWlnaHQgPSBvcHRpb25zLmhlaWdodDsKICAgICAgICBjb25zdCBza2lydEhlaWdodCA9IG9wdGlvbnMuc2tpcnRIZWlnaHQ7CiAgICAgICAgY29uc3QgaGFzU2tpcnRzID0gc2tpcnRIZWlnaHQgPiAwOwogICAgICAgIGNvbnN0IGlzR2VvZ3JhcGhpYyA9IG9wdGlvbnMuaXNHZW9ncmFwaGljID8/IHRydWU7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgICAgICBjb25zdCBvbmVPdmVyR2xvYmVTZW1pbWFqb3JBeGlzID0gMSAvIGVsbGlwc29pZC5tYXhpbXVtUmFkaXVzOwogICAgICAgIGNvbnN0IG5hdGl2ZVJlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKG9wdGlvbnMubmF0aXZlUmVjdGFuZ2xlKTsKICAgICAgICBjb25zdCByZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5jbG9uZShvcHRpb25zLnJlY3RhbmdsZSk7CiAgICAgICAgbGV0IGdlb2dyYXBoaWNXZXN0OwogICAgICAgIGxldCBnZW9ncmFwaGljU291dGg7CiAgICAgICAgbGV0IGdlb2dyYXBoaWNFYXN0OwogICAgICAgIGxldCBnZW9ncmFwaGljTm9ydGg7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVjdGFuZ2xlKSkgewogICAgICAgICAgaWYgKGlzR2VvZ3JhcGhpYykgewogICAgICAgICAgICBnZW9ncmFwaGljV2VzdCA9IHRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUud2VzdCk7CiAgICAgICAgICAgIGdlb2dyYXBoaWNTb3V0aCA9IHRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUuc291dGgpOwogICAgICAgICAgICBnZW9ncmFwaGljRWFzdCA9IHRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUuZWFzdCk7CiAgICAgICAgICAgIGdlb2dyYXBoaWNOb3J0aCA9IHRvUmFkaWFucyhuYXRpdmVSZWN0YW5nbGUubm9ydGgpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgZ2VvZ3JhcGhpY1dlc3QgPSBuYXRpdmVSZWN0YW5nbGUud2VzdCAqIG9uZU92ZXJHbG9iZVNlbWltYWpvckF4aXM7CiAgICAgICAgICAgIGdlb2dyYXBoaWNTb3V0aCA9IHBpT3ZlclR3byAtIDIgKiBhdGFuKGV4cCgtbmF0aXZlUmVjdGFuZ2xlLnNvdXRoICogb25lT3Zlckdsb2JlU2VtaW1ham9yQXhpcykpOwogICAgICAgICAgICBnZW9ncmFwaGljRWFzdCA9IG5hdGl2ZVJlY3RhbmdsZS5lYXN0ICogb25lT3Zlckdsb2JlU2VtaW1ham9yQXhpczsKICAgICAgICAgICAgZ2VvZ3JhcGhpY05vcnRoID0gcGlPdmVyVHdvIC0gMiAqIGF0YW4oZXhwKC1uYXRpdmVSZWN0YW5nbGUubm9ydGggKiBvbmVPdmVyR2xvYmVTZW1pbWFqb3JBeGlzKSk7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGdlb2dyYXBoaWNXZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICAgICAgICBnZW9ncmFwaGljU291dGggPSByZWN0YW5nbGUuc291dGg7CiAgICAgICAgICBnZW9ncmFwaGljRWFzdCA9IHJlY3RhbmdsZS5lYXN0OwogICAgICAgICAgZ2VvZ3JhcGhpY05vcnRoID0gcmVjdGFuZ2xlLm5vcnRoOwogICAgICAgIH0KICAgICAgICBsZXQgcmVsYXRpdmVUb0NlbnRlciA9IG9wdGlvbnMucmVsYXRpdmVUb0NlbnRlcjsKICAgICAgICBjb25zdCBoYXNSZWxhdGl2ZVRvQ2VudGVyID0gZGVmaW5lZF9kZWZhdWx0KHJlbGF0aXZlVG9DZW50ZXIpOwogICAgICAgIHJlbGF0aXZlVG9DZW50ZXIgPSBoYXNSZWxhdGl2ZVRvQ2VudGVyID8gcmVsYXRpdmVUb0NlbnRlciA6IENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPOwogICAgICAgIGNvbnN0IGluY2x1ZGVXZWJNZXJjYXRvclQgPSBvcHRpb25zLmluY2x1ZGVXZWJNZXJjYXRvclQgPz8gZmFsc2U7CiAgICAgICAgY29uc3QgZXhhZ2dlcmF0aW9uID0gb3B0aW9ucy5leGFnZ2VyYXRpb24gPz8gMTsKICAgICAgICBjb25zdCBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodCA9IG9wdGlvbnMuZXhhZ2dlcmF0aW9uUmVsYXRpdmVIZWlnaHQgPz8gMDsKICAgICAgICBjb25zdCBoYXNFeGFnZ2VyYXRpb24gPSBleGFnZ2VyYXRpb24gIT09IDE7CiAgICAgICAgY29uc3QgaW5jbHVkZUdlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBoYXNFeGFnZ2VyYXRpb247CiAgICAgICAgY29uc3Qgc3RydWN0dXJlID0gb3B0aW9ucy5zdHJ1Y3R1cmUgPz8gSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkU7CiAgICAgICAgY29uc3QgaGVpZ2h0U2NhbGUgPSBzdHJ1Y3R1cmUuaGVpZ2h0U2NhbGUgPz8gSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkUuaGVpZ2h0U2NhbGU7CiAgICAgICAgY29uc3QgaGVpZ2h0T2Zmc2V0ID0gc3RydWN0dXJlLmhlaWdodE9mZnNldCA/PyBIZWlnaHRtYXBUZXNzZWxsYXRvci5ERUZBVUxUX1NUUlVDVFVSRS5oZWlnaHRPZmZzZXQ7CiAgICAgICAgY29uc3QgZWxlbWVudHNQZXJIZWlnaHQgPSBzdHJ1Y3R1cmUuZWxlbWVudHNQZXJIZWlnaHQgPz8gSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkUuZWxlbWVudHNQZXJIZWlnaHQ7CiAgICAgICAgY29uc3Qgc3RyaWRlID0gc3RydWN0dXJlLnN0cmlkZSA/PyBIZWlnaHRtYXBUZXNzZWxsYXRvci5ERUZBVUxUX1NUUlVDVFVSRS5zdHJpZGU7CiAgICAgICAgY29uc3QgZWxlbWVudE11bHRpcGxpZXIgPSBzdHJ1Y3R1cmUuZWxlbWVudE11bHRpcGxpZXIgPz8gSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkUuZWxlbWVudE11bHRpcGxpZXI7CiAgICAgICAgY29uc3QgaXNCaWdFbmRpYW4gPSBzdHJ1Y3R1cmUuaXNCaWdFbmRpYW4gPz8gSGVpZ2h0bWFwVGVzc2VsbGF0b3IuREVGQVVMVF9TVFJVQ1RVUkUuaXNCaWdFbmRpYW47CiAgICAgICAgbGV0IHJlY3RhbmdsZVdpZHRoID0gUmVjdGFuZ2xlX2RlZmF1bHQuY29tcHV0ZVdpZHRoKG5hdGl2ZVJlY3RhbmdsZSk7CiAgICAgICAgbGV0IHJlY3RhbmdsZUhlaWdodCA9IFJlY3RhbmdsZV9kZWZhdWx0LmNvbXB1dGVIZWlnaHQobmF0aXZlUmVjdGFuZ2xlKTsKICAgICAgICBjb25zdCBncmFudWxhcml0eVggPSByZWN0YW5nbGVXaWR0aCAvICh3aWR0aCAtIDEpOwogICAgICAgIGNvbnN0IGdyYW51bGFyaXR5WSA9IHJlY3RhbmdsZUhlaWdodCAvIChoZWlnaHQgLSAxKTsKICAgICAgICBpZiAoIWlzR2VvZ3JhcGhpYykgewogICAgICAgICAgcmVjdGFuZ2xlV2lkdGggKj0gb25lT3Zlckdsb2JlU2VtaW1ham9yQXhpczsKICAgICAgICAgIHJlY3RhbmdsZUhlaWdodCAqPSBvbmVPdmVyR2xvYmVTZW1pbWFqb3JBeGlzOwogICAgICAgIH0KICAgICAgICBjb25zdCByYWRpaVNxdWFyZWQgPSBlbGxpcHNvaWQucmFkaWlTcXVhcmVkOwogICAgICAgIGNvbnN0IHJhZGlpU3F1YXJlZFggPSByYWRpaVNxdWFyZWQueDsKICAgICAgICBjb25zdCByYWRpaVNxdWFyZWRZID0gcmFkaWlTcXVhcmVkLnk7CiAgICAgICAgY29uc3QgcmFkaWlTcXVhcmVkWiA9IHJhZGlpU3F1YXJlZC56OwogICAgICAgIGxldCBtaW5pbXVtSGVpZ2h0ID0gNjU1MzY7CiAgICAgICAgbGV0IG1heGltdW1IZWlnaHQgPSAtNjU1MzY7CiAgICAgICAgY29uc3QgZnJvbUVOVSA9IFRyYW5zZm9ybXNfZGVmYXVsdC5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZSgKICAgICAgICAgIHJlbGF0aXZlVG9DZW50ZXIsCiAgICAgICAgICBlbGxpcHNvaWQKICAgICAgICApOwogICAgICAgIGNvbnN0IHRvRU5VID0gTWF0cml4NF9kZWZhdWx0LmludmVyc2VUcmFuc2Zvcm1hdGlvbihmcm9tRU5VLCBtYXRyaXg0U2NyYXRjaDQpOwogICAgICAgIGxldCBzb3V0aE1lcmNhdG9yWTsKICAgICAgICBsZXQgb25lT3Zlck1lcmNhdG9ySGVpZ2h0OwogICAgICAgIGlmIChpbmNsdWRlV2ViTWVyY2F0b3JUKSB7CiAgICAgICAgICBzb3V0aE1lcmNhdG9yWSA9IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUoZ2VvZ3JhcGhpY1NvdXRoKTsKICAgICAgICAgIG9uZU92ZXJNZXJjYXRvckhlaWdodCA9IDEgLyAoV2ViTWVyY2F0b3JQcm9qZWN0aW9uX2RlZmF1bHQuZ2VvZGV0aWNMYXRpdHVkZVRvTWVyY2F0b3JBbmdsZShnZW9ncmFwaGljTm9ydGgpIC0gc291dGhNZXJjYXRvclkpOwogICAgICAgIH0KICAgICAgICBjb25zdCBtaW5pbXVtID0gbWluaW11bVNjcmF0Y2gyOwogICAgICAgIG1pbmltdW0ueCA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgICAgICBtaW5pbXVtLnkgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbWluaW11bS56ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgICAgIGNvbnN0IG1heGltdW0gPSBtYXhpbXVtU2NyYXRjaDI7CiAgICAgICAgbWF4aW11bS54ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgICAgIG1heGltdW0ueSA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgICAgICBtYXhpbXVtLnogPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICAgICAgbGV0IGhNaW4gPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICAgICAgY29uc3QgZ3JpZFZlcnRleENvdW50ID0gd2lkdGggKiBoZWlnaHQ7CiAgICAgICAgY29uc3QgZWRnZVZlcnRleENvdW50ID0gc2tpcnRIZWlnaHQgPiAwID8gd2lkdGggKiAyICsgaGVpZ2h0ICogMiA6IDA7CiAgICAgICAgY29uc3QgdmVydGV4Q291bnQgPSBncmlkVmVydGV4Q291bnQgKyBlZGdlVmVydGV4Q291bnQ7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEFycmF5KHZlcnRleENvdW50KTsKICAgICAgICBjb25zdCBoZWlnaHRzID0gbmV3IEFycmF5KHZlcnRleENvdW50KTsKICAgICAgICBjb25zdCB1dnMgPSBuZXcgQXJyYXkodmVydGV4Q291bnQpOwogICAgICAgIGNvbnN0IHdlYk1lcmNhdG9yVHMgPSBpbmNsdWRlV2ViTWVyY2F0b3JUID8gbmV3IEFycmF5KHZlcnRleENvdW50KSA6IFtdOwogICAgICAgIGNvbnN0IGdlb2RldGljU3VyZmFjZU5vcm1hbHMgPSBpbmNsdWRlR2VvZGV0aWNTdXJmYWNlTm9ybWFscyA/IG5ldyBBcnJheSh2ZXJ0ZXhDb3VudCkgOiBbXTsKICAgICAgICBsZXQgc3RhcnRSb3cgPSAwOwogICAgICAgIGxldCBlbmRSb3cgPSBoZWlnaHQ7CiAgICAgICAgbGV0IHN0YXJ0Q29sID0gMDsKICAgICAgICBsZXQgZW5kQ29sID0gd2lkdGg7CiAgICAgICAgaWYgKGhhc1NraXJ0cykgewogICAgICAgICAgLS1zdGFydFJvdzsKICAgICAgICAgICsrZW5kUm93OwogICAgICAgICAgLS1zdGFydENvbDsKICAgICAgICAgICsrZW5kQ29sOwogICAgICAgIH0KICAgICAgICBjb25zdCBza2lydE9mZnNldFBlcmNlbnRhZ2UgPSAxZS01OwogICAgICAgIGZvciAobGV0IHJvd0luZGV4ID0gc3RhcnRSb3c7IHJvd0luZGV4IDwgZW5kUm93OyArK3Jvd0luZGV4KSB7CiAgICAgICAgICBsZXQgcm93ID0gcm93SW5kZXg7CiAgICAgICAgICBpZiAocm93IDwgMCkgewogICAgICAgICAgICByb3cgPSAwOwogICAgICAgICAgfQogICAgICAgICAgaWYgKHJvdyA+PSBoZWlnaHQpIHsKICAgICAgICAgICAgcm93ID0gaGVpZ2h0IC0gMTsKICAgICAgICAgIH0KICAgICAgICAgIGxldCBsYXRpdHVkZSA9IG5hdGl2ZVJlY3RhbmdsZS5ub3J0aCAtIGdyYW51bGFyaXR5WSAqIHJvdzsKICAgICAgICAgIGlmICghaXNHZW9ncmFwaGljKSB7CiAgICAgICAgICAgIGxhdGl0dWRlID0gcGlPdmVyVHdvIC0gMiAqIGF0YW4oZXhwKC1sYXRpdHVkZSAqIG9uZU92ZXJHbG9iZVNlbWltYWpvckF4aXMpKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGxhdGl0dWRlID0gdG9SYWRpYW5zKGxhdGl0dWRlKTsKICAgICAgICAgIH0KICAgICAgICAgIGxldCB2NCA9IChsYXRpdHVkZSAtIGdlb2dyYXBoaWNTb3V0aCkgLyAoZ2VvZ3JhcGhpY05vcnRoIC0gZ2VvZ3JhcGhpY1NvdXRoKTsKICAgICAgICAgIHY0ID0gTWF0aF9kZWZhdWx0LmNsYW1wKHY0LCAwLCAxKTsKICAgICAgICAgIGNvbnN0IGlzTm9ydGhFZGdlID0gcm93SW5kZXggPT09IHN0YXJ0Um93OwogICAgICAgICAgY29uc3QgaXNTb3V0aEVkZ2UgPSByb3dJbmRleCA9PT0gZW5kUm93IC0gMTsKICAgICAgICAgIGlmIChza2lydEhlaWdodCA+IDApIHsKICAgICAgICAgICAgaWYgKGlzTm9ydGhFZGdlKSB7CiAgICAgICAgICAgICAgbGF0aXR1ZGUgKz0gc2tpcnRPZmZzZXRQZXJjZW50YWdlICogcmVjdGFuZ2xlSGVpZ2h0OwogICAgICAgICAgICB9IGVsc2UgaWYgKGlzU291dGhFZGdlKSB7CiAgICAgICAgICAgICAgbGF0aXR1ZGUgLT0gc2tpcnRPZmZzZXRQZXJjZW50YWdlICogcmVjdGFuZ2xlSGVpZ2h0OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBjb3NMYXRpdHVkZSA9IGNvczQobGF0aXR1ZGUpOwogICAgICAgICAgY29uc3QgblogPSBzaW40KGxhdGl0dWRlKTsKICAgICAgICAgIGNvbnN0IGtaID0gcmFkaWlTcXVhcmVkWiAqIG5aOwogICAgICAgICAgbGV0IHdlYk1lcmNhdG9yVDsKICAgICAgICAgIGlmIChpbmNsdWRlV2ViTWVyY2F0b3JUKSB7CiAgICAgICAgICAgIHdlYk1lcmNhdG9yVCA9IChXZWJNZXJjYXRvclByb2plY3Rpb25fZGVmYXVsdC5nZW9kZXRpY0xhdGl0dWRlVG9NZXJjYXRvckFuZ2xlKGxhdGl0dWRlKSAtIHNvdXRoTWVyY2F0b3JZKSAqIG9uZU92ZXJNZXJjYXRvckhlaWdodDsKICAgICAgICAgIH0KICAgICAgICAgIGZvciAobGV0IGNvbEluZGV4ID0gc3RhcnRDb2w7IGNvbEluZGV4IDwgZW5kQ29sOyArK2NvbEluZGV4KSB7CiAgICAgICAgICAgIGxldCBjb2wgPSBjb2xJbmRleDsKICAgICAgICAgICAgaWYgKGNvbCA8IDApIHsKICAgICAgICAgICAgICBjb2wgPSAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChjb2wgPj0gd2lkdGgpIHsKICAgICAgICAgICAgICBjb2wgPSB3aWR0aCAtIDE7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgdGVycmFpbk9mZnNldCA9IHJvdyAqICh3aWR0aCAqIHN0cmlkZSkgKyBjb2wgKiBzdHJpZGU7CiAgICAgICAgICAgIGxldCBoZWlnaHRTYW1wbGU7CiAgICAgICAgICAgIGlmIChlbGVtZW50c1BlckhlaWdodCA9PT0gMSkgewogICAgICAgICAgICAgIGhlaWdodFNhbXBsZSA9IGhlaWdodG1hcFt0ZXJyYWluT2Zmc2V0XTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBoZWlnaHRTYW1wbGUgPSAwOwogICAgICAgICAgICAgIGxldCBlbGVtZW50T2Zmc2V0OwogICAgICAgICAgICAgIGlmIChpc0JpZ0VuZGlhbikgewogICAgICAgICAgICAgICAgZm9yIChlbGVtZW50T2Zmc2V0ID0gMDsgZWxlbWVudE9mZnNldCA8IGVsZW1lbnRzUGVySGVpZ2h0OyArK2VsZW1lbnRPZmZzZXQpIHsKICAgICAgICAgICAgICAgICAgaGVpZ2h0U2FtcGxlID0gaGVpZ2h0U2FtcGxlICogZWxlbWVudE11bHRpcGxpZXIgKyBoZWlnaHRtYXBbdGVycmFpbk9mZnNldCArIGVsZW1lbnRPZmZzZXRdOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBmb3IgKGVsZW1lbnRPZmZzZXQgPSBlbGVtZW50c1BlckhlaWdodCAtIDE7IGVsZW1lbnRPZmZzZXQgPj0gMDsgLS1lbGVtZW50T2Zmc2V0KSB7CiAgICAgICAgICAgICAgICAgIGhlaWdodFNhbXBsZSA9IGhlaWdodFNhbXBsZSAqIGVsZW1lbnRNdWx0aXBsaWVyICsgaGVpZ2h0bWFwW3RlcnJhaW5PZmZzZXQgKyBlbGVtZW50T2Zmc2V0XTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaGVpZ2h0U2FtcGxlID0gaGVpZ2h0U2FtcGxlICogaGVpZ2h0U2NhbGUgKyBoZWlnaHRPZmZzZXQ7CiAgICAgICAgICAgIG1heGltdW1IZWlnaHQgPSBNYXRoLm1heChtYXhpbXVtSGVpZ2h0LCBoZWlnaHRTYW1wbGUpOwogICAgICAgICAgICBtaW5pbXVtSGVpZ2h0ID0gTWF0aC5taW4obWluaW11bUhlaWdodCwgaGVpZ2h0U2FtcGxlKTsKICAgICAgICAgICAgbGV0IGxvbmdpdHVkZSA9IG5hdGl2ZVJlY3RhbmdsZS53ZXN0ICsgZ3JhbnVsYXJpdHlYICogY29sOwogICAgICAgICAgICBpZiAoIWlzR2VvZ3JhcGhpYykgewogICAgICAgICAgICAgIGxvbmdpdHVkZSA9IGxvbmdpdHVkZSAqIG9uZU92ZXJHbG9iZVNlbWltYWpvckF4aXM7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgbG9uZ2l0dWRlID0gdG9SYWRpYW5zKGxvbmdpdHVkZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbGV0IHU0ID0gKGxvbmdpdHVkZSAtIGdlb2dyYXBoaWNXZXN0KSAvIChnZW9ncmFwaGljRWFzdCAtIGdlb2dyYXBoaWNXZXN0KTsKICAgICAgICAgICAgdTQgPSBNYXRoX2RlZmF1bHQuY2xhbXAodTQsIDAsIDEpOwogICAgICAgICAgICBsZXQgaW5kZXggPSByb3cgKiB3aWR0aCArIGNvbDsKICAgICAgICAgICAgaWYgKHNraXJ0SGVpZ2h0ID4gMCkgewogICAgICAgICAgICAgIGNvbnN0IGlzV2VzdEVkZ2UgPSBjb2xJbmRleCA9PT0gc3RhcnRDb2w7CiAgICAgICAgICAgICAgY29uc3QgaXNFYXN0RWRnZSA9IGNvbEluZGV4ID09PSBlbmRDb2wgLSAxOwogICAgICAgICAgICAgIGNvbnN0IGlzRWRnZTIgPSBpc05vcnRoRWRnZSB8fCBpc1NvdXRoRWRnZSB8fCBpc1dlc3RFZGdlIHx8IGlzRWFzdEVkZ2U7CiAgICAgICAgICAgICAgY29uc3QgaXNDb3JuZXIgPSAoaXNOb3J0aEVkZ2UgfHwgaXNTb3V0aEVkZ2UpICYmIChpc1dlc3RFZGdlIHx8IGlzRWFzdEVkZ2UpOwogICAgICAgICAgICAgIGlmIChpc0Nvcm5lcikgewogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgfSBlbHNlIGlmIChpc0VkZ2UyKSB7CiAgICAgICAgICAgICAgICBoZWlnaHRTYW1wbGUgLT0gc2tpcnRIZWlnaHQ7CiAgICAgICAgICAgICAgICBpZiAoaXNXZXN0RWRnZSkgewogICAgICAgICAgICAgICAgICBpbmRleCA9IGdyaWRWZXJ0ZXhDb3VudCArIChoZWlnaHQgLSByb3cgLSAxKTsKICAgICAgICAgICAgICAgICAgbG9uZ2l0dWRlIC09IHNraXJ0T2Zmc2V0UGVyY2VudGFnZSAqIHJlY3RhbmdsZVdpZHRoOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChpc1NvdXRoRWRnZSkgewogICAgICAgICAgICAgICAgICBpbmRleCA9IGdyaWRWZXJ0ZXhDb3VudCArIGhlaWdodCArICh3aWR0aCAtIGNvbCAtIDEpOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChpc0Vhc3RFZGdlKSB7CiAgICAgICAgICAgICAgICAgIGluZGV4ID0gZ3JpZFZlcnRleENvdW50ICsgaGVpZ2h0ICsgd2lkdGggKyByb3c7CiAgICAgICAgICAgICAgICAgIGxvbmdpdHVkZSArPSBza2lydE9mZnNldFBlcmNlbnRhZ2UgKiByZWN0YW5nbGVXaWR0aDsKICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNOb3J0aEVkZ2UpIHsKICAgICAgICAgICAgICAgICAgaW5kZXggPSBncmlkVmVydGV4Q291bnQgKyBoZWlnaHQgKyB3aWR0aCArIGhlaWdodCArIGNvbDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY29uc3QgblggPSBjb3NMYXRpdHVkZSAqIGNvczQobG9uZ2l0dWRlKTsKICAgICAgICAgICAgY29uc3QgblkgPSBjb3NMYXRpdHVkZSAqIHNpbjQobG9uZ2l0dWRlKTsKICAgICAgICAgICAgY29uc3Qga1ggPSByYWRpaVNxdWFyZWRYICogblg7CiAgICAgICAgICAgIGNvbnN0IGtZID0gcmFkaWlTcXVhcmVkWSAqIG5ZOwogICAgICAgICAgICBjb25zdCBnYW1tYSA9IHNxcnQyKGtYICogblggKyBrWSAqIG5ZICsga1ogKiBuWik7CiAgICAgICAgICAgIGNvbnN0IG9uZU92ZXJHYW1tYSA9IDEgLyBnYW1tYTsKICAgICAgICAgICAgY29uc3QgclN1cmZhY2VYID0ga1ggKiBvbmVPdmVyR2FtbWE7CiAgICAgICAgICAgIGNvbnN0IHJTdXJmYWNlWSA9IGtZICogb25lT3ZlckdhbW1hOwogICAgICAgICAgICBjb25zdCByU3VyZmFjZVogPSBrWiAqIG9uZU92ZXJHYW1tYTsKICAgICAgICAgICAgY29uc3QgcG9zaXRpb24gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgICAgICAgIHBvc2l0aW9uLnggPSByU3VyZmFjZVggKyBuWCAqIGhlaWdodFNhbXBsZTsKICAgICAgICAgICAgcG9zaXRpb24ueSA9IHJTdXJmYWNlWSArIG5ZICogaGVpZ2h0U2FtcGxlOwogICAgICAgICAgICBwb3NpdGlvbi56ID0gclN1cmZhY2VaICsgblogKiBoZWlnaHRTYW1wbGU7CiAgICAgICAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQodG9FTlUsIHBvc2l0aW9uLCBjYXJ0ZXNpYW4zU2NyYXRjaDcpOwogICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWluaW11bUJ5Q29tcG9uZW50KGNhcnRlc2lhbjNTY3JhdGNoNywgbWluaW11bSwgbWluaW11bSk7CiAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQnlDb21wb25lbnQoY2FydGVzaWFuM1NjcmF0Y2g3LCBtYXhpbXVtLCBtYXhpbXVtKTsKICAgICAgICAgICAgaE1pbiA9IE1hdGgubWluKGhNaW4sIGhlaWdodFNhbXBsZSk7CiAgICAgICAgICAgIHBvc2l0aW9uc1tpbmRleF0gPSBwb3NpdGlvbjsKICAgICAgICAgICAgdXZzW2luZGV4XSA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQodTQsIHY0KTsKICAgICAgICAgICAgaGVpZ2h0c1tpbmRleF0gPSBoZWlnaHRTYW1wbGU7CiAgICAgICAgICAgIGlmIChpbmNsdWRlV2ViTWVyY2F0b3JUKSB7CiAgICAgICAgICAgICAgd2ViTWVyY2F0b3JUc1tpbmRleF0gPSB3ZWJNZXJjYXRvclQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzKSB7CiAgICAgICAgICAgICAgZ2VvZGV0aWNTdXJmYWNlTm9ybWFsc1tpbmRleF0gPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBib3VuZGluZ1NwaGVyZTNEID0gQm91bmRpbmdTcGhlcmVfZGVmYXVsdC5mcm9tUG9pbnRzKHBvc2l0aW9ucyk7CiAgICAgICAgbGV0IG9yaWVudGVkQm91bmRpbmdCb3g7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZWN0YW5nbGUpKSB7CiAgICAgICAgICBvcmllbnRlZEJvdW5kaW5nQm94ID0gT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21SZWN0YW5nbGUoCiAgICAgICAgICAgIHJlY3RhbmdsZSwKICAgICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgICAgICAgZWxsaXBzb2lkCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICBsZXQgb2NjbHVkZWVQb2ludEluU2NhbGVkU3BhY2U7CiAgICAgICAgaWYgKGhhc1JlbGF0aXZlVG9DZW50ZXIpIHsKICAgICAgICAgIGNvbnN0IG9jY2x1ZGVyID0gbmV3IEVsbGlwc29pZGFsT2NjbHVkZXJfZGVmYXVsdChlbGxpcHNvaWQpOwogICAgICAgICAgb2NjbHVkZWVQb2ludEluU2NhbGVkU3BhY2UgPSBvY2NsdWRlci5jb21wdXRlSG9yaXpvbkN1bGxpbmdQb2ludFBvc3NpYmx5VW5kZXJFbGxpcHNvaWQoCiAgICAgICAgICAgIHJlbGF0aXZlVG9DZW50ZXIsCiAgICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgICAgbWluaW11bUhlaWdodAogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYWFCb3ggPSBuZXcgQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0KG1pbmltdW0sIG1heGltdW0sIHJlbGF0aXZlVG9DZW50ZXIpOwogICAgICAgIGNvbnN0IGVuY29kaW5nID0gbmV3IFRlcnJhaW5FbmNvZGluZ19kZWZhdWx0KAogICAgICAgICAgcmVsYXRpdmVUb0NlbnRlciwKICAgICAgICAgIGFhQm94LAogICAgICAgICAgaE1pbiwKICAgICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgICBmcm9tRU5VLAogICAgICAgICAgZmFsc2UsCiAgICAgICAgICBpbmNsdWRlV2ViTWVyY2F0b3JULAogICAgICAgICAgaW5jbHVkZUdlb2RldGljU3VyZmFjZU5vcm1hbHMsCiAgICAgICAgICBleGFnZ2VyYXRpb24sCiAgICAgICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgICAgICk7CiAgICAgICAgY29uc3QgdmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KHZlcnRleENvdW50ICogZW5jb2Rpbmcuc3RyaWRlKTsKICAgICAgICBsZXQgYnVmZmVySW5kZXggPSAwOwogICAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCB2ZXJ0ZXhDb3VudDsgKytqMikgewogICAgICAgICAgYnVmZmVySW5kZXggPSBlbmNvZGluZy5lbmNvZGUoCiAgICAgICAgICAgIHZlcnRpY2VzLAogICAgICAgICAgICBidWZmZXJJbmRleCwKICAgICAgICAgICAgcG9zaXRpb25zW2oyXSwKICAgICAgICAgICAgdXZzW2oyXSwKICAgICAgICAgICAgaGVpZ2h0c1tqMl0sCiAgICAgICAgICAgIHZvaWQgMCwKICAgICAgICAgICAgd2ViTWVyY2F0b3JUc1tqMl0sCiAgICAgICAgICAgIGdlb2RldGljU3VyZmFjZU5vcm1hbHNbajJdCiAgICAgICAgICApOwogICAgICAgIH0KICAgICAgICByZXR1cm4gewogICAgICAgICAgdmVydGljZXMsCiAgICAgICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICAgICAgbWluaW11bUhlaWdodCwKICAgICAgICAgIGVuY29kaW5nLAogICAgICAgICAgYm91bmRpbmdTcGhlcmUzRCwKICAgICAgICAgIG9yaWVudGVkQm91bmRpbmdCb3gsCiAgICAgICAgICBvY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZQogICAgICAgIH07CiAgICAgIH07CiAgICAgIEhlaWdodG1hcFRlc3NlbGxhdG9yX2RlZmF1bHQgPSBIZWlnaHRtYXBUZXNzZWxsYXRvcjsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL2xlcmMvTGVyY0RlY29kZS5qcwogIHZhciByZXF1aXJlX0xlcmNEZWNvZGUgPSBfX2NvbW1vbkpTKHsKICAgICJub2RlX21vZHVsZXMvbGVyYy9MZXJjRGVjb2RlLmpzIihleHBvcnRzMiwgbW9kdWxlKSB7CiAgICAgIC8qIENvcHlyaWdodCAyMDE1LTIwMTggRXNyaS4gTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7IHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0IGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMCBAcHJlc2VydmUgKi8KICAgICAgKGZ1bmN0aW9uKCkgewogICAgICAgIHZhciBMZXJjRGVjb2RlID0gKGZ1bmN0aW9uKCkgewogICAgICAgICAgdmFyIENudFpJbWFnZSA9IHt9OwogICAgICAgICAgQ250WkltYWdlLmRlZmF1bHROb0RhdGFWYWx1ZSA9IC0zNDAyNzk5OTM4NzkwMTQ4NGUyMjsKICAgICAgICAgIENudFpJbWFnZS5kZWNvZGUgPSBmdW5jdGlvbihpbnB1dCwgb3B0aW9ucykgewogICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTsKICAgICAgICAgICAgdmFyIHNraXBNYXNrID0gb3B0aW9ucy5lbmNvZGVkTWFza0RhdGEgfHwgb3B0aW9ucy5lbmNvZGVkTWFza0RhdGEgPT09IG51bGw7CiAgICAgICAgICAgIHZhciBwYXJzZWREYXRhID0gcGFyc2UoaW5wdXQsIG9wdGlvbnMuaW5wdXRPZmZzZXQgfHwgMCwgc2tpcE1hc2spOwogICAgICAgICAgICB2YXIgbm9EYXRhVmFsdWUgPSBvcHRpb25zLm5vRGF0YVZhbHVlICE9PSBudWxsID8gb3B0aW9ucy5ub0RhdGFWYWx1ZSA6IENudFpJbWFnZS5kZWZhdWx0Tm9EYXRhVmFsdWU7CiAgICAgICAgICAgIHZhciB1bmNvbXByZXNzZWREYXRhID0gdW5jb21wcmVzc1BpeGVsVmFsdWVzKAogICAgICAgICAgICAgIHBhcnNlZERhdGEsCiAgICAgICAgICAgICAgb3B0aW9ucy5waXhlbFR5cGUgfHwgRmxvYXQzMkFycmF5LAogICAgICAgICAgICAgIG9wdGlvbnMuZW5jb2RlZE1hc2tEYXRhLAogICAgICAgICAgICAgIG5vRGF0YVZhbHVlLAogICAgICAgICAgICAgIG9wdGlvbnMucmV0dXJuTWFzawogICAgICAgICAgICApOwogICAgICAgICAgICB2YXIgcmVzdWx0ID0gewogICAgICAgICAgICAgIHdpZHRoOiBwYXJzZWREYXRhLndpZHRoLAogICAgICAgICAgICAgIGhlaWdodDogcGFyc2VkRGF0YS5oZWlnaHQsCiAgICAgICAgICAgICAgcGl4ZWxEYXRhOiB1bmNvbXByZXNzZWREYXRhLnJlc3VsdFBpeGVscywKICAgICAgICAgICAgICBtaW5WYWx1ZTogdW5jb21wcmVzc2VkRGF0YS5taW5WYWx1ZSwKICAgICAgICAgICAgICBtYXhWYWx1ZTogcGFyc2VkRGF0YS5waXhlbHMubWF4VmFsdWUsCiAgICAgICAgICAgICAgbm9EYXRhVmFsdWUKICAgICAgICAgICAgfTsKICAgICAgICAgICAgaWYgKHVuY29tcHJlc3NlZERhdGEucmVzdWx0TWFzaykgewogICAgICAgICAgICAgIHJlc3VsdC5tYXNrRGF0YSA9IHVuY29tcHJlc3NlZERhdGEucmVzdWx0TWFzazsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAob3B0aW9ucy5yZXR1cm5FbmNvZGVkTWFzayAmJiBwYXJzZWREYXRhLm1hc2spIHsKICAgICAgICAgICAgICByZXN1bHQuZW5jb2RlZE1hc2tEYXRhID0gcGFyc2VkRGF0YS5tYXNrLmJpdHNldCA/IHBhcnNlZERhdGEubWFzay5iaXRzZXQgOiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChvcHRpb25zLnJldHVybkZpbGVJbmZvKSB7CiAgICAgICAgICAgICAgcmVzdWx0LmZpbGVJbmZvID0gZm9ybWF0RmlsZUluZm8ocGFyc2VkRGF0YSk7CiAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuY29tcHV0ZVVzZWRCaXREZXB0aHMpIHsKICAgICAgICAgICAgICAgIHJlc3VsdC5maWxlSW5mby5iaXREZXB0aHMgPSBjb21wdXRlVXNlZEJpdERlcHRocyhwYXJzZWREYXRhKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgIH07CiAgICAgICAgICB2YXIgdW5jb21wcmVzc1BpeGVsVmFsdWVzID0gZnVuY3Rpb24oZGF0YSwgVHlwZWRBcnJheUNsYXNzLCBtYXNrQml0c2V0LCBub0RhdGFWYWx1ZSwgc3RvcmVEZWNvZGVkTWFzaykgewogICAgICAgICAgICB2YXIgYmxvY2tJZHggPSAwOwogICAgICAgICAgICB2YXIgbnVtWCA9IGRhdGEucGl4ZWxzLm51bUJsb2Nrc1g7CiAgICAgICAgICAgIHZhciBudW1ZID0gZGF0YS5waXhlbHMubnVtQmxvY2tzWTsKICAgICAgICAgICAgdmFyIGJsb2NrV2lkdGggPSBNYXRoLmZsb29yKGRhdGEud2lkdGggLyBudW1YKTsKICAgICAgICAgICAgdmFyIGJsb2NrSGVpZ2h0ID0gTWF0aC5mbG9vcihkYXRhLmhlaWdodCAvIG51bVkpOwogICAgICAgICAgICB2YXIgc2NhbGUgPSAyICogZGF0YS5tYXhaRXJyb3I7CiAgICAgICAgICAgIHZhciBtaW5WYWx1ZSA9IE51bWJlci5NQVhfVkFMVUUsIGN1cnJlbnRWYWx1ZTsKICAgICAgICAgICAgbWFza0JpdHNldCA9IG1hc2tCaXRzZXQgfHwgKGRhdGEubWFzayA/IGRhdGEubWFzay5iaXRzZXQgOiBudWxsKTsKICAgICAgICAgICAgdmFyIHJlc3VsdFBpeGVscywgcmVzdWx0TWFzazsKICAgICAgICAgICAgcmVzdWx0UGl4ZWxzID0gbmV3IFR5cGVkQXJyYXlDbGFzcyhkYXRhLndpZHRoICogZGF0YS5oZWlnaHQpOwogICAgICAgICAgICBpZiAoc3RvcmVEZWNvZGVkTWFzayAmJiBtYXNrQml0c2V0KSB7CiAgICAgICAgICAgICAgcmVzdWx0TWFzayA9IG5ldyBVaW50OEFycmF5KGRhdGEud2lkdGggKiBkYXRhLmhlaWdodCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGJsb2NrRGF0YUJ1ZmZlciA9IG5ldyBGbG9hdDMyQXJyYXkoYmxvY2tXaWR0aCAqIGJsb2NrSGVpZ2h0KTsKICAgICAgICAgICAgdmFyIHh4LCB5eTsKICAgICAgICAgICAgZm9yICh2YXIgeTIgPSAwOyB5MiA8PSBudW1ZOyB5MisrKSB7CiAgICAgICAgICAgICAgdmFyIHRoaXNCbG9ja0hlaWdodCA9IHkyICE9PSBudW1ZID8gYmxvY2tIZWlnaHQgOiBkYXRhLmhlaWdodCAlIG51bVk7CiAgICAgICAgICAgICAgaWYgKHRoaXNCbG9ja0hlaWdodCA9PT0gMCkgewogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGZvciAodmFyIHgyID0gMDsgeDIgPD0gbnVtWDsgeDIrKykgewogICAgICAgICAgICAgICAgdmFyIHRoaXNCbG9ja1dpZHRoID0geDIgIT09IG51bVggPyBibG9ja1dpZHRoIDogZGF0YS53aWR0aCAlIG51bVg7CiAgICAgICAgICAgICAgICBpZiAodGhpc0Jsb2NrV2lkdGggPT09IDApIHsKICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB2YXIgb3V0UHRyID0geTIgKiBkYXRhLndpZHRoICogYmxvY2tIZWlnaHQgKyB4MiAqIGJsb2NrV2lkdGg7CiAgICAgICAgICAgICAgICB2YXIgb3V0U3RyaWRlID0gZGF0YS53aWR0aCAtIHRoaXNCbG9ja1dpZHRoOwogICAgICAgICAgICAgICAgdmFyIGJsb2NrID0gZGF0YS5waXhlbHMuYmxvY2tzW2Jsb2NrSWR4XTsKICAgICAgICAgICAgICAgIHZhciBibG9ja0RhdGEsIGJsb2NrUHRyLCBjb25zdFZhbHVlOwogICAgICAgICAgICAgICAgaWYgKGJsb2NrLmVuY29kaW5nIDwgMikgewogICAgICAgICAgICAgICAgICBpZiAoYmxvY2suZW5jb2RpbmcgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICBibG9ja0RhdGEgPSBibG9jay5yYXdEYXRhOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHVuc3R1ZmYoYmxvY2suc3R1ZmZlZERhdGEsIGJsb2NrLmJpdHNQZXJQaXhlbCwgYmxvY2subnVtVmFsaWRQaXhlbHMsIGJsb2NrLm9mZnNldCwgc2NhbGUsIGJsb2NrRGF0YUJ1ZmZlciwgZGF0YS5waXhlbHMubWF4VmFsdWUpOwogICAgICAgICAgICAgICAgICAgIGJsb2NrRGF0YSA9IGJsb2NrRGF0YUJ1ZmZlcjsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBibG9ja1B0ciA9IDA7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGJsb2NrLmVuY29kaW5nID09PSAyKSB7CiAgICAgICAgICAgICAgICAgIGNvbnN0VmFsdWUgPSAwOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgY29uc3RWYWx1ZSA9IGJsb2NrLm9mZnNldDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHZhciBtYXNrQnl0ZTsKICAgICAgICAgICAgICAgIGlmIChtYXNrQml0c2V0KSB7CiAgICAgICAgICAgICAgICAgIGZvciAoeXkgPSAwOyB5eSA8IHRoaXNCbG9ja0hlaWdodDsgeXkrKykgewogICAgICAgICAgICAgICAgICAgIGlmIChvdXRQdHIgJiA3KSB7CiAgICAgICAgICAgICAgICAgICAgICBtYXNrQnl0ZSA9IG1hc2tCaXRzZXRbb3V0UHRyID4+IDNdOwogICAgICAgICAgICAgICAgICAgICAgbWFza0J5dGUgPDw9IG91dFB0ciAmIDc7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGZvciAoeHggPSAwOyB4eCA8IHRoaXNCbG9ja1dpZHRoOyB4eCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICBpZiAoIShvdXRQdHIgJiA3KSkgewogICAgICAgICAgICAgICAgICAgICAgICBtYXNrQnl0ZSA9IG1hc2tCaXRzZXRbb3V0UHRyID4+IDNdOwogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgaWYgKG1hc2tCeXRlICYgMTI4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHRNYXNrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0TWFza1tvdXRQdHJdID0gMTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50VmFsdWUgPSBibG9jay5lbmNvZGluZyA8IDIgPyBibG9ja0RhdGFbYmxvY2tQdHIrK10gOiBjb25zdFZhbHVlOwogICAgICAgICAgICAgICAgICAgICAgICBtaW5WYWx1ZSA9IG1pblZhbHVlID4gY3VycmVudFZhbHVlID8gY3VycmVudFZhbHVlIDogbWluVmFsdWU7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFBpeGVsc1tvdXRQdHIrK10gPSBjdXJyZW50VmFsdWU7CiAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0TWFzaykgewogICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdE1hc2tbb3V0UHRyXSA9IDA7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0UGl4ZWxzW291dFB0cisrXSA9IG5vRGF0YVZhbHVlOwogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgbWFza0J5dGUgPDw9IDE7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIG91dFB0ciArPSBvdXRTdHJpZGU7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIGlmIChibG9jay5lbmNvZGluZyA8IDIpIHsKICAgICAgICAgICAgICAgICAgICBmb3IgKHl5ID0gMDsgeXkgPCB0aGlzQmxvY2tIZWlnaHQ7IHl5KyspIHsKICAgICAgICAgICAgICAgICAgICAgIGZvciAoeHggPSAwOyB4eCA8IHRoaXNCbG9ja1dpZHRoOyB4eCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWYWx1ZSA9IGJsb2NrRGF0YVtibG9ja1B0cisrXTsKICAgICAgICAgICAgICAgICAgICAgICAgbWluVmFsdWUgPSBtaW5WYWx1ZSA+IGN1cnJlbnRWYWx1ZSA/IGN1cnJlbnRWYWx1ZSA6IG1pblZhbHVlOwogICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHNbb3V0UHRyKytdID0gY3VycmVudFZhbHVlOwogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgb3V0UHRyICs9IG91dFN0cmlkZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgbWluVmFsdWUgPSBtaW5WYWx1ZSA+IGNvbnN0VmFsdWUgPyBjb25zdFZhbHVlIDogbWluVmFsdWU7CiAgICAgICAgICAgICAgICAgICAgZm9yICh5eSA9IDA7IHl5IDwgdGhpc0Jsb2NrSGVpZ2h0OyB5eSsrKSB7CiAgICAgICAgICAgICAgICAgICAgICBmb3IgKHh4ID0gMDsgeHggPCB0aGlzQmxvY2tXaWR0aDsgeHgrKykgewogICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHNbb3V0UHRyKytdID0gY29uc3RWYWx1ZTsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIG91dFB0ciArPSBvdXRTdHJpZGU7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoYmxvY2suZW5jb2RpbmcgPT09IDEgJiYgYmxvY2tQdHIgIT09IGJsb2NrLm51bVZhbGlkUGl4ZWxzKSB7CiAgICAgICAgICAgICAgICAgIHRocm93ICJCbG9jayBhbmQgTWFzayBkbyBub3QgbWF0Y2giOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgYmxvY2tJZHgrKzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICByZXN1bHRQaXhlbHMsCiAgICAgICAgICAgICAgcmVzdWx0TWFzaywKICAgICAgICAgICAgICBtaW5WYWx1ZQogICAgICAgICAgICB9OwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBmb3JtYXRGaWxlSW5mbyA9IGZ1bmN0aW9uKGRhdGEpIHsKICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAiZmlsZUlkZW50aWZpZXJTdHJpbmciOiBkYXRhLmZpbGVJZGVudGlmaWVyU3RyaW5nLAogICAgICAgICAgICAgICJmaWxlVmVyc2lvbiI6IGRhdGEuZmlsZVZlcnNpb24sCiAgICAgICAgICAgICAgImltYWdlVHlwZSI6IGRhdGEuaW1hZ2VUeXBlLAogICAgICAgICAgICAgICJoZWlnaHQiOiBkYXRhLmhlaWdodCwKICAgICAgICAgICAgICAid2lkdGgiOiBkYXRhLndpZHRoLAogICAgICAgICAgICAgICJtYXhaRXJyb3IiOiBkYXRhLm1heFpFcnJvciwKICAgICAgICAgICAgICAiZW9mT2Zmc2V0IjogZGF0YS5lb2ZPZmZzZXQsCiAgICAgICAgICAgICAgIm1hc2siOiBkYXRhLm1hc2sgPyB7CiAgICAgICAgICAgICAgICAibnVtQmxvY2tzWCI6IGRhdGEubWFzay5udW1CbG9ja3NYLAogICAgICAgICAgICAgICAgIm51bUJsb2Nrc1kiOiBkYXRhLm1hc2subnVtQmxvY2tzWSwKICAgICAgICAgICAgICAgICJudW1CeXRlcyI6IGRhdGEubWFzay5udW1CeXRlcywKICAgICAgICAgICAgICAgICJtYXhWYWx1ZSI6IGRhdGEubWFzay5tYXhWYWx1ZQogICAgICAgICAgICAgIH0gOiBudWxsLAogICAgICAgICAgICAgICJwaXhlbHMiOiB7CiAgICAgICAgICAgICAgICAibnVtQmxvY2tzWCI6IGRhdGEucGl4ZWxzLm51bUJsb2Nrc1gsCiAgICAgICAgICAgICAgICAibnVtQmxvY2tzWSI6IGRhdGEucGl4ZWxzLm51bUJsb2Nrc1ksCiAgICAgICAgICAgICAgICAibnVtQnl0ZXMiOiBkYXRhLnBpeGVscy5udW1CeXRlcywKICAgICAgICAgICAgICAgICJtYXhWYWx1ZSI6IGRhdGEucGl4ZWxzLm1heFZhbHVlLAogICAgICAgICAgICAgICAgIm5vRGF0YVZhbHVlIjogZGF0YS5ub0RhdGFWYWx1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfTsKICAgICAgICAgIH07CiAgICAgICAgICB2YXIgY29tcHV0ZVVzZWRCaXREZXB0aHMgPSBmdW5jdGlvbihkYXRhKSB7CiAgICAgICAgICAgIHZhciBudW1CbG9ja3MgPSBkYXRhLnBpeGVscy5udW1CbG9ja3NYICogZGF0YS5waXhlbHMubnVtQmxvY2tzWTsKICAgICAgICAgICAgdmFyIGJpdERlcHRocyA9IHt9OwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgbnVtQmxvY2tzOyBpMisrKSB7CiAgICAgICAgICAgICAgdmFyIGJsb2NrID0gZGF0YS5waXhlbHMuYmxvY2tzW2kyXTsKICAgICAgICAgICAgICBpZiAoYmxvY2suZW5jb2RpbmcgPT09IDApIHsKICAgICAgICAgICAgICAgIGJpdERlcHRocy5mbG9hdDMyID0gdHJ1ZTsKICAgICAgICAgICAgICB9IGVsc2UgaWYgKGJsb2NrLmVuY29kaW5nID09PSAxKSB7CiAgICAgICAgICAgICAgICBiaXREZXB0aHNbYmxvY2suYml0c1BlclBpeGVsXSA9IHRydWU7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGJpdERlcHRoc1swXSA9IHRydWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBPYmplY3Qua2V5cyhiaXREZXB0aHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBwYXJzZSA9IGZ1bmN0aW9uKGlucHV0LCBmcCwgc2tpcE1hc2spIHsKICAgICAgICAgICAgdmFyIGRhdGEgPSB7fTsKICAgICAgICAgICAgdmFyIGZpbGVJZFZpZXcgPSBuZXcgVWludDhBcnJheShpbnB1dCwgZnAsIDEwKTsKICAgICAgICAgICAgZGF0YS5maWxlSWRlbnRpZmllclN0cmluZyA9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgZmlsZUlkVmlldyk7CiAgICAgICAgICAgIGlmIChkYXRhLmZpbGVJZGVudGlmaWVyU3RyaW5nLnRyaW0oKSAhPT0gIkNudFpJbWFnZSIpIHsKICAgICAgICAgICAgICB0aHJvdyAiVW5leHBlY3RlZCBmaWxlIGlkZW50aWZpZXIgc3RyaW5nOiAiICsgZGF0YS5maWxlSWRlbnRpZmllclN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgICAgICBmcCArPSAxMDsKICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgRGF0YVZpZXcoaW5wdXQsIGZwLCAyNCk7CiAgICAgICAgICAgIGRhdGEuZmlsZVZlcnNpb24gPSB2aWV3LmdldEludDMyKDAsIHRydWUpOwogICAgICAgICAgICBkYXRhLmltYWdlVHlwZSA9IHZpZXcuZ2V0SW50MzIoNCwgdHJ1ZSk7CiAgICAgICAgICAgIGRhdGEuaGVpZ2h0ID0gdmlldy5nZXRVaW50MzIoOCwgdHJ1ZSk7CiAgICAgICAgICAgIGRhdGEud2lkdGggPSB2aWV3LmdldFVpbnQzMigxMiwgdHJ1ZSk7CiAgICAgICAgICAgIGRhdGEubWF4WkVycm9yID0gdmlldy5nZXRGbG9hdDY0KDE2LCB0cnVlKTsKICAgICAgICAgICAgZnAgKz0gMjQ7CiAgICAgICAgICAgIGlmICghc2tpcE1hc2spIHsKICAgICAgICAgICAgICB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBmcCwgMTYpOwogICAgICAgICAgICAgIGRhdGEubWFzayA9IHt9OwogICAgICAgICAgICAgIGRhdGEubWFzay5udW1CbG9ja3NZID0gdmlldy5nZXRVaW50MzIoMCwgdHJ1ZSk7CiAgICAgICAgICAgICAgZGF0YS5tYXNrLm51bUJsb2Nrc1ggPSB2aWV3LmdldFVpbnQzMig0LCB0cnVlKTsKICAgICAgICAgICAgICBkYXRhLm1hc2subnVtQnl0ZXMgPSB2aWV3LmdldFVpbnQzMig4LCB0cnVlKTsKICAgICAgICAgICAgICBkYXRhLm1hc2subWF4VmFsdWUgPSB2aWV3LmdldEZsb2F0MzIoMTIsIHRydWUpOwogICAgICAgICAgICAgIGZwICs9IDE2OwogICAgICAgICAgICAgIGlmIChkYXRhLm1hc2subnVtQnl0ZXMgPiAwKSB7CiAgICAgICAgICAgICAgICB2YXIgYml0c2V0ID0gbmV3IFVpbnQ4QXJyYXkoTWF0aC5jZWlsKGRhdGEud2lkdGggKiBkYXRhLmhlaWdodCAvIDgpKTsKICAgICAgICAgICAgICAgIHZpZXcgPSBuZXcgRGF0YVZpZXcoaW5wdXQsIGZwLCBkYXRhLm1hc2subnVtQnl0ZXMpOwogICAgICAgICAgICAgICAgdmFyIGNudCA9IHZpZXcuZ2V0SW50MTYoMCwgdHJ1ZSk7CiAgICAgICAgICAgICAgICB2YXIgaXAgPSAyLCBvcCA9IDA7CiAgICAgICAgICAgICAgICBkbyB7CiAgICAgICAgICAgICAgICAgIGlmIChjbnQgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGNudC0tKSB7CiAgICAgICAgICAgICAgICAgICAgICBiaXRzZXRbb3ArK10gPSB2aWV3LmdldFVpbnQ4KGlwKyspOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB2YXIgdmFsID0gdmlldy5nZXRVaW50OChpcCsrKTsKICAgICAgICAgICAgICAgICAgICBjbnQgPSAtY250OwogICAgICAgICAgICAgICAgICAgIHdoaWxlIChjbnQtLSkgewogICAgICAgICAgICAgICAgICAgICAgYml0c2V0W29wKytdID0gdmFsOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBjbnQgPSB2aWV3LmdldEludDE2KGlwLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgaXAgKz0gMjsKICAgICAgICAgICAgICAgIH0gd2hpbGUgKGlwIDwgZGF0YS5tYXNrLm51bUJ5dGVzKTsKICAgICAgICAgICAgICAgIGlmIChjbnQgIT09IC0zMjc2OCB8fCBvcCA8IGJpdHNldC5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgIlVuZXhwZWN0ZWQgZW5kIG9mIG1hc2sgUkxFIGVuY29kaW5nIjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRhdGEubWFzay5iaXRzZXQgPSBiaXRzZXQ7CiAgICAgICAgICAgICAgICBmcCArPSBkYXRhLm1hc2subnVtQnl0ZXM7CiAgICAgICAgICAgICAgfSBlbHNlIGlmICgoZGF0YS5tYXNrLm51bUJ5dGVzIHwgZGF0YS5tYXNrLm51bUJsb2Nrc1kgfCBkYXRhLm1hc2subWF4VmFsdWUpID09PSAwKSB7CiAgICAgICAgICAgICAgICBkYXRhLm1hc2suYml0c2V0ID0gbmV3IFVpbnQ4QXJyYXkoTWF0aC5jZWlsKGRhdGEud2lkdGggKiBkYXRhLmhlaWdodCAvIDgpKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmlldyA9IG5ldyBEYXRhVmlldyhpbnB1dCwgZnAsIDE2KTsKICAgICAgICAgICAgZGF0YS5waXhlbHMgPSB7fTsKICAgICAgICAgICAgZGF0YS5waXhlbHMubnVtQmxvY2tzWSA9IHZpZXcuZ2V0VWludDMyKDAsIHRydWUpOwogICAgICAgICAgICBkYXRhLnBpeGVscy5udW1CbG9ja3NYID0gdmlldy5nZXRVaW50MzIoNCwgdHJ1ZSk7CiAgICAgICAgICAgIGRhdGEucGl4ZWxzLm51bUJ5dGVzID0gdmlldy5nZXRVaW50MzIoOCwgdHJ1ZSk7CiAgICAgICAgICAgIGRhdGEucGl4ZWxzLm1heFZhbHVlID0gdmlldy5nZXRGbG9hdDMyKDEyLCB0cnVlKTsKICAgICAgICAgICAgZnAgKz0gMTY7CiAgICAgICAgICAgIHZhciBudW1CbG9ja3NYID0gZGF0YS5waXhlbHMubnVtQmxvY2tzWDsKICAgICAgICAgICAgdmFyIG51bUJsb2Nrc1kgPSBkYXRhLnBpeGVscy5udW1CbG9ja3NZOwogICAgICAgICAgICB2YXIgYWN0dWFsTnVtQmxvY2tzWCA9IG51bUJsb2Nrc1ggKyAoZGF0YS53aWR0aCAlIG51bUJsb2Nrc1ggPiAwID8gMSA6IDApOwogICAgICAgICAgICB2YXIgYWN0dWFsTnVtQmxvY2tzWSA9IG51bUJsb2Nrc1kgKyAoZGF0YS5oZWlnaHQgJSBudW1CbG9ja3NZID4gMCA/IDEgOiAwKTsKICAgICAgICAgICAgZGF0YS5waXhlbHMuYmxvY2tzID0gbmV3IEFycmF5KGFjdHVhbE51bUJsb2Nrc1ggKiBhY3R1YWxOdW1CbG9ja3NZKTsKICAgICAgICAgICAgdmFyIGJsb2NrSSA9IDA7CiAgICAgICAgICAgIGZvciAodmFyIGJsb2NrWSA9IDA7IGJsb2NrWSA8IGFjdHVhbE51bUJsb2Nrc1k7IGJsb2NrWSsrKSB7CiAgICAgICAgICAgICAgZm9yICh2YXIgYmxvY2tYID0gMDsgYmxvY2tYIDwgYWN0dWFsTnVtQmxvY2tzWDsgYmxvY2tYKyspIHsKICAgICAgICAgICAgICAgIHZhciBzaXplID0gMDsKICAgICAgICAgICAgICAgIHZhciBieXRlc0xlZnQgPSBpbnB1dC5ieXRlTGVuZ3RoIC0gZnA7CiAgICAgICAgICAgICAgICB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBmcCwgTWF0aC5taW4oMTAsIGJ5dGVzTGVmdCkpOwogICAgICAgICAgICAgICAgdmFyIGJsb2NrID0ge307CiAgICAgICAgICAgICAgICBkYXRhLnBpeGVscy5ibG9ja3NbYmxvY2tJKytdID0gYmxvY2s7CiAgICAgICAgICAgICAgICB2YXIgaGVhZGVyQnl0ZSA9IHZpZXcuZ2V0VWludDgoMCk7CiAgICAgICAgICAgICAgICBzaXplKys7CiAgICAgICAgICAgICAgICBibG9jay5lbmNvZGluZyA9IGhlYWRlckJ5dGUgJiA2MzsKICAgICAgICAgICAgICAgIGlmIChibG9jay5lbmNvZGluZyA+IDMpIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgYmxvY2sgZW5jb2RpbmcgKCIgKyBibG9jay5lbmNvZGluZyArICIpIjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChibG9jay5lbmNvZGluZyA9PT0gMikgewogICAgICAgICAgICAgICAgICBmcCsrOwogICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChoZWFkZXJCeXRlICE9PSAwICYmIGhlYWRlckJ5dGUgIT09IDIpIHsKICAgICAgICAgICAgICAgICAgaGVhZGVyQnl0ZSA+Pj0gNjsKICAgICAgICAgICAgICAgICAgYmxvY2sub2Zmc2V0VHlwZSA9IGhlYWRlckJ5dGU7CiAgICAgICAgICAgICAgICAgIGlmIChoZWFkZXJCeXRlID09PSAyKSB7CiAgICAgICAgICAgICAgICAgICAgYmxvY2sub2Zmc2V0ID0gdmlldy5nZXRJbnQ4KDEpOwogICAgICAgICAgICAgICAgICAgIHNpemUrKzsKICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChoZWFkZXJCeXRlID09PSAxKSB7CiAgICAgICAgICAgICAgICAgICAgYmxvY2sub2Zmc2V0ID0gdmlldy5nZXRJbnQxNigxLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICBzaXplICs9IDI7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaGVhZGVyQnl0ZSA9PT0gMCkgewogICAgICAgICAgICAgICAgICAgIGJsb2NrLm9mZnNldCA9IHZpZXcuZ2V0RmxvYXQzMigxLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICBzaXplICs9IDQ7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgYmxvY2sgb2Zmc2V0IHR5cGUiOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChibG9jay5lbmNvZGluZyA9PT0gMSkgewogICAgICAgICAgICAgICAgICAgIGhlYWRlckJ5dGUgPSB2aWV3LmdldFVpbnQ4KHNpemUpOwogICAgICAgICAgICAgICAgICAgIHNpemUrKzsKICAgICAgICAgICAgICAgICAgICBibG9jay5iaXRzUGVyUGl4ZWwgPSBoZWFkZXJCeXRlICYgNjM7CiAgICAgICAgICAgICAgICAgICAgaGVhZGVyQnl0ZSA+Pj0gNjsKICAgICAgICAgICAgICAgICAgICBibG9jay5udW1WYWxpZFBpeGVsc1R5cGUgPSBoZWFkZXJCeXRlOwogICAgICAgICAgICAgICAgICAgIGlmIChoZWFkZXJCeXRlID09PSAyKSB7CiAgICAgICAgICAgICAgICAgICAgICBibG9jay5udW1WYWxpZFBpeGVscyA9IHZpZXcuZ2V0VWludDgoc2l6ZSk7CiAgICAgICAgICAgICAgICAgICAgICBzaXplKys7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChoZWFkZXJCeXRlID09PSAxKSB7CiAgICAgICAgICAgICAgICAgICAgICBibG9jay5udW1WYWxpZFBpeGVscyA9IHZpZXcuZ2V0VWludDE2KHNpemUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgICAgc2l6ZSArPSAyOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaGVhZGVyQnl0ZSA9PT0gMCkgewogICAgICAgICAgICAgICAgICAgICAgYmxvY2subnVtVmFsaWRQaXhlbHMgPSB2aWV3LmdldFVpbnQzMihzaXplLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgICAgIHNpemUgKz0gNDsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgdmFsaWQgcGl4ZWwgY291bnQgdHlwZSI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBmcCArPSBzaXplOwogICAgICAgICAgICAgICAgaWYgKGJsb2NrLmVuY29kaW5nID09PSAzKSB7CiAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdmFyIGFycmF5QnVmLCBzdG9yZTg7CiAgICAgICAgICAgICAgICBpZiAoYmxvY2suZW5jb2RpbmcgPT09IDApIHsKICAgICAgICAgICAgICAgICAgdmFyIG51bVBpeGVscyA9IChkYXRhLnBpeGVscy5udW1CeXRlcyAtIDEpIC8gNDsKICAgICAgICAgICAgICAgICAgaWYgKG51bVBpeGVscyAhPT0gTWF0aC5mbG9vcihudW1QaXhlbHMpKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgInVuY29tcHJlc3NlZCBibG9jayBoYXMgaW52YWxpZCBsZW5ndGgiOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGFycmF5QnVmID0gbmV3IEFycmF5QnVmZmVyKG51bVBpeGVscyAqIDQpOwogICAgICAgICAgICAgICAgICBzdG9yZTggPSBuZXcgVWludDhBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgIHN0b3JlOC5zZXQobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIGZwLCBudW1QaXhlbHMgKiA0KSk7CiAgICAgICAgICAgICAgICAgIHZhciByYXdEYXRhID0gbmV3IEZsb2F0MzJBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgIGJsb2NrLnJhd0RhdGEgPSByYXdEYXRhOwogICAgICAgICAgICAgICAgICBmcCArPSBudW1QaXhlbHMgKiA0OwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChibG9jay5lbmNvZGluZyA9PT0gMSkgewogICAgICAgICAgICAgICAgICB2YXIgZGF0YUJ5dGVzID0gTWF0aC5jZWlsKGJsb2NrLm51bVZhbGlkUGl4ZWxzICogYmxvY2suYml0c1BlclBpeGVsIC8gOCk7CiAgICAgICAgICAgICAgICAgIHZhciBkYXRhV29yZHMgPSBNYXRoLmNlaWwoZGF0YUJ5dGVzIC8gNCk7CiAgICAgICAgICAgICAgICAgIGFycmF5QnVmID0gbmV3IEFycmF5QnVmZmVyKGRhdGFXb3JkcyAqIDQpOwogICAgICAgICAgICAgICAgICBzdG9yZTggPSBuZXcgVWludDhBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgIHN0b3JlOC5zZXQobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIGZwLCBkYXRhQnl0ZXMpKTsKICAgICAgICAgICAgICAgICAgYmxvY2suc3R1ZmZlZERhdGEgPSBuZXcgVWludDMyQXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgICAgICBmcCArPSBkYXRhQnl0ZXM7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGRhdGEuZW9mT2Zmc2V0ID0gZnA7CiAgICAgICAgICAgIHJldHVybiBkYXRhOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciB1bnN0dWZmID0gZnVuY3Rpb24oc3JjLCBiaXRzUGVyUGl4ZWwsIG51bVBpeGVscywgb2Zmc2V0LCBzY2FsZSwgZGVzdCwgbWF4VmFsdWUpIHsKICAgICAgICAgICAgdmFyIGJpdE1hc2sgPSAoMSA8PCBiaXRzUGVyUGl4ZWwpIC0gMTsKICAgICAgICAgICAgdmFyIGkyID0gMCwgbzI7CiAgICAgICAgICAgIHZhciBiaXRzTGVmdCA9IDA7CiAgICAgICAgICAgIHZhciBuMiwgYnVmZmVyOwogICAgICAgICAgICB2YXIgbm1heCA9IE1hdGguY2VpbCgobWF4VmFsdWUgLSBvZmZzZXQpIC8gc2NhbGUpOwogICAgICAgICAgICB2YXIgbnVtSW52YWxpZFRhaWxCeXRlcyA9IHNyYy5sZW5ndGggKiA0IC0gTWF0aC5jZWlsKGJpdHNQZXJQaXhlbCAqIG51bVBpeGVscyAvIDgpOwogICAgICAgICAgICBzcmNbc3JjLmxlbmd0aCAtIDFdIDw8PSA4ICogbnVtSW52YWxpZFRhaWxCeXRlczsKICAgICAgICAgICAgZm9yIChvMiA9IDA7IG8yIDwgbnVtUGl4ZWxzOyBvMisrKSB7CiAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICBiaXRzTGVmdCA9IDMyOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAoYml0c0xlZnQgPj0gYml0c1BlclBpeGVsKSB7CiAgICAgICAgICAgICAgICBuMiA9IGJ1ZmZlciA+Pj4gYml0c0xlZnQgLSBiaXRzUGVyUGl4ZWwgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgYml0c0xlZnQgLT0gYml0c1BlclBpeGVsOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB2YXIgbWlzc2luZ0JpdHMgPSBiaXRzUGVyUGl4ZWwgLSBiaXRzTGVmdDsKICAgICAgICAgICAgICAgIG4yID0gKGJ1ZmZlciAmIGJpdE1hc2spIDw8IG1pc3NpbmdCaXRzICYgYml0TWFzazsKICAgICAgICAgICAgICAgIGJ1ZmZlciA9IHNyY1tpMisrXTsKICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzIgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgIG4yICs9IGJ1ZmZlciA+Pj4gYml0c0xlZnQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGRlc3RbbzJdID0gbjIgPCBubWF4ID8gb2Zmc2V0ICsgbjIgKiBzY2FsZSA6IG1heFZhbHVlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBkZXN0OwogICAgICAgICAgfTsKICAgICAgICAgIHJldHVybiBDbnRaSW1hZ2U7CiAgICAgICAgfSkoKTsKICAgICAgICB2YXIgTGVyYzJEZWNvZGUgPSAoZnVuY3Rpb24oKSB7CiAgICAgICAgICAidXNlIHN0cmljdCI7CiAgICAgICAgICB2YXIgQml0U3R1ZmZlciA9IHsKICAgICAgICAgICAgLy9tZXRob2RzIGVuZGluZyB3aXRoIDIgYXJlIGZvciB0aGUgbmV3IGJ5dGUgb3JkZXIgdXNlZCBieSBMZXJjMi4zIGFuZCBhYm92ZS4KICAgICAgICAgICAgLy9vcmlnaW5hbFVuc3R1ZmYgaXMgdXNlZCB0byB1bnBhY2sgSHVmZm1hbiBjb2RlIHRhYmxlLiBjb2RlIGlzIGR1cGxpY2F0ZWQgdG8gdW5zdHVmZnggZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMuCiAgICAgICAgICAgIHVuc3R1ZmY6IGZ1bmN0aW9uKHNyYywgZGVzdCwgYml0c1BlclBpeGVsLCBudW1QaXhlbHMsIGx1dEFyciwgb2Zmc2V0LCBzY2FsZSwgbWF4VmFsdWUpIHsKICAgICAgICAgICAgICB2YXIgYml0TWFzayA9ICgxIDw8IGJpdHNQZXJQaXhlbCkgLSAxOwogICAgICAgICAgICAgIHZhciBpMiA9IDAsIG8yOwogICAgICAgICAgICAgIHZhciBiaXRzTGVmdCA9IDA7CiAgICAgICAgICAgICAgdmFyIG4yLCBidWZmZXIsIG1pc3NpbmdCaXRzLCBubWF4OwogICAgICAgICAgICAgIHZhciBudW1JbnZhbGlkVGFpbEJ5dGVzID0gc3JjLmxlbmd0aCAqIDQgLSBNYXRoLmNlaWwoYml0c1BlclBpeGVsICogbnVtUGl4ZWxzIC8gOCk7CiAgICAgICAgICAgICAgc3JjW3NyYy5sZW5ndGggLSAxXSA8PD0gOCAqIG51bUludmFsaWRUYWlsQnl0ZXM7CiAgICAgICAgICAgICAgaWYgKGx1dEFycikgewogICAgICAgICAgICAgICAgZm9yIChvMiA9IDA7IG8yIDwgbnVtUGl4ZWxzOyBvMisrKSB7CiAgICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA9PT0gMCkgewogICAgICAgICAgICAgICAgICAgIGJ1ZmZlciA9IHNyY1tpMisrXTsKICAgICAgICAgICAgICAgICAgICBiaXRzTGVmdCA9IDMyOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA+PSBiaXRzUGVyUGl4ZWwpIHsKICAgICAgICAgICAgICAgICAgICBuMiA9IGJ1ZmZlciA+Pj4gYml0c0xlZnQgLSBiaXRzUGVyUGl4ZWwgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0IC09IGJpdHNQZXJQaXhlbDsKICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtaXNzaW5nQml0cyA9IGJpdHNQZXJQaXhlbCAtIGJpdHNMZWZ0OwogICAgICAgICAgICAgICAgICAgIG4yID0gKGJ1ZmZlciAmIGJpdE1hc2spIDw8IG1pc3NpbmdCaXRzICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgPSAzMiAtIG1pc3NpbmdCaXRzOwogICAgICAgICAgICAgICAgICAgIG4yICs9IGJ1ZmZlciA+Pj4gYml0c0xlZnQ7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgZGVzdFtvMl0gPSBsdXRBcnJbbjJdOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBubWF4ID0gTWF0aC5jZWlsKChtYXhWYWx1ZSAtIG9mZnNldCkgLyBzY2FsZSk7CiAgICAgICAgICAgICAgICBmb3IgKG8yID0gMDsgbzIgPCBudW1QaXhlbHM7IG8yKyspIHsKICAgICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgYnVmZmVyID0gc3JjW2kyKytdOwogICAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzI7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID49IGJpdHNQZXJQaXhlbCkgewogICAgICAgICAgICAgICAgICAgIG4yID0gYnVmZmVyID4+PiBiaXRzTGVmdCAtIGJpdHNQZXJQaXhlbCAmIGJpdE1hc2s7CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgLT0gYml0c1BlclBpeGVsOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIG1pc3NpbmdCaXRzID0gYml0c1BlclBpeGVsIC0gYml0c0xlZnQ7CiAgICAgICAgICAgICAgICAgICAgbjIgPSAoYnVmZmVyICYgYml0TWFzaykgPDwgbWlzc2luZ0JpdHMgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgICAgIGJ1ZmZlciA9IHNyY1tpMisrXTsKICAgICAgICAgICAgICAgICAgICBiaXRzTGVmdCA9IDMyIC0gbWlzc2luZ0JpdHM7CiAgICAgICAgICAgICAgICAgICAgbjIgKz0gYnVmZmVyID4+PiBiaXRzTGVmdDsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBkZXN0W28yXSA9IG4yIDwgbm1heCA/IG9mZnNldCArIG4yICogc2NhbGUgOiBtYXhWYWx1ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHVuc3R1ZmZMVVQ6IGZ1bmN0aW9uKHNyYywgYml0c1BlclBpeGVsLCBudW1QaXhlbHMsIG9mZnNldCwgc2NhbGUsIG1heFZhbHVlKSB7CiAgICAgICAgICAgICAgdmFyIGJpdE1hc2sgPSAoMSA8PCBiaXRzUGVyUGl4ZWwpIC0gMTsKICAgICAgICAgICAgICB2YXIgaTIgPSAwLCBvMiA9IDAsIG1pc3NpbmdCaXRzID0gMCwgYml0c0xlZnQgPSAwLCBuMiA9IDA7CiAgICAgICAgICAgICAgdmFyIGJ1ZmZlcjsKICAgICAgICAgICAgICB2YXIgZGVzdCA9IFtdOwogICAgICAgICAgICAgIHZhciBudW1JbnZhbGlkVGFpbEJ5dGVzID0gc3JjLmxlbmd0aCAqIDQgLSBNYXRoLmNlaWwoYml0c1BlclBpeGVsICogbnVtUGl4ZWxzIC8gOCk7CiAgICAgICAgICAgICAgc3JjW3NyYy5sZW5ndGggLSAxXSA8PD0gOCAqIG51bUludmFsaWRUYWlsQnl0ZXM7CiAgICAgICAgICAgICAgdmFyIG5tYXggPSBNYXRoLmNlaWwoKG1heFZhbHVlIC0gb2Zmc2V0KSAvIHNjYWxlKTsKICAgICAgICAgICAgICBmb3IgKG8yID0gMDsgbzIgPCBudW1QaXhlbHM7IG8yKyspIHsKICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA9PT0gMCkgewogICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoYml0c0xlZnQgPj0gYml0c1BlclBpeGVsKSB7CiAgICAgICAgICAgICAgICAgIG4yID0gYnVmZmVyID4+PiBiaXRzTGVmdCAtIGJpdHNQZXJQaXhlbCAmIGJpdE1hc2s7CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0IC09IGJpdHNQZXJQaXhlbDsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIG1pc3NpbmdCaXRzID0gYml0c1BlclBpeGVsIC0gYml0c0xlZnQ7CiAgICAgICAgICAgICAgICAgIG4yID0gKGJ1ZmZlciAmIGJpdE1hc2spIDw8IG1pc3NpbmdCaXRzICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgYnVmZmVyID0gc3JjW2kyKytdOwogICAgICAgICAgICAgICAgICBiaXRzTGVmdCA9IDMyIC0gbWlzc2luZ0JpdHM7CiAgICAgICAgICAgICAgICAgIG4yICs9IGJ1ZmZlciA+Pj4gYml0c0xlZnQ7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkZXN0W28yXSA9IG4yIDwgbm1heCA/IG9mZnNldCArIG4yICogc2NhbGUgOiBtYXhWYWx1ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZGVzdC51bnNoaWZ0KG9mZnNldCk7CiAgICAgICAgICAgICAgcmV0dXJuIGRlc3Q7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHVuc3R1ZmYyOiBmdW5jdGlvbihzcmMsIGRlc3QsIGJpdHNQZXJQaXhlbCwgbnVtUGl4ZWxzLCBsdXRBcnIsIG9mZnNldCwgc2NhbGUsIG1heFZhbHVlKSB7CiAgICAgICAgICAgICAgdmFyIGJpdE1hc2sgPSAoMSA8PCBiaXRzUGVyUGl4ZWwpIC0gMTsKICAgICAgICAgICAgICB2YXIgaTIgPSAwLCBvMjsKICAgICAgICAgICAgICB2YXIgYml0c0xlZnQgPSAwLCBiaXRQb3MgPSAwOwogICAgICAgICAgICAgIHZhciBuMiwgYnVmZmVyLCBtaXNzaW5nQml0czsKICAgICAgICAgICAgICBpZiAobHV0QXJyKSB7CiAgICAgICAgICAgICAgICBmb3IgKG8yID0gMDsgbzIgPCBudW1QaXhlbHM7IG8yKyspIHsKICAgICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgYnVmZmVyID0gc3JjW2kyKytdOwogICAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzI7CiAgICAgICAgICAgICAgICAgICAgYml0UG9zID0gMDsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpZiAoYml0c0xlZnQgPj0gYml0c1BlclBpeGVsKSB7CiAgICAgICAgICAgICAgICAgICAgbjIgPSBidWZmZXIgPj4+IGJpdFBvcyAmIGJpdE1hc2s7CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgLT0gYml0c1BlclBpeGVsOwogICAgICAgICAgICAgICAgICAgIGJpdFBvcyArPSBiaXRzUGVyUGl4ZWw7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgbWlzc2luZ0JpdHMgPSBiaXRzUGVyUGl4ZWwgLSBiaXRzTGVmdDsKICAgICAgICAgICAgICAgICAgICBuMiA9IGJ1ZmZlciA+Pj4gYml0UG9zICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgPSAzMiAtIG1pc3NpbmdCaXRzOwogICAgICAgICAgICAgICAgICAgIG4yIHw9IChidWZmZXIgJiAoMSA8PCBtaXNzaW5nQml0cykgLSAxKSA8PCBiaXRzUGVyUGl4ZWwgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgICBiaXRQb3MgPSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBkZXN0W28yXSA9IGx1dEFycltuMl07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHZhciBubWF4ID0gTWF0aC5jZWlsKChtYXhWYWx1ZSAtIG9mZnNldCkgLyBzY2FsZSk7CiAgICAgICAgICAgICAgICBmb3IgKG8yID0gMDsgbzIgPCBudW1QaXhlbHM7IG8yKyspIHsKICAgICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgICAgYnVmZmVyID0gc3JjW2kyKytdOwogICAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzI7CiAgICAgICAgICAgICAgICAgICAgYml0UG9zID0gMDsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpZiAoYml0c0xlZnQgPj0gYml0c1BlclBpeGVsKSB7CiAgICAgICAgICAgICAgICAgICAgbjIgPSBidWZmZXIgPj4+IGJpdFBvcyAmIGJpdE1hc2s7CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgLT0gYml0c1BlclBpeGVsOwogICAgICAgICAgICAgICAgICAgIGJpdFBvcyArPSBiaXRzUGVyUGl4ZWw7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgbWlzc2luZ0JpdHMgPSBiaXRzUGVyUGl4ZWwgLSBiaXRzTGVmdDsKICAgICAgICAgICAgICAgICAgICBuMiA9IGJ1ZmZlciA+Pj4gYml0UG9zICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgICAgYml0c0xlZnQgPSAzMiAtIG1pc3NpbmdCaXRzOwogICAgICAgICAgICAgICAgICAgIG4yIHw9IChidWZmZXIgJiAoMSA8PCBtaXNzaW5nQml0cykgLSAxKSA8PCBiaXRzUGVyUGl4ZWwgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgICBiaXRQb3MgPSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBkZXN0W28yXSA9IG4yIDwgbm1heCA/IG9mZnNldCArIG4yICogc2NhbGUgOiBtYXhWYWx1ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGRlc3Q7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHVuc3R1ZmZMVVQyOiBmdW5jdGlvbihzcmMsIGJpdHNQZXJQaXhlbCwgbnVtUGl4ZWxzLCBvZmZzZXQsIHNjYWxlLCBtYXhWYWx1ZSkgewogICAgICAgICAgICAgIHZhciBiaXRNYXNrID0gKDEgPDwgYml0c1BlclBpeGVsKSAtIDE7CiAgICAgICAgICAgICAgdmFyIGkyID0gMCwgbzIgPSAwLCBtaXNzaW5nQml0cyA9IDAsIGJpdHNMZWZ0ID0gMCwgbjIgPSAwLCBiaXRQb3MgPSAwOwogICAgICAgICAgICAgIHZhciBidWZmZXI7CiAgICAgICAgICAgICAgdmFyIGRlc3QgPSBbXTsKICAgICAgICAgICAgICB2YXIgbm1heCA9IE1hdGguY2VpbCgobWF4VmFsdWUgLSBvZmZzZXQpIC8gc2NhbGUpOwogICAgICAgICAgICAgIGZvciAobzIgPSAwOyBvMiA8IG51bVBpeGVsczsgbzIrKykgewogICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgIGJ1ZmZlciA9IHNyY1tpMisrXTsKICAgICAgICAgICAgICAgICAgYml0c0xlZnQgPSAzMjsKICAgICAgICAgICAgICAgICAgYml0UG9zID0gMDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA+PSBiaXRzUGVyUGl4ZWwpIHsKICAgICAgICAgICAgICAgICAgbjIgPSBidWZmZXIgPj4+IGJpdFBvcyAmIGJpdE1hc2s7CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0IC09IGJpdHNQZXJQaXhlbDsKICAgICAgICAgICAgICAgICAgYml0UG9zICs9IGJpdHNQZXJQaXhlbDsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIG1pc3NpbmdCaXRzID0gYml0c1BlclBpeGVsIC0gYml0c0xlZnQ7CiAgICAgICAgICAgICAgICAgIG4yID0gYnVmZmVyID4+PiBiaXRQb3MgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzIgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgbjIgfD0gKGJ1ZmZlciAmICgxIDw8IG1pc3NpbmdCaXRzKSAtIDEpIDw8IGJpdHNQZXJQaXhlbCAtIG1pc3NpbmdCaXRzOwogICAgICAgICAgICAgICAgICBiaXRQb3MgPSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRlc3RbbzJdID0gbjIgPCBubWF4ID8gb2Zmc2V0ICsgbjIgKiBzY2FsZSA6IG1heFZhbHVlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBkZXN0LnVuc2hpZnQob2Zmc2V0KTsKICAgICAgICAgICAgICByZXR1cm4gZGVzdDsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgb3JpZ2luYWxVbnN0dWZmOiBmdW5jdGlvbihzcmMsIGRlc3QsIGJpdHNQZXJQaXhlbCwgbnVtUGl4ZWxzKSB7CiAgICAgICAgICAgICAgdmFyIGJpdE1hc2sgPSAoMSA8PCBiaXRzUGVyUGl4ZWwpIC0gMTsKICAgICAgICAgICAgICB2YXIgaTIgPSAwLCBvMjsKICAgICAgICAgICAgICB2YXIgYml0c0xlZnQgPSAwOwogICAgICAgICAgICAgIHZhciBuMiwgYnVmZmVyLCBtaXNzaW5nQml0czsKICAgICAgICAgICAgICB2YXIgbnVtSW52YWxpZFRhaWxCeXRlcyA9IHNyYy5sZW5ndGggKiA0IC0gTWF0aC5jZWlsKGJpdHNQZXJQaXhlbCAqIG51bVBpeGVscyAvIDgpOwogICAgICAgICAgICAgIHNyY1tzcmMubGVuZ3RoIC0gMV0gPDw9IDggKiBudW1JbnZhbGlkVGFpbEJ5dGVzOwogICAgICAgICAgICAgIGZvciAobzIgPSAwOyBvMiA8IG51bVBpeGVsczsgbzIrKykgewogICAgICAgICAgICAgICAgaWYgKGJpdHNMZWZ0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgIGJ1ZmZlciA9IHNyY1tpMisrXTsKICAgICAgICAgICAgICAgICAgYml0c0xlZnQgPSAzMjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA+PSBiaXRzUGVyUGl4ZWwpIHsKICAgICAgICAgICAgICAgICAgbjIgPSBidWZmZXIgPj4+IGJpdHNMZWZ0IC0gYml0c1BlclBpeGVsICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgYml0c0xlZnQgLT0gYml0c1BlclBpeGVsOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgbWlzc2luZ0JpdHMgPSBiaXRzUGVyUGl4ZWwgLSBiaXRzTGVmdDsKICAgICAgICAgICAgICAgICAgbjIgPSAoYnVmZmVyICYgYml0TWFzaykgPDwgbWlzc2luZ0JpdHMgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzIgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgbjIgKz0gYnVmZmVyID4+PiBiaXRzTGVmdDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRlc3RbbzJdID0gbjI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiBkZXN0OwogICAgICAgICAgICB9LAogICAgICAgICAgICBvcmlnaW5hbFVuc3R1ZmYyOiBmdW5jdGlvbihzcmMsIGRlc3QsIGJpdHNQZXJQaXhlbCwgbnVtUGl4ZWxzKSB7CiAgICAgICAgICAgICAgdmFyIGJpdE1hc2sgPSAoMSA8PCBiaXRzUGVyUGl4ZWwpIC0gMTsKICAgICAgICAgICAgICB2YXIgaTIgPSAwLCBvMjsKICAgICAgICAgICAgICB2YXIgYml0c0xlZnQgPSAwLCBiaXRQb3MgPSAwOwogICAgICAgICAgICAgIHZhciBuMiwgYnVmZmVyLCBtaXNzaW5nQml0czsKICAgICAgICAgICAgICBmb3IgKG8yID0gMDsgbzIgPCBudW1QaXhlbHM7IG8yKyspIHsKICAgICAgICAgICAgICAgIGlmIChiaXRzTGVmdCA9PT0gMCkgewogICAgICAgICAgICAgICAgICBidWZmZXIgPSBzcmNbaTIrK107CiAgICAgICAgICAgICAgICAgIGJpdHNMZWZ0ID0gMzI7CiAgICAgICAgICAgICAgICAgIGJpdFBvcyA9IDA7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoYml0c0xlZnQgPj0gYml0c1BlclBpeGVsKSB7CiAgICAgICAgICAgICAgICAgIG4yID0gYnVmZmVyID4+PiBiaXRQb3MgJiBiaXRNYXNrOwogICAgICAgICAgICAgICAgICBiaXRzTGVmdCAtPSBiaXRzUGVyUGl4ZWw7CiAgICAgICAgICAgICAgICAgIGJpdFBvcyArPSBiaXRzUGVyUGl4ZWw7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBtaXNzaW5nQml0cyA9IGJpdHNQZXJQaXhlbCAtIGJpdHNMZWZ0OwogICAgICAgICAgICAgICAgICBuMiA9IGJ1ZmZlciA+Pj4gYml0UG9zICYgYml0TWFzazsKICAgICAgICAgICAgICAgICAgYnVmZmVyID0gc3JjW2kyKytdOwogICAgICAgICAgICAgICAgICBiaXRzTGVmdCA9IDMyIC0gbWlzc2luZ0JpdHM7CiAgICAgICAgICAgICAgICAgIG4yIHw9IChidWZmZXIgJiAoMSA8PCBtaXNzaW5nQml0cykgLSAxKSA8PCBiaXRzUGVyUGl4ZWwgLSBtaXNzaW5nQml0czsKICAgICAgICAgICAgICAgICAgYml0UG9zID0gbWlzc2luZ0JpdHM7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBkZXN0W28yXSA9IG4yOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gZGVzdDsKICAgICAgICAgICAgfQogICAgICAgICAgfTsKICAgICAgICAgIHZhciBMZXJjMkhlbHBlcnMgPSB7CiAgICAgICAgICAgIEhVRkZNQU5fTFVUX0JJVFNfTUFYOiAxMiwKICAgICAgICAgICAgLy91c2UgMl4xMiBsdXQsIHRyZWF0IGl0IGxpa2UgY29uc3RhbnQKICAgICAgICAgICAgY29tcHV0ZUNoZWNrc3VtRmxldGNoZXIzMjogZnVuY3Rpb24oaW5wdXQpIHsKICAgICAgICAgICAgICB2YXIgc3VtMSA9IDY1NTM1LCBzdW0yID0gNjU1MzU7CiAgICAgICAgICAgICAgdmFyIGxlbiA9IGlucHV0Lmxlbmd0aDsKICAgICAgICAgICAgICB2YXIgd29yZHMgPSBNYXRoLmZsb29yKGxlbiAvIDIpOwogICAgICAgICAgICAgIHZhciBpMiA9IDA7CiAgICAgICAgICAgICAgd2hpbGUgKHdvcmRzKSB7CiAgICAgICAgICAgICAgICB2YXIgdGxlbiA9IHdvcmRzID49IDM1OSA/IDM1OSA6IHdvcmRzOwogICAgICAgICAgICAgICAgd29yZHMgLT0gdGxlbjsKICAgICAgICAgICAgICAgIGRvIHsKICAgICAgICAgICAgICAgICAgc3VtMSArPSBpbnB1dFtpMisrXSA8PCA4OwogICAgICAgICAgICAgICAgICBzdW0yICs9IHN1bTEgKz0gaW5wdXRbaTIrK107CiAgICAgICAgICAgICAgICB9IHdoaWxlICgtLXRsZW4pOwogICAgICAgICAgICAgICAgc3VtMSA9IChzdW0xICYgNjU1MzUpICsgKHN1bTEgPj4+IDE2KTsKICAgICAgICAgICAgICAgIHN1bTIgPSAoc3VtMiAmIDY1NTM1KSArIChzdW0yID4+PiAxNik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChsZW4gJiAxKSB7CiAgICAgICAgICAgICAgICBzdW0yICs9IHN1bTEgKz0gaW5wdXRbaTJdIDw8IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHN1bTEgPSAoc3VtMSAmIDY1NTM1KSArIChzdW0xID4+PiAxNik7CiAgICAgICAgICAgICAgc3VtMiA9IChzdW0yICYgNjU1MzUpICsgKHN1bTIgPj4+IDE2KTsKICAgICAgICAgICAgICByZXR1cm4gKHN1bTIgPDwgMTYgfCBzdW0xKSA+Pj4gMDsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVhZEhlYWRlckluZm86IGZ1bmN0aW9uKGlucHV0LCBkYXRhKSB7CiAgICAgICAgICAgICAgdmFyIHB0ciA9IGRhdGEucHRyOwogICAgICAgICAgICAgIHZhciBmaWxlSWRWaWV3ID0gbmV3IFVpbnQ4QXJyYXkoaW5wdXQsIHB0ciwgNik7CiAgICAgICAgICAgICAgdmFyIGhlYWRlckluZm8gPSB7fTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLmZpbGVJZGVudGlmaWVyU3RyaW5nID0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCBmaWxlSWRWaWV3KTsKICAgICAgICAgICAgICBpZiAoaGVhZGVySW5mby5maWxlSWRlbnRpZmllclN0cmluZy5sYXN0SW5kZXhPZigiTGVyYzIiLCAwKSAhPT0gMCkgewogICAgICAgICAgICAgICAgdGhyb3cgIlVuZXhwZWN0ZWQgZmlsZSBpZGVudGlmaWVyIHN0cmluZyAoZXhwZWN0IExlcmMyICk6ICIgKyBoZWFkZXJJbmZvLmZpbGVJZGVudGlmaWVyU3RyaW5nOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBwdHIgKz0gNjsKICAgICAgICAgICAgICB2YXIgdmlldyA9IG5ldyBEYXRhVmlldyhpbnB1dCwgcHRyLCA4KTsKICAgICAgICAgICAgICB2YXIgZmlsZVZlcnNpb24gPSB2aWV3LmdldEludDMyKDAsIHRydWUpOwogICAgICAgICAgICAgIGhlYWRlckluZm8uZmlsZVZlcnNpb24gPSBmaWxlVmVyc2lvbjsKICAgICAgICAgICAgICBwdHIgKz0gNDsKICAgICAgICAgICAgICBpZiAoZmlsZVZlcnNpb24gPj0gMykgewogICAgICAgICAgICAgICAgaGVhZGVySW5mby5jaGVja3N1bSA9IHZpZXcuZ2V0VWludDMyKDQsIHRydWUpOwogICAgICAgICAgICAgICAgcHRyICs9IDQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZpZXcgPSBuZXcgRGF0YVZpZXcoaW5wdXQsIHB0ciwgMTIpOwogICAgICAgICAgICAgIGhlYWRlckluZm8uaGVpZ2h0ID0gdmlldy5nZXRVaW50MzIoMCwgdHJ1ZSk7CiAgICAgICAgICAgICAgaGVhZGVySW5mby53aWR0aCA9IHZpZXcuZ2V0VWludDMyKDQsIHRydWUpOwogICAgICAgICAgICAgIHB0ciArPSA4OwogICAgICAgICAgICAgIGlmIChmaWxlVmVyc2lvbiA+PSA0KSB7CiAgICAgICAgICAgICAgICBoZWFkZXJJbmZvLm51bURpbXMgPSB2aWV3LmdldFVpbnQzMig4LCB0cnVlKTsKICAgICAgICAgICAgICAgIHB0ciArPSA0OwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBoZWFkZXJJbmZvLm51bURpbXMgPSAxOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBwdHIsIDQwKTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLm51bVZhbGlkUGl4ZWwgPSB2aWV3LmdldFVpbnQzMigwLCB0cnVlKTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLm1pY3JvQmxvY2tTaXplID0gdmlldy5nZXRJbnQzMig0LCB0cnVlKTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLmJsb2JTaXplID0gdmlldy5nZXRJbnQzMig4LCB0cnVlKTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLmltYWdlVHlwZSA9IHZpZXcuZ2V0SW50MzIoMTIsIHRydWUpOwogICAgICAgICAgICAgIGhlYWRlckluZm8ubWF4WkVycm9yID0gdmlldy5nZXRGbG9hdDY0KDE2LCB0cnVlKTsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLnpNaW4gPSB2aWV3LmdldEZsb2F0NjQoMjQsIHRydWUpOwogICAgICAgICAgICAgIGhlYWRlckluZm8uek1heCA9IHZpZXcuZ2V0RmxvYXQ2NCgzMiwgdHJ1ZSk7CiAgICAgICAgICAgICAgcHRyICs9IDQwOwogICAgICAgICAgICAgIGRhdGEuaGVhZGVySW5mbyA9IGhlYWRlckluZm87CiAgICAgICAgICAgICAgZGF0YS5wdHIgPSBwdHI7CiAgICAgICAgICAgICAgdmFyIGNoZWNrc3VtLCBrZXlMZW5ndGg7CiAgICAgICAgICAgICAgaWYgKGZpbGVWZXJzaW9uID49IDMpIHsKICAgICAgICAgICAgICAgIGtleUxlbmd0aCA9IGZpbGVWZXJzaW9uID49IDQgPyA1MiA6IDQ4OwogICAgICAgICAgICAgICAgY2hlY2tzdW0gPSB0aGlzLmNvbXB1dGVDaGVja3N1bUZsZXRjaGVyMzIobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIHB0ciAtIGtleUxlbmd0aCwgaGVhZGVySW5mby5ibG9iU2l6ZSAtIDE0KSk7CiAgICAgICAgICAgICAgICBpZiAoY2hlY2tzdW0gIT09IGhlYWRlckluZm8uY2hlY2tzdW0pIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgIkNoZWNrc3VtIGZhaWxlZC4iOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgY2hlY2tNaW5NYXhSYW5nZXM6IGZ1bmN0aW9uKGlucHV0LCBkYXRhKSB7CiAgICAgICAgICAgICAgdmFyIGhlYWRlckluZm8gPSBkYXRhLmhlYWRlckluZm87CiAgICAgICAgICAgICAgdmFyIE91dFBpeGVsVHlwZUFycmF5ID0gdGhpcy5nZXREYXRhVHlwZUFycmF5KGhlYWRlckluZm8uaW1hZ2VUeXBlKTsKICAgICAgICAgICAgICB2YXIgcmFuZ2VCeXRlcyA9IGhlYWRlckluZm8ubnVtRGltcyAqIHRoaXMuZ2V0RGF0YVR5cGVTaXplKGhlYWRlckluZm8uaW1hZ2VUeXBlKTsKICAgICAgICAgICAgICB2YXIgbWluVmFsdWVzID0gdGhpcy5yZWFkU3ViQXJyYXkoaW5wdXQsIGRhdGEucHRyLCBPdXRQaXhlbFR5cGVBcnJheSwgcmFuZ2VCeXRlcyk7CiAgICAgICAgICAgICAgdmFyIG1heFZhbHVlcyA9IHRoaXMucmVhZFN1YkFycmF5KGlucHV0LCBkYXRhLnB0ciArIHJhbmdlQnl0ZXMsIE91dFBpeGVsVHlwZUFycmF5LCByYW5nZUJ5dGVzKTsKICAgICAgICAgICAgICBkYXRhLnB0ciArPSAyICogcmFuZ2VCeXRlczsKICAgICAgICAgICAgICB2YXIgaTIsIGVxdWFsID0gdHJ1ZTsKICAgICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBoZWFkZXJJbmZvLm51bURpbXM7IGkyKyspIHsKICAgICAgICAgICAgICAgIGlmIChtaW5WYWx1ZXNbaTJdICE9PSBtYXhWYWx1ZXNbaTJdKSB7CiAgICAgICAgICAgICAgICAgIGVxdWFsID0gZmFsc2U7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBoZWFkZXJJbmZvLm1pblZhbHVlcyA9IG1pblZhbHVlczsKICAgICAgICAgICAgICBoZWFkZXJJbmZvLm1heFZhbHVlcyA9IG1heFZhbHVlczsKICAgICAgICAgICAgICByZXR1cm4gZXF1YWw7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHJlYWRTdWJBcnJheTogZnVuY3Rpb24oaW5wdXQsIHB0ciwgT3V0UGl4ZWxUeXBlQXJyYXksIG51bUJ5dGVzKSB7CiAgICAgICAgICAgICAgdmFyIHJhd0RhdGE7CiAgICAgICAgICAgICAgaWYgKE91dFBpeGVsVHlwZUFycmF5ID09PSBVaW50OEFycmF5KSB7CiAgICAgICAgICAgICAgICByYXdEYXRhID0gbmV3IFVpbnQ4QXJyYXkoaW5wdXQsIHB0ciwgbnVtQnl0ZXMpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB2YXIgYXJyYXlCdWYgPSBuZXcgQXJyYXlCdWZmZXIobnVtQnl0ZXMpOwogICAgICAgICAgICAgICAgdmFyIHN0b3JlOCA9IG5ldyBVaW50OEFycmF5KGFycmF5QnVmKTsKICAgICAgICAgICAgICAgIHN0b3JlOC5zZXQobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIHB0ciwgbnVtQnl0ZXMpKTsKICAgICAgICAgICAgICAgIHJhd0RhdGEgPSBuZXcgT3V0UGl4ZWxUeXBlQXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gcmF3RGF0YTsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVhZE1hc2s6IGZ1bmN0aW9uKGlucHV0LCBkYXRhKSB7CiAgICAgICAgICAgICAgdmFyIHB0ciA9IGRhdGEucHRyOwogICAgICAgICAgICAgIHZhciBoZWFkZXJJbmZvID0gZGF0YS5oZWFkZXJJbmZvOwogICAgICAgICAgICAgIHZhciBudW1QaXhlbHMgPSBoZWFkZXJJbmZvLndpZHRoICogaGVhZGVySW5mby5oZWlnaHQ7CiAgICAgICAgICAgICAgdmFyIG51bVZhbGlkUGl4ZWwgPSBoZWFkZXJJbmZvLm51bVZhbGlkUGl4ZWw7CiAgICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgRGF0YVZpZXcoaW5wdXQsIHB0ciwgNCk7CiAgICAgICAgICAgICAgdmFyIG1hc2sgPSB7fTsKICAgICAgICAgICAgICBtYXNrLm51bUJ5dGVzID0gdmlldy5nZXRVaW50MzIoMCwgdHJ1ZSk7CiAgICAgICAgICAgICAgcHRyICs9IDQ7CiAgICAgICAgICAgICAgaWYgKCgwID09PSBudW1WYWxpZFBpeGVsIHx8IG51bVBpeGVscyA9PT0gbnVtVmFsaWRQaXhlbCkgJiYgMCAhPT0gbWFzay5udW1CeXRlcykgewogICAgICAgICAgICAgICAgdGhyb3cgImludmFsaWQgbWFzayI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBiaXRzZXQsIHJlc3VsdE1hc2s7CiAgICAgICAgICAgICAgaWYgKG51bVZhbGlkUGl4ZWwgPT09IDApIHsKICAgICAgICAgICAgICAgIGJpdHNldCA9IG5ldyBVaW50OEFycmF5KE1hdGguY2VpbChudW1QaXhlbHMgLyA4KSk7CiAgICAgICAgICAgICAgICBtYXNrLmJpdHNldCA9IGJpdHNldDsKICAgICAgICAgICAgICAgIHJlc3VsdE1hc2sgPSBuZXcgVWludDhBcnJheShudW1QaXhlbHMpOwogICAgICAgICAgICAgICAgZGF0YS5waXhlbHMucmVzdWx0TWFzayA9IHJlc3VsdE1hc2s7CiAgICAgICAgICAgICAgICBwdHIgKz0gbWFzay5udW1CeXRlczsKICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1hc2subnVtQnl0ZXMgPiAwKSB7CiAgICAgICAgICAgICAgICBiaXRzZXQgPSBuZXcgVWludDhBcnJheShNYXRoLmNlaWwobnVtUGl4ZWxzIC8gOCkpOwogICAgICAgICAgICAgICAgdmlldyA9IG5ldyBEYXRhVmlldyhpbnB1dCwgcHRyLCBtYXNrLm51bUJ5dGVzKTsKICAgICAgICAgICAgICAgIHZhciBjbnQgPSB2aWV3LmdldEludDE2KDAsIHRydWUpOwogICAgICAgICAgICAgICAgdmFyIGlwID0gMiwgb3AgPSAwLCB2YWwgPSAwOwogICAgICAgICAgICAgICAgZG8gewogICAgICAgICAgICAgICAgICBpZiAoY250ID4gMCkgewogICAgICAgICAgICAgICAgICAgIHdoaWxlIChjbnQtLSkgewogICAgICAgICAgICAgICAgICAgICAgYml0c2V0W29wKytdID0gdmlldy5nZXRVaW50OChpcCsrKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdmFsID0gdmlldy5nZXRVaW50OChpcCsrKTsKICAgICAgICAgICAgICAgICAgICBjbnQgPSAtY250OwogICAgICAgICAgICAgICAgICAgIHdoaWxlIChjbnQtLSkgewogICAgICAgICAgICAgICAgICAgICAgYml0c2V0W29wKytdID0gdmFsOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBjbnQgPSB2aWV3LmdldEludDE2KGlwLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgaXAgKz0gMjsKICAgICAgICAgICAgICAgIH0gd2hpbGUgKGlwIDwgbWFzay5udW1CeXRlcyk7CiAgICAgICAgICAgICAgICBpZiAoY250ICE9PSAtMzI3NjggfHwgb3AgPCBiaXRzZXQubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAgIHRocm93ICJVbmV4cGVjdGVkIGVuZCBvZiBtYXNrIFJMRSBlbmNvZGluZyI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICByZXN1bHRNYXNrID0gbmV3IFVpbnQ4QXJyYXkobnVtUGl4ZWxzKTsKICAgICAgICAgICAgICAgIHZhciBtYiA9IDAsIGsyID0gMDsKICAgICAgICAgICAgICAgIGZvciAoazIgPSAwOyBrMiA8IG51bVBpeGVsczsgazIrKykgewogICAgICAgICAgICAgICAgICBpZiAoazIgJiA3KSB7CiAgICAgICAgICAgICAgICAgICAgbWIgPSBiaXRzZXRbazIgPj4gM107CiAgICAgICAgICAgICAgICAgICAgbWIgPDw9IGsyICYgNzsKICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBtYiA9IGJpdHNldFtrMiA+PiAzXTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpZiAobWIgJiAxMjgpIHsKICAgICAgICAgICAgICAgICAgICByZXN1bHRNYXNrW2syXSA9IDE7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnJlc3VsdE1hc2sgPSByZXN1bHRNYXNrOwogICAgICAgICAgICAgICAgbWFzay5iaXRzZXQgPSBiaXRzZXQ7CiAgICAgICAgICAgICAgICBwdHIgKz0gbWFzay5udW1CeXRlczsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZGF0YS5wdHIgPSBwdHI7CiAgICAgICAgICAgICAgZGF0YS5tYXNrID0gbWFzazsKICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgcmVhZERhdGFPbmVTd2VlcDogZnVuY3Rpb24oaW5wdXQsIGRhdGEsIE91dFBpeGVsVHlwZUFycmF5KSB7CiAgICAgICAgICAgICAgdmFyIHB0ciA9IGRhdGEucHRyOwogICAgICAgICAgICAgIHZhciBoZWFkZXJJbmZvID0gZGF0YS5oZWFkZXJJbmZvOwogICAgICAgICAgICAgIHZhciBudW1EaW1zID0gaGVhZGVySW5mby5udW1EaW1zOwogICAgICAgICAgICAgIHZhciBudW1QaXhlbHMgPSBoZWFkZXJJbmZvLndpZHRoICogaGVhZGVySW5mby5oZWlnaHQ7CiAgICAgICAgICAgICAgdmFyIGltYWdlVHlwZSA9IGhlYWRlckluZm8uaW1hZ2VUeXBlOwogICAgICAgICAgICAgIHZhciBudW1CeXRlcyA9IGhlYWRlckluZm8ubnVtVmFsaWRQaXhlbCAqIExlcmMySGVscGVycy5nZXREYXRhVHlwZVNpemUoaW1hZ2VUeXBlKSAqIG51bURpbXM7CiAgICAgICAgICAgICAgdmFyIHJhd0RhdGE7CiAgICAgICAgICAgICAgdmFyIG1hc2sgPSBkYXRhLnBpeGVscy5yZXN1bHRNYXNrOwogICAgICAgICAgICAgIGlmIChPdXRQaXhlbFR5cGVBcnJheSA9PT0gVWludDhBcnJheSkgewogICAgICAgICAgICAgICAgcmF3RGF0YSA9IG5ldyBVaW50OEFycmF5KGlucHV0LCBwdHIsIG51bUJ5dGVzKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdmFyIGFycmF5QnVmID0gbmV3IEFycmF5QnVmZmVyKG51bUJ5dGVzKTsKICAgICAgICAgICAgICAgIHZhciBzdG9yZTggPSBuZXcgVWludDhBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICBzdG9yZTguc2V0KG5ldyBVaW50OEFycmF5KGlucHV0LCBwdHIsIG51bUJ5dGVzKSk7CiAgICAgICAgICAgICAgICByYXdEYXRhID0gbmV3IE91dFBpeGVsVHlwZUFycmF5KGFycmF5QnVmKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHJhd0RhdGEubGVuZ3RoID09PSBudW1QaXhlbHMgKiBudW1EaW1zKSB7CiAgICAgICAgICAgICAgICBkYXRhLnBpeGVscy5yZXN1bHRQaXhlbHMgPSByYXdEYXRhOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkYXRhLnBpeGVscy5yZXN1bHRQaXhlbHMgPSBuZXcgT3V0UGl4ZWxUeXBlQXJyYXkobnVtUGl4ZWxzICogbnVtRGltcyk7CiAgICAgICAgICAgICAgICB2YXIgejIgPSAwLCBrMiA9IDAsIGkyID0gMCwgblN0YXJ0ID0gMDsKICAgICAgICAgICAgICAgIGlmIChudW1EaW1zID4gMSkgewogICAgICAgICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1EaW1zOyBpMisrKSB7CiAgICAgICAgICAgICAgICAgICAgblN0YXJ0ID0gaTIgKiBudW1QaXhlbHM7CiAgICAgICAgICAgICAgICAgICAgZm9yIChrMiA9IDA7IGsyIDwgbnVtUGl4ZWxzOyBrMisrKSB7CiAgICAgICAgICAgICAgICAgICAgICBpZiAobWFza1trMl0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzW25TdGFydCArIGsyXSA9IHJhd0RhdGFbejIrK107CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBmb3IgKGsyID0gMDsgazIgPCBudW1QaXhlbHM7IGsyKyspIHsKICAgICAgICAgICAgICAgICAgICBpZiAobWFza1trMl0pIHsKICAgICAgICAgICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnJlc3VsdFBpeGVsc1trMl0gPSByYXdEYXRhW3oyKytdOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBwdHIgKz0gbnVtQnl0ZXM7CiAgICAgICAgICAgICAgZGF0YS5wdHIgPSBwdHI7CiAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHJlYWRIdWZmbWFuVHJlZTogZnVuY3Rpb24oaW5wdXQsIGRhdGEpIHsKICAgICAgICAgICAgICB2YXIgQklUU19NQVggPSB0aGlzLkhVRkZNQU5fTFVUX0JJVFNfTUFYOwogICAgICAgICAgICAgIHZhciB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBkYXRhLnB0ciwgMTYpOwogICAgICAgICAgICAgIGRhdGEucHRyICs9IDE2OwogICAgICAgICAgICAgIHZhciB2ZXJzaW9uID0gdmlldy5nZXRJbnQzMigwLCB0cnVlKTsKICAgICAgICAgICAgICBpZiAodmVyc2lvbiA8IDIpIHsKICAgICAgICAgICAgICAgIHRocm93ICJ1bnN1cHBvcnRlZCBIdWZmbWFuIHZlcnNpb24iOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgc2l6ZSA9IHZpZXcuZ2V0SW50MzIoNCwgdHJ1ZSk7CiAgICAgICAgICAgICAgdmFyIGkwID0gdmlldy5nZXRJbnQzMig4LCB0cnVlKTsKICAgICAgICAgICAgICB2YXIgaTEgPSB2aWV3LmdldEludDMyKDEyLCB0cnVlKTsKICAgICAgICAgICAgICBpZiAoaTAgPj0gaTEpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIGJsb2NrRGF0YUJ1ZmZlciA9IG5ldyBVaW50MzJBcnJheShpMSAtIGkwKTsKICAgICAgICAgICAgICBMZXJjMkhlbHBlcnMuZGVjb2RlQml0cyhpbnB1dCwgZGF0YSwgYmxvY2tEYXRhQnVmZmVyKTsKICAgICAgICAgICAgICB2YXIgY29kZVRhYmxlID0gW107CiAgICAgICAgICAgICAgdmFyIGkyLCBqMiwgazIsIGxlbjsKICAgICAgICAgICAgICBmb3IgKGkyID0gaTA7IGkyIDwgaTE7IGkyKyspIHsKICAgICAgICAgICAgICAgIGoyID0gaTIgLSAoaTIgPCBzaXplID8gMCA6IHNpemUpOwogICAgICAgICAgICAgICAgY29kZVRhYmxlW2oyXSA9IHsgZmlyc3Q6IGJsb2NrRGF0YUJ1ZmZlcltpMiAtIGkwXSwgc2Vjb25kOiBudWxsIH07CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBkYXRhQnl0ZXMgPSBpbnB1dC5ieXRlTGVuZ3RoIC0gZGF0YS5wdHI7CiAgICAgICAgICAgICAgdmFyIGRhdGFXb3JkcyA9IE1hdGguY2VpbChkYXRhQnl0ZXMgLyA0KTsKICAgICAgICAgICAgICB2YXIgYXJyYXlCdWYgPSBuZXcgQXJyYXlCdWZmZXIoZGF0YVdvcmRzICogNCk7CiAgICAgICAgICAgICAgdmFyIHN0b3JlOCA9IG5ldyBVaW50OEFycmF5KGFycmF5QnVmKTsKICAgICAgICAgICAgICBzdG9yZTguc2V0KG5ldyBVaW50OEFycmF5KGlucHV0LCBkYXRhLnB0ciwgZGF0YUJ5dGVzKSk7CiAgICAgICAgICAgICAgdmFyIHN0dWZmZWREYXRhID0gbmV3IFVpbnQzMkFycmF5KGFycmF5QnVmKTsKICAgICAgICAgICAgICB2YXIgYml0UG9zID0gMCwgd29yZCwgc3JjUHRyID0gMDsKICAgICAgICAgICAgICB3b3JkID0gc3R1ZmZlZERhdGFbMF07CiAgICAgICAgICAgICAgZm9yIChpMiA9IGkwOyBpMiA8IGkxOyBpMisrKSB7CiAgICAgICAgICAgICAgICBqMiA9IGkyIC0gKGkyIDwgc2l6ZSA/IDAgOiBzaXplKTsKICAgICAgICAgICAgICAgIGxlbiA9IGNvZGVUYWJsZVtqMl0uZmlyc3Q7CiAgICAgICAgICAgICAgICBpZiAobGVuID4gMCkgewogICAgICAgICAgICAgICAgICBjb2RlVGFibGVbajJdLnNlY29uZCA9IHdvcmQgPDwgYml0UG9zID4+PiAzMiAtIGxlbjsKICAgICAgICAgICAgICAgICAgaWYgKDMyIC0gYml0UG9zID49IGxlbikgewogICAgICAgICAgICAgICAgICAgIGJpdFBvcyArPSBsZW47CiAgICAgICAgICAgICAgICAgICAgaWYgKGJpdFBvcyA9PT0gMzIpIHsKICAgICAgICAgICAgICAgICAgICAgIGJpdFBvcyA9IDA7CiAgICAgICAgICAgICAgICAgICAgICBzcmNQdHIrKzsKICAgICAgICAgICAgICAgICAgICAgIHdvcmQgPSBzdHVmZmVkRGF0YVtzcmNQdHJdOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBiaXRQb3MgKz0gbGVuIC0gMzI7CiAgICAgICAgICAgICAgICAgICAgc3JjUHRyKys7CiAgICAgICAgICAgICAgICAgICAgd29yZCA9IHN0dWZmZWREYXRhW3NyY1B0cl07CiAgICAgICAgICAgICAgICAgICAgY29kZVRhYmxlW2oyXS5zZWNvbmQgfD0gd29yZCA+Pj4gMzIgLSBiaXRQb3M7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIG51bUJpdHNMVVQgPSAwLCBudW1CaXRzTFVUUWljayA9IDA7CiAgICAgICAgICAgICAgdmFyIHRyZWUgPSBuZXcgVHJlZU5vZGUoKTsKICAgICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBjb2RlVGFibGUubGVuZ3RoOyBpMisrKSB7CiAgICAgICAgICAgICAgICBpZiAoY29kZVRhYmxlW2kyXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgICAgICAgIG51bUJpdHNMVVQgPSBNYXRoLm1heChudW1CaXRzTFVULCBjb2RlVGFibGVbaTJdLmZpcnN0KTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKG51bUJpdHNMVVQgPj0gQklUU19NQVgpIHsKICAgICAgICAgICAgICAgIG51bUJpdHNMVVRRaWNrID0gQklUU19NQVg7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIG51bUJpdHNMVVRRaWNrID0gbnVtQml0c0xVVDsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKG51bUJpdHNMVVQgPj0gMzApIHsKICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCJXQVJuaW5nLCBsYXJnZSBOVU0gTFVUIEJJVFMgSVMgIiArIG51bUJpdHNMVVQpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgZGVjb2RlTHV0ID0gW10sIGVudHJ5LCBjb2RlLCBudW1FbnRyaWVzLCBqaiwgY3VycmVudEJpdCwgbm9kZTsKICAgICAgICAgICAgICBmb3IgKGkyID0gaTA7IGkyIDwgaTE7IGkyKyspIHsKICAgICAgICAgICAgICAgIGoyID0gaTIgLSAoaTIgPCBzaXplID8gMCA6IHNpemUpOwogICAgICAgICAgICAgICAgbGVuID0gY29kZVRhYmxlW2oyXS5maXJzdDsKICAgICAgICAgICAgICAgIGlmIChsZW4gPiAwKSB7CiAgICAgICAgICAgICAgICAgIGVudHJ5ID0gW2xlbiwgajJdOwogICAgICAgICAgICAgICAgICBpZiAobGVuIDw9IG51bUJpdHNMVVRRaWNrKSB7CiAgICAgICAgICAgICAgICAgICAgY29kZSA9IGNvZGVUYWJsZVtqMl0uc2Vjb25kIDw8IG51bUJpdHNMVVRRaWNrIC0gbGVuOwogICAgICAgICAgICAgICAgICAgIG51bUVudHJpZXMgPSAxIDw8IG51bUJpdHNMVVRRaWNrIC0gbGVuOwogICAgICAgICAgICAgICAgICAgIGZvciAoazIgPSAwOyBrMiA8IG51bUVudHJpZXM7IGsyKyspIHsKICAgICAgICAgICAgICAgICAgICAgIGRlY29kZUx1dFtjb2RlIHwgazJdID0gZW50cnk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIGNvZGUgPSBjb2RlVGFibGVbajJdLnNlY29uZDsKICAgICAgICAgICAgICAgICAgICBub2RlID0gdHJlZTsKICAgICAgICAgICAgICAgICAgICBmb3IgKGpqID0gbGVuIC0gMTsgamogPj0gMDsgamotLSkgewogICAgICAgICAgICAgICAgICAgICAgY3VycmVudEJpdCA9IGNvZGUgPj4+IGpqICYgMTsKICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50Qml0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghbm9kZS5yaWdodCkgewogICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUucmlnaHQgPSBuZXcgVHJlZU5vZGUoKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBub2RlID0gbm9kZS5yaWdodDsKICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghbm9kZS5sZWZ0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgbm9kZS5sZWZ0ID0gbmV3IFRyZWVOb2RlKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgbm9kZSA9IG5vZGUubGVmdDsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIGlmIChqaiA9PT0gMCAmJiAhbm9kZS52YWwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgbm9kZS52YWwgPSBlbnRyeVsxXTsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgIGRlY29kZUx1dCwKICAgICAgICAgICAgICAgIG51bUJpdHNMVVRRaWNrLAogICAgICAgICAgICAgICAgbnVtQml0c0xVVCwKICAgICAgICAgICAgICAgIHRyZWUsCiAgICAgICAgICAgICAgICBzdHVmZmVkRGF0YSwKICAgICAgICAgICAgICAgIHNyY1B0ciwKICAgICAgICAgICAgICAgIGJpdFBvcwogICAgICAgICAgICAgIH07CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHJlYWRIdWZmbWFuOiBmdW5jdGlvbihpbnB1dCwgZGF0YSwgT3V0UGl4ZWxUeXBlQXJyYXkpIHsKICAgICAgICAgICAgICB2YXIgaGVhZGVySW5mbyA9IGRhdGEuaGVhZGVySW5mbzsKICAgICAgICAgICAgICB2YXIgbnVtRGltcyA9IGhlYWRlckluZm8ubnVtRGltczsKICAgICAgICAgICAgICB2YXIgaGVpZ2h0ID0gZGF0YS5oZWFkZXJJbmZvLmhlaWdodDsKICAgICAgICAgICAgICB2YXIgd2lkdGggPSBkYXRhLmhlYWRlckluZm8ud2lkdGg7CiAgICAgICAgICAgICAgdmFyIG51bVBpeGVscyA9IHdpZHRoICogaGVpZ2h0OwogICAgICAgICAgICAgIHZhciBodWZmbWFuSW5mbyA9IHRoaXMucmVhZEh1ZmZtYW5UcmVlKGlucHV0LCBkYXRhKTsKICAgICAgICAgICAgICB2YXIgZGVjb2RlTHV0ID0gaHVmZm1hbkluZm8uZGVjb2RlTHV0OwogICAgICAgICAgICAgIHZhciB0cmVlID0gaHVmZm1hbkluZm8udHJlZTsKICAgICAgICAgICAgICB2YXIgc3R1ZmZlZERhdGEgPSBodWZmbWFuSW5mby5zdHVmZmVkRGF0YTsKICAgICAgICAgICAgICB2YXIgc3JjUHRyID0gaHVmZm1hbkluZm8uc3JjUHRyOwogICAgICAgICAgICAgIHZhciBiaXRQb3MgPSBodWZmbWFuSW5mby5iaXRQb3M7CiAgICAgICAgICAgICAgdmFyIG51bUJpdHNMVVRRaWNrID0gaHVmZm1hbkluZm8ubnVtQml0c0xVVFFpY2s7CiAgICAgICAgICAgICAgdmFyIG51bUJpdHNMVVQgPSBodWZmbWFuSW5mby5udW1CaXRzTFVUOwogICAgICAgICAgICAgIHZhciBvZmZzZXQgPSBkYXRhLmhlYWRlckluZm8uaW1hZ2VUeXBlID09PSAwID8gMTI4IDogMDsKICAgICAgICAgICAgICB2YXIgbm9kZSwgdmFsLCBkZWx0YSwgbWFzayA9IGRhdGEucGl4ZWxzLnJlc3VsdE1hc2ssIHZhbFRtcCwgdmFsVG1wUXVpY2ssIGN1cnJlbnRCaXQ7CiAgICAgICAgICAgICAgdmFyIGkyLCBqMiwgazIsIGlpOwogICAgICAgICAgICAgIHZhciBwcmV2VmFsID0gMDsKICAgICAgICAgICAgICBpZiAoYml0UG9zID4gMCkgewogICAgICAgICAgICAgICAgc3JjUHRyKys7CiAgICAgICAgICAgICAgICBiaXRQb3MgPSAwOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgd29yZCA9IHN0dWZmZWREYXRhW3NyY1B0cl07CiAgICAgICAgICAgICAgdmFyIGRlbHRhRW5jb2RlID0gZGF0YS5lbmNvZGVNb2RlID09PSAxOwogICAgICAgICAgICAgIHZhciByZXN1bHRQaXhlbHNBbGxEaW0gPSBuZXcgT3V0UGl4ZWxUeXBlQXJyYXkobnVtUGl4ZWxzICogbnVtRGltcyk7CiAgICAgICAgICAgICAgdmFyIHJlc3VsdFBpeGVscyA9IHJlc3VsdFBpeGVsc0FsbERpbTsKICAgICAgICAgICAgICB2YXIgaURpbTsKICAgICAgICAgICAgICBmb3IgKGlEaW0gPSAwOyBpRGltIDwgaGVhZGVySW5mby5udW1EaW1zOyBpRGltKyspIHsKICAgICAgICAgICAgICAgIGlmIChudW1EaW1zID4gMSkgewogICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHMgPSBuZXcgT3V0UGl4ZWxUeXBlQXJyYXkocmVzdWx0UGl4ZWxzQWxsRGltLmJ1ZmZlciwgbnVtUGl4ZWxzICogaURpbSwgbnVtUGl4ZWxzKTsKICAgICAgICAgICAgICAgICAgcHJldlZhbCA9IDA7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoZGF0YS5oZWFkZXJJbmZvLm51bVZhbGlkUGl4ZWwgPT09IHdpZHRoICogaGVpZ2h0KSB7CiAgICAgICAgICAgICAgICAgIGZvciAoazIgPSAwLCBpMiA9IDA7IGkyIDwgaGVpZ2h0OyBpMisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgd2lkdGg7IGoyKyssIGsyKyspIHsKICAgICAgICAgICAgICAgICAgICAgIHZhbCA9IDA7CiAgICAgICAgICAgICAgICAgICAgICB2YWxUbXAgPSB3b3JkIDw8IGJpdFBvcyA+Pj4gMzIgLSBudW1CaXRzTFVUUWljazsKICAgICAgICAgICAgICAgICAgICAgIHZhbFRtcFF1aWNrID0gdmFsVG1wOwogICAgICAgICAgICAgICAgICAgICAgaWYgKDMyIC0gYml0UG9zIDwgbnVtQml0c0xVVFFpY2spIHsKICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wIHw9IHN0dWZmZWREYXRhW3NyY1B0ciArIDFdID4+PiA2NCAtIGJpdFBvcyAtIG51bUJpdHNMVVRRaWNrOwogICAgICAgICAgICAgICAgICAgICAgICB2YWxUbXBRdWljayA9IHZhbFRtcDsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIGlmIChkZWNvZGVMdXRbdmFsVG1wUXVpY2tdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbCA9IGRlY29kZUx1dFt2YWxUbXBRdWlja11bMV07CiAgICAgICAgICAgICAgICAgICAgICAgIGJpdFBvcyArPSBkZWNvZGVMdXRbdmFsVG1wUXVpY2tdWzBdOwogICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wID0gd29yZCA8PCBiaXRQb3MgPj4+IDMyIC0gbnVtQml0c0xVVDsKICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wUXVpY2sgPSB2YWxUbXA7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgzMiAtIGJpdFBvcyA8IG51bUJpdHNMVVQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICB2YWxUbXAgfD0gc3R1ZmZlZERhdGFbc3JjUHRyICsgMV0gPj4+IDY0IC0gYml0UG9zIC0gbnVtQml0c0xVVDsKICAgICAgICAgICAgICAgICAgICAgICAgICB2YWxUbXBRdWljayA9IHZhbFRtcDsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBub2RlID0gdHJlZTsKICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChpaSA9IDA7IGlpIDwgbnVtQml0c0xVVDsgaWkrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRCaXQgPSB2YWxUbXAgPj4+IG51bUJpdHNMVVQgLSBpaSAtIDEgJiAxOwogICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUgPSBjdXJyZW50Qml0ID8gbm9kZS5yaWdodCA6IG5vZGUubGVmdDsKICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIShub2RlLmxlZnQgfHwgbm9kZS5yaWdodCkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbCA9IG5vZGUudmFsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYml0UG9zID0gYml0UG9zICsgaWkgKyAxOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICBpZiAoYml0UG9zID49IDMyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGJpdFBvcyAtPSAzMjsKICAgICAgICAgICAgICAgICAgICAgICAgc3JjUHRyKys7CiAgICAgICAgICAgICAgICAgICAgICAgIHdvcmQgPSBzdHVmZmVkRGF0YVtzcmNQdHJdOwogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgZGVsdGEgPSB2YWwgLSBvZmZzZXQ7CiAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVsdGFFbmNvZGUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGoyID4gMCkgewogICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhICs9IHByZXZWYWw7CiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaTIgPiAwKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsdGEgKz0gcmVzdWx0UGl4ZWxzW2syIC0gd2lkdGhdOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhICs9IHByZXZWYWw7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgZGVsdGEgJj0gMjU1OwogICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHNbazJdID0gZGVsdGE7CiAgICAgICAgICAgICAgICAgICAgICAgIHByZXZWYWwgPSBkZWx0YTsKICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFBpeGVsc1trMl0gPSBkZWx0YTsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIGZvciAoazIgPSAwLCBpMiA9IDA7IGkyIDwgaGVpZ2h0OyBpMisrKSB7CiAgICAgICAgICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgd2lkdGg7IGoyKyssIGsyKyspIHsKICAgICAgICAgICAgICAgICAgICAgIGlmIChtYXNrW2syXSkgewogICAgICAgICAgICAgICAgICAgICAgICB2YWwgPSAwOwogICAgICAgICAgICAgICAgICAgICAgICB2YWxUbXAgPSB3b3JkIDw8IGJpdFBvcyA+Pj4gMzIgLSBudW1CaXRzTFVUUWljazsKICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wUXVpY2sgPSB2YWxUbXA7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgzMiAtIGJpdFBvcyA8IG51bUJpdHNMVVRRaWNrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wIHw9IHN0dWZmZWREYXRhW3NyY1B0ciArIDFdID4+PiA2NCAtIGJpdFBvcyAtIG51bUJpdHNMVVRRaWNrOwogICAgICAgICAgICAgICAgICAgICAgICAgIHZhbFRtcFF1aWNrID0gdmFsVG1wOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZWNvZGVMdXRbdmFsVG1wUXVpY2tdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsID0gZGVjb2RlTHV0W3ZhbFRtcFF1aWNrXVsxXTsKICAgICAgICAgICAgICAgICAgICAgICAgICBiaXRQb3MgKz0gZGVjb2RlTHV0W3ZhbFRtcFF1aWNrXVswXTsKICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICB2YWxUbXAgPSB3b3JkIDw8IGJpdFBvcyA+Pj4gMzIgLSBudW1CaXRzTFVUOwogICAgICAgICAgICAgICAgICAgICAgICAgIHZhbFRtcFF1aWNrID0gdmFsVG1wOwogICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgzMiAtIGJpdFBvcyA8IG51bUJpdHNMVVQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbFRtcCB8PSBzdHVmZmVkRGF0YVtzcmNQdHIgKyAxXSA+Pj4gNjQgLSBiaXRQb3MgLSBudW1CaXRzTFVUOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsVG1wUXVpY2sgPSB2YWxUbXA7CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUgPSB0cmVlOwogICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaWkgPSAwOyBpaSA8IG51bUJpdHNMVVQ7IGlpKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRCaXQgPSB2YWxUbXAgPj4+IG51bUJpdHNMVVQgLSBpaSAtIDEgJiAxOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9kZSA9IGN1cnJlbnRCaXQgPyBub2RlLnJpZ2h0IDogbm9kZS5sZWZ0OwogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEobm9kZS5sZWZ0IHx8IG5vZGUucmlnaHQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbCA9IG5vZGUudmFsOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaXRQb3MgPSBiaXRQb3MgKyBpaSArIDE7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoYml0UG9zID49IDMyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgYml0UG9zIC09IDMyOwogICAgICAgICAgICAgICAgICAgICAgICAgIHNyY1B0cisrOwogICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmQgPSBzdHVmZmVkRGF0YVtzcmNQdHJdOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhID0gdmFsIC0gb2Zmc2V0OwogICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVsdGFFbmNvZGUpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoajIgPiAwICYmIG1hc2tbazIgLSAxXSkgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsdGEgKz0gcHJldlZhbDsKICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkyID4gMCAmJiBtYXNrW2syIC0gd2lkdGhdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YSArPSByZXN1bHRQaXhlbHNbazIgLSB3aWR0aF07CiAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhICs9IHByZXZWYWw7CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhICY9IDI1NTsKICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHNbazJdID0gZGVsdGE7CiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldlZhbCA9IGRlbHRhOwogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFBpeGVsc1trMl0gPSBkZWx0YTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZGF0YS5wdHIgPSBkYXRhLnB0ciArIChzcmNQdHIgKyAxKSAqIDQgKyAoYml0UG9zID4gMCA/IDQgOiAwKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzID0gcmVzdWx0UGl4ZWxzQWxsRGltOwogICAgICAgICAgICB9LAogICAgICAgICAgICBkZWNvZGVCaXRzOiBmdW5jdGlvbihpbnB1dCwgZGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBvZmZzZXQsIGlEaW0pIHsKICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICB2YXIgaGVhZGVySW5mbyA9IGRhdGEuaGVhZGVySW5mbzsKICAgICAgICAgICAgICAgIHZhciBmaWxlVmVyc2lvbiA9IGhlYWRlckluZm8uZmlsZVZlcnNpb247CiAgICAgICAgICAgICAgICB2YXIgYmxvY2tQdHIgPSAwOwogICAgICAgICAgICAgICAgdmFyIHZpZXcgPSBuZXcgRGF0YVZpZXcoaW5wdXQsIGRhdGEucHRyLCA1KTsKICAgICAgICAgICAgICAgIHZhciBoZWFkZXJCeXRlID0gdmlldy5nZXRVaW50OCgwKTsKICAgICAgICAgICAgICAgIGJsb2NrUHRyKys7CiAgICAgICAgICAgICAgICB2YXIgYml0czY3ID0gaGVhZGVyQnl0ZSA+PiA2OwogICAgICAgICAgICAgICAgdmFyIG4yID0gYml0czY3ID09PSAwID8gNCA6IDMgLSBiaXRzNjc7CiAgICAgICAgICAgICAgICB2YXIgZG9MdXQgPSAoaGVhZGVyQnl0ZSAmIDMyKSA+IDAgPyB0cnVlIDogZmFsc2U7CiAgICAgICAgICAgICAgICB2YXIgbnVtQml0cyA9IGhlYWRlckJ5dGUgJiAzMTsKICAgICAgICAgICAgICAgIHZhciBudW1FbGVtZW50cyA9IDA7CiAgICAgICAgICAgICAgICBpZiAobjIgPT09IDEpIHsKICAgICAgICAgICAgICAgICAgbnVtRWxlbWVudHMgPSB2aWV3LmdldFVpbnQ4KGJsb2NrUHRyKTsKICAgICAgICAgICAgICAgICAgYmxvY2tQdHIrKzsKICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobjIgPT09IDIpIHsKICAgICAgICAgICAgICAgICAgbnVtRWxlbWVudHMgPSB2aWV3LmdldFVpbnQxNihibG9ja1B0ciwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgIGJsb2NrUHRyICs9IDI7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG4yID09PSA0KSB7CiAgICAgICAgICAgICAgICAgIG51bUVsZW1lbnRzID0gdmlldy5nZXRVaW50MzIoYmxvY2tQdHIsIHRydWUpOwogICAgICAgICAgICAgICAgICBibG9ja1B0ciArPSA0OwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgdmFsaWQgcGl4ZWwgY291bnQgdHlwZSI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB2YXIgc2NhbGUgPSAyICogaGVhZGVySW5mby5tYXhaRXJyb3I7CiAgICAgICAgICAgICAgICB2YXIgc3R1ZmZlZERhdGEsIGFycmF5QnVmLCBzdG9yZTgsIGRhdGFCeXRlcywgZGF0YVdvcmRzOwogICAgICAgICAgICAgICAgdmFyIGx1dEFyciwgbHV0RGF0YSwgbHV0Qnl0ZXMsIGx1dEJpdHNQZXJFbGVtZW50LCBiaXRzUGVyUGl4ZWw7CiAgICAgICAgICAgICAgICB2YXIgek1heCA9IGhlYWRlckluZm8ubnVtRGltcyA+IDEgPyBoZWFkZXJJbmZvLm1heFZhbHVlc1tpRGltXSA6IGhlYWRlckluZm8uek1heDsKICAgICAgICAgICAgICAgIGlmIChkb0x1dCkgewogICAgICAgICAgICAgICAgICBkYXRhLmNvdW50ZXIubHV0Kys7CiAgICAgICAgICAgICAgICAgIGx1dEJ5dGVzID0gdmlldy5nZXRVaW50OChibG9ja1B0cik7CiAgICAgICAgICAgICAgICAgIGx1dEJpdHNQZXJFbGVtZW50ID0gbnVtQml0czsKICAgICAgICAgICAgICAgICAgYmxvY2tQdHIrKzsKICAgICAgICAgICAgICAgICAgZGF0YUJ5dGVzID0gTWF0aC5jZWlsKChsdXRCeXRlcyAtIDEpICogbnVtQml0cyAvIDgpOwogICAgICAgICAgICAgICAgICBkYXRhV29yZHMgPSBNYXRoLmNlaWwoZGF0YUJ5dGVzIC8gNCk7CiAgICAgICAgICAgICAgICAgIGFycmF5QnVmID0gbmV3IEFycmF5QnVmZmVyKGRhdGFXb3JkcyAqIDQpOwogICAgICAgICAgICAgICAgICBzdG9yZTggPSBuZXcgVWludDhBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgIGRhdGEucHRyICs9IGJsb2NrUHRyOwogICAgICAgICAgICAgICAgICBzdG9yZTguc2V0KG5ldyBVaW50OEFycmF5KGlucHV0LCBkYXRhLnB0ciwgZGF0YUJ5dGVzKSk7CiAgICAgICAgICAgICAgICAgIGx1dERhdGEgPSBuZXcgVWludDMyQXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgICAgICBkYXRhLnB0ciArPSBkYXRhQnl0ZXM7CiAgICAgICAgICAgICAgICAgIGJpdHNQZXJQaXhlbCA9IDA7CiAgICAgICAgICAgICAgICAgIHdoaWxlIChsdXRCeXRlcyAtIDEgPj4+IGJpdHNQZXJQaXhlbCkgewogICAgICAgICAgICAgICAgICAgIGJpdHNQZXJQaXhlbCsrOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGRhdGFCeXRlcyA9IE1hdGguY2VpbChudW1FbGVtZW50cyAqIGJpdHNQZXJQaXhlbCAvIDgpOwogICAgICAgICAgICAgICAgICBkYXRhV29yZHMgPSBNYXRoLmNlaWwoZGF0YUJ5dGVzIC8gNCk7CiAgICAgICAgICAgICAgICAgIGFycmF5QnVmID0gbmV3IEFycmF5QnVmZmVyKGRhdGFXb3JkcyAqIDQpOwogICAgICAgICAgICAgICAgICBzdG9yZTggPSBuZXcgVWludDhBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgIHN0b3JlOC5zZXQobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIGRhdGEucHRyLCBkYXRhQnl0ZXMpKTsKICAgICAgICAgICAgICAgICAgc3R1ZmZlZERhdGEgPSBuZXcgVWludDMyQXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgICAgICBkYXRhLnB0ciArPSBkYXRhQnl0ZXM7CiAgICAgICAgICAgICAgICAgIGlmIChmaWxlVmVyc2lvbiA+PSAzKSB7CiAgICAgICAgICAgICAgICAgICAgbHV0QXJyID0gQml0U3R1ZmZlci51bnN0dWZmTFVUMihsdXREYXRhLCBudW1CaXRzLCBsdXRCeXRlcyAtIDEsIG9mZnNldCwgc2NhbGUsIHpNYXgpOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIGx1dEFyciA9IEJpdFN0dWZmZXIudW5zdHVmZkxVVChsdXREYXRhLCBudW1CaXRzLCBsdXRCeXRlcyAtIDEsIG9mZnNldCwgc2NhbGUsIHpNYXgpOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIGlmIChmaWxlVmVyc2lvbiA+PSAzKSB7CiAgICAgICAgICAgICAgICAgICAgQml0U3R1ZmZlci51bnN0dWZmMihzdHVmZmVkRGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBiaXRzUGVyUGl4ZWwsIG51bUVsZW1lbnRzLCBsdXRBcnIpOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIEJpdFN0dWZmZXIudW5zdHVmZihzdHVmZmVkRGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBiaXRzUGVyUGl4ZWwsIG51bUVsZW1lbnRzLCBsdXRBcnIpOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBkYXRhLmNvdW50ZXIuYml0c3R1ZmZlcisrOwogICAgICAgICAgICAgICAgICBiaXRzUGVyUGl4ZWwgPSBudW1CaXRzOwogICAgICAgICAgICAgICAgICBkYXRhLnB0ciArPSBibG9ja1B0cjsKICAgICAgICAgICAgICAgICAgaWYgKGJpdHNQZXJQaXhlbCA+IDApIHsKICAgICAgICAgICAgICAgICAgICBkYXRhQnl0ZXMgPSBNYXRoLmNlaWwobnVtRWxlbWVudHMgKiBiaXRzUGVyUGl4ZWwgLyA4KTsKICAgICAgICAgICAgICAgICAgICBkYXRhV29yZHMgPSBNYXRoLmNlaWwoZGF0YUJ5dGVzIC8gNCk7CiAgICAgICAgICAgICAgICAgICAgYXJyYXlCdWYgPSBuZXcgQXJyYXlCdWZmZXIoZGF0YVdvcmRzICogNCk7CiAgICAgICAgICAgICAgICAgICAgc3RvcmU4ID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgICAgICAgIHN0b3JlOC5zZXQobmV3IFVpbnQ4QXJyYXkoaW5wdXQsIGRhdGEucHRyLCBkYXRhQnl0ZXMpKTsKICAgICAgICAgICAgICAgICAgICBzdHVmZmVkRGF0YSA9IG5ldyBVaW50MzJBcnJheShhcnJheUJ1Zik7CiAgICAgICAgICAgICAgICAgICAgZGF0YS5wdHIgKz0gZGF0YUJ5dGVzOwogICAgICAgICAgICAgICAgICAgIGlmIChmaWxlVmVyc2lvbiA+PSAzKSB7CiAgICAgICAgICAgICAgICAgICAgICBpZiAob2Zmc2V0ID09IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICAgICAgQml0U3R1ZmZlci5vcmlnaW5hbFVuc3R1ZmYyKHN0dWZmZWREYXRhLCBibG9ja0RhdGFCdWZmZXIsIGJpdHNQZXJQaXhlbCwgbnVtRWxlbWVudHMpOwogICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgQml0U3R1ZmZlci51bnN0dWZmMihzdHVmZmVkRGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBiaXRzUGVyUGl4ZWwsIG51bUVsZW1lbnRzLCBmYWxzZSwgb2Zmc2V0LCBzY2FsZSwgek1heCk7CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgIGlmIChvZmZzZXQgPT0gbnVsbCkgewogICAgICAgICAgICAgICAgICAgICAgICBCaXRTdHVmZmVyLm9yaWdpbmFsVW5zdHVmZihzdHVmZmVkRGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBiaXRzUGVyUGl4ZWwsIG51bUVsZW1lbnRzKTsKICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIEJpdFN0dWZmZXIudW5zdHVmZihzdHVmZmVkRGF0YSwgYmxvY2tEYXRhQnVmZmVyLCBiaXRzUGVyUGl4ZWwsIG51bUVsZW1lbnRzLCBmYWxzZSwgb2Zmc2V0LCBzY2FsZSwgek1heCk7CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICByZWFkVGlsZXM6IGZ1bmN0aW9uKGlucHV0LCBkYXRhLCBPdXRQaXhlbFR5cGVBcnJheSkgewogICAgICAgICAgICAgIHZhciBoZWFkZXJJbmZvID0gZGF0YS5oZWFkZXJJbmZvOwogICAgICAgICAgICAgIHZhciB3aWR0aCA9IGhlYWRlckluZm8ud2lkdGg7CiAgICAgICAgICAgICAgdmFyIGhlaWdodCA9IGhlYWRlckluZm8uaGVpZ2h0OwogICAgICAgICAgICAgIHZhciBtaWNyb0Jsb2NrU2l6ZSA9IGhlYWRlckluZm8ubWljcm9CbG9ja1NpemU7CiAgICAgICAgICAgICAgdmFyIGltYWdlVHlwZSA9IGhlYWRlckluZm8uaW1hZ2VUeXBlOwogICAgICAgICAgICAgIHZhciBkYXRhVHlwZVNpemUgPSBMZXJjMkhlbHBlcnMuZ2V0RGF0YVR5cGVTaXplKGltYWdlVHlwZSk7CiAgICAgICAgICAgICAgdmFyIG51bUJsb2Nrc1ggPSBNYXRoLmNlaWwod2lkdGggLyBtaWNyb0Jsb2NrU2l6ZSk7CiAgICAgICAgICAgICAgdmFyIG51bUJsb2Nrc1kgPSBNYXRoLmNlaWwoaGVpZ2h0IC8gbWljcm9CbG9ja1NpemUpOwogICAgICAgICAgICAgIGRhdGEucGl4ZWxzLm51bUJsb2Nrc1kgPSBudW1CbG9ja3NZOwogICAgICAgICAgICAgIGRhdGEucGl4ZWxzLm51bUJsb2Nrc1ggPSBudW1CbG9ja3NYOwogICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnB0ciA9IDA7CiAgICAgICAgICAgICAgdmFyIHJvdyA9IDAsIGNvbCA9IDAsIGJsb2NrWSA9IDAsIGJsb2NrWCA9IDAsIHRoaXNCbG9ja0hlaWdodCA9IDAsIHRoaXNCbG9ja1dpZHRoID0gMCwgYnl0ZXNMZWZ0ID0gMCwgaGVhZGVyQnl0ZSA9IDAsIGJpdHM2NyA9IDAsIHRlc3RDb2RlID0gMCwgb3V0UHRyID0gMCwgb3V0U3RyaWRlID0gMCwgbnVtQnl0ZXMgPSAwLCBieXRlc2xlZnQgPSAwLCB6MiA9IDAsIGJsb2NrUHRyID0gMDsKICAgICAgICAgICAgICB2YXIgdmlldywgYmxvY2ssIGFycmF5QnVmLCBzdG9yZTgsIHJhd0RhdGE7CiAgICAgICAgICAgICAgdmFyIGJsb2NrRW5jb2Rpbmc7CiAgICAgICAgICAgICAgdmFyIGJsb2NrRGF0YUJ1ZmZlciA9IG5ldyBPdXRQaXhlbFR5cGVBcnJheShtaWNyb0Jsb2NrU2l6ZSAqIG1pY3JvQmxvY2tTaXplKTsKICAgICAgICAgICAgICB2YXIgbGFzdEJsb2NrSGVpZ2h0ID0gaGVpZ2h0ICUgbWljcm9CbG9ja1NpemUgfHwgbWljcm9CbG9ja1NpemU7CiAgICAgICAgICAgICAgdmFyIGxhc3RCbG9ja1dpZHRoID0gd2lkdGggJSBtaWNyb0Jsb2NrU2l6ZSB8fCBtaWNyb0Jsb2NrU2l6ZTsKICAgICAgICAgICAgICB2YXIgb2Zmc2V0VHlwZSwgb2Zmc2V0OwogICAgICAgICAgICAgIHZhciBudW1EaW1zID0gaGVhZGVySW5mby5udW1EaW1zLCBpRGltOwogICAgICAgICAgICAgIHZhciBtYXNrID0gZGF0YS5waXhlbHMucmVzdWx0TWFzazsKICAgICAgICAgICAgICB2YXIgcmVzdWx0UGl4ZWxzID0gZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzOwogICAgICAgICAgICAgIGZvciAoYmxvY2tZID0gMDsgYmxvY2tZIDwgbnVtQmxvY2tzWTsgYmxvY2tZKyspIHsKICAgICAgICAgICAgICAgIHRoaXNCbG9ja0hlaWdodCA9IGJsb2NrWSAhPT0gbnVtQmxvY2tzWSAtIDEgPyBtaWNyb0Jsb2NrU2l6ZSA6IGxhc3RCbG9ja0hlaWdodDsKICAgICAgICAgICAgICAgIGZvciAoYmxvY2tYID0gMDsgYmxvY2tYIDwgbnVtQmxvY2tzWDsgYmxvY2tYKyspIHsKICAgICAgICAgICAgICAgICAgdGhpc0Jsb2NrV2lkdGggPSBibG9ja1ggIT09IG51bUJsb2Nrc1ggLSAxID8gbWljcm9CbG9ja1NpemUgOiBsYXN0QmxvY2tXaWR0aDsKICAgICAgICAgICAgICAgICAgb3V0UHRyID0gYmxvY2tZICogd2lkdGggKiBtaWNyb0Jsb2NrU2l6ZSArIGJsb2NrWCAqIG1pY3JvQmxvY2tTaXplOwogICAgICAgICAgICAgICAgICBvdXRTdHJpZGUgPSB3aWR0aCAtIHRoaXNCbG9ja1dpZHRoOwogICAgICAgICAgICAgICAgICBmb3IgKGlEaW0gPSAwOyBpRGltIDwgbnVtRGltczsgaURpbSsrKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG51bURpbXMgPiAxKSB7CiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHMgPSBuZXcgT3V0UGl4ZWxUeXBlQXJyYXkoZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzLmJ1ZmZlciwgd2lkdGggKiBoZWlnaHQgKiBpRGltICogZGF0YVR5cGVTaXplLCB3aWR0aCAqIGhlaWdodCk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJ5dGVzTGVmdCA9IGlucHV0LmJ5dGVMZW5ndGggLSBkYXRhLnB0cjsKICAgICAgICAgICAgICAgICAgICB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBkYXRhLnB0ciwgTWF0aC5taW4oMTAsIGJ5dGVzTGVmdCkpOwogICAgICAgICAgICAgICAgICAgIGJsb2NrID0ge307CiAgICAgICAgICAgICAgICAgICAgYmxvY2tQdHIgPSAwOwogICAgICAgICAgICAgICAgICAgIGhlYWRlckJ5dGUgPSB2aWV3LmdldFVpbnQ4KDApOwogICAgICAgICAgICAgICAgICAgIGJsb2NrUHRyKys7CiAgICAgICAgICAgICAgICAgICAgYml0czY3ID0gaGVhZGVyQnl0ZSA+PiA2ICYgMjU1OwogICAgICAgICAgICAgICAgICAgIHRlc3RDb2RlID0gaGVhZGVyQnl0ZSA+PiAyICYgMTU7CiAgICAgICAgICAgICAgICAgICAgaWYgKHRlc3RDb2RlICE9PSAoYmxvY2tYICogbWljcm9CbG9ja1NpemUgPj4gMyAmIDE1KSkgewogICAgICAgICAgICAgICAgICAgICAgdGhyb3cgImludGVncml0eSBpc3N1ZSI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIGJsb2NrRW5jb2RpbmcgPSBoZWFkZXJCeXRlICYgMzsKICAgICAgICAgICAgICAgICAgICBpZiAoYmxvY2tFbmNvZGluZyA+IDMpIHsKICAgICAgICAgICAgICAgICAgICAgIGRhdGEucHRyICs9IGJsb2NrUHRyOwogICAgICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgYmxvY2sgZW5jb2RpbmcgKCIgKyBibG9ja0VuY29kaW5nICsgIikiOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYmxvY2tFbmNvZGluZyA9PT0gMikgewogICAgICAgICAgICAgICAgICAgICAgZGF0YS5jb3VudGVyLmNvbnN0YW50Kys7CiAgICAgICAgICAgICAgICAgICAgICBkYXRhLnB0ciArPSBibG9ja1B0cjsKICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoYmxvY2tFbmNvZGluZyA9PT0gMCkgewogICAgICAgICAgICAgICAgICAgICAgZGF0YS5jb3VudGVyLnVuY29tcHJlc3NlZCsrOwogICAgICAgICAgICAgICAgICAgICAgZGF0YS5wdHIgKz0gYmxvY2tQdHI7CiAgICAgICAgICAgICAgICAgICAgICBudW1CeXRlcyA9IHRoaXNCbG9ja0hlaWdodCAqIHRoaXNCbG9ja1dpZHRoICogZGF0YVR5cGVTaXplOwogICAgICAgICAgICAgICAgICAgICAgYnl0ZXNsZWZ0ID0gaW5wdXQuYnl0ZUxlbmd0aCAtIGRhdGEucHRyOwogICAgICAgICAgICAgICAgICAgICAgbnVtQnl0ZXMgPSBudW1CeXRlcyA8IGJ5dGVzbGVmdCA/IG51bUJ5dGVzIDogYnl0ZXNsZWZ0OwogICAgICAgICAgICAgICAgICAgICAgYXJyYXlCdWYgPSBuZXcgQXJyYXlCdWZmZXIobnVtQnl0ZXMgJSBkYXRhVHlwZVNpemUgPT09IDAgPyBudW1CeXRlcyA6IG51bUJ5dGVzICsgZGF0YVR5cGVTaXplIC0gbnVtQnl0ZXMgJSBkYXRhVHlwZVNpemUpOwogICAgICAgICAgICAgICAgICAgICAgc3RvcmU4ID0gbmV3IFVpbnQ4QXJyYXkoYXJyYXlCdWYpOwogICAgICAgICAgICAgICAgICAgICAgc3RvcmU4LnNldChuZXcgVWludDhBcnJheShpbnB1dCwgZGF0YS5wdHIsIG51bUJ5dGVzKSk7CiAgICAgICAgICAgICAgICAgICAgICByYXdEYXRhID0gbmV3IE91dFBpeGVsVHlwZUFycmF5KGFycmF5QnVmKTsKICAgICAgICAgICAgICAgICAgICAgIHoyID0gMDsKICAgICAgICAgICAgICAgICAgICAgIGlmIChtYXNrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAocm93ID0gMDsgcm93IDwgdGhpc0Jsb2NrSGVpZ2h0OyByb3crKykgewogICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29sID0gMDsgY29sIDwgdGhpc0Jsb2NrV2lkdGg7IGNvbCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFza1tvdXRQdHJdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFBpeGVsc1tvdXRQdHJdID0gcmF3RGF0YVt6MisrXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFB0cisrOwogICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRQdHIgKz0gb3V0U3RyaWRlOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHJvdyA9IDA7IHJvdyA8IHRoaXNCbG9ja0hlaWdodDsgcm93KyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbCA9IDA7IGNvbCA8IHRoaXNCbG9ja1dpZHRoOyBjb2wrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0UGl4ZWxzW291dFB0cisrXSA9IHJhd0RhdGFbejIrK107CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgIG91dFB0ciArPSBvdXRTdHJpZGU7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIGRhdGEucHRyICs9IHoyICogZGF0YVR5cGVTaXplOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICBvZmZzZXRUeXBlID0gTGVyYzJIZWxwZXJzLmdldERhdGFUeXBlVXNlZChpbWFnZVR5cGUsIGJpdHM2Nyk7CiAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgPSBMZXJjMkhlbHBlcnMuZ2V0T25lUGl4ZWwoYmxvY2ssIGJsb2NrUHRyLCBvZmZzZXRUeXBlLCB2aWV3KTsKICAgICAgICAgICAgICAgICAgICAgIGJsb2NrUHRyICs9IExlcmMySGVscGVycy5nZXREYXRhVHlwZVNpemUob2Zmc2V0VHlwZSk7CiAgICAgICAgICAgICAgICAgICAgICBpZiAoYmxvY2tFbmNvZGluZyA9PT0gMykgewogICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnB0ciArPSBibG9ja1B0cjsKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5jb3VudGVyLmNvbnN0YW50b2Zmc2V0Kys7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChtYXNrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChyb3cgPSAwOyByb3cgPCB0aGlzQmxvY2tIZWlnaHQ7IHJvdysrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbCA9IDA7IGNvbCA8IHRoaXNCbG9ja1dpZHRoOyBjb2wrKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWFza1tvdXRQdHJdKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0UGl4ZWxzW291dFB0cl0gPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0UHRyKys7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRQdHIgKz0gb3V0U3RyaWRlOwogICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHJvdyA9IDA7IHJvdyA8IHRoaXNCbG9ja0hlaWdodDsgcm93KyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29sID0gMDsgY29sIDwgdGhpc0Jsb2NrV2lkdGg7IGNvbCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFBpeGVsc1tvdXRQdHIrK10gPSBvZmZzZXQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRQdHIgKz0gb3V0U3RyaWRlOwogICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5wdHIgKz0gYmxvY2tQdHI7CiAgICAgICAgICAgICAgICAgICAgICAgIExlcmMySGVscGVycy5kZWNvZGVCaXRzKGlucHV0LCBkYXRhLCBibG9ja0RhdGFCdWZmZXIsIG9mZnNldCwgaURpbSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGJsb2NrUHRyID0gMDsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hc2spIHsKICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHJvdyA9IDA7IHJvdyA8IHRoaXNCbG9ja0hlaWdodDsgcm93KyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29sID0gMDsgY29sIDwgdGhpc0Jsb2NrV2lkdGg7IGNvbCsrKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChtYXNrW291dFB0cl0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRQaXhlbHNbb3V0UHRyXSA9IGJsb2NrRGF0YUJ1ZmZlcltibG9ja1B0cisrXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRQdHIrKzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFB0ciArPSBvdXRTdHJpZGU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAocm93ID0gMDsgcm93IDwgdGhpc0Jsb2NrSGVpZ2h0OyByb3crKykgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChjb2wgPSAwOyBjb2wgPCB0aGlzQmxvY2tXaWR0aDsgY29sKyspIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0UGl4ZWxzW291dFB0cisrXSA9IGJsb2NrRGF0YUJ1ZmZlcltibG9ja1B0cisrXTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFB0ciArPSBvdXRTdHJpZGU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9LAogICAgICAgICAgICAvKioqKioqKioqKioqKioqKioKICAgICAgICAgICAgKiAgcHJpdmF0ZSBtZXRob2RzIChoZWxwZXIgbWV0aG9kcykKICAgICAgICAgICAgKioqKioqKioqKioqKioqKiovCiAgICAgICAgICAgIGZvcm1hdEZpbGVJbmZvOiBmdW5jdGlvbihkYXRhKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgICAgICJmaWxlSWRlbnRpZmllclN0cmluZyI6IGRhdGEuaGVhZGVySW5mby5maWxlSWRlbnRpZmllclN0cmluZywKICAgICAgICAgICAgICAgICJmaWxlVmVyc2lvbiI6IGRhdGEuaGVhZGVySW5mby5maWxlVmVyc2lvbiwKICAgICAgICAgICAgICAgICJpbWFnZVR5cGUiOiBkYXRhLmhlYWRlckluZm8uaW1hZ2VUeXBlLAogICAgICAgICAgICAgICAgImhlaWdodCI6IGRhdGEuaGVhZGVySW5mby5oZWlnaHQsCiAgICAgICAgICAgICAgICAid2lkdGgiOiBkYXRhLmhlYWRlckluZm8ud2lkdGgsCiAgICAgICAgICAgICAgICAibnVtVmFsaWRQaXhlbCI6IGRhdGEuaGVhZGVySW5mby5udW1WYWxpZFBpeGVsLAogICAgICAgICAgICAgICAgIm1pY3JvQmxvY2tTaXplIjogZGF0YS5oZWFkZXJJbmZvLm1pY3JvQmxvY2tTaXplLAogICAgICAgICAgICAgICAgImJsb2JTaXplIjogZGF0YS5oZWFkZXJJbmZvLmJsb2JTaXplLAogICAgICAgICAgICAgICAgIm1heFpFcnJvciI6IGRhdGEuaGVhZGVySW5mby5tYXhaRXJyb3IsCiAgICAgICAgICAgICAgICAicGl4ZWxUeXBlIjogTGVyYzJIZWxwZXJzLmdldFBpeGVsVHlwZShkYXRhLmhlYWRlckluZm8uaW1hZ2VUeXBlKSwKICAgICAgICAgICAgICAgICJlb2ZPZmZzZXQiOiBkYXRhLmVvZk9mZnNldCwKICAgICAgICAgICAgICAgICJtYXNrIjogZGF0YS5tYXNrID8gewogICAgICAgICAgICAgICAgICAibnVtQnl0ZXMiOiBkYXRhLm1hc2subnVtQnl0ZXMKICAgICAgICAgICAgICAgIH0gOiBudWxsLAogICAgICAgICAgICAgICAgInBpeGVscyI6IHsKICAgICAgICAgICAgICAgICAgIm51bUJsb2Nrc1giOiBkYXRhLnBpeGVscy5udW1CbG9ja3NYLAogICAgICAgICAgICAgICAgICAibnVtQmxvY2tzWSI6IGRhdGEucGl4ZWxzLm51bUJsb2Nrc1ksCiAgICAgICAgICAgICAgICAgIC8vIm51bUJ5dGVzIjogZGF0YS5waXhlbHMubnVtQnl0ZXMsCiAgICAgICAgICAgICAgICAgICJtYXhWYWx1ZSI6IGRhdGEuaGVhZGVySW5mby56TWF4LAogICAgICAgICAgICAgICAgICAibWluVmFsdWUiOiBkYXRhLmhlYWRlckluZm8uek1pbiwKICAgICAgICAgICAgICAgICAgIm5vRGF0YVZhbHVlIjogZGF0YS5ub0RhdGFWYWx1ZQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH07CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGNvbnN0cnVjdENvbnN0YW50U3VyZmFjZTogZnVuY3Rpb24oZGF0YSkgewogICAgICAgICAgICAgIHZhciB2YWwgPSBkYXRhLmhlYWRlckluZm8uek1heDsKICAgICAgICAgICAgICB2YXIgbnVtRGltcyA9IGRhdGEuaGVhZGVySW5mby5udW1EaW1zOwogICAgICAgICAgICAgIHZhciBudW1QaXhlbHMgPSBkYXRhLmhlYWRlckluZm8uaGVpZ2h0ICogZGF0YS5oZWFkZXJJbmZvLndpZHRoOwogICAgICAgICAgICAgIHZhciBudW1QaXhlbEFsbERpbXMgPSBudW1QaXhlbHMgKiBudW1EaW1zOwogICAgICAgICAgICAgIHZhciBpMiA9IDAsIGsyID0gMCwgblN0YXJ0ID0gMDsKICAgICAgICAgICAgICB2YXIgbWFzayA9IGRhdGEucGl4ZWxzLnJlc3VsdE1hc2s7CiAgICAgICAgICAgICAgaWYgKG1hc2spIHsKICAgICAgICAgICAgICAgIGlmIChudW1EaW1zID4gMSkgewogICAgICAgICAgICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1EaW1zOyBpMisrKSB7CiAgICAgICAgICAgICAgICAgICAgblN0YXJ0ID0gaTIgKiBudW1QaXhlbHM7CiAgICAgICAgICAgICAgICAgICAgZm9yIChrMiA9IDA7IGsyIDwgbnVtUGl4ZWxzOyBrMisrKSB7CiAgICAgICAgICAgICAgICAgICAgICBpZiAobWFza1trMl0pIHsKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzW25TdGFydCArIGsyXSA9IHZhbDsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIGZvciAoazIgPSAwOyBrMiA8IG51bVBpeGVsczsgazIrKykgewogICAgICAgICAgICAgICAgICAgIGlmIChtYXNrW2syXSkgewogICAgICAgICAgICAgICAgICAgICAgZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzW2syXSA9IHZhbDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgaWYgKGRhdGEucGl4ZWxzLnJlc3VsdFBpeGVscy5maWxsKSB7CiAgICAgICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnJlc3VsdFBpeGVscy5maWxsKHZhbCk7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBmb3IgKGsyID0gMDsgazIgPCBudW1QaXhlbEFsbERpbXM7IGsyKyspIHsKICAgICAgICAgICAgICAgICAgICBkYXRhLnBpeGVscy5yZXN1bHRQaXhlbHNbazJdID0gdmFsOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgZ2V0RGF0YVR5cGVBcnJheTogZnVuY3Rpb24odDIpIHsKICAgICAgICAgICAgICB2YXIgdHA7CiAgICAgICAgICAgICAgc3dpdGNoICh0MikgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICB0cCA9IEludDhBcnJheTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgIHRwID0gVWludDhBcnJheTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgIHRwID0gSW50MTZBcnJheTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDM6CiAgICAgICAgICAgICAgICAgIHRwID0gVWludDE2QXJyYXk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgICB0cCA9IEludDMyQXJyYXk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgICB0cCA9IFVpbnQzMkFycmF5OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgICAgdHAgPSBGbG9hdDMyQXJyYXk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgICB0cCA9IEZsb2F0NjRBcnJheTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICB0cCA9IEZsb2F0MzJBcnJheTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHRwOwogICAgICAgICAgICB9LAogICAgICAgICAgICBnZXRQaXhlbFR5cGU6IGZ1bmN0aW9uKHQyKSB7CiAgICAgICAgICAgICAgdmFyIHRwOwogICAgICAgICAgICAgIHN3aXRjaCAodDIpIHsKICAgICAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICAgICAgdHAgPSAiUzgiOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgICAgdHAgPSAiVTgiOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgICAgdHAgPSAiUzE2IjsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDM6CiAgICAgICAgICAgICAgICAgIHRwID0gIlUxNiI7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgICB0cCA9ICJTMzIiOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgICAgdHAgPSAiVTMyIjsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDY6CiAgICAgICAgICAgICAgICAgIHRwID0gIkYzMiI7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgICB0cCA9ICJGNjQiOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgIHRwID0gIkYzMiI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiB0cDsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgaXNWYWxpZFBpeGVsVmFsdWU6IGZ1bmN0aW9uKHQyLCB2YWwpIHsKICAgICAgICAgICAgICBpZiAodmFsID09IG51bGwpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIGlzVmFsaWQ7CiAgICAgICAgICAgICAgc3dpdGNoICh0MikgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICBpc1ZhbGlkID0gdmFsID49IC0xMjggJiYgdmFsIDw9IDEyNzsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgIGlzVmFsaWQgPSB2YWwgPj0gMCAmJiB2YWwgPD0gMjU1OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgICAgaXNWYWxpZCA9IHZhbCA+PSAtMzI3NjggJiYgdmFsIDw9IDMyNzY3OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgICAgaXNWYWxpZCA9IHZhbCA+PSAwICYmIHZhbCA8PSA2NTUzNjsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDQ6CiAgICAgICAgICAgICAgICAgIGlzVmFsaWQgPSB2YWwgPj0gLTIxNDc0ODM2NDggJiYgdmFsIDw9IDIxNDc0ODM2NDc7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgICBpc1ZhbGlkID0gdmFsID49IDAgJiYgdmFsIDw9IDQyOTQ5NjcyOTY7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA2OgogICAgICAgICAgICAgICAgICBpc1ZhbGlkID0gdmFsID49IC0zNDAyNzk5OTM4NzkwMTQ4NGUyMiAmJiB2YWwgPD0gMzQwMjc5OTkzODc5MDE0ODRlMjI7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgICBpc1ZhbGlkID0gdmFsID49IDVlLTMyNCAmJiB2YWwgPD0gMTc5NzY5MzEzNDg2MjMxNTdlMjkyOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgIGlzVmFsaWQgPSBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGlzVmFsaWQ7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGdldERhdGFUeXBlU2l6ZTogZnVuY3Rpb24odDIpIHsKICAgICAgICAgICAgICB2YXIgczIgPSAwOwogICAgICAgICAgICAgIHN3aXRjaCAodDIpIHsKICAgICAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICAgIC8vdWJ5dGUKICAgICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgICAgczIgPSAxOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgIC8vc2hvcnQKICAgICAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgICAgczIgPSAyOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNDoKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgICAgczIgPSA0OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNzoKICAgICAgICAgICAgICAgICAgczIgPSA4OwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgIHMyID0gdDI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiBzMjsKICAgICAgICAgICAgfSwKICAgICAgICAgICAgZ2V0RGF0YVR5cGVVc2VkOiBmdW5jdGlvbihkdDIsIHRjKSB7CiAgICAgICAgICAgICAgdmFyIHQyID0gZHQyOwogICAgICAgICAgICAgIHN3aXRjaCAoZHQyKSB7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAvL3Nob3J0CiAgICAgICAgICAgICAgICBjYXNlIDQ6CiAgICAgICAgICAgICAgICAgIHQyID0gZHQyIC0gdGM7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgLy91c2hvcnQKICAgICAgICAgICAgICAgIGNhc2UgNToKICAgICAgICAgICAgICAgICAgdDIgPSBkdDIgLSAyICogdGM7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA2OgogICAgICAgICAgICAgICAgICBpZiAoMCA9PT0gdGMpIHsKICAgICAgICAgICAgICAgICAgICB0MiA9IGR0MjsKICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICgxID09PSB0YykgewogICAgICAgICAgICAgICAgICAgIHQyID0gMjsKICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0MiA9IDE7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDc6CiAgICAgICAgICAgICAgICAgIGlmICgwID09PSB0YykgewogICAgICAgICAgICAgICAgICAgIHQyID0gZHQyOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHQyID0gZHQyIC0gMiAqIHRjICsgMTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICAgIHQyID0gZHQyOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHQyOwogICAgICAgICAgICB9LAogICAgICAgICAgICBnZXRPbmVQaXhlbDogZnVuY3Rpb24oYmxvY2ssIGJsb2NrUHRyLCBvZmZzZXRUeXBlLCB2aWV3KSB7CiAgICAgICAgICAgICAgdmFyIHRlbXAgPSAwOwogICAgICAgICAgICAgIHN3aXRjaCAob2Zmc2V0VHlwZSkgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICB0ZW1wID0gdmlldy5nZXRJbnQ4KGJsb2NrUHRyKTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgIHRlbXAgPSB2aWV3LmdldFVpbnQ4KGJsb2NrUHRyKTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgIHRlbXAgPSB2aWV3LmdldEludDE2KGJsb2NrUHRyLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDM6CiAgICAgICAgICAgICAgICAgIHRlbXAgPSB2aWV3LmdldFVpbnQxNihibG9ja1B0ciwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgICB0ZW1wID0gdmlldy5nZXRJbnQzMihibG9ja1B0ciwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA1OgogICAgICAgICAgICAgICAgICB0ZW1wID0gdmlldy5nZXRVSW50MzIoYmxvY2tQdHIsIHRydWUpOwogICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgNjoKICAgICAgICAgICAgICAgICAgdGVtcCA9IHZpZXcuZ2V0RmxvYXQzMihibG9ja1B0ciwgdHJ1ZSk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSA3OgogICAgICAgICAgICAgICAgICB0ZW1wID0gdmlldy5nZXRGbG9hdDY0KGJsb2NrUHRyLCB0cnVlKTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICB0aHJvdyAidGhlIGRlY29kZXIgZG9lcyBub3QgdW5kZXJzdGFuZCB0aGlzIHBpeGVsIHR5cGUiOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gdGVtcDsKICAgICAgICAgICAgfQogICAgICAgICAgfTsKICAgICAgICAgIHZhciBUcmVlTm9kZSA9IGZ1bmN0aW9uKHZhbCwgbGVmdCwgcmlnaHQpIHsKICAgICAgICAgICAgdGhpcy52YWwgPSB2YWw7CiAgICAgICAgICAgIHRoaXMubGVmdCA9IGxlZnQ7CiAgICAgICAgICAgIHRoaXMucmlnaHQgPSByaWdodDsKICAgICAgICAgIH07CiAgICAgICAgICB2YXIgTGVyYzJEZWNvZGUyID0gewogICAgICAgICAgICAvKgogICAgICAgICAgICAqICoqKioqKioqcmVtb3ZlZCBvcHRpb25zIGNvbXBhcmVkIHRvIExFUkMxLiBXZSBjYW4gYnJpbmcgc29tZSBvZiB0aGVtIGJhY2sgaWYgbmVlZGVkLgogICAgICAgICAgICAgKiByZW1vdmVkIHBpeGVsIHR5cGUuIExFUkMyIGlzIHR5cGVkIGFuZCBkb2Vzbid0IHJlcXVpcmUgdXNlciB0byBnaXZlIHBpeGVsIHR5cGUKICAgICAgICAgICAgICogY2hhbmdlZCBlbmNvZGVkTWFza0RhdGEgdG8gbWFza0RhdGEuIExFUkMyICdzIGpzIHZlcnNpb24gbWFrZSBpdCBmYXN0ZXIgdG8gdXNlIG1hc2tEYXRhIGRpcmVjdGx5LgogICAgICAgICAgICAgKiByZW1vdmVkIHJldHVybk1hc2suIG1hc2sgaXMgdXNlZCBieSBMRVJDMiBpbnRlcm5hbGx5IGFuZCBpcyBjb3N0IGZyZWUuIEluIGNhc2Ugb2YgdXNlciBpbnB1dCBtYXNrLCBpdCdzIHJldHVybmVkIGFzIHdlbGwgYW5kIGhhcyBuZWdsaWJsZSBjb3N0LgogICAgICAgICAgICAgKiByZW1vdmVkIG5vZGF0YXZhbHVlLiBCZWNhdXNlIExFUkMyIHBpeGVscyBhcmUgdHlwZWQsIG5vZGF0YXZhbHVlIHdpbGwgc2FjcmlmeSBhIHVzZWZ1bCB2YWx1ZSBmb3IgbWFueSB0eXBlcyAoOGJpdCwgMTZiaXQpIGV0YywKICAgICAgICAgICAgICogICAgICAgdXNlciBoYXMgdG8gYmUga25vd2xlZGdhYmxlIGVub3VnaCBhYm91dCByYXN0ZXIgYW5kIHRoZWlyIGRhdGEgdG8gYXZvaWQgdXNhYmlsaXR5IGlzc3Vlcy4gc28gbm9kYXRhIHZhbHVlIGlzIHNpbXBseSByZW1vdmVkIG5vdy4KICAgICAgICAgICAgICogICAgICAgV2UgY2FuIGFkZCBpdCBiYWNrIGxhdGVyIGlmIHRoZWlyJ3MgYSBjbGVhciByZXF1aXJlbWVudC4KICAgICAgICAgICAgICogcmVtb3ZlZCBlbmNvZGVkTWFzay4gVGhpcyBvcHRpb24gd2FzIG5vdCBpbXBsZW1lbnRlZCBpbiBMZXJjRGVjb2RlLiBJdCBjYW4gYmUgZG9uZSBhZnRlciBkZWNvZGluZyAobGVzcyBlZmZpY2llbnQpCiAgICAgICAgICAgICAqIHJlbW92ZWQgY29tcHV0ZVVzZWRCaXREZXB0aHMuCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqCiAgICAgICAgICAgICAqIHJlc3BvbnNlIGNoYW5nZXMgY29tcGFyZWQgdG8gTEVSQzEKICAgICAgICAgICAgICogMS4gZW5jb2RlZE1hc2tEYXRhIGlzIG5vdCBhdmFpbGFibGUKICAgICAgICAgICAgICogMi4gbm9EYXRhVmFsdWUgaXMgb3B0aW9uYWwgKHJldHVybnMgb25seSBpZiB1c2VyJ3Mgbm9EYXRhVmFsdWUgaXMgd2l0aCBpbiB0aGUgdmFsaWQgZGF0YSB0eXBlIHJhbmdlKQogICAgICAgICAgICAgKiAzLiBtYXNrRGF0YSBpcyBhbHdheXMgYXZhaWxhYmxlCiAgICAgICAgICAgICovCiAgICAgICAgICAgIC8qKioqKioqKioqKioqKioqKgogICAgICAgICAgICAqICBwdWJsaWMgcHJvcGVydGllcwogICAgICAgICAgICAqKioqKioqKioqKioqKioqKiovCiAgICAgICAgICAgIC8vSFVGRk1BTl9MVVRfQklUU19NQVg6IDEyLCAvL3VzZSAyXjEyIGx1dCwgbm90IGNvbmZpZ3VyYWJsZQogICAgICAgICAgICAvKioqKioqKioqKioqKioqKioKICAgICAgICAgICAgKiAgcHVibGljIG1ldGhvZHMKICAgICAgICAgICAgKioqKioqKioqKioqKioqKiovCiAgICAgICAgICAgIC8qKgogICAgICAgICAgICAgKiBEZWNvZGUgYSBMRVJDMiBieXRlIHN0cmVhbSBhbmQgcmV0dXJuIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBwaXhlbCBkYXRhIGFuZCBvcHRpb25hbCBtZXRhZGF0YS4KICAgICAgICAgICAgICoKICAgICAgICAgICAgICogQHBhcmFtIHtBcnJheUJ1ZmZlcn0gaW5wdXQgVGhlIExFUkMgaW5wdXQgYnl0ZSBzdHJlYW0KICAgICAgICAgICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXSBvcHRpb25zIERlY29kaW5nIG9wdGlvbnMKICAgICAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmlucHV0T2Zmc2V0XSBUaGUgbnVtYmVyIG9mIGJ5dGVzIHRvIHNraXAgaW4gdGhlIGlucHV0IGJ5dGUgc3RyZWFtLiBBIHZhbGlkIExFUkMgZmlsZSBpcyBleHBlY3RlZCBhdCB0aGF0IHBvc2l0aW9uCiAgICAgICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMucmV0dXJuRmlsZUluZm9dIElmIHRydWUsIHRoZSByZXR1cm4gdmFsdWUgd2lsbCBoYXZlIGEgZmlsZUluZm8gcHJvcGVydHkgdGhhdCBjb250YWlucyBtZXRhZGF0YSBvYnRhaW5lZCBmcm9tIHRoZSBMRVJDIGhlYWRlcnMgYW5kIHRoZSBkZWNvZGluZyBwcm9jZXNzCiAgICAgICAgICAgICAqLwogICAgICAgICAgICBkZWNvZGU6IGZ1bmN0aW9uKGlucHV0LCBvcHRpb25zKSB7CiAgICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307CiAgICAgICAgICAgICAgdmFyIG5vRGF0YVZhbHVlID0gb3B0aW9ucy5ub0RhdGFWYWx1ZTsKICAgICAgICAgICAgICB2YXIgaTIgPSAwLCBkYXRhID0ge307CiAgICAgICAgICAgICAgZGF0YS5wdHIgPSBvcHRpb25zLmlucHV0T2Zmc2V0IHx8IDA7CiAgICAgICAgICAgICAgZGF0YS5waXhlbHMgPSB7fTsKICAgICAgICAgICAgICBpZiAoIUxlcmMySGVscGVycy5yZWFkSGVhZGVySW5mbyhpbnB1dCwgZGF0YSkpIHsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIGhlYWRlckluZm8gPSBkYXRhLmhlYWRlckluZm87CiAgICAgICAgICAgICAgdmFyIGZpbGVWZXJzaW9uID0gaGVhZGVySW5mby5maWxlVmVyc2lvbjsKICAgICAgICAgICAgICB2YXIgT3V0UGl4ZWxUeXBlQXJyYXkgPSBMZXJjMkhlbHBlcnMuZ2V0RGF0YVR5cGVBcnJheShoZWFkZXJJbmZvLmltYWdlVHlwZSk7CiAgICAgICAgICAgICAgTGVyYzJIZWxwZXJzLnJlYWRNYXNrKGlucHV0LCBkYXRhKTsKICAgICAgICAgICAgICBpZiAoaGVhZGVySW5mby5udW1WYWxpZFBpeGVsICE9PSBoZWFkZXJJbmZvLndpZHRoICogaGVhZGVySW5mby5oZWlnaHQgJiYgIWRhdGEucGl4ZWxzLnJlc3VsdE1hc2spIHsKICAgICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnJlc3VsdE1hc2sgPSBvcHRpb25zLm1hc2tEYXRhOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgbnVtUGl4ZWxzID0gaGVhZGVySW5mby53aWR0aCAqIGhlYWRlckluZm8uaGVpZ2h0OwogICAgICAgICAgICAgIGRhdGEucGl4ZWxzLnJlc3VsdFBpeGVscyA9IG5ldyBPdXRQaXhlbFR5cGVBcnJheShudW1QaXhlbHMgKiBoZWFkZXJJbmZvLm51bURpbXMpOwogICAgICAgICAgICAgIGRhdGEuY291bnRlciA9IHsKICAgICAgICAgICAgICAgIG9uZXN3ZWVwOiAwLAogICAgICAgICAgICAgICAgdW5jb21wcmVzc2VkOiAwLAogICAgICAgICAgICAgICAgbHV0OiAwLAogICAgICAgICAgICAgICAgYml0c3R1ZmZlcjogMCwKICAgICAgICAgICAgICAgIGNvbnN0YW50OiAwLAogICAgICAgICAgICAgICAgY29uc3RhbnRvZmZzZXQ6IDAKICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGlmIChoZWFkZXJJbmZvLm51bVZhbGlkUGl4ZWwgIT09IDApIHsKICAgICAgICAgICAgICAgIGlmIChoZWFkZXJJbmZvLnpNYXggPT09IGhlYWRlckluZm8uek1pbikgewogICAgICAgICAgICAgICAgICBMZXJjMkhlbHBlcnMuY29uc3RydWN0Q29uc3RhbnRTdXJmYWNlKGRhdGEpOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChmaWxlVmVyc2lvbiA+PSA0ICYmIExlcmMySGVscGVycy5jaGVja01pbk1heFJhbmdlcyhpbnB1dCwgZGF0YSkpIHsKICAgICAgICAgICAgICAgICAgTGVyYzJIZWxwZXJzLmNvbnN0cnVjdENvbnN0YW50U3VyZmFjZShkYXRhKTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIHZhciB2aWV3ID0gbmV3IERhdGFWaWV3KGlucHV0LCBkYXRhLnB0ciwgMik7CiAgICAgICAgICAgICAgICAgIHZhciBiUmVhZERhdGFPbmVTd2VlcCA9IHZpZXcuZ2V0VWludDgoMCk7CiAgICAgICAgICAgICAgICAgIGRhdGEucHRyKys7CiAgICAgICAgICAgICAgICAgIGlmIChiUmVhZERhdGFPbmVTd2VlcCkgewogICAgICAgICAgICAgICAgICAgIExlcmMySGVscGVycy5yZWFkRGF0YU9uZVN3ZWVwKGlucHV0LCBkYXRhLCBPdXRQaXhlbFR5cGVBcnJheSk7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGZpbGVWZXJzaW9uID4gMSAmJiBoZWFkZXJJbmZvLmltYWdlVHlwZSA8PSAxICYmIE1hdGguYWJzKGhlYWRlckluZm8ubWF4WkVycm9yIC0gMC41KSA8IDFlLTUpIHsKICAgICAgICAgICAgICAgICAgICAgIHZhciBmbGFnSHVmZm1hbiA9IHZpZXcuZ2V0VWludDgoMSk7CiAgICAgICAgICAgICAgICAgICAgICBkYXRhLnB0cisrOwogICAgICAgICAgICAgICAgICAgICAgZGF0YS5lbmNvZGVNb2RlID0gZmxhZ0h1ZmZtYW47CiAgICAgICAgICAgICAgICAgICAgICBpZiAoZmxhZ0h1ZmZtYW4gPiAyIHx8IGZpbGVWZXJzaW9uIDwgNCAmJiBmbGFnSHVmZm1hbiA+IDEpIHsKICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgIkludmFsaWQgSHVmZm1hbiBmbGFnICIgKyBmbGFnSHVmZm1hbjsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIGlmIChmbGFnSHVmZm1hbikgewogICAgICAgICAgICAgICAgICAgICAgICBMZXJjMkhlbHBlcnMucmVhZEh1ZmZtYW4oaW5wdXQsIGRhdGEsIE91dFBpeGVsVHlwZUFycmF5KTsKICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIExlcmMySGVscGVycy5yZWFkVGlsZXMoaW5wdXQsIGRhdGEsIE91dFBpeGVsVHlwZUFycmF5KTsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgTGVyYzJIZWxwZXJzLnJlYWRUaWxlcyhpbnB1dCwgZGF0YSwgT3V0UGl4ZWxUeXBlQXJyYXkpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBkYXRhLmVvZk9mZnNldCA9IGRhdGEucHRyOwogICAgICAgICAgICAgIHZhciBkaWZmOwogICAgICAgICAgICAgIGlmIChvcHRpb25zLmlucHV0T2Zmc2V0KSB7CiAgICAgICAgICAgICAgICBkaWZmID0gZGF0YS5oZWFkZXJJbmZvLmJsb2JTaXplICsgb3B0aW9ucy5pbnB1dE9mZnNldCAtIGRhdGEucHRyOwogICAgICAgICAgICAgICAgaWYgKE1hdGguYWJzKGRpZmYpID49IDEpIHsKICAgICAgICAgICAgICAgICAgZGF0YS5lb2ZPZmZzZXQgPSBvcHRpb25zLmlucHV0T2Zmc2V0ICsgZGF0YS5oZWFkZXJJbmZvLmJsb2JTaXplOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBkaWZmID0gZGF0YS5oZWFkZXJJbmZvLmJsb2JTaXplIC0gZGF0YS5wdHI7CiAgICAgICAgICAgICAgICBpZiAoTWF0aC5hYnMoZGlmZikgPj0gMSkgewogICAgICAgICAgICAgICAgICBkYXRhLmVvZk9mZnNldCA9IGRhdGEuaGVhZGVySW5mby5ibG9iU2l6ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHsKICAgICAgICAgICAgICAgIHdpZHRoOiBoZWFkZXJJbmZvLndpZHRoLAogICAgICAgICAgICAgICAgaGVpZ2h0OiBoZWFkZXJJbmZvLmhlaWdodCwKICAgICAgICAgICAgICAgIHBpeGVsRGF0YTogZGF0YS5waXhlbHMucmVzdWx0UGl4ZWxzLAogICAgICAgICAgICAgICAgbWluVmFsdWU6IGhlYWRlckluZm8uek1pbiwKICAgICAgICAgICAgICAgIG1heFZhbHVlOiBoZWFkZXJJbmZvLnpNYXgsCiAgICAgICAgICAgICAgICB2YWxpZFBpeGVsQ291bnQ6IGhlYWRlckluZm8ubnVtVmFsaWRQaXhlbCwKICAgICAgICAgICAgICAgIGRpbUNvdW50OiBoZWFkZXJJbmZvLm51bURpbXMsCiAgICAgICAgICAgICAgICBkaW1TdGF0czogewogICAgICAgICAgICAgICAgICBtaW5WYWx1ZXM6IGhlYWRlckluZm8ubWluVmFsdWVzLAogICAgICAgICAgICAgICAgICBtYXhWYWx1ZXM6IGhlYWRlckluZm8ubWF4VmFsdWVzCiAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgbWFza0RhdGE6IGRhdGEucGl4ZWxzLnJlc3VsdE1hc2sKICAgICAgICAgICAgICAgIC8vbm9EYXRhVmFsdWU6IG5vRGF0YVZhbHVlCiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICBpZiAoZGF0YS5waXhlbHMucmVzdWx0TWFzayAmJiBMZXJjMkhlbHBlcnMuaXNWYWxpZFBpeGVsVmFsdWUoaGVhZGVySW5mby5pbWFnZVR5cGUsIG5vRGF0YVZhbHVlKSkgewogICAgICAgICAgICAgICAgdmFyIG1hc2sgPSBkYXRhLnBpeGVscy5yZXN1bHRNYXNrOwogICAgICAgICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtUGl4ZWxzOyBpMisrKSB7CiAgICAgICAgICAgICAgICAgIGlmICghbWFza1tpMl0pIHsKICAgICAgICAgICAgICAgICAgICByZXN1bHQucGl4ZWxEYXRhW2kyXSA9IG5vRGF0YVZhbHVlOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICByZXN1bHQubm9EYXRhVmFsdWUgPSBub0RhdGFWYWx1ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZGF0YS5ub0RhdGFWYWx1ZSA9IG5vRGF0YVZhbHVlOwogICAgICAgICAgICAgIGlmIChvcHRpb25zLnJldHVybkZpbGVJbmZvKSB7CiAgICAgICAgICAgICAgICByZXN1bHQuZmlsZUluZm8gPSBMZXJjMkhlbHBlcnMuZm9ybWF0RmlsZUluZm8oZGF0YSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIGdldEJhbmRDb3VudDogZnVuY3Rpb24oaW5wdXQpIHsKICAgICAgICAgICAgICB2YXIgY291bnQgPSAwOwogICAgICAgICAgICAgIHZhciBpMiA9IDA7CiAgICAgICAgICAgICAgdmFyIHRlbXAgPSB7fTsKICAgICAgICAgICAgICB0ZW1wLnB0ciA9IDA7CiAgICAgICAgICAgICAgdGVtcC5waXhlbHMgPSB7fTsKICAgICAgICAgICAgICB3aGlsZSAoaTIgPCBpbnB1dC5ieXRlTGVuZ3RoIC0gNTgpIHsKICAgICAgICAgICAgICAgIExlcmMySGVscGVycy5yZWFkSGVhZGVySW5mbyhpbnB1dCwgdGVtcCk7CiAgICAgICAgICAgICAgICBpMiArPSB0ZW1wLmhlYWRlckluZm8uYmxvYlNpemU7CiAgICAgICAgICAgICAgICBjb3VudCsrOwogICAgICAgICAgICAgICAgdGVtcC5wdHIgPSBpMjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGNvdW50OwogICAgICAgICAgICB9CiAgICAgICAgICB9OwogICAgICAgICAgcmV0dXJuIExlcmMyRGVjb2RlMjsKICAgICAgICB9KSgpOwogICAgICAgIHZhciBpc1BsYXRmb3JtTGl0dGxlRW5kaWFuID0gKGZ1bmN0aW9uKCkgewogICAgICAgICAgdmFyIGE0ID0gbmV3IEFycmF5QnVmZmVyKDQpOwogICAgICAgICAgdmFyIGIyID0gbmV3IFVpbnQ4QXJyYXkoYTQpOwogICAgICAgICAgdmFyIGMyID0gbmV3IFVpbnQzMkFycmF5KGE0KTsKICAgICAgICAgIGMyWzBdID0gMTsKICAgICAgICAgIHJldHVybiBiMlswXSA9PT0gMTsKICAgICAgICB9KSgpOwogICAgICAgIHZhciBMZXJjMiA9IHsKICAgICAgICAgIC8qKioqKioqKioqKip3cmFwcGVyKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KICAgICAgICAgIC8qKgogICAgICAgICAgICogQSB3cmFwcGVyIGZvciBkZWNvZGluZyBib3RoIExFUkMxIGFuZCBMRVJDMiBieXRlIHN0cmVhbXMgY2FwYWJsZSBvZiBoYW5kbGluZyBtdWx0aWJhbmQgcGl4ZWwgYmxvY2tzIGZvciB2YXJpb3VzIHBpeGVsIHR5cGVzLgogICAgICAgICAgICoKICAgICAgICAgICAqIEBhbGlhcyBtb2R1bGU6TGVyYwogICAgICAgICAgICogQHBhcmFtIHtBcnJheUJ1ZmZlcn0gaW5wdXQgVGhlIExFUkMgaW5wdXQgYnl0ZSBzdHJlYW0KICAgICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gVGhlIGRlY29kaW5nIG9wdGlvbnMgYmVsb3cgYXJlIG9wdGlvbmFsLgogICAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmlucHV0T2Zmc2V0XSBUaGUgbnVtYmVyIG9mIGJ5dGVzIHRvIHNraXAgaW4gdGhlIGlucHV0IGJ5dGUgc3RyZWFtLiBBIHZhbGlkIExlcmMgZmlsZSBpcyBleHBlY3RlZCBhdCB0aGF0IHBvc2l0aW9uLgogICAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRpb25zLnBpeGVsVHlwZV0gKExFUkMxIG9ubHkpIERlZmF1bHQgdmFsdWUgaXMgRjMyLiBWYWxpZCBwaXhlbCB0eXBlcyBmb3IgaW5wdXQgYXJlIFU4L1M4L1MxNi9VMTYvUzMyL1UzMi9GMzIuCiAgICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMubm9EYXRhVmFsdWVdIChMRVJDMSBvbmx5KS4gSXQgaXMgcmVjb21tZW5kZWQgdG8gdXNlIHRoZSByZXR1cm5lZCBtYXNrIGluc3RlYWQgb2Ygc2V0dGluZyB0aGlzIHZhbHVlLgogICAgICAgICAgICogQHJldHVybnMge3t3aWR0aCwgaGVpZ2h0LCBwaXhlbHMsIHBpeGVsVHlwZSwgbWFzaywgc3RhdGlzdGljc319CiAgICAgICAgICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB3aWR0aCBXaWR0aCBvZiBkZWNvZGVkIGltYWdlLgogICAgICAgICAgICAgKiBAcHJvcGVydHkge251bWJlcn0gaGVpZ2h0IEhlaWdodCBvZiBkZWNvZGVkIGltYWdlLgogICAgICAgICAgICAgKiBAcHJvcGVydHkge2FycmF5fSBwaXhlbHMgW2JhbmQxLCBiYW5kMiwg4oCmXSBFYWNoIGJhbmQgaXMgYSB0eXBlZCBhcnJheSBvZiB3aWR0aCpoZWlnaHQuCiAgICAgICAgICAgICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBwaXhlbFR5cGUgVGhlIHR5cGUgb2YgcGl4ZWxzIHJlcHJlc2VudGVkIGluIHRoZSBvdXRwdXQuCiAgICAgICAgICAgICAqIEBwcm9wZXJ0eSB7bWFza30gbWFzayBUeXBlZCBhcnJheSB3aXRoIGEgc2l6ZSBvZiB3aWR0aCpoZWlnaHQsIG9yIG51bGwgaWYgYWxsIHBpeGVscyBhcmUgdmFsaWQuCiAgICAgICAgICAgICAqIEBwcm9wZXJ0eSB7YXJyYXl9IHN0YXRpc3RpY3MgW3N0YXRpc3RpY3NfYmFuZDEsIHN0YXRpc3RpY3NfYmFuZDIsIOKApl0gRWFjaCBlbGVtZW50IGlzIGEgc3RhdGlzdGljcyBvYmplY3QgcmVwcmVzZW50aW5nIG1pbiBhbmQgbWF4IHZhbHVlcwogICAgICAgICAgKiovCiAgICAgICAgICBkZWNvZGU6IGZ1bmN0aW9uKGVuY29kZWREYXRhLCBvcHRpb25zKSB7CiAgICAgICAgICAgIGlmICghaXNQbGF0Zm9ybUxpdHRsZUVuZGlhbikgewogICAgICAgICAgICAgIHRocm93ICJCaWcgZW5kaWFuIHN5c3RlbSBpcyBub3Qgc3VwcG9ydGVkLiI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307CiAgICAgICAgICAgIHZhciBpbnB1dE9mZnNldCA9IG9wdGlvbnMuaW5wdXRPZmZzZXQgfHwgMDsKICAgICAgICAgICAgdmFyIGZpbGVJZFZpZXcgPSBuZXcgVWludDhBcnJheShlbmNvZGVkRGF0YSwgaW5wdXRPZmZzZXQsIDEwKTsKICAgICAgICAgICAgdmFyIGZpbGVJZGVudGlmaWVyU3RyaW5nID0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCBmaWxlSWRWaWV3KTsKICAgICAgICAgICAgdmFyIGxlcmMsIG1ham9yVmVyc2lvbjsKICAgICAgICAgICAgaWYgKGZpbGVJZGVudGlmaWVyU3RyaW5nLnRyaW0oKSA9PT0gIkNudFpJbWFnZSIpIHsKICAgICAgICAgICAgICBsZXJjID0gTGVyY0RlY29kZTsKICAgICAgICAgICAgICBtYWpvclZlcnNpb24gPSAxOwogICAgICAgICAgICB9IGVsc2UgaWYgKGZpbGVJZGVudGlmaWVyU3RyaW5nLnN1YnN0cmluZygwLCA1KSA9PT0gIkxlcmMyIikgewogICAgICAgICAgICAgIGxlcmMgPSBMZXJjMkRlY29kZTsKICAgICAgICAgICAgICBtYWpvclZlcnNpb24gPSAyOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRocm93ICJVbmV4cGVjdGVkIGZpbGUgaWRlbnRpZmllciBzdHJpbmc6ICIgKyBmaWxlSWRlbnRpZmllclN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgaVBsYW5lID0gMCwgZW9mID0gZW5jb2RlZERhdGEuYnl0ZUxlbmd0aCAtIDEwLCBlbmNvZGVkTWFza0RhdGEsIGJhbmRNYXNrcyA9IFtdLCBiYW5kTWFzaywgbWFza0RhdGE7CiAgICAgICAgICAgIHZhciBkZWNvZGVkUGl4ZWxCbG9jayA9IHsKICAgICAgICAgICAgICB3aWR0aDogMCwKICAgICAgICAgICAgICBoZWlnaHQ6IDAsCiAgICAgICAgICAgICAgcGl4ZWxzOiBbXSwKICAgICAgICAgICAgICBwaXhlbFR5cGU6IG9wdGlvbnMucGl4ZWxUeXBlLAogICAgICAgICAgICAgIG1hc2s6IG51bGwsCiAgICAgICAgICAgICAgc3RhdGlzdGljczogW10KICAgICAgICAgICAgfTsKICAgICAgICAgICAgd2hpbGUgKGlucHV0T2Zmc2V0IDwgZW9mKSB7CiAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9IGxlcmMuZGVjb2RlKGVuY29kZWREYXRhLCB7CiAgICAgICAgICAgICAgICBpbnB1dE9mZnNldCwKICAgICAgICAgICAgICAgIC8vZm9yIGJvdGggbGVyYzEgYW5kIGxlcmMyCiAgICAgICAgICAgICAgICBlbmNvZGVkTWFza0RhdGEsCiAgICAgICAgICAgICAgICAvL2xlcmMxIG9ubHkKICAgICAgICAgICAgICAgIG1hc2tEYXRhLAogICAgICAgICAgICAgICAgLy9sZXJjMiBvbmx5CiAgICAgICAgICAgICAgICByZXR1cm5NYXNrOiBpUGxhbmUgPT09IDAgPyB0cnVlIDogZmFsc2UsCiAgICAgICAgICAgICAgICAvL2xlcmMxIG9ubHkKICAgICAgICAgICAgICAgIHJldHVybkVuY29kZWRNYXNrOiBpUGxhbmUgPT09IDAgPyB0cnVlIDogZmFsc2UsCiAgICAgICAgICAgICAgICAvL2xlcmMxIG9ubHkKICAgICAgICAgICAgICAgIHJldHVybkZpbGVJbmZvOiB0cnVlLAogICAgICAgICAgICAgICAgLy9mb3IgYm90aCBsZXJjMSBhbmQgbGVyYzIKICAgICAgICAgICAgICAgIHBpeGVsVHlwZTogb3B0aW9ucy5waXhlbFR5cGUgfHwgbnVsbCwKICAgICAgICAgICAgICAgIC8vbGVyYzEgb25seQogICAgICAgICAgICAgICAgbm9EYXRhVmFsdWU6IG9wdGlvbnMubm9EYXRhVmFsdWUgfHwgbnVsbAogICAgICAgICAgICAgICAgLy9sZXJjMSBvbmx5CiAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgaW5wdXRPZmZzZXQgPSByZXN1bHQuZmlsZUluZm8uZW9mT2Zmc2V0OwogICAgICAgICAgICAgIGlmIChpUGxhbmUgPT09IDApIHsKICAgICAgICAgICAgICAgIGVuY29kZWRNYXNrRGF0YSA9IHJlc3VsdC5lbmNvZGVkTWFza0RhdGE7CiAgICAgICAgICAgICAgICBtYXNrRGF0YSA9IHJlc3VsdC5tYXNrRGF0YTsKICAgICAgICAgICAgICAgIGRlY29kZWRQaXhlbEJsb2NrLndpZHRoID0gcmVzdWx0LndpZHRoOwogICAgICAgICAgICAgICAgZGVjb2RlZFBpeGVsQmxvY2suaGVpZ2h0ID0gcmVzdWx0LmhlaWdodDsKICAgICAgICAgICAgICAgIGRlY29kZWRQaXhlbEJsb2NrLmRpbUNvdW50ID0gcmVzdWx0LmRpbUNvdW50IHx8IDE7CiAgICAgICAgICAgICAgICBkZWNvZGVkUGl4ZWxCbG9jay5waXhlbFR5cGUgPSByZXN1bHQucGl4ZWxUeXBlIHx8IHJlc3VsdC5maWxlSW5mby5waXhlbFR5cGU7CiAgICAgICAgICAgICAgICBkZWNvZGVkUGl4ZWxCbG9jay5tYXNrID0gcmVzdWx0Lm1hc2tEYXRhOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAobWFqb3JWZXJzaW9uID4gMSAmJiByZXN1bHQuZmlsZUluZm8ubWFzayAmJiByZXN1bHQuZmlsZUluZm8ubWFzay5udW1CeXRlcyA+IDApIHsKICAgICAgICAgICAgICAgIGJhbmRNYXNrcy5wdXNoKHJlc3VsdC5tYXNrRGF0YSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlQbGFuZSsrOwogICAgICAgICAgICAgIGRlY29kZWRQaXhlbEJsb2NrLnBpeGVscy5wdXNoKHJlc3VsdC5waXhlbERhdGEpOwogICAgICAgICAgICAgIGRlY29kZWRQaXhlbEJsb2NrLnN0YXRpc3RpY3MucHVzaCh7CiAgICAgICAgICAgICAgICBtaW5WYWx1ZTogcmVzdWx0Lm1pblZhbHVlLAogICAgICAgICAgICAgICAgbWF4VmFsdWU6IHJlc3VsdC5tYXhWYWx1ZSwKICAgICAgICAgICAgICAgIG5vRGF0YVZhbHVlOiByZXN1bHQubm9EYXRhVmFsdWUsCiAgICAgICAgICAgICAgICBkaW1TdGF0czogcmVzdWx0LmRpbVN0YXRzCiAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGkyLCBqMiwgbnVtUGl4ZWxzOwogICAgICAgICAgICBpZiAobWFqb3JWZXJzaW9uID4gMSAmJiBiYW5kTWFza3MubGVuZ3RoID4gMSkgewogICAgICAgICAgICAgIG51bVBpeGVscyA9IGRlY29kZWRQaXhlbEJsb2NrLndpZHRoICogZGVjb2RlZFBpeGVsQmxvY2suaGVpZ2h0OwogICAgICAgICAgICAgIGRlY29kZWRQaXhlbEJsb2NrLmJhbmRNYXNrcyA9IGJhbmRNYXNrczsKICAgICAgICAgICAgICBtYXNrRGF0YSA9IG5ldyBVaW50OEFycmF5KG51bVBpeGVscyk7CiAgICAgICAgICAgICAgbWFza0RhdGEuc2V0KGJhbmRNYXNrc1swXSk7CiAgICAgICAgICAgICAgZm9yIChpMiA9IDE7IGkyIDwgYmFuZE1hc2tzLmxlbmd0aDsgaTIrKykgewogICAgICAgICAgICAgICAgYmFuZE1hc2sgPSBiYW5kTWFza3NbaTJdOwogICAgICAgICAgICAgICAgZm9yIChqMiA9IDA7IGoyIDwgbnVtUGl4ZWxzOyBqMisrKSB7CiAgICAgICAgICAgICAgICAgIG1hc2tEYXRhW2oyXSA9IG1hc2tEYXRhW2oyXSAmIGJhbmRNYXNrW2oyXTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZGVjb2RlZFBpeGVsQmxvY2subWFza0RhdGEgPSBtYXNrRGF0YTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZGVjb2RlZFBpeGVsQmxvY2s7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBpZiAodHlwZW9mIGRlZmluZSA9PT0gImZ1bmN0aW9uIiAmJiBkZWZpbmUuYW1kKSB7CiAgICAgICAgICBkZWZpbmUoW10sIGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gTGVyYzI7CiAgICAgICAgICB9KTsKICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICJ1bmRlZmluZWQiICYmIG1vZHVsZS5leHBvcnRzKSB7CiAgICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IExlcmMyOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICB0aGlzLkxlcmMgPSBMZXJjMjsKICAgICAgICB9CiAgICAgIH0pKCk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXAuanMKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tSGVpZ2h0bWFwX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXBfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlVmVydGljZXNGcm9tSGVpZ2h0bWFwX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXAocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgaWYgKHBhcmFtZXRlcnMuZW5jb2RpbmcgPT09IEhlaWdodG1hcEVuY29kaW5nX2RlZmF1bHQuTEVSQykgewogICAgICBsZXQgcmVzdWx0OwogICAgICB0cnkgewogICAgICAgIHJlc3VsdCA9IGltcG9ydF9sZXJjLmRlZmF1bHQuZGVjb2RlKHBhcmFtZXRlcnMuaGVpZ2h0bWFwKTsKICAgICAgfSBjYXRjaCAoZXJyb3IpIHsKICAgICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoZXJyb3IpOwogICAgICB9CiAgICAgIGNvbnN0IGxlcmNTdGF0aXN0aWNzID0gcmVzdWx0LnN0YXRpc3RpY3NbMF07CiAgICAgIGlmIChsZXJjU3RhdGlzdGljcy5taW5WYWx1ZSA9PT0gTnVtYmVyLk1BWF9WQUxVRSkgewogICAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgiSW52YWxpZCB0aWxlIGRhdGEiKTsKICAgICAgfQogICAgICBwYXJhbWV0ZXJzLmhlaWdodG1hcCA9IHJlc3VsdC5waXhlbHNbMF07CiAgICAgIHBhcmFtZXRlcnMud2lkdGggPSByZXN1bHQud2lkdGg7CiAgICAgIHBhcmFtZXRlcnMuaGVpZ2h0ID0gcmVzdWx0LmhlaWdodDsKICAgIH0KICAgIHBhcmFtZXRlcnMuZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUocGFyYW1ldGVycy5lbGxpcHNvaWQpOwogICAgcGFyYW1ldGVycy5yZWN0YW5nbGUgPSBSZWN0YW5nbGVfZGVmYXVsdC5jbG9uZShwYXJhbWV0ZXJzLnJlY3RhbmdsZSk7CiAgICBjb25zdCBzdGF0aXN0aWNzMiA9IEhlaWdodG1hcFRlc3NlbGxhdG9yX2RlZmF1bHQuY29tcHV0ZVZlcnRpY2VzKHBhcmFtZXRlcnMpOwogICAgY29uc3QgdmVydGljZXMgPSBzdGF0aXN0aWNzMi52ZXJ0aWNlczsKICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaCh2ZXJ0aWNlcy5idWZmZXIpOwogICAgcmV0dXJuIHsKICAgICAgdmVydGljZXM6IHZlcnRpY2VzLmJ1ZmZlciwKICAgICAgbnVtYmVyT2ZBdHRyaWJ1dGVzOiBzdGF0aXN0aWNzMi5lbmNvZGluZy5zdHJpZGUsCiAgICAgIG1pbmltdW1IZWlnaHQ6IHN0YXRpc3RpY3MyLm1pbmltdW1IZWlnaHQsCiAgICAgIG1heGltdW1IZWlnaHQ6IHN0YXRpc3RpY3MyLm1heGltdW1IZWlnaHQsCiAgICAgIGdyaWRXaWR0aDogcGFyYW1ldGVycy53aWR0aCwKICAgICAgZ3JpZEhlaWdodDogcGFyYW1ldGVycy5oZWlnaHQsCiAgICAgIGJvdW5kaW5nU3BoZXJlM0Q6IHN0YXRpc3RpY3MyLmJvdW5kaW5nU3BoZXJlM0QsCiAgICAgIG9yaWVudGVkQm91bmRpbmdCb3g6IHN0YXRpc3RpY3MyLm9yaWVudGVkQm91bmRpbmdCb3gsCiAgICAgIG9jY2x1ZGVlUG9pbnRJblNjYWxlZFNwYWNlOiBzdGF0aXN0aWNzMi5vY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZSwKICAgICAgZW5jb2Rpbmc6IHN0YXRpc3RpY3MyLmVuY29kaW5nLAogICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aDogc3RhdGlzdGljczIud2VzdEluZGljZXNTb3V0aFRvTm9ydGgsCiAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3Q6IHN0YXRpc3RpY3MyLnNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgIGVhc3RJbmRpY2VzTm9ydGhUb1NvdXRoOiBzdGF0aXN0aWNzMi5lYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCwKICAgICAgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdDogc3RhdGlzdGljczIubm9ydGhJbmRpY2VzV2VzdFRvRWFzdAogICAgfTsKICB9CiAgdmFyIGltcG9ydF9sZXJjLCBjcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXBfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXAgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVZlcnRpY2VzRnJvbUhlaWdodG1hcC5qcyIoKSB7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfSGVpZ2h0bWFwRW5jb2RpbmcoKTsKICAgICAgaW5pdF9IZWlnaHRtYXBUZXNzZWxsYXRvcigpOwogICAgICBpbml0X1JlY3RhbmdsZSgpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBpbXBvcnRfbGVyYyA9IF9fdG9FU00ocmVxdWlyZV9MZXJjRGVjb2RlKCksIDEpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgY3JlYXRlVmVydGljZXNGcm9tSGVpZ2h0bWFwX2RlZmF1bHQgPSBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQoY3JlYXRlVmVydGljZXNGcm9tSGVpZ2h0bWFwKTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZVZlcnRpY2VzRnJvbVF1YW50aXplZFRlcnJhaW5NZXNoLmpzCiAgdmFyIGNyZWF0ZVZlcnRpY2VzRnJvbVF1YW50aXplZFRlcnJhaW5NZXNoX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaF9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBjcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaF9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2gocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgcXVhbnRpemVkVmVydGljZXMgPSBwYXJhbWV0ZXJzLnF1YW50aXplZFZlcnRpY2VzOwogICAgY29uc3QgcXVhbnRpemVkVmVydGV4Q291bnQgPSBxdWFudGl6ZWRWZXJ0aWNlcy5sZW5ndGggLyAzOwogICAgY29uc3Qgb2N0RW5jb2RlZE5vcm1hbHMgPSBwYXJhbWV0ZXJzLm9jdEVuY29kZWROb3JtYWxzOwogICAgY29uc3QgZWRnZVZlcnRleENvdW50ID0gcGFyYW1ldGVycy53ZXN0SW5kaWNlcy5sZW5ndGggKyBwYXJhbWV0ZXJzLmVhc3RJbmRpY2VzLmxlbmd0aCArIHBhcmFtZXRlcnMuc291dGhJbmRpY2VzLmxlbmd0aCArIHBhcmFtZXRlcnMubm9ydGhJbmRpY2VzLmxlbmd0aDsKICAgIGNvbnN0IGluY2x1ZGVXZWJNZXJjYXRvclQgPSBwYXJhbWV0ZXJzLmluY2x1ZGVXZWJNZXJjYXRvclQ7CiAgICBjb25zdCBleGFnZ2VyYXRpb24gPSBwYXJhbWV0ZXJzLmV4YWdnZXJhdGlvbjsKICAgIGNvbnN0IGV4YWdnZXJhdGlvblJlbGF0aXZlSGVpZ2h0ID0gcGFyYW1ldGVycy5leGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodDsKICAgIGNvbnN0IGhhc0V4YWdnZXJhdGlvbiA9IGV4YWdnZXJhdGlvbiAhPT0gMTsKICAgIGNvbnN0IGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID0gaGFzRXhhZ2dlcmF0aW9uOwogICAgY29uc3QgcmVjdGFuZ2xlID0gUmVjdGFuZ2xlX2RlZmF1bHQuY2xvbmUocGFyYW1ldGVycy5yZWN0YW5nbGUpOwogICAgY29uc3Qgd2VzdCA9IHJlY3RhbmdsZS53ZXN0OwogICAgY29uc3Qgc291dGggPSByZWN0YW5nbGUuc291dGg7CiAgICBjb25zdCBlYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICBjb25zdCBub3J0aCA9IHJlY3RhbmdsZS5ub3J0aDsKICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKHBhcmFtZXRlcnMuZWxsaXBzb2lkKTsKICAgIGNvbnN0IG1pbmltdW1IZWlnaHQgPSBwYXJhbWV0ZXJzLm1pbmltdW1IZWlnaHQ7CiAgICBjb25zdCBtYXhpbXVtSGVpZ2h0ID0gcGFyYW1ldGVycy5tYXhpbXVtSGVpZ2h0OwogICAgY29uc3QgY2VudGVyID0gcGFyYW1ldGVycy5yZWxhdGl2ZVRvQ2VudGVyOwogICAgY29uc3QgZnJvbUVOVSA9IFRyYW5zZm9ybXNfZGVmYXVsdC5lYXN0Tm9ydGhVcFRvRml4ZWRGcmFtZShjZW50ZXIsIGVsbGlwc29pZCk7CiAgICBjb25zdCB0b0VOVSA9IE1hdHJpeDRfZGVmYXVsdC5pbnZlcnNlVHJhbnNmb3JtYXRpb24oZnJvbUVOVSwgbmV3IE1hdHJpeDRfZGVmYXVsdCgpKTsKICAgIGxldCBzb3V0aE1lcmNhdG9yWTsKICAgIGxldCBvbmVPdmVyTWVyY2F0b3JIZWlnaHQ7CiAgICBpZiAoaW5jbHVkZVdlYk1lcmNhdG9yVCkgewogICAgICBzb3V0aE1lcmNhdG9yWSA9IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUoc291dGgpOwogICAgICBvbmVPdmVyTWVyY2F0b3JIZWlnaHQgPSAxIC8gKFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUobm9ydGgpIC0gc291dGhNZXJjYXRvclkpOwogICAgfQogICAgY29uc3QgdUJ1ZmZlciA9IHF1YW50aXplZFZlcnRpY2VzLnN1YmFycmF5KDAsIHF1YW50aXplZFZlcnRleENvdW50KTsKICAgIGNvbnN0IHZCdWZmZXIgPSBxdWFudGl6ZWRWZXJ0aWNlcy5zdWJhcnJheSgKICAgICAgcXVhbnRpemVkVmVydGV4Q291bnQsCiAgICAgIDIgKiBxdWFudGl6ZWRWZXJ0ZXhDb3VudAogICAgKTsKICAgIGNvbnN0IGhlaWdodEJ1ZmZlciA9IHF1YW50aXplZFZlcnRpY2VzLnN1YmFycmF5KAogICAgICBxdWFudGl6ZWRWZXJ0ZXhDb3VudCAqIDIsCiAgICAgIDMgKiBxdWFudGl6ZWRWZXJ0ZXhDb3VudAogICAgKTsKICAgIGNvbnN0IGhhc1ZlcnRleE5vcm1hbHMgPSBkZWZpbmVkX2RlZmF1bHQob2N0RW5jb2RlZE5vcm1hbHMpOwogICAgY29uc3QgdXZzID0gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KTsKICAgIGNvbnN0IGhlaWdodHMgPSBuZXcgQXJyYXkocXVhbnRpemVkVmVydGV4Q291bnQpOwogICAgY29uc3QgcG9zaXRpb25zID0gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KTsKICAgIGNvbnN0IHdlYk1lcmNhdG9yVHMgPSBpbmNsdWRlV2ViTWVyY2F0b3JUID8gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KSA6IFtdOwogICAgY29uc3QgZ2VvZGV0aWNTdXJmYWNlTm9ybWFscyA9IGluY2x1ZGVHZW9kZXRpY1N1cmZhY2VOb3JtYWxzID8gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KSA6IFtdOwogICAgY29uc3QgbWluaW11bSA9IHNjcmF0Y2hNaW5pbXVtOwogICAgbWluaW11bS54ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgbWluaW11bS55ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgbWluaW11bS56ID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgY29uc3QgbWF4aW11bSA9IHNjcmF0Y2hNYXhpbXVtOwogICAgbWF4aW11bS54ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbWF4aW11bS55ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbWF4aW11bS56ID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgbGV0IG1pbkxvbmdpdHVkZSA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgIGxldCBtYXhMb25naXR1ZGUgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBsZXQgbWluTGF0aXR1ZGUgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBsZXQgbWF4TGF0aXR1ZGUgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcXVhbnRpemVkVmVydGV4Q291bnQ7ICsraTIpIHsKICAgICAgY29uc3QgcmF3VSA9IHVCdWZmZXJbaTJdOwogICAgICBjb25zdCByYXdWID0gdkJ1ZmZlcltpMl07CiAgICAgIGNvbnN0IHU0ID0gcmF3VSAvIG1heFNob3J0NDsKICAgICAgY29uc3QgdjQgPSByYXdWIC8gbWF4U2hvcnQ0OwogICAgICBjb25zdCBoZWlnaHQgPSBNYXRoX2RlZmF1bHQubGVycCgKICAgICAgICBtaW5pbXVtSGVpZ2h0LAogICAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgICAgaGVpZ2h0QnVmZmVyW2kyXSAvIG1heFNob3J0NAogICAgICApOwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoLmxvbmdpdHVkZSA9IE1hdGhfZGVmYXVsdC5sZXJwKHdlc3QsIGVhc3QsIHU0KTsKICAgICAgY2FydG9ncmFwaGljU2NyYXRjaC5sYXRpdHVkZSA9IE1hdGhfZGVmYXVsdC5sZXJwKHNvdXRoLCBub3J0aCwgdjQpOwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoLmhlaWdodCA9IGhlaWdodDsKICAgICAgbWluTG9uZ2l0dWRlID0gTWF0aC5taW4oY2FydG9ncmFwaGljU2NyYXRjaC5sb25naXR1ZGUsIG1pbkxvbmdpdHVkZSk7CiAgICAgIG1heExvbmdpdHVkZSA9IE1hdGgubWF4KGNhcnRvZ3JhcGhpY1NjcmF0Y2gubG9uZ2l0dWRlLCBtYXhMb25naXR1ZGUpOwogICAgICBtaW5MYXRpdHVkZSA9IE1hdGgubWluKGNhcnRvZ3JhcGhpY1NjcmF0Y2gubGF0aXR1ZGUsIG1pbkxhdGl0dWRlKTsKICAgICAgbWF4TGF0aXR1ZGUgPSBNYXRoLm1heChjYXJ0b2dyYXBoaWNTY3JhdGNoLmxhdGl0dWRlLCBtYXhMYXRpdHVkZSk7CiAgICAgIGNvbnN0IHBvc2l0aW9uID0gZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGNhcnRvZ3JhcGhpY1NjcmF0Y2gpOwogICAgICB1dnNbaTJdID0gbmV3IENhcnRlc2lhbjJfZGVmYXVsdCh1NCwgdjQpOwogICAgICBoZWlnaHRzW2kyXSA9IGhlaWdodDsKICAgICAgcG9zaXRpb25zW2kyXSA9IHBvc2l0aW9uOwogICAgICBpZiAoaW5jbHVkZVdlYk1lcmNhdG9yVCkgewogICAgICAgIHdlYk1lcmNhdG9yVHNbaTJdID0gKFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0Lmdlb2RldGljTGF0aXR1ZGVUb01lcmNhdG9yQW5nbGUoCiAgICAgICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoLmxhdGl0dWRlCiAgICAgICAgKSAtIHNvdXRoTWVyY2F0b3JZKSAqIG9uZU92ZXJNZXJjYXRvckhlaWdodDsKICAgICAgfQogICAgICBpZiAoaW5jbHVkZUdlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWxzW2kyXSA9IGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwocG9zaXRpb24pOwogICAgICB9CiAgICAgIE1hdHJpeDRfZGVmYXVsdC5tdWx0aXBseUJ5UG9pbnQodG9FTlUsIHBvc2l0aW9uLCBjYXJ0ZXNpYW4zU2NyYXRjaDgpOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQubWluaW11bUJ5Q29tcG9uZW50KGNhcnRlc2lhbjNTY3JhdGNoOCwgbWluaW11bSwgbWluaW11bSk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQnlDb21wb25lbnQoY2FydGVzaWFuM1NjcmF0Y2g4LCBtYXhpbXVtLCBtYXhpbXVtKTsKICAgIH0KICAgIGNvbnN0IHdlc3RJbmRpY2VzU291dGhUb05vcnRoID0gY29weUFuZFNvcnQoCiAgICAgIHBhcmFtZXRlcnMud2VzdEluZGljZXMsCiAgICAgIGZ1bmN0aW9uKGE0LCBiMikgewogICAgICAgIHJldHVybiB1dnNbYTRdLnkgLSB1dnNbYjJdLnk7CiAgICAgIH0KICAgICk7CiAgICBjb25zdCBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCA9IGNvcHlBbmRTb3J0KAogICAgICBwYXJhbWV0ZXJzLmVhc3RJbmRpY2VzLAogICAgICBmdW5jdGlvbihhNCwgYjIpIHsKICAgICAgICByZXR1cm4gdXZzW2IyXS55IC0gdXZzW2E0XS55OwogICAgICB9CiAgICApOwogICAgY29uc3Qgc291dGhJbmRpY2VzRWFzdFRvV2VzdCA9IGNvcHlBbmRTb3J0KAogICAgICBwYXJhbWV0ZXJzLnNvdXRoSW5kaWNlcywKICAgICAgZnVuY3Rpb24oYTQsIGIyKSB7CiAgICAgICAgcmV0dXJuIHV2c1tiMl0ueCAtIHV2c1thNF0ueDsKICAgICAgfQogICAgKTsKICAgIGNvbnN0IG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QgPSBjb3B5QW5kU29ydCgKICAgICAgcGFyYW1ldGVycy5ub3J0aEluZGljZXMsCiAgICAgIGZ1bmN0aW9uKGE0LCBiMikgewogICAgICAgIHJldHVybiB1dnNbYTRdLnggLSB1dnNbYjJdLng7CiAgICAgIH0KICAgICk7CiAgICBsZXQgb2NjbHVkZWVQb2ludEluU2NhbGVkU3BhY2U7CiAgICBpZiAobWluaW11bUhlaWdodCA8IDApIHsKICAgICAgY29uc3Qgb2NjbHVkZXIgPSBuZXcgRWxsaXBzb2lkYWxPY2NsdWRlcl9kZWZhdWx0KGVsbGlwc29pZCk7CiAgICAgIG9jY2x1ZGVlUG9pbnRJblNjYWxlZFNwYWNlID0gb2NjbHVkZXIuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnRQb3NzaWJseVVuZGVyRWxsaXBzb2lkKAogICAgICAgIGNlbnRlciwKICAgICAgICBwb3NpdGlvbnMsCiAgICAgICAgbWluaW11bUhlaWdodAogICAgICApOwogICAgfQogICAgbGV0IGhNaW4gPSBtaW5pbXVtSGVpZ2h0OwogICAgaE1pbiA9IE1hdGgubWluKAogICAgICBoTWluLAogICAgICBmaW5kTWluTWF4U2tpcnRzKAogICAgICAgIHBhcmFtZXRlcnMud2VzdEluZGljZXMsCiAgICAgICAgcGFyYW1ldGVycy53ZXN0U2tpcnRIZWlnaHQsCiAgICAgICAgaGVpZ2h0cywKICAgICAgICB1dnMsCiAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICB0b0VOVSwKICAgICAgICBtaW5pbXVtLAogICAgICAgIG1heGltdW0KICAgICAgKQogICAgKTsKICAgIGhNaW4gPSBNYXRoLm1pbigKICAgICAgaE1pbiwKICAgICAgZmluZE1pbk1heFNraXJ0cygKICAgICAgICBwYXJhbWV0ZXJzLnNvdXRoSW5kaWNlcywKICAgICAgICBwYXJhbWV0ZXJzLnNvdXRoU2tpcnRIZWlnaHQsCiAgICAgICAgaGVpZ2h0cywKICAgICAgICB1dnMsCiAgICAgICAgcmVjdGFuZ2xlLAogICAgICAgIGVsbGlwc29pZCwKICAgICAgICB0b0VOVSwKICAgICAgICBtaW5pbXVtLAogICAgICAgIG1heGltdW0KICAgICAgKQogICAgKTsKICAgIGhNaW4gPSBNYXRoLm1pbigKICAgICAgaE1pbiwKICAgICAgZmluZE1pbk1heFNraXJ0cygKICAgICAgICBwYXJhbWV0ZXJzLmVhc3RJbmRpY2VzLAogICAgICAgIHBhcmFtZXRlcnMuZWFzdFNraXJ0SGVpZ2h0LAogICAgICAgIGhlaWdodHMsCiAgICAgICAgdXZzLAogICAgICAgIHJlY3RhbmdsZSwKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgdG9FTlUsCiAgICAgICAgbWluaW11bSwKICAgICAgICBtYXhpbXVtCiAgICAgICkKICAgICk7CiAgICBoTWluID0gTWF0aC5taW4oCiAgICAgIGhNaW4sCiAgICAgIGZpbmRNaW5NYXhTa2lydHMoCiAgICAgICAgcGFyYW1ldGVycy5ub3J0aEluZGljZXMsCiAgICAgICAgcGFyYW1ldGVycy5ub3J0aFNraXJ0SGVpZ2h0LAogICAgICAgIGhlaWdodHMsCiAgICAgICAgdXZzLAogICAgICAgIHJlY3RhbmdsZSwKICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgdG9FTlUsCiAgICAgICAgbWluaW11bSwKICAgICAgICBtYXhpbXVtCiAgICAgICkKICAgICk7CiAgICBjb25zdCBhYUJveCA9IG5ldyBBeGlzQWxpZ25lZEJvdW5kaW5nQm94X2RlZmF1bHQobWluaW11bSwgbWF4aW11bSwgY2VudGVyKTsKICAgIGNvbnN0IGVuY29kaW5nID0gbmV3IFRlcnJhaW5FbmNvZGluZ19kZWZhdWx0KAogICAgICBjZW50ZXIsCiAgICAgIGFhQm94LAogICAgICBoTWluLAogICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICBmcm9tRU5VLAogICAgICBoYXNWZXJ0ZXhOb3JtYWxzLAogICAgICBpbmNsdWRlV2ViTWVyY2F0b3JULAogICAgICBpbmNsdWRlR2VvZGV0aWNTdXJmYWNlTm9ybWFscywKICAgICAgZXhhZ2dlcmF0aW9uLAogICAgICBleGFnZ2VyYXRpb25SZWxhdGl2ZUhlaWdodAogICAgKTsKICAgIGNvbnN0IHZlcnRleFN0cmlkZSA9IGVuY29kaW5nLnN0cmlkZTsKICAgIGNvbnN0IHNpemUgPSBxdWFudGl6ZWRWZXJ0ZXhDb3VudCAqIHZlcnRleFN0cmlkZSArIGVkZ2VWZXJ0ZXhDb3VudCAqIHZlcnRleFN0cmlkZTsKICAgIGNvbnN0IHZlcnRleEJ1ZmZlciA9IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSk7CiAgICBsZXQgYnVmZmVySW5kZXggPSAwOwogICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IHF1YW50aXplZFZlcnRleENvdW50OyArK2oyKSB7CiAgICAgIGlmIChoYXNWZXJ0ZXhOb3JtYWxzKSB7CiAgICAgICAgY29uc3QgbjIgPSBqMiAqIDI7CiAgICAgICAgdG9QYWNrLnggPSBvY3RFbmNvZGVkTm9ybWFsc1tuMl07CiAgICAgICAgdG9QYWNrLnkgPSBvY3RFbmNvZGVkTm9ybWFsc1tuMiArIDFdOwogICAgICB9CiAgICAgIGJ1ZmZlckluZGV4ID0gZW5jb2RpbmcuZW5jb2RlKAogICAgICAgIHZlcnRleEJ1ZmZlciwKICAgICAgICBidWZmZXJJbmRleCwKICAgICAgICBwb3NpdGlvbnNbajJdLAogICAgICAgIHV2c1tqMl0sCiAgICAgICAgaGVpZ2h0c1tqMl0sCiAgICAgICAgdG9QYWNrLAogICAgICAgIHdlYk1lcmNhdG9yVHNbajJdLAogICAgICAgIGdlb2RldGljU3VyZmFjZU5vcm1hbHNbajJdCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBlZGdlVHJpYW5nbGVDb3VudCA9IE1hdGgubWF4KDAsIChlZGdlVmVydGV4Q291bnQgLSA0KSAqIDIpOwogICAgY29uc3QgaW5kZXhCdWZmZXJMZW5ndGggPSBwYXJhbWV0ZXJzLmluZGljZXMubGVuZ3RoICsgZWRnZVRyaWFuZ2xlQ291bnQgKiAzOwogICAgY29uc3QgaW5kZXhCdWZmZXIgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgcXVhbnRpemVkVmVydGV4Q291bnQgKyBlZGdlVmVydGV4Q291bnQsCiAgICAgIGluZGV4QnVmZmVyTGVuZ3RoCiAgICApOwogICAgaW5kZXhCdWZmZXIuc2V0KHBhcmFtZXRlcnMuaW5kaWNlcywgMCk7CiAgICBjb25zdCBwZXJjZW50YWdlID0gMWUtNDsKICAgIGNvbnN0IGxvbk9mZnNldCA9IChtYXhMb25naXR1ZGUgLSBtaW5Mb25naXR1ZGUpICogcGVyY2VudGFnZTsKICAgIGNvbnN0IGxhdE9mZnNldCA9IChtYXhMYXRpdHVkZSAtIG1pbkxhdGl0dWRlKSAqIHBlcmNlbnRhZ2U7CiAgICBjb25zdCB3ZXN0TG9uZ2l0dWRlT2Zmc2V0ID0gLWxvbk9mZnNldDsKICAgIGNvbnN0IHdlc3RMYXRpdHVkZU9mZnNldCA9IDA7CiAgICBjb25zdCBlYXN0TG9uZ2l0dWRlT2Zmc2V0ID0gbG9uT2Zmc2V0OwogICAgY29uc3QgZWFzdExhdGl0dWRlT2Zmc2V0ID0gMDsKICAgIGNvbnN0IG5vcnRoTG9uZ2l0dWRlT2Zmc2V0ID0gMDsKICAgIGNvbnN0IG5vcnRoTGF0aXR1ZGVPZmZzZXQgPSBsYXRPZmZzZXQ7CiAgICBjb25zdCBzb3V0aExvbmdpdHVkZU9mZnNldCA9IDA7CiAgICBjb25zdCBzb3V0aExhdGl0dWRlT2Zmc2V0ID0gLWxhdE9mZnNldDsKICAgIGxldCB2ZXJ0ZXhCdWZmZXJJbmRleCA9IHF1YW50aXplZFZlcnRleENvdW50ICogdmVydGV4U3RyaWRlOwogICAgYWRkU2tpcnQyKAogICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgIHZlcnRleEJ1ZmZlckluZGV4LAogICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwKICAgICAgZW5jb2RpbmcsCiAgICAgIGhlaWdodHMsCiAgICAgIHV2cywKICAgICAgb2N0RW5jb2RlZE5vcm1hbHMsCiAgICAgIGVsbGlwc29pZCwKICAgICAgcmVjdGFuZ2xlLAogICAgICBwYXJhbWV0ZXJzLndlc3RTa2lydEhlaWdodCwKICAgICAgc291dGhNZXJjYXRvclksCiAgICAgIG9uZU92ZXJNZXJjYXRvckhlaWdodCwKICAgICAgd2VzdExvbmdpdHVkZU9mZnNldCwKICAgICAgd2VzdExhdGl0dWRlT2Zmc2V0CiAgICApOwogICAgdmVydGV4QnVmZmVySW5kZXggKz0gcGFyYW1ldGVycy53ZXN0SW5kaWNlcy5sZW5ndGggKiB2ZXJ0ZXhTdHJpZGU7CiAgICBhZGRTa2lydDIoCiAgICAgIHZlcnRleEJ1ZmZlciwKICAgICAgdmVydGV4QnVmZmVySW5kZXgsCiAgICAgIHNvdXRoSW5kaWNlc0Vhc3RUb1dlc3QsCiAgICAgIGVuY29kaW5nLAogICAgICBoZWlnaHRzLAogICAgICB1dnMsCiAgICAgIG9jdEVuY29kZWROb3JtYWxzLAogICAgICBlbGxpcHNvaWQsCiAgICAgIHJlY3RhbmdsZSwKICAgICAgcGFyYW1ldGVycy5zb3V0aFNraXJ0SGVpZ2h0LAogICAgICBzb3V0aE1lcmNhdG9yWSwKICAgICAgb25lT3Zlck1lcmNhdG9ySGVpZ2h0LAogICAgICBzb3V0aExvbmdpdHVkZU9mZnNldCwKICAgICAgc291dGhMYXRpdHVkZU9mZnNldAogICAgKTsKICAgIHZlcnRleEJ1ZmZlckluZGV4ICs9IHBhcmFtZXRlcnMuc291dGhJbmRpY2VzLmxlbmd0aCAqIHZlcnRleFN0cmlkZTsKICAgIGFkZFNraXJ0MigKICAgICAgdmVydGV4QnVmZmVyLAogICAgICB2ZXJ0ZXhCdWZmZXJJbmRleCwKICAgICAgZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgIGVuY29kaW5nLAogICAgICBoZWlnaHRzLAogICAgICB1dnMsCiAgICAgIG9jdEVuY29kZWROb3JtYWxzLAogICAgICBlbGxpcHNvaWQsCiAgICAgIHJlY3RhbmdsZSwKICAgICAgcGFyYW1ldGVycy5lYXN0U2tpcnRIZWlnaHQsCiAgICAgIHNvdXRoTWVyY2F0b3JZLAogICAgICBvbmVPdmVyTWVyY2F0b3JIZWlnaHQsCiAgICAgIGVhc3RMb25naXR1ZGVPZmZzZXQsCiAgICAgIGVhc3RMYXRpdHVkZU9mZnNldAogICAgKTsKICAgIHZlcnRleEJ1ZmZlckluZGV4ICs9IHBhcmFtZXRlcnMuZWFzdEluZGljZXMubGVuZ3RoICogdmVydGV4U3RyaWRlOwogICAgYWRkU2tpcnQyKAogICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgIHZlcnRleEJ1ZmZlckluZGV4LAogICAgICBub3J0aEluZGljZXNXZXN0VG9FYXN0LAogICAgICBlbmNvZGluZywKICAgICAgaGVpZ2h0cywKICAgICAgdXZzLAogICAgICBvY3RFbmNvZGVkTm9ybWFscywKICAgICAgZWxsaXBzb2lkLAogICAgICByZWN0YW5nbGUsCiAgICAgIHBhcmFtZXRlcnMubm9ydGhTa2lydEhlaWdodCwKICAgICAgc291dGhNZXJjYXRvclksCiAgICAgIG9uZU92ZXJNZXJjYXRvckhlaWdodCwKICAgICAgbm9ydGhMb25naXR1ZGVPZmZzZXQsCiAgICAgIG5vcnRoTGF0aXR1ZGVPZmZzZXQKICAgICk7CiAgICBUZXJyYWluUHJvdmlkZXJfZGVmYXVsdC5hZGRTa2lydEluZGljZXMoCiAgICAgIHdlc3RJbmRpY2VzU291dGhUb05vcnRoLAogICAgICBzb3V0aEluZGljZXNFYXN0VG9XZXN0LAogICAgICBlYXN0SW5kaWNlc05vcnRoVG9Tb3V0aCwKICAgICAgbm9ydGhJbmRpY2VzV2VzdFRvRWFzdCwKICAgICAgcXVhbnRpemVkVmVydGV4Q291bnQsCiAgICAgIGluZGV4QnVmZmVyLAogICAgICBwYXJhbWV0ZXJzLmluZGljZXMubGVuZ3RoCiAgICApOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKHZlcnRleEJ1ZmZlci5idWZmZXIsIGluZGV4QnVmZmVyLmJ1ZmZlcik7CiAgICByZXR1cm4gewogICAgICB2ZXJ0aWNlczogdmVydGV4QnVmZmVyLmJ1ZmZlciwKICAgICAgaW5kaWNlczogaW5kZXhCdWZmZXIuYnVmZmVyLAogICAgICB3ZXN0SW5kaWNlc1NvdXRoVG9Ob3J0aCwKICAgICAgc291dGhJbmRpY2VzRWFzdFRvV2VzdCwKICAgICAgZWFzdEluZGljZXNOb3J0aFRvU291dGgsCiAgICAgIG5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QsCiAgICAgIHZlcnRleFN0cmlkZSwKICAgICAgY2VudGVyLAogICAgICBtaW5pbXVtSGVpZ2h0LAogICAgICBtYXhpbXVtSGVpZ2h0LAogICAgICBvY2NsdWRlZVBvaW50SW5TY2FsZWRTcGFjZSwKICAgICAgZW5jb2RpbmcsCiAgICAgIGluZGV4Q291bnRXaXRob3V0U2tpcnRzOiBwYXJhbWV0ZXJzLmluZGljZXMubGVuZ3RoCiAgICB9OwogIH0KICBmdW5jdGlvbiBmaW5kTWluTWF4U2tpcnRzKGVkZ2VJbmRpY2VzLCBlZGdlSGVpZ2h0LCBoZWlnaHRzLCB1dnMsIHJlY3RhbmdsZSwgZWxsaXBzb2lkLCB0b0VOVSwgbWluaW11bSwgbWF4aW11bSkgewogICAgbGV0IGhNaW4gPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBjb25zdCBub3J0aCA9IHJlY3RhbmdsZS5ub3J0aDsKICAgIGNvbnN0IHNvdXRoID0gcmVjdGFuZ2xlLnNvdXRoOwogICAgbGV0IGVhc3QgPSByZWN0YW5nbGUuZWFzdDsKICAgIGNvbnN0IHdlc3QgPSByZWN0YW5nbGUud2VzdDsKICAgIGlmIChlYXN0IDwgd2VzdCkgewogICAgICBlYXN0ICs9IE1hdGhfZGVmYXVsdC5UV09fUEk7CiAgICB9CiAgICBjb25zdCBsZW5ndGggPSBlZGdlSW5kaWNlcy5sZW5ndGg7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgIGNvbnN0IGluZGV4ID0gZWRnZUluZGljZXNbaTJdOwogICAgICBjb25zdCBoMiA9IGhlaWdodHNbaW5kZXhdOwogICAgICBjb25zdCB1diA9IHV2c1tpbmRleF07CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gubG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0LmxlcnAod2VzdCwgZWFzdCwgdXYueCk7CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gubGF0aXR1ZGUgPSBNYXRoX2RlZmF1bHQubGVycChzb3V0aCwgbm9ydGgsIHV2LnkpOwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoLmhlaWdodCA9IGgyIC0gZWRnZUhlaWdodDsKICAgICAgY29uc3QgcG9zaXRpb24gPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgY2FydG9ncmFwaGljU2NyYXRjaCwKICAgICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDgKICAgICAgKTsKICAgICAgTWF0cml4NF9kZWZhdWx0Lm11bHRpcGx5QnlQb2ludCh0b0VOVSwgcG9zaXRpb24sIHBvc2l0aW9uKTsKICAgICAgQ2FydGVzaWFuM19kZWZhdWx0Lm1pbmltdW1CeUNvbXBvbmVudChwb3NpdGlvbiwgbWluaW11bSwgbWluaW11bSk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5tYXhpbXVtQnlDb21wb25lbnQocG9zaXRpb24sIG1heGltdW0sIG1heGltdW0pOwogICAgICBoTWluID0gTWF0aC5taW4oaE1pbiwgY2FydG9ncmFwaGljU2NyYXRjaC5oZWlnaHQpOwogICAgfQogICAgcmV0dXJuIGhNaW47CiAgfQogIGZ1bmN0aW9uIGFkZFNraXJ0Mih2ZXJ0ZXhCdWZmZXIsIHZlcnRleEJ1ZmZlckluZGV4LCBlZGdlVmVydGljZXMsIGVuY29kaW5nLCBoZWlnaHRzLCB1dnMsIG9jdEVuY29kZWROb3JtYWxzLCBlbGxpcHNvaWQsIHJlY3RhbmdsZSwgc2tpcnRMZW5ndGgsIHNvdXRoTWVyY2F0b3JZLCBvbmVPdmVyTWVyY2F0b3JIZWlnaHQsIGxvbmdpdHVkZU9mZnNldCwgbGF0aXR1ZGVPZmZzZXQpIHsKICAgIGNvbnN0IGhhc1ZlcnRleE5vcm1hbHMgPSBkZWZpbmVkX2RlZmF1bHQob2N0RW5jb2RlZE5vcm1hbHMpOwogICAgY29uc3Qgbm9ydGggPSByZWN0YW5nbGUubm9ydGg7CiAgICBjb25zdCBzb3V0aCA9IHJlY3RhbmdsZS5zb3V0aDsKICAgIGxldCBlYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICBjb25zdCB3ZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICBpZiAoZWFzdCA8IHdlc3QpIHsKICAgICAgZWFzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgfQogICAgY29uc3QgbGVuZ3RoID0gZWRnZVZlcnRpY2VzLmxlbmd0aDsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgY29uc3QgaW5kZXggPSBlZGdlVmVydGljZXNbaTJdOwogICAgICBjb25zdCBoMiA9IGhlaWdodHNbaW5kZXhdOwogICAgICBjb25zdCB1diA9IHV2c1tpbmRleF07CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gubG9uZ2l0dWRlID0gTWF0aF9kZWZhdWx0LmxlcnAod2VzdCwgZWFzdCwgdXYueCkgKyBsb25naXR1ZGVPZmZzZXQ7CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gubGF0aXR1ZGUgPSBNYXRoX2RlZmF1bHQubGVycChzb3V0aCwgbm9ydGgsIHV2LnkpICsgbGF0aXR1ZGVPZmZzZXQ7CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2guaGVpZ2h0ID0gaDIgLSBza2lydExlbmd0aDsKICAgICAgY29uc3QgcG9zaXRpb24gPSBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oCiAgICAgICAgY2FydG9ncmFwaGljU2NyYXRjaCwKICAgICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDgKICAgICAgKTsKICAgICAgaWYgKGhhc1ZlcnRleE5vcm1hbHMpIHsKICAgICAgICBjb25zdCBuMiA9IGluZGV4ICogMjsKICAgICAgICB0b1BhY2sueCA9IG9jdEVuY29kZWROb3JtYWxzW24yXTsKICAgICAgICB0b1BhY2sueSA9IG9jdEVuY29kZWROb3JtYWxzW24yICsgMV07CiAgICAgIH0KICAgICAgbGV0IHdlYk1lcmNhdG9yVDsKICAgICAgaWYgKGVuY29kaW5nLmhhc1dlYk1lcmNhdG9yVCkgewogICAgICAgIHdlYk1lcmNhdG9yVCA9IChXZWJNZXJjYXRvclByb2plY3Rpb25fZGVmYXVsdC5nZW9kZXRpY0xhdGl0dWRlVG9NZXJjYXRvckFuZ2xlKAogICAgICAgICAgY2FydG9ncmFwaGljU2NyYXRjaC5sYXRpdHVkZQogICAgICAgICkgLSBzb3V0aE1lcmNhdG9yWSkgKiBvbmVPdmVyTWVyY2F0b3JIZWlnaHQ7CiAgICAgIH0KICAgICAgbGV0IGdlb2RldGljU3VyZmFjZU5vcm1hbDsKICAgICAgaWYgKGVuY29kaW5nLmhhc0dlb2RldGljU3VyZmFjZU5vcm1hbHMpIHsKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWwgPSBlbGxpcHNvaWQuZ2VvZGV0aWNTdXJmYWNlTm9ybWFsKHBvc2l0aW9uKTsKICAgICAgfQogICAgICB2ZXJ0ZXhCdWZmZXJJbmRleCA9IGVuY29kaW5nLmVuY29kZSgKICAgICAgICB2ZXJ0ZXhCdWZmZXIsCiAgICAgICAgdmVydGV4QnVmZmVySW5kZXgsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgdXYsCiAgICAgICAgY2FydG9ncmFwaGljU2NyYXRjaC5oZWlnaHQsCiAgICAgICAgdG9QYWNrLAogICAgICAgIHdlYk1lcmNhdG9yVCwKICAgICAgICBnZW9kZXRpY1N1cmZhY2VOb3JtYWwKICAgICAgKTsKICAgIH0KICB9CiAgZnVuY3Rpb24gY29weUFuZFNvcnQodHlwZWRBcnJheSwgY29tcGFyYXRvcikgewogICAgbGV0IGNvcHk7CiAgICBpZiAodHlwZW9mIHR5cGVkQXJyYXkuc2xpY2UgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgY29weSA9IHR5cGVkQXJyYXkuc2xpY2UoKTsKICAgICAgaWYgKHR5cGVvZiBjb3B5LnNvcnQgIT09ICJmdW5jdGlvbiIpIHsKICAgICAgICBjb3B5ID0gdm9pZCAwOwogICAgICB9CiAgICB9CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChjb3B5KSkgewogICAgICBjb3B5ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodHlwZWRBcnJheSk7CiAgICB9CiAgICBjb3B5LnNvcnQoY29tcGFyYXRvcik7CiAgICByZXR1cm4gY29weTsKICB9CiAgdmFyIG1heFNob3J0NCwgY2FydGVzaWFuM1NjcmF0Y2g4LCBzY3JhdGNoTWluaW11bSwgc2NyYXRjaE1heGltdW0sIGNhcnRvZ3JhcGhpY1NjcmF0Y2gsIHRvUGFjaywgY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2hfZGVmYXVsdDsKICB2YXIgaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2guanMiKCkgewogICAgICBpbml0X0F4aXNBbGlnbmVkQm91bmRpbmdCb3goKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NhcnRvZ3JhcGhpYygpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9FbGxpcHNvaWRhbE9jY2x1ZGVyKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X01hdGgoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfUmVjdGFuZ2xlKCk7CiAgICAgIGluaXRfVGVycmFpbkVuY29kaW5nKCk7CiAgICAgIGluaXRfVGVycmFpblByb3ZpZGVyKCk7CiAgICAgIGluaXRfVHJhbnNmb3JtcygpOwogICAgICBpbml0X1dlYk1lcmNhdG9yUHJvamVjdGlvbigpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgbWF4U2hvcnQ0ID0gMzI3Njc7CiAgICAgIGNhcnRlc2lhbjNTY3JhdGNoOCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaE1pbmltdW0gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hNYXhpbXVtID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHRvUGFjayA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2hfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdCgKICAgICAgICBjcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaAogICAgICApOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvV2FsbEdlb21ldHJ5TGlicmFyeS5qcwogIGZ1bmN0aW9uIGxhdExvbkVxdWFscyhjMCwgYzEpIHsKICAgIHJldHVybiBNYXRoX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihjMC5sYXRpdHVkZSwgYzEubGF0aXR1ZGUsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApICYmIE1hdGhfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKGMwLmxvbmdpdHVkZSwgYzEubG9uZ2l0dWRlLCBNYXRoX2RlZmF1bHQuRVBTSUxPTjEwKTsKICB9CiAgZnVuY3Rpb24gcmVtb3ZlRHVwbGljYXRlczIoZWxsaXBzb2lkLCBwb3NpdGlvbnMsIHRvcEhlaWdodHMsIGJvdHRvbUhlaWdodHMpIHsKICAgIHBvc2l0aW9ucyA9IGFycmF5UmVtb3ZlRHVwbGljYXRlc19kZWZhdWx0KHBvc2l0aW9ucywgQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24pOwogICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgIGlmIChsZW5ndGggPCAyKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNvbnN0IGhhc0JvdHRvbUhlaWdodHMgPSBkZWZpbmVkX2RlZmF1bHQoYm90dG9tSGVpZ2h0cyk7CiAgICBjb25zdCBoYXNUb3BIZWlnaHRzID0gZGVmaW5lZF9kZWZhdWx0KHRvcEhlaWdodHMpOwogICAgY29uc3QgY2xlYW5lZFBvc2l0aW9ucyA9IG5ldyBBcnJheShsZW5ndGgpOwogICAgY29uc3QgY2xlYW5lZFRvcEhlaWdodHMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgIGNvbnN0IGNsZWFuZWRCb3R0b21IZWlnaHRzID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICBjb25zdCB2MDIgPSBwb3NpdGlvbnNbMF07CiAgICBjbGVhbmVkUG9zaXRpb25zWzBdID0gdjAyOwogICAgY29uc3QgYzAgPSBlbGxpcHNvaWQuY2FydGVzaWFuVG9DYXJ0b2dyYXBoaWModjAyLCBzY3JhdGNoQ2FydG9ncmFwaGljMTMpOwogICAgaWYgKGhhc1RvcEhlaWdodHMpIHsKICAgICAgYzAuaGVpZ2h0ID0gdG9wSGVpZ2h0c1swXTsKICAgIH0KICAgIGNsZWFuZWRUb3BIZWlnaHRzWzBdID0gYzAuaGVpZ2h0OwogICAgaWYgKGhhc0JvdHRvbUhlaWdodHMpIHsKICAgICAgY2xlYW5lZEJvdHRvbUhlaWdodHNbMF0gPSBib3R0b21IZWlnaHRzWzBdOwogICAgfSBlbHNlIHsKICAgICAgY2xlYW5lZEJvdHRvbUhlaWdodHNbMF0gPSAwOwogICAgfQogICAgY29uc3Qgc3RhcnRUb3BIZWlnaHQgPSBjbGVhbmVkVG9wSGVpZ2h0c1swXTsKICAgIGNvbnN0IHN0YXJ0Qm90dG9tSGVpZ2h0ID0gY2xlYW5lZEJvdHRvbUhlaWdodHNbMF07CiAgICBsZXQgaGFzQWxsU2FtZUhlaWdodHMgPSBzdGFydFRvcEhlaWdodCA9PT0gc3RhcnRCb3R0b21IZWlnaHQ7CiAgICBsZXQgaW5kZXggPSAxOwogICAgZm9yIChsZXQgaTIgPSAxOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICBjb25zdCB2MTIgPSBwb3NpdGlvbnNbaTJdOwogICAgICBjb25zdCBjMSA9IGVsbGlwc29pZC5jYXJ0ZXNpYW5Ub0NhcnRvZ3JhcGhpYyh2MTIsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMyMyk7CiAgICAgIGlmIChoYXNUb3BIZWlnaHRzKSB7CiAgICAgICAgYzEuaGVpZ2h0ID0gdG9wSGVpZ2h0c1tpMl07CiAgICAgIH0KICAgICAgaGFzQWxsU2FtZUhlaWdodHMgPSBoYXNBbGxTYW1lSGVpZ2h0cyAmJiBjMS5oZWlnaHQgPT09IDA7CiAgICAgIGlmICghbGF0TG9uRXF1YWxzKGMwLCBjMSkpIHsKICAgICAgICBjbGVhbmVkUG9zaXRpb25zW2luZGV4XSA9IHYxMjsKICAgICAgICBjbGVhbmVkVG9wSGVpZ2h0c1tpbmRleF0gPSBjMS5oZWlnaHQ7CiAgICAgICAgaWYgKGhhc0JvdHRvbUhlaWdodHMpIHsKICAgICAgICAgIGNsZWFuZWRCb3R0b21IZWlnaHRzW2luZGV4XSA9IGJvdHRvbUhlaWdodHNbaTJdOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjbGVhbmVkQm90dG9tSGVpZ2h0c1tpbmRleF0gPSAwOwogICAgICAgIH0KICAgICAgICBoYXNBbGxTYW1lSGVpZ2h0cyA9IGhhc0FsbFNhbWVIZWlnaHRzICYmIGNsZWFuZWRUb3BIZWlnaHRzW2luZGV4XSA9PT0gY2xlYW5lZEJvdHRvbUhlaWdodHNbaW5kZXhdOwogICAgICAgIENhcnRvZ3JhcGhpY19kZWZhdWx0LmNsb25lKGMxLCBjMCk7CiAgICAgICAgKytpbmRleDsKICAgICAgfSBlbHNlIGlmIChjMC5oZWlnaHQgPCBjMS5oZWlnaHQpIHsKICAgICAgICBjbGVhbmVkVG9wSGVpZ2h0c1tpbmRleCAtIDFdID0gYzEuaGVpZ2h0OwogICAgICB9CiAgICB9CiAgICBpZiAoaGFzQWxsU2FtZUhlaWdodHMgfHwgaW5kZXggPCAyKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNsZWFuZWRQb3NpdGlvbnMubGVuZ3RoID0gaW5kZXg7CiAgICBjbGVhbmVkVG9wSGVpZ2h0cy5sZW5ndGggPSBpbmRleDsKICAgIGNsZWFuZWRCb3R0b21IZWlnaHRzLmxlbmd0aCA9IGluZGV4OwogICAgcmV0dXJuIHsKICAgICAgcG9zaXRpb25zOiBjbGVhbmVkUG9zaXRpb25zLAogICAgICB0b3BIZWlnaHRzOiBjbGVhbmVkVG9wSGVpZ2h0cywKICAgICAgYm90dG9tSGVpZ2h0czogY2xlYW5lZEJvdHRvbUhlaWdodHMKICAgIH07CiAgfQogIHZhciBXYWxsR2VvbWV0cnlMaWJyYXJ5LCBzY3JhdGNoQ2FydG9ncmFwaGljMTMsIHNjcmF0Y2hDYXJ0b2dyYXBoaWMyMywgcG9zaXRpb25zQXJyYXlTY3JhdGNoLCBoZWlnaHRzQXJyYXlTY3JhdGNoLCBnZW5lcmF0ZUFyY09wdGlvbnNTY3JhdGNoMiwgV2FsbEdlb21ldHJ5TGlicmFyeV9kZWZhdWx0OwogIHZhciBpbml0X1dhbGxHZW9tZXRyeUxpYnJhcnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1dhbGxHZW9tZXRyeUxpYnJhcnkuanMiKCkgewogICAgICBpbml0X2FycmF5UmVtb3ZlRHVwbGljYXRlcygpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1BvbHlsaW5lUGlwZWxpbmUoKTsKICAgICAgV2FsbEdlb21ldHJ5TGlicmFyeSA9IHt9OwogICAgICBzY3JhdGNoQ2FydG9ncmFwaGljMTMgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRvZ3JhcGhpYzIzID0gbmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KCk7CiAgICAgIHBvc2l0aW9uc0FycmF5U2NyYXRjaCA9IG5ldyBBcnJheSgyKTsKICAgICAgaGVpZ2h0c0FycmF5U2NyYXRjaCA9IG5ldyBBcnJheSgyKTsKICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zU2NyYXRjaDIgPSB7CiAgICAgICAgcG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgaGVpZ2h0OiB2b2lkIDAsCiAgICAgICAgZ3JhbnVsYXJpdHk6IHZvaWQgMCwKICAgICAgICBlbGxpcHNvaWQ6IHZvaWQgMAogICAgICB9OwogICAgICBXYWxsR2VvbWV0cnlMaWJyYXJ5LmNvbXB1dGVQb3NpdGlvbnMgPSBmdW5jdGlvbihlbGxpcHNvaWQsIHdhbGxQb3NpdGlvbnMsIG1heGltdW1IZWlnaHRzLCBtaW5pbXVtSGVpZ2h0cywgZ3JhbnVsYXJpdHksIGR1cGxpY2F0ZUNvcm5lcnMpIHsKICAgICAgICBjb25zdCBvMiA9IHJlbW92ZUR1cGxpY2F0ZXMyKAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgd2FsbFBvc2l0aW9ucywKICAgICAgICAgIG1heGltdW1IZWlnaHRzLAogICAgICAgICAgbWluaW11bUhlaWdodHMKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG8yKSkgewogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICB3YWxsUG9zaXRpb25zID0gbzIucG9zaXRpb25zOwogICAgICAgIG1heGltdW1IZWlnaHRzID0gbzIudG9wSGVpZ2h0czsKICAgICAgICBtaW5pbXVtSGVpZ2h0cyA9IG8yLmJvdHRvbUhlaWdodHM7CiAgICAgICAgY29uc3QgbGVuZ3RoID0gd2FsbFBvc2l0aW9ucy5sZW5ndGg7CiAgICAgICAgY29uc3QgbnVtQ29ybmVycyA9IGxlbmd0aCAtIDI7CiAgICAgICAgbGV0IHRvcFBvc2l0aW9uczsKICAgICAgICBsZXQgYm90dG9tUG9zaXRpb25zOwogICAgICAgIGNvbnN0IG1pbkRpc3RhbmNlID0gTWF0aF9kZWZhdWx0LmNob3JkTGVuZ3RoKAogICAgICAgICAgZ3JhbnVsYXJpdHksCiAgICAgICAgICBlbGxpcHNvaWQubWF4aW11bVJhZGl1cwogICAgICAgICk7CiAgICAgICAgY29uc3QgZ2VuZXJhdGVBcmNPcHRpb25zID0gZ2VuZXJhdGVBcmNPcHRpb25zU2NyYXRjaDI7CiAgICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zLm1pbkRpc3RhbmNlID0gbWluRGlzdGFuY2U7CiAgICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zLmVsbGlwc29pZCA9IGVsbGlwc29pZDsKICAgICAgICBpZiAoZHVwbGljYXRlQ29ybmVycykgewogICAgICAgICAgbGV0IGNvdW50ID0gMDsKICAgICAgICAgIGxldCBpMjsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgICAgICAgY291bnQgKz0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0Lm51bWJlck9mUG9pbnRzKAogICAgICAgICAgICAgIHdhbGxQb3NpdGlvbnNbaTJdLAogICAgICAgICAgICAgIHdhbGxQb3NpdGlvbnNbaTIgKyAxXSwKICAgICAgICAgICAgICBtaW5EaXN0YW5jZQogICAgICAgICAgICApICsgMTsKICAgICAgICAgIH0KICAgICAgICAgIHRvcFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoY291bnQgKiAzKTsKICAgICAgICAgIGJvdHRvbVBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoY291bnQgKiAzKTsKICAgICAgICAgIGNvbnN0IGdlbmVyYXRlQXJjUG9zaXRpb25zID0gcG9zaXRpb25zQXJyYXlTY3JhdGNoOwogICAgICAgICAgY29uc3QgZ2VuZXJhdGVBcmNIZWlnaHRzID0gaGVpZ2h0c0FycmF5U2NyYXRjaDsKICAgICAgICAgIGdlbmVyYXRlQXJjT3B0aW9ucy5wb3NpdGlvbnMgPSBnZW5lcmF0ZUFyY1Bvc2l0aW9uczsKICAgICAgICAgIGdlbmVyYXRlQXJjT3B0aW9ucy5oZWlnaHQgPSBnZW5lcmF0ZUFyY0hlaWdodHM7CiAgICAgICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aCAtIDE7IGkyKyspIHsKICAgICAgICAgICAgZ2VuZXJhdGVBcmNQb3NpdGlvbnNbMF0gPSB3YWxsUG9zaXRpb25zW2kyXTsKICAgICAgICAgICAgZ2VuZXJhdGVBcmNQb3NpdGlvbnNbMV0gPSB3YWxsUG9zaXRpb25zW2kyICsgMV07CiAgICAgICAgICAgIGdlbmVyYXRlQXJjSGVpZ2h0c1swXSA9IG1heGltdW1IZWlnaHRzW2kyXTsKICAgICAgICAgICAgZ2VuZXJhdGVBcmNIZWlnaHRzWzFdID0gbWF4aW11bUhlaWdodHNbaTIgKyAxXTsKICAgICAgICAgICAgY29uc3QgcG9zID0gUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjKGdlbmVyYXRlQXJjT3B0aW9ucyk7CiAgICAgICAgICAgIHRvcFBvc2l0aW9ucy5zZXQocG9zLCBvZmZzZXQpOwogICAgICAgICAgICBnZW5lcmF0ZUFyY0hlaWdodHNbMF0gPSBtaW5pbXVtSGVpZ2h0c1tpMl07CiAgICAgICAgICAgIGdlbmVyYXRlQXJjSGVpZ2h0c1sxXSA9IG1pbmltdW1IZWlnaHRzW2kyICsgMV07CiAgICAgICAgICAgIGJvdHRvbVBvc2l0aW9ucy5zZXQoCiAgICAgICAgICAgICAgUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjKGdlbmVyYXRlQXJjT3B0aW9ucyksCiAgICAgICAgICAgICAgb2Zmc2V0CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIG9mZnNldCArPSBwb3MubGVuZ3RoOwogICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBnZW5lcmF0ZUFyY09wdGlvbnMucG9zaXRpb25zID0gd2FsbFBvc2l0aW9uczsKICAgICAgICAgIGdlbmVyYXRlQXJjT3B0aW9ucy5oZWlnaHQgPSBtYXhpbXVtSGVpZ2h0czsKICAgICAgICAgIHRvcFBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkoCiAgICAgICAgICAgIFBvbHlsaW5lUGlwZWxpbmVfZGVmYXVsdC5nZW5lcmF0ZUFyYyhnZW5lcmF0ZUFyY09wdGlvbnMpCiAgICAgICAgICApOwogICAgICAgICAgZ2VuZXJhdGVBcmNPcHRpb25zLmhlaWdodCA9IG1pbmltdW1IZWlnaHRzOwogICAgICAgICAgYm90dG9tUG9zaXRpb25zID0gbmV3IEZsb2F0NjRBcnJheSgKICAgICAgICAgICAgUG9seWxpbmVQaXBlbGluZV9kZWZhdWx0LmdlbmVyYXRlQXJjKGdlbmVyYXRlQXJjT3B0aW9ucykKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB7CiAgICAgICAgICBib3R0b21Qb3NpdGlvbnMsCiAgICAgICAgICB0b3BQb3NpdGlvbnMsCiAgICAgICAgICBudW1Db3JuZXJzCiAgICAgICAgfTsKICAgICAgfTsKICAgICAgV2FsbEdlb21ldHJ5TGlicmFyeV9kZWZhdWx0ID0gV2FsbEdlb21ldHJ5TGlicmFyeTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1dhbGxHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIFdhbGxHZW9tZXRyeShvcHRpb25zKSB7CiAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICBjb25zdCB3YWxsUG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICBjb25zdCBtYXhpbXVtSGVpZ2h0cyA9IG9wdGlvbnMubWF4aW11bUhlaWdodHM7CiAgICBjb25zdCBtaW5pbXVtSGVpZ2h0cyA9IG9wdGlvbnMubWluaW11bUhlaWdodHM7CiAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh3YWxsUG9zaXRpb25zKSkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgib3B0aW9ucy5wb3NpdGlvbnMgaXMgcmVxdWlyZWQuIik7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1heGltdW1IZWlnaHRzKSAmJiBtYXhpbXVtSGVpZ2h0cy5sZW5ndGggIT09IHdhbGxQb3NpdGlvbnMubGVuZ3RoKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnBvc2l0aW9ucyBhbmQgb3B0aW9ucy5tYXhpbXVtSGVpZ2h0cyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoLiIKICAgICAgKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWluaW11bUhlaWdodHMpICYmIG1pbmltdW1IZWlnaHRzLmxlbmd0aCAhPT0gd2FsbFBvc2l0aW9ucy5sZW5ndGgpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoCiAgICAgICAgIm9wdGlvbnMucG9zaXRpb25zIGFuZCBvcHRpb25zLm1pbmltdW1IZWlnaHRzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGguIgogICAgICApOwogICAgfQogICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gb3B0aW9ucy52ZXJ0ZXhGb3JtYXQgPz8gVmVydGV4Rm9ybWF0X2RlZmF1bHQuREVGQVVMVDsKICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIHRoaXMuX3Bvc2l0aW9ucyA9IHdhbGxQb3NpdGlvbnM7CiAgICB0aGlzLl9taW5pbXVtSGVpZ2h0cyA9IG1pbmltdW1IZWlnaHRzOwogICAgdGhpcy5fbWF4aW11bUhlaWdodHMgPSBtYXhpbXVtSGVpZ2h0czsKICAgIHRoaXMuX3ZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKHZlcnRleEZvcm1hdCk7CiAgICB0aGlzLl9ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgdGhpcy5fZWxsaXBzb2lkID0gRWxsaXBzb2lkX2RlZmF1bHQuY2xvbmUoZWxsaXBzb2lkKTsKICAgIHRoaXMuX3dvcmtlck5hbWUgPSAiY3JlYXRlV2FsbEdlb21ldHJ5IjsKICAgIGxldCBudW1Db21wb25lbnRzID0gMSArIHdhbGxQb3NpdGlvbnMubGVuZ3RoICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIDI7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSkgewogICAgICBudW1Db21wb25lbnRzICs9IG1pbmltdW1IZWlnaHRzLmxlbmd0aDsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWF4aW11bUhlaWdodHMpKSB7CiAgICAgIG51bUNvbXBvbmVudHMgKz0gbWF4aW11bUhlaWdodHMubGVuZ3RoOwogICAgfQogICAgdGhpcy5wYWNrZWRMZW5ndGggPSBudW1Db21wb25lbnRzICsgRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgVmVydGV4Rm9ybWF0X2RlZmF1bHQucGFja2VkTGVuZ3RoICsgMTsKICB9CiAgdmFyIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xLCBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMiwgc2NyYXRjaENhcnRlc2lhbjNQb3NpdGlvbjQsIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb241LCBzY3JhdGNoQml0YW5nZW50NSwgc2NyYXRjaFRhbmdlbnQ1LCBzY3JhdGNoTm9ybWFsOSwgc2NyYXRjaEVsbGlwc29pZDE3LCBzY3JhdGNoVmVydGV4Rm9ybWF0MTMsIHNjcmF0Y2hPcHRpb25zMjMsIFdhbGxHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X1dhbGxHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvV2FsbEdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9WZXJ0ZXhGb3JtYXQoKTsKICAgICAgaW5pdF9XYWxsR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjNQb3NpdGlvbjQgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb241ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoQml0YW5nZW50NSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaFRhbmdlbnQ1ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoTm9ybWFsOSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgV2FsbEdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2YWx1ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ2YWx1ZSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB2YWx1ZS5fcG9zaXRpb25zOwogICAgICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHBvc2l0aW9uc1tpMl0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbWluaW11bUhlaWdodHMgPSB2YWx1ZS5fbWluaW11bUhlaWdodHM7CiAgICAgICAgbGVuZ3RoID0gZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSA/IG1pbmltdW1IZWlnaHRzLmxlbmd0aCA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSkgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBtaW5pbXVtSGVpZ2h0c1tpMl07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IG1heGltdW1IZWlnaHRzID0gdmFsdWUuX21heGltdW1IZWlnaHRzOwogICAgICAgIGxlbmd0aCA9IGRlZmluZWRfZGVmYXVsdChtYXhpbXVtSGVpZ2h0cykgPyBtYXhpbXVtSGVpZ2h0cy5sZW5ndGggOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChtYXhpbXVtSGVpZ2h0cykpIHsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gbWF4aW11bUhlaWdodHNbaTJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBWZXJ0ZXhGb3JtYXRfZGVmYXVsdC5wYWNrKHZhbHVlLl92ZXJ0ZXhGb3JtYXQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQxNyA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDEzID0gbmV3IFZlcnRleEZvcm1hdF9kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hPcHRpb25zMjMgPSB7CiAgICAgICAgcG9zaXRpb25zOiB2b2lkIDAsCiAgICAgICAgbWluaW11bUhlaWdodHM6IHZvaWQgMCwKICAgICAgICBtYXhpbXVtSGVpZ2h0czogdm9pZCAwLAogICAgICAgIGVsbGlwc29pZDogc2NyYXRjaEVsbGlwc29pZDE3LAogICAgICAgIHZlcnRleEZvcm1hdDogc2NyYXRjaFZlcnRleEZvcm1hdDEzLAogICAgICAgIGdyYW51bGFyaXR5OiB2b2lkIDAKICAgICAgfTsKICAgICAgV2FsbEdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgbGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgcG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGxldCBtaW5pbXVtSGVpZ2h0czsKICAgICAgICBpZiAobGVuZ3RoID4gMCkgewogICAgICAgICAgbWluaW11bUhlaWdodHMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBtaW5pbXVtSGVpZ2h0c1tpMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGxldCBtYXhpbXVtSGVpZ2h0czsKICAgICAgICBpZiAobGVuZ3RoID4gMCkgewogICAgICAgICAgbWF4aW11bUhlaWdodHMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBtYXhpbXVtSGVpZ2h0c1tpMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQxNyk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gVmVydGV4Rm9ybWF0X2RlZmF1bHQudW5wYWNrKAogICAgICAgICAgYXJyYXksCiAgICAgICAgICBzdGFydGluZ0luZGV4LAogICAgICAgICAgc2NyYXRjaFZlcnRleEZvcm1hdDEzCiAgICAgICAgKTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IFZlcnRleEZvcm1hdF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IGFycmF5W3N0YXJ0aW5nSW5kZXhdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjMucG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMyMy5taW5pbXVtSGVpZ2h0cyA9IG1pbmltdW1IZWlnaHRzOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMyMy5tYXhpbXVtSGVpZ2h0cyA9IG1heGltdW1IZWlnaHRzOwogICAgICAgICAgc2NyYXRjaE9wdGlvbnMyMy5ncmFudWxhcml0eSA9IGdyYW51bGFyaXR5OwogICAgICAgICAgcmV0dXJuIG5ldyBXYWxsR2VvbWV0cnkoc2NyYXRjaE9wdGlvbnMyMyk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdC5fcG9zaXRpb25zID0gcG9zaXRpb25zOwogICAgICAgIHJlc3VsdC5fbWluaW11bUhlaWdodHMgPSBtaW5pbXVtSGVpZ2h0czsKICAgICAgICByZXN1bHQuX21heGltdW1IZWlnaHRzID0gbWF4aW11bUhlaWdodHM7CiAgICAgICAgcmVzdWx0Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNvaWQsIHJlc3VsdC5fZWxsaXBzb2lkKTsKICAgICAgICByZXN1bHQuX3ZlcnRleEZvcm1hdCA9IFZlcnRleEZvcm1hdF9kZWZhdWx0LmNsb25lKHZlcnRleEZvcm1hdCwgcmVzdWx0Ll92ZXJ0ZXhGb3JtYXQpOwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBXYWxsR2VvbWV0cnkuZnJvbUNvbnN0YW50SGVpZ2h0cyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHsKICAgICAgICBvcHRpb25zID0gb3B0aW9ucyA/PyBGcm96ZW5fZGVmYXVsdC5FTVBUWV9PQkpFQ1Q7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gb3B0aW9ucy5wb3NpdGlvbnM7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMucG9zaXRpb25zIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBsZXQgbWluSGVpZ2h0czsKICAgICAgICBsZXQgbWF4SGVpZ2h0czsKICAgICAgICBjb25zdCBtaW4zID0gb3B0aW9ucy5taW5pbXVtSGVpZ2h0OwogICAgICAgIGNvbnN0IG1heDMgPSBvcHRpb25zLm1heGltdW1IZWlnaHQ7CiAgICAgICAgY29uc3QgZG9NaW4gPSBkZWZpbmVkX2RlZmF1bHQobWluMyk7CiAgICAgICAgY29uc3QgZG9NYXggPSBkZWZpbmVkX2RlZmF1bHQobWF4Myk7CiAgICAgICAgaWYgKGRvTWluIHx8IGRvTWF4KSB7CiAgICAgICAgICBjb25zdCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgICAgbWluSGVpZ2h0cyA9IGRvTWluID8gbmV3IEFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICAgICAgICBtYXhIZWlnaHRzID0gZG9NYXggPyBuZXcgQXJyYXkobGVuZ3RoKSA6IHZvaWQgMDsKICAgICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgaWYgKGRvTWluKSB7CiAgICAgICAgICAgICAgbWluSGVpZ2h0c1tpMl0gPSBtaW4zOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChkb01heCkgewogICAgICAgICAgICAgIG1heEhlaWdodHNbaTJdID0gbWF4MzsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBuZXdPcHRpb25zID0gewogICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgbWF4aW11bUhlaWdodHM6IG1heEhlaWdodHMsCiAgICAgICAgICBtaW5pbXVtSGVpZ2h0czogbWluSGVpZ2h0cywKICAgICAgICAgIGVsbGlwc29pZDogb3B0aW9ucy5lbGxpcHNvaWQsCiAgICAgICAgICB2ZXJ0ZXhGb3JtYXQ6IG9wdGlvbnMudmVydGV4Rm9ybWF0CiAgICAgICAgfTsKICAgICAgICByZXR1cm4gbmV3IFdhbGxHZW9tZXRyeShuZXdPcHRpb25zKTsKICAgICAgfTsKICAgICAgV2FsbEdlb21ldHJ5LmNyZWF0ZUdlb21ldHJ5ID0gZnVuY3Rpb24od2FsbEdlb21ldHJ5KSB7CiAgICAgICAgY29uc3Qgd2FsbFBvc2l0aW9ucyA9IHdhbGxHZW9tZXRyeS5fcG9zaXRpb25zOwogICAgICAgIGNvbnN0IG1pbmltdW1IZWlnaHRzID0gd2FsbEdlb21ldHJ5Ll9taW5pbXVtSGVpZ2h0czsKICAgICAgICBjb25zdCBtYXhpbXVtSGVpZ2h0cyA9IHdhbGxHZW9tZXRyeS5fbWF4aW11bUhlaWdodHM7CiAgICAgICAgY29uc3QgdmVydGV4Rm9ybWF0ID0gd2FsbEdlb21ldHJ5Ll92ZXJ0ZXhGb3JtYXQ7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSB3YWxsR2VvbWV0cnkuX2dyYW51bGFyaXR5OwogICAgICAgIGNvbnN0IGVsbGlwc29pZCA9IHdhbGxHZW9tZXRyeS5fZWxsaXBzb2lkOwogICAgICAgIGNvbnN0IHBvcyA9IFdhbGxHZW9tZXRyeUxpYnJhcnlfZGVmYXVsdC5jb21wdXRlUG9zaXRpb25zKAogICAgICAgICAgZWxsaXBzb2lkLAogICAgICAgICAgd2FsbFBvc2l0aW9ucywKICAgICAgICAgIG1heGltdW1IZWlnaHRzLAogICAgICAgICAgbWluaW11bUhlaWdodHMsCiAgICAgICAgICBncmFudWxhcml0eSwKICAgICAgICAgIHRydWUKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvcykpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgYm90dG9tUG9zaXRpb25zID0gcG9zLmJvdHRvbVBvc2l0aW9uczsKICAgICAgICBjb25zdCB0b3BQb3NpdGlvbnMgPSBwb3MudG9wUG9zaXRpb25zOwogICAgICAgIGNvbnN0IG51bUNvcm5lcnMgPSBwb3MubnVtQ29ybmVyczsKICAgICAgICBsZXQgbGVuZ3RoID0gdG9wUG9zaXRpb25zLmxlbmd0aDsKICAgICAgICBsZXQgc2l6ZSA9IGxlbmd0aCAqIDI7CiAgICAgICAgY29uc3QgcG9zaXRpb25zID0gdmVydGV4Rm9ybWF0LnBvc2l0aW9uID8gbmV3IEZsb2F0NjRBcnJheShzaXplKSA6IHZvaWQgMDsKICAgICAgICBjb25zdCBub3JtYWxzID0gdmVydGV4Rm9ybWF0Lm5vcm1hbCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSkgOiB2b2lkIDA7CiAgICAgICAgY29uc3QgdGFuZ2VudHMgPSB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSkgOiB2b2lkIDA7CiAgICAgICAgY29uc3QgYml0YW5nZW50cyA9IHZlcnRleEZvcm1hdC5iaXRhbmdlbnQgPyBuZXcgRmxvYXQzMkFycmF5KHNpemUpIDogdm9pZCAwOwogICAgICAgIGNvbnN0IHRleHR1cmVDb29yZGluYXRlcyA9IHZlcnRleEZvcm1hdC5zdCA/IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAvIDMgKiAyKSA6IHZvaWQgMDsKICAgICAgICBsZXQgcG9zaXRpb25JbmRleCA9IDA7CiAgICAgICAgbGV0IG5vcm1hbEluZGV4ID0gMDsKICAgICAgICBsZXQgYml0YW5nZW50SW5kZXggPSAwOwogICAgICAgIGxldCB0YW5nZW50SW5kZXggPSAwOwogICAgICAgIGxldCBzdEluZGV4ID0gMDsKICAgICAgICBsZXQgbm9ybWFsMiA9IHNjcmF0Y2hOb3JtYWw5OwogICAgICAgIGxldCB0YW5nZW50ID0gc2NyYXRjaFRhbmdlbnQ1OwogICAgICAgIGxldCBiaXRhbmdlbnQgPSBzY3JhdGNoQml0YW5nZW50NTsKICAgICAgICBsZXQgcmVjb21wdXRlTm9ybWFsID0gdHJ1ZTsKICAgICAgICBsZW5ndGggLz0gMzsKICAgICAgICBsZXQgaTI7CiAgICAgICAgbGV0IHMyID0gMDsKICAgICAgICBjb25zdCBkcyA9IDEgLyAobGVuZ3RoIC0gbnVtQ29ybmVycyAtIDEpOwogICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgY29uc3QgaTMgPSBpMiAqIDM7CiAgICAgICAgICBjb25zdCB0b3BQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHRvcFBvc2l0aW9ucywKICAgICAgICAgICAgaTMsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgYm90dG9tUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBib3R0b21Qb3NpdGlvbnMsCiAgICAgICAgICAgIGkzLAogICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMgogICAgICAgICAgKTsKICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQucG9zaXRpb24pIHsKICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSBib3R0b21Qb3NpdGlvbi54OwogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IGJvdHRvbVBvc2l0aW9uLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gYm90dG9tUG9zaXRpb24uejsKICAgICAgICAgICAgcG9zaXRpb25zW3Bvc2l0aW9uSW5kZXgrK10gPSB0b3BQb3NpdGlvbi54OwogICAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHRvcFBvc2l0aW9uLnk7CiAgICAgICAgICAgIHBvc2l0aW9uc1twb3NpdGlvbkluZGV4KytdID0gdG9wUG9zaXRpb24uejsKICAgICAgICAgIH0KICAgICAgICAgIGlmICh2ZXJ0ZXhGb3JtYXQuc3QpIHsKICAgICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3N0SW5kZXgrK10gPSBzMjsKICAgICAgICAgICAgdGV4dHVyZUNvb3JkaW5hdGVzW3N0SW5kZXgrK10gPSAwOwogICAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IHMyOwogICAgICAgICAgICB0ZXh0dXJlQ29vcmRpbmF0ZXNbc3RJbmRleCsrXSA9IDE7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0Lm5vcm1hbCB8fCB2ZXJ0ZXhGb3JtYXQudGFuZ2VudCB8fCB2ZXJ0ZXhGb3JtYXQuYml0YW5nZW50KSB7CiAgICAgICAgICAgIGxldCBuZXh0VG9wID0gQ2FydGVzaWFuM19kZWZhdWx0LmNsb25lKAogICAgICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLAogICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb241CiAgICAgICAgICAgICk7CiAgICAgICAgICAgIGNvbnN0IGdyb3VuZFBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICAgICAgICAgIHRvcFBvc2l0aW9uLAogICAgICAgICAgICAgIGVsbGlwc29pZC5nZW9kZXRpY1N1cmZhY2VOb3JtYWwoCiAgICAgICAgICAgICAgICB0b3BQb3NpdGlvbiwKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24yCiAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMgogICAgICAgICAgICApOwogICAgICAgICAgICBpZiAoaTIgKyAxIDwgbGVuZ3RoKSB7CiAgICAgICAgICAgICAgbmV4dFRvcCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgICAgICB0b3BQb3NpdGlvbnMsCiAgICAgICAgICAgICAgICBpMyArIDMsCiAgICAgICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uNQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHJlY29tcHV0ZU5vcm1hbCkgewogICAgICAgICAgICAgIGNvbnN0IHNjYWxlZG5leHRQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICAgICAgICAgIG5leHRUb3AsCiAgICAgICAgICAgICAgICB0b3BQb3NpdGlvbiwKICAgICAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb240CiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICBjb25zdCBzY2FsZWRHcm91bmRQb3NpdGlvbiA9IENhcnRlc2lhbjNfZGVmYXVsdC5zdWJ0cmFjdCgKICAgICAgICAgICAgICAgIGdyb3VuZFBvc2l0aW9uLAogICAgICAgICAgICAgICAgdG9wUG9zaXRpb24sCiAgICAgICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMQogICAgICAgICAgICAgICk7CiAgICAgICAgICAgICAgbm9ybWFsMiA9IENhcnRlc2lhbjNfZGVmYXVsdC5ub3JtYWxpemUoCiAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuY3Jvc3Moc2NhbGVkR3JvdW5kUG9zaXRpb24sIHNjYWxlZG5leHRQb3NpdGlvbiwgbm9ybWFsMiksCiAgICAgICAgICAgICAgICBub3JtYWwyCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICByZWNvbXB1dGVOb3JtYWwgPSBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoQ2FydGVzaWFuM19kZWZhdWx0LmVxdWFsc0Vwc2lsb24odG9wUG9zaXRpb24sIG5leHRUb3AsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgICAgICAgICAgcmVjb21wdXRlTm9ybWFsID0gdHJ1ZTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBzMiArPSBkczsKICAgICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgICAgIHRhbmdlbnQgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQubm9ybWFsaXplKAogICAgICAgICAgICAgICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuc3VidHJhY3QobmV4dFRvcCwgdG9wUG9zaXRpb24sIHRhbmdlbnQpLAogICAgICAgICAgICAgICAgICB0YW5nZW50CiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICAgICAgYml0YW5nZW50ID0gQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZSgKICAgICAgICAgICAgICAgICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKG5vcm1hbDIsIHRhbmdlbnQsIGJpdGFuZ2VudCksCiAgICAgICAgICAgICAgICAgIGJpdGFuZ2VudAogICAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi54OwogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLnk7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIuejsKICAgICAgICAgICAgICBub3JtYWxzW25vcm1hbEluZGV4KytdID0gbm9ybWFsMi54OwogICAgICAgICAgICAgIG5vcm1hbHNbbm9ybWFsSW5kZXgrK10gPSBub3JtYWwyLnk7CiAgICAgICAgICAgICAgbm9ybWFsc1tub3JtYWxJbmRleCsrXSA9IG5vcm1hbDIuejsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnRhbmdlbnQpIHsKICAgICAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lng7CiAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC55OwogICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQuejsKICAgICAgICAgICAgICB0YW5nZW50c1t0YW5nZW50SW5kZXgrK10gPSB0YW5nZW50Lng7CiAgICAgICAgICAgICAgdGFuZ2VudHNbdGFuZ2VudEluZGV4KytdID0gdGFuZ2VudC55OwogICAgICAgICAgICAgIHRhbmdlbnRzW3RhbmdlbnRJbmRleCsrXSA9IHRhbmdlbnQuejsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodmVydGV4Rm9ybWF0LmJpdGFuZ2VudCkgewogICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICAgICAgYml0YW5nZW50c1tiaXRhbmdlbnRJbmRleCsrXSA9IGJpdGFuZ2VudC56OwogICAgICAgICAgICAgIGJpdGFuZ2VudHNbYml0YW5nZW50SW5kZXgrK10gPSBiaXRhbmdlbnQueDsKICAgICAgICAgICAgICBiaXRhbmdlbnRzW2JpdGFuZ2VudEluZGV4KytdID0gYml0YW5nZW50Lnk7CiAgICAgICAgICAgICAgYml0YW5nZW50c1tiaXRhbmdlbnRJbmRleCsrXSA9IGJpdGFuZ2VudC56OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoKTsKICAgICAgICBpZiAodmVydGV4Rm9ybWF0LnBvc2l0aW9uKSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLnBvc2l0aW9uID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5ET1VCTEUsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDMsCiAgICAgICAgICAgIHZhbHVlczogcG9zaXRpb25zCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5ub3JtYWwpIHsKICAgICAgICAgIGF0dHJpYnV0ZXMubm9ybWFsID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgdmFsdWVzOiBub3JtYWxzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC50YW5nZW50KSB7CiAgICAgICAgICBhdHRyaWJ1dGVzLnRhbmdlbnQgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVfZGVmYXVsdCh7CiAgICAgICAgICAgIGNvbXBvbmVudERhdGF0eXBlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LkZMT0FULAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHRhbmdlbnRzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5iaXRhbmdlbnQpIHsKICAgICAgICAgIGF0dHJpYnV0ZXMuYml0YW5nZW50ID0gbmV3IEdlb21ldHJ5QXR0cmlidXRlX2RlZmF1bHQoewogICAgICAgICAgICBjb21wb25lbnREYXRhdHlwZTogQ29tcG9uZW50RGF0YXR5cGVfZGVmYXVsdC5GTE9BVCwKICAgICAgICAgICAgY29tcG9uZW50c1BlckF0dHJpYnV0ZTogMywKICAgICAgICAgICAgdmFsdWVzOiBiaXRhbmdlbnRzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKHZlcnRleEZvcm1hdC5zdCkgewogICAgICAgICAgYXR0cmlidXRlcy5zdCA9IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRkxPQVQsCiAgICAgICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IDIsCiAgICAgICAgICAgIHZhbHVlczogdGV4dHVyZUNvb3JkaW5hdGVzCiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbnVtVmVydGljZXMgPSBzaXplIC8gMzsKICAgICAgICBzaXplIC09IDYgKiAobnVtQ29ybmVycyArIDEpOwogICAgICAgIGNvbnN0IGluZGljZXMgPSBJbmRleERhdGF0eXBlX2RlZmF1bHQuY3JlYXRlVHlwZWRBcnJheShudW1WZXJ0aWNlcywgc2l6ZSk7CiAgICAgICAgbGV0IGVkZ2VJbmRleCA9IDA7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbnVtVmVydGljZXMgLSAyOyBpMiArPSAyKSB7CiAgICAgICAgICBjb25zdCBMTCA9IGkyOwogICAgICAgICAgY29uc3QgTFIgPSBpMiArIDI7CiAgICAgICAgICBjb25zdCBwbCA9IENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkoCiAgICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgICAgTEwgKiAzLAogICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMQogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHByID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICBMUiAqIDMsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24yCiAgICAgICAgICApOwogICAgICAgICAgaWYgKENhcnRlc2lhbjNfZGVmYXVsdC5lcXVhbHNFcHNpbG9uKHBsLCBwciwgTWF0aF9kZWZhdWx0LkVQU0lMT04xMCkpIHsKICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICB9CiAgICAgICAgICBjb25zdCBVTCA9IGkyICsgMTsKICAgICAgICAgIGNvbnN0IFVSID0gaTIgKyAzOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBVTDsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gTEw7CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IFVSOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBVUjsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gTEw7CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IExSOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IEdlb21ldHJ5X2RlZmF1bHQoewogICAgICAgICAgYXR0cmlidXRlcywKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICBwcmltaXRpdmVUeXBlOiBQcmltaXRpdmVUeXBlX2RlZmF1bHQuVFJJQU5HTEVTLAogICAgICAgICAgYm91bmRpbmdTcGhlcmU6IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQuZnJvbVZlcnRpY2VzKHBvc2l0aW9ucykKICAgICAgICB9KTsKICAgICAgfTsKICAgICAgV2FsbEdlb21ldHJ5X2RlZmF1bHQgPSBXYWxsR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVXYWxsR2VvbWV0cnkuanMKICB2YXIgY3JlYXRlV2FsbEdlb21ldHJ5X2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChjcmVhdGVXYWxsR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlV2FsbEdlb21ldHJ5X2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBjcmVhdGVXYWxsR2VvbWV0cnkod2FsbEdlb21ldHJ5LCBvZmZzZXQpIHsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob2Zmc2V0KSkgewogICAgICB3YWxsR2VvbWV0cnkgPSBXYWxsR2VvbWV0cnlfZGVmYXVsdC51bnBhY2sod2FsbEdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgd2FsbEdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZSh3YWxsR2VvbWV0cnkuX2VsbGlwc29pZCk7CiAgICByZXR1cm4gV2FsbEdlb21ldHJ5X2RlZmF1bHQuY3JlYXRlR2VvbWV0cnkod2FsbEdlb21ldHJ5KTsKICB9CiAgdmFyIGNyZWF0ZVdhbGxHZW9tZXRyeV9kZWZhdWx0OwogIHZhciBpbml0X2NyZWF0ZVdhbGxHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlV2FsbEdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfRWxsaXBzb2lkKCk7CiAgICAgIGluaXRfV2FsbEdlb21ldHJ5KCk7CiAgICAgIGNyZWF0ZVdhbGxHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlV2FsbEdlb21ldHJ5OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvV2FsbE91dGxpbmVHZW9tZXRyeS5qcwogIGZ1bmN0aW9uIFdhbGxPdXRsaW5lR2VvbWV0cnkob3B0aW9ucykgewogICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgY29uc3Qgd2FsbFBvc2l0aW9ucyA9IG9wdGlvbnMucG9zaXRpb25zOwogICAgY29uc3QgbWF4aW11bUhlaWdodHMgPSBvcHRpb25zLm1heGltdW1IZWlnaHRzOwogICAgY29uc3QgbWluaW11bUhlaWdodHMgPSBvcHRpb25zLm1pbmltdW1IZWlnaHRzOwogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQod2FsbFBvc2l0aW9ucykpIHsKICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoIm9wdGlvbnMucG9zaXRpb25zIGlzIHJlcXVpcmVkLiIpOwogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChtYXhpbXVtSGVpZ2h0cykgJiYgbWF4aW11bUhlaWdodHMubGVuZ3RoICE9PSB3YWxsUG9zaXRpb25zLmxlbmd0aCkgewogICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgKICAgICAgICAib3B0aW9ucy5wb3NpdGlvbnMgYW5kIG9wdGlvbnMubWF4aW11bUhlaWdodHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aC4iCiAgICAgICk7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSAmJiBtaW5pbXVtSGVpZ2h0cy5sZW5ndGggIT09IHdhbGxQb3NpdGlvbnMubGVuZ3RoKSB7CiAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KAogICAgICAgICJvcHRpb25zLnBvc2l0aW9ucyBhbmQgb3B0aW9ucy5taW5pbXVtSGVpZ2h0cyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoLiIKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IGdyYW51bGFyaXR5ID0gb3B0aW9ucy5ncmFudWxhcml0eSA/PyBNYXRoX2RlZmF1bHQuUkFESUFOU19QRVJfREVHUkVFOwogICAgY29uc3QgZWxsaXBzb2lkID0gb3B0aW9ucy5lbGxpcHNvaWQgPz8gRWxsaXBzb2lkX2RlZmF1bHQuZGVmYXVsdDsKICAgIHRoaXMuX3Bvc2l0aW9ucyA9IHdhbGxQb3NpdGlvbnM7CiAgICB0aGlzLl9taW5pbXVtSGVpZ2h0cyA9IG1pbmltdW1IZWlnaHRzOwogICAgdGhpcy5fbWF4aW11bUhlaWdodHMgPSBtYXhpbXVtSGVpZ2h0czsKICAgIHRoaXMuX2dyYW51bGFyaXR5ID0gZ3JhbnVsYXJpdHk7CiAgICB0aGlzLl9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZShlbGxpcHNvaWQpOwogICAgdGhpcy5fd29ya2VyTmFtZSA9ICJjcmVhdGVXYWxsT3V0bGluZUdlb21ldHJ5IjsKICAgIGxldCBudW1Db21wb25lbnRzID0gMSArIHdhbGxQb3NpdGlvbnMubGVuZ3RoICogQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCArIDI7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSkgewogICAgICBudW1Db21wb25lbnRzICs9IG1pbmltdW1IZWlnaHRzLmxlbmd0aDsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWF4aW11bUhlaWdodHMpKSB7CiAgICAgIG51bUNvbXBvbmVudHMgKz0gbWF4aW11bUhlaWdodHMubGVuZ3RoOwogICAgfQogICAgdGhpcy5wYWNrZWRMZW5ndGggPSBudW1Db21wb25lbnRzICsgRWxsaXBzb2lkX2RlZmF1bHQucGFja2VkTGVuZ3RoICsgMTsKICB9CiAgdmFyIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xMiwgc2NyYXRjaENhcnRlc2lhbjNQb3NpdGlvbjIyLCBzY3JhdGNoRWxsaXBzb2lkMTgsIHNjcmF0Y2hPcHRpb25zMjQsIFdhbGxPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdDsKICB2YXIgaW5pdF9XYWxsT3V0bGluZUdlb21ldHJ5ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9XYWxsT3V0bGluZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjMoKTsKICAgICAgaW5pdF9Db21wb25lbnREYXRhdHlwZSgpOwogICAgICBpbml0X0Zyb3plbigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0dlb21ldHJ5KCk7CiAgICAgIGluaXRfR2VvbWV0cnlBdHRyaWJ1dGUoKTsKICAgICAgaW5pdF9HZW9tZXRyeUF0dHJpYnV0ZXMoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X1ByaW1pdGl2ZVR5cGUoKTsKICAgICAgaW5pdF9XYWxsR2VvbWV0cnlMaWJyYXJ5KCk7CiAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xMiA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgc2NyYXRjaENhcnRlc2lhbjNQb3NpdGlvbjIyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBXYWxsT3V0bGluZUdlb21ldHJ5LnBhY2sgPSBmdW5jdGlvbih2YWx1ZSwgYXJyYXksIHN0YXJ0aW5nSW5kZXgpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh2YWx1ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ2YWx1ZSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSB2YWx1ZS5fcG9zaXRpb25zOwogICAgICAgIGxldCBsZW5ndGggPSBwb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyLCBzdGFydGluZ0luZGV4ICs9IENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrZWRMZW5ndGgpIHsKICAgICAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKHBvc2l0aW9uc1tpMl0sIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICB9CiAgICAgICAgY29uc3QgbWluaW11bUhlaWdodHMgPSB2YWx1ZS5fbWluaW11bUhlaWdodHM7CiAgICAgICAgbGVuZ3RoID0gZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSA/IG1pbmltdW1IZWlnaHRzLmxlbmd0aCA6IDA7CiAgICAgICAgYXJyYXlbc3RhcnRpbmdJbmRleCsrXSA9IGxlbmd0aDsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1pbmltdW1IZWlnaHRzKSkgewogICAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBtaW5pbXVtSGVpZ2h0c1tpMl07CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGNvbnN0IG1heGltdW1IZWlnaHRzID0gdmFsdWUuX21heGltdW1IZWlnaHRzOwogICAgICAgIGxlbmd0aCA9IGRlZmluZWRfZGVmYXVsdChtYXhpbXVtSGVpZ2h0cykgPyBtYXhpbXVtSGVpZ2h0cy5sZW5ndGggOiAwOwogICAgICAgIGFycmF5W3N0YXJ0aW5nSW5kZXgrK10gPSBsZW5ndGg7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChtYXhpbXVtSGVpZ2h0cykpIHsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4KytdID0gbWF4aW11bUhlaWdodHNbaTJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrKHZhbHVlLl9lbGxpcHNvaWQsIGFycmF5LCBzdGFydGluZ0luZGV4KTsKICAgICAgICBzdGFydGluZ0luZGV4ICs9IEVsbGlwc29pZF9kZWZhdWx0LnBhY2tlZExlbmd0aDsKICAgICAgICBhcnJheVtzdGFydGluZ0luZGV4XSA9IHZhbHVlLl9ncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgIH07CiAgICAgIHNjcmF0Y2hFbGxpcHNvaWQxOCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKEVsbGlwc29pZF9kZWZhdWx0LlVOSVRfU1BIRVJFKTsKICAgICAgc2NyYXRjaE9wdGlvbnMyNCA9IHsKICAgICAgICBwb3NpdGlvbnM6IHZvaWQgMCwKICAgICAgICBtaW5pbXVtSGVpZ2h0czogdm9pZCAwLAogICAgICAgIG1heGltdW1IZWlnaHRzOiB2b2lkIDAsCiAgICAgICAgZWxsaXBzb2lkOiBzY3JhdGNoRWxsaXBzb2lkMTgsCiAgICAgICAgZ3JhbnVsYXJpdHk6IHZvaWQgMAogICAgICB9OwogICAgICBXYWxsT3V0bGluZUdlb21ldHJ5LnVucGFjayA9IGZ1bmN0aW9uKGFycmF5LCBzdGFydGluZ0luZGV4LCByZXN1bHQpIHsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChhcnJheSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJhcnJheSBpcyByZXF1aXJlZCIpOwogICAgICAgIH0KICAgICAgICBzdGFydGluZ0luZGV4ID0gc3RhcnRpbmdJbmRleCA/PyAwOwogICAgICAgIGxldCBpMjsKICAgICAgICBsZXQgbGVuZ3RoID0gYXJyYXlbc3RhcnRpbmdJbmRleCsrXTsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBsZW5ndGg7ICsraTIsIHN0YXJ0aW5nSW5kZXggKz0gQ2FydGVzaWFuM19kZWZhdWx0LnBhY2tlZExlbmd0aCkgewogICAgICAgICAgcG9zaXRpb25zW2kyXSA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgpOwogICAgICAgIH0KICAgICAgICBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGxldCBtaW5pbXVtSGVpZ2h0czsKICAgICAgICBpZiAobGVuZ3RoID4gMCkgewogICAgICAgICAgbWluaW11bUhlaWdodHMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBtaW5pbXVtSGVpZ2h0c1tpMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBsZW5ndGggPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgIGxldCBtYXhpbXVtSGVpZ2h0czsKICAgICAgICBpZiAobGVuZ3RoID4gMCkgewogICAgICAgICAgbWF4aW11bUhlaWdodHMgPSBuZXcgQXJyYXkobGVuZ3RoKTsKICAgICAgICAgIGZvciAoaTIgPSAwOyBpMiA8IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICBtYXhpbXVtSGVpZ2h0c1tpMl0gPSBhcnJheVtzdGFydGluZ0luZGV4KytdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBlbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC51bnBhY2soYXJyYXksIHN0YXJ0aW5nSW5kZXgsIHNjcmF0Y2hFbGxpcHNvaWQxOCk7CiAgICAgICAgc3RhcnRpbmdJbmRleCArPSBFbGxpcHNvaWRfZGVmYXVsdC5wYWNrZWRMZW5ndGg7CiAgICAgICAgY29uc3QgZ3JhbnVsYXJpdHkgPSBhcnJheVtzdGFydGluZ0luZGV4XTsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICBzY3JhdGNoT3B0aW9uczI0LnBvc2l0aW9ucyA9IHBvc2l0aW9uczsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjQubWluaW11bUhlaWdodHMgPSBtaW5pbXVtSGVpZ2h0czsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjQubWF4aW11bUhlaWdodHMgPSBtYXhpbXVtSGVpZ2h0czsKICAgICAgICAgIHNjcmF0Y2hPcHRpb25zMjQuZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICAgIHJldHVybiBuZXcgV2FsbE91dGxpbmVHZW9tZXRyeShzY3JhdGNoT3B0aW9uczI0KTsKICAgICAgICB9CiAgICAgICAgcmVzdWx0Ll9wb3NpdGlvbnMgPSBwb3NpdGlvbnM7CiAgICAgICAgcmVzdWx0Ll9taW5pbXVtSGVpZ2h0cyA9IG1pbmltdW1IZWlnaHRzOwogICAgICAgIHJlc3VsdC5fbWF4aW11bUhlaWdodHMgPSBtYXhpbXVtSGVpZ2h0czsKICAgICAgICByZXN1bHQuX2VsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKGVsbGlwc29pZCwgcmVzdWx0Ll9lbGxpcHNvaWQpOwogICAgICAgIHJlc3VsdC5fZ3JhbnVsYXJpdHkgPSBncmFudWxhcml0eTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBXYWxsT3V0bGluZUdlb21ldHJ5LmZyb21Db25zdGFudEhlaWdodHMgPSBmdW5jdGlvbihvcHRpb25zKSB7CiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgPz8gRnJvemVuX2RlZmF1bHQuRU1QVFlfT0JKRUNUOwogICAgICAgIGNvbnN0IHBvc2l0aW9ucyA9IG9wdGlvbnMucG9zaXRpb25zOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJvcHRpb25zLnBvc2l0aW9ucyBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgbGV0IG1pbkhlaWdodHM7CiAgICAgICAgbGV0IG1heEhlaWdodHM7CiAgICAgICAgY29uc3QgbWluMyA9IG9wdGlvbnMubWluaW11bUhlaWdodDsKICAgICAgICBjb25zdCBtYXgzID0gb3B0aW9ucy5tYXhpbXVtSGVpZ2h0OwogICAgICAgIGNvbnN0IGRvTWluID0gZGVmaW5lZF9kZWZhdWx0KG1pbjMpOwogICAgICAgIGNvbnN0IGRvTWF4ID0gZGVmaW5lZF9kZWZhdWx0KG1heDMpOwogICAgICAgIGlmIChkb01pbiB8fCBkb01heCkgewogICAgICAgICAgY29uc3QgbGVuZ3RoID0gcG9zaXRpb25zLmxlbmd0aDsKICAgICAgICAgIG1pbkhlaWdodHMgPSBkb01pbiA/IG5ldyBBcnJheShsZW5ndGgpIDogdm9pZCAwOwogICAgICAgICAgbWF4SGVpZ2h0cyA9IGRvTWF4ID8gbmV3IEFycmF5KGxlbmd0aCkgOiB2b2lkIDA7CiAgICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgIGlmIChkb01pbikgewogICAgICAgICAgICAgIG1pbkhlaWdodHNbaTJdID0gbWluMzsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoZG9NYXgpIHsKICAgICAgICAgICAgICBtYXhIZWlnaHRzW2kyXSA9IG1heDM7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgY29uc3QgbmV3T3B0aW9ucyA9IHsKICAgICAgICAgIHBvc2l0aW9ucywKICAgICAgICAgIG1heGltdW1IZWlnaHRzOiBtYXhIZWlnaHRzLAogICAgICAgICAgbWluaW11bUhlaWdodHM6IG1pbkhlaWdodHMsCiAgICAgICAgICBlbGxpcHNvaWQ6IG9wdGlvbnMuZWxsaXBzb2lkCiAgICAgICAgfTsKICAgICAgICByZXR1cm4gbmV3IFdhbGxPdXRsaW5lR2VvbWV0cnkobmV3T3B0aW9ucyk7CiAgICAgIH07CiAgICAgIFdhbGxPdXRsaW5lR2VvbWV0cnkuY3JlYXRlR2VvbWV0cnkgPSBmdW5jdGlvbih3YWxsR2VvbWV0cnkpIHsKICAgICAgICBjb25zdCB3YWxsUG9zaXRpb25zID0gd2FsbEdlb21ldHJ5Ll9wb3NpdGlvbnM7CiAgICAgICAgY29uc3QgbWluaW11bUhlaWdodHMgPSB3YWxsR2VvbWV0cnkuX21pbmltdW1IZWlnaHRzOwogICAgICAgIGNvbnN0IG1heGltdW1IZWlnaHRzID0gd2FsbEdlb21ldHJ5Ll9tYXhpbXVtSGVpZ2h0czsKICAgICAgICBjb25zdCBncmFudWxhcml0eSA9IHdhbGxHZW9tZXRyeS5fZ3JhbnVsYXJpdHk7CiAgICAgICAgY29uc3QgZWxsaXBzb2lkID0gd2FsbEdlb21ldHJ5Ll9lbGxpcHNvaWQ7CiAgICAgICAgY29uc3QgcG9zID0gV2FsbEdlb21ldHJ5TGlicmFyeV9kZWZhdWx0LmNvbXB1dGVQb3NpdGlvbnMoCiAgICAgICAgICBlbGxpcHNvaWQsCiAgICAgICAgICB3YWxsUG9zaXRpb25zLAogICAgICAgICAgbWF4aW11bUhlaWdodHMsCiAgICAgICAgICBtaW5pbXVtSGVpZ2h0cywKICAgICAgICAgIGdyYW51bGFyaXR5LAogICAgICAgICAgZmFsc2UKICAgICAgICApOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHBvcykpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgYm90dG9tUG9zaXRpb25zID0gcG9zLmJvdHRvbVBvc2l0aW9uczsKICAgICAgICBjb25zdCB0b3BQb3NpdGlvbnMgPSBwb3MudG9wUG9zaXRpb25zOwogICAgICAgIGxldCBsZW5ndGggPSB0b3BQb3NpdGlvbnMubGVuZ3RoOwogICAgICAgIGxldCBzaXplID0gbGVuZ3RoICogMjsKICAgICAgICBjb25zdCBwb3NpdGlvbnMgPSBuZXcgRmxvYXQ2NEFycmF5KHNpemUpOwogICAgICAgIGxldCBwb3NpdGlvbkluZGV4ID0gMDsKICAgICAgICBsZW5ndGggLz0gMzsKICAgICAgICBsZXQgaTI7CiAgICAgICAgZm9yIChpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICBjb25zdCBpMyA9IGkyICogMzsKICAgICAgICAgIGNvbnN0IHRvcFBvc2l0aW9uID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgdG9wUG9zaXRpb25zLAogICAgICAgICAgICBpMywKICAgICAgICAgICAgc2NyYXRjaENhcnRlc2lhbjNQb3NpdGlvbjEyCiAgICAgICAgICApOwogICAgICAgICAgY29uc3QgYm90dG9tUG9zaXRpb24gPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KAogICAgICAgICAgICBib3R0b21Qb3NpdGlvbnMsCiAgICAgICAgICAgIGkzLAogICAgICAgICAgICBzY3JhdGNoQ2FydGVzaWFuM1Bvc2l0aW9uMjIKICAgICAgICAgICk7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IGJvdHRvbVBvc2l0aW9uLng7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IGJvdHRvbVBvc2l0aW9uLnk7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IGJvdHRvbVBvc2l0aW9uLno7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHRvcFBvc2l0aW9uLng7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHRvcFBvc2l0aW9uLnk7CiAgICAgICAgICBwb3NpdGlvbnNbcG9zaXRpb25JbmRleCsrXSA9IHRvcFBvc2l0aW9uLno7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBuZXcgR2VvbWV0cnlBdHRyaWJ1dGVzX2RlZmF1bHQoewogICAgICAgICAgcG9zaXRpb246IG5ldyBHZW9tZXRyeUF0dHJpYnV0ZV9kZWZhdWx0KHsKICAgICAgICAgICAgY29tcG9uZW50RGF0YXR5cGU6IENvbXBvbmVudERhdGF0eXBlX2RlZmF1bHQuRE9VQkxFLAogICAgICAgICAgICBjb21wb25lbnRzUGVyQXR0cmlidXRlOiAzLAogICAgICAgICAgICB2YWx1ZXM6IHBvc2l0aW9ucwogICAgICAgICAgfSkKICAgICAgICB9KTsKICAgICAgICBjb25zdCBudW1WZXJ0aWNlcyA9IHNpemUgLyAzOwogICAgICAgIHNpemUgPSAyICogbnVtVmVydGljZXMgLSA0ICsgbnVtVmVydGljZXM7CiAgICAgICAgY29uc3QgaW5kaWNlcyA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KG51bVZlcnRpY2VzLCBzaXplKTsKICAgICAgICBsZXQgZWRnZUluZGV4ID0gMDsKICAgICAgICBmb3IgKGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlcyAtIDI7IGkyICs9IDIpIHsKICAgICAgICAgIGNvbnN0IExMID0gaTI7CiAgICAgICAgICBjb25zdCBMUiA9IGkyICsgMjsKICAgICAgICAgIGNvbnN0IHBsID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICBMTCAqIDMsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24xMgogICAgICAgICAgKTsKICAgICAgICAgIGNvbnN0IHByID0gQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheSgKICAgICAgICAgICAgcG9zaXRpb25zLAogICAgICAgICAgICBMUiAqIDMsCiAgICAgICAgICAgIHNjcmF0Y2hDYXJ0ZXNpYW4zUG9zaXRpb24yMgogICAgICAgICAgKTsKICAgICAgICAgIGlmIChDYXJ0ZXNpYW4zX2RlZmF1bHQuZXF1YWxzRXBzaWxvbihwbCwgcHIsIE1hdGhfZGVmYXVsdC5FUFNJTE9OMTApKSB7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgfQogICAgICAgICAgY29uc3QgVUwgPSBpMiArIDE7CiAgICAgICAgICBjb25zdCBVUiA9IGkyICsgMzsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gVUw7CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IExMOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBVTDsKICAgICAgICAgIGluZGljZXNbZWRnZUluZGV4KytdID0gVVI7CiAgICAgICAgICBpbmRpY2VzW2VkZ2VJbmRleCsrXSA9IExMOwogICAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBMUjsKICAgICAgICB9CiAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXgrK10gPSBudW1WZXJ0aWNlcyAtIDI7CiAgICAgICAgaW5kaWNlc1tlZGdlSW5kZXhdID0gbnVtVmVydGljZXMgLSAxOwogICAgICAgIHJldHVybiBuZXcgR2VvbWV0cnlfZGVmYXVsdCh7CiAgICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgICAgaW5kaWNlcywKICAgICAgICAgIHByaW1pdGl2ZVR5cGU6IFByaW1pdGl2ZVR5cGVfZGVmYXVsdC5MSU5FUywKICAgICAgICAgIGJvdW5kaW5nU3BoZXJlOiBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcyhwb3NpdGlvbnMpCiAgICAgICAgfSk7CiAgICAgIH07CiAgICAgIFdhbGxPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdCA9IFdhbGxPdXRsaW5lR2VvbWV0cnk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVXYWxsT3V0bGluZUdlb21ldHJ5LmpzCiAgdmFyIGNyZWF0ZVdhbGxPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGNyZWF0ZVdhbGxPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeSh3YWxsR2VvbWV0cnksIG9mZnNldCkgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvZmZzZXQpKSB7CiAgICAgIHdhbGxHZW9tZXRyeSA9IFdhbGxPdXRsaW5lR2VvbWV0cnlfZGVmYXVsdC51bnBhY2sod2FsbEdlb21ldHJ5LCBvZmZzZXQpOwogICAgfQogICAgd2FsbEdlb21ldHJ5Ll9lbGxpcHNvaWQgPSBFbGxpcHNvaWRfZGVmYXVsdC5jbG9uZSh3YWxsR2VvbWV0cnkuX2VsbGlwc29pZCk7CiAgICByZXR1cm4gV2FsbE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0LmNyZWF0ZUdlb21ldHJ5KHdhbGxHZW9tZXRyeSk7CiAgfQogIHZhciBjcmVhdGVXYWxsT3V0bGluZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeSA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeS5qcyIoKSB7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X1dhbGxPdXRsaW5lR2VvbWV0cnkoKTsKICAgICAgY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeV9kZWZhdWx0ID0gY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeTsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL2RyYWNvM2QvZHJhY29fZGVjb2Rlcl9ub2RlanMuanMKICB2YXIgcmVxdWlyZV9kcmFjb19kZWNvZGVyX25vZGVqcyA9IF9fY29tbW9uSlMoewogICAgIm5vZGVfbW9kdWxlcy9kcmFjbzNkL2RyYWNvX2RlY29kZXJfbm9kZWpzLmpzIihleHBvcnRzMiwgbW9kdWxlKSB7CiAgICAgIHZhciAkanNjb21wID0gJGpzY29tcCB8fCB7fTsKICAgICAgJGpzY29tcC5zY29wZSA9IHt9OwogICAgICAkanNjb21wLmFycmF5SXRlcmF0b3JJbXBsID0gZnVuY3Rpb24oazIpIHsKICAgICAgICB2YXIgbjIgPSAwOwogICAgICAgIHJldHVybiBmdW5jdGlvbigpIHsKICAgICAgICAgIHJldHVybiBuMiA8IGsyLmxlbmd0aCA/IHsgZG9uZTogZmFsc2UsIHZhbHVlOiBrMltuMisrXSB9IDogeyBkb25lOiB0cnVlIH07CiAgICAgICAgfTsKICAgICAgfTsKICAgICAgJGpzY29tcC5hcnJheUl0ZXJhdG9yID0gZnVuY3Rpb24oazIpIHsKICAgICAgICByZXR1cm4geyBuZXh0OiAkanNjb21wLmFycmF5SXRlcmF0b3JJbXBsKGsyKSB9OwogICAgICB9OwogICAgICAkanNjb21wLm1ha2VJdGVyYXRvciA9IGZ1bmN0aW9uKGsyKSB7CiAgICAgICAgdmFyIG4yID0gInVuZGVmaW5lZCIgIT0gdHlwZW9mIFN5bWJvbCAmJiBTeW1ib2wuaXRlcmF0b3IgJiYgazJbU3ltYm9sLml0ZXJhdG9yXTsKICAgICAgICByZXR1cm4gbjIgPyBuMi5jYWxsKGsyKSA6ICRqc2NvbXAuYXJyYXlJdGVyYXRvcihrMik7CiAgICAgIH07CiAgICAgICRqc2NvbXAuQVNTVU1FX0VTNSA9IGZhbHNlOwogICAgICAkanNjb21wLkFTU1VNRV9OT19OQVRJVkVfTUFQID0gZmFsc2U7CiAgICAgICRqc2NvbXAuQVNTVU1FX05PX05BVElWRV9TRVQgPSBmYWxzZTsKICAgICAgJGpzY29tcC5TSU1QTEVfRlJPVU5EX1BPTFlGSUxMID0gZmFsc2U7CiAgICAgICRqc2NvbXAuSVNPTEFURV9QT0xZRklMTFMgPSBmYWxzZTsKICAgICAgJGpzY29tcC5GT1JDRV9QT0xZRklMTF9QUk9NSVNFID0gZmFsc2U7CiAgICAgICRqc2NvbXAuRk9SQ0VfUE9MWUZJTExfUFJPTUlTRV9XSEVOX05PX1VOSEFORExFRF9SRUpFQ1RJT04gPSBmYWxzZTsKICAgICAgJGpzY29tcC5nZXRHbG9iYWwgPSBmdW5jdGlvbihrMikgewogICAgICAgIGsyID0gWyJvYmplY3QiID09IHR5cGVvZiBnbG9iYWxUaGlzICYmIGdsb2JhbFRoaXMsIGsyLCAib2JqZWN0IiA9PSB0eXBlb2Ygd2luZG93ICYmIHdpbmRvdywgIm9iamVjdCIgPT0gdHlwZW9mIHNlbGYgJiYgc2VsZiwgIm9iamVjdCIgPT0gdHlwZW9mIGdsb2JhbCAmJiBnbG9iYWxdOwogICAgICAgIGZvciAodmFyIG4yID0gMDsgbjIgPCBrMi5sZW5ndGg7ICsrbjIpIHsKICAgICAgICAgIHZhciBsMiA9IGsyW24yXTsKICAgICAgICAgIGlmIChsMiAmJiBsMi5NYXRoID09IE1hdGgpIHJldHVybiBsMjsKICAgICAgICB9CiAgICAgICAgdGhyb3cgRXJyb3IoIkNhbm5vdCBmaW5kIGdsb2JhbCBvYmplY3QiKTsKICAgICAgfTsKICAgICAgJGpzY29tcC5nbG9iYWwgPSAkanNjb21wLmdldEdsb2JhbChleHBvcnRzMik7CiAgICAgICRqc2NvbXAuZGVmaW5lUHJvcGVydHkgPSAkanNjb21wLkFTU1VNRV9FUzUgfHwgImZ1bmN0aW9uIiA9PSB0eXBlb2YgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMgPyBPYmplY3QuZGVmaW5lUHJvcGVydHkgOiBmdW5jdGlvbihrMiwgbjIsIGwyKSB7CiAgICAgICAgaWYgKGsyID09IEFycmF5LnByb3RvdHlwZSB8fCBrMiA9PSBPYmplY3QucHJvdG90eXBlKSByZXR1cm4gazI7CiAgICAgICAgazJbbjJdID0gbDIudmFsdWU7CiAgICAgICAgcmV0dXJuIGsyOwogICAgICB9OwogICAgICAkanNjb21wLklTX1NZTUJPTF9OQVRJVkUgPSAiZnVuY3Rpb24iID09PSB0eXBlb2YgU3ltYm9sICYmICJzeW1ib2wiID09PSB0eXBlb2YgLyogQF9fUFVSRV9fICovIFN5bWJvbCgieCIpOwogICAgICAkanNjb21wLlRSVVNUX0VTNl9QT0xZRklMTFMgPSAhJGpzY29tcC5JU09MQVRFX1BPTFlGSUxMUyB8fCAkanNjb21wLklTX1NZTUJPTF9OQVRJVkU7CiAgICAgICRqc2NvbXAucG9seWZpbGxzID0ge307CiAgICAgICRqc2NvbXAucHJvcGVydHlUb1BvbHlmaWxsU3ltYm9sID0ge307CiAgICAgICRqc2NvbXAuUE9MWUZJTExfUFJFRklYID0gIiRqc2NwJCI7CiAgICAgICRqc2NvbXAucG9seWZpbGwgPSBmdW5jdGlvbihrMiwgbjIsIGwyLCBwMikgewogICAgICAgIG4yICYmICgkanNjb21wLklTT0xBVEVfUE9MWUZJTExTID8gJGpzY29tcC5wb2x5ZmlsbElzb2xhdGVkKGsyLCBuMiwgbDIsIHAyKSA6ICRqc2NvbXAucG9seWZpbGxVbmlzb2xhdGVkKGsyLCBuMiwgbDIsIHAyKSk7CiAgICAgIH07CiAgICAgICRqc2NvbXAucG9seWZpbGxVbmlzb2xhdGVkID0gZnVuY3Rpb24oazIsIG4yLCBsMiwgcDIpIHsKICAgICAgICBsMiA9ICRqc2NvbXAuZ2xvYmFsOwogICAgICAgIGsyID0gazIuc3BsaXQoIi4iKTsKICAgICAgICBmb3IgKHAyID0gMDsgcDIgPCBrMi5sZW5ndGggLSAxOyBwMisrKSB7CiAgICAgICAgICB2YXIgaDIgPSBrMltwMl07CiAgICAgICAgICBpZiAoIShoMiBpbiBsMikpIHJldHVybjsKICAgICAgICAgIGwyID0gbDJbaDJdOwogICAgICAgIH0KICAgICAgICBrMiA9IGsyW2syLmxlbmd0aCAtIDFdOwogICAgICAgIHAyID0gbDJbazJdOwogICAgICAgIG4yID0gbjIocDIpOwogICAgICAgIG4yICE9IHAyICYmIG51bGwgIT0gbjIgJiYgJGpzY29tcC5kZWZpbmVQcm9wZXJ0eShsMiwgazIsIHsgY29uZmlndXJhYmxlOiB0cnVlLCB3cml0YWJsZTogdHJ1ZSwgdmFsdWU6IG4yIH0pOwogICAgICB9OwogICAgICAkanNjb21wLnBvbHlmaWxsSXNvbGF0ZWQgPSBmdW5jdGlvbihrMiwgbjIsIGwyLCBwMikgewogICAgICAgIHZhciBoMiA9IGsyLnNwbGl0KCIuIik7CiAgICAgICAgazIgPSAxID09PSBoMi5sZW5ndGg7CiAgICAgICAgcDIgPSBoMlswXTsKICAgICAgICBwMiA9ICFrMiAmJiBwMiBpbiAkanNjb21wLnBvbHlmaWxscyA/ICRqc2NvbXAucG9seWZpbGxzIDogJGpzY29tcC5nbG9iYWw7CiAgICAgICAgZm9yICh2YXIgQTIgPSAwOyBBMiA8IGgyLmxlbmd0aCAtIDE7IEEyKyspIHsKICAgICAgICAgIHZhciBmMiA9IGgyW0EyXTsKICAgICAgICAgIGlmICghKGYyIGluIHAyKSkgcmV0dXJuOwogICAgICAgICAgcDIgPSBwMltmMl07CiAgICAgICAgfQogICAgICAgIGgyID0gaDJbaDIubGVuZ3RoIC0gMV07CiAgICAgICAgbDIgPSAkanNjb21wLklTX1NZTUJPTF9OQVRJVkUgJiYgImVzNiIgPT09IGwyID8gcDJbaDJdIDogbnVsbDsKICAgICAgICBuMiA9IG4yKGwyKTsKICAgICAgICBudWxsICE9IG4yICYmIChrMiA/ICRqc2NvbXAuZGVmaW5lUHJvcGVydHkoJGpzY29tcC5wb2x5ZmlsbHMsIGgyLCB7IGNvbmZpZ3VyYWJsZTogdHJ1ZSwgd3JpdGFibGU6IHRydWUsIHZhbHVlOiBuMiB9KSA6IG4yICE9PSBsMiAmJiAodm9pZCAwID09PSAkanNjb21wLnByb3BlcnR5VG9Qb2x5ZmlsbFN5bWJvbFtoMl0gJiYgKGwyID0gMWU5ICogTWF0aC5yYW5kb20oKSA+Pj4gMCwgJGpzY29tcC5wcm9wZXJ0eVRvUG9seWZpbGxTeW1ib2xbaDJdID0gJGpzY29tcC5JU19TWU1CT0xfTkFUSVZFID8gJGpzY29tcC5nbG9iYWwuU3ltYm9sKGgyKSA6ICRqc2NvbXAuUE9MWUZJTExfUFJFRklYICsgbDIgKyAiJCIgKyBoMiksICRqc2NvbXAuZGVmaW5lUHJvcGVydHkocDIsICRqc2NvbXAucHJvcGVydHlUb1BvbHlmaWxsU3ltYm9sW2gyXSwgeyBjb25maWd1cmFibGU6IHRydWUsIHdyaXRhYmxlOiB0cnVlLCB2YWx1ZTogbjIgfSkpKTsKICAgICAgfTsKICAgICAgJGpzY29tcC5wb2x5ZmlsbCgiUHJvbWlzZSIsIGZ1bmN0aW9uKGsyKSB7CiAgICAgICAgZnVuY3Rpb24gbjIoKSB7CiAgICAgICAgICB0aGlzLmJhdGNoXyA9IG51bGw7CiAgICAgICAgfQogICAgICAgIGZ1bmN0aW9uIGwyKGYyKSB7CiAgICAgICAgICByZXR1cm4gZjIgaW5zdGFuY2VvZiBoMiA/IGYyIDogbmV3IGgyKGZ1bmN0aW9uKHEzLCB2NCkgewogICAgICAgICAgICBxMyhmMik7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgICAgaWYgKGsyICYmICghKCRqc2NvbXAuRk9SQ0VfUE9MWUZJTExfUFJPTUlTRSB8fCAkanNjb21wLkZPUkNFX1BPTFlGSUxMX1BST01JU0VfV0hFTl9OT19VTkhBTkRMRURfUkVKRUNUSU9OICYmICJ1bmRlZmluZWQiID09PSB0eXBlb2YgJGpzY29tcC5nbG9iYWwuUHJvbWlzZVJlamVjdGlvbkV2ZW50KSB8fCAhJGpzY29tcC5nbG9iYWwuUHJvbWlzZSB8fCAtMSA9PT0gJGpzY29tcC5nbG9iYWwuUHJvbWlzZS50b1N0cmluZygpLmluZGV4T2YoIltuYXRpdmUgY29kZV0iKSkpIHJldHVybiBrMjsKICAgICAgICBuMi5wcm90b3R5cGUuYXN5bmNFeGVjdXRlID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIGlmIChudWxsID09IHRoaXMuYmF0Y2hfKSB7CiAgICAgICAgICAgIHRoaXMuYmF0Y2hfID0gW107CiAgICAgICAgICAgIHZhciBxMyA9IHRoaXM7CiAgICAgICAgICAgIHRoaXMuYXN5bmNFeGVjdXRlRnVuY3Rpb24oZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgcTMuZXhlY3V0ZUJhdGNoXygpOwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuYmF0Y2hfLnB1c2goZjIpOwogICAgICAgIH07CiAgICAgICAgdmFyIHAyID0gJGpzY29tcC5nbG9iYWwuc2V0VGltZW91dDsKICAgICAgICBuMi5wcm90b3R5cGUuYXN5bmNFeGVjdXRlRnVuY3Rpb24gPSBmdW5jdGlvbihmMikgewogICAgICAgICAgcDIoZjIsIDApOwogICAgICAgIH07CiAgICAgICAgbjIucHJvdG90eXBlLmV4ZWN1dGVCYXRjaF8gPSBmdW5jdGlvbigpIHsKICAgICAgICAgIGZvciAoOyB0aGlzLmJhdGNoXyAmJiB0aGlzLmJhdGNoXy5sZW5ndGg7ICkgewogICAgICAgICAgICB2YXIgZjIgPSB0aGlzLmJhdGNoXzsKICAgICAgICAgICAgdGhpcy5iYXRjaF8gPSBbXTsKICAgICAgICAgICAgZm9yICh2YXIgcTMgPSAwOyBxMyA8IGYyLmxlbmd0aDsgKytxMykgewogICAgICAgICAgICAgIHZhciB2NCA9IGYyW3EzXTsKICAgICAgICAgICAgICBmMltxM10gPSBudWxsOwogICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICB2NCgpOwogICAgICAgICAgICAgIH0gY2F0Y2ggKHoyKSB7CiAgICAgICAgICAgICAgICB0aGlzLmFzeW5jVGhyb3dfKHoyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHRoaXMuYmF0Y2hfID0gbnVsbDsKICAgICAgICB9OwogICAgICAgIG4yLnByb3RvdHlwZS5hc3luY1Rocm93XyA9IGZ1bmN0aW9uKGYyKSB7CiAgICAgICAgICB0aGlzLmFzeW5jRXhlY3V0ZUZ1bmN0aW9uKGZ1bmN0aW9uKCkgewogICAgICAgICAgICB0aHJvdyBmMjsKICAgICAgICAgIH0pOwogICAgICAgIH07CiAgICAgICAgdmFyIGgyID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIHRoaXMuc3RhdGVfID0gMDsKICAgICAgICAgIHRoaXMucmVzdWx0XyA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMub25TZXR0bGVkQ2FsbGJhY2tzXyA9IFtdOwogICAgICAgICAgdGhpcy5pc1JlamVjdGlvbkhhbmRsZWRfID0gZmFsc2U7CiAgICAgICAgICB2YXIgcTMgPSB0aGlzLmNyZWF0ZVJlc29sdmVBbmRSZWplY3RfKCk7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBmMihxMy5yZXNvbHZlLCBxMy5yZWplY3QpOwogICAgICAgICAgfSBjYXRjaCAodjQpIHsKICAgICAgICAgICAgcTMucmVqZWN0KHY0KTsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5jcmVhdGVSZXNvbHZlQW5kUmVqZWN0XyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgZnVuY3Rpb24gZjIoejIpIHsKICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKE8yKSB7CiAgICAgICAgICAgICAgdjQgfHwgKHY0ID0gdHJ1ZSwgejIuY2FsbChxMywgTzIpKTsKICAgICAgICAgICAgfTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBxMyA9IHRoaXMsIHY0ID0gZmFsc2U7CiAgICAgICAgICByZXR1cm4geyByZXNvbHZlOiBmMih0aGlzLnJlc29sdmVUb18pLCByZWplY3Q6IGYyKHRoaXMucmVqZWN0XykgfTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5yZXNvbHZlVG9fID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIGlmIChmMiA9PT0gdGhpcykgdGhpcy5yZWplY3RfKG5ldyBUeXBlRXJyb3IoIkEgUHJvbWlzZSBjYW5ub3QgcmVzb2x2ZSB0byBpdHNlbGYiKSk7CiAgICAgICAgICBlbHNlIGlmIChmMiBpbnN0YW5jZW9mIGgyKSB0aGlzLnNldHRsZVNhbWVBc1Byb21pc2VfKGYyKTsKICAgICAgICAgIGVsc2UgewogICAgICAgICAgICBhOiBzd2l0Y2ggKHR5cGVvZiBmMikgewogICAgICAgICAgICAgIGNhc2UgIm9iamVjdCI6CiAgICAgICAgICAgICAgICB2YXIgcTMgPSBudWxsICE9IGYyOwogICAgICAgICAgICAgICAgYnJlYWsgYTsKICAgICAgICAgICAgICBjYXNlICJmdW5jdGlvbiI6CiAgICAgICAgICAgICAgICBxMyA9IHRydWU7CiAgICAgICAgICAgICAgICBicmVhayBhOwogICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICBxMyA9IGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHEzID8gdGhpcy5yZXNvbHZlVG9Ob25Qcm9taXNlT2JqXyhmMikgOiB0aGlzLmZ1bGZpbGxfKGYyKTsKICAgICAgICAgIH0KICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5yZXNvbHZlVG9Ob25Qcm9taXNlT2JqXyA9IGZ1bmN0aW9uKGYyKSB7CiAgICAgICAgICB2YXIgcTMgPSB2b2lkIDA7CiAgICAgICAgICB0cnkgewogICAgICAgICAgICBxMyA9IGYyLnRoZW47CiAgICAgICAgICB9IGNhdGNoICh2NCkgewogICAgICAgICAgICB0aGlzLnJlamVjdF8odjQpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgICAiZnVuY3Rpb24iID09IHR5cGVvZiBxMyA/IHRoaXMuc2V0dGxlU2FtZUFzVGhlbmFibGVfKHEzLCBmMikgOiB0aGlzLmZ1bGZpbGxfKGYyKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5yZWplY3RfID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIHRoaXMuc2V0dGxlXygyLCBmMik7CiAgICAgICAgfTsKICAgICAgICBoMi5wcm90b3R5cGUuZnVsZmlsbF8gPSBmdW5jdGlvbihmMikgewogICAgICAgICAgdGhpcy5zZXR0bGVfKDEsIGYyKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5zZXR0bGVfID0gZnVuY3Rpb24oZjIsIHEzKSB7CiAgICAgICAgICBpZiAoMCAhPSB0aGlzLnN0YXRlXykgdGhyb3cgRXJyb3IoIkNhbm5vdCBzZXR0bGUoIiArIGYyICsgIiwgIiArIHEzICsgIik6IFByb21pc2UgYWxyZWFkeSBzZXR0bGVkIGluIHN0YXRlIiArIHRoaXMuc3RhdGVfKTsKICAgICAgICAgIHRoaXMuc3RhdGVfID0gZjI7CiAgICAgICAgICB0aGlzLnJlc3VsdF8gPSBxMzsKICAgICAgICAgIDIgPT09IHRoaXMuc3RhdGVfICYmIHRoaXMuc2NoZWR1bGVVbmhhbmRsZWRSZWplY3Rpb25DaGVja18oKTsKICAgICAgICAgIHRoaXMuZXhlY3V0ZU9uU2V0dGxlZENhbGxiYWNrc18oKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5zY2hlZHVsZVVuaGFuZGxlZFJlamVjdGlvbkNoZWNrXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgdmFyIGYyID0gdGhpczsKICAgICAgICAgIHAyKGZ1bmN0aW9uKCkgewogICAgICAgICAgICBpZiAoZjIubm90aWZ5VW5oYW5kbGVkUmVqZWN0aW9uXygpKSB7CiAgICAgICAgICAgICAgdmFyIHEzID0gJGpzY29tcC5nbG9iYWwuY29uc29sZTsKICAgICAgICAgICAgICAidW5kZWZpbmVkIiAhPT0gdHlwZW9mIHEzICYmIHEzLmVycm9yKGYyLnJlc3VsdF8pOwogICAgICAgICAgICB9CiAgICAgICAgICB9LCAxKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5ub3RpZnlVbmhhbmRsZWRSZWplY3Rpb25fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICBpZiAodGhpcy5pc1JlamVjdGlvbkhhbmRsZWRfKSByZXR1cm4gZmFsc2U7CiAgICAgICAgICB2YXIgZjIgPSAkanNjb21wLmdsb2JhbC5DdXN0b21FdmVudCwgcTMgPSAkanNjb21wLmdsb2JhbC5FdmVudCwgdjQgPSAkanNjb21wLmdsb2JhbC5kaXNwYXRjaEV2ZW50OwogICAgICAgICAgaWYgKCJ1bmRlZmluZWQiID09PSB0eXBlb2YgdjQpIHJldHVybiB0cnVlOwogICAgICAgICAgImZ1bmN0aW9uIiA9PT0gdHlwZW9mIGYyID8gZjIgPSBuZXcgZjIoInVuaGFuZGxlZHJlamVjdGlvbiIsIHsgY2FuY2VsYWJsZTogdHJ1ZSB9KSA6ICJmdW5jdGlvbiIgPT09IHR5cGVvZiBxMyA/IGYyID0gbmV3IHEzKCJ1bmhhbmRsZWRyZWplY3Rpb24iLCB7IGNhbmNlbGFibGU6IHRydWUgfSkgOiAoZjIgPSAkanNjb21wLmdsb2JhbC5kb2N1bWVudC5jcmVhdGVFdmVudCgiQ3VzdG9tRXZlbnQiKSwgZjIuaW5pdEN1c3RvbUV2ZW50KCJ1bmhhbmRsZWRyZWplY3Rpb24iLCBmYWxzZSwgdHJ1ZSwgZjIpKTsKICAgICAgICAgIGYyLnByb21pc2UgPSB0aGlzOwogICAgICAgICAgZjIucmVhc29uID0gdGhpcy5yZXN1bHRfOwogICAgICAgICAgcmV0dXJuIHY0KGYyKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5leGVjdXRlT25TZXR0bGVkQ2FsbGJhY2tzXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgaWYgKG51bGwgIT0gdGhpcy5vblNldHRsZWRDYWxsYmFja3NfKSB7CiAgICAgICAgICAgIGZvciAodmFyIGYyID0gMDsgZjIgPCB0aGlzLm9uU2V0dGxlZENhbGxiYWNrc18ubGVuZ3RoOyArK2YyKSBBMi5hc3luY0V4ZWN1dGUodGhpcy5vblNldHRsZWRDYWxsYmFja3NfW2YyXSk7CiAgICAgICAgICAgIHRoaXMub25TZXR0bGVkQ2FsbGJhY2tzXyA9IG51bGw7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICB2YXIgQTIgPSBuZXcgbjIoKTsKICAgICAgICBoMi5wcm90b3R5cGUuc2V0dGxlU2FtZUFzUHJvbWlzZV8gPSBmdW5jdGlvbihmMikgewogICAgICAgICAgdmFyIHEzID0gdGhpcy5jcmVhdGVSZXNvbHZlQW5kUmVqZWN0XygpOwogICAgICAgICAgZjIuY2FsbFdoZW5TZXR0bGVkXyhxMy5yZXNvbHZlLCBxMy5yZWplY3QpOwogICAgICAgIH07CiAgICAgICAgaDIucHJvdG90eXBlLnNldHRsZVNhbWVBc1RoZW5hYmxlXyA9IGZ1bmN0aW9uKGYyLCBxMykgewogICAgICAgICAgdmFyIHY0ID0gdGhpcy5jcmVhdGVSZXNvbHZlQW5kUmVqZWN0XygpOwogICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgZjIuY2FsbChxMywgdjQucmVzb2x2ZSwgdjQucmVqZWN0KTsKICAgICAgICAgIH0gY2F0Y2ggKHoyKSB7CiAgICAgICAgICAgIHY0LnJlamVjdCh6Mik7CiAgICAgICAgICB9CiAgICAgICAgfTsKICAgICAgICBoMi5wcm90b3R5cGUudGhlbiA9IGZ1bmN0aW9uKGYyLCBxMykgewogICAgICAgICAgZnVuY3Rpb24gdjQodDIsIHgyKSB7CiAgICAgICAgICAgIHJldHVybiAiZnVuY3Rpb24iID09IHR5cGVvZiB0MiA/IGZ1bmN0aW9uKEQyKSB7CiAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHoyKHQyKEQyKSk7CiAgICAgICAgICAgICAgfSBjYXRjaCAoUjIpIHsKICAgICAgICAgICAgICAgIE8yKFIyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gOiB4MjsKICAgICAgICAgIH0KICAgICAgICAgIHZhciB6MiwgTzIsIGJhID0gbmV3IGgyKGZ1bmN0aW9uKHQyLCB4MikgewogICAgICAgICAgICB6MiA9IHQyOwogICAgICAgICAgICBPMiA9IHgyOwogICAgICAgICAgfSk7CiAgICAgICAgICB0aGlzLmNhbGxXaGVuU2V0dGxlZF8odjQoZjIsIHoyKSwgdjQocTMsIE8yKSk7CiAgICAgICAgICByZXR1cm4gYmE7CiAgICAgICAgfTsKICAgICAgICBoMi5wcm90b3R5cGUuY2F0Y2ggPSBmdW5jdGlvbihmMikgewogICAgICAgICAgcmV0dXJuIHRoaXMudGhlbih2b2lkIDAsIGYyKTsKICAgICAgICB9OwogICAgICAgIGgyLnByb3RvdHlwZS5jYWxsV2hlblNldHRsZWRfID0gZnVuY3Rpb24oZjIsIHEzKSB7CiAgICAgICAgICBmdW5jdGlvbiB2NCgpIHsKICAgICAgICAgICAgc3dpdGNoICh6Mi5zdGF0ZV8pIHsKICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICBmMih6Mi5yZXN1bHRfKTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgIHEzKHoyLnJlc3VsdF8pOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgIHRocm93IEVycm9yKCJVbmV4cGVjdGVkIHN0YXRlOiAiICsgejIuc3RhdGVfKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdmFyIHoyID0gdGhpczsKICAgICAgICAgIG51bGwgPT0gdGhpcy5vblNldHRsZWRDYWxsYmFja3NfID8gQTIuYXN5bmNFeGVjdXRlKHY0KSA6IHRoaXMub25TZXR0bGVkQ2FsbGJhY2tzXy5wdXNoKHY0KTsKICAgICAgICAgIHRoaXMuaXNSZWplY3Rpb25IYW5kbGVkXyA9IHRydWU7CiAgICAgICAgfTsKICAgICAgICBoMi5yZXNvbHZlID0gbDI7CiAgICAgICAgaDIucmVqZWN0ID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIHJldHVybiBuZXcgaDIoZnVuY3Rpb24ocTMsIHY0KSB7CiAgICAgICAgICAgIHY0KGYyKTsKICAgICAgICAgIH0pOwogICAgICAgIH07CiAgICAgICAgaDIucmFjZSA9IGZ1bmN0aW9uKGYyKSB7CiAgICAgICAgICByZXR1cm4gbmV3IGgyKGZ1bmN0aW9uKHEzLCB2NCkgewogICAgICAgICAgICBmb3IgKHZhciB6MiA9ICRqc2NvbXAubWFrZUl0ZXJhdG9yKGYyKSwgTzIgPSB6Mi5uZXh0KCk7ICFPMi5kb25lOyBPMiA9IHoyLm5leHQoKSkgbDIoTzIudmFsdWUpLmNhbGxXaGVuU2V0dGxlZF8ocTMsIHY0KTsKICAgICAgICAgIH0pOwogICAgICAgIH07CiAgICAgICAgaDIuYWxsID0gZnVuY3Rpb24oZjIpIHsKICAgICAgICAgIHZhciBxMyA9ICRqc2NvbXAubWFrZUl0ZXJhdG9yKGYyKSwgdjQgPSBxMy5uZXh0KCk7CiAgICAgICAgICByZXR1cm4gdjQuZG9uZSA/IGwyKFtdKSA6IG5ldyBoMihmdW5jdGlvbih6MiwgTzIpIHsKICAgICAgICAgICAgZnVuY3Rpb24gYmEoRDIpIHsKICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oUjIpIHsKICAgICAgICAgICAgICAgIHQyW0QyXSA9IFIyOwogICAgICAgICAgICAgICAgeDItLTsKICAgICAgICAgICAgICAgIDAgPT0geDIgJiYgejIodDIpOwogICAgICAgICAgICAgIH07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHQyID0gW10sIHgyID0gMDsKICAgICAgICAgICAgZG8KICAgICAgICAgICAgICB0Mi5wdXNoKHZvaWQgMCksIHgyKyssIGwyKHY0LnZhbHVlKS5jYWxsV2hlblNldHRsZWRfKGJhKHQyLmxlbmd0aCAtIDEpLCBPMiksIHY0ID0gcTMubmV4dCgpOwogICAgICAgICAgICB3aGlsZSAoIXY0LmRvbmUpOwogICAgICAgICAgfSk7CiAgICAgICAgfTsKICAgICAgICByZXR1cm4gaDI7CiAgICAgIH0sICJlczYiLCAiZXMzIik7CiAgICAgICRqc2NvbXAub3ducyA9IGZ1bmN0aW9uKGsyLCBuMikgewogICAgICAgIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoazIsIG4yKTsKICAgICAgfTsKICAgICAgJGpzY29tcC5hc3NpZ24gPSAkanNjb21wLlRSVVNUX0VTNl9QT0xZRklMTFMgJiYgImZ1bmN0aW9uIiA9PSB0eXBlb2YgT2JqZWN0LmFzc2lnbiA/IE9iamVjdC5hc3NpZ24gOiBmdW5jdGlvbihrMiwgbjIpIHsKICAgICAgICBmb3IgKHZhciBsMiA9IDE7IGwyIDwgYXJndW1lbnRzLmxlbmd0aDsgbDIrKykgewogICAgICAgICAgdmFyIHAyID0gYXJndW1lbnRzW2wyXTsKICAgICAgICAgIGlmIChwMikgZm9yICh2YXIgaDIgaW4gcDIpICRqc2NvbXAub3ducyhwMiwgaDIpICYmIChrMltoMl0gPSBwMltoMl0pOwogICAgICAgIH0KICAgICAgICByZXR1cm4gazI7CiAgICAgIH07CiAgICAgICRqc2NvbXAucG9seWZpbGwoIk9iamVjdC5hc3NpZ24iLCBmdW5jdGlvbihrMikgewogICAgICAgIHJldHVybiBrMiB8fCAkanNjb21wLmFzc2lnbjsKICAgICAgfSwgImVzNiIsICJlczMiKTsKICAgICAgJGpzY29tcC5jaGVja1N0cmluZ0FyZ3MgPSBmdW5jdGlvbihrMiwgbjIsIGwyKSB7CiAgICAgICAgaWYgKG51bGwgPT0gazIpIHRocm93IG5ldyBUeXBlRXJyb3IoIlRoZSAndGhpcycgdmFsdWUgZm9yIFN0cmluZy5wcm90b3R5cGUuIiArIGwyICsgIiBtdXN0IG5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZCIpOwogICAgICAgIGlmIChuMiBpbnN0YW5jZW9mIFJlZ0V4cCkgdGhyb3cgbmV3IFR5cGVFcnJvcigiRmlyc3QgYXJndW1lbnQgdG8gU3RyaW5nLnByb3RvdHlwZS4iICsgbDIgKyAiIG11c3Qgbm90IGJlIGEgcmVndWxhciBleHByZXNzaW9uIik7CiAgICAgICAgcmV0dXJuIGsyICsgIiI7CiAgICAgIH07CiAgICAgICRqc2NvbXAucG9seWZpbGwoIlN0cmluZy5wcm90b3R5cGUuc3RhcnRzV2l0aCIsIGZ1bmN0aW9uKGsyKSB7CiAgICAgICAgcmV0dXJuIGsyID8gazIgOiBmdW5jdGlvbihuMiwgbDIpIHsKICAgICAgICAgIHZhciBwMiA9ICRqc2NvbXAuY2hlY2tTdHJpbmdBcmdzKHRoaXMsIG4yLCAic3RhcnRzV2l0aCIpOwogICAgICAgICAgbjIgKz0gIiI7CiAgICAgICAgICB2YXIgaDIgPSBwMi5sZW5ndGgsIEEyID0gbjIubGVuZ3RoOwogICAgICAgICAgbDIgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihsMiB8IDAsIHAyLmxlbmd0aCkpOwogICAgICAgICAgZm9yICh2YXIgZjIgPSAwOyBmMiA8IEEyICYmIGwyIDwgaDI7ICkgaWYgKHAyW2wyKytdICE9IG4yW2YyKytdKSByZXR1cm4gZmFsc2U7CiAgICAgICAgICByZXR1cm4gZjIgPj0gQTI7CiAgICAgICAgfTsKICAgICAgfSwgImVzNiIsICJlczMiKTsKICAgICAgJGpzY29tcC5wb2x5ZmlsbCgiQXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCBmdW5jdGlvbihrMikgewogICAgICAgIGZ1bmN0aW9uIG4yKGwyKSB7CiAgICAgICAgICBsMiA9IE51bWJlcihsMik7CiAgICAgICAgICByZXR1cm4gSW5maW5pdHkgPT09IGwyIHx8IC1JbmZpbml0eSA9PT0gbDIgPyBsMiA6IGwyIHwgMDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGsyID8gazIgOiBmdW5jdGlvbihsMiwgcDIsIGgyKSB7CiAgICAgICAgICB2YXIgQTIgPSB0aGlzLmxlbmd0aDsKICAgICAgICAgIGwyID0gbjIobDIpOwogICAgICAgICAgcDIgPSBuMihwMik7CiAgICAgICAgICBoMiA9IHZvaWQgMCA9PT0gaDIgPyBBMiA6IG4yKGgyKTsKICAgICAgICAgIGwyID0gMCA+IGwyID8gTWF0aC5tYXgoQTIgKyBsMiwgMCkgOiBNYXRoLm1pbihsMiwgQTIpOwogICAgICAgICAgcDIgPSAwID4gcDIgPyBNYXRoLm1heChBMiArIHAyLCAwKSA6IE1hdGgubWluKHAyLCBBMik7CiAgICAgICAgICBoMiA9IDAgPiBoMiA/IE1hdGgubWF4KEEyICsgaDIsIDApIDogTWF0aC5taW4oaDIsIEEyKTsKICAgICAgICAgIGlmIChsMiA8IHAyKSBmb3IgKDsgcDIgPCBoMjsgKSBwMiBpbiB0aGlzID8gdGhpc1tsMisrXSA9IHRoaXNbcDIrK10gOiAoZGVsZXRlIHRoaXNbbDIrK10sIHAyKyspOwogICAgICAgICAgZWxzZSBmb3IgKGgyID0gTWF0aC5taW4oaDIsIEEyICsgcDIgLSBsMiksIGwyICs9IGgyIC0gcDI7IGgyID4gcDI7ICkgLS1oMiBpbiB0aGlzID8gdGhpc1stLWwyXSA9IHRoaXNbaDJdIDogZGVsZXRlIHRoaXNbLS1sMl07CiAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICB9OwogICAgICB9LCAiZXM2IiwgImVzMyIpOwogICAgICAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluID0gZnVuY3Rpb24oazIpIHsKICAgICAgICByZXR1cm4gazIgPyBrMiA6IEFycmF5LnByb3RvdHlwZS5jb3B5V2l0aGluOwogICAgICB9OwogICAgICAkanNjb21wLnBvbHlmaWxsKCJJbnQ4QXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICAkanNjb21wLnBvbHlmaWxsKCJVaW50OEFycmF5LnByb3RvdHlwZS5jb3B5V2l0aGluIiwgJGpzY29tcC50eXBlZEFycmF5Q29weVdpdGhpbiwgImVzNiIsICJlczUiKTsKICAgICAgJGpzY29tcC5wb2x5ZmlsbCgiVWludDhDbGFtcGVkQXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICAkanNjb21wLnBvbHlmaWxsKCJJbnQxNkFycmF5LnByb3RvdHlwZS5jb3B5V2l0aGluIiwgJGpzY29tcC50eXBlZEFycmF5Q29weVdpdGhpbiwgImVzNiIsICJlczUiKTsKICAgICAgJGpzY29tcC5wb2x5ZmlsbCgiVWludDE2QXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICAkanNjb21wLnBvbHlmaWxsKCJJbnQzMkFycmF5LnByb3RvdHlwZS5jb3B5V2l0aGluIiwgJGpzY29tcC50eXBlZEFycmF5Q29weVdpdGhpbiwgImVzNiIsICJlczUiKTsKICAgICAgJGpzY29tcC5wb2x5ZmlsbCgiVWludDMyQXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICAkanNjb21wLnBvbHlmaWxsKCJGbG9hdDMyQXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICAkanNjb21wLnBvbHlmaWxsKCJGbG9hdDY0QXJyYXkucHJvdG90eXBlLmNvcHlXaXRoaW4iLCAkanNjb21wLnR5cGVkQXJyYXlDb3B5V2l0aGluLCAiZXM2IiwgImVzNSIpOwogICAgICB2YXIgRHJhY29EZWNvZGVyTW9kdWxlID0gKGZ1bmN0aW9uKCkgewogICAgICAgIHZhciBrMiA9ICJ1bmRlZmluZWQiICE9PSB0eXBlb2YgZG9jdW1lbnQgJiYgZG9jdW1lbnQuY3VycmVudFNjcmlwdCA/IGRvY3VtZW50LmN1cnJlbnRTY3JpcHQuc3JjIDogdm9pZCAwOwogICAgICAgICJ1bmRlZmluZWQiICE9PSB0eXBlb2YgX19maWxlbmFtZSAmJiAoazIgPSBrMiB8fCBfX2ZpbGVuYW1lKTsKICAgICAgICByZXR1cm4gZnVuY3Rpb24objIpIHsKICAgICAgICAgIGZ1bmN0aW9uIGwyKGUyKSB7CiAgICAgICAgICAgIHJldHVybiBhNC5sb2NhdGVGaWxlID8gYTQubG9jYXRlRmlsZShlMiwgVTIpIDogVTIgKyBlMjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHAyKGUyLCBiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gYjIgKyBjMjsKICAgICAgICAgICAgZm9yIChjMiA9IGIyOyBlMltjMl0gJiYgIShjMiA+PSBkMik7ICkgKytjMjsKICAgICAgICAgICAgaWYgKDE2IDwgYzIgLSBiMiAmJiBlMi5idWZmZXIgJiYgdmEpIHJldHVybiB2YS5kZWNvZGUoZTIuc3ViYXJyYXkoYjIsIGMyKSk7CiAgICAgICAgICAgIGZvciAoZDIgPSAiIjsgYjIgPCBjMjsgKSB7CiAgICAgICAgICAgICAgdmFyIGcyID0gZTJbYjIrK107CiAgICAgICAgICAgICAgaWYgKGcyICYgMTI4KSB7CiAgICAgICAgICAgICAgICB2YXIgdTQgPSBlMltiMisrXSAmIDYzOwogICAgICAgICAgICAgICAgaWYgKDE5MiA9PSAoZzIgJiAyMjQpKSBkMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChnMiAmIDMxKSA8PCA2IHwgdTQpOwogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgIHZhciBYMiA9IGUyW2IyKytdICYgNjM7CiAgICAgICAgICAgICAgICAgIGcyID0gMjI0ID09IChnMiAmIDI0MCkgPyAoZzIgJiAxNSkgPDwgMTIgfCB1NCA8PCA2IHwgWDIgOiAoZzIgJiA3KSA8PCAxOCB8IHU0IDw8IDEyIHwgWDIgPDwgNiB8IGUyW2IyKytdICYgNjM7CiAgICAgICAgICAgICAgICAgIDY1NTM2ID4gZzIgPyBkMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGcyKSA6IChnMiAtPSA2NTUzNiwgZDIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg1NTI5NiB8IGcyID4+IDEwLCA1NjMyMCB8IGcyICYgMTAyMykpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0gZWxzZSBkMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGcyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZDI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBoMihlMiwgYjIpIHsKICAgICAgICAgICAgcmV0dXJuIGUyID8gcDIoZWEsIGUyLCBiMikgOiAiIjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEEyKCkgewogICAgICAgICAgICB2YXIgZTIgPSBqYS5idWZmZXI7CiAgICAgICAgICAgIGE0LkhFQVA4ID0gWTIgPSBuZXcgSW50OEFycmF5KGUyKTsKICAgICAgICAgICAgYTQuSEVBUDE2ID0gbmV3IEludDE2QXJyYXkoZTIpOwogICAgICAgICAgICBhNC5IRUFQMzIgPSBjYSA9IG5ldyBJbnQzMkFycmF5KGUyKTsKICAgICAgICAgICAgYTQuSEVBUFU4ID0gZWEgPSBuZXcgVWludDhBcnJheShlMik7CiAgICAgICAgICAgIGE0LkhFQVBVMTYgPSBuZXcgVWludDE2QXJyYXkoZTIpOwogICAgICAgICAgICBhNC5IRUFQVTMyID0gVjIgPSBuZXcgVWludDMyQXJyYXkoZTIpOwogICAgICAgICAgICBhNC5IRUFQRjMyID0gbmV3IEZsb2F0MzJBcnJheShlMik7CiAgICAgICAgICAgIGE0LkhFQVBGNjQgPSBuZXcgRmxvYXQ2NEFycmF5KGUyKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGYyKGUyKSB7CiAgICAgICAgICAgIGlmIChhNC5vbkFib3J0KSBhNC5vbkFib3J0KGUyKTsKICAgICAgICAgICAgZTIgPSAiQWJvcnRlZCgiICsgZTIgKyAiKSI7CiAgICAgICAgICAgIGRhKGUyKTsKICAgICAgICAgICAgd2EgPSB0cnVlOwogICAgICAgICAgICBlMiA9IG5ldyBXZWJBc3NlbWJseS5SdW50aW1lRXJyb3IoZTIgKyAiLiBCdWlsZCB3aXRoIC1zQVNTRVJUSU9OUyBmb3IgbW9yZSBpbmZvLiIpOwogICAgICAgICAgICBrYShlMik7CiAgICAgICAgICAgIHRocm93IGUyOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gcTMoZTIpIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICBpZiAoZTIgPT0gUDIgJiYgZmEpIHJldHVybiBuZXcgVWludDhBcnJheShmYSk7CiAgICAgICAgICAgICAgaWYgKG1hKSByZXR1cm4gbWEoZTIpOwogICAgICAgICAgICAgIHRocm93ICJib3RoIGFzeW5jIGFuZCBzeW5jIGZldGNoaW5nIG9mIHRoZSB3YXNtIGZhaWxlZCI7CiAgICAgICAgICAgIH0gY2F0Y2ggKGIyKSB7CiAgICAgICAgICAgICAgZjIoYjIpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB2NCgpIHsKICAgICAgICAgICAgaWYgKCFmYSAmJiAoeGEgfHwgaGEpKSB7CiAgICAgICAgICAgICAgaWYgKCJmdW5jdGlvbiIgPT0gdHlwZW9mIGZldGNoICYmICFQMi5zdGFydHNXaXRoKCJmaWxlOi8vIikpIHJldHVybiBmZXRjaChQMiwgeyBjcmVkZW50aWFsczogInNhbWUtb3JpZ2luIiB9KS50aGVuKGZ1bmN0aW9uKGUyKSB7CiAgICAgICAgICAgICAgICBpZiAoIWUyLm9rKSB0aHJvdyAiZmFpbGVkIHRvIGxvYWQgd2FzbSBiaW5hcnkgZmlsZSBhdCAnIiArIFAyICsgIiciOwogICAgICAgICAgICAgICAgcmV0dXJuIGUyLmFycmF5QnVmZmVyKCk7CiAgICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gcTMoUDIpOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIGlmIChuYSkgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKGUyLCBiMikgewogICAgICAgICAgICAgICAgbmEoUDIsIGZ1bmN0aW9uKGMyKSB7CiAgICAgICAgICAgICAgICAgIGUyKG5ldyBVaW50OEFycmF5KGMyKSk7CiAgICAgICAgICAgICAgICB9LCBiMik7CiAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHEzKFAyKTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB6MihlMikgewogICAgICAgICAgICBmb3IgKDsgMCA8IGUyLmxlbmd0aDsgKSBlMi5zaGlmdCgpKGE0KTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIE8yKGUyKSB7CiAgICAgICAgICAgIHRoaXMuZXhjUHRyID0gZTI7CiAgICAgICAgICAgIHRoaXMucHRyID0gZTIgLSAyNDsKICAgICAgICAgICAgdGhpcy5zZXRfdHlwZSA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgICAgVjJbdGhpcy5wdHIgKyA0ID4+IDJdID0gYjI7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHRoaXMuZ2V0X3R5cGUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICByZXR1cm4gVjJbdGhpcy5wdHIgKyA0ID4+IDJdOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnNldF9kZXN0cnVjdG9yID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgICBWMlt0aGlzLnB0ciArIDggPj4gMl0gPSBiMjsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgdGhpcy5nZXRfZGVzdHJ1Y3RvciA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHJldHVybiBWMlt0aGlzLnB0ciArIDggPj4gMl07CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHRoaXMuc2V0X3JlZmNvdW50ID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgICBjYVt0aGlzLnB0ciA+PiAyXSA9IGIyOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnNldF9jYXVnaHQgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICAgIFkyW3RoaXMucHRyICsgMTIgPj4gMF0gPSBiMiA/IDEgOiAwOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLmdldF9jYXVnaHQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICByZXR1cm4gMCAhPSBZMlt0aGlzLnB0ciArIDEyID4+IDBdOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnNldF9yZXRocm93biA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgICAgWTJbdGhpcy5wdHIgKyAxMyA+PiAwXSA9IGIyID8gMSA6IDA7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHRoaXMuZ2V0X3JldGhyb3duID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgcmV0dXJuIDAgIT0gWTJbdGhpcy5wdHIgKyAxMyA+PiAwXTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgdGhpcy5pbml0ID0gZnVuY3Rpb24oYjIsIGMyKSB7CiAgICAgICAgICAgICAgdGhpcy5zZXRfYWRqdXN0ZWRfcHRyKDApOwogICAgICAgICAgICAgIHRoaXMuc2V0X3R5cGUoYjIpOwogICAgICAgICAgICAgIHRoaXMuc2V0X2Rlc3RydWN0b3IoYzIpOwogICAgICAgICAgICAgIHRoaXMuc2V0X3JlZmNvdW50KDApOwogICAgICAgICAgICAgIHRoaXMuc2V0X2NhdWdodChmYWxzZSk7CiAgICAgICAgICAgICAgdGhpcy5zZXRfcmV0aHJvd24oZmFsc2UpOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLmFkZF9yZWYgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICBjYVt0aGlzLnB0ciA+PiAyXSArPSAxOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnJlbGVhc2VfcmVmID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgdmFyIGIyID0gY2FbdGhpcy5wdHIgPj4gMl07CiAgICAgICAgICAgICAgY2FbdGhpcy5wdHIgPj4gMl0gPSBiMiAtIDE7CiAgICAgICAgICAgICAgcmV0dXJuIDEgPT09IGIyOwogICAgICAgICAgICB9OwogICAgICAgICAgICB0aGlzLnNldF9hZGp1c3RlZF9wdHIgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICAgIFYyW3RoaXMucHRyICsgMTYgPj4gMl0gPSBiMjsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgdGhpcy5nZXRfYWRqdXN0ZWRfcHRyID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFYyW3RoaXMucHRyICsgMTYgPj4gMl07CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIHRoaXMuZ2V0X2V4Y2VwdGlvbl9wdHIgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICBpZiAoeWEodGhpcy5nZXRfdHlwZSgpKSkgcmV0dXJuIFYyW3RoaXMuZXhjUHRyID4+IDJdOwogICAgICAgICAgICAgIHZhciBiMiA9IHRoaXMuZ2V0X2FkanVzdGVkX3B0cigpOwogICAgICAgICAgICAgIHJldHVybiAwICE9PSBiMiA/IGIyIDogdGhpcy5leGNQdHI7CiAgICAgICAgICAgIH07CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBiYSgpIHsKICAgICAgICAgICAgZnVuY3Rpb24gZTIoKSB7CiAgICAgICAgICAgICAgaWYgKCFsYSAmJiAobGEgPSB0cnVlLCBhNC5jYWxsZWRSdW4gPSB0cnVlLCAhd2EpKSB7CiAgICAgICAgICAgICAgICB6YSA9IHRydWU7CiAgICAgICAgICAgICAgICB6MihvYSk7CiAgICAgICAgICAgICAgICBBYShhNCk7CiAgICAgICAgICAgICAgICBpZiAoYTQub25SdW50aW1lSW5pdGlhbGl6ZWQpIGE0Lm9uUnVudGltZUluaXRpYWxpemVkKCk7CiAgICAgICAgICAgICAgICBpZiAoYTQucG9zdFJ1bikgZm9yICgiZnVuY3Rpb24iID09IHR5cGVvZiBhNC5wb3N0UnVuICYmIChhNC5wb3N0UnVuID0gW2E0LnBvc3RSdW5dKTsgYTQucG9zdFJ1bi5sZW5ndGg7ICkgQmEudW5zaGlmdChhNC5wb3N0UnVuLnNoaWZ0KCkpOwogICAgICAgICAgICAgICAgejIoQmEpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoISgwIDwgYWEpKSB7CiAgICAgICAgICAgICAgaWYgKGE0LnByZVJ1bikgZm9yICgiZnVuY3Rpb24iID09IHR5cGVvZiBhNC5wcmVSdW4gJiYgKGE0LnByZVJ1biA9IFthNC5wcmVSdW5dKTsgYTQucHJlUnVuLmxlbmd0aDsgKSBDYS51bnNoaWZ0KGE0LnByZVJ1bi5zaGlmdCgpKTsKICAgICAgICAgICAgICB6MihDYSk7CiAgICAgICAgICAgICAgMCA8IGFhIHx8IChhNC5zZXRTdGF0dXMgPyAoYTQuc2V0U3RhdHVzKCJSdW5uaW5nLi4uIiksIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgICAgICBhNC5zZXRTdGF0dXMoIiIpOwogICAgICAgICAgICAgICAgfSwgMSk7CiAgICAgICAgICAgICAgICBlMigpOwogICAgICAgICAgICAgIH0sIDEpKSA6IGUyKCkpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB0MigpIHsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHgyKGUyKSB7CiAgICAgICAgICAgIHJldHVybiAoZTIgfHwgdDIpLl9fY2FjaGVfXzsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEQyKGUyLCBiMikgewogICAgICAgICAgICB2YXIgYzIgPSB4MihiMiksIGQyID0gYzJbZTJdOwogICAgICAgICAgICBpZiAoZDIpIHJldHVybiBkMjsKICAgICAgICAgICAgZDIgPSBPYmplY3QuY3JlYXRlKChiMiB8fCB0MikucHJvdG90eXBlKTsKICAgICAgICAgICAgZDIucHRyID0gZTI7CiAgICAgICAgICAgIHJldHVybiBjMltlMl0gPSBkMjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIFIyKGUyKSB7CiAgICAgICAgICAgIGlmICgic3RyaW5nIiA9PT0gdHlwZW9mIGUyKSB7CiAgICAgICAgICAgICAgZm9yICh2YXIgYjIgPSAwLCBjMiA9IDA7IGMyIDwgZTIubGVuZ3RoOyArK2MyKSB7CiAgICAgICAgICAgICAgICB2YXIgZDIgPSBlMi5jaGFyQ29kZUF0KGMyKTsKICAgICAgICAgICAgICAgIDEyNyA+PSBkMiA/IGIyKysgOiAyMDQ3ID49IGQyID8gYjIgKz0gMiA6IDU1Mjk2IDw9IGQyICYmIDU3MzQzID49IGQyID8gKGIyICs9IDQsICsrYzIpIDogYjIgKz0gMzsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgYjIgPSBBcnJheShiMiArIDEpOwogICAgICAgICAgICAgIGMyID0gMDsKICAgICAgICAgICAgICBkMiA9IGIyLmxlbmd0aDsKICAgICAgICAgICAgICBpZiAoMCA8IGQyKSB7CiAgICAgICAgICAgICAgICBkMiA9IGMyICsgZDIgLSAxOwogICAgICAgICAgICAgICAgZm9yICh2YXIgZzIgPSAwOyBnMiA8IGUyLmxlbmd0aDsgKytnMikgewogICAgICAgICAgICAgICAgICB2YXIgdTQgPSBlMi5jaGFyQ29kZUF0KGcyKTsKICAgICAgICAgICAgICAgICAgaWYgKDU1Mjk2IDw9IHU0ICYmIDU3MzQzID49IHU0KSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIFgyID0gZTIuY2hhckNvZGVBdCgrK2cyKTsKICAgICAgICAgICAgICAgICAgICB1NCA9IDY1NTM2ICsgKCh1NCAmIDEwMjMpIDw8IDEwKSB8IFgyICYgMTAyMzsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpZiAoMTI3ID49IHU0KSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKGMyID49IGQyKSBicmVhazsKICAgICAgICAgICAgICAgICAgICBiMltjMisrXSA9IHU0OwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIGlmICgyMDQ3ID49IHU0KSB7CiAgICAgICAgICAgICAgICAgICAgICBpZiAoYzIgKyAxID49IGQyKSBicmVhazsKICAgICAgICAgICAgICAgICAgICAgIGIyW2MyKytdID0gMTkyIHwgdTQgPj4gNjsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgaWYgKDY1NTM1ID49IHU0KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjMiArIDIgPj0gZDIpIGJyZWFrOwogICAgICAgICAgICAgICAgICAgICAgICBiMltjMisrXSA9IDIyNCB8IHU0ID4+IDEyOwogICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGMyICsgMyA+PSBkMikgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIGIyW2MyKytdID0gMjQwIHwgdTQgPj4gMTg7CiAgICAgICAgICAgICAgICAgICAgICAgIGIyW2MyKytdID0gMTI4IHwgdTQgPj4gMTIgJiA2MzsKICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgIGIyW2MyKytdID0gMTI4IHwgdTQgPj4gNiAmIDYzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBiMltjMisrXSA9IDEyOCB8IHU0ICYgNjM7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGIyW2MyXSA9IDA7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGUyID0gcjIuYWxsb2MoYjIsIFkyKTsKICAgICAgICAgICAgICByMi5jb3B5KGIyLCBZMiwgZTIpOwogICAgICAgICAgICAgIHJldHVybiBlMjsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZTI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBwYShlMikgewogICAgICAgICAgICBpZiAoIm9iamVjdCIgPT09IHR5cGVvZiBlMikgewogICAgICAgICAgICAgIHZhciBiMiA9IHIyLmFsbG9jKGUyLCBZMik7CiAgICAgICAgICAgICAgcjIuY29weShlMiwgWTIsIGIyKTsKICAgICAgICAgICAgICByZXR1cm4gYjI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGUyOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gWjIoKSB7CiAgICAgICAgICAgIHRocm93ICJjYW5ub3QgY29uc3RydWN0IGEgVm9pZFB0ciwgbm8gY29uc3RydWN0b3IgaW4gSURMIjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIFMyKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IERhKCk7CiAgICAgICAgICAgIHgyKFMyKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gUTIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gRWEoKTsKICAgICAgICAgICAgeDIoUTIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBXMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBGYSgpOwogICAgICAgICAgICB4MihXMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHcyKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IEdhKCk7CiAgICAgICAgICAgIHgyKHcyKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gQzIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gSGEoKTsKICAgICAgICAgICAgeDIoQzIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBGMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBJYSgpOwogICAgICAgICAgICB4MihGMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEcyKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IEphKCk7CiAgICAgICAgICAgIHgyKEcyKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gRTIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gS2EoKTsKICAgICAgICAgICAgeDIoRTIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBUMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBMYSgpOwogICAgICAgICAgICB4MihUMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEIyKCkgewogICAgICAgICAgICB0aHJvdyAiY2Fubm90IGNvbnN0cnVjdCBhIFN0YXR1cywgbm8gY29uc3RydWN0b3IgaW4gSURMIjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEgyKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IE1hKCk7CiAgICAgICAgICAgIHgyKEgyKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gSTIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gTmEoKTsKICAgICAgICAgICAgeDIoSTIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBKMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBPYSgpOwogICAgICAgICAgICB4MihKMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIEsyKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IFBhKCk7CiAgICAgICAgICAgIHgyKEsyKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gTDIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gUWEoKTsKICAgICAgICAgICAgeDIoTDIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBNMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBSYSgpOwogICAgICAgICAgICB4MihNMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIE4yKCkgewogICAgICAgICAgICB0aGlzLnB0ciA9IFNhKCk7CiAgICAgICAgICAgIHgyKE4yKVt0aGlzLnB0cl0gPSB0aGlzOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24geTIoKSB7CiAgICAgICAgICAgIHRoaXMucHRyID0gVGEoKTsKICAgICAgICAgICAgeDIoeTIpW3RoaXMucHRyXSA9IHRoaXM7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBtMigpIHsKICAgICAgICAgICAgdGhpcy5wdHIgPSBVYSgpOwogICAgICAgICAgICB4MihtMilbdGhpcy5wdHJdID0gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIG4yID0gdm9pZCAwID09PSBuMiA/IHt9IDogbjI7CiAgICAgICAgICB2YXIgYTQgPSAidW5kZWZpbmVkIiAhPSB0eXBlb2YgbjIgPyBuMiA6IHt9LCBBYSwga2E7CiAgICAgICAgICBhNC5yZWFkeSA9IG5ldyBQcm9taXNlKGZ1bmN0aW9uKGUyLCBiMikgewogICAgICAgICAgICBBYSA9IGUyOwogICAgICAgICAgICBrYSA9IGIyOwogICAgICAgICAgfSk7CiAgICAgICAgICB2YXIgVmEgPSBmYWxzZSwgV2EgPSBmYWxzZTsKICAgICAgICAgIGE0Lm9uUnVudGltZUluaXRpYWxpemVkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIFZhID0gdHJ1ZTsKICAgICAgICAgICAgaWYgKFdhICYmICJmdW5jdGlvbiIgPT09IHR5cGVvZiBhNC5vbk1vZHVsZUxvYWRlZCkgYTQub25Nb2R1bGVMb2FkZWQoYTQpOwogICAgICAgICAgfTsKICAgICAgICAgIGE0Lm9uTW9kdWxlUGFyc2VkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIFdhID0gdHJ1ZTsKICAgICAgICAgICAgaWYgKFZhICYmICJmdW5jdGlvbiIgPT09IHR5cGVvZiBhNC5vbk1vZHVsZUxvYWRlZCkgYTQub25Nb2R1bGVMb2FkZWQoYTQpOwogICAgICAgICAgfTsKICAgICAgICAgIGE0LmlzVmVyc2lvblN1cHBvcnRlZCA9IGZ1bmN0aW9uKGUyKSB7CiAgICAgICAgICAgIGlmICgic3RyaW5nIiAhPT0gdHlwZW9mIGUyKSByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIGUyID0gZTIuc3BsaXQoIi4iKTsKICAgICAgICAgICAgcmV0dXJuIDIgPiBlMi5sZW5ndGggfHwgMyA8IGUyLmxlbmd0aCA/IGZhbHNlIDogMSA9PSBlMlswXSAmJiAwIDw9IGUyWzFdICYmIDUgPj0gZTJbMV0gPyB0cnVlIDogMCAhPSBlMlswXSB8fCAxMCA8IGUyWzFdID8gZmFsc2UgOiB0cnVlOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBYYSA9IE9iamVjdC5hc3NpZ24oe30sIGE0KSwgeGEgPSAib2JqZWN0IiA9PSB0eXBlb2Ygd2luZG93LCBoYSA9ICJmdW5jdGlvbiIgPT0gdHlwZW9mIGltcG9ydFNjcmlwdHMsIFlhID0gIm9iamVjdCIgPT0gdHlwZW9mIHByb2Nlc3MgJiYgIm9iamVjdCIgPT0gdHlwZW9mIHByb2Nlc3MudmVyc2lvbnMgJiYgInN0cmluZyIgPT0gdHlwZW9mIHByb2Nlc3MudmVyc2lvbnMubm9kZSwgVTIgPSAiIjsKICAgICAgICAgIGlmIChZYSkgewogICAgICAgICAgICB2YXIgWmEgPSBfX3JlcXVpcmUoImZzIiksIHFhID0gX19yZXF1aXJlKCJwYXRoIik7CiAgICAgICAgICAgIFUyID0gaGEgPyBxYS5kaXJuYW1lKFUyKSArICIvIiA6IF9fZGlybmFtZSArICIvIjsKICAgICAgICAgICAgdmFyICRhID0gZnVuY3Rpb24oZTIsIGIyKSB7CiAgICAgICAgICAgICAgZTIgPSBlMi5zdGFydHNXaXRoKCJmaWxlOi8vIikgPyBuZXcgVVJMKGUyKSA6IHFhLm5vcm1hbGl6ZShlMik7CiAgICAgICAgICAgICAgcmV0dXJuIFphLnJlYWRGaWxlU3luYyhlMiwgYjIgPyB2b2lkIDAgOiAidXRmOCIpOwogICAgICAgICAgICB9OwogICAgICAgICAgICB2YXIgbWEgPSBmdW5jdGlvbihlMikgewogICAgICAgICAgICAgIGUyID0gJGEoZTIsIHRydWUpOwogICAgICAgICAgICAgIGUyLmJ1ZmZlciB8fCAoZTIgPSBuZXcgVWludDhBcnJheShlMikpOwogICAgICAgICAgICAgIHJldHVybiBlMjsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgdmFyIG5hID0gZnVuY3Rpb24oZTIsIGIyLCBjMikgewogICAgICAgICAgICAgIGUyID0gZTIuc3RhcnRzV2l0aCgiZmlsZTovLyIpID8gbmV3IFVSTChlMikgOiBxYS5ub3JtYWxpemUoZTIpOwogICAgICAgICAgICAgIFphLnJlYWRGaWxlKGUyLCBmdW5jdGlvbihkMiwgZzIpIHsKICAgICAgICAgICAgICAgIGQyID8gYzIoZDIpIDogYjIoZzIuYnVmZmVyKTsKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgMSA8IHByb2Nlc3MuYXJndi5sZW5ndGggJiYgcHJvY2Vzcy5hcmd2WzFdLnJlcGxhY2UoL1xcL2csICIvIik7CiAgICAgICAgICAgIHByb2Nlc3MuYXJndi5zbGljZSgyKTsKICAgICAgICAgICAgYTQuaW5zcGVjdCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHJldHVybiAiW0Vtc2NyaXB0ZW4gTW9kdWxlIG9iamVjdF0iOwogICAgICAgICAgICB9OwogICAgICAgICAgfSBlbHNlIGlmICh4YSB8fCBoYSkgaGEgPyBVMiA9IHNlbGYubG9jYXRpb24uaHJlZiA6ICJ1bmRlZmluZWQiICE9IHR5cGVvZiBkb2N1bWVudCAmJiBkb2N1bWVudC5jdXJyZW50U2NyaXB0ICYmIChVMiA9IGRvY3VtZW50LmN1cnJlbnRTY3JpcHQuc3JjKSwgazIgJiYgKFUyID0gazIpLCBVMiA9IDAgIT09IFUyLmluZGV4T2YoImJsb2I6IikgPyBVMi5zdWJzdHIoMCwgVTIucmVwbGFjZSgvWz8jXS4qLywgIiIpLmxhc3RJbmRleE9mKCIvIikgKyAxKSA6ICIiLCAkYSA9IGZ1bmN0aW9uKGUyKSB7CiAgICAgICAgICAgIHZhciBiMiA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgICAgICBiMi5vcGVuKCJHRVQiLCBlMiwgZmFsc2UpOwogICAgICAgICAgICBiMi5zZW5kKG51bGwpOwogICAgICAgICAgICByZXR1cm4gYjIucmVzcG9uc2VUZXh0OwogICAgICAgICAgfSwgaGEgJiYgKG1hID0gZnVuY3Rpb24oZTIpIHsKICAgICAgICAgICAgdmFyIGIyID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7CiAgICAgICAgICAgIGIyLm9wZW4oIkdFVCIsIGUyLCBmYWxzZSk7CiAgICAgICAgICAgIGIyLnJlc3BvbnNlVHlwZSA9ICJhcnJheWJ1ZmZlciI7CiAgICAgICAgICAgIGIyLnNlbmQobnVsbCk7CiAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShiMi5yZXNwb25zZSk7CiAgICAgICAgICB9KSwgbmEgPSBmdW5jdGlvbihlMiwgYjIsIGMyKSB7CiAgICAgICAgICAgIHZhciBkMiA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwogICAgICAgICAgICBkMi5vcGVuKCJHRVQiLCBlMiwgdHJ1ZSk7CiAgICAgICAgICAgIGQyLnJlc3BvbnNlVHlwZSA9ICJhcnJheWJ1ZmZlciI7CiAgICAgICAgICAgIGQyLm9ubG9hZCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIDIwMCA9PSBkMi5zdGF0dXMgfHwgMCA9PSBkMi5zdGF0dXMgJiYgZDIucmVzcG9uc2UgPyBiMihkMi5yZXNwb25zZSkgOiBjMigpOwogICAgICAgICAgICB9OwogICAgICAgICAgICBkMi5vbmVycm9yID0gYzI7CiAgICAgICAgICAgIGQyLnNlbmQobnVsbCk7CiAgICAgICAgICB9OwogICAgICAgICAgdmFyIHVkID0gYTQucHJpbnQgfHwgY29uc29sZS5sb2cuYmluZChjb25zb2xlKSwgZGEgPSBhNC5wcmludEVyciB8fCBjb25zb2xlLndhcm4uYmluZChjb25zb2xlKTsKICAgICAgICAgIE9iamVjdC5hc3NpZ24oYTQsIFhhKTsKICAgICAgICAgIFhhID0gbnVsbDsKICAgICAgICAgIHZhciBmYTsKICAgICAgICAgIGE0Lndhc21CaW5hcnkgJiYgKGZhID0gYTQud2FzbUJpbmFyeSk7CiAgICAgICAgICAib2JqZWN0IiAhPSB0eXBlb2YgV2ViQXNzZW1ibHkgJiYgZjIoIm5vIG5hdGl2ZSB3YXNtIHN1cHBvcnQgZGV0ZWN0ZWQiKTsKICAgICAgICAgIHZhciBqYSwgd2EgPSBmYWxzZSwgdmEgPSAidW5kZWZpbmVkIiAhPSB0eXBlb2YgVGV4dERlY29kZXIgPyBuZXcgVGV4dERlY29kZXIoInV0ZjgiKSA6IHZvaWQgMCwgWTIsIGVhLCBjYSwgVjIsIENhID0gW10sIG9hID0gW10sIEJhID0gW10sIHphID0gZmFsc2UsIGFhID0gMCwgcmEgPSBudWxsLCBpYSA9IG51bGw7CiAgICAgICAgICB2YXIgUDIgPSAiZHJhY29fZGVjb2Rlci53YXNtIjsKICAgICAgICAgIFAyLnN0YXJ0c1dpdGgoImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCwiKSB8fCAoUDIgPSBsMihQMikpOwogICAgICAgICAgdmFyIHZkID0gMCwgd2QgPSBbbnVsbCwgW10sIFtdXSwgeGQgPSB7IGI6IGZ1bmN0aW9uKGUyLCBiMiwgYzIpIHsKICAgICAgICAgICAgbmV3IE8yKGUyKS5pbml0KGIyLCBjMik7CiAgICAgICAgICAgIHZkKys7CiAgICAgICAgICAgIHRocm93IGUyOwogICAgICAgICAgfSwgYTogZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGYyKCIiKTsKICAgICAgICAgIH0sIGc6IGZ1bmN0aW9uKGUyLCBiMiwgYzIpIHsKICAgICAgICAgICAgZWEuY29weVdpdGhpbihlMiwgYjIsIGIyICsgYzIpOwogICAgICAgICAgfSwgZTogZnVuY3Rpb24oZTIpIHsKICAgICAgICAgICAgdmFyIGIyID0gZWEubGVuZ3RoOwogICAgICAgICAgICBlMiA+Pj49IDA7CiAgICAgICAgICAgIGlmICgyMTQ3NDgzNjQ4IDwgZTIpIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgZm9yICh2YXIgYzIgPSAxOyA0ID49IGMyOyBjMiAqPSAyKSB7CiAgICAgICAgICAgICAgdmFyIGQyID0gYjIgKiAoMSArIDAuMiAvIGMyKTsKICAgICAgICAgICAgICBkMiA9IE1hdGgubWluKGQyLCBlMiArIDEwMDY2MzI5Nik7CiAgICAgICAgICAgICAgdmFyIGcyID0gTWF0aDsKICAgICAgICAgICAgICBkMiA9IE1hdGgubWF4KGUyLCBkMik7CiAgICAgICAgICAgICAgZzIgPSBnMi5taW4uY2FsbChnMiwgMjE0NzQ4MzY0OCwgZDIgKyAoNjU1MzYgLSBkMiAlIDY1NTM2KSAlIDY1NTM2KTsKICAgICAgICAgICAgICBhOiB7CiAgICAgICAgICAgICAgICBkMiA9IGphLmJ1ZmZlcjsKICAgICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICAgIGphLmdyb3coZzIgLSBkMi5ieXRlTGVuZ3RoICsgNjU1MzUgPj4+IDE2KTsKICAgICAgICAgICAgICAgICAgQTIoKTsKICAgICAgICAgICAgICAgICAgdmFyIHU0ID0gMTsKICAgICAgICAgICAgICAgICAgYnJlYWsgYTsKICAgICAgICAgICAgICAgIH0gY2F0Y2ggKFgyKSB7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB1NCA9IHZvaWQgMDsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHU0KSByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICB9LCBmOiBmdW5jdGlvbihlMikgewogICAgICAgICAgICByZXR1cm4gNTI7CiAgICAgICAgICB9LCBkOiBmdW5jdGlvbihlMiwgYjIsIGMyLCBkMiwgZzIpIHsKICAgICAgICAgICAgcmV0dXJuIDcwOwogICAgICAgICAgfSwgYzogZnVuY3Rpb24oZTIsIGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgZm9yICh2YXIgZzIgPSAwLCB1NCA9IDA7IHU0IDwgYzI7IHU0KyspIHsKICAgICAgICAgICAgICB2YXIgWDIgPSBWMltiMiA+PiAyXSwgYWIgPSBWMltiMiArIDQgPj4gMl07CiAgICAgICAgICAgICAgYjIgKz0gODsKICAgICAgICAgICAgICBmb3IgKHZhciBzYSA9IDA7IHNhIDwgYWI7IHNhKyspIHsKICAgICAgICAgICAgICAgIHZhciB0YSA9IGVhW1gyICsgc2FdLCB1YSA9IHdkW2UyXTsKICAgICAgICAgICAgICAgIDAgPT09IHRhIHx8IDEwID09PSB0YSA/ICgoMSA9PT0gZTIgPyB1ZCA6IGRhKShwMih1YSwgMCkpLCB1YS5sZW5ndGggPSAwKSA6IHVhLnB1c2godGEpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBnMiArPSBhYjsKICAgICAgICAgICAgfQogICAgICAgICAgICBWMltkMiA+PiAyXSA9IGcyOwogICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgIH0gfTsKICAgICAgICAgIChmdW5jdGlvbigpIHsKICAgICAgICAgICAgZnVuY3Rpb24gZTIoZzIsIHU0KSB7CiAgICAgICAgICAgICAgYTQuYXNtID0gZzIuZXhwb3J0czsKICAgICAgICAgICAgICBqYSA9IGE0LmFzbS5oOwogICAgICAgICAgICAgIEEyKCk7CiAgICAgICAgICAgICAgb2EudW5zaGlmdChhNC5hc20uaSk7CiAgICAgICAgICAgICAgYWEtLTsKICAgICAgICAgICAgICBhNC5tb25pdG9yUnVuRGVwZW5kZW5jaWVzICYmIGE0Lm1vbml0b3JSdW5EZXBlbmRlbmNpZXMoYWEpOwogICAgICAgICAgICAgIDAgPT0gYWEgJiYgKG51bGwgIT09IHJhICYmIChjbGVhckludGVydmFsKHJhKSwgcmEgPSBudWxsKSwgaWEgJiYgKGcyID0gaWEsIGlhID0gbnVsbCwgZzIoKSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uIGIyKGcyKSB7CiAgICAgICAgICAgICAgZTIoZzIuaW5zdGFuY2UpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uIGMyKGcyKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHY0KCkudGhlbihmdW5jdGlvbih1NCkgewogICAgICAgICAgICAgICAgcmV0dXJuIFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKHU0LCBkMik7CiAgICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbih1NCkgewogICAgICAgICAgICAgICAgcmV0dXJuIHU0OwogICAgICAgICAgICAgIH0pLnRoZW4oZzIsIGZ1bmN0aW9uKHU0KSB7CiAgICAgICAgICAgICAgICBkYSgiZmFpbGVkIHRvIGFzeW5jaHJvbm91c2x5IHByZXBhcmUgd2FzbTogIiArIHU0KTsKICAgICAgICAgICAgICAgIGYyKHU0KTsKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgZDIgPSB7IGE6IHhkIH07CiAgICAgICAgICAgIGFhKys7CiAgICAgICAgICAgIGE0Lm1vbml0b3JSdW5EZXBlbmRlbmNpZXMgJiYgYTQubW9uaXRvclJ1bkRlcGVuZGVuY2llcyhhYSk7CiAgICAgICAgICAgIGlmIChhNC5pbnN0YW50aWF0ZVdhc20pIHRyeSB7CiAgICAgICAgICAgICAgcmV0dXJuIGE0Lmluc3RhbnRpYXRlV2FzbShkMiwgZTIpOwogICAgICAgICAgICB9IGNhdGNoIChnMikgewogICAgICAgICAgICAgIGRhKCJNb2R1bGUuaW5zdGFudGlhdGVXYXNtIGNhbGxiYWNrIGZhaWxlZCB3aXRoIGVycm9yOiAiICsgZzIpLCBrYShnMik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgKGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHJldHVybiBmYSB8fCAiZnVuY3Rpb24iICE9IHR5cGVvZiBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyB8fCBQMi5zdGFydHNXaXRoKCJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsIikgfHwgUDIuc3RhcnRzV2l0aCgiZmlsZTovLyIpIHx8IFlhIHx8ICJmdW5jdGlvbiIgIT0gdHlwZW9mIGZldGNoID8gYzIoYjIpIDogZmV0Y2goUDIsIHsgY3JlZGVudGlhbHM6ICJzYW1lLW9yaWdpbiIgfSkudGhlbihmdW5jdGlvbihnMikgewogICAgICAgICAgICAgICAgcmV0dXJuIFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlU3RyZWFtaW5nKGcyLCBkMikudGhlbihiMiwgZnVuY3Rpb24odTQpIHsKICAgICAgICAgICAgICAgICAgZGEoIndhc20gc3RyZWFtaW5nIGNvbXBpbGUgZmFpbGVkOiAiICsgdTQpOwogICAgICAgICAgICAgICAgICBkYSgiZmFsbGluZyBiYWNrIHRvIEFycmF5QnVmZmVyIGluc3RhbnRpYXRpb24iKTsKICAgICAgICAgICAgICAgICAgcmV0dXJuIGMyKGIyKTsKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9KSgpLmNhdGNoKGthKTsKICAgICAgICAgICAgcmV0dXJuIHt9OwogICAgICAgICAgfSkoKTsKICAgICAgICAgIHZhciBiYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfVm9pZFB0cl9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoYmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1ZvaWRQdHJfX19kZXN0cm95X19fMCA9IGE0LmFzbS5rKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgRGEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJCdWZmZXJfRGVjb2RlckJ1ZmZlcl8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoRGEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJCdWZmZXJfRGVjb2RlckJ1ZmZlcl8wID0gYTQuYXNtLmwpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBjYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2RlckJ1ZmZlcl9Jbml0XzIgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChjYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2RlckJ1ZmZlcl9Jbml0XzIgPSBhNC5hc20ubSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGRiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyQnVmZmVyX19fZGVzdHJveV9fXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChkYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2RlckJ1ZmZlcl9fX2Rlc3Ryb3lfX18wID0gYTQuYXNtLm4pLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBFYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlVHJhbnNmb3JtRGF0YV9BdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChFYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlVHJhbnNmb3JtRGF0YV9BdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhXzAgPSBhNC5hc20ubykuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhX3RyYW5zZm9ybV90eXBlXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChlYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlVHJhbnNmb3JtRGF0YV90cmFuc2Zvcm1fdHlwZV8wID0gYTQuYXNtLnApLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBmYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlVHJhbnNmb3JtRGF0YV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoZmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZVRyYW5zZm9ybURhdGFfX19kZXN0cm95X19fMCA9IGE0LmFzbS5xKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgRmEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0dlb21ldHJ5QXR0cmlidXRlX0dlb21ldHJ5QXR0cmlidXRlXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChGYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfR2VvbWV0cnlBdHRyaWJ1dGVfR2VvbWV0cnlBdHRyaWJ1dGVfMCA9IGE0LmFzbS5yKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgZ2IgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0dlb21ldHJ5QXR0cmlidXRlX19fZGVzdHJveV9fXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChnYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfR2VvbWV0cnlBdHRyaWJ1dGVfX19kZXN0cm95X19fMCA9IGE0LmFzbS5zKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgR2EgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50QXR0cmlidXRlX1BvaW50QXR0cmlidXRlXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChHYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfUG9pbnRBdHRyaWJ1dGVfMCA9IGE0LmFzbS50KS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgaGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50QXR0cmlidXRlX3NpemVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGhiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9zaXplXzAgPSBhNC5hc20udSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9HZXRBdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChpYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfR2V0QXR0cmlidXRlVHJhbnNmb3JtRGF0YV8wID0gYTQuYXNtLnYpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBqYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfYXR0cmlidXRlX3R5cGVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGpiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9hdHRyaWJ1dGVfdHlwZV8wID0gYTQuYXNtLncpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBrYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfZGF0YV90eXBlXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChrYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfZGF0YV90eXBlXzAgPSBhNC5hc20ueCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGxiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9udW1fY29tcG9uZW50c18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAobGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50QXR0cmlidXRlX251bV9jb21wb25lbnRzXzAgPSBhNC5hc20ueSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIG1iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9ub3JtYWxpemVkXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChtYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfbm9ybWFsaXplZF8wID0gYTQuYXNtLnopLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBuYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfYnl0ZV9zdHJpZGVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKG5iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9ieXRlX3N0cmlkZV8wID0gYTQuYXNtLkEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBvYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfYnl0ZV9vZmZzZXRfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKG9iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9ieXRlX29mZnNldF8wID0gYTQuYXNtLkIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBwYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfdW5pcXVlX2lkXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChwYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfUG9pbnRBdHRyaWJ1dGVfdW5pcXVlX2lkXzAgPSBhNC5hc20uQykuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHFiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludEF0dHJpYnV0ZV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAocWIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50QXR0cmlidXRlX19fZGVzdHJveV9fXzAgPSBhNC5hc20uRCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEhhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fQXR0cmlidXRlUXVhbnRpemF0aW9uVHJhbnNmb3JtXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChIYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlUXVhbnRpemF0aW9uVHJhbnNmb3JtX0F0dHJpYnV0ZVF1YW50aXphdGlvblRyYW5zZm9ybV8wID0gYTQuYXNtLkUpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCByYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlUXVhbnRpemF0aW9uVHJhbnNmb3JtX0luaXRGcm9tQXR0cmlidXRlXzEgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChyYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlUXVhbnRpemF0aW9uVHJhbnNmb3JtX0luaXRGcm9tQXR0cmlidXRlXzEgPSBhNC5hc20uRikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHNiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fcXVhbnRpemF0aW9uX2JpdHNfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHNiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fcXVhbnRpemF0aW9uX2JpdHNfMCA9IGE0LmFzbS5HKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgdGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZVF1YW50aXphdGlvblRyYW5zZm9ybV9taW5fdmFsdWVfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHRiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fbWluX3ZhbHVlXzEgPSBhNC5hc20uSCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fcmFuZ2VfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVRdWFudGl6YXRpb25UcmFuc2Zvcm1fcmFuZ2VfMCA9IGE0LmFzbS5JKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgdmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZVF1YW50aXphdGlvblRyYW5zZm9ybV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAodmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZVF1YW50aXphdGlvblRyYW5zZm9ybV9fX2Rlc3Ryb3lfX18wID0gYTQuYXNtLkopLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBJYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlT2N0YWhlZHJvblRyYW5zZm9ybV9BdHRyaWJ1dGVPY3RhaGVkcm9uVHJhbnNmb3JtXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChJYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlT2N0YWhlZHJvblRyYW5zZm9ybV9BdHRyaWJ1dGVPY3RhaGVkcm9uVHJhbnNmb3JtXzAgPSBhNC5hc20uSykuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHdiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVPY3RhaGVkcm9uVHJhbnNmb3JtX0luaXRGcm9tQXR0cmlidXRlXzEgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuICh3YiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlT2N0YWhlZHJvblRyYW5zZm9ybV9Jbml0RnJvbUF0dHJpYnV0ZV8xID0gYTQuYXNtLkwpLmFwcGx5KAogICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgYXJndW1lbnRzCiAgICAgICAgICAgICk7CiAgICAgICAgICB9LCB4YiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfQXR0cmlidXRlT2N0YWhlZHJvblRyYW5zZm9ybV9xdWFudGl6YXRpb25fYml0c18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoeGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZU9jdGFoZWRyb25UcmFuc2Zvcm1fcXVhbnRpemF0aW9uX2JpdHNfMCA9IGE0LmFzbS5NKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgeWIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0F0dHJpYnV0ZU9jdGFoZWRyb25UcmFuc2Zvcm1fX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9BdHRyaWJ1dGVPY3RhaGVkcm9uVHJhbnNmb3JtX19fZGVzdHJveV9fXzAgPSBhNC5hc20uTikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEphID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX1BvaW50Q2xvdWRfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEphID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX1BvaW50Q2xvdWRfMCA9IGE0LmFzbS5PKS5hcHBseSgKICAgICAgICAgICAgICBudWxsLAogICAgICAgICAgICAgIGFyZ3VtZW50cwogICAgICAgICAgICApOwogICAgICAgICAgfSwgemIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50Q2xvdWRfbnVtX2F0dHJpYnV0ZXNfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHpiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX251bV9hdHRyaWJ1dGVzXzAgPSBhNC5hc20uUCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEFiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX251bV9wb2ludHNfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEFiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX251bV9wb2ludHNfMCA9IGE0LmFzbS5RKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgQmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1BvaW50Q2xvdWRfX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEJiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9Qb2ludENsb3VkX19fZGVzdHJveV9fXzAgPSBhNC5hc20uUikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEthID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX01lc2hfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEthID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX01lc2hfMCA9IGE0LmFzbS5TKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgQ2IgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01lc2hfbnVtX2ZhY2VzXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChDYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfTWVzaF9udW1fZmFjZXNfMCA9IGE0LmFzbS5UKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgRGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01lc2hfbnVtX2F0dHJpYnV0ZXNfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKERiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX251bV9hdHRyaWJ1dGVzXzAgPSBhNC5hc20uVSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX251bV9wb2ludHNfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX251bV9wb2ludHNfMCA9IGE0LmFzbS5WKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgRmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01lc2hfX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEZiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXNoX19fZGVzdHJveV9fXzAgPSBhNC5hc20uVykuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIExhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YV9NZXRhZGF0YV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoTGEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhX01ldGFkYXRhXzAgPSBhNC5hc20uWCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEdiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoR2IgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhX19fZGVzdHJveV9fXzAgPSBhNC5hc20uWSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEhiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfY29kZV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoSGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1N0YXR1c19jb2RlXzAgPSBhNC5hc20uWikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfb2tfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfb2tfMCA9IGE0LmFzbS5fKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgSmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX1N0YXR1c19lcnJvcl9tc2dfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEpiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfZXJyb3JfbXNnXzAgPSBhNC5hc20uJCkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEtiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEtiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9TdGF0dXNfX19kZXN0cm95X19fMCA9IGE0LmFzbS5hYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIE1hID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0Zsb2F0MzJBcnJheV9EcmFjb0Zsb2F0MzJBcnJheV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoTWEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvRmxvYXQzMkFycmF5X0RyYWNvRmxvYXQzMkFycmF5XzAgPSBhNC5hc20uYmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBMYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29GbG9hdDMyQXJyYXlfR2V0VmFsdWVfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKExiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0Zsb2F0MzJBcnJheV9HZXRWYWx1ZV8xID0gYTQuYXNtLmNhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgTWIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvRmxvYXQzMkFycmF5X3NpemVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKE1iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0Zsb2F0MzJBcnJheV9zaXplXzAgPSBhNC5hc20uZGEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBOYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29GbG9hdDMyQXJyYXlfX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKE5iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0Zsb2F0MzJBcnJheV9fX2Rlc3Ryb3lfX18wID0gYTQuYXNtLmVhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgTmEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50OEFycmF5X0RyYWNvSW50OEFycmF5XzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChOYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQ4QXJyYXlfRHJhY29JbnQ4QXJyYXlfMCA9IGE0LmFzbS5mYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIE9iID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDhBcnJheV9HZXRWYWx1ZV8xID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoT2IgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50OEFycmF5X0dldFZhbHVlXzEgPSBhNC5hc20uZ2EpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBQYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQ4QXJyYXlfc2l6ZV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoUGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50OEFycmF5X3NpemVfMCA9IGE0LmFzbS5oYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFFiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDhBcnJheV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoUWIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50OEFycmF5X19fZGVzdHJveV9fXzAgPSBhNC5hc20uaWEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBPYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50OEFycmF5X0RyYWNvVUludDhBcnJheV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoT2EgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDhBcnJheV9EcmFjb1VJbnQ4QXJyYXlfMCA9IGE0LmFzbS5qYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFJiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQ4QXJyYXlfR2V0VmFsdWVfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFJiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQ4QXJyYXlfR2V0VmFsdWVfMSA9IGE0LmFzbS5rYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFNiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQ4QXJyYXlfc2l6ZV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoU2IgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDhBcnJheV9zaXplXzAgPSBhNC5hc20ubGEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBUYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50OEFycmF5X19fZGVzdHJveV9fXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChUYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50OEFycmF5X19fZGVzdHJveV9fXzAgPSBhNC5hc20ubWEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBQYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQxNkFycmF5X0RyYWNvSW50MTZBcnJheV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoUGEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50MTZBcnJheV9EcmFjb0ludDE2QXJyYXlfMCA9IGE0LmFzbS5uYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDE2QXJyYXlfR2V0VmFsdWVfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFViID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDE2QXJyYXlfR2V0VmFsdWVfMSA9IGE0LmFzbS5vYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFZiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDE2QXJyYXlfc2l6ZV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoVmIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50MTZBcnJheV9zaXplXzAgPSBhNC5hc20ucGEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBXYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQxNkFycmF5X19fZGVzdHJveV9fXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChXYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQxNkFycmF5X19fZGVzdHJveV9fXzAgPSBhNC5hc20ucWEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBRYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MTZBcnJheV9EcmFjb1VJbnQxNkFycmF5XzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChRYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MTZBcnJheV9EcmFjb1VJbnQxNkFycmF5XzAgPSBhNC5hc20ucmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBYYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MTZBcnJheV9HZXRWYWx1ZV8xID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoWGIgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDE2QXJyYXlfR2V0VmFsdWVfMSA9IGE0LmFzbS5zYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQxNkFycmF5X3NpemVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFliID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQxNkFycmF5X3NpemVfMCA9IGE0LmFzbS50YSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFpiID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQxNkFycmF5X19fZGVzdHJveV9fXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChaYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MTZBcnJheV9fX2Rlc3Ryb3lfX18wID0gYTQuYXNtLnVhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgUmEgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50MzJBcnJheV9EcmFjb0ludDMyQXJyYXlfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFJhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDMyQXJyYXlfRHJhY29JbnQzMkFycmF5XzAgPSBhNC5hc20udmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCAkYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQzMkFycmF5X0dldFZhbHVlXzEgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuICgkYiA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQzMkFycmF5X0dldFZhbHVlXzEgPSBhNC5hc20ud2EpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBhYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29JbnQzMkFycmF5X3NpemVfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGFjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb0ludDMyQXJyYXlfc2l6ZV8wID0gYTQuYXNtLnhhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgYmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50MzJBcnJheV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoYmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvSW50MzJBcnJheV9fX2Rlc3Ryb3lfX18wID0gYTQuYXNtLnlhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgU2EgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDMyQXJyYXlfRHJhY29VSW50MzJBcnJheV8wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoU2EgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDMyQXJyYXlfRHJhY29VSW50MzJBcnJheV8wID0gYTQuYXNtLnphKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgY2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDMyQXJyYXlfR2V0VmFsdWVfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGNjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EcmFjb1VJbnQzMkFycmF5X0dldFZhbHVlXzEgPSBhNC5hc20uQWEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBkYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MzJBcnJheV9zaXplXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChkYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MzJBcnJheV9zaXplXzAgPSBhNC5hc20uQmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBlYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRHJhY29VSW50MzJBcnJheV9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoZWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RyYWNvVUludDMyQXJyYXlfX19kZXN0cm95X19fMCA9IGE0LmFzbS5DYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFRhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfTWV0YWRhdGFRdWVyaWVyXzAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChUYSA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfTWV0YWRhdGFRdWVyaWVyX01ldGFkYXRhUXVlcmllcl8wID0gYTQuYXNtLkRhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgZmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9IYXNFbnRyeV8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoZmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9IYXNFbnRyeV8yID0gYTQuYXNtLkVhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgZ2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9HZXRJbnRFbnRyeV8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoZ2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9HZXRJbnRFbnRyeV8yID0gYTQuYXNtLkZhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgaGMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9HZXRJbnRFbnRyeUFycmF5XzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChoYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfTWV0YWRhdGFRdWVyaWVyX0dldEludEVudHJ5QXJyYXlfMyA9IGE0LmFzbS5HYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGljID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfR2V0RG91YmxlRW50cnlfMiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGljID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfR2V0RG91YmxlRW50cnlfMiA9IGE0LmFzbS5IYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGpjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfR2V0U3RyaW5nRW50cnlfMiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGpjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfR2V0U3RyaW5nRW50cnlfMiA9IGE0LmFzbS5JYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGtjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfTnVtRW50cmllc18xID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoa2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9OdW1FbnRyaWVzXzEgPSBhNC5hc20uSmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBsYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfTWV0YWRhdGFRdWVyaWVyX0dldEVudHJ5TmFtZV8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAobGMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX01ldGFkYXRhUXVlcmllcl9HZXRFbnRyeU5hbWVfMiA9IGE0LmFzbS5LYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIG1jID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfX19kZXN0cm95X19fMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKG1jID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9NZXRhZGF0YVF1ZXJpZXJfX19kZXN0cm95X19fMCA9IGE0LmFzbS5MYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFVhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0RlY29kZXJfMCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFVhID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0RlY29kZXJfMCA9IGE0LmFzbS5NYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIG5jID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0RlY29kZUFycmF5VG9Qb2ludENsb3VkXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChuYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9EZWNvZGVBcnJheVRvUG9pbnRDbG91ZF8zID0gYTQuYXNtLk5hKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgb2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfRGVjb2RlQXJyYXlUb01lc2hfMyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKG9jID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0RlY29kZUFycmF5VG9NZXNoXzMgPSBhNC5hc20uT2EpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBwYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJZF8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAocGMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlSWRfMiA9IGE0LmFzbS5QYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHFjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUlkQnlOYW1lXzIgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChxYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJZEJ5TmFtZV8yID0gYTQuYXNtLlFhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgcmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlSWRCeU1ldGFkYXRhRW50cnlfMyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHJjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUlkQnlNZXRhZGF0YUVudHJ5XzMgPSBhNC5hc20uUmEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBzYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVfMiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHNjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZV8yID0gYTQuYXNtLlNhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgdGMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlQnlVbmlxdWVJZF8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAodGMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlQnlVbmlxdWVJZF8yID0gYTQuYXNtLlRhKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgdWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0TWV0YWRhdGFfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHVjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldE1ldGFkYXRhXzEgPSBhNC5hc20uVWEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCB2YyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVNZXRhZGF0YV8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAodmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlTWV0YWRhdGFfMiA9IGE0LmFzbS5WYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHdjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEZhY2VGcm9tTWVzaF8zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAod2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0RmFjZUZyb21NZXNoXzMgPSBhNC5hc20uV2EpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCB4YyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRUcmlhbmdsZVN0cmlwc0Zyb21NZXNoXzIgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuICh4YyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRUcmlhbmdsZVN0cmlwc0Zyb21NZXNoXzIgPSBhNC5hc20uWGEpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCB5YyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRUcmlhbmdsZXNVSW50MTZBcnJheV8zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoeWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0VHJpYW5nbGVzVUludDE2QXJyYXlfMyA9IGE0LmFzbS5ZYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHpjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldFRyaWFuZ2xlc1VJbnQzMkFycmF5XzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuICh6YyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRUcmlhbmdsZXNVSW50MzJBcnJheV8zID0gYTQuYXNtLlphKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgQWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlRmxvYXRfMyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKEFjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUZsb2F0XzMgPSBhNC5hc20uX2EpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBCYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVGbG9hdEZvckFsbFBvaW50c18zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoQmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlRmxvYXRGb3JBbGxQb2ludHNfMyA9IGE0LmFzbS4kYSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIENjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUludEZvckFsbFBvaW50c18zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoQ2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlSW50Rm9yQWxsUG9pbnRzXzMgPSBhNC5hc20uYWIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBEYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJbnQ4Rm9yQWxsUG9pbnRzXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChEYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJbnQ4Rm9yQWxsUG9pbnRzXzMgPSBhNC5hc20uYmIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBFYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVVSW50OEZvckFsbFBvaW50c18zID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoRWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlVUludDhGb3JBbGxQb2ludHNfMyA9IGE0LmFzbS5jYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEZjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUludDE2Rm9yQWxsUG9pbnRzXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChGYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJbnQxNkZvckFsbFBvaW50c18zID0gYTQuYXNtLmRiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgR2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlVUludDE2Rm9yQWxsUG9pbnRzXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChHYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVVSW50MTZGb3JBbGxQb2ludHNfMyA9IGE0LmFzbS5lYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEhjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZUludDMyRm9yQWxsUG9pbnRzXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChIYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVJbnQzMkZvckFsbFBvaW50c18zID0gYTQuYXNtLmZiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgSWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlVUludDMyRm9yQWxsUG9pbnRzXzMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChJYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRBdHRyaWJ1dGVVSW50MzJGb3JBbGxQb2ludHNfMyA9IGE0LmFzbS5nYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIEpjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEF0dHJpYnV0ZURhdGFBcnJheUZvckFsbFBvaW50c181ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoSmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfR2V0QXR0cmlidXRlRGF0YUFycmF5Rm9yQWxsUG9pbnRzXzUgPSBhNC5hc20uaGIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBLYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9Ta2lwQXR0cmlidXRlVHJhbnNmb3JtXzEgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChLYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9Ta2lwQXR0cmlidXRlVHJhbnNmb3JtXzEgPSBhNC5hc20uaWIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBMYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9HZXRFbmNvZGVkR2VvbWV0cnlUeXBlX0RlcHJlY2F0ZWRfMSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKExjID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0dldEVuY29kZWRHZW9tZXRyeVR5cGVfRGVwcmVjYXRlZF8xID0gYTQuYXNtLmpiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgTWMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfRGVjb2RlQnVmZmVyVG9Qb2ludENsb3VkXzIgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChNYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9EZWNvZGVCdWZmZXJUb1BvaW50Q2xvdWRfMiA9IGE0LmFzbS5rYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIE5jID0gYTQuX2Vtc2NyaXB0ZW5fYmluZF9EZWNvZGVyX0RlY29kZUJ1ZmZlclRvTWVzaF8yID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoTmMgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfRGVjb2RlQnVmZmVyVG9NZXNoXzIgPSBhNC5hc20ubGIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBPYyA9IGE0Ll9lbXNjcmlwdGVuX2JpbmRfRGVjb2Rlcl9fX2Rlc3Ryb3lfX18wID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoT2MgPSBhNC5fZW1zY3JpcHRlbl9iaW5kX0RlY29kZXJfX19kZXN0cm95X19fMCA9IGE0LmFzbS5tYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFBjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19BdHRyaWJ1dGVUcmFuc2Zvcm1UeXBlX0FUVFJJQlVURV9JTlZBTElEX1RSQU5TRk9STSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFBjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19BdHRyaWJ1dGVUcmFuc2Zvcm1UeXBlX0FUVFJJQlVURV9JTlZBTElEX1RSQU5TRk9STSA9IGE0LmFzbS5uYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFFjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19BdHRyaWJ1dGVUcmFuc2Zvcm1UeXBlX0FUVFJJQlVURV9OT19UUkFOU0ZPUk0gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChRYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fQXR0cmlidXRlVHJhbnNmb3JtVHlwZV9BVFRSSUJVVEVfTk9fVFJBTlNGT1JNID0gYTQuYXNtLm9iKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgUmMgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0F0dHJpYnV0ZVRyYW5zZm9ybVR5cGVfQVRUUklCVVRFX1FVQU5USVpBVElPTl9UUkFOU0ZPUk0gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChSYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fQXR0cmlidXRlVHJhbnNmb3JtVHlwZV9BVFRSSUJVVEVfUVVBTlRJWkFUSU9OX1RSQU5TRk9STSA9IGE0LmFzbS5wYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFNjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19BdHRyaWJ1dGVUcmFuc2Zvcm1UeXBlX0FUVFJJQlVURV9PQ1RBSEVEUk9OX1RSQU5TRk9STSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFNjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19BdHRyaWJ1dGVUcmFuc2Zvcm1UeXBlX0FUVFJJQlVURV9PQ1RBSEVEUk9OX1RSQU5TRk9STSA9IGE0LmFzbS5xYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFRjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19HZW9tZXRyeUF0dHJpYnV0ZV9UeXBlX0lOVkFMSUQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChUYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fR2VvbWV0cnlBdHRyaWJ1dGVfVHlwZV9JTlZBTElEID0gYTQuYXNtLnJiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgVWMgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0dlb21ldHJ5QXR0cmlidXRlX1R5cGVfUE9TSVRJT04gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChVYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fR2VvbWV0cnlBdHRyaWJ1dGVfVHlwZV9QT1NJVElPTiA9IGE0LmFzbS5zYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFZjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19HZW9tZXRyeUF0dHJpYnV0ZV9UeXBlX05PUk1BTCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFZjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19HZW9tZXRyeUF0dHJpYnV0ZV9UeXBlX05PUk1BTCA9IGE0LmFzbS50YikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFdjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19HZW9tZXRyeUF0dHJpYnV0ZV9UeXBlX0NPTE9SID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoV2MgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0dlb21ldHJ5QXR0cmlidXRlX1R5cGVfQ09MT1IgPSBhNC5hc20udWIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBYYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fR2VvbWV0cnlBdHRyaWJ1dGVfVHlwZV9URVhfQ09PUkQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChYYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fR2VvbWV0cnlBdHRyaWJ1dGVfVHlwZV9URVhfQ09PUkQgPSBhNC5hc20udmIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBZYyA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fR2VvbWV0cnlBdHRyaWJ1dGVfVHlwZV9HRU5FUklDID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoWWMgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0dlb21ldHJ5QXR0cmlidXRlX1R5cGVfR0VORVJJQyA9IGE0LmFzbS53YikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIFpjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19FbmNvZGVkR2VvbWV0cnlUeXBlX0lOVkFMSURfR0VPTUVUUllfVFlQRSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKFpjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19FbmNvZGVkR2VvbWV0cnlUeXBlX0lOVkFMSURfR0VPTUVUUllfVFlQRSA9IGE0LmFzbS54YikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sICRjID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19FbmNvZGVkR2VvbWV0cnlUeXBlX1BPSU5UX0NMT1VEID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoJGMgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0VuY29kZWRHZW9tZXRyeVR5cGVfUE9JTlRfQ0xPVUQgPSBhNC5hc20ueWIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBhZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRW5jb2RlZEdlb21ldHJ5VHlwZV9UUklBTkdVTEFSX01FU0ggPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChhZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRW5jb2RlZEdlb21ldHJ5VHlwZV9UUklBTkdVTEFSX01FU0ggPSBhNC5hc20uemIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBiZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfSU5WQUxJRCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGJkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9JTlZBTElEID0gYTQuYXNtLkFiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgY2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX0lOVDggPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChjZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfSU5UOCA9IGE0LmFzbS5CYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGRkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9VSU5UOCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGRkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9VSU5UOCA9IGE0LmFzbS5DYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGVkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9JTlQxNiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGVkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9JTlQxNiA9IGE0LmFzbS5EYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGZkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9VSU5UMTYgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChmZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfVUlOVDE2ID0gYTQuYXNtLkViKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgZ2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX0lOVDMyID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoZ2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX0lOVDMyID0gYTQuYXNtLkZiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgaGQgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX1VJTlQzMiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGhkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9VSU5UMzIgPSBhNC5hc20uR2IpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBpZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfSU5UNjQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChpZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfSU5UNjQgPSBhNC5hc20uSGIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBqZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfVUlOVDY0ID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoamQgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX1VJTlQ2NCA9IGE0LmFzbS5JYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIGtkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9GTE9BVDMyID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoa2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX0ZMT0FUMzIgPSBhNC5hc20uSmIpLmFwcGx5KAogICAgICAgICAgICAgIG51bGwsCiAgICAgICAgICAgICAgYXJndW1lbnRzCiAgICAgICAgICAgICk7CiAgICAgICAgICB9LCBsZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfRkxPQVQ2NCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGxkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9GTE9BVDY0ID0gYTQuYXNtLktiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgbWQgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX0RhdGFUeXBlX0RUX0JPT0wgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChtZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fRGF0YVR5cGVfRFRfQk9PTCA9IGE0LmFzbS5MYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIG5kID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9UWVBFU19DT1VOVCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKG5kID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19EYXRhVHlwZV9EVF9UWVBFU19DT1VOVCA9IGE0LmFzbS5NYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIG9kID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19TdGF0dXNDb2RlX09LID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAob2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX1N0YXR1c0NvZGVfT0sgPSBhNC5hc20uTmIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBwZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fU3RhdHVzQ29kZV9EUkFDT19FUlJPUiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHBkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19TdGF0dXNDb2RlX0RSQUNPX0VSUk9SID0gYTQuYXNtLk9iKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfSwgcWQgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX1N0YXR1c0NvZGVfSU9fRVJST1IgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChxZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fU3RhdHVzQ29kZV9JT19FUlJPUiA9IGE0LmFzbS5QYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHJkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19TdGF0dXNDb2RlX0lOVkFMSURfUEFSQU1FVEVSID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAocmQgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX1N0YXR1c0NvZGVfSU5WQUxJRF9QQVJBTUVURVIgPSBhNC5hc20uUWIpLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9LCBzZCA9IGE0Ll9lbXNjcmlwdGVuX2VudW1fZHJhY29fU3RhdHVzQ29kZV9VTlNVUFBPUlRFRF9WRVJTSU9OID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoc2QgPSBhNC5fZW1zY3JpcHRlbl9lbnVtX2RyYWNvX1N0YXR1c0NvZGVfVU5TVVBQT1JURURfVkVSU0lPTiA9IGE0LmFzbS5SYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH0sIHRkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19TdGF0dXNDb2RlX1VOS05PV05fVkVSU0lPTiA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHRkID0gYTQuX2Vtc2NyaXB0ZW5fZW51bV9kcmFjb19TdGF0dXNDb2RlX1VOS05PV05fVkVSU0lPTiA9IGE0LmFzbS5TYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH07CiAgICAgICAgICBhNC5fbWFsbG9jID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoYTQuX21hbGxvYyA9IGE0LmFzbS5UYikuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH07CiAgICAgICAgICBhNC5fZnJlZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKGE0Ll9mcmVlID0gYTQuYXNtLlViKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciB5YSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKHlhID0gYTQuYXNtLlZiKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIGE0Ll9fX3N0YXJ0X2VtX2pzID0gMTU4NTY7CiAgICAgICAgICBhNC5fX19zdG9wX2VtX2pzID0gMTU5NTQ7CiAgICAgICAgICB2YXIgbGE7CiAgICAgICAgICBpYSA9IGZ1bmN0aW9uIGIyKCkgewogICAgICAgICAgICBsYSB8fCBiYSgpOwogICAgICAgICAgICBsYSB8fCAoaWEgPSBiMik7CiAgICAgICAgICB9OwogICAgICAgICAgaWYgKGE0LnByZUluaXQpIGZvciAoImZ1bmN0aW9uIiA9PSB0eXBlb2YgYTQucHJlSW5pdCAmJiAoYTQucHJlSW5pdCA9IFthNC5wcmVJbml0XSk7IDAgPCBhNC5wcmVJbml0Lmxlbmd0aDsgKSBhNC5wcmVJbml0LnBvcCgpKCk7CiAgICAgICAgICBiYSgpOwogICAgICAgICAgdDIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZSh0Mi5wcm90b3R5cGUpOwogICAgICAgICAgdDIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gdDI7CiAgICAgICAgICB0Mi5wcm90b3R5cGUuX19jbGFzc19fID0gdDI7CiAgICAgICAgICB0Mi5fX2NhY2hlX18gPSB7fTsKICAgICAgICAgIGE0LldyYXBwZXJPYmplY3QgPSB0MjsKICAgICAgICAgIGE0LmdldENhY2hlID0geDI7CiAgICAgICAgICBhNC53cmFwUG9pbnRlciA9IEQyOwogICAgICAgICAgYTQuY2FzdE9iamVjdCA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICByZXR1cm4gRDIoYjIucHRyLCBjMik7CiAgICAgICAgICB9OwogICAgICAgICAgYTQuTlVMTCA9IEQyKDApOwogICAgICAgICAgYTQuZGVzdHJveSA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIGlmICghYjIuX19kZXN0cm95X18pIHRocm93ICJFcnJvcjogQ2Fubm90IGRlc3Ryb3kgb2JqZWN0LiAoRGlkIHlvdSBjcmVhdGUgaXQgeW91cnNlbGY/KSI7CiAgICAgICAgICAgIGIyLl9fZGVzdHJveV9fKCk7CiAgICAgICAgICAgIGRlbGV0ZSB4MihiMi5fX2NsYXNzX18pW2IyLnB0cl07CiAgICAgICAgICB9OwogICAgICAgICAgYTQuY29tcGFyZSA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICByZXR1cm4gYjIucHRyID09PSBjMi5wdHI7CiAgICAgICAgICB9OwogICAgICAgICAgYTQuZ2V0UG9pbnRlciA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHJldHVybiBiMi5wdHI7CiAgICAgICAgICB9OwogICAgICAgICAgYTQuZ2V0Q2xhc3MgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICByZXR1cm4gYjIuX19jbGFzc19fOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciByMiA9IHsgYnVmZmVyOiAwLCBzaXplOiAwLCBwb3M6IDAsIHRlbXBzOiBbXSwgbmVlZGVkOiAwLCBwcmVwYXJlOiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgaWYgKHIyLm5lZWRlZCkgewogICAgICAgICAgICAgIGZvciAodmFyIGIyID0gMDsgYjIgPCByMi50ZW1wcy5sZW5ndGg7IGIyKyspIGE0Ll9mcmVlKHIyLnRlbXBzW2IyXSk7CiAgICAgICAgICAgICAgcjIudGVtcHMubGVuZ3RoID0gMDsKICAgICAgICAgICAgICBhNC5fZnJlZShyMi5idWZmZXIpOwogICAgICAgICAgICAgIHIyLmJ1ZmZlciA9IDA7CiAgICAgICAgICAgICAgcjIuc2l6ZSArPSByMi5uZWVkZWQ7CiAgICAgICAgICAgICAgcjIubmVlZGVkID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICByMi5idWZmZXIgfHwgKHIyLnNpemUgKz0gMTI4LCByMi5idWZmZXIgPSBhNC5fbWFsbG9jKHIyLnNpemUpLCByMi5idWZmZXIgfHwgZjIodm9pZCAwKSk7CiAgICAgICAgICAgIHIyLnBvcyA9IDA7CiAgICAgICAgICB9LCBhbGxvYzogZnVuY3Rpb24oYjIsIGMyKSB7CiAgICAgICAgICAgIHIyLmJ1ZmZlciB8fCBmMih2b2lkIDApOwogICAgICAgICAgICBiMiA9IGIyLmxlbmd0aCAqIGMyLkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICAgICAgICBiMiA9IGIyICsgNyAmIC04OwogICAgICAgICAgICByMi5wb3MgKyBiMiA+PSByMi5zaXplID8gKDAgPCBiMiB8fCBmMih2b2lkIDApLCByMi5uZWVkZWQgKz0gYjIsIGMyID0gYTQuX21hbGxvYyhiMiksIHIyLnRlbXBzLnB1c2goYzIpKSA6IChjMiA9IHIyLmJ1ZmZlciArIHIyLnBvcywgcjIucG9zICs9IGIyKTsKICAgICAgICAgICAgcmV0dXJuIGMyOwogICAgICAgICAgfSwgY29weTogZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICBkMiA+Pj49IDA7CiAgICAgICAgICAgIHN3aXRjaCAoYzIuQllURVNfUEVSX0VMRU1FTlQpIHsKICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICBkMiA+Pj49IDE7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICBjYXNlIDQ6CiAgICAgICAgICAgICAgICBkMiA+Pj49IDI7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICBjYXNlIDg6CiAgICAgICAgICAgICAgICBkMiA+Pj49IDM7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZm9yICh2YXIgZzIgPSAwOyBnMiA8IGIyLmxlbmd0aDsgZzIrKykgYzJbZDIgKyBnMl0gPSBiMltnMl07CiAgICAgICAgICB9IH07CiAgICAgICAgICBaMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBaMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBaMjsKICAgICAgICAgIFoyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBaMjsKICAgICAgICAgIFoyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuVm9pZFB0ciA9IFoyOwogICAgICAgICAgWjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gWjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGJiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBTMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBTMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTMjsKICAgICAgICAgIFMyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBTMjsKICAgICAgICAgIFMyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuRGVjb2RlckJ1ZmZlciA9IFMyOwogICAgICAgICAgUzIucHJvdG90eXBlLkluaXQgPSBTMi5wcm90b3R5cGUuSW5pdCA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICB2YXIgZDIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgcjIucHJlcGFyZSgpOwogICAgICAgICAgICAib2JqZWN0IiA9PSB0eXBlb2YgYjIgJiYgKGIyID0gcGEoYjIpKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICBjYihkMiwgYjIsIGMyKTsKICAgICAgICAgIH07CiAgICAgICAgICBTMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBTMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgZGIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIFEyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIFEyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFEyOwogICAgICAgICAgUTIucHJvdG90eXBlLl9fY2xhc3NfXyA9IFEyOwogICAgICAgICAgUTIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5BdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhID0gUTI7CiAgICAgICAgICBRMi5wcm90b3R5cGUudHJhbnNmb3JtX3R5cGUgPSBRMi5wcm90b3R5cGUudHJhbnNmb3JtX3R5cGUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGViKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBRMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBRMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgZmIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIFcyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIFcyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFcyOwogICAgICAgICAgVzIucHJvdG90eXBlLl9fY2xhc3NfXyA9IFcyOwogICAgICAgICAgVzIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5HZW9tZXRyeUF0dHJpYnV0ZSA9IFcyOwogICAgICAgICAgVzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gVzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGdiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICB3Mi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICB3Mi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSB3MjsKICAgICAgICAgIHcyLnByb3RvdHlwZS5fX2NsYXNzX18gPSB3MjsKICAgICAgICAgIHcyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuUG9pbnRBdHRyaWJ1dGUgPSB3MjsKICAgICAgICAgIHcyLnByb3RvdHlwZS5zaXplID0gdzIucHJvdG90eXBlLnNpemUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGhiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICB3Mi5wcm90b3R5cGUuR2V0QXR0cmlidXRlVHJhbnNmb3JtRGF0YSA9IHcyLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVUcmFuc2Zvcm1EYXRhID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBEMihpYih0aGlzLnB0ciksIFEyKTsKICAgICAgICAgIH07CiAgICAgICAgICB3Mi5wcm90b3R5cGUuYXR0cmlidXRlX3R5cGUgPSB3Mi5wcm90b3R5cGUuYXR0cmlidXRlX3R5cGUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGpiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICB3Mi5wcm90b3R5cGUuZGF0YV90eXBlID0gdzIucHJvdG90eXBlLmRhdGFfdHlwZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4ga2IodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIHcyLnByb3RvdHlwZS5udW1fY29tcG9uZW50cyA9IHcyLnByb3RvdHlwZS5udW1fY29tcG9uZW50cyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gbGIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIHcyLnByb3RvdHlwZS5ub3JtYWxpemVkID0gdzIucHJvdG90eXBlLm5vcm1hbGl6ZWQgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuICEhbWIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIHcyLnByb3RvdHlwZS5ieXRlX3N0cmlkZSA9IHcyLnByb3RvdHlwZS5ieXRlX3N0cmlkZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gbmIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIHcyLnByb3RvdHlwZS5ieXRlX29mZnNldCA9IHcyLnByb3RvdHlwZS5ieXRlX29mZnNldCA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gb2IodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIHcyLnByb3RvdHlwZS51bmlxdWVfaWQgPSB3Mi5wcm90b3R5cGUudW5pcXVlX2lkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBwYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgdzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gdzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHFiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBDMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBDMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDMjsKICAgICAgICAgIEMyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBDMjsKICAgICAgICAgIEMyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuQXR0cmlidXRlUXVhbnRpemF0aW9uVHJhbnNmb3JtID0gQzI7CiAgICAgICAgICBDMi5wcm90b3R5cGUuSW5pdEZyb21BdHRyaWJ1dGUgPSBDMi5wcm90b3R5cGUuSW5pdEZyb21BdHRyaWJ1dGUgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICB2YXIgYzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFyYihjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIEMyLnByb3RvdHlwZS5xdWFudGl6YXRpb25fYml0cyA9IEMyLnByb3RvdHlwZS5xdWFudGl6YXRpb25fYml0cyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gc2IodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEMyLnByb3RvdHlwZS5taW5fdmFsdWUgPSBDMi5wcm90b3R5cGUubWluX3ZhbHVlID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIHRiKGMyLCBiMik7CiAgICAgICAgICB9OwogICAgICAgICAgQzIucHJvdG90eXBlLnJhbmdlID0gQzIucHJvdG90eXBlLnJhbmdlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiB1Yih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgQzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gQzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHZiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBGMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBGMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBGMjsKICAgICAgICAgIEYyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBGMjsKICAgICAgICAgIEYyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuQXR0cmlidXRlT2N0YWhlZHJvblRyYW5zZm9ybSA9IEYyOwogICAgICAgICAgRjIucHJvdG90eXBlLkluaXRGcm9tQXR0cmlidXRlID0gRjIucHJvdG90eXBlLkluaXRGcm9tQXR0cmlidXRlID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEhd2IoYzIsIGIyKTsKICAgICAgICAgIH07CiAgICAgICAgICBGMi5wcm90b3R5cGUucXVhbnRpemF0aW9uX2JpdHMgPSBGMi5wcm90b3R5cGUucXVhbnRpemF0aW9uX2JpdHMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHhiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBGMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBGMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgeWIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEcyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIEcyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEcyOwogICAgICAgICAgRzIucHJvdG90eXBlLl9fY2xhc3NfXyA9IEcyOwogICAgICAgICAgRzIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5Qb2ludENsb3VkID0gRzI7CiAgICAgICAgICBHMi5wcm90b3R5cGUubnVtX2F0dHJpYnV0ZXMgPSBHMi5wcm90b3R5cGUubnVtX2F0dHJpYnV0ZXMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIHpiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBHMi5wcm90b3R5cGUubnVtX3BvaW50cyA9IEcyLnByb3RvdHlwZS5udW1fcG9pbnRzID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBBYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgRzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gRzIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIEJiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBFMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBFMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBFMjsKICAgICAgICAgIEUyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBFMjsKICAgICAgICAgIEUyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuTWVzaCA9IEUyOwogICAgICAgICAgRTIucHJvdG90eXBlLm51bV9mYWNlcyA9IEUyLnByb3RvdHlwZS5udW1fZmFjZXMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIENiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBFMi5wcm90b3R5cGUubnVtX2F0dHJpYnV0ZXMgPSBFMi5wcm90b3R5cGUubnVtX2F0dHJpYnV0ZXMgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIERiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBFMi5wcm90b3R5cGUubnVtX3BvaW50cyA9IEUyLnByb3RvdHlwZS5udW1fcG9pbnRzID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBFYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgRTIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gRTIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIEZiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBUMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBUMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBUMjsKICAgICAgICAgIFQyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBUMjsKICAgICAgICAgIFQyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuTWV0YWRhdGEgPSBUMjsKICAgICAgICAgIFQyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IFQyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBHYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgQjIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZSh0Mi5wcm90b3R5cGUpOwogICAgICAgICAgQjIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQjI7CiAgICAgICAgICBCMi5wcm90b3R5cGUuX19jbGFzc19fID0gQjI7CiAgICAgICAgICBCMi5fX2NhY2hlX18gPSB7fTsKICAgICAgICAgIGE0LlN0YXR1cyA9IEIyOwogICAgICAgICAgQjIucHJvdG90eXBlLmNvZGUgPSBCMi5wcm90b3R5cGUuY29kZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gSGIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEIyLnByb3RvdHlwZS5vayA9IEIyLnByb3RvdHlwZS5vayA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gISFJYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgQjIucHJvdG90eXBlLmVycm9yX21zZyA9IEIyLnByb3RvdHlwZS5lcnJvcl9tc2cgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGgyKEpiKHRoaXMucHRyKSk7CiAgICAgICAgICB9OwogICAgICAgICAgQjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gQjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIEtiKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBIMi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICBIMi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBIMjsKICAgICAgICAgIEgyLnByb3RvdHlwZS5fX2NsYXNzX18gPSBIMjsKICAgICAgICAgIEgyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuRHJhY29GbG9hdDMyQXJyYXkgPSBIMjsKICAgICAgICAgIEgyLnByb3RvdHlwZS5HZXRWYWx1ZSA9IEgyLnByb3RvdHlwZS5HZXRWYWx1ZSA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHZhciBjMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBMYihjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIEgyLnByb3RvdHlwZS5zaXplID0gSDIucHJvdG90eXBlLnNpemUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIE1iKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBIMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBIMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgTmIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEkyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIEkyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEkyOwogICAgICAgICAgSTIucHJvdG90eXBlLl9fY2xhc3NfXyA9IEkyOwogICAgICAgICAgSTIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5EcmFjb0ludDhBcnJheSA9IEkyOwogICAgICAgICAgSTIucHJvdG90eXBlLkdldFZhbHVlID0gSTIucHJvdG90eXBlLkdldFZhbHVlID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIE9iKGMyLCBiMik7CiAgICAgICAgICB9OwogICAgICAgICAgSTIucHJvdG90eXBlLnNpemUgPSBJMi5wcm90b3R5cGUuc2l6ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gUGIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEkyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IEkyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBRYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgSjIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZSh0Mi5wcm90b3R5cGUpOwogICAgICAgICAgSjIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSjI7CiAgICAgICAgICBKMi5wcm90b3R5cGUuX19jbGFzc19fID0gSjI7CiAgICAgICAgICBKMi5fX2NhY2hlX18gPSB7fTsKICAgICAgICAgIGE0LkRyYWNvVUludDhBcnJheSA9IEoyOwogICAgICAgICAgSjIucHJvdG90eXBlLkdldFZhbHVlID0gSjIucHJvdG90eXBlLkdldFZhbHVlID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIFJiKGMyLCBiMik7CiAgICAgICAgICB9OwogICAgICAgICAgSjIucHJvdG90eXBlLnNpemUgPSBKMi5wcm90b3R5cGUuc2l6ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gU2IodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEoyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IEoyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBUYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgSzIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZSh0Mi5wcm90b3R5cGUpOwogICAgICAgICAgSzIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSzI7CiAgICAgICAgICBLMi5wcm90b3R5cGUuX19jbGFzc19fID0gSzI7CiAgICAgICAgICBLMi5fX2NhY2hlX18gPSB7fTsKICAgICAgICAgIGE0LkRyYWNvSW50MTZBcnJheSA9IEsyOwogICAgICAgICAgSzIucHJvdG90eXBlLkdldFZhbHVlID0gSzIucHJvdG90eXBlLkdldFZhbHVlID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIFViKGMyLCBiMik7CiAgICAgICAgICB9OwogICAgICAgICAgSzIucHJvdG90eXBlLnNpemUgPSBLMi5wcm90b3R5cGUuc2l6ZSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gVmIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIEsyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IEsyLnByb3RvdHlwZS5fX2Rlc3Ryb3lfXyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICBXYih0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgTDIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZSh0Mi5wcm90b3R5cGUpOwogICAgICAgICAgTDIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTDI7CiAgICAgICAgICBMMi5wcm90b3R5cGUuX19jbGFzc19fID0gTDI7CiAgICAgICAgICBMMi5fX2NhY2hlX18gPSB7fTsKICAgICAgICAgIGE0LkRyYWNvVUludDE2QXJyYXkgPSBMMjsKICAgICAgICAgIEwyLnByb3RvdHlwZS5HZXRWYWx1ZSA9IEwyLnByb3RvdHlwZS5HZXRWYWx1ZSA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHZhciBjMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBYYihjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIEwyLnByb3RvdHlwZS5zaXplID0gTDIucHJvdG90eXBlLnNpemUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIFliKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBMMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBMMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgWmIodGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIE0yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIE0yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IE0yOwogICAgICAgICAgTTIucHJvdG90eXBlLl9fY2xhc3NfXyA9IE0yOwogICAgICAgICAgTTIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5EcmFjb0ludDMyQXJyYXkgPSBNMjsKICAgICAgICAgIE0yLnByb3RvdHlwZS5HZXRWYWx1ZSA9IE0yLnByb3RvdHlwZS5HZXRWYWx1ZSA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHZhciBjMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIHJldHVybiAkYihjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIE0yLnByb3RvdHlwZS5zaXplID0gTTIucHJvdG90eXBlLnNpemUgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIGFjKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICBNMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBNMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgYmModGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIE4yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIE4yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IE4yOwogICAgICAgICAgTjIucHJvdG90eXBlLl9fY2xhc3NfXyA9IE4yOwogICAgICAgICAgTjIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5EcmFjb1VJbnQzMkFycmF5ID0gTjI7CiAgICAgICAgICBOMi5wcm90b3R5cGUuR2V0VmFsdWUgPSBOMi5wcm90b3R5cGUuR2V0VmFsdWUgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICB2YXIgYzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gY2MoYzIsIGIyKTsKICAgICAgICAgIH07CiAgICAgICAgICBOMi5wcm90b3R5cGUuc2l6ZSA9IE4yLnByb3RvdHlwZS5zaXplID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiBkYyh0aGlzLnB0cik7CiAgICAgICAgICB9OwogICAgICAgICAgTjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gTjIucHJvdG90eXBlLl9fZGVzdHJveV9fID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIGVjKHRoaXMucHRyKTsKICAgICAgICAgIH07CiAgICAgICAgICB5Mi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKHQyLnByb3RvdHlwZSk7CiAgICAgICAgICB5Mi5wcm90b3R5cGUuY29uc3RydWN0b3IgPSB5MjsKICAgICAgICAgIHkyLnByb3RvdHlwZS5fX2NsYXNzX18gPSB5MjsKICAgICAgICAgIHkyLl9fY2FjaGVfXyA9IHt9OwogICAgICAgICAgYTQuTWV0YWRhdGFRdWVyaWVyID0geTI7CiAgICAgICAgICB5Mi5wcm90b3R5cGUuSGFzRW50cnkgPSB5Mi5wcm90b3R5cGUuSGFzRW50cnkgPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIHIyLnByZXBhcmUoKTsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiA9IGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgPyBjMi5wdHIgOiBSMihjMik7CiAgICAgICAgICAgIHJldHVybiAhIWZjKGQyLCBiMiwgYzIpOwogICAgICAgICAgfTsKICAgICAgICAgIHkyLnByb3RvdHlwZS5HZXRJbnRFbnRyeSA9IHkyLnByb3RvdHlwZS5HZXRJbnRFbnRyeSA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICB2YXIgZDIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgcjIucHJlcGFyZSgpOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyID0gYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiA/IGMyLnB0ciA6IFIyKGMyKTsKICAgICAgICAgICAgcmV0dXJuIGdjKGQyLCBiMiwgYzIpOwogICAgICAgICAgfTsKICAgICAgICAgIHkyLnByb3RvdHlwZS5HZXRJbnRFbnRyeUFycmF5ID0geTIucHJvdG90eXBlLkdldEludEVudHJ5QXJyYXkgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICByMi5wcmVwYXJlKCk7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgPSBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyID8gYzIucHRyIDogUjIoYzIpOwogICAgICAgICAgICBkMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGQyICYmIChkMiA9IGQyLnB0cik7CiAgICAgICAgICAgIGhjKGcyLCBiMiwgYzIsIGQyKTsKICAgICAgICAgIH07CiAgICAgICAgICB5Mi5wcm90b3R5cGUuR2V0RG91YmxlRW50cnkgPSB5Mi5wcm90b3R5cGUuR2V0RG91YmxlRW50cnkgPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIHIyLnByZXBhcmUoKTsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiA9IGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgPyBjMi5wdHIgOiBSMihjMik7CiAgICAgICAgICAgIHJldHVybiBpYyhkMiwgYjIsIGMyKTsKICAgICAgICAgIH07CiAgICAgICAgICB5Mi5wcm90b3R5cGUuR2V0U3RyaW5nRW50cnkgPSB5Mi5wcm90b3R5cGUuR2V0U3RyaW5nRW50cnkgPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIHIyLnByZXBhcmUoKTsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiA9IGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgPyBjMi5wdHIgOiBSMihjMik7CiAgICAgICAgICAgIHJldHVybiBoMihqYyhkMiwgYjIsIGMyKSk7CiAgICAgICAgICB9OwogICAgICAgICAgeTIucHJvdG90eXBlLk51bUVudHJpZXMgPSB5Mi5wcm90b3R5cGUuTnVtRW50cmllcyA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHZhciBjMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBrYyhjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIHkyLnByb3RvdHlwZS5HZXRFbnRyeU5hbWUgPSB5Mi5wcm90b3R5cGUuR2V0RW50cnlOYW1lID0gZnVuY3Rpb24oYjIsIGMyKSB7CiAgICAgICAgICAgIHZhciBkMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIGgyKGxjKGQyLCBiMiwgYzIpKTsKICAgICAgICAgIH07CiAgICAgICAgICB5Mi5wcm90b3R5cGUuX19kZXN0cm95X18gPSB5Mi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgbWModGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUodDIucHJvdG90eXBlKTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IG0yOwogICAgICAgICAgbTIucHJvdG90eXBlLl9fY2xhc3NfXyA9IG0yOwogICAgICAgICAgbTIuX19jYWNoZV9fID0ge307CiAgICAgICAgICBhNC5EZWNvZGVyID0gbTI7CiAgICAgICAgICBtMi5wcm90b3R5cGUuRGVjb2RlQXJyYXlUb1BvaW50Q2xvdWQgPSBtMi5wcm90b3R5cGUuRGVjb2RlQXJyYXlUb1BvaW50Q2xvdWQgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICByMi5wcmVwYXJlKCk7CiAgICAgICAgICAgICJvYmplY3QiID09IHR5cGVvZiBiMiAmJiAoYjIgPSBwYShiMikpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIEQyKG5jKGcyLCBiMiwgYzIsIGQyKSwgQjIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5EZWNvZGVBcnJheVRvTWVzaCA9IG0yLnByb3RvdHlwZS5EZWNvZGVBcnJheVRvTWVzaCA9IGZ1bmN0aW9uKGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgdmFyIGcyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIHIyLnByZXBhcmUoKTsKICAgICAgICAgICAgIm9iamVjdCIgPT0gdHlwZW9mIGIyICYmIChiMiA9IHBhKGIyKSk7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiAmJiAoZDIgPSBkMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gRDIob2MoZzIsIGIyLCBjMiwgZDIpLCBCMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUlkID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUlkID0gZnVuY3Rpb24oYjIsIGMyKSB7CiAgICAgICAgICAgIHZhciBkMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIHBjKGQyLCBiMiwgYzIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJZEJ5TmFtZSA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJZEJ5TmFtZSA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICB2YXIgZDIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgcjIucHJlcGFyZSgpOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyID0gYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiA/IGMyLnB0ciA6IFIyKGMyKTsKICAgICAgICAgICAgcmV0dXJuIHFjKGQyLCBiMiwgYzIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJZEJ5TWV0YWRhdGFFbnRyeSA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJZEJ5TWV0YWRhdGFFbnRyeSA9IGZ1bmN0aW9uKGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgdmFyIGcyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIHIyLnByZXBhcmUoKTsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiA9IGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgPyBjMi5wdHIgOiBSMihjMik7CiAgICAgICAgICAgIGQyID0gZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiA/IGQyLnB0ciA6IFIyKGQyKTsKICAgICAgICAgICAgcmV0dXJuIHJjKGcyLCBiMiwgYzIsIGQyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZSA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICB2YXIgZDIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBEMihzYyhkMiwgYjIsIGMyKSwgdzIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVCeVVuaXF1ZUlkID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUJ5VW5pcXVlSWQgPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gRDIodGMoZDIsIGIyLCBjMiksIHcyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0TWV0YWRhdGEgPSBtMi5wcm90b3R5cGUuR2V0TWV0YWRhdGEgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICB2YXIgYzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gRDIodWMoYzIsIGIyKSwgVDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVNZXRhZGF0YSA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVNZXRhZGF0YSA9IGZ1bmN0aW9uKGIyLCBjMikgewogICAgICAgICAgICB2YXIgZDIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBEMih2YyhkMiwgYjIsIGMyKSwgVDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRGYWNlRnJvbU1lc2ggPSBtMi5wcm90b3R5cGUuR2V0RmFjZUZyb21NZXNoID0gZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICB2YXIgZzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEhd2MoZzIsIGIyLCBjMiwgZDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRUcmlhbmdsZVN0cmlwc0Zyb21NZXNoID0gbTIucHJvdG90eXBlLkdldFRyaWFuZ2xlU3RyaXBzRnJvbU1lc2ggPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICByZXR1cm4geGMoZDIsIGIyLCBjMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldFRyaWFuZ2xlc1VJbnQxNkFycmF5ID0gbTIucHJvdG90eXBlLkdldFRyaWFuZ2xlc1VJbnQxNkFycmF5ID0gZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICB2YXIgZzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEheWMoZzIsIGIyLCBjMiwgZDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRUcmlhbmdsZXNVSW50MzJBcnJheSA9IG0yLnByb3RvdHlwZS5HZXRUcmlhbmdsZXNVSW50MzJBcnJheSA9IGZ1bmN0aW9uKGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgdmFyIGcyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICBkMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGQyICYmIChkMiA9IGQyLnB0cik7CiAgICAgICAgICAgIHJldHVybiAhIXpjKGcyLCBiMiwgYzIsIGQyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlRmxvYXQgPSBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlRmxvYXQgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiAmJiAoZDIgPSBkMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFBYyhnMiwgYjIsIGMyLCBkMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUZsb2F0Rm9yQWxsUG9pbnRzID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUZsb2F0Rm9yQWxsUG9pbnRzID0gZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICB2YXIgZzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEhQmMoZzIsIGIyLCBjMiwgZDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJbnRGb3JBbGxQb2ludHMgPSBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlSW50Rm9yQWxsUG9pbnRzID0gZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICB2YXIgZzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEhQ2MoZzIsIGIyLCBjMiwgZDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJbnQ4Rm9yQWxsUG9pbnRzID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZUludDhGb3JBbGxQb2ludHMgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiAmJiAoZDIgPSBkMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFEYyhnMiwgYjIsIGMyLCBkMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZVVJbnQ4Rm9yQWxsUG9pbnRzID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZVVJbnQ4Rm9yQWxsUG9pbnRzID0gZnVuY3Rpb24oYjIsIGMyLCBkMikgewogICAgICAgICAgICB2YXIgZzIgPSB0aGlzLnB0cjsKICAgICAgICAgICAgYjIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBiMiAmJiAoYjIgPSBiMi5wdHIpOwogICAgICAgICAgICBjMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGMyICYmIChjMiA9IGMyLnB0cik7CiAgICAgICAgICAgIGQyICYmICJvYmplY3QiID09PSB0eXBlb2YgZDIgJiYgKGQyID0gZDIucHRyKTsKICAgICAgICAgICAgcmV0dXJuICEhRWMoZzIsIGIyLCBjMiwgZDIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJbnQxNkZvckFsbFBvaW50cyA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVJbnQxNkZvckFsbFBvaW50cyA9IGZ1bmN0aW9uKGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgdmFyIGcyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICBkMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGQyICYmIChkMiA9IGQyLnB0cik7CiAgICAgICAgICAgIHJldHVybiAhIUZjKGcyLCBiMiwgYzIsIGQyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlVUludDE2Rm9yQWxsUG9pbnRzID0gbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZVVJbnQxNkZvckFsbFBvaW50cyA9IGZ1bmN0aW9uKGIyLCBjMiwgZDIpIHsKICAgICAgICAgICAgdmFyIGcyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICBkMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGQyICYmIChkMiA9IGQyLnB0cik7CiAgICAgICAgICAgIHJldHVybiAhIUdjKGcyLCBiMiwgYzIsIGQyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlSW50MzJGb3JBbGxQb2ludHMgPSBtMi5wcm90b3R5cGUuR2V0QXR0cmlidXRlSW50MzJGb3JBbGxQb2ludHMgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiAmJiAoZDIgPSBkMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFIYyhnMiwgYjIsIGMyLCBkMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZVVJbnQzMkZvckFsbFBvaW50cyA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVVSW50MzJGb3JBbGxQb2ludHMgPSBmdW5jdGlvbihiMiwgYzIsIGQyKSB7CiAgICAgICAgICAgIHZhciBnMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgZDIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBkMiAmJiAoZDIgPSBkMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFJYyhnMiwgYjIsIGMyLCBkMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkdldEF0dHJpYnV0ZURhdGFBcnJheUZvckFsbFBvaW50cyA9IG0yLnByb3RvdHlwZS5HZXRBdHRyaWJ1dGVEYXRhQXJyYXlGb3JBbGxQb2ludHMgPSBmdW5jdGlvbihiMiwgYzIsIGQyLCBnMiwgdTQpIHsKICAgICAgICAgICAgdmFyIFgyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICBkMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGQyICYmIChkMiA9IGQyLnB0cik7CiAgICAgICAgICAgIGcyICYmICJvYmplY3QiID09PSB0eXBlb2YgZzIgJiYgKGcyID0gZzIucHRyKTsKICAgICAgICAgICAgdTQgJiYgIm9iamVjdCIgPT09IHR5cGVvZiB1NCAmJiAodTQgPSB1NC5wdHIpOwogICAgICAgICAgICByZXR1cm4gISFKYyhYMiwgYjIsIGMyLCBkMiwgZzIsIHU0KTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuU2tpcEF0dHJpYnV0ZVRyYW5zZm9ybSA9IG0yLnByb3RvdHlwZS5Ta2lwQXR0cmlidXRlVHJhbnNmb3JtID0gZnVuY3Rpb24oYjIpIHsKICAgICAgICAgICAgdmFyIGMyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgS2MoYzIsIGIyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuR2V0RW5jb2RlZEdlb21ldHJ5VHlwZV9EZXByZWNhdGVkID0gbTIucHJvdG90eXBlLkdldEVuY29kZWRHZW9tZXRyeVR5cGVfRGVwcmVjYXRlZCA9IGZ1bmN0aW9uKGIyKSB7CiAgICAgICAgICAgIHZhciBjMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIHJldHVybiBMYyhjMiwgYjIpOwogICAgICAgICAgfTsKICAgICAgICAgIG0yLnByb3RvdHlwZS5EZWNvZGVCdWZmZXJUb1BvaW50Q2xvdWQgPSBtMi5wcm90b3R5cGUuRGVjb2RlQnVmZmVyVG9Qb2ludENsb3VkID0gZnVuY3Rpb24oYjIsIGMyKSB7CiAgICAgICAgICAgIHZhciBkMiA9IHRoaXMucHRyOwogICAgICAgICAgICBiMiAmJiAib2JqZWN0IiA9PT0gdHlwZW9mIGIyICYmIChiMiA9IGIyLnB0cik7CiAgICAgICAgICAgIGMyICYmICJvYmplY3QiID09PSB0eXBlb2YgYzIgJiYgKGMyID0gYzIucHRyKTsKICAgICAgICAgICAgcmV0dXJuIEQyKE1jKGQyLCBiMiwgYzIpLCBCMik7CiAgICAgICAgICB9OwogICAgICAgICAgbTIucHJvdG90eXBlLkRlY29kZUJ1ZmZlclRvTWVzaCA9IG0yLnByb3RvdHlwZS5EZWNvZGVCdWZmZXJUb01lc2ggPSBmdW5jdGlvbihiMiwgYzIpIHsKICAgICAgICAgICAgdmFyIGQyID0gdGhpcy5wdHI7CiAgICAgICAgICAgIGIyICYmICJvYmplY3QiID09PSB0eXBlb2YgYjIgJiYgKGIyID0gYjIucHRyKTsKICAgICAgICAgICAgYzIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBjMiAmJiAoYzIgPSBjMi5wdHIpOwogICAgICAgICAgICByZXR1cm4gRDIoTmMoZDIsIGIyLCBjMiksIEIyKTsKICAgICAgICAgIH07CiAgICAgICAgICBtMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBtMi5wcm90b3R5cGUuX19kZXN0cm95X18gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgT2ModGhpcy5wdHIpOwogICAgICAgICAgfTsKICAgICAgICAgIChmdW5jdGlvbigpIHsKICAgICAgICAgICAgZnVuY3Rpb24gYjIoKSB7CiAgICAgICAgICAgICAgYTQuQVRUUklCVVRFX0lOVkFMSURfVFJBTlNGT1JNID0gUGMoKTsKICAgICAgICAgICAgICBhNC5BVFRSSUJVVEVfTk9fVFJBTlNGT1JNID0gUWMoKTsKICAgICAgICAgICAgICBhNC5BVFRSSUJVVEVfUVVBTlRJWkFUSU9OX1RSQU5TRk9STSA9IFJjKCk7CiAgICAgICAgICAgICAgYTQuQVRUUklCVVRFX09DVEFIRURST05fVFJBTlNGT1JNID0gU2MoKTsKICAgICAgICAgICAgICBhNC5JTlZBTElEID0gVGMoKTsKICAgICAgICAgICAgICBhNC5QT1NJVElPTiA9IFVjKCk7CiAgICAgICAgICAgICAgYTQuTk9STUFMID0gVmMoKTsKICAgICAgICAgICAgICBhNC5DT0xPUiA9IFdjKCk7CiAgICAgICAgICAgICAgYTQuVEVYX0NPT1JEID0gWGMoKTsKICAgICAgICAgICAgICBhNC5HRU5FUklDID0gWWMoKTsKICAgICAgICAgICAgICBhNC5JTlZBTElEX0dFT01FVFJZX1RZUEUgPSBaYygpOwogICAgICAgICAgICAgIGE0LlBPSU5UX0NMT1VEID0gJGMoKTsKICAgICAgICAgICAgICBhNC5UUklBTkdVTEFSX01FU0ggPSBhZCgpOwogICAgICAgICAgICAgIGE0LkRUX0lOVkFMSUQgPSBiZCgpOwogICAgICAgICAgICAgIGE0LkRUX0lOVDggPSBjZCgpOwogICAgICAgICAgICAgIGE0LkRUX1VJTlQ4ID0gZGQoKTsKICAgICAgICAgICAgICBhNC5EVF9JTlQxNiA9IGVkKCk7CiAgICAgICAgICAgICAgYTQuRFRfVUlOVDE2ID0gZmQoKTsKICAgICAgICAgICAgICBhNC5EVF9JTlQzMiA9IGdkKCk7CiAgICAgICAgICAgICAgYTQuRFRfVUlOVDMyID0gaGQoKTsKICAgICAgICAgICAgICBhNC5EVF9JTlQ2NCA9IGlkKCk7CiAgICAgICAgICAgICAgYTQuRFRfVUlOVDY0ID0gamQoKTsKICAgICAgICAgICAgICBhNC5EVF9GTE9BVDMyID0ga2QoKTsKICAgICAgICAgICAgICBhNC5EVF9GTE9BVDY0ID0gbGQoKTsKICAgICAgICAgICAgICBhNC5EVF9CT09MID0gbWQoKTsKICAgICAgICAgICAgICBhNC5EVF9UWVBFU19DT1VOVCA9IG5kKCk7CiAgICAgICAgICAgICAgYTQuT0sgPSBvZCgpOwogICAgICAgICAgICAgIGE0LkRSQUNPX0VSUk9SID0gcGQoKTsKICAgICAgICAgICAgICBhNC5JT19FUlJPUiA9IHFkKCk7CiAgICAgICAgICAgICAgYTQuSU5WQUxJRF9QQVJBTUVURVIgPSByZCgpOwogICAgICAgICAgICAgIGE0LlVOU1VQUE9SVEVEX1ZFUlNJT04gPSBzZCgpOwogICAgICAgICAgICAgIGE0LlVOS05PV05fVkVSU0lPTiA9IHRkKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgemEgPyBiMigpIDogb2EudW5zaGlmdChiMik7CiAgICAgICAgICB9KSgpOwogICAgICAgICAgaWYgKCJmdW5jdGlvbiIgPT09IHR5cGVvZiBhNC5vbk1vZHVsZVBhcnNlZCkgYTQub25Nb2R1bGVQYXJzZWQoKTsKICAgICAgICAgIGE0LkRlY29kZXIucHJvdG90eXBlLkdldEVuY29kZWRHZW9tZXRyeVR5cGUgPSBmdW5jdGlvbihiMikgewogICAgICAgICAgICBpZiAoYjIuX19jbGFzc19fICYmIGIyLl9fY2xhc3NfXyA9PT0gYTQuRGVjb2RlckJ1ZmZlcikgcmV0dXJuIGE0LkRlY29kZXIucHJvdG90eXBlLkdldEVuY29kZWRHZW9tZXRyeVR5cGVfRGVwcmVjYXRlZChiMik7CiAgICAgICAgICAgIGlmICg4ID4gYjIuYnl0ZUxlbmd0aCkgcmV0dXJuIGE0LklOVkFMSURfR0VPTUVUUllfVFlQRTsKICAgICAgICAgICAgc3dpdGNoIChiMls3XSkgewogICAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICAgIHJldHVybiBhNC5QT0lOVF9DTE9VRDsKICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICByZXR1cm4gYTQuVFJJQU5HVUxBUl9NRVNIOwogICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICByZXR1cm4gYTQuSU5WQUxJRF9HRU9NRVRSWV9UWVBFOwogICAgICAgICAgICB9CiAgICAgICAgICB9OwogICAgICAgICAgcmV0dXJuIG4yLnJlYWR5OwogICAgICAgIH07CiAgICAgIH0pKCk7CiAgICAgICJvYmplY3QiID09PSB0eXBlb2YgZXhwb3J0czIgJiYgIm9iamVjdCIgPT09IHR5cGVvZiBtb2R1bGUgPyBtb2R1bGUuZXhwb3J0cyA9IERyYWNvRGVjb2Rlck1vZHVsZSA6ICJmdW5jdGlvbiIgPT09IHR5cGVvZiBkZWZpbmUgJiYgZGVmaW5lLmFtZCA/IGRlZmluZShbXSwgZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIERyYWNvRGVjb2Rlck1vZHVsZTsKICAgICAgfSkgOiAib2JqZWN0IiA9PT0gdHlwZW9mIGV4cG9ydHMyICYmIChleHBvcnRzMi5EcmFjb0RlY29kZXJNb2R1bGUgPSBEcmFjb0RlY29kZXJNb2R1bGUpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvZGVjb2RlRHJhY28uanMKICB2YXIgZGVjb2RlRHJhY29fZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGRlY29kZURyYWNvX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGRlY29kZURyYWNvX2RlZmF1bHQKICB9KTsKICBmdW5jdGlvbiBkZWNvZGVJbmRleEFycmF5KGRyYWNvR2VvbWV0cnksIGRyYWNvRGVjb2RlcikgewogICAgY29uc3QgbnVtUG9pbnRzID0gZHJhY29HZW9tZXRyeS5udW1fcG9pbnRzKCk7CiAgICBjb25zdCBudW1GYWNlcyA9IGRyYWNvR2VvbWV0cnkubnVtX2ZhY2VzKCk7CiAgICBjb25zdCBmYWNlSW5kaWNlcyA9IG5ldyBkcmFjby5EcmFjb0ludDMyQXJyYXkoKTsKICAgIGNvbnN0IG51bUluZGljZXMgPSBudW1GYWNlcyAqIDM7CiAgICBjb25zdCBpbmRleEFycmF5ID0gSW5kZXhEYXRhdHlwZV9kZWZhdWx0LmNyZWF0ZVR5cGVkQXJyYXkobnVtUG9pbnRzLCBudW1JbmRpY2VzKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG51bUZhY2VzOyArK2kyKSB7CiAgICAgIGRyYWNvRGVjb2Rlci5HZXRGYWNlRnJvbU1lc2goZHJhY29HZW9tZXRyeSwgaTIsIGZhY2VJbmRpY2VzKTsKICAgICAgaW5kZXhBcnJheVtvZmZzZXQgKyAwXSA9IGZhY2VJbmRpY2VzLkdldFZhbHVlKDApOwogICAgICBpbmRleEFycmF5W29mZnNldCArIDFdID0gZmFjZUluZGljZXMuR2V0VmFsdWUoMSk7CiAgICAgIGluZGV4QXJyYXlbb2Zmc2V0ICsgMl0gPSBmYWNlSW5kaWNlcy5HZXRWYWx1ZSgyKTsKICAgICAgb2Zmc2V0ICs9IDM7CiAgICB9CiAgICBkcmFjby5kZXN0cm95KGZhY2VJbmRpY2VzKTsKICAgIHJldHVybiB7CiAgICAgIHR5cGVkQXJyYXk6IGluZGV4QXJyYXksCiAgICAgIG51bWJlck9mSW5kaWNlczogbnVtSW5kaWNlcwogICAgfTsKICB9CiAgZnVuY3Rpb24gZGVjb2RlUXVhbnRpemVkRHJhY29UeXBlZEFycmF5KGRyYWNvR2VvbWV0cnksIGRyYWNvRGVjb2RlciwgZHJhY29BdHRyaWJ1dGUsIHF1YW50aXphdGlvbiwgdmVydGV4QXJyYXlMZW5ndGgpIHsKICAgIGxldCB2ZXJ0ZXhBcnJheTsKICAgIGxldCBhdHRyaWJ1dGVEYXRhOwogICAgaWYgKHF1YW50aXphdGlvbi5xdWFudGl6YXRpb25CaXRzIDw9IDgpIHsKICAgICAgYXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjby5EcmFjb1VJbnQ4QXJyYXkoKTsKICAgICAgdmVydGV4QXJyYXkgPSBuZXcgVWludDhBcnJheSh2ZXJ0ZXhBcnJheUxlbmd0aCk7CiAgICAgIGRyYWNvRGVjb2Rlci5HZXRBdHRyaWJ1dGVVSW50OEZvckFsbFBvaW50cygKICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgIGF0dHJpYnV0ZURhdGEKICAgICAgKTsKICAgIH0gZWxzZSBpZiAocXVhbnRpemF0aW9uLnF1YW50aXphdGlvbkJpdHMgPD0gMTYpIHsKICAgICAgYXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjby5EcmFjb1VJbnQxNkFycmF5KCk7CiAgICAgIHZlcnRleEFycmF5ID0gbmV3IFVpbnQxNkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZVVJbnQxNkZvckFsbFBvaW50cygKICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgIGF0dHJpYnV0ZURhdGEKICAgICAgKTsKICAgIH0gZWxzZSB7CiAgICAgIGF0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY28uRHJhY29GbG9hdDMyQXJyYXkoKTsKICAgICAgdmVydGV4QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZUZsb2F0Rm9yQWxsUG9pbnRzKAogICAgICAgIGRyYWNvR2VvbWV0cnksCiAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgYXR0cmlidXRlRGF0YQogICAgICApOwogICAgfQogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IHZlcnRleEFycmF5TGVuZ3RoOyArK2kyKSB7CiAgICAgIHZlcnRleEFycmF5W2kyXSA9IGF0dHJpYnV0ZURhdGEuR2V0VmFsdWUoaTIpOwogICAgfQogICAgZHJhY28uZGVzdHJveShhdHRyaWJ1dGVEYXRhKTsKICAgIHJldHVybiB2ZXJ0ZXhBcnJheTsKICB9CiAgZnVuY3Rpb24gZGVjb2RlRHJhY29UeXBlZEFycmF5KGRyYWNvR2VvbWV0cnksIGRyYWNvRGVjb2RlciwgZHJhY29BdHRyaWJ1dGUsIHZlcnRleEFycmF5TGVuZ3RoKSB7CiAgICBsZXQgdmVydGV4QXJyYXk7CiAgICBsZXQgYXR0cmlidXRlRGF0YTsKICAgIHN3aXRjaCAoZHJhY29BdHRyaWJ1dGUuZGF0YV90eXBlKCkpIHsKICAgICAgY2FzZSAxOgogICAgICBjYXNlIDExOgogICAgICAgIGF0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY28uRHJhY29JbnQ4QXJyYXkoKTsKICAgICAgICB2ZXJ0ZXhBcnJheSA9IG5ldyBJbnQ4QXJyYXkodmVydGV4QXJyYXlMZW5ndGgpOwogICAgICAgIGRyYWNvRGVjb2Rlci5HZXRBdHRyaWJ1dGVJbnQ4Rm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgYXR0cmlidXRlRGF0YQogICAgICAgICk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgMjoKICAgICAgICBhdHRyaWJ1dGVEYXRhID0gbmV3IGRyYWNvLkRyYWNvVUludDhBcnJheSgpOwogICAgICAgIHZlcnRleEFycmF5ID0gbmV3IFVpbnQ4QXJyYXkodmVydGV4QXJyYXlMZW5ndGgpOwogICAgICAgIGRyYWNvRGVjb2Rlci5HZXRBdHRyaWJ1dGVVSW50OEZvckFsbFBvaW50cygKICAgICAgICAgIGRyYWNvR2VvbWV0cnksCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZSwKICAgICAgICAgIGF0dHJpYnV0ZURhdGEKICAgICAgICApOwogICAgICAgIGJyZWFrOwogICAgICBjYXNlIDM6CiAgICAgICAgYXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjby5EcmFjb0ludDE2QXJyYXkoKTsKICAgICAgICB2ZXJ0ZXhBcnJheSA9IG5ldyBJbnQxNkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgICBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlSW50MTZGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBhdHRyaWJ1dGVEYXRhCiAgICAgICAgKTsKICAgICAgICBicmVhazsKICAgICAgY2FzZSA0OgogICAgICAgIGF0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY28uRHJhY29VSW50MTZBcnJheSgpOwogICAgICAgIHZlcnRleEFycmF5ID0gbmV3IFVpbnQxNkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgICBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlVUludDE2Rm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgYXR0cmlidXRlRGF0YQogICAgICAgICk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgNToKICAgICAgY2FzZSA3OgogICAgICAgIGF0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY28uRHJhY29JbnQzMkFycmF5KCk7CiAgICAgICAgdmVydGV4QXJyYXkgPSBuZXcgSW50MzJBcnJheSh2ZXJ0ZXhBcnJheUxlbmd0aCk7CiAgICAgICAgZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZUludDMyRm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgYXR0cmlidXRlRGF0YQogICAgICAgICk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgNjoKICAgICAgY2FzZSA4OgogICAgICAgIGF0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY28uRHJhY29VSW50MzJBcnJheSgpOwogICAgICAgIHZlcnRleEFycmF5ID0gbmV3IFVpbnQzMkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgICBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlVUludDMyRm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgYXR0cmlidXRlRGF0YQogICAgICAgICk7CiAgICAgICAgYnJlYWs7CiAgICAgIGNhc2UgOToKICAgICAgY2FzZSAxMDoKICAgICAgICBhdHRyaWJ1dGVEYXRhID0gbmV3IGRyYWNvLkRyYWNvRmxvYXQzMkFycmF5KCk7CiAgICAgICAgdmVydGV4QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KHZlcnRleEFycmF5TGVuZ3RoKTsKICAgICAgICBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlRmxvYXRGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBhdHRyaWJ1dGVEYXRhCiAgICAgICAgKTsKICAgICAgICBicmVhazsKICAgIH0KICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhBcnJheUxlbmd0aDsgKytpMikgewogICAgICB2ZXJ0ZXhBcnJheVtpMl0gPSBhdHRyaWJ1dGVEYXRhLkdldFZhbHVlKGkyKTsKICAgIH0KICAgIGRyYWNvLmRlc3Ryb3koYXR0cmlidXRlRGF0YSk7CiAgICByZXR1cm4gdmVydGV4QXJyYXk7CiAgfQogIGZ1bmN0aW9uIGRlY29kZUF0dHJpYnV0ZShkcmFjb0dlb21ldHJ5LCBkcmFjb0RlY29kZXIsIGRyYWNvQXR0cmlidXRlKSB7CiAgICBjb25zdCBudW1Qb2ludHMgPSBkcmFjb0dlb21ldHJ5Lm51bV9wb2ludHMoKTsKICAgIGNvbnN0IG51bUNvbXBvbmVudHMgPSBkcmFjb0F0dHJpYnV0ZS5udW1fY29tcG9uZW50cygpOwogICAgbGV0IHF1YW50aXphdGlvbjsKICAgIGxldCB0cmFuc2Zvcm0yID0gbmV3IGRyYWNvLkF0dHJpYnV0ZVF1YW50aXphdGlvblRyYW5zZm9ybSgpOwogICAgaWYgKHRyYW5zZm9ybTIuSW5pdEZyb21BdHRyaWJ1dGUoZHJhY29BdHRyaWJ1dGUpKSB7CiAgICAgIGNvbnN0IG1pblZhbHVlcyA9IG5ldyBBcnJheShudW1Db21wb25lbnRzKTsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG51bUNvbXBvbmVudHM7ICsraTIpIHsKICAgICAgICBtaW5WYWx1ZXNbaTJdID0gdHJhbnNmb3JtMi5taW5fdmFsdWUoaTIpOwogICAgICB9CiAgICAgIHF1YW50aXphdGlvbiA9IHsKICAgICAgICBxdWFudGl6YXRpb25CaXRzOiB0cmFuc2Zvcm0yLnF1YW50aXphdGlvbl9iaXRzKCksCiAgICAgICAgbWluVmFsdWVzLAogICAgICAgIHJhbmdlOiB0cmFuc2Zvcm0yLnJhbmdlKCksCiAgICAgICAgb2N0RW5jb2RlZDogZmFsc2UKICAgICAgfTsKICAgIH0KICAgIGRyYWNvLmRlc3Ryb3kodHJhbnNmb3JtMik7CiAgICB0cmFuc2Zvcm0yID0gbmV3IGRyYWNvLkF0dHJpYnV0ZU9jdGFoZWRyb25UcmFuc2Zvcm0oKTsKICAgIGlmICh0cmFuc2Zvcm0yLkluaXRGcm9tQXR0cmlidXRlKGRyYWNvQXR0cmlidXRlKSkgewogICAgICBxdWFudGl6YXRpb24gPSB7CiAgICAgICAgcXVhbnRpemF0aW9uQml0czogdHJhbnNmb3JtMi5xdWFudGl6YXRpb25fYml0cygpLAogICAgICAgIG9jdEVuY29kZWQ6IHRydWUKICAgICAgfTsKICAgIH0KICAgIGRyYWNvLmRlc3Ryb3kodHJhbnNmb3JtMik7CiAgICBjb25zdCB2ZXJ0ZXhBcnJheUxlbmd0aCA9IG51bVBvaW50cyAqIG51bUNvbXBvbmVudHM7CiAgICBsZXQgdmVydGV4QXJyYXk7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHF1YW50aXphdGlvbikpIHsKICAgICAgdmVydGV4QXJyYXkgPSBkZWNvZGVRdWFudGl6ZWREcmFjb1R5cGVkQXJyYXkoCiAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICBkcmFjb0RlY29kZXIsCiAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgcXVhbnRpemF0aW9uLAogICAgICAgIHZlcnRleEFycmF5TGVuZ3RoCiAgICAgICk7CiAgICB9IGVsc2UgewogICAgICB2ZXJ0ZXhBcnJheSA9IGRlY29kZURyYWNvVHlwZWRBcnJheSgKICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgIGRyYWNvRGVjb2RlciwKICAgICAgICBkcmFjb0F0dHJpYnV0ZSwKICAgICAgICB2ZXJ0ZXhBcnJheUxlbmd0aAogICAgICApOwogICAgfQogICAgY29uc3QgY29tcG9uZW50RGF0YXR5cGUgPSBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmZyb21UeXBlZEFycmF5KHZlcnRleEFycmF5KTsKICAgIHJldHVybiB7CiAgICAgIGFycmF5OiB2ZXJ0ZXhBcnJheSwKICAgICAgZGF0YTogewogICAgICAgIGNvbXBvbmVudHNQZXJBdHRyaWJ1dGU6IG51bUNvbXBvbmVudHMsCiAgICAgICAgY29tcG9uZW50RGF0YXR5cGUsCiAgICAgICAgYnl0ZU9mZnNldDogZHJhY29BdHRyaWJ1dGUuYnl0ZV9vZmZzZXQoKSwKICAgICAgICBieXRlU3RyaWRlOiBDb21wb25lbnREYXRhdHlwZV9kZWZhdWx0LmdldFNpemVJbkJ5dGVzKGNvbXBvbmVudERhdGF0eXBlKSAqIG51bUNvbXBvbmVudHMsCiAgICAgICAgbm9ybWFsaXplZDogZHJhY29BdHRyaWJ1dGUubm9ybWFsaXplZCgpLAogICAgICAgIHF1YW50aXphdGlvbgogICAgICB9CiAgICB9OwogIH0KICBmdW5jdGlvbiBkZWNvZGVQb2ludENsb3VkKHBhcmFtZXRlcnMpIHsKICAgIGNvbnN0IGRyYWNvRGVjb2RlciA9IG5ldyBkcmFjby5EZWNvZGVyKCk7CiAgICBpZiAocGFyYW1ldGVycy5kZXF1YW50aXplSW5TaGFkZXIpIHsKICAgICAgZHJhY29EZWNvZGVyLlNraXBBdHRyaWJ1dGVUcmFuc2Zvcm0oZHJhY28uUE9TSVRJT04pOwogICAgICBkcmFjb0RlY29kZXIuU2tpcEF0dHJpYnV0ZVRyYW5zZm9ybShkcmFjby5OT1JNQUwpOwogICAgfQogICAgY29uc3QgYnVmZmVyID0gbmV3IGRyYWNvLkRlY29kZXJCdWZmZXIoKTsKICAgIGJ1ZmZlci5Jbml0KHBhcmFtZXRlcnMuYnVmZmVyLCBwYXJhbWV0ZXJzLmJ1ZmZlci5sZW5ndGgpOwogICAgY29uc3QgZ2VvbWV0cnlUeXBlID0gZHJhY29EZWNvZGVyLkdldEVuY29kZWRHZW9tZXRyeVR5cGUoYnVmZmVyKTsKICAgIGlmIChnZW9tZXRyeVR5cGUgIT09IGRyYWNvLlBPSU5UX0NMT1VEKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgiRHJhY28gZ2VvbWV0cnkgdHlwZSBtdXN0IGJlIFBPSU5UX0NMT1VELiIpOwogICAgfQogICAgY29uc3QgZHJhY29Qb2ludENsb3VkID0gbmV3IGRyYWNvLlBvaW50Q2xvdWQoKTsKICAgIGNvbnN0IGRlY29kaW5nU3RhdHVzID0gZHJhY29EZWNvZGVyLkRlY29kZUJ1ZmZlclRvUG9pbnRDbG91ZCgKICAgICAgYnVmZmVyLAogICAgICBkcmFjb1BvaW50Q2xvdWQKICAgICk7CiAgICBpZiAoIWRlY29kaW5nU3RhdHVzLm9rKCkgfHwgZHJhY29Qb2ludENsb3VkLnB0ciA9PT0gMCkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoCiAgICAgICAgYEVycm9yIGRlY29kaW5nIGRyYWNvIHBvaW50IGNsb3VkOiAke2RlY29kaW5nU3RhdHVzLmVycm9yX21zZygpfWAKICAgICAgKTsKICAgIH0KICAgIGRyYWNvLmRlc3Ryb3koYnVmZmVyKTsKICAgIGNvbnN0IHJlc3VsdCA9IHt9OwogICAgY29uc3QgcHJvcGVydGllcyA9IHBhcmFtZXRlcnMucHJvcGVydGllczsKICAgIGZvciAoY29uc3QgcHJvcGVydHlOYW1lIGluIHByb3BlcnRpZXMpIHsKICAgICAgaWYgKHByb3BlcnRpZXMuaGFzT3duUHJvcGVydHkocHJvcGVydHlOYW1lKSkgewogICAgICAgIGxldCBkcmFjb0F0dHJpYnV0ZTsKICAgICAgICBpZiAocHJvcGVydHlOYW1lID09PSAiUE9TSVRJT04iIHx8IHByb3BlcnR5TmFtZSA9PT0gIk5PUk1BTCIpIHsKICAgICAgICAgIGNvbnN0IGRyYWNvQXR0cmlidXRlSWQgPSBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlSWQoCiAgICAgICAgICAgIGRyYWNvUG9pbnRDbG91ZCwKICAgICAgICAgICAgZHJhY29bcHJvcGVydHlOYW1lXQogICAgICAgICAgKTsKICAgICAgICAgIGRyYWNvQXR0cmlidXRlID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZSgKICAgICAgICAgICAgZHJhY29Qb2ludENsb3VkLAogICAgICAgICAgICBkcmFjb0F0dHJpYnV0ZUlkCiAgICAgICAgICApOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjb25zdCBhdHRyaWJ1dGVJZCA9IHByb3BlcnRpZXNbcHJvcGVydHlOYW1lXTsKICAgICAgICAgIGRyYWNvQXR0cmlidXRlID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZUJ5VW5pcXVlSWQoCiAgICAgICAgICAgIGRyYWNvUG9pbnRDbG91ZCwKICAgICAgICAgICAgYXR0cmlidXRlSWQKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIHJlc3VsdFtwcm9wZXJ0eU5hbWVdID0gZGVjb2RlQXR0cmlidXRlKAogICAgICAgICAgZHJhY29Qb2ludENsb3VkLAogICAgICAgICAgZHJhY29EZWNvZGVyLAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUKICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBkcmFjby5kZXN0cm95KGRyYWNvUG9pbnRDbG91ZCk7CiAgICBkcmFjby5kZXN0cm95KGRyYWNvRGVjb2Rlcik7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBkZWNvZGVQcmltaXRpdmUocGFyYW1ldGVycykgewogICAgY29uc3QgZHJhY29EZWNvZGVyID0gbmV3IGRyYWNvLkRlY29kZXIoKTsKICAgIGlmIChwYXJhbWV0ZXJzLmRlcXVhbnRpemVJblNoYWRlcikgewogICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgcGFyYW1ldGVycy5hdHRyaWJ1dGVzVG9Ta2lwVHJhbnNmb3JtLmxlbmd0aDsgKytpMikgewogICAgICAgIGRyYWNvRGVjb2Rlci5Ta2lwQXR0cmlidXRlVHJhbnNmb3JtKAogICAgICAgICAgZHJhY29bcGFyYW1ldGVycy5hdHRyaWJ1dGVzVG9Ta2lwVHJhbnNmb3JtW2kyXV0KICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBjb25zdCBidWZmZXJWaWV3ID0gcGFyYW1ldGVycy5idWZmZXJWaWV3OwogICAgY29uc3QgYnVmZmVyID0gbmV3IGRyYWNvLkRlY29kZXJCdWZmZXIoKTsKICAgIGJ1ZmZlci5Jbml0KHBhcmFtZXRlcnMuYXJyYXksIGJ1ZmZlclZpZXcuYnl0ZUxlbmd0aCk7CiAgICBjb25zdCBnZW9tZXRyeVR5cGUgPSBkcmFjb0RlY29kZXIuR2V0RW5jb2RlZEdlb21ldHJ5VHlwZShidWZmZXIpOwogICAgaWYgKGdlb21ldHJ5VHlwZSAhPT0gZHJhY28uVFJJQU5HVUxBUl9NRVNIKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgiVW5zdXBwb3J0ZWQgZHJhY28gbWVzaCBnZW9tZXRyeSB0eXBlLiIpOwogICAgfQogICAgY29uc3QgZHJhY29HZW9tZXRyeSA9IG5ldyBkcmFjby5NZXNoKCk7CiAgICBjb25zdCBkZWNvZGluZ1N0YXR1cyA9IGRyYWNvRGVjb2Rlci5EZWNvZGVCdWZmZXJUb01lc2goYnVmZmVyLCBkcmFjb0dlb21ldHJ5KTsKICAgIGlmICghZGVjb2RpbmdTdGF0dXMub2soKSB8fCBkcmFjb0dlb21ldHJ5LnB0ciA9PT0gMCkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoCiAgICAgICAgYEVycm9yIGRlY29kaW5nIGRyYWNvIG1lc2ggZ2VvbWV0cnk6ICR7ZGVjb2RpbmdTdGF0dXMuZXJyb3JfbXNnKCl9YAogICAgICApOwogICAgfQogICAgZHJhY28uZGVzdHJveShidWZmZXIpOwogICAgY29uc3QgYXR0cmlidXRlRGF0YSA9IHt9OwogICAgY29uc3QgY29tcHJlc3NlZEF0dHJpYnV0ZXMgPSBwYXJhbWV0ZXJzLmNvbXByZXNzZWRBdHRyaWJ1dGVzOwogICAgZm9yIChjb25zdCBhdHRyaWJ1dGVOYW1lIGluIGNvbXByZXNzZWRBdHRyaWJ1dGVzKSB7CiAgICAgIGlmIChjb21wcmVzc2VkQXR0cmlidXRlcy5oYXNPd25Qcm9wZXJ0eShhdHRyaWJ1dGVOYW1lKSkgewogICAgICAgIGNvbnN0IGNvbXByZXNzZWRBdHRyaWJ1dGUgPSBjb21wcmVzc2VkQXR0cmlidXRlc1thdHRyaWJ1dGVOYW1lXTsKICAgICAgICBjb25zdCBkcmFjb0F0dHJpYnV0ZSA9IGRyYWNvRGVjb2Rlci5HZXRBdHRyaWJ1dGVCeVVuaXF1ZUlkKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGNvbXByZXNzZWRBdHRyaWJ1dGUKICAgICAgICApOwogICAgICAgIGF0dHJpYnV0ZURhdGFbYXR0cmlidXRlTmFtZV0gPSBkZWNvZGVBdHRyaWJ1dGUoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29EZWNvZGVyLAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUKICAgICAgICApOwogICAgICB9CiAgICB9CiAgICBjb25zdCByZXN1bHQgPSB7CiAgICAgIGluZGV4QXJyYXk6IGRlY29kZUluZGV4QXJyYXkoZHJhY29HZW9tZXRyeSwgZHJhY29EZWNvZGVyKSwKICAgICAgYXR0cmlidXRlRGF0YQogICAgfTsKICAgIGRyYWNvLmRlc3Ryb3koZHJhY29HZW9tZXRyeSk7CiAgICBkcmFjby5kZXN0cm95KGRyYWNvRGVjb2Rlcik7CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBhc3luYyBmdW5jdGlvbiBkZWNvZGUocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgaWYgKGRlZmluZWRfZGVmYXVsdChwYXJhbWV0ZXJzLmJ1ZmZlclZpZXcpKSB7CiAgICAgIHJldHVybiBkZWNvZGVQcmltaXRpdmUocGFyYW1ldGVycyk7CiAgICB9CiAgICByZXR1cm4gZGVjb2RlUG9pbnRDbG91ZChwYXJhbWV0ZXJzKTsKICB9CiAgYXN5bmMgZnVuY3Rpb24gaW5pdFdvcmtlcihwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCB3YXNtQ29uZmlnID0gcGFyYW1ldGVycy53ZWJBc3NlbWJseUNvbmZpZzsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQod2FzbUNvbmZpZykgJiYgZGVmaW5lZF9kZWZhdWx0KHdhc21Db25maWcud2FzbUJpbmFyeUZpbGUpKSB7CiAgICAgIGRyYWNvID0gYXdhaXQgKDAsIGltcG9ydF9kcmFjb19kZWNvZGVyX25vZGVqcy5kZWZhdWx0KSh3YXNtQ29uZmlnKTsKICAgIH0gZWxzZSB7CiAgICAgIGRyYWNvID0gYXdhaXQgKDAsIGltcG9ydF9kcmFjb19kZWNvZGVyX25vZGVqcy5kZWZhdWx0KSgpOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIGRlY29kZURyYWNvKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IHdhc21Db25maWcgPSBwYXJhbWV0ZXJzLndlYkFzc2VtYmx5Q29uZmlnOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdCh3YXNtQ29uZmlnKSkgewogICAgICByZXR1cm4gaW5pdFdvcmtlcihwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgIH0KICAgIHJldHVybiBkZWNvZGUocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cyk7CiAgfQogIHZhciBpbXBvcnRfZHJhY29fZGVjb2Rlcl9ub2RlanMsIGRyYWNvLCBkZWNvZGVEcmFjb19kZWZhdWx0OwogIHZhciBpbml0X2RlY29kZURyYWNvID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9kZWNvZGVEcmFjby5qcyIoKSB7CiAgICAgIGluaXRfQ29tcG9uZW50RGF0YXR5cGUoKTsKICAgICAgaW5pdF9kZWZpbmVkKCk7CiAgICAgIGluaXRfSW5kZXhEYXRhdHlwZSgpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgaW1wb3J0X2RyYWNvX2RlY29kZXJfbm9kZWpzID0gX190b0VTTShyZXF1aXJlX2RyYWNvX2RlY29kZXJfbm9kZWpzKCksIDEpOwogICAgICBkZWNvZGVEcmFjb19kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KGRlY29kZURyYWNvKTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL2RlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGEuanMKICBmdW5jdGlvbiBkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VEYXRhKGtleSwgZGF0YSkgewogICAgaWYgKGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGEucGFzc1Rocm91Z2hEYXRhRm9yVGVzdGluZykgewogICAgICByZXR1cm4gZGF0YTsKICAgIH0KICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgia2V5Iiwga2V5KTsKICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm9iamVjdCgiZGF0YSIsIGRhdGEpOwogICAgY29uc3Qga2V5TGVuZ3RoID0ga2V5LmJ5dGVMZW5ndGg7CiAgICBpZiAoa2V5TGVuZ3RoID09PSAwIHx8IGtleUxlbmd0aCAlIDQgIT09IDApIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KAogICAgICAgICJUaGUgbGVuZ3RoIG9mIGtleSBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwIGFuZCBhIG11bHRpcGxlIG9mIDQuIgogICAgICApOwogICAgfQogICAgY29uc3QgZGF0YVZpZXcgPSBuZXcgRGF0YVZpZXcoZGF0YSk7CiAgICBjb25zdCBtYWdpYyA9IGRhdGFWaWV3LmdldFVpbnQzMigwLCB0cnVlKTsKICAgIGlmIChtYWdpYyA9PT0gY29tcHJlc3NlZE1hZ2ljIHx8IG1hZ2ljID09PSBjb21wcmVzc2VkTWFnaWNTd2FwKSB7CiAgICAgIHJldHVybiBkYXRhOwogICAgfQogICAgY29uc3Qga2V5VmlldyA9IG5ldyBEYXRhVmlldyhrZXkpOwogICAgbGV0IGRwID0gMDsKICAgIGNvbnN0IGRwZW5kID0gZGF0YS5ieXRlTGVuZ3RoOwogICAgY29uc3QgZHBlbmQ2NCA9IGRwZW5kIC0gZHBlbmQgJSA4OwogICAgY29uc3Qga3BlbmQgPSBrZXlMZW5ndGg7CiAgICBsZXQga3A7CiAgICBsZXQgb2ZmID0gODsKICAgIHdoaWxlIChkcCA8IGRwZW5kNjQpIHsKICAgICAgb2ZmID0gKG9mZiArIDgpICUgMjQ7CiAgICAgIGtwID0gb2ZmOwogICAgICB3aGlsZSAoZHAgPCBkcGVuZDY0ICYmIGtwIDwga3BlbmQpIHsKICAgICAgICBkYXRhVmlldy5zZXRVaW50MzIoCiAgICAgICAgICBkcCwKICAgICAgICAgIGRhdGFWaWV3LmdldFVpbnQzMihkcCwgdHJ1ZSkgXiBrZXlWaWV3LmdldFVpbnQzMihrcCwgdHJ1ZSksCiAgICAgICAgICB0cnVlCiAgICAgICAgKTsKICAgICAgICBkYXRhVmlldy5zZXRVaW50MzIoCiAgICAgICAgICBkcCArIDQsCiAgICAgICAgICBkYXRhVmlldy5nZXRVaW50MzIoZHAgKyA0LCB0cnVlKSBeIGtleVZpZXcuZ2V0VWludDMyKGtwICsgNCwgdHJ1ZSksCiAgICAgICAgICB0cnVlCiAgICAgICAgKTsKICAgICAgICBkcCArPSA4OwogICAgICAgIGtwICs9IDI0OwogICAgICB9CiAgICB9CiAgICBpZiAoZHAgPCBkcGVuZCkgewogICAgICBpZiAoa3AgPj0ga3BlbmQpIHsKICAgICAgICBvZmYgPSAob2ZmICsgOCkgJSAyNDsKICAgICAgICBrcCA9IG9mZjsKICAgICAgfQogICAgICB3aGlsZSAoZHAgPCBkcGVuZCkgewogICAgICAgIGRhdGFWaWV3LnNldFVpbnQ4KGRwLCBkYXRhVmlldy5nZXRVaW50OChkcCkgXiBrZXlWaWV3LmdldFVpbnQ4KGtwKSk7CiAgICAgICAgZHArKzsKICAgICAgICBrcCsrOwogICAgICB9CiAgICB9CiAgfQogIHZhciBjb21wcmVzc2VkTWFnaWMsIGNvbXByZXNzZWRNYWdpY1N3YXAsIGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGFfZGVmYXVsdDsKICB2YXIgaW5pdF9kZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VEYXRhID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9kZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VEYXRhLmpzIigpIHsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X1J1bnRpbWVFcnJvcigpOwogICAgICBjb21wcmVzc2VkTWFnaWMgPSAxOTUzMDI5ODA1OwogICAgICBjb21wcmVzc2VkTWFnaWNTd2FwID0gMjkxNzAzNDEwMDsKICAgICAgZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlRGF0YS5wYXNzVGhyb3VnaERhdGFGb3JUZXN0aW5nID0gZmFsc2U7CiAgICAgIGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGFfZGVmYXVsdCA9IGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGE7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9pc0JpdFNldC5qcwogIGZ1bmN0aW9uIGlzQml0U2V0KGJpdHMsIG1hc2spIHsKICAgIHJldHVybiAoYml0cyAmIG1hc2spICE9PSAwOwogIH0KICB2YXIgaXNCaXRTZXRfZGVmYXVsdDsKICB2YXIgaW5pdF9pc0JpdFNldCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvaXNCaXRTZXQuanMiKCkgewogICAgICBpc0JpdFNldF9kZWZhdWx0ID0gaXNCaXRTZXQ7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Hb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24uanMKICBmdW5jdGlvbiBHb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24oYml0cywgY25vZGVWZXJzaW9uLCBpbWFnZXJ5VmVyc2lvbiwgdGVycmFpblZlcnNpb24sIGltYWdlcnlQcm92aWRlciwgdGVycmFpblByb3ZpZGVyKSB7CiAgICB0aGlzLl9iaXRzID0gYml0czsKICAgIHRoaXMuY25vZGVWZXJzaW9uID0gY25vZGVWZXJzaW9uOwogICAgdGhpcy5pbWFnZXJ5VmVyc2lvbiA9IGltYWdlcnlWZXJzaW9uOwogICAgdGhpcy50ZXJyYWluVmVyc2lvbiA9IHRlcnJhaW5WZXJzaW9uOwogICAgdGhpcy5pbWFnZXJ5UHJvdmlkZXIgPSBpbWFnZXJ5UHJvdmlkZXI7CiAgICB0aGlzLnRlcnJhaW5Qcm92aWRlciA9IHRlcnJhaW5Qcm92aWRlcjsKICAgIHRoaXMuYW5jZXN0b3JIYXNUZXJyYWluID0gZmFsc2U7CiAgICB0aGlzLnRlcnJhaW5TdGF0ZSA9IHZvaWQgMDsKICB9CiAgdmFyIGNoaWxkcmVuQml0bWFza3MsIGFueUNoaWxkQml0bWFzaywgY2FjaGVGbGFnQml0bWFzaywgaW1hZ2VCaXRtYXNrLCB0ZXJyYWluQml0bWFzaywgR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uX2RlZmF1bHQ7CiAgdmFyIGluaXRfR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9Hb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24uanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9pc0JpdFNldCgpOwogICAgICBjaGlsZHJlbkJpdG1hc2tzID0gWzEsIDIsIDQsIDhdOwogICAgICBhbnlDaGlsZEJpdG1hc2sgPSAxNTsKICAgICAgY2FjaGVGbGFnQml0bWFzayA9IDE2OwogICAgICBpbWFnZUJpdG1hc2sgPSA2NDsKICAgICAgdGVycmFpbkJpdG1hc2sgPSAxMjg7CiAgICAgIEdvb2dsZUVhcnRoRW50ZXJwcmlzZVRpbGVJbmZvcm1hdGlvbi5jbG9uZSA9IGZ1bmN0aW9uKGluZm8sIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHJlc3VsdCkpIHsKICAgICAgICAgIHJlc3VsdCA9IG5ldyBHb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24oCiAgICAgICAgICAgIGluZm8uX2JpdHMsCiAgICAgICAgICAgIGluZm8uY25vZGVWZXJzaW9uLAogICAgICAgICAgICBpbmZvLmltYWdlcnlWZXJzaW9uLAogICAgICAgICAgICBpbmZvLnRlcnJhaW5WZXJzaW9uLAogICAgICAgICAgICBpbmZvLmltYWdlcnlQcm92aWRlciwKICAgICAgICAgICAgaW5mby50ZXJyYWluUHJvdmlkZXIKICAgICAgICAgICk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlc3VsdC5fYml0cyA9IGluZm8uX2JpdHM7CiAgICAgICAgICByZXN1bHQuY25vZGVWZXJzaW9uID0gaW5mby5jbm9kZVZlcnNpb247CiAgICAgICAgICByZXN1bHQuaW1hZ2VyeVZlcnNpb24gPSBpbmZvLmltYWdlcnlWZXJzaW9uOwogICAgICAgICAgcmVzdWx0LnRlcnJhaW5WZXJzaW9uID0gaW5mby50ZXJyYWluVmVyc2lvbjsKICAgICAgICAgIHJlc3VsdC5pbWFnZXJ5UHJvdmlkZXIgPSBpbmZvLmltYWdlcnlQcm92aWRlcjsKICAgICAgICAgIHJlc3VsdC50ZXJyYWluUHJvdmlkZXIgPSBpbmZvLnRlcnJhaW5Qcm92aWRlcjsKICAgICAgICB9CiAgICAgICAgcmVzdWx0LmFuY2VzdG9ySGFzVGVycmFpbiA9IGluZm8uYW5jZXN0b3JIYXNUZXJyYWluOwogICAgICAgIHJlc3VsdC50ZXJyYWluU3RhdGUgPSBpbmZvLnRlcnJhaW5TdGF0ZTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBHb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24ucHJvdG90eXBlLnNldFBhcmVudCA9IGZ1bmN0aW9uKHBhcmVudCkgewogICAgICAgIHRoaXMuYW5jZXN0b3JIYXNUZXJyYWluID0gcGFyZW50LmFuY2VzdG9ySGFzVGVycmFpbiB8fCB0aGlzLmhhc1RlcnJhaW4oKTsKICAgICAgfTsKICAgICAgR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uLnByb3RvdHlwZS5oYXNTdWJ0cmVlID0gZnVuY3Rpb24oKSB7CiAgICAgICAgcmV0dXJuIGlzQml0U2V0X2RlZmF1bHQodGhpcy5fYml0cywgY2FjaGVGbGFnQml0bWFzayk7CiAgICAgIH07CiAgICAgIEdvb2dsZUVhcnRoRW50ZXJwcmlzZVRpbGVJbmZvcm1hdGlvbi5wcm90b3R5cGUuaGFzSW1hZ2VyeSA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBpc0JpdFNldF9kZWZhdWx0KHRoaXMuX2JpdHMsIGltYWdlQml0bWFzayk7CiAgICAgIH07CiAgICAgIEdvb2dsZUVhcnRoRW50ZXJwcmlzZVRpbGVJbmZvcm1hdGlvbi5wcm90b3R5cGUuaGFzVGVycmFpbiA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBpc0JpdFNldF9kZWZhdWx0KHRoaXMuX2JpdHMsIHRlcnJhaW5CaXRtYXNrKTsKICAgICAgfTsKICAgICAgR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uLnByb3RvdHlwZS5oYXNDaGlsZHJlbiA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBpc0JpdFNldF9kZWZhdWx0KHRoaXMuX2JpdHMsIGFueUNoaWxkQml0bWFzayk7CiAgICAgIH07CiAgICAgIEdvb2dsZUVhcnRoRW50ZXJwcmlzZVRpbGVJbmZvcm1hdGlvbi5wcm90b3R5cGUuaGFzQ2hpbGQgPSBmdW5jdGlvbihpbmRleCkgewogICAgICAgIHJldHVybiBpc0JpdFNldF9kZWZhdWx0KHRoaXMuX2JpdHMsIGNoaWxkcmVuQml0bWFza3NbaW5kZXhdKTsKICAgICAgfTsKICAgICAgR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uLnByb3RvdHlwZS5nZXRDaGlsZEJpdG1hc2sgPSBmdW5jdGlvbigpIHsKICAgICAgICByZXR1cm4gdGhpcy5fYml0cyAmIGFueUNoaWxkQml0bWFzazsKICAgICAgfTsKICAgICAgR29vZ2xlRWFydGhFbnRlcnByaXNlVGlsZUluZm9ybWF0aW9uX2RlZmF1bHQgPSBHb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb247CiAgICB9CiAgfSk7CgogIC8vIG5vZGVfbW9kdWxlcy9wYWtvL2Rpc3QvYnJvd3Nlci9wYWtvX2luZmxhdGUuZXNtLm1pbi5tanMKICBmdW5jdGlvbiBuKGUyKSB7CiAgICBsZXQgdDIgPSBlMi5sZW5ndGg7CiAgICBmb3IgKDsgLS10MiA+PSAwOyApIGUyW3QyXSA9IDA7CiAgfQogIGZ1bmN0aW9uIE9lKGUyLCB0MikgewogICAgbGV0IG4yLCByMiwgaTIsIGE0LCBvMiwgczIsIGMyLCBsMiwgdTQsIGQyLCBmMiwgcDIsIG0yLCBoMiwgZzIsIF8yLCB2NCwgeTIsIGIyLCB4MiwgUzIsIEMyLCB3MiwgVDIsIEUyID0gZTIuc3RhdGU7CiAgICBuMiA9IGUyLm5leHRfaW4sIHcyID0gZTIuaW5wdXQsIHIyID0gbjIgKyAoZTIuYXZhaWxfaW4gLSA1KSwgaTIgPSBlMi5uZXh0X291dCwgVDIgPSBlMi5vdXRwdXQsIGE0ID0gaTIgLSAodDIgLSBlMi5hdmFpbF9vdXQpLCBvMiA9IGkyICsgKGUyLmF2YWlsX291dCAtIDI1NyksIHMyID0gRTIuZG1heCwgYzIgPSBFMi53c2l6ZSwgbDIgPSBFMi53aGF2ZSwgdTQgPSBFMi53bmV4dCwgZDIgPSBFMi53aW5kb3csIGYyID0gRTIuaG9sZCwgcDIgPSBFMi5iaXRzLCBtMiA9IEUyLmxlbmNvZGUsIGgyID0gRTIuZGlzdGNvZGUsIGcyID0gKDEgPDwgRTIubGVuYml0cykgLSAxLCBfMiA9ICgxIDw8IEUyLmRpc3RiaXRzKSAtIDE7CiAgICB0b3A6IGRvIHsKICAgICAgcDIgPCAxNSAmJiAoZjIgKz0gdzJbbjIrK10gPDwgcDIsIHAyICs9IDgsIGYyICs9IHcyW24yKytdIDw8IHAyLCBwMiArPSA4KSwgdjQgPSBtMltmMiAmIGcyXTsKICAgICAgZG9sZW46IGZvciAoOyA7ICkgewogICAgICAgIGlmICh5MiA9IHY0ID4+PiAyNCwgZjIgPj4+PSB5MiwgcDIgLT0geTIsIHkyID0gdjQgPj4+IDE2ICYgMjU1LCB5MiA9PT0gMCkgVDJbaTIrK10gPSB2NCAmIDY1NTM1OwogICAgICAgIGVsc2UgaWYgKHkyICYgMTYpIHsKICAgICAgICAgIGIyID0gdjQgJiA2NTUzNSwgeTIgJj0gMTUsIHkyICYmIChwMiA8IHkyICYmIChmMiArPSB3MltuMisrXSA8PCBwMiwgcDIgKz0gOCksIGIyICs9IGYyICYgKDEgPDwgeTIpIC0gMSwgZjIgPj4+PSB5MiwgcDIgLT0geTIpLCBwMiA8IDE1ICYmIChmMiArPSB3MltuMisrXSA8PCBwMiwgcDIgKz0gOCwgZjIgKz0gdzJbbjIrK10gPDwgcDIsIHAyICs9IDgpLCB2NCA9IGgyW2YyICYgXzJdOwogICAgICAgICAgZG9kaXN0OiBmb3IgKDsgOyApIHsKICAgICAgICAgICAgaWYgKHkyID0gdjQgPj4+IDI0LCBmMiA+Pj49IHkyLCBwMiAtPSB5MiwgeTIgPSB2NCA+Pj4gMTYgJiAyNTUsIHkyICYgMTYpIHsKICAgICAgICAgICAgICBpZiAoeDIgPSB2NCAmIDY1NTM1LCB5MiAmPSAxNSwgcDIgPCB5MiAmJiAoZjIgKz0gdzJbbjIrK10gPDwgcDIsIHAyICs9IDgsIHAyIDwgeTIgJiYgKGYyICs9IHcyW24yKytdIDw8IHAyLCBwMiArPSA4KSksIHgyICs9IGYyICYgKDEgPDwgeTIpIC0gMSwgeDIgPiBzMikgewogICAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrYCwgRTIubW9kZSA9IFY7CiAgICAgICAgICAgICAgICBicmVhayB0b3A7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChmMiA+Pj49IHkyLCBwMiAtPSB5MiwgeTIgPSBpMiAtIGE0LCB4MiA+IHkyKSB7CiAgICAgICAgICAgICAgICBpZiAoeTIgPSB4MiAtIHkyLCB5MiA+IGwyICYmIEUyLnNhbmUpIHsKICAgICAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrYCwgRTIubW9kZSA9IFY7CiAgICAgICAgICAgICAgICAgIGJyZWFrIHRvcDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChTMiA9IDAsIEMyID0gZDIsIHU0ID09PSAwKSB7CiAgICAgICAgICAgICAgICAgIGlmIChTMiArPSBjMiAtIHkyLCB5MiA8IGIyKSB7CiAgICAgICAgICAgICAgICAgICAgYjIgLT0geTI7CiAgICAgICAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgICAgICAgIFQyW2kyKytdID0gZDJbUzIrK107CiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKC0teTIpOwogICAgICAgICAgICAgICAgICAgIFMyID0gaTIgLSB4MiwgQzIgPSBUMjsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSBlbHNlIGlmICh1NCA8IHkyKSB7CiAgICAgICAgICAgICAgICAgIGlmIChTMiArPSBjMiArIHU0IC0geTIsIHkyIC09IHU0LCB5MiA8IGIyKSB7CiAgICAgICAgICAgICAgICAgICAgYjIgLT0geTI7CiAgICAgICAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgICAgICAgIFQyW2kyKytdID0gZDJbUzIrK107CiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKC0teTIpOwogICAgICAgICAgICAgICAgICAgIGlmIChTMiA9IDAsIHU0IDwgYjIpIHsKICAgICAgICAgICAgICAgICAgICAgIHkyID0gdTQsIGIyIC09IHkyOwogICAgICAgICAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgICAgICAgICAgVDJbaTIrK10gPSBkMltTMisrXTsKICAgICAgICAgICAgICAgICAgICAgIHdoaWxlICgtLXkyKTsKICAgICAgICAgICAgICAgICAgICAgIFMyID0gaTIgLSB4MiwgQzIgPSBUMjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoUzIgKz0gdTQgLSB5MiwgeTIgPCBiMikgewogICAgICAgICAgICAgICAgICBiMiAtPSB5MjsKICAgICAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgICAgICBUMltpMisrXSA9IGQyW1MyKytdOwogICAgICAgICAgICAgICAgICB3aGlsZSAoLS15Mik7CiAgICAgICAgICAgICAgICAgIFMyID0gaTIgLSB4MiwgQzIgPSBUMjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZvciAoOyBiMiA+IDI7ICkgVDJbaTIrK10gPSBDMltTMisrXSwgVDJbaTIrK10gPSBDMltTMisrXSwgVDJbaTIrK10gPSBDMltTMisrXSwgYjIgLT0gMzsKICAgICAgICAgICAgICAgIGIyICYmIChUMltpMisrXSA9IEMyW1MyKytdLCBiMiA+IDEgJiYgKFQyW2kyKytdID0gQzJbUzIrK10pKTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgUzIgPSBpMiAtIHgyOwogICAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgICAgVDJbaTIrK10gPSBUMltTMisrXSwgVDJbaTIrK10gPSBUMltTMisrXSwgVDJbaTIrK10gPSBUMltTMisrXSwgYjIgLT0gMzsKICAgICAgICAgICAgICAgIHdoaWxlIChiMiA+IDIpOwogICAgICAgICAgICAgICAgYjIgJiYgKFQyW2kyKytdID0gVDJbUzIrK10sIGIyID4gMSAmJiAoVDJbaTIrK10gPSBUMltTMisrXSkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSBlbHNlIGlmICh5MiAmIDY0KSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgZGlzdGFuY2UgY29kZWAsIEUyLm1vZGUgPSBWOwogICAgICAgICAgICAgIGJyZWFrIHRvcDsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB2NCA9IGgyWyh2NCAmIDY1NTM1KSArIChmMiAmICgxIDw8IHkyKSAtIDEpXTsKICAgICAgICAgICAgICBjb250aW51ZSBkb2Rpc3Q7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIGlmICghKHkyICYgNjQpKSB7CiAgICAgICAgICB2NCA9IG0yWyh2NCAmIDY1NTM1KSArIChmMiAmICgxIDw8IHkyKSAtIDEpXTsKICAgICAgICAgIGNvbnRpbnVlIGRvbGVuOwogICAgICAgIH0gZWxzZSBpZiAoeTIgJiAzMikgewogICAgICAgICAgRTIubW9kZSA9IERlOwogICAgICAgICAgYnJlYWsgdG9wOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBlMi5tc2cgPSBgaW52YWxpZCBsaXRlcmFsL2xlbmd0aCBjb2RlYCwgRTIubW9kZSA9IFY7CiAgICAgICAgICBicmVhayB0b3A7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9IHdoaWxlIChuMiA8IHIyICYmIGkyIDwgbzIpOwogICAgYjIgPSBwMiA+PiAzLCBuMiAtPSBiMiwgcDIgLT0gYjIgPDwgMywgZjIgJj0gKDEgPDwgcDIpIC0gMSwgZTIubmV4dF9pbiA9IG4yLCBlMi5uZXh0X291dCA9IGkyLCBlMi5hdmFpbF9pbiA9IG4yIDwgcjIgPyA1ICsgKHIyIC0gbjIpIDogNSAtIChuMiAtIHIyKSwgZTIuYXZhaWxfb3V0ID0gaTIgPCBvMiA/IDI1NyArIChvMiAtIGkyKSA6IDI1NyAtIChpMiAtIG8yKSwgRTIuaG9sZCA9IGYyLCBFMi5iaXRzID0gcDI7CiAgfQogIGZ1bmN0aW9uIFEoZTIpIHsKICAgICJAYmFiZWwvaGVscGVycyAtIHR5cGVvZiI7CiAgICByZXR1cm4gUSA9IHR5cGVvZiBTeW1ib2wgPT0gYGZ1bmN0aW9uYCAmJiB0eXBlb2YgU3ltYm9sLml0ZXJhdG9yID09IGBzeW1ib2xgID8gZnVuY3Rpb24oZTMpIHsKICAgICAgcmV0dXJuIHR5cGVvZiBlMzsKICAgIH0gOiBmdW5jdGlvbihlMykgewogICAgICByZXR1cm4gZTMgJiYgdHlwZW9mIFN5bWJvbCA9PSBgZnVuY3Rpb25gICYmIGUzLmNvbnN0cnVjdG9yID09PSBTeW1ib2wgJiYgZTMgIT09IFN5bWJvbC5wcm90b3R5cGUgPyBgc3ltYm9sYCA6IHR5cGVvZiBlMzsKICAgIH0sIFEoZTIpOwogIH0KICBmdW5jdGlvbiBBdChlMiwgdDIpIHsKICAgIGlmIChRKGUyKSAhPSBgb2JqZWN0YCB8fCAhZTIpIHJldHVybiBlMjsKICAgIHZhciBuMiA9IGUyW1N5bWJvbC50b1ByaW1pdGl2ZV07CiAgICBpZiAobjIgIT09IHZvaWQgMCkgewogICAgICB2YXIgcjIgPSBuMi5jYWxsKGUyLCB0MiB8fCBgZGVmYXVsdGApOwogICAgICBpZiAoUShyMikgIT0gYG9iamVjdGApIHJldHVybiByMjsKICAgICAgdGhyb3cgVHlwZUVycm9yKGBAQHRvUHJpbWl0aXZlIG11c3QgcmV0dXJuIGEgcHJpbWl0aXZlIHZhbHVlLmApOwogICAgfQogICAgcmV0dXJuICh0MiA9PT0gYHN0cmluZ2AgPyBTdHJpbmcgOiBOdW1iZXIpKGUyKTsKICB9CiAgZnVuY3Rpb24ganQoZTIpIHsKICAgIHZhciB0MiA9IEF0KGUyLCBgc3RyaW5nYCk7CiAgICByZXR1cm4gUSh0MikgPT0gYHN5bWJvbGAgPyB0MiA6IHQyICsgYGA7CiAgfQogIGZ1bmN0aW9uICQoZTIsIHQyLCBuMikgewogICAgcmV0dXJuICh0MiA9IGp0KHQyKSkgaW4gZTIgPyBPYmplY3QuZGVmaW5lUHJvcGVydHkoZTIsIHQyLCB7IHZhbHVlOiBuMiwgZW51bWVyYWJsZTogdHJ1ZSwgY29uZmlndXJhYmxlOiB0cnVlLCB3cml0YWJsZTogdHJ1ZSB9KSA6IGUyW3QyXSA9IG4yLCBlMjsKICB9CiAgZnVuY3Rpb24gTHQoZTIsIHQyID0ge30pIHsKICAgIGxldCBuMiA9IG5ldyBJdCh0Mik7CiAgICBpZiAobjIucHVzaChlMiwgdHJ1ZSksIG4yLmVycikgdGhyb3cgRXJyb3IobjIubXNnKTsKICAgIGxldCByMiA9IG4yLnJlc3VsdDsKICAgIHJldHVybiB0Mi50b1RleHQgPyBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUocjIpIDogcjI7CiAgfQogIHZhciBlLCB0LCByLCBpLCBhMywgbywgcywgYywgbCwgdTMsIGQsIGYsIHAsIG0sIGgsIGcsIF8sIHYzLCB5LCBiLCB4LCBTLCBDLCB3LCBULCBFLCBELCBPLCBlZSwgaywgQSwgdGUsIG5lLCByZSwgaWUsIGFlLCBvZSwgc2UsIGNlLCBsZSwgdWUsIGRlLCBmZSwgaiwgTSwgcGUsIE4sIG1lLCBQLCBoZSwgRiwgSSwgZ2UsIF9lLCB2ZSwgeWUsIGJlLCBMLCB4ZSwgUiwgU2UsIENlLCB3ZSwgVGUsIEVlLCB6LCBCLCBWLCBEZSwgSCwga2UsIEFlLCBqZSwgVSwgTWUsIE5lLCBQZSwgRmUsIEllLCBXLCBMZSwgUmUsIHplLCBHLCBCZSwgVmUsIEhlLCBVZSwgV2UsIEdlLCBLZSwgcWUsIEplLCBLLCBxLCBZZSwgWGUsIFplLCBRZSwgJGUsIGV0LCB0dCwgSiwgWSwgbnQsIHJ0LCBpdCwgYXQsIG90LCBzdCwgY3QsIGx0LCBYLCB1dCwgZHQsIGZ0LCBwdCwgbXQsIGh0LCBaLCBndCwgX3QsIHZ0LCB5dCwgYnQsIHh0LCBTdCwgQ3QsIHd0LCBUdCwgRXQsIER0LCBPdCwga3QsIFB0LCBGdCwgSXQ7CiAgdmFyIGluaXRfcGFrb19pbmZsYXRlX2VzbV9taW4gPSBfX2VzbSh7CiAgICAibm9kZV9tb2R1bGVzL3Bha28vZGlzdC9icm93c2VyL3Bha29faW5mbGF0ZS5lc20ubWluLm1qcyIoKSB7CiAgICAgIGUgPSAwOwogICAgICB0ID0gMTsKICAgICAgciA9IDI5OwogICAgICBpID0gMjU2OwogICAgICBhMyA9IDMwOwogICAgICBvID0gMTk7CiAgICAgIHMgPSA1NzM7CiAgICAgIGMgPSAxNTsKICAgICAgbCA9IDE2OwogICAgICB1MyA9IDI1NjsKICAgICAgZCA9IDE2OwogICAgICBmID0gMTc7CiAgICAgIHAgPSAxODsKICAgICAgbSA9IG5ldyBVaW50OEFycmF5KFswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAxLCAxLCAxLCAxLCAyLCAyLCAyLCAyLCAzLCAzLCAzLCAzLCA0LCA0LCA0LCA0LCA1LCA1LCA1LCA1LCAwXSk7CiAgICAgIGggPSBuZXcgVWludDhBcnJheShbMCwgMCwgMCwgMCwgMSwgMSwgMiwgMiwgMywgMywgNCwgNCwgNSwgNSwgNiwgNiwgNywgNywgOCwgOCwgOSwgOSwgMTAsIDEwLCAxMSwgMTEsIDEyLCAxMiwgMTMsIDEzXSk7CiAgICAgIG5ldyBVaW50OEFycmF5KFswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAyLCAzLCA3XSk7CiAgICAgIGcgPSBuZXcgVWludDhBcnJheShbMTYsIDE3LCAxOCwgMCwgOCwgNywgOSwgNiwgMTAsIDUsIDExLCA0LCAxMiwgMywgMTMsIDIsIDE0LCAxLCAxNV0pOwogICAgICBfID0gNTEyOwogICAgICB2MyA9IEFycmF5KDI4OCAqIDIpOwogICAgICBuKHYzKTsKICAgICAgeSA9IEFycmF5KGEzICogMik7CiAgICAgIG4oeSk7CiAgICAgIGIgPSBBcnJheShfKTsKICAgICAgbihiKTsKICAgICAgeCA9IEFycmF5KDI1Nik7CiAgICAgIG4oeCk7CiAgICAgIFMgPSBBcnJheShyKTsKICAgICAgbihTKTsKICAgICAgQyA9IEFycmF5KGEzKTsKICAgICAgbihDKTsKICAgICAgdyA9IChlMikgPT4gZTIgPCAyNTYgPyBiW2UyXSA6IGJbMjU2ICsgKGUyID4+PiA3KV07CiAgICAgIFQgPSAoZTIsIHQyKSA9PiB7CiAgICAgICAgZTIucGVuZGluZ19idWZbZTIucGVuZGluZysrXSA9IHQyICYgMjU1LCBlMi5wZW5kaW5nX2J1ZltlMi5wZW5kaW5nKytdID0gdDIgPj4+IDggJiAyNTU7CiAgICAgIH07CiAgICAgIEUgPSAoZTIsIHQyLCBuMikgPT4gewogICAgICAgIGUyLmJpX3ZhbGlkID4gbCAtIG4yID8gKGUyLmJpX2J1ZiB8PSB0MiA8PCBlMi5iaV92YWxpZCAmIDY1NTM1LCBUKGUyLCBlMi5iaV9idWYpLCBlMi5iaV9idWYgPSB0MiA+PiBsIC0gZTIuYmlfdmFsaWQsIGUyLmJpX3ZhbGlkICs9IG4yIC0gbCkgOiAoZTIuYmlfYnVmIHw9IHQyIDw8IGUyLmJpX3ZhbGlkICYgNjU1MzUsIGUyLmJpX3ZhbGlkICs9IG4yKTsKICAgICAgfTsKICAgICAgRCA9IChlMiwgdDIsIG4yKSA9PiB7CiAgICAgICAgRShlMiwgbjJbdDIgKiAyXSwgbjJbdDIgKiAyICsgMV0pOwogICAgICB9OwogICAgICBPID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMiA9IDA7CiAgICAgICAgZG8KICAgICAgICAgIG4yIHw9IGUyICYgMSwgZTIgPj4+PSAxLCBuMiA8PD0gMTsKICAgICAgICB3aGlsZSAoLS10MiA+IDApOwogICAgICAgIHJldHVybiBuMiA+Pj4gMTsKICAgICAgfTsKICAgICAgZWUgPSAoZTIsIHQyKSA9PiB7CiAgICAgICAgbGV0IG4yID0gdDIuZHluX3RyZWUsIHIyID0gdDIubWF4X2NvZGUsIGkyID0gdDIuc3RhdF9kZXNjLnN0YXRpY190cmVlLCBhNCA9IHQyLnN0YXRfZGVzYy5oYXNfc3RyZWUsIG8yID0gdDIuc3RhdF9kZXNjLmV4dHJhX2JpdHMsIGwyID0gdDIuc3RhdF9kZXNjLmV4dHJhX2Jhc2UsIHU0ID0gdDIuc3RhdF9kZXNjLm1heF9sZW5ndGgsIGQyLCBmMiwgcDIsIG0yLCBoMiwgZzIsIF8yID0gMDsKICAgICAgICBmb3IgKG0yID0gMDsgbTIgPD0gYzsgbTIrKykgZTIuYmxfY291bnRbbTJdID0gMDsKICAgICAgICBmb3IgKG4yW2UyLmhlYXBbZTIuaGVhcF9tYXhdICogMiArIDFdID0gMCwgZDIgPSBlMi5oZWFwX21heCArIDE7IGQyIDwgczsgZDIrKykgZjIgPSBlMi5oZWFwW2QyXSwgbTIgPSBuMltuMltmMiAqIDIgKyAxXSAqIDIgKyAxXSArIDEsIG0yID4gdTQgJiYgKG0yID0gdTQsIF8yKyspLCBuMltmMiAqIDIgKyAxXSA9IG0yLCAhKGYyID4gcjIpICYmIChlMi5ibF9jb3VudFttMl0rKywgaDIgPSAwLCBmMiA+PSBsMiAmJiAoaDIgPSBvMltmMiAtIGwyXSksIGcyID0gbjJbZjIgKiAyXSwgZTIub3B0X2xlbiArPSBnMiAqIChtMiArIGgyKSwgYTQgJiYgKGUyLnN0YXRpY19sZW4gKz0gZzIgKiAoaTJbZjIgKiAyICsgMV0gKyBoMikpKTsKICAgICAgICBpZiAoXzIgIT09IDApIHsKICAgICAgICAgIGRvIHsKICAgICAgICAgICAgZm9yIChtMiA9IHU0IC0gMTsgZTIuYmxfY291bnRbbTJdID09PSAwOyApIG0yLS07CiAgICAgICAgICAgIGUyLmJsX2NvdW50W20yXS0tLCBlMi5ibF9jb3VudFttMiArIDFdICs9IDIsIGUyLmJsX2NvdW50W3U0XS0tLCBfMiAtPSAyOwogICAgICAgICAgfSB3aGlsZSAoXzIgPiAwKTsKICAgICAgICAgIGZvciAobTIgPSB1NDsgbTIgIT09IDA7IG0yLS0pIGZvciAoZjIgPSBlMi5ibF9jb3VudFttMl07IGYyICE9PSAwOyApIHAyID0gZTIuaGVhcFstLWQyXSwgIShwMiA+IHIyKSAmJiAobjJbcDIgKiAyICsgMV0gIT09IG0yICYmIChlMi5vcHRfbGVuICs9IChtMiAtIG4yW3AyICogMiArIDFdKSAqIG4yW3AyICogMl0sIG4yW3AyICogMiArIDFdID0gbTIpLCBmMi0tKTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIGsgPSAoZTIsIHQyLCBuMikgPT4gewogICAgICAgIGxldCByMiA9IEFycmF5KDE2KSwgaTIgPSAwLCBhNCwgbzI7CiAgICAgICAgZm9yIChhNCA9IDE7IGE0IDw9IGM7IGE0KyspIGkyID0gaTIgKyBuMlthNCAtIDFdIDw8IDEsIHIyW2E0XSA9IGkyOwogICAgICAgIGZvciAobzIgPSAwOyBvMiA8PSB0MjsgbzIrKykgewogICAgICAgICAgbGV0IHQzID0gZTJbbzIgKiAyICsgMV07CiAgICAgICAgICB0MyAhPT0gMCAmJiAoZTJbbzIgKiAyXSA9IE8ocjJbdDNdKyssIHQzKSk7CiAgICAgICAgfQogICAgICB9OwogICAgICBBID0gKGUyKSA9PiB7CiAgICAgICAgbGV0IHQyOwogICAgICAgIGZvciAodDIgPSAwOyB0MiA8IDI4NjsgdDIrKykgZTIuZHluX2x0cmVlW3QyICogMl0gPSAwOwogICAgICAgIGZvciAodDIgPSAwOyB0MiA8IGEzOyB0MisrKSBlMi5keW5fZHRyZWVbdDIgKiAyXSA9IDA7CiAgICAgICAgZm9yICh0MiA9IDA7IHQyIDwgbzsgdDIrKykgZTIuYmxfdHJlZVt0MiAqIDJdID0gMDsKICAgICAgICBlMi5keW5fbHRyZWVbdTMgKiAyXSA9IDEsIGUyLm9wdF9sZW4gPSBlMi5zdGF0aWNfbGVuID0gMCwgZTIuc3ltX25leHQgPSBlMi5tYXRjaGVzID0gMDsKICAgICAgfTsKICAgICAgdGUgPSAoZTIpID0+IHsKICAgICAgICBlMi5iaV92YWxpZCA+IDggPyBUKGUyLCBlMi5iaV9idWYpIDogZTIuYmlfdmFsaWQgPiAwICYmIChlMi5wZW5kaW5nX2J1ZltlMi5wZW5kaW5nKytdID0gZTIuYmlfYnVmKSwgZTIuYmlfYnVmID0gMCwgZTIuYmlfdmFsaWQgPSAwOwogICAgICB9OwogICAgICBuZSA9IChlMiwgdDIsIG4yLCByMikgPT4gewogICAgICAgIGxldCBpMiA9IHQyICogMiwgYTQgPSBuMiAqIDI7CiAgICAgICAgcmV0dXJuIGUyW2kyXSA8IGUyW2E0XSB8fCBlMltpMl0gPT09IGUyW2E0XSAmJiByMlt0Ml0gPD0gcjJbbjJdOwogICAgICB9OwogICAgICByZSA9IChlMiwgdDIsIG4yKSA9PiB7CiAgICAgICAgbGV0IHIyID0gZTIuaGVhcFtuMl0sIGkyID0gbjIgPDwgMTsKICAgICAgICBmb3IgKDsgaTIgPD0gZTIuaGVhcF9sZW4gJiYgKGkyIDwgZTIuaGVhcF9sZW4gJiYgbmUodDIsIGUyLmhlYXBbaTIgKyAxXSwgZTIuaGVhcFtpMl0sIGUyLmRlcHRoKSAmJiBpMisrLCAhbmUodDIsIHIyLCBlMi5oZWFwW2kyXSwgZTIuZGVwdGgpKTsgKSBlMi5oZWFwW24yXSA9IGUyLmhlYXBbaTJdLCBuMiA9IGkyLCBpMiA8PD0gMTsKICAgICAgICBlMi5oZWFwW24yXSA9IHIyOwogICAgICB9OwogICAgICBpZSA9IChlMiwgdDIsIG4yKSA9PiB7CiAgICAgICAgbGV0IHIyLCBhNCwgbzIgPSAwLCBzMiwgYzI7CiAgICAgICAgaWYgKGUyLnN5bV9uZXh0ICE9PSAwKSBkbwogICAgICAgICAgcjIgPSBlMi5wZW5kaW5nX2J1ZltlMi5zeW1fYnVmICsgbzIrK10gJiAyNTUsIHIyICs9IChlMi5wZW5kaW5nX2J1ZltlMi5zeW1fYnVmICsgbzIrK10gJiAyNTUpIDw8IDgsIGE0ID0gZTIucGVuZGluZ19idWZbZTIuc3ltX2J1ZiArIG8yKytdLCByMiA9PT0gMCA/IEQoZTIsIGE0LCB0MikgOiAoczIgPSB4W2E0XSwgRChlMiwgczIgKyBpICsgMSwgdDIpLCBjMiA9IG1bczJdLCBjMiAhPT0gMCAmJiAoYTQgLT0gU1tzMl0sIEUoZTIsIGE0LCBjMikpLCByMi0tLCBzMiA9IHcocjIpLCBEKGUyLCBzMiwgbjIpLCBjMiA9IGhbczJdLCBjMiAhPT0gMCAmJiAocjIgLT0gQ1tzMl0sIEUoZTIsIHIyLCBjMikpKTsKICAgICAgICB3aGlsZSAobzIgPCBlMi5zeW1fbmV4dCk7CiAgICAgICAgRChlMiwgdTMsIHQyKTsKICAgICAgfTsKICAgICAgYWUgPSAoZTIsIHQyKSA9PiB7CiAgICAgICAgbGV0IG4yID0gdDIuZHluX3RyZWUsIHIyID0gdDIuc3RhdF9kZXNjLnN0YXRpY190cmVlLCBpMiA9IHQyLnN0YXRfZGVzYy5oYXNfc3RyZWUsIGE0ID0gdDIuc3RhdF9kZXNjLmVsZW1zLCBvMiwgYzIsIGwyID0gLTEsIHU0OwogICAgICAgIGZvciAoZTIuaGVhcF9sZW4gPSAwLCBlMi5oZWFwX21heCA9IHMsIG8yID0gMDsgbzIgPCBhNDsgbzIrKykgbjJbbzIgKiAyXSA9PT0gMCA/IG4yW28yICogMiArIDFdID0gMCA6IChlMi5oZWFwWysrZTIuaGVhcF9sZW5dID0gbDIgPSBvMiwgZTIuZGVwdGhbbzJdID0gMCk7CiAgICAgICAgZm9yICg7IGUyLmhlYXBfbGVuIDwgMjsgKSB1NCA9IGUyLmhlYXBbKytlMi5oZWFwX2xlbl0gPSBsMiA8IDIgPyArK2wyIDogMCwgbjJbdTQgKiAyXSA9IDEsIGUyLmRlcHRoW3U0XSA9IDAsIGUyLm9wdF9sZW4tLSwgaTIgJiYgKGUyLnN0YXRpY19sZW4gLT0gcjJbdTQgKiAyICsgMV0pOwogICAgICAgIGZvciAodDIubWF4X2NvZGUgPSBsMiwgbzIgPSBlMi5oZWFwX2xlbiA+PiAxOyBvMiA+PSAxOyBvMi0tKSByZShlMiwgbjIsIG8yKTsKICAgICAgICB1NCA9IGE0OwogICAgICAgIGRvCiAgICAgICAgICBvMiA9IGUyLmhlYXBbMV0sIGUyLmhlYXBbMV0gPSBlMi5oZWFwW2UyLmhlYXBfbGVuLS1dLCByZShlMiwgbjIsIDEpLCBjMiA9IGUyLmhlYXBbMV0sIGUyLmhlYXBbLS1lMi5oZWFwX21heF0gPSBvMiwgZTIuaGVhcFstLWUyLmhlYXBfbWF4XSA9IGMyLCBuMlt1NCAqIDJdID0gbjJbbzIgKiAyXSArIG4yW2MyICogMl0sIGUyLmRlcHRoW3U0XSA9IChlMi5kZXB0aFtvMl0gPj0gZTIuZGVwdGhbYzJdID8gZTIuZGVwdGhbbzJdIDogZTIuZGVwdGhbYzJdKSArIDEsIG4yW28yICogMiArIDFdID0gbjJbYzIgKiAyICsgMV0gPSB1NCwgZTIuaGVhcFsxXSA9IHU0KyssIHJlKGUyLCBuMiwgMSk7CiAgICAgICAgd2hpbGUgKGUyLmhlYXBfbGVuID49IDIpOwogICAgICAgIGUyLmhlYXBbLS1lMi5oZWFwX21heF0gPSBlMi5oZWFwWzFdLCBlZShlMiwgdDIpLCBrKG4yLCBsMiwgZTIuYmxfY291bnQpOwogICAgICB9OwogICAgICBvZSA9IChlMiwgdDIsIG4yKSA9PiB7CiAgICAgICAgbGV0IHIyLCBpMiA9IC0xLCBhNCwgbzIgPSB0MlsxXSwgczIgPSAwLCBjMiA9IDcsIGwyID0gNDsKICAgICAgICBmb3IgKG8yID09PSAwICYmIChjMiA9IDEzOCwgbDIgPSAzKSwgdDJbKG4yICsgMSkgKiAyICsgMV0gPSA2NTUzNSwgcjIgPSAwOyByMiA8PSBuMjsgcjIrKykgYTQgPSBvMiwgbzIgPSB0MlsocjIgKyAxKSAqIDIgKyAxXSwgISgrK3MyIDwgYzIgJiYgYTQgPT09IG8yKSAmJiAoczIgPCBsMiA/IGUyLmJsX3RyZWVbYTQgKiAyXSArPSBzMiA6IGE0ID09PSAwID8gczIgPD0gMTAgPyBlMi5ibF90cmVlW2YgKiAyXSsrIDogZTIuYmxfdHJlZVtwICogMl0rKyA6IChhNCAhPT0gaTIgJiYgZTIuYmxfdHJlZVthNCAqIDJdKyssIGUyLmJsX3RyZWVbZCAqIDJdKyspLCBzMiA9IDAsIGkyID0gYTQsIG8yID09PSAwID8gKGMyID0gMTM4LCBsMiA9IDMpIDogYTQgPT09IG8yID8gKGMyID0gNiwgbDIgPSAzKSA6IChjMiA9IDcsIGwyID0gNCkpOwogICAgICB9OwogICAgICBzZSA9IChlMiwgdDIsIG4yKSA9PiB7CiAgICAgICAgbGV0IHIyLCBpMiA9IC0xLCBhNCwgbzIgPSB0MlsxXSwgczIgPSAwLCBjMiA9IDcsIGwyID0gNDsKICAgICAgICBmb3IgKG8yID09PSAwICYmIChjMiA9IDEzOCwgbDIgPSAzKSwgcjIgPSAwOyByMiA8PSBuMjsgcjIrKykgaWYgKGE0ID0gbzIsIG8yID0gdDJbKHIyICsgMSkgKiAyICsgMV0sICEoKytzMiA8IGMyICYmIGE0ID09PSBvMikpIHsKICAgICAgICAgIGlmIChzMiA8IGwyKSBkbwogICAgICAgICAgICBEKGUyLCBhNCwgZTIuYmxfdHJlZSk7CiAgICAgICAgICB3aGlsZSAoLS1zMiAhPT0gMCk7CiAgICAgICAgICBlbHNlIGE0ID09PSAwID8gczIgPD0gMTAgPyAoRChlMiwgZiwgZTIuYmxfdHJlZSksIEUoZTIsIHMyIC0gMywgMykpIDogKEQoZTIsIHAsIGUyLmJsX3RyZWUpLCBFKGUyLCBzMiAtIDExLCA3KSkgOiAoYTQgIT09IGkyICYmIChEKGUyLCBhNCwgZTIuYmxfdHJlZSksIHMyLS0pLCBEKGUyLCBkLCBlMi5ibF90cmVlKSwgRShlMiwgczIgLSAzLCAyKSk7CiAgICAgICAgICBzMiA9IDAsIGkyID0gYTQsIG8yID09PSAwID8gKGMyID0gMTM4LCBsMiA9IDMpIDogYTQgPT09IG8yID8gKGMyID0gNiwgbDIgPSAzKSA6IChjMiA9IDcsIGwyID0gNCk7CiAgICAgICAgfQogICAgICB9OwogICAgICBjZSA9IChlMikgPT4gewogICAgICAgIGxldCB0MjsKICAgICAgICBmb3IgKG9lKGUyLCBlMi5keW5fbHRyZWUsIGUyLmxfZGVzYy5tYXhfY29kZSksIG9lKGUyLCBlMi5keW5fZHRyZWUsIGUyLmRfZGVzYy5tYXhfY29kZSksIGFlKGUyLCBlMi5ibF9kZXNjKSwgdDIgPSBvIC0gMTsgdDIgPj0gMyAmJiBlMi5ibF90cmVlW2dbdDJdICogMiArIDFdID09PSAwOyB0Mi0tKSA7CiAgICAgICAgcmV0dXJuIGUyLm9wdF9sZW4gKz0gMyAqICh0MiArIDEpICsgNSArIDUgKyA0LCB0MjsKICAgICAgfTsKICAgICAgbGUgPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBsZXQgaTI7CiAgICAgICAgZm9yIChFKGUyLCB0MiAtIDI1NywgNSksIEUoZTIsIG4yIC0gMSwgNSksIEUoZTIsIHIyIC0gNCwgNCksIGkyID0gMDsgaTIgPCByMjsgaTIrKykgRShlMiwgZTIuYmxfdHJlZVtnW2kyXSAqIDIgKyAxXSwgMyk7CiAgICAgICAgc2UoZTIsIGUyLmR5bl9sdHJlZSwgdDIgLSAxKSwgc2UoZTIsIGUyLmR5bl9kdHJlZSwgbjIgLSAxKTsKICAgICAgfTsKICAgICAgdWUgPSAobjIpID0+IHsKICAgICAgICBsZXQgcjIgPSA0MDkzNjI0NDQ3LCBhNDsKICAgICAgICBmb3IgKGE0ID0gMDsgYTQgPD0gMzE7IGE0KyssIHIyID4+Pj0gMSkgaWYgKHIyICYgMSAmJiBuMi5keW5fbHRyZWVbYTQgKiAyXSAhPT0gMCkgcmV0dXJuIGU7CiAgICAgICAgaWYgKG4yLmR5bl9sdHJlZVsxOF0gIT09IDAgfHwgbjIuZHluX2x0cmVlWzIwXSAhPT0gMCB8fCBuMi5keW5fbHRyZWVbMjZdICE9PSAwKSByZXR1cm4gdDsKICAgICAgICBmb3IgKGE0ID0gMzI7IGE0IDwgaTsgYTQrKykgaWYgKG4yLmR5bl9sdHJlZVthNCAqIDJdICE9PSAwKSByZXR1cm4gdDsKICAgICAgICByZXR1cm4gZTsKICAgICAgfTsKICAgICAgZGUgPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBFKGUyLCAwICsgKyEhcjIsIDMpLCB0ZShlMiksIFQoZTIsIG4yKSwgVChlMiwgfm4yKSwgbjIgJiYgZTIucGVuZGluZ19idWYuc2V0KGUyLndpbmRvdy5zdWJhcnJheSh0MiwgdDIgKyBuMiksIGUyLnBlbmRpbmcpLCBlMi5wZW5kaW5nICs9IG4yOwogICAgICB9OwogICAgICBmZSA9IChlMiwgdDIsIG4yLCByMikgPT4gewogICAgICAgIGxldCBpMiwgYTQsIG8yID0gMDsKICAgICAgICBlMi5sZXZlbCA+IDAgPyAoZTIuc3RybS5kYXRhX3R5cGUgPT09IDIgJiYgKGUyLnN0cm0uZGF0YV90eXBlID0gdWUoZTIpKSwgYWUoZTIsIGUyLmxfZGVzYyksIGFlKGUyLCBlMi5kX2Rlc2MpLCBvMiA9IGNlKGUyKSwgaTIgPSBlMi5vcHRfbGVuICsgMyArIDcgPj4+IDMsIGE0ID0gZTIuc3RhdGljX2xlbiArIDMgKyA3ID4+PiAzLCBhNCA8PSBpMiAmJiAoaTIgPSBhNCkpIDogaTIgPSBhNCA9IG4yICsgNSwgbjIgKyA0IDw9IGkyICYmIHQyICE9PSAtMSA/IGRlKGUyLCB0MiwgbjIsIHIyKSA6IGUyLnN0cmF0ZWd5ID09PSA0IHx8IGE0ID09PSBpMiA/IChFKGUyLCAyICsgKyEhcjIsIDMpLCBpZShlMiwgdjMsIHkpKSA6IChFKGUyLCA0ICsgKyEhcjIsIDMpLCBsZShlMiwgZTIubF9kZXNjLm1heF9jb2RlICsgMSwgZTIuZF9kZXNjLm1heF9jb2RlICsgMSwgbzIgKyAxKSwgaWUoZTIsIGUyLmR5bl9sdHJlZSwgZTIuZHluX2R0cmVlKSksIEEoZTIpLCByMiAmJiB0ZShlMik7CiAgICAgIH07CiAgICAgIGogPSAoZTIsIHQyLCBuMikgPT4gKGUyLnBlbmRpbmdfYnVmW2UyLnN5bV9idWYgKyBlMi5zeW1fbmV4dCsrXSA9IHQyLCBlMi5wZW5kaW5nX2J1ZltlMi5zeW1fYnVmICsgZTIuc3ltX25leHQrK10gPSB0MiA+PiA4LCBlMi5wZW5kaW5nX2J1ZltlMi5zeW1fYnVmICsgZTIuc3ltX25leHQrK10gPSBuMiwgdDIgPT09IDAgPyBlMi5keW5fbHRyZWVbbjIgKiAyXSsrIDogKGUyLm1hdGNoZXMrKywgdDItLSwgZTIuZHluX2x0cmVlWyh4W24yXSArIGkgKyAxKSAqIDJdKyssIGUyLmR5bl9kdHJlZVt3KHQyKSAqIDJdKyspLCBlMi5zeW1fbmV4dCA9PT0gZTIuc3ltX2VuZCk7CiAgICAgIE0gPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBsZXQgaTIgPSBlMiAmIDY1NTM1IHwgMCwgYTQgPSBlMiA+Pj4gMTYgJiA2NTUzNSB8IDAsIG8yID0gMDsKICAgICAgICBmb3IgKDsgbjIgIT09IDA7ICkgewogICAgICAgICAgbzIgPSBuMiA+IDJlMyA/IDJlMyA6IG4yLCBuMiAtPSBvMjsKICAgICAgICAgIGRvCiAgICAgICAgICAgIGkyID0gaTIgKyB0MltyMisrXSB8IDAsIGE0ID0gYTQgKyBpMiB8IDA7CiAgICAgICAgICB3aGlsZSAoLS1vMik7CiAgICAgICAgICBpMiAlPSA2NTUyMSwgYTQgJT0gNjU1MjE7CiAgICAgICAgfQogICAgICAgIHJldHVybiBpMiB8IGE0IDw8IDE2IHwgMDsKICAgICAgfTsKICAgICAgcGUgPSBuZXcgVWludDMyQXJyYXkoKCgpID0+IHsKICAgICAgICBsZXQgZTIsIHQyID0gW107CiAgICAgICAgZm9yICh2YXIgbjIgPSAwOyBuMiA8IDI1NjsgbjIrKykgewogICAgICAgICAgZTIgPSBuMjsKICAgICAgICAgIGZvciAodmFyIHIyID0gMDsgcjIgPCA4OyByMisrKSBlMiA9IGUyICYgMSA/IDM5ODgyOTIzODQgXiBlMiA+Pj4gMSA6IGUyID4+PiAxOwogICAgICAgICAgdDJbbjJdID0gZTI7CiAgICAgICAgfQogICAgICAgIHJldHVybiB0MjsKICAgICAgfSkoKSk7CiAgICAgIE4gPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBsZXQgaTIgPSBwZSwgYTQgPSByMiArIG4yOwogICAgICAgIGUyIF49IC0xOwogICAgICAgIGZvciAobGV0IG4zID0gcjI7IG4zIDwgYTQ7IG4zKyspIGUyID0gZTIgPj4+IDggXiBpMlsoZTIgXiB0MltuM10pICYgMjU1XTsKICAgICAgICByZXR1cm4gZTIgXiAtMTsKICAgICAgfTsKICAgICAgbWUgPSB7IDI6IGBuZWVkIGRpY3Rpb25hcnlgLCAxOiBgc3RyZWFtIGVuZGAsIDA6IGBgLCAiLTEiOiBgZmlsZSBlcnJvcmAsICItMiI6IGBzdHJlYW0gZXJyb3JgLCAiLTMiOiBgZGF0YSBlcnJvcmAsICItNCI6IGBpbnN1ZmZpY2llbnQgbWVtb3J5YCwgIi01IjogYGJ1ZmZlciBlcnJvcmAsICItNiI6IGBpbmNvbXBhdGlibGUgdmVyc2lvbmAgfTsKICAgICAgUCA9IDM7CiAgICAgIGhlID0gMjU4OwogICAgICBGID0gMjYyOwogICAgICBJID0gMTsKICAgICAgZ2UgPSAyOwogICAgICBfZSA9IDM7CiAgICAgIHZlID0gNDsKICAgICAgeWUgPSAoZTIpID0+IHsKICAgICAgICBsZXQgdDIsIG4yLCByMiwgaTIgPSBlMi53X3NpemU7CiAgICAgICAgdDIgPSBlMi5oYXNoX3NpemUsIHIyID0gdDI7CiAgICAgICAgZG8KICAgICAgICAgIG4yID0gZTIuaGVhZFstLXIyXSwgZTIuaGVhZFtyMl0gPSBuMiA+PSBpMiA/IG4yIC0gaTIgOiAwOwogICAgICAgIHdoaWxlICgtLXQyKTsKICAgICAgICB0MiA9IGkyLCByMiA9IHQyOwogICAgICAgIGRvCiAgICAgICAgICBuMiA9IGUyLnByZXZbLS1yMl0sIGUyLnByZXZbcjJdID0gbjIgPj0gaTIgPyBuMiAtIGkyIDogMDsKICAgICAgICB3aGlsZSAoLS10Mik7CiAgICAgIH07CiAgICAgIGJlID0gKGUyLCB0MiwgbjIpID0+ICh0MiA8PCBlMi5oYXNoX3NoaWZ0IF4gbjIpICYgZTIuaGFzaF9tYXNrOwogICAgICBMID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMjsKICAgICAgICBpZiAoZTIubGVnYWN5X2hhc2gpIG4yID0gZTIuaW5zX2ggPSBiZShlMiwgZTIuaW5zX2gsIGUyLndpbmRvd1t0MiArIFAgLSAxXSk7CiAgICAgICAgZWxzZSB7CiAgICAgICAgICBsZXQgcjMgPSBlMi53aW5kb3csIGkyID0gcjNbdDJdIHwgcjNbdDIgKyAxXSA8PCA4IHwgcjNbdDIgKyAyXSA8PCAxNiB8IHIzW3QyICsgM10gPDwgMjQ7CiAgICAgICAgICBuMiA9IGUyLmluc19oID0gTWF0aC5pbXVsKGkyLCA2NjUyMSkgKyA2NjUyMSA+Pj4gMTYgJiBlMi5oYXNoX21hc2s7CiAgICAgICAgfQogICAgICAgIGxldCByMiA9IGUyLnByZXZbdDIgJiBlMi53X21hc2tdID0gZTIuaGVhZFtuMl07CiAgICAgICAgcmV0dXJuIGUyLmhlYWRbbjJdID0gdDIsIHIyOwogICAgICB9OwogICAgICB4ZSA9IChlMikgPT4gewogICAgICAgIGxldCB0MiA9IGUyLnN0YXRlLCBuMiA9IHQyLnBlbmRpbmc7CiAgICAgICAgbjIgPiBlMi5hdmFpbF9vdXQgJiYgKG4yID0gZTIuYXZhaWxfb3V0KSwgbjIgIT09IDAgJiYgKGUyLm91dHB1dC5zZXQodDIucGVuZGluZ19idWYuc3ViYXJyYXkodDIucGVuZGluZ19vdXQsIHQyLnBlbmRpbmdfb3V0ICsgbjIpLCBlMi5uZXh0X291dCksIGUyLm5leHRfb3V0ICs9IG4yLCB0Mi5wZW5kaW5nX291dCArPSBuMiwgZTIudG90YWxfb3V0ICs9IG4yLCBlMi5hdmFpbF9vdXQgLT0gbjIsIHQyLnBlbmRpbmcgLT0gbjIsIHQyLnBlbmRpbmcgPT09IDAgJiYgKHQyLnBlbmRpbmdfb3V0ID0gMCkpOwogICAgICB9OwogICAgICBSID0gKGUyLCB0MikgPT4gewogICAgICAgIGZlKGUyLCBlMi5ibG9ja19zdGFydCA+PSAwID8gZTIuYmxvY2tfc3RhcnQgOiAtMSwgZTIuc3Ryc3RhcnQgLSBlMi5ibG9ja19zdGFydCwgdDIpLCBlMi5ibG9ja19zdGFydCA9IGUyLnN0cnN0YXJ0LCB4ZShlMi5zdHJtKTsKICAgICAgfTsKICAgICAgU2UgPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBsZXQgaTIgPSBlMi5hdmFpbF9pbjsKICAgICAgICByZXR1cm4gaTIgPiByMiAmJiAoaTIgPSByMiksIGkyID09PSAwID8gMCA6IChlMi5hdmFpbF9pbiAtPSBpMiwgdDIuc2V0KGUyLmlucHV0LnN1YmFycmF5KGUyLm5leHRfaW4sIGUyLm5leHRfaW4gKyBpMiksIG4yKSwgZTIuc3RhdGUud3JhcCA9PT0gMSA/IGUyLmFkbGVyID0gTShlMi5hZGxlciwgdDIsIGkyLCBuMikgOiBlMi5zdGF0ZS53cmFwID09PSAyICYmIChlMi5hZGxlciA9IE4oZTIuYWRsZXIsIHQyLCBpMiwgbjIpKSwgZTIubmV4dF9pbiArPSBpMiwgZTIudG90YWxfaW4gKz0gaTIsIGkyKTsKICAgICAgfTsKICAgICAgQ2UgPSAoZTIsIHQyKSA9PiB7CiAgICAgICAgbGV0IG4yID0gZTIubWF4X2NoYWluX2xlbmd0aCwgcjIgPSBlMi5zdHJzdGFydCwgaTIsIGE0LCBvMiA9IGUyLnByZXZfbGVuZ3RoLCBzMiA9IGUyLm5pY2VfbWF0Y2gsIGMyID0gZTIuc3Ryc3RhcnQgPiBlMi53X3NpemUgLSBGID8gZTIuc3Ryc3RhcnQgLSAoZTIud19zaXplIC0gRikgOiAwLCBsMiA9IGUyLndpbmRvdywgdTQgPSBlMi53X21hc2ssIGQyID0gZTIucHJldiwgZjIgPSBlMi5zdHJzdGFydCArIGhlLCBwMiA9IGwyW3IyICsgbzIgLSAxXSwgbTIgPSBsMltyMiArIG8yXTsKICAgICAgICBlMi5wcmV2X2xlbmd0aCA+PSBlMi5nb29kX21hdGNoICYmIChuMiA+Pj0gMiksIHMyID4gZTIubG9va2FoZWFkICYmIChzMiA9IGUyLmxvb2thaGVhZCk7CiAgICAgICAgZG8gewogICAgICAgICAgaWYgKGkyID0gdDIsIGwyW2kyICsgbzJdICE9PSBtMiB8fCBsMltpMiArIG8yIC0gMV0gIT09IHAyIHx8IGwyW2kyXSAhPT0gbDJbcjJdIHx8IGwyWysraTJdICE9PSBsMltyMiArIDFdKSBjb250aW51ZTsKICAgICAgICAgIHIyICs9IDIsIGkyKys7CiAgICAgICAgICBkbwogICAgICAgICAgICA7CiAgICAgICAgICB3aGlsZSAobDJbKytyMl0gPT09IGwyWysraTJdICYmIGwyWysrcjJdID09PSBsMlsrK2kyXSAmJiBsMlsrK3IyXSA9PT0gbDJbKytpMl0gJiYgbDJbKytyMl0gPT09IGwyWysraTJdICYmIGwyWysrcjJdID09PSBsMlsrK2kyXSAmJiBsMlsrK3IyXSA9PT0gbDJbKytpMl0gJiYgbDJbKytyMl0gPT09IGwyWysraTJdICYmIGwyWysrcjJdID09PSBsMlsrK2kyXSAmJiByMiA8IGYyKTsKICAgICAgICAgIGlmIChhNCA9IGhlIC0gKGYyIC0gcjIpLCByMiA9IGYyIC0gaGUsIGE0ID4gbzIpIHsKICAgICAgICAgICAgaWYgKGUyLm1hdGNoX3N0YXJ0ID0gdDIsIG8yID0gYTQsIGE0ID49IHMyKSBicmVhazsKICAgICAgICAgICAgcDIgPSBsMltyMiArIG8yIC0gMV0sIG0yID0gbDJbcjIgKyBvMl07CiAgICAgICAgICB9CiAgICAgICAgfSB3aGlsZSAoKHQyID0gZDJbdDIgJiB1NF0pID4gYzIgJiYgLS1uMiAhPT0gMCk7CiAgICAgICAgcmV0dXJuIG8yIDw9IGUyLmxvb2thaGVhZCA/IG8yIDogZTIubG9va2FoZWFkOwogICAgICB9OwogICAgICB3ZSA9IChlMikgPT4gewogICAgICAgIGxldCB0MiA9IGUyLndfc2l6ZSwgbjIsIHIyLCBpMjsKICAgICAgICBkbyB7CiAgICAgICAgICBpZiAocjIgPSBlMi53aW5kb3dfc2l6ZSAtIGUyLmxvb2thaGVhZCAtIGUyLnN0cnN0YXJ0LCBlMi5zdHJzdGFydCA+PSB0MiArICh0MiAtIEYpICYmIChlMi53aW5kb3cuc2V0KGUyLndpbmRvdy5zdWJhcnJheSh0MiwgdDIgKyB0MiAtIHIyKSwgMCksIGUyLm1hdGNoX3N0YXJ0IC09IHQyLCBlMi5zdHJzdGFydCAtPSB0MiwgZTIuYmxvY2tfc3RhcnQgLT0gdDIsIGUyLmluc2VydCA+IGUyLnN0cnN0YXJ0ICYmIChlMi5pbnNlcnQgPSBlMi5zdHJzdGFydCksIHllKGUyKSwgcjIgKz0gdDIpLCBlMi5zdHJtLmF2YWlsX2luID09PSAwKSBicmVhazsKICAgICAgICAgIGlmIChuMiA9IFNlKGUyLnN0cm0sIGUyLndpbmRvdywgZTIuc3Ryc3RhcnQgKyBlMi5sb29rYWhlYWQsIHIyKSwgZTIubG9va2FoZWFkICs9IG4yLCAhZTIubGVnYWN5X2hhc2gpIHsKICAgICAgICAgICAgaWYgKGUyLmxvb2thaGVhZCArIGUyLmluc2VydCA+IFApIGZvciAoaTIgPSBlMi5zdHJzdGFydCAtIGUyLmluc2VydDsgZTIuaW5zZXJ0ICYmIChMKGUyLCBpMiksIGkyKyssIGUyLmluc2VydC0tLCAhKGUyLmxvb2thaGVhZCArIGUyLmluc2VydCA8PSBQKSk7ICkgOwogICAgICAgICAgfSBlbHNlIGlmIChlMi5sb29rYWhlYWQgKyBlMi5pbnNlcnQgPj0gUCkgZm9yIChpMiA9IGUyLnN0cnN0YXJ0IC0gZTIuaW5zZXJ0LCBlMi5pbnNfaCA9IGUyLndpbmRvd1tpMl0sIGUyLmluc19oID0gYmUoZTIsIGUyLmluc19oLCBlMi53aW5kb3dbaTIgKyAxXSk7IGUyLmluc2VydCAmJiAoTChlMiwgaTIpLCBpMisrLCBlMi5pbnNlcnQtLSwgIShlMi5sb29rYWhlYWQgKyBlMi5pbnNlcnQgPCBQKSk7ICkgOwogICAgICAgIH0gd2hpbGUgKGUyLmxvb2thaGVhZCA8IEYgJiYgZTIuc3RybS5hdmFpbF9pbiAhPT0gMCk7CiAgICAgIH07CiAgICAgIFRlID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMiA9IGUyLnBlbmRpbmdfYnVmX3NpemUgLSA1ID4gZTIud19zaXplID8gZTIud19zaXplIDogZTIucGVuZGluZ19idWZfc2l6ZSAtIDUsIHIyLCBpMiwgYTQsIG8yID0gMCwgczIgPSBlMi5zdHJtLmF2YWlsX2luOwogICAgICAgIGRvIHsKICAgICAgICAgIGlmIChyMiA9IDY1NTM1LCBhNCA9IGUyLmJpX3ZhbGlkICsgNDIgPj4gMywgZTIuc3RybS5hdmFpbF9vdXQgPCBhNCB8fCAoYTQgPSBlMi5zdHJtLmF2YWlsX291dCAtIGE0LCBpMiA9IGUyLnN0cnN0YXJ0IC0gZTIuYmxvY2tfc3RhcnQsIHIyID4gaTIgKyBlMi5zdHJtLmF2YWlsX2luICYmIChyMiA9IGkyICsgZTIuc3RybS5hdmFpbF9pbiksIHIyID4gYTQgJiYgKHIyID0gYTQpLCByMiA8IG4yICYmIChyMiA9PT0gMCAmJiB0MiAhPT0gNCB8fCB0MiA9PT0gMCB8fCByMiAhPT0gaTIgKyBlMi5zdHJtLmF2YWlsX2luKSkpIGJyZWFrOwogICAgICAgICAgbzIgPSArKHQyID09PSA0ICYmIHIyID09PSBpMiArIGUyLnN0cm0uYXZhaWxfaW4pLCBkZShlMiwgMCwgMCwgbzIpLCBlMi5wZW5kaW5nX2J1ZltlMi5wZW5kaW5nIC0gNF0gPSByMiwgZTIucGVuZGluZ19idWZbZTIucGVuZGluZyAtIDNdID0gcjIgPj4gOCwgZTIucGVuZGluZ19idWZbZTIucGVuZGluZyAtIDJdID0gfnIyLCBlMi5wZW5kaW5nX2J1ZltlMi5wZW5kaW5nIC0gMV0gPSB+cjIgPj4gOCwgeGUoZTIuc3RybSksIGkyICYmIChpMiA+IHIyICYmIChpMiA9IHIyKSwgZTIuc3RybS5vdXRwdXQuc2V0KGUyLndpbmRvdy5zdWJhcnJheShlMi5ibG9ja19zdGFydCwgZTIuYmxvY2tfc3RhcnQgKyBpMiksIGUyLnN0cm0ubmV4dF9vdXQpLCBlMi5zdHJtLm5leHRfb3V0ICs9IGkyLCBlMi5zdHJtLmF2YWlsX291dCAtPSBpMiwgZTIuc3RybS50b3RhbF9vdXQgKz0gaTIsIGUyLmJsb2NrX3N0YXJ0ICs9IGkyLCByMiAtPSBpMiksIHIyICYmIChTZShlMi5zdHJtLCBlMi5zdHJtLm91dHB1dCwgZTIuc3RybS5uZXh0X291dCwgcjIpLCBlMi5zdHJtLm5leHRfb3V0ICs9IHIyLCBlMi5zdHJtLmF2YWlsX291dCAtPSByMiwgZTIuc3RybS50b3RhbF9vdXQgKz0gcjIpOwogICAgICAgIH0gd2hpbGUgKG8yID09PSAwKTsKICAgICAgICByZXR1cm4gczIgLT0gZTIuc3RybS5hdmFpbF9pbiwgczIgJiYgKHMyID49IGUyLndfc2l6ZSA/IChlMi5tYXRjaGVzID0gMiwgZTIud2luZG93LnNldChlMi5zdHJtLmlucHV0LnN1YmFycmF5KGUyLnN0cm0ubmV4dF9pbiAtIGUyLndfc2l6ZSwgZTIuc3RybS5uZXh0X2luKSwgMCksIGUyLnN0cnN0YXJ0ID0gZTIud19zaXplLCBlMi5pbnNlcnQgPSBlMi5zdHJzdGFydCkgOiAoZTIud2luZG93X3NpemUgLSBlMi5zdHJzdGFydCA8PSBzMiAmJiAoZTIuc3Ryc3RhcnQgLT0gZTIud19zaXplLCBlMi53aW5kb3cuc2V0KGUyLndpbmRvdy5zdWJhcnJheShlMi53X3NpemUsIGUyLndfc2l6ZSArIGUyLnN0cnN0YXJ0KSwgMCksIGUyLm1hdGNoZXMgPCAyICYmIGUyLm1hdGNoZXMrKywgZTIuaW5zZXJ0ID4gZTIuc3Ryc3RhcnQgJiYgKGUyLmluc2VydCA9IGUyLnN0cnN0YXJ0KSksIGUyLndpbmRvdy5zZXQoZTIuc3RybS5pbnB1dC5zdWJhcnJheShlMi5zdHJtLm5leHRfaW4gLSBzMiwgZTIuc3RybS5uZXh0X2luKSwgZTIuc3Ryc3RhcnQpLCBlMi5zdHJzdGFydCArPSBzMiwgZTIuaW5zZXJ0ICs9IHMyID4gZTIud19zaXplIC0gZTIuaW5zZXJ0ID8gZTIud19zaXplIC0gZTIuaW5zZXJ0IDogczIpLCBlMi5ibG9ja19zdGFydCA9IGUyLnN0cnN0YXJ0KSwgZTIuaGlnaF93YXRlciA8IGUyLnN0cnN0YXJ0ICYmIChlMi5oaWdoX3dhdGVyID0gZTIuc3Ryc3RhcnQpLCBvMiA/IHZlIDogdDIgIT09IDAgJiYgdDIgIT09IDQgJiYgZTIuc3RybS5hdmFpbF9pbiA9PT0gMCAmJiBlMi5zdHJzdGFydCA9PT0gZTIuYmxvY2tfc3RhcnQgPyBnZSA6IChhNCA9IGUyLndpbmRvd19zaXplIC0gZTIuc3Ryc3RhcnQsIGUyLnN0cm0uYXZhaWxfaW4gPiBhNCAmJiBlMi5ibG9ja19zdGFydCA+PSBlMi53X3NpemUgJiYgKGUyLmJsb2NrX3N0YXJ0IC09IGUyLndfc2l6ZSwgZTIuc3Ryc3RhcnQgLT0gZTIud19zaXplLCBlMi53aW5kb3cuc2V0KGUyLndpbmRvdy5zdWJhcnJheShlMi53X3NpemUsIGUyLndfc2l6ZSArIGUyLnN0cnN0YXJ0KSwgMCksIGUyLm1hdGNoZXMgPCAyICYmIGUyLm1hdGNoZXMrKywgYTQgKz0gZTIud19zaXplLCBlMi5pbnNlcnQgPiBlMi5zdHJzdGFydCAmJiAoZTIuaW5zZXJ0ID0gZTIuc3Ryc3RhcnQpKSwgYTQgPiBlMi5zdHJtLmF2YWlsX2luICYmIChhNCA9IGUyLnN0cm0uYXZhaWxfaW4pLCBhNCAmJiAoU2UoZTIuc3RybSwgZTIud2luZG93LCBlMi5zdHJzdGFydCwgYTQpLCBlMi5zdHJzdGFydCArPSBhNCwgZTIuaW5zZXJ0ICs9IGE0ID4gZTIud19zaXplIC0gZTIuaW5zZXJ0ID8gZTIud19zaXplIC0gZTIuaW5zZXJ0IDogYTQpLCBlMi5oaWdoX3dhdGVyIDwgZTIuc3Ryc3RhcnQgJiYgKGUyLmhpZ2hfd2F0ZXIgPSBlMi5zdHJzdGFydCksIGE0ID0gZTIuYmlfdmFsaWQgKyA0MiA+PiAzLCBhNCA9IGUyLnBlbmRpbmdfYnVmX3NpemUgLSBhNCA+IDY1NTM1ID8gNjU1MzUgOiBlMi5wZW5kaW5nX2J1Zl9zaXplIC0gYTQsIG4yID0gYTQgPiBlMi53X3NpemUgPyBlMi53X3NpemUgOiBhNCwgaTIgPSBlMi5zdHJzdGFydCAtIGUyLmJsb2NrX3N0YXJ0LCAoaTIgPj0gbjIgfHwgKGkyIHx8IHQyID09PSA0KSAmJiB0MiAhPT0gMCAmJiBlMi5zdHJtLmF2YWlsX2luID09PSAwICYmIGkyIDw9IGE0KSAmJiAocjIgPSBpMiA+IGE0ID8gYTQgOiBpMiwgbzIgPSArKHQyID09PSA0ICYmIGUyLnN0cm0uYXZhaWxfaW4gPT09IDAgJiYgcjIgPT09IGkyKSwgZGUoZTIsIGUyLmJsb2NrX3N0YXJ0LCByMiwgbzIpLCBlMi5ibG9ja19zdGFydCArPSByMiwgeGUoZTIuc3RybSkpLCBvMiA/IF9lIDogSSk7CiAgICAgIH07CiAgICAgIEVlID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMiwgcjI7CiAgICAgICAgZm9yICg7IDsgKSB7CiAgICAgICAgICBpZiAoZTIubG9va2FoZWFkIDwgRikgewogICAgICAgICAgICBpZiAod2UoZTIpLCBlMi5sb29rYWhlYWQgPCBGICYmIHQyID09PSAwKSByZXR1cm4gSTsKICAgICAgICAgICAgaWYgKGUyLmxvb2thaGVhZCA9PT0gMCkgYnJlYWs7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAobjIgPSAwLCBlMi5sb29rYWhlYWQgPj0gUCAmJiAobjIgPSBMKGUyLCBlMi5zdHJzdGFydCkpLCBuMiAhPT0gMCAmJiBlMi5zdHJzdGFydCAtIG4yIDw9IGUyLndfc2l6ZSAtIEYgJiYgKGUyLm1hdGNoX2xlbmd0aCA9IENlKGUyLCBuMikpLCBlMi5tYXRjaF9sZW5ndGggPj0gUCkgaWYgKHIyID0gaihlMiwgZTIuc3Ryc3RhcnQgLSBlMi5tYXRjaF9zdGFydCwgZTIubWF0Y2hfbGVuZ3RoIC0gUCksIGUyLmxvb2thaGVhZCAtPSBlMi5tYXRjaF9sZW5ndGgsIGUyLm1hdGNoX2xlbmd0aCA8PSBlMi5tYXhfbGF6eV9tYXRjaCAmJiBlMi5sb29rYWhlYWQgPj0gUCkgewogICAgICAgICAgICBlMi5tYXRjaF9sZW5ndGgtLTsKICAgICAgICAgICAgZG8KICAgICAgICAgICAgICBlMi5zdHJzdGFydCsrLCBuMiA9IEwoZTIsIGUyLnN0cnN0YXJ0KTsKICAgICAgICAgICAgd2hpbGUgKC0tZTIubWF0Y2hfbGVuZ3RoICE9PSAwKTsKICAgICAgICAgICAgZTIuc3Ryc3RhcnQrKzsKICAgICAgICAgIH0gZWxzZSBlMi5zdHJzdGFydCArPSBlMi5tYXRjaF9sZW5ndGgsIGUyLm1hdGNoX2xlbmd0aCA9IDAsIGUyLmxlZ2FjeV9oYXNoICYmIChlMi5pbnNfaCA9IGUyLndpbmRvd1tlMi5zdHJzdGFydF0sIGUyLmluc19oID0gYmUoZTIsIGUyLmluc19oLCBlMi53aW5kb3dbZTIuc3Ryc3RhcnQgKyAxXSkpOwogICAgICAgICAgZWxzZSByMiA9IGooZTIsIDAsIGUyLndpbmRvd1tlMi5zdHJzdGFydF0pLCBlMi5sb29rYWhlYWQtLSwgZTIuc3Ryc3RhcnQrKzsKICAgICAgICAgIGlmIChyMiAmJiAoUihlMiwgZmFsc2UpLCBlMi5zdHJtLmF2YWlsX291dCA9PT0gMCkpIHJldHVybiBJOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTIuaW5zZXJ0ID0gZTIuc3Ryc3RhcnQgPCBQIC0gMSA/IGUyLnN0cnN0YXJ0IDogUCAtIDEsIHQyID09PSA0ID8gKFIoZTIsIHRydWUpLCBlMi5zdHJtLmF2YWlsX291dCA9PT0gMCA/IF9lIDogdmUpIDogZTIuc3ltX25leHQgJiYgKFIoZTIsIGZhbHNlKSwgZTIuc3RybS5hdmFpbF9vdXQgPT09IDApID8gSSA6IGdlOwogICAgICB9OwogICAgICB6ID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMiwgcjIsIGkyOwogICAgICAgIGZvciAoOyA7ICkgewogICAgICAgICAgaWYgKGUyLmxvb2thaGVhZCA8IEYpIHsKICAgICAgICAgICAgaWYgKHdlKGUyKSwgZTIubG9va2FoZWFkIDwgRiAmJiB0MiA9PT0gMCkgcmV0dXJuIEk7CiAgICAgICAgICAgIGlmIChlMi5sb29rYWhlYWQgPT09IDApIGJyZWFrOwogICAgICAgICAgfQogICAgICAgICAgaWYgKG4yID0gMCwgZTIubG9va2FoZWFkID49IFAgJiYgKG4yID0gTChlMiwgZTIuc3Ryc3RhcnQpKSwgZTIucHJldl9sZW5ndGggPSBlMi5tYXRjaF9sZW5ndGgsIGUyLnByZXZfbWF0Y2ggPSBlMi5tYXRjaF9zdGFydCwgZTIubWF0Y2hfbGVuZ3RoID0gUCAtIDEsIG4yICE9PSAwICYmIGUyLnByZXZfbGVuZ3RoIDwgZTIubWF4X2xhenlfbWF0Y2ggJiYgZTIuc3Ryc3RhcnQgLSBuMiA8PSBlMi53X3NpemUgLSBGICYmIChlMi5tYXRjaF9sZW5ndGggPSBDZShlMiwgbjIpLCBlMi5tYXRjaF9sZW5ndGggPD0gNSAmJiAoZTIuc3RyYXRlZ3kgPT09IDEgfHwgZTIubWF0Y2hfbGVuZ3RoID09PSBQICYmIGUyLnN0cnN0YXJ0IC0gZTIubWF0Y2hfc3RhcnQgPiA0MDk2KSAmJiAoZTIubWF0Y2hfbGVuZ3RoID0gUCAtIDEpKSwgZTIucHJldl9sZW5ndGggPj0gUCAmJiBlMi5tYXRjaF9sZW5ndGggPD0gZTIucHJldl9sZW5ndGgpIHsKICAgICAgICAgICAgaTIgPSBlMi5zdHJzdGFydCArIGUyLmxvb2thaGVhZCAtIFAsIHIyID0gaihlMiwgZTIuc3Ryc3RhcnQgLSAxIC0gZTIucHJldl9tYXRjaCwgZTIucHJldl9sZW5ndGggLSBQKSwgZTIubG9va2FoZWFkIC09IGUyLnByZXZfbGVuZ3RoIC0gMSwgZTIucHJldl9sZW5ndGggLT0gMjsKICAgICAgICAgICAgZG8KICAgICAgICAgICAgICArK2UyLnN0cnN0YXJ0IDw9IGkyICYmIChuMiA9IEwoZTIsIGUyLnN0cnN0YXJ0KSk7CiAgICAgICAgICAgIHdoaWxlICgtLWUyLnByZXZfbGVuZ3RoICE9PSAwKTsKICAgICAgICAgICAgaWYgKGUyLm1hdGNoX2F2YWlsYWJsZSA9IDAsIGUyLm1hdGNoX2xlbmd0aCA9IFAgLSAxLCBlMi5zdHJzdGFydCsrLCByMiAmJiAoUihlMiwgZmFsc2UpLCBlMi5zdHJtLmF2YWlsX291dCA9PT0gMCkpIHJldHVybiBJOwogICAgICAgICAgfSBlbHNlIGlmIChlMi5tYXRjaF9hdmFpbGFibGUpIHsKICAgICAgICAgICAgaWYgKHIyID0gaihlMiwgMCwgZTIud2luZG93W2UyLnN0cnN0YXJ0IC0gMV0pLCByMiAmJiBSKGUyLCBmYWxzZSksIGUyLnN0cnN0YXJ0KyssIGUyLmxvb2thaGVhZC0tLCBlMi5zdHJtLmF2YWlsX291dCA9PT0gMCkgcmV0dXJuIEk7CiAgICAgICAgICB9IGVsc2UgZTIubWF0Y2hfYXZhaWxhYmxlID0gMSwgZTIuc3Ryc3RhcnQrKywgZTIubG9va2FoZWFkLS07CiAgICAgICAgfQogICAgICAgIHJldHVybiBlMi5tYXRjaF9hdmFpbGFibGUgJiYgKHIyID0gaihlMiwgMCwgZTIud2luZG93W2UyLnN0cnN0YXJ0IC0gMV0pLCBlMi5tYXRjaF9hdmFpbGFibGUgPSAwKSwgZTIuaW5zZXJ0ID0gZTIuc3Ryc3RhcnQgPCBQIC0gMSA/IGUyLnN0cnN0YXJ0IDogUCAtIDEsIHQyID09PSA0ID8gKFIoZTIsIHRydWUpLCBlMi5zdHJtLmF2YWlsX291dCA9PT0gMCA/IF9lIDogdmUpIDogZTIuc3ltX25leHQgJiYgKFIoZTIsIGZhbHNlKSwgZTIuc3RybS5hdmFpbF9vdXQgPT09IDApID8gSSA6IGdlOwogICAgICB9OwogICAgICBCID0gY2xhc3MgewogICAgICAgIGNvbnN0cnVjdG9yKGUyLCB0MiwgbjIsIHIyLCBpMikgewogICAgICAgICAgdGhpcy5nb29kX2xlbmd0aCA9IGUyLCB0aGlzLm1heF9sYXp5ID0gdDIsIHRoaXMubmljZV9sZW5ndGggPSBuMiwgdGhpcy5tYXhfY2hhaW4gPSByMiwgdGhpcy5mdW5jID0gaTI7CiAgICAgICAgfQogICAgICB9OwogICAgICBuZXcgQigwLCAwLCAwLCAwLCBUZSksIG5ldyBCKDQsIDQsIDgsIDQsIEVlKSwgbmV3IEIoNCwgNSwgMTYsIDgsIEVlKSwgbmV3IEIoNCwgNiwgMzIsIDMyLCBFZSksIG5ldyBCKDQsIDQsIDE2LCAxNiwgeiksIG5ldyBCKDgsIDE2LCAzMiwgMzIsIHopLCBuZXcgQig4LCAxNiwgMTI4LCAxMjgsIHopLCBuZXcgQig4LCAzMiwgMTI4LCAyNTYsIHopLCBuZXcgQigzMiwgMTI4LCAyNTgsIDEwMjQsIHopLCBuZXcgQigzMiwgMjU4LCAyNTgsIDQwOTYsIHopOwogICAgICBWID0gMTYyMDk7CiAgICAgIERlID0gMTYxOTE7CiAgICAgIEggPSAxNTsKICAgICAga2UgPSA4NTI7CiAgICAgIEFlID0gNTkyOwogICAgICBqZSA9IDA7CiAgICAgIFUgPSAxOwogICAgICBNZSA9IDI7CiAgICAgIE5lID0gbmV3IFVpbnQxNkFycmF5KFszLCA0LCA1LCA2LCA3LCA4LCA5LCAxMCwgMTEsIDEzLCAxNSwgMTcsIDE5LCAyMywgMjcsIDMxLCAzNSwgNDMsIDUxLCA1OSwgNjcsIDgzLCA5OSwgMTE1LCAxMzEsIDE2MywgMTk1LCAyMjcsIDI1OCwgMCwgMF0pOwogICAgICBQZSA9IG5ldyBVaW50OEFycmF5KFsxNiwgMTYsIDE2LCAxNiwgMTYsIDE2LCAxNiwgMTYsIDE3LCAxNywgMTcsIDE3LCAxOCwgMTgsIDE4LCAxOCwgMTksIDE5LCAxOSwgMTksIDIwLCAyMCwgMjAsIDIwLCAyMSwgMjEsIDIxLCAyMSwgMTYsIDE5OSwgNzVdKTsKICAgICAgRmUgPSBuZXcgVWludDE2QXJyYXkoWzEsIDIsIDMsIDQsIDUsIDcsIDksIDEzLCAxNywgMjUsIDMzLCA0OSwgNjUsIDk3LCAxMjksIDE5MywgMjU3LCAzODUsIDUxMywgNzY5LCAxMDI1LCAxNTM3LCAyMDQ5LCAzMDczLCA0MDk3LCA2MTQ1LCA4MTkzLCAxMjI4OSwgMTYzODUsIDI0NTc3LCAwLCAwXSk7CiAgICAgIEllID0gbmV3IFVpbnQ4QXJyYXkoWzE2LCAxNiwgMTYsIDE2LCAxNywgMTcsIDE4LCAxOCwgMTksIDE5LCAyMCwgMjAsIDIxLCAyMSwgMjIsIDIyLCAyMywgMjMsIDI0LCAyNCwgMjUsIDI1LCAyNiwgMjYsIDI3LCAyNywgMjgsIDI4LCAyOSwgMjksIDY0LCA2NF0pOwogICAgICBXID0gKGUyLCB0MiwgbjIsIHIyLCBpMiwgYTQsIG8yLCBzMikgPT4gewogICAgICAgIGxldCBjMiA9IHMyLmJpdHMsIGwyID0gMCwgdTQgPSAwLCBkMiA9IDAsIGYyID0gMCwgcDIgPSAwLCBtMiA9IDAsIGgyID0gMCwgZzIgPSAwLCBfMiA9IDAsIHY0ID0gMCwgeTIsIGIyLCB4MiwgUzIsIEMyLCB3MiA9IG51bGwsIFQyLCBFMiA9IG5ldyBVaW50MTZBcnJheSgxNiksIEQyID0gbmV3IFVpbnQxNkFycmF5KDE2KSwgTzIgPSBudWxsLCBlZTIsIGsyLCBBMjsKICAgICAgICBmb3IgKGwyID0gMDsgbDIgPD0gSDsgbDIrKykgRTJbbDJdID0gMDsKICAgICAgICBmb3IgKHU0ID0gMDsgdTQgPCByMjsgdTQrKykgRTJbdDJbbjIgKyB1NF1dKys7CiAgICAgICAgZm9yIChwMiA9IGMyLCBmMiA9IEg7IGYyID49IDEgJiYgRTJbZjJdID09PSAwOyBmMi0tKSA7CiAgICAgICAgaWYgKHAyID4gZjIgJiYgKHAyID0gZjIpLCBmMiA9PT0gMCkgcmV0dXJuIGkyW2E0KytdID0gMjA5NzE1MjAsIGkyW2E0KytdID0gMjA5NzE1MjAsIHMyLmJpdHMgPSAxLCAwOwogICAgICAgIGZvciAoZDIgPSAxOyBkMiA8IGYyICYmIEUyW2QyXSA9PT0gMDsgZDIrKykgOwogICAgICAgIGZvciAocDIgPCBkMiAmJiAocDIgPSBkMiksIGcyID0gMSwgbDIgPSAxOyBsMiA8PSBIOyBsMisrKSBpZiAoZzIgPDw9IDEsIGcyIC09IEUyW2wyXSwgZzIgPCAwKSByZXR1cm4gLTE7CiAgICAgICAgaWYgKGcyID4gMCAmJiAoZTIgPT09IGplIHx8IGYyICE9PSAxKSkgcmV0dXJuIC0xOwogICAgICAgIGZvciAoRDJbMV0gPSAwLCBsMiA9IDE7IGwyIDwgSDsgbDIrKykgRDJbbDIgKyAxXSA9IEQyW2wyXSArIEUyW2wyXTsKICAgICAgICBmb3IgKHU0ID0gMDsgdTQgPCByMjsgdTQrKykgdDJbbjIgKyB1NF0gIT09IDAgJiYgKG8yW0QyW3QyW24yICsgdTRdXSsrXSA9IHU0KTsKICAgICAgICBpZiAoZTIgPT09IGplID8gKHcyID0gTzIgPSBvMiwgVDIgPSAyMCkgOiBlMiA9PT0gVSA/ICh3MiA9IE5lLCBPMiA9IFBlLCBUMiA9IDI1NykgOiAodzIgPSBGZSwgTzIgPSBJZSwgVDIgPSAwKSwgdjQgPSAwLCB1NCA9IDAsIGwyID0gZDIsIEMyID0gYTQsIG0yID0gcDIsIGgyID0gMCwgeDIgPSAtMSwgXzIgPSAxIDw8IHAyLCBTMiA9IF8yIC0gMSwgZTIgPT09IFUgJiYgXzIgPiBrZSB8fCBlMiA9PT0gTWUgJiYgXzIgPiBBZSkgcmV0dXJuIDE7CiAgICAgICAgZm9yICg7IDsgKSB7CiAgICAgICAgICBlZTIgPSBsMiAtIGgyLCBvMlt1NF0gKyAxIDwgVDIgPyAoazIgPSAwLCBBMiA9IG8yW3U0XSkgOiBvMlt1NF0gPj0gVDIgPyAoazIgPSBPMltvMlt1NF0gLSBUMl0sIEEyID0gdzJbbzJbdTRdIC0gVDJdKSA6IChrMiA9IDk2LCBBMiA9IDApLCB5MiA9IDEgPDwgbDIgLSBoMiwgYjIgPSAxIDw8IG0yLCBkMiA9IGIyOwogICAgICAgICAgZG8KICAgICAgICAgICAgYjIgLT0geTIsIGkyW0MyICsgKHY0ID4+IGgyKSArIGIyXSA9IGVlMiA8PCAyNCB8IGsyIDw8IDE2IHwgQTIgfCAwOwogICAgICAgICAgd2hpbGUgKGIyICE9PSAwKTsKICAgICAgICAgIGZvciAoeTIgPSAxIDw8IGwyIC0gMTsgdjQgJiB5MjsgKSB5MiA+Pj0gMTsKICAgICAgICAgIGlmICh5MiA9PT0gMCA/IHY0ID0gMCA6ICh2NCAmPSB5MiAtIDEsIHY0ICs9IHkyKSwgdTQrKywgLS1FMltsMl0gPT09IDApIHsKICAgICAgICAgICAgaWYgKGwyID09PSBmMikgYnJlYWs7CiAgICAgICAgICAgIGwyID0gdDJbbjIgKyBvMlt1NF1dOwogICAgICAgICAgfQogICAgICAgICAgaWYgKGwyID4gcDIgJiYgKHY0ICYgUzIpICE9PSB4MikgewogICAgICAgICAgICBmb3IgKGgyID09PSAwICYmIChoMiA9IHAyKSwgQzIgKz0gZDIsIG0yID0gbDIgLSBoMiwgZzIgPSAxIDw8IG0yOyBtMiArIGgyIDwgZjIgJiYgKGcyIC09IEUyW20yICsgaDJdLCAhKGcyIDw9IDApKTsgKSBtMisrLCBnMiA8PD0gMTsKICAgICAgICAgICAgaWYgKF8yICs9IDEgPDwgbTIsIGUyID09PSBVICYmIF8yID4ga2UgfHwgZTIgPT09IE1lICYmIF8yID4gQWUpIHJldHVybiAxOwogICAgICAgICAgICB4MiA9IHY0ICYgUzIsIGkyW3gyXSA9IHAyIDw8IDI0IHwgbTIgPDwgMTYgfCBDMiAtIGE0IHwgMDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHY0ICE9PSAwICYmIChpMltDMiArIHY0XSA9IGwyIC0gaDIgPDwgMjQgfCA0MTk0MzA0KSwgczIuYml0cyA9IHAyLCAwOwogICAgICB9OwogICAgICBMZSA9IDA7CiAgICAgIFJlID0gMTsKICAgICAgemUgPSAyOwogICAgICBHID0gMTYxODA7CiAgICAgIEJlID0gMTYxODE7CiAgICAgIFZlID0gMTYxODI7CiAgICAgIEhlID0gMTYxODM7CiAgICAgIFVlID0gMTYxODQ7CiAgICAgIFdlID0gMTYxODU7CiAgICAgIEdlID0gMTYxODY7CiAgICAgIEtlID0gMTYxODc7CiAgICAgIHFlID0gMTYxODg7CiAgICAgIEplID0gMTYxODk7CiAgICAgIEsgPSAxNjE5MDsKICAgICAgcSA9IDE2MTkxOwogICAgICBZZSA9IDE2MTkyOwogICAgICBYZSA9IDE2MTkzOwogICAgICBaZSA9IDE2MTk0OwogICAgICBRZSA9IDE2MTk1OwogICAgICAkZSA9IDE2MTk2OwogICAgICBldCA9IDE2MTk3OwogICAgICB0dCA9IDE2MTk4OwogICAgICBKID0gMTYxOTk7CiAgICAgIFkgPSAxNjIwMDsKICAgICAgbnQgPSAxNjIwMTsKICAgICAgcnQgPSAxNjIwMjsKICAgICAgaXQgPSAxNjIwMzsKICAgICAgYXQgPSAxNjIwNDsKICAgICAgb3QgPSAxNjIwNTsKICAgICAgc3QgPSAxNjIwNjsKICAgICAgY3QgPSAxNjIwNzsKICAgICAgbHQgPSAxNjIwODsKICAgICAgWCA9IDE2MjA5OwogICAgICB1dCA9IDE2MjEwOwogICAgICBkdCA9IDE2MjExOwogICAgICBmdCA9IDg1MjsKICAgICAgcHQgPSA1OTI7CiAgICAgIG10ID0gKGUyKSA9PiAoZTIgPj4+IDI0ICYgMjU1KSArIChlMiA+Pj4gOCAmIDY1MjgwKSArICgoZTIgJiA2NTI4MCkgPDwgOCkgKyAoKGUyICYgMjU1KSA8PCAyNCk7CiAgICAgIGh0ID0gY2xhc3MgewogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgdGhpcy5zdHJtID0gbnVsbCwgdGhpcy5tb2RlID0gMCwgdGhpcy5sYXN0ID0gZmFsc2UsIHRoaXMud3JhcCA9IDAsIHRoaXMuaGF2ZWRpY3QgPSBmYWxzZSwgdGhpcy5mbGFncyA9IDAsIHRoaXMuZG1heCA9IDAsIHRoaXMuY2hlY2sgPSAwLCB0aGlzLnRvdGFsID0gMCwgdGhpcy5oZWFkID0gbnVsbCwgdGhpcy53Yml0cyA9IDAsIHRoaXMud3NpemUgPSAwLCB0aGlzLndoYXZlID0gMCwgdGhpcy53bmV4dCA9IDAsIHRoaXMud2luZG93ID0gbnVsbCwgdGhpcy5ob2xkID0gMCwgdGhpcy5iaXRzID0gMCwgdGhpcy5sZW5ndGggPSAwLCB0aGlzLm9mZnNldCA9IDAsIHRoaXMuZXh0cmEgPSAwLCB0aGlzLmxlbmNvZGUgPSBudWxsLCB0aGlzLmRpc3Rjb2RlID0gbnVsbCwgdGhpcy5sZW5iaXRzID0gMCwgdGhpcy5kaXN0Yml0cyA9IDAsIHRoaXMubmNvZGUgPSAwLCB0aGlzLm5sZW4gPSAwLCB0aGlzLm5kaXN0ID0gMCwgdGhpcy5oYXZlID0gMCwgdGhpcy5uZXh0ID0gbnVsbCwgdGhpcy5sZW5zID0gbmV3IFVpbnQxNkFycmF5KDMyMCksIHRoaXMud29yayA9IG5ldyBVaW50MTZBcnJheSgyODgpLCB0aGlzLmxlbmR5biA9IG51bGwsIHRoaXMuZGlzdGR5biA9IG51bGwsIHRoaXMuc2FuZSA9IDAsIHRoaXMuYmFjayA9IDAsIHRoaXMud2FzID0gMDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFogPSAoZTIpID0+IHsKICAgICAgICBpZiAoIWUyKSByZXR1cm4gMTsKICAgICAgICBsZXQgdDIgPSBlMi5zdGF0ZTsKICAgICAgICByZXR1cm4gKyghdDIgfHwgdDIuc3RybSAhPT0gZTIgfHwgdDIubW9kZSA8IEcgfHwgdDIubW9kZSA+IGR0KTsKICAgICAgfTsKICAgICAgZ3QgPSAoZTIpID0+IHsKICAgICAgICBpZiAoWihlMikpIHJldHVybiAtMjsKICAgICAgICBsZXQgdDIgPSBlMi5zdGF0ZTsKICAgICAgICByZXR1cm4gZTIudG90YWxfaW4gPSBlMi50b3RhbF9vdXQgPSB0Mi50b3RhbCA9IDAsIGUyLm1zZyA9IGBgLCB0Mi53cmFwICYmIChlMi5hZGxlciA9IHQyLndyYXAgJiAxKSwgdDIubW9kZSA9IEcsIHQyLmxhc3QgPSAwLCB0Mi5oYXZlZGljdCA9IDAsIHQyLmZsYWdzID0gLTEsIHQyLmRtYXggPSAzMjc2OCwgdDIuaGVhZCA9IG51bGwsIHQyLmhvbGQgPSAwLCB0Mi5iaXRzID0gMCwgdDIubGVuY29kZSA9IHQyLmxlbmR5biA9IG5ldyBJbnQzMkFycmF5KGZ0KSwgdDIuZGlzdGNvZGUgPSB0Mi5kaXN0ZHluID0gbmV3IEludDMyQXJyYXkocHQpLCB0Mi5zYW5lID0gMSwgdDIuYmFjayA9IC0xLCAwOwogICAgICB9OwogICAgICBfdCA9IChlMikgPT4gewogICAgICAgIGlmIChaKGUyKSkgcmV0dXJuIC0yOwogICAgICAgIGxldCB0MiA9IGUyLnN0YXRlOwogICAgICAgIHJldHVybiB0Mi53c2l6ZSA9IDAsIHQyLndoYXZlID0gMCwgdDIud25leHQgPSAwLCBndChlMik7CiAgICAgIH07CiAgICAgIHZ0ID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMjsKICAgICAgICBpZiAoWihlMikpIHJldHVybiAtMjsKICAgICAgICBsZXQgcjIgPSBlMi5zdGF0ZTsKICAgICAgICByZXR1cm4gdDIgPCAwID8gKG4yID0gMCwgdDIgPSAtdDIpIDogKG4yID0gKHQyID4+IDQpICsgNSwgdDIgPCA0OCAmJiAodDIgJj0gMTUpKSwgdDIgJiYgKHQyIDwgOCB8fCB0MiA+IDE1KSA/IC0yIDogKHIyLndpbmRvdyAhPT0gbnVsbCAmJiByMi53Yml0cyAhPT0gdDIgJiYgKHIyLndpbmRvdyA9IG51bGwpLCByMi53cmFwID0gbjIsIHIyLndiaXRzID0gdDIsIF90KGUyKSk7CiAgICAgIH07CiAgICAgIHl0ID0gKGUyLCB0MikgPT4gewogICAgICAgIGlmICghZTIpIHJldHVybiAtMjsKICAgICAgICBsZXQgbjIgPSBuZXcgaHQoKTsKICAgICAgICBlMi5zdGF0ZSA9IG4yLCBuMi5zdHJtID0gZTIsIG4yLndpbmRvdyA9IG51bGwsIG4yLm1vZGUgPSBHOwogICAgICAgIGxldCByMiA9IHZ0KGUyLCB0Mik7CiAgICAgICAgcmV0dXJuIHIyICE9PSAwICYmIChlMi5zdGF0ZSA9IG51bGwpLCByMjsKICAgICAgfTsKICAgICAgYnQgPSB0cnVlOwogICAgICBDdCA9IChlMikgPT4gewogICAgICAgIGlmIChidCkgewogICAgICAgICAgeHQgPSBuZXcgSW50MzJBcnJheSg1MTIpLCBTdCA9IG5ldyBJbnQzMkFycmF5KDMyKTsKICAgICAgICAgIGxldCB0MiA9IDA7CiAgICAgICAgICBmb3IgKDsgdDIgPCAxNDQ7ICkgZTIubGVuc1t0MisrXSA9IDg7CiAgICAgICAgICBmb3IgKDsgdDIgPCAyNTY7ICkgZTIubGVuc1t0MisrXSA9IDk7CiAgICAgICAgICBmb3IgKDsgdDIgPCAyODA7ICkgZTIubGVuc1t0MisrXSA9IDc7CiAgICAgICAgICBmb3IgKDsgdDIgPCAyODg7ICkgZTIubGVuc1t0MisrXSA9IDg7CiAgICAgICAgICBmb3IgKFcoUmUsIGUyLmxlbnMsIDAsIDI4OCwgeHQsIDAsIGUyLndvcmssIHsgYml0czogOSB9KSwgdDIgPSAwOyB0MiA8IDMyOyApIGUyLmxlbnNbdDIrK10gPSA1OwogICAgICAgICAgVyh6ZSwgZTIubGVucywgMCwgMzIsIFN0LCAwLCBlMi53b3JrLCB7IGJpdHM6IDUgfSksIGJ0ID0gZmFsc2U7CiAgICAgICAgfQogICAgICAgIGUyLmxlbmNvZGUgPSB4dCwgZTIubGVuYml0cyA9IDksIGUyLmRpc3Rjb2RlID0gU3QsIGUyLmRpc3RiaXRzID0gNTsKICAgICAgfTsKICAgICAgd3QgPSAoZTIsIHQyLCBuMiwgcjIpID0+IHsKICAgICAgICBsZXQgaTIsIGE0ID0gZTIuc3RhdGU7CiAgICAgICAgcmV0dXJuIGE0LndpbmRvdyA9PT0gbnVsbCAmJiAoYTQud2luZG93ID0gbmV3IFVpbnQ4QXJyYXkoMSA8PCBhNC53Yml0cykpLCBhNC53c2l6ZSA9PT0gMCAmJiAoYTQud3NpemUgPSAxIDw8IGE0LndiaXRzLCBhNC53bmV4dCA9IDAsIGE0LndoYXZlID0gMCksIHIyID49IGE0LndzaXplID8gKGE0LndpbmRvdy5zZXQodDIuc3ViYXJyYXkobjIgLSBhNC53c2l6ZSwgbjIpLCAwKSwgYTQud25leHQgPSAwLCBhNC53aGF2ZSA9IGE0LndzaXplKSA6IChpMiA9IGE0LndzaXplIC0gYTQud25leHQsIGkyID4gcjIgJiYgKGkyID0gcjIpLCBhNC53aW5kb3cuc2V0KHQyLnN1YmFycmF5KG4yIC0gcjIsIG4yIC0gcjIgKyBpMiksIGE0LnduZXh0KSwgcjIgLT0gaTIsIHIyID8gKGE0LndpbmRvdy5zZXQodDIuc3ViYXJyYXkobjIgLSByMiwgbjIpLCAwKSwgYTQud25leHQgPSByMiwgYTQud2hhdmUgPSBhNC53c2l6ZSkgOiAoYTQud25leHQgKz0gaTIsIGE0LnduZXh0ID09PSBhNC53c2l6ZSAmJiAoYTQud25leHQgPSAwKSwgYTQud2hhdmUgPCBhNC53c2l6ZSAmJiAoYTQud2hhdmUgKz0gaTIpKSksIDA7CiAgICAgIH07CiAgICAgIFR0ID0gKGUyLCB0MikgPT4gewogICAgICAgIGxldCBuMiwgcjIsIGkyLCBhNCwgbzIsIHMyLCBjMiwgbDIsIHU0LCBkMiwgZjIsIHAyLCBtMiwgaDIsIGcyID0gMCwgXzIsIHY0LCB5MiwgYjIsIHgyLCBTMiwgQzIsIHcyLCBUMiA9IG5ldyBVaW50OEFycmF5KDQpLCBFMiwgRDIsIE8yID0gbmV3IFVpbnQ4QXJyYXkoWzE2LCAxNywgMTgsIDAsIDgsIDcsIDksIDYsIDEwLCA1LCAxMSwgNCwgMTIsIDMsIDEzLCAyLCAxNCwgMSwgMTVdKTsKICAgICAgICBpZiAoWihlMikgfHwgIWUyLm91dHB1dCB8fCAhZTIuaW5wdXQgJiYgZTIuYXZhaWxfaW4gIT09IDApIHJldHVybiAtMjsKICAgICAgICBuMiA9IGUyLnN0YXRlLCBuMi5tb2RlID09PSBxICYmIChuMi5tb2RlID0gWWUpLCBvMiA9IGUyLm5leHRfb3V0LCBpMiA9IGUyLm91dHB1dCwgYzIgPSBlMi5hdmFpbF9vdXQsIGE0ID0gZTIubmV4dF9pbiwgcjIgPSBlMi5pbnB1dCwgczIgPSBlMi5hdmFpbF9pbiwgbDIgPSBuMi5ob2xkLCB1NCA9IG4yLmJpdHMsIGQyID0gczIsIGYyID0gYzIsIHcyID0gMDsKICAgICAgICBpbmZfbGVhdmU6IGZvciAoOyA7ICkgc3dpdGNoIChuMi5tb2RlKSB7CiAgICAgICAgICBjYXNlIEc6CiAgICAgICAgICAgIGlmIChuMi53cmFwID09PSAwKSB7CiAgICAgICAgICAgICAgbjIubW9kZSA9IFllOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZvciAoOyB1NCA8IDE2OyApIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobjIud3JhcCAmIDIgJiYgbDIgPT09IDM1NjE1KSB7CiAgICAgICAgICAgICAgbjIud2JpdHMgPT09IDAgJiYgKG4yLndiaXRzID0gMTUpLCBuMi5jaGVjayA9IDAsIFQyWzBdID0gbDIgJiAyNTUsIFQyWzFdID0gbDIgPj4+IDggJiAyNTUsIG4yLmNoZWNrID0gTihuMi5jaGVjaywgVDIsIDIsIDApLCBsMiA9IDAsIHU0ID0gMCwgbjIubW9kZSA9IEJlOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuMi5oZWFkICYmIChuMi5oZWFkLmRvbmUgPSBmYWxzZSksICEobjIud3JhcCAmIDEpIHx8ICgoKGwyICYgMjU1KSA8PCA4KSArIChsMiA+PiA4KSkgJSAzMSkgewogICAgICAgICAgICAgIGUyLm1zZyA9IGBpbmNvcnJlY3QgaGVhZGVyIGNoZWNrYCwgbjIubW9kZSA9IFg7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKChsMiAmIDE1KSAhPSA4KSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kYCwgbjIubW9kZSA9IFg7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGwyID4+Pj0gNCwgdTQgLT0gNCwgQzIgPSAobDIgJiAxNSkgKyA4LCBuMi53Yml0cyA9PT0gMCAmJiAobjIud2JpdHMgPSBDMiksIEMyID4gMTUgfHwgQzIgPiBuMi53Yml0cykgewogICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIHdpbmRvdyBzaXplYCwgbjIubW9kZSA9IFg7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbjIuZG1heCA9IDEgPDwgbjIud2JpdHMsIG4yLmZsYWdzID0gMCwgZTIuYWRsZXIgPSBuMi5jaGVjayA9IDEsIG4yLm1vZGUgPSBsMiAmIDUxMiA/IEplIDogcSwgbDIgPSAwLCB1NCA9IDA7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBCZToKICAgICAgICAgICAgZm9yICg7IHU0IDwgMTY7ICkgewogICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgIHMyLS0sIGwyICs9IHIyW2E0KytdIDw8IHU0LCB1NCArPSA4OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuMi5mbGFncyA9IGwyLCAobjIuZmxhZ3MgJiAyNTUpICE9IDgpIHsKICAgICAgICAgICAgICBlMi5tc2cgPSBgdW5rbm93biBjb21wcmVzc2lvbiBtZXRob2RgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobjIuZmxhZ3MgJiA1NzM0NCkgewogICAgICAgICAgICAgIGUyLm1zZyA9IGB1bmtub3duIGhlYWRlciBmbGFncyBzZXRgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBuMi5oZWFkICYmIChuMi5oZWFkLnRleHQgPSBsMiA+PiA4ICYgMSksIG4yLmZsYWdzICYgNTEyICYmIG4yLndyYXAgJiA0ICYmIChUMlswXSA9IGwyICYgMjU1LCBUMlsxXSA9IGwyID4+PiA4ICYgMjU1LCBuMi5jaGVjayA9IE4objIuY2hlY2ssIFQyLCAyLCAwKSksIGwyID0gMCwgdTQgPSAwLCBuMi5tb2RlID0gVmU7CiAgICAgICAgICBjYXNlIFZlOgogICAgICAgICAgICBmb3IgKDsgdTQgPCAzMjsgKSB7CiAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbjIuaGVhZCAmJiAobjIuaGVhZC50aW1lID0gbDIpLCBuMi5mbGFncyAmIDUxMiAmJiBuMi53cmFwICYgNCAmJiAoVDJbMF0gPSBsMiAmIDI1NSwgVDJbMV0gPSBsMiA+Pj4gOCAmIDI1NSwgVDJbMl0gPSBsMiA+Pj4gMTYgJiAyNTUsIFQyWzNdID0gbDIgPj4+IDI0ICYgMjU1LCBuMi5jaGVjayA9IE4objIuY2hlY2ssIFQyLCA0LCAwKSksIGwyID0gMCwgdTQgPSAwLCBuMi5tb2RlID0gSGU7CiAgICAgICAgICBjYXNlIEhlOgogICAgICAgICAgICBmb3IgKDsgdTQgPCAxNjsgKSB7CiAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbjIuaGVhZCAmJiAobjIuaGVhZC54ZmxhZ3MgPSBsMiAmIDI1NSwgbjIuaGVhZC5vcyA9IGwyID4+IDgpLCBuMi5mbGFncyAmIDUxMiAmJiBuMi53cmFwICYgNCAmJiAoVDJbMF0gPSBsMiAmIDI1NSwgVDJbMV0gPSBsMiA+Pj4gOCAmIDI1NSwgbjIuY2hlY2sgPSBOKG4yLmNoZWNrLCBUMiwgMiwgMCkpLCBsMiA9IDAsIHU0ID0gMCwgbjIubW9kZSA9IFVlOwogICAgICAgICAgY2FzZSBVZToKICAgICAgICAgICAgaWYgKG4yLmZsYWdzICYgMTAyNCkgewogICAgICAgICAgICAgIGZvciAoOyB1NCA8IDE2OyApIHsKICAgICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIG4yLmxlbmd0aCA9IGwyLCBuMi5oZWFkICYmIChuMi5oZWFkLmV4dHJhX2xlbiA9IGwyKSwgbjIuZmxhZ3MgJiA1MTIgJiYgbjIud3JhcCAmIDQgJiYgKFQyWzBdID0gbDIgJiAyNTUsIFQyWzFdID0gbDIgPj4+IDggJiAyNTUsIG4yLmNoZWNrID0gTihuMi5jaGVjaywgVDIsIDIsIDApKSwgbDIgPSAwLCB1NCA9IDA7CiAgICAgICAgICAgIH0gZWxzZSBuMi5oZWFkICYmIChuMi5oZWFkLmV4dHJhID0gbnVsbCk7CiAgICAgICAgICAgIG4yLm1vZGUgPSBXZTsKICAgICAgICAgIGNhc2UgV2U6CiAgICAgICAgICAgIGlmIChuMi5mbGFncyAmIDEwMjQgJiYgKHAyID0gbjIubGVuZ3RoLCBwMiA+IHMyICYmIChwMiA9IHMyKSwgcDIgJiYgKG4yLmhlYWQgJiYgKEMyID0gbjIuaGVhZC5leHRyYV9sZW4gLSBuMi5sZW5ndGgsIG4yLmhlYWQuZXh0cmEgfHwgKG4yLmhlYWQuZXh0cmEgPSBuZXcgVWludDhBcnJheShuMi5oZWFkLmV4dHJhX2xlbikpLCBuMi5oZWFkLmV4dHJhLnNldChyMi5zdWJhcnJheShhNCwgYTQgKyBwMiksIEMyKSksIG4yLmZsYWdzICYgNTEyICYmIG4yLndyYXAgJiA0ICYmIChuMi5jaGVjayA9IE4objIuY2hlY2ssIHIyLCBwMiwgYTQpKSwgczIgLT0gcDIsIGE0ICs9IHAyLCBuMi5sZW5ndGggLT0gcDIpLCBuMi5sZW5ndGgpKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgIG4yLmxlbmd0aCA9IDAsIG4yLm1vZGUgPSBHZTsKICAgICAgICAgIGNhc2UgR2U6CiAgICAgICAgICAgIGlmIChuMi5mbGFncyAmIDIwNDgpIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBwMiA9IDA7CiAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgIEMyID0gcjJbYTQgKyBwMisrXSwgbjIuaGVhZCAmJiBDMiAmJiBuMi5sZW5ndGggPCA2NTUzNiAmJiAobjIuaGVhZC5uYW1lICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoQzIpKTsKICAgICAgICAgICAgICB3aGlsZSAoQzIgJiYgcDIgPCBzMik7CiAgICAgICAgICAgICAgaWYgKG4yLmZsYWdzICYgNTEyICYmIG4yLndyYXAgJiA0ICYmIChuMi5jaGVjayA9IE4objIuY2hlY2ssIHIyLCBwMiwgYTQpKSwgczIgLT0gcDIsIGE0ICs9IHAyLCBDMikgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICB9IGVsc2UgbjIuaGVhZCAmJiAobjIuaGVhZC5uYW1lID0gbnVsbCk7CiAgICAgICAgICAgIG4yLmxlbmd0aCA9IDAsIG4yLm1vZGUgPSBLZTsKICAgICAgICAgIGNhc2UgS2U6CiAgICAgICAgICAgIGlmIChuMi5mbGFncyAmIDQwOTYpIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBwMiA9IDA7CiAgICAgICAgICAgICAgZG8KICAgICAgICAgICAgICAgIEMyID0gcjJbYTQgKyBwMisrXSwgbjIuaGVhZCAmJiBDMiAmJiBuMi5sZW5ndGggPCA2NTUzNiAmJiAobjIuaGVhZC5jb21tZW50ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoQzIpKTsKICAgICAgICAgICAgICB3aGlsZSAoQzIgJiYgcDIgPCBzMik7CiAgICAgICAgICAgICAgaWYgKG4yLmZsYWdzICYgNTEyICYmIG4yLndyYXAgJiA0ICYmIChuMi5jaGVjayA9IE4objIuY2hlY2ssIHIyLCBwMiwgYTQpKSwgczIgLT0gcDIsIGE0ICs9IHAyLCBDMikgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICB9IGVsc2UgbjIuaGVhZCAmJiAobjIuaGVhZC5jb21tZW50ID0gbnVsbCk7CiAgICAgICAgICAgIG4yLm1vZGUgPSBxZTsKICAgICAgICAgIGNhc2UgcWU6CiAgICAgICAgICAgIGlmIChuMi5mbGFncyAmIDUxMikgewogICAgICAgICAgICAgIGZvciAoOyB1NCA8IDE2OyApIHsKICAgICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChuMi53cmFwICYgNCAmJiBsMiAhPT0gKG4yLmNoZWNrICYgNjU1MzUpKSB7CiAgICAgICAgICAgICAgICBlMi5tc2cgPSBgaGVhZGVyIGNyYyBtaXNtYXRjaGAsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGwyID0gMCwgdTQgPSAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLmhlYWQgJiYgKG4yLmhlYWQuaGNyYyA9IG4yLmZsYWdzID4+IDkgJiAxLCBuMi5oZWFkLmRvbmUgPSB0cnVlKSwgZTIuYWRsZXIgPSBuMi5jaGVjayA9IDAsIG4yLm1vZGUgPSBxOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgSmU6CiAgICAgICAgICAgIGZvciAoOyB1NCA8IDMyOyApIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgfQogICAgICAgICAgICBlMi5hZGxlciA9IG4yLmNoZWNrID0gbXQobDIpLCBsMiA9IDAsIHU0ID0gMCwgbjIubW9kZSA9IEs7CiAgICAgICAgICBjYXNlIEs6CiAgICAgICAgICAgIGlmIChuMi5oYXZlZGljdCA9PT0gMCkgcmV0dXJuIGUyLm5leHRfb3V0ID0gbzIsIGUyLmF2YWlsX291dCA9IGMyLCBlMi5uZXh0X2luID0gYTQsIGUyLmF2YWlsX2luID0gczIsIG4yLmhvbGQgPSBsMiwgbjIuYml0cyA9IHU0LCAyOwogICAgICAgICAgICBlMi5hZGxlciA9IG4yLmNoZWNrID0gMSwgbjIubW9kZSA9IHE7CiAgICAgICAgICBjYXNlIHE6CiAgICAgICAgICAgIGlmICh0MiA9PT0gNSB8fCB0MiA9PT0gNikgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgY2FzZSBZZToKICAgICAgICAgICAgaWYgKG4yLmxhc3QpIHsKICAgICAgICAgICAgICBsMiA+Pj49IHU0ICYgNywgdTQgLT0gdTQgJiA3LCBuMi5tb2RlID0gc3Q7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZm9yICg7IHU0IDwgMzsgKSB7CiAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc3dpdGNoIChuMi5sYXN0ID0gbDIgJiAxLCBsMiA+Pj49IDEsIC0tdTQsIGwyICYgMykgewogICAgICAgICAgICAgIGNhc2UgMDoKICAgICAgICAgICAgICAgIG4yLm1vZGUgPSBYZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgIGlmIChDdChuMiksIG4yLm1vZGUgPSBKLCB0MiA9PT0gNikgewogICAgICAgICAgICAgICAgICBsMiA+Pj49IDIsIHU0IC09IDI7CiAgICAgICAgICAgICAgICAgIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgIG4yLm1vZGUgPSAkZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgIGNhc2UgMzoKICAgICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIGJsb2NrIHR5cGVgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgfQogICAgICAgICAgICBsMiA+Pj49IDIsIHU0IC09IDI7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBYZToKICAgICAgICAgICAgZm9yIChsMiA+Pj49IHU0ICYgNywgdTQgLT0gdTQgJiA3OyB1NCA8IDMyOyApIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoKGwyICYgNjU1MzUpICE9IChsMiA+Pj4gMTYgXiA2NTUzNSkpIHsKICAgICAgICAgICAgICBlMi5tc2cgPSBgaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3Roc2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuMi5sZW5ndGggPSBsMiAmIDY1NTM1LCBsMiA9IDAsIHU0ID0gMCwgbjIubW9kZSA9IFplLCB0MiA9PT0gNikgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgY2FzZSBaZToKICAgICAgICAgICAgbjIubW9kZSA9IFFlOwogICAgICAgICAgY2FzZSBRZToKICAgICAgICAgICAgaWYgKHAyID0gbjIubGVuZ3RoLCBwMikgewogICAgICAgICAgICAgIGlmIChwMiA+IHMyICYmIChwMiA9IHMyKSwgcDIgPiBjMiAmJiAocDIgPSBjMiksIHAyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgaTIuc2V0KHIyLnN1YmFycmF5KGE0LCBhNCArIHAyKSwgbzIpLCBzMiAtPSBwMiwgYTQgKz0gcDIsIGMyIC09IHAyLCBvMiArPSBwMiwgbjIubGVuZ3RoIC09IHAyOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLm1vZGUgPSBxOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgJGU6CiAgICAgICAgICAgIGZvciAoOyB1NCA8IDE0OyApIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobjIubmxlbiA9IChsMiAmIDMxKSArIDI1NywgbDIgPj4+PSA1LCB1NCAtPSA1LCBuMi5uZGlzdCA9IChsMiAmIDMxKSArIDEsIGwyID4+Pj0gNSwgdTQgLT0gNSwgbjIubmNvZGUgPSAobDIgJiAxNSkgKyA0LCBsMiA+Pj49IDQsIHU0IC09IDQsIG4yLm5sZW4gPiAyODYgfHwgbjIubmRpc3QgPiAzMCkgewogICAgICAgICAgICAgIGUyLm1zZyA9IGB0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9sc2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLmhhdmUgPSAwLCBuMi5tb2RlID0gZXQ7CiAgICAgICAgICBjYXNlIGV0OgogICAgICAgICAgICBmb3IgKDsgbjIuaGF2ZSA8IG4yLm5jb2RlOyApIHsKICAgICAgICAgICAgICBmb3IgKDsgdTQgPCAzOyApIHsKICAgICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIG4yLmxlbnNbTzJbbjIuaGF2ZSsrXV0gPSBsMiAmIDcsIGwyID4+Pj0gMywgdTQgLT0gMzsKICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKDsgbjIuaGF2ZSA8IDE5OyApIG4yLmxlbnNbTzJbbjIuaGF2ZSsrXV0gPSAwOwogICAgICAgICAgICBpZiAobjIubGVuY29kZSA9IG4yLmxlbmR5biwgbjIubGVuYml0cyA9IDcsIEUyID0geyBiaXRzOiBuMi5sZW5iaXRzIH0sIHcyID0gVyhMZSwgbjIubGVucywgMCwgMTksIG4yLmxlbmNvZGUsIDAsIG4yLndvcmssIEUyKSwgbjIubGVuYml0cyA9IEUyLmJpdHMsIHcyKSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgY29kZSBsZW5ndGhzIHNldGAsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLmhhdmUgPSAwLCBuMi5tb2RlID0gdHQ7CiAgICAgICAgICBjYXNlIHR0OgogICAgICAgICAgICBmb3IgKDsgbjIuaGF2ZSA8IG4yLm5sZW4gKyBuMi5uZGlzdDsgKSB7CiAgICAgICAgICAgICAgZm9yICg7IGcyID0gbjIubGVuY29kZVtsMiAmICgxIDw8IG4yLmxlbmJpdHMpIC0gMV0sIF8yID0gZzIgPj4+IDI0LCB2NCA9IGcyID4+PiAxNiAmIDI1NSwgeTIgPSBnMiAmIDY1NTM1LCAhKF8yIDw9IHU0KTsgKSB7CiAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgIHMyLS0sIGwyICs9IHIyW2E0KytdIDw8IHU0LCB1NCArPSA4OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAoeTIgPCAxNikgbDIgPj4+PSBfMiwgdTQgLT0gXzIsIG4yLmxlbnNbbjIuaGF2ZSsrXSA9IHkyOwogICAgICAgICAgICAgIGVsc2UgewogICAgICAgICAgICAgICAgaWYgKHkyID09PSAxNikgewogICAgICAgICAgICAgICAgICBmb3IgKEQyID0gXzIgKyAyOyB1NCA8IEQyOyApIHsKICAgICAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBpZiAobDIgPj4+PSBfMiwgdTQgLT0gXzIsIG4yLmhhdmUgPT09IDApIHsKICAgICAgICAgICAgICAgICAgICBlMi5tc2cgPSBgaW52YWxpZCBiaXQgbGVuZ3RoIHJlcGVhdGAsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIEMyID0gbjIubGVuc1tuMi5oYXZlIC0gMV0sIHAyID0gMyArIChsMiAmIDMpLCBsMiA+Pj49IDIsIHU0IC09IDI7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHkyID09PSAxNykgewogICAgICAgICAgICAgICAgICBmb3IgKEQyID0gXzIgKyAzOyB1NCA8IEQyOyApIHsKICAgICAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBsMiA+Pj49IF8yLCB1NCAtPSBfMiwgQzIgPSAwLCBwMiA9IDMgKyAobDIgJiA3KSwgbDIgPj4+PSAzLCB1NCAtPSAzOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgZm9yIChEMiA9IF8yICsgNzsgdTQgPCBEMjsgKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgbDIgPj4+PSBfMiwgdTQgLT0gXzIsIEMyID0gMCwgcDIgPSAxMSArIChsMiAmIDEyNyksIGwyID4+Pj0gNywgdTQgLT0gNzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChuMi5oYXZlICsgcDIgPiBuMi5ubGVuICsgbjIubmRpc3QpIHsKICAgICAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgYml0IGxlbmd0aCByZXBlYXRgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBmb3IgKDsgcDItLTsgKSBuMi5sZW5zW24yLmhhdmUrK10gPSBDMjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKG4yLm1vZGUgPT09IFgpIGJyZWFrOwogICAgICAgICAgICBpZiAobjIubGVuc1syNTZdID09PSAwKSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgY29kZSAtLSBtaXNzaW5nIGVuZC1vZi1ibG9ja2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuMi5sZW5iaXRzID0gOSwgRTIgPSB7IGJpdHM6IG4yLmxlbmJpdHMgfSwgdzIgPSBXKFJlLCBuMi5sZW5zLCAwLCBuMi5ubGVuLCBuMi5sZW5jb2RlLCAwLCBuMi53b3JrLCBFMiksIG4yLmxlbmJpdHMgPSBFMi5iaXRzLCB3MikgewogICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RocyBzZXRgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobjIuZGlzdGJpdHMgPSA2LCBuMi5kaXN0Y29kZSA9IG4yLmRpc3RkeW4sIEUyID0geyBiaXRzOiBuMi5kaXN0Yml0cyB9LCB3MiA9IFcoemUsIG4yLmxlbnMsIG4yLm5sZW4sIG4yLm5kaXN0LCBuMi5kaXN0Y29kZSwgMCwgbjIud29yaywgRTIpLCBuMi5kaXN0Yml0cyA9IEUyLmJpdHMsIHcyKSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgZGlzdGFuY2VzIHNldGAsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChuMi5tb2RlID0gSiwgdDIgPT09IDYpIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgIGNhc2UgSjoKICAgICAgICAgICAgbjIubW9kZSA9IFk7CiAgICAgICAgICBjYXNlIFk6CiAgICAgICAgICAgIGlmIChzMiA+PSA2ICYmIGMyID49IDI1OCkgewogICAgICAgICAgICAgIGUyLm5leHRfb3V0ID0gbzIsIGUyLmF2YWlsX291dCA9IGMyLCBlMi5uZXh0X2luID0gYTQsIGUyLmF2YWlsX2luID0gczIsIG4yLmhvbGQgPSBsMiwgbjIuYml0cyA9IHU0LCBPZShlMiwgZjIpLCBvMiA9IGUyLm5leHRfb3V0LCBpMiA9IGUyLm91dHB1dCwgYzIgPSBlMi5hdmFpbF9vdXQsIGE0ID0gZTIubmV4dF9pbiwgcjIgPSBlMi5pbnB1dCwgczIgPSBlMi5hdmFpbF9pbiwgbDIgPSBuMi5ob2xkLCB1NCA9IG4yLmJpdHMsIG4yLm1vZGUgPT09IHEgJiYgKG4yLmJhY2sgPSAtMSk7CiAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZm9yIChuMi5iYWNrID0gMDsgZzIgPSBuMi5sZW5jb2RlW2wyICYgKDEgPDwgbjIubGVuYml0cykgLSAxXSwgXzIgPSBnMiA+Pj4gMjQsIHY0ID0gZzIgPj4+IDE2ICYgMjU1LCB5MiA9IGcyICYgNjU1MzUsICEoXzIgPD0gdTQpOyApIHsKICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodjQgJiYgISh2NCAmIDI0MCkpIHsKICAgICAgICAgICAgICBmb3IgKGIyID0gXzIsIHgyID0gdjQsIFMyID0geTI7IGcyID0gbjIubGVuY29kZVtTMiArICgobDIgJiAoMSA8PCBiMiArIHgyKSAtIDEpID4+IGIyKV0sIF8yID0gZzIgPj4+IDI0LCB2NCA9IGcyID4+PiAxNiAmIDI1NSwgeTIgPSBnMiAmIDY1NTM1LCAhKGIyICsgXzIgPD0gdTQpOyApIHsKICAgICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGwyID4+Pj0gYjIsIHU0IC09IGIyLCBuMi5iYWNrICs9IGIyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChsMiA+Pj49IF8yLCB1NCAtPSBfMiwgbjIuYmFjayArPSBfMiwgbjIubGVuZ3RoID0geTIsIHY0ID09PSAwKSB7CiAgICAgICAgICAgICAgbjIubW9kZSA9IG90OwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2NCAmIDMyKSB7CiAgICAgICAgICAgICAgbjIuYmFjayA9IC0xLCBuMi5tb2RlID0gcTsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodjQgJiA2NCkgewogICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGVgLCBuMi5tb2RlID0gWDsKICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgICAgICBuMi5leHRyYSA9IHY0ICYgMTUsIG4yLm1vZGUgPSBudDsKICAgICAgICAgIGNhc2UgbnQ6CiAgICAgICAgICAgIGlmIChuMi5leHRyYSkgewogICAgICAgICAgICAgIGZvciAoRDIgPSBuMi5leHRyYTsgdTQgPCBEMjsgKSB7CiAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgIHMyLS0sIGwyICs9IHIyW2E0KytdIDw8IHU0LCB1NCArPSA4OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBuMi5sZW5ndGggKz0gbDIgJiAoMSA8PCBuMi5leHRyYSkgLSAxLCBsMiA+Pj49IG4yLmV4dHJhLCB1NCAtPSBuMi5leHRyYSwgbjIuYmFjayArPSBuMi5leHRyYTsKICAgICAgICAgICAgfQogICAgICAgICAgICBuMi53YXMgPSBuMi5sZW5ndGgsIG4yLm1vZGUgPSBydDsKICAgICAgICAgIGNhc2UgcnQ6CiAgICAgICAgICAgIGZvciAoOyBnMiA9IG4yLmRpc3Rjb2RlW2wyICYgKDEgPDwgbjIuZGlzdGJpdHMpIC0gMV0sIF8yID0gZzIgPj4+IDI0LCB2NCA9IGcyID4+PiAxNiAmIDI1NSwgeTIgPSBnMiAmIDY1NTM1LCAhKF8yIDw9IHU0KTsgKSB7CiAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgczItLSwgbDIgKz0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCEodjQgJiAyNDApKSB7CiAgICAgICAgICAgICAgZm9yIChiMiA9IF8yLCB4MiA9IHY0LCBTMiA9IHkyOyBnMiA9IG4yLmRpc3Rjb2RlW1MyICsgKChsMiAmICgxIDw8IGIyICsgeDIpIC0gMSkgPj4gYjIpXSwgXzIgPSBnMiA+Pj4gMjQsIHY0ID0gZzIgPj4+IDE2ICYgMjU1LCB5MiA9IGcyICYgNjU1MzUsICEoYjIgKyBfMiA8PSB1NCk7ICkgewogICAgICAgICAgICAgICAgaWYgKHMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgICAgICBzMi0tLCBsMiArPSByMlthNCsrXSA8PCB1NCwgdTQgKz0gODsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgbDIgPj4+PSBiMiwgdTQgLT0gYjIsIG4yLmJhY2sgKz0gYjI7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGwyID4+Pj0gXzIsIHU0IC09IF8yLCBuMi5iYWNrICs9IF8yLCB2NCAmIDY0KSB7CiAgICAgICAgICAgICAgZTIubXNnID0gYGludmFsaWQgZGlzdGFuY2UgY29kZWAsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLm9mZnNldCA9IHkyLCBuMi5leHRyYSA9IHY0ICYgMTUsIG4yLm1vZGUgPSBpdDsKICAgICAgICAgIGNhc2UgaXQ6CiAgICAgICAgICAgIGlmIChuMi5leHRyYSkgewogICAgICAgICAgICAgIGZvciAoRDIgPSBuMi5leHRyYTsgdTQgPCBEMjsgKSB7CiAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgIHMyLS0sIGwyICs9IHIyW2E0KytdIDw8IHU0LCB1NCArPSA4OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBuMi5vZmZzZXQgKz0gbDIgJiAoMSA8PCBuMi5leHRyYSkgLSAxLCBsMiA+Pj49IG4yLmV4dHJhLCB1NCAtPSBuMi5leHRyYSwgbjIuYmFjayArPSBuMi5leHRyYTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobjIub2Zmc2V0ID4gbjIuZG1heCkgewogICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFja2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLm1vZGUgPSBhdDsKICAgICAgICAgIGNhc2UgYXQ6CiAgICAgICAgICAgIGlmIChjMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICBpZiAocDIgPSBmMiAtIGMyLCBuMi5vZmZzZXQgPiBwMikgewogICAgICAgICAgICAgIGlmIChwMiA9IG4yLm9mZnNldCAtIHAyLCBwMiA+IG4yLndoYXZlICYmIG4yLnNhbmUpIHsKICAgICAgICAgICAgICAgIGUyLm1zZyA9IGBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFja2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHAyID4gbjIud25leHQgPyAocDIgLT0gbjIud25leHQsIG0yID0gbjIud3NpemUgLSBwMikgOiBtMiA9IG4yLnduZXh0IC0gcDIsIHAyID4gbjIubGVuZ3RoICYmIChwMiA9IG4yLmxlbmd0aCksIGgyID0gbjIud2luZG93OwogICAgICAgICAgICB9IGVsc2UgaDIgPSBpMiwgbTIgPSBvMiAtIG4yLm9mZnNldCwgcDIgPSBuMi5sZW5ndGg7CiAgICAgICAgICAgIHAyID4gYzIgJiYgKHAyID0gYzIpLCBjMiAtPSBwMiwgbjIubGVuZ3RoIC09IHAyOwogICAgICAgICAgICBkbwogICAgICAgICAgICAgIGkyW28yKytdID0gaDJbbTIrK107CiAgICAgICAgICAgIHdoaWxlICgtLXAyKTsKICAgICAgICAgICAgbjIubGVuZ3RoID09PSAwICYmIChuMi5tb2RlID0gWSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBvdDoKICAgICAgICAgICAgaWYgKGMyID09PSAwKSBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICAgIGkyW28yKytdID0gbjIubGVuZ3RoLCBjMi0tLCBuMi5tb2RlID0gWTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIHN0OgogICAgICAgICAgICBpZiAobjIud3JhcCkgewogICAgICAgICAgICAgIGZvciAoOyB1NCA8IDMyOyApIHsKICAgICAgICAgICAgICAgIGlmIChzMiA9PT0gMCkgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgICAgICAgczItLSwgbDIgfD0gcjJbYTQrK10gPDwgdTQsIHU0ICs9IDg7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChmMiAtPSBjMiwgZTIudG90YWxfb3V0ICs9IGYyLCBuMi50b3RhbCArPSBmMiwgbjIud3JhcCAmIDQgJiYgZjIgJiYgKGUyLmFkbGVyID0gbjIuY2hlY2sgPSBuMi5mbGFncyA/IE4objIuY2hlY2ssIGkyLCBmMiwgbzIgLSBmMikgOiBNKG4yLmNoZWNrLCBpMiwgZjIsIG8yIC0gZjIpKSwgZjIgPSBjMiwgbjIud3JhcCAmIDQgJiYgKG4yLmZsYWdzID8gbDIgOiBtdChsMikpICE9PSBuMi5jaGVjaykgewogICAgICAgICAgICAgICAgZTIubXNnID0gYGluY29ycmVjdCBkYXRhIGNoZWNrYCwgbjIubW9kZSA9IFg7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgbDIgPSAwLCB1NCA9IDA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgbjIubW9kZSA9IGN0OwogICAgICAgICAgY2FzZSBjdDoKICAgICAgICAgICAgaWYgKG4yLndyYXAgJiYgbjIuZmxhZ3MpIHsKICAgICAgICAgICAgICBmb3IgKDsgdTQgPCAzMjsgKSB7CiAgICAgICAgICAgICAgICBpZiAoczIgPT09IDApIGJyZWFrIGluZl9sZWF2ZTsKICAgICAgICAgICAgICAgIHMyLS0sIGwyICs9IHIyW2E0KytdIDw8IHU0LCB1NCArPSA4OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAobjIud3JhcCAmIDQgJiYgbDIgIT09IChuMi50b3RhbCAmIDQyOTQ5NjcyOTUpKSB7CiAgICAgICAgICAgICAgICBlMi5tc2cgPSBgaW5jb3JyZWN0IGxlbmd0aCBjaGVja2AsIG4yLm1vZGUgPSBYOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGwyID0gMCwgdTQgPSAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIG4yLm1vZGUgPSBsdDsKICAgICAgICAgIGNhc2UgbHQ6CiAgICAgICAgICAgIHcyID0gMTsKICAgICAgICAgICAgYnJlYWsgaW5mX2xlYXZlOwogICAgICAgICAgY2FzZSBYOgogICAgICAgICAgICB3MiA9IC0zOwogICAgICAgICAgICBicmVhayBpbmZfbGVhdmU7CiAgICAgICAgICBjYXNlIHV0OgogICAgICAgICAgICByZXR1cm4gLTQ7CiAgICAgICAgICBjYXNlIGR0OgogICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgcmV0dXJuIC0yOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZTIubmV4dF9vdXQgPSBvMiwgZTIuYXZhaWxfb3V0ID0gYzIsIGUyLm5leHRfaW4gPSBhNCwgZTIuYXZhaWxfaW4gPSBzMiwgbjIuaG9sZCA9IGwyLCBuMi5iaXRzID0gdTQsIChuMi53c2l6ZSB8fCBmMiAhPT0gZTIuYXZhaWxfb3V0ICYmIG4yLm1vZGUgPCBYICYmIChuMi5tb2RlIDwgc3QgfHwgdDIgIT09IDQpKSAmJiB3dChlMiwgZTIub3V0cHV0LCBlMi5uZXh0X291dCwgZjIgLSBlMi5hdmFpbF9vdXQpID8gKG4yLm1vZGUgPSB1dCwgLTQpIDogKGQyIC09IGUyLmF2YWlsX2luLCBmMiAtPSBlMi5hdmFpbF9vdXQsIGUyLnRvdGFsX2luICs9IGQyLCBlMi50b3RhbF9vdXQgKz0gZjIsIG4yLnRvdGFsICs9IGYyLCBuMi53cmFwICYgNCAmJiBmMiAmJiAoZTIuYWRsZXIgPSBuMi5jaGVjayA9IG4yLmZsYWdzID8gTihuMi5jaGVjaywgaTIsIGYyLCBlMi5uZXh0X291dCAtIGYyKSA6IE0objIuY2hlY2ssIGkyLCBmMiwgZTIubmV4dF9vdXQgLSBmMikpLCBlMi5kYXRhX3R5cGUgPSBuMi5iaXRzICsgKG4yLmxhc3QgPyA2NCA6IDApICsgKG4yLm1vZGUgPT09IHEgPyAxMjggOiAwKSArIChuMi5tb2RlID09PSBKIHx8IG4yLm1vZGUgPT09IFplID8gMjU2IDogMCksIChkMiA9PT0gMCAmJiBmMiA9PT0gMCB8fCB0MiA9PT0gNCkgJiYgdzIgPT09IDAgJiYgKHcyID0gLTUpLCB3Mik7CiAgICAgIH07CiAgICAgIEV0ID0gKGUyKSA9PiB7CiAgICAgICAgaWYgKFooZTIpKSByZXR1cm4gLTI7CiAgICAgICAgbGV0IHQyID0gZTIuc3RhdGU7CiAgICAgICAgcmV0dXJuIHQyLndpbmRvdyAmJiAodDIud2luZG93ID0gbnVsbCksIGUyLnN0YXRlID0gbnVsbCwgMDsKICAgICAgfTsKICAgICAgRHQgPSAoZTIsIHQyKSA9PiB7CiAgICAgICAgbGV0IG4yID0gdDIubGVuZ3RoLCByMiwgaTIsIGE0OwogICAgICAgIHJldHVybiBaKGUyKSB8fCAocjIgPSBlMi5zdGF0ZSwgcjIud3JhcCAhPT0gMCAmJiByMi5tb2RlICE9PSBLKSA/IC0yIDogcjIubW9kZSA9PT0gSyAmJiAoaTIgPSAxLCBpMiA9IE0oaTIsIHQyLCBuMiwgMCksIGkyICE9PSByMi5jaGVjaykgPyAtMyA6IChhNCA9IHd0KGUyLCB0MiwgbjIsIG4yKSwgYTQgPyAocjIubW9kZSA9IHV0LCAtNCkgOiAocjIuaGF2ZWRpY3QgPSAxLCAwKSk7CiAgICAgIH07CiAgICAgIE90ID0gY2xhc3MgewogICAgICAgIGNvbnN0cnVjdG9yKCkgewogICAgICAgICAgdGhpcy5pbnB1dCA9IG51bGwsIHRoaXMubmV4dF9pbiA9IDAsIHRoaXMuYXZhaWxfaW4gPSAwLCB0aGlzLnRvdGFsX2luID0gMCwgdGhpcy5vdXRwdXQgPSBudWxsLCB0aGlzLm5leHRfb3V0ID0gMCwgdGhpcy5hdmFpbF9vdXQgPSAwLCB0aGlzLnRvdGFsX291dCA9IDAsIHRoaXMubXNnID0gYGAsIHRoaXMuc3RhdGUgPSBudWxsLCB0aGlzLmRhdGFfdHlwZSA9IDIsIHRoaXMuYWRsZXIgPSAwOwogICAgICAgIH0KICAgICAgfTsKICAgICAga3QgPSAoZTIpID0+IHsKICAgICAgICBsZXQgdDIgPSBuZXcgVWludDhBcnJheShlMi5yZWR1Y2UoKGUzLCB0MykgPT4gZTMgKyB0My5sZW5ndGgsIDApKSwgbjIgPSAwOwogICAgICAgIGZvciAobGV0IHIyIG9mIGUyKSB0Mi5zZXQocjIsIG4yKSwgbjIgKz0gcjIubGVuZ3RoOwogICAgICAgIHJldHVybiB0MjsKICAgICAgfTsKICAgICAgUHQgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nOwogICAgICBGdCA9IHsgY2h1bmtTaXplOiAxMDI0ICogNjQsIHdpbmRvd0JpdHM6IDE1LCByYXc6IGZhbHNlLCBkaWN0aW9uYXJ5OiBuZXcgVWludDhBcnJheSgpIH07CiAgICAgIEl0ID0gY2xhc3MgewogICAgICAgIGNvbnN0cnVjdG9yKGUyID0ge30pIHsKICAgICAgICAgICQodGhpcywgYG9wdGlvbnNgLCB2b2lkIDApLCAkKHRoaXMsIGBlcnJgLCB2b2lkIDApLCAkKHRoaXMsIGBtc2dgLCB2b2lkIDApLCAkKHRoaXMsIGBlbmRlZGAsIHZvaWQgMCksICQodGhpcywgYHN0YXJ0ZWRgLCB2b2lkIDApLCAkKHRoaXMsIGBjaHVua3NgLCB2b2lkIDApLCAkKHRoaXMsIGBzdHJtYCwgdm9pZCAwKSwgJCh0aGlzLCBgcmVzdWx0YCwgdm9pZCAwKSwgdGhpcy5vcHRpb25zID0gT2JqZWN0LmFzc2lnbih7fSwgRnQsIGUyKTsKICAgICAgICAgIGxldCB0MiA9IHRoaXMub3B0aW9uczsKICAgICAgICAgIHQyLnJhdyAmJiB0Mi53aW5kb3dCaXRzID49IDAgJiYgdDIud2luZG93Qml0cyA8IDE2ICYmICh0Mi53aW5kb3dCaXRzID0gLXQyLndpbmRvd0JpdHMsIHQyLndpbmRvd0JpdHMgPT09IDAgJiYgKHQyLndpbmRvd0JpdHMgPSAtMTUpKSwgdDIud2luZG93Qml0cyA+PSAwICYmIHQyLndpbmRvd0JpdHMgPCAxNiAmJiAhZTIud2luZG93Qml0cyAmJiAodDIud2luZG93Qml0cyArPSAzMiksIHQyLndpbmRvd0JpdHMgPiAxNSAmJiB0Mi53aW5kb3dCaXRzIDwgNDggJiYgKHQyLndpbmRvd0JpdHMgJiAxNSB8fCAodDIud2luZG93Qml0cyB8PSAxNSkpLCB0aGlzLmVyciA9IDAsIHRoaXMubXNnID0gYGAsIHRoaXMuZW5kZWQgPSBmYWxzZSwgdGhpcy5zdGFydGVkID0gZmFsc2UsIHRoaXMuY2h1bmtzID0gW10sIHRoaXMucmVzdWx0ID0gbmV3IFVpbnQ4QXJyYXkoKSwgdGhpcy5zdHJtID0gbmV3IE90KCksIHRoaXMuc3RybS5hdmFpbF9vdXQgPSAwOwogICAgICAgICAgbGV0IG4yID0geXQodGhpcy5zdHJtLCB0Mi53aW5kb3dCaXRzKTsKICAgICAgICAgIGlmIChuMiAhPT0gMCkgdGhyb3cgRXJyb3IobWVbbjJdKTsKICAgICAgICAgIFB0LmNhbGwodDIuZGljdGlvbmFyeSkgPT09IGBbb2JqZWN0IEFycmF5QnVmZmVyXWAgJiYgKHQyLmRpY3Rpb25hcnkgPSBuZXcgVWludDhBcnJheSh0Mi5kaWN0aW9uYXJ5KSk7CiAgICAgICAgICBsZXQgcjIgPSB0Mi5kaWN0aW9uYXJ5OwogICAgICAgICAgaWYgKHQyLnJhdyAmJiByMi5sZW5ndGggJiYgKG4yID0gRHQodGhpcy5zdHJtLCByMiksIG4yICE9PSAwKSkgdGhyb3cgRXJyb3IobWVbbjJdKTsKICAgICAgICB9CiAgICAgICAgcHVzaChlMiwgdDIgPSBmYWxzZSkgewogICAgICAgICAgbGV0IG4yID0gdGhpcy5zdHJtLCByMiA9IHRoaXMub3B0aW9ucy5jaHVua1NpemUsIGkyLCBhNCwgbzI7CiAgICAgICAgICBpZiAodGhpcy5lbmRlZCkgcmV0dXJuIHRoaXMuZXJyID09PSAwOwogICAgICAgICAgZm9yIChhNCA9IHR5cGVvZiB0MiA9PSBgbnVtYmVyYCA/IHQyIDogdDIgPT09IHRydWUgPyA0IDogMCwgUHQuY2FsbChlMikgPT09IGBbb2JqZWN0IEFycmF5QnVmZmVyXWAgPyBuMi5pbnB1dCA9IG5ldyBVaW50OEFycmF5KGUyKSA6IG4yLmlucHV0ID0gZTIsIG4yLm5leHRfaW4gPSAwLCBuMi5hdmFpbF9pbiA9IG4yLmlucHV0Lmxlbmd0aCwgdGhpcy5zdGFydGVkIHx8ICh0aGlzLnN0YXJ0ZWQgPSB0cnVlLCB0aGlzLm9uU3RhcnQobjIpKTsgOyApIHsKICAgICAgICAgICAgaWYgKG4yLmF2YWlsX291dCA9PT0gMCAmJiAobjIub3V0cHV0ID0gbmV3IFVpbnQ4QXJyYXkocjIpLCBuMi5uZXh0X291dCA9IDAsIG4yLmF2YWlsX291dCA9IHIyKSwgaTIgPSBUdChuMiwgYTQpLCBpMiA9PT0gMikgewogICAgICAgICAgICAgIGxldCBlMyA9IHRoaXMub3B0aW9ucy5kaWN0aW9uYXJ5OwogICAgICAgICAgICAgIGUzLmxlbmd0aCAmJiAoaTIgPSBEdChuMiwgZTMpLCBpMiA9PT0gMCA/IGkyID0gVHQobjIsIGE0KSA6IGkyID09PSAtMyAmJiAoaTIgPSAyKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZm9yICg7IG4yLmF2YWlsX2luID4gMCAmJiBpMiA9PT0gMSAmJiBuMi5zdGF0ZS53cmFwICYgMiAmJiBuMi5zdGF0ZS5mbGFncyAhPT0gMCAmJiBuMi5pbnB1dFtuMi5uZXh0X2luXSAhPT0gMDsgKSBfdChuMiksIGkyID0gVHQobjIsIGE0KTsKICAgICAgICAgICAgaWYgKGkyID09PSAtMiB8fCBpMiA9PT0gLTMgfHwgaTIgPT09IDIgfHwgaTIgPT09IC00KSBicmVhazsKICAgICAgICAgICAgaWYgKG8yID0gbjIuYXZhaWxfb3V0LCBuMi5uZXh0X291dCAmJiAobjIuYXZhaWxfb3V0ID09PSAwIHx8IGkyID09PSAxIHx8IGE0ID4gMCkgJiYgKHRoaXMub25EYXRhKG4yLm91dHB1dC5sZW5ndGggPT09IG4yLm5leHRfb3V0ID8gbjIub3V0cHV0IDogbjIub3V0cHV0LnN1YmFycmF5KDAsIG4yLm5leHRfb3V0KSksIG4yLmF2YWlsX291dCA9IDAsIG4yLm5leHRfb3V0ID0gMCksICEoKGkyID09PSAwIHx8IGkyID09PSAtNSkgJiYgbzIgPT09IDApKSB7CiAgICAgICAgICAgICAgaWYgKGkyID09PSAxKSB7CiAgICAgICAgICAgICAgICBpMiA9IEV0KHRoaXMuc3RybSk7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKG4yLmF2YWlsX2luID09PSAwKSB7CiAgICAgICAgICAgICAgICBpZiAoYTQgPT09IDQpIHsKICAgICAgICAgICAgICAgICAgaTIgPSBFdCh0aGlzLnN0cm0pLCBpMiA9PT0gMCAmJiAoaTIgPSAtNSk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICByZXR1cm4gdGhpcy5lcnIgPSBpMiwgdGhpcy5tc2cgPSBuMi5tc2cgfHwgbWVbaTJdLCB0aGlzLmVuZGVkID0gdHJ1ZSwgdGhpcy5vbkVuZChpMiksIGkyID09PSAwOwogICAgICAgIH0KICAgICAgICBvblN0YXJ0KGUyKSB7CiAgICAgICAgfQogICAgICAgIG9uRGF0YShlMikgewogICAgICAgICAgdGhpcy5jaHVua3MucHVzaChlMik7CiAgICAgICAgfQogICAgICAgIG9uRW5kKGUyKSB7CiAgICAgICAgICBlMiA9PT0gMCAmJiAodGhpcy5yZXN1bHQgPSBrdCh0aGlzLmNodW5rcykpLCB0aGlzLmNodW5rcyA9IFtdOwogICAgICAgIH0KICAgICAgfTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2RlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZVBhY2tldC5qcwogIHZhciBkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXRfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZVBhY2tldF9leHBvcnRzLCB7CiAgICBkZWZhdWx0OiAoKSA9PiBkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXRfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZVBhY2tldChwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCB0eXBlID0gVHlwZXMuZnJvbVN0cmluZyhwYXJhbWV0ZXJzLnR5cGUpOwogICAgbGV0IGJ1ZmZlciA9IHBhcmFtZXRlcnMuYnVmZmVyOwogICAgZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlRGF0YV9kZWZhdWx0KHBhcmFtZXRlcnMua2V5LCBidWZmZXIpOwogICAgY29uc3QgdW5jb21wcmVzc2VkVGVycmFpbiA9IHVuY29tcHJlc3NQYWNrZXQoYnVmZmVyKTsKICAgIGJ1ZmZlciA9IHVuY29tcHJlc3NlZFRlcnJhaW4uYnVmZmVyOwogICAgY29uc3QgbGVuZ3RoID0gdW5jb21wcmVzc2VkVGVycmFpbi5sZW5ndGg7CiAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgY2FzZSBUeXBlcy5NRVRBREFUQToKICAgICAgICByZXR1cm4gcHJvY2Vzc01ldGFkYXRhKGJ1ZmZlciwgbGVuZ3RoLCBwYXJhbWV0ZXJzLnF1YWRLZXkpOwogICAgICBjYXNlIFR5cGVzLlRFUlJBSU46CiAgICAgICAgcmV0dXJuIHByb2Nlc3NUZXJyYWluKGJ1ZmZlciwgbGVuZ3RoLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgICAgY2FzZSBUeXBlcy5EQlJPT1Q6CiAgICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKGJ1ZmZlcik7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgIGJ1ZmZlcgogICAgICAgIH07CiAgICB9CiAgfQogIGZ1bmN0aW9uIHByb2Nlc3NNZXRhZGF0YShidWZmZXIsIHRvdGFsU2l6ZSwgcXVhZEtleSkgewogICAgY29uc3QgZHYgPSBuZXcgRGF0YVZpZXcoYnVmZmVyKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgY29uc3QgbWFnaWMgPSBkdi5nZXRVaW50MzIob2Zmc2V0LCB0cnVlKTsKICAgIG9mZnNldCArPSBzaXplT2ZVaW50MzIyOwogICAgaWYgKG1hZ2ljICE9PSBxdE1hZ2ljKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgiSW52YWxpZCBtYWdpYyIpOwogICAgfQogICAgY29uc3QgZGF0YVR5cGVJZCA9IGR2LmdldFVpbnQzMihvZmZzZXQsIHRydWUpOwogICAgb2Zmc2V0ICs9IHNpemVPZlVpbnQzMjI7CiAgICBpZiAoZGF0YVR5cGVJZCAhPT0gMSkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkludmFsaWQgZGF0YSB0eXBlLiBNdXN0IGJlIDEgZm9yIFF1YWRUcmVlUGFja2V0Iik7CiAgICB9CiAgICBjb25zdCBxdWFkVmVyc2lvbiA9IGR2LmdldFVpbnQzMihvZmZzZXQsIHRydWUpOwogICAgb2Zmc2V0ICs9IHNpemVPZlVpbnQzMjI7CiAgICBpZiAocXVhZFZlcnNpb24gIT09IDIpIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KAogICAgICAgICJJbnZhbGlkIFF1YWRUcmVlUGFja2V0IHZlcnNpb24uIE9ubHkgdmVyc2lvbiAyIGlzIHN1cHBvcnRlZC4iCiAgICAgICk7CiAgICB9CiAgICBjb25zdCBudW1JbnN0YW5jZXMgPSBkdi5nZXRJbnQzMihvZmZzZXQsIHRydWUpOwogICAgb2Zmc2V0ICs9IHNpemVPZkludDMyMjsKICAgIGNvbnN0IGRhdGFJbnN0YW5jZVNpemUgPSBkdi5nZXRJbnQzMihvZmZzZXQsIHRydWUpOwogICAgb2Zmc2V0ICs9IHNpemVPZkludDMyMjsKICAgIGlmIChkYXRhSW5zdGFuY2VTaXplICE9PSAzMikgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkludmFsaWQgaW5zdGFuY2Ugc2l6ZS4iKTsKICAgIH0KICAgIGNvbnN0IGRhdGFCdWZmZXJPZmZzZXQgPSBkdi5nZXRJbnQzMihvZmZzZXQsIHRydWUpOwogICAgb2Zmc2V0ICs9IHNpemVPZkludDMyMjsKICAgIGNvbnN0IGRhdGFCdWZmZXJTaXplID0gZHYuZ2V0SW50MzIob2Zmc2V0LCB0cnVlKTsKICAgIG9mZnNldCArPSBzaXplT2ZJbnQzMjI7CiAgICBjb25zdCBtZXRhQnVmZmVyU2l6ZSA9IGR2LmdldEludDMyKG9mZnNldCwgdHJ1ZSk7CiAgICBvZmZzZXQgKz0gc2l6ZU9mSW50MzIyOwogICAgaWYgKGRhdGFCdWZmZXJPZmZzZXQgIT09IG51bUluc3RhbmNlcyAqIGRhdGFJbnN0YW5jZVNpemUgKyBvZmZzZXQpIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KCJJbnZhbGlkIGRhdGFCdWZmZXJPZmZzZXQiKTsKICAgIH0KICAgIGlmIChkYXRhQnVmZmVyT2Zmc2V0ICsgZGF0YUJ1ZmZlclNpemUgKyBtZXRhQnVmZmVyU2l6ZSAhPT0gdG90YWxTaXplKSB7CiAgICAgIHRocm93IG5ldyBSdW50aW1lRXJyb3JfZGVmYXVsdCgiSW52YWxpZCBwYWNrZXQgb2Zmc2V0cyIpOwogICAgfQogICAgY29uc3QgaW5zdGFuY2VzID0gW107CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtSW5zdGFuY2VzOyArK2kyKSB7CiAgICAgIGNvbnN0IGJpdGZpZWxkID0gZHYuZ2V0VWludDgob2Zmc2V0KTsKICAgICAgKytvZmZzZXQ7CiAgICAgICsrb2Zmc2V0OwogICAgICBjb25zdCBjbm9kZVZlcnNpb24gPSBkdi5nZXRVaW50MTYob2Zmc2V0LCB0cnVlKTsKICAgICAgb2Zmc2V0ICs9IHNpemVPZlVpbnQxNjI7CiAgICAgIGNvbnN0IGltYWdlVmVyc2lvbiA9IGR2LmdldFVpbnQxNihvZmZzZXQsIHRydWUpOwogICAgICBvZmZzZXQgKz0gc2l6ZU9mVWludDE2MjsKICAgICAgY29uc3QgdGVycmFpblZlcnNpb24gPSBkdi5nZXRVaW50MTYob2Zmc2V0LCB0cnVlKTsKICAgICAgb2Zmc2V0ICs9IHNpemVPZlVpbnQxNjI7CiAgICAgIG9mZnNldCArPSBzaXplT2ZVaW50MTYyOwogICAgICBvZmZzZXQgKz0gc2l6ZU9mVWludDE2MjsKICAgICAgb2Zmc2V0ICs9IHNpemVPZkludDMyMjsKICAgICAgb2Zmc2V0ICs9IHNpemVPZkludDMyMjsKICAgICAgb2Zmc2V0ICs9IDg7CiAgICAgIGNvbnN0IGltYWdlUHJvdmlkZXIgPSBkdi5nZXRVaW50OChvZmZzZXQrKyk7CiAgICAgIGNvbnN0IHRlcnJhaW5Qcm92aWRlciA9IGR2LmdldFVpbnQ4KG9mZnNldCsrKTsKICAgICAgb2Zmc2V0ICs9IHNpemVPZlVpbnQxNjI7CiAgICAgIGluc3RhbmNlcy5wdXNoKAogICAgICAgIG5ldyBHb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb25fZGVmYXVsdCgKICAgICAgICAgIGJpdGZpZWxkLAogICAgICAgICAgY25vZGVWZXJzaW9uLAogICAgICAgICAgaW1hZ2VWZXJzaW9uLAogICAgICAgICAgdGVycmFpblZlcnNpb24sCiAgICAgICAgICBpbWFnZVByb3ZpZGVyLAogICAgICAgICAgdGVycmFpblByb3ZpZGVyCiAgICAgICAgKQogICAgICApOwogICAgfQogICAgY29uc3QgdGlsZUluZm8gPSBbXTsKICAgIGxldCBpbmRleCA9IDA7CiAgICBmdW5jdGlvbiBwb3B1bGF0ZVRpbGVzKHBhcmVudEtleSwgcGFyZW50LCBsZXZlbDIpIHsKICAgICAgbGV0IGlzTGVhZiA9IGZhbHNlOwogICAgICBpZiAobGV2ZWwyID09PSA0KSB7CiAgICAgICAgaWYgKHBhcmVudC5oYXNTdWJ0cmVlKCkpIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgaXNMZWFmID0gdHJ1ZTsKICAgICAgfQogICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgNDsgKytpMikgewogICAgICAgIGNvbnN0IGNoaWxkS2V5ID0gcGFyZW50S2V5ICsgaTIudG9TdHJpbmcoKTsKICAgICAgICBpZiAoaXNMZWFmKSB7CiAgICAgICAgICB0aWxlSW5mb1tjaGlsZEtleV0gPSBudWxsOwogICAgICAgIH0gZWxzZSBpZiAobGV2ZWwyIDwgNCkgewogICAgICAgICAgaWYgKCFwYXJlbnQuaGFzQ2hpbGQoaTIpKSB7CiAgICAgICAgICAgIHRpbGVJbmZvW2NoaWxkS2V5XSA9IG51bGw7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBpZiAoaW5kZXggPT09IG51bUluc3RhbmNlcykgewogICAgICAgICAgICAgIGNvbnNvbGUubG9nKCJJbmNvcnJlY3QgbnVtYmVyIG9mIGluc3RhbmNlcyIpOwogICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgfQogICAgICAgICAgICBjb25zdCBpbnN0YW5jZSA9IGluc3RhbmNlc1tpbmRleCsrXTsKICAgICAgICAgICAgdGlsZUluZm9bY2hpbGRLZXldID0gaW5zdGFuY2U7CiAgICAgICAgICAgIHBvcHVsYXRlVGlsZXMoY2hpbGRLZXksIGluc3RhbmNlLCBsZXZlbDIgKyAxKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGxldCBsZXZlbCA9IDA7CiAgICBjb25zdCByb290ID0gaW5zdGFuY2VzW2luZGV4KytdOwogICAgaWYgKHF1YWRLZXkgPT09ICIiKSB7CiAgICAgICsrbGV2ZWw7CiAgICB9IGVsc2UgewogICAgICB0aWxlSW5mb1txdWFkS2V5XSA9IHJvb3Q7CiAgICB9CiAgICBwb3B1bGF0ZVRpbGVzKHF1YWRLZXksIHJvb3QsIGxldmVsKTsKICAgIHJldHVybiB0aWxlSW5mbzsKICB9CiAgZnVuY3Rpb24gcHJvY2Vzc1RlcnJhaW4oYnVmZmVyLCB0b3RhbFNpemUsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IGR2ID0gbmV3IERhdGFWaWV3KGJ1ZmZlcik7CiAgICBjb25zdCBhZHZhbmNlTWVzaCA9IGZ1bmN0aW9uKHBvcykgewogICAgICBmb3IgKGxldCBzdWIgPSAwOyBzdWIgPCBudW1TdWJNZXNoZXNQZXJNZXNoOyArK3N1YikgewogICAgICAgIGNvbnN0IHNpemUgPSBkdi5nZXRVaW50MzIocG9zLCB0cnVlKTsKICAgICAgICBwb3MgKz0gc2l6ZU9mVWludDMyMjsKICAgICAgICBwb3MgKz0gc2l6ZTsKICAgICAgICBpZiAocG9zID4gdG90YWxTaXplKSB7CiAgICAgICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIk1hbGZvcm1lZCB0ZXJyYWluIHBhY2tldCBmb3VuZC4iKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgcmV0dXJuIHBvczsKICAgIH07CiAgICBsZXQgb2Zmc2V0ID0gMDsKICAgIGNvbnN0IHRlcnJhaW5NZXNoZXMgPSBbXTsKICAgIHdoaWxlICh0ZXJyYWluTWVzaGVzLmxlbmd0aCA8IG51bU1lc2hlc1BlclBhY2tldCkgewogICAgICBjb25zdCBzdGFydCA9IG9mZnNldDsKICAgICAgb2Zmc2V0ID0gYWR2YW5jZU1lc2gob2Zmc2V0KTsKICAgICAgY29uc3QgbWVzaCA9IGJ1ZmZlci5zbGljZShzdGFydCwgb2Zmc2V0KTsKICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKG1lc2gpOwogICAgICB0ZXJyYWluTWVzaGVzLnB1c2gobWVzaCk7CiAgICB9CiAgICByZXR1cm4gdGVycmFpbk1lc2hlczsKICB9CiAgZnVuY3Rpb24gdW5jb21wcmVzc1BhY2tldChkYXRhKSB7CiAgICBjb25zdCBkdiA9IG5ldyBEYXRhVmlldyhkYXRhKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgY29uc3QgbWFnaWMgPSBkdi5nZXRVaW50MzIob2Zmc2V0LCB0cnVlKTsKICAgIG9mZnNldCArPSBzaXplT2ZVaW50MzIyOwogICAgaWYgKG1hZ2ljICE9PSBjb21wcmVzc2VkTWFnaWMyICYmIG1hZ2ljICE9PSBjb21wcmVzc2VkTWFnaWNTd2FwMikgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIkludmFsaWQgbWFnaWMiKTsKICAgIH0KICAgIGNvbnN0IHNpemUgPSBkdi5nZXRVaW50MzIob2Zmc2V0LCBtYWdpYyA9PT0gY29tcHJlc3NlZE1hZ2ljMik7CiAgICBvZmZzZXQgKz0gc2l6ZU9mVWludDMyMjsKICAgIGNvbnN0IGNvbXByZXNzZWRQYWNrZXQgPSBuZXcgVWludDhBcnJheShkYXRhLCBvZmZzZXQpOwogICAgY29uc3QgdW5jb21wcmVzc2VkUGFja2V0ID0gTHQoY29tcHJlc3NlZFBhY2tldCk7CiAgICBpZiAodW5jb21wcmVzc2VkUGFja2V0Lmxlbmd0aCAhPT0gc2l6ZSkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIlNpemUgb2YgcGFja2V0IGRvZXNuJ3QgbWF0Y2ggaGVhZGVyIik7CiAgICB9CiAgICByZXR1cm4gdW5jb21wcmVzc2VkUGFja2V0OwogIH0KICB2YXIgc2l6ZU9mVWludDE2Miwgc2l6ZU9mSW50MzIyLCBzaXplT2ZVaW50MzIyLCBUeXBlcywgcXRNYWdpYywgbnVtTWVzaGVzUGVyUGFja2V0LCBudW1TdWJNZXNoZXNQZXJNZXNoLCBjb21wcmVzc2VkTWFnaWMyLCBjb21wcmVzc2VkTWFnaWNTd2FwMiwgZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0X2RlZmF1bHQ7CiAgdmFyIGluaXRfZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9kZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXQuanMiKCkgewogICAgICBpbml0X2RlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZURhdGEoKTsKICAgICAgaW5pdF9Hb29nbGVFYXJ0aEVudGVycHJpc2VUaWxlSW5mb3JtYXRpb24oKTsKICAgICAgaW5pdF9SdW50aW1lRXJyb3IoKTsKICAgICAgaW5pdF9wYWtvX2luZmxhdGVfZXNtX21pbigpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgc2l6ZU9mVWludDE2MiA9IFVpbnQxNkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICBzaXplT2ZJbnQzMjIgPSBJbnQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UOwogICAgICBzaXplT2ZVaW50MzIyID0gVWludDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7CiAgICAgIFR5cGVzID0gewogICAgICAgIE1FVEFEQVRBOiAwLAogICAgICAgIFRFUlJBSU46IDEsCiAgICAgICAgREJST09UOiAyCiAgICAgIH07CiAgICAgIFR5cGVzLmZyb21TdHJpbmcgPSBmdW5jdGlvbihzMikgewogICAgICAgIGlmIChzMiA9PT0gIk1ldGFkYXRhIikgewogICAgICAgICAgcmV0dXJuIFR5cGVzLk1FVEFEQVRBOwogICAgICAgIH0gZWxzZSBpZiAoczIgPT09ICJUZXJyYWluIikgewogICAgICAgICAgcmV0dXJuIFR5cGVzLlRFUlJBSU47CiAgICAgICAgfSBlbHNlIGlmIChzMiA9PT0gIkRiUm9vdCIpIHsKICAgICAgICAgIHJldHVybiBUeXBlcy5EQlJPT1Q7CiAgICAgICAgfQogICAgICB9OwogICAgICBxdE1hZ2ljID0gMzIzMDE7CiAgICAgIG51bU1lc2hlc1BlclBhY2tldCA9IDU7CiAgICAgIG51bVN1Yk1lc2hlc1Blck1lc2ggPSA0OwogICAgICBjb21wcmVzc2VkTWFnaWMyID0gMTk1MzAyOTgwNTsKICAgICAgY29tcHJlc3NlZE1hZ2ljU3dhcDIgPSAyOTE3MDM0MTAwOwogICAgICBkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXRfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXQpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvc3JnYlRvTGluZWFyLmpzCiAgZnVuY3Rpb24gc3JnYlRvTGluZWFyKHZhbHVlKSB7CiAgICBDaGVja19kZWZhdWx0LmRlZmluZWQoInZhbHVlIiwgdmFsdWUpOwogICAgaWYgKHZhbHVlIDw9IDAuMDQwNDUpIHsKICAgICAgcmV0dXJuIHZhbHVlICogMC4wNzczOTkzODA4MDQ5NTM1NzsKICAgIH0KICAgIHJldHVybiBNYXRoLnBvdygKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWxvc3Mtb2YtcHJlY2lzaW9uCiAgICAgICh2YWx1ZSArIDAuMDU1KSAqIDAuOTQ3ODY3Mjk4NTc4MTk5MSwKICAgICAgMi40CiAgICApOwogIH0KICB2YXIgc3JnYlRvTGluZWFyX2RlZmF1bHQ7CiAgdmFyIGluaXRfc3JnYlRvTGluZWFyID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9zcmdiVG9MaW5lYXIuanMiKCkgewogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIHNyZ2JUb0xpbmVhcl9kZWZhdWx0ID0gc3JnYlRvTGluZWFyOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvZGVjb2RlSTNTLmpzCiAgdmFyIGRlY29kZUkzU19leHBvcnRzID0ge307CiAgX19leHBvcnQoZGVjb2RlSTNTX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGRlY29kZUkzU19kZWZhdWx0CiAgfSk7CiAgZnVuY3Rpb24gYmlsaW5lYXJJbnRlcnBvbGF0ZSh0eCwgdHksIGgwMCwgaDEwLCBoMDEsIGgxMSkgewogICAgY29uc3QgYTQgPSBoMDAgKiAoMSAtIHR4KSArIGgxMCAqIHR4OwogICAgY29uc3QgYjIgPSBoMDEgKiAoMSAtIHR4KSArIGgxMSAqIHR4OwogICAgcmV0dXJuIGE0ICogKDEgLSB0eSkgKyBiMiAqIHR5OwogIH0KICBmdW5jdGlvbiBzYW1wbGVNYXAodTQsIHY0LCB3aWR0aCwgZGF0YSkgewogICAgY29uc3QgYWRkcmVzcyA9IHU0ICsgdjQgKiB3aWR0aDsKICAgIHJldHVybiBkYXRhW2FkZHJlc3NdOwogIH0KICBmdW5jdGlvbiBzYW1wbGVHZW9pZChzYW1wbGVYLCBzYW1wbGVZLCBnZW9pZERhdGEpIHsKICAgIGNvbnN0IGV4dGVudCA9IGdlb2lkRGF0YS5uYXRpdmVFeHRlbnQ7CiAgICBsZXQgeDIgPSAoc2FtcGxlWCAtIGV4dGVudC53ZXN0KSAvIChleHRlbnQuZWFzdCAtIGV4dGVudC53ZXN0KSAqIChnZW9pZERhdGEud2lkdGggLSAxKTsKICAgIGxldCB5MiA9IChzYW1wbGVZIC0gZXh0ZW50LnNvdXRoKSAvIChleHRlbnQubm9ydGggLSBleHRlbnQuc291dGgpICogKGdlb2lkRGF0YS5oZWlnaHQgLSAxKTsKICAgIGNvbnN0IHhpID0gTWF0aC5mbG9vcih4Mik7CiAgICBsZXQgeWkgPSBNYXRoLmZsb29yKHkyKTsKICAgIHgyIC09IHhpOwogICAgeTIgLT0geWk7CiAgICBjb25zdCB4TmV4dCA9IHhpIDwgZ2VvaWREYXRhLndpZHRoID8geGkgKyAxIDogeGk7CiAgICBsZXQgeU5leHQgPSB5aSA8IGdlb2lkRGF0YS5oZWlnaHQgPyB5aSArIDEgOiB5aTsKICAgIHlpID0gZ2VvaWREYXRhLmhlaWdodCAtIDEgLSB5aTsKICAgIHlOZXh0ID0gZ2VvaWREYXRhLmhlaWdodCAtIDEgLSB5TmV4dDsKICAgIGNvbnN0IGgwMCA9IHNhbXBsZU1hcCh4aSwgeWksIGdlb2lkRGF0YS53aWR0aCwgZ2VvaWREYXRhLmJ1ZmZlcik7CiAgICBjb25zdCBoMTAgPSBzYW1wbGVNYXAoeE5leHQsIHlpLCBnZW9pZERhdGEud2lkdGgsIGdlb2lkRGF0YS5idWZmZXIpOwogICAgY29uc3QgaDAxID0gc2FtcGxlTWFwKHhpLCB5TmV4dCwgZ2VvaWREYXRhLndpZHRoLCBnZW9pZERhdGEuYnVmZmVyKTsKICAgIGNvbnN0IGgxMSA9IHNhbXBsZU1hcCh4TmV4dCwgeU5leHQsIGdlb2lkRGF0YS53aWR0aCwgZ2VvaWREYXRhLmJ1ZmZlcik7CiAgICBsZXQgZmluYWxIZWlnaHQgPSBiaWxpbmVhckludGVycG9sYXRlKHgyLCB5MiwgaDAwLCBoMTAsIGgwMSwgaDExKTsKICAgIGZpbmFsSGVpZ2h0ID0gZmluYWxIZWlnaHQgKiBnZW9pZERhdGEuc2NhbGUgKyBnZW9pZERhdGEub2Zmc2V0OwogICAgcmV0dXJuIGZpbmFsSGVpZ2h0OwogIH0KICBmdW5jdGlvbiBzYW1wbGVHZW9pZEZyb21MaXN0KGxvbiwgbGF0LCBnZW9pZERhdGFMaXN0KSB7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgZ2VvaWREYXRhTGlzdC5sZW5ndGg7IGkyKyspIHsKICAgICAgY29uc3QgbG9jYWxFeHRlbnQgPSBnZW9pZERhdGFMaXN0W2kyXS5uYXRpdmVFeHRlbnQ7CiAgICAgIGxldCBsb2NhbFB0ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBpZiAoZ2VvaWREYXRhTGlzdFtpMl0ucHJvamVjdGlvblR5cGUgPT09ICJXZWJNZXJjYXRvciIpIHsKICAgICAgICBjb25zdCByYWRpaSA9IGdlb2lkRGF0YUxpc3RbaTJdLnByb2plY3Rpb24uX2VsbGlwc29pZC5fcmFkaWk7CiAgICAgICAgY29uc3Qgd2ViTWVyY2F0b3JQcm9qID0gbmV3IFdlYk1lcmNhdG9yUHJvamVjdGlvbl9kZWZhdWx0KAogICAgICAgICAgbmV3IEVsbGlwc29pZF9kZWZhdWx0KHJhZGlpLngsIHJhZGlpLnksIHJhZGlpLnopCiAgICAgICAgKTsKICAgICAgICBsb2NhbFB0ID0gd2ViTWVyY2F0b3JQcm9qLnByb2plY3QobmV3IENhcnRvZ3JhcGhpY19kZWZhdWx0KGxvbiwgbGF0LCAwKSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgbG9jYWxQdC54ID0gbG9uOwogICAgICAgIGxvY2FsUHQueSA9IGxhdDsKICAgICAgfQogICAgICBpZiAobG9jYWxQdC54ID4gbG9jYWxFeHRlbnQud2VzdCAmJiBsb2NhbFB0LnggPCBsb2NhbEV4dGVudC5lYXN0ICYmIGxvY2FsUHQueSA+IGxvY2FsRXh0ZW50LnNvdXRoICYmIGxvY2FsUHQueSA8IGxvY2FsRXh0ZW50Lm5vcnRoKSB7CiAgICAgICAgcmV0dXJuIHNhbXBsZUdlb2lkKGxvY2FsUHQueCwgbG9jYWxQdC55LCBnZW9pZERhdGFMaXN0W2kyXSk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiAwOwogIH0KICBmdW5jdGlvbiBvcnRob21ldHJpY1RvRWxsaXBzb2lkYWwodmVydGV4Q291bnQsIHBvc2l0aW9uLCBzY2FsZV94LCBzY2FsZV95LCBjZW50ZXIsIGdlb2lkRGF0YUxpc3QsIGZhc3QpIHsKICAgIGlmIChmYXN0KSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNvbnN0IGNlbnRlckhlaWdodCA9IHNhbXBsZUdlb2lkRnJvbUxpc3QoCiAgICAgIGNlbnRlci5sb25naXR1ZGUsCiAgICAgIGNlbnRlci5sYXRpdHVkZSwKICAgICAgZ2VvaWREYXRhTGlzdAogICAgKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudDsgKytpMikgewogICAgICBjb25zdCBoZWlnaHQgPSBzYW1wbGVHZW9pZEZyb21MaXN0KAogICAgICAgIGNlbnRlci5sb25naXR1ZGUgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKHNjYWxlX3ggKiBwb3NpdGlvbltpMiAqIDNdKSwKICAgICAgICBjZW50ZXIubGF0aXR1ZGUgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKHNjYWxlX3kgKiBwb3NpdGlvbltpMiAqIDMgKyAxXSksCiAgICAgICAgZ2VvaWREYXRhTGlzdAogICAgICApOwogICAgICBwb3NpdGlvbltpMiAqIDMgKyAyXSArPSBoZWlnaHQgLSBjZW50ZXJIZWlnaHQ7CiAgICB9CiAgfQogIGZ1bmN0aW9uIHRyYW5zZm9ybVRvTG9jYWwodmVydGV4Q291bnQsIHBvc2l0aW9ucywgbm9ybWFscywgY2FydG9ncmFwaGljQ2VudGVyLCBjYXJ0ZXNpYW5DZW50ZXIsIHBhcmVudFJvdGF0aW9uLCBlbGxpcHNvaWRSYWRpaVNxdWFyZSwgc2NhbGVfeCwgc2NhbGVfeSkgewogICAgaWYgKHZlcnRleENvdW50ID09PSAwIHx8ICFkZWZpbmVkX2RlZmF1bHQocG9zaXRpb25zKSB8fCBwb3NpdGlvbnMubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGNvbnN0IGVsbGlwc29pZCA9IG5ldyBFbGxpcHNvaWRfZGVmYXVsdCgKICAgICAgTWF0aC5zcXJ0KGVsbGlwc29pZFJhZGlpU3F1YXJlLngpLAogICAgICBNYXRoLnNxcnQoZWxsaXBzb2lkUmFkaWlTcXVhcmUueSksCiAgICAgIE1hdGguc3FydChlbGxpcHNvaWRSYWRpaVNxdWFyZS56KQogICAgKTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudDsgKytpMikgewogICAgICBjb25zdCBpbmRleE9mZnNldCA9IGkyICogMzsKICAgICAgY29uc3QgaW5kZXhPZmZzZXQxID0gaW5kZXhPZmZzZXQgKyAxOwogICAgICBjb25zdCBpbmRleE9mZnNldDIgPSBpbmRleE9mZnNldCArIDI7CiAgICAgIGNvbnN0IGNhcnRvZ3JhcGhpYzIgPSBuZXcgQ2FydG9ncmFwaGljX2RlZmF1bHQoKTsKICAgICAgY2FydG9ncmFwaGljMi5sb25naXR1ZGUgPSBjYXJ0b2dyYXBoaWNDZW50ZXIubG9uZ2l0dWRlICsgTWF0aF9kZWZhdWx0LnRvUmFkaWFucyhzY2FsZV94ICogcG9zaXRpb25zW2luZGV4T2Zmc2V0XSk7CiAgICAgIGNhcnRvZ3JhcGhpYzIubGF0aXR1ZGUgPSBjYXJ0b2dyYXBoaWNDZW50ZXIubGF0aXR1ZGUgKyBNYXRoX2RlZmF1bHQudG9SYWRpYW5zKHNjYWxlX3kgKiBwb3NpdGlvbnNbaW5kZXhPZmZzZXQxXSk7CiAgICAgIGNhcnRvZ3JhcGhpYzIuaGVpZ2h0ID0gY2FydG9ncmFwaGljQ2VudGVyLmhlaWdodCArIHBvc2l0aW9uc1tpbmRleE9mZnNldDJdOwogICAgICBjb25zdCBwb3NpdGlvbiA9IHt9OwogICAgICBlbGxpcHNvaWQuY2FydG9ncmFwaGljVG9DYXJ0ZXNpYW4oY2FydG9ncmFwaGljMiwgcG9zaXRpb24pOwogICAgICBwb3NpdGlvbi54IC09IGNhcnRlc2lhbkNlbnRlci54OwogICAgICBwb3NpdGlvbi55IC09IGNhcnRlc2lhbkNlbnRlci55OwogICAgICBwb3NpdGlvbi56IC09IGNhcnRlc2lhbkNlbnRlci56OwogICAgICBjb25zdCByb3RhdGVkUG9zaXRpb24gPSB7fTsKICAgICAgTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IocGFyZW50Um90YXRpb24sIHBvc2l0aW9uLCByb3RhdGVkUG9zaXRpb24pOwogICAgICBwb3NpdGlvbnNbaW5kZXhPZmZzZXRdID0gcm90YXRlZFBvc2l0aW9uLng7CiAgICAgIHBvc2l0aW9uc1tpbmRleE9mZnNldDFdID0gcm90YXRlZFBvc2l0aW9uLnk7CiAgICAgIHBvc2l0aW9uc1tpbmRleE9mZnNldDJdID0gcm90YXRlZFBvc2l0aW9uLno7CiAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobm9ybWFscykpIHsKICAgICAgICBjb25zdCBub3JtYWwyID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgKICAgICAgICAgIG5vcm1hbHNbaW5kZXhPZmZzZXRdLAogICAgICAgICAgbm9ybWFsc1tpbmRleE9mZnNldDFdLAogICAgICAgICAgbm9ybWFsc1tpbmRleE9mZnNldDJdCiAgICAgICAgKTsKICAgICAgICBjb25zdCByb3RhdGVkTm9ybWFsID0ge307CiAgICAgICAgTWF0cml4M19kZWZhdWx0Lm11bHRpcGx5QnlWZWN0b3IocGFyZW50Um90YXRpb24sIG5vcm1hbDIsIHJvdGF0ZWROb3JtYWwpOwogICAgICAgIG5vcm1hbHNbaW5kZXhPZmZzZXRdID0gcm90YXRlZE5vcm1hbC54OwogICAgICAgIG5vcm1hbHNbaW5kZXhPZmZzZXQxXSA9IHJvdGF0ZWROb3JtYWwueTsKICAgICAgICBub3JtYWxzW2luZGV4T2Zmc2V0Ml0gPSByb3RhdGVkTm9ybWFsLno7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gY3JvcFVWcyh2ZXJ0ZXhDb3VudCwgdXYwcywgdXZSZWdpb25zKSB7CiAgICBmb3IgKGxldCB2ZXJ0ZXhJbmRleCA9IDA7IHZlcnRleEluZGV4IDwgdmVydGV4Q291bnQ7ICsrdmVydGV4SW5kZXgpIHsKICAgICAgY29uc3QgbWluVSA9IHV2UmVnaW9uc1t2ZXJ0ZXhJbmRleCAqIDRdIC8gNjU1MzU7CiAgICAgIGNvbnN0IG1pblYgPSB1dlJlZ2lvbnNbdmVydGV4SW5kZXggKiA0ICsgMV0gLyA2NTUzNTsKICAgICAgY29uc3Qgc2NhbGVVID0gKHV2UmVnaW9uc1t2ZXJ0ZXhJbmRleCAqIDQgKyAyXSAtIHV2UmVnaW9uc1t2ZXJ0ZXhJbmRleCAqIDRdKSAvIDY1NTM1OwogICAgICBjb25zdCBzY2FsZVYgPSAodXZSZWdpb25zW3ZlcnRleEluZGV4ICogNCArIDNdIC0gdXZSZWdpb25zW3ZlcnRleEluZGV4ICogNCArIDFdKSAvIDY1NTM1OwogICAgICB1djBzW3ZlcnRleEluZGV4ICogMl0gKj0gc2NhbGVVOwogICAgICB1djBzW3ZlcnRleEluZGV4ICogMl0gKz0gbWluVTsKICAgICAgdXYwc1t2ZXJ0ZXhJbmRleCAqIDIgKyAxXSAqPSBzY2FsZVY7CiAgICAgIHV2MHNbdmVydGV4SW5kZXggKiAyICsgMV0gKz0gbWluVjsKICAgIH0KICB9CiAgZnVuY3Rpb24gZ2VuZXJhdGVJbmRleEFycmF5KHZlcnRleENvdW50LCBpbmRpY2VzLCBjb2xvcnMsIHNwbGl0R2VvbWV0cnlCeUNvbG9yVHJhbnNwYXJlbmN5KSB7CiAgICBjb25zdCBpbmRleEFycmF5ID0gbmV3IFVpbnQzMkFycmF5KHZlcnRleENvdW50KTsKICAgIGNvbnN0IHZlcnRleEluZGV4Rm4gPSBkZWZpbmVkX2RlZmF1bHQoaW5kaWNlcykgPyAodmVydGV4SW5kZXgpID0+IGluZGljZXNbdmVydGV4SW5kZXhdIDogKHZlcnRleEluZGV4KSA9PiB2ZXJ0ZXhJbmRleDsKICAgIGxldCB0cmFuc3BhcmVudFZlcnRleE9mZnNldCA9IDA7CiAgICBpZiAoc3BsaXRHZW9tZXRyeUJ5Q29sb3JUcmFuc3BhcmVuY3kgJiYgZGVmaW5lZF9kZWZhdWx0KGNvbG9ycykpIHsKICAgICAgY29uc3QgaXNWZXJ0ZXhUcmFuc3BhcmVudEZuID0gKHZlcnRleEluZGV4KSA9PiBjb2xvcnNbdmVydGV4SW5kZXhGbih2ZXJ0ZXhJbmRleCkgKiA0ICsgM10gPCAyNTU7CiAgICAgIGZvciAobGV0IHZlcnRleEluZGV4ID0gMDsgdmVydGV4SW5kZXggPCB2ZXJ0ZXhDb3VudDsgdmVydGV4SW5kZXggKz0gMykgewogICAgICAgIGlmICghaXNWZXJ0ZXhUcmFuc3BhcmVudEZuKHZlcnRleEluZGV4KSAmJiAhaXNWZXJ0ZXhUcmFuc3BhcmVudEZuKHZlcnRleEluZGV4ICsgMSkgJiYgIWlzVmVydGV4VHJhbnNwYXJlbnRGbih2ZXJ0ZXhJbmRleCArIDIpKSB7CiAgICAgICAgICBpbmRleEFycmF5W3RyYW5zcGFyZW50VmVydGV4T2Zmc2V0KytdID0gdmVydGV4SW5kZXhGbih2ZXJ0ZXhJbmRleCk7CiAgICAgICAgICBpbmRleEFycmF5W3RyYW5zcGFyZW50VmVydGV4T2Zmc2V0KytdID0gdmVydGV4SW5kZXhGbih2ZXJ0ZXhJbmRleCArIDEpOwogICAgICAgICAgaW5kZXhBcnJheVt0cmFuc3BhcmVudFZlcnRleE9mZnNldCsrXSA9IHZlcnRleEluZGV4Rm4odmVydGV4SW5kZXggKyAyKTsKICAgICAgICB9CiAgICAgIH0KICAgICAgaWYgKHRyYW5zcGFyZW50VmVydGV4T2Zmc2V0ID4gMCkgewogICAgICAgIGxldCBvZmZzZXQgPSB0cmFuc3BhcmVudFZlcnRleE9mZnNldDsKICAgICAgICBmb3IgKGxldCB2ZXJ0ZXhJbmRleCA9IDA7IHZlcnRleEluZGV4IDwgdmVydGV4Q291bnQ7IHZlcnRleEluZGV4ICs9IDMpIHsKICAgICAgICAgIGlmIChpc1ZlcnRleFRyYW5zcGFyZW50Rm4odmVydGV4SW5kZXgpIHx8IGlzVmVydGV4VHJhbnNwYXJlbnRGbih2ZXJ0ZXhJbmRleCArIDEpIHx8IGlzVmVydGV4VHJhbnNwYXJlbnRGbih2ZXJ0ZXhJbmRleCArIDIpKSB7CiAgICAgICAgICAgIGluZGV4QXJyYXlbb2Zmc2V0KytdID0gdmVydGV4SW5kZXhGbih2ZXJ0ZXhJbmRleCk7CiAgICAgICAgICAgIGluZGV4QXJyYXlbb2Zmc2V0KytdID0gdmVydGV4SW5kZXhGbih2ZXJ0ZXhJbmRleCArIDEpOwogICAgICAgICAgICBpbmRleEFycmF5W29mZnNldCsrXSA9IHZlcnRleEluZGV4Rm4odmVydGV4SW5kZXggKyAyKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZm9yIChsZXQgdmVydGV4SW5kZXggPSAwOyB2ZXJ0ZXhJbmRleCA8IHZlcnRleENvdW50OyArK3ZlcnRleEluZGV4KSB7CiAgICAgICAgICBpbmRleEFycmF5W3ZlcnRleEluZGV4XSA9IHZlcnRleEluZGV4Rm4odmVydGV4SW5kZXgpOwogICAgICAgIH0KICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgdHJhbnNwYXJlbnRWZXJ0ZXhPZmZzZXQgPSB2ZXJ0ZXhDb3VudDsKICAgICAgZm9yIChsZXQgdmVydGV4SW5kZXggPSAwOyB2ZXJ0ZXhJbmRleCA8IHZlcnRleENvdW50OyArK3ZlcnRleEluZGV4KSB7CiAgICAgICAgaW5kZXhBcnJheVt2ZXJ0ZXhJbmRleF0gPSB2ZXJ0ZXhJbmRleEZuKHZlcnRleEluZGV4KTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIHsKICAgICAgaW5kZXhBcnJheSwKICAgICAgdHJhbnNwYXJlbnRWZXJ0ZXhPZmZzZXQKICAgIH07CiAgfQogIGZ1bmN0aW9uIGdldEZlYXR1cmVIYXNoKHN5bWJvbG9neURhdGEsIG91dGxpbmVzSGFzaCwgZmVhdHVyZUluZGV4KSB7CiAgICBjb25zdCBmZWF0dXJlSGFzaCA9IG91dGxpbmVzSGFzaFtmZWF0dXJlSW5kZXhdOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChmZWF0dXJlSGFzaCkpIHsKICAgICAgcmV0dXJuIGZlYXR1cmVIYXNoOwogICAgfQogICAgY29uc3QgbmV3RmVhdHVyZUhhc2ggPSBvdXRsaW5lc0hhc2hbZmVhdHVyZUluZGV4XSA9IHsKICAgICAgcG9zaXRpb25zOiB7fSwKICAgICAgaW5kaWNlczoge30sCiAgICAgIGVkZ2VzOiB7fQogICAgfTsKICAgIGNvbnN0IGZlYXR1cmVTeW1ib2xvZ3kgPSBzeW1ib2xvZ3lEYXRhW2ZlYXR1cmVJbmRleF0gPz8gc3ltYm9sb2d5RGF0YS5kZWZhdWx0OwogICAgbmV3RmVhdHVyZUhhc2guaGFzT3V0bGluZSA9IGRlZmluZWRfZGVmYXVsdChmZWF0dXJlU3ltYm9sb2d5Py5lZGdlcyk7CiAgICByZXR1cm4gbmV3RmVhdHVyZUhhc2g7CiAgfQogIGZ1bmN0aW9uIGFkZFZlcnRleFRvSGFzaChpbmRleEhhc2gsIHBvc2l0aW9uSGFzaCwgdmVydGV4SW5kZXgsIHBvc2l0aW9ucykgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoaW5kZXhIYXNoW3ZlcnRleEluZGV4XSkpIHsKICAgICAgY29uc3Qgc3RhcnRQb3NpdGlvbkluZGV4ID0gdmVydGV4SW5kZXggKiAzOwogICAgICBsZXQgY29vcmRpbmF0ZUhhc2ggPSBwb3NpdGlvbkhhc2g7CiAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCAzOyBpbmRleCsrKSB7CiAgICAgICAgY29uc3QgY29vcmRpbmF0ZSA9IHBvc2l0aW9uc1tzdGFydFBvc2l0aW9uSW5kZXggKyBpbmRleF07CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoY29vcmRpbmF0ZUhhc2hbY29vcmRpbmF0ZV0pKSB7CiAgICAgICAgICBjb29yZGluYXRlSGFzaFtjb29yZGluYXRlXSA9IHt9OwogICAgICAgIH0KICAgICAgICBjb29yZGluYXRlSGFzaCA9IGNvb3JkaW5hdGVIYXNoW2Nvb3JkaW5hdGVdOwogICAgICB9CiAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGNvb3JkaW5hdGVIYXNoLmluZGV4KSkgewogICAgICAgIGNvb3JkaW5hdGVIYXNoLmluZGV4ID0gdmVydGV4SW5kZXg7CiAgICAgIH0KICAgICAgaW5kZXhIYXNoW3ZlcnRleEluZGV4XSA9IGNvb3JkaW5hdGVIYXNoLmluZGV4OwogICAgfQogIH0KICBmdW5jdGlvbiBhZGRFZGdlVG9IYXNoKGVkZ2VIYXNoLCB2ZXJ0ZXhBSW5kZXgsIHZlcnRleEJJbmRleCwgdmVydGV4QUluZGV4VW5pcXVlLCB2ZXJ0ZXhCSW5kZXhVbmlxdWUsIG5vcm1hbEluZGV4KSB7CiAgICBsZXQgc3RhcnRWZXJ0ZXhJbmRleDsKICAgIGxldCBlbmRWZXJ0ZXhJbmRleDsKICAgIGlmICh2ZXJ0ZXhBSW5kZXhVbmlxdWUgPCB2ZXJ0ZXhCSW5kZXhVbmlxdWUpIHsKICAgICAgc3RhcnRWZXJ0ZXhJbmRleCA9IHZlcnRleEFJbmRleFVuaXF1ZTsKICAgICAgZW5kVmVydGV4SW5kZXggPSB2ZXJ0ZXhCSW5kZXhVbmlxdWU7CiAgICB9IGVsc2UgewogICAgICBzdGFydFZlcnRleEluZGV4ID0gdmVydGV4QkluZGV4VW5pcXVlOwogICAgICBlbmRWZXJ0ZXhJbmRleCA9IHZlcnRleEFJbmRleFVuaXF1ZTsKICAgIH0KICAgIGxldCBlZGdlU3RhcnQgPSBlZGdlSGFzaFtzdGFydFZlcnRleEluZGV4XTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVkZ2VTdGFydCkpIHsKICAgICAgZWRnZVN0YXJ0ID0gZWRnZUhhc2hbc3RhcnRWZXJ0ZXhJbmRleF0gPSB7fTsKICAgIH0KICAgIGxldCBlZGdlRW5kID0gZWRnZVN0YXJ0W2VuZFZlcnRleEluZGV4XTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGVkZ2VFbmQpKSB7CiAgICAgIGVkZ2VFbmQgPSBlZGdlU3RhcnRbZW5kVmVydGV4SW5kZXhdID0gewogICAgICAgIG5vcm1hbHNJbmRleDogW10sCiAgICAgICAgb3V0bGluZXM6IFtdCiAgICAgIH07CiAgICB9CiAgICBlZGdlRW5kLm5vcm1hbHNJbmRleC5wdXNoKG5vcm1hbEluZGV4KTsKICAgIGlmIChlZGdlRW5kLm91dGxpbmVzLmxlbmd0aCA9PT0gMCB8fCB2ZXJ0ZXhBSW5kZXggIT09IHZlcnRleEFJbmRleFVuaXF1ZSB8fCB2ZXJ0ZXhCSW5kZXggIT09IHZlcnRleEJJbmRleFVuaXF1ZSkgewogICAgICBlZGdlRW5kLm91dGxpbmVzLnB1c2godmVydGV4QUluZGV4LCB2ZXJ0ZXhCSW5kZXgpOwogICAgfQogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZU91dGxpbmVzSGFzaChzeW1ib2xvZ3lEYXRhLCBmZWF0dXJlSW5kZXhBcnJheSwgaW5kZXhBcnJheSwgcG9zaXRpb25zKSB7CiAgICBjb25zdCBvdXRsaW5lc0hhc2ggPSBbXTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBpbmRleEFycmF5Lmxlbmd0aDsgaTIgKz0gMykgewogICAgICBjb25zdCBmZWF0dXJlSW5kZXggPSBkZWZpbmVkX2RlZmF1bHQoZmVhdHVyZUluZGV4QXJyYXkpID8gZmVhdHVyZUluZGV4QXJyYXlbaW5kZXhBcnJheVtpMl1dIDogImRlZmF1bHQiOwogICAgICBjb25zdCBmZWF0dXJlSGFzaCA9IGdldEZlYXR1cmVIYXNoKAogICAgICAgIHN5bWJvbG9neURhdGEsCiAgICAgICAgb3V0bGluZXNIYXNoLAogICAgICAgIGZlYXR1cmVJbmRleAogICAgICApOwogICAgICBpZiAoIWZlYXR1cmVIYXNoLmhhc091dGxpbmUpIHsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBjb25zdCBpbmRleEhhc2ggPSBmZWF0dXJlSGFzaC5pbmRpY2VzOwogICAgICBjb25zdCBwb3NpdGlvbkhhc2ggPSBmZWF0dXJlSGFzaC5wb3NpdGlvbnM7CiAgICAgIGZvciAobGV0IHZlcnRleCA9IDA7IHZlcnRleCA8IDM7IHZlcnRleCsrKSB7CiAgICAgICAgY29uc3QgdmVydGV4SW5kZXggPSBpbmRleEFycmF5W2kyICsgdmVydGV4XTsKICAgICAgICBhZGRWZXJ0ZXhUb0hhc2goaW5kZXhIYXNoLCBwb3NpdGlvbkhhc2gsIHZlcnRleEluZGV4LCBwb3NpdGlvbnMpOwogICAgICB9CiAgICAgIGNvbnN0IGVkZ2VIYXNoID0gZmVhdHVyZUhhc2guZWRnZXM7CiAgICAgIGZvciAobGV0IHZlcnRleCA9IDA7IHZlcnRleCA8IDM7IHZlcnRleCsrKSB7CiAgICAgICAgY29uc3QgdmVydGV4SW5kZXggPSBpbmRleEFycmF5W2kyICsgdmVydGV4XTsKICAgICAgICBjb25zdCBuZXh0VmVydGV4SW5kZXggPSBpbmRleEFycmF5W2kyICsgKHZlcnRleCArIDEpICUgM107CiAgICAgICAgY29uc3QgdW5pcXVlVmVydGV4SW5kZXggPSBpbmRleEhhc2hbdmVydGV4SW5kZXhdOwogICAgICAgIGNvbnN0IHVuaXF1ZU5leHRWZXJ0ZXhJbmRleCA9IGluZGV4SGFzaFtuZXh0VmVydGV4SW5kZXhdOwogICAgICAgIGFkZEVkZ2VUb0hhc2goCiAgICAgICAgICBlZGdlSGFzaCwKICAgICAgICAgIHZlcnRleEluZGV4LAogICAgICAgICAgbmV4dFZlcnRleEluZGV4LAogICAgICAgICAgdW5pcXVlVmVydGV4SW5kZXgsCiAgICAgICAgICB1bmlxdWVOZXh0VmVydGV4SW5kZXgsCiAgICAgICAgICBpMgogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBvdXRsaW5lc0hhc2g7CiAgfQogIGZ1bmN0aW9uIGNhbGN1bGF0ZUZhY2VOb3JtYWwobm9ybWFscywgdmVydGV4QUluZGV4LCBpbmRleEFycmF5LCBwb3NpdGlvbnMpIHsKICAgIGNvbnN0IHBvc2l0aW9uQUluZGV4ID0gaW5kZXhBcnJheVt2ZXJ0ZXhBSW5kZXhdICogMzsKICAgIGNvbnN0IHBvc2l0aW9uQkluZGV4ID0gaW5kZXhBcnJheVt2ZXJ0ZXhBSW5kZXggKyAxXSAqIDM7CiAgICBjb25zdCBwb3NpdGlvbkNJbmRleCA9IGluZGV4QXJyYXlbdmVydGV4QUluZGV4ICsgMl0gKiAzOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmZyb21BcnJheShwb3NpdGlvbnMsIHBvc2l0aW9uQUluZGV4LCBjYWxjdWxhdGVGYWNlTm9ybWFsQSk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KHBvc2l0aW9ucywgcG9zaXRpb25CSW5kZXgsIGNhbGN1bGF0ZUZhY2VOb3JtYWxCKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5mcm9tQXJyYXkocG9zaXRpb25zLCBwb3NpdGlvbkNJbmRleCwgY2FsY3VsYXRlRmFjZU5vcm1hbEMpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsQiwKICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbEEsCiAgICAgIGNhbGN1bGF0ZUZhY2VOb3JtYWxCCiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LnN1YnRyYWN0KAogICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsQywKICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbEEsCiAgICAgIGNhbGN1bGF0ZUZhY2VOb3JtYWxDCiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmNyb3NzKAogICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsQiwKICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbEMsCiAgICAgIGNhbGN1bGF0ZUZhY2VOb3JtYWxBCiAgICApOwogICAgY29uc3QgbWFnbml0dWRlID0gQ2FydGVzaWFuM19kZWZhdWx0Lm1hZ25pdHVkZShjYWxjdWxhdGVGYWNlTm9ybWFsQSk7CiAgICBpZiAobWFnbml0dWRlICE9PSAwKSB7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5kaXZpZGVCeVNjYWxhcigKICAgICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsQSwKICAgICAgICBtYWduaXR1ZGUsCiAgICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbEEKICAgICAgKTsKICAgIH0KICAgIGNvbnN0IG5vcm1hbEFJbmRleCA9IHZlcnRleEFJbmRleCAqIDM7CiAgICBjb25zdCBub3JtYWxCSW5kZXggPSAodmVydGV4QUluZGV4ICsgMSkgKiAzOwogICAgY29uc3Qgbm9ybWFsQ0luZGV4ID0gKHZlcnRleEFJbmRleCArIDIpICogMzsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5wYWNrKGNhbGN1bGF0ZUZhY2VOb3JtYWxBLCBub3JtYWxzLCBub3JtYWxBSW5kZXgpOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LnBhY2soY2FsY3VsYXRlRmFjZU5vcm1hbEEsIG5vcm1hbHMsIG5vcm1hbEJJbmRleCk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQucGFjayhjYWxjdWxhdGVGYWNlTm9ybWFsQSwgbm9ybWFscywgbm9ybWFsQ0luZGV4KTsKICB9CiAgZnVuY3Rpb24gaXNFZGdlU21vb3RoKG5vcm1hbHMsIG5vcm1hbEFJbmRleCwgbm9ybWFsQkluZGV4KSB7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KG5vcm1hbHMsIG5vcm1hbEFJbmRleCwgaXNFZGdlU21vb3RoQSk7CiAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQuZnJvbUFycmF5KG5vcm1hbHMsIG5vcm1hbEJJbmRleCwgaXNFZGdlU21vb3RoQik7CiAgICBjb25zdCBjb3NpbmUgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQuZG90KGlzRWRnZVNtb290aEEsIGlzRWRnZVNtb290aEIpOwogICAgY29uc3Qgc2luZSA9IENhcnRlc2lhbjNfZGVmYXVsdC5tYWduaXR1ZGUoCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jcm9zcyhpc0VkZ2VTbW9vdGhBLCBpc0VkZ2VTbW9vdGhCLCBpc0VkZ2VTbW9vdGhBKQogICAgKTsKICAgIHJldHVybiBNYXRoLmF0YW4yKHNpbmUsIGNvc2luZSkgPCAwLjI1OwogIH0KICBmdW5jdGlvbiBhZGRPdXRsaW5lc0ZvckVkZ2Uob3V0bGluZXMsIGVkZ2VEYXRhLCBpbmRleEFycmF5LCBwb3NpdGlvbnMsIG5vcm1hbHMpIHsKICAgIGlmIChlZGdlRGF0YS5ub3JtYWxzSW5kZXgubGVuZ3RoID4gMSkgewogICAgICBjb25zdCBub3JtYWxzQnlJbmRleCA9IHBvc2l0aW9ucy5sZW5ndGggPT09IG5vcm1hbHMubGVuZ3RoOwogICAgICBmb3IgKGxldCBpbmRleEEgPSAwOyBpbmRleEEgPCBlZGdlRGF0YS5ub3JtYWxzSW5kZXgubGVuZ3RoOyBpbmRleEErKykgewogICAgICAgIGNvbnN0IHZlcnRleEFJbmRleCA9IGVkZ2VEYXRhLm5vcm1hbHNJbmRleFtpbmRleEFdOwogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHNbdmVydGV4QUluZGV4ICogM10pKSB7CiAgICAgICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsKG5vcm1hbHMsIHZlcnRleEFJbmRleCwgaW5kZXhBcnJheSwgcG9zaXRpb25zKTsKICAgICAgICB9CiAgICAgICAgaWYgKGluZGV4QSA9PT0gMCkgewogICAgICAgICAgY29udGludWU7CiAgICAgICAgfQogICAgICAgIGZvciAobGV0IGluZGV4QiA9IDA7IGluZGV4QiA8IGluZGV4QTsgaW5kZXhCKyspIHsKICAgICAgICAgIGNvbnN0IHZlcnRleEJJbmRleCA9IGVkZ2VEYXRhLm5vcm1hbHNJbmRleFtpbmRleEJdOwogICAgICAgICAgY29uc3Qgbm9ybWFsQUluZGV4ID0gbm9ybWFsc0J5SW5kZXggPyBpbmRleEFycmF5W3ZlcnRleEFJbmRleF0gKiAzIDogdmVydGV4QUluZGV4ICogMzsKICAgICAgICAgIGNvbnN0IG5vcm1hbEJJbmRleCA9IG5vcm1hbHNCeUluZGV4ID8gaW5kZXhBcnJheVt2ZXJ0ZXhCSW5kZXhdICogMyA6IHZlcnRleEJJbmRleCAqIDM7CiAgICAgICAgICBpZiAoaXNFZGdlU21vb3RoKG5vcm1hbHMsIG5vcm1hbEFJbmRleCwgbm9ybWFsQkluZGV4KSkgewogICAgICAgICAgICByZXR1cm47CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBvdXRsaW5lcy5wdXNoKC4uLmVkZ2VEYXRhLm91dGxpbmVzKTsKICB9CiAgZnVuY3Rpb24gYWRkT3V0bGluZXNGb3JGZWF0dXJlKG91dGxpbmVzLCBlZGdlSGFzaCwgaW5kZXhBcnJheSwgcG9zaXRpb25zLCBub3JtYWxzKSB7CiAgICBjb25zdCBlZGdlU3RhcnRLZXlzID0gT2JqZWN0LmtleXMoZWRnZUhhc2gpOwogICAgZm9yIChsZXQgc3RhcnRJbmRleCA9IDA7IHN0YXJ0SW5kZXggPCBlZGdlU3RhcnRLZXlzLmxlbmd0aDsgc3RhcnRJbmRleCsrKSB7CiAgICAgIGNvbnN0IGVkZ2VFbmRzID0gZWRnZUhhc2hbZWRnZVN0YXJ0S2V5c1tzdGFydEluZGV4XV07CiAgICAgIGNvbnN0IGVkZ2VFbmRLZXlzID0gT2JqZWN0LmtleXMoZWRnZUVuZHMpOwogICAgICBmb3IgKGxldCBlbmRJbmRleCA9IDA7IGVuZEluZGV4IDwgZWRnZUVuZEtleXMubGVuZ3RoOyBlbmRJbmRleCsrKSB7CiAgICAgICAgY29uc3QgZWRnZURhdGEgPSBlZGdlRW5kc1tlZGdlRW5kS2V5c1tlbmRJbmRleF1dOwogICAgICAgIGFkZE91dGxpbmVzRm9yRWRnZShvdXRsaW5lcywgZWRnZURhdGEsIGluZGV4QXJyYXksIHBvc2l0aW9ucywgbm9ybWFscyk7CiAgICAgIH0KICAgIH0KICB9CiAgZnVuY3Rpb24gZ2VuZXJhdGVPdXRsaW5lc0Zyb21IYXNoKG91dGxpbmVzSGFzaCwgaW5kZXhBcnJheSwgcG9zaXRpb25zLCBub3JtYWxzKSB7CiAgICBjb25zdCBvdXRsaW5lcyA9IFtdOwogICAgY29uc3QgZmVhdHVyZXMgPSBPYmplY3Qua2V5cyhvdXRsaW5lc0hhc2gpOwogICAgZm9yIChsZXQgZmVhdHVyZUluZGV4ID0gMDsgZmVhdHVyZUluZGV4IDwgZmVhdHVyZXMubGVuZ3RoOyBmZWF0dXJlSW5kZXgrKykgewogICAgICBjb25zdCBlZGdlSGFzaCA9IG91dGxpbmVzSGFzaFtmZWF0dXJlc1tmZWF0dXJlSW5kZXhdXS5lZGdlczsKICAgICAgYWRkT3V0bGluZXNGb3JGZWF0dXJlKG91dGxpbmVzLCBlZGdlSGFzaCwgaW5kZXhBcnJheSwgcG9zaXRpb25zLCBub3JtYWxzKTsKICAgIH0KICAgIHJldHVybiBvdXRsaW5lczsKICB9CiAgZnVuY3Rpb24gZ2VuZXJhdGVPdXRsaW5lc0luZGV4QXJyYXkoc3ltYm9sb2d5RGF0YSwgZmVhdHVyZUluZGV4QXJyYXksIGluZGV4QXJyYXksIHBvc2l0aW9ucywgbm9ybWFscykgewogICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoc3ltYm9sb2d5RGF0YSkgfHwgT2JqZWN0LmtleXMoc3ltYm9sb2d5RGF0YSkubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybiB2b2lkIDA7CiAgICB9CiAgICBjb25zdCBvdXRsaW5lc0hhc2ggPSBnZW5lcmF0ZU91dGxpbmVzSGFzaCgKICAgICAgc3ltYm9sb2d5RGF0YSwKICAgICAgZmVhdHVyZUluZGV4QXJyYXksCiAgICAgIGluZGV4QXJyYXksCiAgICAgIHBvc2l0aW9ucwogICAgKTsKICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHMpIHx8IGluZGV4QXJyYXkubGVuZ3RoICogMyAhPT0gbm9ybWFscy5sZW5ndGgpIHsKICAgICAgbm9ybWFscyA9IFtdOwogICAgfQogICAgY29uc3Qgb3V0bGluZXMgPSBnZW5lcmF0ZU91dGxpbmVzRnJvbUhhc2goCiAgICAgIG91dGxpbmVzSGFzaCwKICAgICAgaW5kZXhBcnJheSwKICAgICAgcG9zaXRpb25zLAogICAgICBub3JtYWxzCiAgICApOwogICAgY29uc3Qgb3V0bGluZXNJbmRleEFycmF5ID0gb3V0bGluZXMubGVuZ3RoID4gMCA/IG5ldyBVaW50MzJBcnJheShvdXRsaW5lcykgOiB2b2lkIDA7CiAgICByZXR1cm4gb3V0bGluZXNJbmRleEFycmF5OwogIH0KICBmdW5jdGlvbiBjb252ZXJ0Q29sb3JzQXJyYXkoY29sb3JzKSB7CiAgICBjb25zdCBjb2xvcnNBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoY29sb3JzLmxlbmd0aCk7CiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgY29sb3JzLmxlbmd0aDsgaW5kZXggKz0gNCkgewogICAgICBjb2xvcnNBcnJheVtpbmRleF0gPSBzcmdiVG9MaW5lYXJfZGVmYXVsdChDb2xvcl9kZWZhdWx0LmJ5dGVUb0Zsb2F0KGNvbG9yc1tpbmRleF0pKTsKICAgICAgY29sb3JzQXJyYXlbaW5kZXggKyAxXSA9IHNyZ2JUb0xpbmVhcl9kZWZhdWx0KENvbG9yX2RlZmF1bHQuYnl0ZVRvRmxvYXQoY29sb3JzW2luZGV4ICsgMV0pKTsKICAgICAgY29sb3JzQXJyYXlbaW5kZXggKyAyXSA9IHNyZ2JUb0xpbmVhcl9kZWZhdWx0KENvbG9yX2RlZmF1bHQuYnl0ZVRvRmxvYXQoY29sb3JzW2luZGV4ICsgMl0pKTsKICAgICAgY29sb3JzQXJyYXlbaW5kZXggKyAzXSA9IENvbG9yX2RlZmF1bHQuYnl0ZVRvRmxvYXQoY29sb3JzW2luZGV4ICsgM10pOwogICAgfQogICAgcmV0dXJuIGNvbG9yc0FycmF5OwogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZU5vcm1hbHModmVydGV4Q291bnQsIGluZGljZXMsIHBvc2l0aW9ucywgbm9ybWFscywgdXYwcywgY29sb3JzLCBmZWF0dXJlSW5kZXgpIHsKICAgIGNvbnN0IHJlc3VsdCA9IHsKICAgICAgbm9ybWFsczogdm9pZCAwLAogICAgICBwb3NpdGlvbnM6IHZvaWQgMCwKICAgICAgdXYwczogdm9pZCAwLAogICAgICBjb2xvcnM6IHZvaWQgMCwKICAgICAgZmVhdHVyZUluZGV4OiB2b2lkIDAsCiAgICAgIHZlcnRleENvdW50OiB2b2lkIDAKICAgIH07CiAgICBpZiAodmVydGV4Q291bnQgPT09IDAgfHwgIWRlZmluZWRfZGVmYXVsdChwb3NpdGlvbnMpIHx8IHBvc2l0aW9ucy5sZW5ndGggPT09IDAgfHwgZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHMpKSB7CiAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluZGljZXMpKSB7CiAgICAgIHJlc3VsdC52ZXJ0ZXhDb3VudCA9IGluZGljZXMubGVuZ3RoOwogICAgICByZXN1bHQucG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheShpbmRpY2VzLmxlbmd0aCAqIDMpOwogICAgICByZXN1bHQudXYwcyA9IGRlZmluZWRfZGVmYXVsdCh1djBzKSA/IG5ldyBGbG9hdDMyQXJyYXkoaW5kaWNlcy5sZW5ndGggKiAyKSA6IHZvaWQgMDsKICAgICAgcmVzdWx0LmNvbG9ycyA9IGRlZmluZWRfZGVmYXVsdChjb2xvcnMpID8gbmV3IFVpbnQ4QXJyYXkoaW5kaWNlcy5sZW5ndGggKiA0KSA6IHZvaWQgMDsKICAgICAgcmVzdWx0LmZlYXR1cmVJbmRleCA9IGRlZmluZWRfZGVmYXVsdChmZWF0dXJlSW5kZXgpID8gbmV3IEFycmF5KGluZGljZXMubGVuZ3RoKSA6IHZvaWQgMDsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGluZGljZXMubGVuZ3RoOyBpMisrKSB7CiAgICAgICAgY29uc3QgaW5kZXggPSBpbmRpY2VzW2kyXTsKICAgICAgICByZXN1bHQucG9zaXRpb25zW2kyICogM10gPSBwb3NpdGlvbnNbaW5kZXggKiAzXTsKICAgICAgICByZXN1bHQucG9zaXRpb25zW2kyICogMyArIDFdID0gcG9zaXRpb25zW2luZGV4ICogMyArIDFdOwogICAgICAgIHJlc3VsdC5wb3NpdGlvbnNbaTIgKiAzICsgMl0gPSBwb3NpdGlvbnNbaW5kZXggKiAzICsgMl07CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZXN1bHQudXYwcykpIHsKICAgICAgICAgIHJlc3VsdC51djBzW2kyICogMl0gPSB1djBzW2luZGV4ICogMl07CiAgICAgICAgICByZXN1bHQudXYwc1tpMiAqIDIgKyAxXSA9IHV2MHNbaW5kZXggKiAyICsgMV07CiAgICAgICAgfQogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocmVzdWx0LmNvbG9ycykpIHsKICAgICAgICAgIHJlc3VsdC5jb2xvcnNbaTIgKiA0XSA9IGNvbG9yc1tpbmRleCAqIDRdOwogICAgICAgICAgcmVzdWx0LmNvbG9yc1tpMiAqIDQgKyAxXSA9IGNvbG9yc1tpbmRleCAqIDQgKyAxXTsKICAgICAgICAgIHJlc3VsdC5jb2xvcnNbaTIgKiA0ICsgMl0gPSBjb2xvcnNbaW5kZXggKiA0ICsgMl07CiAgICAgICAgICByZXN1bHQuY29sb3JzW2kyICogNCArIDNdID0gY29sb3JzW2luZGV4ICogNCArIDNdOwogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHJlc3VsdC5mZWF0dXJlSW5kZXgpKSB7CiAgICAgICAgICByZXN1bHQuZmVhdHVyZUluZGV4W2kyXSA9IGZlYXR1cmVJbmRleFtpbmRleF07CiAgICAgICAgfQogICAgICB9CiAgICAgIHZlcnRleENvdW50ID0gaW5kaWNlcy5sZW5ndGg7CiAgICAgIHBvc2l0aW9ucyA9IHJlc3VsdC5wb3NpdGlvbnM7CiAgICB9CiAgICBpbmRpY2VzID0gbmV3IEFycmF5KHZlcnRleENvdW50KTsKICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCB2ZXJ0ZXhDb3VudDsgaTIrKykgewogICAgICBpbmRpY2VzW2kyXSA9IGkyOwogICAgfQogICAgcmVzdWx0Lm5vcm1hbHMgPSBuZXcgRmxvYXQzMkFycmF5KGluZGljZXMubGVuZ3RoICogMyk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgaW5kaWNlcy5sZW5ndGg7IGkyICs9IDMpIHsKICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbChyZXN1bHQubm9ybWFscywgaTIsIGluZGljZXMsIHBvc2l0aW9ucyk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBnZW5lcmF0ZUdsdGZCdWZmZXIodmVydGV4Q291bnQsIGluZGljZXMsIHBvc2l0aW9ucywgbm9ybWFscywgdXYwcywgY29sb3JzLCBmZWF0dXJlSW5kZXgsIHBhcmFtZXRlcnMpIHsKICAgIGlmICh2ZXJ0ZXhDb3VudCA9PT0gMCB8fCAhZGVmaW5lZF9kZWZhdWx0KHBvc2l0aW9ucykgfHwgcG9zaXRpb25zLmxlbmd0aCA9PT0gMCkgewogICAgICByZXR1cm4gewogICAgICAgIGJ1ZmZlcnM6IFtdLAogICAgICAgIGJ1ZmZlclZpZXdzOiBbXSwKICAgICAgICBhY2Nlc3NvcnM6IFtdLAogICAgICAgIG1lc2hlczogW10sCiAgICAgICAgbm9kZXM6IFtdLAogICAgICAgIG5vZGVzSW5TY2VuZTogW10KICAgICAgfTsKICAgIH0KICAgIGNvbnN0IGJ1ZmZlcnMgPSBbXTsKICAgIGNvbnN0IGJ1ZmZlclZpZXdzID0gW107CiAgICBjb25zdCBhY2Nlc3NvcnMgPSBbXTsKICAgIGNvbnN0IG1lc2hlcyA9IFtdOwogICAgY29uc3Qgbm9kZXMgPSBbXTsKICAgIGNvbnN0IG5vZGVzSW5TY2VuZSA9IFtdOwogICAgY29uc3Qgcm9vdEV4dGVuc2lvbnMgPSB7fTsKICAgIGNvbnN0IGV4dGVuc2lvbnNVc2VkID0gW107CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGluZGljZXMpKSB7CiAgICAgIHZlcnRleENvdW50ID0gaW5kaWNlcy5sZW5ndGg7CiAgICB9CiAgICBjb25zdCB7IGluZGV4QXJyYXksIHRyYW5zcGFyZW50VmVydGV4T2Zmc2V0IH0gPSBnZW5lcmF0ZUluZGV4QXJyYXkoCiAgICAgIHZlcnRleENvdW50LAogICAgICBpbmRpY2VzLAogICAgICBjb2xvcnMsCiAgICAgIHBhcmFtZXRlcnMuc3BsaXRHZW9tZXRyeUJ5Q29sb3JUcmFuc3BhcmVuY3kKICAgICk7CiAgICBjb25zdCBpbmRpY2VzQmxvYiA9IG5ldyBCbG9iKFtpbmRleEFycmF5XSwgeyB0eXBlOiAiYXBwbGljYXRpb24vYmluYXJ5IiB9KTsKICAgIGNvbnN0IGluZGljZXNVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGluZGljZXNCbG9iKTsKICAgIGNvbnN0IGVuZEluZGV4ID0gdmVydGV4Q291bnQ7CiAgICBjb25zdCBmZWF0dXJlSW5kZXhBcnJheSA9IHBhcmFtZXRlcnMuZW5hYmxlRmVhdHVyZXMgJiYgZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVJbmRleCkgPyBuZXcgRmxvYXQzMkFycmF5KGZlYXR1cmVJbmRleC5sZW5ndGgpIDogdm9pZCAwOwogICAgbGV0IGZlYXR1cmVDb3VudCA9IDA7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVJbmRleEFycmF5KSkgewogICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgZmVhdHVyZUluZGV4Lmxlbmd0aDsgKytpbmRleCkgewogICAgICAgIGZlYXR1cmVJbmRleEFycmF5W2luZGV4XSA9IGZlYXR1cmVJbmRleFtpbmRleF07CiAgICAgICAgY29uc3QgY291bnRCeUluZGV4ID0gZmVhdHVyZUluZGV4W2luZGV4XSArIDE7CiAgICAgICAgaWYgKGZlYXR1cmVDb3VudCA8IGNvdW50QnlJbmRleCkgewogICAgICAgICAgZmVhdHVyZUNvdW50ID0gY291bnRCeUluZGV4OwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgbGV0IG91dGxpbmVzSW5kaWNlc1VSTDsKICAgIGNvbnN0IG91dGxpbmVzSW5kZXhBcnJheSA9IGdlbmVyYXRlT3V0bGluZXNJbmRleEFycmF5KAogICAgICBwYXJhbWV0ZXJzLnN5bWJvbG9neURhdGEsCiAgICAgIGZlYXR1cmVJbmRleCwKICAgICAgaW5kZXhBcnJheSwKICAgICAgcG9zaXRpb25zLAogICAgICBub3JtYWxzCiAgICApOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChvdXRsaW5lc0luZGV4QXJyYXkpKSB7CiAgICAgIGNvbnN0IG91dGxpbmVzSW5kaWNlc0Jsb2IgPSBuZXcgQmxvYihbb3V0bGluZXNJbmRleEFycmF5XSwgewogICAgICAgIHR5cGU6ICJhcHBsaWNhdGlvbi9iaW5hcnkiCiAgICAgIH0pOwogICAgICBvdXRsaW5lc0luZGljZXNVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKG91dGxpbmVzSW5kaWNlc0Jsb2IpOwogICAgfQogICAgY29uc3QgbWVzaFBvc2l0aW9ucyA9IHBvc2l0aW9ucy5zdWJhcnJheSgwLCBlbmRJbmRleCAqIDMpOwogICAgY29uc3QgcG9zaXRpb25zQmxvYiA9IG5ldyBCbG9iKFttZXNoUG9zaXRpb25zXSwgewogICAgICB0eXBlOiAiYXBwbGljYXRpb24vYmluYXJ5IgogICAgfSk7CiAgICBjb25zdCBwb3NpdGlvbnNVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHBvc2l0aW9uc0Jsb2IpOwogICAgbGV0IG1pblggPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7CiAgICBsZXQgbWF4WCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTsKICAgIGxldCBtaW5ZID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZOwogICAgbGV0IG1heFkgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7CiAgICBsZXQgbWluWiA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTsKICAgIGxldCBtYXhaID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZOwogICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG1lc2hQb3NpdGlvbnMubGVuZ3RoIC8gMzsgaTIrKykgewogICAgICBtaW5YID0gTWF0aC5taW4obWluWCwgbWVzaFBvc2l0aW9uc1tpMiAqIDMgKyAwXSk7CiAgICAgIG1heFggPSBNYXRoLm1heChtYXhYLCBtZXNoUG9zaXRpb25zW2kyICogMyArIDBdKTsKICAgICAgbWluWSA9IE1hdGgubWluKG1pblksIG1lc2hQb3NpdGlvbnNbaTIgKiAzICsgMV0pOwogICAgICBtYXhZID0gTWF0aC5tYXgobWF4WSwgbWVzaFBvc2l0aW9uc1tpMiAqIDMgKyAxXSk7CiAgICAgIG1pblogPSBNYXRoLm1pbihtaW5aLCBtZXNoUG9zaXRpb25zW2kyICogMyArIDJdKTsKICAgICAgbWF4WiA9IE1hdGgubWF4KG1heFosIG1lc2hQb3NpdGlvbnNbaTIgKiAzICsgMl0pOwogICAgfQogICAgY29uc3QgbWVzaE5vcm1hbHMgPSBub3JtYWxzID8gbm9ybWFscy5zdWJhcnJheSgwLCBlbmRJbmRleCAqIDMpIDogdm9pZCAwOwogICAgbGV0IG5vcm1hbHNVUkw7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1lc2hOb3JtYWxzKSkgewogICAgICBjb25zdCBub3JtYWxzQmxvYiA9IG5ldyBCbG9iKFttZXNoTm9ybWFsc10sIHsKICAgICAgICB0eXBlOiAiYXBwbGljYXRpb24vYmluYXJ5IgogICAgICB9KTsKICAgICAgbm9ybWFsc1VSTCA9IFVSTC5jcmVhdGVPYmplY3RVUkwobm9ybWFsc0Jsb2IpOwogICAgfQogICAgY29uc3QgbWVzaFV2MHMgPSB1djBzID8gdXYwcy5zdWJhcnJheSgwLCBlbmRJbmRleCAqIDIpIDogdm9pZCAwOwogICAgbGV0IHV2MFVSTDsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobWVzaFV2MHMpKSB7CiAgICAgIGNvbnN0IHV2MEJsb2IgPSBuZXcgQmxvYihbbWVzaFV2MHNdLCB7IHR5cGU6ICJhcHBsaWNhdGlvbi9iaW5hcnkiIH0pOwogICAgICB1djBVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHV2MEJsb2IpOwogICAgfQogICAgY29uc3QgbWVzaENvbG9yc0luQnl0ZXMgPSBkZWZpbmVkX2RlZmF1bHQoY29sb3JzKSA/IGNvbnZlcnRDb2xvcnNBcnJheShjb2xvcnMuc3ViYXJyYXkoMCwgZW5kSW5kZXggKiA0KSkgOiB2b2lkIDA7CiAgICBsZXQgY29sb3JzVVJMOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChtZXNoQ29sb3JzSW5CeXRlcykpIHsKICAgICAgY29uc3QgY29sb3JzQmxvYiA9IG5ldyBCbG9iKFttZXNoQ29sb3JzSW5CeXRlc10sIHsKICAgICAgICB0eXBlOiAiYXBwbGljYXRpb24vYmluYXJ5IgogICAgICB9KTsKICAgICAgY29sb3JzVVJMID0gVVJMLmNyZWF0ZU9iamVjdFVSTChjb2xvcnNCbG9iKTsKICAgIH0KICAgIGNvbnN0IG1lc2hGZWF0dXJlSWQwID0gZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVJbmRleEFycmF5KSA/IGZlYXR1cmVJbmRleEFycmF5LnN1YmFycmF5KDAsIGVuZEluZGV4KSA6IHZvaWQgMDsKICAgIGxldCBmZWF0dXJlSWQwVVJMOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChtZXNoRmVhdHVyZUlkMCkpIHsKICAgICAgY29uc3QgZmVhdHVyZUlkMEJsb2IgPSBuZXcgQmxvYihbbWVzaEZlYXR1cmVJZDBdLCB7CiAgICAgICAgdHlwZTogImFwcGxpY2F0aW9uL2JpbmFyeSIKICAgICAgfSk7CiAgICAgIGZlYXR1cmVJZDBVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGZlYXR1cmVJZDBCbG9iKTsKICAgIH0KICAgIGNvbnN0IG1lc2hQcm9wZXJ0eVRhYmxlMCA9IGRlZmluZWRfZGVmYXVsdChmZWF0dXJlSW5kZXhBcnJheSkgPyBuZXcgRmxvYXQzMkFycmF5KGZlYXR1cmVDb3VudCkgOiB2b2lkIDA7CiAgICBsZXQgcHJvcGVydHlUYWJsZTBVUkw7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1lc2hQcm9wZXJ0eVRhYmxlMCkpIHsKICAgICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IG1lc2hQcm9wZXJ0eVRhYmxlMC5sZW5ndGg7ICsraW5kZXgpIHsKICAgICAgICBtZXNoUHJvcGVydHlUYWJsZTBbaW5kZXhdID0gaW5kZXg7CiAgICAgIH0KICAgICAgY29uc3QgcHJvcGVydHlUYWJsZTBCbG9iID0gbmV3IEJsb2IoW21lc2hQcm9wZXJ0eVRhYmxlMF0sIHsKICAgICAgICB0eXBlOiAiYXBwbGljYXRpb24vYmluYXJ5IgogICAgICB9KTsKICAgICAgcHJvcGVydHlUYWJsZTBVUkwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKHByb3BlcnR5VGFibGUwQmxvYik7CiAgICB9CiAgICBjb25zdCBhdHRyaWJ1dGVzID0ge307CiAgICBjb25zdCBleHRlbnNpb25zID0ge307CiAgICBhdHRyaWJ1dGVzLlBPU0lUSU9OID0gYWNjZXNzb3JzLmxlbmd0aDsKICAgIGJ1ZmZlcnMucHVzaCh7CiAgICAgIHVyaTogcG9zaXRpb25zVVJMLAogICAgICBieXRlTGVuZ3RoOiBtZXNoUG9zaXRpb25zLmJ5dGVMZW5ndGgKICAgIH0pOwogICAgYnVmZmVyVmlld3MucHVzaCh7CiAgICAgIGJ1ZmZlcjogYnVmZmVycy5sZW5ndGggLSAxLAogICAgICBieXRlT2Zmc2V0OiAwLAogICAgICBieXRlTGVuZ3RoOiBtZXNoUG9zaXRpb25zLmJ5dGVMZW5ndGgsCiAgICAgIHRhcmdldDogMzQ5NjIKICAgIH0pOwogICAgYWNjZXNzb3JzLnB1c2goewogICAgICBidWZmZXJWaWV3OiBidWZmZXJWaWV3cy5sZW5ndGggLSAxLAogICAgICBieXRlT2Zmc2V0OiAwLAogICAgICBjb21wb25lbnRUeXBlOiA1MTI2LAogICAgICBjb3VudDogbWVzaFBvc2l0aW9ucy5sZW5ndGggLyAzLAogICAgICB0eXBlOiAiVkVDMyIsCiAgICAgIG1pbjogW21pblgsIG1pblksIG1pblpdLAogICAgICBtYXg6IFttYXhYLCBtYXhZLCBtYXhaXQogICAgfSk7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG5vcm1hbHNVUkwpKSB7CiAgICAgIGF0dHJpYnV0ZXMuTk9STUFMID0gYWNjZXNzb3JzLmxlbmd0aDsKICAgICAgYnVmZmVycy5wdXNoKHsKICAgICAgICB1cmk6IG5vcm1hbHNVUkwsCiAgICAgICAgYnl0ZUxlbmd0aDogbWVzaE5vcm1hbHMuYnl0ZUxlbmd0aAogICAgICB9KTsKICAgICAgYnVmZmVyVmlld3MucHVzaCh7CiAgICAgICAgYnVmZmVyOiBidWZmZXJzLmxlbmd0aCAtIDEsCiAgICAgICAgYnl0ZU9mZnNldDogMCwKICAgICAgICBieXRlTGVuZ3RoOiBtZXNoTm9ybWFscy5ieXRlTGVuZ3RoLAogICAgICAgIHRhcmdldDogMzQ5NjIKICAgICAgfSk7CiAgICAgIGFjY2Vzc29ycy5wdXNoKHsKICAgICAgICBidWZmZXJWaWV3OiBidWZmZXJWaWV3cy5sZW5ndGggLSAxLAogICAgICAgIGJ5dGVPZmZzZXQ6IDAsCiAgICAgICAgY29tcG9uZW50VHlwZTogNTEyNiwKICAgICAgICBjb3VudDogbWVzaE5vcm1hbHMubGVuZ3RoIC8gMywKICAgICAgICB0eXBlOiAiVkVDMyIKICAgICAgfSk7CiAgICB9CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHV2MFVSTCkpIHsKICAgICAgYXR0cmlidXRlcy5URVhDT09SRF8wID0gYWNjZXNzb3JzLmxlbmd0aDsKICAgICAgYnVmZmVycy5wdXNoKHsKICAgICAgICB1cmk6IHV2MFVSTCwKICAgICAgICBieXRlTGVuZ3RoOiBtZXNoVXYwcy5ieXRlTGVuZ3RoCiAgICAgIH0pOwogICAgICBidWZmZXJWaWV3cy5wdXNoKHsKICAgICAgICBidWZmZXI6IGJ1ZmZlcnMubGVuZ3RoIC0gMSwKICAgICAgICBieXRlT2Zmc2V0OiAwLAogICAgICAgIGJ5dGVMZW5ndGg6IG1lc2hVdjBzLmJ5dGVMZW5ndGgsCiAgICAgICAgdGFyZ2V0OiAzNDk2MgogICAgICB9KTsKICAgICAgYWNjZXNzb3JzLnB1c2goewogICAgICAgIGJ1ZmZlclZpZXc6IGJ1ZmZlclZpZXdzLmxlbmd0aCAtIDEsCiAgICAgICAgYnl0ZU9mZnNldDogMCwKICAgICAgICBjb21wb25lbnRUeXBlOiA1MTI2LAogICAgICAgIGNvdW50OiBtZXNoVXYwcy5sZW5ndGggLyAyLAogICAgICAgIHR5cGU6ICJWRUMyIgogICAgICB9KTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoY29sb3JzVVJMKSkgewogICAgICBhdHRyaWJ1dGVzLkNPTE9SXzAgPSBhY2Nlc3NvcnMubGVuZ3RoOwogICAgICBidWZmZXJzLnB1c2goewogICAgICAgIHVyaTogY29sb3JzVVJMLAogICAgICAgIGJ5dGVMZW5ndGg6IG1lc2hDb2xvcnNJbkJ5dGVzLmJ5dGVMZW5ndGgKICAgICAgfSk7CiAgICAgIGJ1ZmZlclZpZXdzLnB1c2goewogICAgICAgIGJ1ZmZlcjogYnVmZmVycy5sZW5ndGggLSAxLAogICAgICAgIGJ5dGVPZmZzZXQ6IDAsCiAgICAgICAgYnl0ZUxlbmd0aDogbWVzaENvbG9yc0luQnl0ZXMuYnl0ZUxlbmd0aCwKICAgICAgICB0YXJnZXQ6IDM0OTYyCiAgICAgIH0pOwogICAgICBhY2Nlc3NvcnMucHVzaCh7CiAgICAgICAgYnVmZmVyVmlldzogYnVmZmVyVmlld3MubGVuZ3RoIC0gMSwKICAgICAgICBieXRlT2Zmc2V0OiAwLAogICAgICAgIGNvbXBvbmVudFR5cGU6IDUxMjYsCiAgICAgICAgY291bnQ6IG1lc2hDb2xvcnNJbkJ5dGVzLmxlbmd0aCAvIDQsCiAgICAgICAgdHlwZTogIlZFQzQiCiAgICAgIH0pOwogICAgfQogICAgaWYgKGRlZmluZWRfZGVmYXVsdChmZWF0dXJlSWQwVVJMKSkgewogICAgICBhdHRyaWJ1dGVzLl9GRUFUVVJFX0lEXzAgPSBhY2Nlc3NvcnMubGVuZ3RoOwogICAgICBidWZmZXJzLnB1c2goewogICAgICAgIHVyaTogZmVhdHVyZUlkMFVSTCwKICAgICAgICBieXRlTGVuZ3RoOiBtZXNoRmVhdHVyZUlkMC5ieXRlTGVuZ3RoCiAgICAgIH0pOwogICAgICBidWZmZXJWaWV3cy5wdXNoKHsKICAgICAgICBidWZmZXI6IGJ1ZmZlcnMubGVuZ3RoIC0gMSwKICAgICAgICBieXRlT2Zmc2V0OiAwLAogICAgICAgIGJ5dGVMZW5ndGg6IG1lc2hGZWF0dXJlSWQwLmJ5dGVMZW5ndGgsCiAgICAgICAgdGFyZ2V0OiAzNDk2MwogICAgICB9KTsKICAgICAgYWNjZXNzb3JzLnB1c2goewogICAgICAgIGJ1ZmZlclZpZXc6IGJ1ZmZlclZpZXdzLmxlbmd0aCAtIDEsCiAgICAgICAgYnl0ZU9mZnNldDogMCwKICAgICAgICBjb21wb25lbnRUeXBlOiA1MTI2LAogICAgICAgIGNvdW50OiBtZXNoRmVhdHVyZUlkMC5sZW5ndGgsCiAgICAgICAgdHlwZTogIlNDQUxBUiIKICAgICAgfSk7CiAgICAgIGV4dGVuc2lvbnMuRVhUX21lc2hfZmVhdHVyZXMgPSB7CiAgICAgICAgZmVhdHVyZUlkczogWwogICAgICAgICAgewogICAgICAgICAgICBhdHRyaWJ1dGU6IDAsCiAgICAgICAgICAgIHByb3BlcnR5VGFibGU6IDAsCiAgICAgICAgICAgIGZlYXR1cmVDb3VudAogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfTsKICAgICAgZXh0ZW5zaW9uc1VzZWQucHVzaCgiRVhUX21lc2hfZmVhdHVyZXMiKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocHJvcGVydHlUYWJsZTBVUkwpKSB7CiAgICAgIGJ1ZmZlcnMucHVzaCh7CiAgICAgICAgdXJpOiBwcm9wZXJ0eVRhYmxlMFVSTCwKICAgICAgICBieXRlTGVuZ3RoOiBtZXNoUHJvcGVydHlUYWJsZTAuYnl0ZUxlbmd0aAogICAgICB9KTsKICAgICAgYnVmZmVyVmlld3MucHVzaCh7CiAgICAgICAgYnVmZmVyOiBidWZmZXJzLmxlbmd0aCAtIDEsCiAgICAgICAgYnl0ZU9mZnNldDogMCwKICAgICAgICBieXRlTGVuZ3RoOiBtZXNoUHJvcGVydHlUYWJsZTAuYnl0ZUxlbmd0aCwKICAgICAgICB0YXJnZXQ6IDM0OTYzCiAgICAgIH0pOwogICAgICByb290RXh0ZW5zaW9ucy5FWFRfc3RydWN0dXJhbF9tZXRhZGF0YSA9IHsKICAgICAgICBzY2hlbWE6IHsKICAgICAgICAgIGlkOiAiaTNzLW1ldGFkYXRhLXNjaGVtYS0wMDEiLAogICAgICAgICAgbmFtZTogIkkzUyBtZXRhZGF0YSBzY2hlbWEgMDAxIiwKICAgICAgICAgIGRlc2NyaXB0aW9uOiAiVGhlIHNjaGVtYSBmb3IgSTNTIG1ldGFkYXRhIiwKICAgICAgICAgIHZlcnNpb246ICIxLjAiLAogICAgICAgICAgY2xhc3NlczogewogICAgICAgICAgICBmZWF0dXJlOiB7CiAgICAgICAgICAgICAgbmFtZTogImZlYXR1cmUiLAogICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAiRmVhdHVyZSBtZXRhZGF0YSIsCiAgICAgICAgICAgICAgcHJvcGVydGllczogewogICAgICAgICAgICAgICAgaW5kZXg6IHsKICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb246ICJUaGUgZmVhdHVyZSBpbmRleCIsCiAgICAgICAgICAgICAgICAgIHR5cGU6ICJTQ0FMQVIiLAogICAgICAgICAgICAgICAgICBjb21wb25lbnRUeXBlOiAiRkxPQVQzMiIsCiAgICAgICAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICBwcm9wZXJ0eVRhYmxlczogWwogICAgICAgICAgewogICAgICAgICAgICBuYW1lOiAiZmVhdHVyZS1pbmRpY2VzLW1hcHBpbmciLAogICAgICAgICAgICBjbGFzczogImZlYXR1cmUiLAogICAgICAgICAgICBjb3VudDogZmVhdHVyZUNvdW50LAogICAgICAgICAgICBwcm9wZXJ0aWVzOiB7CiAgICAgICAgICAgICAgaW5kZXg6IHsKICAgICAgICAgICAgICAgIHZhbHVlczogYnVmZmVyVmlld3MubGVuZ3RoIC0gMQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfTsKICAgICAgZXh0ZW5zaW9uc1VzZWQucHVzaCgiRVhUX3N0cnVjdHVyYWxfbWV0YWRhdGEiKTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQob3V0bGluZXNJbmRpY2VzVVJMKSkgewogICAgICBidWZmZXJzLnB1c2goewogICAgICAgIHVyaTogb3V0bGluZXNJbmRpY2VzVVJMLAogICAgICAgIGJ5dGVMZW5ndGg6IG91dGxpbmVzSW5kZXhBcnJheS5ieXRlTGVuZ3RoCiAgICAgIH0pOwogICAgICBidWZmZXJWaWV3cy5wdXNoKHsKICAgICAgICBidWZmZXI6IGJ1ZmZlcnMubGVuZ3RoIC0gMSwKICAgICAgICBieXRlT2Zmc2V0OiAwLAogICAgICAgIGJ5dGVMZW5ndGg6IG91dGxpbmVzSW5kZXhBcnJheS5ieXRlTGVuZ3RoLAogICAgICAgIHRhcmdldDogMzQ5NjMKICAgICAgfSk7CiAgICAgIGFjY2Vzc29ycy5wdXNoKHsKICAgICAgICBidWZmZXJWaWV3OiBidWZmZXJWaWV3cy5sZW5ndGggLSAxLAogICAgICAgIGJ5dGVPZmZzZXQ6IDAsCiAgICAgICAgY29tcG9uZW50VHlwZTogNTEyNSwKICAgICAgICBjb3VudDogb3V0bGluZXNJbmRleEFycmF5Lmxlbmd0aCwKICAgICAgICB0eXBlOiAiU0NBTEFSIgogICAgICB9KTsKICAgICAgZXh0ZW5zaW9ucy5DRVNJVU1fcHJpbWl0aXZlX291dGxpbmUgPSB7CiAgICAgICAgaW5kaWNlczogYWNjZXNzb3JzLmxlbmd0aCAtIDEKICAgICAgfTsKICAgICAgZXh0ZW5zaW9uc1VzZWQucHVzaCgiQ0VTSVVNX3ByaW1pdGl2ZV9vdXRsaW5lIik7CiAgICB9CiAgICBidWZmZXJzLnB1c2goewogICAgICB1cmk6IGluZGljZXNVUkwsCiAgICAgIGJ5dGVMZW5ndGg6IGluZGV4QXJyYXkuYnl0ZUxlbmd0aAogICAgfSk7CiAgICBidWZmZXJWaWV3cy5wdXNoKHsKICAgICAgYnVmZmVyOiBidWZmZXJzLmxlbmd0aCAtIDEsCiAgICAgIGJ5dGVPZmZzZXQ6IDAsCiAgICAgIGJ5dGVMZW5ndGg6IGluZGV4QXJyYXkuYnl0ZUxlbmd0aCwKICAgICAgdGFyZ2V0OiAzNDk2MwogICAgfSk7CiAgICBjb25zdCBtZXNoUHJpbWl0aXZlcyA9IFtdOwogICAgaWYgKHRyYW5zcGFyZW50VmVydGV4T2Zmc2V0ID4gMCkgewogICAgICBhY2Nlc3NvcnMucHVzaCh7CiAgICAgICAgYnVmZmVyVmlldzogYnVmZmVyVmlld3MubGVuZ3RoIC0gMSwKICAgICAgICBieXRlT2Zmc2V0OiAwLAogICAgICAgIGNvbXBvbmVudFR5cGU6IDUxMjUsCiAgICAgICAgY291bnQ6IHRyYW5zcGFyZW50VmVydGV4T2Zmc2V0LAogICAgICAgIHR5cGU6ICJTQ0FMQVIiCiAgICAgIH0pOwogICAgICBtZXNoUHJpbWl0aXZlcy5wdXNoKHsKICAgICAgICBhdHRyaWJ1dGVzLAogICAgICAgIGluZGljZXM6IGFjY2Vzc29ycy5sZW5ndGggLSAxLAogICAgICAgIG1hdGVyaWFsOiBtZXNoUHJpbWl0aXZlcy5sZW5ndGgsCiAgICAgICAgZXh0ZW5zaW9ucwogICAgICB9KTsKICAgIH0KICAgIGlmICh0cmFuc3BhcmVudFZlcnRleE9mZnNldCA8IHZlcnRleENvdW50KSB7CiAgICAgIGFjY2Vzc29ycy5wdXNoKHsKICAgICAgICBidWZmZXJWaWV3OiBidWZmZXJWaWV3cy5sZW5ndGggLSAxLAogICAgICAgIGJ5dGVPZmZzZXQ6IDQgKiB0cmFuc3BhcmVudFZlcnRleE9mZnNldCwKICAgICAgICAvLyBza2lwIDQgYnl0ZXMgZm9yIGVhY2ggb3BhcXVlIHZlcnRleAogICAgICAgIGNvbXBvbmVudFR5cGU6IDUxMjUsCiAgICAgICAgY291bnQ6IHZlcnRleENvdW50IC0gdHJhbnNwYXJlbnRWZXJ0ZXhPZmZzZXQsCiAgICAgICAgdHlwZTogIlNDQUxBUiIKICAgICAgfSk7CiAgICAgIG1lc2hQcmltaXRpdmVzLnB1c2goewogICAgICAgIGF0dHJpYnV0ZXMsCiAgICAgICAgaW5kaWNlczogYWNjZXNzb3JzLmxlbmd0aCAtIDEsCiAgICAgICAgbWF0ZXJpYWw6IG1lc2hQcmltaXRpdmVzLmxlbmd0aCwKICAgICAgICBleHRlbnNpb25zLAogICAgICAgIGV4dHJhOiB7CiAgICAgICAgICBpc1RyYW5zcGFyZW50OiB0cnVlCiAgICAgICAgfQogICAgICB9KTsKICAgIH0KICAgIG1lc2hlcy5wdXNoKHsKICAgICAgcHJpbWl0aXZlczogbWVzaFByaW1pdGl2ZXMKICAgIH0pOwogICAgbm9kZXNJblNjZW5lLnB1c2goMCk7CiAgICBub2Rlcy5wdXNoKHsgbWVzaDogMCB9KTsKICAgIHJldHVybiB7CiAgICAgIGJ1ZmZlcnMsCiAgICAgIGJ1ZmZlclZpZXdzLAogICAgICBhY2Nlc3NvcnMsCiAgICAgIG1lc2hlcywKICAgICAgbm9kZXMsCiAgICAgIG5vZGVzSW5TY2VuZSwKICAgICAgcm9vdEV4dGVuc2lvbnMsCiAgICAgIGV4dGVuc2lvbnNVc2VkCiAgICB9OwogIH0KICBmdW5jdGlvbiBkZWNvZGUyKGRhdGEsIHNjaGVtYSwgYnVmZmVySW5mbywgZmVhdHVyZURhdGEpIHsKICAgIGNvbnN0IG1hZ2ljTnVtYmVyID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSwgMCwgNSk7CiAgICBpZiAobWFnaWNOdW1iZXJbMF0gPT09ICJEIi5jaGFyQ29kZUF0KCkgJiYgbWFnaWNOdW1iZXJbMV0gPT09ICJSIi5jaGFyQ29kZUF0KCkgJiYgbWFnaWNOdW1iZXJbMl0gPT09ICJBIi5jaGFyQ29kZUF0KCkgJiYgbWFnaWNOdW1iZXJbM10gPT09ICJDIi5jaGFyQ29kZUF0KCkgJiYgbWFnaWNOdW1iZXJbNF0gPT09ICJPIi5jaGFyQ29kZUF0KCkpIHsKICAgICAgcmV0dXJuIGRlY29kZURyYWNvRW5jb2RlZEdlb21ldHJ5KGRhdGEsIGJ1ZmZlckluZm8pOwogICAgfQogICAgcmV0dXJuIGRlY29kZUJpbmFyeUdlb21ldHJ5KGRhdGEsIHNjaGVtYSwgYnVmZmVySW5mbywgZmVhdHVyZURhdGEpOwogIH0KICBmdW5jdGlvbiBkZWNvZGVEcmFjb0VuY29kZWRHZW9tZXRyeShkYXRhKSB7CiAgICBjb25zdCBkcmFjb0RlY29kZXJNb2R1bGUgPSBkcmFjbzI7CiAgICBjb25zdCBidWZmZXIgPSBuZXcgZHJhY29EZWNvZGVyTW9kdWxlLkRlY29kZXJCdWZmZXIoKTsKICAgIGNvbnN0IGJ5dGVBcnJheSA9IG5ldyBVaW50OEFycmF5KGRhdGEpOwogICAgYnVmZmVyLkluaXQoYnl0ZUFycmF5LCBieXRlQXJyYXkubGVuZ3RoKTsKICAgIGNvbnN0IGRyYWNvRGVjb2RlciA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuRGVjb2RlcigpOwogICAgY29uc3QgZ2VvbWV0cnlUeXBlID0gZHJhY29EZWNvZGVyLkdldEVuY29kZWRHZW9tZXRyeVR5cGUoYnVmZmVyKTsKICAgIGNvbnN0IG1ldGFkYXRhUXVlcmllciA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuTWV0YWRhdGFRdWVyaWVyKCk7CiAgICBsZXQgZHJhY29HZW9tZXRyeTsKICAgIGxldCBzdGF0dXM7CiAgICBpZiAoZ2VvbWV0cnlUeXBlID09PSBkcmFjb0RlY29kZXJNb2R1bGUuVFJJQU5HVUxBUl9NRVNIKSB7CiAgICAgIGRyYWNvR2VvbWV0cnkgPSBuZXcgZHJhY29EZWNvZGVyTW9kdWxlLk1lc2goKTsKICAgICAgc3RhdHVzID0gZHJhY29EZWNvZGVyLkRlY29kZUJ1ZmZlclRvTWVzaChidWZmZXIsIGRyYWNvR2VvbWV0cnkpOwogICAgfQogICAgY29uc3QgZGVjb2RlZEdlb21ldHJ5ID0gewogICAgICB2ZXJ0ZXhDb3VudDogWzBdLAogICAgICBmZWF0dXJlQ291bnQ6IDAKICAgIH07CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHN0YXR1cykgJiYgc3RhdHVzLm9rKCkgJiYgZHJhY29HZW9tZXRyeS5wdHIgIT09IDApIHsKICAgICAgY29uc3QgZmFjZUNvdW50ID0gZHJhY29HZW9tZXRyeS5udW1fZmFjZXMoKTsKICAgICAgY29uc3QgYXR0cmlidXRlc0NvdW50ID0gZHJhY29HZW9tZXRyeS5udW1fYXR0cmlidXRlcygpOwogICAgICBjb25zdCB2ZXJ0ZXhDb3VudCA9IGRyYWNvR2VvbWV0cnkubnVtX3BvaW50cygpOwogICAgICBkZWNvZGVkR2VvbWV0cnkuaW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheShmYWNlQ291bnQgKiAzKTsKICAgICAgY29uc3QgZmFjZXMyID0gZGVjb2RlZEdlb21ldHJ5LmluZGljZXM7CiAgICAgIGRlY29kZWRHZW9tZXRyeS52ZXJ0ZXhDb3VudFswXSA9IHZlcnRleENvdW50OwogICAgICBkZWNvZGVkR2VvbWV0cnkuc2NhbGVfeCA9IDE7CiAgICAgIGRlY29kZWRHZW9tZXRyeS5zY2FsZV95ID0gMTsKICAgICAgY29uc3QgZmFjZSA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuRHJhY29JbnQzMkFycmF5KDMpOwogICAgICBmb3IgKGxldCBmYWNlSW5kZXggPSAwOyBmYWNlSW5kZXggPCBmYWNlQ291bnQ7ICsrZmFjZUluZGV4KSB7CiAgICAgICAgZHJhY29EZWNvZGVyLkdldEZhY2VGcm9tTWVzaChkcmFjb0dlb21ldHJ5LCBmYWNlSW5kZXgsIGZhY2UpOwogICAgICAgIGZhY2VzMltmYWNlSW5kZXggKiAzXSA9IGZhY2UuR2V0VmFsdWUoMCk7CiAgICAgICAgZmFjZXMyW2ZhY2VJbmRleCAqIDMgKyAxXSA9IGZhY2UuR2V0VmFsdWUoMSk7CiAgICAgICAgZmFjZXMyW2ZhY2VJbmRleCAqIDMgKyAyXSA9IGZhY2UuR2V0VmFsdWUoMik7CiAgICAgIH0KICAgICAgZHJhY29EZWNvZGVyTW9kdWxlLmRlc3Ryb3koZmFjZSk7CiAgICAgIGZvciAobGV0IGF0dHJJbmRleCA9IDA7IGF0dHJJbmRleCA8IGF0dHJpYnV0ZXNDb3VudDsgKythdHRySW5kZXgpIHsKICAgICAgICBjb25zdCBkcmFjb0F0dHJpYnV0ZSA9IGRyYWNvRGVjb2Rlci5HZXRBdHRyaWJ1dGUoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgYXR0ckluZGV4CiAgICAgICAgKTsKICAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhID0gZGVjb2RlRHJhY29BdHRyaWJ1dGUoCiAgICAgICAgICBkcmFjb0RlY29kZXJNb2R1bGUsCiAgICAgICAgICBkcmFjb0RlY29kZXIsCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICB2ZXJ0ZXhDb3VudAogICAgICAgICk7CiAgICAgICAgY29uc3QgZHJhY29BdHRyaWJ1dGVUeXBlID0gZHJhY29BdHRyaWJ1dGUuYXR0cmlidXRlX3R5cGUoKTsKICAgICAgICBsZXQgYXR0cmlidXRlaTNzTmFtZSA9ICJ1bmtub3duIjsKICAgICAgICBpZiAoZHJhY29BdHRyaWJ1dGVUeXBlID09PSBkcmFjb0RlY29kZXJNb2R1bGUuUE9TSVRJT04pIHsKICAgICAgICAgIGF0dHJpYnV0ZWkzc05hbWUgPSAicG9zaXRpb25zIjsKICAgICAgICB9IGVsc2UgaWYgKGRyYWNvQXR0cmlidXRlVHlwZSA9PT0gZHJhY29EZWNvZGVyTW9kdWxlLk5PUk1BTCkgewogICAgICAgICAgYXR0cmlidXRlaTNzTmFtZSA9ICJub3JtYWxzIjsKICAgICAgICB9IGVsc2UgaWYgKGRyYWNvQXR0cmlidXRlVHlwZSA9PT0gZHJhY29EZWNvZGVyTW9kdWxlLkNPTE9SKSB7CiAgICAgICAgICBhdHRyaWJ1dGVpM3NOYW1lID0gImNvbG9ycyI7CiAgICAgICAgfSBlbHNlIGlmIChkcmFjb0F0dHJpYnV0ZVR5cGUgPT09IGRyYWNvRGVjb2Rlck1vZHVsZS5URVhfQ09PUkQpIHsKICAgICAgICAgIGF0dHJpYnV0ZWkzc05hbWUgPSAidXYwcyI7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG1ldGFkYXRhID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZU1ldGFkYXRhKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGF0dHJJbmRleAogICAgICAgICk7CiAgICAgICAgaWYgKG1ldGFkYXRhLnB0ciAhPT0gMCkgewogICAgICAgICAgY29uc3QgbnVtRW50cmllcyA9IG1ldGFkYXRhUXVlcmllci5OdW1FbnRyaWVzKG1ldGFkYXRhKTsKICAgICAgICAgIGZvciAobGV0IGVudHJ5ID0gMDsgZW50cnkgPCBudW1FbnRyaWVzOyArK2VudHJ5KSB7CiAgICAgICAgICAgIGNvbnN0IGVudHJ5TmFtZSA9IG1ldGFkYXRhUXVlcmllci5HZXRFbnRyeU5hbWUobWV0YWRhdGEsIGVudHJ5KTsKICAgICAgICAgICAgaWYgKGVudHJ5TmFtZSA9PT0gImkzcy1zY2FsZV94IikgewogICAgICAgICAgICAgIGRlY29kZWRHZW9tZXRyeS5zY2FsZV94ID0gbWV0YWRhdGFRdWVyaWVyLkdldERvdWJsZUVudHJ5KAogICAgICAgICAgICAgICAgbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAiaTNzLXNjYWxlX3giCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfSBlbHNlIGlmIChlbnRyeU5hbWUgPT09ICJpM3Mtc2NhbGVfeSIpIHsKICAgICAgICAgICAgICBkZWNvZGVkR2VvbWV0cnkuc2NhbGVfeSA9IG1ldGFkYXRhUXVlcmllci5HZXREb3VibGVFbnRyeSgKICAgICAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICAgICAgImkzcy1zY2FsZV95IgogICAgICAgICAgICAgICk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAoZW50cnlOYW1lID09PSAiaTNzLWF0dHJpYnV0ZS10eXBlIikgewogICAgICAgICAgICAgIGF0dHJpYnV0ZWkzc05hbWUgPSBtZXRhZGF0YVF1ZXJpZXIuR2V0U3RyaW5nRW50cnkoCiAgICAgICAgICAgICAgICBtZXRhZGF0YSwKICAgICAgICAgICAgICAgICJpM3MtYXR0cmlidXRlLXR5cGUiCiAgICAgICAgICAgICAgKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGRlY29kZWRHZW9tZXRyeVthdHRyaWJ1dGVpM3NOYW1lXSkpIHsKICAgICAgICAgIGNvbnNvbGUubG9nKCJBdHRyaWJ1dGUgYWxyZWFkeSBleGlzdHMiLCBhdHRyaWJ1dGVpM3NOYW1lKTsKICAgICAgICB9CiAgICAgICAgZGVjb2RlZEdlb21ldHJ5W2F0dHJpYnV0ZWkzc05hbWVdID0gYXR0cmlidXRlRGF0YTsKICAgICAgICBpZiAoYXR0cmlidXRlaTNzTmFtZSA9PT0gImZlYXR1cmUtaW5kZXgiKSB7CiAgICAgICAgICBkZWNvZGVkR2VvbWV0cnkuZmVhdHVyZUNvdW50Kys7CiAgICAgICAgfQogICAgICB9CiAgICAgIGRyYWNvRGVjb2Rlck1vZHVsZS5kZXN0cm95KGRyYWNvR2VvbWV0cnkpOwogICAgfQogICAgZHJhY29EZWNvZGVyTW9kdWxlLmRlc3Ryb3kobWV0YWRhdGFRdWVyaWVyKTsKICAgIGRyYWNvRGVjb2Rlck1vZHVsZS5kZXN0cm95KGRyYWNvRGVjb2Rlcik7CiAgICByZXR1cm4gZGVjb2RlZEdlb21ldHJ5OwogIH0KICBmdW5jdGlvbiBkZWNvZGVEcmFjb0F0dHJpYnV0ZShkcmFjb0RlY29kZXJNb2R1bGUsIGRyYWNvRGVjb2RlciwgZHJhY29HZW9tZXRyeSwgZHJhY29BdHRyaWJ1dGUsIHZlcnRleENvdW50KSB7CiAgICBjb25zdCBidWZmZXJTaXplID0gZHJhY29BdHRyaWJ1dGUubnVtX2NvbXBvbmVudHMoKSAqIHZlcnRleENvdW50OwogICAgbGV0IGRyYWNvQXR0cmlidXRlRGF0YTsKICAgIGNvbnN0IGhhbmRsZXJzID0gWwogICAgICBmdW5jdGlvbigpIHsKICAgICAgfSwKICAgICAgLy8gRFRfSU5WQUxJRCAtIDAKICAgICAgZnVuY3Rpb24oKSB7CiAgICAgICAgZHJhY29BdHRyaWJ1dGVEYXRhID0gbmV3IGRyYWNvRGVjb2Rlck1vZHVsZS5EcmFjb0ludDhBcnJheShidWZmZXJTaXplKTsKICAgICAgICBjb25zdCBzdWNjZXNzID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZUludDhGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEKICAgICAgICApOwogICAgICAgIGlmICghc3VjY2VzcykgewogICAgICAgICAgY29uc29sZS5lcnJvcigiQmFkIHN0cmVhbSIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhMiA9IG5ldyBJbnQ4QXJyYXkoYnVmZmVyU2l6ZSk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGJ1ZmZlclNpemU7ICsraTIpIHsKICAgICAgICAgIGF0dHJpYnV0ZURhdGEyW2kyXSA9IGRyYWNvQXR0cmlidXRlRGF0YS5HZXRWYWx1ZShpMik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBhdHRyaWJ1dGVEYXRhMjsKICAgICAgfSwKICAgICAgZnVuY3Rpb24oKSB7CiAgICAgICAgZHJhY29BdHRyaWJ1dGVEYXRhID0gbmV3IGRyYWNvRGVjb2Rlck1vZHVsZS5EcmFjb0ludDhBcnJheShidWZmZXJTaXplKTsKICAgICAgICBjb25zdCBzdWNjZXNzID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZVVJbnQ4Rm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgZHJhY29BdHRyaWJ1dGVEYXRhCiAgICAgICAgKTsKICAgICAgICBpZiAoIXN1Y2Nlc3MpIHsKICAgICAgICAgIGNvbnNvbGUuZXJyb3IoIkJhZCBzdHJlYW0iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlRGF0YTIgPSBuZXcgVWludDhBcnJheShidWZmZXJTaXplKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgYnVmZmVyU2l6ZTsgKytpMikgewogICAgICAgICAgYXR0cmlidXRlRGF0YTJbaTJdID0gZHJhY29BdHRyaWJ1dGVEYXRhLkdldFZhbHVlKGkyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZURhdGEyOwogICAgICB9LAogICAgICBmdW5jdGlvbigpIHsKICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY29EZWNvZGVyTW9kdWxlLkRyYWNvSW50MTZBcnJheShidWZmZXJTaXplKTsKICAgICAgICBjb25zdCBzdWNjZXNzID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZUludDE2Rm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgZHJhY29BdHRyaWJ1dGVEYXRhCiAgICAgICAgKTsKICAgICAgICBpZiAoIXN1Y2Nlc3MpIHsKICAgICAgICAgIGNvbnNvbGUuZXJyb3IoIkJhZCBzdHJlYW0iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlRGF0YTIgPSBuZXcgSW50MTZBcnJheShidWZmZXJTaXplKTsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgYnVmZmVyU2l6ZTsgKytpMikgewogICAgICAgICAgYXR0cmlidXRlRGF0YTJbaTJdID0gZHJhY29BdHRyaWJ1dGVEYXRhLkdldFZhbHVlKGkyKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGF0dHJpYnV0ZURhdGEyOwogICAgICB9LAogICAgICBmdW5jdGlvbigpIHsKICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY29EZWNvZGVyTW9kdWxlLkRyYWNvSW50MTZBcnJheShidWZmZXJTaXplKTsKICAgICAgICBjb25zdCBzdWNjZXNzID0gZHJhY29EZWNvZGVyLkdldEF0dHJpYnV0ZVVJbnQxNkZvckFsbFBvaW50cygKICAgICAgICAgIGRyYWNvR2VvbWV0cnksCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlRGF0YQogICAgICAgICk7CiAgICAgICAgaWYgKCFzdWNjZXNzKSB7CiAgICAgICAgICBjb25zb2xlLmVycm9yKCJCYWQgc3RyZWFtIik7CiAgICAgICAgfQogICAgICAgIGNvbnN0IGF0dHJpYnV0ZURhdGEyID0gbmV3IFVpbnQxNkFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBidWZmZXJTaXplOyArK2kyKSB7CiAgICAgICAgICBhdHRyaWJ1dGVEYXRhMltpMl0gPSBkcmFjb0F0dHJpYnV0ZURhdGEuR2V0VmFsdWUoaTIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gYXR0cmlidXRlRGF0YTI7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uKCkgewogICAgICAgIGRyYWNvQXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuRHJhY29JbnQzMkFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlSW50MzJGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEKICAgICAgICApOwogICAgICAgIGlmICghc3VjY2VzcykgewogICAgICAgICAgY29uc29sZS5lcnJvcigiQmFkIHN0cmVhbSIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhMiA9IG5ldyBJbnQzMkFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBidWZmZXJTaXplOyArK2kyKSB7CiAgICAgICAgICBhdHRyaWJ1dGVEYXRhMltpMl0gPSBkcmFjb0F0dHJpYnV0ZURhdGEuR2V0VmFsdWUoaTIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gYXR0cmlidXRlRGF0YTI7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uKCkgewogICAgICAgIGRyYWNvQXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuRHJhY29JbnQzMkFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlVUludDMyRm9yQWxsUG9pbnRzKAogICAgICAgICAgZHJhY29HZW9tZXRyeSwKICAgICAgICAgIGRyYWNvQXR0cmlidXRlLAogICAgICAgICAgZHJhY29BdHRyaWJ1dGVEYXRhCiAgICAgICAgKTsKICAgICAgICBpZiAoIXN1Y2Nlc3MpIHsKICAgICAgICAgIGNvbnNvbGUuZXJyb3IoIkJhZCBzdHJlYW0iKTsKICAgICAgICB9CiAgICAgICAgY29uc3QgYXR0cmlidXRlRGF0YTIgPSBuZXcgVWludDMyQXJyYXkoYnVmZmVyU2l6ZSk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGJ1ZmZlclNpemU7ICsraTIpIHsKICAgICAgICAgIGF0dHJpYnV0ZURhdGEyW2kyXSA9IGRyYWNvQXR0cmlidXRlRGF0YS5HZXRWYWx1ZShpMik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBhdHRyaWJ1dGVEYXRhMjsKICAgICAgfSwKICAgICAgZnVuY3Rpb24oKSB7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uKCkgewogICAgICB9LAogICAgICBmdW5jdGlvbigpIHsKICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEgPSBuZXcgZHJhY29EZWNvZGVyTW9kdWxlLkRyYWNvRmxvYXQzMkFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlRmxvYXRGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEKICAgICAgICApOwogICAgICAgIGlmICghc3VjY2VzcykgewogICAgICAgICAgY29uc29sZS5lcnJvcigiQmFkIHN0cmVhbSIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhMiA9IG5ldyBGbG9hdDMyQXJyYXkoYnVmZmVyU2l6ZSk7CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IGJ1ZmZlclNpemU7ICsraTIpIHsKICAgICAgICAgIGF0dHJpYnV0ZURhdGEyW2kyXSA9IGRyYWNvQXR0cmlidXRlRGF0YS5HZXRWYWx1ZShpMik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBhdHRyaWJ1dGVEYXRhMjsKICAgICAgfSwKICAgICAgZnVuY3Rpb24oKSB7CiAgICAgIH0sCiAgICAgIGZ1bmN0aW9uKCkgewogICAgICAgIGRyYWNvQXR0cmlidXRlRGF0YSA9IG5ldyBkcmFjb0RlY29kZXJNb2R1bGUuRHJhY29VSW50OEFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBkcmFjb0RlY29kZXIuR2V0QXR0cmlidXRlVUludDhGb3JBbGxQb2ludHMoCiAgICAgICAgICBkcmFjb0dlb21ldHJ5LAogICAgICAgICAgZHJhY29BdHRyaWJ1dGUsCiAgICAgICAgICBkcmFjb0F0dHJpYnV0ZURhdGEKICAgICAgICApOwogICAgICAgIGlmICghc3VjY2VzcykgewogICAgICAgICAgY29uc29sZS5lcnJvcigiQmFkIHN0cmVhbSIpOwogICAgICAgIH0KICAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhMiA9IG5ldyBVaW50OEFycmF5KGJ1ZmZlclNpemUpOwogICAgICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBidWZmZXJTaXplOyArK2kyKSB7CiAgICAgICAgICBhdHRyaWJ1dGVEYXRhMltpMl0gPSBkcmFjb0F0dHJpYnV0ZURhdGEuR2V0VmFsdWUoaTIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gYXR0cmlidXRlRGF0YTI7CiAgICAgIH0KICAgIF07CiAgICBjb25zdCBhdHRyaWJ1dGVEYXRhID0gaGFuZGxlcnNbZHJhY29BdHRyaWJ1dGUuZGF0YV90eXBlKCldKCk7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGRyYWNvQXR0cmlidXRlRGF0YSkpIHsKICAgICAgZHJhY29EZWNvZGVyTW9kdWxlLmRlc3Ryb3koZHJhY29BdHRyaWJ1dGVEYXRhKTsKICAgIH0KICAgIHJldHVybiBhdHRyaWJ1dGVEYXRhOwogIH0KICBmdW5jdGlvbiBkZWNvZGVCaW5hcnlHZW9tZXRyeShkYXRhLCBzY2hlbWEsIGJ1ZmZlckluZm8sIGZlYXR1cmVEYXRhKSB7CiAgICBjb25zdCBkZWNvZGVkR2VvbWV0cnkgPSB7CiAgICAgIHZlcnRleENvdW50OiAwCiAgICB9OwogICAgY29uc3QgZGF0YVZpZXcgPSBuZXcgRGF0YVZpZXcoZGF0YSk7CiAgICB0cnkgewogICAgICBsZXQgb2Zmc2V0ID0gMDsKICAgICAgZGVjb2RlZEdlb21ldHJ5LnZlcnRleENvdW50ID0gZGF0YVZpZXcuZ2V0VWludDMyKG9mZnNldCwgMSk7CiAgICAgIG9mZnNldCArPSA0OwogICAgICBkZWNvZGVkR2VvbWV0cnkuZmVhdHVyZUNvdW50ID0gZGF0YVZpZXcuZ2V0VWludDMyKG9mZnNldCwgMSk7CiAgICAgIG9mZnNldCArPSA0OwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGJ1ZmZlckluZm8pKSB7CiAgICAgICAgZm9yIChsZXQgYXR0ckluZGV4ID0gMDsgYXR0ckluZGV4IDwgYnVmZmVySW5mby5hdHRyaWJ1dGVzLmxlbmd0aDsgYXR0ckluZGV4KyspIHsKICAgICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoYmluYXJ5QXR0cmlidXRlRGVjb2RlcnNbYnVmZmVySW5mby5hdHRyaWJ1dGVzW2F0dHJJbmRleF1dKSkgewogICAgICAgICAgICBvZmZzZXQgPSBiaW5hcnlBdHRyaWJ1dGVEZWNvZGVyc1tidWZmZXJJbmZvLmF0dHJpYnV0ZXNbYXR0ckluZGV4XV0oCiAgICAgICAgICAgICAgZGVjb2RlZEdlb21ldHJ5LAogICAgICAgICAgICAgIGRhdGEsCiAgICAgICAgICAgICAgb2Zmc2V0CiAgICAgICAgICAgICk7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBjb25zb2xlLmVycm9yKAogICAgICAgICAgICAgICJVbmtub3duIGRlY29kZXIgZm9yIiwKICAgICAgICAgICAgICBidWZmZXJJbmZvLmF0dHJpYnV0ZXNbYXR0ckluZGV4XQogICAgICAgICAgICApOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBsZXQgb3JkZXJpbmcgPSBzY2hlbWEub3JkZXJpbmc7CiAgICAgICAgbGV0IGZlYXR1cmVBdHRyaWJ1dGVPcmRlciA9IHNjaGVtYS5mZWF0dXJlQXR0cmlidXRlT3JkZXI7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChmZWF0dXJlRGF0YSkgJiYgZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVEYXRhLmdlb21ldHJ5RGF0YSkgJiYgZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVEYXRhLmdlb21ldHJ5RGF0YVswXSkgJiYgZGVmaW5lZF9kZWZhdWx0KGZlYXR1cmVEYXRhLmdlb21ldHJ5RGF0YVswXS5wYXJhbXMpKSB7CiAgICAgICAgICBvcmRlcmluZyA9IE9iamVjdC5rZXlzKAogICAgICAgICAgICBmZWF0dXJlRGF0YS5nZW9tZXRyeURhdGFbMF0ucGFyYW1zLnZlcnRleEF0dHJpYnV0ZXMKICAgICAgICAgICk7CiAgICAgICAgICBmZWF0dXJlQXR0cmlidXRlT3JkZXIgPSBPYmplY3Qua2V5cygKICAgICAgICAgICAgZmVhdHVyZURhdGEuZ2VvbWV0cnlEYXRhWzBdLnBhcmFtcy5mZWF0dXJlQXR0cmlidXRlcwogICAgICAgICAgKTsKICAgICAgICB9CiAgICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IG9yZGVyaW5nLmxlbmd0aDsgaTIrKykgewogICAgICAgICAgY29uc3QgZGVjb2RlciA9IGJpbmFyeUF0dHJpYnV0ZURlY29kZXJzW29yZGVyaW5nW2kyXV07CiAgICAgICAgICBvZmZzZXQgPSBkZWNvZGVyKGRlY29kZWRHZW9tZXRyeSwgZGF0YSwgb2Zmc2V0KTsKICAgICAgICB9CiAgICAgICAgZm9yIChsZXQgajIgPSAwOyBqMiA8IGZlYXR1cmVBdHRyaWJ1dGVPcmRlci5sZW5ndGg7IGoyKyspIHsKICAgICAgICAgIGNvbnN0IGN1ckRlY29kZXIgPSBiaW5hcnlBdHRyaWJ1dGVEZWNvZGVyc1tmZWF0dXJlQXR0cmlidXRlT3JkZXJbajJdXTsKICAgICAgICAgIG9mZnNldCA9IGN1ckRlY29kZXIoZGVjb2RlZEdlb21ldHJ5LCBkYXRhLCBvZmZzZXQpOwogICAgICAgIH0KICAgICAgfQogICAgfSBjYXRjaCAoZTIpIHsKICAgICAgY29uc29sZS5lcnJvcihlMik7CiAgICB9CiAgICBkZWNvZGVkR2VvbWV0cnkuc2NhbGVfeCA9IDE7CiAgICBkZWNvZGVkR2VvbWV0cnkuc2NhbGVfeSA9IDE7CiAgICByZXR1cm4gZGVjb2RlZEdlb21ldHJ5OwogIH0KICBmdW5jdGlvbiBkZWNvZGVBbmRDcmVhdGVHbHRmKHBhcmFtZXRlcnMpIHsKICAgIGNvbnN0IGdlb21ldHJ5RGF0YSA9IGRlY29kZTIoCiAgICAgIHBhcmFtZXRlcnMuYmluYXJ5RGF0YSwKICAgICAgcGFyYW1ldGVycy5zY2hlbWEsCiAgICAgIHBhcmFtZXRlcnMuYnVmZmVySW5mbywKICAgICAgcGFyYW1ldGVycy5mZWF0dXJlRGF0YQogICAgKTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQocGFyYW1ldGVycy5nZW9pZERhdGFMaXN0KSAmJiBwYXJhbWV0ZXJzLmdlb2lkRGF0YUxpc3QubGVuZ3RoID4gMCkgewogICAgICBvcnRob21ldHJpY1RvRWxsaXBzb2lkYWwoCiAgICAgICAgZ2VvbWV0cnlEYXRhLnZlcnRleENvdW50LAogICAgICAgIGdlb21ldHJ5RGF0YS5wb3NpdGlvbnMsCiAgICAgICAgZ2VvbWV0cnlEYXRhLnNjYWxlX3gsCiAgICAgICAgZ2VvbWV0cnlEYXRhLnNjYWxlX3ksCiAgICAgICAgcGFyYW1ldGVycy5jYXJ0b2dyYXBoaWNDZW50ZXIsCiAgICAgICAgcGFyYW1ldGVycy5nZW9pZERhdGFMaXN0LAogICAgICAgIGZhbHNlCiAgICAgICk7CiAgICB9CiAgICB0cmFuc2Zvcm1Ub0xvY2FsKAogICAgICBnZW9tZXRyeURhdGEudmVydGV4Q291bnQsCiAgICAgIGdlb21ldHJ5RGF0YS5wb3NpdGlvbnMsCiAgICAgIGdlb21ldHJ5RGF0YS5ub3JtYWxzLAogICAgICBwYXJhbWV0ZXJzLmNhcnRvZ3JhcGhpY0NlbnRlciwKICAgICAgcGFyYW1ldGVycy5jYXJ0ZXNpYW5DZW50ZXIsCiAgICAgIHBhcmFtZXRlcnMucGFyZW50Um90YXRpb24sCiAgICAgIHBhcmFtZXRlcnMuZWxsaXBzb2lkUmFkaWlTcXVhcmUsCiAgICAgIGdlb21ldHJ5RGF0YS5zY2FsZV94LAogICAgICBnZW9tZXRyeURhdGEuc2NhbGVfeQogICAgKTsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQoZ2VvbWV0cnlEYXRhLnV2MHMpICYmIGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeURhdGFbInV2LXJlZ2lvbiJdKSkgewogICAgICBjcm9wVVZzKAogICAgICAgIGdlb21ldHJ5RGF0YS52ZXJ0ZXhDb3VudCwKICAgICAgICBnZW9tZXRyeURhdGEudXYwcywKICAgICAgICBnZW9tZXRyeURhdGFbInV2LXJlZ2lvbiJdCiAgICAgICk7CiAgICB9CiAgICBsZXQgZmVhdHVyZUluZGV4OwogICAgaWYgKGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeURhdGFbImZlYXR1cmUtaW5kZXgiXSkpIHsKICAgICAgZmVhdHVyZUluZGV4ID0gZ2VvbWV0cnlEYXRhWyJmZWF0dXJlLWluZGV4Il07CiAgICB9IGVsc2UgaWYgKGRlZmluZWRfZGVmYXVsdChnZW9tZXRyeURhdGFbImZhY2VSYW5nZSJdKSkgewogICAgICBmZWF0dXJlSW5kZXggPSBuZXcgQXJyYXkoZ2VvbWV0cnlEYXRhLnZlcnRleENvdW50KTsKICAgICAgZm9yIChsZXQgcmFuZ2UgPSAwOyByYW5nZSA8IGdlb21ldHJ5RGF0YVsiZmFjZVJhbmdlIl0ubGVuZ3RoIC0gMTsgcmFuZ2UgKz0gMikgewogICAgICAgIGNvbnN0IGN1ckluZGV4ID0gcmFuZ2UgLyAyOwogICAgICAgIGNvbnN0IHJhbmdlU3RhcnQgPSBnZW9tZXRyeURhdGFbImZhY2VSYW5nZSJdW3JhbmdlXTsKICAgICAgICBjb25zdCByYW5nZUVuZCA9IGdlb21ldHJ5RGF0YVsiZmFjZVJhbmdlIl1bcmFuZ2UgKyAxXTsKICAgICAgICBmb3IgKGxldCBpMiA9IHJhbmdlU3RhcnQ7IGkyIDw9IHJhbmdlRW5kOyBpMisrKSB7CiAgICAgICAgICBmZWF0dXJlSW5kZXhbaTIgKiAzXSA9IGN1ckluZGV4OwogICAgICAgICAgZmVhdHVyZUluZGV4W2kyICogMyArIDFdID0gY3VySW5kZXg7CiAgICAgICAgICBmZWF0dXJlSW5kZXhbaTIgKiAzICsgMl0gPSBjdXJJbmRleDsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmIChwYXJhbWV0ZXJzLmNhbGN1bGF0ZU5vcm1hbHMpIHsKICAgICAgY29uc3QgZGF0YSA9IGdlbmVyYXRlTm9ybWFscygKICAgICAgICBnZW9tZXRyeURhdGEudmVydGV4Q291bnQsCiAgICAgICAgZ2VvbWV0cnlEYXRhLmluZGljZXMsCiAgICAgICAgZ2VvbWV0cnlEYXRhLnBvc2l0aW9ucywKICAgICAgICBnZW9tZXRyeURhdGEubm9ybWFscywKICAgICAgICBnZW9tZXRyeURhdGEudXYwcywKICAgICAgICBnZW9tZXRyeURhdGEuY29sb3JzLAogICAgICAgIGZlYXR1cmVJbmRleAogICAgICApOwogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGRhdGEubm9ybWFscykpIHsKICAgICAgICBnZW9tZXRyeURhdGEubm9ybWFscyA9IGRhdGEubm9ybWFsczsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KGRhdGEudmVydGV4Q291bnQpKSB7CiAgICAgICAgICBnZW9tZXRyeURhdGEudmVydGV4Q291bnQgPSBkYXRhLnZlcnRleENvdW50OwogICAgICAgICAgZ2VvbWV0cnlEYXRhLmluZGljZXMgPSBkYXRhLmluZGljZXM7CiAgICAgICAgICBnZW9tZXRyeURhdGEucG9zaXRpb25zID0gZGF0YS5wb3NpdGlvbnM7CiAgICAgICAgICBnZW9tZXRyeURhdGEudXYwcyA9IGRhdGEudXYwczsKICAgICAgICAgIGdlb21ldHJ5RGF0YS5jb2xvcnMgPSBkYXRhLmNvbG9yczsKICAgICAgICAgIGZlYXR1cmVJbmRleCA9IGRhdGEuZmVhdHVyZUluZGV4OwogICAgICAgIH0KICAgICAgfQogICAgfQogICAgY29uc3QgbWVzaERhdGEgPSBnZW5lcmF0ZUdsdGZCdWZmZXIoCiAgICAgIGdlb21ldHJ5RGF0YS52ZXJ0ZXhDb3VudCwKICAgICAgZ2VvbWV0cnlEYXRhLmluZGljZXMsCiAgICAgIGdlb21ldHJ5RGF0YS5wb3NpdGlvbnMsCiAgICAgIGdlb21ldHJ5RGF0YS5ub3JtYWxzLAogICAgICBnZW9tZXRyeURhdGEudXYwcywKICAgICAgZ2VvbWV0cnlEYXRhLmNvbG9ycywKICAgICAgZmVhdHVyZUluZGV4LAogICAgICBwYXJhbWV0ZXJzCiAgICApOwogICAgY29uc3QgY3VzdG9tQXR0cmlidXRlcyA9IHsKICAgICAgcG9zaXRpb25zOiBnZW9tZXRyeURhdGEucG9zaXRpb25zLAogICAgICBpbmRpY2VzOiBnZW9tZXRyeURhdGEuaW5kaWNlcywKICAgICAgZmVhdHVyZUluZGV4LAogICAgICBzb3VyY2VVUkw6IHBhcmFtZXRlcnMudXJsLAogICAgICBjYXJ0ZXNpYW5DZW50ZXI6IHBhcmFtZXRlcnMuY2FydGVzaWFuQ2VudGVyLAogICAgICBwYXJlbnRSb3RhdGlvbjogcGFyYW1ldGVycy5wYXJlbnRSb3RhdGlvbgogICAgfTsKICAgIG1lc2hEYXRhLl9jdXN0b21BdHRyaWJ1dGVzID0gY3VzdG9tQXR0cmlidXRlczsKICAgIGNvbnN0IHJlc3VsdHMgPSB7CiAgICAgIG1lc2hEYXRhCiAgICB9OwogICAgcmV0dXJuIHJlc3VsdHM7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIGluaXRXb3JrZXIyKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IHdhc21Db25maWcgPSBwYXJhbWV0ZXJzLndlYkFzc2VtYmx5Q29uZmlnOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdCh3YXNtQ29uZmlnKSAmJiBkZWZpbmVkX2RlZmF1bHQod2FzbUNvbmZpZy53YXNtQmluYXJ5RmlsZSkpIHsKICAgICAgZHJhY28yID0gYXdhaXQgKDAsIGltcG9ydF9kcmFjb19kZWNvZGVyX25vZGVqczIuZGVmYXVsdCkod2FzbUNvbmZpZyk7CiAgICB9IGVsc2UgewogICAgICBkcmFjbzIgPSBhd2FpdCAoMCwgaW1wb3J0X2RyYWNvX2RlY29kZXJfbm9kZWpzMi5kZWZhdWx0KSgpOwogICAgfQogICAgcmV0dXJuIHRydWU7CiAgfQogIGZ1bmN0aW9uIGRlY29kZUkzUyhwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCB3YXNtQ29uZmlnID0gcGFyYW1ldGVycy53ZWJBc3NlbWJseUNvbmZpZzsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQod2FzbUNvbmZpZykpIHsKICAgICAgcmV0dXJuIGluaXRXb3JrZXIyKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpOwogICAgfQogICAgcmV0dXJuIGRlY29kZUFuZENyZWF0ZUdsdGYocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cyk7CiAgfQogIHZhciBpbXBvcnRfZHJhY29fZGVjb2Rlcl9ub2RlanMyLCBkcmFjbzIsIGNhbGN1bGF0ZUZhY2VOb3JtYWxBLCBjYWxjdWxhdGVGYWNlTm9ybWFsQiwgY2FsY3VsYXRlRmFjZU5vcm1hbEMsIGlzRWRnZVNtb290aEEsIGlzRWRnZVNtb290aEIsIGJpbmFyeUF0dHJpYnV0ZURlY29kZXJzLCBkZWNvZGVJM1NfZGVmYXVsdDsKICB2YXIgaW5pdF9kZWNvZGVJM1MgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2RlY29kZUkzUy5qcyIoKSB7CiAgICAgIGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9XZWJNZXJjYXRvclByb2plY3Rpb24oKTsKICAgICAgaW5pdF9FbGxpcHNvaWQoKTsKICAgICAgaW5pdF9DYXJ0b2dyYXBoaWMoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ29sb3IoKTsKICAgICAgaW5pdF9NYXRyaXgzKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbXBvcnRfZHJhY29fZGVjb2Rlcl9ub2RlanMyID0gX190b0VTTShyZXF1aXJlX2RyYWNvX2RlY29kZXJfbm9kZWpzKCksIDEpOwogICAgICBpbml0X3NyZ2JUb0xpbmVhcigpOwogICAgICBjYWxjdWxhdGVGYWNlTm9ybWFsQSA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgY2FsY3VsYXRlRmFjZU5vcm1hbEIgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIGNhbGN1bGF0ZUZhY2VOb3JtYWxDID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBpc0VkZ2VTbW9vdGhBID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBpc0VkZ2VTbW9vdGhCID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBiaW5hcnlBdHRyaWJ1dGVEZWNvZGVycyA9IHsKICAgICAgICBwb3NpdGlvbjogZnVuY3Rpb24oZGVjb2RlZEdlb21ldHJ5LCBkYXRhLCBvZmZzZXQpIHsKICAgICAgICAgIGNvbnN0IGNvdW50ID0gZGVjb2RlZEdlb21ldHJ5LnZlcnRleENvdW50ICogMzsKICAgICAgICAgIGRlY29kZWRHZW9tZXRyeS5wb3NpdGlvbnMgPSBuZXcgRmxvYXQzMkFycmF5KGRhdGEsIG9mZnNldCwgY291bnQpOwogICAgICAgICAgb2Zmc2V0ICs9IGNvdW50ICogNDsKICAgICAgICAgIHJldHVybiBvZmZzZXQ7CiAgICAgICAgfSwKICAgICAgICBub3JtYWw6IGZ1bmN0aW9uKGRlY29kZWRHZW9tZXRyeSwgZGF0YSwgb2Zmc2V0KSB7CiAgICAgICAgICBjb25zdCBjb3VudCA9IGRlY29kZWRHZW9tZXRyeS52ZXJ0ZXhDb3VudCAqIDM7CiAgICAgICAgICBkZWNvZGVkR2VvbWV0cnkubm9ybWFscyA9IG5ldyBGbG9hdDMyQXJyYXkoZGF0YSwgb2Zmc2V0LCBjb3VudCk7CiAgICAgICAgICBvZmZzZXQgKz0gY291bnQgKiA0OwogICAgICAgICAgcmV0dXJuIG9mZnNldDsKICAgICAgICB9LAogICAgICAgIHV2MDogZnVuY3Rpb24oZGVjb2RlZEdlb21ldHJ5LCBkYXRhLCBvZmZzZXQpIHsKICAgICAgICAgIGNvbnN0IGNvdW50ID0gZGVjb2RlZEdlb21ldHJ5LnZlcnRleENvdW50ICogMjsKICAgICAgICAgIGRlY29kZWRHZW9tZXRyeS51djBzID0gbmV3IEZsb2F0MzJBcnJheShkYXRhLCBvZmZzZXQsIGNvdW50KTsKICAgICAgICAgIG9mZnNldCArPSBjb3VudCAqIDQ7CiAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0sCiAgICAgICAgY29sb3I6IGZ1bmN0aW9uKGRlY29kZWRHZW9tZXRyeSwgZGF0YSwgb2Zmc2V0KSB7CiAgICAgICAgICBjb25zdCBjb3VudCA9IGRlY29kZWRHZW9tZXRyeS52ZXJ0ZXhDb3VudCAqIDQ7CiAgICAgICAgICBkZWNvZGVkR2VvbWV0cnkuY29sb3JzID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSwgb2Zmc2V0LCBjb3VudCk7CiAgICAgICAgICBvZmZzZXQgKz0gY291bnQ7CiAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0sCiAgICAgICAgZmVhdHVyZUlkOiBmdW5jdGlvbihkZWNvZGVkR2VvbWV0cnksIGRhdGEsIG9mZnNldCkgewogICAgICAgICAgY29uc3QgY291bnQgPSBkZWNvZGVkR2VvbWV0cnkuZmVhdHVyZUNvdW50OwogICAgICAgICAgb2Zmc2V0ICs9IGNvdW50ICogODsKICAgICAgICAgIHJldHVybiBvZmZzZXQ7CiAgICAgICAgfSwKICAgICAgICBpZDogZnVuY3Rpb24oZGVjb2RlZEdlb21ldHJ5LCBkYXRhLCBvZmZzZXQpIHsKICAgICAgICAgIGNvbnN0IGNvdW50ID0gZGVjb2RlZEdlb21ldHJ5LmZlYXR1cmVDb3VudDsKICAgICAgICAgIG9mZnNldCArPSBjb3VudCAqIDg7CiAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0sCiAgICAgICAgZmFjZVJhbmdlOiBmdW5jdGlvbihkZWNvZGVkR2VvbWV0cnksIGRhdGEsIG9mZnNldCkgewogICAgICAgICAgY29uc3QgY291bnQgPSBkZWNvZGVkR2VvbWV0cnkuZmVhdHVyZUNvdW50ICogMjsKICAgICAgICAgIGRlY29kZWRHZW9tZXRyeS5mYWNlUmFuZ2UgPSBuZXcgVWludDMyQXJyYXkoZGF0YSwgb2Zmc2V0LCBjb3VudCk7CiAgICAgICAgICBvZmZzZXQgKz0gY291bnQgKiA0OwogICAgICAgICAgcmV0dXJuIG9mZnNldDsKICAgICAgICB9LAogICAgICAgIHV2UmVnaW9uOiBmdW5jdGlvbihkZWNvZGVkR2VvbWV0cnksIGRhdGEsIG9mZnNldCkgewogICAgICAgICAgY29uc3QgY291bnQgPSBkZWNvZGVkR2VvbWV0cnkudmVydGV4Q291bnQgKiA0OwogICAgICAgICAgZGVjb2RlZEdlb21ldHJ5WyJ1di1yZWdpb24iXSA9IG5ldyBVaW50MTZBcnJheShkYXRhLCBvZmZzZXQsIGNvdW50KTsKICAgICAgICAgIG9mZnNldCArPSBjb3VudCAqIDI7CiAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0sCiAgICAgICAgcmVnaW9uOiBmdW5jdGlvbihkZWNvZGVkR2VvbWV0cnksIGRhdGEsIG9mZnNldCkgewogICAgICAgICAgY29uc3QgY291bnQgPSBkZWNvZGVkR2VvbWV0cnkudmVydGV4Q291bnQgKiA0OwogICAgICAgICAgZGVjb2RlZEdlb21ldHJ5WyJ1di1yZWdpb24iXSA9IG5ldyBVaW50MTZBcnJheShkYXRhLCBvZmZzZXQsIGNvdW50KTsKICAgICAgICAgIG9mZnNldCArPSBjb3VudCAqIDI7CiAgICAgICAgICByZXR1cm4gb2Zmc2V0OwogICAgICAgIH0KICAgICAgfTsKICAgICAgZGVjb2RlSTNTX2RlZmF1bHQgPSBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQoZGVjb2RlSTNTKTsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL0BjZXNpdW0vd2FzbS1zcGxhdHMvd2FzbV9zcGxhdHMuanMKICBmdW5jdGlvbiBnZXRVaW50OEFycmF5TWVtb3J5MCgpIHsKICAgIGlmIChjYWNoZWRVaW50OEFycmF5TWVtb3J5MCA9PT0gbnVsbCB8fCBjYWNoZWRVaW50OEFycmF5TWVtb3J5MC5ieXRlTGVuZ3RoID09PSAwKSB7CiAgICAgIGNhY2hlZFVpbnQ4QXJyYXlNZW1vcnkwID0gbmV3IFVpbnQ4QXJyYXkod2FzbS5tZW1vcnkuYnVmZmVyKTsKICAgIH0KICAgIHJldHVybiBjYWNoZWRVaW50OEFycmF5TWVtb3J5MDsKICB9CiAgZnVuY3Rpb24gZ2V0U3RyaW5nRnJvbVdhc20wKHB0ciwgbGVuKSB7CiAgICBwdHIgPSBwdHIgPj4+IDA7CiAgICByZXR1cm4gY2FjaGVkVGV4dERlY29kZXIuZGVjb2RlKGdldFVpbnQ4QXJyYXlNZW1vcnkwKCkuc3ViYXJyYXkocHRyLCBwdHIgKyBsZW4pKTsKICB9CiAgZnVuY3Rpb24gZ2V0VWludDMyQXJyYXlNZW1vcnkwKCkgewogICAgaWYgKGNhY2hlZFVpbnQzMkFycmF5TWVtb3J5MCA9PT0gbnVsbCB8fCBjYWNoZWRVaW50MzJBcnJheU1lbW9yeTAuYnl0ZUxlbmd0aCA9PT0gMCkgewogICAgICBjYWNoZWRVaW50MzJBcnJheU1lbW9yeTAgPSBuZXcgVWludDMyQXJyYXkod2FzbS5tZW1vcnkuYnVmZmVyKTsKICAgIH0KICAgIHJldHVybiBjYWNoZWRVaW50MzJBcnJheU1lbW9yeTA7CiAgfQogIGZ1bmN0aW9uIGdldEFycmF5VTMyRnJvbVdhc20wKHB0ciwgbGVuKSB7CiAgICBwdHIgPSBwdHIgPj4+IDA7CiAgICByZXR1cm4gZ2V0VWludDMyQXJyYXlNZW1vcnkwKCkuc3ViYXJyYXkocHRyIC8gNCwgcHRyIC8gNCArIGxlbik7CiAgfQogIGZ1bmN0aW9uIHBhc3NBcnJheTMyVG9XYXNtMChhcmcsIG1hbGxvYykgewogICAgY29uc3QgcHRyID0gbWFsbG9jKGFyZy5sZW5ndGggKiA0LCA0KSA+Pj4gMDsKICAgIGdldFVpbnQzMkFycmF5TWVtb3J5MCgpLnNldChhcmcsIHB0ciAvIDQpOwogICAgV0FTTV9WRUNUT1JfTEVOID0gYXJnLmxlbmd0aDsKICAgIHJldHVybiBwdHI7CiAgfQogIGZ1bmN0aW9uIHRha2VGcm9tRXh0ZXJucmVmVGFibGUwKGlkeCkgewogICAgY29uc3QgdmFsdWUgPSB3YXNtLl9fd2JpbmRnZW5fZXhwb3J0XzAuZ2V0KGlkeCk7CiAgICB3YXNtLl9fZXh0ZXJucmVmX3RhYmxlX2RlYWxsb2MoaWR4KTsKICAgIHJldHVybiB2YWx1ZTsKICB9CiAgZnVuY3Rpb24gZ2VuZXJhdGVfc3BsYXRfdGV4dHVyZShwb3NpdGlvbnMsIHNjYWxlcywgcm90YXRpb25zLCBjb2xvcnMsIGNvdW50KSB7CiAgICBjb25zdCByZXQgPSB3YXNtLmdlbmVyYXRlX3NwbGF0X3RleHR1cmUocG9zaXRpb25zLCBzY2FsZXMsIHJvdGF0aW9ucywgY29sb3JzLCBjb3VudCk7CiAgICBpZiAocmV0WzJdKSB7CiAgICAgIHRocm93IHRha2VGcm9tRXh0ZXJucmVmVGFibGUwKHJldFsxXSk7CiAgICB9CiAgICByZXR1cm4gVGV4dHVyZURhdGEuX193cmFwKHJldFswXSk7CiAgfQogIGZ1bmN0aW9uIHJhZGl4X3NvcnRfZ2F1c3NpYW5zX2luZGV4ZXMocG9zaXRpb25zX2FyciwgbW9kZWxfdmlld19hcnIsIGNvdW50KSB7CiAgICBjb25zdCByZXQgPSB3YXNtLnJhZGl4X3NvcnRfZ2F1c3NpYW5zX2luZGV4ZXMocG9zaXRpb25zX2FyciwgbW9kZWxfdmlld19hcnIsIGNvdW50KTsKICAgIGlmIChyZXRbMl0pIHsKICAgICAgdGhyb3cgdGFrZUZyb21FeHRlcm5yZWZUYWJsZTAocmV0WzFdKTsKICAgIH0KICAgIHJldHVybiB0YWtlRnJvbUV4dGVybnJlZlRhYmxlMChyZXRbMF0pOwogIH0KICBhc3luYyBmdW5jdGlvbiBfX3diZ19sb2FkKG1vZHVsZSwgaW1wb3J0cykgewogICAgaWYgKHR5cGVvZiBSZXNwb25zZSA9PT0gImZ1bmN0aW9uIiAmJiBtb2R1bGUgaW5zdGFuY2VvZiBSZXNwb25zZSkgewogICAgICBpZiAodHlwZW9mIFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlU3RyZWFtaW5nID09PSAiZnVuY3Rpb24iKSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHJldHVybiBhd2FpdCBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyhtb2R1bGUsIGltcG9ydHMpOwogICAgICAgIH0gY2F0Y2ggKGUyKSB7CiAgICAgICAgICBpZiAobW9kdWxlLmhlYWRlcnMuZ2V0KCJDb250ZW50LVR5cGUiKSAhPSAiYXBwbGljYXRpb24vd2FzbSIpIHsKICAgICAgICAgICAgY29uc29sZS53YXJuKCJgV2ViQXNzZW1ibHkuaW5zdGFudGlhdGVTdHJlYW1pbmdgIGZhaWxlZCBiZWNhdXNlIHlvdXIgc2VydmVyIGRvZXMgbm90IHNlcnZlIFdhc20gd2l0aCBgYXBwbGljYXRpb24vd2FzbWAgTUlNRSB0eXBlLiBGYWxsaW5nIGJhY2sgdG8gYFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlYCB3aGljaCBpcyBzbG93ZXIuIE9yaWdpbmFsIGVycm9yOlxuIiwgZTIpOwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgdGhyb3cgZTI7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICAgIGNvbnN0IGJ5dGVzID0gYXdhaXQgbW9kdWxlLmFycmF5QnVmZmVyKCk7CiAgICAgIHJldHVybiBhd2FpdCBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZShieXRlcywgaW1wb3J0cyk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKG1vZHVsZSwgaW1wb3J0cyk7CiAgICAgIGlmIChpbnN0YW5jZSBpbnN0YW5jZW9mIFdlYkFzc2VtYmx5Lkluc3RhbmNlKSB7CiAgICAgICAgcmV0dXJuIHsgaW5zdGFuY2UsIG1vZHVsZSB9OwogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybiBpbnN0YW5jZTsKICAgICAgfQogICAgfQogIH0KICBmdW5jdGlvbiBfX3diZ19nZXRfaW1wb3J0cygpIHsKICAgIGNvbnN0IGltcG9ydHMgPSB7fTsKICAgIGltcG9ydHMud2JnID0ge307CiAgICBpbXBvcnRzLndiZy5fX3diZ19idWZmZXJfNjA5Y2MzZWVlNTFlZDE1OCA9IGZ1bmN0aW9uKGFyZzApIHsKICAgICAgY29uc3QgcmV0ID0gYXJnMC5idWZmZXI7CiAgICAgIHJldHVybiByZXQ7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193YmdfbGVuZ3RoXzNiNGYwMjIxODhhZThkYjYgPSBmdW5jdGlvbihhcmcwKSB7CiAgICAgIGNvbnN0IHJldCA9IGFyZzAubGVuZ3RoOwogICAgICByZXR1cm4gcmV0OwogICAgfTsKICAgIGltcG9ydHMud2JnLl9fd2JnX2xlbmd0aF9hNDQ2MTkzZGMyMmMxMmY4ID0gZnVuY3Rpb24oYXJnMCkgewogICAgICBjb25zdCByZXQgPSBhcmcwLmxlbmd0aDsKICAgICAgcmV0dXJuIHJldDsKICAgIH07CiAgICBpbXBvcnRzLndiZy5fX3diZ19uZXdfNzgwYWJlZTVjMTczOWZkNyA9IGZ1bmN0aW9uKGFyZzApIHsKICAgICAgY29uc3QgcmV0ID0gbmV3IEZsb2F0MzJBcnJheShhcmcwKTsKICAgICAgcmV0dXJuIHJldDsKICAgIH07CiAgICBpbXBvcnRzLndiZy5fX3diZ19uZXdfYTEyMDAyYTdmOTFjNzViZSA9IGZ1bmN0aW9uKGFyZzApIHsKICAgICAgY29uc3QgcmV0ID0gbmV3IFVpbnQ4QXJyYXkoYXJnMCk7CiAgICAgIHJldHVybiByZXQ7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193YmdfbmV3X2UzYjMyMWRjZmVmODlmYzcgPSBmdW5jdGlvbihhcmcwKSB7CiAgICAgIGNvbnN0IHJldCA9IG5ldyBVaW50MzJBcnJheShhcmcwKTsKICAgICAgcmV0dXJuIHJldDsKICAgIH07CiAgICBpbXBvcnRzLndiZy5fX3diZ19uZXd3aXRoYnl0ZW9mZnNldGFuZGxlbmd0aF9mMWRlYWQ0NGQxZmM3MjEyID0gZnVuY3Rpb24oYXJnMCwgYXJnMSwgYXJnMikgewogICAgICBjb25zdCByZXQgPSBuZXcgVWludDMyQXJyYXkoYXJnMCwgYXJnMSA+Pj4gMCwgYXJnMiA+Pj4gMCk7CiAgICAgIHJldHVybiByZXQ7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193Ymdfc2V0XzEwYmFkOWJlZTBlOWM1OGIgPSBmdW5jdGlvbihhcmcwLCBhcmcxLCBhcmcyKSB7CiAgICAgIGFyZzAuc2V0KGFyZzEsIGFyZzIgPj4+IDApOwogICAgfTsKICAgIGltcG9ydHMud2JnLl9fd2JnX3NldF82NTU5NWJkZDg2OGIzMDA5ID0gZnVuY3Rpb24oYXJnMCwgYXJnMSwgYXJnMikgewogICAgICBhcmcwLnNldChhcmcxLCBhcmcyID4+PiAwKTsKICAgIH07CiAgICBpbXBvcnRzLndiZy5fX3diaW5kZ2VuX2luaXRfZXh0ZXJucmVmX3RhYmxlID0gZnVuY3Rpb24oKSB7CiAgICAgIGNvbnN0IHRhYmxlID0gd2FzbS5fX3diaW5kZ2VuX2V4cG9ydF8wOwogICAgICBjb25zdCBvZmZzZXQgPSB0YWJsZS5ncm93KDQpOwogICAgICB0YWJsZS5zZXQoMCwgdm9pZCAwKTsKICAgICAgdGFibGUuc2V0KG9mZnNldCArIDAsIHZvaWQgMCk7CiAgICAgIHRhYmxlLnNldChvZmZzZXQgKyAxLCBudWxsKTsKICAgICAgdGFibGUuc2V0KG9mZnNldCArIDIsIHRydWUpOwogICAgICB0YWJsZS5zZXQob2Zmc2V0ICsgMywgZmFsc2UpOwogICAgICA7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193YmluZGdlbl9tZW1vcnkgPSBmdW5jdGlvbigpIHsKICAgICAgY29uc3QgcmV0ID0gd2FzbS5tZW1vcnk7CiAgICAgIHJldHVybiByZXQ7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193YmluZGdlbl9zdHJpbmdfbmV3ID0gZnVuY3Rpb24oYXJnMCwgYXJnMSkgewogICAgICBjb25zdCByZXQgPSBnZXRTdHJpbmdGcm9tV2FzbTAoYXJnMCwgYXJnMSk7CiAgICAgIHJldHVybiByZXQ7CiAgICB9OwogICAgaW1wb3J0cy53YmcuX193YmluZGdlbl90aHJvdyA9IGZ1bmN0aW9uKGFyZzAsIGFyZzEpIHsKICAgICAgdGhyb3cgbmV3IEVycm9yKGdldFN0cmluZ0Zyb21XYXNtMChhcmcwLCBhcmcxKSk7CiAgICB9OwogICAgcmV0dXJuIGltcG9ydHM7CiAgfQogIGZ1bmN0aW9uIF9fd2JnX2luaXRfbWVtb3J5KGltcG9ydHMsIG1lbW9yeSkgewogIH0KICBmdW5jdGlvbiBfX3diZ19maW5hbGl6ZV9pbml0KGluc3RhbmNlLCBtb2R1bGUpIHsKICAgIHdhc20gPSBpbnN0YW5jZS5leHBvcnRzOwogICAgX193YmdfaW5pdC5fX3diaW5kZ2VuX3dhc21fbW9kdWxlID0gbW9kdWxlOwogICAgY2FjaGVkVWludDMyQXJyYXlNZW1vcnkwID0gbnVsbDsKICAgIGNhY2hlZFVpbnQ4QXJyYXlNZW1vcnkwID0gbnVsbDsKICAgIHdhc20uX193YmluZGdlbl9zdGFydCgpOwogICAgcmV0dXJuIHdhc207CiAgfQogIGZ1bmN0aW9uIGluaXRTeW5jKG1vZHVsZSkgewogICAgaWYgKHdhc20gIT09IHZvaWQgMCkgcmV0dXJuIHdhc207CiAgICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gInVuZGVmaW5lZCIpIHsKICAgICAgaWYgKE9iamVjdC5nZXRQcm90b3R5cGVPZihtb2R1bGUpID09PSBPYmplY3QucHJvdG90eXBlKSB7CiAgICAgICAgKHsgbW9kdWxlIH0gPSBtb2R1bGUpOwogICAgICB9IGVsc2UgewogICAgICAgIGNvbnNvbGUud2FybigidXNpbmcgZGVwcmVjYXRlZCBwYXJhbWV0ZXJzIGZvciBgaW5pdFN5bmMoKWA7IHBhc3MgYSBzaW5nbGUgb2JqZWN0IGluc3RlYWQiKTsKICAgICAgfQogICAgfQogICAgY29uc3QgaW1wb3J0cyA9IF9fd2JnX2dldF9pbXBvcnRzKCk7CiAgICBfX3diZ19pbml0X21lbW9yeShpbXBvcnRzKTsKICAgIGlmICghKG1vZHVsZSBpbnN0YW5jZW9mIFdlYkFzc2VtYmx5Lk1vZHVsZSkpIHsKICAgICAgbW9kdWxlID0gbmV3IFdlYkFzc2VtYmx5Lk1vZHVsZShtb2R1bGUpOwogICAgfQogICAgY29uc3QgaW5zdGFuY2UgPSBuZXcgV2ViQXNzZW1ibHkuSW5zdGFuY2UobW9kdWxlLCBpbXBvcnRzKTsKICAgIHJldHVybiBfX3diZ19maW5hbGl6ZV9pbml0KGluc3RhbmNlLCBtb2R1bGUpOwogIH0KICBhc3luYyBmdW5jdGlvbiBfX3diZ19pbml0KG1vZHVsZV9vcl9wYXRoKSB7CiAgICBpZiAod2FzbSAhPT0gdm9pZCAwKSByZXR1cm4gd2FzbTsKICAgIGlmICh0eXBlb2YgbW9kdWxlX29yX3BhdGggIT09ICJ1bmRlZmluZWQiKSB7CiAgICAgIGlmIChPYmplY3QuZ2V0UHJvdG90eXBlT2YobW9kdWxlX29yX3BhdGgpID09PSBPYmplY3QucHJvdG90eXBlKSB7CiAgICAgICAgKHsgbW9kdWxlX29yX3BhdGggfSA9IG1vZHVsZV9vcl9wYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjb25zb2xlLndhcm4oInVzaW5nIGRlcHJlY2F0ZWQgcGFyYW1ldGVycyBmb3IgdGhlIGluaXRpYWxpemF0aW9uIGZ1bmN0aW9uOyBwYXNzIGEgc2luZ2xlIG9iamVjdCBpbnN0ZWFkIik7CiAgICAgIH0KICAgIH0KICAgIGlmICh0eXBlb2YgbW9kdWxlX29yX3BhdGggPT09ICJ1bmRlZmluZWQiKSB7CiAgICAgIG1vZHVsZV9vcl9wYXRoID0gbmV3IFVSTCgid2FzbV9zcGxhdHNfYmcud2FzbSIsIGltcG9ydF9tZXRhMi51cmwpOwogICAgfQogICAgY29uc3QgaW1wb3J0cyA9IF9fd2JnX2dldF9pbXBvcnRzKCk7CiAgICBpZiAodHlwZW9mIG1vZHVsZV9vcl9wYXRoID09PSAic3RyaW5nIiB8fCB0eXBlb2YgUmVxdWVzdCA9PT0gImZ1bmN0aW9uIiAmJiBtb2R1bGVfb3JfcGF0aCBpbnN0YW5jZW9mIFJlcXVlc3QgfHwgdHlwZW9mIFVSTCA9PT0gImZ1bmN0aW9uIiAmJiBtb2R1bGVfb3JfcGF0aCBpbnN0YW5jZW9mIFVSTCkgewogICAgICBtb2R1bGVfb3JfcGF0aCA9IGZldGNoKG1vZHVsZV9vcl9wYXRoKTsKICAgIH0KICAgIF9fd2JnX2luaXRfbWVtb3J5KGltcG9ydHMpOwogICAgY29uc3QgeyBpbnN0YW5jZSwgbW9kdWxlIH0gPSBhd2FpdCBfX3diZ19sb2FkKGF3YWl0IG1vZHVsZV9vcl9wYXRoLCBpbXBvcnRzKTsKICAgIHJldHVybiBfX3diZ19maW5hbGl6ZV9pbml0KGluc3RhbmNlLCBtb2R1bGUpOwogIH0KICB2YXIgaW1wb3J0X21ldGEyLCB3YXNtLCBjYWNoZWRUZXh0RGVjb2RlciwgY2FjaGVkVWludDhBcnJheU1lbW9yeTAsIGNhY2hlZFVpbnQzMkFycmF5TWVtb3J5MCwgV0FTTV9WRUNUT1JfTEVOLCBUZXh0dXJlRGF0YUZpbmFsaXphdGlvbiwgVGV4dHVyZURhdGE7CiAgdmFyIGluaXRfd2FzbV9zcGxhdHMgPSBfX2VzbSh7CiAgICAibm9kZV9tb2R1bGVzL0BjZXNpdW0vd2FzbS1zcGxhdHMvd2FzbV9zcGxhdHMuanMiKCkgewogICAgICBpbXBvcnRfbWV0YTIgPSB7fTsKICAgICAgY2FjaGVkVGV4dERlY29kZXIgPSB0eXBlb2YgVGV4dERlY29kZXIgIT09ICJ1bmRlZmluZWQiID8gbmV3IFRleHREZWNvZGVyKCJ1dGYtOCIsIHsgaWdub3JlQk9NOiB0cnVlLCBmYXRhbDogdHJ1ZSB9KSA6IHsgZGVjb2RlOiAoKSA9PiB7CiAgICAgICAgdGhyb3cgRXJyb3IoIlRleHREZWNvZGVyIG5vdCBhdmFpbGFibGUiKTsKICAgICAgfSB9OwogICAgICBpZiAodHlwZW9mIFRleHREZWNvZGVyICE9PSAidW5kZWZpbmVkIikgewogICAgICAgIGNhY2hlZFRleHREZWNvZGVyLmRlY29kZSgpOwogICAgICB9CiAgICAgIGNhY2hlZFVpbnQ4QXJyYXlNZW1vcnkwID0gbnVsbDsKICAgICAgY2FjaGVkVWludDMyQXJyYXlNZW1vcnkwID0gbnVsbDsKICAgICAgV0FTTV9WRUNUT1JfTEVOID0gMDsKICAgICAgVGV4dHVyZURhdGFGaW5hbGl6YXRpb24gPSB0eXBlb2YgRmluYWxpemF0aW9uUmVnaXN0cnkgPT09ICJ1bmRlZmluZWQiID8geyByZWdpc3RlcjogKCkgPT4gewogICAgICB9LCB1bnJlZ2lzdGVyOiAoKSA9PiB7CiAgICAgIH0gfSA6IG5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeSgocHRyKSA9PiB3YXNtLl9fd2JnX3RleHR1cmVkYXRhX2ZyZWUocHRyID4+PiAwLCAxKSk7CiAgICAgIFRleHR1cmVEYXRhID0gY2xhc3MgX1RleHR1cmVEYXRhIHsKICAgICAgICBzdGF0aWMgX193cmFwKHB0cikgewogICAgICAgICAgcHRyID0gcHRyID4+PiAwOwogICAgICAgICAgY29uc3Qgb2JqID0gT2JqZWN0LmNyZWF0ZShfVGV4dHVyZURhdGEucHJvdG90eXBlKTsKICAgICAgICAgIG9iai5fX3diZ19wdHIgPSBwdHI7CiAgICAgICAgICBUZXh0dXJlRGF0YUZpbmFsaXphdGlvbi5yZWdpc3RlcihvYmosIG9iai5fX3diZ19wdHIsIG9iaik7CiAgICAgICAgICByZXR1cm4gb2JqOwogICAgICAgIH0KICAgICAgICBfX2Rlc3Ryb3lfaW50b19yYXcoKSB7CiAgICAgICAgICBjb25zdCBwdHIgPSB0aGlzLl9fd2JnX3B0cjsKICAgICAgICAgIHRoaXMuX193YmdfcHRyID0gMDsKICAgICAgICAgIFRleHR1cmVEYXRhRmluYWxpemF0aW9uLnVucmVnaXN0ZXIodGhpcyk7CiAgICAgICAgICByZXR1cm4gcHRyOwogICAgICAgIH0KICAgICAgICBmcmVlKCkgewogICAgICAgICAgY29uc3QgcHRyID0gdGhpcy5fX2Rlc3Ryb3lfaW50b19yYXcoKTsKICAgICAgICAgIHdhc20uX193YmdfdGV4dHVyZWRhdGFfZnJlZShwdHIsIDApOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIHRoZSB1bmRlcmx5aW5nIHRleHR1cmUgZGF0YS4gQWx3YXlzIHJldHVybnMgYSBjb3B5LgogICAgICAgICAqIEByZXR1cm5zIHtVaW50MzJBcnJheX0KICAgICAgICAgKi8KICAgICAgICBnZXQgZGF0YSgpIHsKICAgICAgICAgIGNvbnN0IHJldCA9IHdhc20udGV4dHVyZWRhdGFfZGF0YSh0aGlzLl9fd2JnX3B0cik7CiAgICAgICAgICB2YXIgdjEyID0gZ2V0QXJyYXlVMzJGcm9tV2FzbTAocmV0WzBdLCByZXRbMV0pLnNsaWNlKCk7CiAgICAgICAgICB3YXNtLl9fd2JpbmRnZW5fZnJlZShyZXRbMF0sIHJldFsxXSAqIDQsIDQpOwogICAgICAgICAgcmV0dXJuIHYxMjsKICAgICAgICB9CiAgICAgICAgLyoqCiAgICAgICAgICogR2V0dGVyIGZvciB0aGUgd2lkdGggb2YgdGhlIHRleHR1cmUgaW4gcGl4ZWxzLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgZ2V0IHdpZHRoKCkgewogICAgICAgICAgY29uc3QgcmV0ID0gd2FzbS50ZXh0dXJlZGF0YV93aWR0aCh0aGlzLl9fd2JnX3B0cik7CiAgICAgICAgICByZXR1cm4gcmV0ID4+PiAwOwogICAgICAgIH0KICAgICAgICAvKioKICAgICAgICAgKiBHZXR0ZXIgZm9yIHRoZSBoZWlnaHQgb2YgdGhlIHRleHR1cmUgaW4gcGl4ZWxzLgogICAgICAgICAqIEByZXR1cm5zIHtudW1iZXJ9CiAgICAgICAgICovCiAgICAgICAgZ2V0IGhlaWdodCgpIHsKICAgICAgICAgIGNvbnN0IHJldCA9IHdhc20udGV4dHVyZWRhdGFfaGVpZ2h0KHRoaXMuX193YmdfcHRyKTsKICAgICAgICAgIHJldHVybiByZXQgPj4+IDA7CiAgICAgICAgfQogICAgICAgIC8qKgogICAgICAgICAqIENyZWF0ZXMgYSBuZXcgdGV4dHVyZSBkYXRhIG9iamVjdCB3aXRoIHRoZSB1bmRlcmx5aW5nIGRhdGEsIHdpZHRoLCBhbmQgaGVpZ2h0LgogICAgICAgICAqIEBwYXJhbSB7VWludDMyQXJyYXl9IGRhdGEKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGgKICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0CiAgICAgICAgICogQHJldHVybnMge1RleHR1cmVEYXRhfQogICAgICAgICAqLwogICAgICAgIHN0YXRpYyBuZXcoZGF0YSwgd2lkdGgsIGhlaWdodCkgewogICAgICAgICAgY29uc3QgcHRyMCA9IHBhc3NBcnJheTMyVG9XYXNtMChkYXRhLCB3YXNtLl9fd2JpbmRnZW5fbWFsbG9jKTsKICAgICAgICAgIGNvbnN0IGxlbjAgPSBXQVNNX1ZFQ1RPUl9MRU47CiAgICAgICAgICBjb25zdCByZXQgPSB3YXNtLnRleHR1cmVkYXRhX25ldyhwdHIwLCBsZW4wLCB3aWR0aCwgaGVpZ2h0KTsKICAgICAgICAgIHJldHVybiBfVGV4dHVyZURhdGEuX193cmFwKHJldCk7CiAgICAgICAgfQogICAgICB9OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvZ2F1c3NpYW5TcGxhdFNvcnRlci5qcwogIHZhciBnYXVzc2lhblNwbGF0U29ydGVyX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChnYXVzc2lhblNwbGF0U29ydGVyX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGdhdXNzaWFuU3BsYXRTb3J0ZXJfZGVmYXVsdAogIH0pOwogIGFzeW5jIGZ1bmN0aW9uIGluaXRXb3JrZXIzKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IHdhc21Db25maWcgPSBwYXJhbWV0ZXJzLndlYkFzc2VtYmx5Q29uZmlnOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdCh3YXNtQ29uZmlnKSAmJiBkZWZpbmVkX2RlZmF1bHQod2FzbUNvbmZpZy53YXNtQmluYXJ5KSkgewogICAgICBpbml0U3luYyh7IG1vZHVsZTogd2FzbUNvbmZpZy53YXNtQmluYXJ5IH0pOwogICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICB9CiAgZnVuY3Rpb24gZ2VuZXJhdGVHYXVzc2lhblNvcnRXb3JrZXIocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3Qgd2FzbUNvbmZpZyA9IHBhcmFtZXRlcnMud2ViQXNzZW1ibHlDb25maWc7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHdhc21Db25maWcpKSB7CiAgICAgIHJldHVybiBpbml0V29ya2VyMyhwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgIH0KICAgIGNvbnN0IHsgcHJpbWl0aXZlLCBzb3J0VHlwZSB9ID0gcGFyYW1ldGVyczsKICAgIGlmIChzb3J0VHlwZSA9PT0gIkluZGV4IikgewogICAgICByZXR1cm4gcmFkaXhfc29ydF9nYXVzc2lhbnNfaW5kZXhlcygKICAgICAgICBwcmltaXRpdmUucG9zaXRpb25zLAogICAgICAgIHByaW1pdGl2ZS5tb2RlbFZpZXcsCiAgICAgICAgcHJpbWl0aXZlLmNvdW50CiAgICAgICk7CiAgICB9CiAgfQogIHZhciBnYXVzc2lhblNwbGF0U29ydGVyX2RlZmF1bHQ7CiAgdmFyIGluaXRfZ2F1c3NpYW5TcGxhdFNvcnRlciA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvZ2F1c3NpYW5TcGxhdFNvcnRlci5qcyIoKSB7CiAgICAgIGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF93YXNtX3NwbGF0cygpOwogICAgICBnYXVzc2lhblNwbGF0U29ydGVyX2RlZmF1bHQgPSBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQoZ2VuZXJhdGVHYXVzc2lhblNvcnRXb3JrZXIpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvZ2F1c3NpYW5TcGxhdFRleHR1cmVHZW5lcmF0b3IuanMKICB2YXIgZ2F1c3NpYW5TcGxhdFRleHR1cmVHZW5lcmF0b3JfZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yX2RlZmF1bHQKICB9KTsKICBhc3luYyBmdW5jdGlvbiBpbml0V29ya2VyNChwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBjb25zdCB3YXNtQ29uZmlnID0gcGFyYW1ldGVycy53ZWJBc3NlbWJseUNvbmZpZzsKICAgIGlmIChkZWZpbmVkX2RlZmF1bHQod2FzbUNvbmZpZykgJiYgZGVmaW5lZF9kZWZhdWx0KHdhc21Db25maWcud2FzbUJpbmFyeSkpIHsKICAgICAgaW5pdFN5bmMoeyBtb2R1bGU6IHdhc21Db25maWcud2FzbUJpbmFyeSB9KTsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICByZXR1cm4gZmFsc2U7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIGdlbmVyYXRlU3BsYXRUZXh0dXJlV29ya2VyKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IHdhc21Db25maWcgPSBwYXJhbWV0ZXJzLndlYkFzc2VtYmx5Q29uZmlnOwogICAgaWYgKGRlZmluZWRfZGVmYXVsdCh3YXNtQ29uZmlnKSkgewogICAgICByZXR1cm4gaW5pdFdvcmtlcjQocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cyk7CiAgICB9CiAgICBjb25zdCB7IGF0dHJpYnV0ZXMsIGNvdW50IH0gPSBwYXJhbWV0ZXJzOwogICAgY29uc3QgcmVzdWx0ID0gZ2VuZXJhdGVfc3BsYXRfdGV4dHVyZSgKICAgICAgYXR0cmlidXRlcy5wb3NpdGlvbnMsCiAgICAgIGF0dHJpYnV0ZXMuc2NhbGVzLAogICAgICBhdHRyaWJ1dGVzLnJvdGF0aW9ucywKICAgICAgYXR0cmlidXRlcy5jb2xvcnMsCiAgICAgIGNvdW50CiAgICApOwogICAgcmV0dXJuIHsKICAgICAgZGF0YTogcmVzdWx0LmRhdGEsCiAgICAgIHdpZHRoOiByZXN1bHQud2lkdGgsCiAgICAgIGhlaWdodDogcmVzdWx0LmhlaWdodAogICAgfTsKICB9CiAgdmFyIGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yX2RlZmF1bHQ7CiAgdmFyIGluaXRfZ2F1c3NpYW5TcGxhdFRleHR1cmVHZW5lcmF0b3IgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2dhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yLmpzIigpIHsKICAgICAgaW5pdF9jcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X3dhc21fc3BsYXRzKCk7CiAgICAgIGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yX2RlZmF1bHQgPSBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyX2RlZmF1bHQoZ2VuZXJhdGVTcGxhdFRleHR1cmVXb3JrZXIpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlci5qcwogIHZhciBpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydChpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXJfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgYWFiYnMgPSBuZXcgRmxvYXQ2NEFycmF5KHBhcmFtZXRlcnMuYWFiYnMpOwogICAgY29uc3Qgbm9kZUFBQkJzID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogNCB9LCAoXzIsIGkyKSA9PiB7CiAgICAgIGNvbnN0IG1pbjMgPSBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKGFhYmJzLCBpMiAqIDYsIHNjcmF0Y2hBQUJCQ29ybmVyTWluKTsKICAgICAgY29uc3QgbWF4MyA9IENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2soYWFiYnMsIGkyICogNiArIDMsIHNjcmF0Y2hBQUJCQ29ybmVyTWF4KTsKICAgICAgcmV0dXJuIEF4aXNBbGlnbmVkQm91bmRpbmdCb3hfZGVmYXVsdC5mcm9tQ29ybmVycygKICAgICAgICBtaW4zLAogICAgICAgIG1heDMsCiAgICAgICAgbmV3IEF4aXNBbGlnbmVkQm91bmRpbmdCb3hfZGVmYXVsdCgpCiAgICAgICk7CiAgICB9KTsKICAgIGNvbnN0IGludmVyc2VUcmFuc2Zvcm1BcnJheSA9IG5ldyBGbG9hdDY0QXJyYXkocGFyYW1ldGVycy5pbnZlcnNlVHJhbnNmb3JtKTsKICAgIGNvbnN0IGludmVyc2VUcmFuc2Zvcm0gPSBNYXRyaXg0X2RlZmF1bHQudW5wYWNrKAogICAgICBpbnZlcnNlVHJhbnNmb3JtQXJyYXksCiAgICAgIDAsCiAgICAgIG5ldyBNYXRyaXg0X2RlZmF1bHQoKQogICAgKTsKICAgIGNvbnN0IHRyaWFuZ2xlSW5kaWNlcyA9IG5ldyBVaW50MzJBcnJheShwYXJhbWV0ZXJzLnRyaWFuZ2xlSW5kaWNlcyk7CiAgICBjb25zdCB0cmlhbmdsZVBvc2l0aW9ucyA9IG5ldyBGbG9hdDY0QXJyYXkocGFyYW1ldGVycy50cmlhbmdsZVBvc2l0aW9ucyk7CiAgICBjb25zdCBpbnRlcnNlY3RpbmdUcmlhbmdsZXNBcnJheXMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiA0IH0sICgpID0+IFtdKTsKICAgIGZvciAobGV0IGoyID0gMDsgajIgPCB0cmlhbmdsZUluZGljZXMubGVuZ3RoOyBqMisrKSB7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2sodHJpYW5nbGVQb3NpdGlvbnMsIGoyICogOSwgc2NyYXRjaFRyaWFuZ2xlUG9pbnRzMlswXSk7CiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC51bnBhY2sodHJpYW5nbGVQb3NpdGlvbnMsIGoyICogOSArIDMsIHNjcmF0Y2hUcmlhbmdsZVBvaW50czJbMV0pOwogICAgICBDYXJ0ZXNpYW4zX2RlZmF1bHQudW5wYWNrKHRyaWFuZ2xlUG9zaXRpb25zLCBqMiAqIDkgKyA2LCBzY3JhdGNoVHJpYW5nbGVQb2ludHMyWzJdKTsKICAgICAgY29uc3QgdHJpYW5nbGVBQUJCID0gY3JlYXRlQUFCQkZyb21UcmlhbmdsZSgKICAgICAgICBpbnZlcnNlVHJhbnNmb3JtLAogICAgICAgIHNjcmF0Y2hUcmlhbmdsZVBvaW50czIKICAgICAgKTsKICAgICAgZm9yIChsZXQgaTIgPSAwOyBpMiA8IDQ7IGkyKyspIHsKICAgICAgICBjb25zdCBhYWJic0ludGVyc2VjdCA9IG5vZGVBQUJCc1tpMl0uaW50ZXJzZWN0QXhpc0FsaWduZWRCb3VuZGluZ0JveCh0cmlhbmdsZUFBQkIpOwogICAgICAgIGlmICghYWFiYnNJbnRlcnNlY3QpIHsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBpbnRlcnNlY3RpbmdUcmlhbmdsZXNBcnJheXNbaTJdLnB1c2godHJpYW5nbGVJbmRpY2VzW2oyXSk7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IGludGVyc2VjdGluZ1RyaWFuZ2xlc1R5cGVkQXJyYXlzID0gaW50ZXJzZWN0aW5nVHJpYW5nbGVzQXJyYXlzLm1hcCgKICAgICAgKGFycmF5KSA9PiB7CiAgICAgICAgY29uc3QgdWludEFycmF5ID0gbmV3IFVpbnQzMkFycmF5KGFycmF5KTsKICAgICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2godWludEFycmF5LmJ1ZmZlcik7CiAgICAgICAgcmV0dXJuIHVpbnRBcnJheS5idWZmZXI7CiAgICAgIH0KICAgICk7CiAgICByZXR1cm4gewogICAgICBpbnRlcnNlY3RpbmdUcmlhbmdsZXNBcnJheXM6IGludGVyc2VjdGluZ1RyaWFuZ2xlc1R5cGVkQXJyYXlzCiAgICB9OwogIH0KICBmdW5jdGlvbiBjcmVhdGVBQUJCRnJvbVRyaWFuZ2xlKGludmVyc2VUcmFuc2Zvcm0sIHRyaWFuZ2xlUG9pbnRzKSB7CiAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICBpbnZlcnNlVHJhbnNmb3JtLAogICAgICB0cmlhbmdsZVBvaW50c1swXSwKICAgICAgdHJpYW5nbGVQb2ludHNbMF0KICAgICk7CiAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICBpbnZlcnNlVHJhbnNmb3JtLAogICAgICB0cmlhbmdsZVBvaW50c1sxXSwKICAgICAgdHJpYW5nbGVQb2ludHNbMV0KICAgICk7CiAgICBNYXRyaXg0X2RlZmF1bHQubXVsdGlwbHlCeVBvaW50KAogICAgICBpbnZlcnNlVHJhbnNmb3JtLAogICAgICB0cmlhbmdsZVBvaW50c1syXSwKICAgICAgdHJpYW5nbGVQb2ludHNbMl0KICAgICk7CiAgICBjb25zdCBhYWJiID0gQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21Qb2ludHMoCiAgICAgIHRyaWFuZ2xlUG9pbnRzLAogICAgICBzY3JhdGNoVHJpYW5nbGVBQUJCCiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0LmNsYW1wKGFhYmIubWluaW11bSwgVElMRV9BQUJCX01JTiwgVElMRV9BQUJCX01BWCwgYWFiYi5taW5pbXVtKTsKICAgIENhcnRlc2lhbjNfZGVmYXVsdC5jbGFtcChhYWJiLm1heGltdW0sIFRJTEVfQUFCQl9NSU4sIFRJTEVfQUFCQl9NQVgsIGFhYmIubWF4aW11bSk7CiAgICByZXR1cm4gYWFiYjsKICB9CiAgdmFyIHNjcmF0Y2hBQUJCQ29ybmVyTWluLCBzY3JhdGNoQUFCQkNvcm5lck1heCwgc2NyYXRjaFRyaWFuZ2xlUG9pbnRzMiwgc2NyYXRjaFRyaWFuZ2xlQUFCQiwgVElMRV9BQUJCX01BWCwgVElMRV9BQUJCX01JTiwgaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlcl9kZWZhdWx0OwogIHZhciBpbml0X2luY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2luY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIuanMiKCkgewogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgaW5pdF9NYXRyaXg0KCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0F4aXNBbGlnbmVkQm91bmRpbmdCb3goKTsKICAgICAgc2NyYXRjaEFBQkJDb3JuZXJNaW4gPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHNjcmF0Y2hBQUJCQ29ybmVyTWF4ID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBzY3JhdGNoVHJpYW5nbGVQb2ludHMyID0gWwogICAgICAgIG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwKICAgICAgICBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCksCiAgICAgICAgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpCiAgICAgIF07CiAgICAgIHNjcmF0Y2hUcmlhbmdsZUFBQkIgPSBuZXcgQXhpc0FsaWduZWRCb3VuZGluZ0JveF9kZWZhdWx0KCk7CiAgICAgIFRJTEVfQUFCQl9NQVggPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KDAuNSwgMC41LCAwLjUpOwogICAgICBUSUxFX0FBQkJfTUlOID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgtMC41LCAtMC41LCAtMC41KTsKICAgICAgaW5jcmVtZW50YWxseUJ1aWxkVGVycmFpblBpY2tlcl9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1JlbmRlcmVyL1BpeGVsRGF0YXR5cGUuanMKICB2YXIgUGl4ZWxEYXRhdHlwZSwgUGl4ZWxEYXRhdHlwZV9kZWZhdWx0OwogIHZhciBpbml0X1BpeGVsRGF0YXR5cGUgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9SZW5kZXJlci9QaXhlbERhdGF0eXBlLmpzIigpIHsKICAgICAgaW5pdF9XZWJHTENvbnN0YW50cygpOwogICAgICBQaXhlbERhdGF0eXBlID0gewogICAgICAgIFVOU0lHTkVEX0JZVEU6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfQllURSwKICAgICAgICBVTlNJR05FRF9TSE9SVDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVCwKICAgICAgICBVTlNJR05FRF9JTlQ6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfSU5ULAogICAgICAgIEZMT0FUOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkZMT0FULAogICAgICAgIEhBTEZfRkxPQVQ6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuSEFMRl9GTE9BVF9PRVMsCiAgICAgICAgVU5TSUdORURfSU5UXzI0Xzg6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfSU5UXzI0XzgsCiAgICAgICAgVU5TSUdORURfU0hPUlRfNF80XzRfNDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVF80XzRfNF80LAogICAgICAgIFVOU0lHTkVEX1NIT1JUXzVfNV81XzE6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfU0hPUlRfNV81XzVfMSwKICAgICAgICBVTlNJR05FRF9TSE9SVF81XzZfNTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVF81XzZfNQogICAgICB9OwogICAgICBQaXhlbERhdGF0eXBlLnRvV2ViR0xDb25zdGFudCA9IGZ1bmN0aW9uKHBpeGVsRGF0YXR5cGUsIGNvbnRleHQpIHsKICAgICAgICBzd2l0Y2ggKHBpeGVsRGF0YXR5cGUpIHsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9CWVRFOgogICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9CWVRFOwogICAgICAgICAgY2FzZSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOgogICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVDsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9JTlQ6CiAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlVOU0lHTkVEX0lOVDsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5GTE9BVDoKICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuRkxPQVQ7CiAgICAgICAgICBjYXNlIFBpeGVsRGF0YXR5cGUuSEFMRl9GTE9BVDoKICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQud2ViZ2wyID8gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5IQUxGX0ZMT0FUIDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5IQUxGX0ZMT0FUX09FUzsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9JTlRfMjRfODoKICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfSU5UXzI0Xzg7CiAgICAgICAgICBjYXNlIFBpeGVsRGF0YXR5cGUuVU5TSUdORURfU0hPUlRfNF80XzRfNDoKICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuVU5TSUdORURfU0hPUlRfNF80XzRfNDsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9TSE9SVF81XzVfNV8xOgogICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5VTlNJR05FRF9TSE9SVF81XzVfNV8xOwogICAgICAgICAgY2FzZSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUXzVfNl81OgogICAgICAgICAgICByZXR1cm4gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9TSE9SVF81XzZfNTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFBpeGVsRGF0YXR5cGUuaXNQYWNrZWQgPSBmdW5jdGlvbihwaXhlbERhdGF0eXBlKSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGUuVU5TSUdORURfSU5UXzI0XzggfHwgcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9TSE9SVF80XzRfNF80IHx8IHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGUuVU5TSUdORURfU0hPUlRfNV81XzVfMSB8fCBwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUXzVfNl81OwogICAgICB9OwogICAgICBQaXhlbERhdGF0eXBlLnNpemVJbkJ5dGVzID0gZnVuY3Rpb24ocGl4ZWxEYXRhdHlwZSkgewogICAgICAgIHN3aXRjaCAocGl4ZWxEYXRhdHlwZSkgewogICAgICAgICAgY2FzZSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX0JZVEU6CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgICAgY2FzZSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUOgogICAgICAgICAgY2FzZSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUXzRfNF80XzQ6CiAgICAgICAgICBjYXNlIFBpeGVsRGF0YXR5cGUuVU5TSUdORURfU0hPUlRfNV81XzVfMToKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9TSE9SVF81XzZfNToKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5IQUxGX0ZMT0FUOgogICAgICAgICAgICByZXR1cm4gMjsKICAgICAgICAgIGNhc2UgUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9JTlQ6CiAgICAgICAgICBjYXNlIFBpeGVsRGF0YXR5cGUuRkxPQVQ6CiAgICAgICAgICBjYXNlIFBpeGVsRGF0YXR5cGUuVU5TSUdORURfSU5UXzI0Xzg6CiAgICAgICAgICAgIHJldHVybiA0OwogICAgICAgIH0KICAgICAgfTsKICAgICAgUGl4ZWxEYXRhdHlwZS52YWxpZGF0ZSA9IGZ1bmN0aW9uKHBpeGVsRGF0YXR5cGUpIHsKICAgICAgICByZXR1cm4gcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9CWVRFIHx8IHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGUuVU5TSUdORURfU0hPUlQgfHwgcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9JTlQgfHwgcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5GTE9BVCB8fCBwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlLkhBTEZfRkxPQVQgfHwgcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9JTlRfMjRfOCB8fCBwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX1NIT1JUXzRfNF80XzQgfHwgcGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZS5VTlNJR05FRF9TSE9SVF81XzVfNV8xIHx8IHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGUuVU5TSUdORURfU0hPUlRfNV82XzU7CiAgICAgIH07CiAgICAgIFBpeGVsRGF0YXR5cGUuZ2V0VHlwZWRBcnJheUNvbnN0cnVjdG9yID0gZnVuY3Rpb24ocGl4ZWxEYXRhdHlwZSkgewogICAgICAgIGNvbnN0IHNpemVJbkJ5dGVzID0gUGl4ZWxEYXRhdHlwZS5zaXplSW5CeXRlcyhwaXhlbERhdGF0eXBlKTsKICAgICAgICBpZiAoc2l6ZUluQnl0ZXMgPT09IFVpbnQ4QXJyYXkuQllURVNfUEVSX0VMRU1FTlQpIHsKICAgICAgICAgIHJldHVybiBVaW50OEFycmF5OwogICAgICAgIH0gZWxzZSBpZiAoc2l6ZUluQnl0ZXMgPT09IFVpbnQxNkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UKSB7CiAgICAgICAgICByZXR1cm4gVWludDE2QXJyYXk7CiAgICAgICAgfSBlbHNlIGlmIChzaXplSW5CeXRlcyA9PT0gRmxvYXQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UICYmIHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGUuRkxPQVQpIHsKICAgICAgICAgIHJldHVybiBGbG9hdDMyQXJyYXk7CiAgICAgICAgfQogICAgICAgIHJldHVybiBVaW50MzJBcnJheTsKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShQaXhlbERhdGF0eXBlKTsKICAgICAgUGl4ZWxEYXRhdHlwZV9kZWZhdWx0ID0gUGl4ZWxEYXRhdHlwZTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL1BpeGVsRm9ybWF0LmpzCiAgdmFyIFBpeGVsRm9ybWF0LCBQaXhlbEZvcm1hdF9kZWZhdWx0OwogIHZhciBpbml0X1BpeGVsRm9ybWF0ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9QaXhlbEZvcm1hdC5qcyIoKSB7CiAgICAgIGluaXRfUGl4ZWxEYXRhdHlwZSgpOwogICAgICBpbml0X1dlYkdMQ29uc3RhbnRzKCk7CiAgICAgIFBpeGVsRm9ybWF0ID0gewogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgYSBkZXB0aCB2YWx1ZS4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgREVQVEhfQ09NUE9ORU5UOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkRFUFRIX0NPTVBPTkVOVCwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIGEgZGVwdGggYW5kIHN0ZW5jaWwgdmFsdWUsIG1vc3Qgb2Z0ZW4gdXNlZCB3aXRoIHtAbGluayBQaXhlbERhdGF0eXBlLlVOU0lHTkVEX0lOVF8yNF84fS4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgREVQVEhfU1RFTkNJTDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5ERVBUSF9TVEVOQ0lMLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgYW4gYWxwaGEgY2hhbm5lbC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgQUxQSEE6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuQUxQSEEsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyBhIHJlZCBjaGFubmVsCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJFRDogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SRUQsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyByZWQgYW5kIGdyZWVuIGNoYW5uZWxzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSRzogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SRywKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGFuZCBibHVlIGNoYW5uZWxzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0I6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYmx1ZSwgYW5kIGFscGhhIGNoYW5uZWxzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0JBOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHQkEsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyBhIHJlZCBjaGFubmVsIGFzIGFuIGludGVnZXIuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSRURfSU5URUdFUjogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SRURfSU5URUdFUiwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCBhbmQgZ3JlZW4gY2hhbm5lbHMgYXMgaW50ZWdlcnMuCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR19JTlRFR0VSOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHX0lOVEVHRVIsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyByZWQsIGdyZWVuLCBhbmQgYmx1ZSBjaGFubmVscyBhcyBpbnRlZ2Vycy4KICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJHQl9JTlRFR0VSOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHQl9JTlRFR0VSLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYmx1ZSwgYW5kIGFscGhhIGNoYW5uZWxzIGFzIGludGVnZXJzLgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCQV9JTlRFR0VSOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHQkFfSU5URUdFUiwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIGEgbHVtaW5hbmNlIChpbnRlbnNpdHkpIGNoYW5uZWwuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIExVTUlOQU5DRTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5MVU1JTkFOQ0UsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyBsdW1pbmFuY2UgKGludGVuc2l0eSkgYW5kIGFscGhhIGNoYW5uZWxzLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBMVU1JTkFOQ0VfQUxQSEE6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuTFVNSU5BTkNFX0FMUEhBLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYW5kIGJsdWUgY2hhbm5lbHMgdGhhdCBpcyBEWFQxIGNvbXByZXNzZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJHQl9EWFQxOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkNPTVBSRVNTRURfUkdCX1MzVENfRFhUMV9FWFQsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyByZWQsIGdyZWVuLCBibHVlLCBhbmQgYWxwaGEgY2hhbm5lbHMgdGhhdCBpcyBEWFQxIGNvbXByZXNzZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJHQkFfRFhUMTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQxX0VYVCwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSBjaGFubmVscyB0aGF0IGlzIERYVDMgY29tcHJlc3NlZC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCQV9EWFQzOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkNPTVBSRVNTRURfUkdCQV9TM1RDX0RYVDNfRVhULAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYmx1ZSwgYW5kIGFscGhhIGNoYW5uZWxzIHRoYXQgaXMgRFhUNSBjb21wcmVzc2VkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0JBX0RYVDU6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuQ09NUFJFU1NFRF9SR0JBX1MzVENfRFhUNV9FWFQsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyByZWQsIGdyZWVuLCBhbmQgYmx1ZSBjaGFubmVscyB0aGF0IGlzIFBWUiA0YnBwIGNvbXByZXNzZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJHQl9QVlJUQ180QlBQVjE6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuQ09NUFJFU1NFRF9SR0JfUFZSVENfNEJQUFYxX0lNRywKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGFuZCBibHVlIGNoYW5uZWxzIHRoYXQgaXMgUFZSIDJicHAgY29tcHJlc3NlZC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCX1BWUlRDXzJCUFBWMTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQl9QVlJUQ18yQlBQVjFfSU1HLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYmx1ZSwgYW5kIGFscGhhIGNoYW5uZWxzIHRoYXQgaXMgUFZSIDRicHAgY29tcHJlc3NlZC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCQV9QVlJUQ180QlBQVjE6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUcsCiAgICAgICAgLyoqCiAgICAgICAgICogQSBwaXhlbCBmb3JtYXQgY29udGFpbmluZyByZWQsIGdyZWVuLCBibHVlLCBhbmQgYWxwaGEgY2hhbm5lbHMgdGhhdCBpcyBQVlIgMmJwcCBjb21wcmVzc2VkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0JBX1BWUlRDXzJCUFBWMTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQkFfUFZSVENfMkJQUFYxX0lNRywKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSBjaGFubmVscyB0aGF0IGlzIEFTVEMgY29tcHJlc3NlZC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCQV9BU1RDOiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkNPTVBSRVNTRURfUkdCQV9BU1RDXzR4NF9XRUJHTCwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGFuZCBibHVlIGNoYW5uZWxzIHRoYXQgaXMgRVRDMSBjb21wcmVzc2VkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0JfRVRDMTogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQl9FVEMxX1dFQkdMLAogICAgICAgIC8qKgogICAgICAgICAqIEEgcGl4ZWwgZm9ybWF0IGNvbnRhaW5pbmcgcmVkLCBncmVlbiwgYW5kIGJsdWUgY2hhbm5lbHMgdGhhdCBpcyBFVEMyIGNvbXByZXNzZWQuCiAgICAgICAgICoKICAgICAgICAgKiBAdHlwZSB7bnVtYmVyfQogICAgICAgICAqIEBjb25zdGFudAogICAgICAgICAqLwogICAgICAgIFJHQjhfRVRDMjogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQjhfRVRDMiwKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSBjaGFubmVscyB0aGF0IGlzIEVUQzIgY29tcHJlc3NlZC4KICAgICAgICAgKgogICAgICAgICAqIEB0eXBlIHtudW1iZXJ9CiAgICAgICAgICogQGNvbnN0YW50CiAgICAgICAgICovCiAgICAgICAgUkdCQThfRVRDMl9FQUM6IFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuQ09NUFJFU1NFRF9SR0JBOF9FVEMyX0VBQywKICAgICAgICAvKioKICAgICAgICAgKiBBIHBpeGVsIGZvcm1hdCBjb250YWluaW5nIHJlZCwgZ3JlZW4sIGJsdWUsIGFuZCBhbHBoYSBjaGFubmVscyB0aGF0IGlzIEJDNyBjb21wcmVzc2VkLgogICAgICAgICAqCiAgICAgICAgICogQHR5cGUge251bWJlcn0KICAgICAgICAgKiBAY29uc3RhbnQKICAgICAgICAgKi8KICAgICAgICBSR0JBX0JDNzogV2ViR0xDb25zdGFudHNfZGVmYXVsdC5DT01QUkVTU0VEX1JHQkFfQlBUQ19VTk9STQogICAgICB9OwogICAgICBQaXhlbEZvcm1hdC5jb21wb25lbnRzTGVuZ3RoID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICBzd2l0Y2ggKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQjoKICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCX0lOVEVHRVI6CiAgICAgICAgICAgIHJldHVybiAzOwogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX0lOVEVHRVI6CiAgICAgICAgICAgIHJldHVybiA0OwogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5MVU1JTkFOQ0VfQUxQSEE6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR19JTlRFR0VSOgogICAgICAgICAgICByZXR1cm4gMjsKICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuQUxQSEE6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJFRDoKICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkVEX0lOVEVHRVI6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LkxVTUlOQU5DRToKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFBpeGVsRm9ybWF0LnZhbGlkYXRlID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICByZXR1cm4gcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkRFUFRIX0NPTVBPTkVOVCB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuREVQVEhfU1RFTkNJTCB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuQUxQSEEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJFRCB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkcgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQiB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkVEX0lOVEVHRVIgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHX0lOVEVHRVIgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQl9JTlRFR0VSIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0lOVEVHRVIgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkxVTUlOQU5DRSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuTFVNSU5BTkNFX0FMUEhBIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfRFhUMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9EWFQxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0RYVDMgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfRFhUNSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCX1BWUlRDXzRCUFBWMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCX1BWUlRDXzJCUFBWMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9QVlJUQ180QlBQVjEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfUFZSVENfMkJQUFYxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0FTVEMgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQl9FVEMxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0I4X0VUQzIgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkE4X0VUQzJfRUFDIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0JDNzsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuaXNDb2xvckZvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SRUQgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkFMUEhBIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0IgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkxVTUlOQU5DRSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuTFVNSU5BTkNFX0FMUEhBOwogICAgICB9OwogICAgICBQaXhlbEZvcm1hdC5pc0RlcHRoRm9ybWF0ID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICByZXR1cm4gcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkRFUFRIX0NPTVBPTkVOVCB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuREVQVEhfU1RFTkNJTDsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuaXNDb21wcmVzc2VkRm9ybWF0ID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICByZXR1cm4gcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQl9EWFQxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0RYVDEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfRFhUMyB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9EWFQ1IHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfUFZSVENfNEJQUFYxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfUFZSVENfMkJQUFYxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX1BWUlRDXzRCUFBWMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9QVlJUQ18yQlBQVjEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfQVNUQyB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCX0VUQzEgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQjhfRVRDMiB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQThfRVRDMl9FQUMgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfQkM3OwogICAgICB9OwogICAgICBQaXhlbEZvcm1hdC5pc0RYVEZvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfRFhUMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9EWFQxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0RYVDMgfHwgcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfRFhUNTsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuaXNQVlJUQ0Zvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfUFZSVENfNEJQUFYxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfUFZSVENfMkJQUFYxIHx8IHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX1BWUlRDXzRCUFBWMSB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQV9QVlJUQ18yQlBQVjE7CiAgICAgIH07CiAgICAgIFBpeGVsRm9ybWF0LmlzQVNUQ0Zvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JBX0FTVEM7CiAgICAgIH07CiAgICAgIFBpeGVsRm9ybWF0LmlzRVRDMUZvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0ID09PSBQaXhlbEZvcm1hdC5SR0JfRVRDMTsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuaXNFVEMyRm9ybWF0ID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICByZXR1cm4gcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQjhfRVRDMiB8fCBwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuUkdCQThfRVRDMl9FQUM7CiAgICAgIH07CiAgICAgIFBpeGVsRm9ybWF0LmlzQkM3Rm9ybWF0ID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQpIHsKICAgICAgICByZXR1cm4gcGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LlJHQkFfQkM3OwogICAgICB9OwogICAgICBQaXhlbEZvcm1hdC5jb21wcmVzc2VkVGV4dHVyZVNpemVJbkJ5dGVzID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQsIHdpZHRoLCBoZWlnaHQpIHsKICAgICAgICBzd2l0Y2ggKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQl9EWFQxOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX0RYVDE6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQl9FVEMxOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0I4X0VUQzI6CiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKCh3aWR0aCArIDMpIC8gNCkgKiBNYXRoLmZsb29yKChoZWlnaHQgKyAzKSAvIDQpICogODsKICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCQV9EWFQzOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX0RYVDU6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQkFfQVNUQzoKICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCQThfRVRDMl9FQUM6CiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKCh3aWR0aCArIDMpIC8gNCkgKiBNYXRoLmZsb29yKChoZWlnaHQgKyAzKSAvIDQpICogMTY7CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQl9QVlJUQ180QlBQVjE6CiAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQkFfUFZSVENfNEJQUFYxOgogICAgICAgICAgICByZXR1cm4gTWF0aC5mbG9vcigoTWF0aC5tYXgod2lkdGgsIDgpICogTWF0aC5tYXgoaGVpZ2h0LCA4KSAqIDQgKyA3KSAvIDgpOwogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JfUFZSVENfMkJQUFYxOgogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX1BWUlRDXzJCUFBWMToKICAgICAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoCiAgICAgICAgICAgICAgKE1hdGgubWF4KHdpZHRoLCAxNikgKiBNYXRoLm1heChoZWlnaHQsIDgpICogMiArIDcpIC8gOAogICAgICAgICAgICApOwogICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX0JDNzoKICAgICAgICAgICAgcmV0dXJuIE1hdGguY2VpbCh3aWR0aCAvIDQpICogTWF0aC5jZWlsKGhlaWdodCAvIDQpICogMTY7CiAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIFBpeGVsRm9ybWF0LnRleHR1cmVTaXplSW5CeXRlcyA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0LCBwaXhlbERhdGF0eXBlLCB3aWR0aCwgaGVpZ2h0KSB7CiAgICAgICAgbGV0IGNvbXBvbmVudHNMZW5ndGggPSBQaXhlbEZvcm1hdC5jb21wb25lbnRzTGVuZ3RoKHBpeGVsRm9ybWF0KTsKICAgICAgICBpZiAoUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LmlzUGFja2VkKHBpeGVsRGF0YXR5cGUpKSB7CiAgICAgICAgICBjb21wb25lbnRzTGVuZ3RoID0gMTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNvbXBvbmVudHNMZW5ndGggKiBQaXhlbERhdGF0eXBlX2RlZmF1bHQuc2l6ZUluQnl0ZXMocGl4ZWxEYXRhdHlwZSkgKiB3aWR0aCAqIGhlaWdodDsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQudGV4dHVyZTNEU2l6ZUluQnl0ZXMgPSBmdW5jdGlvbihwaXhlbEZvcm1hdCwgcGl4ZWxEYXRhdHlwZSwgd2lkdGgsIGhlaWdodCwgZGVwdGgyKSB7CiAgICAgICAgbGV0IGNvbXBvbmVudHNMZW5ndGggPSBQaXhlbEZvcm1hdC5jb21wb25lbnRzTGVuZ3RoKHBpeGVsRm9ybWF0KTsKICAgICAgICBpZiAoUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LmlzUGFja2VkKHBpeGVsRGF0YXR5cGUpKSB7CiAgICAgICAgICBjb21wb25lbnRzTGVuZ3RoID0gMTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNvbXBvbmVudHNMZW5ndGggKiBQaXhlbERhdGF0eXBlX2RlZmF1bHQuc2l6ZUluQnl0ZXMocGl4ZWxEYXRhdHlwZSkgKiB3aWR0aCAqIGhlaWdodCAqIGRlcHRoMjsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuYWxpZ25tZW50SW5CeXRlcyA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0LCBwaXhlbERhdGF0eXBlLCB3aWR0aCkgewogICAgICAgIGNvbnN0IG1vZCA9IFBpeGVsRm9ybWF0LnRleHR1cmVTaXplSW5CeXRlcyhwaXhlbEZvcm1hdCwgcGl4ZWxEYXRhdHlwZSwgd2lkdGgsIDEpICUgNDsKICAgICAgICByZXR1cm4gbW9kID09PSAwID8gNCA6IG1vZCA9PT0gMiA/IDIgOiAxOwogICAgICB9OwogICAgICBQaXhlbEZvcm1hdC5jcmVhdGVUeXBlZEFycmF5ID0gZnVuY3Rpb24ocGl4ZWxGb3JtYXQsIHBpeGVsRGF0YXR5cGUsIHdpZHRoLCBoZWlnaHQpIHsKICAgICAgICBjb25zdCBjb25zdHJ1Y3RvciA9IFBpeGVsRGF0YXR5cGVfZGVmYXVsdC5nZXRUeXBlZEFycmF5Q29uc3RydWN0b3IocGl4ZWxEYXRhdHlwZSk7CiAgICAgICAgY29uc3Qgc2l6ZSA9IFBpeGVsRm9ybWF0LmNvbXBvbmVudHNMZW5ndGgocGl4ZWxGb3JtYXQpICogd2lkdGggKiBoZWlnaHQ7CiAgICAgICAgcmV0dXJuIG5ldyBjb25zdHJ1Y3RvcihzaXplKTsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQuZmxpcFkgPSBmdW5jdGlvbihidWZmZXJWaWV3LCBwaXhlbEZvcm1hdCwgcGl4ZWxEYXRhdHlwZSwgd2lkdGgsIGhlaWdodCkgewogICAgICAgIGlmIChoZWlnaHQgPT09IDEpIHsKICAgICAgICAgIHJldHVybiBidWZmZXJWaWV3OwogICAgICAgIH0KICAgICAgICBjb25zdCBmbGlwcGVkID0gUGl4ZWxGb3JtYXQuY3JlYXRlVHlwZWRBcnJheSgKICAgICAgICAgIHBpeGVsRm9ybWF0LAogICAgICAgICAgcGl4ZWxEYXRhdHlwZSwKICAgICAgICAgIHdpZHRoLAogICAgICAgICAgaGVpZ2h0CiAgICAgICAgKTsKICAgICAgICBjb25zdCBudW1iZXJPZkNvbXBvbmVudHMgPSBQaXhlbEZvcm1hdC5jb21wb25lbnRzTGVuZ3RoKHBpeGVsRm9ybWF0KTsKICAgICAgICBjb25zdCB0ZXh0dXJlV2lkdGggPSB3aWR0aCAqIG51bWJlck9mQ29tcG9uZW50czsKICAgICAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgaGVpZ2h0OyArK2kyKSB7CiAgICAgICAgICBjb25zdCByb3cgPSBpMiAqIHdpZHRoICogbnVtYmVyT2ZDb21wb25lbnRzOwogICAgICAgICAgY29uc3QgZmxpcHBlZFJvdyA9IChoZWlnaHQgLSBpMiAtIDEpICogd2lkdGggKiBudW1iZXJPZkNvbXBvbmVudHM7CiAgICAgICAgICBmb3IgKGxldCBqMiA9IDA7IGoyIDwgdGV4dHVyZVdpZHRoOyArK2oyKSB7CiAgICAgICAgICAgIGZsaXBwZWRbZmxpcHBlZFJvdyArIGoyXSA9IGJ1ZmZlclZpZXdbcm93ICsgajJdOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gZmxpcHBlZDsKICAgICAgfTsKICAgICAgUGl4ZWxGb3JtYXQudG9JbnRlcm5hbEZvcm1hdCA9IGZ1bmN0aW9uKHBpeGVsRm9ybWF0LCBwaXhlbERhdGF0eXBlLCBjb250ZXh0KSB7CiAgICAgICAgaWYgKCFjb250ZXh0LndlYmdsMikgewogICAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0OwogICAgICAgIH0KICAgICAgICBpZiAocGl4ZWxGb3JtYXQgPT09IFBpeGVsRm9ybWF0LkRFUFRIX1NURU5DSUwpIHsKICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkRFUFRIMjRfU1RFTkNJTDg7CiAgICAgICAgfQogICAgICAgIGlmIChwaXhlbEZvcm1hdCA9PT0gUGl4ZWxGb3JtYXQuREVQVEhfQ09NUE9ORU5UKSB7CiAgICAgICAgICBpZiAocGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX1NIT1JUKSB7CiAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkRFUFRIX0NPTVBPTkVOVDE2OwogICAgICAgICAgfSBlbHNlIGlmIChwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlX2RlZmF1bHQuVU5TSUdORURfSU5UKSB7CiAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LkRFUFRIX0NPTVBPTkVOVDI0OwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAocGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LkZMT0FUKSB7CiAgICAgICAgICBzd2l0Y2ggKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCQToKICAgICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SR0JBMzJGOwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQjoKICAgICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SR0IzMkY7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkc6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkczMkY7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkVEOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlIzMkY7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlX2RlZmF1bHQuSEFMRl9GTE9BVCkgewogICAgICAgICAgc3dpdGNoIChwaXhlbEZvcm1hdCkgewogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQkE6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCQTE2RjsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0I6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCMTZGOwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHMTZGOwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJFRDoKICAgICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SMTZGOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAocGl4ZWxEYXRhdHlwZSA9PT0gUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEUpIHsKICAgICAgICAgIHN3aXRjaCAocGl4ZWxGb3JtYXQpIHsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHQkE4OwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHQjoKICAgICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SR0I4OwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHODsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SRUQ6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUjg7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChwaXhlbERhdGF0eXBlID09PSBQaXhlbERhdGF0eXBlX2RlZmF1bHQuSU5UKSB7CiAgICAgICAgICBzd2l0Y2ggKHBpeGVsRm9ybWF0KSB7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCQV9JTlRFR0VSOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHQkEzMkk7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCX0lOVEVHRVI6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCMzJJOwogICAgICAgICAgICBjYXNlIFBpeGVsRm9ybWF0LlJHX0lOVEVHRVI6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkczMkk7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkVEX0lOVEVHRVI6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUjMySTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKHBpeGVsRGF0YXR5cGUgPT09IFBpeGVsRGF0YXR5cGVfZGVmYXVsdC5VTlNJR05FRF9JTlQpIHsKICAgICAgICAgIHN3aXRjaCAocGl4ZWxGb3JtYXQpIHsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR0JBX0lOVEVHRVI6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCQTMyVUk7CiAgICAgICAgICAgIGNhc2UgUGl4ZWxGb3JtYXQuUkdCX0lOVEVHRVI6CiAgICAgICAgICAgICAgcmV0dXJuIFdlYkdMQ29uc3RhbnRzX2RlZmF1bHQuUkdCMzJVSTsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SR19JTlRFR0VSOgogICAgICAgICAgICAgIHJldHVybiBXZWJHTENvbnN0YW50c19kZWZhdWx0LlJHMzJVSTsKICAgICAgICAgICAgY2FzZSBQaXhlbEZvcm1hdC5SRURfSU5URUdFUjoKICAgICAgICAgICAgICByZXR1cm4gV2ViR0xDb25zdGFudHNfZGVmYXVsdC5SMzJVSTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHBpeGVsRm9ybWF0OwogICAgICB9OwogICAgICBPYmplY3QuZnJlZXplKFBpeGVsRm9ybWF0KTsKICAgICAgUGl4ZWxGb3JtYXRfZGVmYXVsdCA9IFBpeGVsRm9ybWF0OwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvVnVsa2FuQ29uc3RhbnRzLmpzCiAgdmFyIFZ1bGthbkNvbnN0YW50cywgVnVsa2FuQ29uc3RhbnRzX2RlZmF1bHQ7CiAgdmFyIGluaXRfVnVsa2FuQ29uc3RhbnRzID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvQ29yZS9WdWxrYW5Db25zdGFudHMuanMiKCkgewogICAgICBWdWxrYW5Db25zdGFudHMgPSB7CiAgICAgICAgVktfRk9STUFUX1VOREVGSU5FRDogMCwKICAgICAgICBWS19GT1JNQVRfUjRHNF9VTk9STV9QQUNLODogMSwKICAgICAgICBWS19GT1JNQVRfUjRHNEI0QTRfVU5PUk1fUEFDSzE2OiAyLAogICAgICAgIFZLX0ZPUk1BVF9CNEc0UjRBNF9VTk9STV9QQUNLMTY6IDMsCiAgICAgICAgVktfRk9STUFUX1I1RzZCNV9VTk9STV9QQUNLMTY6IDQsCiAgICAgICAgVktfRk9STUFUX0I1RzZSNV9VTk9STV9QQUNLMTY6IDUsCiAgICAgICAgVktfRk9STUFUX1I1RzVCNUExX1VOT1JNX1BBQ0sxNjogNiwKICAgICAgICBWS19GT1JNQVRfQjVHNVI1QTFfVU5PUk1fUEFDSzE2OiA3LAogICAgICAgIFZLX0ZPUk1BVF9BMVI1RzVCNV9VTk9STV9QQUNLMTY6IDgsCiAgICAgICAgVktfRk9STUFUX1I4X1VOT1JNOiA5LAogICAgICAgIFZLX0ZPUk1BVF9SOF9TTk9STTogMTAsCiAgICAgICAgVktfRk9STUFUX1I4X1VTQ0FMRUQ6IDExLAogICAgICAgIFZLX0ZPUk1BVF9SOF9TU0NBTEVEOiAxMiwKICAgICAgICBWS19GT1JNQVRfUjhfVUlOVDogMTMsCiAgICAgICAgVktfRk9STUFUX1I4X1NJTlQ6IDE0LAogICAgICAgIFZLX0ZPUk1BVF9SOF9TUkdCOiAxNSwKICAgICAgICBWS19GT1JNQVRfUjhHOF9VTk9STTogMTYsCiAgICAgICAgVktfRk9STUFUX1I4RzhfU05PUk06IDE3LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4X1VTQ0FMRUQ6IDE4LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4X1NTQ0FMRUQ6IDE5LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4X1VJTlQ6IDIwLAogICAgICAgIFZLX0ZPUk1BVF9SOEc4X1NJTlQ6IDIxLAogICAgICAgIFZLX0ZPUk1BVF9SOEc4X1NSR0I6IDIyLAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhfVU5PUk06IDIzLAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhfU05PUk06IDI0LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhfVVNDQUxFRDogMjUsCiAgICAgICAgVktfRk9STUFUX1I4RzhCOF9TU0NBTEVEOiAyNiwKICAgICAgICBWS19GT1JNQVRfUjhHOEI4X1VJTlQ6IDI3LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhfU0lOVDogMjgsCiAgICAgICAgVktfRk9STUFUX1I4RzhCOF9TUkdCOiAyOSwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4X1VOT1JNOiAzMCwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4X1NOT1JNOiAzMSwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4X1VTQ0FMRUQ6IDMyLAogICAgICAgIFZLX0ZPUk1BVF9COEc4UjhfU1NDQUxFRDogMzMsCiAgICAgICAgVktfRk9STUFUX0I4RzhSOF9VSU5UOiAzNCwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4X1NJTlQ6IDM1LAogICAgICAgIFZLX0ZPUk1BVF9COEc4UjhfU1JHQjogMzYsCiAgICAgICAgVktfRk9STUFUX1I4RzhCOEE4X1VOT1JNOiAzNywKICAgICAgICBWS19GT1JNQVRfUjhHOEI4QThfU05PUk06IDM4LAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhBOF9VU0NBTEVEOiAzOSwKICAgICAgICBWS19GT1JNQVRfUjhHOEI4QThfU1NDQUxFRDogNDAsCiAgICAgICAgVktfRk9STUFUX1I4RzhCOEE4X1VJTlQ6IDQxLAogICAgICAgIFZLX0ZPUk1BVF9SOEc4QjhBOF9TSU5UOiA0MiwKICAgICAgICBWS19GT1JNQVRfUjhHOEI4QThfU1JHQjogNDMsCiAgICAgICAgVktfRk9STUFUX0I4RzhSOEE4X1VOT1JNOiA0NCwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4QThfU05PUk06IDQ1LAogICAgICAgIFZLX0ZPUk1BVF9COEc4UjhBOF9VU0NBTEVEOiA0NiwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4QThfU1NDQUxFRDogNDcsCiAgICAgICAgVktfRk9STUFUX0I4RzhSOEE4X1VJTlQ6IDQ4LAogICAgICAgIFZLX0ZPUk1BVF9COEc4UjhBOF9TSU5UOiA0OSwKICAgICAgICBWS19GT1JNQVRfQjhHOFI4QThfU1JHQjogNTAsCiAgICAgICAgVktfRk9STUFUX0E4QjhHOFI4X1VOT1JNX1BBQ0szMjogNTEsCiAgICAgICAgVktfRk9STUFUX0E4QjhHOFI4X1NOT1JNX1BBQ0szMjogNTIsCiAgICAgICAgVktfRk9STUFUX0E4QjhHOFI4X1VTQ0FMRURfUEFDSzMyOiA1MywKICAgICAgICBWS19GT1JNQVRfQThCOEc4UjhfU1NDQUxFRF9QQUNLMzI6IDU0LAogICAgICAgIFZLX0ZPUk1BVF9BOEI4RzhSOF9VSU5UX1BBQ0szMjogNTUsCiAgICAgICAgVktfRk9STUFUX0E4QjhHOFI4X1NJTlRfUEFDSzMyOiA1NiwKICAgICAgICBWS19GT1JNQVRfQThCOEc4UjhfU1JHQl9QQUNLMzI6IDU3LAogICAgICAgIFZLX0ZPUk1BVF9BMlIxMEcxMEIxMF9VTk9STV9QQUNLMzI6IDU4LAogICAgICAgIFZLX0ZPUk1BVF9BMlIxMEcxMEIxMF9TTk9STV9QQUNLMzI6IDU5LAogICAgICAgIFZLX0ZPUk1BVF9BMlIxMEcxMEIxMF9VU0NBTEVEX1BBQ0szMjogNjAsCiAgICAgICAgVktfRk9STUFUX0EyUjEwRzEwQjEwX1NTQ0FMRURfUEFDSzMyOiA2MSwKICAgICAgICBWS19GT1JNQVRfQTJSMTBHMTBCMTBfVUlOVF9QQUNLMzI6IDYyLAogICAgICAgIFZLX0ZPUk1BVF9BMlIxMEcxMEIxMF9TSU5UX1BBQ0szMjogNjMsCiAgICAgICAgVktfRk9STUFUX0EyQjEwRzEwUjEwX1VOT1JNX1BBQ0szMjogNjQsCiAgICAgICAgVktfRk9STUFUX0EyQjEwRzEwUjEwX1NOT1JNX1BBQ0szMjogNjUsCiAgICAgICAgVktfRk9STUFUX0EyQjEwRzEwUjEwX1VTQ0FMRURfUEFDSzMyOiA2NiwKICAgICAgICBWS19GT1JNQVRfQTJCMTBHMTBSMTBfU1NDQUxFRF9QQUNLMzI6IDY3LAogICAgICAgIFZLX0ZPUk1BVF9BMkIxMEcxMFIxMF9VSU5UX1BBQ0szMjogNjgsCiAgICAgICAgVktfRk9STUFUX0EyQjEwRzEwUjEwX1NJTlRfUEFDSzMyOiA2OSwKICAgICAgICBWS19GT1JNQVRfUjE2X1VOT1JNOiA3MCwKICAgICAgICBWS19GT1JNQVRfUjE2X1NOT1JNOiA3MSwKICAgICAgICBWS19GT1JNQVRfUjE2X1VTQ0FMRUQ6IDcyLAogICAgICAgIFZLX0ZPUk1BVF9SMTZfU1NDQUxFRDogNzMsCiAgICAgICAgVktfRk9STUFUX1IxNl9VSU5UOiA3NCwKICAgICAgICBWS19GT1JNQVRfUjE2X1NJTlQ6IDc1LAogICAgICAgIFZLX0ZPUk1BVF9SMTZfU0ZMT0FUOiA3NiwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2X1VOT1JNOiA3NywKICAgICAgICBWS19GT1JNQVRfUjE2RzE2X1NOT1JNOiA3OCwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2X1VTQ0FMRUQ6IDc5LAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZfU1NDQUxFRDogODAsCiAgICAgICAgVktfRk9STUFUX1IxNkcxNl9VSU5UOiA4MSwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2X1NJTlQ6IDgyLAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZfU0ZMT0FUOiA4MywKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2X1VOT1JNOiA4NCwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2X1NOT1JNOiA4NSwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2X1VTQ0FMRUQ6IDg2LAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZCMTZfU1NDQUxFRDogODcsCiAgICAgICAgVktfRk9STUFUX1IxNkcxNkIxNl9VSU5UOiA4OCwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2X1NJTlQ6IDg5LAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZCMTZfU0ZMT0FUOiA5MCwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2QTE2X1VOT1JNOiA5MSwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2QTE2X1NOT1JNOiA5MiwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2QTE2X1VTQ0FMRUQ6IDkzLAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZCMTZBMTZfU1NDQUxFRDogOTQsCiAgICAgICAgVktfRk9STUFUX1IxNkcxNkIxNkExNl9VSU5UOiA5NSwKICAgICAgICBWS19GT1JNQVRfUjE2RzE2QjE2QTE2X1NJTlQ6IDk2LAogICAgICAgIFZLX0ZPUk1BVF9SMTZHMTZCMTZBMTZfU0ZMT0FUOiA5NywKICAgICAgICBWS19GT1JNQVRfUjMyX1VJTlQ6IDk4LAogICAgICAgIFZLX0ZPUk1BVF9SMzJfU0lOVDogOTksCiAgICAgICAgVktfRk9STUFUX1IzMl9TRkxPQVQ6IDEwMCwKICAgICAgICBWS19GT1JNQVRfUjMyRzMyX1VJTlQ6IDEwMSwKICAgICAgICBWS19GT1JNQVRfUjMyRzMyX1NJTlQ6IDEwMiwKICAgICAgICBWS19GT1JNQVRfUjMyRzMyX1NGTE9BVDogMTAzLAogICAgICAgIFZLX0ZPUk1BVF9SMzJHMzJCMzJfVUlOVDogMTA0LAogICAgICAgIFZLX0ZPUk1BVF9SMzJHMzJCMzJfU0lOVDogMTA1LAogICAgICAgIFZLX0ZPUk1BVF9SMzJHMzJCMzJfU0ZMT0FUOiAxMDYsCiAgICAgICAgVktfRk9STUFUX1IzMkczMkIzMkEzMl9VSU5UOiAxMDcsCiAgICAgICAgVktfRk9STUFUX1IzMkczMkIzMkEzMl9TSU5UOiAxMDgsCiAgICAgICAgVktfRk9STUFUX1IzMkczMkIzMkEzMl9TRkxPQVQ6IDEwOSwKICAgICAgICBWS19GT1JNQVRfUjY0X1VJTlQ6IDExMCwKICAgICAgICBWS19GT1JNQVRfUjY0X1NJTlQ6IDExMSwKICAgICAgICBWS19GT1JNQVRfUjY0X1NGTE9BVDogMTEyLAogICAgICAgIFZLX0ZPUk1BVF9SNjRHNjRfVUlOVDogMTEzLAogICAgICAgIFZLX0ZPUk1BVF9SNjRHNjRfU0lOVDogMTE0LAogICAgICAgIFZLX0ZPUk1BVF9SNjRHNjRfU0ZMT0FUOiAxMTUsCiAgICAgICAgVktfRk9STUFUX1I2NEc2NEI2NF9VSU5UOiAxMTYsCiAgICAgICAgVktfRk9STUFUX1I2NEc2NEI2NF9TSU5UOiAxMTcsCiAgICAgICAgVktfRk9STUFUX1I2NEc2NEI2NF9TRkxPQVQ6IDExOCwKICAgICAgICBWS19GT1JNQVRfUjY0RzY0QjY0QTY0X1VJTlQ6IDExOSwKICAgICAgICBWS19GT1JNQVRfUjY0RzY0QjY0QTY0X1NJTlQ6IDEyMCwKICAgICAgICBWS19GT1JNQVRfUjY0RzY0QjY0QTY0X1NGTE9BVDogMTIxLAogICAgICAgIFZLX0ZPUk1BVF9CMTBHMTFSMTFfVUZMT0FUX1BBQ0szMjogMTIyLAogICAgICAgIFZLX0ZPUk1BVF9FNUI5RzlSOV9VRkxPQVRfUEFDSzMyOiAxMjMsCiAgICAgICAgVktfRk9STUFUX0QxNl9VTk9STTogMTI0LAogICAgICAgIFZLX0ZPUk1BVF9YOF9EMjRfVU5PUk1fUEFDSzMyOiAxMjUsCiAgICAgICAgVktfRk9STUFUX0QzMl9TRkxPQVQ6IDEyNiwKICAgICAgICBWS19GT1JNQVRfUzhfVUlOVDogMTI3LAogICAgICAgIFZLX0ZPUk1BVF9EMTZfVU5PUk1fUzhfVUlOVDogMTI4LAogICAgICAgIFZLX0ZPUk1BVF9EMjRfVU5PUk1fUzhfVUlOVDogMTI5LAogICAgICAgIFZLX0ZPUk1BVF9EMzJfU0ZMT0FUX1M4X1VJTlQ6IDEzMCwKICAgICAgICBWS19GT1JNQVRfQkMxX1JHQl9VTk9STV9CTE9DSzogMTMxLAogICAgICAgIFZLX0ZPUk1BVF9CQzFfUkdCX1NSR0JfQkxPQ0s6IDEzMiwKICAgICAgICBWS19GT1JNQVRfQkMxX1JHQkFfVU5PUk1fQkxPQ0s6IDEzMywKICAgICAgICBWS19GT1JNQVRfQkMxX1JHQkFfU1JHQl9CTE9DSzogMTM0LAogICAgICAgIFZLX0ZPUk1BVF9CQzJfVU5PUk1fQkxPQ0s6IDEzNSwKICAgICAgICBWS19GT1JNQVRfQkMyX1NSR0JfQkxPQ0s6IDEzNiwKICAgICAgICBWS19GT1JNQVRfQkMzX1VOT1JNX0JMT0NLOiAxMzcsCiAgICAgICAgVktfRk9STUFUX0JDM19TUkdCX0JMT0NLOiAxMzgsCiAgICAgICAgVktfRk9STUFUX0JDNF9VTk9STV9CTE9DSzogMTM5LAogICAgICAgIFZLX0ZPUk1BVF9CQzRfU05PUk1fQkxPQ0s6IDE0MCwKICAgICAgICBWS19GT1JNQVRfQkM1X1VOT1JNX0JMT0NLOiAxNDEsCiAgICAgICAgVktfRk9STUFUX0JDNV9TTk9STV9CTE9DSzogMTQyLAogICAgICAgIFZLX0ZPUk1BVF9CQzZIX1VGTE9BVF9CTE9DSzogMTQzLAogICAgICAgIFZLX0ZPUk1BVF9CQzZIX1NGTE9BVF9CTE9DSzogMTQ0LAogICAgICAgIFZLX0ZPUk1BVF9CQzdfVU5PUk1fQkxPQ0s6IDE0NSwKICAgICAgICBWS19GT1JNQVRfQkM3X1NSR0JfQkxPQ0s6IDE0NiwKICAgICAgICBWS19GT1JNQVRfRVRDMl9SOEc4QjhfVU5PUk1fQkxPQ0s6IDE0NywKICAgICAgICBWS19GT1JNQVRfRVRDMl9SOEc4QjhfU1JHQl9CTE9DSzogMTQ4LAogICAgICAgIFZLX0ZPUk1BVF9FVEMyX1I4RzhCOEExX1VOT1JNX0JMT0NLOiAxNDksCiAgICAgICAgVktfRk9STUFUX0VUQzJfUjhHOEI4QTFfU1JHQl9CTE9DSzogMTUwLAogICAgICAgIFZLX0ZPUk1BVF9FVEMyX1I4RzhCOEE4X1VOT1JNX0JMT0NLOiAxNTEsCiAgICAgICAgVktfRk9STUFUX0VUQzJfUjhHOEI4QThfU1JHQl9CTE9DSzogMTUyLAogICAgICAgIFZLX0ZPUk1BVF9FQUNfUjExX1VOT1JNX0JMT0NLOiAxNTMsCiAgICAgICAgVktfRk9STUFUX0VBQ19SMTFfU05PUk1fQkxPQ0s6IDE1NCwKICAgICAgICBWS19GT1JNQVRfRUFDX1IxMUcxMV9VTk9STV9CTE9DSzogMTU1LAogICAgICAgIFZLX0ZPUk1BVF9FQUNfUjExRzExX1NOT1JNX0JMT0NLOiAxNTYsCiAgICAgICAgVktfRk9STUFUX0FTVENfNHg0X1VOT1JNX0JMT0NLOiAxNTcsCiAgICAgICAgVktfRk9STUFUX0FTVENfNHg0X1NSR0JfQkxPQ0s6IDE1OCwKICAgICAgICBWS19GT1JNQVRfQVNUQ181eDRfVU5PUk1fQkxPQ0s6IDE1OSwKICAgICAgICBWS19GT1JNQVRfQVNUQ181eDRfU1JHQl9CTE9DSzogMTYwLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzV4NV9VTk9STV9CTE9DSzogMTYxLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzV4NV9TUkdCX0JMT0NLOiAxNjIsCiAgICAgICAgVktfRk9STUFUX0FTVENfNng1X1VOT1JNX0JMT0NLOiAxNjMsCiAgICAgICAgVktfRk9STUFUX0FTVENfNng1X1NSR0JfQkxPQ0s6IDE2NCwKICAgICAgICBWS19GT1JNQVRfQVNUQ182eDZfVU5PUk1fQkxPQ0s6IDE2NSwKICAgICAgICBWS19GT1JNQVRfQVNUQ182eDZfU1JHQl9CTE9DSzogMTY2LAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzh4NV9VTk9STV9CTE9DSzogMTY3LAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzh4NV9TUkdCX0JMT0NLOiAxNjgsCiAgICAgICAgVktfRk9STUFUX0FTVENfOHg2X1VOT1JNX0JMT0NLOiAxNjksCiAgICAgICAgVktfRk9STUFUX0FTVENfOHg2X1NSR0JfQkxPQ0s6IDE3MCwKICAgICAgICBWS19GT1JNQVRfQVNUQ184eDhfVU5PUk1fQkxPQ0s6IDE3MSwKICAgICAgICBWS19GT1JNQVRfQVNUQ184eDhfU1JHQl9CTE9DSzogMTcyLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEweDVfVU5PUk1fQkxPQ0s6IDE3MywKICAgICAgICBWS19GT1JNQVRfQVNUQ18xMHg1X1NSR0JfQkxPQ0s6IDE3NCwKICAgICAgICBWS19GT1JNQVRfQVNUQ18xMHg2X1VOT1JNX0JMT0NLOiAxNzUsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTB4Nl9TUkdCX0JMT0NLOiAxNzYsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTB4OF9VTk9STV9CTE9DSzogMTc3LAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEweDhfU1JHQl9CTE9DSzogMTc4LAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEweDEwX1VOT1JNX0JMT0NLOiAxNzksCiAgICAgICAgVktfRk9STUFUX0FTVENfMTB4MTBfU1JHQl9CTE9DSzogMTgwLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEyeDEwX1VOT1JNX0JMT0NLOiAxODEsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTJ4MTBfU1JHQl9CTE9DSzogMTgyLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEyeDEyX1VOT1JNX0JMT0NLOiAxODMsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTJ4MTJfU1JHQl9CTE9DSzogMTg0LAogICAgICAgIFZLX0ZPUk1BVF9HOEI4RzhSOF80MjJfVU5PUk06IDEwMDAxNTZlMywKICAgICAgICBWS19GT1JNQVRfQjhHOFI4RzhfNDIyX1VOT1JNOiAxMDAwMTU2MDAxLAogICAgICAgIFZLX0ZPUk1BVF9HOF9COF9SOF8zUExBTkVfNDIwX1VOT1JNOiAxMDAwMTU2MDAyLAogICAgICAgIFZLX0ZPUk1BVF9HOF9COFI4XzJQTEFORV80MjBfVU5PUk06IDEwMDAxNTYwMDMsCiAgICAgICAgVktfRk9STUFUX0c4X0I4X1I4XzNQTEFORV80MjJfVU5PUk06IDEwMDAxNTYwMDQsCiAgICAgICAgVktfRk9STUFUX0c4X0I4UjhfMlBMQU5FXzQyMl9VTk9STTogMTAwMDE1NjAwNSwKICAgICAgICBWS19GT1JNQVRfRzhfQjhfUjhfM1BMQU5FXzQ0NF9VTk9STTogMTAwMDE1NjAwNiwKICAgICAgICBWS19GT1JNQVRfUjEwWDZfVU5PUk1fUEFDSzE2OiAxMDAwMTU2MDA3LAogICAgICAgIFZLX0ZPUk1BVF9SMTBYNkcxMFg2X1VOT1JNXzJQQUNLMTY6IDEwMDAxNTYwMDgsCiAgICAgICAgVktfRk9STUFUX1IxMFg2RzEwWDZCMTBYNkExMFg2X1VOT1JNXzRQQUNLMTY6IDEwMDAxNTYwMDksCiAgICAgICAgVktfRk9STUFUX0cxMFg2QjEwWDZHMTBYNlIxMFg2XzQyMl9VTk9STV80UEFDSzE2OiAxMDAwMTU2MDEwLAogICAgICAgIFZLX0ZPUk1BVF9CMTBYNkcxMFg2UjEwWDZHMTBYNl80MjJfVU5PUk1fNFBBQ0sxNjogMTAwMDE1NjAxMSwKICAgICAgICBWS19GT1JNQVRfRzEwWDZfQjEwWDZfUjEwWDZfM1BMQU5FXzQyMF9VTk9STV8zUEFDSzE2OiAxMDAwMTU2MDEyLAogICAgICAgIFZLX0ZPUk1BVF9HMTBYNl9CMTBYNlIxMFg2XzJQTEFORV80MjBfVU5PUk1fM1BBQ0sxNjogMTAwMDE1NjAxMywKICAgICAgICBWS19GT1JNQVRfRzEwWDZfQjEwWDZfUjEwWDZfM1BMQU5FXzQyMl9VTk9STV8zUEFDSzE2OiAxMDAwMTU2MDE0LAogICAgICAgIFZLX0ZPUk1BVF9HMTBYNl9CMTBYNlIxMFg2XzJQTEFORV80MjJfVU5PUk1fM1BBQ0sxNjogMTAwMDE1NjAxNSwKICAgICAgICBWS19GT1JNQVRfRzEwWDZfQjEwWDZfUjEwWDZfM1BMQU5FXzQ0NF9VTk9STV8zUEFDSzE2OiAxMDAwMTU2MDE2LAogICAgICAgIFZLX0ZPUk1BVF9SMTJYNF9VTk9STV9QQUNLMTY6IDEwMDAxNTYwMTcsCiAgICAgICAgVktfRk9STUFUX1IxMlg0RzEyWDRfVU5PUk1fMlBBQ0sxNjogMTAwMDE1NjAxOCwKICAgICAgICBWS19GT1JNQVRfUjEyWDRHMTJYNEIxMlg0QTEyWDRfVU5PUk1fNFBBQ0sxNjogMTAwMDE1NjAxOSwKICAgICAgICBWS19GT1JNQVRfRzEyWDRCMTJYNEcxMlg0UjEyWDRfNDIyX1VOT1JNXzRQQUNLMTY6IDEwMDAxNTYwMjAsCiAgICAgICAgVktfRk9STUFUX0IxMlg0RzEyWDRSMTJYNEcxMlg0XzQyMl9VTk9STV80UEFDSzE2OiAxMDAwMTU2MDIxLAogICAgICAgIFZLX0ZPUk1BVF9HMTJYNF9CMTJYNF9SMTJYNF8zUExBTkVfNDIwX1VOT1JNXzNQQUNLMTY6IDEwMDAxNTYwMjIsCiAgICAgICAgVktfRk9STUFUX0cxMlg0X0IxMlg0UjEyWDRfMlBMQU5FXzQyMF9VTk9STV8zUEFDSzE2OiAxMDAwMTU2MDIzLAogICAgICAgIFZLX0ZPUk1BVF9HMTJYNF9CMTJYNF9SMTJYNF8zUExBTkVfNDIyX1VOT1JNXzNQQUNLMTY6IDEwMDAxNTYwMjQsCiAgICAgICAgVktfRk9STUFUX0cxMlg0X0IxMlg0UjEyWDRfMlBMQU5FXzQyMl9VTk9STV8zUEFDSzE2OiAxMDAwMTU2MDI1LAogICAgICAgIFZLX0ZPUk1BVF9HMTJYNF9CMTJYNF9SMTJYNF8zUExBTkVfNDQ0X1VOT1JNXzNQQUNLMTY6IDEwMDAxNTYwMjYsCiAgICAgICAgVktfRk9STUFUX0cxNkIxNkcxNlIxNl80MjJfVU5PUk06IDEwMDAxNTYwMjcsCiAgICAgICAgVktfRk9STUFUX0IxNkcxNlIxNkcxNl80MjJfVU5PUk06IDEwMDAxNTYwMjgsCiAgICAgICAgVktfRk9STUFUX0cxNl9CMTZfUjE2XzNQTEFORV80MjBfVU5PUk06IDEwMDAxNTYwMjksCiAgICAgICAgVktfRk9STUFUX0cxNl9CMTZSMTZfMlBMQU5FXzQyMF9VTk9STTogMTAwMDE1NjAzMCwKICAgICAgICBWS19GT1JNQVRfRzE2X0IxNl9SMTZfM1BMQU5FXzQyMl9VTk9STTogMTAwMDE1NjAzMSwKICAgICAgICBWS19GT1JNQVRfRzE2X0IxNlIxNl8yUExBTkVfNDIyX1VOT1JNOiAxMDAwMTU2MDMyLAogICAgICAgIFZLX0ZPUk1BVF9HMTZfQjE2X1IxNl8zUExBTkVfNDQ0X1VOT1JNOiAxMDAwMTU2MDMzLAogICAgICAgIFZLX0ZPUk1BVF9QVlJUQzFfMkJQUF9VTk9STV9CTE9DS19JTUc6IDEwMDAwNTRlMywKICAgICAgICBWS19GT1JNQVRfUFZSVEMxXzRCUFBfVU5PUk1fQkxPQ0tfSU1HOiAxMDAwMDU0MDAxLAogICAgICAgIFZLX0ZPUk1BVF9QVlJUQzJfMkJQUF9VTk9STV9CTE9DS19JTUc6IDEwMDAwNTQwMDIsCiAgICAgICAgVktfRk9STUFUX1BWUlRDMl80QlBQX1VOT1JNX0JMT0NLX0lNRzogMTAwMDA1NDAwMywKICAgICAgICBWS19GT1JNQVRfUFZSVEMxXzJCUFBfU1JHQl9CTE9DS19JTUc6IDEwMDAwNTQwMDQsCiAgICAgICAgVktfRk9STUFUX1BWUlRDMV80QlBQX1NSR0JfQkxPQ0tfSU1HOiAxMDAwMDU0MDA1LAogICAgICAgIFZLX0ZPUk1BVF9QVlJUQzJfMkJQUF9TUkdCX0JMT0NLX0lNRzogMTAwMDA1NDAwNiwKICAgICAgICBWS19GT1JNQVRfUFZSVEMyXzRCUFBfU1JHQl9CTE9DS19JTUc6IDEwMDAwNTQwMDcsCiAgICAgICAgVktfRk9STUFUX0FTVENfNHg0X1NGTE9BVF9CTE9DS19FWFQ6IDEwMDAwNjZlMywKICAgICAgICBWS19GT1JNQVRfQVNUQ181eDRfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwMSwKICAgICAgICBWS19GT1JNQVRfQVNUQ181eDVfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwMiwKICAgICAgICBWS19GT1JNQVRfQVNUQ182eDVfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwMywKICAgICAgICBWS19GT1JNQVRfQVNUQ182eDZfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwNCwKICAgICAgICBWS19GT1JNQVRfQVNUQ184eDVfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwNSwKICAgICAgICBWS19GT1JNQVRfQVNUQ184eDZfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwNiwKICAgICAgICBWS19GT1JNQVRfQVNUQ184eDhfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAwNywKICAgICAgICBWS19GT1JNQVRfQVNUQ18xMHg1X1NGTE9BVF9CTE9DS19FWFQ6IDEwMDAwNjYwMDgsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTB4Nl9TRkxPQVRfQkxPQ0tfRVhUOiAxMDAwMDY2MDA5LAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEweDhfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAxMCwKICAgICAgICBWS19GT1JNQVRfQVNUQ18xMHgxMF9TRkxPQVRfQkxPQ0tfRVhUOiAxMDAwMDY2MDExLAogICAgICAgIFZLX0ZPUk1BVF9BU1RDXzEyeDEwX1NGTE9BVF9CTE9DS19FWFQ6IDEwMDAwNjYwMTIsCiAgICAgICAgVktfRk9STUFUX0FTVENfMTJ4MTJfU0ZMT0FUX0JMT0NLX0VYVDogMTAwMDA2NjAxMywKICAgICAgICBWS19GT1JNQVRfRzhCOEc4UjhfNDIyX1VOT1JNX0tIUjogMTAwMDE1NmUzLAogICAgICAgIFZLX0ZPUk1BVF9COEc4UjhHOF80MjJfVU5PUk1fS0hSOiAxMDAwMTU2MDAxLAogICAgICAgIFZLX0ZPUk1BVF9HOF9COF9SOF8zUExBTkVfNDIwX1VOT1JNX0tIUjogMTAwMDE1NjAwMiwKICAgICAgICBWS19GT1JNQVRfRzhfQjhSOF8yUExBTkVfNDIwX1VOT1JNX0tIUjogMTAwMDE1NjAwMywKICAgICAgICBWS19GT1JNQVRfRzhfQjhfUjhfM1BMQU5FXzQyMl9VTk9STV9LSFI6IDEwMDAxNTYwMDQsCiAgICAgICAgVktfRk9STUFUX0c4X0I4UjhfMlBMQU5FXzQyMl9VTk9STV9LSFI6IDEwMDAxNTYwMDUsCiAgICAgICAgVktfRk9STUFUX0c4X0I4X1I4XzNQTEFORV80NDRfVU5PUk1fS0hSOiAxMDAwMTU2MDA2LAogICAgICAgIFZLX0ZPUk1BVF9SMTBYNl9VTk9STV9QQUNLMTZfS0hSOiAxMDAwMTU2MDA3LAogICAgICAgIFZLX0ZPUk1BVF9SMTBYNkcxMFg2X1VOT1JNXzJQQUNLMTZfS0hSOiAxMDAwMTU2MDA4LAogICAgICAgIFZLX0ZPUk1BVF9SMTBYNkcxMFg2QjEwWDZBMTBYNl9VTk9STV80UEFDSzE2X0tIUjogMTAwMDE1NjAwOSwKICAgICAgICBWS19GT1JNQVRfRzEwWDZCMTBYNkcxMFg2UjEwWDZfNDIyX1VOT1JNXzRQQUNLMTZfS0hSOiAxMDAwMTU2MDEwLAogICAgICAgIFZLX0ZPUk1BVF9CMTBYNkcxMFg2UjEwWDZHMTBYNl80MjJfVU5PUk1fNFBBQ0sxNl9LSFI6IDEwMDAxNTYwMTEsCiAgICAgICAgVktfRk9STUFUX0cxMFg2X0IxMFg2X1IxMFg2XzNQTEFORV80MjBfVU5PUk1fM1BBQ0sxNl9LSFI6IDEwMDAxNTYwMTIsCiAgICAgICAgVktfRk9STUFUX0cxMFg2X0IxMFg2UjEwWDZfMlBMQU5FXzQyMF9VTk9STV8zUEFDSzE2X0tIUjogMTAwMDE1NjAxMywKICAgICAgICBWS19GT1JNQVRfRzEwWDZfQjEwWDZfUjEwWDZfM1BMQU5FXzQyMl9VTk9STV8zUEFDSzE2X0tIUjogMTAwMDE1NjAxNCwKICAgICAgICBWS19GT1JNQVRfRzEwWDZfQjEwWDZSMTBYNl8yUExBTkVfNDIyX1VOT1JNXzNQQUNLMTZfS0hSOiAxMDAwMTU2MDE1LAogICAgICAgIFZLX0ZPUk1BVF9HMTBYNl9CMTBYNl9SMTBYNl8zUExBTkVfNDQ0X1VOT1JNXzNQQUNLMTZfS0hSOiAxMDAwMTU2MDE2LAogICAgICAgIFZLX0ZPUk1BVF9SMTJYNF9VTk9STV9QQUNLMTZfS0hSOiAxMDAwMTU2MDE3LAogICAgICAgIFZLX0ZPUk1BVF9SMTJYNEcxMlg0X1VOT1JNXzJQQUNLMTZfS0hSOiAxMDAwMTU2MDE4LAogICAgICAgIFZLX0ZPUk1BVF9SMTJYNEcxMlg0QjEyWDRBMTJYNF9VTk9STV80UEFDSzE2X0tIUjogMTAwMDE1NjAxOSwKICAgICAgICBWS19GT1JNQVRfRzEyWDRCMTJYNEcxMlg0UjEyWDRfNDIyX1VOT1JNXzRQQUNLMTZfS0hSOiAxMDAwMTU2MDIwLAogICAgICAgIFZLX0ZPUk1BVF9CMTJYNEcxMlg0UjEyWDRHMTJYNF80MjJfVU5PUk1fNFBBQ0sxNl9LSFI6IDEwMDAxNTYwMjEsCiAgICAgICAgVktfRk9STUFUX0cxMlg0X0IxMlg0X1IxMlg0XzNQTEFORV80MjBfVU5PUk1fM1BBQ0sxNl9LSFI6IDEwMDAxNTYwMjIsCiAgICAgICAgVktfRk9STUFUX0cxMlg0X0IxMlg0UjEyWDRfMlBMQU5FXzQyMF9VTk9STV8zUEFDSzE2X0tIUjogMTAwMDE1NjAyMywKICAgICAgICBWS19GT1JNQVRfRzEyWDRfQjEyWDRfUjEyWDRfM1BMQU5FXzQyMl9VTk9STV8zUEFDSzE2X0tIUjogMTAwMDE1NjAyNCwKICAgICAgICBWS19GT1JNQVRfRzEyWDRfQjEyWDRSMTJYNF8yUExBTkVfNDIyX1VOT1JNXzNQQUNLMTZfS0hSOiAxMDAwMTU2MDI1LAogICAgICAgIFZLX0ZPUk1BVF9HMTJYNF9CMTJYNF9SMTJYNF8zUExBTkVfNDQ0X1VOT1JNXzNQQUNLMTZfS0hSOiAxMDAwMTU2MDI2LAogICAgICAgIFZLX0ZPUk1BVF9HMTZCMTZHMTZSMTZfNDIyX1VOT1JNX0tIUjogMTAwMDE1NjAyNywKICAgICAgICBWS19GT1JNQVRfQjE2RzE2UjE2RzE2XzQyMl9VTk9STV9LSFI6IDEwMDAxNTYwMjgsCiAgICAgICAgVktfRk9STUFUX0cxNl9CMTZfUjE2XzNQTEFORV80MjBfVU5PUk1fS0hSOiAxMDAwMTU2MDI5LAogICAgICAgIFZLX0ZPUk1BVF9HMTZfQjE2UjE2XzJQTEFORV80MjBfVU5PUk1fS0hSOiAxMDAwMTU2MDMwLAogICAgICAgIFZLX0ZPUk1BVF9HMTZfQjE2X1IxNl8zUExBTkVfNDIyX1VOT1JNX0tIUjogMTAwMDE1NjAzMSwKICAgICAgICBWS19GT1JNQVRfRzE2X0IxNlIxNl8yUExBTkVfNDIyX1VOT1JNX0tIUjogMTAwMDE1NjAzMiwKICAgICAgICBWS19GT1JNQVRfRzE2X0IxNl9SMTZfM1BMQU5FXzQ0NF9VTk9STV9LSFI6IDEwMDAxNTYwMzMKICAgICAgfTsKICAgICAgT2JqZWN0LmZyZWV6ZShWdWxrYW5Db25zdGFudHMpOwogICAgICBWdWxrYW5Db25zdGFudHNfZGVmYXVsdCA9IFZ1bGthbkNvbnN0YW50czsKICAgIH0KICB9KTsKCiAgLy8gbm9kZV9tb2R1bGVzL2t0eC1wYXJzZS9kaXN0L2t0eC1wYXJzZS5tb2Rlcm4uanMKICBmdW5jdGlvbiBjcmVhdGVEZWZhdWx0Q29udGFpbmVyKCkgewogICAgcmV0dXJuIHsKICAgICAgdmtGb3JtYXQ6IFZLX0ZPUk1BVF9VTkRFRklORUQsCiAgICAgIHR5cGVTaXplOiAxLAogICAgICBwaXhlbFdpZHRoOiAwLAogICAgICBwaXhlbEhlaWdodDogMCwKICAgICAgcGl4ZWxEZXB0aDogMCwKICAgICAgbGF5ZXJDb3VudDogMCwKICAgICAgZmFjZUNvdW50OiAxLAogICAgICBsZXZlbENvdW50OiAwLAogICAgICBzdXBlcmNvbXByZXNzaW9uU2NoZW1lOiBLSFJfU1VQRVJDT01QUkVTU0lPTl9OT05FLAogICAgICBsZXZlbHM6IFtdLAogICAgICBkYXRhRm9ybWF0RGVzY3JpcHRvcjogW3sKICAgICAgICB2ZW5kb3JJZDogS0hSX0RGX1ZFTkRPUklEX0tIUk9OT1MsCiAgICAgICAgZGVzY3JpcHRvclR5cGU6IEtIUl9ERl9LSFJfREVTQ1JJUFRPUlRZUEVfQkFTSUNGT1JNQVQsCiAgICAgICAgdmVyc2lvbk51bWJlcjogS0hSX0RGX1ZFUlNJT04sCiAgICAgICAgY29sb3JNb2RlbDogS0hSX0RGX01PREVMX1VOU1BFQ0lGSUVELAogICAgICAgIGNvbG9yUHJpbWFyaWVzOiBLSFJfREZfUFJJTUFSSUVTX0JUNzA5LAogICAgICAgIHRyYW5zZmVyRnVuY3Rpb246IEtIUl9ERl9UUkFOU0ZFUl9TUkdCLAogICAgICAgIGZsYWdzOiBLSFJfREZfRkxBR19BTFBIQV9TVFJBSUdIVCwKICAgICAgICB0ZXhlbEJsb2NrRGltZW5zaW9uOiBbMCwgMCwgMCwgMF0sCiAgICAgICAgYnl0ZXNQbGFuZTogWzAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdLAogICAgICAgIHNhbXBsZXM6IFtdCiAgICAgIH1dLAogICAgICBrZXlWYWx1ZToge30sCiAgICAgIGdsb2JhbERhdGE6IG51bGwKICAgIH07CiAgfQogIGZ1bmN0aW9uIGRlY29kZVRleHQoYnVmZmVyKSB7CiAgICByZXR1cm4gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGJ1ZmZlcik7CiAgfQogIGZ1bmN0aW9uIHJlYWQyKGRhdGEpIHsKICAgIGNvbnN0IGlkID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5idWZmZXIsIGRhdGEuYnl0ZU9mZnNldCwgS1RYMl9JRC5sZW5ndGgpOwogICAgaWYgKGlkWzBdICE9PSBLVFgyX0lEWzBdIHx8IC8vICfCtCcKICAgIGlkWzFdICE9PSBLVFgyX0lEWzFdIHx8IC8vICdLJwogICAgaWRbMl0gIT09IEtUWDJfSURbMl0gfHwgLy8gJ1QnCiAgICBpZFszXSAhPT0gS1RYMl9JRFszXSB8fCAvLyAnWCcKICAgIGlkWzRdICE9PSBLVFgyX0lEWzRdIHx8IC8vICcgJwogICAgaWRbNV0gIT09IEtUWDJfSURbNV0gfHwgLy8gJzInCiAgICBpZFs2XSAhPT0gS1RYMl9JRFs2XSB8fCAvLyAnMCcKICAgIGlkWzddICE9PSBLVFgyX0lEWzddIHx8IC8vICfCqicKICAgIGlkWzhdICE9PSBLVFgyX0lEWzhdIHx8IC8vICdccicKICAgIGlkWzldICE9PSBLVFgyX0lEWzldIHx8IC8vICdcbicKICAgIGlkWzEwXSAhPT0gS1RYMl9JRFsxMF0gfHwgLy8gJ1x4MUEnCiAgICBpZFsxMV0gIT09IEtUWDJfSURbMTFdKSB7CiAgICAgIHRocm93IG5ldyBFcnJvcigiTWlzc2luZyBLVFggMi4wIGlkZW50aWZpZXIuIik7CiAgICB9CiAgICBjb25zdCBjb250YWluZXIgPSBjcmVhdGVEZWZhdWx0Q29udGFpbmVyKCk7CiAgICBjb25zdCBoZWFkZXJCeXRlTGVuZ3RoID0gMTcgKiBVaW50MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVDsKICAgIGNvbnN0IGhlYWRlclJlYWRlciA9IG5ldyBCdWZmZXJSZWFkZXIoZGF0YSwgS1RYMl9JRC5sZW5ndGgsIGhlYWRlckJ5dGVMZW5ndGgsIHRydWUpOwogICAgY29udGFpbmVyLnZrRm9ybWF0ID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb250YWluZXIudHlwZVNpemUgPSBoZWFkZXJSZWFkZXIuX25leHRVaW50MzIoKTsKICAgIGNvbnRhaW5lci5waXhlbFdpZHRoID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb250YWluZXIucGl4ZWxIZWlnaHQgPSBoZWFkZXJSZWFkZXIuX25leHRVaW50MzIoKTsKICAgIGNvbnRhaW5lci5waXhlbERlcHRoID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb250YWluZXIubGF5ZXJDb3VudCA9IGhlYWRlclJlYWRlci5fbmV4dFVpbnQzMigpOwogICAgY29udGFpbmVyLmZhY2VDb3VudCA9IGhlYWRlclJlYWRlci5fbmV4dFVpbnQzMigpOwogICAgY29udGFpbmVyLmxldmVsQ291bnQgPSBoZWFkZXJSZWFkZXIuX25leHRVaW50MzIoKTsKICAgIGNvbnRhaW5lci5zdXBlcmNvbXByZXNzaW9uU2NoZW1lID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBkZmRCeXRlT2Zmc2V0ID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBkZmRCeXRlTGVuZ3RoID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBrdmRCeXRlT2Zmc2V0ID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBrdmRCeXRlTGVuZ3RoID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBzZ2RCeXRlT2Zmc2V0ID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDY0KCk7CiAgICBjb25zdCBzZ2RCeXRlTGVuZ3RoID0gaGVhZGVyUmVhZGVyLl9uZXh0VWludDY0KCk7CiAgICBjb25zdCBsZXZlbEJ5dGVMZW5ndGggPSBNYXRoLm1heChjb250YWluZXIubGV2ZWxDb3VudCwgMSkgKiAzICogODsKICAgIGNvbnN0IGxldmVsUmVhZGVyID0gbmV3IEJ1ZmZlclJlYWRlcihkYXRhLCBLVFgyX0lELmxlbmd0aCArIGhlYWRlckJ5dGVMZW5ndGgsIGxldmVsQnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgICBmb3IgKGxldCBpMiA9IDAsIGlsID0gTWF0aC5tYXgoY29udGFpbmVyLmxldmVsQ291bnQsIDEpOyBpMiA8IGlsOyBpMisrKSB7CiAgICAgIGNvbnRhaW5lci5sZXZlbHMucHVzaCh7CiAgICAgICAgbGV2ZWxEYXRhOiBuZXcgVWludDhBcnJheShkYXRhLmJ1ZmZlciwgZGF0YS5ieXRlT2Zmc2V0ICsgbGV2ZWxSZWFkZXIuX25leHRVaW50NjQoKSwgbGV2ZWxSZWFkZXIuX25leHRVaW50NjQoKSksCiAgICAgICAgdW5jb21wcmVzc2VkQnl0ZUxlbmd0aDogbGV2ZWxSZWFkZXIuX25leHRVaW50NjQoKQogICAgICB9KTsKICAgIH0KICAgIGNvbnN0IGRmZFJlYWRlciA9IG5ldyBCdWZmZXJSZWFkZXIoZGF0YSwgZGZkQnl0ZU9mZnNldCwgZGZkQnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgICBkZmRSZWFkZXIuX3NraXAoNCk7CiAgICBjb25zdCB2ZW5kb3JJZCA9IGRmZFJlYWRlci5fbmV4dFVpbnQxNigpOwogICAgY29uc3QgZGVzY3JpcHRvclR5cGUgPSBkZmRSZWFkZXIuX25leHRVaW50MTYoKTsKICAgIGNvbnN0IHZlcnNpb25OdW1iZXIgPSBkZmRSZWFkZXIuX25leHRVaW50MTYoKTsKICAgIGNvbnN0IGRlc2NyaXB0b3JCbG9ja1NpemUgPSBkZmRSZWFkZXIuX25leHRVaW50MTYoKTsKICAgIGNvbnN0IGNvbG9yTW9kZWwgPSBkZmRSZWFkZXIuX25leHRVaW50OCgpOwogICAgY29uc3QgY29sb3JQcmltYXJpZXMgPSBkZmRSZWFkZXIuX25leHRVaW50OCgpOwogICAgY29uc3QgdHJhbnNmZXJGdW5jdGlvbiA9IGRmZFJlYWRlci5fbmV4dFVpbnQ4KCk7CiAgICBjb25zdCBmbGFncyA9IGRmZFJlYWRlci5fbmV4dFVpbnQ4KCk7CiAgICBjb25zdCB0ZXhlbEJsb2NrRGltZW5zaW9uID0gW2RmZFJlYWRlci5fbmV4dFVpbnQ4KCksIGRmZFJlYWRlci5fbmV4dFVpbnQ4KCksIGRmZFJlYWRlci5fbmV4dFVpbnQ4KCksIGRmZFJlYWRlci5fbmV4dFVpbnQ4KCldOwogICAgY29uc3QgYnl0ZXNQbGFuZSA9IFtkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpXTsKICAgIGNvbnN0IHNhbXBsZXMgPSBbXTsKICAgIGNvbnN0IGRmZCA9IHsKICAgICAgdmVuZG9ySWQsCiAgICAgIGRlc2NyaXB0b3JUeXBlLAogICAgICB2ZXJzaW9uTnVtYmVyLAogICAgICBjb2xvck1vZGVsLAogICAgICBjb2xvclByaW1hcmllcywKICAgICAgdHJhbnNmZXJGdW5jdGlvbiwKICAgICAgZmxhZ3MsCiAgICAgIHRleGVsQmxvY2tEaW1lbnNpb24sCiAgICAgIGJ5dGVzUGxhbmUsCiAgICAgIHNhbXBsZXMKICAgIH07CiAgICBjb25zdCBzYW1wbGVTdGFydCA9IDY7CiAgICBjb25zdCBzYW1wbGVXb3JkcyA9IDQ7CiAgICBjb25zdCBudW1TYW1wbGVzID0gKGRlc2NyaXB0b3JCbG9ja1NpemUgLyA0IC0gc2FtcGxlU3RhcnQpIC8gc2FtcGxlV29yZHM7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbnVtU2FtcGxlczsgaTIrKykgewogICAgICBjb25zdCBzYW1wbGUgPSB7CiAgICAgICAgYml0T2Zmc2V0OiBkZmRSZWFkZXIuX25leHRVaW50MTYoKSwKICAgICAgICBiaXRMZW5ndGg6IGRmZFJlYWRlci5fbmV4dFVpbnQ4KCksCiAgICAgICAgY2hhbm5lbFR5cGU6IGRmZFJlYWRlci5fbmV4dFVpbnQ4KCksCiAgICAgICAgc2FtcGxlUG9zaXRpb246IFtkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpLCBkZmRSZWFkZXIuX25leHRVaW50OCgpXSwKICAgICAgICBzYW1wbGVMb3dlcjogTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZLAogICAgICAgIHNhbXBsZVVwcGVyOiBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFkKICAgICAgfTsKICAgICAgaWYgKHNhbXBsZS5jaGFubmVsVHlwZSAmIEtIUl9ERl9TQU1QTEVfREFUQVRZUEVfU0lHTkVEKSB7CiAgICAgICAgc2FtcGxlLnNhbXBsZUxvd2VyID0gZGZkUmVhZGVyLl9uZXh0SW50MzIoKTsKICAgICAgICBzYW1wbGUuc2FtcGxlVXBwZXIgPSBkZmRSZWFkZXIuX25leHRJbnQzMigpOwogICAgICB9IGVsc2UgewogICAgICAgIHNhbXBsZS5zYW1wbGVMb3dlciA9IGRmZFJlYWRlci5fbmV4dFVpbnQzMigpOwogICAgICAgIHNhbXBsZS5zYW1wbGVVcHBlciA9IGRmZFJlYWRlci5fbmV4dFVpbnQzMigpOwogICAgICB9CiAgICAgIGRmZC5zYW1wbGVzW2kyXSA9IHNhbXBsZTsKICAgIH0KICAgIGNvbnRhaW5lci5kYXRhRm9ybWF0RGVzY3JpcHRvci5sZW5ndGggPSAwOwogICAgY29udGFpbmVyLmRhdGFGb3JtYXREZXNjcmlwdG9yLnB1c2goZGZkKTsKICAgIGNvbnN0IGt2ZFJlYWRlciA9IG5ldyBCdWZmZXJSZWFkZXIoZGF0YSwga3ZkQnl0ZU9mZnNldCwga3ZkQnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgICB3aGlsZSAoa3ZkUmVhZGVyLl9vZmZzZXQgPCBrdmRCeXRlTGVuZ3RoKSB7CiAgICAgIGNvbnN0IGtleVZhbHVlQnl0ZUxlbmd0aCA9IGt2ZFJlYWRlci5fbmV4dFVpbnQzMigpOwogICAgICBjb25zdCBrZXlEYXRhID0ga3ZkUmVhZGVyLl9zY2FuKGtleVZhbHVlQnl0ZUxlbmd0aCk7CiAgICAgIGNvbnN0IGtleSA9IGRlY29kZVRleHQoa2V5RGF0YSk7CiAgICAgIGNvbnRhaW5lci5rZXlWYWx1ZVtrZXldID0ga3ZkUmVhZGVyLl9uZXh0VWludDhBcnJheShrZXlWYWx1ZUJ5dGVMZW5ndGggLSBrZXlEYXRhLmJ5dGVMZW5ndGggLSAxKTsKICAgICAgaWYgKGtleS5tYXRjaCgvXmt0eC9pKSkgewogICAgICAgIGNvbnN0IHRleHQgPSBkZWNvZGVUZXh0KGNvbnRhaW5lci5rZXlWYWx1ZVtrZXldKTsKICAgICAgICBjb250YWluZXIua2V5VmFsdWVba2V5XSA9IHRleHQuc3Vic3RyaW5nKDAsIHRleHQubGFzdEluZGV4T2YoIlwwIikpOwogICAgICB9CiAgICAgIGNvbnN0IGt2UGFkZGluZyA9IGtleVZhbHVlQnl0ZUxlbmd0aCAlIDQgPyA0IC0ga2V5VmFsdWVCeXRlTGVuZ3RoICUgNCA6IDA7CiAgICAgIGt2ZFJlYWRlci5fc2tpcChrdlBhZGRpbmcpOwogICAgfQogICAgaWYgKHNnZEJ5dGVMZW5ndGggPD0gMCkgcmV0dXJuIGNvbnRhaW5lcjsKICAgIGNvbnN0IHNnZFJlYWRlciA9IG5ldyBCdWZmZXJSZWFkZXIoZGF0YSwgc2dkQnl0ZU9mZnNldCwgc2dkQnl0ZUxlbmd0aCwgdHJ1ZSk7CiAgICBjb25zdCBlbmRwb2ludENvdW50ID0gc2dkUmVhZGVyLl9uZXh0VWludDE2KCk7CiAgICBjb25zdCBzZWxlY3RvckNvdW50ID0gc2dkUmVhZGVyLl9uZXh0VWludDE2KCk7CiAgICBjb25zdCBlbmRwb2ludHNCeXRlTGVuZ3RoID0gc2dkUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBzZWxlY3RvcnNCeXRlTGVuZ3RoID0gc2dkUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCB0YWJsZXNCeXRlTGVuZ3RoID0gc2dkUmVhZGVyLl9uZXh0VWludDMyKCk7CiAgICBjb25zdCBleHRlbmRlZEJ5dGVMZW5ndGggPSBzZ2RSZWFkZXIuX25leHRVaW50MzIoKTsKICAgIGNvbnN0IGltYWdlRGVzY3MgPSBbXTsKICAgIGZvciAobGV0IGkyID0gMCwgaWwgPSBNYXRoLm1heChjb250YWluZXIubGV2ZWxDb3VudCwgMSk7IGkyIDwgaWw7IGkyKyspIHsKICAgICAgaW1hZ2VEZXNjcy5wdXNoKHsKICAgICAgICBpbWFnZUZsYWdzOiBzZ2RSZWFkZXIuX25leHRVaW50MzIoKSwKICAgICAgICByZ2JTbGljZUJ5dGVPZmZzZXQ6IHNnZFJlYWRlci5fbmV4dFVpbnQzMigpLAogICAgICAgIHJnYlNsaWNlQnl0ZUxlbmd0aDogc2dkUmVhZGVyLl9uZXh0VWludDMyKCksCiAgICAgICAgYWxwaGFTbGljZUJ5dGVPZmZzZXQ6IHNnZFJlYWRlci5fbmV4dFVpbnQzMigpLAogICAgICAgIGFscGhhU2xpY2VCeXRlTGVuZ3RoOiBzZ2RSZWFkZXIuX25leHRVaW50MzIoKQogICAgICB9KTsKICAgIH0KICAgIGNvbnN0IGVuZHBvaW50c0J5dGVPZmZzZXQgPSBzZ2RCeXRlT2Zmc2V0ICsgc2dkUmVhZGVyLl9vZmZzZXQ7CiAgICBjb25zdCBzZWxlY3RvcnNCeXRlT2Zmc2V0ID0gZW5kcG9pbnRzQnl0ZU9mZnNldCArIGVuZHBvaW50c0J5dGVMZW5ndGg7CiAgICBjb25zdCB0YWJsZXNCeXRlT2Zmc2V0ID0gc2VsZWN0b3JzQnl0ZU9mZnNldCArIHNlbGVjdG9yc0J5dGVMZW5ndGg7CiAgICBjb25zdCBleHRlbmRlZEJ5dGVPZmZzZXQgPSB0YWJsZXNCeXRlT2Zmc2V0ICsgdGFibGVzQnl0ZUxlbmd0aDsKICAgIGNvbnN0IGVuZHBvaW50c0RhdGEgPSBuZXcgVWludDhBcnJheShkYXRhLmJ1ZmZlciwgZGF0YS5ieXRlT2Zmc2V0ICsgZW5kcG9pbnRzQnl0ZU9mZnNldCwgZW5kcG9pbnRzQnl0ZUxlbmd0aCk7CiAgICBjb25zdCBzZWxlY3RvcnNEYXRhID0gbmV3IFVpbnQ4QXJyYXkoZGF0YS5idWZmZXIsIGRhdGEuYnl0ZU9mZnNldCArIHNlbGVjdG9yc0J5dGVPZmZzZXQsIHNlbGVjdG9yc0J5dGVMZW5ndGgpOwogICAgY29uc3QgdGFibGVzRGF0YSA9IG5ldyBVaW50OEFycmF5KGRhdGEuYnVmZmVyLCBkYXRhLmJ5dGVPZmZzZXQgKyB0YWJsZXNCeXRlT2Zmc2V0LCB0YWJsZXNCeXRlTGVuZ3RoKTsKICAgIGNvbnN0IGV4dGVuZGVkRGF0YSA9IG5ldyBVaW50OEFycmF5KGRhdGEuYnVmZmVyLCBkYXRhLmJ5dGVPZmZzZXQgKyBleHRlbmRlZEJ5dGVPZmZzZXQsIGV4dGVuZGVkQnl0ZUxlbmd0aCk7CiAgICBjb250YWluZXIuZ2xvYmFsRGF0YSA9IHsKICAgICAgZW5kcG9pbnRDb3VudCwKICAgICAgc2VsZWN0b3JDb3VudCwKICAgICAgaW1hZ2VEZXNjcywKICAgICAgZW5kcG9pbnRzRGF0YSwKICAgICAgc2VsZWN0b3JzRGF0YSwKICAgICAgdGFibGVzRGF0YSwKICAgICAgZXh0ZW5kZWREYXRhCiAgICB9OwogICAgcmV0dXJuIGNvbnRhaW5lcjsKICB9CiAgdmFyIEtIUl9TVVBFUkNPTVBSRVNTSU9OX05PTkUsIEtIUl9ERl9LSFJfREVTQ1JJUFRPUlRZUEVfQkFTSUNGT1JNQVQsIEtIUl9ERl9WRU5ET1JJRF9LSFJPTk9TLCBLSFJfREZfVkVSU0lPTiwgS0hSX0RGX01PREVMX1VOU1BFQ0lGSUVELCBLSFJfREZfRkxBR19BTFBIQV9TVFJBSUdIVCwgS0hSX0RGX1RSQU5TRkVSX1NSR0IsIEtIUl9ERl9QUklNQVJJRVNfQlQ3MDksIEtIUl9ERl9TQU1QTEVfREFUQVRZUEVfU0lHTkVELCBWS19GT1JNQVRfVU5ERUZJTkVELCBCdWZmZXJSZWFkZXIsIE5VTCwgS1RYMl9JRDsKICB2YXIgaW5pdF9rdHhfcGFyc2VfbW9kZXJuID0gX19lc20oewogICAgIm5vZGVfbW9kdWxlcy9rdHgtcGFyc2UvZGlzdC9rdHgtcGFyc2UubW9kZXJuLmpzIigpIHsKICAgICAgS0hSX1NVUEVSQ09NUFJFU1NJT05fTk9ORSA9IDA7CiAgICAgIEtIUl9ERl9LSFJfREVTQ1JJUFRPUlRZUEVfQkFTSUNGT1JNQVQgPSAwOwogICAgICBLSFJfREZfVkVORE9SSURfS0hST05PUyA9IDA7CiAgICAgIEtIUl9ERl9WRVJTSU9OID0gMjsKICAgICAgS0hSX0RGX01PREVMX1VOU1BFQ0lGSUVEID0gMDsKICAgICAgS0hSX0RGX0ZMQUdfQUxQSEFfU1RSQUlHSFQgPSAwOwogICAgICBLSFJfREZfVFJBTlNGRVJfU1JHQiA9IDI7CiAgICAgIEtIUl9ERl9QUklNQVJJRVNfQlQ3MDkgPSAxOwogICAgICBLSFJfREZfU0FNUExFX0RBVEFUWVBFX1NJR05FRCA9IDY0OwogICAgICBWS19GT1JNQVRfVU5ERUZJTkVEID0gMDsKICAgICAgQnVmZmVyUmVhZGVyID0gY2xhc3MgewogICAgICAgIGNvbnN0cnVjdG9yKGRhdGEsIGJ5dGVPZmZzZXQsIGJ5dGVMZW5ndGgsIGxpdHRsZUVuZGlhbjIpIHsKICAgICAgICAgIHRoaXMuX2RhdGFWaWV3ID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fbGl0dGxlRW5kaWFuID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fb2Zmc2V0ID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5fZGF0YVZpZXcgPSBuZXcgRGF0YVZpZXcoZGF0YS5idWZmZXIsIGRhdGEuYnl0ZU9mZnNldCArIGJ5dGVPZmZzZXQsIGJ5dGVMZW5ndGgpOwogICAgICAgICAgdGhpcy5fbGl0dGxlRW5kaWFuID0gbGl0dGxlRW5kaWFuMjsKICAgICAgICAgIHRoaXMuX29mZnNldCA9IDA7CiAgICAgICAgfQogICAgICAgIF9uZXh0VWludDgoKSB7CiAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuX2RhdGFWaWV3LmdldFVpbnQ4KHRoaXMuX29mZnNldCk7CiAgICAgICAgICB0aGlzLl9vZmZzZXQgKz0gMTsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgX25leHRVaW50MTYoKSB7CiAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuX2RhdGFWaWV3LmdldFVpbnQxNih0aGlzLl9vZmZzZXQsIHRoaXMuX2xpdHRsZUVuZGlhbik7CiAgICAgICAgICB0aGlzLl9vZmZzZXQgKz0gMjsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgX25leHRVaW50MzIoKSB7CiAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuX2RhdGFWaWV3LmdldFVpbnQzMih0aGlzLl9vZmZzZXQsIHRoaXMuX2xpdHRsZUVuZGlhbik7CiAgICAgICAgICB0aGlzLl9vZmZzZXQgKz0gNDsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgX25leHRVaW50NjQoKSB7CiAgICAgICAgICBjb25zdCBsZWZ0ID0gdGhpcy5fZGF0YVZpZXcuZ2V0VWludDMyKHRoaXMuX29mZnNldCwgdGhpcy5fbGl0dGxlRW5kaWFuKTsKICAgICAgICAgIGNvbnN0IHJpZ2h0ID0gdGhpcy5fZGF0YVZpZXcuZ2V0VWludDMyKHRoaXMuX29mZnNldCArIDQsIHRoaXMuX2xpdHRsZUVuZGlhbik7CiAgICAgICAgICBjb25zdCB2YWx1ZSA9IGxlZnQgKyAyICoqIDMyICogcmlnaHQ7CiAgICAgICAgICB0aGlzLl9vZmZzZXQgKz0gODsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgX25leHRJbnQzMigpIHsKICAgICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fZGF0YVZpZXcuZ2V0SW50MzIodGhpcy5fb2Zmc2V0LCB0aGlzLl9saXR0bGVFbmRpYW4pOwogICAgICAgICAgdGhpcy5fb2Zmc2V0ICs9IDQ7CiAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgICAgfQogICAgICAgIF9uZXh0VWludDhBcnJheShsZW4pIHsKICAgICAgICAgIGNvbnN0IHZhbHVlID0gbmV3IFVpbnQ4QXJyYXkodGhpcy5fZGF0YVZpZXcuYnVmZmVyLCB0aGlzLl9kYXRhVmlldy5ieXRlT2Zmc2V0ICsgdGhpcy5fb2Zmc2V0LCBsZW4pOwogICAgICAgICAgdGhpcy5fb2Zmc2V0ICs9IGxlbjsKICAgICAgICAgIHJldHVybiB2YWx1ZTsKICAgICAgICB9CiAgICAgICAgX3NraXAoYnl0ZXMpIHsKICAgICAgICAgIHRoaXMuX29mZnNldCArPSBieXRlczsKICAgICAgICAgIHJldHVybiB0aGlzOwogICAgICAgIH0KICAgICAgICBfc2NhbihtYXhCeXRlTGVuZ3RoLCB0ZXJtID0gMCkgewogICAgICAgICAgY29uc3QgYnl0ZU9mZnNldCA9IHRoaXMuX29mZnNldDsKICAgICAgICAgIGxldCBieXRlTGVuZ3RoID0gMDsKICAgICAgICAgIHdoaWxlICh0aGlzLl9kYXRhVmlldy5nZXRVaW50OCh0aGlzLl9vZmZzZXQpICE9PSB0ZXJtICYmIGJ5dGVMZW5ndGggPCBtYXhCeXRlTGVuZ3RoKSB7CiAgICAgICAgICAgIGJ5dGVMZW5ndGgrKzsKICAgICAgICAgICAgdGhpcy5fb2Zmc2V0Kys7CiAgICAgICAgICB9CiAgICAgICAgICBpZiAoYnl0ZUxlbmd0aCA8IG1heEJ5dGVMZW5ndGgpIHRoaXMuX29mZnNldCsrOwogICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHRoaXMuX2RhdGFWaWV3LmJ1ZmZlciwgdGhpcy5fZGF0YVZpZXcuYnl0ZU9mZnNldCArIGJ5dGVPZmZzZXQsIGJ5dGVMZW5ndGgpOwogICAgICAgIH0KICAgICAgfTsKICAgICAgTlVMID0gbmV3IFVpbnQ4QXJyYXkoWzBdKTsKICAgICAgS1RYMl9JRCA9IFsKICAgICAgICAvLyAnwrQnLCAnSycsICdUJywgJ1gnLCAnMicsICcwJywgJ8KqJywgJ1xyJywgJ1xuJywgJ1x4MUEnLCAnXG4nCiAgICAgICAgMTcxLAogICAgICAgIDc1LAogICAgICAgIDg0LAogICAgICAgIDg4LAogICAgICAgIDMyLAogICAgICAgIDUwLAogICAgICAgIDQ4LAogICAgICAgIDE4NywKICAgICAgICAxMywKICAgICAgICAxMCwKICAgICAgICAyNiwKICAgICAgICAxMAogICAgICBdOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1RoaXJkUGFydHkvV29ya2Vycy9iYXNpc190cmFuc2NvZGVyLmpzCiAgdmFyIHJlcXVpcmVfYmFzaXNfdHJhbnNjb2RlciA9IF9fY29tbW9uSlMoewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvVGhpcmRQYXJ0eS9Xb3JrZXJzL2Jhc2lzX3RyYW5zY29kZXIuanMiKGV4cG9ydHMyLCBtb2R1bGUpIHsKICAgICAgdmFyIEJBU0lTID0gKGZ1bmN0aW9uKCkgewogICAgICAgIHZhciBfc2NyaXB0RGlyID0gdHlwZW9mIGRvY3VtZW50ICE9PSAidW5kZWZpbmVkIiAmJiBkb2N1bWVudC5jdXJyZW50U2NyaXB0ID8gZG9jdW1lbnQuY3VycmVudFNjcmlwdC5zcmMgOiB2b2lkIDA7CiAgICAgICAgaWYgKHR5cGVvZiBfX2ZpbGVuYW1lICE9PSAidW5kZWZpbmVkIikgX3NjcmlwdERpciA9IF9zY3JpcHREaXIgfHwgX19maWxlbmFtZTsKICAgICAgICByZXR1cm4gKGZ1bmN0aW9uKEJBU0lTMikgewogICAgICAgICAgQkFTSVMyID0gQkFTSVMyIHx8IHt9OwogICAgICAgICAgdmFyIE1vZHVsZSA9IHR5cGVvZiBCQVNJUzIgIT09ICJ1bmRlZmluZWQiID8gQkFTSVMyIDoge307CiAgICAgICAgICB2YXIgcmVhZHlQcm9taXNlUmVzb2x2ZSwgcmVhZHlQcm9taXNlUmVqZWN0OwogICAgICAgICAgTW9kdWxlWyJyZWFkeSJdID0gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7CiAgICAgICAgICAgIHJlYWR5UHJvbWlzZVJlc29sdmUgPSByZXNvbHZlOwogICAgICAgICAgICByZWFkeVByb21pc2VSZWplY3QgPSByZWplY3Q7CiAgICAgICAgICB9KTsKICAgICAgICAgIHZhciBtb2R1bGVPdmVycmlkZXMgPSB7fTsKICAgICAgICAgIHZhciBrZXk7CiAgICAgICAgICBmb3IgKGtleSBpbiBNb2R1bGUpIHsKICAgICAgICAgICAgaWYgKE1vZHVsZS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7CiAgICAgICAgICAgICAgbW9kdWxlT3ZlcnJpZGVzW2tleV0gPSBNb2R1bGVba2V5XTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdmFyIGFyZ3VtZW50c18gPSBbXTsKICAgICAgICAgIHZhciB0aGlzUHJvZ3JhbSA9ICIuL3RoaXMucHJvZ3JhbSI7CiAgICAgICAgICB2YXIgcXVpdF8gPSBmdW5jdGlvbihzdGF0dXMsIHRvVGhyb3cpIHsKICAgICAgICAgICAgdGhyb3cgdG9UaHJvdzsKICAgICAgICAgIH07CiAgICAgICAgICB2YXIgRU5WSVJPTk1FTlRfSVNfV0VCID0gZmFsc2U7CiAgICAgICAgICB2YXIgRU5WSVJPTk1FTlRfSVNfV09SS0VSID0gZmFsc2U7CiAgICAgICAgICB2YXIgRU5WSVJPTk1FTlRfSVNfTk9ERSA9IGZhbHNlOwogICAgICAgICAgdmFyIEVOVklST05NRU5UX0lTX1NIRUxMID0gZmFsc2U7CiAgICAgICAgICBFTlZJUk9OTUVOVF9JU19XRUIgPSB0eXBlb2Ygd2luZG93ID09PSAib2JqZWN0IjsKICAgICAgICAgIEVOVklST05NRU5UX0lTX1dPUktFUiA9IHR5cGVvZiBpbXBvcnRTY3JpcHRzID09PSAiZnVuY3Rpb24iOwogICAgICAgICAgRU5WSVJPTk1FTlRfSVNfTk9ERSA9IHR5cGVvZiBwcm9jZXNzID09PSAib2JqZWN0IiAmJiB0eXBlb2YgcHJvY2Vzcy52ZXJzaW9ucyA9PT0gIm9iamVjdCIgJiYgdHlwZW9mIHByb2Nlc3MudmVyc2lvbnMubm9kZSA9PT0gInN0cmluZyI7CiAgICAgICAgICBFTlZJUk9OTUVOVF9JU19TSEVMTCA9ICFFTlZJUk9OTUVOVF9JU19XRUIgJiYgIUVOVklST05NRU5UX0lTX05PREUgJiYgIUVOVklST05NRU5UX0lTX1dPUktFUjsKICAgICAgICAgIHZhciBzY3JpcHREaXJlY3RvcnkgPSAiIjsKICAgICAgICAgIGZ1bmN0aW9uIGxvY2F0ZUZpbGUocGF0aCkgewogICAgICAgICAgICBpZiAoTW9kdWxlWyJsb2NhdGVGaWxlIl0pIHsKICAgICAgICAgICAgICByZXR1cm4gTW9kdWxlWyJsb2NhdGVGaWxlIl0ocGF0aCwgc2NyaXB0RGlyZWN0b3J5KTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gc2NyaXB0RGlyZWN0b3J5ICsgcGF0aDsKICAgICAgICAgIH0KICAgICAgICAgIHZhciByZWFkXywgcmVhZEFzeW5jLCByZWFkQmluYXJ5LCBzZXRXaW5kb3dUaXRsZTsKICAgICAgICAgIHZhciBub2RlRlM7CiAgICAgICAgICB2YXIgbm9kZVBhdGg7CiAgICAgICAgICBpZiAoRU5WSVJPTk1FTlRfSVNfTk9ERSkgewogICAgICAgICAgICBpZiAoRU5WSVJPTk1FTlRfSVNfV09SS0VSKSB7CiAgICAgICAgICAgICAgc2NyaXB0RGlyZWN0b3J5ID0gX19yZXF1aXJlKCJwYXRoIikuZGlybmFtZShzY3JpcHREaXJlY3RvcnkpICsgIi8iOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHNjcmlwdERpcmVjdG9yeSA9IF9fZGlybmFtZSArICIvIjsKICAgICAgICAgICAgfQogICAgICAgICAgICByZWFkXyA9IGZ1bmN0aW9uIHNoZWxsX3JlYWQoZmlsZW5hbWUsIGJpbmFyeSkgewogICAgICAgICAgICAgIGlmICghbm9kZUZTKSBub2RlRlMgPSBfX3JlcXVpcmUoImZzIik7CiAgICAgICAgICAgICAgaWYgKCFub2RlUGF0aCkgbm9kZVBhdGggPSBfX3JlcXVpcmUoInBhdGgiKTsKICAgICAgICAgICAgICBmaWxlbmFtZSA9IG5vZGVQYXRoWyJub3JtYWxpemUiXShmaWxlbmFtZSk7CiAgICAgICAgICAgICAgcmV0dXJuIG5vZGVGU1sicmVhZEZpbGVTeW5jIl0oZmlsZW5hbWUsIGJpbmFyeSA/IG51bGwgOiAidXRmOCIpOwogICAgICAgICAgICB9OwogICAgICAgICAgICByZWFkQmluYXJ5ID0gZnVuY3Rpb24gcmVhZEJpbmFyeTIoZmlsZW5hbWUpIHsKICAgICAgICAgICAgICB2YXIgcmV0ID0gcmVhZF8oZmlsZW5hbWUsIHRydWUpOwogICAgICAgICAgICAgIGlmICghcmV0LmJ1ZmZlcikgewogICAgICAgICAgICAgICAgcmV0ID0gbmV3IFVpbnQ4QXJyYXkocmV0KTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgYXNzZXJ0KHJldC5idWZmZXIpOwogICAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGlmIChwcm9jZXNzWyJhcmd2Il0ubGVuZ3RoID4gMSkgewogICAgICAgICAgICAgIHRoaXNQcm9ncmFtID0gcHJvY2Vzc1siYXJndiJdWzFdLnJlcGxhY2UoL1xcL2csICIvIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgYXJndW1lbnRzXyA9IHByb2Nlc3NbImFyZ3YiXS5zbGljZSgyKTsKICAgICAgICAgICAgcHJvY2Vzc1sib24iXSgidW5jYXVnaHRFeGNlcHRpb24iLCBmdW5jdGlvbihleCkgewogICAgICAgICAgICAgIGlmICghKGV4IGluc3RhbmNlb2YgRXhpdFN0YXR1cykpIHsKICAgICAgICAgICAgICAgIHRocm93IGV4OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIHByb2Nlc3NbIm9uIl0oInVuaGFuZGxlZFJlamVjdGlvbiIsIGFib3J0KTsKICAgICAgICAgICAgcXVpdF8gPSBmdW5jdGlvbihzdGF0dXMpIHsKICAgICAgICAgICAgICBwcm9jZXNzWyJleGl0Il0oc3RhdHVzKTsKICAgICAgICAgICAgfTsKICAgICAgICAgICAgTW9kdWxlWyJpbnNwZWN0Il0gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICByZXR1cm4gIltFbXNjcmlwdGVuIE1vZHVsZSBvYmplY3RdIjsKICAgICAgICAgICAgfTsKICAgICAgICAgIH0gZWxzZSBpZiAoRU5WSVJPTk1FTlRfSVNfU0hFTEwpIHsKICAgICAgICAgICAgaWYgKHR5cGVvZiByZWFkICE9ICJ1bmRlZmluZWQiKSB7CiAgICAgICAgICAgICAgcmVhZF8gPSBmdW5jdGlvbiBzaGVsbF9yZWFkKGYyKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gcmVhZChmMik7CiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZWFkQmluYXJ5ID0gZnVuY3Rpb24gcmVhZEJpbmFyeTIoZjIpIHsKICAgICAgICAgICAgICB2YXIgZGF0YTsKICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlYWRidWZmZXIgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShyZWFkYnVmZmVyKGYyKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGRhdGEgPSByZWFkKGYyLCAiYmluYXJ5Iik7CiAgICAgICAgICAgICAgYXNzZXJ0KHR5cGVvZiBkYXRhID09PSAib2JqZWN0Iik7CiAgICAgICAgICAgICAgcmV0dXJuIGRhdGE7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGlmICh0eXBlb2Ygc2NyaXB0QXJncyAhPSAidW5kZWZpbmVkIikgewogICAgICAgICAgICAgIGFyZ3VtZW50c18gPSBzY3JpcHRBcmdzOwogICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBhcmd1bWVudHMgIT0gInVuZGVmaW5lZCIpIHsKICAgICAgICAgICAgICBhcmd1bWVudHNfID0gYXJndW1lbnRzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh0eXBlb2YgcXVpdCA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICAgIHF1aXRfID0gZnVuY3Rpb24oc3RhdHVzKSB7CiAgICAgICAgICAgICAgICBxdWl0KHN0YXR1cyk7CiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodHlwZW9mIHByaW50ICE9PSAidW5kZWZpbmVkIikgewogICAgICAgICAgICAgIGlmICh0eXBlb2YgY29uc29sZSA9PT0gInVuZGVmaW5lZCIpIGNvbnNvbGUgPSB7fTsKICAgICAgICAgICAgICBjb25zb2xlLmxvZyA9IHByaW50OwogICAgICAgICAgICAgIGNvbnNvbGUud2FybiA9IGNvbnNvbGUuZXJyb3IgPSB0eXBlb2YgcHJpbnRFcnIgIT09ICJ1bmRlZmluZWQiID8gcHJpbnRFcnIgOiBwcmludDsKICAgICAgICAgICAgfQogICAgICAgICAgfSBlbHNlIGlmIChFTlZJUk9OTUVOVF9JU19XRUIgfHwgRU5WSVJPTk1FTlRfSVNfV09SS0VSKSB7CiAgICAgICAgICAgIGlmIChFTlZJUk9OTUVOVF9JU19XT1JLRVIpIHsKICAgICAgICAgICAgICBzY3JpcHREaXJlY3RvcnkgPSBzZWxmLmxvY2F0aW9uLmhyZWY7CiAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRvY3VtZW50ICE9PSAidW5kZWZpbmVkIiAmJiBkb2N1bWVudC5jdXJyZW50U2NyaXB0KSB7CiAgICAgICAgICAgICAgc2NyaXB0RGlyZWN0b3J5ID0gZG9jdW1lbnQuY3VycmVudFNjcmlwdC5zcmM7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKF9zY3JpcHREaXIpIHsKICAgICAgICAgICAgICBzY3JpcHREaXJlY3RvcnkgPSBfc2NyaXB0RGlyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChzY3JpcHREaXJlY3RvcnkuaW5kZXhPZigiYmxvYjoiKSAhPT0gMCkgewogICAgICAgICAgICAgIHNjcmlwdERpcmVjdG9yeSA9IHNjcmlwdERpcmVjdG9yeS5zdWJzdHIoMCwgc2NyaXB0RGlyZWN0b3J5Lmxhc3RJbmRleE9mKCIvIikgKyAxKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBzY3JpcHREaXJlY3RvcnkgPSAiIjsKICAgICAgICAgICAgfQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgcmVhZF8gPSBmdW5jdGlvbih1cmwpIHsKICAgICAgICAgICAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTsKICAgICAgICAgICAgICAgIHhoci5vcGVuKCJHRVQiLCB1cmwsIGZhbHNlKTsKICAgICAgICAgICAgICAgIHhoci5zZW5kKG51bGwpOwogICAgICAgICAgICAgICAgcmV0dXJuIHhoci5yZXNwb25zZVRleHQ7CiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICBpZiAoRU5WSVJPTk1FTlRfSVNfV09SS0VSKSB7CiAgICAgICAgICAgICAgICByZWFkQmluYXJ5ID0gZnVuY3Rpb24odXJsKSB7CiAgICAgICAgICAgICAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTsKICAgICAgICAgICAgICAgICAgeGhyLm9wZW4oIkdFVCIsIHVybCwgZmFsc2UpOwogICAgICAgICAgICAgICAgICB4aHIucmVzcG9uc2VUeXBlID0gImFycmF5YnVmZmVyIjsKICAgICAgICAgICAgICAgICAgeGhyLnNlbmQobnVsbCk7CiAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheSh4aHIucmVzcG9uc2UpOwogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmVhZEFzeW5jID0gZnVuY3Rpb24odXJsLCBvbmxvYWQsIG9uZXJyb3IpIHsKICAgICAgICAgICAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTsKICAgICAgICAgICAgICAgIHhoci5vcGVuKCJHRVQiLCB1cmwsIHRydWUpOwogICAgICAgICAgICAgICAgeGhyLnJlc3BvbnNlVHlwZSA9ICJhcnJheWJ1ZmZlciI7CiAgICAgICAgICAgICAgICB4aHIub25sb2FkID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICAgIGlmICh4aHIuc3RhdHVzID09IDIwMCB8fCB4aHIuc3RhdHVzID09IDAgJiYgeGhyLnJlc3BvbnNlKSB7CiAgICAgICAgICAgICAgICAgICAgb25sb2FkKHhoci5yZXNwb25zZSk7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIG9uZXJyb3IoKTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgICB4aHIub25lcnJvciA9IG9uZXJyb3I7CiAgICAgICAgICAgICAgICB4aHIuc2VuZChudWxsKTsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICB9CiAgICAgICAgICAgIHNldFdpbmRvd1RpdGxlID0gZnVuY3Rpb24odGl0bGUpIHsKICAgICAgICAgICAgICBkb2N1bWVudC50aXRsZSA9IHRpdGxlOwogICAgICAgICAgICB9OwogICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBvdXQgPSBNb2R1bGVbInByaW50Il0gfHwgY29uc29sZS5sb2cuYmluZChjb25zb2xlKTsKICAgICAgICAgIHZhciBlcnIgPSBNb2R1bGVbInByaW50RXJyIl0gfHwgY29uc29sZS53YXJuLmJpbmQoY29uc29sZSk7CiAgICAgICAgICBmb3IgKGtleSBpbiBtb2R1bGVPdmVycmlkZXMpIHsKICAgICAgICAgICAgaWYgKG1vZHVsZU92ZXJyaWRlcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7CiAgICAgICAgICAgICAgTW9kdWxlW2tleV0gPSBtb2R1bGVPdmVycmlkZXNba2V5XTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgbW9kdWxlT3ZlcnJpZGVzID0gbnVsbDsKICAgICAgICAgIGlmIChNb2R1bGVbImFyZ3VtZW50cyJdKSBhcmd1bWVudHNfID0gTW9kdWxlWyJhcmd1bWVudHMiXTsKICAgICAgICAgIGlmIChNb2R1bGVbInRoaXNQcm9ncmFtIl0pIHRoaXNQcm9ncmFtID0gTW9kdWxlWyJ0aGlzUHJvZ3JhbSJdOwogICAgICAgICAgaWYgKE1vZHVsZVsicXVpdCJdKSBxdWl0XyA9IE1vZHVsZVsicXVpdCJdOwogICAgICAgICAgdmFyIHRlbXBSZXQwID0gMDsKICAgICAgICAgIHZhciBzZXRUZW1wUmV0MCA9IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgICAgIHRlbXBSZXQwID0gdmFsdWU7CiAgICAgICAgICB9OwogICAgICAgICAgdmFyIHdhc21CaW5hcnk7CiAgICAgICAgICBpZiAoTW9kdWxlWyJ3YXNtQmluYXJ5Il0pIHdhc21CaW5hcnkgPSBNb2R1bGVbIndhc21CaW5hcnkiXTsKICAgICAgICAgIHZhciBub0V4aXRSdW50aW1lID0gTW9kdWxlWyJub0V4aXRSdW50aW1lIl0gfHwgdHJ1ZTsKICAgICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkgIT09ICJvYmplY3QiKSB7CiAgICAgICAgICAgIGFib3J0KCJubyBuYXRpdmUgd2FzbSBzdXBwb3J0IGRldGVjdGVkIik7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgd2FzbU1lbW9yeTsKICAgICAgICAgIHZhciBBQk9SVCA9IGZhbHNlOwogICAgICAgICAgdmFyIEVYSVRTVEFUVVM7CiAgICAgICAgICBmdW5jdGlvbiBhc3NlcnQoY29uZGl0aW9uLCB0ZXh0KSB7CiAgICAgICAgICAgIGlmICghY29uZGl0aW9uKSB7CiAgICAgICAgICAgICAgYWJvcnQoIkFzc2VydGlvbiBmYWlsZWQ6ICIgKyB0ZXh0KTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgdmFyIFVURjhEZWNvZGVyID0gdHlwZW9mIFRleHREZWNvZGVyICE9PSAidW5kZWZpbmVkIiA/IG5ldyBUZXh0RGVjb2RlcigidXRmOCIpIDogdm9pZCAwOwogICAgICAgICAgZnVuY3Rpb24gVVRGOEFycmF5VG9TdHJpbmcoaGVhcCwgaWR4LCBtYXhCeXRlc1RvUmVhZCkgewogICAgICAgICAgICB2YXIgZW5kSWR4ID0gaWR4ICsgbWF4Qnl0ZXNUb1JlYWQ7CiAgICAgICAgICAgIHZhciBlbmRQdHIgPSBpZHg7CiAgICAgICAgICAgIHdoaWxlIChoZWFwW2VuZFB0cl0gJiYgIShlbmRQdHIgPj0gZW5kSWR4KSkgKytlbmRQdHI7CiAgICAgICAgICAgIGlmIChlbmRQdHIgLSBpZHggPiAxNiAmJiBoZWFwLnN1YmFycmF5ICYmIFVURjhEZWNvZGVyKSB7CiAgICAgICAgICAgICAgcmV0dXJuIFVURjhEZWNvZGVyLmRlY29kZShoZWFwLnN1YmFycmF5KGlkeCwgZW5kUHRyKSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdmFyIHN0ciA9ICIiOwogICAgICAgICAgICAgIHdoaWxlIChpZHggPCBlbmRQdHIpIHsKICAgICAgICAgICAgICAgIHZhciB1MCA9IGhlYXBbaWR4KytdOwogICAgICAgICAgICAgICAgaWYgKCEodTAgJiAxMjgpKSB7CiAgICAgICAgICAgICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHUwKTsKICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB2YXIgdTEyID0gaGVhcFtpZHgrK10gJiA2MzsKICAgICAgICAgICAgICAgIGlmICgodTAgJiAyMjQpID09IDE5MikgewogICAgICAgICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgodTAgJiAzMSkgPDwgNiB8IHUxMik7CiAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdmFyIHUyMiA9IGhlYXBbaWR4KytdICYgNjM7CiAgICAgICAgICAgICAgICBpZiAoKHUwICYgMjQwKSA9PSAyMjQpIHsKICAgICAgICAgICAgICAgICAgdTAgPSAodTAgJiAxNSkgPDwgMTIgfCB1MTIgPDwgNiB8IHUyMjsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgIHUwID0gKHUwICYgNykgPDwgMTggfCB1MTIgPDwgMTIgfCB1MjIgPDwgNiB8IGhlYXBbaWR4KytdICYgNjM7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAodTAgPCA2NTUzNikgewogICAgICAgICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh1MCk7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICB2YXIgY2ggPSB1MCAtIDY1NTM2OwogICAgICAgICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg1NTI5NiB8IGNoID4+IDEwLCA1NjMyMCB8IGNoICYgMTAyMyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBzdHI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBVVEY4VG9TdHJpbmcocHRyLCBtYXhCeXRlc1RvUmVhZCkgewogICAgICAgICAgICByZXR1cm4gcHRyID8gVVRGOEFycmF5VG9TdHJpbmcoSEVBUFU4LCBwdHIsIG1heEJ5dGVzVG9SZWFkKSA6ICIiOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gc3RyaW5nVG9VVEY4QXJyYXkoc3RyLCBoZWFwLCBvdXRJZHgsIG1heEJ5dGVzVG9Xcml0ZSkgewogICAgICAgICAgICBpZiAoIShtYXhCeXRlc1RvV3JpdGUgPiAwKSkgcmV0dXJuIDA7CiAgICAgICAgICAgIHZhciBzdGFydElkeCA9IG91dElkeDsKICAgICAgICAgICAgdmFyIGVuZElkeCA9IG91dElkeCArIG1heEJ5dGVzVG9Xcml0ZSAtIDE7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBzdHIubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgdmFyIHU0ID0gc3RyLmNoYXJDb2RlQXQoaTIpOwogICAgICAgICAgICAgIGlmICh1NCA+PSA1NTI5NiAmJiB1NCA8PSA1NzM0MykgewogICAgICAgICAgICAgICAgdmFyIHUxMiA9IHN0ci5jaGFyQ29kZUF0KCsraTIpOwogICAgICAgICAgICAgICAgdTQgPSA2NTUzNiArICgodTQgJiAxMDIzKSA8PCAxMCkgfCB1MTIgJiAxMDIzOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAodTQgPD0gMTI3KSB7CiAgICAgICAgICAgICAgICBpZiAob3V0SWR4ID49IGVuZElkeCkgYnJlYWs7CiAgICAgICAgICAgICAgICBoZWFwW291dElkeCsrXSA9IHU0OwogICAgICAgICAgICAgIH0gZWxzZSBpZiAodTQgPD0gMjA0NykgewogICAgICAgICAgICAgICAgaWYgKG91dElkeCArIDEgPj0gZW5kSWR4KSBicmVhazsKICAgICAgICAgICAgICAgIGhlYXBbb3V0SWR4KytdID0gMTkyIHwgdTQgPj4gNjsKICAgICAgICAgICAgICAgIGhlYXBbb3V0SWR4KytdID0gMTI4IHwgdTQgJiA2MzsKICAgICAgICAgICAgICB9IGVsc2UgaWYgKHU0IDw9IDY1NTM1KSB7CiAgICAgICAgICAgICAgICBpZiAob3V0SWR4ICsgMiA+PSBlbmRJZHgpIGJyZWFrOwogICAgICAgICAgICAgICAgaGVhcFtvdXRJZHgrK10gPSAyMjQgfCB1NCA+PiAxMjsKICAgICAgICAgICAgICAgIGhlYXBbb3V0SWR4KytdID0gMTI4IHwgdTQgPj4gNiAmIDYzOwogICAgICAgICAgICAgICAgaGVhcFtvdXRJZHgrK10gPSAxMjggfCB1NCAmIDYzOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBpZiAob3V0SWR4ICsgMyA+PSBlbmRJZHgpIGJyZWFrOwogICAgICAgICAgICAgICAgaGVhcFtvdXRJZHgrK10gPSAyNDAgfCB1NCA+PiAxODsKICAgICAgICAgICAgICAgIGhlYXBbb3V0SWR4KytdID0gMTI4IHwgdTQgPj4gMTIgJiA2MzsKICAgICAgICAgICAgICAgIGhlYXBbb3V0SWR4KytdID0gMTI4IHwgdTQgPj4gNiAmIDYzOwogICAgICAgICAgICAgICAgaGVhcFtvdXRJZHgrK10gPSAxMjggfCB1NCAmIDYzOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBoZWFwW291dElkeF0gPSAwOwogICAgICAgICAgICByZXR1cm4gb3V0SWR4IC0gc3RhcnRJZHg7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBzdHJpbmdUb1VURjgoc3RyLCBvdXRQdHIsIG1heEJ5dGVzVG9Xcml0ZSkgewogICAgICAgICAgICByZXR1cm4gc3RyaW5nVG9VVEY4QXJyYXkoc3RyLCBIRUFQVTgsIG91dFB0ciwgbWF4Qnl0ZXNUb1dyaXRlKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGxlbmd0aEJ5dGVzVVRGOChzdHIpIHsKICAgICAgICAgICAgdmFyIGxlbiA9IDA7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBzdHIubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgdmFyIHU0ID0gc3RyLmNoYXJDb2RlQXQoaTIpOwogICAgICAgICAgICAgIGlmICh1NCA+PSA1NTI5NiAmJiB1NCA8PSA1NzM0MykgdTQgPSA2NTUzNiArICgodTQgJiAxMDIzKSA8PCAxMCkgfCBzdHIuY2hhckNvZGVBdCgrK2kyKSAmIDEwMjM7CiAgICAgICAgICAgICAgaWYgKHU0IDw9IDEyNykgKytsZW47CiAgICAgICAgICAgICAgZWxzZSBpZiAodTQgPD0gMjA0NykgbGVuICs9IDI7CiAgICAgICAgICAgICAgZWxzZSBpZiAodTQgPD0gNjU1MzUpIGxlbiArPSAzOwogICAgICAgICAgICAgIGVsc2UgbGVuICs9IDQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGxlbjsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBVVEYxNkRlY29kZXIgPSB0eXBlb2YgVGV4dERlY29kZXIgIT09ICJ1bmRlZmluZWQiID8gbmV3IFRleHREZWNvZGVyKCJ1dGYtMTZsZSIpIDogdm9pZCAwOwogICAgICAgICAgZnVuY3Rpb24gVVRGMTZUb1N0cmluZyhwdHIsIG1heEJ5dGVzVG9SZWFkKSB7CiAgICAgICAgICAgIHZhciBlbmRQdHIgPSBwdHI7CiAgICAgICAgICAgIHZhciBpZHggPSBlbmRQdHIgPj4gMTsKICAgICAgICAgICAgdmFyIG1heElkeCA9IGlkeCArIG1heEJ5dGVzVG9SZWFkIC8gMjsKICAgICAgICAgICAgd2hpbGUgKCEoaWR4ID49IG1heElkeCkgJiYgSEVBUFUxNltpZHhdKSArK2lkeDsKICAgICAgICAgICAgZW5kUHRyID0gaWR4IDw8IDE7CiAgICAgICAgICAgIGlmIChlbmRQdHIgLSBwdHIgPiAzMiAmJiBVVEYxNkRlY29kZXIpIHsKICAgICAgICAgICAgICByZXR1cm4gVVRGMTZEZWNvZGVyLmRlY29kZShIRUFQVTguc3ViYXJyYXkocHRyLCBlbmRQdHIpKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB2YXIgc3RyID0gIiI7CiAgICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyAhKGkyID49IG1heEJ5dGVzVG9SZWFkIC8gMik7ICsraTIpIHsKICAgICAgICAgICAgICAgIHZhciBjb2RlVW5pdCA9IEhFQVAxNltwdHIgKyBpMiAqIDIgPj4gMV07CiAgICAgICAgICAgICAgICBpZiAoY29kZVVuaXQgPT0gMCkgYnJlYWs7CiAgICAgICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjb2RlVW5pdCk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiBzdHI7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHN0cmluZ1RvVVRGMTYoc3RyLCBvdXRQdHIsIG1heEJ5dGVzVG9Xcml0ZSkgewogICAgICAgICAgICBpZiAobWF4Qnl0ZXNUb1dyaXRlID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICBtYXhCeXRlc1RvV3JpdGUgPSAyMTQ3NDgzNjQ3OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChtYXhCeXRlc1RvV3JpdGUgPCAyKSByZXR1cm4gMDsKICAgICAgICAgICAgbWF4Qnl0ZXNUb1dyaXRlIC09IDI7CiAgICAgICAgICAgIHZhciBzdGFydFB0ciA9IG91dFB0cjsKICAgICAgICAgICAgdmFyIG51bUNoYXJzVG9Xcml0ZSA9IG1heEJ5dGVzVG9Xcml0ZSA8IHN0ci5sZW5ndGggKiAyID8gbWF4Qnl0ZXNUb1dyaXRlIC8gMiA6IHN0ci5sZW5ndGg7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBudW1DaGFyc1RvV3JpdGU7ICsraTIpIHsKICAgICAgICAgICAgICB2YXIgY29kZVVuaXQgPSBzdHIuY2hhckNvZGVBdChpMik7CiAgICAgICAgICAgICAgSEVBUDE2W291dFB0ciA+PiAxXSA9IGNvZGVVbml0OwogICAgICAgICAgICAgIG91dFB0ciArPSAyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIEhFQVAxNltvdXRQdHIgPj4gMV0gPSAwOwogICAgICAgICAgICByZXR1cm4gb3V0UHRyIC0gc3RhcnRQdHI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBsZW5ndGhCeXRlc1VURjE2KHN0cikgewogICAgICAgICAgICByZXR1cm4gc3RyLmxlbmd0aCAqIDI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBVVEYzMlRvU3RyaW5nKHB0ciwgbWF4Qnl0ZXNUb1JlYWQpIHsKICAgICAgICAgICAgdmFyIGkyID0gMDsKICAgICAgICAgICAgdmFyIHN0ciA9ICIiOwogICAgICAgICAgICB3aGlsZSAoIShpMiA+PSBtYXhCeXRlc1RvUmVhZCAvIDQpKSB7CiAgICAgICAgICAgICAgdmFyIHV0ZjMyID0gSEVBUDMyW3B0ciArIGkyICogNCA+PiAyXTsKICAgICAgICAgICAgICBpZiAodXRmMzIgPT0gMCkgYnJlYWs7CiAgICAgICAgICAgICAgKytpMjsKICAgICAgICAgICAgICBpZiAodXRmMzIgPj0gNjU1MzYpIHsKICAgICAgICAgICAgICAgIHZhciBjaCA9IHV0ZjMyIC0gNjU1MzY7CiAgICAgICAgICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg1NTI5NiB8IGNoID4+IDEwLCA1NjMyMCB8IGNoICYgMTAyMyk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHV0ZjMyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHN0cjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHN0cmluZ1RvVVRGMzIoc3RyLCBvdXRQdHIsIG1heEJ5dGVzVG9Xcml0ZSkgewogICAgICAgICAgICBpZiAobWF4Qnl0ZXNUb1dyaXRlID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICBtYXhCeXRlc1RvV3JpdGUgPSAyMTQ3NDgzNjQ3OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChtYXhCeXRlc1RvV3JpdGUgPCA0KSByZXR1cm4gMDsKICAgICAgICAgICAgdmFyIHN0YXJ0UHRyID0gb3V0UHRyOwogICAgICAgICAgICB2YXIgZW5kUHRyID0gc3RhcnRQdHIgKyBtYXhCeXRlc1RvV3JpdGUgLSA0OwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgc3RyLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgIHZhciBjb2RlVW5pdCA9IHN0ci5jaGFyQ29kZUF0KGkyKTsKICAgICAgICAgICAgICBpZiAoY29kZVVuaXQgPj0gNTUyOTYgJiYgY29kZVVuaXQgPD0gNTczNDMpIHsKICAgICAgICAgICAgICAgIHZhciB0cmFpbFN1cnJvZ2F0ZSA9IHN0ci5jaGFyQ29kZUF0KCsraTIpOwogICAgICAgICAgICAgICAgY29kZVVuaXQgPSA2NTUzNiArICgoY29kZVVuaXQgJiAxMDIzKSA8PCAxMCkgfCB0cmFpbFN1cnJvZ2F0ZSAmIDEwMjM7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIEhFQVAzMltvdXRQdHIgPj4gMl0gPSBjb2RlVW5pdDsKICAgICAgICAgICAgICBvdXRQdHIgKz0gNDsKICAgICAgICAgICAgICBpZiAob3V0UHRyICsgNCA+IGVuZFB0cikgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgSEVBUDMyW291dFB0ciA+PiAyXSA9IDA7CiAgICAgICAgICAgIHJldHVybiBvdXRQdHIgLSBzdGFydFB0cjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGxlbmd0aEJ5dGVzVVRGMzIoc3RyKSB7CiAgICAgICAgICAgIHZhciBsZW4gPSAwOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgc3RyLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgIHZhciBjb2RlVW5pdCA9IHN0ci5jaGFyQ29kZUF0KGkyKTsKICAgICAgICAgICAgICBpZiAoY29kZVVuaXQgPj0gNTUyOTYgJiYgY29kZVVuaXQgPD0gNTczNDMpICsraTI7CiAgICAgICAgICAgICAgbGVuICs9IDQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGxlbjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGFsaWduVXAoeDIsIG11bHRpcGxlKSB7CiAgICAgICAgICAgIGlmICh4MiAlIG11bHRpcGxlID4gMCkgewogICAgICAgICAgICAgIHgyICs9IG11bHRpcGxlIC0geDIgJSBtdWx0aXBsZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4geDI7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgYnVmZmVyLCBIRUFQOCwgSEVBUFU4LCBIRUFQMTYsIEhFQVBVMTYsIEhFQVAzMiwgSEVBUFUzMiwgSEVBUEYzMiwgSEVBUEY2NDsKICAgICAgICAgIGZ1bmN0aW9uIHVwZGF0ZUdsb2JhbEJ1ZmZlckFuZFZpZXdzKGJ1ZikgewogICAgICAgICAgICBidWZmZXIgPSBidWY7CiAgICAgICAgICAgIE1vZHVsZVsiSEVBUDgiXSA9IEhFQVA4ID0gbmV3IEludDhBcnJheShidWYpOwogICAgICAgICAgICBNb2R1bGVbIkhFQVAxNiJdID0gSEVBUDE2ID0gbmV3IEludDE2QXJyYXkoYnVmKTsKICAgICAgICAgICAgTW9kdWxlWyJIRUFQMzIiXSA9IEhFQVAzMiA9IG5ldyBJbnQzMkFycmF5KGJ1Zik7CiAgICAgICAgICAgIE1vZHVsZVsiSEVBUFU4Il0gPSBIRUFQVTggPSBuZXcgVWludDhBcnJheShidWYpOwogICAgICAgICAgICBNb2R1bGVbIkhFQVBVMTYiXSA9IEhFQVBVMTYgPSBuZXcgVWludDE2QXJyYXkoYnVmKTsKICAgICAgICAgICAgTW9kdWxlWyJIRUFQVTMyIl0gPSBIRUFQVTMyID0gbmV3IFVpbnQzMkFycmF5KGJ1Zik7CiAgICAgICAgICAgIE1vZHVsZVsiSEVBUEYzMiJdID0gSEVBUEYzMiA9IG5ldyBGbG9hdDMyQXJyYXkoYnVmKTsKICAgICAgICAgICAgTW9kdWxlWyJIRUFQRjY0Il0gPSBIRUFQRjY0ID0gbmV3IEZsb2F0NjRBcnJheShidWYpOwogICAgICAgICAgfQogICAgICAgICAgdmFyIElOSVRJQUxfTUVNT1JZID0gTW9kdWxlWyJJTklUSUFMX01FTU9SWSJdIHx8IDE2Nzc3MjE2OwogICAgICAgICAgdmFyIHdhc21UYWJsZTsKICAgICAgICAgIHZhciBfX0FUUFJFUlVOX18gPSBbXTsKICAgICAgICAgIHZhciBfX0FUSU5JVF9fID0gW107CiAgICAgICAgICB2YXIgX19BVE1BSU5fXyA9IFtdOwogICAgICAgICAgdmFyIF9fQVRQT1NUUlVOX18gPSBbXTsKICAgICAgICAgIHZhciBydW50aW1lSW5pdGlhbGl6ZWQgPSBmYWxzZTsKICAgICAgICAgIGZ1bmN0aW9uIHByZVJ1bigpIHsKICAgICAgICAgICAgaWYgKE1vZHVsZVsicHJlUnVuIl0pIHsKICAgICAgICAgICAgICBpZiAodHlwZW9mIE1vZHVsZVsicHJlUnVuIl0gPT0gImZ1bmN0aW9uIikgTW9kdWxlWyJwcmVSdW4iXSA9IFtNb2R1bGVbInByZVJ1biJdXTsKICAgICAgICAgICAgICB3aGlsZSAoTW9kdWxlWyJwcmVSdW4iXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFkZE9uUHJlUnVuKE1vZHVsZVsicHJlUnVuIl0uc2hpZnQoKSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGNhbGxSdW50aW1lQ2FsbGJhY2tzKF9fQVRQUkVSVU5fXyk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBpbml0UnVudGltZSgpIHsKICAgICAgICAgICAgcnVudGltZUluaXRpYWxpemVkID0gdHJ1ZTsKICAgICAgICAgICAgY2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVElOSVRfXyk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBwcmVNYWluKCkgewogICAgICAgICAgICBjYWxsUnVudGltZUNhbGxiYWNrcyhfX0FUTUFJTl9fKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHBvc3RSdW4oKSB7CiAgICAgICAgICAgIGlmIChNb2R1bGVbInBvc3RSdW4iXSkgewogICAgICAgICAgICAgIGlmICh0eXBlb2YgTW9kdWxlWyJwb3N0UnVuIl0gPT0gImZ1bmN0aW9uIikgTW9kdWxlWyJwb3N0UnVuIl0gPSBbTW9kdWxlWyJwb3N0UnVuIl1dOwogICAgICAgICAgICAgIHdoaWxlIChNb2R1bGVbInBvc3RSdW4iXS5sZW5ndGgpIHsKICAgICAgICAgICAgICAgIGFkZE9uUG9zdFJ1bihNb2R1bGVbInBvc3RSdW4iXS5zaGlmdCgpKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVFBPU1RSVU5fXyk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBhZGRPblByZVJ1bihjYikgewogICAgICAgICAgICBfX0FUUFJFUlVOX18udW5zaGlmdChjYik7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBhZGRPbkluaXQoY2IpIHsKICAgICAgICAgICAgX19BVElOSVRfXy51bnNoaWZ0KGNiKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGFkZE9uUG9zdFJ1bihjYikgewogICAgICAgICAgICBfX0FUUE9TVFJVTl9fLnVuc2hpZnQoY2IpOwogICAgICAgICAgfQogICAgICAgICAgdmFyIHJ1bkRlcGVuZGVuY2llcyA9IDA7CiAgICAgICAgICB2YXIgcnVuRGVwZW5kZW5jeVdhdGNoZXIgPSBudWxsOwogICAgICAgICAgdmFyIGRlcGVuZGVuY2llc0Z1bGZpbGxlZCA9IG51bGw7CiAgICAgICAgICBmdW5jdGlvbiBhZGRSdW5EZXBlbmRlbmN5KGlkKSB7CiAgICAgICAgICAgIHJ1bkRlcGVuZGVuY2llcysrOwogICAgICAgICAgICBpZiAoTW9kdWxlWyJtb25pdG9yUnVuRGVwZW5kZW5jaWVzIl0pIHsKICAgICAgICAgICAgICBNb2R1bGVbIm1vbml0b3JSdW5EZXBlbmRlbmNpZXMiXShydW5EZXBlbmRlbmNpZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiByZW1vdmVSdW5EZXBlbmRlbmN5KGlkKSB7CiAgICAgICAgICAgIHJ1bkRlcGVuZGVuY2llcy0tOwogICAgICAgICAgICBpZiAoTW9kdWxlWyJtb25pdG9yUnVuRGVwZW5kZW5jaWVzIl0pIHsKICAgICAgICAgICAgICBNb2R1bGVbIm1vbml0b3JSdW5EZXBlbmRlbmNpZXMiXShydW5EZXBlbmRlbmNpZXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChydW5EZXBlbmRlbmNpZXMgPT0gMCkgewogICAgICAgICAgICAgIGlmIChydW5EZXBlbmRlbmN5V2F0Y2hlciAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChydW5EZXBlbmRlbmN5V2F0Y2hlcik7CiAgICAgICAgICAgICAgICBydW5EZXBlbmRlbmN5V2F0Y2hlciA9IG51bGw7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmIChkZXBlbmRlbmNpZXNGdWxmaWxsZWQpIHsKICAgICAgICAgICAgICAgIHZhciBjYWxsYmFjayA9IGRlcGVuZGVuY2llc0Z1bGZpbGxlZDsKICAgICAgICAgICAgICAgIGRlcGVuZGVuY2llc0Z1bGZpbGxlZCA9IG51bGw7CiAgICAgICAgICAgICAgICBjYWxsYmFjaygpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgTW9kdWxlWyJwcmVsb2FkZWRJbWFnZXMiXSA9IHt9OwogICAgICAgICAgTW9kdWxlWyJwcmVsb2FkZWRBdWRpb3MiXSA9IHt9OwogICAgICAgICAgZnVuY3Rpb24gYWJvcnQod2hhdCkgewogICAgICAgICAgICBpZiAoTW9kdWxlWyJvbkFib3J0Il0pIHsKICAgICAgICAgICAgICBNb2R1bGVbIm9uQWJvcnQiXSh3aGF0KTsKICAgICAgICAgICAgfQogICAgICAgICAgICB3aGF0ICs9ICIiOwogICAgICAgICAgICBlcnIod2hhdCk7CiAgICAgICAgICAgIEFCT1JUID0gdHJ1ZTsKICAgICAgICAgICAgRVhJVFNUQVRVUyA9IDE7CiAgICAgICAgICAgIHdoYXQgPSAiYWJvcnQoIiArIHdoYXQgKyAiKS4gQnVpbGQgd2l0aCAtcyBBU1NFUlRJT05TPTEgZm9yIG1vcmUgaW5mby4iOwogICAgICAgICAgICB2YXIgZTIgPSBuZXcgV2ViQXNzZW1ibHkuUnVudGltZUVycm9yKHdoYXQpOwogICAgICAgICAgICByZWFkeVByb21pc2VSZWplY3QoZTIpOwogICAgICAgICAgICB0aHJvdyBlMjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGhhc1ByZWZpeChzdHIsIHByZWZpeCkgewogICAgICAgICAgICByZXR1cm4gU3RyaW5nLnByb3RvdHlwZS5zdGFydHNXaXRoID8gc3RyLnN0YXJ0c1dpdGgocHJlZml4KSA6IHN0ci5pbmRleE9mKHByZWZpeCkgPT09IDA7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgZGF0YVVSSVByZWZpeCA9ICJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsIjsKICAgICAgICAgIGZ1bmN0aW9uIGlzRGF0YVVSSShmaWxlbmFtZSkgewogICAgICAgICAgICByZXR1cm4gaGFzUHJlZml4KGZpbGVuYW1lLCBkYXRhVVJJUHJlZml4KTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBmaWxlVVJJUHJlZml4ID0gImZpbGU6Ly8iOwogICAgICAgICAgZnVuY3Rpb24gaXNGaWxlVVJJKGZpbGVuYW1lKSB7CiAgICAgICAgICAgIHJldHVybiBoYXNQcmVmaXgoZmlsZW5hbWUsIGZpbGVVUklQcmVmaXgpOwogICAgICAgICAgfQogICAgICAgICAgdmFyIHdhc21CaW5hcnlGaWxlID0gImJhc2lzX3RyYW5zY29kZXIud2FzbSI7CiAgICAgICAgICBpZiAoIWlzRGF0YVVSSSh3YXNtQmluYXJ5RmlsZSkpIHsKICAgICAgICAgICAgd2FzbUJpbmFyeUZpbGUgPSBsb2NhdGVGaWxlKHdhc21CaW5hcnlGaWxlKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGdldEJpbmFyeShmaWxlKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgaWYgKGZpbGUgPT0gd2FzbUJpbmFyeUZpbGUgJiYgd2FzbUJpbmFyeSkgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBVaW50OEFycmF5KHdhc21CaW5hcnkpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAocmVhZEJpbmFyeSkgewogICAgICAgICAgICAgICAgcmV0dXJuIHJlYWRCaW5hcnkoZmlsZSk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHRocm93ICJib3RoIGFzeW5jIGFuZCBzeW5jIGZldGNoaW5nIG9mIHRoZSB3YXNtIGZhaWxlZCI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGNhdGNoIChlcnIyKSB7CiAgICAgICAgICAgICAgYWJvcnQoZXJyMik7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGdldEJpbmFyeVByb21pc2UoKSB7CiAgICAgICAgICAgIGlmICghd2FzbUJpbmFyeSAmJiAoRU5WSVJPTk1FTlRfSVNfV0VCIHx8IEVOVklST05NRU5UX0lTX1dPUktFUikpIHsKICAgICAgICAgICAgICBpZiAodHlwZW9mIGZldGNoID09PSAiZnVuY3Rpb24iICYmICFpc0ZpbGVVUkkod2FzbUJpbmFyeUZpbGUpKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZmV0Y2god2FzbUJpbmFyeUZpbGUsIHsgY3JlZGVudGlhbHM6ICJzYW1lLW9yaWdpbiIgfSkudGhlbihmdW5jdGlvbihyZXNwb25zZSkgewogICAgICAgICAgICAgICAgICBpZiAoIXJlc3BvbnNlWyJvayJdKSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgImZhaWxlZCB0byBsb2FkIHdhc20gYmluYXJ5IGZpbGUgYXQgJyIgKyB3YXNtQmluYXJ5RmlsZSArICInIjsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2VbImFycmF5QnVmZmVyIl0oKTsKICAgICAgICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgICAgICByZXR1cm4gZ2V0QmluYXJ5KHdhc21CaW5hcnlGaWxlKTsKICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBpZiAocmVhZEFzeW5jKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHsKICAgICAgICAgICAgICAgICAgICByZWFkQXN5bmMod2FzbUJpbmFyeUZpbGUsIGZ1bmN0aW9uKHJlc3BvbnNlKSB7CiAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKG5ldyBVaW50OEFycmF5KHJlc3BvbnNlKSk7CiAgICAgICAgICAgICAgICAgICAgfSwgcmVqZWN0KTsKICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKS50aGVuKGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHJldHVybiBnZXRCaW5hcnkod2FzbUJpbmFyeUZpbGUpOwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGNyZWF0ZVdhc20oKSB7CiAgICAgICAgICAgIHZhciBpbmZvID0geyAiYSI6IGFzbUxpYnJhcnlBcmcgfTsKICAgICAgICAgICAgZnVuY3Rpb24gcmVjZWl2ZUluc3RhbmNlKGluc3RhbmNlLCBtb2R1bGUyKSB7CiAgICAgICAgICAgICAgdmFyIGV4cG9ydHM0ID0gaW5zdGFuY2UuZXhwb3J0czsKICAgICAgICAgICAgICBNb2R1bGVbImFzbSJdID0gZXhwb3J0czQ7CiAgICAgICAgICAgICAgd2FzbU1lbW9yeSA9IE1vZHVsZVsiYXNtIl1bIksiXTsKICAgICAgICAgICAgICB1cGRhdGVHbG9iYWxCdWZmZXJBbmRWaWV3cyh3YXNtTWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICAgICAgd2FzbVRhYmxlID0gTW9kdWxlWyJhc20iXVsiTyJdOwogICAgICAgICAgICAgIGFkZE9uSW5pdChNb2R1bGVbImFzbSJdWyJMIl0pOwogICAgICAgICAgICAgIHJlbW92ZVJ1bkRlcGVuZGVuY3koIndhc20taW5zdGFudGlhdGUiKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBhZGRSdW5EZXBlbmRlbmN5KCJ3YXNtLWluc3RhbnRpYXRlIik7CiAgICAgICAgICAgIGZ1bmN0aW9uIHJlY2VpdmVJbnN0YW50aWF0ZWRTb3VyY2Uob3V0cHV0KSB7CiAgICAgICAgICAgICAgcmVjZWl2ZUluc3RhbmNlKG91dHB1dFsiaW5zdGFuY2UiXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZnVuY3Rpb24gaW5zdGFudGlhdGVBcnJheUJ1ZmZlcihyZWNlaXZlcikgewogICAgICAgICAgICAgIHJldHVybiBnZXRCaW5hcnlQcm9taXNlKCkudGhlbihmdW5jdGlvbihiaW5hcnkpIHsKICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZShiaW5hcnksIGluZm8pOwogICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICAgICAgICB9KS50aGVuKHJlY2VpdmVyLCBmdW5jdGlvbihyZWFzb24pIHsKICAgICAgICAgICAgICAgIGVycigiZmFpbGVkIHRvIGFzeW5jaHJvbm91c2x5IHByZXBhcmUgd2FzbTogIiArIHJlYXNvbik7CiAgICAgICAgICAgICAgICBhYm9ydChyZWFzb24pOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uIGluc3RhbnRpYXRlQXN5bmMoKSB7CiAgICAgICAgICAgICAgaWYgKCF3YXNtQmluYXJ5ICYmIHR5cGVvZiBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyA9PT0gImZ1bmN0aW9uIiAmJiAhaXNEYXRhVVJJKHdhc21CaW5hcnlGaWxlKSAmJiAhaXNGaWxlVVJJKHdhc21CaW5hcnlGaWxlKSAmJiB0eXBlb2YgZmV0Y2ggPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICAgIHJldHVybiBmZXRjaCh3YXNtQmluYXJ5RmlsZSwgeyBjcmVkZW50aWFsczogInNhbWUtb3JpZ2luIiB9KS50aGVuKGZ1bmN0aW9uKHJlc3BvbnNlKSB7CiAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyhyZXNwb25zZSwgaW5mbyk7CiAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQudGhlbihyZWNlaXZlSW5zdGFudGlhdGVkU291cmNlLCBmdW5jdGlvbihyZWFzb24pIHsKICAgICAgICAgICAgICAgICAgICBlcnIoIndhc20gc3RyZWFtaW5nIGNvbXBpbGUgZmFpbGVkOiAiICsgcmVhc29uKTsKICAgICAgICAgICAgICAgICAgICBlcnIoImZhbGxpbmcgYmFjayB0byBBcnJheUJ1ZmZlciBpbnN0YW50aWF0aW9uIik7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGluc3RhbnRpYXRlQXJyYXlCdWZmZXIocmVjZWl2ZUluc3RhbnRpYXRlZFNvdXJjZSk7CiAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBpbnN0YW50aWF0ZUFycmF5QnVmZmVyKHJlY2VpdmVJbnN0YW50aWF0ZWRTb3VyY2UpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoTW9kdWxlWyJpbnN0YW50aWF0ZVdhc20iXSkgewogICAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICB2YXIgZXhwb3J0czMgPSBNb2R1bGVbImluc3RhbnRpYXRlV2FzbSJdKGluZm8sIHJlY2VpdmVJbnN0YW5jZSk7CiAgICAgICAgICAgICAgICByZXR1cm4gZXhwb3J0czM7CiAgICAgICAgICAgICAgfSBjYXRjaCAoZTIpIHsKICAgICAgICAgICAgICAgIGVycigiTW9kdWxlLmluc3RhbnRpYXRlV2FzbSBjYWxsYmFjayBmYWlsZWQgd2l0aCBlcnJvcjogIiArIGUyKTsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaW5zdGFudGlhdGVBc3luYygpLmNhdGNoKHJlYWR5UHJvbWlzZVJlamVjdCk7CiAgICAgICAgICAgIHJldHVybiB7fTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGNhbGxSdW50aW1lQ2FsbGJhY2tzKGNhbGxiYWNrcykgewogICAgICAgICAgICB3aGlsZSAoY2FsbGJhY2tzLmxlbmd0aCA+IDApIHsKICAgICAgICAgICAgICB2YXIgY2FsbGJhY2sgPSBjYWxsYmFja3Muc2hpZnQoKTsKICAgICAgICAgICAgICBpZiAodHlwZW9mIGNhbGxiYWNrID09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgICAgICAgIGNhbGxiYWNrKE1vZHVsZSk7CiAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIGZ1bmMgPSBjYWxsYmFjay5mdW5jOwogICAgICAgICAgICAgIGlmICh0eXBlb2YgZnVuYyA9PT0gIm51bWJlciIpIHsKICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjay5hcmcgPT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgICB3YXNtVGFibGUuZ2V0KGZ1bmMpKCk7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICB3YXNtVGFibGUuZ2V0KGZ1bmMpKGNhbGxiYWNrLmFyZyk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGZ1bmMoY2FsbGJhY2suYXJnID09PSB2b2lkIDAgPyBudWxsIDogY2FsbGJhY2suYXJnKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIHZhciBzdHJ1Y3RSZWdpc3RyYXRpb25zID0ge307CiAgICAgICAgICBmdW5jdGlvbiBydW5EZXN0cnVjdG9ycyhkZXN0cnVjdG9ycykgewogICAgICAgICAgICB3aGlsZSAoZGVzdHJ1Y3RvcnMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgdmFyIHB0ciA9IGRlc3RydWN0b3JzLnBvcCgpOwogICAgICAgICAgICAgIHZhciBkZWwgPSBkZXN0cnVjdG9ycy5wb3AoKTsKICAgICAgICAgICAgICBkZWwocHRyKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gc2ltcGxlUmVhZFZhbHVlRnJvbVBvaW50ZXIocG9pbnRlcikgewogICAgICAgICAgICByZXR1cm4gdGhpc1siZnJvbVdpcmVUeXBlIl0oSEVBUFUzMltwb2ludGVyID4+IDJdKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBhd2FpdGluZ0RlcGVuZGVuY2llcyA9IHt9OwogICAgICAgICAgdmFyIHJlZ2lzdGVyZWRUeXBlcyA9IHt9OwogICAgICAgICAgdmFyIHR5cGVEZXBlbmRlbmNpZXMgPSB7fTsKICAgICAgICAgIHZhciBjaGFyXzAgPSA0ODsKICAgICAgICAgIHZhciBjaGFyXzkgPSA1NzsKICAgICAgICAgIGZ1bmN0aW9uIG1ha2VMZWdhbEZ1bmN0aW9uTmFtZShuYW1lKSB7CiAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IG5hbWUpIHsKICAgICAgICAgICAgICByZXR1cm4gIl91bmtub3duIjsKICAgICAgICAgICAgfQogICAgICAgICAgICBuYW1lID0gbmFtZS5yZXBsYWNlKC9bXmEtekEtWjAtOV9dL2csICIkIik7CiAgICAgICAgICAgIHZhciBmMiA9IG5hbWUuY2hhckNvZGVBdCgwKTsKICAgICAgICAgICAgaWYgKGYyID49IGNoYXJfMCAmJiBmMiA8PSBjaGFyXzkpIHsKICAgICAgICAgICAgICByZXR1cm4gIl8iICsgbmFtZTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gbmFtZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gY3JlYXRlTmFtZWRGdW5jdGlvbihuYW1lLCBib2R5KSB7CiAgICAgICAgICAgIG5hbWUgPSBtYWtlTGVnYWxGdW5jdGlvbk5hbWUobmFtZSk7CiAgICAgICAgICAgIHJldHVybiBuZXcgRnVuY3Rpb24oImJvZHkiLCAicmV0dXJuIGZ1bmN0aW9uICIgKyBuYW1lICsgJygpIHtcbiAgICAidXNlIHN0cmljdCI7ICAgIHJldHVybiBib2R5LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuJykoYm9keSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBleHRlbmRFcnJvcihiYXNlRXJyb3JUeXBlLCBlcnJvck5hbWUpIHsKICAgICAgICAgICAgdmFyIGVycm9yQ2xhc3MgPSBjcmVhdGVOYW1lZEZ1bmN0aW9uKGVycm9yTmFtZSwgZnVuY3Rpb24obWVzc2FnZSkgewogICAgICAgICAgICAgIHRoaXMubmFtZSA9IGVycm9yTmFtZTsKICAgICAgICAgICAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlOwogICAgICAgICAgICAgIHZhciBzdGFjayA9IG5ldyBFcnJvcihtZXNzYWdlKS5zdGFjazsKICAgICAgICAgICAgICBpZiAoc3RhY2sgIT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgdGhpcy5zdGFjayA9IHRoaXMudG9TdHJpbmcoKSArICJcbiIgKyBzdGFjay5yZXBsYWNlKC9eRXJyb3IoOlteXG5dKik/XG4vLCAiIik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgZXJyb3JDbGFzcy5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKGJhc2VFcnJvclR5cGUucHJvdG90eXBlKTsKICAgICAgICAgICAgZXJyb3JDbGFzcy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBlcnJvckNsYXNzOwogICAgICAgICAgICBlcnJvckNsYXNzLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIGlmICh0aGlzLm1lc3NhZ2UgPT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubmFtZTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubmFtZSArICI6ICIgKyB0aGlzLm1lc3NhZ2U7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9OwogICAgICAgICAgICByZXR1cm4gZXJyb3JDbGFzczsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBJbnRlcm5hbEVycm9yID0gdm9pZCAwOwogICAgICAgICAgZnVuY3Rpb24gdGhyb3dJbnRlcm5hbEVycm9yKG1lc3NhZ2UpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IobWVzc2FnZSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB3aGVuRGVwZW5kZW50VHlwZXNBcmVSZXNvbHZlZChteVR5cGVzLCBkZXBlbmRlbnRUeXBlcywgZ2V0VHlwZUNvbnZlcnRlcnMpIHsKICAgICAgICAgICAgbXlUeXBlcy5mb3JFYWNoKGZ1bmN0aW9uKHR5cGUpIHsKICAgICAgICAgICAgICB0eXBlRGVwZW5kZW5jaWVzW3R5cGVdID0gZGVwZW5kZW50VHlwZXM7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBmdW5jdGlvbiBvbkNvbXBsZXRlKHR5cGVDb252ZXJ0ZXJzMikgewogICAgICAgICAgICAgIHZhciBteVR5cGVDb252ZXJ0ZXJzID0gZ2V0VHlwZUNvbnZlcnRlcnModHlwZUNvbnZlcnRlcnMyKTsKICAgICAgICAgICAgICBpZiAobXlUeXBlQ29udmVydGVycy5sZW5ndGggIT09IG15VHlwZXMubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICB0aHJvd0ludGVybmFsRXJyb3IoIk1pc21hdGNoZWQgdHlwZSBjb252ZXJ0ZXIgY291bnQiKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IG15VHlwZXMubGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgICByZWdpc3RlclR5cGUobXlUeXBlc1tpMl0sIG15VHlwZUNvbnZlcnRlcnNbaTJdKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHR5cGVDb252ZXJ0ZXJzID0gbmV3IEFycmF5KGRlcGVuZGVudFR5cGVzLmxlbmd0aCk7CiAgICAgICAgICAgIHZhciB1bnJlZ2lzdGVyZWRUeXBlcyA9IFtdOwogICAgICAgICAgICB2YXIgcmVnaXN0ZXJlZCA9IDA7CiAgICAgICAgICAgIGRlcGVuZGVudFR5cGVzLmZvckVhY2goZnVuY3Rpb24oZHQyLCBpMikgewogICAgICAgICAgICAgIGlmIChyZWdpc3RlcmVkVHlwZXMuaGFzT3duUHJvcGVydHkoZHQyKSkgewogICAgICAgICAgICAgICAgdHlwZUNvbnZlcnRlcnNbaTJdID0gcmVnaXN0ZXJlZFR5cGVzW2R0Ml07CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHVucmVnaXN0ZXJlZFR5cGVzLnB1c2goZHQyKTsKICAgICAgICAgICAgICAgIGlmICghYXdhaXRpbmdEZXBlbmRlbmNpZXMuaGFzT3duUHJvcGVydHkoZHQyKSkgewogICAgICAgICAgICAgICAgICBhd2FpdGluZ0RlcGVuZGVuY2llc1tkdDJdID0gW107CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBhd2FpdGluZ0RlcGVuZGVuY2llc1tkdDJdLnB1c2goZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICAgIHR5cGVDb252ZXJ0ZXJzW2kyXSA9IHJlZ2lzdGVyZWRUeXBlc1tkdDJdOwogICAgICAgICAgICAgICAgICArK3JlZ2lzdGVyZWQ7CiAgICAgICAgICAgICAgICAgIGlmIChyZWdpc3RlcmVkID09PSB1bnJlZ2lzdGVyZWRUeXBlcy5sZW5ndGgpIHsKICAgICAgICAgICAgICAgICAgICBvbkNvbXBsZXRlKHR5cGVDb252ZXJ0ZXJzKTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9KTsKICAgICAgICAgICAgaWYgKDAgPT09IHVucmVnaXN0ZXJlZFR5cGVzLmxlbmd0aCkgewogICAgICAgICAgICAgIG9uQ29tcGxldGUodHlwZUNvbnZlcnRlcnMpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9maW5hbGl6ZV92YWx1ZV9vYmplY3Qoc3RydWN0VHlwZSkgewogICAgICAgICAgICB2YXIgcmVnID0gc3RydWN0UmVnaXN0cmF0aW9uc1tzdHJ1Y3RUeXBlXTsKICAgICAgICAgICAgZGVsZXRlIHN0cnVjdFJlZ2lzdHJhdGlvbnNbc3RydWN0VHlwZV07CiAgICAgICAgICAgIHZhciByYXdDb25zdHJ1Y3RvciA9IHJlZy5yYXdDb25zdHJ1Y3RvcjsKICAgICAgICAgICAgdmFyIHJhd0Rlc3RydWN0b3IgPSByZWcucmF3RGVzdHJ1Y3RvcjsKICAgICAgICAgICAgdmFyIGZpZWxkUmVjb3JkcyA9IHJlZy5maWVsZHM7CiAgICAgICAgICAgIHZhciBmaWVsZFR5cGVzID0gZmllbGRSZWNvcmRzLm1hcChmdW5jdGlvbihmaWVsZCkgewogICAgICAgICAgICAgIHJldHVybiBmaWVsZC5nZXR0ZXJSZXR1cm5UeXBlOwogICAgICAgICAgICB9KS5jb25jYXQoZmllbGRSZWNvcmRzLm1hcChmdW5jdGlvbihmaWVsZCkgewogICAgICAgICAgICAgIHJldHVybiBmaWVsZC5zZXR0ZXJBcmd1bWVudFR5cGU7CiAgICAgICAgICAgIH0pKTsKICAgICAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW3N0cnVjdFR5cGVdLCBmaWVsZFR5cGVzLCBmdW5jdGlvbihmaWVsZFR5cGVzMikgewogICAgICAgICAgICAgIHZhciBmaWVsZHMgPSB7fTsKICAgICAgICAgICAgICBmaWVsZFJlY29yZHMuZm9yRWFjaChmdW5jdGlvbihmaWVsZCwgaTIpIHsKICAgICAgICAgICAgICAgIHZhciBmaWVsZE5hbWUgPSBmaWVsZC5maWVsZE5hbWU7CiAgICAgICAgICAgICAgICB2YXIgZ2V0dGVyUmV0dXJuVHlwZSA9IGZpZWxkVHlwZXMyW2kyXTsKICAgICAgICAgICAgICAgIHZhciBnZXR0ZXIgPSBmaWVsZC5nZXR0ZXI7CiAgICAgICAgICAgICAgICB2YXIgZ2V0dGVyQ29udGV4dCA9IGZpZWxkLmdldHRlckNvbnRleHQ7CiAgICAgICAgICAgICAgICB2YXIgc2V0dGVyQXJndW1lbnRUeXBlID0gZmllbGRUeXBlczJbaTIgKyBmaWVsZFJlY29yZHMubGVuZ3RoXTsKICAgICAgICAgICAgICAgIHZhciBzZXR0ZXIgPSBmaWVsZC5zZXR0ZXI7CiAgICAgICAgICAgICAgICB2YXIgc2V0dGVyQ29udGV4dCA9IGZpZWxkLnNldHRlckNvbnRleHQ7CiAgICAgICAgICAgICAgICBmaWVsZHNbZmllbGROYW1lXSA9IHsgcmVhZDogZnVuY3Rpb24ocHRyKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiBnZXR0ZXJSZXR1cm5UeXBlWyJmcm9tV2lyZVR5cGUiXShnZXR0ZXIoZ2V0dGVyQ29udGV4dCwgcHRyKSk7CiAgICAgICAgICAgICAgICB9LCB3cml0ZTogZnVuY3Rpb24ocHRyLCBvMikgewogICAgICAgICAgICAgICAgICB2YXIgZGVzdHJ1Y3RvcnMgPSBbXTsKICAgICAgICAgICAgICAgICAgc2V0dGVyKHNldHRlckNvbnRleHQsIHB0ciwgc2V0dGVyQXJndW1lbnRUeXBlWyJ0b1dpcmVUeXBlIl0oZGVzdHJ1Y3RvcnMsIG8yKSk7CiAgICAgICAgICAgICAgICAgIHJ1bkRlc3RydWN0b3JzKGRlc3RydWN0b3JzKTsKICAgICAgICAgICAgICAgIH0gfTsKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICByZXR1cm4gW3sgbmFtZTogcmVnLm5hbWUsICJmcm9tV2lyZVR5cGUiOiBmdW5jdGlvbihwdHIpIHsKICAgICAgICAgICAgICAgIHZhciBydiA9IHt9OwogICAgICAgICAgICAgICAgZm9yICh2YXIgaTIgaW4gZmllbGRzKSB7CiAgICAgICAgICAgICAgICAgIHJ2W2kyXSA9IGZpZWxkc1tpMl0ucmVhZChwdHIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmF3RGVzdHJ1Y3RvcihwdHIpOwogICAgICAgICAgICAgICAgcmV0dXJuIHJ2OwogICAgICAgICAgICAgIH0sICJ0b1dpcmVUeXBlIjogZnVuY3Rpb24oZGVzdHJ1Y3RvcnMsIG8yKSB7CiAgICAgICAgICAgICAgICBmb3IgKHZhciBmaWVsZE5hbWUgaW4gZmllbGRzKSB7CiAgICAgICAgICAgICAgICAgIGlmICghKGZpZWxkTmFtZSBpbiBvMikpIHsKICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdNaXNzaW5nIGZpZWxkOiAgIicgKyBmaWVsZE5hbWUgKyAnIicpOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB2YXIgcHRyID0gcmF3Q29uc3RydWN0b3IoKTsKICAgICAgICAgICAgICAgIGZvciAoZmllbGROYW1lIGluIGZpZWxkcykgewogICAgICAgICAgICAgICAgICBmaWVsZHNbZmllbGROYW1lXS53cml0ZShwdHIsIG8yW2ZpZWxkTmFtZV0pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKGRlc3RydWN0b3JzICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICAgIGRlc3RydWN0b3JzLnB1c2gocmF3RGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBwdHI7CiAgICAgICAgICAgICAgfSwgImFyZ1BhY2tBZHZhbmNlIjogOCwgInJlYWRWYWx1ZUZyb21Qb2ludGVyIjogc2ltcGxlUmVhZFZhbHVlRnJvbVBvaW50ZXIsIGRlc3RydWN0b3JGdW5jdGlvbjogcmF3RGVzdHJ1Y3RvciB9XTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBnZXRTaGlmdEZyb21TaXplKHNpemUpIHsKICAgICAgICAgICAgc3dpdGNoIChzaXplKSB7CiAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgcmV0dXJuIDA7CiAgICAgICAgICAgICAgY2FzZSAyOgogICAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAgICAgY2FzZSA0OgogICAgICAgICAgICAgICAgcmV0dXJuIDI7CiAgICAgICAgICAgICAgY2FzZSA4OgogICAgICAgICAgICAgICAgcmV0dXJuIDM7CiAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIlVua25vd24gdHlwZSBzaXplOiAiICsgc2l6ZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGVtYmluZF9pbml0X2NoYXJDb2RlcygpIHsKICAgICAgICAgICAgdmFyIGNvZGVzID0gbmV3IEFycmF5KDI1Nik7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCAyNTY7ICsraTIpIHsKICAgICAgICAgICAgICBjb2Rlc1tpMl0gPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGkyKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBlbWJpbmRfY2hhckNvZGVzID0gY29kZXM7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgZW1iaW5kX2NoYXJDb2RlcyA9IHZvaWQgMDsKICAgICAgICAgIGZ1bmN0aW9uIHJlYWRMYXRpbjFTdHJpbmcocHRyKSB7CiAgICAgICAgICAgIHZhciByZXQgPSAiIjsKICAgICAgICAgICAgdmFyIGMyID0gcHRyOwogICAgICAgICAgICB3aGlsZSAoSEVBUFU4W2MyXSkgewogICAgICAgICAgICAgIHJldCArPSBlbWJpbmRfY2hhckNvZGVzW0hFQVBVOFtjMisrXV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBCaW5kaW5nRXJyb3IgPSB2b2lkIDA7CiAgICAgICAgICBmdW5jdGlvbiB0aHJvd0JpbmRpbmdFcnJvcihtZXNzYWdlKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBCaW5kaW5nRXJyb3IobWVzc2FnZSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiByZWdpc3RlclR5cGUocmF3VHlwZSwgcmVnaXN0ZXJlZEluc3RhbmNlLCBvcHRpb25zKSB7CiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9OwogICAgICAgICAgICBpZiAoISgiYXJnUGFja0FkdmFuY2UiIGluIHJlZ2lzdGVyZWRJbnN0YW5jZSkpIHsKICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJyZWdpc3RlclR5cGUgcmVnaXN0ZXJlZEluc3RhbmNlIHJlcXVpcmVzIGFyZ1BhY2tBZHZhbmNlIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIG5hbWUgPSByZWdpc3RlcmVkSW5zdGFuY2UubmFtZTsKICAgICAgICAgICAgaWYgKCFyYXdUeXBlKSB7CiAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ3R5cGUgIicgKyBuYW1lICsgJyIgbXVzdCBoYXZlIGEgcG9zaXRpdmUgaW50ZWdlciB0eXBlaWQgcG9pbnRlcicpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChyZWdpc3RlcmVkVHlwZXMuaGFzT3duUHJvcGVydHkocmF3VHlwZSkpIHsKICAgICAgICAgICAgICBpZiAob3B0aW9ucy5pZ25vcmVEdXBsaWNhdGVSZWdpc3RyYXRpb25zKSB7CiAgICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgcmVnaXN0ZXIgdHlwZSAnIiArIG5hbWUgKyAiJyB0d2ljZSIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICByZWdpc3RlcmVkVHlwZXNbcmF3VHlwZV0gPSByZWdpc3RlcmVkSW5zdGFuY2U7CiAgICAgICAgICAgIGRlbGV0ZSB0eXBlRGVwZW5kZW5jaWVzW3Jhd1R5cGVdOwogICAgICAgICAgICBpZiAoYXdhaXRpbmdEZXBlbmRlbmNpZXMuaGFzT3duUHJvcGVydHkocmF3VHlwZSkpIHsKICAgICAgICAgICAgICB2YXIgY2FsbGJhY2tzID0gYXdhaXRpbmdEZXBlbmRlbmNpZXNbcmF3VHlwZV07CiAgICAgICAgICAgICAgZGVsZXRlIGF3YWl0aW5nRGVwZW5kZW5jaWVzW3Jhd1R5cGVdOwogICAgICAgICAgICAgIGNhbGxiYWNrcy5mb3JFYWNoKGZ1bmN0aW9uKGNiKSB7CiAgICAgICAgICAgICAgICBjYigpOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9ib29sKHJhd1R5cGUsIG5hbWUsIHNpemUsIHRydWVWYWx1ZSwgZmFsc2VWYWx1ZSkgewogICAgICAgICAgICB2YXIgc2hpZnQgPSBnZXRTaGlmdEZyb21TaXplKHNpemUpOwogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsgbmFtZSwgImZyb21XaXJlVHlwZSI6IGZ1bmN0aW9uKHd0MikgewogICAgICAgICAgICAgIHJldHVybiAhIXd0MjsKICAgICAgICAgICAgfSwgInRvV2lyZVR5cGUiOiBmdW5jdGlvbihkZXN0cnVjdG9ycywgbzIpIHsKICAgICAgICAgICAgICByZXR1cm4gbzIgPyB0cnVlVmFsdWUgOiBmYWxzZVZhbHVlOwogICAgICAgICAgICB9LCAiYXJnUGFja0FkdmFuY2UiOiA4LCAicmVhZFZhbHVlRnJvbVBvaW50ZXIiOiBmdW5jdGlvbihwb2ludGVyKSB7CiAgICAgICAgICAgICAgdmFyIGhlYXA7CiAgICAgICAgICAgICAgaWYgKHNpemUgPT09IDEpIHsKICAgICAgICAgICAgICAgIGhlYXAgPSBIRUFQODsKICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNpemUgPT09IDIpIHsKICAgICAgICAgICAgICAgIGhlYXAgPSBIRUFQMTY7CiAgICAgICAgICAgICAgfSBlbHNlIGlmIChzaXplID09PSA0KSB7CiAgICAgICAgICAgICAgICBoZWFwID0gSEVBUDMyOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIGJvb2xlYW4gdHlwZSBzaXplOiAiICsgbmFtZSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiB0aGlzWyJmcm9tV2lyZVR5cGUiXShoZWFwW3BvaW50ZXIgPj4gc2hpZnRdKTsKICAgICAgICAgICAgfSwgZGVzdHJ1Y3RvckZ1bmN0aW9uOiBudWxsIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gQ2xhc3NIYW5kbGVfaXNBbGlhc09mKG90aGVyKSB7CiAgICAgICAgICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBDbGFzc0hhbmRsZSkpIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCEob3RoZXIgaW5zdGFuY2VvZiBDbGFzc0hhbmRsZSkpIHsKICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGxlZnRDbGFzcyA9IHRoaXMuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgIHZhciBsZWZ0ID0gdGhpcy4kJC5wdHI7CiAgICAgICAgICAgIHZhciByaWdodENsYXNzID0gb3RoZXIuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgIHZhciByaWdodCA9IG90aGVyLiQkLnB0cjsKICAgICAgICAgICAgd2hpbGUgKGxlZnRDbGFzcy5iYXNlQ2xhc3MpIHsKICAgICAgICAgICAgICBsZWZ0ID0gbGVmdENsYXNzLnVwY2FzdChsZWZ0KTsKICAgICAgICAgICAgICBsZWZ0Q2xhc3MgPSBsZWZ0Q2xhc3MuYmFzZUNsYXNzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHdoaWxlIChyaWdodENsYXNzLmJhc2VDbGFzcykgewogICAgICAgICAgICAgIHJpZ2h0ID0gcmlnaHRDbGFzcy51cGNhc3QocmlnaHQpOwogICAgICAgICAgICAgIHJpZ2h0Q2xhc3MgPSByaWdodENsYXNzLmJhc2VDbGFzczsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gbGVmdENsYXNzID09PSByaWdodENsYXNzICYmIGxlZnQgPT09IHJpZ2h0OwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gc2hhbGxvd0NvcHlJbnRlcm5hbFBvaW50ZXIobzIpIHsKICAgICAgICAgICAgcmV0dXJuIHsgY291bnQ6IG8yLmNvdW50LCBkZWxldGVTY2hlZHVsZWQ6IG8yLmRlbGV0ZVNjaGVkdWxlZCwgcHJlc2VydmVQb2ludGVyT25EZWxldGU6IG8yLnByZXNlcnZlUG9pbnRlck9uRGVsZXRlLCBwdHI6IG8yLnB0ciwgcHRyVHlwZTogbzIucHRyVHlwZSwgc21hcnRQdHI6IG8yLnNtYXJ0UHRyLCBzbWFydFB0clR5cGU6IG8yLnNtYXJ0UHRyVHlwZSB9OwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gdGhyb3dJbnN0YW5jZUFscmVhZHlEZWxldGVkKG9iaikgewogICAgICAgICAgICBmdW5jdGlvbiBnZXRJbnN0YW5jZVR5cGVOYW1lKGhhbmRsZSkgewogICAgICAgICAgICAgIHJldHVybiBoYW5kbGUuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3MubmFtZTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcihnZXRJbnN0YW5jZVR5cGVOYW1lKG9iaikgKyAiIGluc3RhbmNlIGFscmVhZHkgZGVsZXRlZCIpOwogICAgICAgICAgfQogICAgICAgICAgdmFyIGZpbmFsaXphdGlvbkdyb3VwID0gZmFsc2U7CiAgICAgICAgICBmdW5jdGlvbiBkZXRhY2hGaW5hbGl6ZXIoaGFuZGxlKSB7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBydW5EZXN0cnVjdG9yKCQkKSB7CiAgICAgICAgICAgIGlmICgkJC5zbWFydFB0cikgewogICAgICAgICAgICAgICQkLnNtYXJ0UHRyVHlwZS5yYXdEZXN0cnVjdG9yKCQkLnNtYXJ0UHRyKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAkJC5wdHJUeXBlLnJlZ2lzdGVyZWRDbGFzcy5yYXdEZXN0cnVjdG9yKCQkLnB0cik7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHJlbGVhc2VDbGFzc0hhbmRsZSgkJCkgewogICAgICAgICAgICAkJC5jb3VudC52YWx1ZSAtPSAxOwogICAgICAgICAgICB2YXIgdG9EZWxldGUgPSAwID09PSAkJC5jb3VudC52YWx1ZTsKICAgICAgICAgICAgaWYgKHRvRGVsZXRlKSB7CiAgICAgICAgICAgICAgcnVuRGVzdHJ1Y3RvcigkJCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGF0dGFjaEZpbmFsaXplcihoYW5kbGUpIHsKICAgICAgICAgICAgaWYgKCJ1bmRlZmluZWQiID09PSB0eXBlb2YgRmluYWxpemF0aW9uR3JvdXApIHsKICAgICAgICAgICAgICBhdHRhY2hGaW5hbGl6ZXIgPSBmdW5jdGlvbihoYW5kbGUyKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlMjsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIHJldHVybiBoYW5kbGU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZmluYWxpemF0aW9uR3JvdXAgPSBuZXcgRmluYWxpemF0aW9uR3JvdXAoZnVuY3Rpb24oaXRlcikgewogICAgICAgICAgICAgIGZvciAodmFyIHJlc3VsdCA9IGl0ZXIubmV4dCgpOyAhcmVzdWx0LmRvbmU7IHJlc3VsdCA9IGl0ZXIubmV4dCgpKSB7CiAgICAgICAgICAgICAgICB2YXIgJCQgPSByZXN1bHQudmFsdWU7CiAgICAgICAgICAgICAgICBpZiAoISQkLnB0cikgewogICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oIm9iamVjdCBhbHJlYWR5IGRlbGV0ZWQ6ICIgKyAkJC5wdHIpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgcmVsZWFzZUNsYXNzSGFuZGxlKCQkKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBhdHRhY2hGaW5hbGl6ZXIgPSBmdW5jdGlvbihoYW5kbGUyKSB7CiAgICAgICAgICAgICAgZmluYWxpemF0aW9uR3JvdXAucmVnaXN0ZXIoaGFuZGxlMiwgaGFuZGxlMi4kJCwgaGFuZGxlMi4kJCk7CiAgICAgICAgICAgICAgcmV0dXJuIGhhbmRsZTI7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGRldGFjaEZpbmFsaXplciA9IGZ1bmN0aW9uKGhhbmRsZTIpIHsKICAgICAgICAgICAgICBmaW5hbGl6YXRpb25Hcm91cC51bnJlZ2lzdGVyKGhhbmRsZTIuJCQpOwogICAgICAgICAgICB9OwogICAgICAgICAgICByZXR1cm4gYXR0YWNoRmluYWxpemVyKGhhbmRsZSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBDbGFzc0hhbmRsZV9jbG9uZSgpIHsKICAgICAgICAgICAgaWYgKCF0aGlzLiQkLnB0cikgewogICAgICAgICAgICAgIHRocm93SW5zdGFuY2VBbHJlYWR5RGVsZXRlZCh0aGlzKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodGhpcy4kJC5wcmVzZXJ2ZVBvaW50ZXJPbkRlbGV0ZSkgewogICAgICAgICAgICAgIHRoaXMuJCQuY291bnQudmFsdWUgKz0gMTsKICAgICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICB2YXIgY2xvbmUyID0gYXR0YWNoRmluYWxpemVyKE9iamVjdC5jcmVhdGUoT2JqZWN0LmdldFByb3RvdHlwZU9mKHRoaXMpLCB7ICQkOiB7IHZhbHVlOiBzaGFsbG93Q29weUludGVybmFsUG9pbnRlcih0aGlzLiQkKSB9IH0pKTsKICAgICAgICAgICAgICBjbG9uZTIuJCQuY291bnQudmFsdWUgKz0gMTsKICAgICAgICAgICAgICBjbG9uZTIuJCQuZGVsZXRlU2NoZWR1bGVkID0gZmFsc2U7CiAgICAgICAgICAgICAgcmV0dXJuIGNsb25lMjsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gQ2xhc3NIYW5kbGVfZGVsZXRlKCkgewogICAgICAgICAgICBpZiAoIXRoaXMuJCQucHRyKSB7CiAgICAgICAgICAgICAgdGhyb3dJbnN0YW5jZUFscmVhZHlEZWxldGVkKHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh0aGlzLiQkLmRlbGV0ZVNjaGVkdWxlZCAmJiAhdGhpcy4kJC5wcmVzZXJ2ZVBvaW50ZXJPbkRlbGV0ZSkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJPYmplY3QgYWxyZWFkeSBzY2hlZHVsZWQgZm9yIGRlbGV0aW9uIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGV0YWNoRmluYWxpemVyKHRoaXMpOwogICAgICAgICAgICByZWxlYXNlQ2xhc3NIYW5kbGUodGhpcy4kJCk7CiAgICAgICAgICAgIGlmICghdGhpcy4kJC5wcmVzZXJ2ZVBvaW50ZXJPbkRlbGV0ZSkgewogICAgICAgICAgICAgIHRoaXMuJCQuc21hcnRQdHIgPSB2b2lkIDA7CiAgICAgICAgICAgICAgdGhpcy4kJC5wdHIgPSB2b2lkIDA7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlX2lzRGVsZXRlZCgpIHsKICAgICAgICAgICAgcmV0dXJuICF0aGlzLiQkLnB0cjsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBkZWxheUZ1bmN0aW9uID0gdm9pZCAwOwogICAgICAgICAgdmFyIGRlbGV0aW9uUXVldWUgPSBbXTsKICAgICAgICAgIGZ1bmN0aW9uIGZsdXNoUGVuZGluZ0RlbGV0ZXMoKSB7CiAgICAgICAgICAgIHdoaWxlIChkZWxldGlvblF1ZXVlLmxlbmd0aCkgewogICAgICAgICAgICAgIHZhciBvYmogPSBkZWxldGlvblF1ZXVlLnBvcCgpOwogICAgICAgICAgICAgIG9iai4kJC5kZWxldGVTY2hlZHVsZWQgPSBmYWxzZTsKICAgICAgICAgICAgICBvYmpbImRlbGV0ZSJdKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlX2RlbGV0ZUxhdGVyKCkgewogICAgICAgICAgICBpZiAoIXRoaXMuJCQucHRyKSB7CiAgICAgICAgICAgICAgdGhyb3dJbnN0YW5jZUFscmVhZHlEZWxldGVkKHRoaXMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh0aGlzLiQkLmRlbGV0ZVNjaGVkdWxlZCAmJiAhdGhpcy4kJC5wcmVzZXJ2ZVBvaW50ZXJPbkRlbGV0ZSkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJPYmplY3QgYWxyZWFkeSBzY2hlZHVsZWQgZm9yIGRlbGV0aW9uIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGVsZXRpb25RdWV1ZS5wdXNoKHRoaXMpOwogICAgICAgICAgICBpZiAoZGVsZXRpb25RdWV1ZS5sZW5ndGggPT09IDEgJiYgZGVsYXlGdW5jdGlvbikgewogICAgICAgICAgICAgIGRlbGF5RnVuY3Rpb24oZmx1c2hQZW5kaW5nRGVsZXRlcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdGhpcy4kJC5kZWxldGVTY2hlZHVsZWQgPSB0cnVlOwogICAgICAgICAgICByZXR1cm4gdGhpczsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGluaXRfQ2xhc3NIYW5kbGUoKSB7CiAgICAgICAgICAgIENsYXNzSGFuZGxlLnByb3RvdHlwZVsiaXNBbGlhc09mIl0gPSBDbGFzc0hhbmRsZV9pc0FsaWFzT2Y7CiAgICAgICAgICAgIENsYXNzSGFuZGxlLnByb3RvdHlwZVsiY2xvbmUiXSA9IENsYXNzSGFuZGxlX2Nsb25lOwogICAgICAgICAgICBDbGFzc0hhbmRsZS5wcm90b3R5cGVbImRlbGV0ZSJdID0gQ2xhc3NIYW5kbGVfZGVsZXRlOwogICAgICAgICAgICBDbGFzc0hhbmRsZS5wcm90b3R5cGVbImlzRGVsZXRlZCJdID0gQ2xhc3NIYW5kbGVfaXNEZWxldGVkOwogICAgICAgICAgICBDbGFzc0hhbmRsZS5wcm90b3R5cGVbImRlbGV0ZUxhdGVyIl0gPSBDbGFzc0hhbmRsZV9kZWxldGVMYXRlcjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIENsYXNzSGFuZGxlKCkgewogICAgICAgICAgfQogICAgICAgICAgdmFyIHJlZ2lzdGVyZWRQb2ludGVycyA9IHt9OwogICAgICAgICAgZnVuY3Rpb24gZW5zdXJlT3ZlcmxvYWRUYWJsZShwcm90bywgbWV0aG9kTmFtZSwgaHVtYW5OYW1lKSB7CiAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IHByb3RvW21ldGhvZE5hbWVdLm92ZXJsb2FkVGFibGUpIHsKICAgICAgICAgICAgICB2YXIgcHJldkZ1bmMgPSBwcm90b1ttZXRob2ROYW1lXTsKICAgICAgICAgICAgICBwcm90b1ttZXRob2ROYW1lXSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgICAgaWYgKCFwcm90b1ttZXRob2ROYW1lXS5vdmVybG9hZFRhYmxlLmhhc093blByb3BlcnR5KGFyZ3VtZW50cy5sZW5ndGgpKSB7CiAgICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJGdW5jdGlvbiAnIiArIGh1bWFuTmFtZSArICInIGNhbGxlZCB3aXRoIGFuIGludmFsaWQgbnVtYmVyIG9mIGFyZ3VtZW50cyAoIiArIGFyZ3VtZW50cy5sZW5ndGggKyAiKSAtIGV4cGVjdHMgb25lIG9mICgiICsgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZSArICIpISIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgcmV0dXJuIHByb3RvW21ldGhvZE5hbWVdLm92ZXJsb2FkVGFibGVbYXJndW1lbnRzLmxlbmd0aF0uYXBwbHkodGhpcywgYXJndW1lbnRzKTsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIHByb3RvW21ldGhvZE5hbWVdLm92ZXJsb2FkVGFibGUgPSBbXTsKICAgICAgICAgICAgICBwcm90b1ttZXRob2ROYW1lXS5vdmVybG9hZFRhYmxlW3ByZXZGdW5jLmFyZ0NvdW50XSA9IHByZXZGdW5jOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBleHBvc2VQdWJsaWNTeW1ib2wobmFtZSwgdmFsdWUsIG51bUFyZ3VtZW50cykgewogICAgICAgICAgICBpZiAoTW9kdWxlLmhhc093blByb3BlcnR5KG5hbWUpKSB7CiAgICAgICAgICAgICAgaWYgKHZvaWQgMCA9PT0gbnVtQXJndW1lbnRzIHx8IHZvaWQgMCAhPT0gTW9kdWxlW25hbWVdLm92ZXJsb2FkVGFibGUgJiYgdm9pZCAwICE9PSBNb2R1bGVbbmFtZV0ub3ZlcmxvYWRUYWJsZVtudW1Bcmd1bWVudHNdKSB7CiAgICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IHJlZ2lzdGVyIHB1YmxpYyBuYW1lICciICsgbmFtZSArICInIHR3aWNlIik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGVuc3VyZU92ZXJsb2FkVGFibGUoTW9kdWxlLCBuYW1lLCBuYW1lKTsKICAgICAgICAgICAgICBpZiAoTW9kdWxlLmhhc093blByb3BlcnR5KG51bUFyZ3VtZW50cykpIHsKICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgcmVnaXN0ZXIgbXVsdGlwbGUgb3ZlcmxvYWRzIG9mIGEgZnVuY3Rpb24gd2l0aCB0aGUgc2FtZSBudW1iZXIgb2YgYXJndW1lbnRzICgiICsgbnVtQXJndW1lbnRzICsgIikhIik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIE1vZHVsZVtuYW1lXS5vdmVybG9hZFRhYmxlW251bUFyZ3VtZW50c10gPSB2YWx1ZTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBNb2R1bGVbbmFtZV0gPSB2YWx1ZTsKICAgICAgICAgICAgICBpZiAodm9pZCAwICE9PSBudW1Bcmd1bWVudHMpIHsKICAgICAgICAgICAgICAgIE1vZHVsZVtuYW1lXS5udW1Bcmd1bWVudHMgPSBudW1Bcmd1bWVudHM7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBSZWdpc3RlcmVkQ2xhc3MobmFtZSwgY29uc3RydWN0b3IsIGluc3RhbmNlUHJvdG90eXBlLCByYXdEZXN0cnVjdG9yLCBiYXNlQ2xhc3MsIGdldEFjdHVhbFR5cGUsIHVwY2FzdCwgZG93bmNhc3QpIHsKICAgICAgICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgICAgICAgdGhpcy5jb25zdHJ1Y3RvciA9IGNvbnN0cnVjdG9yOwogICAgICAgICAgICB0aGlzLmluc3RhbmNlUHJvdG90eXBlID0gaW5zdGFuY2VQcm90b3R5cGU7CiAgICAgICAgICAgIHRoaXMucmF3RGVzdHJ1Y3RvciA9IHJhd0Rlc3RydWN0b3I7CiAgICAgICAgICAgIHRoaXMuYmFzZUNsYXNzID0gYmFzZUNsYXNzOwogICAgICAgICAgICB0aGlzLmdldEFjdHVhbFR5cGUgPSBnZXRBY3R1YWxUeXBlOwogICAgICAgICAgICB0aGlzLnVwY2FzdCA9IHVwY2FzdDsKICAgICAgICAgICAgdGhpcy5kb3duY2FzdCA9IGRvd25jYXN0OwogICAgICAgICAgICB0aGlzLnB1cmVWaXJ0dWFsRnVuY3Rpb25zID0gW107CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB1cGNhc3RQb2ludGVyKHB0ciwgcHRyQ2xhc3MsIGRlc2lyZWRDbGFzcykgewogICAgICAgICAgICB3aGlsZSAocHRyQ2xhc3MgIT09IGRlc2lyZWRDbGFzcykgewogICAgICAgICAgICAgIGlmICghcHRyQ2xhc3MudXBjYXN0KSB7CiAgICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiRXhwZWN0ZWQgbnVsbCBvciBpbnN0YW5jZSBvZiAiICsgZGVzaXJlZENsYXNzLm5hbWUgKyAiLCBnb3QgYW4gaW5zdGFuY2Ugb2YgIiArIHB0ckNsYXNzLm5hbWUpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBwdHIgPSBwdHJDbGFzcy51cGNhc3QocHRyKTsKICAgICAgICAgICAgICBwdHJDbGFzcyA9IHB0ckNsYXNzLmJhc2VDbGFzczsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcHRyOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gY29uc3ROb1NtYXJ0UHRyUmF3UG9pbnRlclRvV2lyZVR5cGUoZGVzdHJ1Y3RvcnMsIGhhbmRsZSkgewogICAgICAgICAgICBpZiAoaGFuZGxlID09PSBudWxsKSB7CiAgICAgICAgICAgICAgaWYgKHRoaXMuaXNSZWZlcmVuY2UpIHsKICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJudWxsIGlzIG5vdCBhIHZhbGlkICIgKyB0aGlzLm5hbWUpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWhhbmRsZS4kJCkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdDYW5ub3QgcGFzcyAiJyArIF9lbWJpbmRfcmVwcihoYW5kbGUpICsgJyIgYXMgYSAnICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWhhbmRsZS4kJC5wdHIpIHsKICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IHBhc3MgZGVsZXRlZCBvYmplY3QgYXMgYSBwb2ludGVyIG9mIHR5cGUgIiArIHRoaXMubmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGhhbmRsZUNsYXNzID0gaGFuZGxlLiQkLnB0clR5cGUucmVnaXN0ZXJlZENsYXNzOwogICAgICAgICAgICB2YXIgcHRyID0gdXBjYXN0UG9pbnRlcihoYW5kbGUuJCQucHRyLCBoYW5kbGVDbGFzcywgdGhpcy5yZWdpc3RlcmVkQ2xhc3MpOwogICAgICAgICAgICByZXR1cm4gcHRyOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZ2VuZXJpY1BvaW50ZXJUb1dpcmVUeXBlKGRlc3RydWN0b3JzLCBoYW5kbGUpIHsKICAgICAgICAgICAgdmFyIHB0cjsKICAgICAgICAgICAgaWYgKGhhbmRsZSA9PT0gbnVsbCkgewogICAgICAgICAgICAgIGlmICh0aGlzLmlzUmVmZXJlbmNlKSB7CiAgICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigibnVsbCBpcyBub3QgYSB2YWxpZCAiICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICAgICAgICAgIHB0ciA9IHRoaXMucmF3Q29uc3RydWN0b3IoKTsKICAgICAgICAgICAgICAgIGlmIChkZXN0cnVjdG9ycyAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKHRoaXMucmF3RGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBwdHI7CiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWhhbmRsZS4kJCkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCdDYW5ub3QgcGFzcyAiJyArIF9lbWJpbmRfcmVwcihoYW5kbGUpICsgJyIgYXMgYSAnICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIWhhbmRsZS4kJC5wdHIpIHsKICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IHBhc3MgZGVsZXRlZCBvYmplY3QgYXMgYSBwb2ludGVyIG9mIHR5cGUgIiArIHRoaXMubmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCF0aGlzLmlzQ29uc3QgJiYgaGFuZGxlLiQkLnB0clR5cGUuaXNDb25zdCkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgY29udmVydCBhcmd1bWVudCBvZiB0eXBlICIgKyAoaGFuZGxlLiQkLnNtYXJ0UHRyVHlwZSA/IGhhbmRsZS4kJC5zbWFydFB0clR5cGUubmFtZSA6IGhhbmRsZS4kJC5wdHJUeXBlLm5hbWUpICsgIiB0byBwYXJhbWV0ZXIgdHlwZSAiICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgaGFuZGxlQ2xhc3MgPSBoYW5kbGUuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgIHB0ciA9IHVwY2FzdFBvaW50ZXIoaGFuZGxlLiQkLnB0ciwgaGFuZGxlQ2xhc3MsIHRoaXMucmVnaXN0ZXJlZENsYXNzKTsKICAgICAgICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICAgICAgICBpZiAodm9pZCAwID09PSBoYW5kbGUuJCQuc21hcnRQdHIpIHsKICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJQYXNzaW5nIHJhdyBwb2ludGVyIHRvIHNtYXJ0IHBvaW50ZXIgaXMgaWxsZWdhbCIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBzd2l0Y2ggKHRoaXMuc2hhcmluZ1BvbGljeSkgewogICAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgICBpZiAoaGFuZGxlLiQkLnNtYXJ0UHRyVHlwZSA9PT0gdGhpcykgewogICAgICAgICAgICAgICAgICAgIHB0ciA9IGhhbmRsZS4kJC5zbWFydFB0cjsKICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiQ2Fubm90IGNvbnZlcnQgYXJndW1lbnQgb2YgdHlwZSAiICsgKGhhbmRsZS4kJC5zbWFydFB0clR5cGUgPyBoYW5kbGUuJCQuc21hcnRQdHJUeXBlLm5hbWUgOiBoYW5kbGUuJCQucHRyVHlwZS5uYW1lKSArICIgdG8gcGFyYW1ldGVyIHR5cGUgIiArIHRoaXMubmFtZSk7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDE6CiAgICAgICAgICAgICAgICAgIHB0ciA9IGhhbmRsZS4kJC5zbWFydFB0cjsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICAgIGlmIChoYW5kbGUuJCQuc21hcnRQdHJUeXBlID09PSB0aGlzKSB7CiAgICAgICAgICAgICAgICAgICAgcHRyID0gaGFuZGxlLiQkLnNtYXJ0UHRyOwogICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHZhciBjbG9uZWRIYW5kbGUgPSBoYW5kbGVbImNsb25lIl0oKTsKICAgICAgICAgICAgICAgICAgICBwdHIgPSB0aGlzLnJhd1NoYXJlKHB0ciwgX19lbXZhbF9yZWdpc3RlcihmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgICAgICAgIGNsb25lZEhhbmRsZVsiZGVsZXRlIl0oKTsKICAgICAgICAgICAgICAgICAgICB9KSk7CiAgICAgICAgICAgICAgICAgICAgaWYgKGRlc3RydWN0b3JzICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKHRoaXMucmF3RGVzdHJ1Y3RvciwgcHRyKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICBkZWZhdWx0OgogICAgICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigiVW5zdXBwb3J0aW5nIHNoYXJpbmcgcG9saWN5Iik7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBwdHI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBub25Db25zdE5vU21hcnRQdHJSYXdQb2ludGVyVG9XaXJlVHlwZShkZXN0cnVjdG9ycywgaGFuZGxlKSB7CiAgICAgICAgICAgIGlmIChoYW5kbGUgPT09IG51bGwpIHsKICAgICAgICAgICAgICBpZiAodGhpcy5pc1JlZmVyZW5jZSkgewogICAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoIm51bGwgaXMgbm90IGEgdmFsaWQgIiArIHRoaXMubmFtZSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghaGFuZGxlLiQkKSB7CiAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoJ0Nhbm5vdCBwYXNzICInICsgX2VtYmluZF9yZXByKGhhbmRsZSkgKyAnIiBhcyBhICcgKyB0aGlzLm5hbWUpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICghaGFuZGxlLiQkLnB0cikgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgcGFzcyBkZWxldGVkIG9iamVjdCBhcyBhIHBvaW50ZXIgb2YgdHlwZSAiICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoaGFuZGxlLiQkLnB0clR5cGUuaXNDb25zdCkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgY29udmVydCBhcmd1bWVudCBvZiB0eXBlICIgKyBoYW5kbGUuJCQucHRyVHlwZS5uYW1lICsgIiB0byBwYXJhbWV0ZXIgdHlwZSAiICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgaGFuZGxlQ2xhc3MgPSBoYW5kbGUuJCQucHRyVHlwZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgIHZhciBwdHIgPSB1cGNhc3RQb2ludGVyKGhhbmRsZS4kJC5wdHIsIGhhbmRsZUNsYXNzLCB0aGlzLnJlZ2lzdGVyZWRDbGFzcyk7CiAgICAgICAgICAgIHJldHVybiBwdHI7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBSZWdpc3RlcmVkUG9pbnRlcl9nZXRQb2ludGVlKHB0cikgewogICAgICAgICAgICBpZiAodGhpcy5yYXdHZXRQb2ludGVlKSB7CiAgICAgICAgICAgICAgcHRyID0gdGhpcy5yYXdHZXRQb2ludGVlKHB0cik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHB0cjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIFJlZ2lzdGVyZWRQb2ludGVyX2Rlc3RydWN0b3IocHRyKSB7CiAgICAgICAgICAgIGlmICh0aGlzLnJhd0Rlc3RydWN0b3IpIHsKICAgICAgICAgICAgICB0aGlzLnJhd0Rlc3RydWN0b3IocHRyKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXJfZGVsZXRlT2JqZWN0KGhhbmRsZSkgewogICAgICAgICAgICBpZiAoaGFuZGxlICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgaGFuZGxlWyJkZWxldGUiXSgpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBkb3duY2FzdFBvaW50ZXIocHRyLCBwdHJDbGFzcywgZGVzaXJlZENsYXNzKSB7CiAgICAgICAgICAgIGlmIChwdHJDbGFzcyA9PT0gZGVzaXJlZENsYXNzKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHB0cjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodm9pZCAwID09PSBkZXNpcmVkQ2xhc3MuYmFzZUNsYXNzKSB7CiAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHJ2ID0gZG93bmNhc3RQb2ludGVyKHB0ciwgcHRyQ2xhc3MsIGRlc2lyZWRDbGFzcy5iYXNlQ2xhc3MpOwogICAgICAgICAgICBpZiAocnYgPT09IG51bGwpIHsKICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZGVzaXJlZENsYXNzLmRvd25jYXN0KHJ2KTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGdldEluaGVyaXRlZEluc3RhbmNlQ291bnQoKSB7CiAgICAgICAgICAgIHJldHVybiBPYmplY3Qua2V5cyhyZWdpc3RlcmVkSW5zdGFuY2VzKS5sZW5ndGg7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBnZXRMaXZlSW5oZXJpdGVkSW5zdGFuY2VzKCkgewogICAgICAgICAgICB2YXIgcnYgPSBbXTsKICAgICAgICAgICAgZm9yICh2YXIgazIgaW4gcmVnaXN0ZXJlZEluc3RhbmNlcykgewogICAgICAgICAgICAgIGlmIChyZWdpc3RlcmVkSW5zdGFuY2VzLmhhc093blByb3BlcnR5KGsyKSkgewogICAgICAgICAgICAgICAgcnYucHVzaChyZWdpc3RlcmVkSW5zdGFuY2VzW2syXSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBydjsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIHNldERlbGF5RnVuY3Rpb24oZm4pIHsKICAgICAgICAgICAgZGVsYXlGdW5jdGlvbiA9IGZuOwogICAgICAgICAgICBpZiAoZGVsZXRpb25RdWV1ZS5sZW5ndGggJiYgZGVsYXlGdW5jdGlvbikgewogICAgICAgICAgICAgIGRlbGF5RnVuY3Rpb24oZmx1c2hQZW5kaW5nRGVsZXRlcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGluaXRfZW1iaW5kKCkgewogICAgICAgICAgICBNb2R1bGVbImdldEluaGVyaXRlZEluc3RhbmNlQ291bnQiXSA9IGdldEluaGVyaXRlZEluc3RhbmNlQ291bnQ7CiAgICAgICAgICAgIE1vZHVsZVsiZ2V0TGl2ZUluaGVyaXRlZEluc3RhbmNlcyJdID0gZ2V0TGl2ZUluaGVyaXRlZEluc3RhbmNlczsKICAgICAgICAgICAgTW9kdWxlWyJmbHVzaFBlbmRpbmdEZWxldGVzIl0gPSBmbHVzaFBlbmRpbmdEZWxldGVzOwogICAgICAgICAgICBNb2R1bGVbInNldERlbGF5RnVuY3Rpb24iXSA9IHNldERlbGF5RnVuY3Rpb247CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgcmVnaXN0ZXJlZEluc3RhbmNlcyA9IHt9OwogICAgICAgICAgZnVuY3Rpb24gZ2V0QmFzZXN0UG9pbnRlcihjbGFzc18sIHB0cikgewogICAgICAgICAgICBpZiAocHRyID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICB0aHJvd0JpbmRpbmdFcnJvcigicHRyIHNob3VsZCBub3QgYmUgdW5kZWZpbmVkIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgd2hpbGUgKGNsYXNzXy5iYXNlQ2xhc3MpIHsKICAgICAgICAgICAgICBwdHIgPSBjbGFzc18udXBjYXN0KHB0cik7CiAgICAgICAgICAgICAgY2xhc3NfID0gY2xhc3NfLmJhc2VDbGFzczsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gcHRyOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZ2V0SW5oZXJpdGVkSW5zdGFuY2UoY2xhc3NfLCBwdHIpIHsKICAgICAgICAgICAgcHRyID0gZ2V0QmFzZXN0UG9pbnRlcihjbGFzc18sIHB0cik7CiAgICAgICAgICAgIHJldHVybiByZWdpc3RlcmVkSW5zdGFuY2VzW3B0cl07CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBtYWtlQ2xhc3NIYW5kbGUocHJvdG90eXBlLCByZWNvcmQpIHsKICAgICAgICAgICAgaWYgKCFyZWNvcmQucHRyVHlwZSB8fCAhcmVjb3JkLnB0cikgewogICAgICAgICAgICAgIHRocm93SW50ZXJuYWxFcnJvcigibWFrZUNsYXNzSGFuZGxlIHJlcXVpcmVzIHB0ciBhbmQgcHRyVHlwZSIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBoYXNTbWFydFB0clR5cGUgPSAhIXJlY29yZC5zbWFydFB0clR5cGU7CiAgICAgICAgICAgIHZhciBoYXNTbWFydFB0ciA9ICEhcmVjb3JkLnNtYXJ0UHRyOwogICAgICAgICAgICBpZiAoaGFzU21hcnRQdHJUeXBlICE9PSBoYXNTbWFydFB0cikgewogICAgICAgICAgICAgIHRocm93SW50ZXJuYWxFcnJvcigiQm90aCBzbWFydFB0clR5cGUgYW5kIHNtYXJ0UHRyIG11c3QgYmUgc3BlY2lmaWVkIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmVjb3JkLmNvdW50ID0geyB2YWx1ZTogMSB9OwogICAgICAgICAgICByZXR1cm4gYXR0YWNoRmluYWxpemVyKE9iamVjdC5jcmVhdGUocHJvdG90eXBlLCB7ICQkOiB7IHZhbHVlOiByZWNvcmQgfSB9KSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBSZWdpc3RlcmVkUG9pbnRlcl9mcm9tV2lyZVR5cGUocHRyKSB7CiAgICAgICAgICAgIHZhciByYXdQb2ludGVyID0gdGhpcy5nZXRQb2ludGVlKHB0cik7CiAgICAgICAgICAgIGlmICghcmF3UG9pbnRlcikgewogICAgICAgICAgICAgIHRoaXMuZGVzdHJ1Y3RvcihwdHIpOwogICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciByZWdpc3RlcmVkSW5zdGFuY2UgPSBnZXRJbmhlcml0ZWRJbnN0YW5jZSh0aGlzLnJlZ2lzdGVyZWRDbGFzcywgcmF3UG9pbnRlcik7CiAgICAgICAgICAgIGlmICh2b2lkIDAgIT09IHJlZ2lzdGVyZWRJbnN0YW5jZSkgewogICAgICAgICAgICAgIGlmICgwID09PSByZWdpc3RlcmVkSW5zdGFuY2UuJCQuY291bnQudmFsdWUpIHsKICAgICAgICAgICAgICAgIHJlZ2lzdGVyZWRJbnN0YW5jZS4kJC5wdHIgPSByYXdQb2ludGVyOwogICAgICAgICAgICAgICAgcmVnaXN0ZXJlZEluc3RhbmNlLiQkLnNtYXJ0UHRyID0gcHRyOwogICAgICAgICAgICAgICAgcmV0dXJuIHJlZ2lzdGVyZWRJbnN0YW5jZVsiY2xvbmUiXSgpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICB2YXIgcnYgPSByZWdpc3RlcmVkSW5zdGFuY2VbImNsb25lIl0oKTsKICAgICAgICAgICAgICAgIHRoaXMuZGVzdHJ1Y3RvcihwdHIpOwogICAgICAgICAgICAgICAgcmV0dXJuIHJ2OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmdW5jdGlvbiBtYWtlRGVmYXVsdEhhbmRsZSgpIHsKICAgICAgICAgICAgICBpZiAodGhpcy5pc1NtYXJ0UG9pbnRlcikgewogICAgICAgICAgICAgICAgcmV0dXJuIG1ha2VDbGFzc0hhbmRsZSh0aGlzLnJlZ2lzdGVyZWRDbGFzcy5pbnN0YW5jZVByb3RvdHlwZSwgeyBwdHJUeXBlOiB0aGlzLnBvaW50ZWVUeXBlLCBwdHI6IHJhd1BvaW50ZXIsIHNtYXJ0UHRyVHlwZTogdGhpcywgc21hcnRQdHI6IHB0ciB9KTsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgcmV0dXJuIG1ha2VDbGFzc0hhbmRsZSh0aGlzLnJlZ2lzdGVyZWRDbGFzcy5pbnN0YW5jZVByb3RvdHlwZSwgeyBwdHJUeXBlOiB0aGlzLCBwdHIgfSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBhY3R1YWxUeXBlID0gdGhpcy5yZWdpc3RlcmVkQ2xhc3MuZ2V0QWN0dWFsVHlwZShyYXdQb2ludGVyKTsKICAgICAgICAgICAgdmFyIHJlZ2lzdGVyZWRQb2ludGVyUmVjb3JkID0gcmVnaXN0ZXJlZFBvaW50ZXJzW2FjdHVhbFR5cGVdOwogICAgICAgICAgICBpZiAoIXJlZ2lzdGVyZWRQb2ludGVyUmVjb3JkKSB7CiAgICAgICAgICAgICAgcmV0dXJuIG1ha2VEZWZhdWx0SGFuZGxlLmNhbGwodGhpcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIHRvVHlwZTsKICAgICAgICAgICAgaWYgKHRoaXMuaXNDb25zdCkgewogICAgICAgICAgICAgIHRvVHlwZSA9IHJlZ2lzdGVyZWRQb2ludGVyUmVjb3JkLmNvbnN0UG9pbnRlclR5cGU7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdG9UeXBlID0gcmVnaXN0ZXJlZFBvaW50ZXJSZWNvcmQucG9pbnRlclR5cGU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGRwID0gZG93bmNhc3RQb2ludGVyKHJhd1BvaW50ZXIsIHRoaXMucmVnaXN0ZXJlZENsYXNzLCB0b1R5cGUucmVnaXN0ZXJlZENsYXNzKTsKICAgICAgICAgICAgaWYgKGRwID09PSBudWxsKSB7CiAgICAgICAgICAgICAgcmV0dXJuIG1ha2VEZWZhdWx0SGFuZGxlLmNhbGwodGhpcyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHRoaXMuaXNTbWFydFBvaW50ZXIpIHsKICAgICAgICAgICAgICByZXR1cm4gbWFrZUNsYXNzSGFuZGxlKHRvVHlwZS5yZWdpc3RlcmVkQ2xhc3MuaW5zdGFuY2VQcm90b3R5cGUsIHsgcHRyVHlwZTogdG9UeXBlLCBwdHI6IGRwLCBzbWFydFB0clR5cGU6IHRoaXMsIHNtYXJ0UHRyOiBwdHIgfSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgcmV0dXJuIG1ha2VDbGFzc0hhbmRsZSh0b1R5cGUucmVnaXN0ZXJlZENsYXNzLmluc3RhbmNlUHJvdG90eXBlLCB7IHB0clR5cGU6IHRvVHlwZSwgcHRyOiBkcCB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gaW5pdF9SZWdpc3RlcmVkUG9pbnRlcigpIHsKICAgICAgICAgICAgUmVnaXN0ZXJlZFBvaW50ZXIucHJvdG90eXBlLmdldFBvaW50ZWUgPSBSZWdpc3RlcmVkUG9pbnRlcl9nZXRQb2ludGVlOwogICAgICAgICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGUuZGVzdHJ1Y3RvciA9IFJlZ2lzdGVyZWRQb2ludGVyX2Rlc3RydWN0b3I7CiAgICAgICAgICAgIFJlZ2lzdGVyZWRQb2ludGVyLnByb3RvdHlwZVsiYXJnUGFja0FkdmFuY2UiXSA9IDg7CiAgICAgICAgICAgIFJlZ2lzdGVyZWRQb2ludGVyLnByb3RvdHlwZVsicmVhZFZhbHVlRnJvbVBvaW50ZXIiXSA9IHNpbXBsZVJlYWRWYWx1ZUZyb21Qb2ludGVyOwogICAgICAgICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGVbImRlbGV0ZU9iamVjdCJdID0gUmVnaXN0ZXJlZFBvaW50ZXJfZGVsZXRlT2JqZWN0OwogICAgICAgICAgICBSZWdpc3RlcmVkUG9pbnRlci5wcm90b3R5cGVbImZyb21XaXJlVHlwZSJdID0gUmVnaXN0ZXJlZFBvaW50ZXJfZnJvbVdpcmVUeXBlOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gUmVnaXN0ZXJlZFBvaW50ZXIobmFtZSwgcmVnaXN0ZXJlZENsYXNzLCBpc1JlZmVyZW5jZSwgaXNDb25zdCwgaXNTbWFydFBvaW50ZXIsIHBvaW50ZWVUeXBlLCBzaGFyaW5nUG9saWN5LCByYXdHZXRQb2ludGVlLCByYXdDb25zdHJ1Y3RvciwgcmF3U2hhcmUsIHJhd0Rlc3RydWN0b3IpIHsKICAgICAgICAgICAgdGhpcy5uYW1lID0gbmFtZTsKICAgICAgICAgICAgdGhpcy5yZWdpc3RlcmVkQ2xhc3MgPSByZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgIHRoaXMuaXNSZWZlcmVuY2UgPSBpc1JlZmVyZW5jZTsKICAgICAgICAgICAgdGhpcy5pc0NvbnN0ID0gaXNDb25zdDsKICAgICAgICAgICAgdGhpcy5pc1NtYXJ0UG9pbnRlciA9IGlzU21hcnRQb2ludGVyOwogICAgICAgICAgICB0aGlzLnBvaW50ZWVUeXBlID0gcG9pbnRlZVR5cGU7CiAgICAgICAgICAgIHRoaXMuc2hhcmluZ1BvbGljeSA9IHNoYXJpbmdQb2xpY3k7CiAgICAgICAgICAgIHRoaXMucmF3R2V0UG9pbnRlZSA9IHJhd0dldFBvaW50ZWU7CiAgICAgICAgICAgIHRoaXMucmF3Q29uc3RydWN0b3IgPSByYXdDb25zdHJ1Y3RvcjsKICAgICAgICAgICAgdGhpcy5yYXdTaGFyZSA9IHJhd1NoYXJlOwogICAgICAgICAgICB0aGlzLnJhd0Rlc3RydWN0b3IgPSByYXdEZXN0cnVjdG9yOwogICAgICAgICAgICBpZiAoIWlzU21hcnRQb2ludGVyICYmIHJlZ2lzdGVyZWRDbGFzcy5iYXNlQ2xhc3MgPT09IHZvaWQgMCkgewogICAgICAgICAgICAgIGlmIChpc0NvbnN0KSB7CiAgICAgICAgICAgICAgICB0aGlzWyJ0b1dpcmVUeXBlIl0gPSBjb25zdE5vU21hcnRQdHJSYXdQb2ludGVyVG9XaXJlVHlwZTsKICAgICAgICAgICAgICAgIHRoaXMuZGVzdHJ1Y3RvckZ1bmN0aW9uID0gbnVsbDsKICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdGhpc1sidG9XaXJlVHlwZSJdID0gbm9uQ29uc3ROb1NtYXJ0UHRyUmF3UG9pbnRlclRvV2lyZVR5cGU7CiAgICAgICAgICAgICAgICB0aGlzLmRlc3RydWN0b3JGdW5jdGlvbiA9IG51bGw7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRoaXNbInRvV2lyZVR5cGUiXSA9IGdlbmVyaWNQb2ludGVyVG9XaXJlVHlwZTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gcmVwbGFjZVB1YmxpY1N5bWJvbChuYW1lLCB2YWx1ZSwgbnVtQXJndW1lbnRzKSB7CiAgICAgICAgICAgIGlmICghTW9kdWxlLmhhc093blByb3BlcnR5KG5hbWUpKSB7CiAgICAgICAgICAgICAgdGhyb3dJbnRlcm5hbEVycm9yKCJSZXBsYWNpbmcgbm9uZXhpc3RhbnQgcHVibGljIHN5bWJvbCIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh2b2lkIDAgIT09IE1vZHVsZVtuYW1lXS5vdmVybG9hZFRhYmxlICYmIHZvaWQgMCAhPT0gbnVtQXJndW1lbnRzKSB7CiAgICAgICAgICAgICAgTW9kdWxlW25hbWVdLm92ZXJsb2FkVGFibGVbbnVtQXJndW1lbnRzXSA9IHZhbHVlOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIE1vZHVsZVtuYW1lXSA9IHZhbHVlOwogICAgICAgICAgICAgIE1vZHVsZVtuYW1lXS5hcmdDb3VudCA9IG51bUFyZ3VtZW50czsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZHluQ2FsbExlZ2FjeShzaWcsIHB0ciwgYXJncykgewogICAgICAgICAgICB2YXIgZjIgPSBNb2R1bGVbImR5bkNhbGxfIiArIHNpZ107CiAgICAgICAgICAgIHJldHVybiBhcmdzICYmIGFyZ3MubGVuZ3RoID8gZjIuYXBwbHkobnVsbCwgW3B0cl0uY29uY2F0KGFyZ3MpKSA6IGYyLmNhbGwobnVsbCwgcHRyKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGR5bkNhbGwoc2lnLCBwdHIsIGFyZ3MpIHsKICAgICAgICAgICAgaWYgKHNpZy5pbmRleE9mKCJqIikgIT0gLTEpIHsKICAgICAgICAgICAgICByZXR1cm4gZHluQ2FsbExlZ2FjeShzaWcsIHB0ciwgYXJncyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIHdhc21UYWJsZS5nZXQocHRyKS5hcHBseShudWxsLCBhcmdzKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGdldER5bkNhbGxlcihzaWcsIHB0cikgewogICAgICAgICAgICB2YXIgYXJnQ2FjaGUgPSBbXTsKICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIGFyZ0NhY2hlLmxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7CiAgICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGFyZ3VtZW50cy5sZW5ndGg7IGkyKyspIHsKICAgICAgICAgICAgICAgIGFyZ0NhY2hlW2kyXSA9IGFyZ3VtZW50c1tpMl07CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHJldHVybiBkeW5DYWxsKHNpZywgcHRyLCBhcmdDYWNoZSk7CiAgICAgICAgICAgIH07CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihzaWduYXR1cmUsIHJhd0Z1bmN0aW9uKSB7CiAgICAgICAgICAgIHNpZ25hdHVyZSA9IHJlYWRMYXRpbjFTdHJpbmcoc2lnbmF0dXJlKTsKICAgICAgICAgICAgZnVuY3Rpb24gbWFrZUR5bkNhbGxlcigpIHsKICAgICAgICAgICAgICBpZiAoc2lnbmF0dXJlLmluZGV4T2YoImoiKSAhPSAtMSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGdldER5bkNhbGxlcihzaWduYXR1cmUsIHJhd0Z1bmN0aW9uKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHdhc21UYWJsZS5nZXQocmF3RnVuY3Rpb24pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBmcCA9IG1ha2VEeW5DYWxsZXIoKTsKICAgICAgICAgICAgaWYgKHR5cGVvZiBmcCAhPT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJ1bmtub3duIGZ1bmN0aW9uIHBvaW50ZXIgd2l0aCBzaWduYXR1cmUgIiArIHNpZ25hdHVyZSArICI6ICIgKyByYXdGdW5jdGlvbik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGZwOwogICAgICAgICAgfQogICAgICAgICAgdmFyIFVuYm91bmRUeXBlRXJyb3IgPSB2b2lkIDA7CiAgICAgICAgICBmdW5jdGlvbiBnZXRUeXBlTmFtZSh0eXBlKSB7CiAgICAgICAgICAgIHZhciBwdHIgPSBfX19nZXRUeXBlTmFtZSh0eXBlKTsKICAgICAgICAgICAgdmFyIHJ2ID0gcmVhZExhdGluMVN0cmluZyhwdHIpOwogICAgICAgICAgICBfZnJlZShwdHIpOwogICAgICAgICAgICByZXR1cm4gcnY7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiB0aHJvd1VuYm91bmRUeXBlRXJyb3IobWVzc2FnZSwgdHlwZXMpIHsKICAgICAgICAgICAgdmFyIHVuYm91bmRUeXBlcyA9IFtdOwogICAgICAgICAgICB2YXIgc2VlbiA9IHt9OwogICAgICAgICAgICBmdW5jdGlvbiB2aXNpdCh0eXBlKSB7CiAgICAgICAgICAgICAgaWYgKHNlZW5bdHlwZV0pIHsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHJlZ2lzdGVyZWRUeXBlc1t0eXBlXSkgewogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAodHlwZURlcGVuZGVuY2llc1t0eXBlXSkgewogICAgICAgICAgICAgICAgdHlwZURlcGVuZGVuY2llc1t0eXBlXS5mb3JFYWNoKHZpc2l0KTsKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdW5ib3VuZFR5cGVzLnB1c2godHlwZSk7CiAgICAgICAgICAgICAgc2Vlblt0eXBlXSA9IHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdHlwZXMuZm9yRWFjaCh2aXNpdCk7CiAgICAgICAgICAgIHRocm93IG5ldyBVbmJvdW5kVHlwZUVycm9yKG1lc3NhZ2UgKyAiOiAiICsgdW5ib3VuZFR5cGVzLm1hcChnZXRUeXBlTmFtZSkuam9pbihbIiwgIl0pKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX2NsYXNzKHJhd1R5cGUsIHJhd1BvaW50ZXJUeXBlLCByYXdDb25zdFBvaW50ZXJUeXBlLCBiYXNlQ2xhc3NSYXdUeXBlLCBnZXRBY3R1YWxUeXBlU2lnbmF0dXJlLCBnZXRBY3R1YWxUeXBlLCB1cGNhc3RTaWduYXR1cmUsIHVwY2FzdCwgZG93bmNhc3RTaWduYXR1cmUsIGRvd25jYXN0LCBuYW1lLCBkZXN0cnVjdG9yU2lnbmF0dXJlLCByYXdEZXN0cnVjdG9yKSB7CiAgICAgICAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICAgICAgICBnZXRBY3R1YWxUeXBlID0gZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oZ2V0QWN0dWFsVHlwZVNpZ25hdHVyZSwgZ2V0QWN0dWFsVHlwZSk7CiAgICAgICAgICAgIGlmICh1cGNhc3QpIHsKICAgICAgICAgICAgICB1cGNhc3QgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbih1cGNhc3RTaWduYXR1cmUsIHVwY2FzdCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGRvd25jYXN0KSB7CiAgICAgICAgICAgICAgZG93bmNhc3QgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihkb3duY2FzdFNpZ25hdHVyZSwgZG93bmNhc3QpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJhd0Rlc3RydWN0b3IgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihkZXN0cnVjdG9yU2lnbmF0dXJlLCByYXdEZXN0cnVjdG9yKTsKICAgICAgICAgICAgdmFyIGxlZ2FsRnVuY3Rpb25OYW1lID0gbWFrZUxlZ2FsRnVuY3Rpb25OYW1lKG5hbWUpOwogICAgICAgICAgICBleHBvc2VQdWJsaWNTeW1ib2wobGVnYWxGdW5jdGlvbk5hbWUsIGZ1bmN0aW9uKCkgewogICAgICAgICAgICAgIHRocm93VW5ib3VuZFR5cGVFcnJvcigiQ2Fubm90IGNvbnN0cnVjdCAiICsgbmFtZSArICIgZHVlIHRvIHVuYm91bmQgdHlwZXMiLCBbYmFzZUNsYXNzUmF3VHlwZV0pOwogICAgICAgICAgICB9KTsKICAgICAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW3Jhd1R5cGUsIHJhd1BvaW50ZXJUeXBlLCByYXdDb25zdFBvaW50ZXJUeXBlXSwgYmFzZUNsYXNzUmF3VHlwZSA/IFtiYXNlQ2xhc3NSYXdUeXBlXSA6IFtdLCBmdW5jdGlvbihiYXNlKSB7CiAgICAgICAgICAgICAgYmFzZSA9IGJhc2VbMF07CiAgICAgICAgICAgICAgdmFyIGJhc2VDbGFzczsKICAgICAgICAgICAgICB2YXIgYmFzZVByb3RvdHlwZTsKICAgICAgICAgICAgICBpZiAoYmFzZUNsYXNzUmF3VHlwZSkgewogICAgICAgICAgICAgICAgYmFzZUNsYXNzID0gYmFzZS5yZWdpc3RlcmVkQ2xhc3M7CiAgICAgICAgICAgICAgICBiYXNlUHJvdG90eXBlID0gYmFzZUNsYXNzLmluc3RhbmNlUHJvdG90eXBlOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBiYXNlUHJvdG90eXBlID0gQ2xhc3NIYW5kbGUucHJvdG90eXBlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgY29uc3RydWN0b3IgPSBjcmVhdGVOYW1lZEZ1bmN0aW9uKGxlZ2FsRnVuY3Rpb25OYW1lLCBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgIGlmIChPYmplY3QuZ2V0UHJvdG90eXBlT2YodGhpcykgIT09IGluc3RhbmNlUHJvdG90eXBlKSB7CiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBCaW5kaW5nRXJyb3IoIlVzZSAnbmV3JyB0byBjb25zdHJ1Y3QgIiArIG5hbWUpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKHZvaWQgMCA9PT0gcmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHkpIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEJpbmRpbmdFcnJvcihuYW1lICsgIiBoYXMgbm8gYWNjZXNzaWJsZSBjb25zdHJ1Y3RvciIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgdmFyIGJvZHkgPSByZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keVthcmd1bWVudHMubGVuZ3RoXTsKICAgICAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IGJvZHkpIHsKICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEJpbmRpbmdFcnJvcigiVHJpZWQgdG8gaW52b2tlIGN0b3Igb2YgIiArIG5hbWUgKyAiIHdpdGggaW52YWxpZCBudW1iZXIgb2YgcGFyYW1ldGVycyAoIiArIGFyZ3VtZW50cy5sZW5ndGggKyAiKSAtIGV4cGVjdGVkICgiICsgT2JqZWN0LmtleXMocmVnaXN0ZXJlZENsYXNzLmNvbnN0cnVjdG9yX2JvZHkpLnRvU3RyaW5nKCkgKyAiKSBwYXJhbWV0ZXJzIGluc3RlYWQhIik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICByZXR1cm4gYm9keS5hcHBseSh0aGlzLCBhcmd1bWVudHMpOwogICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgIHZhciBpbnN0YW5jZVByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYmFzZVByb3RvdHlwZSwgeyBjb25zdHJ1Y3RvcjogeyB2YWx1ZTogY29uc3RydWN0b3IgfSB9KTsKICAgICAgICAgICAgICBjb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSBpbnN0YW5jZVByb3RvdHlwZTsKICAgICAgICAgICAgICB2YXIgcmVnaXN0ZXJlZENsYXNzID0gbmV3IFJlZ2lzdGVyZWRDbGFzcyhuYW1lLCBjb25zdHJ1Y3RvciwgaW5zdGFuY2VQcm90b3R5cGUsIHJhd0Rlc3RydWN0b3IsIGJhc2VDbGFzcywgZ2V0QWN0dWFsVHlwZSwgdXBjYXN0LCBkb3duY2FzdCk7CiAgICAgICAgICAgICAgdmFyIHJlZmVyZW5jZUNvbnZlcnRlciA9IG5ldyBSZWdpc3RlcmVkUG9pbnRlcihuYW1lLCByZWdpc3RlcmVkQ2xhc3MsIHRydWUsIGZhbHNlLCBmYWxzZSk7CiAgICAgICAgICAgICAgdmFyIHBvaW50ZXJDb252ZXJ0ZXIgPSBuZXcgUmVnaXN0ZXJlZFBvaW50ZXIobmFtZSArICIqIiwgcmVnaXN0ZXJlZENsYXNzLCBmYWxzZSwgZmFsc2UsIGZhbHNlKTsKICAgICAgICAgICAgICB2YXIgY29uc3RQb2ludGVyQ29udmVydGVyID0gbmV3IFJlZ2lzdGVyZWRQb2ludGVyKG5hbWUgKyAiIGNvbnN0KiIsIHJlZ2lzdGVyZWRDbGFzcywgZmFsc2UsIHRydWUsIGZhbHNlKTsKICAgICAgICAgICAgICByZWdpc3RlcmVkUG9pbnRlcnNbcmF3VHlwZV0gPSB7IHBvaW50ZXJUeXBlOiBwb2ludGVyQ29udmVydGVyLCBjb25zdFBvaW50ZXJUeXBlOiBjb25zdFBvaW50ZXJDb252ZXJ0ZXIgfTsKICAgICAgICAgICAgICByZXBsYWNlUHVibGljU3ltYm9sKGxlZ2FsRnVuY3Rpb25OYW1lLCBjb25zdHJ1Y3Rvcik7CiAgICAgICAgICAgICAgcmV0dXJuIFtyZWZlcmVuY2VDb252ZXJ0ZXIsIHBvaW50ZXJDb252ZXJ0ZXIsIGNvbnN0UG9pbnRlckNvbnZlcnRlcl07CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gaGVhcDMyVmVjdG9yVG9BcnJheShjb3VudCwgZmlyc3RFbGVtZW50KSB7CiAgICAgICAgICAgIHZhciBhcnJheSA9IFtdOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgY291bnQ7IGkyKyspIHsKICAgICAgICAgICAgICBhcnJheS5wdXNoKEhFQVAzMlsoZmlyc3RFbGVtZW50ID4+IDIpICsgaTJdKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gYXJyYXk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19jb25zdHJ1Y3RvcihyYXdDbGFzc1R5cGUsIGFyZ0NvdW50LCByYXdBcmdUeXBlc0FkZHIsIGludm9rZXJTaWduYXR1cmUsIGludm9rZXIsIHJhd0NvbnN0cnVjdG9yKSB7CiAgICAgICAgICAgIGFzc2VydChhcmdDb3VudCA+IDApOwogICAgICAgICAgICB2YXIgcmF3QXJnVHlwZXMgPSBoZWFwMzJWZWN0b3JUb0FycmF5KGFyZ0NvdW50LCByYXdBcmdUeXBlc0FkZHIpOwogICAgICAgICAgICBpbnZva2VyID0gZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oaW52b2tlclNpZ25hdHVyZSwgaW52b2tlcik7CiAgICAgICAgICAgIHZhciBhcmdzID0gW3Jhd0NvbnN0cnVjdG9yXTsKICAgICAgICAgICAgdmFyIGRlc3RydWN0b3JzID0gW107CiAgICAgICAgICAgIHdoZW5EZXBlbmRlbnRUeXBlc0FyZVJlc29sdmVkKFtdLCBbcmF3Q2xhc3NUeXBlXSwgZnVuY3Rpb24oY2xhc3NUeXBlKSB7CiAgICAgICAgICAgICAgY2xhc3NUeXBlID0gY2xhc3NUeXBlWzBdOwogICAgICAgICAgICAgIHZhciBodW1hbk5hbWUgPSAiY29uc3RydWN0b3IgIiArIGNsYXNzVHlwZS5uYW1lOwogICAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keSkgewogICAgICAgICAgICAgICAgY2xhc3NUeXBlLnJlZ2lzdGVyZWRDbGFzcy5jb25zdHJ1Y3Rvcl9ib2R5ID0gW107CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGlmICh2b2lkIDAgIT09IGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keVthcmdDb3VudCAtIDFdKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgQmluZGluZ0Vycm9yKCJDYW5ub3QgcmVnaXN0ZXIgbXVsdGlwbGUgY29uc3RydWN0b3JzIHdpdGggaWRlbnRpY2FsIG51bWJlciBvZiBwYXJhbWV0ZXJzICgiICsgKGFyZ0NvdW50IC0gMSkgKyAiKSBmb3IgY2xhc3MgJyIgKyBjbGFzc1R5cGUubmFtZSArICInISBPdmVybG9hZCByZXNvbHV0aW9uIGlzIGN1cnJlbnRseSBvbmx5IHBlcmZvcm1lZCB1c2luZyB0aGUgcGFyYW1ldGVyIGNvdW50LCBub3QgYWN0dWFsIHR5cGUgaW5mbyEiKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgY2xhc3NUeXBlLnJlZ2lzdGVyZWRDbGFzcy5jb25zdHJ1Y3Rvcl9ib2R5W2FyZ0NvdW50IC0gMV0gPSBmdW5jdGlvbiB1bmJvdW5kVHlwZUhhbmRsZXIoKSB7CiAgICAgICAgICAgICAgICB0aHJvd1VuYm91bmRUeXBlRXJyb3IoIkNhbm5vdCBjb25zdHJ1Y3QgIiArIGNsYXNzVHlwZS5uYW1lICsgIiBkdWUgdG8gdW5ib3VuZCB0eXBlcyIsIHJhd0FyZ1R5cGVzKTsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIHdoZW5EZXBlbmRlbnRUeXBlc0FyZVJlc29sdmVkKFtdLCByYXdBcmdUeXBlcywgZnVuY3Rpb24oYXJnVHlwZXMpIHsKICAgICAgICAgICAgICAgIGNsYXNzVHlwZS5yZWdpc3RlcmVkQ2xhc3MuY29uc3RydWN0b3JfYm9keVthcmdDb3VudCAtIDFdID0gZnVuY3Rpb24gY29uc3RydWN0b3JfYm9keSgpIHsKICAgICAgICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggIT09IGFyZ0NvdW50IC0gMSkgewogICAgICAgICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKGh1bWFuTmFtZSArICIgY2FsbGVkIHdpdGggIiArIGFyZ3VtZW50cy5sZW5ndGggKyAiIGFyZ3VtZW50cywgZXhwZWN0ZWQgIiArIChhcmdDb3VudCAtIDEpKTsKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICBkZXN0cnVjdG9ycy5sZW5ndGggPSAwOwogICAgICAgICAgICAgICAgICBhcmdzLmxlbmd0aCA9IGFyZ0NvdW50OwogICAgICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDE7IGkyIDwgYXJnQ291bnQ7ICsraTIpIHsKICAgICAgICAgICAgICAgICAgICBhcmdzW2kyXSA9IGFyZ1R5cGVzW2kyXVsidG9XaXJlVHlwZSJdKGRlc3RydWN0b3JzLCBhcmd1bWVudHNbaTIgLSAxXSk7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgdmFyIHB0ciA9IGludm9rZXIuYXBwbHkobnVsbCwgYXJncyk7CiAgICAgICAgICAgICAgICAgIHJ1bkRlc3RydWN0b3JzKGRlc3RydWN0b3JzKTsKICAgICAgICAgICAgICAgICAgcmV0dXJuIGFyZ1R5cGVzWzBdWyJmcm9tV2lyZVR5cGUiXShwdHIpOwogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICByZXR1cm4gW107CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gbmV3Xyhjb25zdHJ1Y3RvciwgYXJndW1lbnRMaXN0KSB7CiAgICAgICAgICAgIGlmICghKGNvbnN0cnVjdG9yIGluc3RhbmNlb2YgRnVuY3Rpb24pKSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigibmV3XyBjYWxsZWQgd2l0aCBjb25zdHJ1Y3RvciB0eXBlICIgKyB0eXBlb2YgY29uc3RydWN0b3IgKyAiIHdoaWNoIGlzIG5vdCBhIGZ1bmN0aW9uIik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGR1bW15ID0gY3JlYXRlTmFtZWRGdW5jdGlvbihjb25zdHJ1Y3Rvci5uYW1lIHx8ICJ1bmtub3duRnVuY3Rpb25OYW1lIiwgZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkdW1teS5wcm90b3R5cGUgPSBjb25zdHJ1Y3Rvci5wcm90b3R5cGU7CiAgICAgICAgICAgIHZhciBvYmogPSBuZXcgZHVtbXkoKTsKICAgICAgICAgICAgdmFyIHIyID0gY29uc3RydWN0b3IuYXBwbHkob2JqLCBhcmd1bWVudExpc3QpOwogICAgICAgICAgICByZXR1cm4gcjIgaW5zdGFuY2VvZiBPYmplY3QgPyByMiA6IG9iajsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGNyYWZ0SW52b2tlckZ1bmN0aW9uKGh1bWFuTmFtZSwgYXJnVHlwZXMsIGNsYXNzVHlwZSwgY3BwSW52b2tlckZ1bmMsIGNwcFRhcmdldEZ1bmMpIHsKICAgICAgICAgICAgdmFyIGFyZ0NvdW50ID0gYXJnVHlwZXMubGVuZ3RoOwogICAgICAgICAgICBpZiAoYXJnQ291bnQgPCAyKSB7CiAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoImFyZ1R5cGVzIGFycmF5IHNpemUgbWlzbWF0Y2ghIE11c3QgYXQgbGVhc3QgZ2V0IHJldHVybiB2YWx1ZSBhbmQgJ3RoaXMnIHR5cGVzISIpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBpc0NsYXNzTWV0aG9kRnVuYyA9IGFyZ1R5cGVzWzFdICE9PSBudWxsICYmIGNsYXNzVHlwZSAhPT0gbnVsbDsKICAgICAgICAgICAgdmFyIG5lZWRzRGVzdHJ1Y3RvclN0YWNrID0gZmFsc2U7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMTsgaTIgPCBhcmdUeXBlcy5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgICBpZiAoYXJnVHlwZXNbaTJdICE9PSBudWxsICYmIGFyZ1R5cGVzW2kyXS5kZXN0cnVjdG9yRnVuY3Rpb24gPT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgbmVlZHNEZXN0cnVjdG9yU3RhY2sgPSB0cnVlOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciByZXR1cm5zID0gYXJnVHlwZXNbMF0ubmFtZSAhPT0gInZvaWQiOwogICAgICAgICAgICB2YXIgYXJnc0xpc3QgPSAiIjsKICAgICAgICAgICAgdmFyIGFyZ3NMaXN0V2lyZWQgPSAiIjsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGFyZ0NvdW50IC0gMjsgKytpMikgewogICAgICAgICAgICAgIGFyZ3NMaXN0ICs9IChpMiAhPT0gMCA/ICIsICIgOiAiIikgKyAiYXJnIiArIGkyOwogICAgICAgICAgICAgIGFyZ3NMaXN0V2lyZWQgKz0gKGkyICE9PSAwID8gIiwgIiA6ICIiKSArICJhcmciICsgaTIgKyAiV2lyZWQiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBpbnZva2VyRm5Cb2R5ID0gInJldHVybiBmdW5jdGlvbiAiICsgbWFrZUxlZ2FsRnVuY3Rpb25OYW1lKGh1bWFuTmFtZSkgKyAiKCIgKyBhcmdzTGlzdCArICIpIHtcbmlmIChhcmd1bWVudHMubGVuZ3RoICE9PSAiICsgKGFyZ0NvdW50IC0gMikgKyAiKSB7XG50aHJvd0JpbmRpbmdFcnJvcignZnVuY3Rpb24gIiArIGh1bWFuTmFtZSArICIgY2FsbGVkIHdpdGggJyArIGFyZ3VtZW50cy5sZW5ndGggKyAnIGFyZ3VtZW50cywgZXhwZWN0ZWQgIiArIChhcmdDb3VudCAtIDIpICsgIiBhcmdzIScpO1xufVxuIjsKICAgICAgICAgICAgaWYgKG5lZWRzRGVzdHJ1Y3RvclN0YWNrKSB7CiAgICAgICAgICAgICAgaW52b2tlckZuQm9keSArPSAidmFyIGRlc3RydWN0b3JzID0gW107XG4iOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBkdG9yU3RhY2sgPSBuZWVkc0Rlc3RydWN0b3JTdGFjayA/ICJkZXN0cnVjdG9ycyIgOiAibnVsbCI7CiAgICAgICAgICAgIHZhciBhcmdzMSA9IFsidGhyb3dCaW5kaW5nRXJyb3IiLCAiaW52b2tlciIsICJmbiIsICJydW5EZXN0cnVjdG9ycyIsICJyZXRUeXBlIiwgImNsYXNzUGFyYW0iXTsKICAgICAgICAgICAgdmFyIGFyZ3MyID0gW3Rocm93QmluZGluZ0Vycm9yLCBjcHBJbnZva2VyRnVuYywgY3BwVGFyZ2V0RnVuYywgcnVuRGVzdHJ1Y3RvcnMsIGFyZ1R5cGVzWzBdLCBhcmdUeXBlc1sxXV07CiAgICAgICAgICAgIGlmIChpc0NsYXNzTWV0aG9kRnVuYykgewogICAgICAgICAgICAgIGludm9rZXJGbkJvZHkgKz0gInZhciB0aGlzV2lyZWQgPSBjbGFzc1BhcmFtLnRvV2lyZVR5cGUoIiArIGR0b3JTdGFjayArICIsIHRoaXMpO1xuIjsKICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgYXJnQ291bnQgLSAyOyArK2kyKSB7CiAgICAgICAgICAgICAgaW52b2tlckZuQm9keSArPSAidmFyIGFyZyIgKyBpMiArICJXaXJlZCA9IGFyZ1R5cGUiICsgaTIgKyAiLnRvV2lyZVR5cGUoIiArIGR0b3JTdGFjayArICIsIGFyZyIgKyBpMiArICIpOyAvLyAiICsgYXJnVHlwZXNbaTIgKyAyXS5uYW1lICsgIlxuIjsKICAgICAgICAgICAgICBhcmdzMS5wdXNoKCJhcmdUeXBlIiArIGkyKTsKICAgICAgICAgICAgICBhcmdzMi5wdXNoKGFyZ1R5cGVzW2kyICsgMl0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChpc0NsYXNzTWV0aG9kRnVuYykgewogICAgICAgICAgICAgIGFyZ3NMaXN0V2lyZWQgPSAidGhpc1dpcmVkIiArIChhcmdzTGlzdFdpcmVkLmxlbmd0aCA+IDAgPyAiLCAiIDogIiIpICsgYXJnc0xpc3RXaXJlZDsKICAgICAgICAgICAgfQogICAgICAgICAgICBpbnZva2VyRm5Cb2R5ICs9IChyZXR1cm5zID8gInZhciBydiA9ICIgOiAiIikgKyAiaW52b2tlcihmbiIgKyAoYXJnc0xpc3RXaXJlZC5sZW5ndGggPiAwID8gIiwgIiA6ICIiKSArIGFyZ3NMaXN0V2lyZWQgKyAiKTtcbiI7CiAgICAgICAgICAgIGlmIChuZWVkc0Rlc3RydWN0b3JTdGFjaykgewogICAgICAgICAgICAgIGludm9rZXJGbkJvZHkgKz0gInJ1bkRlc3RydWN0b3JzKGRlc3RydWN0b3JzKTtcbiI7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgZm9yICh2YXIgaTIgPSBpc0NsYXNzTWV0aG9kRnVuYyA/IDEgOiAyOyBpMiA8IGFyZ1R5cGVzLmxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgICAgdmFyIHBhcmFtTmFtZSA9IGkyID09PSAxID8gInRoaXNXaXJlZCIgOiAiYXJnIiArIChpMiAtIDIpICsgIldpcmVkIjsKICAgICAgICAgICAgICAgIGlmIChhcmdUeXBlc1tpMl0uZGVzdHJ1Y3RvckZ1bmN0aW9uICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICAgIGludm9rZXJGbkJvZHkgKz0gcGFyYW1OYW1lICsgIl9kdG9yKCIgKyBwYXJhbU5hbWUgKyAiKTsgLy8gIiArIGFyZ1R5cGVzW2kyXS5uYW1lICsgIlxuIjsKICAgICAgICAgICAgICAgICAgYXJnczEucHVzaChwYXJhbU5hbWUgKyAiX2R0b3IiKTsKICAgICAgICAgICAgICAgICAgYXJnczIucHVzaChhcmdUeXBlc1tpMl0uZGVzdHJ1Y3RvckZ1bmN0aW9uKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKHJldHVybnMpIHsKICAgICAgICAgICAgICBpbnZva2VyRm5Cb2R5ICs9ICJ2YXIgcmV0ID0gcmV0VHlwZS5mcm9tV2lyZVR5cGUocnYpO1xucmV0dXJuIHJldDtcbiI7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaW52b2tlckZuQm9keSArPSAifVxuIjsKICAgICAgICAgICAgYXJnczEucHVzaChpbnZva2VyRm5Cb2R5KTsKICAgICAgICAgICAgdmFyIGludm9rZXJGdW5jdGlvbiA9IG5ld18oRnVuY3Rpb24sIGFyZ3MxKS5hcHBseShudWxsLCBhcmdzMik7CiAgICAgICAgICAgIHJldHVybiBpbnZva2VyRnVuY3Rpb247CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19mdW5jdGlvbihyYXdDbGFzc1R5cGUsIG1ldGhvZE5hbWUsIGFyZ0NvdW50LCByYXdBcmdUeXBlc0FkZHIsIGludm9rZXJTaWduYXR1cmUsIHJhd0ludm9rZXIsIGNvbnRleHQsIGlzUHVyZVZpcnR1YWwpIHsKICAgICAgICAgICAgdmFyIHJhd0FyZ1R5cGVzID0gaGVhcDMyVmVjdG9yVG9BcnJheShhcmdDb3VudCwgcmF3QXJnVHlwZXNBZGRyKTsKICAgICAgICAgICAgbWV0aG9kTmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobWV0aG9kTmFtZSk7CiAgICAgICAgICAgIHJhd0ludm9rZXIgPSBlbWJpbmRfX3JlcXVpcmVGdW5jdGlvbihpbnZva2VyU2lnbmF0dXJlLCByYXdJbnZva2VyKTsKICAgICAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIFtyYXdDbGFzc1R5cGVdLCBmdW5jdGlvbihjbGFzc1R5cGUpIHsKICAgICAgICAgICAgICBjbGFzc1R5cGUgPSBjbGFzc1R5cGVbMF07CiAgICAgICAgICAgICAgdmFyIGh1bWFuTmFtZSA9IGNsYXNzVHlwZS5uYW1lICsgIi4iICsgbWV0aG9kTmFtZTsKICAgICAgICAgICAgICBpZiAoaXNQdXJlVmlydHVhbCkgewogICAgICAgICAgICAgICAgY2xhc3NUeXBlLnJlZ2lzdGVyZWRDbGFzcy5wdXJlVmlydHVhbEZ1bmN0aW9ucy5wdXNoKG1ldGhvZE5hbWUpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBmdW5jdGlvbiB1bmJvdW5kVHlwZXNIYW5kbGVyKCkgewogICAgICAgICAgICAgICAgdGhyb3dVbmJvdW5kVHlwZUVycm9yKCJDYW5ub3QgY2FsbCAiICsgaHVtYW5OYW1lICsgIiBkdWUgdG8gdW5ib3VuZCB0eXBlcyIsIHJhd0FyZ1R5cGVzKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIHByb3RvID0gY2xhc3NUeXBlLnJlZ2lzdGVyZWRDbGFzcy5pbnN0YW5jZVByb3RvdHlwZTsKICAgICAgICAgICAgICB2YXIgbWV0aG9kID0gcHJvdG9bbWV0aG9kTmFtZV07CiAgICAgICAgICAgICAgaWYgKHZvaWQgMCA9PT0gbWV0aG9kIHx8IHZvaWQgMCA9PT0gbWV0aG9kLm92ZXJsb2FkVGFibGUgJiYgbWV0aG9kLmNsYXNzTmFtZSAhPT0gY2xhc3NUeXBlLm5hbWUgJiYgbWV0aG9kLmFyZ0NvdW50ID09PSBhcmdDb3VudCAtIDIpIHsKICAgICAgICAgICAgICAgIHVuYm91bmRUeXBlc0hhbmRsZXIuYXJnQ291bnQgPSBhcmdDb3VudCAtIDI7CiAgICAgICAgICAgICAgICB1bmJvdW5kVHlwZXNIYW5kbGVyLmNsYXNzTmFtZSA9IGNsYXNzVHlwZS5uYW1lOwogICAgICAgICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0gPSB1bmJvdW5kVHlwZXNIYW5kbGVyOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBlbnN1cmVPdmVybG9hZFRhYmxlKHByb3RvLCBtZXRob2ROYW1lLCBodW1hbk5hbWUpOwogICAgICAgICAgICAgICAgcHJvdG9bbWV0aG9kTmFtZV0ub3ZlcmxvYWRUYWJsZVthcmdDb3VudCAtIDJdID0gdW5ib3VuZFR5cGVzSGFuZGxlcjsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIHJhd0FyZ1R5cGVzLCBmdW5jdGlvbihhcmdUeXBlcykgewogICAgICAgICAgICAgICAgdmFyIG1lbWJlckZ1bmN0aW9uID0gY3JhZnRJbnZva2VyRnVuY3Rpb24oaHVtYW5OYW1lLCBhcmdUeXBlcywgY2xhc3NUeXBlLCByYXdJbnZva2VyLCBjb250ZXh0KTsKICAgICAgICAgICAgICAgIGlmICh2b2lkIDAgPT09IHByb3RvW21ldGhvZE5hbWVdLm92ZXJsb2FkVGFibGUpIHsKICAgICAgICAgICAgICAgICAgbWVtYmVyRnVuY3Rpb24uYXJnQ291bnQgPSBhcmdDb3VudCAtIDI7CiAgICAgICAgICAgICAgICAgIHByb3RvW21ldGhvZE5hbWVdID0gbWVtYmVyRnVuY3Rpb247CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBwcm90b1ttZXRob2ROYW1lXS5vdmVybG9hZFRhYmxlW2FyZ0NvdW50IC0gMl0gPSBtZW1iZXJGdW5jdGlvbjsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICByZXR1cm4gW107CiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfY29uc3RhbnQobmFtZSwgdHlwZSwgdmFsdWUpIHsKICAgICAgICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgICAgICAgIHdoZW5EZXBlbmRlbnRUeXBlc0FyZVJlc29sdmVkKFtdLCBbdHlwZV0sIGZ1bmN0aW9uKHR5cGUyKSB7CiAgICAgICAgICAgICAgdHlwZTIgPSB0eXBlMlswXTsKICAgICAgICAgICAgICBNb2R1bGVbbmFtZV0gPSB0eXBlMlsiZnJvbVdpcmVUeXBlIl0odmFsdWUpOwogICAgICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgZW12YWxfZnJlZV9saXN0ID0gW107CiAgICAgICAgICB2YXIgZW12YWxfaGFuZGxlX2FycmF5ID0gW3t9LCB7IHZhbHVlOiB2b2lkIDAgfSwgeyB2YWx1ZTogbnVsbCB9LCB7IHZhbHVlOiB0cnVlIH0sIHsgdmFsdWU6IGZhbHNlIH1dOwogICAgICAgICAgZnVuY3Rpb24gX19lbXZhbF9kZWNyZWYoaGFuZGxlKSB7CiAgICAgICAgICAgIGlmIChoYW5kbGUgPiA0ICYmIDAgPT09IC0tZW12YWxfaGFuZGxlX2FycmF5W2hhbmRsZV0ucmVmY291bnQpIHsKICAgICAgICAgICAgICBlbXZhbF9oYW5kbGVfYXJyYXlbaGFuZGxlXSA9IHZvaWQgMDsKICAgICAgICAgICAgICBlbXZhbF9mcmVlX2xpc3QucHVzaChoYW5kbGUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBjb3VudF9lbXZhbF9oYW5kbGVzKCkgewogICAgICAgICAgICB2YXIgY291bnQgPSAwOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDU7IGkyIDwgZW12YWxfaGFuZGxlX2FycmF5Lmxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgIGlmIChlbXZhbF9oYW5kbGVfYXJyYXlbaTJdICE9PSB2b2lkIDApIHsKICAgICAgICAgICAgICAgICsrY291bnQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBjb3VudDsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGdldF9maXJzdF9lbXZhbCgpIHsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSA1OyBpMiA8IGVtdmFsX2hhbmRsZV9hcnJheS5sZW5ndGg7ICsraTIpIHsKICAgICAgICAgICAgICBpZiAoZW12YWxfaGFuZGxlX2FycmF5W2kyXSAhPT0gdm9pZCAwKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gZW12YWxfaGFuZGxlX2FycmF5W2kyXTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBpbml0X2VtdmFsKCkgewogICAgICAgICAgICBNb2R1bGVbImNvdW50X2VtdmFsX2hhbmRsZXMiXSA9IGNvdW50X2VtdmFsX2hhbmRsZXM7CiAgICAgICAgICAgIE1vZHVsZVsiZ2V0X2ZpcnN0X2VtdmFsIl0gPSBnZXRfZmlyc3RfZW12YWw7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtdmFsX3JlZ2lzdGVyKHZhbHVlKSB7CiAgICAgICAgICAgIHN3aXRjaCAodmFsdWUpIHsKICAgICAgICAgICAgICBjYXNlIHZvaWQgMDogewogICAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNhc2UgbnVsbDogewogICAgICAgICAgICAgICAgcmV0dXJuIDI7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNhc2UgdHJ1ZTogewogICAgICAgICAgICAgICAgcmV0dXJuIDM7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIGNhc2UgZmFsc2U6IHsKICAgICAgICAgICAgICAgIHJldHVybiA0OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBkZWZhdWx0OiB7CiAgICAgICAgICAgICAgICB2YXIgaGFuZGxlID0gZW12YWxfZnJlZV9saXN0Lmxlbmd0aCA/IGVtdmFsX2ZyZWVfbGlzdC5wb3AoKSA6IGVtdmFsX2hhbmRsZV9hcnJheS5sZW5ndGg7CiAgICAgICAgICAgICAgICBlbXZhbF9oYW5kbGVfYXJyYXlbaGFuZGxlXSA9IHsgcmVmY291bnQ6IDEsIHZhbHVlIH07CiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfZW12YWwocmF3VHlwZSwgbmFtZSkgewogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsgbmFtZSwgImZyb21XaXJlVHlwZSI6IGZ1bmN0aW9uKGhhbmRsZSkgewogICAgICAgICAgICAgIHZhciBydiA9IGVtdmFsX2hhbmRsZV9hcnJheVtoYW5kbGVdLnZhbHVlOwogICAgICAgICAgICAgIF9fZW12YWxfZGVjcmVmKGhhbmRsZSk7CiAgICAgICAgICAgICAgcmV0dXJuIHJ2OwogICAgICAgICAgICB9LCAidG9XaXJlVHlwZSI6IGZ1bmN0aW9uKGRlc3RydWN0b3JzLCB2YWx1ZSkgewogICAgICAgICAgICAgIHJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKHZhbHVlKTsKICAgICAgICAgICAgfSwgImFyZ1BhY2tBZHZhbmNlIjogOCwgInJlYWRWYWx1ZUZyb21Qb2ludGVyIjogc2ltcGxlUmVhZFZhbHVlRnJvbVBvaW50ZXIsIGRlc3RydWN0b3JGdW5jdGlvbjogbnVsbCB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGVudW1SZWFkVmFsdWVGcm9tUG9pbnRlcihuYW1lLCBzaGlmdCwgc2lnbmVkKSB7CiAgICAgICAgICAgIHN3aXRjaCAoc2hpZnQpIHsKICAgICAgICAgICAgICBjYXNlIDA6CiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24ocG9pbnRlcikgewogICAgICAgICAgICAgICAgICB2YXIgaGVhcCA9IHNpZ25lZCA/IEhFQVA4IDogSEVBUFU4OwogICAgICAgICAgICAgICAgICByZXR1cm4gdGhpc1siZnJvbVdpcmVUeXBlIl0oaGVhcFtwb2ludGVyXSk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGNhc2UgMToKICAgICAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICAgIHZhciBoZWFwID0gc2lnbmVkID8gSEVBUDE2IDogSEVBUFUxNjsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXNbImZyb21XaXJlVHlwZSJdKGhlYXBbcG9pbnRlciA+PiAxXSk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGNhc2UgMjoKICAgICAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICAgIHZhciBoZWFwID0gc2lnbmVkID8gSEVBUDMyIDogSEVBUFUzMjsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXNbImZyb21XaXJlVHlwZSJdKGhlYXBbcG9pbnRlciA+PiAyXSk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIGludGVnZXIgdHlwZTogIiArIG5hbWUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9lbnVtKHJhd1R5cGUsIG5hbWUsIHNpemUsIGlzU2lnbmVkKSB7CiAgICAgICAgICAgIHZhciBzaGlmdCA9IGdldFNoaWZ0RnJvbVNpemUoc2l6ZSk7CiAgICAgICAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICAgICAgICBmdW5jdGlvbiBjdG9yKCkgewogICAgICAgICAgICB9CiAgICAgICAgICAgIGN0b3IudmFsdWVzID0ge307CiAgICAgICAgICAgIHJlZ2lzdGVyVHlwZShyYXdUeXBlLCB7IG5hbWUsIGNvbnN0cnVjdG9yOiBjdG9yLCAiZnJvbVdpcmVUeXBlIjogZnVuY3Rpb24oYzIpIHsKICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci52YWx1ZXNbYzJdOwogICAgICAgICAgICB9LCAidG9XaXJlVHlwZSI6IGZ1bmN0aW9uKGRlc3RydWN0b3JzLCBjMikgewogICAgICAgICAgICAgIHJldHVybiBjMi52YWx1ZTsKICAgICAgICAgICAgfSwgImFyZ1BhY2tBZHZhbmNlIjogOCwgInJlYWRWYWx1ZUZyb21Qb2ludGVyIjogZW51bVJlYWRWYWx1ZUZyb21Qb2ludGVyKG5hbWUsIHNoaWZ0LCBpc1NpZ25lZCksIGRlc3RydWN0b3JGdW5jdGlvbjogbnVsbCB9KTsKICAgICAgICAgICAgZXhwb3NlUHVibGljU3ltYm9sKG5hbWUsIGN0b3IpOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gcmVxdWlyZVJlZ2lzdGVyZWRUeXBlKHJhd1R5cGUsIGh1bWFuTmFtZSkgewogICAgICAgICAgICB2YXIgaW1wbCA9IHJlZ2lzdGVyZWRUeXBlc1tyYXdUeXBlXTsKICAgICAgICAgICAgaWYgKHZvaWQgMCA9PT0gaW1wbCkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKGh1bWFuTmFtZSArICIgaGFzIHVua25vd24gdHlwZSAiICsgZ2V0VHlwZU5hbWUocmF3VHlwZSkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBpbXBsOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfZW51bV92YWx1ZShyYXdFbnVtVHlwZSwgbmFtZSwgZW51bVZhbHVlKSB7CiAgICAgICAgICAgIHZhciBlbnVtVHlwZSA9IHJlcXVpcmVSZWdpc3RlcmVkVHlwZShyYXdFbnVtVHlwZSwgImVudW0iKTsKICAgICAgICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgICAgICAgIHZhciBFbnVtID0gZW51bVR5cGUuY29uc3RydWN0b3I7CiAgICAgICAgICAgIHZhciBWYWx1ZSA9IE9iamVjdC5jcmVhdGUoZW51bVR5cGUuY29uc3RydWN0b3IucHJvdG90eXBlLCB7IHZhbHVlOiB7IHZhbHVlOiBlbnVtVmFsdWUgfSwgY29uc3RydWN0b3I6IHsgdmFsdWU6IGNyZWF0ZU5hbWVkRnVuY3Rpb24oZW51bVR5cGUubmFtZSArICJfIiArIG5hbWUsIGZ1bmN0aW9uKCkgewogICAgICAgICAgICB9KSB9IH0pOwogICAgICAgICAgICBFbnVtLnZhbHVlc1tlbnVtVmFsdWVdID0gVmFsdWU7CiAgICAgICAgICAgIEVudW1bbmFtZV0gPSBWYWx1ZTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9lbWJpbmRfcmVwcih2NCkgewogICAgICAgICAgICBpZiAodjQgPT09IG51bGwpIHsKICAgICAgICAgICAgICByZXR1cm4gIm51bGwiOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciB0MiA9IHR5cGVvZiB2NDsKICAgICAgICAgICAgaWYgKHQyID09PSAib2JqZWN0IiB8fCB0MiA9PT0gImFycmF5IiB8fCB0MiA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgICAgIHJldHVybiB2NC50b1N0cmluZygpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHJldHVybiAiIiArIHY0OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBmbG9hdFJlYWRWYWx1ZUZyb21Qb2ludGVyKG5hbWUsIHNoaWZ0KSB7CiAgICAgICAgICAgIHN3aXRjaCAoc2hpZnQpIHsKICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24ocG9pbnRlcikgewogICAgICAgICAgICAgICAgICByZXR1cm4gdGhpc1siZnJvbVdpcmVUeXBlIl0oSEVBUEYzMltwb2ludGVyID4+IDJdKTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgY2FzZSAzOgogICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXNbImZyb21XaXJlVHlwZSJdKEhFQVBGNjRbcG9pbnRlciA+PiAzXSk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIGZsb2F0IHR5cGU6ICIgKyBuYW1lKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfZmxvYXQocmF3VHlwZSwgbmFtZSwgc2l6ZSkgewogICAgICAgICAgICB2YXIgc2hpZnQgPSBnZXRTaGlmdEZyb21TaXplKHNpemUpOwogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsgbmFtZSwgImZyb21XaXJlVHlwZSI6IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgICAgICB9LCAidG9XaXJlVHlwZSI6IGZ1bmN0aW9uKGRlc3RydWN0b3JzLCB2YWx1ZSkgewogICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICJudW1iZXIiICYmIHR5cGVvZiB2YWx1ZSAhPT0gImJvb2xlYW4iKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY29udmVydCAiJyArIF9lbWJpbmRfcmVwcih2YWx1ZSkgKyAnIiB0byAnICsgdGhpcy5uYW1lKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlOwogICAgICAgICAgICB9LCAiYXJnUGFja0FkdmFuY2UiOiA4LCAicmVhZFZhbHVlRnJvbVBvaW50ZXIiOiBmbG9hdFJlYWRWYWx1ZUZyb21Qb2ludGVyKG5hbWUsIHNoaWZ0KSwgZGVzdHJ1Y3RvckZ1bmN0aW9uOiBudWxsIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfZnVuY3Rpb24obmFtZSwgYXJnQ291bnQsIHJhd0FyZ1R5cGVzQWRkciwgc2lnbmF0dXJlLCByYXdJbnZva2VyLCBmbikgewogICAgICAgICAgICB2YXIgYXJnVHlwZXMgPSBoZWFwMzJWZWN0b3JUb0FycmF5KGFyZ0NvdW50LCByYXdBcmdUeXBlc0FkZHIpOwogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgcmF3SW52b2tlciA9IGVtYmluZF9fcmVxdWlyZUZ1bmN0aW9uKHNpZ25hdHVyZSwgcmF3SW52b2tlcik7CiAgICAgICAgICAgIGV4cG9zZVB1YmxpY1N5bWJvbChuYW1lLCBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICB0aHJvd1VuYm91bmRUeXBlRXJyb3IoIkNhbm5vdCBjYWxsICIgKyBuYW1lICsgIiBkdWUgdG8gdW5ib3VuZCB0eXBlcyIsIGFyZ1R5cGVzKTsKICAgICAgICAgICAgfSwgYXJnQ291bnQgLSAxKTsKICAgICAgICAgICAgd2hlbkRlcGVuZGVudFR5cGVzQXJlUmVzb2x2ZWQoW10sIGFyZ1R5cGVzLCBmdW5jdGlvbihhcmdUeXBlczIpIHsKICAgICAgICAgICAgICB2YXIgaW52b2tlckFyZ3NBcnJheSA9IFthcmdUeXBlczJbMF0sIG51bGxdLmNvbmNhdChhcmdUeXBlczIuc2xpY2UoMSkpOwogICAgICAgICAgICAgIHJlcGxhY2VQdWJsaWNTeW1ib2wobmFtZSwgY3JhZnRJbnZva2VyRnVuY3Rpb24obmFtZSwgaW52b2tlckFyZ3NBcnJheSwgbnVsbCwgcmF3SW52b2tlciwgZm4pLCBhcmdDb3VudCAtIDEpOwogICAgICAgICAgICAgIHJldHVybiBbXTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBpbnRlZ2VyUmVhZFZhbHVlRnJvbVBvaW50ZXIobmFtZSwgc2hpZnQsIHNpZ25lZCkgewogICAgICAgICAgICBzd2l0Y2ggKHNoaWZ0KSB7CiAgICAgICAgICAgICAgY2FzZSAwOgogICAgICAgICAgICAgICAgcmV0dXJuIHNpZ25lZCA/IGZ1bmN0aW9uIHJlYWRTOEZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIEhFQVA4W3BvaW50ZXJdOwogICAgICAgICAgICAgICAgfSA6IGZ1bmN0aW9uIHJlYWRVOEZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIEhFQVBVOFtwb2ludGVyXTsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgY2FzZSAxOgogICAgICAgICAgICAgICAgcmV0dXJuIHNpZ25lZCA/IGZ1bmN0aW9uIHJlYWRTMTZGcm9tUG9pbnRlcihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiBIRUFQMTZbcG9pbnRlciA+PiAxXTsKICAgICAgICAgICAgICAgIH0gOiBmdW5jdGlvbiByZWFkVTE2RnJvbVBvaW50ZXIocG9pbnRlcikgewogICAgICAgICAgICAgICAgICByZXR1cm4gSEVBUFUxNltwb2ludGVyID4+IDFdOwogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgICBjYXNlIDI6CiAgICAgICAgICAgICAgICByZXR1cm4gc2lnbmVkID8gZnVuY3Rpb24gcmVhZFMzMkZyb21Qb2ludGVyKHBvaW50ZXIpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIEhFQVAzMltwb2ludGVyID4+IDJdOwogICAgICAgICAgICAgICAgfSA6IGZ1bmN0aW9uIHJlYWRVMzJGcm9tUG9pbnRlcihwb2ludGVyKSB7CiAgICAgICAgICAgICAgICAgIHJldHVybiBIRUFQVTMyW3BvaW50ZXIgPj4gMl07CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIGRlZmF1bHQ6CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCJVbmtub3duIGludGVnZXIgdHlwZTogIiArIG5hbWUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9pbnRlZ2VyKHByaW1pdGl2ZVR5cGUsIG5hbWUsIHNpemUsIG1pblJhbmdlLCBtYXhSYW5nZSkgewogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgaWYgKG1heFJhbmdlID09PSAtMSkgewogICAgICAgICAgICAgIG1heFJhbmdlID0gNDI5NDk2NzI5NTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgc2hpZnQgPSBnZXRTaGlmdEZyb21TaXplKHNpemUpOwogICAgICAgICAgICB2YXIgZnJvbVdpcmVUeXBlID0gZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7CiAgICAgICAgICAgIH07CiAgICAgICAgICAgIGlmIChtaW5SYW5nZSA9PT0gMCkgewogICAgICAgICAgICAgIHZhciBiaXRzaGlmdCA9IDMyIC0gOCAqIHNpemU7CiAgICAgICAgICAgICAgZnJvbVdpcmVUeXBlID0gZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZSA8PCBiaXRzaGlmdCA+Pj4gYml0c2hpZnQ7CiAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgaXNVbnNpZ25lZFR5cGUgPSBuYW1lLmluZGV4T2YoInVuc2lnbmVkIikgIT0gLTE7CiAgICAgICAgICAgIHJlZ2lzdGVyVHlwZShwcmltaXRpdmVUeXBlLCB7IG5hbWUsICJmcm9tV2lyZVR5cGUiOiBmcm9tV2lyZVR5cGUsICJ0b1dpcmVUeXBlIjogZnVuY3Rpb24oZGVzdHJ1Y3RvcnMsIHZhbHVlKSB7CiAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gIm51bWJlciIgJiYgdHlwZW9mIHZhbHVlICE9PSAiYm9vbGVhbiIpIHsKICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0ICInICsgX2VtYmluZF9yZXByKHZhbHVlKSArICciIHRvICcgKyB0aGlzLm5hbWUpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBpZiAodmFsdWUgPCBtaW5SYW5nZSB8fCB2YWx1ZSA+IG1heFJhbmdlKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQYXNzaW5nIGEgbnVtYmVyICInICsgX2VtYmluZF9yZXByKHZhbHVlKSArICciIGZyb20gSlMgc2lkZSB0byBDL0MrKyBzaWRlIHRvIGFuIGFyZ3VtZW50IG9mIHR5cGUgIicgKyBuYW1lICsgJyIsIHdoaWNoIGlzIG91dHNpZGUgdGhlIHZhbGlkIHJhbmdlIFsnICsgbWluUmFuZ2UgKyAiLCAiICsgbWF4UmFuZ2UgKyAiXSEiKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIGlzVW5zaWduZWRUeXBlID8gdmFsdWUgPj4+IDAgOiB2YWx1ZSB8IDA7CiAgICAgICAgICAgIH0sICJhcmdQYWNrQWR2YW5jZSI6IDgsICJyZWFkVmFsdWVGcm9tUG9pbnRlciI6IGludGVnZXJSZWFkVmFsdWVGcm9tUG9pbnRlcihuYW1lLCBzaGlmdCwgbWluUmFuZ2UgIT09IDApLCBkZXN0cnVjdG9yRnVuY3Rpb246IG51bGwgfSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl9tZW1vcnlfdmlldyhyYXdUeXBlLCBkYXRhVHlwZUluZGV4LCBuYW1lKSB7CiAgICAgICAgICAgIHZhciB0eXBlTWFwcGluZyA9IFtJbnQ4QXJyYXksIFVpbnQ4QXJyYXksIEludDE2QXJyYXksIFVpbnQxNkFycmF5LCBJbnQzMkFycmF5LCBVaW50MzJBcnJheSwgRmxvYXQzMkFycmF5LCBGbG9hdDY0QXJyYXldOwogICAgICAgICAgICB2YXIgVEEgPSB0eXBlTWFwcGluZ1tkYXRhVHlwZUluZGV4XTsKICAgICAgICAgICAgZnVuY3Rpb24gZGVjb2RlTWVtb3J5VmlldyhoYW5kbGUpIHsKICAgICAgICAgICAgICBoYW5kbGUgPSBoYW5kbGUgPj4gMjsKICAgICAgICAgICAgICB2YXIgaGVhcCA9IEhFQVBVMzI7CiAgICAgICAgICAgICAgdmFyIHNpemUgPSBoZWFwW2hhbmRsZV07CiAgICAgICAgICAgICAgdmFyIGRhdGEgPSBoZWFwW2hhbmRsZSArIDFdOwogICAgICAgICAgICAgIHJldHVybiBuZXcgVEEoYnVmZmVyLCBkYXRhLCBzaXplKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBuYW1lID0gcmVhZExhdGluMVN0cmluZyhuYW1lKTsKICAgICAgICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsgbmFtZSwgImZyb21XaXJlVHlwZSI6IGRlY29kZU1lbW9yeVZpZXcsICJhcmdQYWNrQWR2YW5jZSI6IDgsICJyZWFkVmFsdWVGcm9tUG9pbnRlciI6IGRlY29kZU1lbW9yeVZpZXcgfSwgeyBpZ25vcmVEdXBsaWNhdGVSZWdpc3RyYXRpb25zOiB0cnVlIH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfc3RkX3N0cmluZyhyYXdUeXBlLCBuYW1lKSB7CiAgICAgICAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICAgICAgICB2YXIgc3RkU3RyaW5nSXNVVEY4ID0gbmFtZSA9PT0gInN0ZDo6c3RyaW5nIjsKICAgICAgICAgICAgcmVnaXN0ZXJUeXBlKHJhd1R5cGUsIHsgbmFtZSwgImZyb21XaXJlVHlwZSI6IGZ1bmN0aW9uKHZhbHVlKSB7CiAgICAgICAgICAgICAgdmFyIGxlbmd0aCA9IEhFQVBVMzJbdmFsdWUgPj4gMl07CiAgICAgICAgICAgICAgdmFyIHN0cjsKICAgICAgICAgICAgICBpZiAoc3RkU3RyaW5nSXNVVEY4KSB7CiAgICAgICAgICAgICAgICB2YXIgZGVjb2RlU3RhcnRQdHIgPSB2YWx1ZSArIDQ7CiAgICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDw9IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgICAgICB2YXIgY3VycmVudEJ5dGVQdHIgPSB2YWx1ZSArIDQgKyBpMjsKICAgICAgICAgICAgICAgICAgaWYgKGkyID09IGxlbmd0aCB8fCBIRUFQVThbY3VycmVudEJ5dGVQdHJdID09IDApIHsKICAgICAgICAgICAgICAgICAgICB2YXIgbWF4UmVhZCA9IGN1cnJlbnRCeXRlUHRyIC0gZGVjb2RlU3RhcnRQdHI7CiAgICAgICAgICAgICAgICAgICAgdmFyIHN0cmluZ1NlZ21lbnQgPSBVVEY4VG9TdHJpbmcoZGVjb2RlU3RhcnRQdHIsIG1heFJlYWQpOwogICAgICAgICAgICAgICAgICAgIGlmIChzdHIgPT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgICAgICAgc3RyID0gc3RyaW5nU2VnbWVudDsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7CiAgICAgICAgICAgICAgICAgICAgICBzdHIgKz0gc3RyaW5nU2VnbWVudDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZGVjb2RlU3RhcnRQdHIgPSBjdXJyZW50Qnl0ZVB0ciArIDE7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgdmFyIGE0ID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgICAgIGE0W2kyXSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoSEVBUFU4W3ZhbHVlICsgNCArIGkyXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBzdHIgPSBhNC5qb2luKCIiKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgX2ZyZWUodmFsdWUpOwogICAgICAgICAgICAgIHJldHVybiBzdHI7CiAgICAgICAgICAgIH0sICJ0b1dpcmVUeXBlIjogZnVuY3Rpb24oZGVzdHJ1Y3RvcnMsIHZhbHVlKSB7CiAgICAgICAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHsKICAgICAgICAgICAgICAgIHZhbHVlID0gbmV3IFVpbnQ4QXJyYXkodmFsdWUpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB2YXIgZ2V0TGVuZ3RoOwogICAgICAgICAgICAgIHZhciB2YWx1ZUlzT2ZUeXBlU3RyaW5nID0gdHlwZW9mIHZhbHVlID09PSAic3RyaW5nIjsKICAgICAgICAgICAgICBpZiAoISh2YWx1ZUlzT2ZUeXBlU3RyaW5nIHx8IHZhbHVlIGluc3RhbmNlb2YgVWludDhBcnJheSB8fCB2YWx1ZSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5IHx8IHZhbHVlIGluc3RhbmNlb2YgSW50OEFycmF5KSkgewogICAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoIkNhbm5vdCBwYXNzIG5vbi1zdHJpbmcgdG8gc3RkOjpzdHJpbmciKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKHN0ZFN0cmluZ0lzVVRGOCAmJiB2YWx1ZUlzT2ZUeXBlU3RyaW5nKSB7CiAgICAgICAgICAgICAgICBnZXRMZW5ndGggPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIGxlbmd0aEJ5dGVzVVRGOCh2YWx1ZSk7CiAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBnZXRMZW5ndGggPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLmxlbmd0aDsKICAgICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHZhciBsZW5ndGggPSBnZXRMZW5ndGgoKTsKICAgICAgICAgICAgICB2YXIgcHRyID0gX21hbGxvYyg0ICsgbGVuZ3RoICsgMSk7CiAgICAgICAgICAgICAgSEVBUFUzMltwdHIgPj4gMl0gPSBsZW5ndGg7CiAgICAgICAgICAgICAgaWYgKHN0ZFN0cmluZ0lzVVRGOCAmJiB2YWx1ZUlzT2ZUeXBlU3RyaW5nKSB7CiAgICAgICAgICAgICAgICBzdHJpbmdUb1VURjgodmFsdWUsIHB0ciArIDQsIGxlbmd0aCArIDEpOwogICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBpZiAodmFsdWVJc09mVHlwZVN0cmluZykgewogICAgICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgICAgICAgdmFyIGNoYXJDb2RlID0gdmFsdWUuY2hhckNvZGVBdChpMik7CiAgICAgICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlID4gMjU1KSB7CiAgICAgICAgICAgICAgICAgICAgICBfZnJlZShwdHIpOwogICAgICAgICAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoIlN0cmluZyBoYXMgVVRGLTE2IGNvZGUgdW5pdHMgdGhhdCBkbyBub3QgZml0IGluIDggYml0cyIpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBIRUFQVThbcHRyICsgNCArIGkyXSA9IGNoYXJDb2RlOwogICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgbGVuZ3RoOyArK2kyKSB7CiAgICAgICAgICAgICAgICAgICAgSEVBUFU4W3B0ciArIDQgKyBpMl0gPSB2YWx1ZVtpMl07CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgaWYgKGRlc3RydWN0b3JzICE9PSBudWxsKSB7CiAgICAgICAgICAgICAgICBkZXN0cnVjdG9ycy5wdXNoKF9mcmVlLCBwdHIpOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICByZXR1cm4gcHRyOwogICAgICAgICAgICB9LCAiYXJnUGFja0FkdmFuY2UiOiA4LCAicmVhZFZhbHVlRnJvbVBvaW50ZXIiOiBzaW1wbGVSZWFkVmFsdWVGcm9tUG9pbnRlciwgZGVzdHJ1Y3RvckZ1bmN0aW9uOiBmdW5jdGlvbihwdHIpIHsKICAgICAgICAgICAgICBfZnJlZShwdHIpOwogICAgICAgICAgICB9IH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfc3RkX3dzdHJpbmcocmF3VHlwZSwgY2hhclNpemUsIG5hbWUpIHsKICAgICAgICAgICAgbmFtZSA9IHJlYWRMYXRpbjFTdHJpbmcobmFtZSk7CiAgICAgICAgICAgIHZhciBkZWNvZGVTdHJpbmcsIGVuY29kZVN0cmluZywgZ2V0SGVhcCwgbGVuZ3RoQnl0ZXNVVEYsIHNoaWZ0OwogICAgICAgICAgICBpZiAoY2hhclNpemUgPT09IDIpIHsKICAgICAgICAgICAgICBkZWNvZGVTdHJpbmcgPSBVVEYxNlRvU3RyaW5nOwogICAgICAgICAgICAgIGVuY29kZVN0cmluZyA9IHN0cmluZ1RvVVRGMTY7CiAgICAgICAgICAgICAgbGVuZ3RoQnl0ZXNVVEYgPSBsZW5ndGhCeXRlc1VURjE2OwogICAgICAgICAgICAgIGdldEhlYXAgPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgIHJldHVybiBIRUFQVTE2OwogICAgICAgICAgICAgIH07CiAgICAgICAgICAgICAgc2hpZnQgPSAxOwogICAgICAgICAgICB9IGVsc2UgaWYgKGNoYXJTaXplID09PSA0KSB7CiAgICAgICAgICAgICAgZGVjb2RlU3RyaW5nID0gVVRGMzJUb1N0cmluZzsKICAgICAgICAgICAgICBlbmNvZGVTdHJpbmcgPSBzdHJpbmdUb1VURjMyOwogICAgICAgICAgICAgIGxlbmd0aEJ5dGVzVVRGID0gbGVuZ3RoQnl0ZXNVVEYzMjsKICAgICAgICAgICAgICBnZXRIZWFwID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gSEVBUFUzMjsKICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgIHNoaWZ0ID0gMjsKICAgICAgICAgICAgfQogICAgICAgICAgICByZWdpc3RlclR5cGUocmF3VHlwZSwgeyBuYW1lLCAiZnJvbVdpcmVUeXBlIjogZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgICAgICB2YXIgbGVuZ3RoID0gSEVBUFUzMlt2YWx1ZSA+PiAyXTsKICAgICAgICAgICAgICB2YXIgSEVBUCA9IGdldEhlYXAoKTsKICAgICAgICAgICAgICB2YXIgc3RyOwogICAgICAgICAgICAgIHZhciBkZWNvZGVTdGFydFB0ciA9IHZhbHVlICsgNDsKICAgICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDw9IGxlbmd0aDsgKytpMikgewogICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRCeXRlUHRyID0gdmFsdWUgKyA0ICsgaTIgKiBjaGFyU2l6ZTsKICAgICAgICAgICAgICAgIGlmIChpMiA9PSBsZW5ndGggfHwgSEVBUFtjdXJyZW50Qnl0ZVB0ciA+PiBzaGlmdF0gPT0gMCkgewogICAgICAgICAgICAgICAgICB2YXIgbWF4UmVhZEJ5dGVzID0gY3VycmVudEJ5dGVQdHIgLSBkZWNvZGVTdGFydFB0cjsKICAgICAgICAgICAgICAgICAgdmFyIHN0cmluZ1NlZ21lbnQgPSBkZWNvZGVTdHJpbmcoZGVjb2RlU3RhcnRQdHIsIG1heFJlYWRCeXRlcyk7CiAgICAgICAgICAgICAgICAgIGlmIChzdHIgPT09IHZvaWQgMCkgewogICAgICAgICAgICAgICAgICAgIHN0ciA9IHN0cmluZ1NlZ21lbnQ7CiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7CiAgICAgICAgICAgICAgICAgICAgc3RyICs9IHN0cmluZ1NlZ21lbnQ7CiAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgZGVjb2RlU3RhcnRQdHIgPSBjdXJyZW50Qnl0ZVB0ciArIGNoYXJTaXplOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgICBfZnJlZSh2YWx1ZSk7CiAgICAgICAgICAgICAgcmV0dXJuIHN0cjsKICAgICAgICAgICAgfSwgInRvV2lyZVR5cGUiOiBmdW5jdGlvbihkZXN0cnVjdG9ycywgdmFsdWUpIHsKICAgICAgICAgICAgICBpZiAoISh0eXBlb2YgdmFsdWUgPT09ICJzdHJpbmciKSkgewogICAgICAgICAgICAgICAgdGhyb3dCaW5kaW5nRXJyb3IoIkNhbm5vdCBwYXNzIG5vbi1zdHJpbmcgdG8gQysrIHN0cmluZyB0eXBlICIgKyBuYW1lKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgdmFyIGxlbmd0aCA9IGxlbmd0aEJ5dGVzVVRGKHZhbHVlKTsKICAgICAgICAgICAgICB2YXIgcHRyID0gX21hbGxvYyg0ICsgbGVuZ3RoICsgY2hhclNpemUpOwogICAgICAgICAgICAgIEhFQVBVMzJbcHRyID4+IDJdID0gbGVuZ3RoID4+IHNoaWZ0OwogICAgICAgICAgICAgIGVuY29kZVN0cmluZyh2YWx1ZSwgcHRyICsgNCwgbGVuZ3RoICsgY2hhclNpemUpOwogICAgICAgICAgICAgIGlmIChkZXN0cnVjdG9ycyAhPT0gbnVsbCkgewogICAgICAgICAgICAgICAgZGVzdHJ1Y3RvcnMucHVzaChfZnJlZSwgcHRyKTsKICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgcmV0dXJuIHB0cjsKICAgICAgICAgICAgfSwgImFyZ1BhY2tBZHZhbmNlIjogOCwgInJlYWRWYWx1ZUZyb21Qb2ludGVyIjogc2ltcGxlUmVhZFZhbHVlRnJvbVBvaW50ZXIsIGRlc3RydWN0b3JGdW5jdGlvbjogZnVuY3Rpb24ocHRyKSB7CiAgICAgICAgICAgICAgX2ZyZWUocHRyKTsKICAgICAgICAgICAgfSB9KTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW1iaW5kX3JlZ2lzdGVyX3ZhbHVlX29iamVjdChyYXdUeXBlLCBuYW1lLCBjb25zdHJ1Y3RvclNpZ25hdHVyZSwgcmF3Q29uc3RydWN0b3IsIGRlc3RydWN0b3JTaWduYXR1cmUsIHJhd0Rlc3RydWN0b3IpIHsKICAgICAgICAgICAgc3RydWN0UmVnaXN0cmF0aW9uc1tyYXdUeXBlXSA9IHsgbmFtZTogcmVhZExhdGluMVN0cmluZyhuYW1lKSwgcmF3Q29uc3RydWN0b3I6IGVtYmluZF9fcmVxdWlyZUZ1bmN0aW9uKGNvbnN0cnVjdG9yU2lnbmF0dXJlLCByYXdDb25zdHJ1Y3RvciksIHJhd0Rlc3RydWN0b3I6IGVtYmluZF9fcmVxdWlyZUZ1bmN0aW9uKGRlc3RydWN0b3JTaWduYXR1cmUsIHJhd0Rlc3RydWN0b3IpLCBmaWVsZHM6IFtdIH07CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3RfZmllbGQoc3RydWN0VHlwZSwgZmllbGROYW1lLCBnZXR0ZXJSZXR1cm5UeXBlLCBnZXR0ZXJTaWduYXR1cmUsIGdldHRlciwgZ2V0dGVyQ29udGV4dCwgc2V0dGVyQXJndW1lbnRUeXBlLCBzZXR0ZXJTaWduYXR1cmUsIHNldHRlciwgc2V0dGVyQ29udGV4dCkgewogICAgICAgICAgICBzdHJ1Y3RSZWdpc3RyYXRpb25zW3N0cnVjdFR5cGVdLmZpZWxkcy5wdXNoKHsgZmllbGROYW1lOiByZWFkTGF0aW4xU3RyaW5nKGZpZWxkTmFtZSksIGdldHRlclJldHVyblR5cGUsIGdldHRlcjogZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oZ2V0dGVyU2lnbmF0dXJlLCBnZXR0ZXIpLCBnZXR0ZXJDb250ZXh0LCBzZXR0ZXJBcmd1bWVudFR5cGUsIHNldHRlcjogZW1iaW5kX19yZXF1aXJlRnVuY3Rpb24oc2V0dGVyU2lnbmF0dXJlLCBzZXR0ZXIpLCBzZXR0ZXJDb250ZXh0IH0pOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbWJpbmRfcmVnaXN0ZXJfdm9pZChyYXdUeXBlLCBuYW1lKSB7CiAgICAgICAgICAgIG5hbWUgPSByZWFkTGF0aW4xU3RyaW5nKG5hbWUpOwogICAgICAgICAgICByZWdpc3RlclR5cGUocmF3VHlwZSwgeyBpc1ZvaWQ6IHRydWUsIG5hbWUsICJhcmdQYWNrQWR2YW5jZSI6IDAsICJmcm9tV2lyZVR5cGUiOiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgICByZXR1cm4gdm9pZCAwOwogICAgICAgICAgICB9LCAidG9XaXJlVHlwZSI6IGZ1bmN0aW9uKGRlc3RydWN0b3JzLCBvMikgewogICAgICAgICAgICAgIHJldHVybiB2b2lkIDA7CiAgICAgICAgICAgIH0gfSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiByZXF1aXJlSGFuZGxlKGhhbmRsZSkgewogICAgICAgICAgICBpZiAoIWhhbmRsZSkgewogICAgICAgICAgICAgIHRocm93QmluZGluZ0Vycm9yKCJDYW5ub3QgdXNlIGRlbGV0ZWQgdmFsLiBoYW5kbGUgPSAiICsgaGFuZGxlKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZW12YWxfaGFuZGxlX2FycmF5W2hhbmRsZV0udmFsdWU7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtdmFsX2FzKGhhbmRsZSwgcmV0dXJuVHlwZSwgZGVzdHJ1Y3RvcnNSZWYpIHsKICAgICAgICAgICAgaGFuZGxlID0gcmVxdWlyZUhhbmRsZShoYW5kbGUpOwogICAgICAgICAgICByZXR1cm5UeXBlID0gcmVxdWlyZVJlZ2lzdGVyZWRUeXBlKHJldHVyblR5cGUsICJlbXZhbDo6YXMiKTsKICAgICAgICAgICAgdmFyIGRlc3RydWN0b3JzID0gW107CiAgICAgICAgICAgIHZhciByZCA9IF9fZW12YWxfcmVnaXN0ZXIoZGVzdHJ1Y3RvcnMpOwogICAgICAgICAgICBIRUFQMzJbZGVzdHJ1Y3RvcnNSZWYgPj4gMl0gPSByZDsKICAgICAgICAgICAgcmV0dXJuIHJldHVyblR5cGVbInRvV2lyZVR5cGUiXShkZXN0cnVjdG9ycywgaGFuZGxlKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBlbXZhbF9zeW1ib2xzID0ge307CiAgICAgICAgICBmdW5jdGlvbiBnZXRTdHJpbmdPclN5bWJvbChhZGRyZXNzKSB7CiAgICAgICAgICAgIHZhciBzeW1ib2wgPSBlbXZhbF9zeW1ib2xzW2FkZHJlc3NdOwogICAgICAgICAgICBpZiAoc3ltYm9sID09PSB2b2lkIDApIHsKICAgICAgICAgICAgICByZXR1cm4gcmVhZExhdGluMVN0cmluZyhhZGRyZXNzKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICByZXR1cm4gc3ltYm9sOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgICB2YXIgZW12YWxfbWV0aG9kQ2FsbGVycyA9IFtdOwogICAgICAgICAgZnVuY3Rpb24gX19lbXZhbF9jYWxsX3ZvaWRfbWV0aG9kKGNhbGxlciwgaGFuZGxlLCBtZXRob2ROYW1lLCBhcmdzKSB7CiAgICAgICAgICAgIGNhbGxlciA9IGVtdmFsX21ldGhvZENhbGxlcnNbY2FsbGVyXTsKICAgICAgICAgICAgaGFuZGxlID0gcmVxdWlyZUhhbmRsZShoYW5kbGUpOwogICAgICAgICAgICBtZXRob2ROYW1lID0gZ2V0U3RyaW5nT3JTeW1ib2wobWV0aG9kTmFtZSk7CiAgICAgICAgICAgIGNhbGxlcihoYW5kbGUsIG1ldGhvZE5hbWUsIG51bGwsIGFyZ3MpOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gZW12YWxfZ2V0X2dsb2JhbCgpIHsKICAgICAgICAgICAgaWYgKHR5cGVvZiBnbG9iYWxUaGlzID09PSAib2JqZWN0IikgewogICAgICAgICAgICAgIHJldHVybiBnbG9iYWxUaGlzOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiAoLyogQF9fUFVSRV9fICovIChmdW5jdGlvbigpIHsKICAgICAgICAgICAgICByZXR1cm4gRnVuY3Rpb247CiAgICAgICAgICAgIH0pKCkpKCJyZXR1cm4gdGhpcyIpKCk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtdmFsX2dldF9nbG9iYWwobmFtZSkgewogICAgICAgICAgICBpZiAobmFtZSA9PT0gMCkgewogICAgICAgICAgICAgIHJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKGVtdmFsX2dldF9nbG9iYWwoKSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgbmFtZSA9IGdldFN0cmluZ09yU3ltYm9sKG5hbWUpOwogICAgICAgICAgICAgIHJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKGVtdmFsX2dldF9nbG9iYWwoKVtuYW1lXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfYWRkTWV0aG9kQ2FsbGVyKGNhbGxlcikgewogICAgICAgICAgICB2YXIgaWQgPSBlbXZhbF9tZXRob2RDYWxsZXJzLmxlbmd0aDsKICAgICAgICAgICAgZW12YWxfbWV0aG9kQ2FsbGVycy5wdXNoKGNhbGxlcik7CiAgICAgICAgICAgIHJldHVybiBpZDsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfbG9va3VwVHlwZXMoYXJnQ291bnQsIGFyZ1R5cGVzKSB7CiAgICAgICAgICAgIHZhciBhNCA9IG5ldyBBcnJheShhcmdDb3VudCk7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBhcmdDb3VudDsgKytpMikgewogICAgICAgICAgICAgIGE0W2kyXSA9IHJlcXVpcmVSZWdpc3RlcmVkVHlwZShIRUFQMzJbKGFyZ1R5cGVzID4+IDIpICsgaTJdLCAicGFyYW1ldGVyICIgKyBpMik7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGE0OwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX19lbXZhbF9nZXRfbWV0aG9kX2NhbGxlcihhcmdDb3VudCwgYXJnVHlwZXMpIHsKICAgICAgICAgICAgdmFyIHR5cGVzID0gX19lbXZhbF9sb29rdXBUeXBlcyhhcmdDb3VudCwgYXJnVHlwZXMpOwogICAgICAgICAgICB2YXIgcmV0VHlwZSA9IHR5cGVzWzBdOwogICAgICAgICAgICB2YXIgc2lnbmF0dXJlTmFtZSA9IHJldFR5cGUubmFtZSArICJfJCIgKyB0eXBlcy5zbGljZSgxKS5tYXAoZnVuY3Rpb24odDIpIHsKICAgICAgICAgICAgICByZXR1cm4gdDIubmFtZTsKICAgICAgICAgICAgfSkuam9pbigiXyIpICsgIiQiOwogICAgICAgICAgICB2YXIgcGFyYW1zID0gWyJyZXRUeXBlIl07CiAgICAgICAgICAgIHZhciBhcmdzID0gW3JldFR5cGVdOwogICAgICAgICAgICB2YXIgYXJnc0xpc3QgPSAiIjsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGFyZ0NvdW50IC0gMTsgKytpMikgewogICAgICAgICAgICAgIGFyZ3NMaXN0ICs9IChpMiAhPT0gMCA/ICIsICIgOiAiIikgKyAiYXJnIiArIGkyOwogICAgICAgICAgICAgIHBhcmFtcy5wdXNoKCJhcmdUeXBlIiArIGkyKTsKICAgICAgICAgICAgICBhcmdzLnB1c2godHlwZXNbMSArIGkyXSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgdmFyIGZ1bmN0aW9uTmFtZSA9IG1ha2VMZWdhbEZ1bmN0aW9uTmFtZSgibWV0aG9kQ2FsbGVyXyIgKyBzaWduYXR1cmVOYW1lKTsKICAgICAgICAgICAgdmFyIGZ1bmN0aW9uQm9keSA9ICJyZXR1cm4gZnVuY3Rpb24gIiArIGZ1bmN0aW9uTmFtZSArICIoaGFuZGxlLCBuYW1lLCBkZXN0cnVjdG9ycywgYXJncykge1xuIjsKICAgICAgICAgICAgdmFyIG9mZnNldCA9IDA7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBhcmdDb3VudCAtIDE7ICsraTIpIHsKICAgICAgICAgICAgICBmdW5jdGlvbkJvZHkgKz0gIiAgICB2YXIgYXJnIiArIGkyICsgIiA9IGFyZ1R5cGUiICsgaTIgKyAiLnJlYWRWYWx1ZUZyb21Qb2ludGVyKGFyZ3MiICsgKG9mZnNldCA/ICIrIiArIG9mZnNldCA6ICIiKSArICIpO1xuIjsKICAgICAgICAgICAgICBvZmZzZXQgKz0gdHlwZXNbaTIgKyAxXVsiYXJnUGFja0FkdmFuY2UiXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBmdW5jdGlvbkJvZHkgKz0gIiAgICB2YXIgcnYgPSBoYW5kbGVbbmFtZV0oIiArIGFyZ3NMaXN0ICsgIik7XG4iOwogICAgICAgICAgICBmb3IgKHZhciBpMiA9IDA7IGkyIDwgYXJnQ291bnQgLSAxOyArK2kyKSB7CiAgICAgICAgICAgICAgaWYgKHR5cGVzW2kyICsgMV1bImRlbGV0ZU9iamVjdCJdKSB7CiAgICAgICAgICAgICAgICBmdW5jdGlvbkJvZHkgKz0gIiAgICBhcmdUeXBlIiArIGkyICsgIi5kZWxldGVPYmplY3QoYXJnIiArIGkyICsgIik7XG4iOwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoIXJldFR5cGUuaXNWb2lkKSB7CiAgICAgICAgICAgICAgZnVuY3Rpb25Cb2R5ICs9ICIgICAgcmV0dXJuIHJldFR5cGUudG9XaXJlVHlwZShkZXN0cnVjdG9ycywgcnYpO1xuIjsKICAgICAgICAgICAgfQogICAgICAgICAgICBmdW5jdGlvbkJvZHkgKz0gIn07XG4iOwogICAgICAgICAgICBwYXJhbXMucHVzaChmdW5jdGlvbkJvZHkpOwogICAgICAgICAgICB2YXIgaW52b2tlckZ1bmN0aW9uID0gbmV3XyhGdW5jdGlvbiwgcGFyYW1zKS5hcHBseShudWxsLCBhcmdzKTsKICAgICAgICAgICAgcmV0dXJuIF9fZW12YWxfYWRkTWV0aG9kQ2FsbGVyKGludm9rZXJGdW5jdGlvbik7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtdmFsX2dldF9tb2R1bGVfcHJvcGVydHkobmFtZSkgewogICAgICAgICAgICBuYW1lID0gZ2V0U3RyaW5nT3JTeW1ib2wobmFtZSk7CiAgICAgICAgICAgIHJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKE1vZHVsZVtuYW1lXSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBfX2VtdmFsX2dldF9wcm9wZXJ0eShoYW5kbGUsIGtleTIpIHsKICAgICAgICAgICAgaGFuZGxlID0gcmVxdWlyZUhhbmRsZShoYW5kbGUpOwogICAgICAgICAgICBrZXkyID0gcmVxdWlyZUhhbmRsZShrZXkyKTsKICAgICAgICAgICAgcmV0dXJuIF9fZW12YWxfcmVnaXN0ZXIoaGFuZGxlW2tleTJdKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfaW5jcmVmKGhhbmRsZSkgewogICAgICAgICAgICBpZiAoaGFuZGxlID4gNCkgewogICAgICAgICAgICAgIGVtdmFsX2hhbmRsZV9hcnJheVtoYW5kbGVdLnJlZmNvdW50ICs9IDE7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIGNyYWZ0RW12YWxBbGxvY2F0b3IoYXJnQ291bnQpIHsKICAgICAgICAgICAgdmFyIGFyZ3NMaXN0ID0gIiI7CiAgICAgICAgICAgIGZvciAodmFyIGkyID0gMDsgaTIgPCBhcmdDb3VudDsgKytpMikgewogICAgICAgICAgICAgIGFyZ3NMaXN0ICs9IChpMiAhPT0gMCA/ICIsICIgOiAiIikgKyAiYXJnIiArIGkyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHZhciBmdW5jdGlvbkJvZHkgPSAicmV0dXJuIGZ1bmN0aW9uIGVtdmFsX2FsbG9jYXRvcl8iICsgYXJnQ291bnQgKyAiKGNvbnN0cnVjdG9yLCBhcmdUeXBlcywgYXJncykge1xuIjsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGFyZ0NvdW50OyArK2kyKSB7CiAgICAgICAgICAgICAgZnVuY3Rpb25Cb2R5ICs9ICJ2YXIgYXJnVHlwZSIgKyBpMiArICIgPSByZXF1aXJlUmVnaXN0ZXJlZFR5cGUoTW9kdWxlWydIRUFQMzInXVsoYXJnVHlwZXMgPj4+IDIpICsgIiArIGkyICsgJ10sICJwYXJhbWV0ZXIgJyArIGkyICsgJyIpO1xudmFyIGFyZycgKyBpMiArICIgPSBhcmdUeXBlIiArIGkyICsgIi5yZWFkVmFsdWVGcm9tUG9pbnRlcihhcmdzKTtcbmFyZ3MgKz0gYXJnVHlwZSIgKyBpMiArICJbJ2FyZ1BhY2tBZHZhbmNlJ107XG4iOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uQm9keSArPSAidmFyIG9iaiA9IG5ldyBjb25zdHJ1Y3RvcigiICsgYXJnc0xpc3QgKyAiKTtcbnJldHVybiBfX2VtdmFsX3JlZ2lzdGVyKG9iaik7XG59XG4iOwogICAgICAgICAgICByZXR1cm4gbmV3IEZ1bmN0aW9uKCJyZXF1aXJlUmVnaXN0ZXJlZFR5cGUiLCAiTW9kdWxlIiwgIl9fZW12YWxfcmVnaXN0ZXIiLCBmdW5jdGlvbkJvZHkpKHJlcXVpcmVSZWdpc3RlcmVkVHlwZSwgTW9kdWxlLCBfX2VtdmFsX3JlZ2lzdGVyKTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBlbXZhbF9uZXdlcnMgPSB7fTsKICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfbmV3KGhhbmRsZSwgYXJnQ291bnQsIGFyZ1R5cGVzLCBhcmdzKSB7CiAgICAgICAgICAgIGhhbmRsZSA9IHJlcXVpcmVIYW5kbGUoaGFuZGxlKTsKICAgICAgICAgICAgdmFyIG5ld2VyID0gZW12YWxfbmV3ZXJzW2FyZ0NvdW50XTsKICAgICAgICAgICAgaWYgKCFuZXdlcikgewogICAgICAgICAgICAgIG5ld2VyID0gY3JhZnRFbXZhbEFsbG9jYXRvcihhcmdDb3VudCk7CiAgICAgICAgICAgICAgZW12YWxfbmV3ZXJzW2FyZ0NvdW50XSA9IG5ld2VyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBuZXdlcihoYW5kbGUsIGFyZ1R5cGVzLCBhcmdzKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfbmV3X2NzdHJpbmcodjQpIHsKICAgICAgICAgICAgcmV0dXJuIF9fZW12YWxfcmVnaXN0ZXIoZ2V0U3RyaW5nT3JTeW1ib2wodjQpKTsKICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9fZW12YWxfcnVuX2Rlc3RydWN0b3JzKGhhbmRsZSkgewogICAgICAgICAgICB2YXIgZGVzdHJ1Y3RvcnMgPSBlbXZhbF9oYW5kbGVfYXJyYXlbaGFuZGxlXS52YWx1ZTsKICAgICAgICAgICAgcnVuRGVzdHJ1Y3RvcnMoZGVzdHJ1Y3RvcnMpOwogICAgICAgICAgICBfX2VtdmFsX2RlY3JlZihoYW5kbGUpOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX2Fib3J0KCkgewogICAgICAgICAgICBhYm9ydCgpOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX2Vtc2NyaXB0ZW5fbWVtY3B5X2JpZyhkZXN0LCBzcmMsIG51bSkgewogICAgICAgICAgICBIRUFQVTguY29weVdpdGhpbihkZXN0LCBzcmMsIHNyYyArIG51bSk7CiAgICAgICAgICB9CiAgICAgICAgICBmdW5jdGlvbiBlbXNjcmlwdGVuX3JlYWxsb2NfYnVmZmVyKHNpemUpIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICB3YXNtTWVtb3J5Lmdyb3coc2l6ZSAtIGJ1ZmZlci5ieXRlTGVuZ3RoICsgNjU1MzUgPj4+IDE2KTsKICAgICAgICAgICAgICB1cGRhdGVHbG9iYWxCdWZmZXJBbmRWaWV3cyh3YXNtTWVtb3J5LmJ1ZmZlcik7CiAgICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgICAgIH0gY2F0Y2ggKGUyKSB7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIGZ1bmN0aW9uIF9lbXNjcmlwdGVuX3Jlc2l6ZV9oZWFwKHJlcXVlc3RlZFNpemUpIHsKICAgICAgICAgICAgdmFyIG9sZFNpemUgPSBIRUFQVTgubGVuZ3RoOwogICAgICAgICAgICByZXF1ZXN0ZWRTaXplID0gcmVxdWVzdGVkU2l6ZSA+Pj4gMDsKICAgICAgICAgICAgdmFyIG1heEhlYXBTaXplID0gMjE0NzQ4MzY0ODsKICAgICAgICAgICAgaWYgKHJlcXVlc3RlZFNpemUgPiBtYXhIZWFwU2l6ZSkgewogICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBmb3IgKHZhciBjdXREb3duID0gMTsgY3V0RG93biA8PSA0OyBjdXREb3duICo9IDIpIHsKICAgICAgICAgICAgICB2YXIgb3Zlckdyb3duSGVhcFNpemUgPSBvbGRTaXplICogKDEgKyAwLjIgLyBjdXREb3duKTsKICAgICAgICAgICAgICBvdmVyR3Jvd25IZWFwU2l6ZSA9IE1hdGgubWluKG92ZXJHcm93bkhlYXBTaXplLCByZXF1ZXN0ZWRTaXplICsgMTAwNjYzMjk2KTsKICAgICAgICAgICAgICB2YXIgbmV3U2l6ZSA9IE1hdGgubWluKG1heEhlYXBTaXplLCBhbGlnblVwKE1hdGgubWF4KHJlcXVlc3RlZFNpemUsIG92ZXJHcm93bkhlYXBTaXplKSwgNjU1MzYpKTsKICAgICAgICAgICAgICB2YXIgcmVwbGFjZW1lbnQgPSBlbXNjcmlwdGVuX3JlYWxsb2NfYnVmZmVyKG5ld1NpemUpOwogICAgICAgICAgICAgIGlmIChyZXBsYWNlbWVudCkgewogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgIH0KICAgICAgICAgIHZhciBTWVNDQUxMUyA9IHsgbWFwcGluZ3M6IHt9LCBidWZmZXJzOiBbbnVsbCwgW10sIFtdXSwgcHJpbnRDaGFyOiBmdW5jdGlvbihzdHJlYW0sIGN1cnIpIHsKICAgICAgICAgICAgdmFyIGJ1ZmZlcjIgPSBTWVNDQUxMUy5idWZmZXJzW3N0cmVhbV07CiAgICAgICAgICAgIGlmIChjdXJyID09PSAwIHx8IGN1cnIgPT09IDEwKSB7CiAgICAgICAgICAgICAgKHN0cmVhbSA9PT0gMSA/IG91dCA6IGVycikoVVRGOEFycmF5VG9TdHJpbmcoYnVmZmVyMiwgMCkpOwogICAgICAgICAgICAgIGJ1ZmZlcjIubGVuZ3RoID0gMDsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICBidWZmZXIyLnB1c2goY3Vycik7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0sIHZhcmFyZ3M6IHZvaWQgMCwgZ2V0OiBmdW5jdGlvbigpIHsKICAgICAgICAgICAgU1lTQ0FMTFMudmFyYXJncyArPSA0OwogICAgICAgICAgICB2YXIgcmV0ID0gSEVBUDMyW1NZU0NBTExTLnZhcmFyZ3MgLSA0ID4+IDJdOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfSwgZ2V0U3RyOiBmdW5jdGlvbihwdHIpIHsKICAgICAgICAgICAgdmFyIHJldCA9IFVURjhUb1N0cmluZyhwdHIpOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgfSwgZ2V0NjQ6IGZ1bmN0aW9uKGxvdywgaGlnaCkgewogICAgICAgICAgICByZXR1cm4gbG93OwogICAgICAgICAgfSB9OwogICAgICAgICAgZnVuY3Rpb24gX2ZkX2Nsb3NlKGZkKSB7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX2ZkX3NlZWsoZmQsIG9mZnNldF9sb3csIG9mZnNldF9oaWdoLCB3aGVuY2UsIG5ld09mZnNldCkgewogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX2ZkX3dyaXRlKGZkLCBpb3YsIGlvdmNudCwgcG51bSkgewogICAgICAgICAgICB2YXIgbnVtID0gMDsKICAgICAgICAgICAgZm9yICh2YXIgaTIgPSAwOyBpMiA8IGlvdmNudDsgaTIrKykgewogICAgICAgICAgICAgIHZhciBwdHIgPSBIRUFQMzJbaW92ICsgaTIgKiA4ID4+IDJdOwogICAgICAgICAgICAgIHZhciBsZW4gPSBIRUFQMzJbaW92ICsgKGkyICogOCArIDQpID4+IDJdOwogICAgICAgICAgICAgIGZvciAodmFyIGoyID0gMDsgajIgPCBsZW47IGoyKyspIHsKICAgICAgICAgICAgICAgIFNZU0NBTExTLnByaW50Q2hhcihmZCwgSEVBUFU4W3B0ciArIGoyXSk7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIG51bSArPSBsZW47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgSEVBUDMyW3BudW0gPj4gMl0gPSBudW07CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgfQogICAgICAgICAgZnVuY3Rpb24gX3NldFRlbXBSZXQwKCRpKSB7CiAgICAgICAgICAgIHNldFRlbXBSZXQwKCRpIHwgMCk7CiAgICAgICAgICB9CiAgICAgICAgICBJbnRlcm5hbEVycm9yID0gTW9kdWxlWyJJbnRlcm5hbEVycm9yIl0gPSBleHRlbmRFcnJvcihFcnJvciwgIkludGVybmFsRXJyb3IiKTsKICAgICAgICAgIGVtYmluZF9pbml0X2NoYXJDb2RlcygpOwogICAgICAgICAgQmluZGluZ0Vycm9yID0gTW9kdWxlWyJCaW5kaW5nRXJyb3IiXSA9IGV4dGVuZEVycm9yKEVycm9yLCAiQmluZGluZ0Vycm9yIik7CiAgICAgICAgICBpbml0X0NsYXNzSGFuZGxlKCk7CiAgICAgICAgICBpbml0X1JlZ2lzdGVyZWRQb2ludGVyKCk7CiAgICAgICAgICBpbml0X2VtYmluZCgpOwogICAgICAgICAgVW5ib3VuZFR5cGVFcnJvciA9IE1vZHVsZVsiVW5ib3VuZFR5cGVFcnJvciJdID0gZXh0ZW5kRXJyb3IoRXJyb3IsICJVbmJvdW5kVHlwZUVycm9yIik7CiAgICAgICAgICBpbml0X2VtdmFsKCk7CiAgICAgICAgICB2YXIgYXNtTGlicmFyeUFyZyA9IHsgInQiOiBfX2VtYmluZF9maW5hbGl6ZV92YWx1ZV9vYmplY3QsICJJIjogX19lbWJpbmRfcmVnaXN0ZXJfYm9vbCwgIngiOiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzcywgInciOiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19jb25zdHJ1Y3RvciwgImQiOiBfX2VtYmluZF9yZWdpc3Rlcl9jbGFzc19mdW5jdGlvbiwgImsiOiBfX2VtYmluZF9yZWdpc3Rlcl9jb25zdGFudCwgIkgiOiBfX2VtYmluZF9yZWdpc3Rlcl9lbXZhbCwgIm4iOiBfX2VtYmluZF9yZWdpc3Rlcl9lbnVtLCAiYSI6IF9fZW1iaW5kX3JlZ2lzdGVyX2VudW1fdmFsdWUsICJBIjogX19lbWJpbmRfcmVnaXN0ZXJfZmxvYXQsICJpIjogX19lbWJpbmRfcmVnaXN0ZXJfZnVuY3Rpb24sICJqIjogX19lbWJpbmRfcmVnaXN0ZXJfaW50ZWdlciwgImgiOiBfX2VtYmluZF9yZWdpc3Rlcl9tZW1vcnlfdmlldywgIkIiOiBfX2VtYmluZF9yZWdpc3Rlcl9zdGRfc3RyaW5nLCAidiI6IF9fZW1iaW5kX3JlZ2lzdGVyX3N0ZF93c3RyaW5nLCAidSI6IF9fZW1iaW5kX3JlZ2lzdGVyX3ZhbHVlX29iamVjdCwgImMiOiBfX2VtYmluZF9yZWdpc3Rlcl92YWx1ZV9vYmplY3RfZmllbGQsICJKIjogX19lbWJpbmRfcmVnaXN0ZXJfdm9pZCwgIm0iOiBfX2VtdmFsX2FzLCAicyI6IF9fZW12YWxfY2FsbF92b2lkX21ldGhvZCwgImIiOiBfX2VtdmFsX2RlY3JlZiwgInkiOiBfX2VtdmFsX2dldF9nbG9iYWwsICJwIjogX19lbXZhbF9nZXRfbWV0aG9kX2NhbGxlciwgInIiOiBfX2VtdmFsX2dldF9tb2R1bGVfcHJvcGVydHksICJlIjogX19lbXZhbF9nZXRfcHJvcGVydHksICJnIjogX19lbXZhbF9pbmNyZWYsICJxIjogX19lbXZhbF9uZXcsICJmIjogX19lbXZhbF9uZXdfY3N0cmluZywgImwiOiBfX2VtdmFsX3J1bl9kZXN0cnVjdG9ycywgIm8iOiBfYWJvcnQsICJFIjogX2Vtc2NyaXB0ZW5fbWVtY3B5X2JpZywgIkYiOiBfZW1zY3JpcHRlbl9yZXNpemVfaGVhcCwgIkciOiBfZmRfY2xvc2UsICJDIjogX2ZkX3NlZWssICJ6IjogX2ZkX3dyaXRlLCAiRCI6IF9zZXRUZW1wUmV0MCB9OwogICAgICAgICAgdmFyIGFzbSA9IGNyZWF0ZVdhc20oKTsKICAgICAgICAgIHZhciBfX193YXNtX2NhbGxfY3RvcnMgPSBNb2R1bGVbIl9fX3dhc21fY2FsbF9jdG9ycyJdID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoX19fd2FzbV9jYWxsX2N0b3JzID0gTW9kdWxlWyJfX193YXNtX2NhbGxfY3RvcnMiXSA9IE1vZHVsZVsiYXNtIl1bIkwiXSkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTsKICAgICAgICAgIH07CiAgICAgICAgICB2YXIgX21hbGxvYyA9IE1vZHVsZVsiX21hbGxvYyJdID0gZnVuY3Rpb24oKSB7CiAgICAgICAgICAgIHJldHVybiAoX21hbGxvYyA9IE1vZHVsZVsiX21hbGxvYyJdID0gTW9kdWxlWyJhc20iXVsiTSJdKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBfZnJlZSA9IE1vZHVsZVsiX2ZyZWUiXSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKF9mcmVlID0gTW9kdWxlWyJfZnJlZSJdID0gTW9kdWxlWyJhc20iXVsiTiJdKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBfX19nZXRUeXBlTmFtZSA9IE1vZHVsZVsiX19fZ2V0VHlwZU5hbWUiXSA9IGZ1bmN0aW9uKCkgewogICAgICAgICAgICByZXR1cm4gKF9fX2dldFR5cGVOYW1lID0gTW9kdWxlWyJfX19nZXRUeXBlTmFtZSJdID0gTW9kdWxlWyJhc20iXVsiUCJdKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBfX19lbWJpbmRfcmVnaXN0ZXJfbmF0aXZlX2FuZF9idWlsdGluX3R5cGVzID0gTW9kdWxlWyJfX19lbWJpbmRfcmVnaXN0ZXJfbmF0aXZlX2FuZF9idWlsdGluX3R5cGVzIl0gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChfX19lbWJpbmRfcmVnaXN0ZXJfbmF0aXZlX2FuZF9idWlsdGluX3R5cGVzID0gTW9kdWxlWyJfX19lbWJpbmRfcmVnaXN0ZXJfbmF0aXZlX2FuZF9idWlsdGluX3R5cGVzIl0gPSBNb2R1bGVbImFzbSJdWyJRIl0pLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7CiAgICAgICAgICB9OwogICAgICAgICAgdmFyIGR5bkNhbGxfamlqaSA9IE1vZHVsZVsiZHluQ2FsbF9qaWppIl0gPSBmdW5jdGlvbigpIHsKICAgICAgICAgICAgcmV0dXJuIChkeW5DYWxsX2ppamkgPSBNb2R1bGVbImR5bkNhbGxfamlqaSJdID0gTW9kdWxlWyJhc20iXVsiUiJdKS5hcHBseShudWxsLCBhcmd1bWVudHMpOwogICAgICAgICAgfTsKICAgICAgICAgIHZhciBjYWxsZWRSdW47CiAgICAgICAgICBmdW5jdGlvbiBFeGl0U3RhdHVzKHN0YXR1cykgewogICAgICAgICAgICB0aGlzLm5hbWUgPSAiRXhpdFN0YXR1cyI7CiAgICAgICAgICAgIHRoaXMubWVzc2FnZSA9ICJQcm9ncmFtIHRlcm1pbmF0ZWQgd2l0aCBleGl0KCIgKyBzdGF0dXMgKyAiKSI7CiAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzOwogICAgICAgICAgfQogICAgICAgICAgZGVwZW5kZW5jaWVzRnVsZmlsbGVkID0gZnVuY3Rpb24gcnVuQ2FsbGVyKCkgewogICAgICAgICAgICBpZiAoIWNhbGxlZFJ1bikgcnVuKCk7CiAgICAgICAgICAgIGlmICghY2FsbGVkUnVuKSBkZXBlbmRlbmNpZXNGdWxmaWxsZWQgPSBydW5DYWxsZXI7CiAgICAgICAgICB9OwogICAgICAgICAgZnVuY3Rpb24gcnVuKGFyZ3MpIHsKICAgICAgICAgICAgYXJncyA9IGFyZ3MgfHwgYXJndW1lbnRzXzsKICAgICAgICAgICAgaWYgKHJ1bkRlcGVuZGVuY2llcyA+IDApIHsKICAgICAgICAgICAgICByZXR1cm47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcHJlUnVuKCk7CiAgICAgICAgICAgIGlmIChydW5EZXBlbmRlbmNpZXMgPiAwKSB7CiAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZ1bmN0aW9uIGRvUnVuKCkgewogICAgICAgICAgICAgIGlmIChjYWxsZWRSdW4pIHJldHVybjsKICAgICAgICAgICAgICBjYWxsZWRSdW4gPSB0cnVlOwogICAgICAgICAgICAgIE1vZHVsZVsiY2FsbGVkUnVuIl0gPSB0cnVlOwogICAgICAgICAgICAgIGlmIChBQk9SVCkgcmV0dXJuOwogICAgICAgICAgICAgIGluaXRSdW50aW1lKCk7CiAgICAgICAgICAgICAgcHJlTWFpbigpOwogICAgICAgICAgICAgIHJlYWR5UHJvbWlzZVJlc29sdmUoTW9kdWxlKTsKICAgICAgICAgICAgICBpZiAoTW9kdWxlWyJvblJ1bnRpbWVJbml0aWFsaXplZCJdKSBNb2R1bGVbIm9uUnVudGltZUluaXRpYWxpemVkIl0oKTsKICAgICAgICAgICAgICBwb3N0UnVuKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKE1vZHVsZVsic2V0U3RhdHVzIl0pIHsKICAgICAgICAgICAgICBNb2R1bGVbInNldFN0YXR1cyJdKCJSdW5uaW5nLi4uIik7CiAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHsKICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7CiAgICAgICAgICAgICAgICAgIE1vZHVsZVsic2V0U3RhdHVzIl0oIiIpOwogICAgICAgICAgICAgICAgfSwgMSk7CiAgICAgICAgICAgICAgICBkb1J1bigpOwogICAgICAgICAgICAgIH0sIDEpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIGRvUnVuKCk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICAgIE1vZHVsZVsicnVuIl0gPSBydW47CiAgICAgICAgICBpZiAoTW9kdWxlWyJwcmVJbml0Il0pIHsKICAgICAgICAgICAgaWYgKHR5cGVvZiBNb2R1bGVbInByZUluaXQiXSA9PSAiZnVuY3Rpb24iKSBNb2R1bGVbInByZUluaXQiXSA9IFtNb2R1bGVbInByZUluaXQiXV07CiAgICAgICAgICAgIHdoaWxlIChNb2R1bGVbInByZUluaXQiXS5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgICAgTW9kdWxlWyJwcmVJbml0Il0ucG9wKCkoKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgICAgcnVuKCk7CiAgICAgICAgICByZXR1cm4gQkFTSVMyLnJlYWR5OwogICAgICAgIH0pOwogICAgICB9KSgpOwogICAgICBpZiAodHlwZW9mIGV4cG9ydHMyID09PSAib2JqZWN0IiAmJiB0eXBlb2YgbW9kdWxlID09PSAib2JqZWN0IikKICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IEJBU0lTOwogICAgICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSAiZnVuY3Rpb24iICYmIGRlZmluZVsiYW1kIl0pCiAgICAgICAgZGVmaW5lKFtdLCBmdW5jdGlvbigpIHsKICAgICAgICAgIHJldHVybiBCQVNJUzsKICAgICAgICB9KTsKICAgICAgZWxzZSBpZiAodHlwZW9mIGV4cG9ydHMyID09PSAib2JqZWN0IikKICAgICAgICBleHBvcnRzMlsiQkFTSVMiXSA9IEJBU0lTOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdHJhbnNjb2RlS1RYMi5qcwogIHZhciB0cmFuc2NvZGVLVFgyX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydCh0cmFuc2NvZGVLVFgyX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IHRyYW5zY29kZUtUWDJfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIHRyYW5zY29kZShwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKSB7CiAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5vYmplY3QoInRyYW5zY29kZXJNb2R1bGUiLCB0cmFuc2NvZGVyTW9kdWxlKTsKICAgIGNvbnN0IGRhdGEgPSBwYXJhbWV0ZXJzLmt0eDJCdWZmZXI7CiAgICBjb25zdCBzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzID0gcGFyYW1ldGVycy5zdXBwb3J0ZWRUYXJnZXRGb3JtYXRzOwogICAgbGV0IGhlYWRlcjsKICAgIHRyeSB7CiAgICAgIGhlYWRlciA9IHJlYWQyKGRhdGEpOwogICAgfSBjYXRjaCAoZTIpIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KCJJbnZhbGlkIEtUWDIgZmlsZS4iKTsKICAgIH0KICAgIGlmIChoZWFkZXIubGF5ZXJDb3VudCAhPT0gMCkgewogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoIktUWDIgdGV4dHVyZSBhcnJheXMgYXJlIG5vdCBzdXBwb3J0ZWQuIik7CiAgICB9CiAgICBpZiAoaGVhZGVyLnBpeGVsRGVwdGggIT09IDApIHsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KCJLVFgyIDNEIHRleHR1cmVzIGFyZSB1bnN1cHBvcnRlZC4iKTsKICAgIH0KICAgIGNvbnN0IGRmZCA9IGhlYWRlci5kYXRhRm9ybWF0RGVzY3JpcHRvclswXTsKICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheShoZWFkZXIubGV2ZWxDb3VudCk7CiAgICBpZiAoaGVhZGVyLnZrRm9ybWF0ID09PSAwICYmIChkZmQuY29sb3JNb2RlbCA9PT0gY29sb3JNb2RlbEVUQzFTIHx8IGRmZC5jb2xvck1vZGVsID09PSBjb2xvck1vZGVsVUFTVEMpKSB7CiAgICAgIHRyYW5zY29kZUNvbXByZXNzZWQoCiAgICAgICAgZGF0YSwKICAgICAgICBoZWFkZXIsCiAgICAgICAgc3VwcG9ydGVkVGFyZ2V0Rm9ybWF0cywKICAgICAgICB0cmFuc2NvZGVyTW9kdWxlLAogICAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMsCiAgICAgICAgcmVzdWx0CiAgICAgICk7CiAgICB9IGVsc2UgewogICAgICB0cmFuc2ZlcmFibGVPYmplY3RzLnB1c2goZGF0YS5idWZmZXIpOwogICAgICBwYXJzZVVuY29tcHJlc3NlZChoZWFkZXIsIHJlc3VsdCk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0OwogIH0KICBmdW5jdGlvbiBwYXJzZVVuY29tcHJlc3NlZChoZWFkZXIsIHJlc3VsdCkgewogICAgY29uc3QgaW50ZXJuYWxGb3JtYXQgPSBoZWFkZXIudmtGb3JtYXQgPT09IFZ1bGthbkNvbnN0YW50c19kZWZhdWx0LlZLX0ZPUk1BVF9SOEc4QjhfU1JHQiA/IFBpeGVsRm9ybWF0X2RlZmF1bHQuUkdCIDogUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0JBOwogICAgbGV0IGRhdGF0eXBlOwogICAgaWYgKGhlYWRlci52a0Zvcm1hdCA9PT0gVnVsa2FuQ29uc3RhbnRzX2RlZmF1bHQuVktfRk9STUFUX1I4RzhCOEE4X1VOT1JNKSB7CiAgICAgIGRhdGF0eXBlID0gUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LlVOU0lHTkVEX0JZVEU7CiAgICB9IGVsc2UgaWYgKGhlYWRlci52a0Zvcm1hdCA9PT0gVnVsa2FuQ29uc3RhbnRzX2RlZmF1bHQuVktfRk9STUFUX1IxNkcxNkIxNkExNl9TRkxPQVQpIHsKICAgICAgZGF0YXR5cGUgPSBQaXhlbERhdGF0eXBlX2RlZmF1bHQuSEFMRl9GTE9BVDsKICAgIH0gZWxzZSBpZiAoaGVhZGVyLnZrRm9ybWF0ID09PSBWdWxrYW5Db25zdGFudHNfZGVmYXVsdC5WS19GT1JNQVRfUjMyRzMyQjMyQTMyX1NGTE9BVCkgewogICAgICBkYXRhdHlwZSA9IFBpeGVsRGF0YXR5cGVfZGVmYXVsdC5GTE9BVDsKICAgIH0KICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBoZWFkZXIubGV2ZWxzLmxlbmd0aDsgKytpMikgewogICAgICBjb25zdCBsZXZlbCA9IHt9OwogICAgICByZXN1bHRbaTJdID0gbGV2ZWw7CiAgICAgIGNvbnN0IGxldmVsQnVmZmVyID0gaGVhZGVyLmxldmVsc1tpMl0ubGV2ZWxEYXRhOwogICAgICBjb25zdCB3aWR0aCA9IGhlYWRlci5waXhlbFdpZHRoID4+IGkyOwogICAgICBjb25zdCBoZWlnaHQgPSBoZWFkZXIucGl4ZWxIZWlnaHQgPj4gaTI7CiAgICAgIGNvbnN0IGZhY2VMZW5ndGggPSB3aWR0aCAqIGhlaWdodCAqIFBpeGVsRm9ybWF0X2RlZmF1bHQuY29tcG9uZW50c0xlbmd0aChpbnRlcm5hbEZvcm1hdCk7CiAgICAgIGZvciAobGV0IGoyID0gMDsgajIgPCBoZWFkZXIuZmFjZUNvdW50OyArK2oyKSB7CiAgICAgICAgY29uc3QgZmFjZUJ5dGVPZmZzZXQgPSBsZXZlbEJ1ZmZlci5ieXRlT2Zmc2V0ICsgZmFjZUxlbmd0aCAqIGhlYWRlci50eXBlU2l6ZSAqIGoyOwogICAgICAgIGxldCBmYWNlVmlldzsKICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChkYXRhdHlwZSkgfHwgUGl4ZWxEYXRhdHlwZV9kZWZhdWx0LnNpemVJbkJ5dGVzKGRhdGF0eXBlKSA9PT0gMSkgewogICAgICAgICAgZmFjZVZpZXcgPSBuZXcgVWludDhBcnJheSgKICAgICAgICAgICAgbGV2ZWxCdWZmZXIuYnVmZmVyLAogICAgICAgICAgICBmYWNlQnl0ZU9mZnNldCwKICAgICAgICAgICAgZmFjZUxlbmd0aAogICAgICAgICAgKTsKICAgICAgICB9IGVsc2UgaWYgKFBpeGVsRGF0YXR5cGVfZGVmYXVsdC5zaXplSW5CeXRlcyhkYXRhdHlwZSkgPT09IDIpIHsKICAgICAgICAgIGZhY2VWaWV3ID0gbmV3IFVpbnQxNkFycmF5KAogICAgICAgICAgICBsZXZlbEJ1ZmZlci5idWZmZXIsCiAgICAgICAgICAgIGZhY2VCeXRlT2Zmc2V0LAogICAgICAgICAgICBmYWNlTGVuZ3RoCiAgICAgICAgICApOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBmYWNlVmlldyA9IG5ldyBGbG9hdDMyQXJyYXkoCiAgICAgICAgICAgIGxldmVsQnVmZmVyLmJ1ZmZlciwKICAgICAgICAgICAgZmFjZUJ5dGVPZmZzZXQsCiAgICAgICAgICAgIGZhY2VMZW5ndGgKICAgICAgICAgICk7CiAgICAgICAgfQogICAgICAgIGxldmVsW2ZhY2VPcmRlcltqMl1dID0gewogICAgICAgICAgaW50ZXJuYWxGb3JtYXQsCiAgICAgICAgICBkYXRhdHlwZSwKICAgICAgICAgIHdpZHRoLAogICAgICAgICAgaGVpZ2h0LAogICAgICAgICAgbGV2ZWxCdWZmZXI6IGZhY2VWaWV3CiAgICAgICAgfTsKICAgICAgfQogICAgfQogIH0KICBmdW5jdGlvbiB0cmFuc2NvZGVDb21wcmVzc2VkKGRhdGEsIGhlYWRlciwgc3VwcG9ydGVkVGFyZ2V0Rm9ybWF0cywgdHJhbnNjb2Rlck1vZHVsZTIsIHRyYW5zZmVyYWJsZU9iamVjdHMsIHJlc3VsdCkgewogICAgY29uc3Qga3R4MkZpbGUgPSBuZXcgdHJhbnNjb2Rlck1vZHVsZTIuS1RYMkZpbGUoZGF0YSk7CiAgICBsZXQgd2lkdGggPSBrdHgyRmlsZS5nZXRXaWR0aCgpOwogICAgbGV0IGhlaWdodCA9IGt0eDJGaWxlLmdldEhlaWdodCgpOwogICAgY29uc3QgbGV2ZWxzID0ga3R4MkZpbGUuZ2V0TGV2ZWxzKCk7CiAgICBjb25zdCBoYXNBbHBoYSA9IGt0eDJGaWxlLmdldEhhc0FscGhhKCk7CiAgICBpZiAoISh3aWR0aCA+IDApIHx8ICEoaGVpZ2h0ID4gMCkgfHwgIShsZXZlbHMgPiAwKSkgewogICAgICBrdHgyRmlsZS5jbG9zZSgpOwogICAgICBrdHgyRmlsZS5kZWxldGUoKTsKICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KCJJbnZhbGlkIEtUWDIgZmlsZSIpOwogICAgfQogICAgbGV0IGludGVybmFsRm9ybWF0LCB0cmFuc2NvZGVyRm9ybWF0OwogICAgY29uc3QgZGZkID0gaGVhZGVyLmRhdGFGb3JtYXREZXNjcmlwdG9yWzBdOwogICAgY29uc3QgQmFzaXNGb3JtYXQgPSB0cmFuc2NvZGVyTW9kdWxlMi50cmFuc2NvZGVyX3RleHR1cmVfZm9ybWF0OwogICAgaWYgKGRmZC5jb2xvck1vZGVsID09PSBjb2xvck1vZGVsRVRDMVMpIHsKICAgICAgaWYgKHN1cHBvcnRlZFRhcmdldEZvcm1hdHMuZXRjKSB7CiAgICAgICAgaW50ZXJuYWxGb3JtYXQgPSBoYXNBbHBoYSA/IFBpeGVsRm9ybWF0X2RlZmF1bHQuUkdCQThfRVRDMl9FQUMgOiBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQjhfRVRDMjsKICAgICAgICB0cmFuc2NvZGVyRm9ybWF0ID0gaGFzQWxwaGEgPyBCYXNpc0Zvcm1hdC5jVEZFVEMyX1JHQkEgOiBCYXNpc0Zvcm1hdC5jVEZFVEMxX1JHQjsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLmV0YzEgJiYgIWhhc0FscGhhKSB7CiAgICAgICAgaW50ZXJuYWxGb3JtYXQgPSBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQl9FVEMxOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBCYXNpc0Zvcm1hdC5jVEZFVEMxX1JHQjsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLnMzdGMpIHsKICAgICAgICBpbnRlcm5hbEZvcm1hdCA9IGhhc0FscGhhID8gUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0JBX0RYVDUgOiBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQl9EWFQxOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBoYXNBbHBoYSA/IEJhc2lzRm9ybWF0LmNURkJDM19SR0JBIDogQmFzaXNGb3JtYXQuY1RGQkMxX1JHQjsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLnB2cnRjKSB7CiAgICAgICAgaW50ZXJuYWxGb3JtYXQgPSBoYXNBbHBoYSA/IFBpeGVsRm9ybWF0X2RlZmF1bHQuUkdCQV9QVlJUQ180QlBQVjEgOiBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQl9QVlJUQ180QlBQVjE7CiAgICAgICAgdHJhbnNjb2RlckZvcm1hdCA9IGhhc0FscGhhID8gQmFzaXNGb3JtYXQuY1RGUFZSVEMxXzRfUkdCQSA6IEJhc2lzRm9ybWF0LmNURlBWUlRDMV80X1JHQjsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLmFzdGMpIHsKICAgICAgICBpbnRlcm5hbEZvcm1hdCA9IFBpeGVsRm9ybWF0X2RlZmF1bHQuUkdCQV9BU1RDOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBCYXNpc0Zvcm1hdC5jVEZBU1RDXzR4NF9SR0JBOwogICAgICB9IGVsc2UgaWYgKHN1cHBvcnRlZFRhcmdldEZvcm1hdHMuYmM3KSB7CiAgICAgICAgaW50ZXJuYWxGb3JtYXQgPSBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQkFfQkM3OwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBCYXNpc0Zvcm1hdC5jVEZCQzdfUkdCQTsKICAgICAgfSBlbHNlIHsKICAgICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoCiAgICAgICAgICAiTm8gdHJhbnNjb2RpbmcgZm9ybWF0IHRhcmdldCBhdmFpbGFibGUgZm9yIEVUQzFTIGNvbXByZXNzZWQga3R4Mi4iCiAgICAgICAgKTsKICAgICAgfQogICAgfSBlbHNlIGlmIChkZmQuY29sb3JNb2RlbCA9PT0gY29sb3JNb2RlbFVBU1RDKSB7CiAgICAgIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLmFzdGMpIHsKICAgICAgICBpbnRlcm5hbEZvcm1hdCA9IFBpeGVsRm9ybWF0X2RlZmF1bHQuUkdCQV9BU1RDOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBCYXNpc0Zvcm1hdC5jVEZBU1RDXzR4NF9SR0JBOwogICAgICB9IGVsc2UgaWYgKHN1cHBvcnRlZFRhcmdldEZvcm1hdHMuYmM3KSB7CiAgICAgICAgaW50ZXJuYWxGb3JtYXQgPSBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQkFfQkM3OwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBCYXNpc0Zvcm1hdC5jVEZCQzdfUkdCQTsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLnMzdGMpIHsKICAgICAgICBpbnRlcm5hbEZvcm1hdCA9IGhhc0FscGhhID8gUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0JBX0RYVDUgOiBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQl9EWFQxOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBoYXNBbHBoYSA/IEJhc2lzRm9ybWF0LmNURkJDM19SR0JBIDogQmFzaXNGb3JtYXQuY1RGQkMxX1JHQjsKICAgICAgfSBlbHNlIGlmIChzdXBwb3J0ZWRUYXJnZXRGb3JtYXRzLmV0YykgewogICAgICAgIGludGVybmFsRm9ybWF0ID0gaGFzQWxwaGEgPyBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQkE4X0VUQzJfRUFDIDogUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0I4X0VUQzI7CiAgICAgICAgdHJhbnNjb2RlckZvcm1hdCA9IGhhc0FscGhhID8gQmFzaXNGb3JtYXQuY1RGRVRDMl9SR0JBIDogQmFzaXNGb3JtYXQuY1RGRVRDMV9SR0I7CiAgICAgIH0gZWxzZSBpZiAoc3VwcG9ydGVkVGFyZ2V0Rm9ybWF0cy5ldGMxICYmICFoYXNBbHBoYSkgewogICAgICAgIGludGVybmFsRm9ybWF0ID0gUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0JfRVRDMTsKICAgICAgICB0cmFuc2NvZGVyRm9ybWF0ID0gQmFzaXNGb3JtYXQuY1RGRVRDMV9SR0I7CiAgICAgIH0gZWxzZSBpZiAoc3VwcG9ydGVkVGFyZ2V0Rm9ybWF0cy5wdnJ0YykgewogICAgICAgIGludGVybmFsRm9ybWF0ID0gaGFzQWxwaGEgPyBQaXhlbEZvcm1hdF9kZWZhdWx0LlJHQkFfUFZSVENfNEJQUFYxIDogUGl4ZWxGb3JtYXRfZGVmYXVsdC5SR0JfUFZSVENfNEJQUFYxOwogICAgICAgIHRyYW5zY29kZXJGb3JtYXQgPSBoYXNBbHBoYSA/IEJhc2lzRm9ybWF0LmNURlBWUlRDMV80X1JHQkEgOiBCYXNpc0Zvcm1hdC5jVEZQVlJUQzFfNF9SR0I7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFcnJvcl9kZWZhdWx0KAogICAgICAgICAgIk5vIHRyYW5zY29kaW5nIGZvcm1hdCB0YXJnZXQgYXZhaWxhYmxlIGZvciBVQVNUQyBjb21wcmVzc2VkIGt0eDIuIgogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIGlmICgha3R4MkZpbGUuc3RhcnRUcmFuc2NvZGluZygpKSB7CiAgICAgIGt0eDJGaWxlLmNsb3NlKCk7CiAgICAgIGt0eDJGaWxlLmRlbGV0ZSgpOwogICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoInN0YXJ0VHJhbnNjb2RpbmcoKSBmYWlsZWQiKTsKICAgIH0KICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBoZWFkZXIubGV2ZWxzLmxlbmd0aDsgKytpMikgewogICAgICBjb25zdCBsZXZlbCA9IHt9OwogICAgICByZXN1bHRbaTJdID0gbGV2ZWw7CiAgICAgIHdpZHRoID0gaGVhZGVyLnBpeGVsV2lkdGggPj4gaTI7CiAgICAgIGhlaWdodCA9IGhlYWRlci5waXhlbEhlaWdodCA+PiBpMjsKICAgICAgY29uc3QgZHN0U2l6ZSA9IGt0eDJGaWxlLmdldEltYWdlVHJhbnNjb2RlZFNpemVJbkJ5dGVzKAogICAgICAgIGkyLAogICAgICAgIC8vIGxldmVsIGluZGV4CiAgICAgICAgMCwKICAgICAgICAvLyBsYXllciBpbmRleAogICAgICAgIDAsCiAgICAgICAgLy8gZmFjZSBpbmRleAogICAgICAgIHRyYW5zY29kZXJGb3JtYXQudmFsdWUKICAgICAgKTsKICAgICAgY29uc3QgZHN0ID0gbmV3IFVpbnQ4QXJyYXkoZHN0U2l6ZSk7CiAgICAgIGNvbnN0IHRyYW5zY29kZWQgPSBrdHgyRmlsZS50cmFuc2NvZGVJbWFnZSgKICAgICAgICBkc3QsCiAgICAgICAgaTIsCiAgICAgICAgLy8gbGV2ZWwgaW5kZXgKICAgICAgICAwLAogICAgICAgIC8vIGxheWVyIGluZGV4CiAgICAgICAgMCwKICAgICAgICAvLyBmYWNlIGluZGV4CiAgICAgICAgdHJhbnNjb2RlckZvcm1hdC52YWx1ZSwKICAgICAgICAwLAogICAgICAgIC8vIGdldF9hbHBoYV9mb3Jfb3BhcXVlX2Zvcm1hdHMKICAgICAgICAtMSwKICAgICAgICAvLyBjaGFubmVsMAogICAgICAgIC0xCiAgICAgICAgLy8gY2hhbm5lbDEKICAgICAgKTsKICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQodHJhbnNjb2RlZCkpIHsKICAgICAgICB0aHJvdyBuZXcgUnVudGltZUVycm9yX2RlZmF1bHQoInRyYW5zY29kZUltYWdlKCkgZmFpbGVkLiIpOwogICAgICB9CiAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMucHVzaChkc3QuYnVmZmVyKTsKICAgICAgbGV2ZWxbZmFjZU9yZGVyWzBdXSA9IHsKICAgICAgICBpbnRlcm5hbEZvcm1hdCwKICAgICAgICB3aWR0aCwKICAgICAgICBoZWlnaHQsCiAgICAgICAgbGV2ZWxCdWZmZXI6IGRzdAogICAgICB9OwogICAgfQogICAga3R4MkZpbGUuY2xvc2UoKTsKICAgIGt0eDJGaWxlLmRlbGV0ZSgpOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgYXN5bmMgZnVuY3Rpb24gaW5pdFdvcmtlcjUocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3Qgd2FzbUNvbmZpZyA9IHBhcmFtZXRlcnMud2ViQXNzZW1ibHlDb25maWc7CiAgICBjb25zdCBiYXNpc1RyYW5zY29kZXIgPSBpbXBvcnRfYmFzaXNfdHJhbnNjb2Rlci5kZWZhdWx0ID8/IHNlbGYuQkFTSVM7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHdhc21Db25maWcud2FzbUJpbmFyeUZpbGUpKSB7CiAgICAgIHRyYW5zY29kZXJNb2R1bGUgPSBhd2FpdCBiYXNpc1RyYW5zY29kZXIod2FzbUNvbmZpZyk7CiAgICB9IGVsc2UgewogICAgICB0cmFuc2NvZGVyTW9kdWxlID0gYXdhaXQgYmFzaXNUcmFuc2NvZGVyKCk7CiAgICB9CiAgICB0cmFuc2NvZGVyTW9kdWxlLmluaXRpYWxpemVCYXNpcygpOwogICAgcmV0dXJuIHRydWU7CiAgfQogIGZ1bmN0aW9uIHRyYW5zY29kZUtUWDIocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3Qgd2FzbUNvbmZpZyA9IHBhcmFtZXRlcnMud2ViQXNzZW1ibHlDb25maWc7CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHdhc21Db25maWcpKSB7CiAgICAgIHJldHVybiBpbml0V29ya2VyNShwYXJhbWV0ZXJzLCB0cmFuc2ZlcmFibGVPYmplY3RzKTsKICAgIH0KICAgIHJldHVybiB0cmFuc2NvZGUocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cyk7CiAgfQogIHZhciBpbXBvcnRfYmFzaXNfdHJhbnNjb2RlciwgZmFjZU9yZGVyLCBjb2xvck1vZGVsRVRDMVMsIGNvbG9yTW9kZWxVQVNUQywgdHJhbnNjb2Rlck1vZHVsZSwgdHJhbnNjb2RlS1RYMl9kZWZhdWx0OwogIHZhciBpbml0X3RyYW5zY29kZUtUWDIgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL3RyYW5zY29kZUtUWDIuanMiKCkgewogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9DaGVjaygpOwogICAgICBpbml0X1BpeGVsRm9ybWF0KCk7CiAgICAgIGluaXRfUnVudGltZUVycm9yKCk7CiAgICAgIGluaXRfVnVsa2FuQ29uc3RhbnRzKCk7CiAgICAgIGluaXRfUGl4ZWxEYXRhdHlwZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgaW5pdF9rdHhfcGFyc2VfbW9kZXJuKCk7CiAgICAgIGltcG9ydF9iYXNpc190cmFuc2NvZGVyID0gX190b0VTTShyZXF1aXJlX2Jhc2lzX3RyYW5zY29kZXIoKSwgMSk7CiAgICAgIGZhY2VPcmRlciA9IFsKICAgICAgICAicG9zaXRpdmVYIiwKICAgICAgICAibmVnYXRpdmVYIiwKICAgICAgICAicG9zaXRpdmVZIiwKICAgICAgICAibmVnYXRpdmVZIiwKICAgICAgICAicG9zaXRpdmVaIiwKICAgICAgICAibmVnYXRpdmVaIgogICAgICBdOwogICAgICBjb2xvck1vZGVsRVRDMVMgPSAxNjM7CiAgICAgIGNvbG9yTW9kZWxVQVNUQyA9IDE2NjsKICAgICAgdHJhbnNjb2RlS1RYMl9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KHRyYW5zY29kZUtUWDIpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdHJhbnNmZXJUeXBlZEFycmF5VGVzdC5qcwogIHZhciB0cmFuc2ZlclR5cGVkQXJyYXlUZXN0X2V4cG9ydHMgPSB7fTsKICB2YXIgaW5pdF90cmFuc2ZlclR5cGVkQXJyYXlUZXN0ID0gX19lc20oewogICAgInBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy90cmFuc2ZlclR5cGVkQXJyYXlUZXN0LmpzIigpIHsKICAgICAgc2VsZi5vbm1lc3NhZ2UgPSBmdW5jdGlvbihldmVudCkgewogICAgICAgIGNvbnN0IGFycmF5ID0gZXZlbnQuZGF0YS5hcnJheTsKICAgICAgICBjb25zdCBwb3N0TWVzc2FnZTIgPSBzZWxmLndlYmtpdFBvc3RNZXNzYWdlIHx8IHNlbGYucG9zdE1lc3NhZ2U7CiAgICAgICAgdHJ5IHsKICAgICAgICAgIHBvc3RNZXNzYWdlMigKICAgICAgICAgICAgewogICAgICAgICAgICAgIGFycmF5CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIFthcnJheS5idWZmZXJdCiAgICAgICAgICApOwogICAgICAgIH0gY2F0Y2ggKGUyKSB7CiAgICAgICAgICBwb3N0TWVzc2FnZTIoe30pOwogICAgICAgIH0KICAgICAgfTsKICAgIH0KICB9KTsKCiAgLy8gcGFja2FnZXMvZW5naW5lL1NvdXJjZS9Db3JlL0ludGVyc2VjdGlvbnMyRC5qcwogIHZhciBJbnRlcnNlY3Rpb25zMkQsIEludGVyc2VjdGlvbnMyRF9kZWZhdWx0OwogIHZhciBpbml0X0ludGVyc2VjdGlvbnMyRCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL0NvcmUvSW50ZXJzZWN0aW9uczJELmpzIigpIHsKICAgICAgaW5pdF9DYXJ0ZXNpYW4yKCk7CiAgICAgIGluaXRfQ2FydGVzaWFuMygpOwogICAgICBpbml0X0NoZWNrKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0RldmVsb3BlckVycm9yKCk7CiAgICAgIEludGVyc2VjdGlvbnMyRCA9IHt9OwogICAgICBJbnRlcnNlY3Rpb25zMkQuY2xpcFRyaWFuZ2xlQXRBeGlzQWxpZ25lZFRocmVzaG9sZCA9IGZ1bmN0aW9uKHRocmVzaG9sZCwga2VlcEFib3ZlLCB1MCwgdTEyLCB1MjIsIHJlc3VsdCkgewogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHRocmVzaG9sZCkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ0aHJlc2hvbGQgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KGtlZXBBYm92ZSkpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJrZWVwQWJvdmUgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHUwKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInUwIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh1MTIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgidTEgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHUyMikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ1MiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gW107CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlc3VsdC5sZW5ndGggPSAwOwogICAgICAgIH0KICAgICAgICBsZXQgdTBCZWhpbmQ7CiAgICAgICAgbGV0IHUxQmVoaW5kOwogICAgICAgIGxldCB1MkJlaGluZDsKICAgICAgICBpZiAoa2VlcEFib3ZlKSB7CiAgICAgICAgICB1MEJlaGluZCA9IHUwIDwgdGhyZXNob2xkOwogICAgICAgICAgdTFCZWhpbmQgPSB1MTIgPCB0aHJlc2hvbGQ7CiAgICAgICAgICB1MkJlaGluZCA9IHUyMiA8IHRocmVzaG9sZDsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdTBCZWhpbmQgPSB1MCA+IHRocmVzaG9sZDsKICAgICAgICAgIHUxQmVoaW5kID0gdTEyID4gdGhyZXNob2xkOwogICAgICAgICAgdTJCZWhpbmQgPSB1MjIgPiB0aHJlc2hvbGQ7CiAgICAgICAgfQogICAgICAgIGNvbnN0IG51bUJlaGluZCA9IHUwQmVoaW5kICsgdTFCZWhpbmQgKyB1MkJlaGluZDsKICAgICAgICBsZXQgdTAxUmF0aW87CiAgICAgICAgbGV0IHUwMlJhdGlvOwogICAgICAgIGxldCB1MTJSYXRpbzsKICAgICAgICBsZXQgdTEwUmF0aW87CiAgICAgICAgbGV0IHUyMFJhdGlvOwogICAgICAgIGxldCB1MjFSYXRpbzsKICAgICAgICBpZiAobnVtQmVoaW5kID09PSAxKSB7CiAgICAgICAgICBpZiAodTBCZWhpbmQpIHsKICAgICAgICAgICAgdTAxUmF0aW8gPSAodGhyZXNob2xkIC0gdTApIC8gKHUxMiAtIHUwKTsKICAgICAgICAgICAgdTAyUmF0aW8gPSAodGhyZXNob2xkIC0gdTApIC8gKHUyMiAtIHUwKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMSk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDIpOwogICAgICAgICAgICBpZiAodTAyUmF0aW8gIT09IDEpIHsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgtMSk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMCk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2godTAyUmF0aW8pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh1MDFSYXRpbyAhPT0gMSkgewogICAgICAgICAgICAgIHJlc3VsdC5wdXNoKC0xKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgwKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCh1MDFSYXRpbyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAodTFCZWhpbmQpIHsKICAgICAgICAgICAgdTEyUmF0aW8gPSAodGhyZXNob2xkIC0gdTEyKSAvICh1MjIgLSB1MTIpOwogICAgICAgICAgICB1MTBSYXRpbyA9ICh0aHJlc2hvbGQgLSB1MTIpIC8gKHUwIC0gdTEyKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDApOwogICAgICAgICAgICBpZiAodTEwUmF0aW8gIT09IDEpIHsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgtMSk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMSk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMCk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2godTEwUmF0aW8pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh1MTJSYXRpbyAhPT0gMSkgewogICAgICAgICAgICAgIHJlc3VsdC5wdXNoKC0xKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgyKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCh1MTJSYXRpbyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0gZWxzZSBpZiAodTJCZWhpbmQpIHsKICAgICAgICAgICAgdTIwUmF0aW8gPSAodGhyZXNob2xkIC0gdTIyKSAvICh1MCAtIHUyMik7CiAgICAgICAgICAgIHUyMVJhdGlvID0gKHRocmVzaG9sZCAtIHUyMikgLyAodTEyIC0gdTIyKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMCk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDEpOwogICAgICAgICAgICBpZiAodTIxUmF0aW8gIT09IDEpIHsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgtMSk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2goMSk7CiAgICAgICAgICAgICAgcmVzdWx0LnB1c2godTIxUmF0aW8pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh1MjBSYXRpbyAhPT0gMSkgewogICAgICAgICAgICAgIHJlc3VsdC5wdXNoKC0xKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgyKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCgwKTsKICAgICAgICAgICAgICByZXN1bHQucHVzaCh1MjBSYXRpbyk7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYgKG51bUJlaGluZCA9PT0gMikgewogICAgICAgICAgaWYgKCF1MEJlaGluZCAmJiB1MCAhPT0gdGhyZXNob2xkKSB7CiAgICAgICAgICAgIHUxMFJhdGlvID0gKHRocmVzaG9sZCAtIHUxMikgLyAodTAgLSB1MTIpOwogICAgICAgICAgICB1MjBSYXRpbyA9ICh0aHJlc2hvbGQgLSB1MjIpIC8gKHUwIC0gdTIyKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMCk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKC0xKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMSk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDApOwogICAgICAgICAgICByZXN1bHQucHVzaCh1MTBSYXRpbyk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKC0xKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDApOwogICAgICAgICAgICByZXN1bHQucHVzaCh1MjBSYXRpbyk7CiAgICAgICAgICB9IGVsc2UgaWYgKCF1MUJlaGluZCAmJiB1MTIgIT09IHRocmVzaG9sZCkgewogICAgICAgICAgICB1MjFSYXRpbyA9ICh0aHJlc2hvbGQgLSB1MjIpIC8gKHUxMiAtIHUyMik7CiAgICAgICAgICAgIHUwMVJhdGlvID0gKHRocmVzaG9sZCAtIHUwKSAvICh1MTIgLSB1MCk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDEpOwogICAgICAgICAgICByZXN1bHQucHVzaCgtMSk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDIpOwogICAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2godTIxUmF0aW8pOwogICAgICAgICAgICByZXN1bHQucHVzaCgtMSk7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKDApOwogICAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2godTAxUmF0aW8pOwogICAgICAgICAgfSBlbHNlIGlmICghdTJCZWhpbmQgJiYgdTIyICE9PSB0aHJlc2hvbGQpIHsKICAgICAgICAgICAgdTAyUmF0aW8gPSAodGhyZXNob2xkIC0gdTApIC8gKHUyMiAtIHUwKTsKICAgICAgICAgICAgdTEyUmF0aW8gPSAodGhyZXNob2xkIC0gdTEyKSAvICh1MjIgLSB1MTIpOwogICAgICAgICAgICByZXN1bHQucHVzaCgyKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goLTEpOwogICAgICAgICAgICByZXN1bHQucHVzaCgwKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHUwMlJhdGlvKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goLTEpOwogICAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgICAgcmVzdWx0LnB1c2goMik7CiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHUxMlJhdGlvKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgaWYgKG51bUJlaGluZCAhPT0gMykgewogICAgICAgICAgcmVzdWx0LnB1c2goMCk7CiAgICAgICAgICByZXN1bHQucHVzaCgxKTsKICAgICAgICAgIHJlc3VsdC5wdXNoKDIpOwogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBJbnRlcnNlY3Rpb25zMkQuY29tcHV0ZUJhcnljZW50cmljQ29vcmRpbmF0ZXMgPSBmdW5jdGlvbih4MiwgeTIsIHgxLCB5MSwgeDIyLCB5MjIsIHgzLCB5MywgcmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoeDIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieCBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoeTIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieSBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoeDEpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieDEgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHkxKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInkxIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdCh4MjIpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieDIgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHkyMikpIHsKICAgICAgICAgIHRocm93IG5ldyBEZXZlbG9wZXJFcnJvcl9kZWZhdWx0KCJ5MiBpcyByZXF1aXJlZC4iKTsKICAgICAgICB9CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQoeDMpKSB7CiAgICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgieDMgaXMgcmVxdWlyZWQuIik7CiAgICAgICAgfQogICAgICAgIGlmICghZGVmaW5lZF9kZWZhdWx0KHkzKSkgewogICAgICAgICAgdGhyb3cgbmV3IERldmVsb3BlckVycm9yX2RlZmF1bHQoInkzIGlzIHJlcXVpcmVkLiIpOwogICAgICAgIH0KICAgICAgICBjb25zdCB4MW14MyA9IHgxIC0geDM7CiAgICAgICAgY29uc3QgeDNteDIgPSB4MyAtIHgyMjsKICAgICAgICBjb25zdCB5Mm15MyA9IHkyMiAtIHkzOwogICAgICAgIGNvbnN0IHkxbXkzID0geTEgLSB5MzsKICAgICAgICBjb25zdCBpbnZlcnNlRGV0ZXJtaW5hbnQgPSAxIC8gKHkybXkzICogeDFteDMgKyB4M214MiAqIHkxbXkzKTsKICAgICAgICBjb25zdCB5bXkzID0geTIgLSB5MzsKICAgICAgICBjb25zdCB4bXgzID0geDIgLSB4MzsKICAgICAgICBjb25zdCBsMSA9ICh5Mm15MyAqIHhteDMgKyB4M214MiAqIHlteTMpICogaW52ZXJzZURldGVybWluYW50OwogICAgICAgIGNvbnN0IGwyID0gKC15MW15MyAqIHhteDMgKyB4MW14MyAqIHlteTMpICogaW52ZXJzZURldGVybWluYW50OwogICAgICAgIGNvbnN0IGwzID0gMSAtIGwxIC0gbDI7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICByZXN1bHQueCA9IGwxOwogICAgICAgICAgcmVzdWx0LnkgPSBsMjsKICAgICAgICAgIHJlc3VsdC56ID0gbDM7CiAgICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICAgIH0KICAgICAgICByZXR1cm4gbmV3IENhcnRlc2lhbjNfZGVmYXVsdChsMSwgbDIsIGwzKTsKICAgICAgfTsKICAgICAgSW50ZXJzZWN0aW9uczJELmNvbXB1dGVMaW5lU2VnbWVudExpbmVTZWdtZW50SW50ZXJzZWN0aW9uID0gZnVuY3Rpb24oeDAwLCB5MDAsIHgwMSwgeTAxLCB4MTAsIHkxMCwgeDExLCB5MTEsIHJlc3VsdCkgewogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigieDAwIiwgeDAwKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInkwMCIsIHkwMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ4MDEiLCB4MDEpOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigieTAxIiwgeTAxKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoIngxMCIsIHgxMCk7CiAgICAgICAgQ2hlY2tfZGVmYXVsdC50eXBlT2YubnVtYmVyKCJ5MTAiLCB5MTApOwogICAgICAgIENoZWNrX2RlZmF1bHQudHlwZU9mLm51bWJlcigieDExIiwgeDExKTsKICAgICAgICBDaGVja19kZWZhdWx0LnR5cGVPZi5udW1iZXIoInkxMSIsIHkxMSk7CiAgICAgICAgY29uc3QgbnVtZXJhdG9yMUEgPSAoeDExIC0geDEwKSAqICh5MDAgLSB5MTApIC0gKHkxMSAtIHkxMCkgKiAoeDAwIC0geDEwKTsKICAgICAgICBjb25zdCBudW1lcmF0b3IxQiA9ICh4MDEgLSB4MDApICogKHkwMCAtIHkxMCkgLSAoeTAxIC0geTAwKSAqICh4MDAgLSB4MTApOwogICAgICAgIGNvbnN0IGRlbm9taW5hdG9yMSA9ICh5MTEgLSB5MTApICogKHgwMSAtIHgwMCkgLSAoeDExIC0geDEwKSAqICh5MDEgLSB5MDApOwogICAgICAgIGlmIChkZW5vbWluYXRvcjEgPT09IDApIHsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgdWExID0gbnVtZXJhdG9yMUEgLyBkZW5vbWluYXRvcjE7CiAgICAgICAgY29uc3QgdWIxID0gbnVtZXJhdG9yMUIgLyBkZW5vbWluYXRvcjE7CiAgICAgICAgaWYgKHVhMSA+PSAwICYmIHVhMSA8PSAxICYmIHViMSA+PSAwICYmIHViMSA8PSAxKSB7CiAgICAgICAgICBpZiAoIWRlZmluZWRfZGVmYXVsdChyZXN1bHQpKSB7CiAgICAgICAgICAgIHJlc3VsdCA9IG5ldyBDYXJ0ZXNpYW4yX2RlZmF1bHQoKTsKICAgICAgICAgIH0KICAgICAgICAgIHJlc3VsdC54ID0geDAwICsgdWExICogKHgwMSAtIHgwMCk7CiAgICAgICAgICByZXN1bHQueSA9IHkwMCArIHVhMSAqICh5MDEgLSB5MDApOwogICAgICAgICAgcmV0dXJuIHJlc3VsdDsKICAgICAgICB9CiAgICAgIH07CiAgICAgIEludGVyc2VjdGlvbnMyRF9kZWZhdWx0ID0gSW50ZXJzZWN0aW9uczJEOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaC5qcwogIHZhciB1cHNhbXBsZVF1YW50aXplZFRlcnJhaW5NZXNoX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydCh1cHNhbXBsZVF1YW50aXplZFRlcnJhaW5NZXNoX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IHVwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2hfZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIHVwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2gocGFyYW1ldGVycywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgaXNFYXN0Q2hpbGQgPSBwYXJhbWV0ZXJzLmlzRWFzdENoaWxkOwogICAgY29uc3QgaXNOb3J0aENoaWxkID0gcGFyYW1ldGVycy5pc05vcnRoQ2hpbGQ7CiAgICBjb25zdCBtaW5VID0gaXNFYXN0Q2hpbGQgPyBoYWxmTWF4U2hvcnQgOiAwOwogICAgY29uc3QgbWF4VSA9IGlzRWFzdENoaWxkID8gbWF4U2hvcnQ1IDogaGFsZk1heFNob3J0OwogICAgY29uc3QgbWluViA9IGlzTm9ydGhDaGlsZCA/IGhhbGZNYXhTaG9ydCA6IDA7CiAgICBjb25zdCBtYXhWID0gaXNOb3J0aENoaWxkID8gbWF4U2hvcnQ1IDogaGFsZk1heFNob3J0OwogICAgY29uc3QgdUJ1ZmZlciA9IHVTY3JhdGNoOwogICAgY29uc3QgdkJ1ZmZlciA9IHZTY3JhdGNoOwogICAgY29uc3QgaGVpZ2h0QnVmZmVyID0gaGVpZ2h0U2NyYXRjaDsKICAgIGNvbnN0IG5vcm1hbEJ1ZmZlciA9IG5vcm1hbHNTY3JhdGNoOwogICAgdUJ1ZmZlci5sZW5ndGggPSAwOwogICAgdkJ1ZmZlci5sZW5ndGggPSAwOwogICAgaGVpZ2h0QnVmZmVyLmxlbmd0aCA9IDA7CiAgICBub3JtYWxCdWZmZXIubGVuZ3RoID0gMDsKICAgIGNvbnN0IGluZGljZXMgPSBpbmRpY2VzU2NyYXRjaDsKICAgIGluZGljZXMubGVuZ3RoID0gMDsKICAgIGNvbnN0IHZlcnRleE1hcCA9IHt9OwogICAgY29uc3QgcGFyZW50VmVydGljZXMgPSBwYXJhbWV0ZXJzLnZlcnRpY2VzOwogICAgbGV0IHBhcmVudEluZGljZXMgPSBwYXJhbWV0ZXJzLmluZGljZXM7CiAgICBwYXJlbnRJbmRpY2VzID0gcGFyZW50SW5kaWNlcy5zdWJhcnJheSgwLCBwYXJhbWV0ZXJzLmluZGV4Q291bnRXaXRob3V0U2tpcnRzKTsKICAgIGNvbnN0IGVuY29kaW5nID0gVGVycmFpbkVuY29kaW5nX2RlZmF1bHQuY2xvbmUocGFyYW1ldGVycy5lbmNvZGluZyk7CiAgICBjb25zdCBoYXNWZXJ0ZXhOb3JtYWxzID0gZW5jb2RpbmcuaGFzVmVydGV4Tm9ybWFsczsKICAgIGxldCB2ZXJ0ZXhDb3VudCA9IDA7CiAgICBjb25zdCBxdWFudGl6ZWRWZXJ0ZXhDb3VudCA9IHBhcmFtZXRlcnMudmVydGV4Q291bnRXaXRob3V0U2tpcnRzOwogICAgY29uc3QgcGFyZW50TWluaW11bUhlaWdodCA9IHBhcmFtZXRlcnMubWluaW11bUhlaWdodDsKICAgIGNvbnN0IHBhcmVudE1heGltdW1IZWlnaHQgPSBwYXJhbWV0ZXJzLm1heGltdW1IZWlnaHQ7CiAgICBjb25zdCBwYXJlbnRVQnVmZmVyID0gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KTsKICAgIGNvbnN0IHBhcmVudFZCdWZmZXIgPSBuZXcgQXJyYXkocXVhbnRpemVkVmVydGV4Q291bnQpOwogICAgY29uc3QgcGFyZW50SGVpZ2h0QnVmZmVyID0gbmV3IEFycmF5KHF1YW50aXplZFZlcnRleENvdW50KTsKICAgIGNvbnN0IHBhcmVudE5vcm1hbEJ1ZmZlciA9IGhhc1ZlcnRleE5vcm1hbHMgPyBuZXcgQXJyYXkocXVhbnRpemVkVmVydGV4Q291bnQgKiAyKSA6IHZvaWQgMDsKICAgIGNvbnN0IHRocmVzaG9sZCA9IDIwOwogICAgbGV0IGhlaWdodDsKICAgIGxldCBpMiwgbjI7CiAgICBsZXQgdTQsIHY0OwogICAgZm9yIChpMiA9IDAsIG4yID0gMDsgaTIgPCBxdWFudGl6ZWRWZXJ0ZXhDb3VudDsgKytpMiwgbjIgKz0gMikgewogICAgICBjb25zdCB0ZXhDb29yZHMgPSBlbmNvZGluZy5kZWNvZGVUZXh0dXJlQ29vcmRpbmF0ZXMoCiAgICAgICAgcGFyZW50VmVydGljZXMsCiAgICAgICAgaTIsCiAgICAgICAgZGVjb2RlVGV4Q29vcmRzU2NyYXRjaAogICAgICApOwogICAgICBoZWlnaHQgPSBlbmNvZGluZy5kZWNvZGVIZWlnaHQocGFyZW50VmVydGljZXMsIGkyKTsKICAgICAgdTQgPSBNYXRoX2RlZmF1bHQuY2xhbXAodGV4Q29vcmRzLnggKiBtYXhTaG9ydDUgfCAwLCAwLCBtYXhTaG9ydDUpOwogICAgICB2NCA9IE1hdGhfZGVmYXVsdC5jbGFtcCh0ZXhDb29yZHMueSAqIG1heFNob3J0NSB8IDAsIDAsIG1heFNob3J0NSk7CiAgICAgIHBhcmVudEhlaWdodEJ1ZmZlcltpMl0gPSBNYXRoX2RlZmF1bHQuY2xhbXAoCiAgICAgICAgKGhlaWdodCAtIHBhcmVudE1pbmltdW1IZWlnaHQpIC8gKHBhcmVudE1heGltdW1IZWlnaHQgLSBwYXJlbnRNaW5pbXVtSGVpZ2h0KSAqIG1heFNob3J0NSB8IDAsCiAgICAgICAgMCwKICAgICAgICBtYXhTaG9ydDUKICAgICAgKTsKICAgICAgaWYgKHU0IDwgdGhyZXNob2xkKSB7CiAgICAgICAgdTQgPSAwOwogICAgICB9CiAgICAgIGlmICh2NCA8IHRocmVzaG9sZCkgewogICAgICAgIHY0ID0gMDsKICAgICAgfQogICAgICBpZiAobWF4U2hvcnQ1IC0gdTQgPCB0aHJlc2hvbGQpIHsKICAgICAgICB1NCA9IG1heFNob3J0NTsKICAgICAgfQogICAgICBpZiAobWF4U2hvcnQ1IC0gdjQgPCB0aHJlc2hvbGQpIHsKICAgICAgICB2NCA9IG1heFNob3J0NTsKICAgICAgfQogICAgICBwYXJlbnRVQnVmZmVyW2kyXSA9IHU0OwogICAgICBwYXJlbnRWQnVmZmVyW2kyXSA9IHY0OwogICAgICBpZiAoaGFzVmVydGV4Tm9ybWFscykgewogICAgICAgIGNvbnN0IGVuY29kZWROb3JtYWwgPSBlbmNvZGluZy5nZXRPY3RFbmNvZGVkTm9ybWFsKAogICAgICAgICAgcGFyZW50VmVydGljZXMsCiAgICAgICAgICBpMiwKICAgICAgICAgIG9jdEVuY29kZWROb3JtYWxTY3JhdGNoCiAgICAgICAgKTsKICAgICAgICBwYXJlbnROb3JtYWxCdWZmZXJbbjJdID0gZW5jb2RlZE5vcm1hbC54OwogICAgICAgIHBhcmVudE5vcm1hbEJ1ZmZlcltuMiArIDFdID0gZW5jb2RlZE5vcm1hbC55OwogICAgICB9CiAgICAgIGlmICgoaXNFYXN0Q2hpbGQgJiYgdTQgPj0gaGFsZk1heFNob3J0IHx8ICFpc0Vhc3RDaGlsZCAmJiB1NCA8PSBoYWxmTWF4U2hvcnQpICYmIChpc05vcnRoQ2hpbGQgJiYgdjQgPj0gaGFsZk1heFNob3J0IHx8ICFpc05vcnRoQ2hpbGQgJiYgdjQgPD0gaGFsZk1heFNob3J0KSkgewogICAgICAgIHZlcnRleE1hcFtpMl0gPSB2ZXJ0ZXhDb3VudDsKICAgICAgICB1QnVmZmVyLnB1c2godTQpOwogICAgICAgIHZCdWZmZXIucHVzaCh2NCk7CiAgICAgICAgaGVpZ2h0QnVmZmVyLnB1c2gocGFyZW50SGVpZ2h0QnVmZmVyW2kyXSk7CiAgICAgICAgaWYgKGhhc1ZlcnRleE5vcm1hbHMpIHsKICAgICAgICAgIG5vcm1hbEJ1ZmZlci5wdXNoKHBhcmVudE5vcm1hbEJ1ZmZlcltuMl0pOwogICAgICAgICAgbm9ybWFsQnVmZmVyLnB1c2gocGFyZW50Tm9ybWFsQnVmZmVyW24yICsgMV0pOwogICAgICAgIH0KICAgICAgICArK3ZlcnRleENvdW50OwogICAgICB9CiAgICB9CiAgICBjb25zdCB0cmlhbmdsZVZlcnRpY2VzID0gW107CiAgICB0cmlhbmdsZVZlcnRpY2VzLnB1c2gobmV3IFZlcnRleCgpKTsKICAgIHRyaWFuZ2xlVmVydGljZXMucHVzaChuZXcgVmVydGV4KCkpOwogICAgdHJpYW5nbGVWZXJ0aWNlcy5wdXNoKG5ldyBWZXJ0ZXgoKSk7CiAgICBjb25zdCBjbGlwcGVkVHJpYW5nbGVWZXJ0aWNlcyA9IFtdOwogICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXMucHVzaChuZXcgVmVydGV4KCkpOwogICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXMucHVzaChuZXcgVmVydGV4KCkpOwogICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXMucHVzaChuZXcgVmVydGV4KCkpOwogICAgbGV0IGNsaXBwZWRJbmRleDsKICAgIGxldCBjbGlwcGVkMjsKICAgIGZvciAoaTIgPSAwOyBpMiA8IHBhcmVudEluZGljZXMubGVuZ3RoOyBpMiArPSAzKSB7CiAgICAgIGNvbnN0IGkwID0gcGFyZW50SW5kaWNlc1tpMl07CiAgICAgIGNvbnN0IGkxID0gcGFyZW50SW5kaWNlc1tpMiArIDFdOwogICAgICBjb25zdCBpMjIgPSBwYXJlbnRJbmRpY2VzW2kyICsgMl07CiAgICAgIGNvbnN0IHUwID0gcGFyZW50VUJ1ZmZlcltpMF07CiAgICAgIGNvbnN0IHUxMiA9IHBhcmVudFVCdWZmZXJbaTFdOwogICAgICBjb25zdCB1MjIgPSBwYXJlbnRVQnVmZmVyW2kyMl07CiAgICAgIHRyaWFuZ2xlVmVydGljZXNbMF0uaW5pdGlhbGl6ZUluZGV4ZWQoCiAgICAgICAgcGFyZW50VUJ1ZmZlciwKICAgICAgICBwYXJlbnRWQnVmZmVyLAogICAgICAgIHBhcmVudEhlaWdodEJ1ZmZlciwKICAgICAgICBwYXJlbnROb3JtYWxCdWZmZXIsCiAgICAgICAgaTAKICAgICAgKTsKICAgICAgdHJpYW5nbGVWZXJ0aWNlc1sxXS5pbml0aWFsaXplSW5kZXhlZCgKICAgICAgICBwYXJlbnRVQnVmZmVyLAogICAgICAgIHBhcmVudFZCdWZmZXIsCiAgICAgICAgcGFyZW50SGVpZ2h0QnVmZmVyLAogICAgICAgIHBhcmVudE5vcm1hbEJ1ZmZlciwKICAgICAgICBpMQogICAgICApOwogICAgICB0cmlhbmdsZVZlcnRpY2VzWzJdLmluaXRpYWxpemVJbmRleGVkKAogICAgICAgIHBhcmVudFVCdWZmZXIsCiAgICAgICAgcGFyZW50VkJ1ZmZlciwKICAgICAgICBwYXJlbnRIZWlnaHRCdWZmZXIsCiAgICAgICAgcGFyZW50Tm9ybWFsQnVmZmVyLAogICAgICAgIGkyMgogICAgICApOwogICAgICBjb25zdCBjbGlwcGVkID0gSW50ZXJzZWN0aW9uczJEX2RlZmF1bHQuY2xpcFRyaWFuZ2xlQXRBeGlzQWxpZ25lZFRocmVzaG9sZCgKICAgICAgICBoYWxmTWF4U2hvcnQsCiAgICAgICAgaXNFYXN0Q2hpbGQsCiAgICAgICAgdTAsCiAgICAgICAgdTEyLAogICAgICAgIHUyMiwKICAgICAgICBjbGlwU2NyYXRjaAogICAgICApOwogICAgICBjbGlwcGVkSW5kZXggPSAwOwogICAgICBpZiAoY2xpcHBlZEluZGV4ID49IGNsaXBwZWQubGVuZ3RoKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KICAgICAgY2xpcHBlZEluZGV4ID0gY2xpcHBlZFRyaWFuZ2xlVmVydGljZXNbMF0uaW5pdGlhbGl6ZUZyb21DbGlwUmVzdWx0KAogICAgICAgIGNsaXBwZWQsCiAgICAgICAgY2xpcHBlZEluZGV4LAogICAgICAgIHRyaWFuZ2xlVmVydGljZXMKICAgICAgKTsKICAgICAgaWYgKGNsaXBwZWRJbmRleCA+PSBjbGlwcGVkLmxlbmd0aCkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CiAgICAgIGNsaXBwZWRJbmRleCA9IGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzWzFdLmluaXRpYWxpemVGcm9tQ2xpcFJlc3VsdCgKICAgICAgICBjbGlwcGVkLAogICAgICAgIGNsaXBwZWRJbmRleCwKICAgICAgICB0cmlhbmdsZVZlcnRpY2VzCiAgICAgICk7CiAgICAgIGlmIChjbGlwcGVkSW5kZXggPj0gY2xpcHBlZC5sZW5ndGgpIHsKICAgICAgICBjb250aW51ZTsKICAgICAgfQogICAgICBjbGlwcGVkSW5kZXggPSBjbGlwcGVkVHJpYW5nbGVWZXJ0aWNlc1syXS5pbml0aWFsaXplRnJvbUNsaXBSZXN1bHQoCiAgICAgICAgY2xpcHBlZCwKICAgICAgICBjbGlwcGVkSW5kZXgsCiAgICAgICAgdHJpYW5nbGVWZXJ0aWNlcwogICAgICApOwogICAgICBjbGlwcGVkMiA9IEludGVyc2VjdGlvbnMyRF9kZWZhdWx0LmNsaXBUcmlhbmdsZUF0QXhpc0FsaWduZWRUaHJlc2hvbGQoCiAgICAgICAgaGFsZk1heFNob3J0LAogICAgICAgIGlzTm9ydGhDaGlsZCwKICAgICAgICBjbGlwcGVkVHJpYW5nbGVWZXJ0aWNlc1swXS5nZXRWKCksCiAgICAgICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXNbMV0uZ2V0VigpLAogICAgICAgIGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzWzJdLmdldFYoKSwKICAgICAgICBjbGlwU2NyYXRjaDIKICAgICAgKTsKICAgICAgYWRkQ2xpcHBlZFBvbHlnb24oCiAgICAgICAgdUJ1ZmZlciwKICAgICAgICB2QnVmZmVyLAogICAgICAgIGhlaWdodEJ1ZmZlciwKICAgICAgICBub3JtYWxCdWZmZXIsCiAgICAgICAgaW5kaWNlcywKICAgICAgICB2ZXJ0ZXhNYXAsCiAgICAgICAgY2xpcHBlZDIsCiAgICAgICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXMsCiAgICAgICAgaGFzVmVydGV4Tm9ybWFscwogICAgICApOwogICAgICBpZiAoY2xpcHBlZEluZGV4IDwgY2xpcHBlZC5sZW5ndGgpIHsKICAgICAgICBjbGlwcGVkVHJpYW5nbGVWZXJ0aWNlc1syXS5jbG9uZShjbGlwcGVkVHJpYW5nbGVWZXJ0aWNlc1sxXSk7CiAgICAgICAgY2xpcHBlZFRyaWFuZ2xlVmVydGljZXNbMl0uaW5pdGlhbGl6ZUZyb21DbGlwUmVzdWx0KAogICAgICAgICAgY2xpcHBlZCwKICAgICAgICAgIGNsaXBwZWRJbmRleCwKICAgICAgICAgIHRyaWFuZ2xlVmVydGljZXMKICAgICAgICApOwogICAgICAgIGNsaXBwZWQyID0gSW50ZXJzZWN0aW9uczJEX2RlZmF1bHQuY2xpcFRyaWFuZ2xlQXRBeGlzQWxpZ25lZFRocmVzaG9sZCgKICAgICAgICAgIGhhbGZNYXhTaG9ydCwKICAgICAgICAgIGlzTm9ydGhDaGlsZCwKICAgICAgICAgIGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzWzBdLmdldFYoKSwKICAgICAgICAgIGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzWzFdLmdldFYoKSwKICAgICAgICAgIGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzWzJdLmdldFYoKSwKICAgICAgICAgIGNsaXBTY3JhdGNoMgogICAgICAgICk7CiAgICAgICAgYWRkQ2xpcHBlZFBvbHlnb24oCiAgICAgICAgICB1QnVmZmVyLAogICAgICAgICAgdkJ1ZmZlciwKICAgICAgICAgIGhlaWdodEJ1ZmZlciwKICAgICAgICAgIG5vcm1hbEJ1ZmZlciwKICAgICAgICAgIGluZGljZXMsCiAgICAgICAgICB2ZXJ0ZXhNYXAsCiAgICAgICAgICBjbGlwcGVkMiwKICAgICAgICAgIGNsaXBwZWRUcmlhbmdsZVZlcnRpY2VzLAogICAgICAgICAgaGFzVmVydGV4Tm9ybWFscwogICAgICAgICk7CiAgICAgIH0KICAgIH0KICAgIGNvbnN0IHVPZmZzZXQgPSBpc0Vhc3RDaGlsZCA/IC1tYXhTaG9ydDUgOiAwOwogICAgY29uc3Qgdk9mZnNldCA9IGlzTm9ydGhDaGlsZCA/IC1tYXhTaG9ydDUgOiAwOwogICAgY29uc3Qgd2VzdEluZGljZXMgPSBbXTsKICAgIGNvbnN0IHNvdXRoSW5kaWNlcyA9IFtdOwogICAgY29uc3QgZWFzdEluZGljZXMgPSBbXTsKICAgIGNvbnN0IG5vcnRoSW5kaWNlcyA9IFtdOwogICAgbGV0IG1pbmltdW1IZWlnaHQgPSBOdW1iZXIuTUFYX1ZBTFVFOwogICAgbGV0IG1heGltdW1IZWlnaHQgPSAtbWluaW11bUhlaWdodDsKICAgIGNvbnN0IGNhcnRlc2lhblZlcnRpY2VzID0gdmVydGljZXNTY3JhdGNoOwogICAgY2FydGVzaWFuVmVydGljZXMubGVuZ3RoID0gMDsKICAgIGNvbnN0IGVsbGlwc29pZCA9IEVsbGlwc29pZF9kZWZhdWx0LmNsb25lKHBhcmFtZXRlcnMuZWxsaXBzb2lkKTsKICAgIGNvbnN0IHJlY3RhbmdsZSA9IFJlY3RhbmdsZV9kZWZhdWx0LmNsb25lKHBhcmFtZXRlcnMuY2hpbGRSZWN0YW5nbGUpOwogICAgY29uc3Qgbm9ydGggPSByZWN0YW5nbGUubm9ydGg7CiAgICBjb25zdCBzb3V0aCA9IHJlY3RhbmdsZS5zb3V0aDsKICAgIGxldCBlYXN0ID0gcmVjdGFuZ2xlLmVhc3Q7CiAgICBjb25zdCB3ZXN0ID0gcmVjdGFuZ2xlLndlc3Q7CiAgICBpZiAoZWFzdCA8IHdlc3QpIHsKICAgICAgZWFzdCArPSBNYXRoX2RlZmF1bHQuVFdPX1BJOwogICAgfQogICAgZm9yIChpMiA9IDA7IGkyIDwgdUJ1ZmZlci5sZW5ndGg7ICsraTIpIHsKICAgICAgdTQgPSBNYXRoLnJvdW5kKHVCdWZmZXJbaTJdKTsKICAgICAgaWYgKHU0IDw9IG1pblUpIHsKICAgICAgICB3ZXN0SW5kaWNlcy5wdXNoKGkyKTsKICAgICAgICB1NCA9IDA7CiAgICAgIH0gZWxzZSBpZiAodTQgPj0gbWF4VSkgewogICAgICAgIGVhc3RJbmRpY2VzLnB1c2goaTIpOwogICAgICAgIHU0ID0gbWF4U2hvcnQ1OwogICAgICB9IGVsc2UgewogICAgICAgIHU0ID0gdTQgKiAyICsgdU9mZnNldDsKICAgICAgfQogICAgICB1QnVmZmVyW2kyXSA9IHU0OwogICAgICB2NCA9IE1hdGgucm91bmQodkJ1ZmZlcltpMl0pOwogICAgICBpZiAodjQgPD0gbWluVikgewogICAgICAgIHNvdXRoSW5kaWNlcy5wdXNoKGkyKTsKICAgICAgICB2NCA9IDA7CiAgICAgIH0gZWxzZSBpZiAodjQgPj0gbWF4VikgewogICAgICAgIG5vcnRoSW5kaWNlcy5wdXNoKGkyKTsKICAgICAgICB2NCA9IG1heFNob3J0NTsKICAgICAgfSBlbHNlIHsKICAgICAgICB2NCA9IHY0ICogMiArIHZPZmZzZXQ7CiAgICAgIH0KICAgICAgdkJ1ZmZlcltpMl0gPSB2NDsKICAgICAgaGVpZ2h0ID0gTWF0aF9kZWZhdWx0LmxlcnAoCiAgICAgICAgcGFyZW50TWluaW11bUhlaWdodCwKICAgICAgICBwYXJlbnRNYXhpbXVtSGVpZ2h0LAogICAgICAgIGhlaWdodEJ1ZmZlcltpMl0gLyBtYXhTaG9ydDUKICAgICAgKTsKICAgICAgaWYgKGhlaWdodCA8IG1pbmltdW1IZWlnaHQpIHsKICAgICAgICBtaW5pbXVtSGVpZ2h0ID0gaGVpZ2h0OwogICAgICB9CiAgICAgIGlmIChoZWlnaHQgPiBtYXhpbXVtSGVpZ2h0KSB7CiAgICAgICAgbWF4aW11bUhlaWdodCA9IGhlaWdodDsKICAgICAgfQogICAgICBoZWlnaHRCdWZmZXJbaTJdID0gaGVpZ2h0OwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoMi5sb25naXR1ZGUgPSBNYXRoX2RlZmF1bHQubGVycCh3ZXN0LCBlYXN0LCB1NCAvIG1heFNob3J0NSk7CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gyLmxhdGl0dWRlID0gTWF0aF9kZWZhdWx0LmxlcnAoc291dGgsIG5vcnRoLCB2NCAvIG1heFNob3J0NSk7CiAgICAgIGNhcnRvZ3JhcGhpY1NjcmF0Y2gyLmhlaWdodCA9IGhlaWdodDsKICAgICAgZWxsaXBzb2lkLmNhcnRvZ3JhcGhpY1RvQ2FydGVzaWFuKGNhcnRvZ3JhcGhpY1NjcmF0Y2gyLCBjYXJ0ZXNpYW4zU2NyYXRjaDkpOwogICAgICBjYXJ0ZXNpYW5WZXJ0aWNlcy5wdXNoKGNhcnRlc2lhbjNTY3JhdGNoOS54KTsKICAgICAgY2FydGVzaWFuVmVydGljZXMucHVzaChjYXJ0ZXNpYW4zU2NyYXRjaDkueSk7CiAgICAgIGNhcnRlc2lhblZlcnRpY2VzLnB1c2goY2FydGVzaWFuM1NjcmF0Y2g5LnopOwogICAgfQogICAgY29uc3QgYm91bmRpbmdTcGhlcmUgPSBCb3VuZGluZ1NwaGVyZV9kZWZhdWx0LmZyb21WZXJ0aWNlcygKICAgICAgY2FydGVzaWFuVmVydGljZXMsCiAgICAgIENhcnRlc2lhbjNfZGVmYXVsdC5aRVJPLAogICAgICAzLAogICAgICBib3VuZGluZ1NwaGVyZVNjcmF0Y2gKICAgICk7CiAgICBjb25zdCBvcmllbnRlZEJvdW5kaW5nQm94ID0gT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0LmZyb21SZWN0YW5nbGUoCiAgICAgIHJlY3RhbmdsZSwKICAgICAgbWluaW11bUhlaWdodCwKICAgICAgbWF4aW11bUhlaWdodCwKICAgICAgZWxsaXBzb2lkLAogICAgICBvcmllbnRlZEJvdW5kaW5nQm94U2NyYXRjaAogICAgKTsKICAgIGNvbnN0IG9jY2x1ZGVyID0gbmV3IEVsbGlwc29pZGFsT2NjbHVkZXJfZGVmYXVsdChlbGxpcHNvaWQpOwogICAgY29uc3QgaG9yaXpvbk9jY2x1c2lvblBvaW50ID0gb2NjbHVkZXIuY29tcHV0ZUhvcml6b25DdWxsaW5nUG9pbnRGcm9tVmVydGljZXNQb3NzaWJseVVuZGVyRWxsaXBzb2lkKAogICAgICBib3VuZGluZ1NwaGVyZS5jZW50ZXIsCiAgICAgIGNhcnRlc2lhblZlcnRpY2VzLAogICAgICAzLAogICAgICBib3VuZGluZ1NwaGVyZS5jZW50ZXIsCiAgICAgIG1pbmltdW1IZWlnaHQsCiAgICAgIGhvcml6b25PY2NsdXNpb25Qb2ludFNjcmF0Y2gKICAgICk7CiAgICBjb25zdCBoZWlnaHRSYW5nZSA9IG1heGltdW1IZWlnaHQgLSBtaW5pbXVtSGVpZ2h0OwogICAgY29uc3QgdmVydGljZXMgPSBuZXcgVWludDE2QXJyYXkoCiAgICAgIHVCdWZmZXIubGVuZ3RoICsgdkJ1ZmZlci5sZW5ndGggKyBoZWlnaHRCdWZmZXIubGVuZ3RoCiAgICApOwogICAgZm9yIChpMiA9IDA7IGkyIDwgdUJ1ZmZlci5sZW5ndGg7ICsraTIpIHsKICAgICAgdmVydGljZXNbaTJdID0gdUJ1ZmZlcltpMl07CiAgICB9CiAgICBsZXQgc3RhcnQgPSB1QnVmZmVyLmxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IHZCdWZmZXIubGVuZ3RoOyArK2kyKSB7CiAgICAgIHZlcnRpY2VzW3N0YXJ0ICsgaTJdID0gdkJ1ZmZlcltpMl07CiAgICB9CiAgICBzdGFydCArPSB2QnVmZmVyLmxlbmd0aDsKICAgIGZvciAoaTIgPSAwOyBpMiA8IGhlaWdodEJ1ZmZlci5sZW5ndGg7ICsraTIpIHsKICAgICAgdmVydGljZXNbc3RhcnQgKyBpMl0gPSBtYXhTaG9ydDUgKiAoaGVpZ2h0QnVmZmVyW2kyXSAtIG1pbmltdW1IZWlnaHQpIC8gaGVpZ2h0UmFuZ2U7CiAgICB9CiAgICBjb25zdCBpbmRpY2VzVHlwZWRBcnJheSA9IEluZGV4RGF0YXR5cGVfZGVmYXVsdC5jcmVhdGVUeXBlZEFycmF5KAogICAgICB1QnVmZmVyLmxlbmd0aCwKICAgICAgaW5kaWNlcwogICAgKTsKICAgIGxldCBlbmNvZGVkTm9ybWFsczsKICAgIGlmIChoYXNWZXJ0ZXhOb3JtYWxzKSB7CiAgICAgIGNvbnN0IG5vcm1hbEFycmF5ID0gbmV3IFVpbnQ4QXJyYXkobm9ybWFsQnVmZmVyKTsKICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICAgIHZlcnRpY2VzLmJ1ZmZlciwKICAgICAgICBpbmRpY2VzVHlwZWRBcnJheS5idWZmZXIsCiAgICAgICAgbm9ybWFsQXJyYXkuYnVmZmVyCiAgICAgICk7CiAgICAgIGVuY29kZWROb3JtYWxzID0gbm9ybWFsQXJyYXkuYnVmZmVyOwogICAgfSBlbHNlIHsKICAgICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKHZlcnRpY2VzLmJ1ZmZlciwgaW5kaWNlc1R5cGVkQXJyYXkuYnVmZmVyKTsKICAgIH0KICAgIHJldHVybiB7CiAgICAgIHZlcnRpY2VzOiB2ZXJ0aWNlcy5idWZmZXIsCiAgICAgIGVuY29kZWROb3JtYWxzLAogICAgICBpbmRpY2VzOiBpbmRpY2VzVHlwZWRBcnJheS5idWZmZXIsCiAgICAgIG1pbmltdW1IZWlnaHQsCiAgICAgIG1heGltdW1IZWlnaHQsCiAgICAgIHdlc3RJbmRpY2VzLAogICAgICBzb3V0aEluZGljZXMsCiAgICAgIGVhc3RJbmRpY2VzLAogICAgICBub3J0aEluZGljZXMsCiAgICAgIGJvdW5kaW5nU3BoZXJlLAogICAgICBvcmllbnRlZEJvdW5kaW5nQm94LAogICAgICBob3Jpem9uT2NjbHVzaW9uUG9pbnQKICAgIH07CiAgfQogIGZ1bmN0aW9uIFZlcnRleCgpIHsKICAgIHRoaXMudmVydGV4QnVmZmVyID0gdm9pZCAwOwogICAgdGhpcy5pbmRleCA9IHZvaWQgMDsKICAgIHRoaXMuZmlyc3QgPSB2b2lkIDA7CiAgICB0aGlzLnNlY29uZCA9IHZvaWQgMDsKICAgIHRoaXMucmF0aW8gPSB2b2lkIDA7CiAgfQogIGZ1bmN0aW9uIGxlcnBPY3RFbmNvZGVkTm9ybWFsKHZlcnRleCwgcmVzdWx0KSB7CiAgICArK2RlcHRoOwogICAgbGV0IGZpcnN0ID0gY2FydGVzaWFuU2NyYXRjaDFbZGVwdGhdOwogICAgbGV0IHNlY29uZCA9IGNhcnRlc2lhblNjcmF0Y2gyW2RlcHRoXTsKICAgIGZpcnN0ID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5vY3REZWNvZGUoCiAgICAgIHZlcnRleC5maXJzdC5nZXROb3JtYWxYKCksCiAgICAgIHZlcnRleC5maXJzdC5nZXROb3JtYWxZKCksCiAgICAgIGZpcnN0CiAgICApOwogICAgc2Vjb25kID0gQXR0cmlidXRlQ29tcHJlc3Npb25fZGVmYXVsdC5vY3REZWNvZGUoCiAgICAgIHZlcnRleC5zZWNvbmQuZ2V0Tm9ybWFsWCgpLAogICAgICB2ZXJ0ZXguc2Vjb25kLmdldE5vcm1hbFkoKSwKICAgICAgc2Vjb25kCiAgICApOwogICAgY2FydGVzaWFuM1NjcmF0Y2g5ID0gQ2FydGVzaWFuM19kZWZhdWx0LmxlcnAoCiAgICAgIGZpcnN0LAogICAgICBzZWNvbmQsCiAgICAgIHZlcnRleC5yYXRpbywKICAgICAgY2FydGVzaWFuM1NjcmF0Y2g5CiAgICApOwogICAgQ2FydGVzaWFuM19kZWZhdWx0Lm5vcm1hbGl6ZShjYXJ0ZXNpYW4zU2NyYXRjaDksIGNhcnRlc2lhbjNTY3JhdGNoOSk7CiAgICBBdHRyaWJ1dGVDb21wcmVzc2lvbl9kZWZhdWx0Lm9jdEVuY29kZShjYXJ0ZXNpYW4zU2NyYXRjaDksIHJlc3VsdCk7CiAgICAtLWRlcHRoOwogICAgcmV0dXJuIHJlc3VsdDsKICB9CiAgZnVuY3Rpb24gYWRkQ2xpcHBlZFBvbHlnb24odUJ1ZmZlciwgdkJ1ZmZlciwgaGVpZ2h0QnVmZmVyLCBub3JtYWxCdWZmZXIsIGluZGljZXMsIHZlcnRleE1hcCwgY2xpcHBlZCwgdHJpYW5nbGVWZXJ0aWNlcywgaGFzVmVydGV4Tm9ybWFscykgewogICAgaWYgKGNsaXBwZWQubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGxldCBudW1WZXJ0aWNlcyA9IDA7CiAgICBsZXQgY2xpcHBlZEluZGV4ID0gMDsKICAgIHdoaWxlIChjbGlwcGVkSW5kZXggPCBjbGlwcGVkLmxlbmd0aCkgewogICAgICBjbGlwcGVkSW5kZXggPSBwb2x5Z29uVmVydGljZXNbbnVtVmVydGljZXMrK10uaW5pdGlhbGl6ZUZyb21DbGlwUmVzdWx0KAogICAgICAgIGNsaXBwZWQsCiAgICAgICAgY2xpcHBlZEluZGV4LAogICAgICAgIHRyaWFuZ2xlVmVydGljZXMKICAgICAgKTsKICAgIH0KICAgIGZvciAobGV0IGkyID0gMDsgaTIgPCBudW1WZXJ0aWNlczsgKytpMikgewogICAgICBjb25zdCBwb2x5Z29uVmVydGV4ID0gcG9seWdvblZlcnRpY2VzW2kyXTsKICAgICAgaWYgKCFwb2x5Z29uVmVydGV4LmlzSW5kZXhlZCgpKSB7CiAgICAgICAgY29uc3Qga2V5ID0gcG9seWdvblZlcnRleC5nZXRLZXkoKTsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHZlcnRleE1hcFtrZXldKSkgewogICAgICAgICAgcG9seWdvblZlcnRleC5uZXdJbmRleCA9IHZlcnRleE1hcFtrZXldOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBjb25zdCBuZXdJbmRleCA9IHVCdWZmZXIubGVuZ3RoOwogICAgICAgICAgdUJ1ZmZlci5wdXNoKHBvbHlnb25WZXJ0ZXguZ2V0VSgpKTsKICAgICAgICAgIHZCdWZmZXIucHVzaChwb2x5Z29uVmVydGV4LmdldFYoKSk7CiAgICAgICAgICBoZWlnaHRCdWZmZXIucHVzaChwb2x5Z29uVmVydGV4LmdldEgoKSk7CiAgICAgICAgICBpZiAoaGFzVmVydGV4Tm9ybWFscykgewogICAgICAgICAgICBub3JtYWxCdWZmZXIucHVzaChwb2x5Z29uVmVydGV4LmdldE5vcm1hbFgoKSk7CiAgICAgICAgICAgIG5vcm1hbEJ1ZmZlci5wdXNoKHBvbHlnb25WZXJ0ZXguZ2V0Tm9ybWFsWSgpKTsKICAgICAgICAgIH0KICAgICAgICAgIHBvbHlnb25WZXJ0ZXgubmV3SW5kZXggPSBuZXdJbmRleDsKICAgICAgICAgIHZlcnRleE1hcFtrZXldID0gbmV3SW5kZXg7CiAgICAgICAgfQogICAgICB9IGVsc2UgewogICAgICAgIHBvbHlnb25WZXJ0ZXgubmV3SW5kZXggPSB2ZXJ0ZXhNYXBbcG9seWdvblZlcnRleC5pbmRleF07CiAgICAgICAgcG9seWdvblZlcnRleC51QnVmZmVyID0gdUJ1ZmZlcjsKICAgICAgICBwb2x5Z29uVmVydGV4LnZCdWZmZXIgPSB2QnVmZmVyOwogICAgICAgIHBvbHlnb25WZXJ0ZXguaGVpZ2h0QnVmZmVyID0gaGVpZ2h0QnVmZmVyOwogICAgICAgIGlmIChoYXNWZXJ0ZXhOb3JtYWxzKSB7CiAgICAgICAgICBwb2x5Z29uVmVydGV4Lm5vcm1hbEJ1ZmZlciA9IG5vcm1hbEJ1ZmZlcjsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIGlmIChudW1WZXJ0aWNlcyA9PT0gMykgewogICAgICBpbmRpY2VzLnB1c2gocG9seWdvblZlcnRpY2VzWzBdLm5ld0luZGV4KTsKICAgICAgaW5kaWNlcy5wdXNoKHBvbHlnb25WZXJ0aWNlc1sxXS5uZXdJbmRleCk7CiAgICAgIGluZGljZXMucHVzaChwb2x5Z29uVmVydGljZXNbMl0ubmV3SW5kZXgpOwogICAgfSBlbHNlIGlmIChudW1WZXJ0aWNlcyA9PT0gNCkgewogICAgICBpbmRpY2VzLnB1c2gocG9seWdvblZlcnRpY2VzWzBdLm5ld0luZGV4KTsKICAgICAgaW5kaWNlcy5wdXNoKHBvbHlnb25WZXJ0aWNlc1sxXS5uZXdJbmRleCk7CiAgICAgIGluZGljZXMucHVzaChwb2x5Z29uVmVydGljZXNbMl0ubmV3SW5kZXgpOwogICAgICBpbmRpY2VzLnB1c2gocG9seWdvblZlcnRpY2VzWzBdLm5ld0luZGV4KTsKICAgICAgaW5kaWNlcy5wdXNoKHBvbHlnb25WZXJ0aWNlc1syXS5uZXdJbmRleCk7CiAgICAgIGluZGljZXMucHVzaChwb2x5Z29uVmVydGljZXNbM10ubmV3SW5kZXgpOwogICAgfQogIH0KICB2YXIgbWF4U2hvcnQ1LCBoYWxmTWF4U2hvcnQsIGNsaXBTY3JhdGNoLCBjbGlwU2NyYXRjaDIsIHZlcnRpY2VzU2NyYXRjaCwgY2FydG9ncmFwaGljU2NyYXRjaDIsIGNhcnRlc2lhbjNTY3JhdGNoOSwgdVNjcmF0Y2gsIHZTY3JhdGNoLCBoZWlnaHRTY3JhdGNoLCBpbmRpY2VzU2NyYXRjaCwgbm9ybWFsc1NjcmF0Y2gsIGhvcml6b25PY2NsdXNpb25Qb2ludFNjcmF0Y2gsIGJvdW5kaW5nU3BoZXJlU2NyYXRjaCwgb3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2gsIGRlY29kZVRleENvb3Jkc1NjcmF0Y2gsIG9jdEVuY29kZWROb3JtYWxTY3JhdGNoLCBlbmNvZGVkU2NyYXRjaCwgZGVwdGgsIGNhcnRlc2lhblNjcmF0Y2gxLCBjYXJ0ZXNpYW5TY3JhdGNoMiwgcG9seWdvblZlcnRpY2VzLCB1cHNhbXBsZVF1YW50aXplZFRlcnJhaW5NZXNoX2RlZmF1bHQ7CiAgdmFyIGluaXRfdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaCA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaC5qcyIoKSB7CiAgICAgIGluaXRfQXR0cmlidXRlQ29tcHJlc3Npb24oKTsKICAgICAgaW5pdF9Cb3VuZGluZ1NwaGVyZSgpOwogICAgICBpbml0X0NhcnRlc2lhbjIoKTsKICAgICAgaW5pdF9DYXJ0ZXNpYW4zKCk7CiAgICAgIGluaXRfQ2FydG9ncmFwaGljKCk7CiAgICAgIGluaXRfZGVmaW5lZCgpOwogICAgICBpbml0X0VsbGlwc29pZCgpOwogICAgICBpbml0X0VsbGlwc29pZGFsT2NjbHVkZXIoKTsKICAgICAgaW5pdF9JbmRleERhdGF0eXBlKCk7CiAgICAgIGluaXRfSW50ZXJzZWN0aW9uczJEKCk7CiAgICAgIGluaXRfTWF0aCgpOwogICAgICBpbml0X09yaWVudGVkQm91bmRpbmdCb3goKTsKICAgICAgaW5pdF9SZWN0YW5nbGUoKTsKICAgICAgaW5pdF9UZXJyYWluRW5jb2RpbmcoKTsKICAgICAgaW5pdF9jcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyKCk7CiAgICAgIG1heFNob3J0NSA9IDMyNzY3OwogICAgICBoYWxmTWF4U2hvcnQgPSBtYXhTaG9ydDUgLyAyIHwgMDsKICAgICAgY2xpcFNjcmF0Y2ggPSBbXTsKICAgICAgY2xpcFNjcmF0Y2gyID0gW107CiAgICAgIHZlcnRpY2VzU2NyYXRjaCA9IFtdOwogICAgICBjYXJ0b2dyYXBoaWNTY3JhdGNoMiA9IG5ldyBDYXJ0b2dyYXBoaWNfZGVmYXVsdCgpOwogICAgICBjYXJ0ZXNpYW4zU2NyYXRjaDkgPSBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCk7CiAgICAgIHVTY3JhdGNoID0gW107CiAgICAgIHZTY3JhdGNoID0gW107CiAgICAgIGhlaWdodFNjcmF0Y2ggPSBbXTsKICAgICAgaW5kaWNlc1NjcmF0Y2ggPSBbXTsKICAgICAgbm9ybWFsc1NjcmF0Y2ggPSBbXTsKICAgICAgaG9yaXpvbk9jY2x1c2lvblBvaW50U2NyYXRjaCA9IG5ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKTsKICAgICAgYm91bmRpbmdTcGhlcmVTY3JhdGNoID0gbmV3IEJvdW5kaW5nU3BoZXJlX2RlZmF1bHQoKTsKICAgICAgb3JpZW50ZWRCb3VuZGluZ0JveFNjcmF0Y2ggPSBuZXcgT3JpZW50ZWRCb3VuZGluZ0JveF9kZWZhdWx0KCk7CiAgICAgIGRlY29kZVRleENvb3Jkc1NjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIG9jdEVuY29kZWROb3JtYWxTY3JhdGNoID0gbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpOwogICAgICBWZXJ0ZXgucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgaWYgKCFkZWZpbmVkX2RlZmF1bHQocmVzdWx0KSkgewogICAgICAgICAgcmVzdWx0ID0gbmV3IFZlcnRleCgpOwogICAgICAgIH0KICAgICAgICByZXN1bHQudUJ1ZmZlciA9IHRoaXMudUJ1ZmZlcjsKICAgICAgICByZXN1bHQudkJ1ZmZlciA9IHRoaXMudkJ1ZmZlcjsKICAgICAgICByZXN1bHQuaGVpZ2h0QnVmZmVyID0gdGhpcy5oZWlnaHRCdWZmZXI7CiAgICAgICAgcmVzdWx0Lm5vcm1hbEJ1ZmZlciA9IHRoaXMubm9ybWFsQnVmZmVyOwogICAgICAgIHJlc3VsdC5pbmRleCA9IHRoaXMuaW5kZXg7CiAgICAgICAgcmVzdWx0LmZpcnN0ID0gdGhpcy5maXJzdDsKICAgICAgICByZXN1bHQuc2Vjb25kID0gdGhpcy5zZWNvbmQ7CiAgICAgICAgcmVzdWx0LnJhdGlvID0gdGhpcy5yYXRpbzsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgICB9OwogICAgICBWZXJ0ZXgucHJvdG90eXBlLmluaXRpYWxpemVJbmRleGVkID0gZnVuY3Rpb24odUJ1ZmZlciwgdkJ1ZmZlciwgaGVpZ2h0QnVmZmVyLCBub3JtYWxCdWZmZXIsIGluZGV4KSB7CiAgICAgICAgdGhpcy51QnVmZmVyID0gdUJ1ZmZlcjsKICAgICAgICB0aGlzLnZCdWZmZXIgPSB2QnVmZmVyOwogICAgICAgIHRoaXMuaGVpZ2h0QnVmZmVyID0gaGVpZ2h0QnVmZmVyOwogICAgICAgIHRoaXMubm9ybWFsQnVmZmVyID0gbm9ybWFsQnVmZmVyOwogICAgICAgIHRoaXMuaW5kZXggPSBpbmRleDsKICAgICAgICB0aGlzLmZpcnN0ID0gdm9pZCAwOwogICAgICAgIHRoaXMuc2Vjb25kID0gdm9pZCAwOwogICAgICAgIHRoaXMucmF0aW8gPSB2b2lkIDA7CiAgICAgIH07CiAgICAgIFZlcnRleC5wcm90b3R5cGUuaW5pdGlhbGl6ZUZyb21DbGlwUmVzdWx0ID0gZnVuY3Rpb24oY2xpcFJlc3VsdCwgaW5kZXgsIHZlcnRpY2VzKSB7CiAgICAgICAgbGV0IG5leHRJbmRleCA9IGluZGV4ICsgMTsKICAgICAgICBpZiAoY2xpcFJlc3VsdFtpbmRleF0gIT09IC0xKSB7CiAgICAgICAgICB2ZXJ0aWNlc1tjbGlwUmVzdWx0W2luZGV4XV0uY2xvbmUodGhpcyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRoaXMudmVydGV4QnVmZmVyID0gdm9pZCAwOwogICAgICAgICAgdGhpcy5pbmRleCA9IHZvaWQgMDsKICAgICAgICAgIHRoaXMuZmlyc3QgPSB2ZXJ0aWNlc1tjbGlwUmVzdWx0W25leHRJbmRleF1dOwogICAgICAgICAgKytuZXh0SW5kZXg7CiAgICAgICAgICB0aGlzLnNlY29uZCA9IHZlcnRpY2VzW2NsaXBSZXN1bHRbbmV4dEluZGV4XV07CiAgICAgICAgICArK25leHRJbmRleDsKICAgICAgICAgIHRoaXMucmF0aW8gPSBjbGlwUmVzdWx0W25leHRJbmRleF07CiAgICAgICAgICArK25leHRJbmRleDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG5leHRJbmRleDsKICAgICAgfTsKICAgICAgVmVydGV4LnByb3RvdHlwZS5nZXRLZXkgPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAodGhpcy5pc0luZGV4ZWQoKSkgewogICAgICAgICAgcmV0dXJuIHRoaXMuaW5kZXg7CiAgICAgICAgfQogICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh7CiAgICAgICAgICBmaXJzdDogdGhpcy5maXJzdC5nZXRLZXkoKSwKICAgICAgICAgIHNlY29uZDogdGhpcy5zZWNvbmQuZ2V0S2V5KCksCiAgICAgICAgICByYXRpbzogdGhpcy5yYXRpbwogICAgICAgIH0pOwogICAgICB9OwogICAgICBWZXJ0ZXgucHJvdG90eXBlLmlzSW5kZXhlZCA9IGZ1bmN0aW9uKCkgewogICAgICAgIHJldHVybiBkZWZpbmVkX2RlZmF1bHQodGhpcy5pbmRleCk7CiAgICAgIH07CiAgICAgIFZlcnRleC5wcm90b3R5cGUuZ2V0SCA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGhpcy5pbmRleCkpIHsKICAgICAgICAgIHJldHVybiB0aGlzLmhlaWdodEJ1ZmZlclt0aGlzLmluZGV4XTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIE1hdGhfZGVmYXVsdC5sZXJwKHRoaXMuZmlyc3QuZ2V0SCgpLCB0aGlzLnNlY29uZC5nZXRIKCksIHRoaXMucmF0aW8pOwogICAgICB9OwogICAgICBWZXJ0ZXgucHJvdG90eXBlLmdldFUgPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRoaXMuaW5kZXgpKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy51QnVmZmVyW3RoaXMuaW5kZXhdOwogICAgICAgIH0KICAgICAgICByZXR1cm4gTWF0aF9kZWZhdWx0LmxlcnAodGhpcy5maXJzdC5nZXRVKCksIHRoaXMuc2Vjb25kLmdldFUoKSwgdGhpcy5yYXRpbyk7CiAgICAgIH07CiAgICAgIFZlcnRleC5wcm90b3R5cGUuZ2V0ViA9IGZ1bmN0aW9uKCkgewogICAgICAgIGlmIChkZWZpbmVkX2RlZmF1bHQodGhpcy5pbmRleCkpIHsKICAgICAgICAgIHJldHVybiB0aGlzLnZCdWZmZXJbdGhpcy5pbmRleF07CiAgICAgICAgfQogICAgICAgIHJldHVybiBNYXRoX2RlZmF1bHQubGVycCh0aGlzLmZpcnN0LmdldFYoKSwgdGhpcy5zZWNvbmQuZ2V0VigpLCB0aGlzLnJhdGlvKTsKICAgICAgfTsKICAgICAgZW5jb2RlZFNjcmF0Y2ggPSBuZXcgQ2FydGVzaWFuMl9kZWZhdWx0KCk7CiAgICAgIGRlcHRoID0gLTE7CiAgICAgIGNhcnRlc2lhblNjcmF0Y2gxID0gW25ldyBDYXJ0ZXNpYW4zX2RlZmF1bHQoKSwgbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpXTsKICAgICAgY2FydGVzaWFuU2NyYXRjaDIgPSBbbmV3IENhcnRlc2lhbjNfZGVmYXVsdCgpLCBuZXcgQ2FydGVzaWFuM19kZWZhdWx0KCldOwogICAgICBWZXJ0ZXgucHJvdG90eXBlLmdldE5vcm1hbFggPSBmdW5jdGlvbigpIHsKICAgICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KHRoaXMuaW5kZXgpKSB7CiAgICAgICAgICByZXR1cm4gdGhpcy5ub3JtYWxCdWZmZXJbdGhpcy5pbmRleCAqIDJdOwogICAgICAgIH0KICAgICAgICBlbmNvZGVkU2NyYXRjaCA9IGxlcnBPY3RFbmNvZGVkTm9ybWFsKHRoaXMsIGVuY29kZWRTY3JhdGNoKTsKICAgICAgICByZXR1cm4gZW5jb2RlZFNjcmF0Y2gueDsKICAgICAgfTsKICAgICAgVmVydGV4LnByb3RvdHlwZS5nZXROb3JtYWxZID0gZnVuY3Rpb24oKSB7CiAgICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdCh0aGlzLmluZGV4KSkgewogICAgICAgICAgcmV0dXJuIHRoaXMubm9ybWFsQnVmZmVyW3RoaXMuaW5kZXggKiAyICsgMV07CiAgICAgICAgfQogICAgICAgIGVuY29kZWRTY3JhdGNoID0gbGVycE9jdEVuY29kZWROb3JtYWwodGhpcywgZW5jb2RlZFNjcmF0Y2gpOwogICAgICAgIHJldHVybiBlbmNvZGVkU2NyYXRjaC55OwogICAgICB9OwogICAgICBwb2x5Z29uVmVydGljZXMgPSBbXTsKICAgICAgcG9seWdvblZlcnRpY2VzLnB1c2gobmV3IFZlcnRleCgpKTsKICAgICAgcG9seWdvblZlcnRpY2VzLnB1c2gobmV3IFZlcnRleCgpKTsKICAgICAgcG9seWdvblZlcnRpY2VzLnB1c2gobmV3IFZlcnRleCgpKTsKICAgICAgcG9seWdvblZlcnRpY2VzLnB1c2gobmV3IFZlcnRleCgpKTsKICAgICAgdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaF9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KHVwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2gpOwogICAgfQogIH0pOwoKICAvLyBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbi5qcwogIHZhciB1cHNhbXBsZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2V4cG9ydHMgPSB7fTsKICBfX2V4cG9ydCh1cHNhbXBsZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2V4cG9ydHMsIHsKICAgIGRlZmF1bHQ6ICgpID0+IHVwc2FtcGxlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW5fZGVmYXVsdAogIH0pOwogIGZ1bmN0aW9uIHVwc2FtcGxlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4ob3B0aW9ucywgdHJhbnNmZXJhYmxlT2JqZWN0cykgewogICAgY29uc3QgbWVzaCA9IENlc2l1bTNEVGlsZXNUZXJyYWluR2VvbWV0cnlQcm9jZXNzb3JfZGVmYXVsdC51cHNhbXBsZU1lc2gob3B0aW9ucyk7CiAgICBjb25zdCB2ZXJ0aWNlc0J1ZmZlciA9IG1lc2gudmVydGljZXMuYnVmZmVyOwogICAgY29uc3QgaW5kaWNlc0J1ZmZlciA9IG1lc2guaW5kaWNlcy5idWZmZXI7CiAgICBjb25zdCB3ZXN0SW5kaWNlc0J1ZmZlciA9IG1lc2gud2VzdEluZGljZXNTb3V0aFRvTm9ydGguYnVmZmVyOwogICAgY29uc3Qgc291dGhJbmRpY2VzQnVmZmVyID0gbWVzaC5zb3V0aEluZGljZXNFYXN0VG9XZXN0LmJ1ZmZlcjsKICAgIGNvbnN0IGVhc3RJbmRpY2VzQnVmZmVyID0gbWVzaC5lYXN0SW5kaWNlc05vcnRoVG9Tb3V0aC5idWZmZXI7CiAgICBjb25zdCBub3J0aEluZGljZXNCdWZmZXIgPSBtZXNoLm5vcnRoSW5kaWNlc1dlc3RUb0Vhc3QuYnVmZmVyOwogICAgdHJhbnNmZXJhYmxlT2JqZWN0cy5wdXNoKAogICAgICB2ZXJ0aWNlc0J1ZmZlciwKICAgICAgaW5kaWNlc0J1ZmZlciwKICAgICAgd2VzdEluZGljZXNCdWZmZXIsCiAgICAgIHNvdXRoSW5kaWNlc0J1ZmZlciwKICAgICAgZWFzdEluZGljZXNCdWZmZXIsCiAgICAgIG5vcnRoSW5kaWNlc0J1ZmZlcgogICAgKTsKICAgIGNvbnN0IHJlc3VsdCA9IHsKICAgICAgdmVydGljZXNCdWZmZXIsCiAgICAgIGluZGljZXNCdWZmZXIsCiAgICAgIHZlcnRleENvdW50V2l0aG91dFNraXJ0czogbWVzaC52ZXJ0ZXhDb3VudFdpdGhvdXRTa2lydHMsCiAgICAgIGluZGV4Q291bnRXaXRob3V0U2tpcnRzOiBtZXNoLmluZGV4Q291bnRXaXRob3V0U2tpcnRzLAogICAgICBlbmNvZGluZzogbWVzaC5lbmNvZGluZywKICAgICAgd2VzdEluZGljZXNCdWZmZXIsCiAgICAgIHNvdXRoSW5kaWNlc0J1ZmZlciwKICAgICAgZWFzdEluZGljZXNCdWZmZXIsCiAgICAgIG5vcnRoSW5kaWNlc0J1ZmZlciwKICAgICAgbWluaW11bUhlaWdodDogbWVzaC5taW5pbXVtSGVpZ2h0LAogICAgICBtYXhpbXVtSGVpZ2h0OiBtZXNoLm1heGltdW1IZWlnaHQsCiAgICAgIGJvdW5kaW5nU3BoZXJlOiBtZXNoLmJvdW5kaW5nU3BoZXJlM0QsCiAgICAgIG9yaWVudGVkQm91bmRpbmdCb3g6IG1lc2gub3JpZW50ZWRCb3VuZGluZ0JveCwKICAgICAgaG9yaXpvbk9jY2x1c2lvblBvaW50OiBtZXNoLmhvcml6b25PY2NsdXNpb25Qb2ludAogICAgfTsKICAgIHJldHVybiByZXN1bHQ7CiAgfQogIHZhciB1cHNhbXBsZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluX2RlZmF1bHQ7CiAgdmFyIGluaXRfdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbiA9IF9fZXNtKHsKICAgICJwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbi5qcyIoKSB7CiAgICAgIGluaXRfQ2VzaXVtM0RUaWxlc1RlcnJhaW5HZW9tZXRyeVByb2Nlc3NvcigpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbl9kZWZhdWx0ID0gY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9kZWZhdWx0KAogICAgICAgIHVwc2FtcGxlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4KICAgICAgKTsKICAgIH0KICB9KTsKCiAgLy8gaW1wb3J0KCIuLyoqLyouanMiKSBpbiBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlR2VvbWV0cnkuanMKICB2YXIgZ2xvYkltcG9ydF9qczsKICB2YXIgaW5pdF8gPSBfX2VzbSh7CiAgICAnaW1wb3J0KCIuLyoqLyouanMiKSBpbiBwYWNrYWdlcy9lbmdpbmUvU291cmNlL1dvcmtlcnMvY3JlYXRlR2VvbWV0cnkuanMnKCkgewogICAgICBnbG9iSW1wb3J0X2pzID0gX19nbG9iKHsKICAgICAgICAiLi9jb21iaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NvbWJpbmVHZW9tZXRyeSgpLCBjb21iaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUJveEdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVCb3hHZW9tZXRyeSgpLCBjcmVhdGVCb3hHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnkoKSwgY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVDaXJjbGVHZW9tZXRyeS5qcyI6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gKGluaXRfY3JlYXRlQ2lyY2xlR2VvbWV0cnkoKSwgY3JlYXRlQ2lyY2xlR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeS5qcyI6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gKGluaXRfY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5KCksIGNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5KCksIGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeSgpLCBjcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUNvcnJpZG9yR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUNvcnJpZG9yR2VvbWV0cnkoKSwgY3JlYXRlQ29ycmlkb3JHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5KCksIGNyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVDeWxpbmRlckdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVDeWxpbmRlckdlb21ldHJ5KCksIGNyZWF0ZUN5bGluZGVyR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVDeWxpbmRlck91dGxpbmVHZW9tZXRyeSgpLCBjcmVhdGVDeWxpbmRlck91dGxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlRWxsaXBzZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVFbGxpcHNlR2VvbWV0cnkoKSwgY3JlYXRlRWxsaXBzZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5KCksIGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUVsbGlwc29pZEdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVFbGxpcHNvaWRHZW9tZXRyeSgpLCBjcmVhdGVFbGxpcHNvaWRHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVFbGxpcHNvaWRPdXRsaW5lR2VvbWV0cnkoKSwgY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVGcnVzdHVtR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUZydXN0dW1HZW9tZXRyeSgpLCBjcmVhdGVGcnVzdHVtR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnkoKSwgY3JlYXRlRnJ1c3R1bU91dGxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZUdlb21ldHJ5KCksIGNyZWF0ZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5KCksIGNyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVBsYW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVBsYW5lR2VvbWV0cnkoKSwgY3JlYXRlUGxhbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVBsYW5lT3V0bGluZUdlb21ldHJ5KCksIGNyZWF0ZVBsYW5lT3V0bGluZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVQb2x5Z29uR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVBvbHlnb25HZW9tZXRyeSgpLCBjcmVhdGVQb2x5Z29uR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnkoKSwgY3JlYXRlUG9seWdvbk91dGxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlUG9seWxpbmVHZW9tZXRyeS5qcyI6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gKGluaXRfY3JlYXRlUG9seWxpbmVHZW9tZXRyeSgpLCBjcmVhdGVQb2x5bGluZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5KCksIGNyZWF0ZVBvbHlsaW5lVm9sdW1lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeSgpLCBjcmVhdGVQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5KCksIGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeSgpLCBjcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVNpbXBsZVBvbHlsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVNpbXBsZVBvbHlsaW5lR2VvbWV0cnkoKSwgY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeV9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlU3BoZXJlR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVNwaGVyZUdlb21ldHJ5KCksIGNyZWF0ZVNwaGVyZUdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnkuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeSgpLCBjcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKSwgY3JlYXRlVGFza1Byb2Nlc3Nvcldvcmtlcl9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXMuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzKCksIGNyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzX2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllcy5qcyI6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gKGluaXRfY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXMoKSwgY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXNfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVZlY3RvclRpbGVQb2ludHMuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVZlY3RvclRpbGVQb2ludHMoKSwgY3JlYXRlVmVjdG9yVGlsZVBvaW50c19leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlVmVjdG9yVGlsZVBvbHlnb25zLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVWZWN0b3JUaWxlUG9seWdvbnMoKSwgY3JlYXRlVmVjdG9yVGlsZVBvbHlnb25zX2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzKCksIGNyZWF0ZVZlY3RvclRpbGVQb2x5bGluZXNfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbigpLCBjcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbl9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXIoKSwgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyX2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXAuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2NyZWF0ZVZlcnRpY2VzRnJvbUhlaWdodG1hcCgpLCBjcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXBfZXhwb3J0cykpLAogICAgICAgICIuL2NyZWF0ZVZlcnRpY2VzRnJvbVF1YW50aXplZFRlcnJhaW5NZXNoLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaCgpLCBjcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaF9leHBvcnRzKSksCiAgICAgICAgIi4vY3JlYXRlV2FsbEdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVXYWxsR2VvbWV0cnkoKSwgY3JlYXRlV2FsbEdlb21ldHJ5X2V4cG9ydHMpKSwKICAgICAgICAiLi9jcmVhdGVXYWxsT3V0bGluZUdlb21ldHJ5LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9jcmVhdGVXYWxsT3V0bGluZUdlb21ldHJ5KCksIGNyZWF0ZVdhbGxPdXRsaW5lR2VvbWV0cnlfZXhwb3J0cykpLAogICAgICAgICIuL2RlY29kZURyYWNvLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9kZWNvZGVEcmFjbygpLCBkZWNvZGVEcmFjb19leHBvcnRzKSksCiAgICAgICAgIi4vZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0LmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9kZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXQoKSwgZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0X2V4cG9ydHMpKSwKICAgICAgICAiLi9kZWNvZGVJM1MuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2RlY29kZUkzUygpLCBkZWNvZGVJM1NfZXhwb3J0cykpLAogICAgICAgICIuL2dhdXNzaWFuU3BsYXRTb3J0ZXIuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2dhdXNzaWFuU3BsYXRTb3J0ZXIoKSwgZ2F1c3NpYW5TcGxhdFNvcnRlcl9leHBvcnRzKSksCiAgICAgICAgIi4vZ2F1c3NpYW5TcGxhdFRleHR1cmVHZW5lcmF0b3IuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X2dhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yKCksIGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yX2V4cG9ydHMpKSwKICAgICAgICAiLi9pbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF9pbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyKCksIGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXJfZXhwb3J0cykpLAogICAgICAgICIuL3RyYW5zY29kZUtUWDIuanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X3RyYW5zY29kZUtUWDIoKSwgdHJhbnNjb2RlS1RYMl9leHBvcnRzKSksCiAgICAgICAgIi4vdHJhbnNmZXJUeXBlZEFycmF5VGVzdC5qcyI6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gKGluaXRfdHJhbnNmZXJUeXBlZEFycmF5VGVzdCgpLCB0cmFuc2ZlclR5cGVkQXJyYXlUZXN0X2V4cG9ydHMpKSwKICAgICAgICAiLi91cHNhbXBsZVF1YW50aXplZFRlcnJhaW5NZXNoLmpzIjogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiAoaW5pdF91cHNhbXBsZVF1YW50aXplZFRlcnJhaW5NZXNoKCksIHVwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2hfZXhwb3J0cykpLAogICAgICAgICIuL3Vwc2FtcGxlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4uanMiOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IChpbml0X3Vwc2FtcGxlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4oKSwgdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbl9leHBvcnRzKSkKICAgICAgfSk7CiAgICB9CiAgfSk7CgogIC8vIHBhY2thZ2VzL2VuZ2luZS9Tb3VyY2UvV29ya2Vycy9jcmVhdGVHZW9tZXRyeS5qcwogIHZhciBjcmVhdGVHZW9tZXRyeV9leHBvcnRzID0ge307CiAgX19leHBvcnQoY3JlYXRlR2VvbWV0cnlfZXhwb3J0cywgewogICAgZGVmYXVsdDogKCkgPT4gY3JlYXRlR2VvbWV0cnlfZGVmYXVsdAogIH0pOwogIGFzeW5jIGZ1bmN0aW9uIGdldE1vZHVsZShtb2R1bGVOYW1lLCBtb2R1bGVQYXRoKSB7CiAgICBsZXQgbW9kdWxlID0gbW9kdWxlQ2FjaGVbbW9kdWxlUGF0aF0gPz8gbW9kdWxlQ2FjaGVbbW9kdWxlTmFtZV07CiAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1vZHVsZSkpIHsKICAgICAgcmV0dXJuIG1vZHVsZTsKICAgIH0KICAgIGlmIChkZWZpbmVkX2RlZmF1bHQobW9kdWxlUGF0aCkpIHsKICAgICAgaWYgKHR5cGVvZiBleHBvcnRzID09PSAib2JqZWN0IikgewogICAgICAgIG1vZHVsZSA9IF9fcmVxdWlyZShtb2R1bGVQYXRoKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBpbXBvcnQobW9kdWxlUGF0aCk7CiAgICAgICAgbW9kdWxlID0gcmVzdWx0LmRlZmF1bHQ7CiAgICAgIH0KICAgICAgbW9kdWxlQ2FjaGVbbW9kdWxlUGF0aF0gPSBtb2R1bGU7CiAgICAgIHJldHVybiBtb2R1bGU7CiAgICB9CiAgICBpZiAodHlwZW9mIGV4cG9ydHMgPT09ICJvYmplY3QiKSB7CiAgICAgIG1vZHVsZSA9IF9fcmVxdWlyZShgV29ya2Vycy8ke21vZHVsZU5hbWV9YCk7CiAgICB9IGVsc2UgewogICAgICBjb25zdCByZXN1bHQgPSBkZWZpbmVkX2RlZmF1bHQobW9kdWxlUGF0aCkgPyBhd2FpdCBpbXBvcnQobW9kdWxlUGF0aCkgOiBhd2FpdCBnbG9iSW1wb3J0X2pzKGAuLyR7bW9kdWxlTmFtZX0uanNgKTsKICAgICAgbW9kdWxlID0gcmVzdWx0LmRlZmF1bHQ7CiAgICB9CiAgICBtb2R1bGVDYWNoZVttb2R1bGVOYW1lXSA9IG1vZHVsZTsKICAgIHJldHVybiBtb2R1bGU7CiAgfQogIGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUdlb21ldHJ5KHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIGNvbnN0IHN1YlRhc2tzID0gcGFyYW1ldGVycy5zdWJUYXNrczsKICAgIGNvbnN0IGxlbmd0aCA9IHN1YlRhc2tzLmxlbmd0aDsKICAgIGNvbnN0IHJlc3VsdHNPclByb21pc2VzID0gbmV3IEFycmF5KGxlbmd0aCk7CiAgICBmb3IgKGxldCBpMiA9IDA7IGkyIDwgbGVuZ3RoOyBpMisrKSB7CiAgICAgIGNvbnN0IHRhc2sgPSBzdWJUYXNrc1tpMl07CiAgICAgIGNvbnN0IGdlb21ldHJ5ID0gdGFzay5nZW9tZXRyeTsKICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IHRhc2subW9kdWxlTmFtZTsKICAgICAgY29uc3QgbW9kdWxlUGF0aCA9IHRhc2subW9kdWxlUGF0aDsKICAgICAgaWYgKGRlZmluZWRfZGVmYXVsdChtb2R1bGVOYW1lKSAmJiBkZWZpbmVkX2RlZmF1bHQobW9kdWxlUGF0aCkpIHsKICAgICAgICB0aHJvdyBuZXcgRGV2ZWxvcGVyRXJyb3JfZGVmYXVsdCgiTXVzdCBvbmx5IHNldCBtb2R1bGVOYW1lIG9yIG1vZHVsZVBhdGgiKTsKICAgICAgfQogICAgICBpZiAoZGVmaW5lZF9kZWZhdWx0KG1vZHVsZU5hbWUpIHx8IGRlZmluZWRfZGVmYXVsdChtb2R1bGVQYXRoKSkgewogICAgICAgIHJlc3VsdHNPclByb21pc2VzW2kyXSA9IGdldE1vZHVsZShtb2R1bGVOYW1lLCBtb2R1bGVQYXRoKS50aGVuKAogICAgICAgICAgKGNyZWF0ZUZ1bmN0aW9uKSA9PiBjcmVhdGVGdW5jdGlvbihnZW9tZXRyeSwgdGFzay5vZmZzZXQpCiAgICAgICAgKTsKICAgICAgfSBlbHNlIHsKICAgICAgICByZXN1bHRzT3JQcm9taXNlc1tpMl0gPSBnZW9tZXRyeTsKICAgICAgfQogICAgfQogICAgcmV0dXJuIFByb21pc2UuYWxsKHJlc3VsdHNPclByb21pc2VzKS50aGVuKGZ1bmN0aW9uKHJlc3VsdHMpIHsKICAgICAgcmV0dXJuIFByaW1pdGl2ZVBpcGVsaW5lX2RlZmF1bHQucGFja0NyZWF0ZUdlb21ldHJ5UmVzdWx0cygKICAgICAgICByZXN1bHRzLAogICAgICAgIHRyYW5zZmVyYWJsZU9iamVjdHMKICAgICAgKTsKICAgIH0pOwogIH0KICB2YXIgbW9kdWxlQ2FjaGUsIGNyZWF0ZUdlb21ldHJ5X2RlZmF1bHQ7CiAgdmFyIGluaXRfY3JlYXRlR2VvbWV0cnkgPSBfX2VzbSh7CiAgICAicGFja2FnZXMvZW5naW5lL1NvdXJjZS9Xb3JrZXJzL2NyZWF0ZUdlb21ldHJ5LmpzIigpIHsKICAgICAgaW5pdF9EZXZlbG9wZXJFcnJvcigpOwogICAgICBpbml0X2RlZmluZWQoKTsKICAgICAgaW5pdF9QcmltaXRpdmVQaXBlbGluZSgpOwogICAgICBpbml0X2NyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXIoKTsKICAgICAgaW5pdF8oKTsKICAgICAgbW9kdWxlQ2FjaGUgPSB7fTsKICAgICAgY3JlYXRlR2VvbWV0cnlfZGVmYXVsdCA9IGNyZWF0ZVRhc2tQcm9jZXNzb3JXb3JrZXJfZGVmYXVsdChjcmVhdGVHZW9tZXRyeSk7CiAgICB9CiAgfSk7CgogIC8vIDxzdGRpbj4KICB2YXIgc3RkaW5fZXhwb3J0cyA9IHt9OwogIF9fZXhwb3J0KHN0ZGluX2V4cG9ydHMsIHsKICAgIGNvbWJpbmVHZW9tZXRyeTogKCkgPT4gY29tYmluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUJveEdlb21ldHJ5OiAoKSA9PiBjcmVhdGVCb3hHZW9tZXRyeTIsCiAgICBjcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUJveE91dGxpbmVHZW9tZXRyeTIsCiAgICBjcmVhdGVDaXJjbGVHZW9tZXRyeTogKCkgPT4gY3JlYXRlQ2lyY2xlR2VvbWV0cnkyLAogICAgY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5OiAoKSA9PiBjcmVhdGVDaXJjbGVPdXRsaW5lR2VvbWV0cnkyLAogICAgY3JlYXRlQ29wbGFuYXJQb2x5Z29uR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5MiwKICAgIGNyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlQ29wbGFuYXJQb2x5Z29uT3V0bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUNvcnJpZG9yR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUNvcnJpZG9yR2VvbWV0cnkyLAogICAgY3JlYXRlQ29ycmlkb3JPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUN5bGluZGVyR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUN5bGluZGVyR2VvbWV0cnkyLAogICAgY3JlYXRlQ3lsaW5kZXJPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUVsbGlwc2VHZW9tZXRyeTogKCkgPT4gY3JlYXRlRWxsaXBzZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUVsbGlwc2VPdXRsaW5lR2VvbWV0cnkyLAogICAgY3JlYXRlRWxsaXBzb2lkR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUVsbGlwc29pZEdlb21ldHJ5MiwKICAgIGNyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlRWxsaXBzb2lkT3V0bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUZydXN0dW1HZW9tZXRyeTogKCkgPT4gY3JlYXRlRnJ1c3R1bUdlb21ldHJ5MiwKICAgIGNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUZydXN0dW1PdXRsaW5lR2VvbWV0cnkyLAogICAgY3JlYXRlR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUdlb21ldHJ5MiwKICAgIGNyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZUdyb3VuZFBvbHlsaW5lR2VvbWV0cnkyLAogICAgY3JlYXRlUGxhbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlUGxhbmVHZW9tZXRyeTIsCiAgICBjcmVhdGVQbGFuZU91dGxpbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnkyLAogICAgY3JlYXRlUG9seWdvbkdlb21ldHJ5OiAoKSA9PiBjcmVhdGVQb2x5Z29uR2VvbWV0cnkyLAogICAgY3JlYXRlUG9seWdvbk91dGxpbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlUG9seWdvbk91dGxpbmVHZW9tZXRyeTIsCiAgICBjcmVhdGVQb2x5bGluZUdlb21ldHJ5OiAoKSA9PiBjcmVhdGVQb2x5bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZVBvbHlsaW5lVm9sdW1lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZVBvbHlsaW5lVm9sdW1lR2VvbWV0cnkyLAogICAgY3JlYXRlUG9seWxpbmVWb2x1bWVPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZVJlY3RhbmdsZUdlb21ldHJ5OiAoKSA9PiBjcmVhdGVSZWN0YW5nbGVHZW9tZXRyeTIsCiAgICBjcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZVJlY3RhbmdsZU91dGxpbmVHZW9tZXRyeTIsCiAgICBjcmVhdGVTaW1wbGVQb2x5bGluZUdlb21ldHJ5OiAoKSA9PiBjcmVhdGVTaW1wbGVQb2x5bGluZUdlb21ldHJ5MiwKICAgIGNyZWF0ZVNwaGVyZUdlb21ldHJ5OiAoKSA9PiBjcmVhdGVTcGhlcmVHZW9tZXRyeTIsCiAgICBjcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnk6ICgpID0+IGNyZWF0ZVNwaGVyZU91dGxpbmVHZW9tZXRyeTIsCiAgICBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyOiAoKSA9PiBjcmVhdGVUYXNrUHJvY2Vzc29yV29ya2VyMiwKICAgIGNyZWF0ZVZlY3RvclRpbGVDbGFtcGVkUG9seWxpbmVzOiAoKSA9PiBjcmVhdGVWZWN0b3JUaWxlQ2xhbXBlZFBvbHlsaW5lczIsCiAgICBjcmVhdGVWZWN0b3JUaWxlR2VvbWV0cmllczogKCkgPT4gY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXMyLAogICAgY3JlYXRlVmVjdG9yVGlsZVBvaW50czogKCkgPT4gY3JlYXRlVmVjdG9yVGlsZVBvaW50czIsCiAgICBjcmVhdGVWZWN0b3JUaWxlUG9seWdvbnM6ICgpID0+IGNyZWF0ZVZlY3RvclRpbGVQb2x5Z29uczIsCiAgICBjcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzOiAoKSA9PiBjcmVhdGVWZWN0b3JUaWxlUG9seWxpbmVzMiwKICAgIGNyZWF0ZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluOiAoKSA9PiBjcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbjIsCiAgICBjcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXI6ICgpID0+IGNyZWF0ZVZlcnRpY2VzRnJvbUdvb2dsZUVhcnRoRW50ZXJwcmlzZUJ1ZmZlcjIsCiAgICBjcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXA6ICgpID0+IGNyZWF0ZVZlcnRpY2VzRnJvbUhlaWdodG1hcDIsCiAgICBjcmVhdGVWZXJ0aWNlc0Zyb21RdWFudGl6ZWRUZXJyYWluTWVzaDogKCkgPT4gY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2gyLAogICAgY3JlYXRlV2FsbEdlb21ldHJ5OiAoKSA9PiBjcmVhdGVXYWxsR2VvbWV0cnkyLAogICAgY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeTogKCkgPT4gY3JlYXRlV2FsbE91dGxpbmVHZW9tZXRyeTIsCiAgICBkZWNvZGVEcmFjbzogKCkgPT4gZGVjb2RlRHJhY28yLAogICAgZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0OiAoKSA9PiBkZWNvZGVHb29nbGVFYXJ0aEVudGVycHJpc2VQYWNrZXQyLAogICAgZGVjb2RlSTNTOiAoKSA9PiBkZWNvZGVJM1MyLAogICAgZ2F1c3NpYW5TcGxhdFNvcnRlcjogKCkgPT4gZ2F1c3NpYW5TcGxhdFNvcnRlciwKICAgIGdhdXNzaWFuU3BsYXRUZXh0dXJlR2VuZXJhdG9yOiAoKSA9PiBnYXVzc2lhblNwbGF0VGV4dHVyZUdlbmVyYXRvciwKICAgIGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXI6ICgpID0+IGluY3JlbWVudGFsbHlCdWlsZFRlcnJhaW5QaWNrZXIyLAogICAgdHJhbnNjb2RlS1RYMjogKCkgPT4gdHJhbnNjb2RlS1RYMjIsCiAgICB0cmFuc2ZlclR5cGVkQXJyYXlUZXN0OiAoKSA9PiB0cmFuc2ZlclR5cGVkQXJyYXlUZXN0LAogICAgdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaDogKCkgPT4gdXBzYW1wbGVRdWFudGl6ZWRUZXJyYWluTWVzaDIsCiAgICB1cHNhbXBsZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluOiAoKSA9PiB1cHNhbXBsZVZlcnRpY2VzRnJvbUNlc2l1bTNEVGlsZXNUZXJyYWluMgogIH0pOwogIHZhciBjb21iaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NvbWJpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVCb3hHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlQm94R2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlQm94T3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVCb3hPdXRsaW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlQ2lyY2xlR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZUNpcmNsZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUNpcmNsZU91dGxpbmVHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlQ2lyY2xlT3V0bGluZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUNvcGxhbmFyUG9seWdvbkdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVDb3BsYW5hclBvbHlnb25HZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVDb3BsYW5hclBvbHlnb25PdXRsaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZUNvcGxhbmFyUG9seWdvbk91dGxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVDb3JyaWRvckdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVDb3JyaWRvckdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUNvcnJpZG9yT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVDb3JyaWRvck91dGxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVDeWxpbmRlckdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVDeWxpbmRlckdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUN5bGluZGVyT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVDeWxpbmRlck91dGxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVFbGxpcHNlR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZUVsbGlwc2VHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVFbGxpcHNlT3V0bGluZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUVsbGlwc29pZEdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVFbGxpcHNvaWRHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVFbGxpcHNvaWRPdXRsaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZUVsbGlwc29pZE91dGxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVGcnVzdHVtR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZUZydXN0dW1HZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVGcnVzdHVtT3V0bGluZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVHcm91bmRQb2x5bGluZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZVBsYW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVBsYW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlUGxhbmVPdXRsaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVBsYW5lT3V0bGluZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZVBvbHlnb25HZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlUG9seWdvbkdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVBvbHlnb25PdXRsaW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlUG9seWxpbmVHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlUG9seWxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVQb2x5bGluZVZvbHVtZUdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZVBvbHlsaW5lVm9sdW1lT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVQb2x5bGluZVZvbHVtZU91dGxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVSZWN0YW5nbGVHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlUmVjdGFuZ2xlR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlUmVjdGFuZ2xlT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVSZWN0YW5nbGVPdXRsaW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlU2ltcGxlUG9seWxpbmVHZW9tZXRyeSgpKTsKICB9OwogIHZhciBjcmVhdGVTcGhlcmVHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlU3BoZXJlR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlU3BoZXJlT3V0bGluZUdlb21ldHJ5MiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVTcGhlcmVPdXRsaW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcjIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlVGFza1Byb2Nlc3NvcldvcmtlcigpKTsKICB9OwogIHZhciBjcmVhdGVWZWN0b3JUaWxlQ2xhbXBlZFBvbHlsaW5lczIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlVmVjdG9yVGlsZUNsYW1wZWRQb2x5bGluZXMoKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVjdG9yVGlsZUdlb21ldHJpZXMyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVZlY3RvclRpbGVHZW9tZXRyaWVzKCkpOwogIH07CiAgdmFyIGNyZWF0ZVZlY3RvclRpbGVQb2ludHMyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVZlY3RvclRpbGVQb2ludHMoKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVjdG9yVGlsZVBvbHlnb25zMiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVWZWN0b3JUaWxlUG9seWdvbnMoKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVjdG9yVGlsZVBvbHlsaW5lczIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlVmVjdG9yVGlsZVBvbHlsaW5lcygpKTsKICB9OwogIHZhciBjcmVhdGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbjIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlVmVydGljZXNGcm9tQ2VzaXVtM0RUaWxlc1RlcnJhaW4oKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tR29vZ2xlRWFydGhFbnRlcnByaXNlQnVmZmVyMiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21Hb29nbGVFYXJ0aEVudGVycHJpc2VCdWZmZXIoKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tSGVpZ2h0bWFwMiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9jcmVhdGVWZXJ0aWNlc0Zyb21IZWlnaHRtYXAoKSk7CiAgfTsKICB2YXIgY3JlYXRlVmVydGljZXNGcm9tUXVhbnRpemVkVGVycmFpbk1lc2gyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVZlcnRpY2VzRnJvbVF1YW50aXplZFRlcnJhaW5NZXNoKCkpOwogIH07CiAgdmFyIGNyZWF0ZVdhbGxHZW9tZXRyeTIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfY3JlYXRlV2FsbEdlb21ldHJ5KCkpOwogIH07CiAgdmFyIGNyZWF0ZVdhbGxPdXRsaW5lR2VvbWV0cnkyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2NyZWF0ZVdhbGxPdXRsaW5lR2VvbWV0cnkoKSk7CiAgfTsKICB2YXIgZGVjb2RlRHJhY28yID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X2RlY29kZURyYWNvKCkpOwogIH07CiAgdmFyIGRlY29kZUdvb2dsZUVhcnRoRW50ZXJwcmlzZVBhY2tldDIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfZGVjb2RlR29vZ2xlRWFydGhFbnRlcnByaXNlUGFja2V0KCkpOwogIH07CiAgdmFyIGRlY29kZUkzUzIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfZGVjb2RlSTNTKCkpOwogIH07CiAgdmFyIGdhdXNzaWFuU3BsYXRTb3J0ZXIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfZ2F1c3NpYW5TcGxhdFNvcnRlcigpKTsKICB9OwogIHZhciBnYXVzc2lhblNwbGF0VGV4dHVyZUdlbmVyYXRvciA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9nYXVzc2lhblNwbGF0VGV4dHVyZUdlbmVyYXRvcigpKTsKICB9OwogIHZhciBpbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyMiA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF9pbmNyZW1lbnRhbGx5QnVpbGRUZXJyYWluUGlja2VyKCkpOwogIH07CiAgdmFyIHRyYW5zY29kZUtUWDIyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X3RyYW5zY29kZUtUWDIoKSk7CiAgfTsKICB2YXIgdHJhbnNmZXJUeXBlZEFycmF5VGVzdCA9ICgpID0+IHsKICAgIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4gaW5pdF90cmFuc2ZlclR5cGVkQXJyYXlUZXN0KCkpOwogIH07CiAgdmFyIHVwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2gyID0gKCkgPT4gewogICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiBpbml0X3Vwc2FtcGxlUXVhbnRpemVkVGVycmFpbk1lc2goKSk7CiAgfTsKICB2YXIgdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbjIgPSAoKSA9PiB7CiAgICBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IGluaXRfdXBzYW1wbGVWZXJ0aWNlc0Zyb21DZXNpdW0zRFRpbGVzVGVycmFpbigpKTsKICB9OwogIHJldHVybiBfX3RvQ29tbW9uSlMoc3RkaW5fZXhwb3J0cyk7Cn0pKCk7Cg=="); } }); // node_modules/mersenne-twister/src/mersenne-twister.js var require_mersenne_twister = __commonJS({ "node_modules/mersenne-twister/src/mersenne-twister.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); var MersenneTwister4 = function(seed) { if (seed == void 0) { seed = (/* @__PURE__ */ new Date()).getTime(); } this.N = 624; this.M = 397; this.MATRIX_A = 2567483615; this.UPPER_MASK = 2147483648; this.LOWER_MASK = 2147483647; this.mt = new Array(this.N); this.mti = this.N + 1; if (seed.constructor == Array) { this.init_by_array(seed, seed.length); } else { this.init_seed(seed); } }; MersenneTwister4.prototype.init_seed = function(s2) { this.mt[0] = s2 >>> 0; for (this.mti = 1; this.mti < this.N; this.mti++) { var s2 = this.mt[this.mti - 1] ^ this.mt[this.mti - 1] >>> 30; this.mt[this.mti] = (((s2 & 4294901760) >>> 16) * 1812433253 << 16) + (s2 & 65535) * 1812433253 + this.mti; this.mt[this.mti] >>>= 0; } }; MersenneTwister4.prototype.init_by_array = function(init_key, key_length) { var i, j, k; this.init_seed(19650218); i = 1; j = 0; k = this.N > key_length ? this.N : key_length; for (; k; k--) { var s2 = this.mt[i - 1] ^ this.mt[i - 1] >>> 30; this.mt[i] = (this.mt[i] ^ (((s2 & 4294901760) >>> 16) * 1664525 << 16) + (s2 & 65535) * 1664525) + init_key[j] + j; this.mt[i] >>>= 0; i++; j++; if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; } if (j >= key_length) j = 0; } for (k = this.N - 1; k; k--) { var s2 = this.mt[i - 1] ^ this.mt[i - 1] >>> 30; this.mt[i] = (this.mt[i] ^ (((s2 & 4294901760) >>> 16) * 1566083941 << 16) + (s2 & 65535) * 1566083941) - i; this.mt[i] >>>= 0; i++; if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; } } this.mt[0] = 2147483648; }; MersenneTwister4.prototype.random_int = function() { var y; var mag01 = new Array(0, this.MATRIX_A); if (this.mti >= this.N) { var kk; if (this.mti == this.N + 1) this.init_seed(5489); for (kk = 0; kk < this.N - this.M; kk++) { y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; this.mt[kk] = this.mt[kk + this.M] ^ y >>> 1 ^ mag01[y & 1]; } for (; kk < this.N - 1; kk++) { y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK; this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ y >>> 1 ^ mag01[y & 1]; } y = this.mt[this.N - 1] & this.UPPER_MASK | this.mt[0] & this.LOWER_MASK; this.mt[this.N - 1] = this.mt[this.M - 1] ^ y >>> 1 ^ mag01[y & 1]; this.mti = 0; } y = this.mt[this.mti++]; y ^= y >>> 11; y ^= y << 7 & 2636928640; y ^= y << 15 & 4022730752; y ^= y >>> 18; return y >>> 0; }; MersenneTwister4.prototype.random_int31 = function() { return this.random_int() >>> 1; }; MersenneTwister4.prototype.random_incl = function() { return this.random_int() * (1 / 4294967295); }; MersenneTwister4.prototype.random = function() { return this.random_int() * (1 / 4294967296); }; MersenneTwister4.prototype.random_excl = function() { return (this.random_int() + 0.5) * (1 / 4294967296); }; MersenneTwister4.prototype.random_long = function() { var a3 = this.random_int() >>> 5, b = this.random_int() >>> 6; return (a3 * 67108864 + b) * (1 / 9007199254740992); }; module.exports = MersenneTwister4; } }); // node_modules/urijs/src/punycode.js var require_punycode = __commonJS({ "node_modules/urijs/src/punycode.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /*! https://mths.be/punycode v1.4.0 by @mathias */ (function(root) { var freeExports = typeof exports == "object" && exports && !exports.nodeType && exports; var freeModule = typeof module == "object" && module && !module.nodeType && module; var freeGlobal = typeof global == "object" && global; if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal) { root = freeGlobal; } var punycode, maxInt = 2147483647, base = 36, tMin = 1, tMax = 26, skew = 38, damp = 700, initialBias = 72, initialN = 128, delimiter = "-", regexPunycode = /^xn--/, regexNonASCII = /[^\x20-\x7E]/, regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, errors = { "overflow": "Overflow: input needs wider integers to process", "not-basic": "Illegal input >= 0x80 (not a basic code point)", "invalid-input": "Invalid input" }, baseMinusTMin = base - tMin, floor = Math.floor, stringFromCharCode = String.fromCharCode, key; function error(type) { throw new RangeError(errors[type]); } function map(array, fn) { var length2 = array.length; var result = []; while (length2--) { result[length2] = fn(array[length2]); } return result; } function mapDomain(string, fn) { var parts = string.split("@"); var result = ""; if (parts.length > 1) { result = parts[0] + "@"; string = parts[1]; } string = string.replace(regexSeparators, "."); var labels = string.split("."); var encoded = map(labels, fn).join("."); return result + encoded; } function ucs2decode(string) { var output = [], counter = 0, length2 = string.length, value, extra; while (counter < length2) { value = string.charCodeAt(counter++); if (value >= 55296 && value <= 56319 && counter < length2) { extra = string.charCodeAt(counter++); if ((extra & 64512) == 56320) { output.push(((value & 1023) << 10) + (extra & 1023) + 65536); } else { output.push(value); counter--; } } else { output.push(value); } } return output; } function ucs2encode(array) { return map(array, function(value) { var output = ""; if (value > 65535) { value -= 65536; output += stringFromCharCode(value >>> 10 & 1023 | 55296); value = 56320 | value & 1023; } output += stringFromCharCode(value); return output; }).join(""); } function basicToDigit(codePoint) { if (codePoint - 48 < 10) { return codePoint - 22; } if (codePoint - 65 < 26) { return codePoint - 65; } if (codePoint - 97 < 26) { return codePoint - 97; } return base; } function digitToBasic(digit, flag) { return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); } function adapt(delta, numPoints, firstTime) { var k = 0; delta = firstTime ? floor(delta / damp) : delta >> 1; delta += floor(delta / numPoints); for (; delta > baseMinusTMin * tMax >> 1; k += base) { delta = floor(delta / baseMinusTMin); } return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); } function decode(input) { var output = [], inputLength = input.length, out, i = 0, n2 = initialN, bias = initialBias, basic, j, index, oldi, w, k, digit, t2, baseMinusT; basic = input.lastIndexOf(delimiter); if (basic < 0) { basic = 0; } for (j = 0; j < basic; ++j) { if (input.charCodeAt(j) >= 128) { error("not-basic"); } output.push(input.charCodeAt(j)); } for (index = basic > 0 ? basic + 1 : 0; index < inputLength; ) { for (oldi = i, w = 1, k = base; ; k += base) { if (index >= inputLength) { error("invalid-input"); } digit = basicToDigit(input.charCodeAt(index++)); if (digit >= base || digit > floor((maxInt - i) / w)) { error("overflow"); } i += digit * w; t2 = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; if (digit < t2) { break; } baseMinusT = base - t2; if (w > floor(maxInt / baseMinusT)) { error("overflow"); } w *= baseMinusT; } out = output.length + 1; bias = adapt(i - oldi, out, oldi == 0); if (floor(i / out) > maxInt - n2) { error("overflow"); } n2 += floor(i / out); i %= out; output.splice(i++, 0, n2); } return ucs2encode(output); } function encode(input) { var n2, delta, handledCPCount, basicLength, bias, j, m, q, k, t2, currentValue, output = [], inputLength, handledCPCountPlusOne, baseMinusT, qMinusT; input = ucs2decode(input); inputLength = input.length; n2 = initialN; delta = 0; bias = initialBias; for (j = 0; j < inputLength; ++j) { currentValue = input[j]; if (currentValue < 128) { output.push(stringFromCharCode(currentValue)); } } handledCPCount = basicLength = output.length; if (basicLength) { output.push(delimiter); } while (handledCPCount < inputLength) { for (m = maxInt, j = 0; j < inputLength; ++j) { currentValue = input[j]; if (currentValue >= n2 && currentValue < m) { m = currentValue; } } handledCPCountPlusOne = handledCPCount + 1; if (m - n2 > floor((maxInt - delta) / handledCPCountPlusOne)) { error("overflow"); } delta += (m - n2) * handledCPCountPlusOne; n2 = m; for (j = 0; j < inputLength; ++j) { currentValue = input[j]; if (currentValue < n2 && ++delta > maxInt) { error("overflow"); } if (currentValue == n2) { for (q = delta, k = base; ; k += base) { t2 = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; if (q < t2) { break; } qMinusT = q - t2; baseMinusT = base - t2; output.push( stringFromCharCode(digitToBasic(t2 + qMinusT % baseMinusT, 0)) ); q = floor(qMinusT / baseMinusT); } output.push(stringFromCharCode(digitToBasic(q, 0))); bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); delta = 0; ++handledCPCount; } } ++delta; ++n2; } return output.join(""); } function toUnicode(input) { return mapDomain(input, function(string) { return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; }); } function toASCII(input) { return mapDomain(input, function(string) { return regexNonASCII.test(string) ? "xn--" + encode(string) : string; }); } punycode = { /** * A string representing the current Punycode.js version number. * @memberOf punycode * @type String */ "version": "1.3.2", /** * An object of methods to convert from JavaScript's internal character * representation (UCS-2) to Unicode code points, and back. * @see * @memberOf punycode * @type Object */ "ucs2": { "decode": ucs2decode, "encode": ucs2encode }, "decode": decode, "encode": encode, "toASCII": toASCII, "toUnicode": toUnicode }; if (typeof define == "function" && typeof define.amd == "object" && define.amd) { define("punycode", function() { return punycode; }); } else if (freeExports && freeModule) { if (module.exports == freeExports) { freeModule.exports = punycode; } else { for (key in punycode) { punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); } } } else { root.punycode = punycode; } })(exports); } }); // node_modules/urijs/src/IPv6.js var require_IPv6 = __commonJS({ "node_modules/urijs/src/IPv6.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /*! * URI.js - Mutating URLs * IPv6 Support * * Version: 1.19.11 * * Author: Rodney Rehm * Web: http://medialize.github.io/URI.js/ * * Licensed under * MIT License http://www.opensource.org/licenses/mit-license * */ (function(root, factory) { "use strict"; if (typeof module === "object" && module.exports) { module.exports = factory(); } else if (typeof define === "function" && define.amd) { define(factory); } else { root.IPv6 = factory(root); } })(exports, function(root) { "use strict"; var _IPv6 = root && root.IPv6; function bestPresentation(address) { var _address = address.toLowerCase(); var segments = _address.split(":"); var length2 = segments.length; var total = 8; if (segments[0] === "" && segments[1] === "" && segments[2] === "") { segments.shift(); segments.shift(); } else if (segments[0] === "" && segments[1] === "") { segments.shift(); } else if (segments[length2 - 1] === "" && segments[length2 - 2] === "") { segments.pop(); } length2 = segments.length; if (segments[length2 - 1].indexOf(".") !== -1) { total = 7; } var pos; for (pos = 0; pos < length2; pos++) { if (segments[pos] === "") { break; } } if (pos < total) { segments.splice(pos, 1, "0000"); while (segments.length < total) { segments.splice(pos, 0, "0000"); } } var _segments; for (var i = 0; i < total; i++) { _segments = segments[i].split(""); for (var j = 0; j < 3; j++) { if (_segments[0] === "0" && _segments.length > 1) { _segments.splice(0, 1); } else { break; } } segments[i] = _segments.join(""); } var best = -1; var _best = 0; var _current = 0; var current = -1; var inzeroes = false; for (i = 0; i < total; i++) { if (inzeroes) { if (segments[i] === "0") { _current += 1; } else { inzeroes = false; if (_current > _best) { best = current; _best = _current; } } } else { if (segments[i] === "0") { inzeroes = true; current = i; _current = 1; } } } if (_current > _best) { best = current; _best = _current; } if (_best > 1) { segments.splice(best, _best, ""); } length2 = segments.length; var result = ""; if (segments[0] === "") { result = ":"; } for (i = 0; i < length2; i++) { result += segments[i]; if (i === length2 - 1) { break; } result += ":"; } if (segments[length2 - 1] === "") { result += ":"; } return result; } function noConflict() { if (root.IPv6 === this) { root.IPv6 = _IPv6; } return this; } return { best: bestPresentation, noConflict }; }); } }); // node_modules/urijs/src/SecondLevelDomains.js var require_SecondLevelDomains = __commonJS({ "node_modules/urijs/src/SecondLevelDomains.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /*! * URI.js - Mutating URLs * Second Level Domain (SLD) Support * * Version: 1.19.11 * * Author: Rodney Rehm * Web: http://medialize.github.io/URI.js/ * * Licensed under * MIT License http://www.opensource.org/licenses/mit-license * */ (function(root, factory) { "use strict"; if (typeof module === "object" && module.exports) { module.exports = factory(); } else if (typeof define === "function" && define.amd) { define(factory); } else { root.SecondLevelDomains = factory(root); } })(exports, function(root) { "use strict"; var _SecondLevelDomains = root && root.SecondLevelDomains; var SLD = { // list of known Second Level Domains // converted list of SLDs from https://github.com/gavingmiller/second-level-domains // ---- // publicsuffix.org is more current and actually used by a couple of browsers internally. // downside is it also contains domains like "dyndns.org" - which is fine for the security // issues browser have to deal with (SOP for cookies, etc) - but is way overboard for URI.js // ---- list: { "ac": " com gov mil net org ", "ae": " ac co gov mil name net org pro sch ", "af": " com edu gov net org ", "al": " com edu gov mil net org ", "ao": " co ed gv it og pb ", "ar": " com edu gob gov int mil net org tur ", "at": " ac co gv or ", "au": " asn com csiro edu gov id net org ", "ba": " co com edu gov mil net org rs unbi unmo unsa untz unze ", "bb": " biz co com edu gov info net org store tv ", "bh": " biz cc com edu gov info net org ", "bn": " com edu gov net org ", "bo": " com edu gob gov int mil net org tv ", "br": " adm adv agr am arq art ato b bio blog bmd cim cng cnt com coop ecn edu eng esp etc eti far flog fm fnd fot fst g12 ggf gov imb ind inf jor jus lel mat med mil mus net nom not ntr odo org ppg pro psc psi qsl rec slg srv tmp trd tur tv vet vlog wiki zlg ", "bs": " com edu gov net org ", "bz": " du et om ov rg ", "ca": " ab bc mb nb nf nl ns nt nu on pe qc sk yk ", "ck": " biz co edu gen gov info net org ", "cn": " ac ah bj com cq edu fj gd gov gs gx gz ha hb he hi hl hn jl js jx ln mil net nm nx org qh sc sd sh sn sx tj tw xj xz yn zj ", "co": " com edu gov mil net nom org ", "cr": " ac c co ed fi go or sa ", "cy": " ac biz com ekloges gov ltd name net org parliament press pro tm ", "do": " art com edu gob gov mil net org sld web ", "dz": " art asso com edu gov net org pol ", "ec": " com edu fin gov info med mil net org pro ", "eg": " com edu eun gov mil name net org sci ", "er": " com edu gov ind mil net org rochest w ", "es": " com edu gob nom org ", "et": " biz com edu gov info name net org ", "fj": " ac biz com info mil name net org pro ", "fk": " ac co gov net nom org ", "fr": " asso com f gouv nom prd presse tm ", "gg": " co net org ", "gh": " com edu gov mil org ", "gn": " ac com gov net org ", "gr": " com edu gov mil net org ", "gt": " com edu gob ind mil net org ", "gu": " com edu gov net org ", "hk": " com edu gov idv net org ", "hu": " 2000 agrar bolt casino city co erotica erotika film forum games hotel info ingatlan jogasz konyvelo lakas media news org priv reklam sex shop sport suli szex tm tozsde utazas video ", "id": " ac co go mil net or sch web ", "il": " ac co gov idf k12 muni net org ", "in": " ac co edu ernet firm gen gov i ind mil net nic org res ", "iq": " com edu gov i mil net org ", "ir": " ac co dnssec gov i id net org sch ", "it": " edu gov ", "je": " co net org ", "jo": " com edu gov mil name net org sch ", "jp": " ac ad co ed go gr lg ne or ", "ke": " ac co go info me mobi ne or sc ", "kh": " com edu gov mil net org per ", "ki": " biz com de edu gov info mob net org tel ", "km": " asso com coop edu gouv k medecin mil nom notaires pharmaciens presse tm veterinaire ", "kn": " edu gov net org ", "kr": " ac busan chungbuk chungnam co daegu daejeon es gangwon go gwangju gyeongbuk gyeonggi gyeongnam hs incheon jeju jeonbuk jeonnam k kg mil ms ne or pe re sc seoul ulsan ", "kw": " com edu gov net org ", "ky": " com edu gov net org ", "kz": " com edu gov mil net org ", "lb": " com edu gov net org ", "lk": " assn com edu gov grp hotel int ltd net ngo org sch soc web ", "lr": " com edu gov net org ", "lv": " asn com conf edu gov id mil net org ", "ly": " com edu gov id med net org plc sch ", "ma": " ac co gov m net org press ", "mc": " asso tm ", "me": " ac co edu gov its net org priv ", "mg": " com edu gov mil nom org prd tm ", "mk": " com edu gov inf name net org pro ", "ml": " com edu gov net org presse ", "mn": " edu gov org ", "mo": " com edu gov net org ", "mt": " com edu gov net org ", "mv": " aero biz com coop edu gov info int mil museum name net org pro ", "mw": " ac co com coop edu gov int museum net org ", "mx": " com edu gob net org ", "my": " com edu gov mil name net org sch ", "nf": " arts com firm info net other per rec store web ", "ng": " biz com edu gov mil mobi name net org sch ", "ni": " ac co com edu gob mil net nom org ", "np": " com edu gov mil net org ", "nr": " biz com edu gov info net org ", "om": " ac biz co com edu gov med mil museum net org pro sch ", "pe": " com edu gob mil net nom org sld ", "ph": " com edu gov i mil net ngo org ", "pk": " biz com edu fam gob gok gon gop gos gov net org web ", "pl": " art bialystok biz com edu gda gdansk gorzow gov info katowice krakow lodz lublin mil net ngo olsztyn org poznan pwr radom slupsk szczecin torun warszawa waw wroc wroclaw zgora ", "pr": " ac biz com edu est gov info isla name net org pro prof ", "ps": " com edu gov net org plo sec ", "pw": " belau co ed go ne or ", "ro": " arts com firm info nom nt org rec store tm www ", "rs": " ac co edu gov in org ", "sb": " com edu gov net org ", "sc": " com edu gov net org ", "sh": " co com edu gov net nom org ", "sl": " com edu gov net org ", "st": " co com consulado edu embaixada gov mil net org principe saotome store ", "sv": " com edu gob org red ", "sz": " ac co org ", "tr": " av bbs bel biz com dr edu gen gov info k12 name net org pol tel tsk tv web ", "tt": " aero biz cat co com coop edu gov info int jobs mil mobi museum name net org pro tel travel ", "tw": " club com ebiz edu game gov idv mil net org ", "mu": " ac co com gov net or org ", "mz": " ac co edu gov org ", "na": " co com ", "nz": " ac co cri geek gen govt health iwi maori mil net org parliament school ", "pa": " abo ac com edu gob ing med net nom org sld ", "pt": " com edu gov int net nome org publ ", "py": " com edu gov mil net org ", "qa": " com edu gov mil net org ", "re": " asso com nom ", "ru": " ac adygeya altai amur arkhangelsk astrakhan bashkiria belgorod bir bryansk buryatia cbg chel chelyabinsk chita chukotka chuvashia com dagestan e-burg edu gov grozny int irkutsk ivanovo izhevsk jar joshkar-ola kalmykia kaluga kamchatka karelia kazan kchr kemerovo khabarovsk khakassia khv kirov koenig komi kostroma kranoyarsk kuban kurgan kursk lipetsk magadan mari mari-el marine mil mordovia mosreg msk murmansk nalchik net nnov nov novosibirsk nsk omsk orenburg org oryol penza perm pp pskov ptz rnd ryazan sakhalin samara saratov simbirsk smolensk spb stavropol stv surgut tambov tatarstan tom tomsk tsaritsyn tsk tula tuva tver tyumen udm udmurtia ulan-ude vladikavkaz vladimir vladivostok volgograd vologda voronezh vrn vyatka yakutia yamal yekaterinburg yuzhno-sakhalinsk ", "rw": " ac co com edu gouv gov int mil net ", "sa": " com edu gov med net org pub sch ", "sd": " com edu gov info med net org tv ", "se": " a ac b bd c d e f g h i k l m n o org p parti pp press r s t tm u w x y z ", "sg": " com edu gov idn net org per ", "sn": " art com edu gouv org perso univ ", "sy": " com edu gov mil net news org ", "th": " ac co go in mi net or ", "tj": " ac biz co com edu go gov info int mil name net nic org test web ", "tn": " agrinet com defense edunet ens fin gov ind info intl mincom nat net org perso rnrt rns rnu tourism ", "tz": " ac co go ne or ", "ua": " biz cherkassy chernigov chernovtsy ck cn co com crimea cv dn dnepropetrovsk donetsk dp edu gov if in ivano-frankivsk kh kharkov kherson khmelnitskiy kiev kirovograd km kr ks kv lg lugansk lutsk lviv me mk net nikolaev od odessa org pl poltava pp rovno rv sebastopol sumy te ternopil uzhgorod vinnica vn zaporizhzhe zhitomir zp zt ", "ug": " ac co go ne or org sc ", "uk": " ac bl british-library co cym gov govt icnet jet lea ltd me mil mod national-library-scotland nel net nhs nic nls org orgn parliament plc police sch scot soc ", "us": " dni fed isa kids nsn ", "uy": " com edu gub mil net org ", "ve": " co com edu gob info mil net org web ", "vi": " co com k12 net org ", "vn": " ac biz com edu gov health info int name net org pro ", "ye": " co com gov ltd me net org plc ", "yu": " ac co edu gov org ", "za": " ac agric alt bourse city co cybernet db edu gov grondar iaccess imt inca landesign law mil net ngo nis nom olivetti org pix school tm web ", "zm": " ac co com edu gov net org sch ", // https://en.wikipedia.org/wiki/CentralNic#Second-level_domains "com": "ar br cn de eu gb gr hu jpn kr no qc ru sa se uk us uy za ", "net": "gb jp se uk ", "org": "ae", "de": "com " }, // gorhill 2013-10-25: Using indexOf() instead Regexp(). Significant boost // in both performance and memory footprint. No initialization required. // http://jsperf.com/uri-js-sld-regex-vs-binary-search/4 // Following methods use lastIndexOf() rather than array.split() in order // to avoid any memory allocations. has: function(domain) { var tldOffset = domain.lastIndexOf("."); if (tldOffset <= 0 || tldOffset >= domain.length - 1) { return false; } var sldOffset = domain.lastIndexOf(".", tldOffset - 1); if (sldOffset <= 0 || sldOffset >= tldOffset - 1) { return false; } var sldList = SLD.list[domain.slice(tldOffset + 1)]; if (!sldList) { return false; } return sldList.indexOf(" " + domain.slice(sldOffset + 1, tldOffset) + " ") >= 0; }, is: function(domain) { var tldOffset = domain.lastIndexOf("."); if (tldOffset <= 0 || tldOffset >= domain.length - 1) { return false; } var sldOffset = domain.lastIndexOf(".", tldOffset - 1); if (sldOffset >= 0) { return false; } var sldList = SLD.list[domain.slice(tldOffset + 1)]; if (!sldList) { return false; } return sldList.indexOf(" " + domain.slice(0, tldOffset) + " ") >= 0; }, get: function(domain) { var tldOffset = domain.lastIndexOf("."); if (tldOffset <= 0 || tldOffset >= domain.length - 1) { return null; } var sldOffset = domain.lastIndexOf(".", tldOffset - 1); if (sldOffset <= 0 || sldOffset >= tldOffset - 1) { return null; } var sldList = SLD.list[domain.slice(tldOffset + 1)]; if (!sldList) { return null; } if (sldList.indexOf(" " + domain.slice(sldOffset + 1, tldOffset) + " ") < 0) { return null; } return domain.slice(sldOffset + 1); }, noConflict: function() { if (root.SecondLevelDomains === this) { root.SecondLevelDomains = _SecondLevelDomains; } return this; } }; return SLD; }); } }); // node_modules/urijs/src/URI.js var require_URI = __commonJS({ "node_modules/urijs/src/URI.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /*! * URI.js - Mutating URLs * * Version: 1.19.11 * * Author: Rodney Rehm * Web: http://medialize.github.io/URI.js/ * * Licensed under * MIT License http://www.opensource.org/licenses/mit-license * */ (function(root, factory) { "use strict"; if (typeof module === "object" && module.exports) { module.exports = factory(require_punycode(), require_IPv6(), require_SecondLevelDomains()); } else if (typeof define === "function" && define.amd) { define(["./punycode", "./IPv6", "./SecondLevelDomains"], factory); } else { root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root); } })(exports, function(punycode, IPv6, SLD, root) { "use strict"; var _URI = root && root.URI; function URI(url2, base) { var _urlSupplied = arguments.length >= 1; var _baseSupplied = arguments.length >= 2; if (!(this instanceof URI)) { if (_urlSupplied) { if (_baseSupplied) { return new URI(url2, base); } return new URI(url2); } return new URI(); } if (url2 === void 0) { if (_urlSupplied) { throw new TypeError("undefined is not a valid argument for URI"); } if (typeof location !== "undefined") { url2 = location.href + ""; } else { url2 = ""; } } if (url2 === null) { if (_urlSupplied) { throw new TypeError("null is not a valid argument for URI"); } } this.href(url2); if (base !== void 0) { return this.absoluteTo(base); } return this; } function isInteger(value) { return /^[0-9]+$/.test(value); } URI.version = "1.19.11"; var p = URI.prototype; var hasOwn = Object.prototype.hasOwnProperty; function escapeRegEx(string) { return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1"); } function getType(value) { if (value === void 0) { return "Undefined"; } return String(Object.prototype.toString.call(value)).slice(8, -1); } function isArray(obj) { return getType(obj) === "Array"; } function filterArrayValues(data, value) { var lookup = {}; var i, length2; if (getType(value) === "RegExp") { lookup = null; } else if (isArray(value)) { for (i = 0, length2 = value.length; i < length2; i++) { lookup[value[i]] = true; } } else { lookup[value] = true; } for (i = 0, length2 = data.length; i < length2; i++) { var _match = lookup && lookup[data[i]] !== void 0 || !lookup && value.test(data[i]); if (_match) { data.splice(i, 1); length2--; i--; } } return data; } function arrayContains(list, value) { var i, length2; if (isArray(value)) { for (i = 0, length2 = value.length; i < length2; i++) { if (!arrayContains(list, value[i])) { return false; } } return true; } var _type = getType(value); for (i = 0, length2 = list.length; i < length2; i++) { if (_type === "RegExp") { if (typeof list[i] === "string" && list[i].match(value)) { return true; } } else if (list[i] === value) { return true; } } return false; } function arraysEqual(one, two) { if (!isArray(one) || !isArray(two)) { return false; } if (one.length !== two.length) { return false; } one.sort(); two.sort(); for (var i = 0, l2 = one.length; i < l2; i++) { if (one[i] !== two[i]) { return false; } } return true; } function trimSlashes(text2) { var trim_expression = /^\/+|\/+$/g; return text2.replace(trim_expression, ""); } URI._parts = function() { return { protocol: null, username: null, password: null, hostname: null, urn: null, port: null, path: null, query: null, fragment: null, // state preventInvalidHostname: URI.preventInvalidHostname, duplicateQueryParameters: URI.duplicateQueryParameters, escapeQuerySpace: URI.escapeQuerySpace }; }; URI.preventInvalidHostname = false; URI.duplicateQueryParameters = false; URI.escapeQuerySpace = true; URI.protocol_expression = /^[a-z][a-z0-9.+-]*$/i; URI.idn_expression = /[^a-z0-9\._-]/i; URI.punycode_expression = /(xn--)/i; URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig; URI.findUri = { // valid "scheme://" or "www." start: /\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi, // everything up to the next whitespace end: /[\s\r\n]|$/, // trim trailing punctuation captured by end RegExp trim: /[`!()\[\]{};:'".,<>?«»“”„‘’]+$/, // balanced parens inclusion (), [], {}, <> parens: /(\([^\)]*\)|\[[^\]]*\]|\{[^}]*\}|<[^>]*>)/g }; URI.leading_whitespace_expression = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/; URI.ascii_tab_whitespace = /[\u0009\u000A\u000D]+/g; URI.defaultPorts = { http: "80", https: "443", ftp: "21", gopher: "70", ws: "80", wss: "443" }; URI.hostProtocols = [ "http", "https" ]; URI.invalid_hostname_characters = /[^a-zA-Z0-9\.\-:_]/; URI.domAttributes = { "a": "href", "blockquote": "cite", "link": "href", "base": "href", "script": "src", "form": "action", "img": "src", "area": "href", "iframe": "src", "embed": "src", "source": "src", "track": "src", "input": "src", // but only if type="image" "audio": "src", "video": "src" }; URI.getDomAttribute = function(node) { if (!node || !node.nodeName) { return void 0; } var nodeName = node.nodeName.toLowerCase(); if (nodeName === "input" && node.type !== "image") { return void 0; } return URI.domAttributes[nodeName]; }; function escapeForDumbFirefox36(value) { return escape(value); } function strictEncodeURIComponent(string) { return encodeURIComponent(string).replace(/[!'()*]/g, escapeForDumbFirefox36).replace(/\*/g, "%2A"); } URI.encode = strictEncodeURIComponent; URI.decode = decodeURIComponent; URI.iso8859 = function() { URI.encode = escape; URI.decode = unescape; }; URI.unicode = function() { URI.encode = strictEncodeURIComponent; URI.decode = decodeURIComponent; }; URI.characters = { pathname: { encode: { // RFC3986 2.1: For consistency, URI producers and normalizers should // use uppercase hexadecimal digits for all percent-encodings. expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig, map: { // -._~!'()* "%24": "$", "%26": "&", "%2B": "+", "%2C": ",", "%3B": ";", "%3D": "=", "%3A": ":", "%40": "@" } }, decode: { expression: /[\/\?#]/g, map: { "/": "%2F", "?": "%3F", "#": "%23" } } }, reserved: { encode: { // RFC3986 2.1: For consistency, URI producers and normalizers should // use uppercase hexadecimal digits for all percent-encodings. expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig, map: { // gen-delims "%3A": ":", "%2F": "/", "%3F": "?", "%23": "#", "%5B": "[", "%5D": "]", "%40": "@", // sub-delims "%21": "!", "%24": "$", "%26": "&", "%27": "'", "%28": "(", "%29": ")", "%2A": "*", "%2B": "+", "%2C": ",", "%3B": ";", "%3D": "=" } } }, urnpath: { // The characters under `encode` are the characters called out by RFC 2141 as being acceptable // for usage in a URN. RFC2141 also calls out "-", ".", and "_" as acceptable characters, but // these aren't encoded by encodeURIComponent, so we don't have to call them out here. Also // note that the colon character is not featured in the encoding map; this is because URI.js // gives the colons in URNs semantic meaning as the delimiters of path segements, and so it // should not appear unencoded in a segment itself. // See also the note above about RFC3986 and capitalalized hex digits. encode: { expression: /%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig, map: { "%21": "!", "%24": "$", "%27": "'", "%28": "(", "%29": ")", "%2A": "*", "%2B": "+", "%2C": ",", "%3B": ";", "%3D": "=", "%40": "@" } }, // These characters are the characters called out by RFC2141 as "reserved" characters that // should never appear in a URN, plus the colon character (see note above). decode: { expression: /[\/\?#:]/g, map: { "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" } } } }; URI.encodeQuery = function(string, escapeQuerySpace) { var escaped = URI.encode(string + ""); if (escapeQuerySpace === void 0) { escapeQuerySpace = URI.escapeQuerySpace; } return escapeQuerySpace ? escaped.replace(/%20/g, "+") : escaped; }; URI.decodeQuery = function(string, escapeQuerySpace) { string += ""; if (escapeQuerySpace === void 0) { escapeQuerySpace = URI.escapeQuerySpace; } try { return URI.decode(escapeQuerySpace ? string.replace(/\+/g, "%20") : string); } catch (e) { return string; } }; var _parts = { "encode": "encode", "decode": "decode" }; var _part; var generateAccessor = function(_group, _part2) { return function(string) { try { return URI[_part2](string + "").replace(URI.characters[_group][_part2].expression, function(c14) { return URI.characters[_group][_part2].map[c14]; }); } catch (e) { return string; } }; }; for (_part in _parts) { URI[_part + "PathSegment"] = generateAccessor("pathname", _parts[_part]); URI[_part + "UrnPathSegment"] = generateAccessor("urnpath", _parts[_part]); } var generateSegmentedPathFunction = function(_sep, _codingFuncName, _innerCodingFuncName) { return function(string) { var actualCodingFunc; if (!_innerCodingFuncName) { actualCodingFunc = URI[_codingFuncName]; } else { actualCodingFunc = function(string2) { return URI[_codingFuncName](URI[_innerCodingFuncName](string2)); }; } var segments = (string + "").split(_sep); for (var i = 0, length2 = segments.length; i < length2; i++) { segments[i] = actualCodingFunc(segments[i]); } return segments.join(_sep); }; }; URI.decodePath = generateSegmentedPathFunction("/", "decodePathSegment"); URI.decodeUrnPath = generateSegmentedPathFunction(":", "decodeUrnPathSegment"); URI.recodePath = generateSegmentedPathFunction("/", "encodePathSegment", "decode"); URI.recodeUrnPath = generateSegmentedPathFunction(":", "encodeUrnPathSegment", "decode"); URI.encodeReserved = generateAccessor("reserved", "encode"); URI.parse = function(string, parts) { var pos; if (!parts) { parts = { preventInvalidHostname: URI.preventInvalidHostname }; } string = string.replace(URI.leading_whitespace_expression, ""); string = string.replace(URI.ascii_tab_whitespace, ""); pos = string.indexOf("#"); if (pos > -1) { parts.fragment = string.substring(pos + 1) || null; string = string.substring(0, pos); } pos = string.indexOf("?"); if (pos > -1) { parts.query = string.substring(pos + 1) || null; string = string.substring(0, pos); } string = string.replace(/^(https?|ftp|wss?)?:+[/\\]*/i, "$1://"); string = string.replace(/^[/\\]{2,}/i, "//"); if (string.substring(0, 2) === "//") { parts.protocol = null; string = string.substring(2); string = URI.parseAuthority(string, parts); } else { pos = string.indexOf(":"); if (pos > -1) { parts.protocol = string.substring(0, pos) || null; if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) { parts.protocol = void 0; } else if (string.substring(pos + 1, pos + 3).replace(/\\/g, "/") === "//") { string = string.substring(pos + 3); string = URI.parseAuthority(string, parts); } else { string = string.substring(pos + 1); parts.urn = true; } } } parts.path = string; return parts; }; URI.parseHost = function(string, parts) { if (!string) { string = ""; } string = string.replace(/\\/g, "/"); var pos = string.indexOf("/"); var bracketPos; var t2; if (pos === -1) { pos = string.length; } if (string.charAt(0) === "[") { bracketPos = string.indexOf("]"); parts.hostname = string.substring(1, bracketPos) || null; parts.port = string.substring(bracketPos + 2, pos) || null; if (parts.port === "/") { parts.port = null; } } else { var firstColon = string.indexOf(":"); var firstSlash = string.indexOf("/"); var nextColon = string.indexOf(":", firstColon + 1); if (nextColon !== -1 && (firstSlash === -1 || nextColon < firstSlash)) { parts.hostname = string.substring(0, pos) || null; parts.port = null; } else { t2 = string.substring(0, pos).split(":"); parts.hostname = t2[0] || null; parts.port = t2[1] || null; } } if (parts.hostname && string.substring(pos).charAt(0) !== "/") { pos++; string = "/" + string; } if (parts.preventInvalidHostname) { URI.ensureValidHostname(parts.hostname, parts.protocol); } if (parts.port) { URI.ensureValidPort(parts.port); } return string.substring(pos) || "/"; }; URI.parseAuthority = function(string, parts) { string = URI.parseUserinfo(string, parts); return URI.parseHost(string, parts); }; URI.parseUserinfo = function(string, parts) { var _string = string; var firstBackSlash = string.indexOf("\\"); if (firstBackSlash !== -1) { string = string.replace(/\\/g, "/"); } var firstSlash = string.indexOf("/"); var pos = string.lastIndexOf("@", firstSlash > -1 ? firstSlash : string.length - 1); var t2; if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) { t2 = string.substring(0, pos).split(":"); parts.username = t2[0] ? URI.decode(t2[0]) : null; t2.shift(); parts.password = t2[0] ? URI.decode(t2.join(":")) : null; string = _string.substring(pos + 1); } else { parts.username = null; parts.password = null; } return string; }; URI.parseQuery = function(string, escapeQuerySpace) { if (!string) { return {}; } string = string.replace(/&+/g, "&").replace(/^\?*&*|&+$/g, ""); if (!string) { return {}; } var items = {}; var splits = string.split("&"); var length2 = splits.length; var v3, name, value; for (var i = 0; i < length2; i++) { v3 = splits[i].split("="); name = URI.decodeQuery(v3.shift(), escapeQuerySpace); value = v3.length ? URI.decodeQuery(v3.join("="), escapeQuerySpace) : null; if (name === "__proto__") { continue; } else if (hasOwn.call(items, name)) { if (typeof items[name] === "string" || items[name] === null) { items[name] = [items[name]]; } items[name].push(value); } else { items[name] = value; } } return items; }; URI.build = function(parts) { var t2 = ""; var requireAbsolutePath = false; if (parts.protocol) { t2 += parts.protocol + ":"; } if (!parts.urn && (t2 || parts.hostname)) { t2 += "//"; requireAbsolutePath = true; } t2 += URI.buildAuthority(parts) || ""; if (typeof parts.path === "string") { if (parts.path.charAt(0) !== "/" && requireAbsolutePath) { t2 += "/"; } t2 += parts.path; } if (typeof parts.query === "string" && parts.query) { t2 += "?" + parts.query; } if (typeof parts.fragment === "string" && parts.fragment) { t2 += "#" + parts.fragment; } return t2; }; URI.buildHost = function(parts) { var t2 = ""; if (!parts.hostname) { return ""; } else if (URI.ip6_expression.test(parts.hostname)) { t2 += "[" + parts.hostname + "]"; } else { t2 += parts.hostname; } if (parts.port) { t2 += ":" + parts.port; } return t2; }; URI.buildAuthority = function(parts) { return URI.buildUserinfo(parts) + URI.buildHost(parts); }; URI.buildUserinfo = function(parts) { var t2 = ""; if (parts.username) { t2 += URI.encode(parts.username); } if (parts.password) { t2 += ":" + URI.encode(parts.password); } if (t2) { t2 += "@"; } return t2; }; URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) { var t2 = ""; var unique, key, i, length2; for (key in data) { if (key === "__proto__") { continue; } else if (hasOwn.call(data, key)) { if (isArray(data[key])) { unique = {}; for (i = 0, length2 = data[key].length; i < length2; i++) { if (data[key][i] !== void 0 && unique[data[key][i] + ""] === void 0) { t2 += "&" + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace); if (duplicateQueryParameters !== true) { unique[data[key][i] + ""] = true; } } } } else if (data[key] !== void 0) { t2 += "&" + URI.buildQueryParameter(key, data[key], escapeQuerySpace); } } } return t2.substring(1); }; URI.buildQueryParameter = function(name, value, escapeQuerySpace) { return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? "=" + URI.encodeQuery(value, escapeQuerySpace) : ""); }; URI.addQuery = function(data, name, value) { if (typeof name === "object") { for (var key in name) { if (hasOwn.call(name, key)) { URI.addQuery(data, key, name[key]); } } } else if (typeof name === "string") { if (data[name] === void 0) { data[name] = value; return; } else if (typeof data[name] === "string") { data[name] = [data[name]]; } if (!isArray(value)) { value = [value]; } data[name] = (data[name] || []).concat(value); } else { throw new TypeError("URI.addQuery() accepts an object, string as the name parameter"); } }; URI.setQuery = function(data, name, value) { if (typeof name === "object") { for (var key in name) { if (hasOwn.call(name, key)) { URI.setQuery(data, key, name[key]); } } } else if (typeof name === "string") { data[name] = value === void 0 ? null : value; } else { throw new TypeError("URI.setQuery() accepts an object, string as the name parameter"); } }; URI.removeQuery = function(data, name, value) { var i, length2, key; if (isArray(name)) { for (i = 0, length2 = name.length; i < length2; i++) { data[name[i]] = void 0; } } else if (getType(name) === "RegExp") { for (key in data) { if (name.test(key)) { data[key] = void 0; } } } else if (typeof name === "object") { for (key in name) { if (hasOwn.call(name, key)) { URI.removeQuery(data, key, name[key]); } } } else if (typeof name === "string") { if (value !== void 0) { if (getType(value) === "RegExp") { if (!isArray(data[name]) && value.test(data[name])) { data[name] = void 0; } else { data[name] = filterArrayValues(data[name], value); } } else if (data[name] === String(value) && (!isArray(value) || value.length === 1)) { data[name] = void 0; } else if (isArray(data[name])) { data[name] = filterArrayValues(data[name], value); } } else { data[name] = void 0; } } else { throw new TypeError("URI.removeQuery() accepts an object, string, RegExp as the first parameter"); } }; URI.hasQuery = function(data, name, value, withinArray) { switch (getType(name)) { case "String": break; case "RegExp": for (var key in data) { if (hasOwn.call(data, key)) { if (name.test(key) && (value === void 0 || URI.hasQuery(data, key, value))) { return true; } } } return false; case "Object": for (var _key in name) { if (hasOwn.call(name, _key)) { if (!URI.hasQuery(data, _key, name[_key])) { return false; } } } return true; default: throw new TypeError("URI.hasQuery() accepts a string, regular expression or object as the name parameter"); } switch (getType(value)) { case "Undefined": return name in data; // data[name] !== undefined; case "Boolean": var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]); return value === _booly; case "Function": return !!value(data[name], name, data); case "Array": if (!isArray(data[name])) { return false; } var op = withinArray ? arrayContains : arraysEqual; return op(data[name], value); case "RegExp": if (!isArray(data[name])) { return Boolean(data[name] && data[name].match(value)); } if (!withinArray) { return false; } return arrayContains(data[name], value); case "Number": value = String(value); /* falls through */ case "String": if (!isArray(data[name])) { return data[name] === value; } if (!withinArray) { return false; } return arrayContains(data[name], value); default: throw new TypeError("URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter"); } }; URI.joinPaths = function() { var input = []; var segments = []; var nonEmptySegments = 0; for (var i = 0; i < arguments.length; i++) { var url2 = new URI(arguments[i]); input.push(url2); var _segments = url2.segment(); for (var s2 = 0; s2 < _segments.length; s2++) { if (typeof _segments[s2] === "string") { segments.push(_segments[s2]); } if (_segments[s2]) { nonEmptySegments++; } } } if (!segments.length || !nonEmptySegments) { return new URI(""); } var uri = new URI("").segment(segments); if (input[0].path() === "" || input[0].path().slice(0, 1) === "/") { uri.path("/" + uri.path()); } return uri.normalize(); }; URI.commonPath = function(one, two) { var length2 = Math.min(one.length, two.length); var pos; for (pos = 0; pos < length2; pos++) { if (one.charAt(pos) !== two.charAt(pos)) { pos--; break; } } if (pos < 1) { return one.charAt(0) === two.charAt(0) && one.charAt(0) === "/" ? "/" : ""; } if (one.charAt(pos) !== "/" || two.charAt(pos) !== "/") { pos = one.substring(0, pos).lastIndexOf("/"); } return one.substring(0, pos + 1); }; URI.withinString = function(string, callback, options) { options || (options = {}); var _start = options.start || URI.findUri.start; var _end = options.end || URI.findUri.end; var _trim = options.trim || URI.findUri.trim; var _parens = options.parens || URI.findUri.parens; var _attributeOpen = /[a-z0-9-]=["']?$/i; _start.lastIndex = 0; while (true) { var match = _start.exec(string); if (!match) { break; } var start = match.index; if (options.ignoreHtml) { var attributeOpen = string.slice(Math.max(start - 3, 0), start); if (attributeOpen && _attributeOpen.test(attributeOpen)) { continue; } } var end = start + string.slice(start).search(_end); var slice = string.slice(start, end); var parensEnd = -1; while (true) { var parensMatch = _parens.exec(slice); if (!parensMatch) { break; } var parensMatchEnd = parensMatch.index + parensMatch[0].length; parensEnd = Math.max(parensEnd, parensMatchEnd); } if (parensEnd > -1) { slice = slice.slice(0, parensEnd) + slice.slice(parensEnd).replace(_trim, ""); } else { slice = slice.replace(_trim, ""); } if (slice.length <= match[0].length) { continue; } if (options.ignore && options.ignore.test(slice)) { continue; } end = start + slice.length; var result = callback(slice, start, end, string); if (result === void 0) { _start.lastIndex = end; continue; } result = String(result); string = string.slice(0, start) + result + string.slice(end); _start.lastIndex = start + result.length; } _start.lastIndex = 0; return string; }; URI.ensureValidHostname = function(v3, protocol) { var hasHostname = !!v3; var hasProtocol = !!protocol; var rejectEmptyHostname = false; if (hasProtocol) { rejectEmptyHostname = arrayContains(URI.hostProtocols, protocol); } if (rejectEmptyHostname && !hasHostname) { throw new TypeError("Hostname cannot be empty, if protocol is " + protocol); } else if (v3 && v3.match(URI.invalid_hostname_characters)) { if (!punycode) { throw new TypeError('Hostname "' + v3 + '" contains characters other than [A-Z0-9.-:_] and Punycode.js is not available'); } if (punycode.toASCII(v3).match(URI.invalid_hostname_characters)) { throw new TypeError('Hostname "' + v3 + '" contains characters other than [A-Z0-9.-:_]'); } } }; URI.ensureValidPort = function(v3) { if (!v3) { return; } var port = Number(v3); if (isInteger(port) && port > 0 && port < 65536) { return; } throw new TypeError('Port "' + v3 + '" is not a valid port'); }; URI.noConflict = function(removeAll2) { if (removeAll2) { var unconflicted = { URI: this.noConflict() }; if (root.URITemplate && typeof root.URITemplate.noConflict === "function") { unconflicted.URITemplate = root.URITemplate.noConflict(); } if (root.IPv6 && typeof root.IPv6.noConflict === "function") { unconflicted.IPv6 = root.IPv6.noConflict(); } if (root.SecondLevelDomains && typeof root.SecondLevelDomains.noConflict === "function") { unconflicted.SecondLevelDomains = root.SecondLevelDomains.noConflict(); } return unconflicted; } else if (root.URI === this) { root.URI = _URI; } return this; }; p.build = function(deferBuild) { if (deferBuild === true) { this._deferred_build = true; } else if (deferBuild === void 0 || this._deferred_build) { this._string = URI.build(this._parts); this._deferred_build = false; } return this; }; p.clone = function() { return new URI(this); }; p.valueOf = p.toString = function() { return this.build(false)._string; }; function generateSimpleAccessor(_part2) { return function(v3, build) { if (v3 === void 0) { return this._parts[_part2] || ""; } else { this._parts[_part2] = v3 || null; this.build(!build); return this; } }; } function generatePrefixAccessor(_part2, _key) { return function(v3, build) { if (v3 === void 0) { return this._parts[_part2] || ""; } else { if (v3 !== null) { v3 = v3 + ""; if (v3.charAt(0) === _key) { v3 = v3.substring(1); } } this._parts[_part2] = v3; this.build(!build); return this; } }; } p.protocol = generateSimpleAccessor("protocol"); p.username = generateSimpleAccessor("username"); p.password = generateSimpleAccessor("password"); p.hostname = generateSimpleAccessor("hostname"); p.port = generateSimpleAccessor("port"); p.query = generatePrefixAccessor("query", "?"); p.fragment = generatePrefixAccessor("fragment", "#"); p.search = function(v3, build) { var t2 = this.query(v3, build); return typeof t2 === "string" && t2.length ? "?" + t2 : t2; }; p.hash = function(v3, build) { var t2 = this.fragment(v3, build); return typeof t2 === "string" && t2.length ? "#" + t2 : t2; }; p.pathname = function(v3, build) { if (v3 === void 0 || v3 === true) { var res = this._parts.path || (this._parts.hostname ? "/" : ""); return v3 ? (this._parts.urn ? URI.decodeUrnPath : URI.decodePath)(res) : res; } else { if (this._parts.urn) { this._parts.path = v3 ? URI.recodeUrnPath(v3) : ""; } else { this._parts.path = v3 ? URI.recodePath(v3) : "/"; } this.build(!build); return this; } }; p.path = p.pathname; p.href = function(href, build) { var key; if (href === void 0) { return this.toString(); } this._string = ""; this._parts = URI._parts(); var _URI2 = href instanceof URI; var _object = typeof href === "object" && (href.hostname || href.path || href.pathname); if (href.nodeName) { var attribute = URI.getDomAttribute(href); href = href[attribute] || ""; _object = false; } if (!_URI2 && _object && href.pathname !== void 0) { href = href.toString(); } if (typeof href === "string" || href instanceof String) { this._parts = URI.parse(String(href), this._parts); } else if (_URI2 || _object) { var src = _URI2 ? href._parts : href; for (key in src) { if (key === "query") { continue; } if (hasOwn.call(this._parts, key)) { this._parts[key] = src[key]; } } if (src.query) { this.query(src.query, false); } } else { throw new TypeError("invalid input"); } this.build(!build); return this; }; p.is = function(what) { var ip = false; var ip4 = false; var ip6 = false; var name = false; var sld = false; var idn = false; var punycode2 = false; var relative = !this._parts.urn; if (this._parts.hostname) { relative = false; ip4 = URI.ip4_expression.test(this._parts.hostname); ip6 = URI.ip6_expression.test(this._parts.hostname); ip = ip4 || ip6; name = !ip; sld = name && SLD && SLD.has(this._parts.hostname); idn = name && URI.idn_expression.test(this._parts.hostname); punycode2 = name && URI.punycode_expression.test(this._parts.hostname); } switch (what.toLowerCase()) { case "relative": return relative; case "absolute": return !relative; // hostname identification case "domain": case "name": return name; case "sld": return sld; case "ip": return ip; case "ip4": case "ipv4": case "inet4": return ip4; case "ip6": case "ipv6": case "inet6": return ip6; case "idn": return idn; case "url": return !this._parts.urn; case "urn": return !!this._parts.urn; case "punycode": return punycode2; } return null; }; var _protocol = p.protocol; var _port = p.port; var _hostname = p.hostname; p.protocol = function(v3, build) { if (v3) { v3 = v3.replace(/:(\/\/)?$/, ""); if (!v3.match(URI.protocol_expression)) { throw new TypeError('Protocol "' + v3 + `" contains characters other than [A-Z0-9.+-] or doesn't start with [A-Z]`); } } return _protocol.call(this, v3, build); }; p.scheme = p.protocol; p.port = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 !== void 0) { if (v3 === 0) { v3 = null; } if (v3) { v3 += ""; if (v3.charAt(0) === ":") { v3 = v3.substring(1); } URI.ensureValidPort(v3); } } return _port.call(this, v3, build); }; p.hostname = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 !== void 0) { var x = { preventInvalidHostname: this._parts.preventInvalidHostname }; var res = URI.parseHost(v3, x); if (res !== "/") { throw new TypeError('Hostname "' + v3 + '" contains characters other than [A-Z0-9.-]'); } v3 = x.hostname; if (this._parts.preventInvalidHostname) { URI.ensureValidHostname(v3, this._parts.protocol); } } return _hostname.call(this, v3, build); }; p.origin = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0) { var protocol = this.protocol(); var authority = this.authority(); if (!authority) { return ""; } return (protocol ? protocol + "://" : "") + this.authority(); } else { var origin = URI(v3); this.protocol(origin.protocol()).authority(origin.authority()).build(!build); return this; } }; p.host = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0) { return this._parts.hostname ? URI.buildHost(this._parts) : ""; } else { var res = URI.parseHost(v3, this._parts); if (res !== "/") { throw new TypeError('Hostname "' + v3 + '" contains characters other than [A-Z0-9.-]'); } this.build(!build); return this; } }; p.authority = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0) { return this._parts.hostname ? URI.buildAuthority(this._parts) : ""; } else { var res = URI.parseAuthority(v3, this._parts); if (res !== "/") { throw new TypeError('Hostname "' + v3 + '" contains characters other than [A-Z0-9.-]'); } this.build(!build); return this; } }; p.userinfo = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0) { var t2 = URI.buildUserinfo(this._parts); return t2 ? t2.substring(0, t2.length - 1) : t2; } else { if (v3[v3.length - 1] !== "@") { v3 += "@"; } URI.parseUserinfo(v3, this._parts); this.build(!build); return this; } }; p.resource = function(v3, build) { var parts; if (v3 === void 0) { return this.path() + this.search() + this.hash(); } parts = URI.parse(v3); this._parts.path = parts.path; this._parts.query = parts.query; this._parts.fragment = parts.fragment; this.build(!build); return this; }; p.subdomain = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0) { if (!this._parts.hostname || this.is("IP")) { return ""; } var end = this._parts.hostname.length - this.domain().length - 1; return this._parts.hostname.substring(0, end) || ""; } else { var e = this._parts.hostname.length - this.domain().length; var sub = this._parts.hostname.substring(0, e); var replace = new RegExp("^" + escapeRegEx(sub)); if (v3 && v3.charAt(v3.length - 1) !== ".") { v3 += "."; } if (v3.indexOf(":") !== -1) { throw new TypeError("Domains cannot contain colons"); } if (v3) { URI.ensureValidHostname(v3, this._parts.protocol); } this._parts.hostname = this._parts.hostname.replace(replace, v3); this.build(!build); return this; } }; p.domain = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (typeof v3 === "boolean") { build = v3; v3 = void 0; } if (v3 === void 0) { if (!this._parts.hostname || this.is("IP")) { return ""; } var t2 = this._parts.hostname.match(/\./g); if (t2 && t2.length < 2) { return this._parts.hostname; } var end = this._parts.hostname.length - this.tld(build).length - 1; end = this._parts.hostname.lastIndexOf(".", end - 1) + 1; return this._parts.hostname.substring(end) || ""; } else { if (!v3) { throw new TypeError("cannot set domain empty"); } if (v3.indexOf(":") !== -1) { throw new TypeError("Domains cannot contain colons"); } URI.ensureValidHostname(v3, this._parts.protocol); if (!this._parts.hostname || this.is("IP")) { this._parts.hostname = v3; } else { var replace = new RegExp(escapeRegEx(this.domain()) + "$"); this._parts.hostname = this._parts.hostname.replace(replace, v3); } this.build(!build); return this; } }; p.tld = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (typeof v3 === "boolean") { build = v3; v3 = void 0; } if (v3 === void 0) { if (!this._parts.hostname || this.is("IP")) { return ""; } var pos = this._parts.hostname.lastIndexOf("."); var tld = this._parts.hostname.substring(pos + 1); if (build !== true && SLD && SLD.list[tld.toLowerCase()]) { return SLD.get(this._parts.hostname) || tld; } return tld; } else { var replace; if (!v3) { throw new TypeError("cannot set TLD empty"); } else if (v3.match(/[^a-zA-Z0-9-]/)) { if (SLD && SLD.is(v3)) { replace = new RegExp(escapeRegEx(this.tld()) + "$"); this._parts.hostname = this._parts.hostname.replace(replace, v3); } else { throw new TypeError('TLD "' + v3 + '" contains characters other than [A-Z0-9]'); } } else if (!this._parts.hostname || this.is("IP")) { throw new ReferenceError("cannot set TLD on non-domain host"); } else { replace = new RegExp(escapeRegEx(this.tld()) + "$"); this._parts.hostname = this._parts.hostname.replace(replace, v3); } this.build(!build); return this; } }; p.directory = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0 || v3 === true) { if (!this._parts.path && !this._parts.hostname) { return ""; } if (this._parts.path === "/") { return "/"; } var end = this._parts.path.length - this.filename().length - 1; var res = this._parts.path.substring(0, end) || (this._parts.hostname ? "/" : ""); return v3 ? URI.decodePath(res) : res; } else { var e = this._parts.path.length - this.filename().length; var directory = this._parts.path.substring(0, e); var replace = new RegExp("^" + escapeRegEx(directory)); if (!this.is("relative")) { if (!v3) { v3 = "/"; } if (v3.charAt(0) !== "/") { v3 = "/" + v3; } } if (v3 && v3.charAt(v3.length - 1) !== "/") { v3 += "/"; } v3 = URI.recodePath(v3); this._parts.path = this._parts.path.replace(replace, v3); this.build(!build); return this; } }; p.filename = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (typeof v3 !== "string") { if (!this._parts.path || this._parts.path === "/") { return ""; } var pos = this._parts.path.lastIndexOf("/"); var res = this._parts.path.substring(pos + 1); return v3 ? URI.decodePathSegment(res) : res; } else { var mutatedDirectory = false; if (v3.charAt(0) === "/") { v3 = v3.substring(1); } if (v3.match(/\.?\//)) { mutatedDirectory = true; } var replace = new RegExp(escapeRegEx(this.filename()) + "$"); v3 = URI.recodePath(v3); this._parts.path = this._parts.path.replace(replace, v3); if (mutatedDirectory) { this.normalizePath(build); } else { this.build(!build); } return this; } }; p.suffix = function(v3, build) { if (this._parts.urn) { return v3 === void 0 ? "" : this; } if (v3 === void 0 || v3 === true) { if (!this._parts.path || this._parts.path === "/") { return ""; } var filename = this.filename(); var pos = filename.lastIndexOf("."); var s2, res; if (pos === -1) { return ""; } s2 = filename.substring(pos + 1); res = /^[a-z0-9%]+$/i.test(s2) ? s2 : ""; return v3 ? URI.decodePathSegment(res) : res; } else { if (v3.charAt(0) === ".") { v3 = v3.substring(1); } var suffix = this.suffix(); var replace; if (!suffix) { if (!v3) { return this; } this._parts.path += "." + URI.recodePath(v3); } else if (!v3) { replace = new RegExp(escapeRegEx("." + suffix) + "$"); } else { replace = new RegExp(escapeRegEx(suffix) + "$"); } if (replace) { v3 = URI.recodePath(v3); this._parts.path = this._parts.path.replace(replace, v3); } this.build(!build); return this; } }; p.segment = function(segment, v3, build) { var separator = this._parts.urn ? ":" : "/"; var path = this.path(); var absolute = path.substring(0, 1) === "/"; var segments = path.split(separator); if (segment !== void 0 && typeof segment !== "number") { build = v3; v3 = segment; segment = void 0; } if (segment !== void 0 && typeof segment !== "number") { throw new Error('Bad segment "' + segment + '", must be 0-based integer'); } if (absolute) { segments.shift(); } if (segment < 0) { segment = Math.max(segments.length + segment, 0); } if (v3 === void 0) { return segment === void 0 ? segments : segments[segment]; } else if (segment === null || segments[segment] === void 0) { if (isArray(v3)) { segments = []; for (var i = 0, l2 = v3.length; i < l2; i++) { if (!v3[i].length && (!segments.length || !segments[segments.length - 1].length)) { continue; } if (segments.length && !segments[segments.length - 1].length) { segments.pop(); } segments.push(trimSlashes(v3[i])); } } else if (v3 || typeof v3 === "string") { v3 = trimSlashes(v3); if (segments[segments.length - 1] === "") { segments[segments.length - 1] = v3; } else { segments.push(v3); } } } else { if (v3) { segments[segment] = trimSlashes(v3); } else { segments.splice(segment, 1); } } if (absolute) { segments.unshift(""); } return this.path(segments.join(separator), build); }; p.segmentCoded = function(segment, v3, build) { var segments, i, l2; if (typeof segment !== "number") { build = v3; v3 = segment; segment = void 0; } if (v3 === void 0) { segments = this.segment(segment, v3, build); if (!isArray(segments)) { segments = segments !== void 0 ? URI.decode(segments) : void 0; } else { for (i = 0, l2 = segments.length; i < l2; i++) { segments[i] = URI.decode(segments[i]); } } return segments; } if (!isArray(v3)) { v3 = typeof v3 === "string" || v3 instanceof String ? URI.encode(v3) : v3; } else { for (i = 0, l2 = v3.length; i < l2; i++) { v3[i] = URI.encode(v3[i]); } } return this.segment(segment, v3, build); }; var q = p.query; p.query = function(v3, build) { if (v3 === true) { return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); } else if (typeof v3 === "function") { var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); var result = v3.call(this, data); this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace); this.build(!build); return this; } else if (v3 !== void 0 && typeof v3 !== "string") { this._parts.query = URI.buildQuery(v3, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace); this.build(!build); return this; } else { return q.call(this, v3, build); } }; p.setQuery = function(name, value, build) { var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); if (typeof name === "string" || name instanceof String) { data[name] = value !== void 0 ? value : null; } else if (typeof name === "object") { for (var key in name) { if (hasOwn.call(name, key)) { data[key] = name[key]; } } } else { throw new TypeError("URI.addQuery() accepts an object, string as the name parameter"); } this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace); if (typeof name !== "string") { build = value; } this.build(!build); return this; }; p.addQuery = function(name, value, build) { var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); URI.addQuery(data, name, value === void 0 ? null : value); this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace); if (typeof name !== "string") { build = value; } this.build(!build); return this; }; p.removeQuery = function(name, value, build) { var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); URI.removeQuery(data, name, value); this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace); if (typeof name !== "string") { build = value; } this.build(!build); return this; }; p.hasQuery = function(name, value, withinArray) { var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace); return URI.hasQuery(data, name, value, withinArray); }; p.setSearch = p.setQuery; p.addSearch = p.addQuery; p.removeSearch = p.removeQuery; p.hasSearch = p.hasQuery; p.normalize = function() { if (this._parts.urn) { return this.normalizeProtocol(false).normalizePath(false).normalizeQuery(false).normalizeFragment(false).build(); } return this.normalizeProtocol(false).normalizeHostname(false).normalizePort(false).normalizePath(false).normalizeQuery(false).normalizeFragment(false).build(); }; p.normalizeProtocol = function(build) { if (typeof this._parts.protocol === "string") { this._parts.protocol = this._parts.protocol.toLowerCase(); this.build(!build); } return this; }; p.normalizeHostname = function(build) { if (this._parts.hostname) { if (this.is("IDN") && punycode) { this._parts.hostname = punycode.toASCII(this._parts.hostname); } else if (this.is("IPv6") && IPv6) { this._parts.hostname = IPv6.best(this._parts.hostname); } this._parts.hostname = this._parts.hostname.toLowerCase(); this.build(!build); } return this; }; p.normalizePort = function(build) { if (typeof this._parts.protocol === "string" && this._parts.port === URI.defaultPorts[this._parts.protocol]) { this._parts.port = null; this.build(!build); } return this; }; p.normalizePath = function(build) { var _path = this._parts.path; if (!_path) { return this; } if (this._parts.urn) { this._parts.path = URI.recodeUrnPath(this._parts.path); this.build(!build); return this; } if (this._parts.path === "/") { return this; } _path = URI.recodePath(_path); var _was_relative; var _leadingParents = ""; var _parent, _pos; if (_path.charAt(0) !== "/") { _was_relative = true; _path = "/" + _path; } if (_path.slice(-3) === "/.." || _path.slice(-2) === "/.") { _path += "/"; } _path = _path.replace(/(\/(\.\/)+)|(\/\.$)/g, "/").replace(/\/{2,}/g, "/"); if (_was_relative) { _leadingParents = _path.substring(1).match(/^(\.\.\/)+/) || ""; if (_leadingParents) { _leadingParents = _leadingParents[0]; } } while (true) { _parent = _path.search(/\/\.\.(\/|$)/); if (_parent === -1) { break; } else if (_parent === 0) { _path = _path.substring(3); continue; } _pos = _path.substring(0, _parent).lastIndexOf("/"); if (_pos === -1) { _pos = _parent; } _path = _path.substring(0, _pos) + _path.substring(_parent + 3); } if (_was_relative && this.is("relative")) { _path = _leadingParents + _path.substring(1); } this._parts.path = _path; this.build(!build); return this; }; p.normalizePathname = p.normalizePath; p.normalizeQuery = function(build) { if (typeof this._parts.query === "string") { if (!this._parts.query.length) { this._parts.query = null; } else { this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace)); } this.build(!build); } return this; }; p.normalizeFragment = function(build) { if (!this._parts.fragment) { this._parts.fragment = null; this.build(!build); } return this; }; p.normalizeSearch = p.normalizeQuery; p.normalizeHash = p.normalizeFragment; p.iso8859 = function() { var e = URI.encode; var d = URI.decode; URI.encode = escape; URI.decode = decodeURIComponent; try { this.normalize(); } finally { URI.encode = e; URI.decode = d; } return this; }; p.unicode = function() { var e = URI.encode; var d = URI.decode; URI.encode = strictEncodeURIComponent; URI.decode = unescape; try { this.normalize(); } finally { URI.encode = e; URI.decode = d; } return this; }; p.readable = function() { var uri = this.clone(); uri.username("").password("").normalize(); var t2 = ""; if (uri._parts.protocol) { t2 += uri._parts.protocol + "://"; } if (uri._parts.hostname) { if (uri.is("punycode") && punycode) { t2 += punycode.toUnicode(uri._parts.hostname); if (uri._parts.port) { t2 += ":" + uri._parts.port; } } else { t2 += uri.host(); } } if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== "/") { t2 += "/"; } t2 += uri.path(true); if (uri._parts.query) { var q3 = ""; for (var i = 0, qp = uri._parts.query.split("&"), l2 = qp.length; i < l2; i++) { var kv = (qp[i] || "").split("="); q3 += "&" + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace).replace(/&/g, "%26"); if (kv[1] !== void 0) { q3 += "=" + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace).replace(/&/g, "%26"); } } t2 += "?" + q3.substring(1); } t2 += URI.decodeQuery(uri.hash(), true); return t2; }; p.absoluteTo = function(base) { var resolved = this.clone(); var properties = ["protocol", "username", "password", "hostname", "port"]; var basedir, i, p2; if (this._parts.urn) { throw new Error("URNs do not have any generally defined hierarchical components"); } if (!(base instanceof URI)) { base = new URI(base); } if (resolved._parts.protocol) { return resolved; } else { resolved._parts.protocol = base._parts.protocol; } if (this._parts.hostname) { return resolved; } for (i = 0; p2 = properties[i]; i++) { resolved._parts[p2] = base._parts[p2]; } if (!resolved._parts.path) { resolved._parts.path = base._parts.path; if (!resolved._parts.query) { resolved._parts.query = base._parts.query; } } else { if (resolved._parts.path.substring(-2) === "..") { resolved._parts.path += "/"; } if (resolved.path().charAt(0) !== "/") { basedir = base.directory(); basedir = basedir ? basedir : base.path().indexOf("/") === 0 ? "/" : ""; resolved._parts.path = (basedir ? basedir + "/" : "") + resolved._parts.path; resolved.normalizePath(); } } resolved.build(); return resolved; }; p.relativeTo = function(base) { var relative = this.clone().normalize(); var relativeParts, baseParts, common, relativePath, basePath; if (relative._parts.urn) { throw new Error("URNs do not have any generally defined hierarchical components"); } base = new URI(base).normalize(); relativeParts = relative._parts; baseParts = base._parts; relativePath = relative.path(); basePath = base.path(); if (relativePath.charAt(0) !== "/") { throw new Error("URI is already relative"); } if (basePath.charAt(0) !== "/") { throw new Error("Cannot calculate a URI relative to another relative URI"); } if (relativeParts.protocol === baseParts.protocol) { relativeParts.protocol = null; } if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) { return relative.build(); } if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) { return relative.build(); } if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) { relativeParts.hostname = null; relativeParts.port = null; } else { return relative.build(); } if (relativePath === basePath) { relativeParts.path = ""; return relative.build(); } common = URI.commonPath(relativePath, basePath); if (!common) { return relative.build(); } var parents = baseParts.path.substring(common.length).replace(/[^\/]*$/, "").replace(/.*?\//g, "../"); relativeParts.path = parents + relativeParts.path.substring(common.length) || "./"; return relative.build(); }; p.equals = function(uri) { var one = this.clone(); var two = new URI(uri); var one_map = {}; var two_map = {}; var checked = {}; var one_query, two_query, key; one.normalize(); two.normalize(); if (one.toString() === two.toString()) { return true; } one_query = one.query(); two_query = two.query(); one.query(""); two.query(""); if (one.toString() !== two.toString()) { return false; } if (one_query.length !== two_query.length) { return false; } one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace); two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace); for (key in one_map) { if (hasOwn.call(one_map, key)) { if (!isArray(one_map[key])) { if (one_map[key] !== two_map[key]) { return false; } } else if (!arraysEqual(one_map[key], two_map[key])) { return false; } checked[key] = true; } } for (key in two_map) { if (hasOwn.call(two_map, key)) { if (!checked[key]) { return false; } } } return true; }; p.preventInvalidHostname = function(v3) { this._parts.preventInvalidHostname = !!v3; return this; }; p.duplicateQueryParameters = function(v3) { this._parts.duplicateQueryParameters = !!v3; return this; }; p.escapeQuerySpace = function(v3) { this._parts.escapeQuerySpace = !!v3; return this; }; return URI; }); } }); // node_modules/bitmap-sdf/index.js var require_bitmap_sdf = __commonJS({ "node_modules/bitmap-sdf/index.js"(exports, module) { "use strict"; var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); module.exports = calcSDF; var INF = 1e20; function calcSDF(src, options) { if (!options) options = {}; var cutoff = options.cutoff == null ? 0.25 : options.cutoff; var radius = options.radius == null ? 8 : options.radius; var channel = options.channel || 0; var w, h, size, data, intData, stride, ctx, canvas, imgData, i, l2; if (ArrayBuffer.isView(src) || Array.isArray(src)) { if (!options.width || !options.height) throw Error("For raw data width and height should be provided by options"); w = options.width, h = options.height; data = src; if (!options.stride) stride = Math.floor(src.length / w / h); else stride = options.stride; } else { if (window.HTMLCanvasElement && src instanceof window.HTMLCanvasElement) { canvas = src; ctx = canvas.getContext("2d"); w = canvas.width, h = canvas.height; imgData = ctx.getImageData(0, 0, w, h); data = imgData.data; stride = 4; } else if (window.CanvasRenderingContext2D && src instanceof window.CanvasRenderingContext2D) { canvas = src.canvas; ctx = src; w = canvas.width, h = canvas.height; imgData = ctx.getImageData(0, 0, w, h); data = imgData.data; stride = 4; } else if (window.ImageData && src instanceof window.ImageData) { imgData = src; w = src.width, h = src.height; data = imgData.data; stride = 4; } } size = Math.max(w, h); if (window.Uint8ClampedArray && data instanceof window.Uint8ClampedArray || window.Uint8Array && data instanceof window.Uint8Array) { intData = data; data = Array(w * h); for (i = 0, l2 = Math.floor(intData.length / stride); i < l2; i++) { data[i] = intData[i * stride + channel] / 255; } } else { if (stride !== 1) throw Error("Raw data can have only 1 value per pixel"); } var gridOuter = Array(w * h); var gridInner = Array(w * h); var f2 = Array(size); var d = Array(size); var z2 = Array(size + 1); var v3 = Array(size); for (i = 0, l2 = w * h; i < l2; i++) { var a3 = data[i]; gridOuter[i] = a3 === 1 ? 0 : a3 === 0 ? INF : Math.pow(Math.max(0, 0.5 - a3), 2); gridInner[i] = a3 === 1 ? INF : a3 === 0 ? 0 : Math.pow(Math.max(0, a3 - 0.5), 2); } edt(gridOuter, w, h, f2, d, v3, z2); edt(gridInner, w, h, f2, d, v3, z2); var dist = window.Float32Array ? new Float32Array(w * h) : new Array(w * h); for (i = 0, l2 = w * h; i < l2; i++) { dist[i] = Math.min(Math.max(1 - ((gridOuter[i] - gridInner[i]) / radius + cutoff), 0), 1); } return dist; } function edt(data, width, height, f2, d, v3, z2) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { f2[y] = data[y * width + x]; } edt1d(f2, d, v3, z2, height); for (y = 0; y < height; y++) { data[y * width + x] = d[y]; } } for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { f2[x] = data[y * width + x]; } edt1d(f2, d, v3, z2, width); for (x = 0; x < width; x++) { data[y * width + x] = Math.sqrt(d[x]); } } } function edt1d(f2, d, v3, z2, n2) { v3[0] = 0; z2[0] = -INF; z2[1] = +INF; for (var q = 1, k = 0; q < n2; q++) { var s2 = (f2[q] + q * q - (f2[v3[k]] + v3[k] * v3[k])) / (2 * q - 2 * v3[k]); while (s2 <= z2[k]) { k--; s2 = (f2[q] + q * q - (f2[v3[k]] + v3[k] * v3[k])) / (2 * q - 2 * v3[k]); } k++; v3[k] = q; z2[k] = s2; z2[k + 1] = +INF; } for (q = 0, k = 0; q < n2; q++) { while (z2[k + 1] < q) k++; d[q] = (q - v3[k]) * (q - v3[k]) + f2[v3[k]]; } } } }); // node_modules/grapheme-splitter/index.js var require_grapheme_splitter = __commonJS({ "node_modules/grapheme-splitter/index.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); function GraphemeSplitter2() { var CR = 0, LF = 1, Control = 2, Extend = 3, Regional_Indicator = 4, SpacingMark = 5, L = 6, V = 7, T8 = 8, LV = 9, LVT = 10, Other = 11, Prepend = 12, E_Base = 13, E_Modifier = 14, ZWJ = 15, Glue_After_Zwj = 16, E_Base_GAZ = 17; var NotBreak = 0, BreakStart = 1, Break = 2, BreakLastRegional = 3, BreakPenultimateRegional = 4; function isSurrogate(str, pos) { return 55296 <= str.charCodeAt(pos) && str.charCodeAt(pos) <= 56319 && 56320 <= str.charCodeAt(pos + 1) && str.charCodeAt(pos + 1) <= 57343; } function codePointAt(str, idx) { if (idx === void 0) { idx = 0; } var code = str.charCodeAt(idx); if (55296 <= code && code <= 56319 && idx < str.length - 1) { var hi = code; var low = str.charCodeAt(idx + 1); if (56320 <= low && low <= 57343) { return (hi - 55296) * 1024 + (low - 56320) + 65536; } return hi; } if (56320 <= code && code <= 57343 && idx >= 1) { var hi = str.charCodeAt(idx - 1); var low = code; if (55296 <= hi && hi <= 56319) { return (hi - 55296) * 1024 + (low - 56320) + 65536; } return low; } return code; } function shouldBreak(start, mid, end) { var all = [start].concat(mid).concat([end]); var previous = all[all.length - 2]; var next = end; var eModifierIndex = all.lastIndexOf(E_Modifier); if (eModifierIndex > 1 && all.slice(1, eModifierIndex).every(function(c14) { return c14 == Extend; }) && [Extend, E_Base, E_Base_GAZ].indexOf(start) == -1) { return Break; } var rIIndex = all.lastIndexOf(Regional_Indicator); if (rIIndex > 0 && all.slice(1, rIIndex).every(function(c14) { return c14 == Regional_Indicator; }) && [Prepend, Regional_Indicator].indexOf(previous) == -1) { if (all.filter(function(c14) { return c14 == Regional_Indicator; }).length % 2 == 1) { return BreakLastRegional; } else { return BreakPenultimateRegional; } } if (previous == CR && next == LF) { return NotBreak; } else if (previous == Control || previous == CR || previous == LF) { if (next == E_Modifier && mid.every(function(c14) { return c14 == Extend; })) { return Break; } else { return BreakStart; } } else if (next == Control || next == CR || next == LF) { return BreakStart; } else if (previous == L && (next == L || next == V || next == LV || next == LVT)) { return NotBreak; } else if ((previous == LV || previous == V) && (next == V || next == T8)) { return NotBreak; } else if ((previous == LVT || previous == T8) && next == T8) { return NotBreak; } else if (next == Extend || next == ZWJ) { return NotBreak; } else if (next == SpacingMark) { return NotBreak; } else if (previous == Prepend) { return NotBreak; } var previousNonExtendIndex = all.indexOf(Extend) != -1 ? all.lastIndexOf(Extend) - 1 : all.length - 2; if ([E_Base, E_Base_GAZ].indexOf(all[previousNonExtendIndex]) != -1 && all.slice(previousNonExtendIndex + 1, -1).every(function(c14) { return c14 == Extend; }) && next == E_Modifier) { return NotBreak; } if (previous == ZWJ && [Glue_After_Zwj, E_Base_GAZ].indexOf(next) != -1) { return NotBreak; } if (mid.indexOf(Regional_Indicator) != -1) { return Break; } if (previous == Regional_Indicator && next == Regional_Indicator) { return NotBreak; } return BreakStart; } this.nextBreak = function(string, index) { if (index === void 0) { index = 0; } if (index < 0) { return 0; } if (index >= string.length - 1) { return string.length; } var prev = getGraphemeBreakProperty(codePointAt(string, index)); var mid = []; for (var i = index + 1; i < string.length; i++) { if (isSurrogate(string, i - 1)) { continue; } var next = getGraphemeBreakProperty(codePointAt(string, i)); if (shouldBreak(prev, mid, next)) { return i; } mid.push(next); } return string.length; }; this.splitGraphemes = function(str) { var res = []; var index = 0; var brk; while ((brk = this.nextBreak(str, index)) < str.length) { res.push(str.slice(index, brk)); index = brk; } if (index < str.length) { res.push(str.slice(index)); } return res; }; this.iterateGraphemes = function(str) { var index = 0; var res = { next: (function() { var value; var brk; if ((brk = this.nextBreak(str, index)) < str.length) { value = str.slice(index, brk); index = brk; return { value, done: false }; } if (index < str.length) { value = str.slice(index); index = str.length; return { value, done: false }; } return { value: void 0, done: true }; }).bind(this) }; if (typeof Symbol !== "undefined" && Symbol.iterator) { res[Symbol.iterator] = function() { return res; }; } return res; }; this.countGraphemes = function(str) { var count = 0; var index = 0; var brk; while ((brk = this.nextBreak(str, index)) < str.length) { index = brk; count++; } if (index < str.length) { count++; } return count; }; function getGraphemeBreakProperty(code) { if (1536 <= code && code <= 1541 || // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE 1757 == code || // Cf ARABIC END OF AYAH 1807 == code || // Cf SYRIAC ABBREVIATION MARK 2274 == code || // Cf ARABIC DISPUTED END OF AYAH 3406 == code || // Lo MALAYALAM LETTER DOT REPH 69821 == code || // Cf KAITHI NUMBER SIGN 70082 <= code && code <= 70083 || // Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA 72250 == code || // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA 72326 <= code && code <= 72329 || // Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA 73030 == code) { return Prepend; } if (13 == code) { return CR; } if (10 == code) { return LF; } if (0 <= code && code <= 9 || // Cc [10] .. 11 <= code && code <= 12 || // Cc [2] .. 14 <= code && code <= 31 || // Cc [18] .. 127 <= code && code <= 159 || // Cc [33] .. 173 == code || // Cf SOFT HYPHEN 1564 == code || // Cf ARABIC LETTER MARK 6158 == code || // Cf MONGOLIAN VOWEL SEPARATOR 8203 == code || // Cf ZERO WIDTH SPACE 8206 <= code && code <= 8207 || // Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK 8232 == code || // Zl LINE SEPARATOR 8233 == code || // Zp PARAGRAPH SEPARATOR 8234 <= code && code <= 8238 || // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE 8288 <= code && code <= 8292 || // Cf [5] WORD JOINER..INVISIBLE PLUS 8293 == code || // Cn 8294 <= code && code <= 8303 || // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES 55296 <= code && code <= 57343 || // Cs [2048] .. 65279 == code || // Cf ZERO WIDTH NO-BREAK SPACE 65520 <= code && code <= 65528 || // Cn [9] .. 65529 <= code && code <= 65531 || // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR 113824 <= code && code <= 113827 || // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 119155 <= code && code <= 119162 || // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE 917504 == code || // Cn 917505 == code || // Cf LANGUAGE TAG 917506 <= code && code <= 917535 || // Cn [30] .. 917632 <= code && code <= 917759 || // Cn [128] .. 918e3 <= code && code <= 921599) { return Control; } if (768 <= code && code <= 879 || // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X 1155 <= code && code <= 1159 || // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE 1160 <= code && code <= 1161 || // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN 1425 <= code && code <= 1469 || // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG 1471 == code || // Mn HEBREW POINT RAFE 1473 <= code && code <= 1474 || // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT 1476 <= code && code <= 1477 || // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT 1479 == code || // Mn HEBREW POINT QAMATS QATAN 1552 <= code && code <= 1562 || // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA 1611 <= code && code <= 1631 || // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW 1648 == code || // Mn ARABIC LETTER SUPERSCRIPT ALEF 1750 <= code && code <= 1756 || // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN 1759 <= code && code <= 1764 || // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA 1767 <= code && code <= 1768 || // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON 1770 <= code && code <= 1773 || // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM 1809 == code || // Mn SYRIAC LETTER SUPERSCRIPT ALAPH 1840 <= code && code <= 1866 || // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH 1958 <= code && code <= 1968 || // Mn [11] THAANA ABAFILI..THAANA SUKUN 2027 <= code && code <= 2035 || // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE 2070 <= code && code <= 2073 || // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH 2075 <= code && code <= 2083 || // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A 2085 <= code && code <= 2087 || // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 2089 <= code && code <= 2093 || // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 2137 <= code && code <= 2139 || // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 2260 <= code && code <= 2273 || // Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 2275 <= code && code <= 2306 || // Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 2362 == code || // Mn DEVANAGARI VOWEL SIGN OE 2364 == code || // Mn DEVANAGARI SIGN NUKTA 2369 <= code && code <= 2376 || // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI 2381 == code || // Mn DEVANAGARI SIGN VIRAMA 2385 <= code && code <= 2391 || // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE 2402 <= code && code <= 2403 || // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL 2433 == code || // Mn BENGALI SIGN CANDRABINDU 2492 == code || // Mn BENGALI SIGN NUKTA 2494 == code || // Mc BENGALI VOWEL SIGN AA 2497 <= code && code <= 2500 || // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR 2509 == code || // Mn BENGALI SIGN VIRAMA 2519 == code || // Mc BENGALI AU LENGTH MARK 2530 <= code && code <= 2531 || // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL 2561 <= code && code <= 2562 || // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI 2620 == code || // Mn GURMUKHI SIGN NUKTA 2625 <= code && code <= 2626 || // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU 2631 <= code && code <= 2632 || // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI 2635 <= code && code <= 2637 || // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA 2641 == code || // Mn GURMUKHI SIGN UDAAT 2672 <= code && code <= 2673 || // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK 2677 == code || // Mn GURMUKHI SIGN YAKASH 2689 <= code && code <= 2690 || // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA 2748 == code || // Mn GUJARATI SIGN NUKTA 2753 <= code && code <= 2757 || // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E 2759 <= code && code <= 2760 || // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI 2765 == code || // Mn GUJARATI SIGN VIRAMA 2786 <= code && code <= 2787 || // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL 2810 <= code && code <= 2815 || // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 2817 == code || // Mn ORIYA SIGN CANDRABINDU 2876 == code || // Mn ORIYA SIGN NUKTA 2878 == code || // Mc ORIYA VOWEL SIGN AA 2879 == code || // Mn ORIYA VOWEL SIGN I 2881 <= code && code <= 2884 || // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR 2893 == code || // Mn ORIYA SIGN VIRAMA 2902 == code || // Mn ORIYA AI LENGTH MARK 2903 == code || // Mc ORIYA AU LENGTH MARK 2914 <= code && code <= 2915 || // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL 2946 == code || // Mn TAMIL SIGN ANUSVARA 3006 == code || // Mc TAMIL VOWEL SIGN AA 3008 == code || // Mn TAMIL VOWEL SIGN II 3021 == code || // Mn TAMIL SIGN VIRAMA 3031 == code || // Mc TAMIL AU LENGTH MARK 3072 == code || // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE 3134 <= code && code <= 3136 || // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II 3142 <= code && code <= 3144 || // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI 3146 <= code && code <= 3149 || // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA 3157 <= code && code <= 3158 || // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK 3170 <= code && code <= 3171 || // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL 3201 == code || // Mn KANNADA SIGN CANDRABINDU 3260 == code || // Mn KANNADA SIGN NUKTA 3263 == code || // Mn KANNADA VOWEL SIGN I 3266 == code || // Mc KANNADA VOWEL SIGN UU 3270 == code || // Mn KANNADA VOWEL SIGN E 3276 <= code && code <= 3277 || // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 3285 <= code && code <= 3286 || // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 3298 <= code && code <= 3299 || // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 3328 <= code && code <= 3329 || // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 3387 <= code && code <= 3388 || // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 3390 == code || // Mc MALAYALAM VOWEL SIGN AA 3393 <= code && code <= 3396 || // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR 3405 == code || // Mn MALAYALAM SIGN VIRAMA 3415 == code || // Mc MALAYALAM AU LENGTH MARK 3426 <= code && code <= 3427 || // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 3530 == code || // Mn SINHALA SIGN AL-LAKUNA 3535 == code || // Mc SINHALA VOWEL SIGN AELA-PILLA 3538 <= code && code <= 3540 || // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA 3542 == code || // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA 3551 == code || // Mc SINHALA VOWEL SIGN GAYANUKITTA 3633 == code || // Mn THAI CHARACTER MAI HAN-AKAT 3636 <= code && code <= 3642 || // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU 3655 <= code && code <= 3662 || // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN 3761 == code || // Mn LAO VOWEL SIGN MAI KAN 3764 <= code && code <= 3769 || // Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU 3771 <= code && code <= 3772 || // Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO 3784 <= code && code <= 3789 || // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA 3864 <= code && code <= 3865 || // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS 3893 == code || // Mn TIBETAN MARK NGAS BZUNG NYI ZLA 3895 == code || // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS 3897 == code || // Mn TIBETAN MARK TSA -PHRU 3953 <= code && code <= 3966 || // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO 3968 <= code && code <= 3972 || // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA 3974 <= code && code <= 3975 || // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS 3981 <= code && code <= 3991 || // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA 3993 <= code && code <= 4028 || // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA 4038 == code || // Mn TIBETAN SYMBOL PADMA GDAN 4141 <= code && code <= 4144 || // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU 4146 <= code && code <= 4151 || // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW 4153 <= code && code <= 4154 || // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT 4157 <= code && code <= 4158 || // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA 4184 <= code && code <= 4185 || // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL 4190 <= code && code <= 4192 || // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA 4209 <= code && code <= 4212 || // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE 4226 == code || // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA 4229 <= code && code <= 4230 || // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y 4237 == code || // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE 4253 == code || // Mn MYANMAR VOWEL SIGN AITON AI 4957 <= code && code <= 4959 || // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK 5906 <= code && code <= 5908 || // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA 5938 <= code && code <= 5940 || // Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD 5970 <= code && code <= 5971 || // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U 6002 <= code && code <= 6003 || // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U 6068 <= code && code <= 6069 || // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA 6071 <= code && code <= 6077 || // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA 6086 == code || // Mn KHMER SIGN NIKAHIT 6089 <= code && code <= 6099 || // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 6109 == code || // Mn KHMER SIGN ATTHACAN 6155 <= code && code <= 6157 || // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE 6277 <= code && code <= 6278 || // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 6313 == code || // Mn MONGOLIAN LETTER ALI GALI DAGALGA 6432 <= code && code <= 6434 || // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 6439 <= code && code <= 6440 || // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O 6450 == code || // Mn LIMBU SMALL LETTER ANUSVARA 6457 <= code && code <= 6459 || // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I 6679 <= code && code <= 6680 || // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U 6683 == code || // Mn BUGINESE VOWEL SIGN AE 6742 == code || // Mn TAI THAM CONSONANT SIGN MEDIAL LA 6744 <= code && code <= 6750 || // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA 6752 == code || // Mn TAI THAM SIGN SAKOT 6754 == code || // Mn TAI THAM VOWEL SIGN MAI SAT 6757 <= code && code <= 6764 || // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW 6771 <= code && code <= 6780 || // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN 6783 == code || // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT 6832 <= code && code <= 6845 || // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 6846 == code || // Me COMBINING PARENTHESES OVERLAY 6912 <= code && code <= 6915 || // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG 6964 == code || // Mn BALINESE SIGN REREKAN 6966 <= code && code <= 6970 || // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA 6972 == code || // Mn BALINESE VOWEL SIGN LA LENGA 6978 == code || // Mn BALINESE VOWEL SIGN PEPET 7019 <= code && code <= 7027 || // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG 7040 <= code && code <= 7041 || // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR 7074 <= code && code <= 7077 || // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU 7080 <= code && code <= 7081 || // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG 7083 <= code && code <= 7085 || // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA 7142 == code || // Mn BATAK SIGN TOMPI 7144 <= code && code <= 7145 || // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE 7149 == code || // Mn BATAK VOWEL SIGN KARO O 7151 <= code && code <= 7153 || // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H 7212 <= code && code <= 7219 || // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T 7222 <= code && code <= 7223 || // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA 7376 <= code && code <= 7378 || // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA 7380 <= code && code <= 7392 || // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA 7394 <= code && code <= 7400 || // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL 7405 == code || // Mn VEDIC SIGN TIRYAK 7412 == code || // Mn VEDIC TONE CANDRA ABOVE 7416 <= code && code <= 7417 || // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 7616 <= code && code <= 7673 || // Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW 7675 <= code && code <= 7679 || // Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 8204 == code || // Cf ZERO WIDTH NON-JOINER 8400 <= code && code <= 8412 || // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 8413 <= code && code <= 8416 || // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 8417 == code || // Mn COMBINING LEFT RIGHT ARROW ABOVE 8418 <= code && code <= 8420 || // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE 8421 <= code && code <= 8432 || // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE 11503 <= code && code <= 11505 || // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS 11647 == code || // Mn TIFINAGH CONSONANT JOINER 11744 <= code && code <= 11775 || // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS 12330 <= code && code <= 12333 || // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK 12334 <= code && code <= 12335 || // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK 12441 <= code && code <= 12442 || // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK 42607 == code || // Mn COMBINING CYRILLIC VZMET 42608 <= code && code <= 42610 || // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN 42612 <= code && code <= 42621 || // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK 42654 <= code && code <= 42655 || // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E 42736 <= code && code <= 42737 || // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS 43010 == code || // Mn SYLOTI NAGRI SIGN DVISVARA 43014 == code || // Mn SYLOTI NAGRI SIGN HASANTA 43019 == code || // Mn SYLOTI NAGRI SIGN ANUSVARA 43045 <= code && code <= 43046 || // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E 43204 <= code && code <= 43205 || // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU 43232 <= code && code <= 43249 || // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA 43302 <= code && code <= 43309 || // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU 43335 <= code && code <= 43345 || // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R 43392 <= code && code <= 43394 || // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR 43443 == code || // Mn JAVANESE SIGN CECAK TELU 43446 <= code && code <= 43449 || // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT 43452 == code || // Mn JAVANESE VOWEL SIGN PEPET 43493 == code || // Mn MYANMAR SIGN SHAN SAW 43561 <= code && code <= 43566 || // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE 43569 <= code && code <= 43570 || // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE 43573 <= code && code <= 43574 || // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA 43587 == code || // Mn CHAM CONSONANT SIGN FINAL NG 43596 == code || // Mn CHAM CONSONANT SIGN FINAL M 43644 == code || // Mn MYANMAR SIGN TAI LAING TONE-2 43696 == code || // Mn TAI VIET MAI KANG 43698 <= code && code <= 43700 || // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U 43703 <= code && code <= 43704 || // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA 43710 <= code && code <= 43711 || // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK 43713 == code || // Mn TAI VIET TONE MAI THO 43756 <= code && code <= 43757 || // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI 43766 == code || // Mn MEETEI MAYEK VIRAMA 44005 == code || // Mn MEETEI MAYEK VOWEL SIGN ANAP 44008 == code || // Mn MEETEI MAYEK VOWEL SIGN UNAP 44013 == code || // Mn MEETEI MAYEK APUN IYEK 64286 == code || // Mn HEBREW POINT JUDEO-SPANISH VARIKA 65024 <= code && code <= 65039 || // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 65056 <= code && code <= 65071 || // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF 65438 <= code && code <= 65439 || // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK 66045 == code || // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE 66272 == code || // Mn COPTIC EPACT THOUSANDS MARK 66422 <= code && code <= 66426 || // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII 68097 <= code && code <= 68099 || // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R 68101 <= code && code <= 68102 || // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O 68108 <= code && code <= 68111 || // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA 68152 <= code && code <= 68154 || // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW 68159 == code || // Mn KHAROSHTHI VIRAMA 68325 <= code && code <= 68326 || // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW 69633 == code || // Mn BRAHMI SIGN ANUSVARA 69688 <= code && code <= 69702 || // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA 69759 <= code && code <= 69761 || // Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA 69811 <= code && code <= 69814 || // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI 69817 <= code && code <= 69818 || // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA 69888 <= code && code <= 69890 || // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA 69927 <= code && code <= 69931 || // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU 69933 <= code && code <= 69940 || // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA 70003 == code || // Mn MAHAJANI SIGN NUKTA 70016 <= code && code <= 70017 || // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA 70070 <= code && code <= 70078 || // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O 70090 <= code && code <= 70092 || // Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK 70191 <= code && code <= 70193 || // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI 70196 == code || // Mn KHOJKI SIGN ANUSVARA 70198 <= code && code <= 70199 || // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 70206 == code || // Mn KHOJKI SIGN SUKUN 70367 == code || // Mn KHUDAWADI SIGN ANUSVARA 70371 <= code && code <= 70378 || // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA 70400 <= code && code <= 70401 || // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU 70460 == code || // Mn GRANTHA SIGN NUKTA 70462 == code || // Mc GRANTHA VOWEL SIGN AA 70464 == code || // Mn GRANTHA VOWEL SIGN II 70487 == code || // Mc GRANTHA AU LENGTH MARK 70502 <= code && code <= 70508 || // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 70512 <= code && code <= 70516 || // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA 70712 <= code && code <= 70719 || // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI 70722 <= code && code <= 70724 || // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 70726 == code || // Mn NEWA SIGN NUKTA 70832 == code || // Mc TIRHUTA VOWEL SIGN AA 70835 <= code && code <= 70840 || // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 70842 == code || // Mn TIRHUTA VOWEL SIGN SHORT E 70845 == code || // Mc TIRHUTA VOWEL SIGN SHORT O 70847 <= code && code <= 70848 || // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA 70850 <= code && code <= 70851 || // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA 71087 == code || // Mc SIDDHAM VOWEL SIGN AA 71090 <= code && code <= 71093 || // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR 71100 <= code && code <= 71101 || // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA 71103 <= code && code <= 71104 || // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA 71132 <= code && code <= 71133 || // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU 71219 <= code && code <= 71226 || // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI 71229 == code || // Mn MODI SIGN ANUSVARA 71231 <= code && code <= 71232 || // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA 71339 == code || // Mn TAKRI SIGN ANUSVARA 71341 == code || // Mn TAKRI VOWEL SIGN AA 71344 <= code && code <= 71349 || // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU 71351 == code || // Mn TAKRI SIGN NUKTA 71453 <= code && code <= 71455 || // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA 71458 <= code && code <= 71461 || // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 71463 <= code && code <= 71467 || // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER 72193 <= code && code <= 72198 || // Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O 72201 <= code && code <= 72202 || // Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK 72243 <= code && code <= 72248 || // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA 72251 <= code && code <= 72254 || // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA 72263 == code || // Mn ZANABAZAR SQUARE SUBJOINER 72273 <= code && code <= 72278 || // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE 72281 <= code && code <= 72283 || // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK 72330 <= code && code <= 72342 || // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA 72344 <= code && code <= 72345 || // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER 72752 <= code && code <= 72758 || // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L 72760 <= code && code <= 72765 || // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA 72767 == code || // Mn BHAIKSUKI SIGN VIRAMA 72850 <= code && code <= 72871 || // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA 72874 <= code && code <= 72880 || // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA 72882 <= code && code <= 72883 || // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E 72885 <= code && code <= 72886 || // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU 73009 <= code && code <= 73014 || // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R 73018 == code || // Mn MASARAM GONDI VOWEL SIGN E 73020 <= code && code <= 73021 || // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O 73023 <= code && code <= 73029 || // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA 73031 == code || // Mn MASARAM GONDI RA-KARA 92912 <= code && code <= 92916 || // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 92976 <= code && code <= 92982 || // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 94095 <= code && code <= 94098 || // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 113821 <= code && code <= 113822 || // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK 119141 == code || // Mc MUSICAL SYMBOL COMBINING STEM 119143 <= code && code <= 119145 || // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 119150 <= code && code <= 119154 || // Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 119163 <= code && code <= 119170 || // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE 119173 <= code && code <= 119179 || // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 119210 <= code && code <= 119213 || // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO 119362 <= code && code <= 119364 || // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME 121344 <= code && code <= 121398 || // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN 121403 <= code && code <= 121452 || // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT 121461 == code || // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS 121476 == code || // Mn SIGNWRITING LOCATION HEAD NECK 121499 <= code && code <= 121503 || // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 121505 <= code && code <= 121519 || // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 122880 <= code && code <= 122886 || // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE 122888 <= code && code <= 122904 || // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU 122907 <= code && code <= 122913 || // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI 122915 <= code && code <= 122916 || // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS 122918 <= code && code <= 122922 || // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 125136 <= code && code <= 125142 || // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS 125252 <= code && code <= 125258 || // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA 917536 <= code && code <= 917631 || // Cf [96] TAG SPACE..CANCEL TAG 917760 <= code && code <= 917999) { return Extend; } if (127462 <= code && code <= 127487) { return Regional_Indicator; } if (2307 == code || // Mc DEVANAGARI SIGN VISARGA 2363 == code || // Mc DEVANAGARI VOWEL SIGN OOE 2366 <= code && code <= 2368 || // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II 2377 <= code && code <= 2380 || // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU 2382 <= code && code <= 2383 || // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW 2434 <= code && code <= 2435 || // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA 2495 <= code && code <= 2496 || // Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II 2503 <= code && code <= 2504 || // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI 2507 <= code && code <= 2508 || // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU 2563 == code || // Mc GURMUKHI SIGN VISARGA 2622 <= code && code <= 2624 || // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II 2691 == code || // Mc GUJARATI SIGN VISARGA 2750 <= code && code <= 2752 || // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II 2761 == code || // Mc GUJARATI VOWEL SIGN CANDRA O 2763 <= code && code <= 2764 || // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU 2818 <= code && code <= 2819 || // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 2880 == code || // Mc ORIYA VOWEL SIGN II 2887 <= code && code <= 2888 || // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI 2891 <= code && code <= 2892 || // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU 3007 == code || // Mc TAMIL VOWEL SIGN I 3009 <= code && code <= 3010 || // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU 3014 <= code && code <= 3016 || // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI 3018 <= code && code <= 3020 || // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU 3073 <= code && code <= 3075 || // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA 3137 <= code && code <= 3140 || // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR 3202 <= code && code <= 3203 || // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 3262 == code || // Mc KANNADA VOWEL SIGN AA 3264 <= code && code <= 3265 || // Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U 3267 <= code && code <= 3268 || // Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR 3271 <= code && code <= 3272 || // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI 3274 <= code && code <= 3275 || // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO 3330 <= code && code <= 3331 || // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 3391 <= code && code <= 3392 || // Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II 3398 <= code && code <= 3400 || // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI 3402 <= code && code <= 3404 || // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 3458 <= code && code <= 3459 || // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA 3536 <= code && code <= 3537 || // Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA 3544 <= code && code <= 3550 || // Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA 3570 <= code && code <= 3571 || // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA 3635 == code || // Lo THAI CHARACTER SARA AM 3763 == code || // Lo LAO VOWEL SIGN AM 3902 <= code && code <= 3903 || // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES 3967 == code || // Mc TIBETAN SIGN RNAM BCAD 4145 == code || // Mc MYANMAR VOWEL SIGN E 4155 <= code && code <= 4156 || // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA 4182 <= code && code <= 4183 || // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR 4228 == code || // Mc MYANMAR VOWEL SIGN SHAN E 6070 == code || // Mc KHMER VOWEL SIGN AA 6078 <= code && code <= 6085 || // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU 6087 <= code && code <= 6088 || // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU 6435 <= code && code <= 6438 || // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU 6441 <= code && code <= 6443 || // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA 6448 <= code && code <= 6449 || // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA 6451 <= code && code <= 6456 || // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA 6681 <= code && code <= 6682 || // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O 6741 == code || // Mc TAI THAM CONSONANT SIGN MEDIAL RA 6743 == code || // Mc TAI THAM CONSONANT SIGN LA TANG LAI 6765 <= code && code <= 6770 || // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI 6916 == code || // Mc BALINESE SIGN BISAH 6965 == code || // Mc BALINESE VOWEL SIGN TEDUNG 6971 == code || // Mc BALINESE VOWEL SIGN RA REPA TEDUNG 6973 <= code && code <= 6977 || // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG 6979 <= code && code <= 6980 || // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG 7042 == code || // Mc SUNDANESE SIGN PANGWISAD 7073 == code || // Mc SUNDANESE CONSONANT SIGN PAMINGKAL 7078 <= code && code <= 7079 || // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 7082 == code || // Mc SUNDANESE SIGN PAMAAEH 7143 == code || // Mc BATAK VOWEL SIGN E 7146 <= code && code <= 7148 || // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O 7150 == code || // Mc BATAK VOWEL SIGN U 7154 <= code && code <= 7155 || // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN 7204 <= code && code <= 7211 || // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU 7220 <= code && code <= 7221 || // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 7393 == code || // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA 7410 <= code && code <= 7411 || // Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 7415 == code || // Mc VEDIC SIGN ATIKRAMA 43043 <= code && code <= 43044 || // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I 43047 == code || // Mc SYLOTI NAGRI VOWEL SIGN OO 43136 <= code && code <= 43137 || // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA 43188 <= code && code <= 43203 || // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU 43346 <= code && code <= 43347 || // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA 43395 == code || // Mc JAVANESE SIGN WIGNYAN 43444 <= code && code <= 43445 || // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG 43450 <= code && code <= 43451 || // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE 43453 <= code && code <= 43456 || // Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON 43567 <= code && code <= 43568 || // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI 43571 <= code && code <= 43572 || // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA 43597 == code || // Mc CHAM CONSONANT SIGN FINAL H 43755 == code || // Mc MEETEI MAYEK VOWEL SIGN II 43758 <= code && code <= 43759 || // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU 43765 == code || // Mc MEETEI MAYEK VOWEL SIGN VISARGA 44003 <= code && code <= 44004 || // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP 44006 <= code && code <= 44007 || // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP 44009 <= code && code <= 44010 || // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG 44012 == code || // Mc MEETEI MAYEK LUM IYEK 69632 == code || // Mc BRAHMI SIGN CANDRABINDU 69634 == code || // Mc BRAHMI SIGN VISARGA 69762 == code || // Mc KAITHI SIGN VISARGA 69808 <= code && code <= 69810 || // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II 69815 <= code && code <= 69816 || // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU 69932 == code || // Mc CHAKMA VOWEL SIGN E 70018 == code || // Mc SHARADA SIGN VISARGA 70067 <= code && code <= 70069 || // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II 70079 <= code && code <= 70080 || // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA 70188 <= code && code <= 70190 || // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II 70194 <= code && code <= 70195 || // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU 70197 == code || // Mc KHOJKI SIGN VIRAMA 70368 <= code && code <= 70370 || // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 70402 <= code && code <= 70403 || // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA 70463 == code || // Mc GRANTHA VOWEL SIGN I 70465 <= code && code <= 70468 || // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR 70471 <= code && code <= 70472 || // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI 70475 <= code && code <= 70477 || // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA 70498 <= code && code <= 70499 || // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 70709 <= code && code <= 70711 || // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II 70720 <= code && code <= 70721 || // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU 70725 == code || // Mc NEWA SIGN VISARGA 70833 <= code && code <= 70834 || // Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II 70841 == code || // Mc TIRHUTA VOWEL SIGN E 70843 <= code && code <= 70844 || // Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O 70846 == code || // Mc TIRHUTA VOWEL SIGN AU 70849 == code || // Mc TIRHUTA SIGN VISARGA 71088 <= code && code <= 71089 || // Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II 71096 <= code && code <= 71099 || // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU 71102 == code || // Mc SIDDHAM SIGN VISARGA 71216 <= code && code <= 71218 || // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II 71227 <= code && code <= 71228 || // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU 71230 == code || // Mc MODI SIGN VISARGA 71340 == code || // Mc TAKRI SIGN VISARGA 71342 <= code && code <= 71343 || // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II 71350 == code || // Mc TAKRI SIGN VIRAMA 71456 <= code && code <= 71457 || // Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 71462 == code || // Mc AHOM VOWEL SIGN E 72199 <= code && code <= 72200 || // Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU 72249 == code || // Mc ZANABAZAR SQUARE SIGN VISARGA 72279 <= code && code <= 72280 || // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU 72343 == code || // Mc SOYOMBO SIGN VISARGA 72751 == code || // Mc BHAIKSUKI VOWEL SIGN AA 72766 == code || // Mc BHAIKSUKI SIGN VISARGA 72873 == code || // Mc MARCHEN SUBJOINED LETTER YA 72881 == code || // Mc MARCHEN VOWEL SIGN I 72884 == code || // Mc MARCHEN VOWEL SIGN O 94033 <= code && code <= 94078 || // Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 119142 == code || // Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 119149 == code) { return SpacingMark; } if (4352 <= code && code <= 4447 || // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER 43360 <= code && code <= 43388) { return L; } if (4448 <= code && code <= 4519 || // Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE 55216 <= code && code <= 55238) { return V; } if (4520 <= code && code <= 4607 || // Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN 55243 <= code && code <= 55291) { return T8; } if (44032 == code || // Lo HANGUL SYLLABLE GA 44060 == code || // Lo HANGUL SYLLABLE GAE 44088 == code || // Lo HANGUL SYLLABLE GYA 44116 == code || // Lo HANGUL SYLLABLE GYAE 44144 == code || // Lo HANGUL SYLLABLE GEO 44172 == code || // Lo HANGUL SYLLABLE GE 44200 == code || // Lo HANGUL SYLLABLE GYEO 44228 == code || // Lo HANGUL SYLLABLE GYE 44256 == code || // Lo HANGUL SYLLABLE GO 44284 == code || // Lo HANGUL SYLLABLE GWA 44312 == code || // Lo HANGUL SYLLABLE GWAE 44340 == code || // Lo HANGUL SYLLABLE GOE 44368 == code || // Lo HANGUL SYLLABLE GYO 44396 == code || // Lo HANGUL SYLLABLE GU 44424 == code || // Lo HANGUL SYLLABLE GWEO 44452 == code || // Lo HANGUL SYLLABLE GWE 44480 == code || // Lo HANGUL SYLLABLE GWI 44508 == code || // Lo HANGUL SYLLABLE GYU 44536 == code || // Lo HANGUL SYLLABLE GEU 44564 == code || // Lo HANGUL SYLLABLE GYI 44592 == code || // Lo HANGUL SYLLABLE GI 44620 == code || // Lo HANGUL SYLLABLE GGA 44648 == code || // Lo HANGUL SYLLABLE GGAE 44676 == code || // Lo HANGUL SYLLABLE GGYA 44704 == code || // Lo HANGUL SYLLABLE GGYAE 44732 == code || // Lo HANGUL SYLLABLE GGEO 44760 == code || // Lo HANGUL SYLLABLE GGE 44788 == code || // Lo HANGUL SYLLABLE GGYEO 44816 == code || // Lo HANGUL SYLLABLE GGYE 44844 == code || // Lo HANGUL SYLLABLE GGO 44872 == code || // Lo HANGUL SYLLABLE GGWA 44900 == code || // Lo HANGUL SYLLABLE GGWAE 44928 == code || // Lo HANGUL SYLLABLE GGOE 44956 == code || // Lo HANGUL SYLLABLE GGYO 44984 == code || // Lo HANGUL SYLLABLE GGU 45012 == code || // Lo HANGUL SYLLABLE GGWEO 45040 == code || // Lo HANGUL SYLLABLE GGWE 45068 == code || // Lo HANGUL SYLLABLE GGWI 45096 == code || // Lo HANGUL SYLLABLE GGYU 45124 == code || // Lo HANGUL SYLLABLE GGEU 45152 == code || // Lo HANGUL SYLLABLE GGYI 45180 == code || // Lo HANGUL SYLLABLE GGI 45208 == code || // Lo HANGUL SYLLABLE NA 45236 == code || // Lo HANGUL SYLLABLE NAE 45264 == code || // Lo HANGUL SYLLABLE NYA 45292 == code || // Lo HANGUL SYLLABLE NYAE 45320 == code || // Lo HANGUL SYLLABLE NEO 45348 == code || // Lo HANGUL SYLLABLE NE 45376 == code || // Lo HANGUL SYLLABLE NYEO 45404 == code || // Lo HANGUL SYLLABLE NYE 45432 == code || // Lo HANGUL SYLLABLE NO 45460 == code || // Lo HANGUL SYLLABLE NWA 45488 == code || // Lo HANGUL SYLLABLE NWAE 45516 == code || // Lo HANGUL SYLLABLE NOE 45544 == code || // Lo HANGUL SYLLABLE NYO 45572 == code || // Lo HANGUL SYLLABLE NU 45600 == code || // Lo HANGUL SYLLABLE NWEO 45628 == code || // Lo HANGUL SYLLABLE NWE 45656 == code || // Lo HANGUL SYLLABLE NWI 45684 == code || // Lo HANGUL SYLLABLE NYU 45712 == code || // Lo HANGUL SYLLABLE NEU 45740 == code || // Lo HANGUL SYLLABLE NYI 45768 == code || // Lo HANGUL SYLLABLE NI 45796 == code || // Lo HANGUL SYLLABLE DA 45824 == code || // Lo HANGUL SYLLABLE DAE 45852 == code || // Lo HANGUL SYLLABLE DYA 45880 == code || // Lo HANGUL SYLLABLE DYAE 45908 == code || // Lo HANGUL SYLLABLE DEO 45936 == code || // Lo HANGUL SYLLABLE DE 45964 == code || // Lo HANGUL SYLLABLE DYEO 45992 == code || // Lo HANGUL SYLLABLE DYE 46020 == code || // Lo HANGUL SYLLABLE DO 46048 == code || // Lo HANGUL SYLLABLE DWA 46076 == code || // Lo HANGUL SYLLABLE DWAE 46104 == code || // Lo HANGUL SYLLABLE DOE 46132 == code || // Lo HANGUL SYLLABLE DYO 46160 == code || // Lo HANGUL SYLLABLE DU 46188 == code || // Lo HANGUL SYLLABLE DWEO 46216 == code || // Lo HANGUL SYLLABLE DWE 46244 == code || // Lo HANGUL SYLLABLE DWI 46272 == code || // Lo HANGUL SYLLABLE DYU 46300 == code || // Lo HANGUL SYLLABLE DEU 46328 == code || // Lo HANGUL SYLLABLE DYI 46356 == code || // Lo HANGUL SYLLABLE DI 46384 == code || // Lo HANGUL SYLLABLE DDA 46412 == code || // Lo HANGUL SYLLABLE DDAE 46440 == code || // Lo HANGUL SYLLABLE DDYA 46468 == code || // Lo HANGUL SYLLABLE DDYAE 46496 == code || // Lo HANGUL SYLLABLE DDEO 46524 == code || // Lo HANGUL SYLLABLE DDE 46552 == code || // Lo HANGUL SYLLABLE DDYEO 46580 == code || // Lo HANGUL SYLLABLE DDYE 46608 == code || // Lo HANGUL SYLLABLE DDO 46636 == code || // Lo HANGUL SYLLABLE DDWA 46664 == code || // Lo HANGUL SYLLABLE DDWAE 46692 == code || // Lo HANGUL SYLLABLE DDOE 46720 == code || // Lo HANGUL SYLLABLE DDYO 46748 == code || // Lo HANGUL SYLLABLE DDU 46776 == code || // Lo HANGUL SYLLABLE DDWEO 46804 == code || // Lo HANGUL SYLLABLE DDWE 46832 == code || // Lo HANGUL SYLLABLE DDWI 46860 == code || // Lo HANGUL SYLLABLE DDYU 46888 == code || // Lo HANGUL SYLLABLE DDEU 46916 == code || // Lo HANGUL SYLLABLE DDYI 46944 == code || // Lo HANGUL SYLLABLE DDI 46972 == code || // Lo HANGUL SYLLABLE RA 47e3 == code || // Lo HANGUL SYLLABLE RAE 47028 == code || // Lo HANGUL SYLLABLE RYA 47056 == code || // Lo HANGUL SYLLABLE RYAE 47084 == code || // Lo HANGUL SYLLABLE REO 47112 == code || // Lo HANGUL SYLLABLE RE 47140 == code || // Lo HANGUL SYLLABLE RYEO 47168 == code || // Lo HANGUL SYLLABLE RYE 47196 == code || // Lo HANGUL SYLLABLE RO 47224 == code || // Lo HANGUL SYLLABLE RWA 47252 == code || // Lo HANGUL SYLLABLE RWAE 47280 == code || // Lo HANGUL SYLLABLE ROE 47308 == code || // Lo HANGUL SYLLABLE RYO 47336 == code || // Lo HANGUL SYLLABLE RU 47364 == code || // Lo HANGUL SYLLABLE RWEO 47392 == code || // Lo HANGUL SYLLABLE RWE 47420 == code || // Lo HANGUL SYLLABLE RWI 47448 == code || // Lo HANGUL SYLLABLE RYU 47476 == code || // Lo HANGUL SYLLABLE REU 47504 == code || // Lo HANGUL SYLLABLE RYI 47532 == code || // Lo HANGUL SYLLABLE RI 47560 == code || // Lo HANGUL SYLLABLE MA 47588 == code || // Lo HANGUL SYLLABLE MAE 47616 == code || // Lo HANGUL SYLLABLE MYA 47644 == code || // Lo HANGUL SYLLABLE MYAE 47672 == code || // Lo HANGUL SYLLABLE MEO 47700 == code || // Lo HANGUL SYLLABLE ME 47728 == code || // Lo HANGUL SYLLABLE MYEO 47756 == code || // Lo HANGUL SYLLABLE MYE 47784 == code || // Lo HANGUL SYLLABLE MO 47812 == code || // Lo HANGUL SYLLABLE MWA 47840 == code || // Lo HANGUL SYLLABLE MWAE 47868 == code || // Lo HANGUL SYLLABLE MOE 47896 == code || // Lo HANGUL SYLLABLE MYO 47924 == code || // Lo HANGUL SYLLABLE MU 47952 == code || // Lo HANGUL SYLLABLE MWEO 47980 == code || // Lo HANGUL SYLLABLE MWE 48008 == code || // Lo HANGUL SYLLABLE MWI 48036 == code || // Lo HANGUL SYLLABLE MYU 48064 == code || // Lo HANGUL SYLLABLE MEU 48092 == code || // Lo HANGUL SYLLABLE MYI 48120 == code || // Lo HANGUL SYLLABLE MI 48148 == code || // Lo HANGUL SYLLABLE BA 48176 == code || // Lo HANGUL SYLLABLE BAE 48204 == code || // Lo HANGUL SYLLABLE BYA 48232 == code || // Lo HANGUL SYLLABLE BYAE 48260 == code || // Lo HANGUL SYLLABLE BEO 48288 == code || // Lo HANGUL SYLLABLE BE 48316 == code || // Lo HANGUL SYLLABLE BYEO 48344 == code || // Lo HANGUL SYLLABLE BYE 48372 == code || // Lo HANGUL SYLLABLE BO 48400 == code || // Lo HANGUL SYLLABLE BWA 48428 == code || // Lo HANGUL SYLLABLE BWAE 48456 == code || // Lo HANGUL SYLLABLE BOE 48484 == code || // Lo HANGUL SYLLABLE BYO 48512 == code || // Lo HANGUL SYLLABLE BU 48540 == code || // Lo HANGUL SYLLABLE BWEO 48568 == code || // Lo HANGUL SYLLABLE BWE 48596 == code || // Lo HANGUL SYLLABLE BWI 48624 == code || // Lo HANGUL SYLLABLE BYU 48652 == code || // Lo HANGUL SYLLABLE BEU 48680 == code || // Lo HANGUL SYLLABLE BYI 48708 == code || // Lo HANGUL SYLLABLE BI 48736 == code || // Lo HANGUL SYLLABLE BBA 48764 == code || // Lo HANGUL SYLLABLE BBAE 48792 == code || // Lo HANGUL SYLLABLE BBYA 48820 == code || // Lo HANGUL SYLLABLE BBYAE 48848 == code || // Lo HANGUL SYLLABLE BBEO 48876 == code || // Lo HANGUL SYLLABLE BBE 48904 == code || // Lo HANGUL SYLLABLE BBYEO 48932 == code || // Lo HANGUL SYLLABLE BBYE 48960 == code || // Lo HANGUL SYLLABLE BBO 48988 == code || // Lo HANGUL SYLLABLE BBWA 49016 == code || // Lo HANGUL SYLLABLE BBWAE 49044 == code || // Lo HANGUL SYLLABLE BBOE 49072 == code || // Lo HANGUL SYLLABLE BBYO 49100 == code || // Lo HANGUL SYLLABLE BBU 49128 == code || // Lo HANGUL SYLLABLE BBWEO 49156 == code || // Lo HANGUL SYLLABLE BBWE 49184 == code || // Lo HANGUL SYLLABLE BBWI 49212 == code || // Lo HANGUL SYLLABLE BBYU 49240 == code || // Lo HANGUL SYLLABLE BBEU 49268 == code || // Lo HANGUL SYLLABLE BBYI 49296 == code || // Lo HANGUL SYLLABLE BBI 49324 == code || // Lo HANGUL SYLLABLE SA 49352 == code || // Lo HANGUL SYLLABLE SAE 49380 == code || // Lo HANGUL SYLLABLE SYA 49408 == code || // Lo HANGUL SYLLABLE SYAE 49436 == code || // Lo HANGUL SYLLABLE SEO 49464 == code || // Lo HANGUL SYLLABLE SE 49492 == code || // Lo HANGUL SYLLABLE SYEO 49520 == code || // Lo HANGUL SYLLABLE SYE 49548 == code || // Lo HANGUL SYLLABLE SO 49576 == code || // Lo HANGUL SYLLABLE SWA 49604 == code || // Lo HANGUL SYLLABLE SWAE 49632 == code || // Lo HANGUL SYLLABLE SOE 49660 == code || // Lo HANGUL SYLLABLE SYO 49688 == code || // Lo HANGUL SYLLABLE SU 49716 == code || // Lo HANGUL SYLLABLE SWEO 49744 == code || // Lo HANGUL SYLLABLE SWE 49772 == code || // Lo HANGUL SYLLABLE SWI 49800 == code || // Lo HANGUL SYLLABLE SYU 49828 == code || // Lo HANGUL SYLLABLE SEU 49856 == code || // Lo HANGUL SYLLABLE SYI 49884 == code || // Lo HANGUL SYLLABLE SI 49912 == code || // Lo HANGUL SYLLABLE SSA 49940 == code || // Lo HANGUL SYLLABLE SSAE 49968 == code || // Lo HANGUL SYLLABLE SSYA 49996 == code || // Lo HANGUL SYLLABLE SSYAE 50024 == code || // Lo HANGUL SYLLABLE SSEO 50052 == code || // Lo HANGUL SYLLABLE SSE 50080 == code || // Lo HANGUL SYLLABLE SSYEO 50108 == code || // Lo HANGUL SYLLABLE SSYE 50136 == code || // Lo HANGUL SYLLABLE SSO 50164 == code || // Lo HANGUL SYLLABLE SSWA 50192 == code || // Lo HANGUL SYLLABLE SSWAE 50220 == code || // Lo HANGUL SYLLABLE SSOE 50248 == code || // Lo HANGUL SYLLABLE SSYO 50276 == code || // Lo HANGUL SYLLABLE SSU 50304 == code || // Lo HANGUL SYLLABLE SSWEO 50332 == code || // Lo HANGUL SYLLABLE SSWE 50360 == code || // Lo HANGUL SYLLABLE SSWI 50388 == code || // Lo HANGUL SYLLABLE SSYU 50416 == code || // Lo HANGUL SYLLABLE SSEU 50444 == code || // Lo HANGUL SYLLABLE SSYI 50472 == code || // Lo HANGUL SYLLABLE SSI 50500 == code || // Lo HANGUL SYLLABLE A 50528 == code || // Lo HANGUL SYLLABLE AE 50556 == code || // Lo HANGUL SYLLABLE YA 50584 == code || // Lo HANGUL SYLLABLE YAE 50612 == code || // Lo HANGUL SYLLABLE EO 50640 == code || // Lo HANGUL SYLLABLE E 50668 == code || // Lo HANGUL SYLLABLE YEO 50696 == code || // Lo HANGUL SYLLABLE YE 50724 == code || // Lo HANGUL SYLLABLE O 50752 == code || // Lo HANGUL SYLLABLE WA 50780 == code || // Lo HANGUL SYLLABLE WAE 50808 == code || // Lo HANGUL SYLLABLE OE 50836 == code || // Lo HANGUL SYLLABLE YO 50864 == code || // Lo HANGUL SYLLABLE U 50892 == code || // Lo HANGUL SYLLABLE WEO 50920 == code || // Lo HANGUL SYLLABLE WE 50948 == code || // Lo HANGUL SYLLABLE WI 50976 == code || // Lo HANGUL SYLLABLE YU 51004 == code || // Lo HANGUL SYLLABLE EU 51032 == code || // Lo HANGUL SYLLABLE YI 51060 == code || // Lo HANGUL SYLLABLE I 51088 == code || // Lo HANGUL SYLLABLE JA 51116 == code || // Lo HANGUL SYLLABLE JAE 51144 == code || // Lo HANGUL SYLLABLE JYA 51172 == code || // Lo HANGUL SYLLABLE JYAE 51200 == code || // Lo HANGUL SYLLABLE JEO 51228 == code || // Lo HANGUL SYLLABLE JE 51256 == code || // Lo HANGUL SYLLABLE JYEO 51284 == code || // Lo HANGUL SYLLABLE JYE 51312 == code || // Lo HANGUL SYLLABLE JO 51340 == code || // Lo HANGUL SYLLABLE JWA 51368 == code || // Lo HANGUL SYLLABLE JWAE 51396 == code || // Lo HANGUL SYLLABLE JOE 51424 == code || // Lo HANGUL SYLLABLE JYO 51452 == code || // Lo HANGUL SYLLABLE JU 51480 == code || // Lo HANGUL SYLLABLE JWEO 51508 == code || // Lo HANGUL SYLLABLE JWE 51536 == code || // Lo HANGUL SYLLABLE JWI 51564 == code || // Lo HANGUL SYLLABLE JYU 51592 == code || // Lo HANGUL SYLLABLE JEU 51620 == code || // Lo HANGUL SYLLABLE JYI 51648 == code || // Lo HANGUL SYLLABLE JI 51676 == code || // Lo HANGUL SYLLABLE JJA 51704 == code || // Lo HANGUL SYLLABLE JJAE 51732 == code || // Lo HANGUL SYLLABLE JJYA 51760 == code || // Lo HANGUL SYLLABLE JJYAE 51788 == code || // Lo HANGUL SYLLABLE JJEO 51816 == code || // Lo HANGUL SYLLABLE JJE 51844 == code || // Lo HANGUL SYLLABLE JJYEO 51872 == code || // Lo HANGUL SYLLABLE JJYE 51900 == code || // Lo HANGUL SYLLABLE JJO 51928 == code || // Lo HANGUL SYLLABLE JJWA 51956 == code || // Lo HANGUL SYLLABLE JJWAE 51984 == code || // Lo HANGUL SYLLABLE JJOE 52012 == code || // Lo HANGUL SYLLABLE JJYO 52040 == code || // Lo HANGUL SYLLABLE JJU 52068 == code || // Lo HANGUL SYLLABLE JJWEO 52096 == code || // Lo HANGUL SYLLABLE JJWE 52124 == code || // Lo HANGUL SYLLABLE JJWI 52152 == code || // Lo HANGUL SYLLABLE JJYU 52180 == code || // Lo HANGUL SYLLABLE JJEU 52208 == code || // Lo HANGUL SYLLABLE JJYI 52236 == code || // Lo HANGUL SYLLABLE JJI 52264 == code || // Lo HANGUL SYLLABLE CA 52292 == code || // Lo HANGUL SYLLABLE CAE 52320 == code || // Lo HANGUL SYLLABLE CYA 52348 == code || // Lo HANGUL SYLLABLE CYAE 52376 == code || // Lo HANGUL SYLLABLE CEO 52404 == code || // Lo HANGUL SYLLABLE CE 52432 == code || // Lo HANGUL SYLLABLE CYEO 52460 == code || // Lo HANGUL SYLLABLE CYE 52488 == code || // Lo HANGUL SYLLABLE CO 52516 == code || // Lo HANGUL SYLLABLE CWA 52544 == code || // Lo HANGUL SYLLABLE CWAE 52572 == code || // Lo HANGUL SYLLABLE COE 52600 == code || // Lo HANGUL SYLLABLE CYO 52628 == code || // Lo HANGUL SYLLABLE CU 52656 == code || // Lo HANGUL SYLLABLE CWEO 52684 == code || // Lo HANGUL SYLLABLE CWE 52712 == code || // Lo HANGUL SYLLABLE CWI 52740 == code || // Lo HANGUL SYLLABLE CYU 52768 == code || // Lo HANGUL SYLLABLE CEU 52796 == code || // Lo HANGUL SYLLABLE CYI 52824 == code || // Lo HANGUL SYLLABLE CI 52852 == code || // Lo HANGUL SYLLABLE KA 52880 == code || // Lo HANGUL SYLLABLE KAE 52908 == code || // Lo HANGUL SYLLABLE KYA 52936 == code || // Lo HANGUL SYLLABLE KYAE 52964 == code || // Lo HANGUL SYLLABLE KEO 52992 == code || // Lo HANGUL SYLLABLE KE 53020 == code || // Lo HANGUL SYLLABLE KYEO 53048 == code || // Lo HANGUL SYLLABLE KYE 53076 == code || // Lo HANGUL SYLLABLE KO 53104 == code || // Lo HANGUL SYLLABLE KWA 53132 == code || // Lo HANGUL SYLLABLE KWAE 53160 == code || // Lo HANGUL SYLLABLE KOE 53188 == code || // Lo HANGUL SYLLABLE KYO 53216 == code || // Lo HANGUL SYLLABLE KU 53244 == code || // Lo HANGUL SYLLABLE KWEO 53272 == code || // Lo HANGUL SYLLABLE KWE 53300 == code || // Lo HANGUL SYLLABLE KWI 53328 == code || // Lo HANGUL SYLLABLE KYU 53356 == code || // Lo HANGUL SYLLABLE KEU 53384 == code || // Lo HANGUL SYLLABLE KYI 53412 == code || // Lo HANGUL SYLLABLE KI 53440 == code || // Lo HANGUL SYLLABLE TA 53468 == code || // Lo HANGUL SYLLABLE TAE 53496 == code || // Lo HANGUL SYLLABLE TYA 53524 == code || // Lo HANGUL SYLLABLE TYAE 53552 == code || // Lo HANGUL SYLLABLE TEO 53580 == code || // Lo HANGUL SYLLABLE TE 53608 == code || // Lo HANGUL SYLLABLE TYEO 53636 == code || // Lo HANGUL SYLLABLE TYE 53664 == code || // Lo HANGUL SYLLABLE TO 53692 == code || // Lo HANGUL SYLLABLE TWA 53720 == code || // Lo HANGUL SYLLABLE TWAE 53748 == code || // Lo HANGUL SYLLABLE TOE 53776 == code || // Lo HANGUL SYLLABLE TYO 53804 == code || // Lo HANGUL SYLLABLE TU 53832 == code || // Lo HANGUL SYLLABLE TWEO 53860 == code || // Lo HANGUL SYLLABLE TWE 53888 == code || // Lo HANGUL SYLLABLE TWI 53916 == code || // Lo HANGUL SYLLABLE TYU 53944 == code || // Lo HANGUL SYLLABLE TEU 53972 == code || // Lo HANGUL SYLLABLE TYI 54e3 == code || // Lo HANGUL SYLLABLE TI 54028 == code || // Lo HANGUL SYLLABLE PA 54056 == code || // Lo HANGUL SYLLABLE PAE 54084 == code || // Lo HANGUL SYLLABLE PYA 54112 == code || // Lo HANGUL SYLLABLE PYAE 54140 == code || // Lo HANGUL SYLLABLE PEO 54168 == code || // Lo HANGUL SYLLABLE PE 54196 == code || // Lo HANGUL SYLLABLE PYEO 54224 == code || // Lo HANGUL SYLLABLE PYE 54252 == code || // Lo HANGUL SYLLABLE PO 54280 == code || // Lo HANGUL SYLLABLE PWA 54308 == code || // Lo HANGUL SYLLABLE PWAE 54336 == code || // Lo HANGUL SYLLABLE POE 54364 == code || // Lo HANGUL SYLLABLE PYO 54392 == code || // Lo HANGUL SYLLABLE PU 54420 == code || // Lo HANGUL SYLLABLE PWEO 54448 == code || // Lo HANGUL SYLLABLE PWE 54476 == code || // Lo HANGUL SYLLABLE PWI 54504 == code || // Lo HANGUL SYLLABLE PYU 54532 == code || // Lo HANGUL SYLLABLE PEU 54560 == code || // Lo HANGUL SYLLABLE PYI 54588 == code || // Lo HANGUL SYLLABLE PI 54616 == code || // Lo HANGUL SYLLABLE HA 54644 == code || // Lo HANGUL SYLLABLE HAE 54672 == code || // Lo HANGUL SYLLABLE HYA 54700 == code || // Lo HANGUL SYLLABLE HYAE 54728 == code || // Lo HANGUL SYLLABLE HEO 54756 == code || // Lo HANGUL SYLLABLE HE 54784 == code || // Lo HANGUL SYLLABLE HYEO 54812 == code || // Lo HANGUL SYLLABLE HYE 54840 == code || // Lo HANGUL SYLLABLE HO 54868 == code || // Lo HANGUL SYLLABLE HWA 54896 == code || // Lo HANGUL SYLLABLE HWAE 54924 == code || // Lo HANGUL SYLLABLE HOE 54952 == code || // Lo HANGUL SYLLABLE HYO 54980 == code || // Lo HANGUL SYLLABLE HU 55008 == code || // Lo HANGUL SYLLABLE HWEO 55036 == code || // Lo HANGUL SYLLABLE HWE 55064 == code || // Lo HANGUL SYLLABLE HWI 55092 == code || // Lo HANGUL SYLLABLE HYU 55120 == code || // Lo HANGUL SYLLABLE HEU 55148 == code || // Lo HANGUL SYLLABLE HYI 55176 == code) { return LV; } if (44033 <= code && code <= 44059 || // Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH 44061 <= code && code <= 44087 || // Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH 44089 <= code && code <= 44115 || // Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH 44117 <= code && code <= 44143 || // Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH 44145 <= code && code <= 44171 || // Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH 44173 <= code && code <= 44199 || // Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH 44201 <= code && code <= 44227 || // Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH 44229 <= code && code <= 44255 || // Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH 44257 <= code && code <= 44283 || // Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH 44285 <= code && code <= 44311 || // Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH 44313 <= code && code <= 44339 || // Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH 44341 <= code && code <= 44367 || // Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH 44369 <= code && code <= 44395 || // Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH 44397 <= code && code <= 44423 || // Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH 44425 <= code && code <= 44451 || // Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH 44453 <= code && code <= 44479 || // Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH 44481 <= code && code <= 44507 || // Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH 44509 <= code && code <= 44535 || // Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH 44537 <= code && code <= 44563 || // Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH 44565 <= code && code <= 44591 || // Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH 44593 <= code && code <= 44619 || // Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH 44621 <= code && code <= 44647 || // Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH 44649 <= code && code <= 44675 || // Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH 44677 <= code && code <= 44703 || // Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH 44705 <= code && code <= 44731 || // Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH 44733 <= code && code <= 44759 || // Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH 44761 <= code && code <= 44787 || // Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH 44789 <= code && code <= 44815 || // Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH 44817 <= code && code <= 44843 || // Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH 44845 <= code && code <= 44871 || // Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH 44873 <= code && code <= 44899 || // Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH 44901 <= code && code <= 44927 || // Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH 44929 <= code && code <= 44955 || // Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH 44957 <= code && code <= 44983 || // Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH 44985 <= code && code <= 45011 || // Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH 45013 <= code && code <= 45039 || // Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH 45041 <= code && code <= 45067 || // Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH 45069 <= code && code <= 45095 || // Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH 45097 <= code && code <= 45123 || // Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH 45125 <= code && code <= 45151 || // Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH 45153 <= code && code <= 45179 || // Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH 45181 <= code && code <= 45207 || // Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH 45209 <= code && code <= 45235 || // Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH 45237 <= code && code <= 45263 || // Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH 45265 <= code && code <= 45291 || // Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH 45293 <= code && code <= 45319 || // Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH 45321 <= code && code <= 45347 || // Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH 45349 <= code && code <= 45375 || // Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH 45377 <= code && code <= 45403 || // Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH 45405 <= code && code <= 45431 || // Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH 45433 <= code && code <= 45459 || // Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH 45461 <= code && code <= 45487 || // Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH 45489 <= code && code <= 45515 || // Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH 45517 <= code && code <= 45543 || // Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH 45545 <= code && code <= 45571 || // Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH 45573 <= code && code <= 45599 || // Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH 45601 <= code && code <= 45627 || // Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH 45629 <= code && code <= 45655 || // Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH 45657 <= code && code <= 45683 || // Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH 45685 <= code && code <= 45711 || // Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH 45713 <= code && code <= 45739 || // Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH 45741 <= code && code <= 45767 || // Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH 45769 <= code && code <= 45795 || // Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH 45797 <= code && code <= 45823 || // Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH 45825 <= code && code <= 45851 || // Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH 45853 <= code && code <= 45879 || // Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH 45881 <= code && code <= 45907 || // Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH 45909 <= code && code <= 45935 || // Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH 45937 <= code && code <= 45963 || // Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH 45965 <= code && code <= 45991 || // Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH 45993 <= code && code <= 46019 || // Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH 46021 <= code && code <= 46047 || // Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH 46049 <= code && code <= 46075 || // Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH 46077 <= code && code <= 46103 || // Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH 46105 <= code && code <= 46131 || // Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH 46133 <= code && code <= 46159 || // Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH 46161 <= code && code <= 46187 || // Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH 46189 <= code && code <= 46215 || // Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH 46217 <= code && code <= 46243 || // Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH 46245 <= code && code <= 46271 || // Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH 46273 <= code && code <= 46299 || // Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH 46301 <= code && code <= 46327 || // Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH 46329 <= code && code <= 46355 || // Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH 46357 <= code && code <= 46383 || // Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH 46385 <= code && code <= 46411 || // Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH 46413 <= code && code <= 46439 || // Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH 46441 <= code && code <= 46467 || // Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH 46469 <= code && code <= 46495 || // Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH 46497 <= code && code <= 46523 || // Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH 46525 <= code && code <= 46551 || // Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH 46553 <= code && code <= 46579 || // Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH 46581 <= code && code <= 46607 || // Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH 46609 <= code && code <= 46635 || // Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH 46637 <= code && code <= 46663 || // Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH 46665 <= code && code <= 46691 || // Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH 46693 <= code && code <= 46719 || // Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH 46721 <= code && code <= 46747 || // Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH 46749 <= code && code <= 46775 || // Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH 46777 <= code && code <= 46803 || // Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH 46805 <= code && code <= 46831 || // Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH 46833 <= code && code <= 46859 || // Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH 46861 <= code && code <= 46887 || // Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH 46889 <= code && code <= 46915 || // Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH 46917 <= code && code <= 46943 || // Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH 46945 <= code && code <= 46971 || // Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH 46973 <= code && code <= 46999 || // Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH 47001 <= code && code <= 47027 || // Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH 47029 <= code && code <= 47055 || // Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH 47057 <= code && code <= 47083 || // Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH 47085 <= code && code <= 47111 || // Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH 47113 <= code && code <= 47139 || // Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH 47141 <= code && code <= 47167 || // Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH 47169 <= code && code <= 47195 || // Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH 47197 <= code && code <= 47223 || // Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH 47225 <= code && code <= 47251 || // Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH 47253 <= code && code <= 47279 || // Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH 47281 <= code && code <= 47307 || // Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH 47309 <= code && code <= 47335 || // Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH 47337 <= code && code <= 47363 || // Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH 47365 <= code && code <= 47391 || // Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH 47393 <= code && code <= 47419 || // Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH 47421 <= code && code <= 47447 || // Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH 47449 <= code && code <= 47475 || // Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH 47477 <= code && code <= 47503 || // Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH 47505 <= code && code <= 47531 || // Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH 47533 <= code && code <= 47559 || // Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH 47561 <= code && code <= 47587 || // Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH 47589 <= code && code <= 47615 || // Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH 47617 <= code && code <= 47643 || // Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH 47645 <= code && code <= 47671 || // Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH 47673 <= code && code <= 47699 || // Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH 47701 <= code && code <= 47727 || // Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH 47729 <= code && code <= 47755 || // Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH 47757 <= code && code <= 47783 || // Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH 47785 <= code && code <= 47811 || // Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH 47813 <= code && code <= 47839 || // Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH 47841 <= code && code <= 47867 || // Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH 47869 <= code && code <= 47895 || // Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH 47897 <= code && code <= 47923 || // Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH 47925 <= code && code <= 47951 || // Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH 47953 <= code && code <= 47979 || // Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH 47981 <= code && code <= 48007 || // Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH 48009 <= code && code <= 48035 || // Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH 48037 <= code && code <= 48063 || // Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH 48065 <= code && code <= 48091 || // Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH 48093 <= code && code <= 48119 || // Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH 48121 <= code && code <= 48147 || // Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH 48149 <= code && code <= 48175 || // Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH 48177 <= code && code <= 48203 || // Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH 48205 <= code && code <= 48231 || // Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH 48233 <= code && code <= 48259 || // Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH 48261 <= code && code <= 48287 || // Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH 48289 <= code && code <= 48315 || // Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH 48317 <= code && code <= 48343 || // Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH 48345 <= code && code <= 48371 || // Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH 48373 <= code && code <= 48399 || // Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH 48401 <= code && code <= 48427 || // Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH 48429 <= code && code <= 48455 || // Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH 48457 <= code && code <= 48483 || // Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH 48485 <= code && code <= 48511 || // Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH 48513 <= code && code <= 48539 || // Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH 48541 <= code && code <= 48567 || // Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH 48569 <= code && code <= 48595 || // Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH 48597 <= code && code <= 48623 || // Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH 48625 <= code && code <= 48651 || // Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH 48653 <= code && code <= 48679 || // Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH 48681 <= code && code <= 48707 || // Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH 48709 <= code && code <= 48735 || // Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH 48737 <= code && code <= 48763 || // Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH 48765 <= code && code <= 48791 || // Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH 48793 <= code && code <= 48819 || // Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH 48821 <= code && code <= 48847 || // Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH 48849 <= code && code <= 48875 || // Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH 48877 <= code && code <= 48903 || // Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH 48905 <= code && code <= 48931 || // Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH 48933 <= code && code <= 48959 || // Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH 48961 <= code && code <= 48987 || // Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH 48989 <= code && code <= 49015 || // Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH 49017 <= code && code <= 49043 || // Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH 49045 <= code && code <= 49071 || // Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH 49073 <= code && code <= 49099 || // Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH 49101 <= code && code <= 49127 || // Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH 49129 <= code && code <= 49155 || // Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH 49157 <= code && code <= 49183 || // Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH 49185 <= code && code <= 49211 || // Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH 49213 <= code && code <= 49239 || // Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH 49241 <= code && code <= 49267 || // Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH 49269 <= code && code <= 49295 || // Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH 49297 <= code && code <= 49323 || // Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH 49325 <= code && code <= 49351 || // Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH 49353 <= code && code <= 49379 || // Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH 49381 <= code && code <= 49407 || // Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH 49409 <= code && code <= 49435 || // Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH 49437 <= code && code <= 49463 || // Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH 49465 <= code && code <= 49491 || // Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH 49493 <= code && code <= 49519 || // Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH 49521 <= code && code <= 49547 || // Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH 49549 <= code && code <= 49575 || // Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH 49577 <= code && code <= 49603 || // Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH 49605 <= code && code <= 49631 || // Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH 49633 <= code && code <= 49659 || // Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH 49661 <= code && code <= 49687 || // Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH 49689 <= code && code <= 49715 || // Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH 49717 <= code && code <= 49743 || // Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH 49745 <= code && code <= 49771 || // Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH 49773 <= code && code <= 49799 || // Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH 49801 <= code && code <= 49827 || // Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH 49829 <= code && code <= 49855 || // Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH 49857 <= code && code <= 49883 || // Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH 49885 <= code && code <= 49911 || // Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH 49913 <= code && code <= 49939 || // Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH 49941 <= code && code <= 49967 || // Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH 49969 <= code && code <= 49995 || // Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH 49997 <= code && code <= 50023 || // Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH 50025 <= code && code <= 50051 || // Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH 50053 <= code && code <= 50079 || // Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH 50081 <= code && code <= 50107 || // Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH 50109 <= code && code <= 50135 || // Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH 50137 <= code && code <= 50163 || // Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH 50165 <= code && code <= 50191 || // Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH 50193 <= code && code <= 50219 || // Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH 50221 <= code && code <= 50247 || // Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH 50249 <= code && code <= 50275 || // Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH 50277 <= code && code <= 50303 || // Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH 50305 <= code && code <= 50331 || // Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH 50333 <= code && code <= 50359 || // Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH 50361 <= code && code <= 50387 || // Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH 50389 <= code && code <= 50415 || // Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH 50417 <= code && code <= 50443 || // Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH 50445 <= code && code <= 50471 || // Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH 50473 <= code && code <= 50499 || // Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH 50501 <= code && code <= 50527 || // Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH 50529 <= code && code <= 50555 || // Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH 50557 <= code && code <= 50583 || // Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH 50585 <= code && code <= 50611 || // Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH 50613 <= code && code <= 50639 || // Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH 50641 <= code && code <= 50667 || // Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH 50669 <= code && code <= 50695 || // Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH 50697 <= code && code <= 50723 || // Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH 50725 <= code && code <= 50751 || // Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH 50753 <= code && code <= 50779 || // Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH 50781 <= code && code <= 50807 || // Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH 50809 <= code && code <= 50835 || // Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH 50837 <= code && code <= 50863 || // Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH 50865 <= code && code <= 50891 || // Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH 50893 <= code && code <= 50919 || // Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH 50921 <= code && code <= 50947 || // Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH 50949 <= code && code <= 50975 || // Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH 50977 <= code && code <= 51003 || // Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH 51005 <= code && code <= 51031 || // Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH 51033 <= code && code <= 51059 || // Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH 51061 <= code && code <= 51087 || // Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH 51089 <= code && code <= 51115 || // Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH 51117 <= code && code <= 51143 || // Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH 51145 <= code && code <= 51171 || // Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH 51173 <= code && code <= 51199 || // Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH 51201 <= code && code <= 51227 || // Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH 51229 <= code && code <= 51255 || // Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH 51257 <= code && code <= 51283 || // Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH 51285 <= code && code <= 51311 || // Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH 51313 <= code && code <= 51339 || // Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH 51341 <= code && code <= 51367 || // Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH 51369 <= code && code <= 51395 || // Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH 51397 <= code && code <= 51423 || // Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH 51425 <= code && code <= 51451 || // Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH 51453 <= code && code <= 51479 || // Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH 51481 <= code && code <= 51507 || // Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH 51509 <= code && code <= 51535 || // Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH 51537 <= code && code <= 51563 || // Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH 51565 <= code && code <= 51591 || // Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH 51593 <= code && code <= 51619 || // Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH 51621 <= code && code <= 51647 || // Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH 51649 <= code && code <= 51675 || // Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH 51677 <= code && code <= 51703 || // Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH 51705 <= code && code <= 51731 || // Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH 51733 <= code && code <= 51759 || // Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH 51761 <= code && code <= 51787 || // Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH 51789 <= code && code <= 51815 || // Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH 51817 <= code && code <= 51843 || // Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH 51845 <= code && code <= 51871 || // Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH 51873 <= code && code <= 51899 || // Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH 51901 <= code && code <= 51927 || // Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH 51929 <= code && code <= 51955 || // Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH 51957 <= code && code <= 51983 || // Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH 51985 <= code && code <= 52011 || // Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH 52013 <= code && code <= 52039 || // Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH 52041 <= code && code <= 52067 || // Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH 52069 <= code && code <= 52095 || // Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH 52097 <= code && code <= 52123 || // Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH 52125 <= code && code <= 52151 || // Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH 52153 <= code && code <= 52179 || // Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH 52181 <= code && code <= 52207 || // Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH 52209 <= code && code <= 52235 || // Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH 52237 <= code && code <= 52263 || // Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH 52265 <= code && code <= 52291 || // Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH 52293 <= code && code <= 52319 || // Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH 52321 <= code && code <= 52347 || // Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH 52349 <= code && code <= 52375 || // Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH 52377 <= code && code <= 52403 || // Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH 52405 <= code && code <= 52431 || // Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH 52433 <= code && code <= 52459 || // Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH 52461 <= code && code <= 52487 || // Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH 52489 <= code && code <= 52515 || // Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH 52517 <= code && code <= 52543 || // Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH 52545 <= code && code <= 52571 || // Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH 52573 <= code && code <= 52599 || // Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH 52601 <= code && code <= 52627 || // Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH 52629 <= code && code <= 52655 || // Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH 52657 <= code && code <= 52683 || // Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH 52685 <= code && code <= 52711 || // Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH 52713 <= code && code <= 52739 || // Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH 52741 <= code && code <= 52767 || // Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH 52769 <= code && code <= 52795 || // Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH 52797 <= code && code <= 52823 || // Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH 52825 <= code && code <= 52851 || // Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH 52853 <= code && code <= 52879 || // Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH 52881 <= code && code <= 52907 || // Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH 52909 <= code && code <= 52935 || // Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH 52937 <= code && code <= 52963 || // Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH 52965 <= code && code <= 52991 || // Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH 52993 <= code && code <= 53019 || // Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH 53021 <= code && code <= 53047 || // Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH 53049 <= code && code <= 53075 || // Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH 53077 <= code && code <= 53103 || // Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH 53105 <= code && code <= 53131 || // Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH 53133 <= code && code <= 53159 || // Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH 53161 <= code && code <= 53187 || // Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH 53189 <= code && code <= 53215 || // Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH 53217 <= code && code <= 53243 || // Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH 53245 <= code && code <= 53271 || // Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH 53273 <= code && code <= 53299 || // Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH 53301 <= code && code <= 53327 || // Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH 53329 <= code && code <= 53355 || // Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH 53357 <= code && code <= 53383 || // Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH 53385 <= code && code <= 53411 || // Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH 53413 <= code && code <= 53439 || // Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH 53441 <= code && code <= 53467 || // Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH 53469 <= code && code <= 53495 || // Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH 53497 <= code && code <= 53523 || // Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH 53525 <= code && code <= 53551 || // Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH 53553 <= code && code <= 53579 || // Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH 53581 <= code && code <= 53607 || // Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH 53609 <= code && code <= 53635 || // Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH 53637 <= code && code <= 53663 || // Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH 53665 <= code && code <= 53691 || // Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH 53693 <= code && code <= 53719 || // Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH 53721 <= code && code <= 53747 || // Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH 53749 <= code && code <= 53775 || // Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH 53777 <= code && code <= 53803 || // Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH 53805 <= code && code <= 53831 || // Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH 53833 <= code && code <= 53859 || // Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH 53861 <= code && code <= 53887 || // Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH 53889 <= code && code <= 53915 || // Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH 53917 <= code && code <= 53943 || // Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH 53945 <= code && code <= 53971 || // Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH 53973 <= code && code <= 53999 || // Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH 54001 <= code && code <= 54027 || // Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH 54029 <= code && code <= 54055 || // Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH 54057 <= code && code <= 54083 || // Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH 54085 <= code && code <= 54111 || // Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH 54113 <= code && code <= 54139 || // Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH 54141 <= code && code <= 54167 || // Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH 54169 <= code && code <= 54195 || // Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH 54197 <= code && code <= 54223 || // Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH 54225 <= code && code <= 54251 || // Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH 54253 <= code && code <= 54279 || // Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH 54281 <= code && code <= 54307 || // Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH 54309 <= code && code <= 54335 || // Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH 54337 <= code && code <= 54363 || // Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH 54365 <= code && code <= 54391 || // Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH 54393 <= code && code <= 54419 || // Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH 54421 <= code && code <= 54447 || // Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH 54449 <= code && code <= 54475 || // Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH 54477 <= code && code <= 54503 || // Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH 54505 <= code && code <= 54531 || // Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH 54533 <= code && code <= 54559 || // Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH 54561 <= code && code <= 54587 || // Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH 54589 <= code && code <= 54615 || // Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH 54617 <= code && code <= 54643 || // Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH 54645 <= code && code <= 54671 || // Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH 54673 <= code && code <= 54699 || // Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH 54701 <= code && code <= 54727 || // Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH 54729 <= code && code <= 54755 || // Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH 54757 <= code && code <= 54783 || // Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH 54785 <= code && code <= 54811 || // Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH 54813 <= code && code <= 54839 || // Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH 54841 <= code && code <= 54867 || // Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH 54869 <= code && code <= 54895 || // Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH 54897 <= code && code <= 54923 || // Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH 54925 <= code && code <= 54951 || // Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH 54953 <= code && code <= 54979 || // Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH 54981 <= code && code <= 55007 || // Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH 55009 <= code && code <= 55035 || // Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH 55037 <= code && code <= 55063 || // Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH 55065 <= code && code <= 55091 || // Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH 55093 <= code && code <= 55119 || // Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH 55121 <= code && code <= 55147 || // Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH 55149 <= code && code <= 55175 || // Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH 55177 <= code && code <= 55203) { return LVT; } if (9757 == code || // So WHITE UP POINTING INDEX 9977 == code || // So PERSON WITH BALL 9994 <= code && code <= 9997 || // So [4] RAISED FIST..WRITING HAND 127877 == code || // So FATHER CHRISTMAS 127938 <= code && code <= 127940 || // So [3] SNOWBOARDER..SURFER 127943 == code || // So HORSE RACING 127946 <= code && code <= 127948 || // So [3] SWIMMER..GOLFER 128066 <= code && code <= 128067 || // So [2] EAR..NOSE 128070 <= code && code <= 128080 || // So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN 128110 == code || // So POLICE OFFICER 128112 <= code && code <= 128120 || // So [9] BRIDE WITH VEIL..PRINCESS 128124 == code || // So BABY ANGEL 128129 <= code && code <= 128131 || // So [3] INFORMATION DESK PERSON..DANCER 128133 <= code && code <= 128135 || // So [3] NAIL POLISH..HAIRCUT 128170 == code || // So FLEXED BICEPS 128372 <= code && code <= 128373 || // So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY 128378 == code || // So MAN DANCING 128400 == code || // So RAISED HAND WITH FINGERS SPLAYED 128405 <= code && code <= 128406 || // So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS 128581 <= code && code <= 128583 || // So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY 128587 <= code && code <= 128591 || // So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS 128675 == code || // So ROWBOAT 128692 <= code && code <= 128694 || // So [3] BICYCLIST..PEDESTRIAN 128704 == code || // So BATH 128716 == code || // So SLEEPING ACCOMMODATION 129304 <= code && code <= 129308 || // So [5] SIGN OF THE HORNS..RIGHT-FACING FIST 129310 <= code && code <= 129311 || // So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN 129318 == code || // So FACE PALM 129328 <= code && code <= 129337 || // So [10] PREGNANT WOMAN..JUGGLING 129341 <= code && code <= 129342 || // So [2] WATER POLO..HANDBALL 129489 <= code && code <= 129501) { return E_Base; } if (127995 <= code && code <= 127999) { return E_Modifier; } if (8205 == code) { return ZWJ; } if (9792 == code || // So FEMALE SIGN 9794 == code || // So MALE SIGN 9877 <= code && code <= 9878 || // So [2] STAFF OF AESCULAPIUS..SCALES 9992 == code || // So AIRPLANE 10084 == code || // So HEAVY BLACK HEART 127752 == code || // So RAINBOW 127806 == code || // So EAR OF RICE 127859 == code || // So COOKING 127891 == code || // So GRADUATION CAP 127908 == code || // So MICROPHONE 127912 == code || // So ARTIST PALETTE 127979 == code || // So SCHOOL 127981 == code || // So FACTORY 128139 == code || // So KISS MARK 128187 <= code && code <= 128188 || // So [2] PERSONAL COMPUTER..BRIEFCASE 128295 == code || // So WRENCH 128300 == code || // So MICROSCOPE 128488 == code || // So LEFT SPEECH BUBBLE 128640 == code || // So ROCKET 128658 == code) { return Glue_After_Zwj; } if (128102 <= code && code <= 128105) { return E_Base_GAZ; } return Other; } return this; } if (typeof module != "undefined" && module.exports) { module.exports = GraphemeSplitter2; } } }); // node_modules/protobufjs/dist/minimal/protobuf.js var require_protobuf = __commonJS({ "node_modules/protobufjs/dist/minimal/protobuf.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /*! * protobuf.js v8.7.1 (c) 2016, daniel wirtz * compiled mon, 13 jul 2026 11:04:12 utc * licensed under the bsd-3-clause license * see: https://github.com/dcodeio/protobuf.js for details */ (function(undefined2) { "use strict"; (function prelude(modules, cache, entries2) { function $require(name) { var $module = cache[name]; if (!$module) modules[name][0].call($module = cache[name] = { exports: {} }, $require, $module, $module.exports); return $module.exports; } var protobuf3 = $require(entries2[0]); protobuf3.util.global.protobuf = protobuf3; if (typeof define === "function" && define.amd) define(["long"], function(Long) { if (Long && Long.isLong) { protobuf3.util.Long = Long; protobuf3.configure(); } return protobuf3; }); if (typeof module === "object" && module && module.exports) module.exports = protobuf3; })({ 1: [function(require2, module2, exports2) { "use strict"; exports2.build = "minimal"; exports2.Writer = require2(15); exports2.BufferWriter = require2(16); exports2.Reader = require2(2); exports2.BufferReader = require2(3); exports2.util = require2(12); exports2.rpc = require2(5); exports2.roots = require2(4); exports2.configure = configure2; function configure2() { exports2.util.LongBits._configure(exports2.util.Long); exports2.Writer._configure(exports2.BufferWriter); exports2.Reader._configure(exports2.BufferReader); } configure2(); }, { "12": 12, "15": 15, "16": 16, "2": 2, "3": 3, "4": 4, "5": 5 }], 2: [function(require2, module2, exports2) { "use strict"; module2.exports = Reader3; var util = require2(12); var BufferReader; var LongBits = util.LongBits, utf8 = util.utf8; function indexOutOfRange(reader, writeLength) { return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len); } function Reader3(buffer2) { this.buf = buffer2; this.pos = 0; this.len = buffer2.length; this.view = null; this.discardUnknown = Reader3.discardUnknown; } function create_array(buffer2) { if (Array.isArray(buffer2)) buffer2 = new Uint8Array(buffer2); if (buffer2 instanceof Uint8Array) return new Reader3(buffer2); throw Error("illegal buffer"); } var create2 = function create3() { return util.Buffer ? function create_buffer_setup(buffer2) { return (Reader3.create = function create_buffer(buffer3) { return util.Buffer.isBuffer(buffer3) ? new BufferReader(buffer3) : create_array(buffer3); })(buffer2); } : create_array; }; Reader3.create = create2(); Reader3.prototype.raw = function read_raw(start, end) { return this.buf.subarray(start, end); }; Reader3.prototype.uint32 = function read_uint32() { var buf = this.buf, pos = this.pos, value = (buf[pos] & 127) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 7) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 14) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 21) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 15) << 28) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } for (var i = 0; i < 5; ++i) { if (pos >= this.len) { this.pos = pos; throw indexOutOfRange(this); } if (buf[pos++] < 128) { this.pos = pos; return value; } } this.pos = pos; throw Error("invalid varint encoding"); }; Reader3.prototype.tag = function read_tag() { var buf = this.buf, pos = this.pos, value = (buf[pos] & 127) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 7) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 14) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 127) << 21) >>> 0; if (buf[pos++] < 128) { this.pos = pos; return value; } value = (value | (buf[pos] & 15) << 28) >>> 0; if (buf[pos] < 128 && (buf[pos] & 112) === 0) { this.pos = pos + 1; return value; } this.pos = pos + 1; throw Error("invalid tag encoding"); }; Reader3.prototype.int32 = function read_int32() { return this.uint32() | 0; }; Reader3.prototype.sint32 = function read_sint32() { var value = this.uint32(); return value >>> 1 ^ -(value & 1) | 0; }; function readLongVarint() { var bits = new LongBits(0, 0); var i = 0; if (this.len - this.pos > 4) { for (; i < 4; ++i) { bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0; bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0; if (this.buf[this.pos++] < 128) return bits; i = 0; } else { for (; i < 4; ++i) { if (this.pos >= this.len) throw indexOutOfRange(this); bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) return bits; } throw indexOutOfRange(this); } if (this.len - this.pos > 4) { for (; i < 5; ++i) { bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } else { for (; i < 5; ++i) { if (this.pos >= this.len) throw indexOutOfRange(this); bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) return bits; } } throw Error("invalid varint encoding"); } Reader3.prototype.bool = function read_bool() { var value = false, b; for (var i = 0; i < 10; ++i) { if (this.pos >= this.len) throw indexOutOfRange(this); b = this.buf[this.pos++]; if (b & 127) value = true; if (b < 128) return value; } throw Error("invalid varint encoding"); }; function readFixed32_end(buf, end) { return (buf[end - 4] | buf[end - 3] << 8 | buf[end - 2] << 16 | buf[end - 1] << 24) >>> 0; } Reader3.prototype.fixed32 = function read_fixed32() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4); }; Reader3.prototype.sfixed32 = function read_sfixed32() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); return readFixed32_end(this.buf, this.pos += 4) | 0; }; function readFixed64() { if (this.pos + 8 > this.len) throw indexOutOfRange(this, 8); return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4)); } Reader3.prototype.float = function read_float() { if (this.pos + 4 > this.len) throw indexOutOfRange(this, 4); var value = util.float.readFloatLE(this.buf, this.pos); this.pos += 4; return value; }; Reader3.prototype.double = function read_double() { if (this.pos + 8 > this.len) throw indexOutOfRange(this, 4); var value = util.float.readDoubleLE(this.buf, this.pos); this.pos += 8; return value; }; Reader3.prototype.uint32s = function read_uint32s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.uint32()); return array; }; Reader3.prototype.int32s = function read_int32s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.int32()); return array; }; Reader3.prototype.sint32s = function read_sint32s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.sint32()); return array; }; Reader3.prototype.bools = function read_bools(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.bool()); return array; }; var VIEW_THRESHOLD_FLOAT = 8, VIEW_THRESHOLD_INT = 128; function getLazyView(reader, count, threshold) { var view = reader.view; if (view || count < threshold) return view; var buf = reader.buf; return reader.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); } Reader3.prototype.fixed32s = function read_fixed32s(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 2, i = array.length, pos = this.pos; array.length = i + count; var dv = getLazyView(this, count, VIEW_THRESHOLD_INT); if (dv) for (var k = 0; k < count; ++k, pos += 4) array[i++] = dv.getUint32(pos, true); else { var buf = this.buf; for (var j = 0; j < count; ++j, pos += 4) array[i++] = readFixed32_end(buf, pos + 4); } this.pos = pos; if (pos !== end) throw indexOutOfRange(this, 4); return array; }; Reader3.prototype.sfixed32s = function read_sfixed32s(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 2, i = array.length, pos = this.pos; array.length = i + count; var dv = getLazyView(this, count, VIEW_THRESHOLD_INT); if (dv) for (var k = 0; k < count; ++k, pos += 4) array[i++] = dv.getInt32(pos, true); else { var buf = this.buf; for (var j = 0; j < count; ++j, pos += 4) array[i++] = readFixed32_end(buf, pos + 4) | 0; } this.pos = pos; if (pos !== end) throw indexOutOfRange(this, 4); return array; }; Reader3.prototype.floats = function read_floats(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 2, i = array.length, pos = this.pos; array.length = i + count; var dv = getLazyView(this, count, VIEW_THRESHOLD_FLOAT); if (dv) for (var k = 0; k < count; ++k, pos += 4) array[i++] = dv.getFloat32(pos, true); else { var buf = this.buf; for (var j = 0; j < count; ++j, pos += 4) array[i++] = util.float.readFloatLE(buf, pos); } this.pos = pos; if (pos !== end) throw indexOutOfRange(this, 4); return array; }; Reader3.prototype.doubles = function read_doubles(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 3, i = array.length, pos = this.pos; array.length = i + count; var dv = getLazyView(this, count, VIEW_THRESHOLD_FLOAT); if (dv) for (var k = 0; k < count; ++k, pos += 8) array[i++] = dv.getFloat64(pos, true); else { var buf = this.buf; for (var j = 0; j < count; ++j, pos += 8) array[i++] = util.float.readDoubleLE(buf, pos); } this.pos = pos; if (pos !== end) throw indexOutOfRange(this, 8); return array; }; Reader3.prototype.uint64s = function read_uint64s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.uint64()); return array; }; Reader3.prototype.int64s = function read_int64s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.int64()); return array; }; Reader3.prototype.sint64s = function read_sint64s(array) { if (array === undefined2) array = []; var end = this.uint32() + this.pos; while (this.pos < end) array.push(this.sint64()); return array; }; Reader3.prototype.fixed64s = function read_fixed64s(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len, i = array.length; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 3; array.length = i + count; for (var j = 0; j < count; ++j) array[i++] = this.fixed64(); if (this.pos !== end) throw indexOutOfRange(this, 8); return array; }; Reader3.prototype.sfixed64s = function read_sfixed64s(array) { if (array === undefined2) array = []; var len = this.uint32(), end = this.pos + len, i = array.length; if (end > this.len) throw indexOutOfRange(this, len); var count = len >>> 3; array.length = i + count; for (var j = 0; j < count; ++j) array[i++] = this.sfixed64(); if (this.pos !== end) throw indexOutOfRange(this, 8); return array; }; Reader3.prototype.bytes = function read_bytes() { var length2 = this.uint32(), start = this.pos, end = this.pos + length2; if (end > this.len) throw indexOutOfRange(this, length2); this.pos = end; return this.raw(start, end); }; Reader3.prototype.string = function read_string() { var length2 = this.uint32(), start = this.pos, end = this.pos + length2; if (end > this.len) throw indexOutOfRange(this, length2); this.pos = end; return utf8.read(this.buf, start, end); }; Reader3.prototype.stringVerify = function read_string_verify() { var length2 = this.uint32(), start = this.pos, end = this.pos + length2; if (end > this.len) throw indexOutOfRange(this, length2); this.pos = end; return utf8.readStrict(this.buf, start, end); }; Reader3.prototype.skip = function skip(length2) { if (typeof length2 === "number") { if (this.pos + length2 > this.len) throw indexOutOfRange(this, length2); this.pos += length2; } else { do { if (this.pos >= this.len) throw indexOutOfRange(this); } while (this.buf[this.pos++] & 128); } return this; }; Reader3.recursionLimit = util.recursionLimit; Reader3.discardUnknown = true; Reader3.prototype.skipType = function(wireType, depth, fieldNumber) { if (depth === undefined2) depth = 0; if (depth > Reader3.recursionLimit) throw Error("max depth exceeded"); if (fieldNumber === 0) throw Error("illegal tag: field number 0"); switch (wireType) { case 0: this.skip(); break; case 1: this.skip(8); break; case 2: this.skip(this.uint32()); break; case 3: while (true) { var tag = this.tag(); var nestedField = tag >>> 3; wireType = tag & 7; if (!nestedField) throw Error("illegal tag: field number 0"); if (wireType === 4) { if (fieldNumber !== undefined2 && nestedField !== fieldNumber) throw Error("invalid end group tag"); break; } this.skipType(wireType, depth + 1, nestedField); } break; case 5: this.skip(4); break; /* istanbul ignore next */ default: throw Error("invalid wire type " + wireType + " at offset " + this.pos); } return this; }; Reader3._configure = function(BufferReader_) { BufferReader = BufferReader_; Reader3.create = create2(); BufferReader._configure(); var fn = util.Long ? "toLong" : ( /* istanbul ignore next */ "toNumber" ); util.merge(Reader3.prototype, { int64: function read_int64() { return readLongVarint.call(this)[fn](false); }, uint64: function read_uint64() { return readLongVarint.call(this)[fn](true); }, sint64: function read_sint64() { return readLongVarint.call(this).zzDecode()[fn](false); }, fixed64: function read_fixed64() { return readFixed64.call(this)[fn](true); }, sfixed64: function read_sfixed64() { return readFixed64.call(this)[fn](false); } }); }; }, { "12": 12 }], 3: [function(require2, module2, exports2) { "use strict"; module2.exports = BufferReader; var Reader3 = require2(2); BufferReader.prototype = Object.create(Reader3.prototype, { constructor: { value: BufferReader, writable: true, enumerable: false, configurable: true } }); var util = require2(12); function BufferReader(buffer2) { Reader3.call(this, buffer2); } BufferReader._configure = function() { if (util.Buffer) BufferReader.prototype._slice = util.Buffer.prototype.slice; }; BufferReader.prototype.raw = function read_raw_buffer(start, end) { return this._slice.call(this.buf, start, end); }; BufferReader.prototype.string = function read_string_buffer() { var len = this.uint32(), start = this.pos, end = this.pos + len; if (end > this.len) throw RangeError("index out of range: " + this.pos + " + " + len + " > " + this.len); this.pos = end; return this.buf.utf8Slice ? this.buf.utf8Slice(start, end) : this.buf.toString("utf-8", start, end); }; BufferReader._configure(); }, { "12": 12, "2": 2 }], 4: [function(require2, module2, exports2) { "use strict"; module2.exports = /* @__PURE__ */ Object.create(null); }, {}], 5: [function(require2, module2, exports2) { "use strict"; var rpc = exports2; rpc.Service = require2(6); }, { "6": 6 }], 6: [function(require2, module2, exports2) { "use strict"; module2.exports = Service; var util = require2(12); Service.prototype = Object.create(util.EventEmitter.prototype, { constructor: { value: Service, writable: true, enumerable: false, configurable: true } }); function Service(rpcImpl, requestDelimited, responseDelimited) { if (typeof rpcImpl !== "function") throw TypeError("rpcImpl must be a function"); util.EventEmitter.call(this); this.rpcImpl = rpcImpl; this.requestDelimited = Boolean(requestDelimited); this.responseDelimited = Boolean(responseDelimited); } Service.prototype.rpcCall = function rpcCall(method, requestCtor, responseCtor, request, callback) { if (!request) throw TypeError("request must be specified"); var self2 = this; if (!callback) return util.asPromise(rpcCall, self2, method, requestCtor, responseCtor, request); if (!self2.rpcImpl) { setTimeout(function() { callback(Error("already ended")); }, 0); return undefined2; } try { return self2.rpcImpl( method, requestCtor[self2.requestDelimited ? "encodeDelimited" : "encode"](request).finish(), function rpcCallback(err, response) { if (err) { self2.emit("error", err, method); return callback(err); } if (response === null) { self2.end( /* endedByRPC */ true ); return undefined2; } if (!(response instanceof responseCtor)) { try { response = responseCtor[self2.responseDelimited ? "decodeDelimited" : "decode"](response); } catch (err2) { self2.emit("error", err2, method); return callback(err2); } } self2.emit("data", response, method); return callback(null, response); } ); } catch (err) { self2.emit("error", err, method); setTimeout(function() { callback(err); }, 0); return undefined2; } }; Service.prototype.end = function end(endedByRPC) { if (this.rpcImpl) { if (!endedByRPC) this.rpcImpl(null, null, null); this.rpcImpl = null; this.emit("end").off(); } return this; }; }, { "12": 12 }], 7: [function(require2, module2, exports2) { "use strict"; module2.exports = asPromise; function asPromise(fn, ctx) { var params = new Array(arguments.length - 1), offset = 0, index = 2, pending = true; while (index < arguments.length) params[offset++] = arguments[index++]; return new Promise(function executor(resolve2, reject) { params[offset] = function callback(err) { if (pending) { pending = false; if (err) reject(err); else { var params2 = new Array(arguments.length - 1), offset2 = 0; while (offset2 < params2.length) params2[offset2++] = arguments[offset2]; resolve2.apply(null, params2); } } }; try { fn.apply(ctx || null, params); } catch (err) { if (pending) { pending = false; reject(err); } } }); } }, {}], 8: [function(require2, module2, exports2) { "use strict"; var base64 = exports2; base64.length = function length2(string) { var p = string.length; if (!p) return 0; while (p > 0 && string.charAt(p - 1) === "=") --p; return Math.floor(p * 3 / 4); }; var b64 = new Array(64); var s64 = new Array(123); for (var i = 0; i < 64; ) s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++; s64[45] = 62; s64[95] = 63; base64.encode = function encode(buffer2, start, end) { var parts = null, chunk = []; var i2 = 0, j = 0, t2; while (start < end) { var b = buffer2[start++]; switch (j) { case 0: chunk[i2++] = b64[b >> 2]; t2 = (b & 3) << 4; j = 1; break; case 1: chunk[i2++] = b64[t2 | b >> 4]; t2 = (b & 15) << 2; j = 2; break; case 2: chunk[i2++] = b64[t2 | b >> 6]; chunk[i2++] = b64[b & 63]; j = 0; break; } if (i2 > 8191) { (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk)); i2 = 0; } } if (j) { chunk[i2++] = b64[t2]; chunk[i2++] = 61; if (j === 1) chunk[i2++] = 61; } if (parts) { if (i2) parts.push(String.fromCharCode.apply(String, chunk.slice(0, i2))); return parts.join(""); } return String.fromCharCode.apply(String, chunk.slice(0, i2)); }; var invalidEncoding = "invalid encoding"; base64.decode = function decode(string, buffer2, offset) { var start = offset; var j = 0, t2; for (var i2 = 0; i2 < string.length; ) { var c14 = string.charCodeAt(i2++); if (c14 === 61 && j > 1) break; if ((c14 = s64[c14]) === undefined2) throw Error(invalidEncoding); switch (j) { case 0: t2 = c14; j = 1; break; case 1: buffer2[offset++] = t2 << 2 | (c14 & 48) >> 4; t2 = c14; j = 2; break; case 2: buffer2[offset++] = (t2 & 15) << 4 | (c14 & 60) >> 2; t2 = c14; j = 3; break; case 3: buffer2[offset++] = (t2 & 3) << 6 | c14; j = 0; break; } } if (j === 1) throw Error(invalidEncoding); return offset - start; }; var base64Re = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/, base64UrlRe = /[-_]/, base64UrlNoPaddingRe = /^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2}(?:==)?|[A-Za-z0-9_-]{3}=?)?$/; base64.test = function test(string) { return base64Re.test(string) || base64UrlRe.test(string) && base64UrlNoPaddingRe.test(string); }; }, {}], 9: [function(require2, module2, exports2) { "use strict"; module2.exports = EventEmitter; function EventEmitter() { this._listeners = /* @__PURE__ */ Object.create(null); } EventEmitter.prototype.on = function on(evt, fn, ctx) { (this._listeners[evt] || (this._listeners[evt] = [])).push({ fn, ctx: ctx || this }); return this; }; EventEmitter.prototype.off = function off(evt, fn) { if (evt === undefined2) this._listeners = /* @__PURE__ */ Object.create(null); else { if (fn === undefined2) this._listeners[evt] = []; else { var listeners = this._listeners[evt]; if (!listeners) return this; for (var i = 0; i < listeners.length; ) if (listeners[i].fn === fn) listeners.splice(i, 1); else ++i; } } return this; }; EventEmitter.prototype.emit = function emit(evt) { var listeners = this._listeners[evt]; if (listeners) { var args = [], i = 1; for (; i < arguments.length; ) args.push(arguments[i++]); for (i = 0; i < listeners.length; ) listeners[i].fn.apply(listeners[i++].ctx, args); } return this; }; }, {}], 10: [function(require2, module2, exports2) { "use strict"; module2.exports = factory(factory); function factory(exports3) { if (typeof Float32Array !== "undefined") (function() { var f32 = new Float32Array([-0]), f8b = new Uint8Array(f32.buffer), le = f8b[3] === 128; function writeFloat_f32_cpy(val, buf, pos) { f32[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; } function writeFloat_f32_rev(val, buf, pos) { f32[0] = val; buf[pos] = f8b[3]; buf[pos + 1] = f8b[2]; buf[pos + 2] = f8b[1]; buf[pos + 3] = f8b[0]; } exports3.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev; exports3.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy; function readFloat_f32_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; return f32[0]; } function readFloat_f32_rev(buf, pos) { f8b[3] = buf[pos]; f8b[2] = buf[pos + 1]; f8b[1] = buf[pos + 2]; f8b[0] = buf[pos + 3]; return f32[0]; } exports3.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev; exports3.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy; })(); else (function() { function writeFloat_ieee754(writeUint, val, buf, pos) { var sign3 = val < 0 ? 1 : 0; if (sign3) val = -val; if (val === 0) writeUint(1 / val > 0 ? ( /* positive */ 0 ) : ( /* negative 0 */ 2147483648 ), buf, pos); else if (isNaN(val)) writeUint(2143289344, buf, pos); else if (val > 34028234663852886e22) writeUint((sign3 << 31 | 2139095040) >>> 0, buf, pos); else if (val < 11754943508222875e-54) writeUint((sign3 << 31 | Math.round(val / 1401298464324817e-60)) >>> 0, buf, pos); else { var exponent = Math.floor(Math.log(val) / Math.LN2), mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607; writeUint((sign3 << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos); } } exports3.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE); exports3.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE); function readFloat_ieee754(readUint, buf, pos) { var uint = readUint(buf, pos), sign3 = (uint >> 31) * 2 + 1, exponent = uint >>> 23 & 255, mantissa = uint & 8388607; return exponent === 255 ? mantissa ? NaN : sign3 * Infinity : exponent === 0 ? sign3 * 1401298464324817e-60 * mantissa : sign3 * Math.pow(2, exponent - 150) * (mantissa + 8388608); } exports3.readFloatLE = readFloat_ieee754.bind(null, readUintLE); exports3.readFloatBE = readFloat_ieee754.bind(null, readUintBE); })(); if (typeof Float64Array !== "undefined") (function() { var f64 = new Float64Array([-0]), f8b = new Uint8Array(f64.buffer), le = f8b[7] === 128; function writeDouble_f64_cpy(val, buf, pos) { f64[0] = val; buf[pos] = f8b[0]; buf[pos + 1] = f8b[1]; buf[pos + 2] = f8b[2]; buf[pos + 3] = f8b[3]; buf[pos + 4] = f8b[4]; buf[pos + 5] = f8b[5]; buf[pos + 6] = f8b[6]; buf[pos + 7] = f8b[7]; } function writeDouble_f64_rev(val, buf, pos) { f64[0] = val; buf[pos] = f8b[7]; buf[pos + 1] = f8b[6]; buf[pos + 2] = f8b[5]; buf[pos + 3] = f8b[4]; buf[pos + 4] = f8b[3]; buf[pos + 5] = f8b[2]; buf[pos + 6] = f8b[1]; buf[pos + 7] = f8b[0]; } exports3.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev; exports3.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy; function readDouble_f64_cpy(buf, pos) { f8b[0] = buf[pos]; f8b[1] = buf[pos + 1]; f8b[2] = buf[pos + 2]; f8b[3] = buf[pos + 3]; f8b[4] = buf[pos + 4]; f8b[5] = buf[pos + 5]; f8b[6] = buf[pos + 6]; f8b[7] = buf[pos + 7]; return f64[0]; } function readDouble_f64_rev(buf, pos) { f8b[7] = buf[pos]; f8b[6] = buf[pos + 1]; f8b[5] = buf[pos + 2]; f8b[4] = buf[pos + 3]; f8b[3] = buf[pos + 4]; f8b[2] = buf[pos + 5]; f8b[1] = buf[pos + 6]; f8b[0] = buf[pos + 7]; return f64[0]; } exports3.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev; exports3.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy; })(); else (function() { function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) { var sign3 = val < 0 ? 1 : 0; if (sign3) val = -val; if (val === 0) { writeUint(0, buf, pos + off0); writeUint(1 / val > 0 ? ( /* positive */ 0 ) : ( /* negative 0 */ 2147483648 ), buf, pos + off1); } else if (isNaN(val)) { writeUint(0, buf, pos + off0); writeUint(2146959360, buf, pos + off1); } else if (val > 17976931348623157e292) { writeUint(0, buf, pos + off0); writeUint((sign3 << 31 | 2146435072) >>> 0, buf, pos + off1); } else { var mantissa; if (val < 22250738585072014e-324) { mantissa = val / 5e-324; writeUint(mantissa >>> 0, buf, pos + off0); writeUint((sign3 << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1); } else { var exponent = Math.floor(Math.log(val) / Math.LN2); if (exponent === 1024) exponent = 1023; mantissa = val * Math.pow(2, -exponent); writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0); writeUint((sign3 << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1); } } } exports3.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4); exports3.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0); function readDouble_ieee754(readUint, off0, off1, buf, pos) { var lo = readUint(buf, pos + off0), hi = readUint(buf, pos + off1); var sign3 = (hi >> 31) * 2 + 1, exponent = hi >>> 20 & 2047, mantissa = 4294967296 * (hi & 1048575) + lo; return exponent === 2047 ? mantissa ? NaN : sign3 * Infinity : exponent === 0 ? sign3 * 5e-324 * mantissa : sign3 * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496); } exports3.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4); exports3.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0); })(); return exports3; } function writeUintLE(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } function writeUintBE(val, buf, pos) { buf[pos] = val >>> 24; buf[pos + 1] = val >>> 16 & 255; buf[pos + 2] = val >>> 8 & 255; buf[pos + 3] = val & 255; } function readUintLE(buf, pos) { return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16 | buf[pos + 3] << 24) >>> 0; } function readUintBE(buf, pos) { return (buf[pos] << 24 | buf[pos + 1] << 16 | buf[pos + 2] << 8 | buf[pos + 3]) >>> 0; } }, {}], 11: [function(require2, module2, exports2) { "use strict"; module2.exports = LongBits; var Long; function LongBits(lo, hi) { this.lo = lo >>> 0; this.hi = hi >>> 0; } var zero = LongBits.zero = new LongBits(0, 0); zero.toNumber = function() { return 0; }; zero.zzEncode = zero.zzDecode = function() { return this; }; zero.length = function() { return 1; }; var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0"; LongBits.fromNumber = function fromNumber(value) { if (value === 0) return zero; var sign3 = value < 0; if (sign3) value = -value; var lo = value >>> 0, hi = (value - lo) / 4294967296 >>> 0; if (sign3) { hi = ~hi >>> 0; lo = ~lo >>> 0; if (++lo > 4294967295) { lo = 0; if (++hi > 4294967295) hi = 0; } } return new LongBits(lo, hi); }; LongBits.from = function from(value) { if (typeof value === "number") return LongBits.fromNumber(value); if (typeof value === "string" || value instanceof String) { if (Long) value = Long.fromString(value); else return LongBits.fromNumber(parseInt(value, 10)); } return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero; }; LongBits.prototype.toNumber = function toNumber(unsigned) { if (!unsigned && this.hi >>> 31) { var lo = ~this.lo + 1 >>> 0, hi = ~this.hi >>> 0; if (!lo) hi = hi + 1 >>> 0; return -(lo + hi * 4294967296); } return this.lo + this.hi * 4294967296; }; LongBits.prototype.toLong = function toLong(unsigned) { return Long ? new Long(this.lo | 0, this.hi | 0, Boolean(unsigned)) : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) }; }; var charCodeAt = String.prototype.charCodeAt; LongBits.fromHash = function fromHash(hash2) { if (hash2 === zeroHash) return zero; return new LongBits( (charCodeAt.call(hash2, 0) | charCodeAt.call(hash2, 1) << 8 | charCodeAt.call(hash2, 2) << 16 | charCodeAt.call(hash2, 3) << 24) >>> 0, (charCodeAt.call(hash2, 4) | charCodeAt.call(hash2, 5) << 8 | charCodeAt.call(hash2, 6) << 16 | charCodeAt.call(hash2, 7) << 24) >>> 0 ); }; LongBits.prototype.toHash = function toHash() { return String.fromCharCode( this.lo & 255, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, this.hi & 255, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24 ); }; LongBits.prototype.zzEncode = function zzEncode() { var mask = this.hi >> 31; this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0; this.lo = (this.lo << 1 ^ mask) >>> 0; return this; }; LongBits.prototype.zzDecode = function zzDecode() { var mask = -(this.lo & 1); this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0; this.hi = (this.hi >>> 1 ^ mask) >>> 0; return this; }; LongBits.prototype.length = function length2() { var part0 = this.lo, part1 = (this.lo >>> 28 | this.hi << 4) >>> 0, part2 = this.hi >>> 24; return part2 === 0 ? part1 === 0 ? part0 < 16384 ? part0 < 128 ? 1 : 2 : part0 < 2097152 ? 3 : 4 : part1 < 16384 ? part1 < 128 ? 5 : 6 : part1 < 2097152 ? 7 : 8 : part2 < 128 ? 9 : 10; }; LongBits._configure = function(Long_) { Long = Long_; }; }, {}], 12: [function(require2, module2, exports2) { "use strict"; var util = exports2; util.asPromise = require2(7); util.base64 = require2(8); util.EventEmitter = require2(9); util.float = require2(10); util.utf8 = require2(14); util.pool = require2(13); util.LongBits = require2(11); function isUnsafeProperty(key) { return key === "__proto__" || key === "prototype" || key === "constructor"; } util.isUnsafeProperty = isUnsafeProperty; util.isNode = Boolean(typeof global !== "undefined" && global && global.process && global.process.versions && global.process.versions.node); util.global = util.isNode && global || typeof window !== "undefined" && window || typeof self !== "undefined" && self || typeof globalThis !== "undefined" && globalThis || this; util.emptyArray = Object.freeze ? Object.freeze([]) : ( /* istanbul ignore next */ [] ); util.emptyObject = Object.freeze ? Object.freeze({}) : ( /* istanbul ignore next */ {} ); util.isInteger = Number.isInteger || /* istanbul ignore next */ function isInteger(value) { return typeof value === "number" && isFinite(value) && Math.floor(value) === value; }; util.isString = function isString(value) { return typeof value === "string" || value instanceof String; }; util.isObject = function isObject(value) { return value && typeof value === "object"; }; util.isset = /** * Checks if a property on a message is considered to be present. * @param {Object} obj Plain object or message instance * @param {string} prop Property name * @returns {boolean} `true` if considered to be present, otherwise `false` */ util.isSet = function isSet(obj, prop) { var value = obj[prop]; if (value != null && Object.hasOwnProperty.call(obj, prop)) return typeof value !== "object" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0; return false; }; util.Buffer = (function() { try { var Buffer3 = util.global.Buffer; return Buffer3.prototype.utf8Write || util.isNode ? Buffer3 : ( /* istanbul ignore next */ null ); } catch (e) { return null; } })(); util.newBuffer = function newBuffer(sizeOrArray) { var Buffer3 = util.Buffer; return typeof sizeOrArray === "number" ? Buffer3 ? Buffer3.allocUnsafe(sizeOrArray) : new Uint8Array(sizeOrArray) : Buffer3 ? Buffer3.from(sizeOrArray) : new Uint8Array(sizeOrArray); }; util.rawField = function rawField(id, wireType, data) { var out = [], tag = id << 3 | wireType; tag >>>= 0; while (tag > 127) { out.push(tag & 127 | 128); tag >>>= 7; } out.push(tag); for (var i = 0; i < data.length; ++i) out.push(data[i]); return util.newBuffer(out); }; util.Array = Uint8Array; util.Long = /* istanbul ignore next */ util.global.dcodeIO && /* istanbul ignore next */ util.global.dcodeIO.Long || /* istanbul ignore next */ util.global.Long || (function() { try { var Long = require2("long"); return Long && Long.isLong ? Long : null; } catch (e) { return null; } })(); util.key2Re = /^(?:true|false|0|1)$/; util.key32Re = /^-?(?:0|[1-9][0-9]*)$/; util.key64Re = /^(?:[\x00-\xff]{8}|-?(?:0|[1-9][0-9]*))$/; util.longToHash = function longToHash(value) { return value ? util.LongBits.from(value).toHash() : util.LongBits.zeroHash; }; util.longFromHash = function longFromHash(hash2, unsigned) { var bits = util.LongBits.fromHash(hash2); if (util.Long) return util.Long.fromBits(bits.lo, bits.hi, unsigned); return bits.toNumber(Boolean(unsigned)); }; util.longFromKey = function longFromKey(key, unsigned) { return util.key64Re.test(key) && !util.key32Re.test(key) ? util.longFromHash(key, unsigned) : key; }; util.boolFromKey = function boolFromKey(key) { return key === "true" || key === "1"; }; function merge2(dst) { var ifNotSet = typeof arguments[arguments.length - 1] === "boolean", limit = ifNotSet ? arguments.length - 1 : arguments.length; ifNotSet = ifNotSet && arguments[arguments.length - 1]; for (var a3 = 1; a3 < limit; ++a3) { var src = arguments[a3]; if (!src) continue; for (var keys = Object.keys(src), i = 0; i < keys.length; ++i) if (!isUnsafeProperty(keys[i]) && (!ifNotSet || !Object.prototype.hasOwnProperty.call(dst, keys[i]) || dst[keys[i]] === undefined2)) dst[keys[i]] = src[keys[i]]; } return dst; } util.merge = merge2; util.nestingLimit = 32; util.recursionLimit = 100; util.makeProp = function makeProp(obj, key, enumerable) { if (Object.prototype.hasOwnProperty.call(obj, key)) return; Object.defineProperty(obj, key, { enumerable: enumerable === undefined2 ? true : enumerable, configurable: true, writable: true }); }; util.lcFirst = function lcFirst(str) { return str.charAt(0).toLowerCase() + str.substring(1); }; function newError(name) { function CustomError(message, properties) { if (!(this instanceof CustomError)) return new CustomError(message, properties); Object.defineProperty(this, "message", { get: function() { return message; } }); if (Error.captureStackTrace) Error.captureStackTrace(this, CustomError); else Object.defineProperty(this, "stack", { value: new Error().stack || "" }); if (properties) merge2(this, properties); } CustomError.prototype = Object.create(Error.prototype, { constructor: { value: CustomError, writable: true, enumerable: false, configurable: true }, name: { get: function get2() { return name; }, set: undefined2, enumerable: false, // configurable: false would accurately preserve the behavior of // the original, but I'm guessing that was not intentional. // For an actual error subclass, this property would // be configurable. configurable: true }, toString: { value: function value() { return this.name + ": " + this.message; }, writable: true, enumerable: false, configurable: true } }); return CustomError; } util.newError = newError; util.ProtocolError = newError("ProtocolError"); util.oneOfGetter = function getOneOf(fieldNames) { var fieldMap = {}; for (var i = 0; i < fieldNames.length; ++i) fieldMap[fieldNames[i]] = 1; return function() { for (var keys = Object.keys(this), i2 = keys.length - 1; i2 > -1; --i2) if (fieldMap[keys[i2]] === 1 && this[keys[i2]] !== undefined2 && this[keys[i2]] !== null) return keys[i2]; }; }; util.oneOfSetter = function setOneOf(fieldNames) { return function(name) { for (var i = 0; i < fieldNames.length; ++i) if (fieldNames[i] !== name) delete this[fieldNames[i]]; }; }; util.toJSONOptions = { longs: String, enums: String, bytes: String, json: true }; }, { "10": 10, "11": 11, "13": 13, "14": 14, "7": 7, "8": 8, "9": 9, "long": "long" }], 13: [function(require2, module2, exports2) { "use strict"; module2.exports = pool2; function pool2(alloc, slice, size) { var SIZE = size || 8192; var MAX = SIZE >>> 1; var slab = null; var offset = SIZE; return function pool_alloc(size2) { if (size2 < 1 || size2 > MAX) return alloc(size2); if (offset + size2 > SIZE) { slab = alloc(SIZE); offset = 0; } var buf = slice.call(slab, offset, offset += size2); if (offset & 7) offset = (offset | 7) + 1; return buf; }; } }, {}], 14: [function(require2, module2, exports2) { "use strict"; var utf8 = exports2, replacementChar = "\uFFFD", looseDecoder = new TextDecoder("utf-8", { ignoreBOM: true }), strictDecoder; var TEXT_DECODER_MIN_LENGTH = 64; try { strictDecoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }); } catch (err) { strictDecoder = looseDecoder; } utf8.length = function utf8_length(string) { var len = 0, c14 = 0; for (var i = 0; i < string.length; ++i) { c14 = string.charCodeAt(i); if (c14 < 128) len += 1; else if (c14 < 2048) len += 2; else if ((c14 & 64512) === 55296 && (string.charCodeAt(i + 1) & 64512) === 56320) { ++i; len += 4; } else len += 3; } return len; }; function utf8_read_js(buffer2, start, end, str) { for (var i = start; i < end; ) { var t2 = buffer2[i++]; if (t2 <= 127) { str += String.fromCharCode(t2); } else if (t2 >= 192 && t2 < 224) { var c22 = (t2 & 31) << 6 | buffer2[i++] & 63; str += c22 >= 128 ? String.fromCharCode(c22) : replacementChar; } else if (t2 >= 224 && t2 < 240) { var c33 = (t2 & 15) << 12 | (buffer2[i++] & 63) << 6 | buffer2[i++] & 63; str += c33 >= 2048 ? String.fromCharCode(c33) : replacementChar; } else if (t2 >= 240) { var t22 = (t2 & 7) << 18 | (buffer2[i++] & 63) << 12 | (buffer2[i++] & 63) << 6 | buffer2[i++] & 63; if (t22 < 65536 || t22 > 1114111) str += replacementChar; else { t22 -= 65536; str += String.fromCharCode(55296 + (t22 >> 10)); str += String.fromCharCode(56320 + (t22 & 1023)); } } } return str; } function utf8_read_decoder(decoder, buffer2, start, end) { var source = start === 0 && end === buffer2.length ? buffer2 : buffer2.subarray(start, end); return decoder.decode(source); } utf8.read = function utf8_read_loose(buffer2, start, end) { if (end - start < 1) return ""; if (end - start >= TEXT_DECODER_MIN_LENGTH) return utf8_read_decoder(looseDecoder, buffer2, start, end); var str = "", i = start, c14, c22, c33, c42, c52, c62, c72, c82; for (; i + 7 < end; i += 8) { c14 = buffer2[i]; c22 = buffer2[i + 1]; c33 = buffer2[i + 2]; c42 = buffer2[i + 3]; c52 = buffer2[i + 4]; c62 = buffer2[i + 5]; c72 = buffer2[i + 6]; c82 = buffer2[i + 7]; if ((c14 | c22 | c33 | c42 | c52 | c62 | c72 | c82) & 128) return utf8_read_js(buffer2, i, end, str); str += String.fromCharCode(c14, c22, c33, c42, c52, c62, c72, c82); } for (; i < end; ++i) { c14 = buffer2[i]; if (c14 & 128) return utf8_read_js(buffer2, i, end, str); str += String.fromCharCode(c14); } return str; }; utf8.readStrict = function utf8_read_strict(buffer2, start, end) { if (end - start < 1) return ""; if (end - start >= TEXT_DECODER_MIN_LENGTH) return utf8_read_decoder(strictDecoder, buffer2, start, end); var str = "", i = start, c14, c22, c33, c42, c52, c62, c72, c82; for (; i + 7 < end; i += 8) { c14 = buffer2[i]; c22 = buffer2[i + 1]; c33 = buffer2[i + 2]; c42 = buffer2[i + 3]; c52 = buffer2[i + 4]; c62 = buffer2[i + 5]; c72 = buffer2[i + 6]; c82 = buffer2[i + 7]; if ((c14 | c22 | c33 | c42 | c52 | c62 | c72 | c82) & 128) return str + utf8_read_decoder(strictDecoder, buffer2, i, end); str += String.fromCharCode(c14, c22, c33, c42, c52, c62, c72, c82); } for (; i < end; ++i) { c14 = buffer2[i]; if (c14 & 128) return str + utf8_read_decoder(strictDecoder, buffer2, i, end); str += String.fromCharCode(c14); } return str; }; utf8.write = function utf8_write(string, buffer2, offset) { var start = offset, c14, c22; for (var i = 0; i < string.length; ++i) { c14 = string.charCodeAt(i); if (c14 < 128) { buffer2[offset++] = c14; } else if (c14 < 2048) { buffer2[offset++] = c14 >> 6 | 192; buffer2[offset++] = c14 & 63 | 128; } else if ((c14 & 64512) === 55296 && ((c22 = string.charCodeAt(i + 1)) & 64512) === 56320) { c14 = 65536 + ((c14 & 1023) << 10) + (c22 & 1023); ++i; buffer2[offset++] = c14 >> 18 | 240; buffer2[offset++] = c14 >> 12 & 63 | 128; buffer2[offset++] = c14 >> 6 & 63 | 128; buffer2[offset++] = c14 & 63 | 128; } else { buffer2[offset++] = c14 >> 12 | 224; buffer2[offset++] = c14 >> 6 & 63 | 128; buffer2[offset++] = c14 & 63 | 128; } } return offset - start; }; }, {}], 15: [function(require2, module2, exports2) { "use strict"; module2.exports = Writer2; var util = require2(12); var BufferWriter; var LongBits = util.LongBits, base64 = util.base64, utf8 = util.utf8; function Writer2() { this.pos = 0; this.buf = this.constructor.alloc(64); this.view = null; this.states = null; } Object.defineProperty(Writer2.prototype, "len", { configurable: true, enumerable: true, get: function get_len() { return this.pos; } }); var create2 = function create3() { return util.Buffer ? function create_buffer_setup() { return (Writer2.create = function create_buffer() { return new BufferWriter(); })(); } : function create_array() { return new Writer2(); }; }; Writer2.create = create2(); Writer2.alloc = function alloc(size) { return new Uint8Array(size); }; Writer2.alloc = util.pool(Writer2.alloc, Uint8Array.prototype.subarray); function sizeVarint32(value) { return value < 128 ? 1 : value < 16384 ? 2 : value < 2097152 ? 3 : value < 268435456 ? 4 : 5; } Writer2.prototype._reserve = function _reserve(n2) { var need = this.pos + n2; if (need > this.buf.length) { var size = this.buf.length << 1; if (size < need) size = need; var buf = this.constructor.alloc(size); buf.set(this.buf.subarray(0, this.pos), 0); this.buf = buf; this.view = null; } }; function writeStringAscii(val, buf, pos) { for (var i = 0; i < val.length; ) buf[pos++] = val.charCodeAt(i++); } function writeVarint32(val, buf, pos) { while (val > 127) { buf[pos++] = val & 127 | 128; val >>>= 7; } buf[pos] = val; return pos + 1; } Writer2.prototype.uint32 = function write_uint32(value) { value = value >>> 0; this._reserve(5); var pos = this.pos; this.pos = writeVarint32(value, this.buf, pos); return this; }; Writer2.prototype.int32 = function write_int32(value) { if ((value |= 0) < 0) { this._reserve(10); writeVarint64(LongBits.fromNumber(value), this.buf, this.pos); this.pos += 10; return this; } return this.uint32(value); }; Writer2.prototype.sint32 = function write_sint32(value) { return this.uint32((value << 1 ^ value >> 31) >>> 0); }; function writeVarint64(val, buf, pos) { var lo = val.lo, hi = val.hi; while (hi) { buf[pos++] = lo & 127 | 128; lo = (lo >>> 7 | hi << 25) >>> 0; hi >>>= 7; } while (lo > 127) { buf[pos++] = lo & 127 | 128; lo = lo >>> 7; } buf[pos] = lo; return pos + 1; } Writer2.prototype.uint64 = function write_uint64(value) { var bits = LongBits.from(value); this._reserve(10); var pos = this.pos; this.pos = writeVarint64(bits, this.buf, pos); return this; }; Writer2.prototype.int64 = Writer2.prototype.uint64; Writer2.prototype.sint64 = function write_sint64(value) { var bits = LongBits.from(value).zzEncode(); this._reserve(10); var pos = this.pos; this.pos = writeVarint64(bits, this.buf, pos); return this; }; Writer2.prototype.bool = function write_bool(value) { this._reserve(1); this.buf[this.pos++] = value ? 1 : 0; return this; }; function writeFixed32(val, buf, pos) { buf[pos] = val & 255; buf[pos + 1] = val >>> 8 & 255; buf[pos + 2] = val >>> 16 & 255; buf[pos + 3] = val >>> 24; } Writer2.prototype.fixed32 = function write_fixed32(value) { this._reserve(4); writeFixed32(value >>> 0, this.buf, this.pos); this.pos += 4; return this; }; Writer2.prototype.sfixed32 = Writer2.prototype.fixed32; Writer2.prototype.fixed64 = function write_fixed64(value) { var bits = LongBits.from(value); this._reserve(8); writeFixed32(bits.lo, this.buf, this.pos); writeFixed32(bits.hi, this.buf, this.pos + 4); this.pos += 8; return this; }; Writer2.prototype.sfixed64 = Writer2.prototype.fixed64; Writer2.prototype.float = function write_float(value) { this._reserve(4); util.float.writeFloatLE(value, this.buf, this.pos); this.pos += 4; return this; }; Writer2.prototype.double = function write_double(value) { this._reserve(8); util.float.writeDoubleLE(value, this.buf, this.pos); this.pos += 8; return this; }; Writer2.prototype.bytes = function write_bytes(value) { var len = value.length >>> 0; if (!len) { this._reserve(1); this.buf[this.pos++] = 0; return this; } if (util.isString(value)) { var buf = Writer2.alloc(len = base64.length(value)); base64.decode(value, buf, 0); value = buf; } this.uint32(len); this._reserve(len); this.buf.set(value, this.pos); this.pos += len; return this; }; Writer2.prototype.raw = function write_raw(value) { var len = value.length >>> 0; if (!len) return this; this._reserve(len); this.buf.set(value, this.pos); this.pos += len; return this; }; Writer2.prototype._delim = function _delim(pos, len) { var n2 = sizeVarint32(len); if (n2 > 1) this.buf.copyWithin(pos + n2, pos + 1, pos + 1 + len); writeVarint32(len, this.buf, pos); this.pos = pos + n2 + len; return this; }; Writer2.prototype.string = function write_string(value) { var n2 = value.length; if (!n2) { this._reserve(1); this.buf[this.pos++] = 0; return this; } if (n2 < 128) { this._reserve(n2 * 3 + 5); var lenPos = this.pos; return this._delim(lenPos, utf8.write(value, this.buf, lenPos + 1)); } var len = utf8.length(value); this.uint32(len); this._reserve(len); if (len === value.length) writeStringAscii(value, this.buf, this.pos); else utf8.write(value, this.buf, this.pos); this.pos += len; return this; }; Writer2.prototype.uint32s = function write_uint32s(value) { var n2 = value.length; this._reserve(n2 * 5 + 5); var buf = this.buf, lenPos = this.pos, p = lenPos + 1; for (var i = 0; i < n2; ++i) p = writeVarint32(value[i] >>> 0, buf, p); return this._delim(lenPos, p - lenPos - 1); }; Writer2.prototype.int32s = function write_int32s(value) { var n2 = value.length; this._reserve(n2 * 10 + 5); var buf = this.buf, lenPos = this.pos, pos = lenPos + 1, val; for (var i = 0; i < n2; ++i) { if ((val = value[i] | 0) < 0) { pos = writeVarint64(LongBits.fromNumber(val), buf, pos); } else { pos = writeVarint32(val, buf, pos); } } return this._delim(lenPos, pos - lenPos - 1); }; Writer2.prototype.sint32s = function write_sint32s(value) { var n2 = value.length; this._reserve(n2 * 5 + 5); var buf = this.buf, lenPos = this.pos, pos = lenPos + 1; for (var i = 0; i < n2; ++i) pos = writeVarint32((value[i] << 1 ^ value[i] >> 31) >>> 0, buf, pos); return this._delim(lenPos, pos - lenPos - 1); }; Writer2.prototype.uint64s = function write_uint64s(value) { var n2 = value.length; this._reserve(n2 * 10 + 5); var buf = this.buf, lenPos = this.pos, pos = lenPos + 1; for (var i = 0; i < n2; ++i) { pos = writeVarint64(LongBits.from(value[i]), buf, pos); } return this._delim(lenPos, pos - lenPos - 1); }; Writer2.prototype.int64s = Writer2.prototype.uint64s; Writer2.prototype.sint64s = function write_sint64s(value) { var n2 = value.length; this._reserve(n2 * 10 + 5); var buf = this.buf, lenPos = this.pos, pos = lenPos + 1; for (var i = 0; i < n2; ++i) { pos = writeVarint64(LongBits.from(value[i]).zzEncode(), buf, pos); } return this._delim(lenPos, pos - lenPos - 1); }; Writer2.prototype.bools = function write_bools(value) { var n2 = value.length; this.uint32(n2); this._reserve(n2); var buf = this.buf, p = this.pos; for (var i = 0; i < n2; ++i) buf[p++] = value[i] ? 1 : 0; this.pos += n2; return this; }; var VIEW_THRESHOLD_FLOAT = 16, VIEW_THRESHOLD_INT = 128; function getLazyView(writer, count, threshold) { var view = writer.view; if (view || count < threshold) return view; var buf = writer.buf; return writer.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); } Writer2.prototype.fixed32s = function write_fixed32s(value) { var n2 = value.length, bytes = n2 * 4; this.uint32(bytes); this._reserve(bytes); var p = this.pos, i, dv = getLazyView(this, n2, VIEW_THRESHOLD_INT); if (dv) for (i = 0; i < n2; ++i) { dv.setUint32(p, value[i] >>> 0, true); p += 4; } else { var buf = this.buf; for (i = 0; i < n2; ++i) { writeFixed32(value[i] >>> 0, buf, p); p += 4; } } this.pos += bytes; return this; }; Writer2.prototype.sfixed32s = Writer2.prototype.fixed32s; Writer2.prototype.fixed64s = function write_fixed64s(value) { var n2 = value.length, bytes = n2 * 8; this.uint32(bytes); this._reserve(bytes); var p = this.pos, i, bits, dv = getLazyView(this, n2, VIEW_THRESHOLD_INT); if (dv) for (i = 0; i < n2; ++i) { bits = LongBits.from(value[i]); dv.setUint32(p, bits.lo, true); dv.setUint32(p + 4, bits.hi, true); p += 8; } else { var buf = this.buf; for (i = 0; i < n2; ++i) { bits = LongBits.from(value[i]); writeFixed32(bits.lo, buf, p); writeFixed32(bits.hi, buf, p + 4); p += 8; } } this.pos += bytes; return this; }; Writer2.prototype.sfixed64s = Writer2.prototype.fixed64s; Writer2.prototype.floats = function write_floats(value) { var n2 = value.length, bytes = n2 * 4; this.uint32(bytes); this._reserve(bytes); var p = this.pos, i, dv = getLazyView(this, n2, VIEW_THRESHOLD_FLOAT); if (dv) for (i = 0; i < n2; ++i) { dv.setFloat32(p, value[i], true); p += 4; } else { var buf = this.buf; for (i = 0; i < n2; ++i) { util.float.writeFloatLE(value[i], buf, p); p += 4; } } this.pos += bytes; return this; }; Writer2.prototype.doubles = function write_doubles(value) { var n2 = value.length, bytes = n2 * 8; this.uint32(bytes); this._reserve(bytes); var p = this.pos, i, dv = getLazyView(this, n2, VIEW_THRESHOLD_FLOAT); if (dv) for (i = 0; i < n2; ++i) { dv.setFloat64(p, value[i], true); p += 8; } else { var buf = this.buf; for (i = 0; i < n2; ++i) { util.float.writeDoubleLE(value[i], buf, p); p += 8; } } this.pos += bytes; return this; }; Writer2.prototype.fork = function fork() { this._reserve(1); (this.states || (this.states = [])).push(this.pos); this.pos += 1; return this; }; Writer2.prototype.reset = function reset2() { var states = this.states; if (states && states.length) { this.pos = states.pop(); } else { this.pos = 0; } return this; }; Writer2.prototype.ldelim = function ldelim() { var states = this.states, len, vlen; if (states && states.length) { var lenPos = states.pop(); len = this.pos - lenPos - 1; vlen = sizeVarint32(len); if (vlen > 1) { this._reserve(vlen - 1); this.buf.copyWithin(lenPos + vlen, lenPos + 1, lenPos + 1 + len); this.pos += vlen - 1; writeVarint32(len, this.buf, lenPos); } else { this.buf[lenPos] = len; } } else { len = this.pos; vlen = sizeVarint32(len); this._reserve(vlen); this.buf.copyWithin(vlen, 0, len); writeVarint32(len, this.buf, 0); this.pos += vlen; } return this; }; Writer2.prototype.finish = function finish(shared) { if (shared) return this.buf.subarray(0, this.pos); var buf = this.constructor.alloc(this.pos); buf.set(this.buf.subarray(0, this.pos), 0); return buf; }; Writer2.prototype.finishInto = function finishInto(buf, offset) { if (offset === undefined2) offset = 0; buf.set(this.buf.subarray(0, this.pos), offset); return buf; }; Writer2._configure = function(BufferWriter_) { BufferWriter = BufferWriter_; Writer2.create = create2(); BufferWriter._configure(); }; }, { "12": 12 }], 16: [function(require2, module2, exports2) { "use strict"; module2.exports = BufferWriter; var Writer2 = require2(15); BufferWriter.prototype = Object.create(Writer2.prototype, { constructor: { value: BufferWriter, writable: true, enumerable: false, configurable: true } }); var util = require2(12); function BufferWriter() { Writer2.call(this); } var writeStringBuffer; BufferWriter._configure = function() { BufferWriter.alloc = util.Buffer && util.Buffer.allocUnsafe; writeStringBuffer = util.Buffer && util.Buffer.prototype.utf8Write ? function writeStringBuffer_utf8Write(val, buf, pos) { return buf.utf8Write(val, pos); } : function writeStringBuffer_write(val, buf, pos) { return buf.write(val, pos); }; }; BufferWriter.prototype.bytes = function write_bytes_buffer(value) { if (util.isString(value)) value = util.Buffer.from(value, "base64"); var len = value.length >>> 0; this.uint32(len); if (len) { this._reserve(len); this.buf.set(value, this.pos); this.pos += len; } return this; }; BufferWriter.prototype.string = function write_string_buffer(value) { var n2 = value.length; if (!n2) { this._reserve(1); this.buf[this.pos++] = 0; return this; } if (n2 < 128) { this._reserve(n2 * 3 + 5); var pos = this.pos, buf = this.buf; return this._delim( pos, n2 < 40 ? util.utf8.write(value, buf, pos + 1) : writeStringBuffer(value, buf, pos + 1) ); } var len = util.Buffer.byteLength(value); this.uint32(len); this._reserve(len); writeStringBuffer(value, this.buf, this.pos); this.pos += len; return this; }; BufferWriter._configure(); }, { "12": 12, "15": 15 }] }, {}, [1]); })(); } }); // node_modules/lerc/LercDecode.js var require_LercDecode = __commonJS({ "node_modules/lerc/LercDecode.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); /* Copyright 2015-2018 Esri. 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 @preserve */ (function() { var LercDecode = (function() { var CntZImage = {}; CntZImage.defaultNoDataValue = -34027999387901484e22; CntZImage.decode = function(input, options) { options = options || {}; var skipMask = options.encodedMaskData || options.encodedMaskData === null; var parsedData = parse3(input, options.inputOffset || 0, skipMask); var noDataValue = options.noDataValue !== null ? options.noDataValue : CntZImage.defaultNoDataValue; var uncompressedData = uncompressPixelValues( parsedData, options.pixelType || Float32Array, options.encodedMaskData, noDataValue, options.returnMask ); var result = { width: parsedData.width, height: parsedData.height, pixelData: uncompressedData.resultPixels, minValue: uncompressedData.minValue, maxValue: parsedData.pixels.maxValue, noDataValue }; if (uncompressedData.resultMask) { result.maskData = uncompressedData.resultMask; } if (options.returnEncodedMask && parsedData.mask) { result.encodedMaskData = parsedData.mask.bitset ? parsedData.mask.bitset : null; } if (options.returnFileInfo) { result.fileInfo = formatFileInfo(parsedData); if (options.computeUsedBitDepths) { result.fileInfo.bitDepths = computeUsedBitDepths(parsedData); } } return result; }; var uncompressPixelValues = function(data, TypedArrayClass, maskBitset, noDataValue, storeDecodedMask) { var blockIdx = 0; var numX = data.pixels.numBlocksX; var numY = data.pixels.numBlocksY; var blockWidth = Math.floor(data.width / numX); var blockHeight = Math.floor(data.height / numY); var scale = 2 * data.maxZError; var minValue = Number.MAX_VALUE, currentValue; maskBitset = maskBitset || (data.mask ? data.mask.bitset : null); var resultPixels, resultMask; resultPixels = new TypedArrayClass(data.width * data.height); if (storeDecodedMask && maskBitset) { resultMask = new Uint8Array(data.width * data.height); } var blockDataBuffer = new Float32Array(blockWidth * blockHeight); var xx, yy; for (var y = 0; y <= numY; y++) { var thisBlockHeight = y !== numY ? blockHeight : data.height % numY; if (thisBlockHeight === 0) { continue; } for (var x = 0; x <= numX; x++) { var thisBlockWidth = x !== numX ? blockWidth : data.width % numX; if (thisBlockWidth === 0) { continue; } var outPtr = y * data.width * blockHeight + x * blockWidth; var outStride = data.width - thisBlockWidth; var block = data.pixels.blocks[blockIdx]; var blockData, blockPtr, constValue; if (block.encoding < 2) { if (block.encoding === 0) { blockData = block.rawData; } else { unstuff(block.stuffedData, block.bitsPerPixel, block.numValidPixels, block.offset, scale, blockDataBuffer, data.pixels.maxValue); blockData = blockDataBuffer; } blockPtr = 0; } else if (block.encoding === 2) { constValue = 0; } else { constValue = block.offset; } var maskByte; if (maskBitset) { for (yy = 0; yy < thisBlockHeight; yy++) { if (outPtr & 7) { maskByte = maskBitset[outPtr >> 3]; maskByte <<= outPtr & 7; } for (xx = 0; xx < thisBlockWidth; xx++) { if (!(outPtr & 7)) { maskByte = maskBitset[outPtr >> 3]; } if (maskByte & 128) { if (resultMask) { resultMask[outPtr] = 1; } currentValue = block.encoding < 2 ? blockData[blockPtr++] : constValue; minValue = minValue > currentValue ? currentValue : minValue; resultPixels[outPtr++] = currentValue; } else { if (resultMask) { resultMask[outPtr] = 0; } resultPixels[outPtr++] = noDataValue; } maskByte <<= 1; } outPtr += outStride; } } else { if (block.encoding < 2) { for (yy = 0; yy < thisBlockHeight; yy++) { for (xx = 0; xx < thisBlockWidth; xx++) { currentValue = blockData[blockPtr++]; minValue = minValue > currentValue ? currentValue : minValue; resultPixels[outPtr++] = currentValue; } outPtr += outStride; } } else { minValue = minValue > constValue ? constValue : minValue; for (yy = 0; yy < thisBlockHeight; yy++) { for (xx = 0; xx < thisBlockWidth; xx++) { resultPixels[outPtr++] = constValue; } outPtr += outStride; } } } if (block.encoding === 1 && blockPtr !== block.numValidPixels) { throw "Block and Mask do not match"; } blockIdx++; } } return { resultPixels, resultMask, minValue }; }; var formatFileInfo = function(data) { return { "fileIdentifierString": data.fileIdentifierString, "fileVersion": data.fileVersion, "imageType": data.imageType, "height": data.height, "width": data.width, "maxZError": data.maxZError, "eofOffset": data.eofOffset, "mask": data.mask ? { "numBlocksX": data.mask.numBlocksX, "numBlocksY": data.mask.numBlocksY, "numBytes": data.mask.numBytes, "maxValue": data.mask.maxValue } : null, "pixels": { "numBlocksX": data.pixels.numBlocksX, "numBlocksY": data.pixels.numBlocksY, "numBytes": data.pixels.numBytes, "maxValue": data.pixels.maxValue, "noDataValue": data.noDataValue } }; }; var computeUsedBitDepths = function(data) { var numBlocks = data.pixels.numBlocksX * data.pixels.numBlocksY; var bitDepths = {}; for (var i = 0; i < numBlocks; i++) { var block = data.pixels.blocks[i]; if (block.encoding === 0) { bitDepths.float32 = true; } else if (block.encoding === 1) { bitDepths[block.bitsPerPixel] = true; } else { bitDepths[0] = true; } } return Object.keys(bitDepths); }; var parse3 = function(input, fp, skipMask) { var data = {}; var fileIdView = new Uint8Array(input, fp, 10); data.fileIdentifierString = String.fromCharCode.apply(null, fileIdView); if (data.fileIdentifierString.trim() !== "CntZImage") { throw "Unexpected file identifier string: " + data.fileIdentifierString; } fp += 10; var view = new DataView(input, fp, 24); data.fileVersion = view.getInt32(0, true); data.imageType = view.getInt32(4, true); data.height = view.getUint32(8, true); data.width = view.getUint32(12, true); data.maxZError = view.getFloat64(16, true); fp += 24; if (!skipMask) { view = new DataView(input, fp, 16); data.mask = {}; data.mask.numBlocksY = view.getUint32(0, true); data.mask.numBlocksX = view.getUint32(4, true); data.mask.numBytes = view.getUint32(8, true); data.mask.maxValue = view.getFloat32(12, true); fp += 16; if (data.mask.numBytes > 0) { var bitset = new Uint8Array(Math.ceil(data.width * data.height / 8)); view = new DataView(input, fp, data.mask.numBytes); var cnt = view.getInt16(0, true); var ip = 2, op = 0; do { if (cnt > 0) { while (cnt--) { bitset[op++] = view.getUint8(ip++); } } else { var val = view.getUint8(ip++); cnt = -cnt; while (cnt--) { bitset[op++] = val; } } cnt = view.getInt16(ip, true); ip += 2; } while (ip < data.mask.numBytes); if (cnt !== -32768 || op < bitset.length) { throw "Unexpected end of mask RLE encoding"; } data.mask.bitset = bitset; fp += data.mask.numBytes; } else if ((data.mask.numBytes | data.mask.numBlocksY | data.mask.maxValue) === 0) { data.mask.bitset = new Uint8Array(Math.ceil(data.width * data.height / 8)); } } view = new DataView(input, fp, 16); data.pixels = {}; data.pixels.numBlocksY = view.getUint32(0, true); data.pixels.numBlocksX = view.getUint32(4, true); data.pixels.numBytes = view.getUint32(8, true); data.pixels.maxValue = view.getFloat32(12, true); fp += 16; var numBlocksX = data.pixels.numBlocksX; var numBlocksY = data.pixels.numBlocksY; var actualNumBlocksX = numBlocksX + (data.width % numBlocksX > 0 ? 1 : 0); var actualNumBlocksY = numBlocksY + (data.height % numBlocksY > 0 ? 1 : 0); data.pixels.blocks = new Array(actualNumBlocksX * actualNumBlocksY); var blockI = 0; for (var blockY = 0; blockY < actualNumBlocksY; blockY++) { for (var blockX = 0; blockX < actualNumBlocksX; blockX++) { var size = 0; var bytesLeft = input.byteLength - fp; view = new DataView(input, fp, Math.min(10, bytesLeft)); var block = {}; data.pixels.blocks[blockI++] = block; var headerByte = view.getUint8(0); size++; block.encoding = headerByte & 63; if (block.encoding > 3) { throw "Invalid block encoding (" + block.encoding + ")"; } if (block.encoding === 2) { fp++; continue; } if (headerByte !== 0 && headerByte !== 2) { headerByte >>= 6; block.offsetType = headerByte; if (headerByte === 2) { block.offset = view.getInt8(1); size++; } else if (headerByte === 1) { block.offset = view.getInt16(1, true); size += 2; } else if (headerByte === 0) { block.offset = view.getFloat32(1, true); size += 4; } else { throw "Invalid block offset type"; } if (block.encoding === 1) { headerByte = view.getUint8(size); size++; block.bitsPerPixel = headerByte & 63; headerByte >>= 6; block.numValidPixelsType = headerByte; if (headerByte === 2) { block.numValidPixels = view.getUint8(size); size++; } else if (headerByte === 1) { block.numValidPixels = view.getUint16(size, true); size += 2; } else if (headerByte === 0) { block.numValidPixels = view.getUint32(size, true); size += 4; } else { throw "Invalid valid pixel count type"; } } } fp += size; if (block.encoding === 3) { continue; } var arrayBuf, store8; if (block.encoding === 0) { var numPixels = (data.pixels.numBytes - 1) / 4; if (numPixels !== Math.floor(numPixels)) { throw "uncompressed block has invalid length"; } arrayBuf = new ArrayBuffer(numPixels * 4); store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, fp, numPixels * 4)); var rawData = new Float32Array(arrayBuf); block.rawData = rawData; fp += numPixels * 4; } else if (block.encoding === 1) { var dataBytes = Math.ceil(block.numValidPixels * block.bitsPerPixel / 8); var dataWords = Math.ceil(dataBytes / 4); arrayBuf = new ArrayBuffer(dataWords * 4); store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, fp, dataBytes)); block.stuffedData = new Uint32Array(arrayBuf); fp += dataBytes; } } } data.eofOffset = fp; return data; }; var unstuff = function(src, bitsPerPixel, numPixels, offset, scale, dest, maxValue) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o; var bitsLeft = 0; var n2, buffer2; var nmax = Math.ceil((maxValue - offset) / scale); var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8); src[src.length - 1] <<= 8 * numInvalidTailBytes; for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitsLeft - bitsPerPixel & bitMask; bitsLeft -= bitsPerPixel; } else { var missingBits = bitsPerPixel - bitsLeft; n2 = (buffer2 & bitMask) << missingBits & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 += buffer2 >>> bitsLeft; } dest[o] = n2 < nmax ? offset + n2 * scale : maxValue; } return dest; }; return CntZImage; })(); var Lerc2Decode = (function() { "use strict"; var BitStuffer = { //methods ending with 2 are for the new byte order used by Lerc2.3 and above. //originalUnstuff is used to unpack Huffman code table. code is duplicated to unstuffx for performance reasons. unstuff: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o; var bitsLeft = 0; var n2, buffer2, missingBits, nmax; var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8); src[src.length - 1] <<= 8 * numInvalidTailBytes; if (lutArr) { for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitsLeft - bitsPerPixel & bitMask; bitsLeft -= bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = (buffer2 & bitMask) << missingBits & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 += buffer2 >>> bitsLeft; } dest[o] = lutArr[n2]; } } else { nmax = Math.ceil((maxValue - offset) / scale); for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitsLeft - bitsPerPixel & bitMask; bitsLeft -= bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = (buffer2 & bitMask) << missingBits & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 += buffer2 >>> bitsLeft; } dest[o] = n2 < nmax ? offset + n2 * scale : maxValue; } } }, unstuffLUT: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n2 = 0; var buffer2; var dest = []; var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8); src[src.length - 1] <<= 8 * numInvalidTailBytes; var nmax = Math.ceil((maxValue - offset) / scale); for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitsLeft - bitsPerPixel & bitMask; bitsLeft -= bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = (buffer2 & bitMask) << missingBits & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 += buffer2 >>> bitsLeft; } dest[o] = n2 < nmax ? offset + n2 * scale : maxValue; } dest.unshift(offset); return dest; }, unstuff2: function(src, dest, bitsPerPixel, numPixels, lutArr, offset, scale, maxValue) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o; var bitsLeft = 0, bitPos = 0; var n2, buffer2, missingBits; if (lutArr) { for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; bitPos = 0; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitPos & bitMask; bitsLeft -= bitsPerPixel; bitPos += bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = buffer2 >>> bitPos & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 |= (buffer2 & (1 << missingBits) - 1) << bitsPerPixel - missingBits; bitPos = missingBits; } dest[o] = lutArr[n2]; } } else { var nmax = Math.ceil((maxValue - offset) / scale); for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; bitPos = 0; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitPos & bitMask; bitsLeft -= bitsPerPixel; bitPos += bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = buffer2 >>> bitPos & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 |= (buffer2 & (1 << missingBits) - 1) << bitsPerPixel - missingBits; bitPos = missingBits; } dest[o] = n2 < nmax ? offset + n2 * scale : maxValue; } } return dest; }, unstuffLUT2: function(src, bitsPerPixel, numPixels, offset, scale, maxValue) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o = 0, missingBits = 0, bitsLeft = 0, n2 = 0, bitPos = 0; var buffer2; var dest = []; var nmax = Math.ceil((maxValue - offset) / scale); for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; bitPos = 0; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitPos & bitMask; bitsLeft -= bitsPerPixel; bitPos += bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = buffer2 >>> bitPos & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 |= (buffer2 & (1 << missingBits) - 1) << bitsPerPixel - missingBits; bitPos = missingBits; } dest[o] = n2 < nmax ? offset + n2 * scale : maxValue; } dest.unshift(offset); return dest; }, originalUnstuff: function(src, dest, bitsPerPixel, numPixels) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o; var bitsLeft = 0; var n2, buffer2, missingBits; var numInvalidTailBytes = src.length * 4 - Math.ceil(bitsPerPixel * numPixels / 8); src[src.length - 1] <<= 8 * numInvalidTailBytes; for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitsLeft - bitsPerPixel & bitMask; bitsLeft -= bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = (buffer2 & bitMask) << missingBits & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 += buffer2 >>> bitsLeft; } dest[o] = n2; } return dest; }, originalUnstuff2: function(src, dest, bitsPerPixel, numPixels) { var bitMask = (1 << bitsPerPixel) - 1; var i = 0, o; var bitsLeft = 0, bitPos = 0; var n2, buffer2, missingBits; for (o = 0; o < numPixels; o++) { if (bitsLeft === 0) { buffer2 = src[i++]; bitsLeft = 32; bitPos = 0; } if (bitsLeft >= bitsPerPixel) { n2 = buffer2 >>> bitPos & bitMask; bitsLeft -= bitsPerPixel; bitPos += bitsPerPixel; } else { missingBits = bitsPerPixel - bitsLeft; n2 = buffer2 >>> bitPos & bitMask; buffer2 = src[i++]; bitsLeft = 32 - missingBits; n2 |= (buffer2 & (1 << missingBits) - 1) << bitsPerPixel - missingBits; bitPos = missingBits; } dest[o] = n2; } return dest; } }; var Lerc2Helpers = { HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, treat it like constant computeChecksumFletcher32: function(input) { var sum1 = 65535, sum2 = 65535; var len = input.length; var words = Math.floor(len / 2); var i = 0; while (words) { var tlen = words >= 359 ? 359 : words; words -= tlen; do { sum1 += input[i++] << 8; sum2 += sum1 += input[i++]; } while (--tlen); sum1 = (sum1 & 65535) + (sum1 >>> 16); sum2 = (sum2 & 65535) + (sum2 >>> 16); } if (len & 1) { sum2 += sum1 += input[i] << 8; } sum1 = (sum1 & 65535) + (sum1 >>> 16); sum2 = (sum2 & 65535) + (sum2 >>> 16); return (sum2 << 16 | sum1) >>> 0; }, readHeaderInfo: function(input, data) { var ptr = data.ptr; var fileIdView = new Uint8Array(input, ptr, 6); var headerInfo = {}; headerInfo.fileIdentifierString = String.fromCharCode.apply(null, fileIdView); if (headerInfo.fileIdentifierString.lastIndexOf("Lerc2", 0) !== 0) { throw "Unexpected file identifier string (expect Lerc2 ): " + headerInfo.fileIdentifierString; } ptr += 6; var view = new DataView(input, ptr, 8); var fileVersion = view.getInt32(0, true); headerInfo.fileVersion = fileVersion; ptr += 4; if (fileVersion >= 3) { headerInfo.checksum = view.getUint32(4, true); ptr += 4; } view = new DataView(input, ptr, 12); headerInfo.height = view.getUint32(0, true); headerInfo.width = view.getUint32(4, true); ptr += 8; if (fileVersion >= 4) { headerInfo.numDims = view.getUint32(8, true); ptr += 4; } else { headerInfo.numDims = 1; } view = new DataView(input, ptr, 40); headerInfo.numValidPixel = view.getUint32(0, true); headerInfo.microBlockSize = view.getInt32(4, true); headerInfo.blobSize = view.getInt32(8, true); headerInfo.imageType = view.getInt32(12, true); headerInfo.maxZError = view.getFloat64(16, true); headerInfo.zMin = view.getFloat64(24, true); headerInfo.zMax = view.getFloat64(32, true); ptr += 40; data.headerInfo = headerInfo; data.ptr = ptr; var checksum, keyLength; if (fileVersion >= 3) { keyLength = fileVersion >= 4 ? 52 : 48; checksum = this.computeChecksumFletcher32(new Uint8Array(input, ptr - keyLength, headerInfo.blobSize - 14)); if (checksum !== headerInfo.checksum) { throw "Checksum failed."; } } return true; }, checkMinMaxRanges: function(input, data) { var headerInfo = data.headerInfo; var OutPixelTypeArray = this.getDataTypeArray(headerInfo.imageType); var rangeBytes = headerInfo.numDims * this.getDataTypeSize(headerInfo.imageType); var minValues = this.readSubArray(input, data.ptr, OutPixelTypeArray, rangeBytes); var maxValues = this.readSubArray(input, data.ptr + rangeBytes, OutPixelTypeArray, rangeBytes); data.ptr += 2 * rangeBytes; var i, equal = true; for (i = 0; i < headerInfo.numDims; i++) { if (minValues[i] !== maxValues[i]) { equal = false; break; } } headerInfo.minValues = minValues; headerInfo.maxValues = maxValues; return equal; }, readSubArray: function(input, ptr, OutPixelTypeArray, numBytes) { var rawData; if (OutPixelTypeArray === Uint8Array) { rawData = new Uint8Array(input, ptr, numBytes); } else { var arrayBuf = new ArrayBuffer(numBytes); var store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, ptr, numBytes)); rawData = new OutPixelTypeArray(arrayBuf); } return rawData; }, readMask: function(input, data) { var ptr = data.ptr; var headerInfo = data.headerInfo; var numPixels = headerInfo.width * headerInfo.height; var numValidPixel = headerInfo.numValidPixel; var view = new DataView(input, ptr, 4); var mask = {}; mask.numBytes = view.getUint32(0, true); ptr += 4; if ((0 === numValidPixel || numPixels === numValidPixel) && 0 !== mask.numBytes) { throw "invalid mask"; } var bitset, resultMask; if (numValidPixel === 0) { bitset = new Uint8Array(Math.ceil(numPixels / 8)); mask.bitset = bitset; resultMask = new Uint8Array(numPixels); data.pixels.resultMask = resultMask; ptr += mask.numBytes; } else if (mask.numBytes > 0) { bitset = new Uint8Array(Math.ceil(numPixels / 8)); view = new DataView(input, ptr, mask.numBytes); var cnt = view.getInt16(0, true); var ip = 2, op = 0, val = 0; do { if (cnt > 0) { while (cnt--) { bitset[op++] = view.getUint8(ip++); } } else { val = view.getUint8(ip++); cnt = -cnt; while (cnt--) { bitset[op++] = val; } } cnt = view.getInt16(ip, true); ip += 2; } while (ip < mask.numBytes); if (cnt !== -32768 || op < bitset.length) { throw "Unexpected end of mask RLE encoding"; } resultMask = new Uint8Array(numPixels); var mb = 0, k = 0; for (k = 0; k < numPixels; k++) { if (k & 7) { mb = bitset[k >> 3]; mb <<= k & 7; } else { mb = bitset[k >> 3]; } if (mb & 128) { resultMask[k] = 1; } } data.pixels.resultMask = resultMask; mask.bitset = bitset; ptr += mask.numBytes; } data.ptr = ptr; data.mask = mask; return true; }, readDataOneSweep: function(input, data, OutPixelTypeArray) { var ptr = data.ptr; var headerInfo = data.headerInfo; var numDims = headerInfo.numDims; var numPixels = headerInfo.width * headerInfo.height; var imageType = headerInfo.imageType; var numBytes = headerInfo.numValidPixel * Lerc2Helpers.getDataTypeSize(imageType) * numDims; var rawData; var mask = data.pixels.resultMask; if (OutPixelTypeArray === Uint8Array) { rawData = new Uint8Array(input, ptr, numBytes); } else { var arrayBuf = new ArrayBuffer(numBytes); var store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, ptr, numBytes)); rawData = new OutPixelTypeArray(arrayBuf); } if (rawData.length === numPixels * numDims) { data.pixels.resultPixels = rawData; } else { data.pixels.resultPixels = new OutPixelTypeArray(numPixels * numDims); var z2 = 0, k = 0, i = 0, nStart = 0; if (numDims > 1) { for (i = 0; i < numDims; i++) { nStart = i * numPixels; for (k = 0; k < numPixels; k++) { if (mask[k]) { data.pixels.resultPixels[nStart + k] = rawData[z2++]; } } } } else { for (k = 0; k < numPixels; k++) { if (mask[k]) { data.pixels.resultPixels[k] = rawData[z2++]; } } } } ptr += numBytes; data.ptr = ptr; return true; }, readHuffmanTree: function(input, data) { var BITS_MAX = this.HUFFMAN_LUT_BITS_MAX; var view = new DataView(input, data.ptr, 16); data.ptr += 16; var version2 = view.getInt32(0, true); if (version2 < 2) { throw "unsupported Huffman version"; } var size = view.getInt32(4, true); var i0 = view.getInt32(8, true); var i1 = view.getInt32(12, true); if (i0 >= i1) { return false; } var blockDataBuffer = new Uint32Array(i1 - i0); Lerc2Helpers.decodeBits(input, data, blockDataBuffer); var codeTable = []; var i, j, k, len; for (i = i0; i < i1; i++) { j = i - (i < size ? 0 : size); codeTable[j] = { first: blockDataBuffer[i - i0], second: null }; } var dataBytes = input.byteLength - data.ptr; var dataWords = Math.ceil(dataBytes / 4); var arrayBuf = new ArrayBuffer(dataWords * 4); var store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, data.ptr, dataBytes)); var stuffedData = new Uint32Array(arrayBuf); var bitPos = 0, word, srcPtr = 0; word = stuffedData[0]; for (i = i0; i < i1; i++) { j = i - (i < size ? 0 : size); len = codeTable[j].first; if (len > 0) { codeTable[j].second = word << bitPos >>> 32 - len; if (32 - bitPos >= len) { bitPos += len; if (bitPos === 32) { bitPos = 0; srcPtr++; word = stuffedData[srcPtr]; } } else { bitPos += len - 32; srcPtr++; word = stuffedData[srcPtr]; codeTable[j].second |= word >>> 32 - bitPos; } } } var numBitsLUT = 0, numBitsLUTQick = 0; var tree = new TreeNode(); for (i = 0; i < codeTable.length; i++) { if (codeTable[i] !== void 0) { numBitsLUT = Math.max(numBitsLUT, codeTable[i].first); } } if (numBitsLUT >= BITS_MAX) { numBitsLUTQick = BITS_MAX; } else { numBitsLUTQick = numBitsLUT; } if (numBitsLUT >= 30) { console.log("WARning, large NUM LUT BITS IS " + numBitsLUT); } var decodeLut = [], entry, code, numEntries, jj, currentBit, node; for (i = i0; i < i1; i++) { j = i - (i < size ? 0 : size); len = codeTable[j].first; if (len > 0) { entry = [len, j]; if (len <= numBitsLUTQick) { code = codeTable[j].second << numBitsLUTQick - len; numEntries = 1 << numBitsLUTQick - len; for (k = 0; k < numEntries; k++) { decodeLut[code | k] = entry; } } else { code = codeTable[j].second; node = tree; for (jj = len - 1; jj >= 0; jj--) { currentBit = code >>> jj & 1; if (currentBit) { if (!node.right) { node.right = new TreeNode(); } node = node.right; } else { if (!node.left) { node.left = new TreeNode(); } node = node.left; } if (jj === 0 && !node.val) { node.val = entry[1]; } } } } } return { decodeLut, numBitsLUTQick, numBitsLUT, tree, stuffedData, srcPtr, bitPos }; }, readHuffman: function(input, data, OutPixelTypeArray) { var headerInfo = data.headerInfo; var numDims = headerInfo.numDims; var height = data.headerInfo.height; var width = data.headerInfo.width; var numPixels = width * height; var huffmanInfo = this.readHuffmanTree(input, data); var decodeLut = huffmanInfo.decodeLut; var tree = huffmanInfo.tree; var stuffedData = huffmanInfo.stuffedData; var srcPtr = huffmanInfo.srcPtr; var bitPos = huffmanInfo.bitPos; var numBitsLUTQick = huffmanInfo.numBitsLUTQick; var numBitsLUT = huffmanInfo.numBitsLUT; var offset = data.headerInfo.imageType === 0 ? 128 : 0; var node, val, delta, mask = data.pixels.resultMask, valTmp, valTmpQuick, currentBit; var i, j, k, ii; var prevVal = 0; if (bitPos > 0) { srcPtr++; bitPos = 0; } var word = stuffedData[srcPtr]; var deltaEncode = data.encodeMode === 1; var resultPixelsAllDim = new OutPixelTypeArray(numPixels * numDims); var resultPixels = resultPixelsAllDim; var iDim; for (iDim = 0; iDim < headerInfo.numDims; iDim++) { if (numDims > 1) { resultPixels = new OutPixelTypeArray(resultPixelsAllDim.buffer, numPixels * iDim, numPixels); prevVal = 0; } if (data.headerInfo.numValidPixel === width * height) { for (k = 0, i = 0; i < height; i++) { for (j = 0; j < width; j++, k++) { val = 0; valTmp = word << bitPos >>> 32 - numBitsLUTQick; valTmpQuick = valTmp; if (32 - bitPos < numBitsLUTQick) { valTmp |= stuffedData[srcPtr + 1] >>> 64 - bitPos - numBitsLUTQick; valTmpQuick = valTmp; } if (decodeLut[valTmpQuick]) { val = decodeLut[valTmpQuick][1]; bitPos += decodeLut[valTmpQuick][0]; } else { valTmp = word << bitPos >>> 32 - numBitsLUT; valTmpQuick = valTmp; if (32 - bitPos < numBitsLUT) { valTmp |= stuffedData[srcPtr + 1] >>> 64 - bitPos - numBitsLUT; valTmpQuick = valTmp; } node = tree; for (ii = 0; ii < numBitsLUT; ii++) { currentBit = valTmp >>> numBitsLUT - ii - 1 & 1; node = currentBit ? node.right : node.left; if (!(node.left || node.right)) { val = node.val; bitPos = bitPos + ii + 1; break; } } } if (bitPos >= 32) { bitPos -= 32; srcPtr++; word = stuffedData[srcPtr]; } delta = val - offset; if (deltaEncode) { if (j > 0) { delta += prevVal; } else if (i > 0) { delta += resultPixels[k - width]; } else { delta += prevVal; } delta &= 255; resultPixels[k] = delta; prevVal = delta; } else { resultPixels[k] = delta; } } } } else { for (k = 0, i = 0; i < height; i++) { for (j = 0; j < width; j++, k++) { if (mask[k]) { val = 0; valTmp = word << bitPos >>> 32 - numBitsLUTQick; valTmpQuick = valTmp; if (32 - bitPos < numBitsLUTQick) { valTmp |= stuffedData[srcPtr + 1] >>> 64 - bitPos - numBitsLUTQick; valTmpQuick = valTmp; } if (decodeLut[valTmpQuick]) { val = decodeLut[valTmpQuick][1]; bitPos += decodeLut[valTmpQuick][0]; } else { valTmp = word << bitPos >>> 32 - numBitsLUT; valTmpQuick = valTmp; if (32 - bitPos < numBitsLUT) { valTmp |= stuffedData[srcPtr + 1] >>> 64 - bitPos - numBitsLUT; valTmpQuick = valTmp; } node = tree; for (ii = 0; ii < numBitsLUT; ii++) { currentBit = valTmp >>> numBitsLUT - ii - 1 & 1; node = currentBit ? node.right : node.left; if (!(node.left || node.right)) { val = node.val; bitPos = bitPos + ii + 1; break; } } } if (bitPos >= 32) { bitPos -= 32; srcPtr++; word = stuffedData[srcPtr]; } delta = val - offset; if (deltaEncode) { if (j > 0 && mask[k - 1]) { delta += prevVal; } else if (i > 0 && mask[k - width]) { delta += resultPixels[k - width]; } else { delta += prevVal; } delta &= 255; resultPixels[k] = delta; prevVal = delta; } else { resultPixels[k] = delta; } } } } } data.ptr = data.ptr + (srcPtr + 1) * 4 + (bitPos > 0 ? 4 : 0); } data.pixels.resultPixels = resultPixelsAllDim; }, decodeBits: function(input, data, blockDataBuffer, offset, iDim) { { var headerInfo = data.headerInfo; var fileVersion = headerInfo.fileVersion; var blockPtr = 0; var view = new DataView(input, data.ptr, 5); var headerByte = view.getUint8(0); blockPtr++; var bits67 = headerByte >> 6; var n2 = bits67 === 0 ? 4 : 3 - bits67; var doLut = (headerByte & 32) > 0 ? true : false; var numBits = headerByte & 31; var numElements = 0; if (n2 === 1) { numElements = view.getUint8(blockPtr); blockPtr++; } else if (n2 === 2) { numElements = view.getUint16(blockPtr, true); blockPtr += 2; } else if (n2 === 4) { numElements = view.getUint32(blockPtr, true); blockPtr += 4; } else { throw "Invalid valid pixel count type"; } var scale = 2 * headerInfo.maxZError; var stuffedData, arrayBuf, store8, dataBytes, dataWords; var lutArr, lutData, lutBytes, lutBitsPerElement, bitsPerPixel; var zMax = headerInfo.numDims > 1 ? headerInfo.maxValues[iDim] : headerInfo.zMax; if (doLut) { data.counter.lut++; lutBytes = view.getUint8(blockPtr); lutBitsPerElement = numBits; blockPtr++; dataBytes = Math.ceil((lutBytes - 1) * numBits / 8); dataWords = Math.ceil(dataBytes / 4); arrayBuf = new ArrayBuffer(dataWords * 4); store8 = new Uint8Array(arrayBuf); data.ptr += blockPtr; store8.set(new Uint8Array(input, data.ptr, dataBytes)); lutData = new Uint32Array(arrayBuf); data.ptr += dataBytes; bitsPerPixel = 0; while (lutBytes - 1 >>> bitsPerPixel) { bitsPerPixel++; } dataBytes = Math.ceil(numElements * bitsPerPixel / 8); dataWords = Math.ceil(dataBytes / 4); arrayBuf = new ArrayBuffer(dataWords * 4); store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, data.ptr, dataBytes)); stuffedData = new Uint32Array(arrayBuf); data.ptr += dataBytes; if (fileVersion >= 3) { lutArr = BitStuffer.unstuffLUT2(lutData, numBits, lutBytes - 1, offset, scale, zMax); } else { lutArr = BitStuffer.unstuffLUT(lutData, numBits, lutBytes - 1, offset, scale, zMax); } if (fileVersion >= 3) { BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr); } else { BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, lutArr); } } else { data.counter.bitstuffer++; bitsPerPixel = numBits; data.ptr += blockPtr; if (bitsPerPixel > 0) { dataBytes = Math.ceil(numElements * bitsPerPixel / 8); dataWords = Math.ceil(dataBytes / 4); arrayBuf = new ArrayBuffer(dataWords * 4); store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, data.ptr, dataBytes)); stuffedData = new Uint32Array(arrayBuf); data.ptr += dataBytes; if (fileVersion >= 3) { if (offset == null) { BitStuffer.originalUnstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements); } else { BitStuffer.unstuff2(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax); } } else { if (offset == null) { BitStuffer.originalUnstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements); } else { BitStuffer.unstuff(stuffedData, blockDataBuffer, bitsPerPixel, numElements, false, offset, scale, zMax); } } } } } }, readTiles: function(input, data, OutPixelTypeArray) { var headerInfo = data.headerInfo; var width = headerInfo.width; var height = headerInfo.height; var microBlockSize = headerInfo.microBlockSize; var imageType = headerInfo.imageType; var dataTypeSize = Lerc2Helpers.getDataTypeSize(imageType); var numBlocksX = Math.ceil(width / microBlockSize); var numBlocksY = Math.ceil(height / microBlockSize); data.pixels.numBlocksY = numBlocksY; data.pixels.numBlocksX = numBlocksX; data.pixels.ptr = 0; var row = 0, col = 0, blockY = 0, blockX = 0, thisBlockHeight = 0, thisBlockWidth = 0, bytesLeft = 0, headerByte = 0, bits67 = 0, testCode = 0, outPtr = 0, outStride = 0, numBytes = 0, bytesleft = 0, z2 = 0, blockPtr = 0; var view, block, arrayBuf, store8, rawData; var blockEncoding; var blockDataBuffer = new OutPixelTypeArray(microBlockSize * microBlockSize); var lastBlockHeight = height % microBlockSize || microBlockSize; var lastBlockWidth = width % microBlockSize || microBlockSize; var offsetType, offset; var numDims = headerInfo.numDims, iDim; var mask = data.pixels.resultMask; var resultPixels = data.pixels.resultPixels; for (blockY = 0; blockY < numBlocksY; blockY++) { thisBlockHeight = blockY !== numBlocksY - 1 ? microBlockSize : lastBlockHeight; for (blockX = 0; blockX < numBlocksX; blockX++) { thisBlockWidth = blockX !== numBlocksX - 1 ? microBlockSize : lastBlockWidth; outPtr = blockY * width * microBlockSize + blockX * microBlockSize; outStride = width - thisBlockWidth; for (iDim = 0; iDim < numDims; iDim++) { if (numDims > 1) { resultPixels = new OutPixelTypeArray(data.pixels.resultPixels.buffer, width * height * iDim * dataTypeSize, width * height); } bytesLeft = input.byteLength - data.ptr; view = new DataView(input, data.ptr, Math.min(10, bytesLeft)); block = {}; blockPtr = 0; headerByte = view.getUint8(0); blockPtr++; bits67 = headerByte >> 6 & 255; testCode = headerByte >> 2 & 15; if (testCode !== (blockX * microBlockSize >> 3 & 15)) { throw "integrity issue"; } blockEncoding = headerByte & 3; if (blockEncoding > 3) { data.ptr += blockPtr; throw "Invalid block encoding (" + blockEncoding + ")"; } else if (blockEncoding === 2) { data.counter.constant++; data.ptr += blockPtr; continue; } else if (blockEncoding === 0) { data.counter.uncompressed++; data.ptr += blockPtr; numBytes = thisBlockHeight * thisBlockWidth * dataTypeSize; bytesleft = input.byteLength - data.ptr; numBytes = numBytes < bytesleft ? numBytes : bytesleft; arrayBuf = new ArrayBuffer(numBytes % dataTypeSize === 0 ? numBytes : numBytes + dataTypeSize - numBytes % dataTypeSize); store8 = new Uint8Array(arrayBuf); store8.set(new Uint8Array(input, data.ptr, numBytes)); rawData = new OutPixelTypeArray(arrayBuf); z2 = 0; if (mask) { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { if (mask[outPtr]) { resultPixels[outPtr] = rawData[z2++]; } outPtr++; } outPtr += outStride; } } else { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { resultPixels[outPtr++] = rawData[z2++]; } outPtr += outStride; } } data.ptr += z2 * dataTypeSize; } else { offsetType = Lerc2Helpers.getDataTypeUsed(imageType, bits67); offset = Lerc2Helpers.getOnePixel(block, blockPtr, offsetType, view); blockPtr += Lerc2Helpers.getDataTypeSize(offsetType); if (blockEncoding === 3) { data.ptr += blockPtr; data.counter.constantoffset++; if (mask) { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { if (mask[outPtr]) { resultPixels[outPtr] = offset; } outPtr++; } outPtr += outStride; } } else { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { resultPixels[outPtr++] = offset; } outPtr += outStride; } } } else { data.ptr += blockPtr; Lerc2Helpers.decodeBits(input, data, blockDataBuffer, offset, iDim); blockPtr = 0; if (mask) { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { if (mask[outPtr]) { resultPixels[outPtr] = blockDataBuffer[blockPtr++]; } outPtr++; } outPtr += outStride; } } else { for (row = 0; row < thisBlockHeight; row++) { for (col = 0; col < thisBlockWidth; col++) { resultPixels[outPtr++] = blockDataBuffer[blockPtr++]; } outPtr += outStride; } } } } } } } }, /***************** * private methods (helper methods) *****************/ formatFileInfo: function(data) { return { "fileIdentifierString": data.headerInfo.fileIdentifierString, "fileVersion": data.headerInfo.fileVersion, "imageType": data.headerInfo.imageType, "height": data.headerInfo.height, "width": data.headerInfo.width, "numValidPixel": data.headerInfo.numValidPixel, "microBlockSize": data.headerInfo.microBlockSize, "blobSize": data.headerInfo.blobSize, "maxZError": data.headerInfo.maxZError, "pixelType": Lerc2Helpers.getPixelType(data.headerInfo.imageType), "eofOffset": data.eofOffset, "mask": data.mask ? { "numBytes": data.mask.numBytes } : null, "pixels": { "numBlocksX": data.pixels.numBlocksX, "numBlocksY": data.pixels.numBlocksY, //"numBytes": data.pixels.numBytes, "maxValue": data.headerInfo.zMax, "minValue": data.headerInfo.zMin, "noDataValue": data.noDataValue } }; }, constructConstantSurface: function(data) { var val = data.headerInfo.zMax; var numDims = data.headerInfo.numDims; var numPixels = data.headerInfo.height * data.headerInfo.width; var numPixelAllDims = numPixels * numDims; var i = 0, k = 0, nStart = 0; var mask = data.pixels.resultMask; if (mask) { if (numDims > 1) { for (i = 0; i < numDims; i++) { nStart = i * numPixels; for (k = 0; k < numPixels; k++) { if (mask[k]) { data.pixels.resultPixels[nStart + k] = val; } } } } else { for (k = 0; k < numPixels; k++) { if (mask[k]) { data.pixels.resultPixels[k] = val; } } } } else { if (data.pixels.resultPixels.fill) { data.pixels.resultPixels.fill(val); } else { for (k = 0; k < numPixelAllDims; k++) { data.pixels.resultPixels[k] = val; } } } return; }, getDataTypeArray: function(t2) { var tp; switch (t2) { case 0: tp = Int8Array; break; case 1: tp = Uint8Array; break; case 2: tp = Int16Array; break; case 3: tp = Uint16Array; break; case 4: tp = Int32Array; break; case 5: tp = Uint32Array; break; case 6: tp = Float32Array; break; case 7: tp = Float64Array; break; default: tp = Float32Array; } return tp; }, getPixelType: function(t2) { var tp; switch (t2) { case 0: tp = "S8"; break; case 1: tp = "U8"; break; case 2: tp = "S16"; break; case 3: tp = "U16"; break; case 4: tp = "S32"; break; case 5: tp = "U32"; break; case 6: tp = "F32"; break; case 7: tp = "F64"; break; default: tp = "F32"; } return tp; }, isValidPixelValue: function(t2, val) { if (val == null) { return false; } var isValid; switch (t2) { case 0: isValid = val >= -128 && val <= 127; break; case 1: isValid = val >= 0 && val <= 255; break; case 2: isValid = val >= -32768 && val <= 32767; break; case 3: isValid = val >= 0 && val <= 65536; break; case 4: isValid = val >= -2147483648 && val <= 2147483647; break; case 5: isValid = val >= 0 && val <= 4294967296; break; case 6: isValid = val >= -34027999387901484e22 && val <= 34027999387901484e22; break; case 7: isValid = val >= 5e-324 && val <= 17976931348623157e292; break; default: isValid = false; } return isValid; }, getDataTypeSize: function(t2) { var s2 = 0; switch (t2) { case 0: //ubyte case 1: s2 = 1; break; case 2: //short case 3: s2 = 2; break; case 4: case 5: case 6: s2 = 4; break; case 7: s2 = 8; break; default: s2 = t2; } return s2; }, getDataTypeUsed: function(dt, tc) { var t2 = dt; switch (dt) { case 2: //short case 4: t2 = dt - tc; break; case 3: //ushort case 5: t2 = dt - 2 * tc; break; case 6: if (0 === tc) { t2 = dt; } else if (1 === tc) { t2 = 2; } else { t2 = 1; } break; case 7: if (0 === tc) { t2 = dt; } else { t2 = dt - 2 * tc + 1; } break; default: t2 = dt; break; } return t2; }, getOnePixel: function(block, blockPtr, offsetType, view) { var temp = 0; switch (offsetType) { case 0: temp = view.getInt8(blockPtr); break; case 1: temp = view.getUint8(blockPtr); break; case 2: temp = view.getInt16(blockPtr, true); break; case 3: temp = view.getUint16(blockPtr, true); break; case 4: temp = view.getInt32(blockPtr, true); break; case 5: temp = view.getUInt32(blockPtr, true); break; case 6: temp = view.getFloat32(blockPtr, true); break; case 7: temp = view.getFloat64(blockPtr, true); break; default: throw "the decoder does not understand this pixel type"; } return temp; } }; var TreeNode = function(val, left, right) { this.val = val; this.left = left; this.right = right; }; var Lerc2Decode2 = { /* * ********removed options compared to LERC1. We can bring some of them back if needed. * removed pixel type. LERC2 is typed and doesn't require user to give pixel type * changed encodedMaskData to maskData. LERC2 's js version make it faster to use maskData directly. * removed returnMask. mask is used by LERC2 internally and is cost free. In case of user input mask, it's returned as well and has neglible cost. * removed nodatavalue. Because LERC2 pixels are typed, nodatavalue will sacrify a useful value for many types (8bit, 16bit) etc, * user has to be knowledgable enough about raster and their data to avoid usability issues. so nodata value is simply removed now. * We can add it back later if their's a clear requirement. * removed encodedMask. This option was not implemented in LercDecode. It can be done after decoding (less efficient) * removed computeUsedBitDepths. * * * response changes compared to LERC1 * 1. encodedMaskData is not available * 2. noDataValue is optional (returns only if user's noDataValue is with in the valid data type range) * 3. maskData is always available */ /***************** * public properties ******************/ //HUFFMAN_LUT_BITS_MAX: 12, //use 2^12 lut, not configurable /***************** * public methods *****************/ /** * Decode a LERC2 byte stream and return an object containing the pixel data and optional metadata. * * @param {ArrayBuffer} input The LERC input byte stream * @param {object} [options] options Decoding options * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid LERC file is expected at that position * @param {boolean} [options.returnFileInfo] If true, the return value will have a fileInfo property that contains metadata obtained from the LERC headers and the decoding process */ decode: function(input, options) { options = options || {}; var noDataValue = options.noDataValue; var i = 0, data = {}; data.ptr = options.inputOffset || 0; data.pixels = {}; if (!Lerc2Helpers.readHeaderInfo(input, data)) { return; } var headerInfo = data.headerInfo; var fileVersion = headerInfo.fileVersion; var OutPixelTypeArray = Lerc2Helpers.getDataTypeArray(headerInfo.imageType); Lerc2Helpers.readMask(input, data); if (headerInfo.numValidPixel !== headerInfo.width * headerInfo.height && !data.pixels.resultMask) { data.pixels.resultMask = options.maskData; } var numPixels = headerInfo.width * headerInfo.height; data.pixels.resultPixels = new OutPixelTypeArray(numPixels * headerInfo.numDims); data.counter = { onesweep: 0, uncompressed: 0, lut: 0, bitstuffer: 0, constant: 0, constantoffset: 0 }; if (headerInfo.numValidPixel !== 0) { if (headerInfo.zMax === headerInfo.zMin) { Lerc2Helpers.constructConstantSurface(data); } else if (fileVersion >= 4 && Lerc2Helpers.checkMinMaxRanges(input, data)) { Lerc2Helpers.constructConstantSurface(data); } else { var view = new DataView(input, data.ptr, 2); var bReadDataOneSweep = view.getUint8(0); data.ptr++; if (bReadDataOneSweep) { Lerc2Helpers.readDataOneSweep(input, data, OutPixelTypeArray); } else { if (fileVersion > 1 && headerInfo.imageType <= 1 && Math.abs(headerInfo.maxZError - 0.5) < 1e-5) { var flagHuffman = view.getUint8(1); data.ptr++; data.encodeMode = flagHuffman; if (flagHuffman > 2 || fileVersion < 4 && flagHuffman > 1) { throw "Invalid Huffman flag " + flagHuffman; } if (flagHuffman) { Lerc2Helpers.readHuffman(input, data, OutPixelTypeArray); } else { Lerc2Helpers.readTiles(input, data, OutPixelTypeArray); } } else { Lerc2Helpers.readTiles(input, data, OutPixelTypeArray); } } } } data.eofOffset = data.ptr; var diff; if (options.inputOffset) { diff = data.headerInfo.blobSize + options.inputOffset - data.ptr; if (Math.abs(diff) >= 1) { data.eofOffset = options.inputOffset + data.headerInfo.blobSize; } } else { diff = data.headerInfo.blobSize - data.ptr; if (Math.abs(diff) >= 1) { data.eofOffset = data.headerInfo.blobSize; } } var result = { width: headerInfo.width, height: headerInfo.height, pixelData: data.pixels.resultPixels, minValue: headerInfo.zMin, maxValue: headerInfo.zMax, validPixelCount: headerInfo.numValidPixel, dimCount: headerInfo.numDims, dimStats: { minValues: headerInfo.minValues, maxValues: headerInfo.maxValues }, maskData: data.pixels.resultMask //noDataValue: noDataValue }; if (data.pixels.resultMask && Lerc2Helpers.isValidPixelValue(headerInfo.imageType, noDataValue)) { var mask = data.pixels.resultMask; for (i = 0; i < numPixels; i++) { if (!mask[i]) { result.pixelData[i] = noDataValue; } } result.noDataValue = noDataValue; } data.noDataValue = noDataValue; if (options.returnFileInfo) { result.fileInfo = Lerc2Helpers.formatFileInfo(data); } return result; }, getBandCount: function(input) { var count = 0; var i = 0; var temp = {}; temp.ptr = 0; temp.pixels = {}; while (i < input.byteLength - 58) { Lerc2Helpers.readHeaderInfo(input, temp); i += temp.headerInfo.blobSize; count++; temp.ptr = i; } return count; } }; return Lerc2Decode2; })(); var isPlatformLittleEndian = (function() { var a3 = new ArrayBuffer(4); var b = new Uint8Array(a3); var c14 = new Uint32Array(a3); c14[0] = 1; return b[0] === 1; })(); var Lerc2 = { /************wrapper**********************************************/ /** * A wrapper for decoding both LERC1 and LERC2 byte streams capable of handling multiband pixel blocks for various pixel types. * * @alias module:Lerc * @param {ArrayBuffer} input The LERC input byte stream * @param {object} [options] The decoding options below are optional. * @param {number} [options.inputOffset] The number of bytes to skip in the input byte stream. A valid Lerc file is expected at that position. * @param {string} [options.pixelType] (LERC1 only) Default value is F32. Valid pixel types for input are U8/S8/S16/U16/S32/U32/F32. * @param {number} [options.noDataValue] (LERC1 only). It is recommended to use the returned mask instead of setting this value. * @returns {{width, height, pixels, pixelType, mask, statistics}} * @property {number} width Width of decoded image. * @property {number} height Height of decoded image. * @property {array} pixels [band1, band2, …] Each band is a typed array of width*height. * @property {string} pixelType The type of pixels represented in the output. * @property {mask} mask Typed array with a size of width*height, or null if all pixels are valid. * @property {array} statistics [statistics_band1, statistics_band2, …] Each element is a statistics object representing min and max values **/ decode: function(encodedData, options) { if (!isPlatformLittleEndian) { throw "Big endian system is not supported."; } options = options || {}; var inputOffset = options.inputOffset || 0; var fileIdView = new Uint8Array(encodedData, inputOffset, 10); var fileIdentifierString = String.fromCharCode.apply(null, fileIdView); var lerc, majorVersion; if (fileIdentifierString.trim() === "CntZImage") { lerc = LercDecode; majorVersion = 1; } else if (fileIdentifierString.substring(0, 5) === "Lerc2") { lerc = Lerc2Decode; majorVersion = 2; } else { throw "Unexpected file identifier string: " + fileIdentifierString; } var iPlane = 0, eof = encodedData.byteLength - 10, encodedMaskData, bandMasks = [], bandMask, maskData; var decodedPixelBlock = { width: 0, height: 0, pixels: [], pixelType: options.pixelType, mask: null, statistics: [] }; while (inputOffset < eof) { var result = lerc.decode(encodedData, { inputOffset, //for both lerc1 and lerc2 encodedMaskData, //lerc1 only maskData, //lerc2 only returnMask: iPlane === 0 ? true : false, //lerc1 only returnEncodedMask: iPlane === 0 ? true : false, //lerc1 only returnFileInfo: true, //for both lerc1 and lerc2 pixelType: options.pixelType || null, //lerc1 only noDataValue: options.noDataValue || null //lerc1 only }); inputOffset = result.fileInfo.eofOffset; if (iPlane === 0) { encodedMaskData = result.encodedMaskData; maskData = result.maskData; decodedPixelBlock.width = result.width; decodedPixelBlock.height = result.height; decodedPixelBlock.dimCount = result.dimCount || 1; decodedPixelBlock.pixelType = result.pixelType || result.fileInfo.pixelType; decodedPixelBlock.mask = result.maskData; } if (majorVersion > 1 && result.fileInfo.mask && result.fileInfo.mask.numBytes > 0) { bandMasks.push(result.maskData); } iPlane++; decodedPixelBlock.pixels.push(result.pixelData); decodedPixelBlock.statistics.push({ minValue: result.minValue, maxValue: result.maxValue, noDataValue: result.noDataValue, dimStats: result.dimStats }); } var i, j, numPixels; if (majorVersion > 1 && bandMasks.length > 1) { numPixels = decodedPixelBlock.width * decodedPixelBlock.height; decodedPixelBlock.bandMasks = bandMasks; maskData = new Uint8Array(numPixels); maskData.set(bandMasks[0]); for (i = 1; i < bandMasks.length; i++) { bandMask = bandMasks[i]; for (j = 0; j < numPixels; j++) { maskData[j] = maskData[j] & bandMask[j]; } } decodedPixelBlock.maskData = maskData; } return decodedPixelBlock; } }; if (typeof define === "function" && define.amd) { define([], function() { return Lerc2; }); } else if (typeof module !== "undefined" && module.exports) { module.exports = Lerc2; } else { this.Lerc = Lerc2; } })(); } }); // node_modules/nosleep.js/src/media.js var require_media = __commonJS({ "node_modules/nosleep.js/src/media.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); module.exports = { webm: "data:video/webm;base64,GkXfowEAAAAAAAAfQoaBAUL3gQFC8oEEQvOBCEKChHdlYm1Ch4EEQoWBAhhTgGcBAAAAAAAVkhFNm3RALE27i1OrhBVJqWZTrIHfTbuMU6uEFlSua1OsggEwTbuMU6uEHFO7a1OsghV17AEAAAAAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmAQAAAAAAAEUq17GDD0JATYCNTGF2ZjU1LjMzLjEwMFdBjUxhdmY1NS4zMy4xMDBzpJBlrrXf3DCDVB8KcgbMpcr+RImIQJBgAAAAAAAWVK5rAQAAAAAAD++uAQAAAAAAADLXgQFzxYEBnIEAIrWcg3VuZIaFVl9WUDiDgQEj44OEAmJaAOABAAAAAAAABrCBsLqBkK4BAAAAAAAPq9eBAnPFgQKcgQAitZyDdW5khohBX1ZPUkJJU4OBAuEBAAAAAAAAEZ+BArWIQOdwAAAAAABiZIEgY6JPbwIeVgF2b3JiaXMAAAAAAoC7AAAAAAAAgLUBAAAAAAC4AQN2b3JiaXMtAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAxMDExMDEgKFNjaGF1ZmVudWdnZXQpAQAAABUAAABlbmNvZGVyPUxhdmM1NS41Mi4xMDIBBXZvcmJpcyVCQ1YBAEAAACRzGCpGpXMWhBAaQlAZ4xxCzmvsGUJMEYIcMkxbyyVzkCGkoEKIWyiB0JBVAABAAACHQXgUhIpBCCGEJT1YkoMnPQghhIg5eBSEaUEIIYQQQgghhBBCCCGERTlokoMnQQgdhOMwOAyD5Tj4HIRFOVgQgydB6CCED0K4moOsOQghhCQ1SFCDBjnoHITCLCiKgsQwuBaEBDUojILkMMjUgwtCiJqDSTX4GoRnQXgWhGlBCCGEJEFIkIMGQcgYhEZBWJKDBjm4FITLQagahCo5CB+EIDRkFQCQAACgoiiKoigKEBqyCgDIAAAQQFEUx3EcyZEcybEcCwgNWQUAAAEACAAAoEiKpEiO5EiSJFmSJVmSJVmS5omqLMuyLMuyLMsyEBqyCgBIAABQUQxFcRQHCA1ZBQBkAAAIoDiKpViKpWiK54iOCISGrAIAgAAABAAAEDRDUzxHlETPVFXXtm3btm3btm3btm3btm1blmUZCA1ZBQBAAAAQ0mlmqQaIMAMZBkJDVgEACAAAgBGKMMSA0JBVAABAAACAGEoOogmtOd+c46BZDppKsTkdnEi1eZKbirk555xzzsnmnDHOOeecopxZDJoJrTnnnMSgWQqaCa0555wnsXnQmiqtOeeccc7pYJwRxjnnnCateZCajbU555wFrWmOmkuxOeecSLl5UptLtTnnnHPOOeecc84555zqxekcnBPOOeecqL25lpvQxTnnnE/G6d6cEM4555xzzjnnnHPOOeecIDRkFQAABABAEIaNYdwpCNLnaCBGEWIaMulB9+gwCRqDnELq0ehopJQ6CCWVcVJKJwgNWQUAAAIAQAghhRRSSCGFFFJIIYUUYoghhhhyyimnoIJKKqmooowyyyyzzDLLLLPMOuyssw47DDHEEEMrrcRSU2011lhr7jnnmoO0VlprrbVSSimllFIKQkNWAQAgAAAEQgYZZJBRSCGFFGKIKaeccgoqqIDQkFUAACAAgAAAAABP8hzRER3RER3RER3RER3R8RzPESVREiVREi3TMjXTU0VVdWXXlnVZt31b2IVd933d933d+HVhWJZlWZZlWZZlWZZlWZZlWZYgNGQVAAACAAAghBBCSCGFFFJIKcYYc8w56CSUEAgNWQUAAAIACAAAAHAUR3EcyZEcSbIkS9IkzdIsT/M0TxM9URRF0zRV0RVdUTdtUTZl0zVdUzZdVVZtV5ZtW7Z125dl2/d93/d93/d93/d93/d9XQdCQ1YBABIAADqSIymSIimS4ziOJElAaMgqAEAGAEAAAIriKI7jOJIkSZIlaZJneZaomZrpmZ4qqkBoyCoAABAAQAAAAAAAAIqmeIqpeIqoeI7oiJJomZaoqZoryqbsuq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq4LhIasAgAkAAB0JEdyJEdSJEVSJEdygNCQVQCADACAAAAcwzEkRXIsy9I0T/M0TxM90RM901NFV3SB0JBVAAAgAIAAAAAAAAAMybAUy9EcTRIl1VItVVMt1VJF1VNVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVN0zRNEwgNWQkAkAEAkBBTLS3GmgmLJGLSaqugYwxS7KWxSCpntbfKMYUYtV4ah5RREHupJGOKQcwtpNApJq3WVEKFFKSYYyoVUg5SIDRkhQAQmgHgcBxAsixAsiwAAAAAAAAAkDQN0DwPsDQPAAAAAAAAACRNAyxPAzTPAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA0jRA8zxA8zwAAAAAAAAA0DwP8DwR8EQRAAAAAAAAACzPAzTRAzxRBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA0jRA8zxA8zwAAAAAAAAAsDwP8EQR0DwRAAAAAAAAACzPAzxRBDzRAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAEOAAABBgIRQasiIAiBMAcEgSJAmSBM0DSJYFTYOmwTQBkmVB06BpME0AAAAAAAAAAAAAJE2DpkHTIIoASdOgadA0iCIAAAAAAAAAAAAAkqZB06BpEEWApGnQNGgaRBEAAAAAAAAAAAAAzzQhihBFmCbAM02IIkQRpgkAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAGHAAAAgwoQwUGrIiAIgTAHA4imUBAIDjOJYFAACO41gWAABYliWKAABgWZooAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAYcAAACDChDBQashIAiAIAcCiKZQHHsSzgOJYFJMmyAJYF0DyApgFEEQAIAAAocAAACLBBU2JxgEJDVgIAUQAABsWxLE0TRZKkaZoniiRJ0zxPFGma53meacLzPM80IYqiaJoQRVE0TZimaaoqME1VFQAAUOAAABBgg6bE4gCFhqwEAEICAByKYlma5nmeJ4qmqZokSdM8TxRF0TRNU1VJkqZ5niiKommapqqyLE3zPFEURdNUVVWFpnmeKIqiaaqq6sLzPE8URdE0VdV14XmeJ4qiaJqq6roQRVE0TdNUTVV1XSCKpmmaqqqqrgtETxRNU1Vd13WB54miaaqqq7ouEE3TVFVVdV1ZBpimaaqq68oyQFVV1XVdV5YBqqqqruu6sgxQVdd1XVmWZQCu67qyLMsCAAAOHAAAAoygk4wqi7DRhAsPQKEhKwKAKAAAwBimFFPKMCYhpBAaxiSEFEImJaXSUqogpFJSKRWEVEoqJaOUUmopVRBSKamUCkIqJZVSAADYgQMA2IGFUGjISgAgDwCAMEYpxhhzTiKkFGPOOScRUoox55yTSjHmnHPOSSkZc8w556SUzjnnnHNSSuacc845KaVzzjnnnJRSSuecc05KKSWEzkEnpZTSOeecEwAAVOAAABBgo8jmBCNBhYasBABSAQAMjmNZmuZ5omialiRpmud5niiapiZJmuZ5nieKqsnzPE8URdE0VZXneZ4oiqJpqirXFUXTNE1VVV2yLIqmaZqq6rowTdNUVdd1XZimaaqq67oubFtVVdV1ZRm2raqq6rqyDFzXdWXZloEsu67s2rIAAPAEBwCgAhtWRzgpGgssNGQlAJABAEAYg5BCCCFlEEIKIYSUUggJAAAYcAAACDChDBQashIASAUAAIyx1lprrbXWQGettdZaa62AzFprrbXWWmuttdZaa6211lJrrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmstpZRSSimllFJKKaWUUkoppZRSSgUA+lU4APg/2LA6wknRWGChISsBgHAAAMAYpRhzDEIppVQIMeacdFRai7FCiDHnJKTUWmzFc85BKCGV1mIsnnMOQikpxVZjUSmEUlJKLbZYi0qho5JSSq3VWIwxqaTWWoutxmKMSSm01FqLMRYjbE2ptdhqq7EYY2sqLbQYY4zFCF9kbC2m2moNxggjWywt1VprMMYY3VuLpbaaizE++NpSLDHWXAAAd4MDAESCjTOsJJ0VjgYXGrISAAgJACAQUooxxhhzzjnnpFKMOeaccw5CCKFUijHGnHMOQgghlIwx5pxzEEIIIYRSSsaccxBCCCGEkFLqnHMQQgghhBBKKZ1zDkIIIYQQQimlgxBCCCGEEEoopaQUQgghhBBCCKmklEIIIYRSQighlZRSCCGEEEIpJaSUUgohhFJCCKGElFJKKYUQQgillJJSSimlEkoJJYQSUikppRRKCCGUUkpKKaVUSgmhhBJKKSWllFJKIYQQSikFAAAcOAAABBhBJxlVFmGjCRcegEJDVgIAZAAAkKKUUiktRYIipRikGEtGFXNQWoqocgxSzalSziDmJJaIMYSUk1Qy5hRCDELqHHVMKQYtlRhCxhik2HJLoXMOAAAAQQCAgJAAAAMEBTMAwOAA4XMQdAIERxsAgCBEZohEw0JweFAJEBFTAUBigkIuAFRYXKRdXECXAS7o4q4DIQQhCEEsDqCABByccMMTb3jCDU7QKSp1IAAAAAAADADwAACQXAAREdHMYWRobHB0eHyAhIiMkAgAAAAAABcAfAAAJCVAREQ0cxgZGhscHR4fICEiIyQBAIAAAgAAAAAggAAEBAQAAAAAAAIAAAAEBB9DtnUBAAAAAAAEPueBAKOFggAAgACjzoEAA4BwBwCdASqwAJAAAEcIhYWIhYSIAgIABhwJ7kPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99YAD+/6tQgKOFggADgAqjhYIAD4AOo4WCACSADqOZgQArADECAAEQEAAYABhYL/QACIBDmAYAAKOFggA6gA6jhYIAT4AOo5mBAFMAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCAGSADqOFggB6gA6jmYEAewAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYIAj4AOo5mBAKMAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCAKSADqOFggC6gA6jmYEAywAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYIAz4AOo4WCAOSADqOZgQDzADECAAEQEAAYABhYL/QACIBDmAYAAKOFggD6gA6jhYIBD4AOo5iBARsAEQIAARAQFGAAYWC/0AAiAQ5gGACjhYIBJIAOo4WCATqADqOZgQFDADECAAEQEAAYABhYL/QACIBDmAYAAKOFggFPgA6jhYIBZIAOo5mBAWsAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCAXqADqOFggGPgA6jmYEBkwAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYIBpIAOo4WCAbqADqOZgQG7ADECAAEQEAAYABhYL/QACIBDmAYAAKOFggHPgA6jmYEB4wAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYIB5IAOo4WCAfqADqOZgQILADECAAEQEAAYABhYL/QACIBDmAYAAKOFggIPgA6jhYICJIAOo5mBAjMAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCAjqADqOFggJPgA6jmYECWwAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYICZIAOo4WCAnqADqOZgQKDADECAAEQEAAYABhYL/QACIBDmAYAAKOFggKPgA6jhYICpIAOo5mBAqsAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCArqADqOFggLPgA6jmIEC0wARAgABEBAUYABhYL/QACIBDmAYAKOFggLkgA6jhYIC+oAOo5mBAvsAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCAw+ADqOZgQMjADECAAEQEAAYABhYL/QACIBDmAYAAKOFggMkgA6jhYIDOoAOo5mBA0sAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCA0+ADqOFggNkgA6jmYEDcwAxAgABEBAAGAAYWC/0AAiAQ5gGAACjhYIDeoAOo4WCA4+ADqOZgQObADECAAEQEAAYABhYL/QACIBDmAYAAKOFggOkgA6jhYIDuoAOo5mBA8MAMQIAARAQABgAGFgv9AAIgEOYBgAAo4WCA8+ADqOFggPkgA6jhYID+oAOo4WCBA+ADhxTu2sBAAAAAAAAEbuPs4EDt4r3gQHxghEr8IEK", mp4: "data:video/mp4;base64,AAAAHGZ0eXBNNFYgAAACAGlzb21pc28yYXZjMQAAAAhmcmVlAAAGF21kYXTeBAAAbGliZmFhYyAxLjI4AABCAJMgBDIARwAAArEGBf//rdxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxNDIgcjIgOTU2YzhkOCAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMTQgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0wIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDE6MHgxMTEgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTAgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz02IGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MCB3ZWlnaHRwPTAga2V5aW50PTI1MCBrZXlpbnRfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCB2YnZfbWF4cmF0ZT03NjggdmJ2X2J1ZnNpemU9MzAwMCBjcmZfbWF4PTAuMCBuYWxfaHJkPW5vbmUgZmlsbGVyPTAgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAFZliIQL8mKAAKvMnJycnJycnJycnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXiEASZACGQAjgCEASZACGQAjgAAAAAdBmjgX4GSAIQBJkAIZACOAAAAAB0GaVAX4GSAhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZpgL8DJIQBJkAIZACOAIQBJkAIZACOAAAAABkGagC/AySEASZACGQAjgAAAAAZBmqAvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZrAL8DJIQBJkAIZACOAAAAABkGa4C/AySEASZACGQAjgCEASZACGQAjgAAAAAZBmwAvwMkhAEmQAhkAI4AAAAAGQZsgL8DJIQBJkAIZACOAIQBJkAIZACOAAAAABkGbQC/AySEASZACGQAjgCEASZACGQAjgAAAAAZBm2AvwMkhAEmQAhkAI4AAAAAGQZuAL8DJIQBJkAIZACOAIQBJkAIZACOAAAAABkGboC/AySEASZACGQAjgAAAAAZBm8AvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZvgL8DJIQBJkAIZACOAAAAABkGaAC/AySEASZACGQAjgCEASZACGQAjgAAAAAZBmiAvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZpAL8DJIQBJkAIZACOAAAAABkGaYC/AySEASZACGQAjgCEASZACGQAjgAAAAAZBmoAvwMkhAEmQAhkAI4AAAAAGQZqgL8DJIQBJkAIZACOAIQBJkAIZACOAAAAABkGawC/AySEASZACGQAjgAAAAAZBmuAvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZsAL8DJIQBJkAIZACOAAAAABkGbIC/AySEASZACGQAjgCEASZACGQAjgAAAAAZBm0AvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZtgL8DJIQBJkAIZACOAAAAABkGbgCvAySEASZACGQAjgCEASZACGQAjgAAAAAZBm6AnwMkhAEmQAhkAI4AhAEmQAhkAI4AhAEmQAhkAI4AhAEmQAhkAI4AAAAhubW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAABDcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAzB0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAA+kAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAALAAAACQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAPpAAAAAAABAAAAAAKobWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAB1MAAAdU5VxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAACU21pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAhNzdGJsAAAAr3N0c2QAAAAAAAAAAQAAAJ9hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAALAAkABIAAAASAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAALWF2Y0MBQsAN/+EAFWdCwA3ZAsTsBEAAAPpAADqYA8UKkgEABWjLg8sgAAAAHHV1aWRraEDyXyRPxbo5pRvPAyPzAAAAAAAAABhzdHRzAAAAAAAAAAEAAAAeAAAD6QAAABRzdHNzAAAAAAAAAAEAAAABAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAAIxzdHN6AAAAAAAAAAAAAAAeAAADDwAAAAsAAAALAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAAiHN0Y28AAAAAAAAAHgAAAEYAAANnAAADewAAA5gAAAO0AAADxwAAA+MAAAP2AAAEEgAABCUAAARBAAAEXQAABHAAAASMAAAEnwAABLsAAATOAAAE6gAABQYAAAUZAAAFNQAABUgAAAVkAAAFdwAABZMAAAWmAAAFwgAABd4AAAXxAAAGDQAABGh0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAACAAAAAAAABDcAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAQkAAADcAABAAAAAAPgbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAC7gAAAykBVxAAAAAAALWhkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAADi21pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAADT3N0YmwAAABnc3RzZAAAAAAAAAABAAAAV21wNGEAAAAAAAAAAQAAAAAAAAAAAAIAEAAAAAC7gAAAAAAAM2VzZHMAAAAAA4CAgCIAAgAEgICAFEAVBbjYAAu4AAAADcoFgICAAhGQBoCAgAECAAAAIHN0dHMAAAAAAAAAAgAAADIAAAQAAAAAAQAAAkAAAAFUc3RzYwAAAAAAAAAbAAAAAQAAAAEAAAABAAAAAgAAAAIAAAABAAAAAwAAAAEAAAABAAAABAAAAAIAAAABAAAABgAAAAEAAAABAAAABwAAAAIAAAABAAAACAAAAAEAAAABAAAACQAAAAIAAAABAAAACgAAAAEAAAABAAAACwAAAAIAAAABAAAADQAAAAEAAAABAAAADgAAAAIAAAABAAAADwAAAAEAAAABAAAAEAAAAAIAAAABAAAAEQAAAAEAAAABAAAAEgAAAAIAAAABAAAAFAAAAAEAAAABAAAAFQAAAAIAAAABAAAAFgAAAAEAAAABAAAAFwAAAAIAAAABAAAAGAAAAAEAAAABAAAAGQAAAAIAAAABAAAAGgAAAAEAAAABAAAAGwAAAAIAAAABAAAAHQAAAAEAAAABAAAAHgAAAAIAAAABAAAAHwAAAAQAAAABAAAA4HN0c3oAAAAAAAAAAAAAADMAAAAaAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAACMc3RjbwAAAAAAAAAfAAAALAAAA1UAAANyAAADhgAAA6IAAAO+AAAD0QAAA+0AAAQAAAAEHAAABC8AAARLAAAEZwAABHoAAASWAAAEqQAABMUAAATYAAAE9AAABRAAAAUjAAAFPwAABVIAAAVuAAAFgQAABZ0AAAWwAAAFzAAABegAAAX7AAAGFwAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTUuMzMuMTAw" }; } }); // node_modules/nosleep.js/src/index.js var require_src = __commonJS({ "node_modules/nosleep.js/src/index.js"(exports, module) { var import_InlineWorkers1435 = __toESM(require_InlineWorkers()); var { webm, mp4 } = require_media(); var oldIOS = () => typeof navigator !== "undefined" && parseFloat( ("" + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec( navigator.userAgent ) || [0, ""])[1]).replace("undefined", "3_2").replace("_", ".").replace("_", "") ) < 10 && !window.MSStream; var nativeWakeLock = () => "wakeLock" in navigator; var NoSleep2 = class { constructor() { this.enabled = false; if (nativeWakeLock()) { this._wakeLock = null; const handleVisibilityChange = () => { if (this._wakeLock !== null && document.visibilityState === "visible") { this.enable(); } }; document.addEventListener("visibilitychange", handleVisibilityChange); document.addEventListener("fullscreenchange", handleVisibilityChange); } else if (oldIOS()) { this.noSleepTimer = null; } else { this.noSleepVideo = document.createElement("video"); this.noSleepVideo.setAttribute("title", "No Sleep"); this.noSleepVideo.setAttribute("playsinline", ""); this._addSourceToVideo(this.noSleepVideo, "webm", webm); this._addSourceToVideo(this.noSleepVideo, "mp4", mp4); this.noSleepVideo.addEventListener("loadedmetadata", () => { if (this.noSleepVideo.duration <= 1) { this.noSleepVideo.setAttribute("loop", ""); } else { this.noSleepVideo.addEventListener("timeupdate", () => { if (this.noSleepVideo.currentTime > 0.5) { this.noSleepVideo.currentTime = Math.random(); } }); } }); } } _addSourceToVideo(element, type, dataURI) { var source = document.createElement("source"); source.src = dataURI; source.type = `video/${type}`; element.appendChild(source); } get isEnabled() { return this.enabled; } enable() { if (nativeWakeLock()) { return navigator.wakeLock.request("screen").then((wakeLock) => { this._wakeLock = wakeLock; this.enabled = true; console.log("Wake Lock active."); this._wakeLock.addEventListener("release", () => { console.log("Wake Lock released."); }); }).catch((err) => { this.enabled = false; console.error(`${err.name}, ${err.message}`); throw err; }); } else if (oldIOS()) { this.disable(); console.warn(` NoSleep enabled for older iOS devices. This can interrupt active or long-running network requests from completing successfully. See https://github.com/richtr/NoSleep.js/issues/15 for more details. `); this.noSleepTimer = window.setInterval(() => { if (!document.hidden) { window.location.href = window.location.href.split("#")[0]; window.setTimeout(window.stop, 0); } }, 15e3); this.enabled = true; return Promise.resolve(); } else { let playPromise = this.noSleepVideo.play(); return playPromise.then((res) => { this.enabled = true; return res; }).catch((err) => { this.enabled = false; throw err; }); } } disable() { if (nativeWakeLock()) { if (this._wakeLock) { this._wakeLock.release(); } this._wakeLock = null; } else if (oldIOS()) { if (this.noSleepTimer) { console.warn(` NoSleep now disabled for older iOS devices. `); window.clearInterval(this.noSleepTimer); this.noSleepTimer = null; } } else { this.noSleepVideo.pause(); } this.enabled = false; } }; module.exports = NoSleep2; } }); // Source/Cesium.js var Cesium_exports = {}; __export(Cesium_exports, { AlphaMode: () => AlphaMode_default, AlphaPipelineStage: () => AlphaPipelineStage_default, AnchorPointDirect: () => AnchorPointDirect_default, AnchorPointIndirect: () => AnchorPointIndirect_default, Animation: () => Animation_default, AnimationViewModel: () => AnimationViewModel_default, Appearance: () => Appearance_default, ApproximateTerrainHeights: () => ApproximateTerrainHeights_default, ArcGISTiledElevationTerrainProvider: () => ArcGISTiledElevationTerrainProvider_default, ArcGisBaseMapType: () => ArcGisBaseMapType_default, ArcGisMapServerImageryProvider: () => ArcGisMapServerImageryProvider_default, ArcGisMapService: () => ArcGisMapService_default, ArcType: () => ArcType_default, ArticulationStageType: () => ArticulationStageType_default, AssociativeArray: () => AssociativeArray_default, Atmosphere: () => Atmosphere_default, AtmospherePipelineStage: () => AtmospherePipelineStage_default, AttributeCompression: () => AttributeCompression_default, AttributeType: () => AttributeType_default, AutoExposure: () => AutoExposure_default, AutomaticUniforms: () => AutomaticUniforms_default, Axis: () => Axis_default, AxisAlignedBoundingBox: () => AxisAlignedBoundingBox_default, Azure2DImageryProvider: () => Azure2DImageryProvider_default, B3dmLoader: () => B3dmLoader_default, B3dmParser: () => B3dmParser_default, BaseLayerPicker: () => BaseLayerPicker_default, BaseLayerPickerViewModel: () => BaseLayerPickerViewModel_default, BatchTable: () => BatchTable_default, BatchTableHierarchy: () => BatchTableHierarchy_default, BatchTexture: () => BatchTexture_default, BatchTexturePipelineStage: () => BatchTexturePipelineStage_default, Billboard: () => Billboard_default, BillboardCollection: () => BillboardCollection_default, BillboardGraphics: () => BillboardGraphics_default, BillboardLoadState: () => BillboardLoadState_default, BillboardTexture: () => BillboardTexture_default, BillboardVisualizer: () => BillboardVisualizer_default, BingMapsGeocoderService: () => BingMapsGeocoderService_default, BingMapsImageryProvider: () => BingMapsImageryProvider_default, BingMapsStyle: () => BingMapsStyle_default, BlendEquation: () => BlendEquation_default, BlendFunction: () => BlendFunction_default, BlendOption: () => BlendOption_default, BlendingState: () => BlendingState_default, BoundingRectangle: () => BoundingRectangle_default, BoundingSphere: () => BoundingSphere_default, BoundingSphereState: () => BoundingSphereState_default, BoundingVolumeSemantics: () => BoundingVolumeSemantics_default, BoxEmitter: () => BoxEmitter_default, BoxGeometry: () => BoxGeometry_default, BoxGeometryUpdater: () => BoxGeometryUpdater_default, BoxGraphics: () => BoxGraphics_default, BoxOutlineGeometry: () => BoxOutlineGeometry_default, BrdfLutGenerator: () => BrdfLutGenerator_default, Buffer: () => Buffer_default, BufferLoader: () => BufferLoader_default, BufferPoint: () => BufferPoint_default, BufferPointCollection: () => BufferPointCollection_default, BufferPointMaterial: () => BufferPointMaterial_default, BufferPolygon: () => BufferPolygon_default, BufferPolygonCollection: () => BufferPolygonCollection_default, BufferPolygonMaterial: () => BufferPolygonMaterial_default, BufferPolyline: () => BufferPolyline_default, BufferPolylineCollection: () => BufferPolylineCollection_default, BufferPolylineMaterial: () => BufferPolylineMaterial_default, BufferPrimitive: () => BufferPrimitive_default, BufferPrimitiveCollection: () => BufferPrimitiveCollection_default, BufferPrimitiveMaterial: () => BufferPrimitiveMaterial_default, BufferUsage: () => BufferUsage_default, CPUStylingPipelineStage: () => CPUStylingPipelineStage_default, CallbackPositionProperty: () => CallbackPositionProperty_default, CallbackProperty: () => CallbackProperty_default, Camera: () => Camera_default, CameraEventAggregator: () => CameraEventAggregator_default, CameraEventType: () => CameraEventType_default, CameraFlightPath: () => CameraFlightPath_default, Cartesian2: () => Cartesian2_default, Cartesian3: () => Cartesian3_default, Cartesian4: () => Cartesian4_default, CartesianRectangle: () => CartesianRectangle_default, Cartographic: () => Cartographic_default, CartographicGeocoderService: () => CartographicGeocoderService_default, CatmullRomSpline: () => CatmullRomSpline_default, Cesium3DContentGroup: () => Cesium3DContentGroup_default, Cesium3DTile: () => Cesium3DTile_default, Cesium3DTileBatchTable: () => Cesium3DTileBatchTable_default, Cesium3DTileColorBlendMode: () => Cesium3DTileColorBlendMode_default, Cesium3DTileContent: () => Cesium3DTileContent_default, Cesium3DTileContentFactory: () => Cesium3DTileContentFactory_default, Cesium3DTileContentState: () => Cesium3DTileContentState_default, Cesium3DTileContentType: () => Cesium3DTileContentType_default, Cesium3DTileFeature: () => Cesium3DTileFeature_default, Cesium3DTileFeatureTable: () => Cesium3DTileFeatureTable_default, Cesium3DTileOptimizationHint: () => Cesium3DTileOptimizationHint_default, Cesium3DTileOptimizations: () => Cesium3DTileOptimizations_default, Cesium3DTilePass: () => Cesium3DTilePass_default, Cesium3DTilePassState: () => Cesium3DTilePassState_default, Cesium3DTilePointFeature: () => Cesium3DTilePointFeature_default, Cesium3DTileRefine: () => Cesium3DTileRefine_default, Cesium3DTileStyle: () => Cesium3DTileStyle_default, Cesium3DTileStyleEngine: () => Cesium3DTileStyleEngine_default, Cesium3DTileVectorFeature: () => Cesium3DTileVectorFeature_default, Cesium3DTilesInspector: () => Cesium3DTilesInspector_default, Cesium3DTilesInspectorViewModel: () => Cesium3DTilesInspectorViewModel_default, Cesium3DTilesTerrainData: () => Cesium3DTilesTerrainData_default, Cesium3DTilesTerrainGeometryProcessor: () => Cesium3DTilesTerrainGeometryProcessor_default, Cesium3DTilesTerrainProvider: () => Cesium3DTilesTerrainProvider_default, Cesium3DTilesVoxelProvider: () => Cesium3DTilesVoxelProvider_default, Cesium3DTileset: () => Cesium3DTileset_default, Cesium3DTilesetBaseTraversal: () => Cesium3DTilesetBaseTraversal_default, Cesium3DTilesetCache: () => Cesium3DTilesetCache_default, Cesium3DTilesetGraphics: () => Cesium3DTilesetGraphics_default, Cesium3DTilesetHeatmap: () => Cesium3DTilesetHeatmap_default, Cesium3DTilesetMetadata: () => Cesium3DTilesetMetadata_default, Cesium3DTilesetMostDetailedTraversal: () => Cesium3DTilesetMostDetailedTraversal_default, Cesium3DTilesetSkipTraversal: () => Cesium3DTilesetSkipTraversal_default, Cesium3DTilesetStatistics: () => Cesium3DTilesetStatistics_default, Cesium3DTilesetTraversal: () => Cesium3DTilesetTraversal_default, Cesium3DTilesetVisualizer: () => Cesium3DTilesetVisualizer_default, CesiumInspector: () => CesiumInspector_default, CesiumInspectorViewModel: () => CesiumInspectorViewModel_default, CesiumTerrainProvider: () => CesiumTerrainProvider_default, CesiumWidget: () => CesiumWidget_default, Check: () => Check_default, CheckerboardMaterialProperty: () => CheckerboardMaterialProperty_default, CircleEmitter: () => CircleEmitter_default, CircleGeometry: () => CircleGeometry_default, CircleOutlineGeometry: () => CircleOutlineGeometry_default, ClassificationModelDrawCommand: () => ClassificationModelDrawCommand_default, ClassificationPipelineStage: () => ClassificationPipelineStage_default, ClassificationPrimitive: () => ClassificationPrimitive_default, ClassificationType: () => ClassificationType_default, ClearCommand: () => ClearCommand_default, ClippingPlane: () => ClippingPlane_default, ClippingPlaneCollection: () => ClippingPlaneCollection_default, ClippingPolygon: () => ClippingPolygon_default, ClippingPolygonCollection: () => ClippingPolygonCollection_default, Clock: () => Clock_default, ClockRange: () => ClockRange_default, ClockStep: () => ClockStep_default, ClockViewModel: () => ClockViewModel_default, CloudCollection: () => CloudCollection_default, CloudType: () => CloudType_default, Color: () => Color_default, ColorBlendMode: () => ColorBlendMode_default, ColorGeometryInstanceAttribute: () => ColorGeometryInstanceAttribute_default, ColorMaterialProperty: () => ColorMaterialProperty_default, Command: () => Command_default, ComponentDatatype: () => ComponentDatatype_default, Composite3DTileContent: () => Composite3DTileContent_default, CompositeEntityCollection: () => CompositeEntityCollection_default, CompositeMaterialProperty: () => CompositeMaterialProperty_default, CompositePositionProperty: () => CompositePositionProperty_default, CompositeProperty: () => CompositeProperty_default, CompressedTextureBuffer: () => CompressedTextureBuffer_default, ComputeCommand: () => ComputeCommand_default, ComputeEngine: () => ComputeEngine_default, ConditionsExpression: () => ConditionsExpression_default, ConeEmitter: () => ConeEmitter_default, ConstantPositionProperty: () => ConstantPositionProperty_default, ConstantProperty: () => ConstantProperty_default, ConstantSpline: () => ConstantSpline_default, ContentMetadata: () => ContentMetadata_default, Context: () => Context_default, ContextLimits: () => ContextLimits_default, Controller: () => Controller_default, ControllerHost: () => ControllerHost_default, CoplanarPolygonGeometry: () => CoplanarPolygonGeometry_default, CoplanarPolygonGeometryLibrary: () => CoplanarPolygonGeometryLibrary_default, CoplanarPolygonOutlineGeometry: () => CoplanarPolygonOutlineGeometry_default, CornerType: () => CornerType_default, CorrelationGroup: () => CorrelationGroup_default, CorridorGeometry: () => CorridorGeometry_default, CorridorGeometryLibrary: () => CorridorGeometryLibrary_default, CorridorGeometryUpdater: () => CorridorGeometryUpdater_default, CorridorGraphics: () => CorridorGraphics_default, CorridorOutlineGeometry: () => CorridorOutlineGeometry_default, Credit: () => Credit_default, CreditDisplay: () => CreditDisplay_default, CubeMap: () => CubeMap_default, CubeMapFace: () => CubeMapFace_default, CubeMapPanorama: () => CubeMapPanorama_default, CubicRealPolynomial: () => CubicRealPolynomial_default, CullFace: () => CullFace_default, CullingVolume: () => CullingVolume_default, CumulusCloud: () => CumulusCloud_default, CustomDataSource: () => CustomDataSource_default, CustomHeightmapTerrainProvider: () => CustomHeightmapTerrainProvider_default, CustomShader: () => CustomShader_default, CustomShaderMode: () => CustomShaderMode_default, CustomShaderPipelineStage: () => CustomShaderPipelineStage_default, CustomShaderTranslucencyMode: () => CustomShaderTranslucencyMode_default, CylinderGeometry: () => CylinderGeometry_default, CylinderGeometryLibrary: () => CylinderGeometryLibrary_default, CylinderGeometryUpdater: () => CylinderGeometryUpdater_default, CylinderGraphics: () => CylinderGraphics_default, CylinderOutlineGeometry: () => CylinderOutlineGeometry_default, CzmlDataSource: () => CzmlDataSource_default, DataSource: () => DataSource_default, DataSourceClock: () => DataSourceClock_default, DataSourceCollection: () => DataSourceCollection_default, DataSourceDisplay: () => DataSourceDisplay_default, DebugAppearance: () => DebugAppearance_default, DebugCameraPrimitive: () => DebugCameraPrimitive_default, DebugInspector: () => DebugInspector_default, DebugModelMatrixPrimitive: () => DebugModelMatrixPrimitive_default, DefaultProxy: () => DefaultProxy_default, DepthFunction: () => DepthFunction_default, DepthPlane: () => DepthPlane_default, DequantizationPipelineStage: () => DequantizationPipelineStage_default, DerivedCommand: () => DerivedCommand_default, DeveloperError: () => DeveloperError_default, DeviceOrientationCameraController: () => DeviceOrientationCameraController_default, DirectionalLight: () => DirectionalLight_default, DiscardEmptyTileImagePolicy: () => DiscardEmptyTileImagePolicy_default, DiscardMissingTileImagePolicy: () => DiscardMissingTileImagePolicy_default, DistanceDisplayCondition: () => DistanceDisplayCondition_default, DistanceDisplayConditionGeometryInstanceAttribute: () => DistanceDisplayConditionGeometryInstanceAttribute_default, DoubleEndedPriorityQueue: () => DoubleEndedPriorityQueue_default, DoublyLinkedList: () => DoublyLinkedList_default, DracoLoader: () => DracoLoader_default, DrawCommand: () => DrawCommand_default, DynamicAtmosphereLightingType: () => DynamicAtmosphereLightingType_default, DynamicEnvironmentMapManager: () => DynamicEnvironmentMapManager_default, DynamicGeometryBatch: () => DynamicGeometryBatch_default, DynamicGeometryUpdater: () => DynamicGeometryUpdater_default, EarthOrientationParameters: () => EarthOrientationParameters_default, EarthOrientationParametersSample: () => EarthOrientationParametersSample_default, EasingFunction: () => EasingFunction_default, EdgeDetectionPipelineStage: () => EdgeDetectionPipelineStage_default, EdgeDisplayMode: () => EdgeDisplayMode_default, EdgeFramebuffer: () => EdgeFramebuffer_default, EdgeVisibilityPipelineStage: () => EdgeVisibilityPipelineStage_default, EllipseGeometry: () => EllipseGeometry_default, EllipseGeometryLibrary: () => EllipseGeometryLibrary_default, EllipseGeometryUpdater: () => EllipseGeometryUpdater_default, EllipseGraphics: () => EllipseGraphics_default, EllipseOutlineGeometry: () => EllipseOutlineGeometry_default, Ellipsoid: () => Ellipsoid_default, EllipsoidGeodesic: () => EllipsoidGeodesic_default, EllipsoidGeometry: () => EllipsoidGeometry_default, EllipsoidGeometryUpdater: () => EllipsoidGeometryUpdater_default, EllipsoidGraphics: () => EllipsoidGraphics_default, EllipsoidOutlineGeometry: () => EllipsoidOutlineGeometry_default, EllipsoidPrimitive: () => EllipsoidPrimitive_default, EllipsoidRhumbLine: () => EllipsoidRhumbLine_default, EllipsoidSurfaceAppearance: () => EllipsoidSurfaceAppearance_default, EllipsoidTangentPlane: () => EllipsoidTangentPlane_default, EllipsoidTerrainProvider: () => EllipsoidTerrainProvider_default, EllipsoidalOccluder: () => EllipsoidalOccluder_default, Empty3DTileContent: () => Empty3DTileContent_default, EncodedCartesian3: () => EncodedCartesian3_default, Entity: () => Entity_default, EntityCluster: () => EntityCluster_default, EntityCollection: () => EntityCollection_default, EntityView: () => EntityView_default, EquirectangularPanorama: () => EquirectangularPanorama_default, Event: () => Event_default, EventHelper: () => EventHelper_default, Expression: () => Expression_default, ExpressionNodeType: () => ExpressionNodeType_default, ExtrapolationType: () => ExtrapolationType_default, FeatureDetection: () => FeatureDetection_default, FeatureIdPipelineStage: () => FeatureIdPipelineStage_default, Fog: () => Fog_default, ForEach: () => ForEach_default, FrameRateMonitor: () => FrameRateMonitor_default, FrameState: () => FrameState_default, Framebuffer: () => Framebuffer_default, FramebufferManager: () => FramebufferManager_default, Frozen: () => Frozen_default, FrustumCommands: () => FrustumCommands_default, FrustumGeometry: () => FrustumGeometry_default, FrustumOutlineGeometry: () => FrustumOutlineGeometry_default, Fullscreen: () => Fullscreen_default, FullscreenButton: () => FullscreenButton_default, FullscreenButtonViewModel: () => FullscreenButtonViewModel_default, GaussianSplat3DTileContent: () => GaussianSplat3DTileContent_default, GaussianSplatPrimitive: () => GaussianSplatPrimitive_default, GaussianSplatRenderResources: () => GaussianSplatRenderResources_default, GaussianSplatSorter: () => GaussianSplatSorter_default, GaussianSplatTextureGenerator: () => GaussianSplatTextureGenerator_default, GeoJsonDataSource: () => GeoJsonDataSource_default, GeoJsonLoader: () => GeoJsonLoader_default, GeoJsonPrimitive: () => GeoJsonPrimitive_default, GeocodeType: () => GeocodeType_default, Geocoder: () => Geocoder_default, GeocoderService: () => GeocoderService_default, GeocoderViewModel: () => GeocoderViewModel_default, GeographicProjection: () => GeographicProjection_default, GeographicTilingScheme: () => GeographicTilingScheme_default, Geometry: () => Geometry_default, Geometry3DTileContent: () => Geometry3DTileContent_default, GeometryAttribute: () => GeometryAttribute_default, GeometryAttributes: () => GeometryAttributes_default, GeometryFactory: () => GeometryFactory_default, GeometryInstance: () => GeometryInstance_default, GeometryInstanceAttribute: () => GeometryInstanceAttribute_default, GeometryOffsetAttribute: () => GeometryOffsetAttribute_default, GeometryPipeline: () => GeometryPipeline_default, GeometryPipelineStage: () => GeometryPipelineStage_default, GeometryType: () => GeometryType_default, GeometryUpdater: () => GeometryUpdater_default, GeometryUpdaterSet: () => GeometryUpdaterSet_default, GeometryVisualizer: () => GeometryVisualizer_default, GetFeatureInfoFormat: () => GetFeatureInfoFormat_default, Globe: () => Globe_default, GlobeDepth: () => GlobeDepth_default, GlobeSurfaceShaderSet: () => GlobeSurfaceShaderSet_default, GlobeSurfaceTile: () => GlobeSurfaceTile_default, GlobeSurfaceTileProvider: () => GlobeSurfaceTileProvider_default, GlobeTranslucency: () => GlobeTranslucency_default, GlobeTranslucencyFramebuffer: () => GlobeTranslucencyFramebuffer_default, GlobeTranslucencyState: () => GlobeTranslucencyState_default, GltfBufferViewLoader: () => GltfBufferViewLoader_default, GltfDracoLoader: () => GltfDracoLoader_default, GltfGpmLoader: () => GltfGpmLoader_default, GltfGpmLocal: () => GltfGpmLocal_default, GltfImageLoader: () => GltfImageLoader_default, GltfIndexBufferLoader: () => GltfIndexBufferLoader_default, GltfJsonLoader: () => GltfJsonLoader_default, GltfLoader: () => GltfLoader_default, GltfLoaderUtil: () => GltfLoaderUtil_default, GltfMeshPrimitiveGpmLoader: () => GltfMeshPrimitiveGpmLoader_default, GltfSpzLoader: () => GltfSpzLoader_default, GltfStructuralMetadataLoader: () => GltfStructuralMetadataLoader_default, GltfTextureLoader: () => GltfTextureLoader_default, GltfVertexBufferLoader: () => GltfVertexBufferLoader_default, Google2DImageryProvider: () => Google2DImageryProvider_default, GoogleEarthEnterpriseImageryProvider: () => GoogleEarthEnterpriseImageryProvider_default, GoogleEarthEnterpriseMapsProvider: () => GoogleEarthEnterpriseMapsProvider_default, GoogleEarthEnterpriseMetadata: () => GoogleEarthEnterpriseMetadata_default, GoogleEarthEnterpriseTerrainData: () => GoogleEarthEnterpriseTerrainData_default, GoogleEarthEnterpriseTerrainProvider: () => GoogleEarthEnterpriseTerrainProvider_default, GoogleEarthEnterpriseTileInformation: () => GoogleEarthEnterpriseTileInformation_default, GoogleGeocoderService: () => GoogleGeocoderService_default, GoogleMaps: () => GoogleMaps_default, GoogleStreetViewCubeMapPanoramaProvider: () => GoogleStreetViewCubeMapPanoramaProvider_default, GpxDataSource: () => GpxDataSource_default, GregorianDate: () => GregorianDate_default, GridImageryProvider: () => GridImageryProvider_default, GridMaterialProperty: () => GridMaterialProperty_default, GroundGeometryUpdater: () => GroundGeometryUpdater_default, GroundPolylineGeometry: () => GroundPolylineGeometry_default, GroundPolylinePrimitive: () => GroundPolylinePrimitive_default, GroundPrimitive: () => GroundPrimitive_default, GroupMetadata: () => GroupMetadata_default, HeadingPitchRange: () => HeadingPitchRange_default, HeadingPitchRoll: () => HeadingPitchRoll_default, Heap: () => Heap_default, HeightReference: () => HeightReference_default, HeightmapEncoding: () => HeightmapEncoding_default, HeightmapTerrainData: () => HeightmapTerrainData_default, HeightmapTessellator: () => HeightmapTessellator_default, HermitePolynomialApproximation: () => HermitePolynomialApproximation_default, HermiteSpline: () => HermiteSpline_default, HilbertOrder: () => HilbertOrder_default, HomeButton: () => HomeButton_default, HomeButtonViewModel: () => HomeButtonViewModel_default, HorizontalOrigin: () => HorizontalOrigin_default, HybridScreenSpacePanCameraController: () => HybridScreenSpacePanCameraController_default, I3SBuildingSceneLayerExplorer: () => I3SBuildingSceneLayerExplorer_default, I3SBuildingSceneLayerExplorerViewModel: () => I3SBuildingSceneLayerExplorerViewModel_default, I3SDataProvider: () => I3SDataProvider_default, I3SDecoder: () => I3SDecoder_default, I3SFeature: () => I3SFeature_default, I3SField: () => I3SField_default, I3SGeometry: () => I3SGeometry_default, I3SLayer: () => I3SLayer_default, I3SNode: () => I3SNode_default, I3SStatistics: () => I3SStatistics_default, I3SSublayer: () => I3SSublayer_default, I3SSymbology: () => I3SSymbology_default, I3dmLoader: () => I3dmLoader_default, I3dmParser: () => I3dmParser_default, ITwinData: () => ITwinData_default, ITwinPlatform: () => ITwinPlatform_default, Iau2000Orientation: () => Iau2000Orientation_default, Iau2006XysData: () => Iau2006XysData_default, Iau2006XysSample: () => Iau2006XysSample_default, IauOrientationAxes: () => IauOrientationAxes_default, IauOrientationParameters: () => IauOrientationParameters_default, ImageBasedLighting: () => ImageBasedLighting_default, ImageBasedLightingPipelineStage: () => ImageBasedLightingPipelineStage_default, ImageMaterialProperty: () => ImageMaterialProperty_default, Imagery: () => Imagery_default, ImageryConfiguration: () => ImageryConfiguration_default, ImageryCoverage: () => ImageryCoverage_default, ImageryFlags: () => ImageryFlags_default, ImageryInput: () => ImageryInput_default, ImageryLayer: () => ImageryLayer_default, ImageryLayerCollection: () => ImageryLayerCollection_default, ImageryLayerFeatureInfo: () => ImageryLayerFeatureInfo_default, ImageryPipelineStage: () => ImageryPipelineStage_default, ImageryProvider: () => ImageryProvider_default, ImageryState: () => ImageryState_default, Implicit3DTileContent: () => Implicit3DTileContent_default, ImplicitAvailabilityBitstream: () => ImplicitAvailabilityBitstream_default, ImplicitMetadataView: () => ImplicitMetadataView_default, ImplicitSubdivisionScheme: () => ImplicitSubdivisionScheme_default, ImplicitSubtree: () => ImplicitSubtree_default, ImplicitSubtreeCache: () => ImplicitSubtreeCache_default, ImplicitSubtreeMetadata: () => ImplicitSubtreeMetadata_default, ImplicitTileCoordinates: () => ImplicitTileCoordinates_default, ImplicitTileset: () => ImplicitTileset_default, IndexDatatype: () => IndexDatatype_default, InfoBox: () => InfoBox_default, InfoBoxViewModel: () => InfoBoxViewModel_default, InspectorShared: () => InspectorShared_default, InstanceAttributeSemantic: () => InstanceAttributeSemantic_default, InstancingPipelineStage: () => InstancingPipelineStage_default, InterpolationAlgorithm: () => InterpolationAlgorithm_default, InterpolationType: () => InterpolationType_default, Intersect: () => Intersect_default, IntersectionTests: () => IntersectionTests_default, Intersections2D: () => Intersections2D_default, Interval: () => Interval_default, InvertClassification: () => InvertClassification_default, Ion: () => Ion_default, IonGeocodeProviderType: () => IonGeocodeProviderType_default, IonGeocoderService: () => IonGeocoderService_default, IonImageryProvider: () => IonImageryProvider_default, IonImageryProviderFactory: () => IonImageryProviderFactory_default, IonResource: () => IonResource_default, IonWorldImageryStyle: () => IonWorldImageryStyle_default, Iso8601: () => Iso8601_default, JobScheduler: () => JobScheduler_default, JobType: () => JobType_default, JsonMetadataTable: () => JsonMetadataTable_default, JulianDate: () => JulianDate_default, KTX2Transcoder: () => KTX2Transcoder_default, KeyboardEventModifier: () => KeyboardEventModifier_default, KeyframeNode: () => KeyframeNode_default, KmlCamera: () => KmlCamera_default, KmlDataSource: () => KmlDataSource_default, KmlLookAt: () => KmlLookAt_default, KmlTour: () => KmlTour_default, KmlTourFlyTo: () => KmlTourFlyTo_default, KmlTourWait: () => KmlTourWait_default, Label: () => Label_default, LabelCollection: () => LabelCollection_default, LabelGraphics: () => LabelGraphics_default, LabelStyle: () => LabelStyle_default, LabelVisualizer: () => LabelVisualizer_default, LagrangePolynomialApproximation: () => LagrangePolynomialApproximation_default, LeapSecond: () => LeapSecond_default, Light: () => Light_default, LightingModel: () => LightingModel_default, LightingPipelineStage: () => LightingPipelineStage_default, LinearApproximation: () => LinearApproximation_default, LinearSpline: () => LinearSpline_default, MVTDataProvider: () => MVTDataProvider_default, ManagedArray: () => ManagedArray_default, MapMode2D: () => MapMode2D_default, MapProjection: () => MapProjection_default, MapboxImageryProvider: () => MapboxImageryProvider_default, MapboxStyleImageryProvider: () => MapboxStyleImageryProvider_default, MappedPositions: () => MappedPositions_default, Material: () => Material_default, MaterialAppearance: () => MaterialAppearance_default, MaterialPipelineStage: () => MaterialPipelineStage_default, MaterialProperty: () => MaterialProperty_default, Math: () => Math_default, Matrix2: () => Matrix2_default, Matrix3: () => Matrix3_default, Matrix4: () => Matrix4_default, Megatexture: () => Megatexture_default2, MeshPrimitiveGpmLocal: () => MeshPrimitiveGpmLocal_default, MetadataClass: () => MetadataClass_default, MetadataClassProperty: () => MetadataClassProperty_default, MetadataComponentType: () => MetadataComponentType_default, MetadataEntity: () => MetadataEntity_default, MetadataEnum: () => MetadataEnum_default, MetadataEnumValue: () => MetadataEnumValue_default, MetadataPicking: () => MetadataPicking_default, MetadataPickingPipelineStage: () => MetadataPickingPipelineStage_default, MetadataPipelineStage: () => MetadataPipelineStage_default, MetadataSchema: () => MetadataSchema_default, MetadataSchemaLoader: () => MetadataSchemaLoader_default, MetadataSemantic: () => MetadataSemantic_default, MetadataTable: () => MetadataTable_default, MetadataTableProperty: () => MetadataTableProperty_default, MetadataType: () => MetadataType_default, MipmapHint: () => MipmapHint_default, Model: () => Model_default, Model3DTileContent: () => Model3DTileContent_default, ModelAlphaOptions: () => ModelAlphaOptions_default, ModelAnimation: () => ModelAnimation_default, ModelAnimationChannel: () => ModelAnimationChannel_default, ModelAnimationCollection: () => ModelAnimationCollection_default, ModelAnimationLoop: () => ModelAnimationLoop_default, ModelAnimationState: () => ModelAnimationState_default, ModelArticulation: () => ModelArticulation_default, ModelArticulationStage: () => ModelArticulationStage_default, ModelClippingPlanesPipelineStage: () => ModelClippingPlanesPipelineStage_default, ModelClippingPolygonsPipelineStage: () => ModelClippingPolygonsPipelineStage_default, ModelColorPipelineStage: () => ModelColorPipelineStage_default, ModelComponents: () => ModelComponents_default, ModelDrawCommand: () => ModelDrawCommand_default, ModelDrawCommands: () => ModelDrawCommands_default, ModelFeature: () => ModelFeature_default, ModelFeatureTable: () => ModelFeatureTable_default, ModelGraphics: () => ModelGraphics_default, ModelImagery: () => ModelImagery_default, ModelImageryMapping: () => ModelImageryMapping_default, ModelLightingOptions: () => ModelLightingOptions_default, ModelMatrixUpdateStage: () => ModelMatrixUpdateStage_default, ModelNode: () => ModelNode_default, ModelPrimitiveImagery: () => ModelPrimitiveImagery_default, ModelReader: () => ModelReader_default, ModelRenderResources: () => ModelRenderResources_default, ModelRuntimeNode: () => ModelRuntimeNode_default, ModelRuntimePrimitive: () => ModelRuntimePrimitive_default, ModelSceneGraph: () => ModelSceneGraph_default, ModelSilhouettePipelineStage: () => ModelSilhouettePipelineStage_default, ModelSkin: () => ModelSkin_default, ModelSplitterPipelineStage: () => ModelSplitterPipelineStage_default, ModelStatistics: () => ModelStatistics_default, ModelType: () => ModelType_default, ModelUtility: () => ModelUtility_default, ModelVisualizer: () => ModelVisualizer_default, Moon: () => Moon_default, MorphTargetsPipelineStage: () => MorphTargetsPipelineStage_default, MorphWeightSpline: () => MorphWeightSpline_default, MortonOrder: () => MortonOrder_default, MouseButton: () => MouseButton_default, Multiple3DTileContent: () => Multiple3DTileContent_default, MultisampleFramebuffer: () => MultisampleFramebuffer_default, NavigationHelpButton: () => NavigationHelpButton_default, NavigationHelpButtonViewModel: () => NavigationHelpButtonViewModel_default, NearFarScalar: () => NearFarScalar_default, NeverTileDiscardPolicy: () => NeverTileDiscardPolicy_default, NodeRenderResources: () => NodeRenderResources_default, NodeStatisticsPipelineStage: () => NodeStatisticsPipelineStage_default, NodeTransformationProperty: () => NodeTransformationProperty_default, OIT: () => OIT_default, Occluder: () => Occluder_default, OffsetGeometryInstanceAttribute: () => OffsetGeometryInstanceAttribute_default, OpenCageGeocoderService: () => OpenCageGeocoderService_default, OpenStreetMapImageryProvider: () => OpenStreetMapImageryProvider_default, OrderedGroundPrimitiveCollection: () => OrderedGroundPrimitiveCollection_default, OrientedBoundingBox: () => OrientedBoundingBox_default, OrthographicFrustum: () => OrthographicFrustum_default, OrthographicOffCenterFrustum: () => OrthographicOffCenterFrustum_default, Packable: () => Packable_default, PackableForInterpolation: () => PackableForInterpolation_default, Panorama: () => Panorama_default, PanoramaProvider: () => PanoramaProvider_default, Particle: () => Particle_default, ParticleBurst: () => ParticleBurst_default, ParticleEmitter: () => ParticleEmitter_default, ParticleSystem: () => ParticleSystem_default, Pass: () => Pass_default, PassState: () => PassState_default, PathGraphics: () => PathGraphics_default, PathMode: () => PathMode_default, PathVisualizer: () => PathVisualizer_default, PeliasGeocoderService: () => PeliasGeocoderService_default, PerInstanceColorAppearance: () => PerInstanceColorAppearance_default, PerformanceDisplay: () => PerformanceDisplay_default, PerformanceWatchdog: () => PerformanceWatchdog_default, PerformanceWatchdogViewModel: () => PerformanceWatchdogViewModel_default, PerspectiveFrustum: () => PerspectiveFrustum_default, PerspectiveOffCenterFrustum: () => PerspectiveOffCenterFrustum_default, PickDepth: () => PickDepth_default, PickDepthFramebuffer: () => PickDepthFramebuffer_default, PickFramebuffer: () => PickFramebuffer_default, PickId: () => PickId_default, PickedMetadataInfo: () => PickedMetadataInfo_default, Picking: () => Picking_default, PickingPipelineStage: () => PickingPipelineStage_default, PinBuilder: () => PinBuilder_default, PixelDatatype: () => PixelDatatype_default, PixelFormat: () => PixelFormat_default, PlanarFillIdFramebuffer: () => PlanarFillIdFramebuffer_default, Plane: () => Plane_default, PlaneGeometry: () => PlaneGeometry_default, PlaneGeometryUpdater: () => PlaneGeometryUpdater_default, PlaneGraphics: () => PlaneGraphics_default, PlaneOutlineGeometry: () => PlaneOutlineGeometry_default, PntsLoader: () => PntsLoader_default, PntsParser: () => PntsParser_default, PointCloud: () => PointCloud_default, PointCloudEyeDomeLighting: () => PointCloudEyeDomeLighting_default2, PointCloudShading: () => PointCloudShading_default, PointCloudStylingPipelineStage: () => PointCloudStylingPipelineStage_default, PointGraphics: () => PointGraphics_default, PointPrimitive: () => PointPrimitive_default, PointPrimitiveCollection: () => PointPrimitiveCollection_default, PointVisualizer: () => PointVisualizer_default, PolygonGeometry: () => PolygonGeometry_default, PolygonGeometryLibrary: () => PolygonGeometryLibrary_default, PolygonGeometryUpdater: () => PolygonGeometryUpdater_default, PolygonGraphics: () => PolygonGraphics_default, PolygonHierarchy: () => PolygonHierarchy_default, PolygonOutlineGeometry: () => PolygonOutlineGeometry_default, PolygonPipeline: () => PolygonPipeline_default, Polyline: () => Polyline_default, PolylineArrowMaterialProperty: () => PolylineArrowMaterialProperty_default, PolylineCollection: () => PolylineCollection_default, PolylineColorAppearance: () => PolylineColorAppearance_default, PolylineDashMaterialProperty: () => PolylineDashMaterialProperty_default, PolylineGeometry: () => PolylineGeometry_default, PolylineGeometryUpdater: () => PolylineGeometryUpdater_default, PolylineGlowMaterialProperty: () => PolylineGlowMaterialProperty_default, PolylineGraphics: () => PolylineGraphics_default, PolylineMaterialAppearance: () => PolylineMaterialAppearance_default, PolylineOutlineMaterialProperty: () => PolylineOutlineMaterialProperty_default, PolylinePipeline: () => PolylinePipeline_default, PolylineVisualizer: () => PolylineVisualizer_default, PolylineVolumeGeometry: () => PolylineVolumeGeometry_default, PolylineVolumeGeometryLibrary: () => PolylineVolumeGeometryLibrary_default, PolylineVolumeGeometryUpdater: () => PolylineVolumeGeometryUpdater_default, PolylineVolumeGraphics: () => PolylineVolumeGraphics_default, PolylineVolumeOutlineGeometry: () => PolylineVolumeOutlineGeometry_default, PositionProperty: () => PositionProperty_default, PositionPropertyArray: () => PositionPropertyArray_default, PostProcessStage: () => PostProcessStage_default, PostProcessStageCollection: () => PostProcessStageCollection_default, PostProcessStageComposite: () => PostProcessStageComposite_default, PostProcessStageLibrary: () => PostProcessStageLibrary_default, PostProcessStageSampleMode: () => PostProcessStageSampleMode_default, PostProcessStageTextureCache: () => PostProcessStageTextureCache_default, PpeMetadata: () => PpeMetadata_default, PpeSource: () => PpeSource_default, PpeTexture: () => PpeTexture_default, Primitive: () => Primitive_default, PrimitiveCollection: () => PrimitiveCollection_default, PrimitiveLoadPlan: () => PrimitiveLoadPlan_default, PrimitiveOutlineGenerator: () => PrimitiveOutlineGenerator_default, PrimitiveOutlinePipelineStage: () => PrimitiveOutlinePipelineStage_default, PrimitivePipeline: () => PrimitivePipeline_default, PrimitiveRenderResources: () => PrimitiveRenderResources_default, PrimitiveState: () => PrimitiveState_default, PrimitiveStatisticsPipelineStage: () => PrimitiveStatisticsPipelineStage_default, PrimitiveType: () => PrimitiveType_default, ProjectionPicker: () => ProjectionPicker_default, ProjectionPickerViewModel: () => ProjectionPickerViewModel_default, Property: () => Property_default, PropertyArray: () => PropertyArray_default, PropertyAttribute: () => PropertyAttribute_default, PropertyAttributeProperty: () => PropertyAttributeProperty_default, PropertyBag: () => PropertyBag_default, PropertyTable: () => PropertyTable_default, PropertyTexture: () => PropertyTexture_default, PropertyTextureProperty: () => PropertyTextureProperty_default, ProviderViewModel: () => ProviderViewModel_default, Proxy: () => Proxy_default, QuadraticRealPolynomial: () => QuadraticRealPolynomial_default, QuadtreeOccluders: () => QuadtreeOccluders_default, QuadtreePrimitive: () => QuadtreePrimitive_default, QuadtreeTile: () => QuadtreeTile_default, QuadtreeTileLoadState: () => QuadtreeTileLoadState_default, QuadtreeTileProvider: () => QuadtreeTileProvider_default, QuantizedMeshTerrainData: () => QuantizedMeshTerrainData_default, QuarticRealPolynomial: () => QuarticRealPolynomial_default, Quaternion: () => Quaternion_default, QuaternionSpline: () => QuaternionSpline_default, Queue: () => Queue_default, Ray: () => Ray_default, Rectangle: () => Rectangle_default, RectangleCollisionChecker: () => RectangleCollisionChecker_default, RectangleGeometry: () => RectangleGeometry_default, RectangleGeometryLibrary: () => RectangleGeometryLibrary_default, RectangleGeometryUpdater: () => RectangleGeometryUpdater_default, RectangleGraphics: () => RectangleGraphics_default, RectangleOutlineGeometry: () => RectangleOutlineGeometry_default, ReferenceFrame: () => ReferenceFrame_default, ReferenceProperty: () => ReferenceProperty_default, RenderState: () => RenderState_default, Renderbuffer: () => Renderbuffer_default, RenderbufferFormat: () => RenderbufferFormat_default, Request: () => Request_default, RequestErrorEvent: () => RequestErrorEvent_default, RequestScheduler: () => RequestScheduler_default, RequestState: () => RequestState_default, RequestType: () => RequestType_default, Resource: () => Resource_default, ResourceCache: () => ResourceCache_default, ResourceCacheKey: () => ResourceCacheKey_default, ResourceCacheStatistics: () => ResourceCacheStatistics_default, ResourceLoader: () => ResourceLoader_default, ResourceLoaderState: () => ResourceLoaderState_default, Rotation: () => Rotation_default, RuntimeError: () => RuntimeError_default, S2Cell: () => S2Cell_default, SDFSettings: () => SDFSettings_default, SampledPositionProperty: () => SampledPositionProperty_default, SampledProperty: () => SampledProperty_default, Sampler: () => Sampler_default, ScaledPositionProperty: () => ScaledPositionProperty_default, Scene: () => Scene_default, SceneFramebuffer: () => SceneFramebuffer_default, SceneMode: () => SceneMode_default, SceneMode2DPipelineStage: () => SceneMode2DPipelineStage_default, SceneModePicker: () => SceneModePicker_default, SceneModePickerViewModel: () => SceneModePickerViewModel_default, SceneTransforms: () => SceneTransforms_default, SceneTransitioner: () => SceneTransitioner_default, ScreenSpaceCameraController: () => ScreenSpaceCameraController_default, ScreenSpaceElevatorCameraController: () => ScreenSpaceElevatorCameraController_default, ScreenSpaceEventHandler: () => ScreenSpaceEventHandler_default, ScreenSpaceEventType: () => ScreenSpaceEventType_default, ScreenSpaceInputBindings: () => ScreenSpaceInputBindings_default, ScreenSpaceMapCameraController: () => ScreenSpaceMapCameraController_default, ScreenSpaceTiltOrbitCameraController: () => ScreenSpaceTiltOrbitCameraController_default, ScreenSpaceZoomCameraController: () => ScreenSpaceZoomCameraController_default, SelectedFeatureIdPipelineStage: () => SelectedFeatureIdPipelineStage_default, SelectionIndicator: () => SelectionIndicator_default, SelectionIndicatorViewModel: () => SelectionIndicatorViewModel_default, SensorVolumePortionToDisplay: () => SensorVolumePortionToDisplay_default, ShaderBuilder: () => ShaderBuilder_default, ShaderCache: () => ShaderCache_default, ShaderDestination: () => ShaderDestination_default, ShaderFunction: () => ShaderFunction_default, ShaderProgram: () => ShaderProgram_default, ShaderSource: () => ShaderSource_default, ShaderStruct: () => ShaderStruct_default, ShadowMap: () => ShadowMap_default, ShadowMapShader: () => ShadowMapShader_default, ShadowMode: () => ShadowMode_default, ShadowVolumeAppearance: () => ShadowVolumeAppearance_default, SharedContext: () => SharedContext_default, ShowGeometryInstanceAttribute: () => ShowGeometryInstanceAttribute_default, Simon1994PlanetaryPositions: () => Simon1994PlanetaryPositions_default, SimplePolylineGeometry: () => SimplePolylineGeometry_default, SingleTileImageryProvider: () => SingleTileImageryProvider_default, SkinningPipelineStage: () => SkinningPipelineStage_default, SkyAtmosphere: () => SkyAtmosphere_default, SkyBox: () => SkyBox_default, SnapFramebuffer: () => SnapFramebuffer_default, Snapping: () => Snapping_default, SpatialNode: () => SpatialNode_default, Spdcf: () => Spdcf_default, SpecularEnvironmentCubeMap: () => SpecularEnvironmentCubeMap_default, SphereEmitter: () => SphereEmitter_default, SphereGeometry: () => SphereGeometry_default, SphereOutlineGeometry: () => SphereOutlineGeometry_default, Spherical: () => Spherical_default, Spline: () => Spline_default, SplitDirection: () => SplitDirection_default, Splitter: () => Splitter_default, StaticGeometryColorBatch: () => StaticGeometryColorBatch_default, StaticGeometryPerMaterialBatch: () => StaticGeometryPerMaterialBatch_default, StaticGroundGeometryColorBatch: () => StaticGroundGeometryColorBatch_default, StaticGroundGeometryPerMaterialBatch: () => StaticGroundGeometryPerMaterialBatch_default, StaticGroundPolylinePerMaterialBatch: () => StaticGroundPolylinePerMaterialBatch_default, StaticOutlineGeometryBatch: () => StaticOutlineGeometryBatch_default, StencilConstants: () => StencilConstants_default, StencilFunction: () => StencilFunction_default, StencilOperation: () => StencilOperation_default, SteppedSpline: () => SteppedSpline_default, Stereographic: () => Stereographic_default, StorageType: () => StorageType_default, StripeMaterialProperty: () => StripeMaterialProperty_default, StripeOrientation: () => StripeOrientation_default, StructuralMetadata: () => StructuralMetadata_default, StyleCommandsNeeded: () => StyleCommandsNeeded_default, StyleExpression: () => StyleExpression_default, Sun: () => Sun_default, SunLight: () => SunLight_default, SunPostProcess: () => SunPostProcess_default, SupportedImageFormats: () => SupportedImageFormats_default, SvgPathBindingHandler: () => SvgPathBindingHandler_default, Sync: () => Sync_default, TaskProcessor: () => TaskProcessor_default, Terrain: () => Terrain_default, TerrainData: () => TerrainData_default, TerrainEncoding: () => TerrainEncoding_default, TerrainFillMesh: () => TerrainFillMesh_default, TerrainMesh: () => TerrainMesh_default, TerrainOffsetProperty: () => TerrainOffsetProperty_default, TerrainPicker: () => TerrainPicker_default, TerrainProvider: () => TerrainProvider_default, TerrainQuantization: () => TerrainQuantization_default, TerrainState: () => TerrainState_default, Texture: () => Texture_default, Texture3D: () => Texture3D_default, TextureAtlas: () => TextureAtlas_default, TextureCache: () => TextureCache_default, TextureMagnificationFilter: () => TextureMagnificationFilter_default, TextureManager: () => TextureManager_default, TextureMinificationFilter: () => TextureMinificationFilter_default, TexturePacker: () => TexturePacker_default, TextureUniform: () => TextureUniform_default, TextureWrap: () => TextureWrap_default, TileAvailability: () => TileAvailability_default, TileBoundingRegion: () => TileBoundingRegion_default, TileBoundingS2Cell: () => TileBoundingS2Cell_default, TileBoundingSphere: () => TileBoundingSphere_default, TileBoundingVolume: () => TileBoundingVolume_default, TileCoordinatesImageryProvider: () => TileCoordinatesImageryProvider_default, TileDiscardPolicy: () => TileDiscardPolicy_default, TileEdge: () => TileEdge_default, TileImagery: () => TileImagery_default, TileMapServiceImageryProvider: () => TileMapServiceImageryProvider_default, TileMetadata: () => TileMetadata_default, TileOrientedBoundingBox: () => TileOrientedBoundingBox_default, TileProviderError: () => TileProviderError_default, TileReplacementQueue: () => TileReplacementQueue_default, TileSelectionResult: () => TileSelectionResult_default, TileState: () => TileState_default, Tileset3DTileContent: () => Tileset3DTileContent_default, TilesetMetadata: () => TilesetMetadata_default, TilesetPipelineStage: () => TilesetPipelineStage_default, TilingScheme: () => TilingScheme_default, TimeConstants: () => TimeConstants_default, TimeDynamicImagery: () => TimeDynamicImagery_default, TimeDynamicPointCloud: () => TimeDynamicPointCloud_default, TimeInterval: () => TimeInterval_default, TimeIntervalCollection: () => TimeIntervalCollection_default, TimeIntervalCollectionPositionProperty: () => TimeIntervalCollectionPositionProperty_default, TimeIntervalCollectionProperty: () => TimeIntervalCollectionProperty_default, TimeStandard: () => TimeStandard_default, Timeline: () => Timeline_default, TimelineHighlightRange: () => TimelineHighlightRange_default, TimelineTrack: () => TimelineTrack_default, Tipsify: () => Tipsify_default, ToggleButtonViewModel: () => ToggleButtonViewModel_default, Tonemapper: () => Tonemapper_default, TrackingReferenceFrame: () => TrackingReferenceFrame_default, Transforms: () => Transforms_default, TranslationRotationScale: () => TranslationRotationScale_default, TranslucentTileClassification: () => TranslucentTileClassification_default, TridiagonalSystemSolver: () => TridiagonalSystemSolver_default, TrustedServers: () => TrustedServers_default, TweenCollection: () => TweenCollection_default, UniformState: () => UniformState_default, UniformType: () => UniformType_default, UrlTemplate3DTilesDataProvider: () => UrlTemplate3DTilesDataProvider_default, UrlTemplateImageryProvider: () => UrlTemplateImageryProvider_default, VERSION: () => VERSION2, VRButton: () => VRButton_default, VRButtonViewModel: () => VRButtonViewModel_default, VRTheWorldTerrainProvider: () => VRTheWorldTerrainProvider_default, VaryingType: () => VaryingType_default, Vector3DTileBatch: () => Vector3DTileBatch_default, Vector3DTileClampedPolylines: () => Vector3DTileClampedPolylines_default, Vector3DTileContent: () => Vector3DTileContent_default, Vector3DTileGeometry: () => Vector3DTileGeometry_default, Vector3DTilePoints: () => Vector3DTilePoints_default, Vector3DTilePolygons: () => Vector3DTilePolygons_default, Vector3DTilePolylines: () => Vector3DTilePolylines_default, Vector3DTilePrimitive: () => Vector3DTilePrimitive_default, VectorGltf3DTileContent: () => VectorGltf3DTileContent_default, VectorPipeline: () => VectorPipeline_default, VectorProvider: () => VectorProvider_default, VelocityOrientationProperty: () => VelocityOrientationProperty_default, VelocityVectorProperty: () => VelocityVectorProperty_default, VertexArray: () => VertexArray_default, VertexArrayFacade: () => VertexArrayFacade_default, VertexAttributeSemantic: () => VertexAttributeSemantic_default, VertexFormat: () => VertexFormat_default, VerticalExaggeration: () => VerticalExaggeration_default, VerticalExaggerationPipelineStage: () => VerticalExaggerationPipelineStage_default, VerticalOrigin: () => VerticalOrigin_default, VideoSynchronizer: () => VideoSynchronizer_default, View: () => View_default, Viewer: () => Viewer_default, ViewportQuad: () => ViewportQuad_default, Visibility: () => Visibility_default, Visualizer: () => Visualizer_default, VoxelBoundsCollection: () => VoxelBoundsCollection_default, VoxelBoxShape: () => VoxelBoxShape_default, VoxelCell: () => VoxelCell_default, VoxelContent: () => VoxelContent_default, VoxelCylinderShape: () => VoxelCylinderShape_default, VoxelEllipsoidShape: () => VoxelEllipsoidShape_default, VoxelInspector: () => VoxelInspector_default, VoxelInspectorViewModel: () => VoxelInspectorViewModel_default, VoxelMetadataOrder: () => VoxelMetadataOrder_default, VoxelPrimitive: () => VoxelPrimitive_default, VoxelProvider: () => VoxelProvider_default, VoxelRenderResources: () => VoxelRenderResources_default, VoxelShape: () => VoxelShape_default, VoxelShapeType: () => VoxelShapeType_default, VoxelTraversal: () => VoxelTraversal_default, VulkanConstants: () => VulkanConstants_default, WallGeometry: () => WallGeometry_default, WallGeometryLibrary: () => WallGeometryLibrary_default, WallGeometryUpdater: () => WallGeometryUpdater_default, WallGraphics: () => WallGraphics_default, WallOutlineGeometry: () => WallOutlineGeometry_default, WebGLConstants: () => WebGLConstants_default, WebMapServiceImageryProvider: () => WebMapServiceImageryProvider_default, WebMapTileServiceImageryProvider: () => WebMapTileServiceImageryProvider_default, WebMercatorProjection: () => WebMercatorProjection_default, WebMercatorTilingScheme: () => WebMercatorTilingScheme_default, WindingOrder: () => WindingOrder_default, WireframeIndexGenerator: () => WireframeIndexGenerator_default, WireframePipelineStage: () => WireframePipelineStage_default, _shadersAcesTonemappingStage: () => AcesTonemappingStage_default, _shadersAdditiveBlend: () => AdditiveBlend_default, _shadersAdjustTranslucentFS: () => AdjustTranslucentFS_default, _shadersAllMaterialAppearanceFS: () => AllMaterialAppearanceFS_default, _shadersAllMaterialAppearanceVS: () => AllMaterialAppearanceVS_default, _shadersAmbientOcclusionGenerate: () => AmbientOcclusionGenerate_default, _shadersAmbientOcclusionModulate: () => AmbientOcclusionModulate_default, _shadersAspectRampMaterial: () => AspectRampMaterial_default, _shadersAtmosphereCommon: () => AtmosphereCommon_default, _shadersAtmosphereStageFS: () => AtmosphereStageFS_default, _shadersAtmosphereStageVS: () => AtmosphereStageVS_default, _shadersBasicMaterialAppearanceFS: () => BasicMaterialAppearanceFS_default, _shadersBasicMaterialAppearanceVS: () => BasicMaterialAppearanceVS_default, _shadersBillboardCollectionFS: () => BillboardCollectionFS_default, _shadersBillboardCollectionVS: () => BillboardCollectionVS_default, _shadersBlackAndWhite: () => BlackAndWhite_default, _shadersBloomComposite: () => BloomComposite_default, _shadersBrdfLutGeneratorFS: () => BrdfLutGeneratorFS_default, _shadersBrightPass: () => BrightPass_default, _shadersBrightness: () => Brightness_default, _shadersBufferPointMaterialFS: () => BufferPointMaterialFS_default, _shadersBufferPointMaterialVS: () => BufferPointMaterialVS_default, _shadersBufferPolygonMaterialFS: () => BufferPolygonMaterialFS_default, _shadersBufferPolygonMaterialVS: () => BufferPolygonMaterialVS_default, _shadersBufferPolylineMaterialFS: () => BufferPolylineMaterialFS_default, _shadersBufferPolylineMaterialVS: () => BufferPolylineMaterialVS_default, _shadersBumpMapMaterial: () => BumpMapMaterial_default, _shadersCPUStylingStageFS: () => CPUStylingStageFS_default, _shadersCPUStylingStageVS: () => CPUStylingStageVS_default, _shadersCheckerboardMaterial: () => CheckerboardMaterial_default, _shadersCloudCollectionFS: () => CloudCollectionFS_default, _shadersCloudCollectionVS: () => CloudCollectionVS_default, _shadersCloudNoiseFS: () => CloudNoiseFS_default, _shadersCloudNoiseVS: () => CloudNoiseVS_default, _shadersCompareAndPackTranslucentDepth: () => CompareAndPackTranslucentDepth_default, _shadersCompositeOITFS: () => CompositeOITFS_default, _shadersCompositeTranslucentClassification: () => CompositeTranslucentClassification_default, _shadersComputeIrradianceFS: () => ComputeIrradianceFS_default, _shadersComputeRadianceMapFS: () => ComputeRadianceMapFS_default, _shadersConstantLodStageFS: () => ConstantLodStageFS_default, _shadersConstantLodStageVS: () => ConstantLodStageVS_default, _shadersContrastBias: () => ContrastBias_default, _shadersConvolveSpecularMapFS: () => ConvolveSpecularMapFS_default, _shadersConvolveSpecularMapVS: () => ConvolveSpecularMapVS_default, _shadersCubeMapPanoramaVS: () => CubeMapPanoramaVS_default, _shadersCustomShaderStageFS: () => CustomShaderStageFS_default, _shadersCustomShaderStageVS: () => CustomShaderStageVS_default, _shadersCzmBuiltins: () => CzmBuiltins_default, _shadersDepthOfField: () => DepthOfField_default, _shadersDepthPlaneFS: () => DepthPlaneFS_default, _shadersDepthPlaneVS: () => DepthPlaneVS_default, _shadersDepthView: () => DepthView_default, _shadersDepthViewPacked: () => DepthViewPacked_default, _shadersDotMaterial: () => DotMaterial_default, _shadersEdgeDetection: () => EdgeDetection_default, _shadersEdgeDetectionStageFS: () => EdgeDetectionStageFS_default, _shadersEdgeVisibilityStageFS: () => EdgeVisibilityStageFS_default, _shadersEdgeVisibilityStageVS: () => EdgeVisibilityStageVS_default, _shadersElevationBandMaterial: () => ElevationBandMaterial_default, _shadersElevationContourMaterial: () => ElevationContourMaterial_default, _shadersElevationRampMaterial: () => ElevationRampMaterial_default, _shadersEllipsoidFS: () => EllipsoidFS_default, _shadersEllipsoidSurfaceAppearanceFS: () => EllipsoidSurfaceAppearanceFS_default, _shadersEllipsoidSurfaceAppearanceVS: () => EllipsoidSurfaceAppearanceVS_default, _shadersEllipsoidVS: () => EllipsoidVS_default, _shadersFXAA: () => FXAA_default, _shadersFXAA3_11: () => FXAA3_11_default, _shadersFadeMaterial: () => FadeMaterial_default, _shadersFeatureIdStageFS: () => FeatureIdStageFS_default, _shadersFeatureIdStageVS: () => FeatureIdStageVS_default, _shadersFilmicTonemapping: () => FilmicTonemapping_default, _shadersGaussianBlur1D: () => GaussianBlur1D_default, _shadersGeometryStageFS: () => GeometryStageFS_default, _shadersGeometryStageVS: () => GeometryStageVS_default, _shadersGlobeFS: () => GlobeFS_default, _shadersGlobeVS: () => GlobeVS_default, _shadersGridMaterial: () => GridMaterial_default, _shadersGroundAtmosphere: () => GroundAtmosphere_default, _shadersHSBToRGB: () => HSBToRGB_default, _shadersHSLToRGB: () => HSLToRGB_default, _shadersImageBasedLightingStageFS: () => ImageBasedLightingStageFS_default, _shadersInstancingStageCommon: () => InstancingStageCommon_default, _shadersInstancingStageVS: () => InstancingStageVS_default, _shadersIntersectBox: () => IntersectBox_default, _shadersIntersectCylinder: () => IntersectCylinder_default, _shadersIntersectDepth: () => IntersectDepth_default, _shadersIntersectEllipsoid: () => IntersectEllipsoid_default, _shadersIntersectLongitude: () => IntersectLongitude_default, _shadersIntersectPlane: () => IntersectPlane_default, _shadersIntersection: () => Intersection_default, _shadersIntersectionUtils: () => IntersectionUtils_default, _shadersLegacyInstancingStageVS: () => LegacyInstancingStageVS_default, _shadersLensFlare: () => LensFlare_default, _shadersLightingStageFS: () => LightingStageFS_default, _shadersMaterialStageFS: () => MaterialStageFS_default, _shadersMegatexture: () => Megatexture_default, _shadersMetadataStageFS: () => MetadataStageFS_default, _shadersMetadataStageVS: () => MetadataStageVS_default, _shadersModelClippingPlanesStageFS: () => ModelClippingPlanesStageFS_default, _shadersModelClippingPolygonsStageFS: () => ModelClippingPolygonsStageFS_default, _shadersModelClippingPolygonsStageVS: () => ModelClippingPolygonsStageVS_default, _shadersModelColorStageFS: () => ModelColorStageFS_default, _shadersModelFS: () => ModelFS_default, _shadersModelSilhouetteStageFS: () => ModelSilhouetteStageFS_default, _shadersModelSilhouetteStageVS: () => ModelSilhouetteStageVS_default, _shadersModelSplitterStageFS: () => ModelSplitterStageFS_default, _shadersModelVS: () => ModelVS_default, _shadersModifiedReinhardTonemapping: () => ModifiedReinhardTonemapping_default, _shadersMorphTargetsStageVS: () => MorphTargetsStageVS_default, _shadersNightVision: () => NightVision_default, _shadersNormalMapMaterial: () => NormalMapMaterial_default, _shadersOctree: () => Octree_default, _shadersPassThrough: () => PassThrough_default, _shadersPassThroughDepth: () => PassThroughDepth_default, _shadersPbrNeutralTonemapping: () => PbrNeutralTonemapping_default, _shadersPerInstanceColorAppearanceFS: () => PerInstanceColorAppearanceFS_default, _shadersPerInstanceColorAppearanceVS: () => PerInstanceColorAppearanceVS_default, _shadersPerInstanceFlatColorAppearanceFS: () => PerInstanceFlatColorAppearanceFS_default, _shadersPerInstanceFlatColorAppearanceVS: () => PerInstanceFlatColorAppearanceVS_default, _shadersPointCloudEyeDomeLighting: () => PointCloudEyeDomeLighting_default, _shadersPointCloudStylingStageVS: () => PointCloudStylingStageVS_default, _shadersPointPrimitiveCollectionFS: () => PointPrimitiveCollectionFS_default, _shadersPointPrimitiveCollectionVS: () => PointPrimitiveCollectionVS_default, _shadersPolygonSignedDistanceFS: () => PolygonSignedDistanceFS_default, _shadersPolylineArrowMaterial: () => PolylineArrowMaterial_default, _shadersPolylineColorAppearanceVS: () => PolylineColorAppearanceVS_default, _shadersPolylineCommon: () => PolylineCommon_default, _shadersPolylineDashMaterial: () => PolylineDashMaterial_default, _shadersPolylineFS: () => PolylineFS_default, _shadersPolylineGlowMaterial: () => PolylineGlowMaterial_default, _shadersPolylineMaterialAppearanceVS: () => PolylineMaterialAppearanceVS_default, _shadersPolylineOutlineMaterial: () => PolylineOutlineMaterial_default, _shadersPolylineShadowVolumeFS: () => PolylineShadowVolumeFS_default, _shadersPolylineShadowVolumeMorphFS: () => PolylineShadowVolumeMorphFS_default, _shadersPolylineShadowVolumeMorphVS: () => PolylineShadowVolumeMorphVS_default, _shadersPolylineShadowVolumeVS: () => PolylineShadowVolumeVS_default, _shadersPolylineVS: () => PolylineVS_default, _shadersPrimitiveGaussianSplatFS: () => PrimitiveGaussianSplatFS_default, _shadersPrimitiveGaussianSplatVS: () => PrimitiveGaussianSplatVS_default, _shadersPrimitiveOutlineStageFS: () => PrimitiveOutlineStageFS_default, _shadersPrimitiveOutlineStageVS: () => PrimitiveOutlineStageVS_default, _shadersRGBToHSB: () => RGBToHSB_default, _shadersRGBToHSL: () => RGBToHSL_default, _shadersRGBToXYZ: () => RGBToXYZ_default, _shadersReinhardTonemapping: () => ReinhardTonemapping_default, _shadersReprojectWebMercatorFS: () => ReprojectWebMercatorFS_default, _shadersReprojectWebMercatorVS: () => ReprojectWebMercatorVS_default, _shadersRimLightingMaterial: () => RimLightingMaterial_default, _shadersSelectedFeatureIdStageCommon: () => SelectedFeatureIdStageCommon_default, _shadersShadowVolumeAppearanceFS: () => ShadowVolumeAppearanceFS_default, _shadersShadowVolumeAppearanceVS: () => ShadowVolumeAppearanceVS_default, _shadersShadowVolumeFS: () => ShadowVolumeFS_default, _shadersSilhouette: () => Silhouette_default, _shadersSkinningStageVS: () => SkinningStageVS_default, _shadersSkyAtmosphereCommon: () => SkyAtmosphereCommon_default, _shadersSkyAtmosphereFS: () => SkyAtmosphereFS_default, _shadersSkyAtmosphereVS: () => SkyAtmosphereVS_default, _shadersSkyBoxFS: () => SkyBoxFS_default, _shadersSkyBoxVS: () => SkyBoxVS_default, _shadersSlopeRampMaterial: () => SlopeRampMaterial_default, _shadersStripeMaterial: () => StripeMaterial_default, _shadersSunFS: () => SunFS_default, _shadersSunTextureFS: () => SunTextureFS_default, _shadersSunVS: () => SunVS_default, _shadersTexturedMaterialAppearanceFS: () => TexturedMaterialAppearanceFS_default, _shadersTexturedMaterialAppearanceVS: () => TexturedMaterialAppearanceVS_default, _shadersVector3DTileClampedPolylinesFS: () => Vector3DTileClampedPolylinesFS_default, _shadersVector3DTileClampedPolylinesVS: () => Vector3DTileClampedPolylinesVS_default, _shadersVector3DTilePolylinesVS: () => Vector3DTilePolylinesVS_default, _shadersVectorCommon: () => VectorCommon_default, _shadersVectorTileVS: () => VectorTileVS_default, _shadersVerticalExaggerationStageVS: () => VerticalExaggerationStageVS_default, _shadersViewportQuadFS: () => ViewportQuadFS_default, _shadersViewportQuadVS: () => ViewportQuadVS_default, _shadersVoxelFS: () => VoxelFS_default, _shadersVoxelUtils: () => VoxelUtils_default, _shadersVoxelVS: () => VoxelVS_default, _shadersWater: () => Water_default, _shadersWaterMaskMaterial: () => WaterMaskMaterial_default, _shadersXYZToRGB: () => XYZToRGB_default, _shadersacesTonemapping: () => acesTonemapping_default, _shadersalphaWeight: () => alphaWeight_default, _shadersantialias: () => antialias_default, _shadersapplyHSBShift: () => applyHSBShift_default, _shadersapproximateSphericalCoordinates: () => approximateSphericalCoordinates_default, _shadersapproximateTanh: () => approximateTanh_default, _shadersbackFacing: () => backFacing_default, _shadersbranchFreeTernary: () => branchFreeTernary_default, _shaderscascadeColor: () => cascadeColor_default, _shaderscascadeDistance: () => cascadeDistance_default, _shaderscascadeMatrix: () => cascadeMatrix_default, _shaderscascadeWeights: () => cascadeWeights_default, _shadersclipPolygons: () => clipPolygons_default, _shaderscolumbusViewMorph: () => columbusViewMorph_default, _shaderscomputeAtmosphereColor: () => computeAtmosphereColor_default, _shaderscomputeGroundAtmosphereScattering: () => computeGroundAtmosphereScattering_default, _shaderscomputePosition: () => computePosition_default, _shaderscomputeScattering: () => computeScattering_default, _shaderscomputeTextureTransform: () => computeTextureTransform_default, _shadersconvertLocalToBoxUv: () => convertLocalToBoxUv_default, _shadersconvertLocalToCylinderUv: () => convertLocalToCylinderUv_default, _shadersconvertLocalToEllipsoidUv: () => convertLocalToEllipsoidUv_default, _shaderscosineAndSine: () => cosineAndSine_default, _shadersdecodeRGB8: () => decodeRGB8_default, _shadersdecompressTextureCoordinates: () => decompressTextureCoordinates_default, _shadersdegreesPerRadian: () => degreesPerRadian_default, _shadersdepthClamp: () => depthClamp_default, _shadersdepthRange: () => depthRange_default, _shadersdepthRangeStruct: () => depthRangeStruct_default, _shaderseastNorthUpToEyeCoordinates: () => eastNorthUpToEyeCoordinates_default, _shadersellipsoidContainsPoint: () => ellipsoidContainsPoint_default, _shadersellipsoidTextureCoordinates: () => ellipsoidTextureCoordinates_default, _shadersepsilon1: () => epsilon1_default, _shadersepsilon2: () => epsilon2_default, _shadersepsilon3: () => epsilon3_default, _shadersepsilon4: () => epsilon4_default, _shadersepsilon5: () => epsilon5_default, _shadersepsilon6: () => epsilon6_default, _shadersepsilon7: () => epsilon7_default, _shadersequalsEpsilon: () => equalsEpsilon_default, _shaderseyeOffset: () => eyeOffset_default, _shaderseyeToWindowCoordinates: () => eyeToWindowCoordinates_default, _shadersfastApproximateAtan: () => fastApproximateAtan_default, _shadersfog: () => fog_default, _shadersgammaCorrect: () => gammaCorrect_default, _shadersgeodeticSurfaceNormal: () => geodeticSurfaceNormal_default, _shadersgetDefaultMaterial: () => getDefaultMaterial_default, _shadersgetDynamicAtmosphereLightDirection: () => getDynamicAtmosphereLightDirection_default, _shadersgetLambertDiffuse: () => getLambertDiffuse_default, _shadersgetSpecular: () => getSpecular_default, _shadersgetWaterNoise: () => getWaterNoise_default, _shadershue: () => hue_default, _shadersinfinity: () => infinity_default, _shadersinverseGamma: () => inverseGamma_default, _shadersisEmpty: () => isEmpty_default, _shadersisFull: () => isFull_default, _shaderslatitudeToWebMercatorFraction: () => latitudeToWebMercatorFraction_default, _shaderslineDistance: () => lineDistance_default, _shaderslinearToSrgb: () => linearToSrgb_default, _shadersluminance: () => luminance_default, _shadersmaterial: () => material_default, _shadersmaterialInput: () => materialInput_default, _shadersmaximumComponent: () => maximumComponent_default, _shadersmetersPerPixel: () => metersPerPixel_default, _shadersmodelMaterial: () => modelMaterial_default, _shadersmodelToWindowCoordinates: () => modelToWindowCoordinates_default, _shadersmodelVertexOutput: () => modelVertexOutput_default, _shadersmultiplyWithColorBalance: () => multiplyWithColorBalance_default, _shadersnearFarScalar: () => nearFarScalar_default, _shadersoctDecode: () => octDecode_default, _shadersoneOverPi: () => oneOverPi_default, _shadersoneOverTwoPi: () => oneOverTwoPi_default, _shaderspackDepth: () => packDepth_default, _shaderspassCesium3DTile: () => passCesium3DTile_default, _shaderspassCesium3DTileClassification: () => passCesium3DTileClassification_default, _shaderspassCesium3DTileClassificationIgnoreShow: () => passCesium3DTileClassificationIgnoreShow_default, _shaderspassCesium3DTileEdges: () => passCesium3DTileEdges_default, _shaderspassCesium3DTileEdgesDirect: () => passCesium3DTileEdgesDirect_default, _shaderspassCesium3DTilePlanarFillId: () => passCesium3DTilePlanarFillId_default, _shaderspassClassification: () => passClassification_default, _shaderspassCompute: () => passCompute_default, _shaderspassEnvironment: () => passEnvironment_default, _shaderspassGaussianSplats: () => passGaussianSplats_default, _shaderspassGlobe: () => passGlobe_default, _shaderspassOpaque: () => passOpaque_default, _shaderspassOverlay: () => passOverlay_default, _shaderspassTerrainClassification: () => passTerrainClassification_default, _shaderspassTranslucent: () => passTranslucent_default, _shaderspassVoxels: () => passVoxels_default, _shaderspbrLighting: () => pbrLighting_default, _shaderspbrNeutralTonemapping: () => pbrNeutralTonemapping_default, _shadersphong: () => phong_default, _shaderspi: () => pi_default, _shaderspiOverFour: () => piOverFour_default, _shaderspiOverSix: () => piOverSix_default, _shaderspiOverThree: () => piOverThree_default, _shaderspiOverTwo: () => piOverTwo_default, _shadersplaneDistance: () => planeDistance_default, _shaderspointAlongRay: () => pointAlongRay_default, _shadersradiansPerDegree: () => radiansPerDegree_default, _shadersray: () => ray_default, _shadersrayEllipsoidIntersectionInterval: () => rayEllipsoidIntersectionInterval_default, _shadersraySegment: () => raySegment_default, _shadersraySphereIntersectionInterval: () => raySphereIntersectionInterval_default, _shadersreadDepth: () => readDepth_default, _shadersreadNonPerspective: () => readNonPerspective_default, _shadersreverseLogDepth: () => reverseLogDepth_default, _shadersround: () => round_default, _shaderssaturation: () => saturation_default, _shaderssceneMode2D: () => sceneMode2D_default, _shaderssceneMode3D: () => sceneMode3D_default, _shaderssceneModeColumbusView: () => sceneModeColumbusView_default, _shaderssceneModeMorphing: () => sceneModeMorphing_default, _shadersshadowDepthCompare: () => shadowDepthCompare_default, _shadersshadowParameters: () => shadowParameters_default, _shadersshadowVisibility: () => shadowVisibility_default, _shaderssignNotZero: () => signNotZero_default, _shaderssolarRadius: () => solarRadius_default, _shaderssphericalHarmonics: () => sphericalHarmonics_default, _shaderssrgbToLinear: () => srgbToLinear_default, _shaderstangentToEyeSpaceMatrix: () => tangentToEyeSpaceMatrix_default, _shaderstextureCube: () => textureCube_default, _shadersthreePiOver2: () => threePiOver2_default, _shaderstransformPlane: () => transformPlane_default, _shaderstranslateRelativeToEye: () => translateRelativeToEye_default, _shaderstranslucentPhong: () => translucentPhong_default, _shaderstranspose: () => transpose_default, _shaderstwoPi: () => twoPi_default, _shadersunpackClippingExtents: () => unpackClippingExtents_default, _shadersunpackDepth: () => unpackDepth_default, _shadersunpackFloat: () => unpackFloat_default, _shadersunpackTexture: () => unpackTexture_default, _shadersunpackUint: () => unpackUint_default, _shadersvalueTransform: () => valueTransform_default, _shadersvertexLogDepth: () => vertexLogDepth_default, _shaderswebMercatorMaxLatitude: () => webMercatorMaxLatitude_default, _shaderswindowToEyeCoordinates: () => windowToEyeCoordinates_default, _shaderswriteDepthClamp: () => writeDepthClamp_default, _shaderswriteLogDepth: () => writeLogDepth_default, _shaderswriteNonPerspective: () => writeNonPerspective_default, addAllToArray: () => addAllToArray_default, addBuffer: () => addBuffer_default, addDefaults: () => addDefaults_default, addExtensionsRequired: () => addExtensionsRequired_default, addExtensionsUsed: () => addExtensionsUsed_default, addPipelineExtras: () => addPipelineExtras_default, addToArray: () => addToArray_default, appendForwardSlash: () => appendForwardSlash_default, arrayRemoveDuplicates: () => arrayRemoveDuplicates_default, assert: () => assert_default, barycentricCoordinates: () => barycentricCoordinates_default, binarySearch: () => binarySearch_default, buildModuleUrl: () => buildModuleUrl_default, buildVectorGltfFromMVT: () => buildVectorGltfFromMVT_default, buildVoxelCustomShader: () => buildVoxelCustomShader_default, buildVoxelDrawCommands: () => buildVoxelDrawCommands_default, clone: () => clone_default, combine: () => combine_default, computeFlyToLocationForRectangle: () => computeFlyToLocationForRectangle_default, createBillboardPointCallback: () => createBillboardPointCallback_default, createColorRamp: () => createColorRamp_default, createCommand: () => createCommand_default, createDefaultImageryProviderViewModels: () => createDefaultImageryProviderViewModels_default, createDefaultTerrainProviderViewModels: () => createDefaultTerrainProviderViewModels_default, createElevationBandMaterial: () => createElevationBandMaterial_default, createGooglePhotorealistic3DTileset: () => createGooglePhotorealistic3DTileset_default, createGuid: () => createGuid_default, createMaterialPropertyDescriptor: () => createMaterialPropertyDescriptor_default, createOsmBuildingsAsync: () => createOsmBuildingsAsync_default, createPropertyDescriptor: () => createPropertyDescriptor_default, createRawPropertyDescriptor: () => createRawPropertyDescriptor_default, createTangentSpaceDebugPrimitive: () => createTangentSpaceDebugPrimitive_default, createTaskProcessorWorker: () => createTaskProcessorWorker_default, createUniform: () => createUniform_default, createUniformArray: () => createUniformArray_default, createVectorTileBuffersFromModelComponents: () => createVectorTileBuffersFromModelComponents_default, createWorldBathymetryAsync: () => createWorldBathymetryAsync_default, createWorldImageryAsync: () => createWorldImageryAsync_default, createWorldTerrainAsync: () => createWorldTerrainAsync_default, decodeGoogleEarthEnterpriseData: () => decodeGoogleEarthEnterpriseData_default, decodeMVT: () => decodeMVT_default, decodeVectorPolylinePositions: () => decodeVectorPolylinePositions_default, defaultPickWorldPosition: () => defaultPickWorldPosition_default, defer: () => defer_default, defined: () => defined_default, demodernizeShader: () => demodernizeShader_default, deprecationWarning: () => deprecationWarning_default, destroyObject: () => destroyObject_default, exportKml: () => exportKml_default, findAccessorMinMax: () => findAccessorMinMax_default, findContentMetadata: () => findContentMetadata_default, findGroupMetadata: () => findGroupMetadata_default, findMeshoptExtension: () => findMeshoptExtension_default, findTileMetadata: () => findTileMetadata_default, forEachTextureInMaterial: () => forEachTextureInMaterial_default, formatError: () => formatError_default, freezeRenderState: () => freezeRenderState_default, getAbsoluteUri: () => getAbsoluteUri_default, getAccessorByteStride: () => getAccessorByteStride_default, getBaseUri: () => getBaseUri_default, getBinaryAccessor: () => getBinaryAccessor_default, getClipAndStyleCode: () => getClipAndStyleCode_default, getClippingFunction: () => getClippingFunction_default, getComponentReader: () => getComponentReader_default, getElement: () => getElement_default, getExtensionFromUri: () => getExtensionFromUri_default, getFilenameFromUri: () => getFilenameFromUri_default, getImageFromTypedArray: () => getImageFromTypedArray_default, getImagePixels: () => getImagePixels_default, getJsonFromTypedArray: () => getJsonFromTypedArray_default, getMagic: () => getMagic_default, getMeshPrimitives: () => getMeshPrimitives_default, getMetadataClassProperty: () => getMetadataClassProperty_default, getMetadataProperty: () => getMetadataProperty_default, getStringFromTypedArray: () => getStringFromTypedArray_default, getTimestamp: () => getTimestamp_default, hasExtension: () => hasExtension_default, heightReferenceOnEntityPropertyChanged: () => heightReferenceOnEntityPropertyChanged_default, isBitSet: () => isBitSet_default, isBlobUri: () => isBlobUri_default, isCrossOriginUrl: () => isCrossOriginUrl_default, isDataUri: () => isDataUri_default, isLeapYear: () => isLeapYear_default, knockout: () => knockout_default, knockout_3_5_1: () => knockout_3_5_1_default, knockout_es5: () => knockout_es5_default, loadAndExecuteScript: () => loadAndExecuteScript_default, loadCubeMap: () => loadCubeMap_default, loadImageFromTypedArray: () => loadImageFromTypedArray_default, loadKTX2: () => loadKTX2_default, mergeSort: () => mergeSort_default, moveTechniqueRenderStates: () => moveTechniqueRenderStates_default, moveTechniquesToExtension: () => moveTechniquesToExtension_default, numberOfComponentsForType: () => numberOfComponentsForType_default, objectToQuery: () => objectToQuery_default, oneTimeWarning: () => oneTimeWarning_default, parseBatchTable: () => parseBatchTable_default, parseFeatureMetadataLegacy: () => parseFeatureMetadataLegacy_default, parseGlb: () => parseGlb_default, parseResponseHeaders: () => parseResponseHeaders_default, parseStructuralMetadata: () => parseStructuralMetadata_default, pickModel: () => pickModel, pointInsideTriangle: () => pointInsideTriangle_default, preprocess3DTileContent: () => preprocess3DTileContent_default, processVoxelProperties: () => processVoxelProperties_default, queryToObject: () => queryToObject_default, readAccessorPacked: () => readAccessorPacked_default, removeExtension: () => removeExtension_default, removeExtensionsRequired: () => removeExtensionsRequired_default, removeExtensionsUsed: () => removeExtensionsUsed_default, removePipelineExtras: () => removePipelineExtras_default, removeUnusedElements: () => removeUnusedElements_default, renderBufferPointCollection: () => renderBufferPointCollection_default, renderBufferPolygonCollection: () => renderBufferPolygonCollection_default, renderBufferPolylineCollection: () => renderBufferPolylineCollection_default, resizeImageToNextPowerOfTwo: () => resizeImageToNextPowerOfTwo_default, sampleTerrain: () => sampleTerrain_default, sampleTerrainMostDetailed: () => sampleTerrainMostDetailed_default, scaleToGeodeticSurface: () => scaleToGeodeticSurface_default, srgbToLinear: () => srgbToLinear_default2, subdivideArray: () => subdivideArray_default, subscribeAndEvaluate: () => subscribeAndEvaluate_default, updateAccessorComponentTypes: () => updateAccessorComponentTypes_default, updateVersion: () => updateVersion_default, usesExtension: () => usesExtension_default, viewerCesium3DTilesInspectorMixin: () => viewerCesium3DTilesInspectorMixin_default, viewerCesiumInspectorMixin: () => viewerCesiumInspectorMixin_default, viewerDragDropMixin: () => viewerDragDropMixin_default, viewerPerformanceWatchdogMixin: () => viewerPerformanceWatchdogMixin_default, viewerVoxelInspectorMixin: () => viewerVoxelInspectorMixin_default, webGLConstantToGlslType: () => webGLConstantToGlslType_default, wrapFunction: () => wrapFunction_default, writeTextToCanvas: () => writeTextToCanvas_default }); var import_InlineWorkers1434 = __toESM(require_InlineWorkers(), 1); // packages/engine/index.js var import_InlineWorkers1378 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/AutomaticUniforms.js var import_InlineWorkers12 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Cartesian3.js var import_InlineWorkers5 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Check.js var import_InlineWorkers3 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/defined.js var import_InlineWorkers = __toESM(require_InlineWorkers(), 1); function defined(value) { return value !== void 0 && value !== null; } var defined_default = defined; // packages/engine/Source/Core/DeveloperError.js var import_InlineWorkers2 = __toESM(require_InlineWorkers(), 1); function DeveloperError(message) { this.name = "DeveloperError"; this.message = message; let stack; try { throw new Error(); } catch (e) { stack = e.stack; } this.stack = stack; } if (defined_default(Object.create)) { DeveloperError.prototype = Object.create(Error.prototype); DeveloperError.prototype.constructor = DeveloperError; } DeveloperError.prototype.toString = function() { let str = `${this.name}: ${this.message}`; if (defined_default(this.stack)) { str += ` ${this.stack.toString()}`; } return str; }; DeveloperError.throwInstantiationError = function() { throw new DeveloperError( "This function defines an interface and should not be called directly." ); }; var DeveloperError_default = DeveloperError; // packages/engine/Source/Core/Check.js var Check = {}; Check.typeOf = {}; function getUndefinedErrorMessage(name) { return `${name} is required, actual value was undefined`; } function getFailedTypeErrorMessage(actual, expected, name) { return `Expected ${name} to be typeof ${expected}, actual typeof was ${actual}`; } Check.defined = function(name, test) { if (!defined_default(test)) { throw new DeveloperError_default(getUndefinedErrorMessage(name)); } }; Check.typeOf.func = function(name, test) { if (typeof test !== "function") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "function", name) ); } }; Check.typeOf.string = function(name, test) { if (typeof test !== "string") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "string", name) ); } }; Check.typeOf.number = function(name, test) { if (typeof test !== "number") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "number", name) ); } }; Check.typeOf.number.lessThan = function(name, test, limit) { Check.typeOf.number(name, test); if (test >= limit) { throw new DeveloperError_default( `Expected ${name} to be less than ${limit}, actual value was ${test}` ); } }; Check.typeOf.number.lessThanOrEquals = function(name, test, limit) { Check.typeOf.number(name, test); if (test > limit) { throw new DeveloperError_default( `Expected ${name} to be less than or equal to ${limit}, actual value was ${test}` ); } }; Check.typeOf.number.greaterThan = function(name, test, limit) { Check.typeOf.number(name, test); if (test <= limit) { throw new DeveloperError_default( `Expected ${name} to be greater than ${limit}, actual value was ${test}` ); } }; Check.typeOf.number.greaterThanOrEquals = function(name, test, limit) { Check.typeOf.number(name, test); if (test < limit) { throw new DeveloperError_default( `Expected ${name} to be greater than or equal to ${limit}, actual value was ${test}` ); } }; Check.typeOf.object = function(name, test) { if (typeof test !== "object") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "object", name) ); } }; Check.typeOf.bool = function(name, test) { if (typeof test !== "boolean") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "boolean", name) ); } }; Check.typeOf.bigint = function(name, test) { if (typeof test !== "bigint") { throw new DeveloperError_default( getFailedTypeErrorMessage(typeof test, "bigint", name) ); } }; Check.typeOf.number.equals = function(name1, name2, test1, test2) { Check.typeOf.number(name1, test1); Check.typeOf.number(name2, test2); if (test1 !== test2) { throw new DeveloperError_default( `${name1} must be equal to ${name2}, the actual values are ${test1} and ${test2}` ); } }; var Check_default = Check; // packages/engine/Source/Core/Math.js var import_InlineWorkers4 = __toESM(require_InlineWorkers(), 1); var import_mersenne_twister = __toESM(require_mersenne_twister(), 1); var CesiumMath = {}; CesiumMath.EPSILON1 = 0.1; CesiumMath.EPSILON2 = 0.01; CesiumMath.EPSILON3 = 1e-3; CesiumMath.EPSILON4 = 1e-4; CesiumMath.EPSILON5 = 1e-5; CesiumMath.EPSILON6 = 1e-6; CesiumMath.EPSILON7 = 1e-7; CesiumMath.EPSILON8 = 1e-8; CesiumMath.EPSILON9 = 1e-9; CesiumMath.EPSILON10 = 1e-10; CesiumMath.EPSILON11 = 1e-11; CesiumMath.EPSILON12 = 1e-12; CesiumMath.EPSILON13 = 1e-13; CesiumMath.EPSILON14 = 1e-14; CesiumMath.EPSILON15 = 1e-15; CesiumMath.EPSILON16 = 1e-16; CesiumMath.EPSILON17 = 1e-17; CesiumMath.EPSILON18 = 1e-18; CesiumMath.EPSILON19 = 1e-19; CesiumMath.EPSILON20 = 1e-20; CesiumMath.EPSILON21 = 1e-21; CesiumMath.GRAVITATIONALPARAMETER = 3986004418e5; CesiumMath.SOLAR_RADIUS = 6955e5; CesiumMath.LUNAR_RADIUS = 1737400; CesiumMath.SIXTY_FOUR_KILOBYTES = 64 * 1024; CesiumMath.FOUR_GIGABYTES = 4 * 1024 * 1024 * 1024; CesiumMath.sign = Math.sign ?? function sign(value) { value = +value; if (value === 0 || value !== value) { return value; } return value > 0 ? 1 : -1; }; CesiumMath.signNotZero = function(value) { return value < 0 ? -1 : 1; }; CesiumMath.toSNorm = function(value, rangeMaximum) { rangeMaximum = rangeMaximum ?? 255; return Math.round( (CesiumMath.clamp(value, -1, 1) * 0.5 + 0.5) * rangeMaximum ); }; CesiumMath.fromSNorm = function(value, rangeMaximum) { rangeMaximum = rangeMaximum ?? 255; return CesiumMath.clamp(value, 0, rangeMaximum) / rangeMaximum * 2 - 1; }; CesiumMath.normalize = function(value, rangeMinimum, rangeMaximum) { rangeMaximum = Math.max(rangeMaximum - rangeMinimum, 0); return rangeMaximum === 0 ? 0 : CesiumMath.clamp((value - rangeMinimum) / rangeMaximum, 0, 1); }; CesiumMath.sinh = Math.sinh ?? function sinh(value) { return (Math.exp(value) - Math.exp(-value)) / 2; }; CesiumMath.cosh = Math.cosh ?? function cosh(value) { return (Math.exp(value) + Math.exp(-value)) / 2; }; CesiumMath.lerp = function(p, q, time) { return (1 - time) * p + time * q; }; CesiumMath.smoothDamp = function(p, q, velocity, deltaTime2 = 0, maximumSpeed = Number.POSITIVE_INFINITY, smoothTime = 1e-4, result = {}) { Check_default.typeOf.number("p", p); Check_default.typeOf.number("q", q); Check_default.typeOf.number("velocity", velocity); Check_default.typeOf.number.greaterThanOrEquals("deltaTime", deltaTime2, 0); Check_default.typeOf.number.greaterThanOrEquals("maximumSpeed", maximumSpeed, 0); Check_default.typeOf.number.greaterThanOrEquals("smoothTime", smoothTime, 1e-4); Check_default.typeOf.object("result", result); smoothTime = Math.max(1e-4, smoothTime); const omega = 2 / smoothTime; const x = omega * deltaTime2; const exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x); const maxChange = maximumSpeed * smoothTime; let change = p - q; change = CesiumMath.clamp(change, -maxChange, maxChange); const target = p - change; const temp = (velocity + omega * change) * deltaTime2; velocity = (velocity - omega * temp) * exp; result.value = target + (change + temp) * exp; result.velocity = velocity; return result; }; CesiumMath.PI = Math.PI; CesiumMath.ONE_OVER_PI = 1 / Math.PI; CesiumMath.PI_OVER_TWO = Math.PI / 2; CesiumMath.PI_OVER_THREE = Math.PI / 3; CesiumMath.PI_OVER_FOUR = Math.PI / 4; CesiumMath.PI_OVER_SIX = Math.PI / 6; CesiumMath.THREE_PI_OVER_TWO = 3 * Math.PI / 2; CesiumMath.TWO_PI = 2 * Math.PI; CesiumMath.ONE_OVER_TWO_PI = 1 / (2 * Math.PI); CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180; CesiumMath.DEGREES_PER_RADIAN = 180 / Math.PI; CesiumMath.RADIANS_PER_ARCSECOND = CesiumMath.RADIANS_PER_DEGREE / 3600; CesiumMath.toRadians = function(degrees) { if (!defined_default(degrees)) { throw new DeveloperError_default("degrees is required."); } return degrees * CesiumMath.RADIANS_PER_DEGREE; }; CesiumMath.toDegrees = function(radians) { if (!defined_default(radians)) { throw new DeveloperError_default("radians is required."); } return radians * CesiumMath.DEGREES_PER_RADIAN; }; CesiumMath.convertLongitudeRange = function(angle) { if (!defined_default(angle)) { throw new DeveloperError_default("angle is required."); } const twoPi = CesiumMath.TWO_PI; const simplified = angle - Math.floor(angle / twoPi) * twoPi; if (simplified < -Math.PI) { return simplified + twoPi; } if (simplified >= Math.PI) { return simplified - twoPi; } return simplified; }; CesiumMath.clampToLatitudeRange = function(angle) { if (!defined_default(angle)) { throw new DeveloperError_default("angle is required."); } return CesiumMath.clamp( angle, -1 * CesiumMath.PI_OVER_TWO, CesiumMath.PI_OVER_TWO ); }; CesiumMath.negativePiToPi = function(angle) { if (!defined_default(angle)) { throw new DeveloperError_default("angle is required."); } if (angle >= -CesiumMath.PI && angle <= CesiumMath.PI) { return angle; } return CesiumMath.zeroToTwoPi(angle + CesiumMath.PI) - CesiumMath.PI; }; CesiumMath.zeroToTwoPi = function(angle) { if (!defined_default(angle)) { throw new DeveloperError_default("angle is required."); } if (angle >= 0 && angle <= CesiumMath.TWO_PI) { return angle; } const mod = CesiumMath.mod(angle, CesiumMath.TWO_PI); if (Math.abs(mod) < CesiumMath.EPSILON14 && Math.abs(angle) > CesiumMath.EPSILON14) { return CesiumMath.TWO_PI; } return mod; }; CesiumMath.mod = function(m, n2) { if (!defined_default(m)) { throw new DeveloperError_default("m is required."); } if (!defined_default(n2)) { throw new DeveloperError_default("n is required."); } if (n2 === 0) { throw new DeveloperError_default("divisor cannot be 0."); } if (CesiumMath.sign(m) === CesiumMath.sign(n2) && Math.abs(m) < Math.abs(n2)) { return m; } return (m % n2 + n2) % n2; }; CesiumMath.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) { if (!defined_default(left)) { throw new DeveloperError_default("left is required."); } if (!defined_default(right)) { throw new DeveloperError_default("right is required."); } relativeEpsilon = relativeEpsilon ?? 0; absoluteEpsilon = absoluteEpsilon ?? relativeEpsilon; const absDiff = Math.abs(left - right); return absDiff <= absoluteEpsilon || absDiff <= relativeEpsilon * Math.max(Math.abs(left), Math.abs(right)); }; CesiumMath.lessThan = function(left, right, absoluteEpsilon) { if (!defined_default(left)) { throw new DeveloperError_default("first is required."); } if (!defined_default(right)) { throw new DeveloperError_default("second is required."); } if (!defined_default(absoluteEpsilon)) { throw new DeveloperError_default("absoluteEpsilon is required."); } return left - right < -absoluteEpsilon; }; CesiumMath.lessThanOrEquals = function(left, right, absoluteEpsilon) { if (!defined_default(left)) { throw new DeveloperError_default("first is required."); } if (!defined_default(right)) { throw new DeveloperError_default("second is required."); } if (!defined_default(absoluteEpsilon)) { throw new DeveloperError_default("absoluteEpsilon is required."); } return left - right < absoluteEpsilon; }; CesiumMath.greaterThan = function(left, right, absoluteEpsilon) { if (!defined_default(left)) { throw new DeveloperError_default("first is required."); } if (!defined_default(right)) { throw new DeveloperError_default("second is required."); } if (!defined_default(absoluteEpsilon)) { throw new DeveloperError_default("absoluteEpsilon is required."); } return left - right > absoluteEpsilon; }; CesiumMath.greaterThanOrEquals = function(left, right, absoluteEpsilon) { if (!defined_default(left)) { throw new DeveloperError_default("first is required."); } if (!defined_default(right)) { throw new DeveloperError_default("second is required."); } if (!defined_default(absoluteEpsilon)) { throw new DeveloperError_default("absoluteEpsilon is required."); } return left - right > -absoluteEpsilon; }; var factorials = [1]; CesiumMath.factorial = function(n2) { if (typeof n2 !== "number" || n2 < 0) { throw new DeveloperError_default( "A number greater than or equal to 0 is required." ); } const length2 = factorials.length; if (n2 >= length2) { let sum = factorials[length2 - 1]; for (let i = length2; i <= n2; i++) { const next = sum * i; factorials.push(next); sum = next; } } return factorials[n2]; }; CesiumMath.incrementWrap = function(n2, maximumValue, minimumValue) { minimumValue = minimumValue ?? 0; if (!defined_default(n2)) { throw new DeveloperError_default("n is required."); } if (maximumValue <= minimumValue) { throw new DeveloperError_default("maximumValue must be greater than minimumValue."); } ++n2; if (n2 > maximumValue) { n2 = minimumValue; } return n2; }; CesiumMath.isPowerOfTwo = function(n2) { if (typeof n2 !== "number" || n2 < 0 || n2 > 4294967295) { throw new DeveloperError_default("A number between 0 and (2^32)-1 is required."); } return n2 !== 0 && (n2 & n2 - 1) === 0; }; CesiumMath.nextPowerOfTwo = function(n2) { if (typeof n2 !== "number" || n2 < 0 || n2 > 2147483648) { throw new DeveloperError_default("A number between 0 and 2^31 is required."); } --n2; n2 |= n2 >> 1; n2 |= n2 >> 2; n2 |= n2 >> 4; n2 |= n2 >> 8; n2 |= n2 >> 16; ++n2; return n2; }; CesiumMath.previousPowerOfTwo = function(n2) { if (typeof n2 !== "number" || n2 < 0 || n2 > 4294967295) { throw new DeveloperError_default("A number between 0 and (2^32)-1 is required."); } n2 |= n2 >> 1; n2 |= n2 >> 2; n2 |= n2 >> 4; n2 |= n2 >> 8; n2 |= n2 >> 16; n2 |= n2 >> 32; n2 = (n2 >>> 0) - (n2 >>> 1); return n2; }; CesiumMath.clamp = function(value, min3, max3) { Check_default.typeOf.number("value", value); Check_default.typeOf.number("min", min3); Check_default.typeOf.number("max", max3); return value < min3 ? min3 : value > max3 ? max3 : value; }; var randomNumberGenerator = new import_mersenne_twister.default(); CesiumMath.setRandomNumberSeed = function(seed) { if (!defined_default(seed)) { throw new DeveloperError_default("seed is required."); } randomNumberGenerator = new import_mersenne_twister.default(seed); }; CesiumMath.nextRandomNumber = function() { return randomNumberGenerator.random(); }; CesiumMath.randomBetween = function(min3, max3) { return CesiumMath.nextRandomNumber() * (max3 - min3) + min3; }; CesiumMath.acosClamped = function(value) { if (!defined_default(value)) { throw new DeveloperError_default("value is required."); } return Math.acos(CesiumMath.clamp(value, -1, 1)); }; CesiumMath.asinClamped = function(value) { if (!defined_default(value)) { throw new DeveloperError_default("value is required."); } return Math.asin(CesiumMath.clamp(value, -1, 1)); }; CesiumMath.chordLength = function(angle, radius) { if (!defined_default(angle)) { throw new DeveloperError_default("angle is required."); } if (!defined_default(radius)) { throw new DeveloperError_default("radius is required."); } return 2 * radius * Math.sin(angle * 0.5); }; CesiumMath.logBase = function(number, base) { if (!defined_default(number)) { throw new DeveloperError_default("number is required."); } if (!defined_default(base)) { throw new DeveloperError_default("base is required."); } return Math.log(number) / Math.log(base); }; CesiumMath.cbrt = Math.cbrt ?? function cbrt(number) { const result = Math.pow(Math.abs(number), 1 / 3); return number < 0 ? -result : result; }; CesiumMath.log2 = Math.log2 ?? function log2(number) { return Math.log(number) * Math.LOG2E; }; CesiumMath.fog = function(distanceToCamera, density) { const scalar = distanceToCamera * density; return 1 - Math.exp(-(scalar * scalar)); }; CesiumMath.fastApproximateAtan = function(x) { Check_default.typeOf.number("x", x); return x * (-0.1784 * Math.abs(x) - 0.0663 * x * x + 1.0301); }; CesiumMath.fastApproximateAtan2 = function(x, y) { Check_default.typeOf.number("x", x); Check_default.typeOf.number("y", y); let opposite; let t2 = Math.abs(x); opposite = Math.abs(y); const adjacent = Math.max(t2, opposite); opposite = Math.min(t2, opposite); const oppositeOverAdjacent = opposite / adjacent; if (isNaN(oppositeOverAdjacent)) { throw new DeveloperError_default("either x or y must be nonzero"); } t2 = CesiumMath.fastApproximateAtan(oppositeOverAdjacent); t2 = Math.abs(y) > Math.abs(x) ? CesiumMath.PI_OVER_TWO - t2 : t2; t2 = x < 0 ? CesiumMath.PI - t2 : t2; t2 = y < 0 ? -t2 : t2; return t2; }; var Math_default = CesiumMath; // packages/engine/Source/Core/Cartesian3.js var Cartesian3 = class _Cartesian3 { /** * @param {number} [x=0.0] The X component. * @param {number} [y=0.0] The Y component. * @param {number} [z=0.0] The Z component. */ constructor(x, y, z2) { this.x = x ?? 0; this.y = y ?? 0; this.z = z2 ?? 0; } /** * Converts the provided Spherical into Cartesian3 coordinates. * * @param {Spherical} spherical The Spherical to be converted to Cartesian3. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. */ static fromSpherical(spherical, result) { Check_default.typeOf.object("spherical", spherical); if (!defined_default(result)) { result = new _Cartesian3(); } const clock = spherical.clock; const cone = spherical.cone; const magnitude = spherical.magnitude ?? 1; const radial = magnitude * Math.sin(cone); result.x = radial * Math.cos(clock); result.y = radial * Math.sin(clock); result.z = magnitude * Math.cos(cone); return result; } /** * Creates a Cartesian3 instance from x, y and z coordinates. * * @param {number} x The x coordinate. * @param {number} y The y coordinate. * @param {number} z The z coordinate. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. */ static fromElements(x, y, z2, result) { if (!defined_default(result)) { return new _Cartesian3(x, y, z2); } result.x = x; result.y = y; result.z = z2; return result; } /** * Duplicates a Cartesian3 instance. * * @param {Cartesian3} cartesian The Cartesian to duplicate. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. (Returns undefined if cartesian is undefined) */ static clone(cartesian11, result) { if (!defined_default(cartesian11)) { return void 0; } if (!defined_default(result)) { return new _Cartesian3(cartesian11.x, cartesian11.y, cartesian11.z); } result.x = cartesian11.x; result.y = cartesian11.y; result.z = cartesian11.z; return result; } /** * Stores the provided instance into the provided array. * * @param {Cartesian3} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.x; array[startingIndex++] = value.y; array[startingIndex] = value.z; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Cartesian3} [result] The object into which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Cartesian3(); } result.x = array[startingIndex++]; result.y = array[startingIndex++]; result.z = array[startingIndex]; return result; } /** * Flattens an array of Cartesian3s into an array of components. * * @param {Cartesian3[]} array The array of cartesians to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 3 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 3) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 3; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 3 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Cartesian3.pack(array[i], result, i * 3); } return result; } /** * Unpacks an array of cartesian components into an array of Cartesian3s. * * @param {number[]} array The array of components to unpack. * @param {Cartesian3[]} [result] The array onto which to store the result. * @returns {Cartesian3[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 3); if (array.length % 3 !== 0) { throw new DeveloperError_default("array length must be a multiple of 3."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 3); } else { result.length = length2 / 3; } for (let i = 0; i < length2; i += 3) { const index = i / 3; result[index] = _Cartesian3.unpack(array, i, result[index]); } return result; } /** * Computes the value of the maximum component for the supplied Cartesian. * * @param {Cartesian3} cartesian The cartesian to use. * @returns {number} The value of the maximum component. */ static maximumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.max(cartesian11.x, cartesian11.y, cartesian11.z); } /** * Computes the value of the minimum component for the supplied Cartesian. * * @param {Cartesian3} cartesian The cartesian to use. * @returns {number} The value of the minimum component. */ static minimumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.min(cartesian11.x, cartesian11.y, cartesian11.z); } /** * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians. * * @param {Cartesian3} first A cartesian to compare. * @param {Cartesian3} second A cartesian to compare. * @param {Cartesian3} result The object into which to store the result. * @returns {Cartesian3} A cartesian with the minimum components. */ static minimumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.min(first.x, second.x); result.y = Math.min(first.y, second.y); result.z = Math.min(first.z, second.z); return result; } /** * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians. * * @param {Cartesian3} first A cartesian to compare. * @param {Cartesian3} second A cartesian to compare. * @param {Cartesian3} result The object into which to store the result. * @returns {Cartesian3} A cartesian with the maximum components. */ static maximumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.max(first.x, second.x); result.y = Math.max(first.y, second.y); result.z = Math.max(first.z, second.z); return result; } /** * Constrain a value to lie between two values. * * @param {Cartesian3} value The value to clamp. * @param {Cartesian3} min The minimum bound. * @param {Cartesian3} max The maximum bound. * @param {Cartesian3} result The object into which to store the result. * @returns {Cartesian3} The clamped value such that min <= value <= max. */ static clamp(value, min3, max3, result) { Check_default.typeOf.object("value", value); Check_default.typeOf.object("min", min3); Check_default.typeOf.object("max", max3); Check_default.typeOf.object("result", result); const x = Math_default.clamp(value.x, min3.x, max3.x); const y = Math_default.clamp(value.y, min3.y, max3.y); const z2 = Math_default.clamp(value.z, min3.z, max3.z); result.x = x; result.y = y; result.z = z2; return result; } /** * Computes the provided Cartesian's squared magnitude. * * @param {Cartesian3} cartesian The Cartesian instance whose squared magnitude is to be computed. * @returns {number} The squared magnitude. */ static magnitudeSquared(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return cartesian11.x * cartesian11.x + cartesian11.y * cartesian11.y + cartesian11.z * cartesian11.z; } /** * Computes the Cartesian's magnitude (length). * * @param {Cartesian3} cartesian The Cartesian instance whose magnitude is to be computed. * @returns {number} The magnitude. */ static magnitude(cartesian11) { return Math.sqrt(_Cartesian3.magnitudeSquared(cartesian11)); } /** * Computes the distance between two points. * * @param {Cartesian3} left The first point to compute the distance from. * @param {Cartesian3} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 1.0 * const d = Cesium.Cartesian3.distance(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(2.0, 0.0, 0.0)); */ static distance(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian3.subtract(left, right, distanceScratch); return _Cartesian3.magnitude(distanceScratch); } /** * Computes the squared distance between two points. Comparing squared distances * using this function is more efficient than comparing distances using {@link Cartesian3#distance}. * * @param {Cartesian3} left The first point to compute the distance from. * @param {Cartesian3} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 4.0, not 2.0 * const d = Cesium.Cartesian3.distanceSquared(new Cesium.Cartesian3(1.0, 0.0, 0.0), new Cesium.Cartesian3(3.0, 0.0, 0.0)); */ static distanceSquared(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian3.subtract(left, right, distanceScratch); return _Cartesian3.magnitudeSquared(distanceScratch); } /** * Computes the normalized form of the supplied Cartesian. * * @param {Cartesian3} cartesian The Cartesian to be normalized. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static normalize(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const magnitude = _Cartesian3.magnitude(cartesian11); result.x = cartesian11.x / magnitude; result.y = cartesian11.y / magnitude; result.z = cartesian11.z / magnitude; if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z)) { throw new DeveloperError_default("normalized result is not a number"); } return result; } /** * Computes the dot (scalar) product of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @returns {number} The dot product. */ static dot(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.x * right.x + left.y * right.y + left.z * right.z; } /** * Computes the componentwise product of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static multiplyComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x * right.x; result.y = left.y * right.y; result.z = left.z * right.z; return result; } /** * Computes the componentwise quotient of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static divideComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x / right.x; result.y = left.y / right.y; result.z = left.z / right.z; return result; } /** * Computes the componentwise sum of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x + right.x; result.y = left.y + right.y; result.z = left.z + right.z; return result; } /** * Computes the componentwise difference of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x - right.x; result.y = left.y - right.y; result.z = left.z - right.z; return result; } /** * Multiplies the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian3} cartesian The Cartesian to be scaled. * @param {number} scalar The scalar to multiply with. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static multiplyByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x * scalar; result.y = cartesian11.y * scalar; result.z = cartesian11.z * scalar; return result; } /** * Divides the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian3} cartesian The Cartesian to be divided. * @param {number} scalar The scalar to divide by. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static divideByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x / scalar; result.y = cartesian11.y / scalar; result.z = cartesian11.z / scalar; return result; } /** * Negates the provided Cartesian. * * @param {Cartesian3} cartesian The Cartesian to be negated. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static negate(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = -cartesian11.x; result.y = -cartesian11.y; result.z = -cartesian11.z; return result; } /** * Computes the absolute value of the provided Cartesian. * * @param {Cartesian3} cartesian The Cartesian whose absolute value is to be computed. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static abs(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = Math.abs(cartesian11.x); result.y = Math.abs(cartesian11.y); result.z = Math.abs(cartesian11.z); return result; } /** * Computes the linear interpolation or extrapolation at t using the provided cartesians. * * @param {Cartesian3} start The value corresponding to t at 0.0. * @param {Cartesian3} end The value corresponding to t at 1.0. * @param {number} t The point along t at which to interpolate. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static lerp(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); _Cartesian3.multiplyByScalar(end, t2, lerpScratch); result = _Cartesian3.multiplyByScalar(start, 1 - t2, result); return _Cartesian3.add(lerpScratch, result, result); } /** * Returns the angle, in radians, between the provided Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @returns {number} The angle between the Cartesians. */ static angleBetween(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian3.normalize(left, angleBetweenScratch); _Cartesian3.normalize(right, angleBetweenScratch2); const cosine = _Cartesian3.dot(angleBetweenScratch, angleBetweenScratch2); const sine = _Cartesian3.magnitude( _Cartesian3.cross( angleBetweenScratch, angleBetweenScratch2, angleBetweenScratch ) ); return Math.atan2(sine, cosine); } /** * Returns the axis that is most orthogonal to the provided Cartesian. * * @param {Cartesian3} cartesian The Cartesian on which to find the most orthogonal axis. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The most orthogonal axis. */ static mostOrthogonalAxis(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const f2 = _Cartesian3.normalize(cartesian11, mostOrthogonalAxisScratch); _Cartesian3.abs(f2, f2); if (f2.x <= f2.y) { if (f2.x <= f2.z) { result = _Cartesian3.clone(_Cartesian3.UNIT_X, result); } else { result = _Cartesian3.clone(_Cartesian3.UNIT_Z, result); } } else if (f2.y <= f2.z) { result = _Cartesian3.clone(_Cartesian3.UNIT_Y, result); } else { result = _Cartesian3.clone(_Cartesian3.UNIT_Z, result); } return result; } /** * Projects vector a onto vector b * @param {Cartesian3} a The vector that needs projecting * @param {Cartesian3} b The vector to project onto * @param {Cartesian3} result The result cartesian * @returns {Cartesian3} The modified result parameter */ static projectVector(a3, b, result) { Check_default.defined("a", a3); Check_default.defined("b", b); Check_default.defined("result", result); const scalar = _Cartesian3.dot(a3, b) / _Cartesian3.dot(b, b); return _Cartesian3.multiplyByScalar(b, scalar, result); } /** * Compares the provided Cartesians componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian3} [left] The first Cartesian. * @param {Cartesian3} [right] The second Cartesian. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.x === right.x && left.y === right.y && left.z === right.z; } /** * @param {Cartesian3} cartesian * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(cartesian11, array, offset) { return cartesian11.x === array[offset] && cartesian11.y === array[offset + 1] && cartesian11.z === array[offset + 2]; } /** * Compares the provided Cartesians componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian3} [left] The first Cartesian. * @param {Cartesian3} [right] The second Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, relativeEpsilon, absoluteEpsilon) { return left === right || defined_default(left) && defined_default(right) && Math_default.equalsEpsilon( left.x, right.x, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.y, right.y, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.z, right.z, relativeEpsilon, absoluteEpsilon ); } /** * Computes the cross (outer) product of two Cartesians. * * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The cross product. */ static cross(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const leftX = left.x; const leftY = left.y; const leftZ = left.z; const rightX = right.x; const rightY = right.y; const rightZ = right.z; const x = leftY * rightZ - leftZ * rightY; const y = leftZ * rightX - leftX * rightZ; const z2 = leftX * rightY - leftY * rightX; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes the midpoint between the right and left Cartesian. * @param {Cartesian3} left The first Cartesian. * @param {Cartesian3} right The second Cartesian. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The midpoint. */ static midpoint(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = (left.x + right.x) * 0.5; result.y = (left.y + right.y) * 0.5; result.z = (left.z + right.z) * 0.5; return result; } /** * Returns a Cartesian3 position from longitude and latitude values given in degrees. * * @param {number} longitude The longitude, in degrees * @param {number} latitude The latitude, in degrees * @param {number} [height=0.0] The height, in meters, above the ellipsoid. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The position * * @example * const position = Cesium.Cartesian3.fromDegrees(-115.0, 37.0); */ static fromDegrees(longitude, latitude, height, ellipsoid, result) { Check_default.typeOf.number("longitude", longitude); Check_default.typeOf.number("latitude", latitude); longitude = Math_default.toRadians(longitude); latitude = Math_default.toRadians(latitude); return _Cartesian3.fromRadians( longitude, latitude, height, ellipsoid, result ); } /** * Returns a Cartesian3 position from longitude and latitude values given in radians. * * @param {number} longitude The longitude, in radians * @param {number} latitude The latitude, in radians * @param {number} [height=0.0] The height, in meters, above the ellipsoid. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The position * * @example * const position = Cesium.Cartesian3.fromRadians(-2.007, 0.645); */ static fromRadians(longitude, latitude, height, ellipsoid, result) { Check_default.typeOf.number("longitude", longitude); Check_default.typeOf.number("latitude", latitude); height = height ?? 0; const radiiSquared = !defined_default(ellipsoid) ? _Cartesian3._ellipsoidRadiiSquared : ellipsoid.radiiSquared; const cosLatitude = Math.cos(latitude); scratchN.x = cosLatitude * Math.cos(longitude); scratchN.y = cosLatitude * Math.sin(longitude); scratchN.z = Math.sin(latitude); scratchN = _Cartesian3.normalize(scratchN, scratchN); _Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK); const gamma = Math.sqrt(_Cartesian3.dot(scratchN, scratchK)); scratchK = _Cartesian3.divideByScalar(scratchK, gamma, scratchK); scratchN = _Cartesian3.multiplyByScalar(scratchN, height, scratchN); if (!defined_default(result)) { result = new _Cartesian3(); } return _Cartesian3.add(scratchK, scratchN, result); } /** * Returns an array of Cartesian3 positions given an array of longitude and latitude values given in degrees. * * @param {number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...]. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the coordinates lie. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result. * @returns {Cartesian3[]} The array of positions. * * @example * const positions = Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0, -107.0, 33.0]); */ static fromDegreesArray(coordinates, ellipsoid, result) { Check_default.defined("coordinates", coordinates); if (coordinates.length < 2 || coordinates.length % 2 !== 0) { throw new DeveloperError_default( "the number of coordinates must be a multiple of 2 and at least 2" ); } const length2 = coordinates.length; if (!defined_default(result)) { result = new Array(length2 / 2); } else { result.length = length2 / 2; } for (let i = 0; i < length2; i += 2) { const longitude = coordinates[i]; const latitude = coordinates[i + 1]; const index = i / 2; result[index] = _Cartesian3.fromDegrees( longitude, latitude, 0, ellipsoid, result[index] ); } return result; } /** * Returns an array of Cartesian3 positions given an array of longitude and latitude values given in radians. * * @param {number[]} coordinates A list of longitude and latitude values. Values alternate [longitude, latitude, longitude, latitude...]. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the coordinates lie. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result. * @returns {Cartesian3[]} The array of positions. * * @example * const positions = Cesium.Cartesian3.fromRadiansArray([-2.007, 0.645, -1.867, .575]); */ static fromRadiansArray(coordinates, ellipsoid, result) { Check_default.defined("coordinates", coordinates); if (coordinates.length < 2 || coordinates.length % 2 !== 0) { throw new DeveloperError_default( "the number of coordinates must be a multiple of 2 and at least 2" ); } const length2 = coordinates.length; if (!defined_default(result)) { result = new Array(length2 / 2); } else { result.length = length2 / 2; } for (let i = 0; i < length2; i += 2) { const longitude = coordinates[i]; const latitude = coordinates[i + 1]; const index = i / 2; result[index] = _Cartesian3.fromRadians( longitude, latitude, 0, ellipsoid, result[index] ); } return result; } /** * Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in degrees. * * @param {number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...]. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result. * @returns {Cartesian3[]} The array of positions. * * @example * const positions = Cesium.Cartesian3.fromDegreesArrayHeights([-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]); */ static fromDegreesArrayHeights(coordinates, ellipsoid, result) { Check_default.defined("coordinates", coordinates); if (coordinates.length < 3 || coordinates.length % 3 !== 0) { throw new DeveloperError_default( "the number of coordinates must be a multiple of 3 and at least 3" ); } const length2 = coordinates.length; if (!defined_default(result)) { result = new Array(length2 / 3); } else { result.length = length2 / 3; } for (let i = 0; i < length2; i += 3) { const longitude = coordinates[i]; const latitude = coordinates[i + 1]; const height = coordinates[i + 2]; const index = i / 3; result[index] = _Cartesian3.fromDegrees( longitude, latitude, height, ellipsoid, result[index] ); } return result; } /** * Returns an array of Cartesian3 positions given an array of longitude, latitude and height values where longitude and latitude are given in radians. * * @param {number[]} coordinates A list of longitude, latitude and height values. Values alternate [longitude, latitude, height, longitude, latitude, height...]. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartesian3[]} [result] An array of Cartesian3 objects to store the result. * @returns {Cartesian3[]} The array of positions. * * @example * const positions = Cesium.Cartesian3.fromRadiansArrayHeights([-2.007, 0.645, 100000.0, -1.867, .575, 150000.0]); */ static fromRadiansArrayHeights(coordinates, ellipsoid, result) { Check_default.defined("coordinates", coordinates); if (coordinates.length < 3 || coordinates.length % 3 !== 0) { throw new DeveloperError_default( "the number of coordinates must be a multiple of 3 and at least 3" ); } const length2 = coordinates.length; if (!defined_default(result)) { result = new Array(length2 / 3); } else { result.length = length2 / 3; } for (let i = 0; i < length2; i += 3) { const longitude = coordinates[i]; const latitude = coordinates[i + 1]; const height = coordinates[i + 2]; const index = i / 3; result[index] = _Cartesian3.fromRadians( longitude, latitude, height, ellipsoid, result[index] ); } return result; } /** * Duplicates this Cartesian3 instance. * * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if one was not provided. */ clone(result) { return _Cartesian3.clone(this, result); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian3} [right] The right hand side Cartesian. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Cartesian3.equals(this, right); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian3} [right] The right hand side Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, relativeEpsilon, absoluteEpsilon) { return _Cartesian3.equalsEpsilon( this, right, relativeEpsilon, absoluteEpsilon ); } /** * Creates a string representing this Cartesian in the format '(x, y, z)'. * * @returns {string} A string representing this Cartesian in the format '(x, y, z)'. */ toString() { return `(${this.x}, ${this.y}, ${this.z})`; } }; Cartesian3.fromCartesian4 = Cartesian3.clone; Cartesian3.packedLength = 3; Cartesian3.fromArray = Cartesian3.unpack; var distanceScratch = new Cartesian3(); var lerpScratch = new Cartesian3(); var angleBetweenScratch = new Cartesian3(); var angleBetweenScratch2 = new Cartesian3(); var mostOrthogonalAxisScratch = new Cartesian3(); var scratchN = new Cartesian3(); var scratchK = new Cartesian3(); Cartesian3._ellipsoidRadiiSquared = new Cartesian3( 6378137 * 6378137, 6378137 * 6378137, 6356752314245179e-9 * 6356752314245179e-9 ); Cartesian3.ZERO = Object.freeze(new Cartesian3(0, 0, 0)); Cartesian3.ONE = Object.freeze(new Cartesian3(1, 1, 1)); Cartesian3.UNIT_X = Object.freeze(new Cartesian3(1, 0, 0)); Cartesian3.UNIT_Y = Object.freeze(new Cartesian3(0, 1, 0)); Cartesian3.UNIT_Z = Object.freeze(new Cartesian3(0, 0, 1)); var Cartesian3_default = Cartesian3; // packages/engine/Source/Core/Matrix4.js var import_InlineWorkers10 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Cartesian4.js var import_InlineWorkers6 = __toESM(require_InlineWorkers(), 1); var Cartesian4 = class _Cartesian4 { /** * @param {number} [x=0.0] The X component. * @param {number} [y=0.0] The Y component. * @param {number} [z=0.0] The Z component. * @param {number} [w=0.0] The W component. */ constructor(x, y, z2, w) { this.x = x ?? 0; this.y = y ?? 0; this.z = z2 ?? 0; this.w = w ?? 0; } /** * Creates a Cartesian4 instance from x, y, z and w coordinates. * * @param {number} x The x coordinate. * @param {number} y The y coordinate. * @param {number} z The z coordinate. * @param {number} w The w coordinate. * @param {Cartesian4} [result] The object onto which to store the result. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. */ static fromElements(x, y, z2, w, result) { if (!defined_default(result)) { return new _Cartesian4(x, y, z2, w); } result.x = x; result.y = y; result.z = z2; result.w = w; return result; } /** * Creates a Cartesian4 instance from a {@link Color}. red, green, blue, * and alpha map to x, y, z, and w, respectively. * * @param {Color} color The source color. * @param {Cartesian4} [result] The object onto which to store the result. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. */ static fromColor(color, result) { Check_default.typeOf.object("color", color); if (!defined_default(result)) { return new _Cartesian4(color.red, color.green, color.blue, color.alpha); } result.x = color.red; result.y = color.green; result.z = color.blue; result.w = color.alpha; return result; } /** * Duplicates a Cartesian4 instance. * * @param {Cartesian4} cartesian The Cartesian to duplicate. * @param {Cartesian4} [result] The object onto which to store the result. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. (Returns undefined if cartesian is undefined) */ static clone(cartesian11, result) { if (!defined_default(cartesian11)) { return void 0; } if (!defined_default(result)) { return new _Cartesian4(cartesian11.x, cartesian11.y, cartesian11.z, cartesian11.w); } result.x = cartesian11.x; result.y = cartesian11.y; result.z = cartesian11.z; result.w = cartesian11.w; return result; } /** * Stores the provided instance into the provided array. * * @param {Cartesian4} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.x; array[startingIndex++] = value.y; array[startingIndex++] = value.z; array[startingIndex] = value.w; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Cartesian4} [result] The object into which to store the result. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Cartesian4(); } result.x = array[startingIndex++]; result.y = array[startingIndex++]; result.z = array[startingIndex++]; result.w = array[startingIndex]; return result; } /** * Flattens an array of Cartesian4s into an array of components. * * @param {Cartesian4[]} array The array of cartesians to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 4 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 4) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 4; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 4 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Cartesian4.pack(array[i], result, i * 4); } return result; } /** * Unpacks an array of cartesian components into an array of Cartesian4s. * * @param {number[]} array The array of components to unpack. * @param {Cartesian4[]} [result] The array onto which to store the result. * @returns {Cartesian4[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 4); if (array.length % 4 !== 0) { throw new DeveloperError_default("array length must be a multiple of 4."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 4); } else { result.length = length2 / 4; } for (let i = 0; i < length2; i += 4) { const index = i / 4; result[index] = _Cartesian4.unpack(array, i, result[index]); } return result; } /** * Computes the value of the maximum component for the supplied Cartesian. * * @param {Cartesian4} cartesian The cartesian to use. * @returns {number} The value of the maximum component. */ static maximumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.max(cartesian11.x, cartesian11.y, cartesian11.z, cartesian11.w); } /** * Computes the value of the minimum component for the supplied Cartesian. * * @param {Cartesian4} cartesian The cartesian to use. * @returns {number} The value of the minimum component. */ static minimumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.min(cartesian11.x, cartesian11.y, cartesian11.z, cartesian11.w); } /** * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians. * * @param {Cartesian4} first A cartesian to compare. * @param {Cartesian4} second A cartesian to compare. * @param {Cartesian4} result The object into which to store the result. * @returns {Cartesian4} A cartesian with the minimum components. */ static minimumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.min(first.x, second.x); result.y = Math.min(first.y, second.y); result.z = Math.min(first.z, second.z); result.w = Math.min(first.w, second.w); return result; } /** * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians. * * @param {Cartesian4} first A cartesian to compare. * @param {Cartesian4} second A cartesian to compare. * @param {Cartesian4} result The object into which to store the result. * @returns {Cartesian4} A cartesian with the maximum components. */ static maximumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.max(first.x, second.x); result.y = Math.max(first.y, second.y); result.z = Math.max(first.z, second.z); result.w = Math.max(first.w, second.w); return result; } /** * Constrain a value to lie between two values. * * @param {Cartesian4} value The value to clamp. * @param {Cartesian4} min The minimum bound. * @param {Cartesian4} max The maximum bound. * @param {Cartesian4} result The object into which to store the result. * @returns {Cartesian4} The clamped value such that min <= result <= max. */ static clamp(value, min3, max3, result) { Check_default.typeOf.object("value", value); Check_default.typeOf.object("min", min3); Check_default.typeOf.object("max", max3); Check_default.typeOf.object("result", result); const x = Math_default.clamp(value.x, min3.x, max3.x); const y = Math_default.clamp(value.y, min3.y, max3.y); const z2 = Math_default.clamp(value.z, min3.z, max3.z); const w = Math_default.clamp(value.w, min3.w, max3.w); result.x = x; result.y = y; result.z = z2; result.w = w; return result; } /** * Computes the provided Cartesian's squared magnitude. * * @param {Cartesian4} cartesian The Cartesian instance whose squared magnitude is to be computed. * @returns {number} The squared magnitude. */ static magnitudeSquared(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return cartesian11.x * cartesian11.x + cartesian11.y * cartesian11.y + cartesian11.z * cartesian11.z + cartesian11.w * cartesian11.w; } /** * Computes the Cartesian's magnitude (length). * * @param {Cartesian4} cartesian The Cartesian instance whose magnitude is to be computed. * @returns {number} The magnitude. */ static magnitude(cartesian11) { return Math.sqrt(_Cartesian4.magnitudeSquared(cartesian11)); } /** * Computes the 4-space distance between two points. * * @param {Cartesian4} left The first point to compute the distance from. * @param {Cartesian4} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 1.0 * const d = Cesium.Cartesian4.distance( * new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0), * new Cesium.Cartesian4(2.0, 0.0, 0.0, 0.0)); */ static distance(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian4.subtract(left, right, distanceScratch2); return _Cartesian4.magnitude(distanceScratch2); } /** * Computes the squared distance between two points. Comparing squared distances * using this function is more efficient than comparing distances using {@link Cartesian4#distance}. * * @param {Cartesian4} left The first point to compute the distance from. * @param {Cartesian4} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 4.0, not 2.0 * const d = Cesium.Cartesian4.distance( * new Cesium.Cartesian4(1.0, 0.0, 0.0, 0.0), * new Cesium.Cartesian4(3.0, 0.0, 0.0, 0.0)); */ static distanceSquared(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian4.subtract(left, right, distanceScratch2); return _Cartesian4.magnitudeSquared(distanceScratch2); } /** * Computes the normalized form of the supplied Cartesian. * * @param {Cartesian4} cartesian The Cartesian to be normalized. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static normalize(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const magnitude = _Cartesian4.magnitude(cartesian11); result.x = cartesian11.x / magnitude; result.y = cartesian11.y / magnitude; result.z = cartesian11.z / magnitude; result.w = cartesian11.w / magnitude; if (isNaN(result.x) || isNaN(result.y) || isNaN(result.z) || isNaN(result.w)) { throw new DeveloperError_default("normalized result is not a number"); } return result; } /** * Computes the dot (scalar) product of two Cartesians. * * @param {Cartesian4} left The first Cartesian. * @param {Cartesian4} right The second Cartesian. * @returns {number} The dot product. */ static dot(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w; } /** * Computes the componentwise product of two Cartesians. * * @param {Cartesian4} left The first Cartesian. * @param {Cartesian4} right The second Cartesian. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static multiplyComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x * right.x; result.y = left.y * right.y; result.z = left.z * right.z; result.w = left.w * right.w; return result; } /** * Computes the componentwise quotient of two Cartesians. * * @param {Cartesian4} left The first Cartesian. * @param {Cartesian4} right The second Cartesian. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static divideComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x / right.x; result.y = left.y / right.y; result.z = left.z / right.z; result.w = left.w / right.w; return result; } /** * Computes the componentwise sum of two Cartesians. * * @param {Cartesian4} left The first Cartesian. * @param {Cartesian4} right The second Cartesian. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x + right.x; result.y = left.y + right.y; result.z = left.z + right.z; result.w = left.w + right.w; return result; } /** * Computes the componentwise difference of two Cartesians. * * @param {Cartesian4} left The first Cartesian. * @param {Cartesian4} right The second Cartesian. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x - right.x; result.y = left.y - right.y; result.z = left.z - right.z; result.w = left.w - right.w; return result; } /** * Multiplies the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian4} cartesian The Cartesian to be scaled. * @param {number} scalar The scalar to multiply with. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static multiplyByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x * scalar; result.y = cartesian11.y * scalar; result.z = cartesian11.z * scalar; result.w = cartesian11.w * scalar; return result; } /** * Divides the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian4} cartesian The Cartesian to be divided. * @param {number} scalar The scalar to divide by. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static divideByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x / scalar; result.y = cartesian11.y / scalar; result.z = cartesian11.z / scalar; result.w = cartesian11.w / scalar; return result; } /** * Negates the provided Cartesian. * * @param {Cartesian4} cartesian The Cartesian to be negated. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static negate(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = -cartesian11.x; result.y = -cartesian11.y; result.z = -cartesian11.z; result.w = -cartesian11.w; return result; } /** * Computes the absolute value of the provided Cartesian. * * @param {Cartesian4} cartesian The Cartesian whose absolute value is to be computed. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static abs(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = Math.abs(cartesian11.x); result.y = Math.abs(cartesian11.y); result.z = Math.abs(cartesian11.z); result.w = Math.abs(cartesian11.w); return result; } /** * Computes the linear interpolation or extrapolation at t using the provided cartesians. * * @param {Cartesian4} start The value corresponding to t at 0.0. * @param {Cartesian4}end The value corresponding to t at 1.0. * @param {number} t The point along t at which to interpolate. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static lerp(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); _Cartesian4.multiplyByScalar(end, t2, lerpScratch2); result = _Cartesian4.multiplyByScalar(start, 1 - t2, result); return _Cartesian4.add(lerpScratch2, result, result); } /** * Returns the axis that is most orthogonal to the provided Cartesian. * * @param {Cartesian4} cartesian The Cartesian on which to find the most orthogonal axis. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The most orthogonal axis. */ static mostOrthogonalAxis(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const f2 = _Cartesian4.normalize(cartesian11, mostOrthogonalAxisScratch2); _Cartesian4.abs(f2, f2); if (f2.x <= f2.y) { if (f2.x <= f2.z) { if (f2.x <= f2.w) { result = _Cartesian4.clone(_Cartesian4.UNIT_X, result); } else { result = _Cartesian4.clone(_Cartesian4.UNIT_W, result); } } else if (f2.z <= f2.w) { result = _Cartesian4.clone(_Cartesian4.UNIT_Z, result); } else { result = _Cartesian4.clone(_Cartesian4.UNIT_W, result); } } else if (f2.y <= f2.z) { if (f2.y <= f2.w) { result = _Cartesian4.clone(_Cartesian4.UNIT_Y, result); } else { result = _Cartesian4.clone(_Cartesian4.UNIT_W, result); } } else if (f2.z <= f2.w) { result = _Cartesian4.clone(_Cartesian4.UNIT_Z, result); } else { result = _Cartesian4.clone(_Cartesian4.UNIT_W, result); } return result; } /** * Compares the provided Cartesians componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian4} [left] The first Cartesian. * @param {Cartesian4} [right] The second Cartesian. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.x === right.x && left.y === right.y && left.z === right.z && left.w === right.w; } /** * @param {Cartesian4} cartesian * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(cartesian11, array, offset) { return cartesian11.x === array[offset] && cartesian11.y === array[offset + 1] && cartesian11.z === array[offset + 2] && cartesian11.w === array[offset + 3]; } /** * Compares the provided Cartesians componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian4} [left] The first Cartesian. * @param {Cartesian4} [right] The second Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, relativeEpsilon, absoluteEpsilon) { return left === right || defined_default(left) && defined_default(right) && Math_default.equalsEpsilon( left.x, right.x, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.y, right.y, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.z, right.z, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.w, right.w, relativeEpsilon, absoluteEpsilon ); } /** * Duplicates this Cartesian4 instance. * * @param {Cartesian4} [result] The object onto which to store the result. * @returns {Cartesian4} The modified result parameter or a new Cartesian4 instance if one was not provided. */ clone(result) { return _Cartesian4.clone(this, result); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian4} [right] The right hand side Cartesian. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Cartesian4.equals(this, right); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian4} [right] The right hand side Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, relativeEpsilon, absoluteEpsilon) { return _Cartesian4.equalsEpsilon( this, right, relativeEpsilon, absoluteEpsilon ); } /** * Creates a string representing this Cartesian in the format '(x, y, z, w)'. * * @returns {string} A string representing the provided Cartesian in the format '(x, y, z, w)'. */ toString() { return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`; } /** * Packs an arbitrary floating point value to 4 values representable using uint8. * * @param {number} value A floating point number. * @param {Cartesian4} [result] The Cartesian4 that will contain the packed float. * @returns {Cartesian4} A Cartesian4 representing the float packed to values in x, y, z, and w. */ static packFloat(value, result) { Check_default.typeOf.number("value", value); if (!defined_default(result)) { result = new _Cartesian4(); } scratchF32Array[0] = value; if (littleEndian) { result.x = scratchU8Array[0]; result.y = scratchU8Array[1]; result.z = scratchU8Array[2]; result.w = scratchU8Array[3]; } else { result.x = scratchU8Array[3]; result.y = scratchU8Array[2]; result.z = scratchU8Array[1]; result.w = scratchU8Array[0]; } return result; } /** * Unpacks a float packed using Cartesian4.packFloat. * * @param {Cartesian4} packedFloat A Cartesian4 containing a float packed to 4 values representable using uint8. * @returns {number} The unpacked float. * @private */ static unpackFloat(packedFloat) { Check_default.typeOf.object("packedFloat", packedFloat); if (littleEndian) { scratchU8Array[0] = packedFloat.x; scratchU8Array[1] = packedFloat.y; scratchU8Array[2] = packedFloat.z; scratchU8Array[3] = packedFloat.w; } else { scratchU8Array[0] = packedFloat.w; scratchU8Array[1] = packedFloat.z; scratchU8Array[2] = packedFloat.y; scratchU8Array[3] = packedFloat.x; } return scratchF32Array[0]; } }; Cartesian4.packedLength = 4; Cartesian4.fromArray = Cartesian4.unpack; var distanceScratch2 = new Cartesian4(); var lerpScratch2 = new Cartesian4(); var mostOrthogonalAxisScratch2 = new Cartesian4(); Cartesian4.ZERO = Object.freeze(new Cartesian4(0, 0, 0, 0)); Cartesian4.ONE = Object.freeze(new Cartesian4(1, 1, 1, 1)); Cartesian4.UNIT_X = Object.freeze(new Cartesian4(1, 0, 0, 0)); Cartesian4.UNIT_Y = Object.freeze(new Cartesian4(0, 1, 0, 0)); Cartesian4.UNIT_Z = Object.freeze(new Cartesian4(0, 0, 1, 0)); Cartesian4.UNIT_W = Object.freeze(new Cartesian4(0, 0, 0, 1)); var scratchF32Array = new Float32Array(1); var scratchU8Array = new Uint8Array(scratchF32Array.buffer); var testU32 = new Uint32Array([287454020]); var testU8 = new Uint8Array(testU32.buffer); var littleEndian = testU8[0] === 68; var Cartesian4_default = Cartesian4; // packages/engine/Source/Core/Frozen.js var import_InlineWorkers7 = __toESM(require_InlineWorkers(), 1); var Frozen = {}; Frozen.EMPTY_OBJECT = Object.freeze({}); Frozen.EMPTY_ARRAY = Object.freeze([]); var Frozen_default = Frozen; // packages/engine/Source/Core/Matrix3.js var import_InlineWorkers8 = __toESM(require_InlineWorkers(), 1); var Matrix3 = class _Matrix3 { /** * @param {number} [column0Row0=0.0] The value for column 0, row 0. * @param {number} [column1Row0=0.0] The value for column 1, row 0. * @param {number} [column2Row0=0.0] The value for column 2, row 0. * @param {number} [column0Row1=0.0] The value for column 0, row 1. * @param {number} [column1Row1=0.0] The value for column 1, row 1. * @param {number} [column2Row1=0.0] The value for column 2, row 1. * @param {number} [column0Row2=0.0] The value for column 0, row 2. * @param {number} [column1Row2=0.0] The value for column 1, row 2. * @param {number} [column2Row2=0.0] The value for column 2, row 2. */ constructor(column0Row0, column1Row0, column2Row0, column0Row1, column1Row1, column2Row1, column0Row2, column1Row2, column2Row2) { this[0] = column0Row0 ?? 0; this[1] = column0Row1 ?? 0; this[2] = column0Row2 ?? 0; this[3] = column1Row0 ?? 0; this[4] = column1Row1 ?? 0; this[5] = column1Row2 ?? 0; this[6] = column2Row0 ?? 0; this[7] = column2Row1 ?? 0; this[8] = column2Row2 ?? 0; } /** * Stores the provided instance into the provided array. * * @param {Matrix3} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value[0]; array[startingIndex++] = value[1]; array[startingIndex++] = value[2]; array[startingIndex++] = value[3]; array[startingIndex++] = value[4]; array[startingIndex++] = value[5]; array[startingIndex++] = value[6]; array[startingIndex++] = value[7]; array[startingIndex] = value[8]; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Matrix3} [result] The object into which to store the result. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Matrix3(); } result[0] = array[startingIndex++]; result[1] = array[startingIndex++]; result[2] = array[startingIndex++]; result[3] = array[startingIndex++]; result[4] = array[startingIndex++]; result[5] = array[startingIndex++]; result[6] = array[startingIndex++]; result[7] = array[startingIndex++]; result[8] = array[startingIndex]; return result; } /** * Flattens an array of Matrix3s into an array of components. The components * are stored in column-major order. * * @param {Matrix3[]} array The array of matrices to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 9 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 9) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 9; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 9 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Matrix3.pack(array[i], result, i * 9); } return result; } /** * Unpacks an array of column-major matrix components into an array of Matrix3s. * * @param {number[]} array The array of components to unpack. * @param {Matrix3[]} [result] The array onto which to store the result. * @returns {Matrix3[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 9); if (array.length % 9 !== 0) { throw new DeveloperError_default("array length must be a multiple of 9."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 9); } else { result.length = length2 / 9; } for (let i = 0; i < length2; i += 9) { const index = i / 9; result[index] = _Matrix3.unpack(array, i, result[index]); } return result; } /** * Duplicates a Matrix3 instance. * * @param {Matrix3} matrix The matrix to duplicate. * @param {Matrix3} [result] The object onto which to store the result. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided. (Returns undefined if matrix is undefined) */ static clone(matrix, result) { if (!defined_default(matrix)) { return void 0; } if (!defined_default(result)) { return new _Matrix3( matrix[0], matrix[3], matrix[6], matrix[1], matrix[4], matrix[7], matrix[2], matrix[5], matrix[8] ); } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; return result; } /** * Creates a Matrix3 instance from a column-major order array. * * @param {number[]} values The column-major order array. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. */ static fromColumnMajorArray(values, result) { Check_default.defined("values", values); return _Matrix3.clone(values, result); } /** * Creates a Matrix3 instance from a row-major order array. * The resulting matrix will be in column-major order. * * @param {number[]} values The row-major order array. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. */ static fromRowMajorArray(values, result) { Check_default.defined("values", values); if (!defined_default(result)) { return new _Matrix3( values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8] ); } result[0] = values[0]; result[1] = values[3]; result[2] = values[6]; result[3] = values[1]; result[4] = values[4]; result[5] = values[7]; result[6] = values[2]; result[7] = values[5]; result[8] = values[8]; return result; } /** * Computes a 3x3 rotation matrix from the provided quaternion. * * @param {Quaternion} quaternion the quaternion to use. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The 3x3 rotation matrix from this quaternion. */ static fromQuaternion(quaternion, result) { Check_default.typeOf.object("quaternion", quaternion); const x2 = quaternion.x * quaternion.x; const xy = quaternion.x * quaternion.y; const xz = quaternion.x * quaternion.z; const xw = quaternion.x * quaternion.w; const y2 = quaternion.y * quaternion.y; const yz = quaternion.y * quaternion.z; const yw = quaternion.y * quaternion.w; const z2 = quaternion.z * quaternion.z; const zw = quaternion.z * quaternion.w; const w2 = quaternion.w * quaternion.w; const m00 = x2 - y2 - z2 + w2; const m01 = 2 * (xy - zw); const m02 = 2 * (xz + yw); const m10 = 2 * (xy + zw); const m11 = -x2 + y2 - z2 + w2; const m12 = 2 * (yz - xw); const m20 = 2 * (xz - yw); const m21 = 2 * (yz + xw); const m22 = -x2 - y2 + z2 + w2; if (!defined_default(result)) { return new _Matrix3(m00, m01, m02, m10, m11, m12, m20, m21, m22); } result[0] = m00; result[1] = m10; result[2] = m20; result[3] = m01; result[4] = m11; result[5] = m21; result[6] = m02; result[7] = m12; result[8] = m22; return result; } /** * Computes a 3x3 rotation matrix from the provided headingPitchRoll. (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles ) * * @param {HeadingPitchRoll} headingPitchRoll the headingPitchRoll to use. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The 3x3 rotation matrix from this headingPitchRoll. */ static fromHeadingPitchRoll(headingPitchRoll, result) { Check_default.typeOf.object("headingPitchRoll", headingPitchRoll); const cosTheta = Math.cos(-headingPitchRoll.pitch); const cosPsi = Math.cos(-headingPitchRoll.heading); const cosPhi = Math.cos(headingPitchRoll.roll); const sinTheta = Math.sin(-headingPitchRoll.pitch); const sinPsi = Math.sin(-headingPitchRoll.heading); const sinPhi = Math.sin(headingPitchRoll.roll); const m00 = cosTheta * cosPsi; const m01 = -cosPhi * sinPsi + sinPhi * sinTheta * cosPsi; const m02 = sinPhi * sinPsi + cosPhi * sinTheta * cosPsi; const m10 = cosTheta * sinPsi; const m11 = cosPhi * cosPsi + sinPhi * sinTheta * sinPsi; const m12 = -sinPhi * cosPsi + cosPhi * sinTheta * sinPsi; const m20 = -sinTheta; const m21 = sinPhi * cosTheta; const m22 = cosPhi * cosTheta; if (!defined_default(result)) { return new _Matrix3(m00, m01, m02, m10, m11, m12, m20, m21, m22); } result[0] = m00; result[1] = m10; result[2] = m20; result[3] = m01; result[4] = m11; result[5] = m21; result[6] = m02; result[7] = m12; result[8] = m22; return result; } /** * Computes a Matrix3 instance representing a non-uniform scale. * * @param {Cartesian3} scale The x, y, and z scale factors. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Creates * // [7.0, 0.0, 0.0] * // [0.0, 8.0, 0.0] * // [0.0, 0.0, 9.0] * const m = Cesium.Matrix3.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0)); */ static fromScale(scale, result) { Check_default.typeOf.object("scale", scale); if (!defined_default(result)) { return new _Matrix3( scale.x, 0, 0, 0, scale.y, 0, 0, 0, scale.z ); } result[0] = scale.x; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = scale.y; result[5] = 0; result[6] = 0; result[7] = 0; result[8] = scale.z; return result; } /** * Computes a Matrix3 instance representing a uniform scale. * * @param {number} scale The uniform scale factor. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Creates * // [2.0, 0.0, 0.0] * // [0.0, 2.0, 0.0] * // [0.0, 0.0, 2.0] * const m = Cesium.Matrix3.fromUniformScale(2.0); */ static fromUniformScale(scale, result) { Check_default.typeOf.number("scale", scale); if (!defined_default(result)) { return new _Matrix3(scale, 0, 0, 0, scale, 0, 0, 0, scale); } result[0] = scale; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = scale; result[5] = 0; result[6] = 0; result[7] = 0; result[8] = scale; return result; } /** * Computes a Matrix3 instance representing the cross product equivalent matrix of a Cartesian3 vector. * * @param {Cartesian3} vector the vector on the left hand side of the cross product operation. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Creates * // [0.0, -9.0, 8.0] * // [9.0, 0.0, -7.0] * // [-8.0, 7.0, 0.0] * const m = Cesium.Matrix3.fromCrossProduct(new Cesium.Cartesian3(7.0, 8.0, 9.0)); */ static fromCrossProduct(vector, result) { Check_default.typeOf.object("vector", vector); if (!defined_default(result)) { return new _Matrix3( 0, -vector.z, vector.y, vector.z, 0, -vector.x, -vector.y, vector.x, 0 ); } result[0] = 0; result[1] = vector.z; result[2] = -vector.y; result[3] = -vector.z; result[4] = 0; result[5] = vector.x; result[6] = vector.y; result[7] = -vector.x; result[8] = 0; return result; } /** * Creates a rotation matrix around the x-axis. * * @param {number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Rotate a point 45 degrees counterclockwise around the x-axis. * const p = new Cesium.Cartesian3(5, 6, 7); * const m = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(45.0)); * const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3()); */ static fromRotationX(angle, result) { Check_default.typeOf.number("angle", angle); const cosAngle = Math.cos(angle); const sinAngle = Math.sin(angle); if (!defined_default(result)) { return new _Matrix3( 1, 0, 0, 0, cosAngle, -sinAngle, 0, sinAngle, cosAngle ); } result[0] = 1; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = cosAngle; result[5] = sinAngle; result[6] = 0; result[7] = -sinAngle; result[8] = cosAngle; return result; } /** * Creates a rotation matrix around the y-axis. * * @param {number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Rotate a point 45 degrees counterclockwise around the y-axis. * const p = new Cesium.Cartesian3(5, 6, 7); * const m = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(45.0)); * const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3()); */ static fromRotationY(angle, result) { Check_default.typeOf.number("angle", angle); const cosAngle = Math.cos(angle); const sinAngle = Math.sin(angle); if (!defined_default(result)) { return new _Matrix3( cosAngle, 0, sinAngle, 0, 1, 0, -sinAngle, 0, cosAngle ); } result[0] = cosAngle; result[1] = 0; result[2] = -sinAngle; result[3] = 0; result[4] = 1; result[5] = 0; result[6] = sinAngle; result[7] = 0; result[8] = cosAngle; return result; } /** * Creates a rotation matrix around the z-axis. * * @param {number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise. * @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix3} The modified result parameter, or a new Matrix3 instance if one was not provided. * * @example * // Rotate a point 45 degrees counterclockwise around the z-axis. * const p = new Cesium.Cartesian3(5, 6, 7); * const m = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(45.0)); * const rotated = Cesium.Matrix3.multiplyByVector(m, p, new Cesium.Cartesian3()); */ static fromRotationZ(angle, result) { Check_default.typeOf.number("angle", angle); const cosAngle = Math.cos(angle); const sinAngle = Math.sin(angle); if (!defined_default(result)) { return new _Matrix3( cosAngle, -sinAngle, 0, sinAngle, cosAngle, 0, 0, 0, 1 ); } result[0] = cosAngle; result[1] = sinAngle; result[2] = 0; result[3] = -sinAngle; result[4] = cosAngle; result[5] = 0; result[6] = 0; result[7] = 0; result[8] = 1; return result; } /** * Creates an Array from the provided Matrix3 instance. * The array will be in column-major order. * * @param {Matrix3} matrix The matrix to use.. * @param {number[]} [result] The Array onto which to store the result. * @returns {number[]} The modified Array parameter or a new Array instance if one was not provided. */ static toArray(matrix, result) { Check_default.typeOf.object("matrix", matrix); if (!defined_default(result)) { return [ matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8] ]; } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; return result; } /** * Computes the array index of the element at the provided row and column. * * @param {number} column The zero-based index of the column. * @param {number} row The zero-based index of the row. * @returns {number} The index of the element at the provided row and column. * * @exception {DeveloperError} row must be 0, 1, or 2. * @exception {DeveloperError} column must be 0, 1, or 2. * * @example * const myMatrix = new Cesium.Matrix3(); * const column1Row0Index = Cesium.Matrix3.getElementIndex(1, 0); * const column1Row0 = myMatrix[column1Row0Index] * myMatrix[column1Row0Index] = 10.0; */ static getElementIndex(column, row) { Check_default.typeOf.number.greaterThanOrEquals("row", row, 0); Check_default.typeOf.number.lessThanOrEquals("row", row, 2); Check_default.typeOf.number.greaterThanOrEquals("column", column, 0); Check_default.typeOf.number.lessThanOrEquals("column", column, 2); return column * 3 + row; } /** * Retrieves a copy of the matrix column at the provided index as a Cartesian3 instance. * * @param {Matrix3} matrix The matrix to use. * @param {number} index The zero-based index of the column to retrieve. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, or 2. */ static getColumn(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 2); Check_default.typeOf.object("result", result); const startIndex = index * 3; const x = matrix[startIndex]; const y = matrix[startIndex + 1]; const z2 = matrix[startIndex + 2]; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian3 instance. * * @param {Matrix3} matrix The matrix to use. * @param {number} index The zero-based index of the column to set. * @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified column. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, or 2. */ static setColumn(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 2); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix3.clone(matrix, result); const startIndex = index * 3; result[startIndex] = cartesian11.x; result[startIndex + 1] = cartesian11.y; result[startIndex + 2] = cartesian11.z; return result; } /** * Retrieves a copy of the matrix row at the provided index as a Cartesian3 instance. * * @param {Matrix3} matrix The matrix to use. * @param {number} index The zero-based index of the row to retrieve. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, or 2. */ static getRow(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 2); Check_default.typeOf.object("result", result); const x = matrix[index]; const y = matrix[index + 3]; const z2 = matrix[index + 6]; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian3 instance. * * @param {Matrix3} matrix The matrix to use. * @param {number} index The zero-based index of the row to set. * @param {Cartesian3} cartesian The Cartesian whose values will be assigned to the specified row. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, or 2. */ static setRow(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 2); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix3.clone(matrix, result); result[index] = cartesian11.x; result[index + 3] = cartesian11.y; result[index + 6] = cartesian11.z; return result; } /** * Computes a new matrix that replaces the scale with the provided scale. * This assumes the matrix is an affine transformation. * * @param {Matrix3} matrix The matrix to use. * @param {Cartesian3} scale The scale that replaces the scale of the provided matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @see Matrix3.setUniformScale * @see Matrix3.fromScale * @see Matrix3.fromUniformScale * @see Matrix3.multiplyByScale * @see Matrix3.multiplyByUniformScale * @see Matrix3.getScale */ static setScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix3.getScale(matrix, scaleScratch1); const scaleRatioX = scale.x / existingScale.x; const scaleRatioY = scale.y / existingScale.y; const scaleRatioZ = scale.z / existingScale.z; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioX; result[3] = matrix[3] * scaleRatioY; result[4] = matrix[4] * scaleRatioY; result[5] = matrix[5] * scaleRatioY; result[6] = matrix[6] * scaleRatioZ; result[7] = matrix[7] * scaleRatioZ; result[8] = matrix[8] * scaleRatioZ; return result; } /** * Computes a new matrix that replaces the scale with the provided uniform scale. * This assumes the matrix is an affine transformation. * * @param {Matrix3} matrix The matrix to use. * @param {number} scale The uniform scale that replaces the scale of the provided matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @see Matrix3.setScale * @see Matrix3.fromScale * @see Matrix3.fromUniformScale * @see Matrix3.multiplyByScale * @see Matrix3.multiplyByUniformScale * @see Matrix3.getScale */ static setUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix3.getScale(matrix, scaleScratch2); const scaleRatioX = scale / existingScale.x; const scaleRatioY = scale / existingScale.y; const scaleRatioZ = scale / existingScale.z; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioX; result[3] = matrix[3] * scaleRatioY; result[4] = matrix[4] * scaleRatioY; result[5] = matrix[5] * scaleRatioY; result[6] = matrix[6] * scaleRatioZ; result[7] = matrix[7] * scaleRatioZ; result[8] = matrix[8] * scaleRatioZ; return result; } /** * Extracts the non-uniform scale assuming the matrix is an affine transformation. * * @param {Matrix3} matrix The matrix. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. * * @see Matrix3.multiplyByScale * @see Matrix3.multiplyByUniformScale * @see Matrix3.fromScale * @see Matrix3.fromUniformScale * @see Matrix3.setScale * @see Matrix3.setUniformScale */ static getScale(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result.x = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn) ); result.y = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[3], matrix[4], matrix[5], scratchColumn) ); result.z = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[6], matrix[7], matrix[8], scratchColumn) ); return result; } /** * Computes the maximum scale assuming the matrix is an affine transformation. * The maximum scale is the maximum length of the column vectors. * * @param {Matrix3} matrix The matrix. * @returns {number} The maximum scale. */ static getMaximumScale(matrix) { _Matrix3.getScale(matrix, scaleScratch3); return Cartesian3_default.maximumComponent(scaleScratch3); } /** * Sets the rotation assuming the matrix is an affine transformation. * * @param {Matrix3} matrix The matrix. * @param {Matrix3} rotation The rotation matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @see Matrix3.getRotation */ static setRotation(matrix, rotation, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix3.getScale(matrix, scaleScratch4); result[0] = rotation[0] * scale.x; result[1] = rotation[1] * scale.x; result[2] = rotation[2] * scale.x; result[3] = rotation[3] * scale.y; result[4] = rotation[4] * scale.y; result[5] = rotation[5] * scale.y; result[6] = rotation[6] * scale.z; result[7] = rotation[7] * scale.z; result[8] = rotation[8] * scale.z; return result; } /** * Extracts the rotation matrix assuming the matrix is an affine transformation. * * @param {Matrix3} matrix The matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @see Matrix3.setRotation */ static getRotation(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix3.getScale(matrix, scaleScratch5); result[0] = matrix[0] / scale.x; result[1] = matrix[1] / scale.x; result[2] = matrix[2] / scale.x; result[3] = matrix[3] / scale.y; result[4] = matrix[4] / scale.y; result[5] = matrix[5] / scale.y; result[6] = matrix[6] / scale.z; result[7] = matrix[7] / scale.z; result[8] = matrix[8] / scale.z; return result; } /** * Computes the product of two matrices. * * @param {Matrix3} left The first matrix. * @param {Matrix3} right The second matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static multiply(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const column0Row0 = left[0] * right[0] + left[3] * right[1] + left[6] * right[2]; const column0Row1 = left[1] * right[0] + left[4] * right[1] + left[7] * right[2]; const column0Row2 = left[2] * right[0] + left[5] * right[1] + left[8] * right[2]; const column1Row0 = left[0] * right[3] + left[3] * right[4] + left[6] * right[5]; const column1Row1 = left[1] * right[3] + left[4] * right[4] + left[7] * right[5]; const column1Row2 = left[2] * right[3] + left[5] * right[4] + left[8] * right[5]; const column2Row0 = left[0] * right[6] + left[3] * right[7] + left[6] * right[8]; const column2Row1 = left[1] * right[6] + left[4] * right[7] + left[7] * right[8]; const column2Row2 = left[2] * right[6] + left[5] * right[7] + left[8] * right[8]; result[0] = column0Row0; result[1] = column0Row1; result[2] = column0Row2; result[3] = column1Row0; result[4] = column1Row1; result[5] = column1Row2; result[6] = column2Row0; result[7] = column2Row1; result[8] = column2Row2; return result; } /** * Computes the sum of two matrices. * * @param {Matrix3} left The first matrix. * @param {Matrix3} right The second matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] + right[0]; result[1] = left[1] + right[1]; result[2] = left[2] + right[2]; result[3] = left[3] + right[3]; result[4] = left[4] + right[4]; result[5] = left[5] + right[5]; result[6] = left[6] + right[6]; result[7] = left[7] + right[7]; result[8] = left[8] + right[8]; return result; } /** * Computes the difference of two matrices. * * @param {Matrix3} left The first matrix. * @param {Matrix3} right The second matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] - right[0]; result[1] = left[1] - right[1]; result[2] = left[2] - right[2]; result[3] = left[3] - right[3]; result[4] = left[4] - right[4]; result[5] = left[5] - right[5]; result[6] = left[6] - right[6]; result[7] = left[7] - right[7]; result[8] = left[8] - right[8]; return result; } /** * Computes the product of a matrix and a column vector. * * @param {Matrix3} matrix The matrix. * @param {Cartesian3} cartesian The column. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static multiplyByVector(matrix, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const vX = cartesian11.x; const vY = cartesian11.y; const vZ = cartesian11.z; const x = matrix[0] * vX + matrix[3] * vY + matrix[6] * vZ; const y = matrix[1] * vX + matrix[4] * vY + matrix[7] * vZ; const z2 = matrix[2] * vX + matrix[5] * vY + matrix[8] * vZ; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes the product of a matrix and a scalar. * * @param {Matrix3} matrix The matrix. * @param {number} scalar The number to multiply by. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static multiplyByScalar(matrix, scalar, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scalar; result[1] = matrix[1] * scalar; result[2] = matrix[2] * scalar; result[3] = matrix[3] * scalar; result[4] = matrix[4] * scalar; result[5] = matrix[5] * scalar; result[6] = matrix[6] * scalar; result[7] = matrix[7] * scalar; result[8] = matrix[8] * scalar; return result; } /** * Computes the product of a matrix times a (non-uniform) scale, as if the scale were a scale matrix. * * @param {Matrix3} matrix The matrix on the left-hand side. * @param {Cartesian3} scale The non-uniform scale on the right-hand side. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * * @example * // Instead of Cesium.Matrix3.multiply(m, Cesium.Matrix3.fromScale(scale), m); * Cesium.Matrix3.multiplyByScale(m, scale, m); * * @see Matrix3.multiplyByUniformScale * @see Matrix3.fromScale * @see Matrix3.fromUniformScale * @see Matrix3.setScale * @see Matrix3.setUniformScale * @see Matrix3.getScale */ static multiplyByScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scale.x; result[1] = matrix[1] * scale.x; result[2] = matrix[2] * scale.x; result[3] = matrix[3] * scale.y; result[4] = matrix[4] * scale.y; result[5] = matrix[5] * scale.y; result[6] = matrix[6] * scale.z; result[7] = matrix[7] * scale.z; result[8] = matrix[8] * scale.z; return result; } /** * Computes the product of a matrix times a uniform scale, as if the scale were a scale matrix. * * @param {Matrix3} matrix The matrix on the left-hand side. * @param {number} scale The uniform scale on the right-hand side. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @example * // Instead of Cesium.Matrix3.multiply(m, Cesium.Matrix3.fromUniformScale(scale), m); * Cesium.Matrix3.multiplyByUniformScale(m, scale, m); * * @see Matrix3.multiplyByScale * @see Matrix3.fromScale * @see Matrix3.fromUniformScale * @see Matrix3.setScale * @see Matrix3.setUniformScale * @see Matrix3.getScale */ static multiplyByUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scale; result[1] = matrix[1] * scale; result[2] = matrix[2] * scale; result[3] = matrix[3] * scale; result[4] = matrix[4] * scale; result[5] = matrix[5] * scale; result[6] = matrix[6] * scale; result[7] = matrix[7] * scale; result[8] = matrix[8] * scale; return result; } /** * Creates a negated copy of the provided matrix. * * @param {Matrix3} matrix The matrix to negate. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static negate(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = -matrix[0]; result[1] = -matrix[1]; result[2] = -matrix[2]; result[3] = -matrix[3]; result[4] = -matrix[4]; result[5] = -matrix[5]; result[6] = -matrix[6]; result[7] = -matrix[7]; result[8] = -matrix[8]; return result; } /** * Computes the transpose of the provided matrix. * * @param {Matrix3} matrix The matrix to transpose. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static transpose(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const column0Row0 = matrix[0]; const column0Row1 = matrix[3]; const column0Row2 = matrix[6]; const column1Row0 = matrix[1]; const column1Row1 = matrix[4]; const column1Row2 = matrix[7]; const column2Row0 = matrix[2]; const column2Row1 = matrix[5]; const column2Row2 = matrix[8]; result[0] = column0Row0; result[1] = column0Row1; result[2] = column0Row2; result[3] = column1Row0; result[4] = column1Row1; result[5] = column1Row2; result[6] = column2Row0; result[7] = column2Row1; result[8] = column2Row2; return result; } /** * Computes the eigenvectors and eigenvalues of a symmetric matrix. *

* Returns a diagonal matrix and unitary matrix such that: * matrix = unitary matrix * diagonal matrix * transpose(unitary matrix) *

*

* The values along the diagonal of the diagonal matrix are the eigenvalues. The columns * of the unitary matrix are the corresponding eigenvectors. *

* * @param {Matrix3} matrix The matrix to decompose into diagonal and unitary matrix. Expected to be symmetric. * @param {EigenDecompositionResult} [result] An object with unitary and diagonal properties which are matrices onto which to store the result. * @returns {EigenDecompositionResult} An object with unitary and diagonal properties which are the unitary and diagonal matrices, respectively. * * @example * const a = //... symetric matrix * const result = { * unitary : new Cesium.Matrix3(), * diagonal : new Cesium.Matrix3() * }; * Cesium.Matrix3.computeEigenDecomposition(a, result); * * const unitaryTranspose = Cesium.Matrix3.transpose(result.unitary, new Cesium.Matrix3()); * const b = Cesium.Matrix3.multiply(result.unitary, result.diagonal, new Cesium.Matrix3()); * Cesium.Matrix3.multiply(b, unitaryTranspose, b); // b is now equal to a * * const lambda = Cesium.Matrix3.getColumn(result.diagonal, 0, new Cesium.Cartesian3()).x; // first eigenvalue * const v = Cesium.Matrix3.getColumn(result.unitary, 0, new Cesium.Cartesian3()); // first eigenvector * const c = Cesium.Cartesian3.multiplyByScalar(v, lambda, new Cesium.Cartesian3()); // equal to Cesium.Matrix3.multiplyByVector(a, v) */ static computeEigenDecomposition(matrix, result) { Check_default.typeOf.object("matrix", matrix); const tolerance = Math_default.EPSILON20; const maxSweeps = 10; let count = 0; let sweep = 0; if (!defined_default(result)) { result = {}; } const unitaryMatrix = result.unitary = _Matrix3.clone( _Matrix3.IDENTITY, result.unitary ); const diagMatrix = result.diagonal = _Matrix3.clone( matrix, result.diagonal ); const epsilon = tolerance * computeFrobeniusNorm(diagMatrix); while (sweep < maxSweeps && offDiagonalFrobeniusNorm(diagMatrix) > epsilon) { shurDecomposition(diagMatrix, jMatrix); _Matrix3.transpose(jMatrix, jMatrixTranspose); _Matrix3.multiply(diagMatrix, jMatrix, diagMatrix); _Matrix3.multiply(jMatrixTranspose, diagMatrix, diagMatrix); _Matrix3.multiply(unitaryMatrix, jMatrix, unitaryMatrix); if (++count > 2) { ++sweep; count = 0; } } return result; } /** * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements. * * @param {Matrix3} matrix The matrix with signed elements. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static abs(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = Math.abs(matrix[0]); result[1] = Math.abs(matrix[1]); result[2] = Math.abs(matrix[2]); result[3] = Math.abs(matrix[3]); result[4] = Math.abs(matrix[4]); result[5] = Math.abs(matrix[5]); result[6] = Math.abs(matrix[6]); result[7] = Math.abs(matrix[7]); result[8] = Math.abs(matrix[8]); return result; } /** * Computes the determinant of the provided matrix. * * @param {Matrix3} matrix The matrix to use. * @returns {number} The value of the determinant of the matrix. */ static determinant(matrix) { Check_default.typeOf.object("matrix", matrix); const m11 = matrix[0]; const m21 = matrix[3]; const m31 = matrix[6]; const m12 = matrix[1]; const m22 = matrix[4]; const m32 = matrix[7]; const m13 = matrix[2]; const m23 = matrix[5]; const m33 = matrix[8]; return m11 * (m22 * m33 - m23 * m32) + m12 * (m23 * m31 - m21 * m33) + m13 * (m21 * m32 - m22 * m31); } /** * Computes the inverse of the provided matrix. * * @param {Matrix3} matrix The matrix to invert. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @exception {DeveloperError} matrix is not invertible. */ static inverse(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const m11 = matrix[0]; const m21 = matrix[1]; const m31 = matrix[2]; const m12 = matrix[3]; const m22 = matrix[4]; const m32 = matrix[5]; const m13 = matrix[6]; const m23 = matrix[7]; const m33 = matrix[8]; const determinant = _Matrix3.determinant(matrix); if (Math.abs(determinant) <= Math_default.EPSILON15) { throw new DeveloperError_default("matrix is not invertible"); } result[0] = m22 * m33 - m23 * m32; result[1] = m23 * m31 - m21 * m33; result[2] = m21 * m32 - m22 * m31; result[3] = m13 * m32 - m12 * m33; result[4] = m11 * m33 - m13 * m31; result[5] = m12 * m31 - m11 * m32; result[6] = m12 * m23 - m13 * m22; result[7] = m13 * m21 - m11 * m23; result[8] = m11 * m22 - m12 * m21; const scale = 1 / determinant; return _Matrix3.multiplyByScalar(result, scale, result); } /** * Computes the inverse transpose of a matrix. * * @param {Matrix3} matrix The matrix to transpose and invert. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. */ static inverseTranspose(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); return _Matrix3.inverse( _Matrix3.transpose(matrix, scratchTransposeMatrix), result ); } /** * Compares the provided matrices componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix3} [left] The first matrix. * @param {Matrix3} [right] The second matrix. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left[0] === right[0] && left[1] === right[1] && left[2] === right[2] && left[3] === right[3] && left[4] === right[4] && left[5] === right[5] && left[6] === right[6] && left[7] === right[7] && left[8] === right[8]; } /** * Compares the provided matrices componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix3} [left] The first matrix. * @param {Matrix3} [right] The second matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left[0] - right[0]) <= epsilon && Math.abs(left[1] - right[1]) <= epsilon && Math.abs(left[2] - right[2]) <= epsilon && Math.abs(left[3] - right[3]) <= epsilon && Math.abs(left[4] - right[4]) <= epsilon && Math.abs(left[5] - right[5]) <= epsilon && Math.abs(left[6] - right[6]) <= epsilon && Math.abs(left[7] - right[7]) <= epsilon && Math.abs(left[8] - right[8]) <= epsilon; } /** * Gets the number of items in the collection. * * @type {number} */ get length() { return _Matrix3.packedLength; } /** * Duplicates the provided Matrix3 instance. * * @param {Matrix3} [result] The object onto which to store the result. * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if one was not provided. */ clone(result) { return _Matrix3.clone(this, result); } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix3} [right] The right hand side matrix. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Matrix3.equals(this, right); } /** * Compares provided matrix and array, starting from a given array offset. * * @param {Matrix3} matrix * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(matrix, array, offset) { return matrix[0] === array[offset] && matrix[1] === array[offset + 1] && matrix[2] === array[offset + 2] && matrix[3] === array[offset + 3] && matrix[4] === array[offset + 4] && matrix[5] === array[offset + 5] && matrix[6] === array[offset + 6] && matrix[7] === array[offset + 7] && matrix[8] === array[offset + 8]; } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix3} [right] The right hand side matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, epsilon) { return _Matrix3.equalsEpsilon(this, right, epsilon); } /** * Creates a string representing this Matrix with each row being * on a separate line and in the format '(column0, column1, column2)'. * * @returns {string} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2)'. */ toString() { return `(${this[0]}, ${this[3]}, ${this[6]}) (${this[1]}, ${this[4]}, ${this[7]}) (${this[2]}, ${this[5]}, ${this[8]})`; } }; Matrix3.packedLength = 9; Matrix3.fromArray = Matrix3.unpack; Matrix3.IDENTITY = Object.freeze( new Matrix3(1, 0, 0, 0, 1, 0, 0, 0, 1) ); Matrix3.ZERO = Object.freeze( new Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0) ); Matrix3.COLUMN0ROW0 = 0; Matrix3.COLUMN0ROW1 = 1; Matrix3.COLUMN0ROW2 = 2; Matrix3.COLUMN1ROW0 = 3; Matrix3.COLUMN1ROW1 = 4; Matrix3.COLUMN1ROW2 = 5; Matrix3.COLUMN2ROW0 = 6; Matrix3.COLUMN2ROW1 = 7; Matrix3.COLUMN2ROW2 = 8; var scaleScratch1 = new Cartesian3_default(); var scaleScratch2 = new Cartesian3_default(); var scratchColumn = new Cartesian3_default(); var scaleScratch3 = new Cartesian3_default(); var scaleScratch4 = new Cartesian3_default(); var scaleScratch5 = new Cartesian3_default(); var jMatrix = new Matrix3(); var jMatrixTranspose = new Matrix3(); var scratchTransposeMatrix = new Matrix3(); function computeFrobeniusNorm(matrix) { let norm = 0; for (let i = 0; i < 9; ++i) { const temp = matrix[i]; norm += temp * temp; } return Math.sqrt(norm); } var rowVal = [1, 0, 0]; var colVal = [2, 2, 1]; function offDiagonalFrobeniusNorm(matrix) { let norm = 0; for (let i = 0; i < 3; ++i) { const temp = matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])]; norm += 2 * temp * temp; } return Math.sqrt(norm); } function shurDecomposition(matrix, result) { const tolerance = Math_default.EPSILON15; let maxDiagonal = 0; let rotAxis2 = 1; for (let i = 0; i < 3; ++i) { const temp = Math.abs( // @ts-expect-error TODO(tsd-jsdoc): Requires index signature support. matrix[Matrix3.getElementIndex(colVal[i], rowVal[i])] ); if (temp > maxDiagonal) { rotAxis2 = i; maxDiagonal = temp; } } let c14 = 1; let s2 = 0; const p = rowVal[rotAxis2]; const q = colVal[rotAxis2]; if (Math.abs(matrix[Matrix3.getElementIndex(q, p)]) > tolerance) { const qq = matrix[Matrix3.getElementIndex(q, q)]; const pp = matrix[Matrix3.getElementIndex(p, p)]; const qp = matrix[Matrix3.getElementIndex(q, p)]; const tau = (qq - pp) / 2 / qp; let t2; if (tau < 0) { t2 = -1 / (-tau + Math.sqrt(1 + tau * tau)); } else { t2 = 1 / (tau + Math.sqrt(1 + tau * tau)); } c14 = 1 / Math.sqrt(1 + t2 * t2); s2 = t2 * c14; } result = Matrix3.clone(Matrix3.IDENTITY, result); result[Matrix3.getElementIndex(p, p)] = result[Matrix3.getElementIndex(q, q)] = c14; result[Matrix3.getElementIndex(q, p)] = s2; result[Matrix3.getElementIndex(p, q)] = -s2; return result; } var Matrix3_default = Matrix3; // packages/engine/Source/Core/RuntimeError.js var import_InlineWorkers9 = __toESM(require_InlineWorkers(), 1); function RuntimeError(message) { this.name = "RuntimeError"; this.message = message; let stack; try { throw new Error(); } catch (e) { stack = e.stack; } this.stack = stack; } if (defined_default(Object.create)) { RuntimeError.prototype = Object.create(Error.prototype); RuntimeError.prototype.constructor = RuntimeError; } RuntimeError.prototype.toString = function() { let str = `${this.name}: ${this.message}`; if (defined_default(this.stack)) { str += ` ${this.stack.toString()}`; } return str; }; var RuntimeError_default = RuntimeError; // packages/engine/Source/Core/Matrix4.js var Matrix4 = class _Matrix4 { /** * @param {number} [column0Row0=0.0] The value for column 0, row 0. * @param {number} [column1Row0=0.0] The value for column 1, row 0. * @param {number} [column2Row0=0.0] The value for column 2, row 0. * @param {number} [column3Row0=0.0] The value for column 3, row 0. * @param {number} [column0Row1=0.0] The value for column 0, row 1. * @param {number} [column1Row1=0.0] The value for column 1, row 1. * @param {number} [column2Row1=0.0] The value for column 2, row 1. * @param {number} [column3Row1=0.0] The value for column 3, row 1. * @param {number} [column0Row2=0.0] The value for column 0, row 2. * @param {number} [column1Row2=0.0] The value for column 1, row 2. * @param {number} [column2Row2=0.0] The value for column 2, row 2. * @param {number} [column3Row2=0.0] The value for column 3, row 2. * @param {number} [column0Row3=0.0] The value for column 0, row 3. * @param {number} [column1Row3=0.0] The value for column 1, row 3. * @param {number} [column2Row3=0.0] The value for column 2, row 3. * @param {number} [column3Row3=0.0] The value for column 3, row 3. */ constructor(column0Row0, column1Row0, column2Row0, column3Row0, column0Row1, column1Row1, column2Row1, column3Row1, column0Row2, column1Row2, column2Row2, column3Row2, column0Row3, column1Row3, column2Row3, column3Row3) { this[0] = column0Row0 ?? 0; this[1] = column0Row1 ?? 0; this[2] = column0Row2 ?? 0; this[3] = column0Row3 ?? 0; this[4] = column1Row0 ?? 0; this[5] = column1Row1 ?? 0; this[6] = column1Row2 ?? 0; this[7] = column1Row3 ?? 0; this[8] = column2Row0 ?? 0; this[9] = column2Row1 ?? 0; this[10] = column2Row2 ?? 0; this[11] = column2Row3 ?? 0; this[12] = column3Row0 ?? 0; this[13] = column3Row1 ?? 0; this[14] = column3Row2 ?? 0; this[15] = column3Row3 ?? 0; } /** * Stores the provided instance into the provided array. * * @param {Matrix4} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value[0]; array[startingIndex++] = value[1]; array[startingIndex++] = value[2]; array[startingIndex++] = value[3]; array[startingIndex++] = value[4]; array[startingIndex++] = value[5]; array[startingIndex++] = value[6]; array[startingIndex++] = value[7]; array[startingIndex++] = value[8]; array[startingIndex++] = value[9]; array[startingIndex++] = value[10]; array[startingIndex++] = value[11]; array[startingIndex++] = value[12]; array[startingIndex++] = value[13]; array[startingIndex++] = value[14]; array[startingIndex] = value[15]; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Matrix4} [result] The object into which to store the result. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Matrix4(); } result[0] = array[startingIndex++]; result[1] = array[startingIndex++]; result[2] = array[startingIndex++]; result[3] = array[startingIndex++]; result[4] = array[startingIndex++]; result[5] = array[startingIndex++]; result[6] = array[startingIndex++]; result[7] = array[startingIndex++]; result[8] = array[startingIndex++]; result[9] = array[startingIndex++]; result[10] = array[startingIndex++]; result[11] = array[startingIndex++]; result[12] = array[startingIndex++]; result[13] = array[startingIndex++]; result[14] = array[startingIndex++]; result[15] = array[startingIndex]; return result; } /** * Flattens an array of Matrix4s into an array of components. The components * are stored in column-major order. * * @param {Matrix4[]} array The array of matrices to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 16 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 16) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 16; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 16 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Matrix4.pack(array[i], result, i * 16); } return result; } /** * Unpacks an array of column-major matrix components into an array of Matrix4s. * * @param {number[]} array The array of components to unpack. * @param {Matrix4[]} [result] The array onto which to store the result. * @returns {Matrix4[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 16); if (array.length % 16 !== 0) { throw new DeveloperError_default("array length must be a multiple of 16."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 16); } else { result.length = length2 / 16; } for (let i = 0; i < length2; i += 16) { const index = i / 16; result[index] = _Matrix4.unpack(array, i, result[index]); } return result; } /** * Duplicates a Matrix4 instance. * * @param {Matrix4} matrix The matrix to duplicate. * @param {Matrix4} [result] The object onto which to store the result. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. (Returns undefined if matrix is undefined) */ static clone(matrix, result) { if (!defined_default(matrix)) { return void 0; } if (!defined_default(result)) { return new _Matrix4( matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], matrix[2], matrix[6], matrix[10], matrix[14], matrix[3], matrix[7], matrix[11], matrix[15] ); } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; result[9] = matrix[9]; result[10] = matrix[10]; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Computes a Matrix4 instance from a column-major order array. * * @param {number[]} values The column-major order array. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromColumnMajorArray(values, result) { Check_default.defined("values", values); return _Matrix4.clone(values, result); } /** * Computes a Matrix4 instance from a row-major order array. * The resulting matrix will be in column-major order. * * @param {number[]} values The row-major order array. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromRowMajorArray(values, result) { Check_default.defined("values", values); if (!defined_default(result)) { return new _Matrix4( values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15] ); } result[0] = values[0]; result[1] = values[4]; result[2] = values[8]; result[3] = values[12]; result[4] = values[1]; result[5] = values[5]; result[6] = values[9]; result[7] = values[13]; result[8] = values[2]; result[9] = values[6]; result[10] = values[10]; result[11] = values[14]; result[12] = values[3]; result[13] = values[7]; result[14] = values[11]; result[15] = values[15]; return result; } /** * Computes a Matrix4 instance from a Matrix3 representing the rotation * and a Cartesian3 representing the translation. * * @param {Matrix3} rotation The upper left portion of the matrix representing the rotation. * @param {Cartesian3} [translation=Cartesian3.ZERO] The upper right portion of the matrix representing the translation. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromRotationTranslation(rotation, translation3, result) { Check_default.typeOf.object("rotation", rotation); translation3 = translation3 ?? Cartesian3_default.ZERO; if (!defined_default(result)) { return new _Matrix4( rotation[0], rotation[3], rotation[6], translation3.x, rotation[1], rotation[4], rotation[7], translation3.y, rotation[2], rotation[5], rotation[8], translation3.z, 0, 0, 0, 1 ); } result[0] = rotation[0]; result[1] = rotation[1]; result[2] = rotation[2]; result[3] = 0; result[4] = rotation[3]; result[5] = rotation[4]; result[6] = rotation[5]; result[7] = 0; result[8] = rotation[6]; result[9] = rotation[7]; result[10] = rotation[8]; result[11] = 0; result[12] = translation3.x; result[13] = translation3.y; result[14] = translation3.z; result[15] = 1; return result; } /** * Computes a Matrix4 instance from a translation, rotation, and scale (TRS) * representation with the rotation represented as a quaternion. * * @param {Cartesian3} translation The translation transformation. * @param {Quaternion} rotation The rotation transformation. * @param {Cartesian3} scale The non-uniform scale transformation. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. * * @example * const result = Cesium.Matrix4.fromTranslationQuaternionRotationScale( * new Cesium.Cartesian3(1.0, 2.0, 3.0), // translation * Cesium.Quaternion.IDENTITY, // rotation * new Cesium.Cartesian3(7.0, 8.0, 9.0), // scale * result); */ static fromTranslationQuaternionRotationScale(translation3, rotation, scale, result) { Check_default.typeOf.object("translation", translation3); Check_default.typeOf.object("rotation", rotation); Check_default.typeOf.object("scale", scale); if (!defined_default(result)) { result = new _Matrix4(); } const scaleX = scale.x; const scaleY = scale.y; const scaleZ = scale.z; const x2 = rotation.x * rotation.x; const xy = rotation.x * rotation.y; const xz = rotation.x * rotation.z; const xw = rotation.x * rotation.w; const y2 = rotation.y * rotation.y; const yz = rotation.y * rotation.z; const yw = rotation.y * rotation.w; const z2 = rotation.z * rotation.z; const zw = rotation.z * rotation.w; const w2 = rotation.w * rotation.w; const m00 = x2 - y2 - z2 + w2; const m01 = 2 * (xy - zw); const m02 = 2 * (xz + yw); const m10 = 2 * (xy + zw); const m11 = -x2 + y2 - z2 + w2; const m12 = 2 * (yz - xw); const m20 = 2 * (xz - yw); const m21 = 2 * (yz + xw); const m22 = -x2 - y2 + z2 + w2; result[0] = m00 * scaleX; result[1] = m10 * scaleX; result[2] = m20 * scaleX; result[3] = 0; result[4] = m01 * scaleY; result[5] = m11 * scaleY; result[6] = m21 * scaleY; result[7] = 0; result[8] = m02 * scaleZ; result[9] = m12 * scaleZ; result[10] = m22 * scaleZ; result[11] = 0; result[12] = translation3.x; result[13] = translation3.y; result[14] = translation3.z; result[15] = 1; return result; } /** * Creates a Matrix4 instance from a {@link TranslationRotationScale} instance. * * @param {TranslationRotationScale} translationRotationScale The instance. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromTranslationRotationScale(translationRotationScale, result) { Check_default.typeOf.object("translationRotationScale", translationRotationScale); return _Matrix4.fromTranslationQuaternionRotationScale( translationRotationScale.translation, translationRotationScale.rotation, translationRotationScale.scale, result ); } /** * Creates a Matrix4 instance from a Cartesian3 representing the translation. * * @param {Cartesian3} translation The upper right portion of the matrix representing the translation. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. * * @see Matrix4.multiplyByTranslation */ static fromTranslation(translation3, result) { Check_default.typeOf.object("translation", translation3); return _Matrix4.fromRotationTranslation( Matrix3_default.IDENTITY, translation3, result ); } /** * Computes a Matrix4 instance representing a non-uniform scale. * * @param {Cartesian3} scale The x, y, and z scale factors. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. * * @example * // Creates * // [7.0, 0.0, 0.0, 0.0] * // [0.0, 8.0, 0.0, 0.0] * // [0.0, 0.0, 9.0, 0.0] * // [0.0, 0.0, 0.0, 1.0] * const m = Cesium.Matrix4.fromScale(new Cesium.Cartesian3(7.0, 8.0, 9.0)); */ static fromScale(scale, result) { Check_default.typeOf.object("scale", scale); if (!defined_default(result)) { return new _Matrix4( scale.x, 0, 0, 0, 0, scale.y, 0, 0, 0, 0, scale.z, 0, 0, 0, 0, 1 ); } result[0] = scale.x; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = scale.y; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = scale.z; result[11] = 0; result[12] = 0; result[13] = 0; result[14] = 0; result[15] = 1; return result; } /** * Computes a Matrix4 instance representing a uniform scale. * * @param {number} scale The uniform scale factor. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. * * @example * // Creates * // [2.0, 0.0, 0.0, 0.0] * // [0.0, 2.0, 0.0, 0.0] * // [0.0, 0.0, 2.0, 0.0] * // [0.0, 0.0, 0.0, 1.0] * const m = Cesium.Matrix4.fromUniformScale(2.0); */ static fromUniformScale(scale, result) { Check_default.typeOf.number("scale", scale); if (!defined_default(result)) { return new _Matrix4( scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1 ); } result[0] = scale; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = scale; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = scale; result[11] = 0; result[12] = 0; result[13] = 0; result[14] = 0; result[15] = 1; return result; } /** * Creates a rotation matrix. * * @param {Matrix3} rotation The rotation matrix. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromRotation(rotation, result) { Check_default.typeOf.object("rotation", rotation); if (!defined_default(result)) { result = new _Matrix4(); } result[0] = rotation[0]; result[1] = rotation[1]; result[2] = rotation[2]; result[3] = 0; result[4] = rotation[3]; result[5] = rotation[4]; result[6] = rotation[5]; result[7] = 0; result[8] = rotation[6]; result[9] = rotation[7]; result[10] = rotation[8]; result[11] = 0; result[12] = 0; result[13] = 0; result[14] = 0; result[15] = 1; return result; } /** * Computes a Matrix4 instance from a Camera. * * @param {Camera} camera The camera to use. * @param {Matrix4} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix4} The modified result parameter, or a new Matrix4 instance if one was not provided. */ static fromCamera(camera, result) { Check_default.typeOf.object("camera", camera); const position = camera.position; const direction2 = camera.direction; const up = camera.up; Check_default.typeOf.object("camera.position", position); Check_default.typeOf.object("camera.direction", direction2); Check_default.typeOf.object("camera.up", up); Cartesian3_default.normalize(direction2, fromCameraF); Cartesian3_default.normalize( Cartesian3_default.cross(fromCameraF, up, fromCameraR), fromCameraR ); Cartesian3_default.normalize( Cartesian3_default.cross(fromCameraR, fromCameraF, fromCameraU), fromCameraU ); const sX = fromCameraR.x; const sY = fromCameraR.y; const sZ = fromCameraR.z; const fX = fromCameraF.x; const fY = fromCameraF.y; const fZ = fromCameraF.z; const uX = fromCameraU.x; const uY = fromCameraU.y; const uZ = fromCameraU.z; const positionX = position.x; const positionY = position.y; const positionZ = position.z; const t0 = sX * -positionX + sY * -positionY + sZ * -positionZ; const t1 = uX * -positionX + uY * -positionY + uZ * -positionZ; const t2 = fX * positionX + fY * positionY + fZ * positionZ; if (!defined_default(result)) { return new _Matrix4( sX, sY, sZ, t0, uX, uY, uZ, t1, -fX, -fY, -fZ, t2, 0, 0, 0, 1 ); } result[0] = sX; result[1] = uX; result[2] = -fX; result[3] = 0; result[4] = sY; result[5] = uY; result[6] = -fY; result[7] = 0; result[8] = sZ; result[9] = uZ; result[10] = -fZ; result[11] = 0; result[12] = t0; result[13] = t1; result[14] = t2; result[15] = 1; return result; } /** * Computes a Matrix4 instance representing a perspective transformation matrix. * * @param {number} fovY The field of view along the Y axis in radians. * @param {number} aspectRatio The aspect ratio. * @param {number} near The distance to the near plane in meters. * @param {number} far The distance to the far plane in meters. * @param {Matrix4} result The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. * * @exception {DeveloperError} fovY must be in (0, PI]. * @exception {DeveloperError} aspectRatio must be greater than zero. * @exception {DeveloperError} near must be greater than zero. * @exception {DeveloperError} far must be greater than zero. */ static computePerspectiveFieldOfView(fovY, aspectRatio, near, far, result) { Check_default.typeOf.number.greaterThan("fovY", fovY, 0); Check_default.typeOf.number.lessThan("fovY", fovY, Math.PI); Check_default.typeOf.number.greaterThan("near", near, 0); Check_default.typeOf.number.greaterThan("far", far, 0); Check_default.typeOf.object("result", result); const bottom = Math.tan(fovY * 0.5); const column1Row1 = 1 / bottom; const column0Row0 = column1Row1 / aspectRatio; const column2Row2 = (far + near) / (near - far); const column3Row2 = 2 * far * near / (near - far); result[0] = column0Row0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = column1Row1; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = column2Row2; result[11] = -1; result[12] = 0; result[13] = 0; result[14] = column3Row2; result[15] = 0; return result; } /** * Computes a Matrix4 instance representing an orthographic transformation matrix. * * @param {number} left The number of meters to the left of the camera that will be in view. * @param {number} right The number of meters to the right of the camera that will be in view. * @param {number} bottom The number of meters below of the camera that will be in view. * @param {number} top The number of meters above of the camera that will be in view. * @param {number} near The distance to the near plane in meters. * @param {number} far The distance to the far plane in meters. * @param {Matrix4} result The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. */ static computeOrthographicOffCenter(left, right, bottom, top, near, far, result) { Check_default.typeOf.number("left", left); Check_default.typeOf.number("right", right); Check_default.typeOf.number("bottom", bottom); Check_default.typeOf.number("top", top); Check_default.typeOf.number("near", near); Check_default.typeOf.number("far", far); Check_default.typeOf.object("result", result); let a3 = 1 / (right - left); let b = 1 / (top - bottom); let c14 = 1 / (far - near); const tx = -(right + left) * a3; const ty = -(top + bottom) * b; const tz = -(far + near) * c14; a3 *= 2; b *= 2; c14 *= -2; result[0] = a3; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = b; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = c14; result[11] = 0; result[12] = tx; result[13] = ty; result[14] = tz; result[15] = 1; return result; } /** * Computes a Matrix4 instance representing an off center perspective transformation. * * @param {number} left The number of meters to the left of the camera that will be in view. * @param {number} right The number of meters to the right of the camera that will be in view. * @param {number} bottom The number of meters below the camera that will be in view. * @param {number} top The number of meters above the camera that will be in view. * @param {number} near The distance to the near plane in meters. * @param {number} far The distance to the far plane in meters. * @param {Matrix4} result The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. */ static computePerspectiveOffCenter(left, right, bottom, top, near, far, result) { Check_default.typeOf.number("left", left); Check_default.typeOf.number("right", right); Check_default.typeOf.number("bottom", bottom); Check_default.typeOf.number("top", top); Check_default.typeOf.number("near", near); Check_default.typeOf.number("far", far); Check_default.typeOf.object("result", result); const column0Row0 = 2 * near / (right - left); const column1Row1 = 2 * near / (top - bottom); const column2Row0 = (right + left) / (right - left); const column2Row1 = (top + bottom) / (top - bottom); const column2Row2 = -(far + near) / (far - near); const column2Row3 = -1; const column3Row2 = -2 * far * near / (far - near); result[0] = column0Row0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = column1Row1; result[6] = 0; result[7] = 0; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = column2Row3; result[12] = 0; result[13] = 0; result[14] = column3Row2; result[15] = 0; return result; } /** * Computes a Matrix4 instance representing an infinite off center perspective transformation. * * @param {number} left The number of meters to the left of the camera that will be in view. * @param {number} right The number of meters to the right of the camera that will be in view. * @param {number} bottom The number of meters below of the camera that will be in view. * @param {number} top The number of meters above of the camera that will be in view. * @param {number} near The distance to the near plane in meters. * @param {Matrix4} result The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. */ static computeInfinitePerspectiveOffCenter(left, right, bottom, top, near, result) { Check_default.typeOf.number("left", left); Check_default.typeOf.number("right", right); Check_default.typeOf.number("bottom", bottom); Check_default.typeOf.number("top", top); Check_default.typeOf.number("near", near); Check_default.typeOf.object("result", result); const column0Row0 = 2 * near / (right - left); const column1Row1 = 2 * near / (top - bottom); const column2Row0 = (right + left) / (right - left); const column2Row1 = (top + bottom) / (top - bottom); const column2Row2 = -1; const column2Row3 = -1; const column3Row2 = -2 * near; result[0] = column0Row0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = column1Row1; result[6] = 0; result[7] = 0; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = column2Row3; result[12] = 0; result[13] = 0; result[14] = column3Row2; result[15] = 0; return result; } /** * Computes a Matrix4 instance that transforms from normalized device coordinates to window coordinates. * * @param {Viewport} [viewport = { x : 0.0, y : 0.0, width : 0.0, height : 0.0 }] The viewport's corners as shown in Example 1. * @param {number} [nearDepthRange=0.0] The near plane distance in window coordinates. * @param {number} [farDepthRange=1.0] The far plane distance in window coordinates. * @param {Matrix4} [result] The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. * * @example * // Create viewport transformation using an explicit viewport and depth range. * const m = Cesium.Matrix4.computeViewportTransformation({ * x : 0.0, * y : 0.0, * width : 1024.0, * height : 768.0 * }, 0.0, 1.0, new Cesium.Matrix4()); */ static computeViewportTransformation(viewport, nearDepthRange, farDepthRange, result) { if (!defined_default(result)) { result = new _Matrix4(); } viewport = viewport ?? Frozen_default.EMPTY_OBJECT; const x = viewport.x ?? 0; const y = viewport.y ?? 0; const width = viewport.width ?? 0; const height = viewport.height ?? 0; nearDepthRange = nearDepthRange ?? 0; farDepthRange = farDepthRange ?? 1; const halfWidth = width * 0.5; const halfHeight = height * 0.5; const halfDepth = (farDepthRange - nearDepthRange) * 0.5; const column0Row0 = halfWidth; const column1Row1 = halfHeight; const column2Row2 = halfDepth; const column3Row0 = x + halfWidth; const column3Row1 = y + halfHeight; const column3Row2 = nearDepthRange + halfDepth; const column3Row3 = 1; result[0] = column0Row0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = column1Row1; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = column2Row2; result[11] = 0; result[12] = column3Row0; result[13] = column3Row1; result[14] = column3Row2; result[15] = column3Row3; return result; } /** * Computes a Matrix4 instance that transforms from world space to view space. * * @param {Cartesian3} position The position of the camera. * @param {Cartesian3} direction The forward direction. * @param {Cartesian3} up The up direction. * @param {Cartesian3} right The right direction. * @param {Matrix4} result The object in which the result will be stored. * @returns {Matrix4} The modified result parameter. */ static computeView(position, direction2, up, right, result) { Check_default.typeOf.object("position", position); Check_default.typeOf.object("direction", direction2); Check_default.typeOf.object("up", up); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = right.x; result[1] = up.x; result[2] = -direction2.x; result[3] = 0; result[4] = right.y; result[5] = up.y; result[6] = -direction2.y; result[7] = 0; result[8] = right.z; result[9] = up.z; result[10] = -direction2.z; result[11] = 0; result[12] = -Cartesian3_default.dot(right, position); result[13] = -Cartesian3_default.dot(up, position); result[14] = Cartesian3_default.dot(direction2, position); result[15] = 1; return result; } /** * Computes an Array from the provided Matrix4 instance. * The array will be in column-major order. * * @param {Matrix4} matrix The matrix to use.. * @param {number[]} [result] The Array onto which to store the result. * @returns {number[]} The modified Array parameter or a new Array instance if one was not provided. * * @example * //create an array from an instance of Matrix4 * // m = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] * const a = Cesium.Matrix4.toArray(m); * * // m remains the same * //creates a = [10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0] */ static toArray(matrix, result) { Check_default.typeOf.object("matrix", matrix); if (!defined_default(result)) { return [ matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11], matrix[12], matrix[13], matrix[14], matrix[15] ]; } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; result[9] = matrix[9]; result[10] = matrix[10]; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Computes the array index of the element at the provided row and column. * * @param {number} row The zero-based index of the row. * @param {number} column The zero-based index of the column. * @returns {number} The index of the element at the provided row and column. * * @exception {DeveloperError} row must be 0, 1, 2, or 3. * @exception {DeveloperError} column must be 0, 1, 2, or 3. * * @example * const myMatrix = new Cesium.Matrix4(); * const column1Row0Index = Cesium.Matrix4.getElementIndex(1, 0); * const column1Row0 = myMatrix[column1Row0Index]; * myMatrix[column1Row0Index] = 10.0; */ static getElementIndex(column, row) { Check_default.typeOf.number.greaterThanOrEquals("row", row, 0); Check_default.typeOf.number.lessThanOrEquals("row", row, 3); Check_default.typeOf.number.greaterThanOrEquals("column", column, 0); Check_default.typeOf.number.lessThanOrEquals("column", column, 3); return column * 4 + row; } /** * Retrieves a copy of the matrix column at the provided index as a Cartesian4 instance. * * @param {Matrix4} matrix The matrix to use. * @param {number} index The zero-based index of the column to retrieve. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, 2, or 3. * * @example * //returns a Cartesian4 instance with values from the specified column * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * //Example 1: Creates an instance of Cartesian * const a = Cesium.Matrix4.getColumn(m, 2, new Cesium.Cartesian4()); * * @example * //Example 2: Sets values for Cartesian instance * const a = new Cesium.Cartesian4(); * Cesium.Matrix4.getColumn(m, 2, a); * * // a.x = 12.0; a.y = 16.0; a.z = 20.0; a.w = 24.0; */ static getColumn(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 3); Check_default.typeOf.object("result", result); const startIndex = index * 4; const x = matrix[startIndex]; const y = matrix[startIndex + 1]; const z2 = matrix[startIndex + 2]; const w = matrix[startIndex + 3]; result.x = x; result.y = y; result.z = z2; result.w = w; return result; } /** * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian4 instance. * * @param {Matrix4} matrix The matrix to use. * @param {number} index The zero-based index of the column to set. * @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified column. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, 2, or 3. * * @example * //creates a new Matrix4 instance with new column values from the Cartesian4 instance * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * const a = Cesium.Matrix4.setColumn(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4()); * * // m remains the same * // a = [10.0, 11.0, 99.0, 13.0] * // [14.0, 15.0, 98.0, 17.0] * // [18.0, 19.0, 97.0, 21.0] * // [22.0, 23.0, 96.0, 25.0] */ static setColumn(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 3); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix4.clone(matrix, result); const startIndex = index * 4; result[startIndex] = cartesian11.x; result[startIndex + 1] = cartesian11.y; result[startIndex + 2] = cartesian11.z; result[startIndex + 3] = cartesian11.w; return result; } /** * Retrieves a copy of the matrix row at the provided index as a Cartesian4 instance. * * @param {Matrix4} matrix The matrix to use. * @param {number} index The zero-based index of the row to retrieve. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, 2, or 3. * * @example * //returns a Cartesian4 instance with values from the specified column * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * //Example 1: Returns an instance of Cartesian * const a = Cesium.Matrix4.getRow(m, 2, new Cesium.Cartesian4()); * * @example * //Example 2: Sets values for a Cartesian instance * const a = new Cesium.Cartesian4(); * Cesium.Matrix4.getRow(m, 2, a); * * // a.x = 18.0; a.y = 19.0; a.z = 20.0; a.w = 21.0; */ static getRow(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 3); Check_default.typeOf.object("result", result); const x = matrix[index]; const y = matrix[index + 4]; const z2 = matrix[index + 8]; const w = matrix[index + 12]; result.x = x; result.y = y; result.z = z2; result.w = w; return result; } /** * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian4 instance. * * @param {Matrix4} matrix The matrix to use. * @param {number} index The zero-based index of the row to set. * @param {Cartesian4} cartesian The Cartesian whose values will be assigned to the specified row. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @exception {DeveloperError} index must be 0, 1, 2, or 3. * * @example * //create a new Matrix4 instance with new row values from the Cartesian4 instance * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * const a = Cesium.Matrix4.setRow(m, 2, new Cesium.Cartesian4(99.0, 98.0, 97.0, 96.0), new Cesium.Matrix4()); * * // m remains the same * // a = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [99.0, 98.0, 97.0, 96.0] * // [22.0, 23.0, 24.0, 25.0] */ static setRow(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 3); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix4.clone(matrix, result); result[index] = cartesian11.x; result[index + 4] = cartesian11.y; result[index + 8] = cartesian11.z; result[index + 12] = cartesian11.w; return result; } /** * Computes a new matrix that replaces the translation in the rightmost column of the provided * matrix with the provided translation. This assumes the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix to use. * @param {Cartesian3} translation The translation that replaces the translation of the provided matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static setTranslation(matrix, translation3, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("translation", translation3); Check_default.typeOf.object("result", result); result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; result[9] = matrix[9]; result[10] = matrix[10]; result[11] = matrix[11]; result[12] = translation3.x; result[13] = translation3.y; result[14] = translation3.z; result[15] = matrix[15]; return result; } /** * Computes a new matrix that replaces the scale with the provided scale. * This assumes the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix to use. * @param {Cartesian3} scale The scale that replaces the scale of the provided matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @see Matrix4.setUniformScale * @see Matrix4.fromScale * @see Matrix4.fromUniformScale * @see Matrix4.multiplyByScale * @see Matrix4.multiplyByUniformScale * @see Matrix4.getScale */ static setScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix4.getScale(matrix, scaleScratch12); const scaleRatioX = scale.x / existingScale.x; const scaleRatioY = scale.y / existingScale.y; const scaleRatioZ = scale.z / existingScale.z; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioX; result[3] = matrix[3]; result[4] = matrix[4] * scaleRatioY; result[5] = matrix[5] * scaleRatioY; result[6] = matrix[6] * scaleRatioY; result[7] = matrix[7]; result[8] = matrix[8] * scaleRatioZ; result[9] = matrix[9] * scaleRatioZ; result[10] = matrix[10] * scaleRatioZ; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Computes a new matrix that replaces the scale with the provided uniform scale. * This assumes the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix to use. * @param {number} scale The uniform scale that replaces the scale of the provided matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @see Matrix4.setScale * @see Matrix4.fromScale * @see Matrix4.fromUniformScale * @see Matrix4.multiplyByScale * @see Matrix4.multiplyByUniformScale * @see Matrix4.getScale */ static setUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix4.getScale(matrix, scaleScratch22); const scaleRatioX = scale / existingScale.x; const scaleRatioY = scale / existingScale.y; const scaleRatioZ = scale / existingScale.z; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioX; result[3] = matrix[3]; result[4] = matrix[4] * scaleRatioY; result[5] = matrix[5] * scaleRatioY; result[6] = matrix[6] * scaleRatioY; result[7] = matrix[7]; result[8] = matrix[8] * scaleRatioZ; result[9] = matrix[9] * scaleRatioZ; result[10] = matrix[10] * scaleRatioZ; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Extracts the non-uniform scale assuming the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter * * @see Matrix4.multiplyByScale * @see Matrix4.multiplyByUniformScale * @see Matrix4.fromScale * @see Matrix4.fromUniformScale * @see Matrix4.setScale * @see Matrix4.setUniformScale */ static getScale(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result.x = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[0], matrix[1], matrix[2], scratchColumn2) ); result.y = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[4], matrix[5], matrix[6], scratchColumn2) ); result.z = Cartesian3_default.magnitude( Cartesian3_default.fromElements(matrix[8], matrix[9], matrix[10], scratchColumn2) ); return result; } /** * Computes the maximum scale assuming the matrix is an affine transformation. * The maximum scale is the maximum length of the column vectors in the upper-left * 3x3 matrix. * * @param {Matrix4} matrix The matrix. * @returns {number} The maximum scale. */ static getMaximumScale(matrix) { _Matrix4.getScale(matrix, scaleScratch32); return Cartesian3_default.maximumComponent(scaleScratch32); } /** * Sets the rotation assuming the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix. * @param {Matrix3} rotation The rotation matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @see Matrix4.fromRotation * @see Matrix4.getRotation */ static setRotation(matrix, rotation, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix4.getScale(matrix, scaleScratch42); result[0] = rotation[0] * scale.x; result[1] = rotation[1] * scale.x; result[2] = rotation[2] * scale.x; result[3] = matrix[3]; result[4] = rotation[3] * scale.y; result[5] = rotation[4] * scale.y; result[6] = rotation[5] * scale.y; result[7] = matrix[7]; result[8] = rotation[6] * scale.z; result[9] = rotation[7] * scale.z; result[10] = rotation[8] * scale.z; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Extracts the rotation matrix assuming the matrix is an affine transformation. * * @param {Matrix4} matrix The matrix. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @see Matrix4.setRotation * @see Matrix4.fromRotation */ static getRotation(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix4.getScale(matrix, scaleScratch52); result[0] = matrix[0] / scale.x; result[1] = matrix[1] / scale.x; result[2] = matrix[2] / scale.x; result[3] = matrix[4] / scale.y; result[4] = matrix[5] / scale.y; result[5] = matrix[6] / scale.y; result[6] = matrix[8] / scale.z; result[7] = matrix[9] / scale.z; result[8] = matrix[10] / scale.z; return result; } /** * Computes the product of two matrices. * * @param {Matrix4} left The first matrix. * @param {Matrix4} right The second matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static multiply(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const left0 = left[0]; const left1 = left[1]; const left2 = left[2]; const left3 = left[3]; const left4 = left[4]; const left5 = left[5]; const left6 = left[6]; const left7 = left[7]; const left8 = left[8]; const left9 = left[9]; const left10 = left[10]; const left11 = left[11]; const left12 = left[12]; const left13 = left[13]; const left14 = left[14]; const left15 = left[15]; const right0 = right[0]; const right1 = right[1]; const right2 = right[2]; const right3 = right[3]; const right4 = right[4]; const right5 = right[5]; const right6 = right[6]; const right7 = right[7]; const right8 = right[8]; const right9 = right[9]; const right10 = right[10]; const right11 = right[11]; const right12 = right[12]; const right13 = right[13]; const right14 = right[14]; const right15 = right[15]; const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2 + left12 * right3; const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2 + left13 * right3; const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2 + left14 * right3; const column0Row3 = left3 * right0 + left7 * right1 + left11 * right2 + left15 * right3; const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6 + left12 * right7; const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6 + left13 * right7; const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6 + left14 * right7; const column1Row3 = left3 * right4 + left7 * right5 + left11 * right6 + left15 * right7; const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10 + left12 * right11; const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10 + left13 * right11; const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10 + left14 * right11; const column2Row3 = left3 * right8 + left7 * right9 + left11 * right10 + left15 * right11; const column3Row0 = left0 * right12 + left4 * right13 + left8 * right14 + left12 * right15; const column3Row1 = left1 * right12 + left5 * right13 + left9 * right14 + left13 * right15; const column3Row2 = left2 * right12 + left6 * right13 + left10 * right14 + left14 * right15; const column3Row3 = left3 * right12 + left7 * right13 + left11 * right14 + left15 * right15; result[0] = column0Row0; result[1] = column0Row1; result[2] = column0Row2; result[3] = column0Row3; result[4] = column1Row0; result[5] = column1Row1; result[6] = column1Row2; result[7] = column1Row3; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = column2Row3; result[12] = column3Row0; result[13] = column3Row1; result[14] = column3Row2; result[15] = column3Row3; return result; } /** * Computes the sum of two matrices. * * @param {Matrix4} left The first matrix. * @param {Matrix4} right The second matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] + right[0]; result[1] = left[1] + right[1]; result[2] = left[2] + right[2]; result[3] = left[3] + right[3]; result[4] = left[4] + right[4]; result[5] = left[5] + right[5]; result[6] = left[6] + right[6]; result[7] = left[7] + right[7]; result[8] = left[8] + right[8]; result[9] = left[9] + right[9]; result[10] = left[10] + right[10]; result[11] = left[11] + right[11]; result[12] = left[12] + right[12]; result[13] = left[13] + right[13]; result[14] = left[14] + right[14]; result[15] = left[15] + right[15]; return result; } /** * Computes the difference of two matrices. * * @param {Matrix4} left The first matrix. * @param {Matrix4} right The second matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] - right[0]; result[1] = left[1] - right[1]; result[2] = left[2] - right[2]; result[3] = left[3] - right[3]; result[4] = left[4] - right[4]; result[5] = left[5] - right[5]; result[6] = left[6] - right[6]; result[7] = left[7] - right[7]; result[8] = left[8] - right[8]; result[9] = left[9] - right[9]; result[10] = left[10] - right[10]; result[11] = left[11] - right[11]; result[12] = left[12] - right[12]; result[13] = left[13] - right[13]; result[14] = left[14] - right[14]; result[15] = left[15] - right[15]; return result; } /** * Computes the product of two matrices assuming the matrices are affine transformation matrices, * where the upper left 3x3 elements are any matrix, and * the upper three elements in the fourth column are the translation. * The bottom row is assumed to be [0, 0, 0, 1]. * The matrix is not verified to be in the proper form. * This method is faster than computing the product for general 4x4 * matrices using {@link Matrix4.multiply}. * * @param {Matrix4} left The first matrix. * @param {Matrix4} right The second matrix. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * const m1 = new Cesium.Matrix4(1.0, 6.0, 7.0, 0.0, 2.0, 5.0, 8.0, 0.0, 3.0, 4.0, 9.0, 0.0, 0.0, 0.0, 0.0, 1.0); * const m2 = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3(1.0, 1.0, 1.0)); * const m3 = Cesium.Matrix4.multiplyTransformation(m1, m2, new Cesium.Matrix4()); */ static multiplyTransformation(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const left0 = left[0]; const left1 = left[1]; const left2 = left[2]; const left4 = left[4]; const left5 = left[5]; const left6 = left[6]; const left8 = left[8]; const left9 = left[9]; const left10 = left[10]; const left12 = left[12]; const left13 = left[13]; const left14 = left[14]; const right0 = right[0]; const right1 = right[1]; const right2 = right[2]; const right4 = right[4]; const right5 = right[5]; const right6 = right[6]; const right8 = right[8]; const right9 = right[9]; const right10 = right[10]; const right12 = right[12]; const right13 = right[13]; const right14 = right[14]; const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2; const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2; const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2; const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6; const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6; const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6; const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10; const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10; const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10; const column3Row0 = left0 * right12 + left4 * right13 + left8 * right14 + left12; const column3Row1 = left1 * right12 + left5 * right13 + left9 * right14 + left13; const column3Row2 = left2 * right12 + left6 * right13 + left10 * right14 + left14; result[0] = column0Row0; result[1] = column0Row1; result[2] = column0Row2; result[3] = 0; result[4] = column1Row0; result[5] = column1Row1; result[6] = column1Row2; result[7] = 0; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = 0; result[12] = column3Row0; result[13] = column3Row1; result[14] = column3Row2; result[15] = 1; return result; } /** * Multiplies a transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]) * by a 3x3 rotation matrix. This is an optimization * for Matrix4.multiply(m, Matrix4.fromRotationTranslation(rotation), m); with less allocations and arithmetic operations. * * @param {Matrix4} matrix The matrix on the left-hand side. * @param {Matrix3} rotation The 3x3 rotation matrix on the right-hand side. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromRotationTranslation(rotation), m); * Cesium.Matrix4.multiplyByMatrix3(m, rotation, m); */ static multiplyByMatrix3(matrix, rotation, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("rotation", rotation); Check_default.typeOf.object("result", result); const left0 = matrix[0]; const left1 = matrix[1]; const left2 = matrix[2]; const left4 = matrix[4]; const left5 = matrix[5]; const left6 = matrix[6]; const left8 = matrix[8]; const left9 = matrix[9]; const left10 = matrix[10]; const right0 = rotation[0]; const right1 = rotation[1]; const right2 = rotation[2]; const right4 = rotation[3]; const right5 = rotation[4]; const right6 = rotation[5]; const right8 = rotation[6]; const right9 = rotation[7]; const right10 = rotation[8]; const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2; const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2; const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2; const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6; const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6; const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6; const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10; const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10; const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10; result[0] = column0Row0; result[1] = column0Row1; result[2] = column0Row2; result[3] = 0; result[4] = column1Row0; result[5] = column1Row1; result[6] = column1Row2; result[7] = 0; result[8] = column2Row0; result[9] = column2Row1; result[10] = column2Row2; result[11] = 0; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Multiplies a transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]) * by an implicit translation matrix defined by a {@link Cartesian3}. This is an optimization * for Matrix4.multiply(m, Matrix4.fromTranslation(position), m); with less allocations and arithmetic operations. * * @param {Matrix4} matrix The matrix on the left-hand side. * @param {Cartesian3} translation The translation on the right-hand side. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromTranslation(position), m); * Cesium.Matrix4.multiplyByTranslation(m, position, m); */ static multiplyByTranslation(matrix, translation3, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("translation", translation3); Check_default.typeOf.object("result", result); const x = translation3.x; const y = translation3.y; const z2 = translation3.z; const tx = x * matrix[0] + y * matrix[4] + z2 * matrix[8] + matrix[12]; const ty = x * matrix[1] + y * matrix[5] + z2 * matrix[9] + matrix[13]; const tz = x * matrix[2] + y * matrix[6] + z2 * matrix[10] + matrix[14]; result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; result[4] = matrix[4]; result[5] = matrix[5]; result[6] = matrix[6]; result[7] = matrix[7]; result[8] = matrix[8]; result[9] = matrix[9]; result[10] = matrix[10]; result[11] = matrix[11]; result[12] = tx; result[13] = ty; result[14] = tz; result[15] = matrix[15]; return result; } /** * Multiplies an affine transformation matrix (with a bottom row of [0.0, 0.0, 0.0, 1.0]) * by an implicit non-uniform scale matrix. This is an optimization * for Matrix4.multiply(m, Matrix4.fromUniformScale(scale), m);, where * m must be an affine matrix. * This function performs fewer allocations and arithmetic operations. * * @param {Matrix4} matrix The affine matrix on the left-hand side. * @param {Cartesian3} scale The non-uniform scale on the right-hand side. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * * @example * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromScale(scale), m); * Cesium.Matrix4.multiplyByScale(m, scale, m); * * @see Matrix4.multiplyByUniformScale * @see Matrix4.fromScale * @see Matrix4.fromUniformScale * @see Matrix4.setScale * @see Matrix4.setUniformScale * @see Matrix4.getScale */ static multiplyByScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); const scaleX = scale.x; const scaleY = scale.y; const scaleZ = scale.z; if (scaleX === 1 && scaleY === 1 && scaleZ === 1) { return _Matrix4.clone(matrix, result); } result[0] = scaleX * matrix[0]; result[1] = scaleX * matrix[1]; result[2] = scaleX * matrix[2]; result[3] = matrix[3]; result[4] = scaleY * matrix[4]; result[5] = scaleY * matrix[5]; result[6] = scaleY * matrix[6]; result[7] = matrix[7]; result[8] = scaleZ * matrix[8]; result[9] = scaleZ * matrix[9]; result[10] = scaleZ * matrix[10]; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Computes the product of a matrix times a uniform scale, as if the scale were a scale matrix. * * @param {Matrix4} matrix The matrix on the left-hand side. * @param {number} scale The uniform scale on the right-hand side. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * // Instead of Cesium.Matrix4.multiply(m, Cesium.Matrix4.fromUniformScale(scale), m); * Cesium.Matrix4.multiplyByUniformScale(m, scale, m); * * @see Matrix4.multiplyByScale * @see Matrix4.fromScale * @see Matrix4.fromUniformScale * @see Matrix4.setScale * @see Matrix4.setUniformScale * @see Matrix4.getScale */ static multiplyByUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scale; result[1] = matrix[1] * scale; result[2] = matrix[2] * scale; result[3] = matrix[3]; result[4] = matrix[4] * scale; result[5] = matrix[5] * scale; result[6] = matrix[6] * scale; result[7] = matrix[7]; result[8] = matrix[8] * scale; result[9] = matrix[9] * scale; result[10] = matrix[10] * scale; result[11] = matrix[11]; result[12] = matrix[12]; result[13] = matrix[13]; result[14] = matrix[14]; result[15] = matrix[15]; return result; } /** * Computes the product of a matrix and a column vector. * * @param {Matrix4} matrix The matrix. * @param {Cartesian4} cartesian The vector. * @param {Cartesian4} result The object onto which to store the result. * @returns {Cartesian4} The modified result parameter. */ static multiplyByVector(matrix, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const vX = cartesian11.x; const vY = cartesian11.y; const vZ = cartesian11.z; const vW = cartesian11.w; const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12] * vW; const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13] * vW; const z2 = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14] * vW; const w = matrix[3] * vX + matrix[7] * vY + matrix[11] * vZ + matrix[15] * vW; result.x = x; result.y = y; result.z = z2; result.w = w; return result; } /** * Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector} * with a {@link Cartesian4} with a w component of zero. * * @param {Matrix4} matrix The matrix. * @param {Cartesian3} cartesian The point. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. * * @example * const p = new Cesium.Cartesian3(1.0, 2.0, 3.0); * const result = Cesium.Matrix4.multiplyByPointAsVector(matrix, p, new Cesium.Cartesian3()); * // A shortcut for * // Cartesian3 p = ... * // Cesium.Matrix4.multiplyByVector(matrix, new Cesium.Cartesian4(p.x, p.y, p.z, 0.0), result); */ static multiplyByPointAsVector(matrix, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const vX = cartesian11.x; const vY = cartesian11.y; const vZ = cartesian11.z; const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ; const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ; const z2 = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes the product of a matrix and a {@link Cartesian3}. This is equivalent to calling {@link Matrix4.multiplyByVector} * with a {@link Cartesian4} with a w component of 1, but returns a {@link Cartesian3} instead of a {@link Cartesian4}. * * @param {Matrix4} matrix The matrix. * @param {Cartesian3} cartesian The point. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. * * @example * const p = new Cesium.Cartesian3(1.0, 2.0, 3.0); * const result = Cesium.Matrix4.multiplyByPoint(matrix, p, new Cesium.Cartesian3()); */ static multiplyByPoint(matrix, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const vX = cartesian11.x; const vY = cartesian11.y; const vZ = cartesian11.z; const x = matrix[0] * vX + matrix[4] * vY + matrix[8] * vZ + matrix[12]; const y = matrix[1] * vX + matrix[5] * vY + matrix[9] * vZ + matrix[13]; const z2 = matrix[2] * vX + matrix[6] * vY + matrix[10] * vZ + matrix[14]; result.x = x; result.y = y; result.z = z2; return result; } /** * Computes the product of a matrix and a scalar. * * @param {Matrix4} matrix The matrix. * @param {number} scalar The number to multiply by. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * //create a Matrix4 instance which is a scaled version of the supplied Matrix4 * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * const a = Cesium.Matrix4.multiplyByScalar(m, -2, new Cesium.Matrix4()); * * // m remains the same * // a = [-20.0, -22.0, -24.0, -26.0] * // [-28.0, -30.0, -32.0, -34.0] * // [-36.0, -38.0, -40.0, -42.0] * // [-44.0, -46.0, -48.0, -50.0] */ static multiplyByScalar(matrix, scalar, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scalar; result[1] = matrix[1] * scalar; result[2] = matrix[2] * scalar; result[3] = matrix[3] * scalar; result[4] = matrix[4] * scalar; result[5] = matrix[5] * scalar; result[6] = matrix[6] * scalar; result[7] = matrix[7] * scalar; result[8] = matrix[8] * scalar; result[9] = matrix[9] * scalar; result[10] = matrix[10] * scalar; result[11] = matrix[11] * scalar; result[12] = matrix[12] * scalar; result[13] = matrix[13] * scalar; result[14] = matrix[14] * scalar; result[15] = matrix[15] * scalar; return result; } /** * Computes a negated copy of the provided matrix. * * @param {Matrix4} matrix The matrix to negate. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * //create a new Matrix4 instance which is a negation of a Matrix4 * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * const a = Cesium.Matrix4.negate(m, new Cesium.Matrix4()); * * // m remains the same * // a = [-10.0, -11.0, -12.0, -13.0] * // [-14.0, -15.0, -16.0, -17.0] * // [-18.0, -19.0, -20.0, -21.0] * // [-22.0, -23.0, -24.0, -25.0] */ static negate(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = -matrix[0]; result[1] = -matrix[1]; result[2] = -matrix[2]; result[3] = -matrix[3]; result[4] = -matrix[4]; result[5] = -matrix[5]; result[6] = -matrix[6]; result[7] = -matrix[7]; result[8] = -matrix[8]; result[9] = -matrix[9]; result[10] = -matrix[10]; result[11] = -matrix[11]; result[12] = -matrix[12]; result[13] = -matrix[13]; result[14] = -matrix[14]; result[15] = -matrix[15]; return result; } /** * Computes the transpose of the provided matrix. * * @param {Matrix4} matrix The matrix to transpose. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @example * //returns transpose of a Matrix4 * // m = [10.0, 11.0, 12.0, 13.0] * // [14.0, 15.0, 16.0, 17.0] * // [18.0, 19.0, 20.0, 21.0] * // [22.0, 23.0, 24.0, 25.0] * * const a = Cesium.Matrix4.transpose(m, new Cesium.Matrix4()); * * // m remains the same * // a = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] */ static transpose(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const matrix1 = matrix[1]; const matrix2 = matrix[2]; const matrix3 = matrix[3]; const matrix6 = matrix[6]; const matrix7 = matrix[7]; const matrix11 = matrix[11]; result[0] = matrix[0]; result[1] = matrix[4]; result[2] = matrix[8]; result[3] = matrix[12]; result[4] = matrix1; result[5] = matrix[5]; result[6] = matrix[9]; result[7] = matrix[13]; result[8] = matrix2; result[9] = matrix6; result[10] = matrix[10]; result[11] = matrix[14]; result[12] = matrix3; result[13] = matrix7; result[14] = matrix11; result[15] = matrix[15]; return result; } /** * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements. * * @param {Matrix4} matrix The matrix with signed elements. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static abs(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = Math.abs(matrix[0]); result[1] = Math.abs(matrix[1]); result[2] = Math.abs(matrix[2]); result[3] = Math.abs(matrix[3]); result[4] = Math.abs(matrix[4]); result[5] = Math.abs(matrix[5]); result[6] = Math.abs(matrix[6]); result[7] = Math.abs(matrix[7]); result[8] = Math.abs(matrix[8]); result[9] = Math.abs(matrix[9]); result[10] = Math.abs(matrix[10]); result[11] = Math.abs(matrix[11]); result[12] = Math.abs(matrix[12]); result[13] = Math.abs(matrix[13]); result[14] = Math.abs(matrix[14]); result[15] = Math.abs(matrix[15]); return result; } /** * Compares the provided matrices componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix4} [left] The first matrix. * @param {Matrix4} [right] The second matrix. * @returns {boolean} true if left and right are equal, false otherwise. * * @example * //compares two Matrix4 instances * * // a = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] * * // b = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] * * if(Cesium.Matrix4.equals(a,b)) { * console.log("Both matrices are equal"); * } else { * console.log("They are not equal"); * } * * //Prints "Both matrices are equal" on the console */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && // Translation left[12] === right[12] && left[13] === right[13] && left[14] === right[14] && // Rotation/scale left[0] === right[0] && left[1] === right[1] && left[2] === right[2] && left[4] === right[4] && left[5] === right[5] && left[6] === right[6] && left[8] === right[8] && left[9] === right[9] && left[10] === right[10] && // Bottom row left[3] === right[3] && left[7] === right[7] && left[11] === right[11] && left[15] === right[15]; } /** * Compares the provided matrices componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix4} [left] The first matrix. * @param {Matrix4} [right] The second matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. * * @example * //compares two Matrix4 instances * * // a = [10.5, 14.5, 18.5, 22.5] * // [11.5, 15.5, 19.5, 23.5] * // [12.5, 16.5, 20.5, 24.5] * // [13.5, 17.5, 21.5, 25.5] * * // b = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] * * if(Cesium.Matrix4.equalsEpsilon(a,b,0.1)){ * console.log("Difference between both the matrices is less than 0.1"); * } else { * console.log("Difference between both the matrices is not less than 0.1"); * } * * //Prints "Difference between both the matrices is not less than 0.1" on the console */ static equalsEpsilon(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left[0] - right[0]) <= epsilon && Math.abs(left[1] - right[1]) <= epsilon && Math.abs(left[2] - right[2]) <= epsilon && Math.abs(left[3] - right[3]) <= epsilon && Math.abs(left[4] - right[4]) <= epsilon && Math.abs(left[5] - right[5]) <= epsilon && Math.abs(left[6] - right[6]) <= epsilon && Math.abs(left[7] - right[7]) <= epsilon && Math.abs(left[8] - right[8]) <= epsilon && Math.abs(left[9] - right[9]) <= epsilon && Math.abs(left[10] - right[10]) <= epsilon && Math.abs(left[11] - right[11]) <= epsilon && Math.abs(left[12] - right[12]) <= epsilon && Math.abs(left[13] - right[13]) <= epsilon && Math.abs(left[14] - right[14]) <= epsilon && Math.abs(left[15] - right[15]) <= epsilon; } /** * Gets the translation portion of the provided matrix, assuming the matrix is an affine transformation matrix. * * @param {Matrix4} matrix The matrix to use. * @param {Cartesian3} result The object onto which to store the result. * @returns {Cartesian3} The modified result parameter. */ static getTranslation(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result.x = matrix[12]; result.y = matrix[13]; result.z = matrix[14]; return result; } /** * Gets the upper left 3x3 matrix of the provided matrix. * * @param {Matrix4} matrix The matrix to use. * @param {Matrix3} result The object onto which to store the result. * @returns {Matrix3} The modified result parameter. * * @example * // returns a Matrix3 instance from a Matrix4 instance * * // m = [10.0, 14.0, 18.0, 22.0] * // [11.0, 15.0, 19.0, 23.0] * // [12.0, 16.0, 20.0, 24.0] * // [13.0, 17.0, 21.0, 25.0] * * const b = new Cesium.Matrix3(); * Cesium.Matrix4.getMatrix3(m,b); * * // b = [10.0, 14.0, 18.0] * // [11.0, 15.0, 19.0] * // [12.0, 16.0, 20.0] */ static getMatrix3(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[4]; result[4] = matrix[5]; result[5] = matrix[6]; result[6] = matrix[8]; result[7] = matrix[9]; result[8] = matrix[10]; return result; } /** * Computes the inverse of the provided matrix using Cramers Rule. * If the determinant is zero, the matrix can not be inverted, and an exception is thrown. * If the matrix is a proper rigid transformation, it is more efficient * to invert it with {@link Matrix4.inverseTransformation}. * * @param {Matrix4} matrix The matrix to invert. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. * * @exception {RuntimeError} matrix is not invertible because its determinate is zero. */ static inverse(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const src0 = matrix[0]; const src1 = matrix[4]; const src2 = matrix[8]; const src3 = matrix[12]; const src4 = matrix[1]; const src5 = matrix[5]; const src6 = matrix[9]; const src7 = matrix[13]; const src8 = matrix[2]; const src9 = matrix[6]; const src10 = matrix[10]; const src11 = matrix[14]; const src12 = matrix[3]; const src13 = matrix[7]; const src14 = matrix[11]; const src15 = matrix[15]; let tmp0 = src10 * src15; let tmp1 = src11 * src14; let tmp2 = src9 * src15; let tmp3 = src11 * src13; let tmp4 = src9 * src14; let tmp5 = src10 * src13; let tmp6 = src8 * src15; let tmp7 = src11 * src12; let tmp8 = src8 * src14; let tmp9 = src10 * src12; let tmp10 = src8 * src13; let tmp11 = src9 * src12; const dst0 = tmp0 * src5 + tmp3 * src6 + tmp4 * src7 - (tmp1 * src5 + tmp2 * src6 + tmp5 * src7); const dst1 = tmp1 * src4 + tmp6 * src6 + tmp9 * src7 - (tmp0 * src4 + tmp7 * src6 + tmp8 * src7); const dst2 = tmp2 * src4 + tmp7 * src5 + tmp10 * src7 - (tmp3 * src4 + tmp6 * src5 + tmp11 * src7); const dst3 = tmp5 * src4 + tmp8 * src5 + tmp11 * src6 - (tmp4 * src4 + tmp9 * src5 + tmp10 * src6); const dst4 = tmp1 * src1 + tmp2 * src2 + tmp5 * src3 - (tmp0 * src1 + tmp3 * src2 + tmp4 * src3); const dst5 = tmp0 * src0 + tmp7 * src2 + tmp8 * src3 - (tmp1 * src0 + tmp6 * src2 + tmp9 * src3); const dst6 = tmp3 * src0 + tmp6 * src1 + tmp11 * src3 - (tmp2 * src0 + tmp7 * src1 + tmp10 * src3); const dst7 = tmp4 * src0 + tmp9 * src1 + tmp10 * src2 - (tmp5 * src0 + tmp8 * src1 + tmp11 * src2); tmp0 = src2 * src7; tmp1 = src3 * src6; tmp2 = src1 * src7; tmp3 = src3 * src5; tmp4 = src1 * src6; tmp5 = src2 * src5; tmp6 = src0 * src7; tmp7 = src3 * src4; tmp8 = src0 * src6; tmp9 = src2 * src4; tmp10 = src0 * src5; tmp11 = src1 * src4; const dst8 = tmp0 * src13 + tmp3 * src14 + tmp4 * src15 - (tmp1 * src13 + tmp2 * src14 + tmp5 * src15); const dst9 = tmp1 * src12 + tmp6 * src14 + tmp9 * src15 - (tmp0 * src12 + tmp7 * src14 + tmp8 * src15); const dst10 = tmp2 * src12 + tmp7 * src13 + tmp10 * src15 - (tmp3 * src12 + tmp6 * src13 + tmp11 * src15); const dst11 = tmp5 * src12 + tmp8 * src13 + tmp11 * src14 - (tmp4 * src12 + tmp9 * src13 + tmp10 * src14); const dst12 = tmp2 * src10 + tmp5 * src11 + tmp1 * src9 - (tmp4 * src11 + tmp0 * src9 + tmp3 * src10); const dst13 = tmp8 * src11 + tmp0 * src8 + tmp7 * src10 - (tmp6 * src10 + tmp9 * src11 + tmp1 * src8); const dst14 = tmp6 * src9 + tmp11 * src11 + tmp3 * src8 - (tmp10 * src11 + tmp2 * src8 + tmp7 * src9); const dst15 = tmp10 * src10 + tmp4 * src8 + tmp9 * src9 - (tmp8 * src9 + tmp11 * src10 + tmp5 * src8); let det = src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3; if (Math.abs(det) < Math_default.EPSILON21) { if (Matrix3_default.equalsEpsilon( _Matrix4.getMatrix3(matrix, scratchInverseRotation), scratchMatrix3Zero, Math_default.EPSILON7 ) && Cartesian4_default.equals( _Matrix4.getRow(matrix, 3, scratchBottomRow), scratchExpectedBottomRow )) { result[0] = 0; result[1] = 0; result[2] = 0; result[3] = 0; result[4] = 0; result[5] = 0; result[6] = 0; result[7] = 0; result[8] = 0; result[9] = 0; result[10] = 0; result[11] = 0; result[12] = -matrix[12]; result[13] = -matrix[13]; result[14] = -matrix[14]; result[15] = 1; return result; } throw new RuntimeError_default( "matrix is not invertible because its determinate is zero." ); } det = 1 / det; result[0] = dst0 * det; result[1] = dst1 * det; result[2] = dst2 * det; result[3] = dst3 * det; result[4] = dst4 * det; result[5] = dst5 * det; result[6] = dst6 * det; result[7] = dst7 * det; result[8] = dst8 * det; result[9] = dst9 * det; result[10] = dst10 * det; result[11] = dst11 * det; result[12] = dst12 * det; result[13] = dst13 * det; result[14] = dst14 * det; result[15] = dst15 * det; return result; } /** * Computes the inverse of the provided matrix assuming it is a proper rigid matrix, * where the upper left 3x3 elements are a rotation matrix, * and the upper three elements in the fourth column are the translation. * The bottom row is assumed to be [0, 0, 0, 1]. * The matrix is not verified to be in the proper form. * This method is faster than computing the inverse for a general 4x4 * matrix using {@link Matrix4.inverse}. * * @param {Matrix4} matrix The matrix to invert. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static inverseTransformation(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const matrix0 = matrix[0]; const matrix1 = matrix[1]; const matrix2 = matrix[2]; const matrix4 = matrix[4]; const matrix5 = matrix[5]; const matrix6 = matrix[6]; const matrix8 = matrix[8]; const matrix9 = matrix[9]; const matrix10 = matrix[10]; const vX = matrix[12]; const vY = matrix[13]; const vZ = matrix[14]; const x = -matrix0 * vX - matrix1 * vY - matrix2 * vZ; const y = -matrix4 * vX - matrix5 * vY - matrix6 * vZ; const z2 = -matrix8 * vX - matrix9 * vY - matrix10 * vZ; result[0] = matrix0; result[1] = matrix4; result[2] = matrix8; result[3] = 0; result[4] = matrix1; result[5] = matrix5; result[6] = matrix9; result[7] = 0; result[8] = matrix2; result[9] = matrix6; result[10] = matrix10; result[11] = 0; result[12] = x; result[13] = y; result[14] = z2; result[15] = 1; return result; } /** * Computes the inverse transpose of a matrix. * * @param {Matrix4} matrix The matrix to transpose and invert. * @param {Matrix4} result The object onto which to store the result. * @returns {Matrix4} The modified result parameter. */ static inverseTranspose(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); return _Matrix4.inverse( _Matrix4.transpose(matrix, scratchTransposeMatrix2), result ); } /** * Gets the number of items in the collection. * * @type {number} */ get length() { return _Matrix4.packedLength; } /** * Duplicates the provided Matrix4 instance. * * @param {Matrix4} [result] The object onto which to store the result. * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if one was not provided. */ clone(result) { return _Matrix4.clone(this, result); } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix4} [right] The right hand side matrix. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Matrix4.equals(this, right); } /** * Compares provided matrix and array, starting from a given array offset. * * @param {Matrix4} matrix * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(matrix, array, offset) { return matrix[0] === array[offset] && matrix[1] === array[offset + 1] && matrix[2] === array[offset + 2] && matrix[3] === array[offset + 3] && matrix[4] === array[offset + 4] && matrix[5] === array[offset + 5] && matrix[6] === array[offset + 6] && matrix[7] === array[offset + 7] && matrix[8] === array[offset + 8] && matrix[9] === array[offset + 9] && matrix[10] === array[offset + 10] && matrix[11] === array[offset + 11] && matrix[12] === array[offset + 12] && matrix[13] === array[offset + 13] && matrix[14] === array[offset + 14] && matrix[15] === array[offset + 15]; } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix4} [right] The right hand side matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, epsilon) { return _Matrix4.equalsEpsilon(this, right, epsilon); } /** * Computes a string representing this Matrix with each row being * on a separate line and in the format '(column0, column1, column2, column3)'. * * @returns {string} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1, column2, column3)'. */ toString() { return `(${this[0]}, ${this[4]}, ${this[8]}, ${this[12]}) (${this[1]}, ${this[5]}, ${this[9]}, ${this[13]}) (${this[2]}, ${this[6]}, ${this[10]}, ${this[14]}) (${this[3]}, ${this[7]}, ${this[11]}, ${this[15]})`; } }; Matrix4.packedLength = 16; Matrix4.fromArray = Matrix4.unpack; Matrix4.IDENTITY = Object.freeze( new Matrix4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ) ); Matrix4.ZERO = Object.freeze( new Matrix4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) ); Matrix4.COLUMN0ROW0 = 0; Matrix4.COLUMN0ROW1 = 1; Matrix4.COLUMN0ROW2 = 2; Matrix4.COLUMN0ROW3 = 3; Matrix4.COLUMN1ROW0 = 4; Matrix4.COLUMN1ROW1 = 5; Matrix4.COLUMN1ROW2 = 6; Matrix4.COLUMN1ROW3 = 7; Matrix4.COLUMN2ROW0 = 8; Matrix4.COLUMN2ROW1 = 9; Matrix4.COLUMN2ROW2 = 10; Matrix4.COLUMN2ROW3 = 11; Matrix4.COLUMN3ROW0 = 12; Matrix4.COLUMN3ROW1 = 13; Matrix4.COLUMN3ROW2 = 14; Matrix4.COLUMN3ROW3 = 15; var fromCameraF = new Cartesian3_default(); var fromCameraR = new Cartesian3_default(); var fromCameraU = new Cartesian3_default(); var scaleScratch12 = new Cartesian3_default(); var scaleScratch22 = new Cartesian3_default(); var scratchColumn2 = new Cartesian3_default(); var scaleScratch32 = new Cartesian3_default(); var scaleScratch42 = new Cartesian3_default(); var scaleScratch52 = new Cartesian3_default(); var scratchInverseRotation = new Matrix3_default(); var scratchMatrix3Zero = new Matrix3_default(); var scratchBottomRow = new Cartesian4_default(); var scratchExpectedBottomRow = new Cartesian4_default(0, 0, 0, 1); var scratchTransposeMatrix2 = new Matrix4(); var Matrix4_default = Matrix4; // packages/engine/Source/Core/WebGLConstants.js var import_InlineWorkers11 = __toESM(require_InlineWorkers(), 1); var WebGLConstants = { DEPTH_BUFFER_BIT: 256, STENCIL_BUFFER_BIT: 1024, COLOR_BUFFER_BIT: 16384, POINTS: 0, LINES: 1, LINE_LOOP: 2, LINE_STRIP: 3, TRIANGLES: 4, TRIANGLE_STRIP: 5, TRIANGLE_FAN: 6, ZERO: 0, ONE: 1, SRC_COLOR: 768, ONE_MINUS_SRC_COLOR: 769, SRC_ALPHA: 770, ONE_MINUS_SRC_ALPHA: 771, DST_ALPHA: 772, ONE_MINUS_DST_ALPHA: 773, DST_COLOR: 774, ONE_MINUS_DST_COLOR: 775, SRC_ALPHA_SATURATE: 776, FUNC_ADD: 32774, BLEND_EQUATION: 32777, BLEND_EQUATION_RGB: 32777, // same as BLEND_EQUATION BLEND_EQUATION_ALPHA: 34877, FUNC_SUBTRACT: 32778, FUNC_REVERSE_SUBTRACT: 32779, BLEND_DST_RGB: 32968, BLEND_SRC_RGB: 32969, BLEND_DST_ALPHA: 32970, BLEND_SRC_ALPHA: 32971, CONSTANT_COLOR: 32769, ONE_MINUS_CONSTANT_COLOR: 32770, CONSTANT_ALPHA: 32771, ONE_MINUS_CONSTANT_ALPHA: 32772, BLEND_COLOR: 32773, ARRAY_BUFFER: 34962, ELEMENT_ARRAY_BUFFER: 34963, ARRAY_BUFFER_BINDING: 34964, ELEMENT_ARRAY_BUFFER_BINDING: 34965, STREAM_DRAW: 35040, STATIC_DRAW: 35044, DYNAMIC_DRAW: 35048, BUFFER_SIZE: 34660, BUFFER_USAGE: 34661, CURRENT_VERTEX_ATTRIB: 34342, FRONT: 1028, BACK: 1029, FRONT_AND_BACK: 1032, CULL_FACE: 2884, BLEND: 3042, DITHER: 3024, STENCIL_TEST: 2960, DEPTH_TEST: 2929, SCISSOR_TEST: 3089, POLYGON_OFFSET_FILL: 32823, SAMPLE_ALPHA_TO_COVERAGE: 32926, SAMPLE_COVERAGE: 32928, NO_ERROR: 0, INVALID_ENUM: 1280, INVALID_VALUE: 1281, INVALID_OPERATION: 1282, OUT_OF_MEMORY: 1285, CW: 2304, CCW: 2305, LINE_WIDTH: 2849, ALIASED_POINT_SIZE_RANGE: 33901, ALIASED_LINE_WIDTH_RANGE: 33902, CULL_FACE_MODE: 2885, FRONT_FACE: 2886, DEPTH_RANGE: 2928, DEPTH_WRITEMASK: 2930, DEPTH_CLEAR_VALUE: 2931, DEPTH_FUNC: 2932, STENCIL_CLEAR_VALUE: 2961, STENCIL_FUNC: 2962, STENCIL_FAIL: 2964, STENCIL_PASS_DEPTH_FAIL: 2965, STENCIL_PASS_DEPTH_PASS: 2966, STENCIL_REF: 2967, STENCIL_VALUE_MASK: 2963, STENCIL_WRITEMASK: 2968, STENCIL_BACK_FUNC: 34816, STENCIL_BACK_FAIL: 34817, STENCIL_BACK_PASS_DEPTH_FAIL: 34818, STENCIL_BACK_PASS_DEPTH_PASS: 34819, STENCIL_BACK_REF: 36003, STENCIL_BACK_VALUE_MASK: 36004, STENCIL_BACK_WRITEMASK: 36005, VIEWPORT: 2978, SCISSOR_BOX: 3088, COLOR_CLEAR_VALUE: 3106, COLOR_WRITEMASK: 3107, UNPACK_ALIGNMENT: 3317, PACK_ALIGNMENT: 3333, MAX_TEXTURE_SIZE: 3379, MAX_VIEWPORT_DIMS: 3386, SUBPIXEL_BITS: 3408, RED_BITS: 3410, GREEN_BITS: 3411, BLUE_BITS: 3412, ALPHA_BITS: 3413, DEPTH_BITS: 3414, STENCIL_BITS: 3415, POLYGON_OFFSET_UNITS: 10752, POLYGON_OFFSET_FACTOR: 32824, TEXTURE_BINDING_2D: 32873, SAMPLE_BUFFERS: 32936, SAMPLES: 32937, SAMPLE_COVERAGE_VALUE: 32938, SAMPLE_COVERAGE_INVERT: 32939, COMPRESSED_TEXTURE_FORMATS: 34467, DONT_CARE: 4352, FASTEST: 4353, NICEST: 4354, GENERATE_MIPMAP_HINT: 33170, BYTE: 5120, UNSIGNED_BYTE: 5121, SHORT: 5122, UNSIGNED_SHORT: 5123, INT: 5124, UNSIGNED_INT: 5125, FLOAT: 5126, DEPTH_COMPONENT: 6402, ALPHA: 6406, RGB: 6407, RGBA: 6408, LUMINANCE: 6409, LUMINANCE_ALPHA: 6410, UNSIGNED_SHORT_4_4_4_4: 32819, UNSIGNED_SHORT_5_5_5_1: 32820, UNSIGNED_SHORT_5_6_5: 33635, FRAGMENT_SHADER: 35632, VERTEX_SHADER: 35633, MAX_VERTEX_ATTRIBS: 34921, MAX_VERTEX_UNIFORM_VECTORS: 36347, MAX_VARYING_VECTORS: 36348, MAX_COMBINED_TEXTURE_IMAGE_UNITS: 35661, MAX_VERTEX_TEXTURE_IMAGE_UNITS: 35660, MAX_TEXTURE_IMAGE_UNITS: 34930, MAX_FRAGMENT_UNIFORM_VECTORS: 36349, SHADER_TYPE: 35663, DELETE_STATUS: 35712, LINK_STATUS: 35714, VALIDATE_STATUS: 35715, ATTACHED_SHADERS: 35717, ACTIVE_UNIFORMS: 35718, ACTIVE_ATTRIBUTES: 35721, SHADING_LANGUAGE_VERSION: 35724, CURRENT_PROGRAM: 35725, NEVER: 512, LESS: 513, EQUAL: 514, LEQUAL: 515, GREATER: 516, NOTEQUAL: 517, GEQUAL: 518, ALWAYS: 519, KEEP: 7680, REPLACE: 7681, INCR: 7682, DECR: 7683, INVERT: 5386, INCR_WRAP: 34055, DECR_WRAP: 34056, VENDOR: 7936, RENDERER: 7937, VERSION: 7938, NEAREST: 9728, LINEAR: 9729, NEAREST_MIPMAP_NEAREST: 9984, LINEAR_MIPMAP_NEAREST: 9985, NEAREST_MIPMAP_LINEAR: 9986, LINEAR_MIPMAP_LINEAR: 9987, TEXTURE_MAG_FILTER: 10240, TEXTURE_MIN_FILTER: 10241, TEXTURE_WRAP_S: 10242, TEXTURE_WRAP_T: 10243, TEXTURE_2D: 3553, TEXTURE: 5890, TEXTURE_CUBE_MAP: 34067, TEXTURE_BINDING_CUBE_MAP: 34068, TEXTURE_CUBE_MAP_POSITIVE_X: 34069, TEXTURE_CUBE_MAP_NEGATIVE_X: 34070, TEXTURE_CUBE_MAP_POSITIVE_Y: 34071, TEXTURE_CUBE_MAP_NEGATIVE_Y: 34072, TEXTURE_CUBE_MAP_POSITIVE_Z: 34073, TEXTURE_CUBE_MAP_NEGATIVE_Z: 34074, MAX_CUBE_MAP_TEXTURE_SIZE: 34076, TEXTURE0: 33984, TEXTURE1: 33985, TEXTURE2: 33986, TEXTURE3: 33987, TEXTURE4: 33988, TEXTURE5: 33989, TEXTURE6: 33990, TEXTURE7: 33991, TEXTURE8: 33992, TEXTURE9: 33993, TEXTURE10: 33994, TEXTURE11: 33995, TEXTURE12: 33996, TEXTURE13: 33997, TEXTURE14: 33998, TEXTURE15: 33999, TEXTURE16: 34e3, TEXTURE17: 34001, TEXTURE18: 34002, TEXTURE19: 34003, TEXTURE20: 34004, TEXTURE21: 34005, TEXTURE22: 34006, TEXTURE23: 34007, TEXTURE24: 34008, TEXTURE25: 34009, TEXTURE26: 34010, TEXTURE27: 34011, TEXTURE28: 34012, TEXTURE29: 34013, TEXTURE30: 34014, TEXTURE31: 34015, ACTIVE_TEXTURE: 34016, REPEAT: 10497, CLAMP_TO_EDGE: 33071, MIRRORED_REPEAT: 33648, FLOAT_VEC2: 35664, FLOAT_VEC3: 35665, FLOAT_VEC4: 35666, INT_VEC2: 35667, INT_VEC3: 35668, INT_VEC4: 35669, BOOL: 35670, BOOL_VEC2: 35671, BOOL_VEC3: 35672, BOOL_VEC4: 35673, FLOAT_MAT2: 35674, FLOAT_MAT3: 35675, FLOAT_MAT4: 35676, SAMPLER_2D: 35678, SAMPLER_CUBE: 35680, VERTEX_ATTRIB_ARRAY_ENABLED: 34338, VERTEX_ATTRIB_ARRAY_SIZE: 34339, VERTEX_ATTRIB_ARRAY_STRIDE: 34340, VERTEX_ATTRIB_ARRAY_TYPE: 34341, VERTEX_ATTRIB_ARRAY_NORMALIZED: 34922, VERTEX_ATTRIB_ARRAY_POINTER: 34373, VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 34975, IMPLEMENTATION_COLOR_READ_TYPE: 35738, IMPLEMENTATION_COLOR_READ_FORMAT: 35739, COMPILE_STATUS: 35713, LOW_FLOAT: 36336, MEDIUM_FLOAT: 36337, HIGH_FLOAT: 36338, LOW_INT: 36339, MEDIUM_INT: 36340, HIGH_INT: 36341, FRAMEBUFFER: 36160, RENDERBUFFER: 36161, RGBA4: 32854, RGB5_A1: 32855, RGB565: 36194, DEPTH_COMPONENT16: 33189, STENCIL_INDEX: 6401, STENCIL_INDEX8: 36168, DEPTH_STENCIL: 34041, RENDERBUFFER_WIDTH: 36162, RENDERBUFFER_HEIGHT: 36163, RENDERBUFFER_INTERNAL_FORMAT: 36164, RENDERBUFFER_RED_SIZE: 36176, RENDERBUFFER_GREEN_SIZE: 36177, RENDERBUFFER_BLUE_SIZE: 36178, RENDERBUFFER_ALPHA_SIZE: 36179, RENDERBUFFER_DEPTH_SIZE: 36180, RENDERBUFFER_STENCIL_SIZE: 36181, FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 36048, FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 36049, FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 36050, FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 36051, COLOR_ATTACHMENT0: 36064, DEPTH_ATTACHMENT: 36096, STENCIL_ATTACHMENT: 36128, DEPTH_STENCIL_ATTACHMENT: 33306, NONE: 0, FRAMEBUFFER_COMPLETE: 36053, FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 36054, FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 36055, FRAMEBUFFER_INCOMPLETE_DIMENSIONS: 36057, FRAMEBUFFER_UNSUPPORTED: 36061, FRAMEBUFFER_BINDING: 36006, RENDERBUFFER_BINDING: 36007, MAX_RENDERBUFFER_SIZE: 34024, INVALID_FRAMEBUFFER_OPERATION: 1286, UNPACK_FLIP_Y_WEBGL: 37440, UNPACK_PREMULTIPLY_ALPHA_WEBGL: 37441, CONTEXT_LOST_WEBGL: 37442, UNPACK_COLORSPACE_CONVERSION_WEBGL: 37443, BROWSER_DEFAULT_WEBGL: 37444, // WEBGL_compressed_texture_s3tc COMPRESSED_RGB_S3TC_DXT1_EXT: 33776, COMPRESSED_RGBA_S3TC_DXT1_EXT: 33777, COMPRESSED_RGBA_S3TC_DXT3_EXT: 33778, COMPRESSED_RGBA_S3TC_DXT5_EXT: 33779, // WEBGL_compressed_texture_pvrtc COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 35840, COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 35841, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 35842, COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: 35843, // WEBGL_compressed_texture_astc COMPRESSED_RGBA_ASTC_4x4_WEBGL: 37808, // WEBGL_compressed_texture_etc1 COMPRESSED_RGB_ETC1_WEBGL: 36196, // EXT_texture_compression_bptc COMPRESSED_RGBA_BPTC_UNORM: 36492, // EXT_color_buffer_half_float HALF_FLOAT_OES: 36193, // Desktop OpenGL DOUBLE: 5130, // WebGL 2 READ_BUFFER: 3074, UNPACK_ROW_LENGTH: 3314, UNPACK_SKIP_ROWS: 3315, UNPACK_SKIP_PIXELS: 3316, PACK_ROW_LENGTH: 3330, PACK_SKIP_ROWS: 3331, PACK_SKIP_PIXELS: 3332, COLOR: 6144, DEPTH: 6145, STENCIL: 6146, RED: 6403, RGB8: 32849, RGBA8: 32856, RGB10_A2: 32857, TEXTURE_BINDING_3D: 32874, UNPACK_SKIP_IMAGES: 32877, UNPACK_IMAGE_HEIGHT: 32878, TEXTURE_3D: 32879, TEXTURE_WRAP_R: 32882, MAX_3D_TEXTURE_SIZE: 32883, UNSIGNED_INT_2_10_10_10_REV: 33640, MAX_ELEMENTS_VERTICES: 33e3, MAX_ELEMENTS_INDICES: 33001, TEXTURE_MIN_LOD: 33082, TEXTURE_MAX_LOD: 33083, TEXTURE_BASE_LEVEL: 33084, TEXTURE_MAX_LEVEL: 33085, MIN: 32775, MAX: 32776, DEPTH_COMPONENT24: 33190, MAX_TEXTURE_LOD_BIAS: 34045, TEXTURE_COMPARE_MODE: 34892, TEXTURE_COMPARE_FUNC: 34893, CURRENT_QUERY: 34917, QUERY_RESULT: 34918, QUERY_RESULT_AVAILABLE: 34919, STREAM_READ: 35041, STREAM_COPY: 35042, STATIC_READ: 35045, STATIC_COPY: 35046, DYNAMIC_READ: 35049, DYNAMIC_COPY: 35050, MAX_DRAW_BUFFERS: 34852, DRAW_BUFFER0: 34853, DRAW_BUFFER1: 34854, DRAW_BUFFER2: 34855, DRAW_BUFFER3: 34856, DRAW_BUFFER4: 34857, DRAW_BUFFER5: 34858, DRAW_BUFFER6: 34859, DRAW_BUFFER7: 34860, DRAW_BUFFER8: 34861, DRAW_BUFFER9: 34862, DRAW_BUFFER10: 34863, DRAW_BUFFER11: 34864, DRAW_BUFFER12: 34865, DRAW_BUFFER13: 34866, DRAW_BUFFER14: 34867, DRAW_BUFFER15: 34868, MAX_FRAGMENT_UNIFORM_COMPONENTS: 35657, MAX_VERTEX_UNIFORM_COMPONENTS: 35658, SAMPLER_3D: 35679, SAMPLER_2D_SHADOW: 35682, FRAGMENT_SHADER_DERIVATIVE_HINT: 35723, PIXEL_PACK_BUFFER: 35051, PIXEL_UNPACK_BUFFER: 35052, PIXEL_PACK_BUFFER_BINDING: 35053, PIXEL_UNPACK_BUFFER_BINDING: 35055, FLOAT_MAT2x3: 35685, FLOAT_MAT2x4: 35686, FLOAT_MAT3x2: 35687, FLOAT_MAT3x4: 35688, FLOAT_MAT4x2: 35689, FLOAT_MAT4x3: 35690, SRGB: 35904, SRGB8: 35905, SRGB8_ALPHA8: 35907, COMPARE_REF_TO_TEXTURE: 34894, RGBA32F: 34836, RGB32F: 34837, RGBA16F: 34842, RGB16F: 34843, VERTEX_ATTRIB_ARRAY_INTEGER: 35069, MAX_ARRAY_TEXTURE_LAYERS: 35071, MIN_PROGRAM_TEXEL_OFFSET: 35076, MAX_PROGRAM_TEXEL_OFFSET: 35077, MAX_VARYING_COMPONENTS: 35659, TEXTURE_2D_ARRAY: 35866, TEXTURE_BINDING_2D_ARRAY: 35869, R11F_G11F_B10F: 35898, UNSIGNED_INT_10F_11F_11F_REV: 35899, RGB9_E5: 35901, UNSIGNED_INT_5_9_9_9_REV: 35902, TRANSFORM_FEEDBACK_BUFFER_MODE: 35967, MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: 35968, TRANSFORM_FEEDBACK_VARYINGS: 35971, TRANSFORM_FEEDBACK_BUFFER_START: 35972, TRANSFORM_FEEDBACK_BUFFER_SIZE: 35973, TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 35976, RASTERIZER_DISCARD: 35977, MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: 35978, MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: 35979, INTERLEAVED_ATTRIBS: 35980, SEPARATE_ATTRIBS: 35981, TRANSFORM_FEEDBACK_BUFFER: 35982, TRANSFORM_FEEDBACK_BUFFER_BINDING: 35983, RGBA32UI: 36208, RGB32UI: 36209, RGBA16UI: 36214, RGB16UI: 36215, RGBA8UI: 36220, RGB8UI: 36221, RGBA32I: 36226, RGB32I: 36227, RGBA16I: 36232, RGB16I: 36233, RGBA8I: 36238, RGB8I: 36239, RED_INTEGER: 36244, RGB_INTEGER: 36248, RGBA_INTEGER: 36249, SAMPLER_2D_ARRAY: 36289, SAMPLER_2D_ARRAY_SHADOW: 36292, SAMPLER_CUBE_SHADOW: 36293, UNSIGNED_INT_VEC2: 36294, UNSIGNED_INT_VEC3: 36295, UNSIGNED_INT_VEC4: 36296, INT_SAMPLER_2D: 36298, INT_SAMPLER_3D: 36299, INT_SAMPLER_CUBE: 36300, INT_SAMPLER_2D_ARRAY: 36303, UNSIGNED_INT_SAMPLER_2D: 36306, UNSIGNED_INT_SAMPLER_3D: 36307, UNSIGNED_INT_SAMPLER_CUBE: 36308, UNSIGNED_INT_SAMPLER_2D_ARRAY: 36311, DEPTH_COMPONENT32F: 36012, DEPTH32F_STENCIL8: 36013, FLOAT_32_UNSIGNED_INT_24_8_REV: 36269, FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 33296, FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 33297, FRAMEBUFFER_ATTACHMENT_RED_SIZE: 33298, FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 33299, FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 33300, FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 33301, FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 33302, FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 33303, FRAMEBUFFER_DEFAULT: 33304, UNSIGNED_INT_24_8: 34042, DEPTH24_STENCIL8: 35056, UNSIGNED_NORMALIZED: 35863, DRAW_FRAMEBUFFER_BINDING: 36006, // Same as FRAMEBUFFER_BINDING READ_FRAMEBUFFER: 36008, DRAW_FRAMEBUFFER: 36009, READ_FRAMEBUFFER_BINDING: 36010, RENDERBUFFER_SAMPLES: 36011, FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: 36052, MAX_COLOR_ATTACHMENTS: 36063, COLOR_ATTACHMENT1: 36065, COLOR_ATTACHMENT2: 36066, COLOR_ATTACHMENT3: 36067, COLOR_ATTACHMENT4: 36068, COLOR_ATTACHMENT5: 36069, COLOR_ATTACHMENT6: 36070, COLOR_ATTACHMENT7: 36071, COLOR_ATTACHMENT8: 36072, COLOR_ATTACHMENT9: 36073, COLOR_ATTACHMENT10: 36074, COLOR_ATTACHMENT11: 36075, COLOR_ATTACHMENT12: 36076, COLOR_ATTACHMENT13: 36077, COLOR_ATTACHMENT14: 36078, COLOR_ATTACHMENT15: 36079, FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: 36182, MAX_SAMPLES: 36183, HALF_FLOAT: 5131, RG: 33319, RG_INTEGER: 33320, R8: 33321, RG8: 33323, R16F: 33325, R32F: 33326, RG16F: 33327, RG32F: 33328, R8I: 33329, R8UI: 33330, R16I: 33331, R16UI: 33332, R32I: 33333, R32UI: 33334, RG8I: 33335, RG8UI: 33336, RG16I: 33337, RG16UI: 33338, RG32I: 33339, RG32UI: 33340, VERTEX_ARRAY_BINDING: 34229, R8_SNORM: 36756, RG8_SNORM: 36757, RGB8_SNORM: 36758, RGBA8_SNORM: 36759, SIGNED_NORMALIZED: 36764, COPY_READ_BUFFER: 36662, COPY_WRITE_BUFFER: 36663, COPY_READ_BUFFER_BINDING: 36662, // Same as COPY_READ_BUFFER COPY_WRITE_BUFFER_BINDING: 36663, // Same as COPY_WRITE_BUFFER UNIFORM_BUFFER: 35345, UNIFORM_BUFFER_BINDING: 35368, UNIFORM_BUFFER_START: 35369, UNIFORM_BUFFER_SIZE: 35370, MAX_VERTEX_UNIFORM_BLOCKS: 35371, MAX_FRAGMENT_UNIFORM_BLOCKS: 35373, MAX_COMBINED_UNIFORM_BLOCKS: 35374, MAX_UNIFORM_BUFFER_BINDINGS: 35375, MAX_UNIFORM_BLOCK_SIZE: 35376, MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: 35377, MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: 35379, UNIFORM_BUFFER_OFFSET_ALIGNMENT: 35380, ACTIVE_UNIFORM_BLOCKS: 35382, UNIFORM_TYPE: 35383, UNIFORM_SIZE: 35384, UNIFORM_BLOCK_INDEX: 35386, UNIFORM_OFFSET: 35387, UNIFORM_ARRAY_STRIDE: 35388, UNIFORM_MATRIX_STRIDE: 35389, UNIFORM_IS_ROW_MAJOR: 35390, UNIFORM_BLOCK_BINDING: 35391, UNIFORM_BLOCK_DATA_SIZE: 35392, UNIFORM_BLOCK_ACTIVE_UNIFORMS: 35394, UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: 35395, UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: 35396, UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: 35398, INVALID_INDEX: 4294967295, MAX_VERTEX_OUTPUT_COMPONENTS: 37154, MAX_FRAGMENT_INPUT_COMPONENTS: 37157, MAX_SERVER_WAIT_TIMEOUT: 37137, OBJECT_TYPE: 37138, SYNC_CONDITION: 37139, SYNC_STATUS: 37140, SYNC_FLAGS: 37141, SYNC_FENCE: 37142, SYNC_GPU_COMMANDS_COMPLETE: 37143, UNSIGNALED: 37144, SIGNALED: 37145, ALREADY_SIGNALED: 37146, TIMEOUT_EXPIRED: 37147, CONDITION_SATISFIED: 37148, WAIT_FAILED: 37149, SYNC_FLUSH_COMMANDS_BIT: 1, VERTEX_ATTRIB_ARRAY_DIVISOR: 35070, ANY_SAMPLES_PASSED: 35887, ANY_SAMPLES_PASSED_CONSERVATIVE: 36202, SAMPLER_BINDING: 35097, RGB10_A2UI: 36975, INT_2_10_10_10_REV: 36255, TRANSFORM_FEEDBACK: 36386, TRANSFORM_FEEDBACK_PAUSED: 36387, TRANSFORM_FEEDBACK_ACTIVE: 36388, TRANSFORM_FEEDBACK_BINDING: 36389, COMPRESSED_R11_EAC: 37488, COMPRESSED_SIGNED_R11_EAC: 37489, COMPRESSED_RG11_EAC: 37490, COMPRESSED_SIGNED_RG11_EAC: 37491, COMPRESSED_RGB8_ETC2: 37492, COMPRESSED_SRGB8_ETC2: 37493, COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: 37494, COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: 37495, COMPRESSED_RGBA8_ETC2_EAC: 37496, COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: 37497, TEXTURE_IMMUTABLE_FORMAT: 37167, MAX_ELEMENT_INDEX: 36203, TEXTURE_IMMUTABLE_LEVELS: 33503, // Extensions MAX_TEXTURE_MAX_ANISOTROPY_EXT: 34047 }; Object.freeze(WebGLConstants); var WebGLConstants_default = WebGLConstants; // packages/engine/Source/Renderer/AutomaticUniforms.js var viewerPositionWCScratch = new Cartesian3_default(); function AutomaticUniform(options) { this._size = options.size; this._datatype = options.datatype; this.getValue = options.getValue; } var datatypeToGlsl = {}; datatypeToGlsl[WebGLConstants_default.FLOAT] = "float"; datatypeToGlsl[WebGLConstants_default.FLOAT_VEC2] = "vec2"; datatypeToGlsl[WebGLConstants_default.FLOAT_VEC3] = "vec3"; datatypeToGlsl[WebGLConstants_default.FLOAT_VEC4] = "vec4"; datatypeToGlsl[WebGLConstants_default.INT] = "int"; datatypeToGlsl[WebGLConstants_default.INT_VEC2] = "ivec2"; datatypeToGlsl[WebGLConstants_default.INT_VEC3] = "ivec3"; datatypeToGlsl[WebGLConstants_default.INT_VEC4] = "ivec4"; datatypeToGlsl[WebGLConstants_default.BOOL] = "bool"; datatypeToGlsl[WebGLConstants_default.BOOL_VEC2] = "bvec2"; datatypeToGlsl[WebGLConstants_default.BOOL_VEC3] = "bvec3"; datatypeToGlsl[WebGLConstants_default.BOOL_VEC4] = "bvec4"; datatypeToGlsl[WebGLConstants_default.FLOAT_MAT2] = "mat2"; datatypeToGlsl[WebGLConstants_default.FLOAT_MAT3] = "mat3"; datatypeToGlsl[WebGLConstants_default.FLOAT_MAT4] = "mat4"; datatypeToGlsl[WebGLConstants_default.SAMPLER_2D] = "sampler2D"; datatypeToGlsl[WebGLConstants_default.SAMPLER_CUBE] = "samplerCube"; AutomaticUniform.prototype.getDeclaration = function(name) { let declaration = `uniform ${datatypeToGlsl[this._datatype]} ${name}`; const size = this._size; if (size === 1) { declaration += ";"; } else { declaration += `[${size.toString()}];`; } return declaration; }; var AutomaticUniforms = { /** * An automatic GLSL uniform containing the viewport's x, y, width, * and height properties in an vec4's x, y, z, * and w components, respectively. * * @example * // GLSL declaration * uniform vec4 czm_viewport; * * // Scale the window coordinate components to [0, 1] by dividing * // by the viewport's width and height. * vec2 v = gl_FragCoord.xy / czm_viewport.zw; * * @see Context#getViewport */ czm_viewport: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC4, getValue: function(uniformState) { return uniformState.viewportCartesian4; } }), /** * An automatic GLSL uniform representing a 4x4 orthographic projection matrix that * transforms window coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. *

* This transform is useful when a vertex shader inputs or manipulates window coordinates * as done by {@link BillboardCollection}. *

* Do not confuse {@link czm_viewportTransformation} with czm_viewportOrthographic. * The former transforms from normalized device coordinates to window coordinates; the later transforms * from window coordinates to clip coordinates, and is often used to assign to gl_Position. * * @example * // GLSL declaration * uniform mat4 czm_viewportOrthographic; * * // Example * gl_Position = czm_viewportOrthographic * vec4(windowPosition, 0.0, 1.0); * * @see UniformState#viewportOrthographic * @see czm_viewport * @see czm_viewportTransformation * @see BillboardCollection */ czm_viewportOrthographic: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.viewportOrthographic; } }), /** * An automatic GLSL uniform representing a 4x4 transformation matrix that * transforms normalized device coordinates to window coordinates. The context's * full viewport is used, and the depth range is assumed to be near = 0 * and far = 1. *

* This transform is useful when there is a need to manipulate window coordinates * in a vertex shader as done by {@link BillboardCollection}. In many cases, * this matrix will not be used directly; instead, {@link czm_modelToWindowCoordinates} * will be used to transform directly from model to window coordinates. *

* Do not confuse czm_viewportTransformation with {@link czm_viewportOrthographic}. * The former transforms from normalized device coordinates to window coordinates; the later transforms * from window coordinates to clip coordinates, and is often used to assign to gl_Position. * * @example * // GLSL declaration * uniform mat4 czm_viewportTransformation; * * // Use czm_viewportTransformation as part of the * // transform from model to window coordinates. * vec4 q = czm_modelViewProjection * positionMC; // model to clip coordinates * q.xyz /= q.w; // clip to normalized device coordinates (ndc) * q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz; // ndc to window coordinates * * @see UniformState#viewportTransformation * @see czm_viewport * @see czm_viewportOrthographic * @see czm_modelToWindowCoordinates * @see BillboardCollection */ czm_viewportTransformation: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.viewportTransformation; } }), /** * An automatic GLSL uniform representing the depth of the scene * after the globe pass and then updated after the 3D Tiles pass. * The depth is packed into an RGBA texture. * * @example * // GLSL declaration * uniform sampler2D czm_globeDepthTexture; * * // Get the depth at the current fragment * vec2 coords = gl_FragCoord.xy / czm_viewport.zw; * float depth = czm_unpackDepth(texture(czm_globeDepthTexture, coords)); */ czm_globeDepthTexture: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.globeDepthTexture; } }), /** * An automatic GLSL uniform representing a texture containing edge IDs * from the 3D Tiles edge rendering pass. Used for edge detection and * avoiding z-fighting between edges and surfaces. * * @example * // GLSL declaration * uniform sampler2D czm_edgeIdTexture; * * // Get the edge ID at the current fragment * vec2 coords = gl_FragCoord.xy / czm_viewport.zw; * vec4 edgeId = texture(czm_edgeIdTexture, coords); */ czm_edgeIdTexture: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.edgeIdTexture; } }), /** * An automatic GLSL uniform containing the edge color texture. * This texture contains the edge content rendered during the CESIUM_3D_TILE_EDGES pass. * * @example * // GLSL declaration * uniform sampler2D czm_edgeColorTexture; * * // Sample the edge color at the current fragment * vec2 coords = gl_FragCoord.xy / czm_viewport.zw; * vec4 edgeColor = texture(czm_edgeColorTexture, coords); */ czm_edgeColorTexture: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.edgeColorTexture; } }), /** * An automatic GLSL uniform containing the packed depth texture produced by the * edge visibility pass. The depth is packed via czm_packDepth and should be * unpacked with czm_unpackDepth. * * @example * // GLSL declaration * uniform sampler2D czm_edgeDepthTexture; * * vec2 coords = gl_FragCoord.xy / czm_viewport.zw; * float d = czm_unpackDepth(texture(czm_edgeDepthTexture, coords)); */ czm_edgeDepthTexture: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.edgeDepthTexture; } }), /** * An automatic GLSL uniform containing the feature-ID texture produced by * the planar fill pre-pass (BENTLEY_materials_planar_fill). Non-behind * planar fill geometry writes its per-fragment feature ID here so that * behind fills can test whether the existing pixel belongs to the same * logical object. * * @example * // GLSL declaration * uniform sampler2D czm_planarFillIdTexture; * * // Sample * vec2 coords = gl_FragCoord.xy / czm_viewport.zw; * float existingFeatureId = texture(czm_planarFillIdTexture, coords).r; */ czm_planarFillIdTexture: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.planarFillIdTexture; } }), /** * An automatic GLSL uniform representing a 4x4 model transformation matrix that * transforms model coordinates to world coordinates. * * @example * // GLSL declaration * uniform mat4 czm_model; * * // Example * vec4 worldPosition = czm_model * modelPosition; * * @see UniformState#model * @see czm_inverseModel * @see czm_modelView * @see czm_modelViewProjection */ czm_model: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.model; } }), /** * An automatic GLSL uniform representing a 4x4 model transformation matrix that * transforms world coordinates to model coordinates. * * @example * // GLSL declaration * uniform mat4 czm_inverseModel; * * // Example * vec4 modelPosition = czm_inverseModel * worldPosition; * * @see UniformState#inverseModel * @see czm_model * @see czm_inverseModelView */ czm_inverseModel: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseModel; } }), /** * An automatic GLSL uniform representing a 4x4 view transformation matrix that * transforms world coordinates to eye coordinates. * * @example * // GLSL declaration * uniform mat4 czm_view; * * // Example * vec4 eyePosition = czm_view * worldPosition; * * @see UniformState#view * @see czm_viewRotation * @see czm_modelView * @see czm_viewProjection * @see czm_modelViewProjection * @see czm_inverseView */ czm_view: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.view; } }), /** * An automatic GLSL uniform representing a 4x4 view transformation matrix that * transforms 3D world coordinates to eye coordinates. In 3D mode, this is identical to * {@link czm_view}, but in 2D and Columbus View it represents the view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat4 czm_view3D; * * // Example * vec4 eyePosition3D = czm_view3D * worldPosition3D; * * @see UniformState#view3D * @see czm_view */ czm_view3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.view3D; } }), /** * An automatic GLSL uniform representing a 3x3 view rotation matrix that * transforms vectors in world coordinates to eye coordinates. * * @example * // GLSL declaration * uniform mat3 czm_viewRotation; * * // Example * vec3 eyeVector = czm_viewRotation * worldVector; * * @see UniformState#viewRotation * @see czm_view * @see czm_inverseView * @see czm_inverseViewRotation */ czm_viewRotation: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.viewRotation; } }), /** * An automatic GLSL uniform representing a 3x3 view rotation matrix that * transforms vectors in 3D world coordinates to eye coordinates. In 3D mode, this is identical to * {@link czm_viewRotation}, but in 2D and Columbus View it represents the view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat3 czm_viewRotation3D; * * // Example * vec3 eyeVector = czm_viewRotation3D * worldVector; * * @see UniformState#viewRotation3D * @see czm_viewRotation */ czm_viewRotation3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.viewRotation3D; } }), /** * An automatic GLSL uniform representing a 4x4 transformation matrix that * transforms from eye coordinates to world coordinates. * * @example * // GLSL declaration * uniform mat4 czm_inverseView; * * // Example * vec4 worldPosition = czm_inverseView * eyePosition; * * @see UniformState#inverseView * @see czm_view * @see czm_inverseNormal */ czm_inverseView: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseView; } }), /** * An automatic GLSL uniform representing a 4x4 transformation matrix that * transforms from 3D eye coordinates to world coordinates. In 3D mode, this is identical to * {@link czm_inverseView}, but in 2D and Columbus View it represents the inverse view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat4 czm_inverseView3D; * * // Example * vec4 worldPosition = czm_inverseView3D * eyePosition; * * @see UniformState#inverseView3D * @see czm_inverseView */ czm_inverseView3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseView3D; } }), /** * An automatic GLSL uniform representing a 3x3 rotation matrix that * transforms vectors from eye coordinates to world coordinates. * * @example * // GLSL declaration * uniform mat3 czm_inverseViewRotation; * * // Example * vec4 worldVector = czm_inverseViewRotation * eyeVector; * * @see UniformState#inverseView * @see czm_view * @see czm_viewRotation * @see czm_inverseViewRotation */ czm_inverseViewRotation: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.inverseViewRotation; } }), /** * An automatic GLSL uniform representing a 3x3 rotation matrix that * transforms vectors from 3D eye coordinates to world coordinates. In 3D mode, this is identical to * {@link czm_inverseViewRotation}, but in 2D and Columbus View it represents the inverse view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat3 czm_inverseViewRotation3D; * * // Example * vec4 worldVector = czm_inverseViewRotation3D * eyeVector; * * @see UniformState#inverseView3D * @see czm_inverseViewRotation */ czm_inverseViewRotation3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.inverseViewRotation3D; } }), /** * An automatic GLSL uniform representing a 4x4 projection transformation matrix that * transforms eye coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_projection; * * // Example * gl_Position = czm_projection * eyePosition; * * @see UniformState#projection * @see czm_viewProjection * @see czm_modelViewProjection * @see czm_infiniteProjection */ czm_projection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.projection; } }), /** * An automatic GLSL uniform representing a 4x4 inverse projection transformation matrix that * transforms from clip coordinates to eye coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_inverseProjection; * * // Example * vec4 eyePosition = czm_inverseProjection * clipPosition; * * @see UniformState#inverseProjection * @see czm_projection */ czm_inverseProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseProjection; } }), /** * An automatic GLSL uniform representing a 4x4 projection transformation matrix with the far plane at infinity, * that transforms eye coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. An infinite far plane is used * in algorithms like shadow volumes and GPU ray casting with proxy geometry to ensure that triangles * are not clipped by the far plane. * * @example * // GLSL declaration * uniform mat4 czm_infiniteProjection; * * // Example * gl_Position = czm_infiniteProjection * eyePosition; * * @see UniformState#infiniteProjection * @see czm_projection * @see czm_modelViewInfiniteProjection */ czm_infiniteProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.infiniteProjection; } }), /** * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that * transforms model coordinates to eye coordinates. *

* Positions should be transformed to eye coordinates using czm_modelView and * normals should be transformed using {@link czm_normal}. * * @example * // GLSL declaration * uniform mat4 czm_modelView; * * // Example * vec4 eyePosition = czm_modelView * modelPosition; * * // The above is equivalent to, but more efficient than: * vec4 eyePosition = czm_view * czm_model * modelPosition; * * @see UniformState#modelView * @see czm_model * @see czm_view * @see czm_modelViewProjection * @see czm_normal */ czm_modelView: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelView; } }), /** * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that * transforms 3D model coordinates to eye coordinates. In 3D mode, this is identical to * {@link czm_modelView}, but in 2D and Columbus View it represents the model-view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. *

* Positions should be transformed to eye coordinates using czm_modelView3D and * normals should be transformed using {@link czm_normal3D}. * * @example * // GLSL declaration * uniform mat4 czm_modelView3D; * * // Example * vec4 eyePosition = czm_modelView3D * modelPosition; * * // The above is equivalent to, but more efficient than: * vec4 eyePosition = czm_view3D * czm_model * modelPosition; * * @see UniformState#modelView3D * @see czm_modelView */ czm_modelView3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelView3D; } }), /** * An automatic GLSL uniform representing a 4x4 model-view transformation matrix that * transforms model coordinates, relative to the eye, to eye coordinates. This is used * in conjunction with {@link czm_translateRelativeToEye}. * * @example * // GLSL declaration * uniform mat4 czm_modelViewRelativeToEye; * * // Example * attribute vec3 positionHigh; * attribute vec3 positionLow; * * void main() * { * vec4 p = czm_translateRelativeToEye(positionHigh, positionLow); * gl_Position = czm_projection * (czm_modelViewRelativeToEye * p); * } * * @see czm_modelViewProjectionRelativeToEye * @see czm_translateRelativeToEye * @see EncodedCartesian3 */ czm_modelViewRelativeToEye: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelViewRelativeToEye; } }), /** * An automatic GLSL uniform representing a 4x4 transformation matrix that * transforms from eye coordinates to model coordinates. * * @example * // GLSL declaration * uniform mat4 czm_inverseModelView; * * // Example * vec4 modelPosition = czm_inverseModelView * eyePosition; * * @see UniformState#inverseModelView * @see czm_modelView */ czm_inverseModelView: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseModelView; } }), /** * An automatic GLSL uniform representing a 4x4 transformation matrix that * transforms from eye coordinates to 3D model coordinates. In 3D mode, this is identical to * {@link czm_inverseModelView}, but in 2D and Columbus View it represents the inverse model-view matrix * as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat4 czm_inverseModelView3D; * * // Example * vec4 modelPosition = czm_inverseModelView3D * eyePosition; * * @see UniformState#inverseModelView * @see czm_inverseModelView * @see czm_modelView3D */ czm_inverseModelView3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseModelView3D; } }), /** * An automatic GLSL uniform representing a 4x4 view-projection transformation matrix that * transforms world coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_viewProjection; * * // Example * vec4 gl_Position = czm_viewProjection * czm_model * modelPosition; * * // The above is equivalent to, but more efficient than: * gl_Position = czm_projection * czm_view * czm_model * modelPosition; * * @see UniformState#viewProjection * @see czm_view * @see czm_projection * @see czm_modelViewProjection * @see czm_inverseViewProjection */ czm_viewProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.viewProjection; } }), /** * An automatic GLSL uniform representing a 4x4 view-projection transformation matrix that * transforms clip coordinates to world coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_inverseViewProjection; * * // Example * vec4 worldPosition = czm_inverseViewProjection * clipPosition; * * @see UniformState#inverseViewProjection * @see czm_viewProjection */ czm_inverseViewProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseViewProjection; } }), /** * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that * transforms model coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_modelViewProjection; * * // Example * vec4 gl_Position = czm_modelViewProjection * modelPosition; * * // The above is equivalent to, but more efficient than: * gl_Position = czm_projection * czm_view * czm_model * modelPosition; * * @see UniformState#modelViewProjection * @see czm_model * @see czm_view * @see czm_projection * @see czm_modelView * @see czm_viewProjection * @see czm_modelViewInfiniteProjection * @see czm_inverseModelViewProjection */ czm_modelViewProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelViewProjection; } }), /** * An automatic GLSL uniform representing a 4x4 inverse model-view-projection transformation matrix that * transforms clip coordinates to model coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. * * @example * // GLSL declaration * uniform mat4 czm_inverseModelViewProjection; * * // Example * vec4 modelPosition = czm_inverseModelViewProjection * clipPosition; * * @see UniformState#modelViewProjection * @see czm_modelViewProjection */ czm_inverseModelViewProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.inverseModelViewProjection; } }), /** * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that * transforms model coordinates, relative to the eye, to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. This is used in * conjunction with {@link czm_translateRelativeToEye}. * * @example * // GLSL declaration * uniform mat4 czm_modelViewProjectionRelativeToEye; * * // Example * attribute vec3 positionHigh; * attribute vec3 positionLow; * * void main() * { * vec4 p = czm_translateRelativeToEye(positionHigh, positionLow); * gl_Position = czm_modelViewProjectionRelativeToEye * p; * } * * @see czm_modelViewRelativeToEye * @see czm_translateRelativeToEye * @see EncodedCartesian3 */ czm_modelViewProjectionRelativeToEye: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelViewProjectionRelativeToEye; } }), /** * An automatic GLSL uniform representing a 4x4 model-view-projection transformation matrix that * transforms model coordinates to clip coordinates. Clip coordinates is the * coordinate system for a vertex shader's gl_Position output. The projection matrix places * the far plane at infinity. This is useful in algorithms like shadow volumes and GPU ray casting with * proxy geometry to ensure that triangles are not clipped by the far plane. * * @example * // GLSL declaration * uniform mat4 czm_modelViewInfiniteProjection; * * // Example * vec4 gl_Position = czm_modelViewInfiniteProjection * modelPosition; * * // The above is equivalent to, but more efficient than: * gl_Position = czm_infiniteProjection * czm_view * czm_model * modelPosition; * * @see UniformState#modelViewInfiniteProjection * @see czm_model * @see czm_view * @see czm_infiniteProjection * @see czm_modelViewProjection */ czm_modelViewInfiniteProjection: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelViewInfiniteProjection; } }), /** * An automatic GLSL uniform that indicates if the current camera is orthographic in 3D. * * @see UniformState#orthographicIn3D */ czm_orthographicIn3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.orthographicIn3D ? 1 : 0; } }), /** * An automatic GLSL uniform representing a 3x3 normal transformation matrix that * transforms normal vectors in model coordinates to eye coordinates. *

* Positions should be transformed to eye coordinates using {@link czm_modelView} and * normals should be transformed using czm_normal. * * @example * // GLSL declaration * uniform mat3 czm_normal; * * // Example * vec3 eyeNormal = czm_normal * normal; * * @see UniformState#normal * @see czm_inverseNormal * @see czm_modelView */ czm_normal: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.normal; } }), /** * An automatic GLSL uniform representing a 3x3 normal transformation matrix that * transforms normal vectors in 3D model coordinates to eye coordinates. * In 3D mode, this is identical to * {@link czm_normal}, but in 2D and Columbus View it represents the normal transformation * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. *

* Positions should be transformed to eye coordinates using {@link czm_modelView3D} and * normals should be transformed using czm_normal3D. * * @example * // GLSL declaration * uniform mat3 czm_normal3D; * * // Example * vec3 eyeNormal = czm_normal3D * normal; * * @see UniformState#normal3D * @see czm_normal */ czm_normal3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.normal3D; } }), /** * An automatic GLSL uniform representing a 3x3 normal transformation matrix that * transforms normal vectors in eye coordinates to model coordinates. This is * the opposite of the transform provided by {@link czm_normal}. * * @example * // GLSL declaration * uniform mat3 czm_inverseNormal; * * // Example * vec3 normalMC = czm_inverseNormal * normalEC; * * @see UniformState#inverseNormal * @see czm_normal * @see czm_modelView * @see czm_inverseView */ czm_inverseNormal: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.inverseNormal; } }), /** * An automatic GLSL uniform representing a 3x3 normal transformation matrix that * transforms normal vectors in eye coordinates to 3D model coordinates. This is * the opposite of the transform provided by {@link czm_normal}. * In 3D mode, this is identical to * {@link czm_inverseNormal}, but in 2D and Columbus View it represents the inverse normal transformation * matrix as if the camera were at an equivalent location in 3D mode. This is useful for lighting * 2D and Columbus View in the same way that 3D is lit. * * @example * // GLSL declaration * uniform mat3 czm_inverseNormal3D; * * // Example * vec3 normalMC = czm_inverseNormal3D * normalEC; * * @see UniformState#inverseNormal3D * @see czm_inverseNormal */ czm_inverseNormal3D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.inverseNormal3D; } }), /** * An automatic GLSL uniform containing the height in meters of the * eye (camera) above or below the ellipsoid. * * @see UniformState#eyeHeight */ czm_eyeHeight: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.eyeHeight; } }), /** * An automatic GLSL uniform containing height (x) and height squared (y) * in meters of the eye (camera) above the 2D world plane. This uniform is only valid * when the {@link SceneMode} is SCENE2D. * * @see UniformState#eyeHeight2D */ czm_eyeHeight2D: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC2, getValue: function(uniformState) { return uniformState.eyeHeight2D; } }), /** * An automatic GLSL uniform containing the ellipsoid surface normal * at the position below the eye (camera), in eye coordinates. * This uniform is only valid when the {@link SceneMode} is SCENE3D. */ czm_eyeEllipsoidNormalEC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.eyeEllipsoidNormalEC; } }), /** * An automatic GLSL uniform containing the ellipsoid radii of curvature at the camera position. * The .x component is the prime vertical radius of curvature (east-west direction) * .y is the meridional radius of curvature (north-south direction) * This uniform is only valid when the {@link SceneMode} is SCENE3D. */ czm_eyeEllipsoidCurvature: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC2, getValue: function(uniformState) { return uniformState.eyeEllipsoidCurvature; } }), /** * An automatic GLSL uniform containing the transform from model coordinates * to an east-north-up coordinate system centered at the position on the * ellipsoid below the camera. * This uniform is only valid when the {@link SceneMode} is SCENE3D. */ czm_modelToEnu: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.modelToEnu; } }), /** * An automatic GLSL uniform containing the the inverse of * {@link AutomaticUniforms.czm_modelToEnu}. * This uniform is only valid when the {@link SceneMode} is SCENE3D. */ czm_enuToModel: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT4, getValue: function(uniformState) { return uniformState.enuToModel; } }), /** * An automatic GLSL uniform containing the near distance (x) and the far distance (y) * of the frustum defined by the camera. This is the largest possible frustum, not an individual * frustum used for multi-frustum rendering. * * @example * // GLSL declaration * uniform vec2 czm_entireFrustum; * * // Example * float frustumLength = czm_entireFrustum.y - czm_entireFrustum.x; * * @see UniformState#entireFrustum * @see czm_currentFrustum */ czm_entireFrustum: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC2, getValue: function(uniformState) { return uniformState.entireFrustum; } }), /** * An automatic GLSL uniform containing the near distance (x) and the far distance (y) * of the frustum defined by the camera. This is the individual * frustum used for multi-frustum rendering. * * @example * // GLSL declaration * uniform vec2 czm_currentFrustum; * * // Example * float frustumLength = czm_currentFrustum.y - czm_currentFrustum.x; * * @see UniformState#currentFrustum * @see czm_entireFrustum */ czm_currentFrustum: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC2, getValue: function(uniformState) { return uniformState.currentFrustum; } }), /** * The distances to the frustum planes. The top, bottom, left and right distances are * the x, y, z, and w components, respectively. */ czm_frustumPlanes: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC4, getValue: function(uniformState) { return uniformState.frustumPlanes; } }), /** * Gets the far plane's distance from the near plane, plus 1.0. */ czm_farDepthFromNearPlusOne: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.farDepthFromNearPlusOne; } }), /** * Gets the log2 of {@link AutomaticUniforms#czm_farDepthFromNearPlusOne}. */ czm_log2FarDepthFromNearPlusOne: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.log2FarDepthFromNearPlusOne; } }), /** * Gets 1.0 divided by {@link AutomaticUniforms#czm_log2FarDepthFromNearPlusOne}. */ czm_oneOverLog2FarDepthFromNearPlusOne: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.oneOverLog2FarDepthFromNearPlusOne; } }), /** * An automatic GLSL uniform representing the sun position in world coordinates. * * @example * // GLSL declaration * uniform vec3 czm_sunPositionWC; * * @see UniformState#sunPositionWC * @see czm_sunPositionColumbusView * @see czm_sunDirectionWC */ czm_sunPositionWC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.sunPositionWC; } }), /** * An automatic GLSL uniform representing the sun position in Columbus view world coordinates. * * @example * // GLSL declaration * uniform vec3 czm_sunPositionColumbusView; * * @see UniformState#sunPositionColumbusView * @see czm_sunPositionWC */ czm_sunPositionColumbusView: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.sunPositionColumbusView; } }), /** * An automatic GLSL uniform representing the normalized direction to the sun in eye coordinates. * * @example * // GLSL declaration * uniform vec3 czm_sunDirectionEC; * * // Example * float diffuse = max(dot(czm_sunDirectionEC, normalEC), 0.0); * * @see UniformState#sunDirectionEC * @see czm_moonDirectionEC * @see czm_sunDirectionWC */ czm_sunDirectionEC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.sunDirectionEC; } }), /** * An automatic GLSL uniform representing the normalized direction to the sun in world coordinates. * * @example * // GLSL declaration * uniform vec3 czm_sunDirectionWC; * * // Example * float diffuse = max(dot(czm_sunDirectionWC, normalWC), 0.0); * * @see UniformState#sunDirectionWC * @see czm_sunPositionWC * @see czm_sunDirectionEC */ czm_sunDirectionWC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.sunDirectionWC; } }), /** * An automatic GLSL uniform representing the normalized direction to the moon in eye coordinates. * * @example * // GLSL declaration * uniform vec3 czm_moonDirectionEC; * * // Example * float diffuse = max(dot(czm_moonDirectionEC, normalEC), 0.0); * * @see UniformState#moonDirectionEC * @see czm_sunDirectionEC */ czm_moonDirectionEC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.moonDirectionEC; } }), /** * An automatic GLSL uniform representing the normalized direction to the scene's light source in eye coordinates. * This is commonly used for directional lighting computations. * * @example * // GLSL declaration * uniform vec3 czm_lightDirectionEC; * * // Example * float diffuse = max(dot(czm_lightDirectionEC, normalEC), 0.0); * * @see UniformState#lightDirectionEC * @see czm_lightDirectionWC */ czm_lightDirectionEC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.lightDirectionEC; } }), /** * An automatic GLSL uniform representing the normalized direction to the scene's light source in world coordinates. * This is commonly used for directional lighting computations. * * @example * // GLSL declaration * uniform vec3 czm_lightDirectionWC; * * // Example * float diffuse = max(dot(czm_lightDirectionWC, normalWC), 0.0); * * @see UniformState#lightDirectionWC * @see czm_lightDirectionEC */ czm_lightDirectionWC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.lightDirectionWC; } }), /** * An automatic GLSL uniform that represents the color of light emitted by the scene's light source. This * is equivalent to the light color multiplied by the light intensity limited to a maximum luminance of 1.0 * suitable for non-HDR lighting. * * @example * // GLSL declaration * uniform vec3 czm_lightColor; * * // Example * vec3 diffuseColor = czm_lightColor * max(dot(czm_lightDirectionWC, normalWC), 0.0); * * @see UniformState#lightColor * @see czm_lightColorHdr */ czm_lightColor: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.lightColor; } }), /** * An automatic GLSL uniform that represents the high dynamic range color of light emitted by the scene's light * source. This is equivalent to the light color multiplied by the light intensity suitable for HDR lighting. * * @example * // GLSL declaration * uniform vec3 czm_lightColorHdr; * * // Example * vec3 diffuseColor = czm_lightColorHdr * max(dot(czm_lightDirectionWC, normalWC), 0.0); * * @see UniformState#lightColorHdr * @see czm_lightColor */ czm_lightColorHdr: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.lightColorHdr; } }), /** * An automatic GLSL uniform representing the high bits of the camera position in model * coordinates. This is used for GPU RTE to eliminate jittering artifacts when rendering * as described in {@link http://help.agi.com/AGIComponents/html/BlogPrecisionsPrecisions.htm|Precisions, Precisions}. * * @example * // GLSL declaration * uniform vec3 czm_encodedCameraPositionMCHigh; * * @see czm_encodedCameraPositionMCLow * @see czm_modelViewRelativeToEye * @see czm_modelViewProjectionRelativeToEye */ czm_encodedCameraPositionMCHigh: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.encodedCameraPositionMCHigh; } }), /** * An automatic GLSL uniform representing the low bits of the camera position in model * coordinates. This is used for GPU RTE to eliminate jittering artifacts when rendering * as described in {@linkhttp://help.agi.com/AGIComponents/html/BlogPrecisionsPrecisions.htm|Precisions, Precisions}. * * @example * // GLSL declaration * uniform vec3 czm_encodedCameraPositionMCLow; * * @see czm_encodedCameraPositionMCHigh * @see czm_modelViewRelativeToEye * @see czm_modelViewProjectionRelativeToEye */ czm_encodedCameraPositionMCLow: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.encodedCameraPositionMCLow; } }), /** * An automatic GLSL uniform representing the position of the viewer (camera) in world coordinates. * * @example * // GLSL declaration * uniform vec3 czm_viewerPositionWC; */ czm_viewerPositionWC: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return Matrix4_default.getTranslation( uniformState.inverseView, viewerPositionWCScratch ); } }), /** * An automatic GLSL uniform representing the frame number. This uniform is automatically incremented * every frame. * * @example * // GLSL declaration * uniform float czm_frameNumber; */ czm_frameNumber: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.frameState.frameNumber; } }), /** * An automatic GLSL uniform representing the current morph transition time between * 2D/Columbus View and 3D, with 0.0 being 2D or Columbus View and 1.0 being 3D. * * @example * // GLSL declaration * uniform float czm_morphTime; * * // Example * vec4 p = czm_columbusViewMorph(position2D, position3D, czm_morphTime); */ czm_morphTime: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.frameState.morphTime; } }), /** * An automatic GLSL uniform representing the current {@link SceneMode}, expressed * as a float. * * @example * // GLSL declaration * uniform float czm_sceneMode; * * // Example * if (czm_sceneMode == czm_sceneMode2D) * { * eyeHeightSq = czm_eyeHeight2D.y; * } * * @see czm_sceneMode2D * @see czm_sceneModeColumbusView * @see czm_sceneMode3D * @see czm_sceneModeMorphing */ czm_sceneMode: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.frameState.mode; } }), /** * An automatic GLSL uniform representing the current rendering pass. * * @example * // GLSL declaration * uniform float czm_pass; * * // Example * if ((czm_pass == czm_passTranslucent) && isOpaque()) * { * gl_Position *= 0.0; // Cull opaque geometry in the translucent pass * } */ czm_pass: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.pass; } }), /** * An automatic GLSL uniform representing the current scene background color. * * @example * // GLSL declaration * uniform vec4 czm_backgroundColor; * * // Example: If the given color's RGB matches the background color, invert it. * vec4 adjustColorForContrast(vec4 color) * { * if (czm_backgroundColor.rgb == color.rgb) * { * color.rgb = vec3(1.0) - color.rgb; * } * * return color; * } */ czm_backgroundColor: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC4, getValue: function(uniformState) { return uniformState.backgroundColor; } }), /** * An automatic GLSL uniform containing the BRDF look up texture used for image-based lighting computations. * * @example * // GLSL declaration * uniform sampler2D czm_brdfLut; * * // Example: For a given roughness and NdotV value, find the material's BRDF information in the red and green channels * float roughness = 0.5; * float NdotV = dot(normal, view); * vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg; */ czm_brdfLut: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_2D, getValue: function(uniformState) { return uniformState.brdfLut; } }), /** * An automatic GLSL uniform containing the environment map used within the scene. * * @example * // GLSL declaration * uniform samplerCube czm_environmentMap; * * // Example: Create a perfect reflection of the environment map on a model * float reflected = reflect(view, normal); * vec4 reflectedColor = texture(czm_environmentMap, reflected); */ czm_environmentMap: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_CUBE, getValue: function(uniformState) { return uniformState.environmentMap; } }), /** * An automatic GLSL uniform containing the specular environment cube map used within the scene. * * @example * // GLSL declaration * uniform samplerCube czm_specularEnvironmentMaps; */ czm_specularEnvironmentMaps: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.SAMPLER_CUBE, getValue: function(uniformState) { return uniformState.specularEnvironmentMaps; } }), /** * An automatic GLSL uniform containing the maximum valid level-of-detail of the specular environment cube map used within the scene. * * @example * // GLSL declaration * uniform float czm_specularEnvironmentMapsMaximumLOD; */ czm_specularEnvironmentMapsMaximumLOD: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.specularEnvironmentMapsMaximumLOD; } }), /** * An automatic GLSL uniform containing the spherical harmonic coefficients used within the scene. * * @example * // GLSL declaration * uniform vec3[9] czm_sphericalHarmonicCoefficients; */ czm_sphericalHarmonicCoefficients: new AutomaticUniform({ size: 9, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.sphericalHarmonicCoefficients; } }), /** * An automatic GLSL uniform representing a 3x3 rotation matrix that transforms * from True Equator Mean Equinox (TEME) axes to the pseudo-fixed axes at the current scene time. * * @example * // GLSL declaration * uniform mat3 czm_temeToPseudoFixed; * * // Example * vec3 pseudoFixed = czm_temeToPseudoFixed * teme; * * @see UniformState#temeToPseudoFixedMatrix * @see Transforms.computeTemeToPseudoFixedMatrix */ czm_temeToPseudoFixed: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_MAT3, getValue: function(uniformState) { return uniformState.temeToPseudoFixedMatrix; } }), /** * An automatic GLSL uniform representing the ratio of canvas coordinate space to canvas pixel space. * * @example * uniform float czm_pixelRatio; */ czm_pixelRatio: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.pixelRatio; } }), /** * An automatic GLSL uniform scalar used to mix a color with the fog color based on the distance to the camera. * * @see czm_fog */ czm_fogDensity: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.fogDensity; } }), /** * An automatic GLSL uniform scalar used to mix a color with the fog color based on the distance to the camera. * * @see czm_fog */ czm_fogVisualDensityScalar: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.fogVisualDensityScalar; } }), /** * An automatic GLSL uniform scalar used to set a minimum brightness when dynamic lighting is applied to fog. * * @see czm_fog */ czm_fogMinimumBrightness: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.fogMinimumBrightness; } }), /** * An automatic uniform representing the color shift for the atmosphere in HSB color space * * @example * uniform vec3 czm_atmosphereHsbShift; */ czm_atmosphereHsbShift: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.atmosphereHsbShift; } }), /** * An automatic uniform representing the intensity of the light that is used for computing the atmosphere color * * @example * uniform float czm_atmosphereLightIntensity; */ czm_atmosphereLightIntensity: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.atmosphereLightIntensity; } }), /** * An automatic uniform representing the Rayleigh scattering coefficient used when computing the atmosphere scattering * * @example * uniform vec3 czm_atmosphereRayleighCoefficient; */ czm_atmosphereRayleighCoefficient: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.atmosphereRayleighCoefficient; } }), /** * An automatic uniform representing the Rayleigh scale height in meters used for computing atmosphere scattering. * * @example * uniform vec3 czm_atmosphereRayleighScaleHeight; */ czm_atmosphereRayleighScaleHeight: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.atmosphereRayleighScaleHeight; } }), /** * An automatic uniform representing the Mie scattering coefficient used when computing atmosphere scattering. * * @example * uniform vec3 czm_atmosphereMieCoefficient; */ czm_atmosphereMieCoefficient: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.atmosphereMieCoefficient; } }), /** * An automatic uniform storign the Mie scale height used when computing atmosphere scattering. * * @example * uniform float czm_atmosphereMieScaleHeight; */ czm_atmosphereMieScaleHeight: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.atmosphereMieScaleHeight; } }), /** * An automatic uniform representing the anisotropy of the medium to consider for Mie scattering. * * @example * uniform float czm_atmosphereAnisotropy; */ czm_atmosphereMieAnisotropy: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.atmosphereMieAnisotropy; } }), /** * An automatic uniform representing which light source to use for dynamic lighting * * @example * uniform float czm_atmosphereDynamicLighting */ czm_atmosphereDynamicLighting: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.atmosphereDynamicLighting; } }), /** * An automatic GLSL uniform representing the splitter position to use when rendering with a splitter. * This will be in pixel coordinates relative to the canvas. * * @example * // GLSL declaration * uniform float czm_splitPosition; */ czm_splitPosition: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.splitPosition; } }), /** * An automatic GLSL uniform scalar representing the geometric tolerance per meter */ czm_geometricToleranceOverMeter: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.geometricToleranceOverMeter; } }), /** * An automatic GLSL uniform representing the distance from the camera at which to disable the depth test of billboards, labels and points * to, for example, prevent clipping against terrain. When set to zero, the depth test should always be applied. When less than zero, * the depth test should never be applied. */ czm_minimumDisableDepthTestDistance: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.minimumDisableDepthTestDistance; } }), /** * An automatic GLSL uniform that will be the highlight color of unclassified 3D Tiles. */ czm_invertClassificationColor: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC4, getValue: function(uniformState) { return uniformState.invertClassificationColor; } }), /** * An automatic GLSL uniform that is used for gamma correction. */ czm_gamma: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT, getValue: function(uniformState) { return uniformState.gamma; } }), /** * An automatic GLSL uniform that stores the ellipsoid radii. */ czm_ellipsoidRadii: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.ellipsoid.radii; } }), /** * An automatic GLSL uniform that stores the ellipsoid inverse radii. */ czm_ellipsoidInverseRadii: new AutomaticUniform({ size: 1, datatype: WebGLConstants_default.FLOAT_VEC3, getValue: function(uniformState) { return uniformState.ellipsoid.oneOverRadii; } }) }; var AutomaticUniforms_default = AutomaticUniforms; // packages/engine/Source/Renderer/Buffer.js var import_InlineWorkers17 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/createGuid.js var import_InlineWorkers13 = __toESM(require_InlineWorkers(), 1); function createGuid() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c14) { const r2 = Math.random() * 16 | 0; const v3 = c14 === "x" ? r2 : r2 & 3 | 8; return v3.toString(16); }); } var createGuid_default = createGuid; // packages/engine/Source/Core/destroyObject.js var import_InlineWorkers14 = __toESM(require_InlineWorkers(), 1); function returnTrue() { return true; } function destroyObject(object2, message) { message = message ?? "This object was destroyed, i.e., destroy() was called."; function throwOnDestroyed() { throw new DeveloperError_default(message); } for (const key in object2) { if (typeof object2[key] === "function") { object2[key] = throwOnDestroyed; } } object2.isDestroyed = returnTrue; return void 0; } var destroyObject_default = destroyObject; // packages/engine/Source/Core/IndexDatatype.js var import_InlineWorkers15 = __toESM(require_InlineWorkers(), 1); var IndexDatatype = { /** * 8-bit unsigned byte corresponding to UNSIGNED_BYTE and the type * of an element in Uint8Array. * * @type {number} * @constant */ UNSIGNED_BYTE: WebGLConstants_default.UNSIGNED_BYTE, /** * 16-bit unsigned short corresponding to UNSIGNED_SHORT and the type * of an element in Uint16Array. * * @type {number} * @constant */ UNSIGNED_SHORT: WebGLConstants_default.UNSIGNED_SHORT, /** * 32-bit unsigned int corresponding to UNSIGNED_INT and the type * of an element in Uint32Array. * * @type {number} * @constant */ UNSIGNED_INT: WebGLConstants_default.UNSIGNED_INT }; IndexDatatype.getSizeInBytes = function(indexDatatype) { switch (indexDatatype) { case IndexDatatype.UNSIGNED_BYTE: return Uint8Array.BYTES_PER_ELEMENT; case IndexDatatype.UNSIGNED_SHORT: return Uint16Array.BYTES_PER_ELEMENT; case IndexDatatype.UNSIGNED_INT: return Uint32Array.BYTES_PER_ELEMENT; } throw new DeveloperError_default( "indexDatatype is required and must be a valid IndexDatatype constant." ); }; IndexDatatype.fromSizeInBytes = function(sizeInBytes) { switch (sizeInBytes) { case 2: return IndexDatatype.UNSIGNED_SHORT; case 4: return IndexDatatype.UNSIGNED_INT; case 1: return IndexDatatype.UNSIGNED_BYTE; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default( "Size in bytes cannot be mapped to an IndexDatatype" ); } }; IndexDatatype.validate = function(indexDatatype) { return defined_default(indexDatatype) && (indexDatatype === IndexDatatype.UNSIGNED_BYTE || indexDatatype === IndexDatatype.UNSIGNED_SHORT || indexDatatype === IndexDatatype.UNSIGNED_INT); }; IndexDatatype.createTypedArray = function(numberOfVertices, indicesLengthOrArray) { if (!defined_default(numberOfVertices)) { throw new DeveloperError_default("numberOfVertices is required."); } if (numberOfVertices >= Math_default.SIXTY_FOUR_KILOBYTES) { return new Uint32Array(indicesLengthOrArray); } return new Uint16Array(indicesLengthOrArray); }; IndexDatatype.createTypedArrayFromArrayBuffer = function(numberOfVertices, sourceArray, byteOffset, length2) { if (!defined_default(numberOfVertices)) { throw new DeveloperError_default("numberOfVertices is required."); } if (!defined_default(sourceArray)) { throw new DeveloperError_default("sourceArray is required."); } if (!defined_default(byteOffset)) { throw new DeveloperError_default("byteOffset is required."); } if (numberOfVertices >= Math_default.SIXTY_FOUR_KILOBYTES) { return new Uint32Array(sourceArray, byteOffset, length2); } return new Uint16Array(sourceArray, byteOffset, length2); }; IndexDatatype.fromTypedArray = function(array) { if (array instanceof Uint8Array) { return IndexDatatype.UNSIGNED_BYTE; } if (array instanceof Uint16Array) { return IndexDatatype.UNSIGNED_SHORT; } if (array instanceof Uint32Array) { return IndexDatatype.UNSIGNED_INT; } throw new DeveloperError_default( "array must be a Uint8Array, Uint16Array, or Uint32Array." ); }; Object.freeze(IndexDatatype); var IndexDatatype_default = IndexDatatype; // packages/engine/Source/Renderer/BufferUsage.js var import_InlineWorkers16 = __toESM(require_InlineWorkers(), 1); var BufferUsage = { STREAM_DRAW: WebGLConstants_default.STREAM_DRAW, STATIC_DRAW: WebGLConstants_default.STATIC_DRAW, DYNAMIC_DRAW: WebGLConstants_default.DYNAMIC_DRAW, DYNAMIC_READ: WebGLConstants_default.DYNAMIC_READ }; BufferUsage.validate = function(bufferUsage) { return bufferUsage === BufferUsage.STREAM_DRAW || bufferUsage === BufferUsage.STATIC_DRAW || bufferUsage === BufferUsage.DYNAMIC_DRAW || bufferUsage === BufferUsage.DYNAMIC_READ; }; Object.freeze(BufferUsage); var BufferUsage_default = BufferUsage; // packages/engine/Source/Renderer/Buffer.js function Buffer2(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); if (!defined_default(options.typedArray) && !defined_default(options.sizeInBytes)) { throw new DeveloperError_default( "Either options.sizeInBytes or options.typedArray is required." ); } if (defined_default(options.typedArray) && defined_default(options.sizeInBytes)) { throw new DeveloperError_default( "Cannot pass in both options.sizeInBytes and options.typedArray." ); } if (defined_default(options.typedArray)) { Check_default.typeOf.object("options.typedArray", options.typedArray); Check_default.typeOf.number( "options.typedArray.byteLength", options.typedArray.byteLength ); } if (!BufferUsage_default.validate(options.usage)) { throw new DeveloperError_default("usage is invalid."); } const gl = options.context._gl; const bufferTarget = options.bufferTarget; const typedArray = options.typedArray; let sizeInBytes = options.sizeInBytes; const usage = options.usage; const hasArray = defined_default(typedArray); if (hasArray) { sizeInBytes = typedArray.byteLength; } Check_default.typeOf.number.greaterThan("sizeInBytes", sizeInBytes, 0); const buffer2 = gl.createBuffer(); gl.bindBuffer(bufferTarget, buffer2); gl.bufferData(bufferTarget, hasArray ? typedArray : sizeInBytes, usage); gl.bindBuffer(bufferTarget, null); this._id = createGuid_default(); this._gl = gl; this._webgl2 = options.context._webgl2; this._bufferTarget = bufferTarget; this._sizeInBytes = sizeInBytes; this._usage = usage; this._buffer = buffer2; this.vertexArrayDestroyable = true; } Buffer2.createPixelBuffer = function(options) { Check_default.defined("options.context", options.context); if (!options.context._webgl2) { throw new DeveloperError_default( "A WebGL 2 context is required to create PixelBuffers." ); } return new Buffer2({ context: options.context, bufferTarget: WebGLConstants_default.PIXEL_PACK_BUFFER, typedArray: options.typedArray, sizeInBytes: options.sizeInBytes, usage: options.usage }); }; Buffer2.createVertexBuffer = function(options) { Check_default.defined("options.context", options.context); return new Buffer2({ context: options.context, bufferTarget: WebGLConstants_default.ARRAY_BUFFER, typedArray: options.typedArray, sizeInBytes: options.sizeInBytes, usage: options.usage }); }; Buffer2.createIndexBuffer = function(options) { Check_default.defined("options.context", options.context); if (!IndexDatatype_default.validate(options.indexDatatype)) { throw new DeveloperError_default("Invalid indexDatatype."); } if (options.indexDatatype === IndexDatatype_default.UNSIGNED_INT && !options.context.elementIndexUint) { throw new DeveloperError_default( "IndexDatatype.UNSIGNED_INT requires OES_element_index_uint, which is not supported on this system. Check context.elementIndexUint." ); } const context = options.context; const indexDatatype = options.indexDatatype; const bytesPerIndex = IndexDatatype_default.getSizeInBytes(indexDatatype); const buffer2 = new Buffer2({ context, bufferTarget: WebGLConstants_default.ELEMENT_ARRAY_BUFFER, typedArray: options.typedArray, sizeInBytes: options.sizeInBytes, usage: options.usage }); const numberOfIndices = buffer2.sizeInBytes / bytesPerIndex; Object.defineProperties(buffer2, { indexDatatype: { get: function() { return indexDatatype; } }, bytesPerIndex: { get: function() { return bytesPerIndex; } }, numberOfIndices: { get: function() { return numberOfIndices; } } }); return buffer2; }; Object.defineProperties(Buffer2.prototype, { sizeInBytes: { get: function() { return this._sizeInBytes; } }, usage: { get: function() { return this._usage; } } }); Buffer2.prototype._getBuffer = function() { return this._buffer; }; Buffer2.prototype._bind = function() { const gl = this._gl; const target = this._bufferTarget; gl.bindBuffer(target, this._buffer); }; Buffer2.prototype._unBind = function() { const gl = this._gl; const target = this._bufferTarget; gl.bindBuffer(target, null); }; Buffer2.prototype.copyFromArrayView = function(arrayView, offsetInBytes) { offsetInBytes = offsetInBytes ?? 0; Check_default.defined("arrayView", arrayView); Check_default.typeOf.number.lessThanOrEquals( "offsetInBytes + arrayView.byteLength", offsetInBytes + arrayView.byteLength, this._sizeInBytes ); const gl = this._gl; const target = this._bufferTarget; gl.bindBuffer(target, this._buffer); gl.bufferSubData(target, offsetInBytes, arrayView); gl.bindBuffer(target, null); }; Buffer2.prototype.copyFromBuffer = function(readBuffer, readOffset, writeOffset, sizeInBytes) { if (!this._webgl2) { throw new DeveloperError_default("A WebGL 2 context is required."); } if (!defined_default(readBuffer)) { throw new DeveloperError_default("readBuffer must be defined."); } if (!defined_default(sizeInBytes) || sizeInBytes <= 0) { throw new DeveloperError_default( "sizeInBytes must be defined and be greater than zero." ); } if (!defined_default(readOffset) || readOffset < 0 || readOffset + sizeInBytes > readBuffer._sizeInBytes) { throw new DeveloperError_default( "readOffset must be greater than or equal to zero and readOffset + sizeInBytes must be less than of equal to readBuffer.sizeInBytes." ); } if (!defined_default(writeOffset) || writeOffset < 0 || writeOffset + sizeInBytes > this._sizeInBytes) { throw new DeveloperError_default( "writeOffset must be greater than or equal to zero and writeOffset + sizeInBytes must be less than of equal to this.sizeInBytes." ); } if (this._buffer === readBuffer._buffer && (writeOffset >= readOffset && writeOffset < readOffset + sizeInBytes || readOffset > writeOffset && readOffset < writeOffset + sizeInBytes)) { throw new DeveloperError_default( "When readBuffer is equal to this, the ranges [readOffset + sizeInBytes) and [writeOffset, writeOffset + sizeInBytes) must not overlap." ); } if (this._bufferTarget === WebGLConstants_default.ELEMENT_ARRAY_BUFFER && readBuffer._bufferTarget !== WebGLConstants_default.ELEMENT_ARRAY_BUFFER || this._bufferTarget !== WebGLConstants_default.ELEMENT_ARRAY_BUFFER && readBuffer._bufferTarget === WebGLConstants_default.ELEMENT_ARRAY_BUFFER) { throw new DeveloperError_default( "Can not copy an index buffer into another buffer type." ); } const readTarget = WebGLConstants_default.COPY_READ_BUFFER; const writeTarget = WebGLConstants_default.COPY_WRITE_BUFFER; const gl = this._gl; gl.bindBuffer(writeTarget, this._buffer); gl.bindBuffer(readTarget, readBuffer._buffer); gl.copyBufferSubData( readTarget, writeTarget, readOffset, writeOffset, sizeInBytes ); gl.bindBuffer(writeTarget, null); gl.bindBuffer(readTarget, null); }; Buffer2.prototype.getBufferData = function(arrayView, sourceOffset, destinationOffset, length2) { sourceOffset = sourceOffset ?? 0; destinationOffset = destinationOffset ?? 0; if (!this._webgl2) { throw new DeveloperError_default("A WebGL 2 context is required."); } if (!defined_default(arrayView)) { throw new DeveloperError_default("arrayView is required."); } let copyLength; let elementSize; let arrayLength = arrayView.byteLength; if (!defined_default(length2)) { if (defined_default(arrayLength)) { copyLength = arrayLength - destinationOffset; elementSize = 1; } else { arrayLength = arrayView.length; copyLength = arrayLength - destinationOffset; elementSize = arrayView.BYTES_PER_ELEMENT; } } else { copyLength = length2; if (defined_default(arrayLength)) { elementSize = 1; } else { arrayLength = arrayView.length; elementSize = arrayView.BYTES_PER_ELEMENT; } } if (destinationOffset < 0 || destinationOffset > arrayLength) { throw new DeveloperError_default( "destinationOffset must be greater than zero and less than the arrayView length." ); } if (destinationOffset + copyLength > arrayLength) { throw new DeveloperError_default( "destinationOffset + length must be less than or equal to the arrayViewLength." ); } if (sourceOffset < 0 || sourceOffset > this._sizeInBytes) { throw new DeveloperError_default( "sourceOffset must be greater than zero and less than the buffers size." ); } if (sourceOffset + copyLength * elementSize > this._sizeInBytes) { throw new DeveloperError_default( "sourceOffset + length must be less than the buffers size." ); } const gl = this._gl; const target = WebGLConstants_default.COPY_READ_BUFFER; gl.bindBuffer(target, this._buffer); gl.getBufferSubData( target, sourceOffset, arrayView, destinationOffset, length2 ); gl.bindBuffer(target, null); }; Buffer2.prototype.isDestroyed = function() { return false; }; Buffer2.prototype.destroy = function() { this._gl.deleteBuffer(this._buffer); return destroyObject_default(this); }; var Buffer_default = Buffer2; // packages/engine/Source/Renderer/ClearCommand.js var import_InlineWorkers21 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Color.js var import_InlineWorkers20 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/FeatureDetection.js var import_InlineWorkers19 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Fullscreen.js var import_InlineWorkers18 = __toESM(require_InlineWorkers(), 1); var _supportsFullscreen; var _names = { requestFullscreen: void 0, exitFullscreen: void 0, fullscreenEnabled: void 0, fullscreenElement: void 0, fullscreenchange: void 0, fullscreenerror: void 0 }; var Fullscreen = {}; Object.defineProperties(Fullscreen, { /** * The element that is currently fullscreen, if any. To simply check if the * browser is in fullscreen mode or not, use {@link Fullscreen#fullscreen}. * @memberof Fullscreen * @type {object} * @readonly */ element: { get: function() { if (!Fullscreen.supportsFullscreen()) { return void 0; } return document[_names.fullscreenElement]; } }, /** * The name of the event on the document that is fired when fullscreen is * entered or exited. This event name is intended for use with addEventListener. * In your event handler, to determine if the browser is in fullscreen mode or not, * use {@link Fullscreen#fullscreen}. * @memberof Fullscreen * @type {string} * @readonly */ changeEventName: { get: function() { if (!Fullscreen.supportsFullscreen()) { return void 0; } return _names.fullscreenchange; } }, /** * The name of the event that is fired when a fullscreen error * occurs. This event name is intended for use with addEventListener. * @memberof Fullscreen * @type {string} * @readonly */ errorEventName: { get: function() { if (!Fullscreen.supportsFullscreen()) { return void 0; } return _names.fullscreenerror; } }, /** * Determine whether the browser will allow an element to be made fullscreen, or not. * For example, by default, iframes cannot go fullscreen unless the containing page * adds an "allowfullscreen" attribute (or prefixed equivalent). * @memberof Fullscreen * @type {boolean} * @readonly */ enabled: { get: function() { if (!Fullscreen.supportsFullscreen()) { return void 0; } return document[_names.fullscreenEnabled]; } }, /** * Determines if the browser is currently in fullscreen mode. * @memberof Fullscreen * @type {boolean} * @readonly */ fullscreen: { get: function() { if (!Fullscreen.supportsFullscreen()) { return void 0; } return Fullscreen.element !== null; } } }); Fullscreen.supportsFullscreen = function() { if (defined_default(_supportsFullscreen)) { return _supportsFullscreen; } _supportsFullscreen = false; const body = document.body; if (typeof body.requestFullscreen === "function") { _names.requestFullscreen = "requestFullscreen"; _names.exitFullscreen = "exitFullscreen"; _names.fullscreenEnabled = "fullscreenEnabled"; _names.fullscreenElement = "fullscreenElement"; _names.fullscreenchange = "fullscreenchange"; _names.fullscreenerror = "fullscreenerror"; _supportsFullscreen = true; return _supportsFullscreen; } const prefixes = ["webkit", "moz", "o", "ms", "khtml"]; let name; for (let i = 0, len = prefixes.length; i < len; ++i) { const prefix = prefixes[i]; name = `${prefix}RequestFullscreen`; if (typeof body[name] === "function") { _names.requestFullscreen = name; _supportsFullscreen = true; } else { name = `${prefix}RequestFullScreen`; if (typeof body[name] === "function") { _names.requestFullscreen = name; _supportsFullscreen = true; } } name = `${prefix}ExitFullscreen`; if (typeof document[name] === "function") { _names.exitFullscreen = name; } else { name = `${prefix}CancelFullScreen`; if (typeof document[name] === "function") { _names.exitFullscreen = name; } } name = `${prefix}FullscreenEnabled`; if (document[name] !== void 0) { _names.fullscreenEnabled = name; } else { name = `${prefix}FullScreenEnabled`; if (document[name] !== void 0) { _names.fullscreenEnabled = name; } } name = `${prefix}FullscreenElement`; if (document[name] !== void 0) { _names.fullscreenElement = name; } else { name = `${prefix}FullScreenElement`; if (document[name] !== void 0) { _names.fullscreenElement = name; } } name = `${prefix}fullscreenchange`; if (document[`on${name}`] !== void 0) { if (prefix === "ms") { name = "MSFullscreenChange"; } _names.fullscreenchange = name; } name = `${prefix}fullscreenerror`; if (document[`on${name}`] !== void 0) { if (prefix === "ms") { name = "MSFullscreenError"; } _names.fullscreenerror = name; } } return _supportsFullscreen; }; Fullscreen.requestFullscreen = function(element, vrDevice) { if (!Fullscreen.supportsFullscreen()) { return; } element[_names.requestFullscreen]({ vrDisplay: vrDevice }); }; Fullscreen.exitFullscreen = function() { if (!Fullscreen.supportsFullscreen()) { return; } document[_names.exitFullscreen](); }; Fullscreen._names = _names; var Fullscreen_default = Fullscreen; // packages/engine/Source/Core/FeatureDetection.js var theNavigator; if (typeof navigator !== "undefined") { theNavigator = navigator; } else { theNavigator = {}; } function extractVersion(versionString) { const parts = versionString.split("."); for (let i = 0, len = parts.length; i < len; ++i) { parts[i] = parseInt(parts[i], 10); } return parts; } var isChromeResult; var chromeVersionResult; function isChrome() { if (!defined_default(isChromeResult)) { isChromeResult = false; if (!isEdge()) { const fields = / Chrome\/([\.0-9]+)/.exec(theNavigator.userAgent); if (fields !== null) { isChromeResult = true; chromeVersionResult = extractVersion(fields[1]); } } } return isChromeResult; } function chromeVersion() { return isChrome() && chromeVersionResult; } var isSafariResult; var safariVersionResult; function isSafari() { if (!defined_default(isSafariResult)) { isSafariResult = false; if (!isChrome() && !isEdge() && / Safari\/[\.0-9]+/.test(theNavigator.userAgent)) { const fields = / Version\/([\.0-9]+)/.exec(theNavigator.userAgent); if (fields !== null) { isSafariResult = true; safariVersionResult = extractVersion(fields[1]); } } } return isSafariResult; } function safariVersion() { return isSafari() && safariVersionResult; } var isWebkitResult; var webkitVersionResult; function isWebkit() { if (!defined_default(isWebkitResult)) { isWebkitResult = false; const fields = / AppleWebKit\/([\.0-9]+)(\+?)/.exec(theNavigator.userAgent); if (fields !== null) { isWebkitResult = true; webkitVersionResult = extractVersion(fields[1]); webkitVersionResult.isNightly = !!fields[2]; } } return isWebkitResult; } function webkitVersion() { return isWebkit() && webkitVersionResult; } var isEdgeResult; var edgeVersionResult; function isEdge() { if (!defined_default(isEdgeResult)) { isEdgeResult = false; const fields = / Edg\/([\.0-9]+)/.exec(theNavigator.userAgent); if (fields !== null) { isEdgeResult = true; edgeVersionResult = extractVersion(fields[1]); } } return isEdgeResult; } function edgeVersion() { return isEdge() && edgeVersionResult; } var isFirefoxResult; var firefoxVersionResult; function isFirefox() { if (!defined_default(isFirefoxResult)) { isFirefoxResult = false; const fields = /Firefox\/([\.0-9]+)/.exec(theNavigator.userAgent); if (fields !== null) { isFirefoxResult = true; firefoxVersionResult = extractVersion(fields[1]); } } return isFirefoxResult; } var isWindowsResult; function isWindows() { if (!defined_default(isWindowsResult)) { isWindowsResult = /Windows/i.test(theNavigator.appVersion); } return isWindowsResult; } var isIPadOrIOSResult; function isIPadOrIOS() { if (!defined_default(isIPadOrIOSResult)) { isIPadOrIOSResult = navigator.platform === "iPhone" || navigator.platform === "iPod" || navigator.platform === "iPad"; } return isIPadOrIOSResult; } function firefoxVersion() { return isFirefox() && firefoxVersionResult; } var hasPointerEvents; function supportsPointerEvents() { if (!defined_default(hasPointerEvents)) { hasPointerEvents = !isFirefox() && typeof PointerEvent !== "undefined" && (!defined_default(theNavigator.pointerEnabled) || theNavigator.pointerEnabled); } return hasPointerEvents; } var imageRenderingValueResult; var supportsImageRenderingPixelatedResult; function supportsImageRenderingPixelated() { if (!defined_default(supportsImageRenderingPixelatedResult)) { const canvas = document.createElement("canvas"); canvas.setAttribute( "style", "image-rendering: -moz-crisp-edges;image-rendering: pixelated;" ); const tmp2 = canvas.style.imageRendering; supportsImageRenderingPixelatedResult = defined_default(tmp2) && tmp2 !== ""; if (supportsImageRenderingPixelatedResult) { imageRenderingValueResult = tmp2; } } return supportsImageRenderingPixelatedResult; } function imageRenderingValue() { return supportsImageRenderingPixelated() ? imageRenderingValueResult : void 0; } function supportsWebP() { if (!supportsWebP.initialized) { throw new DeveloperError_default( "You must call FeatureDetection.supportsWebP.initialize and wait for the promise to resolve before calling FeatureDetection.supportsWebP" ); } return supportsWebP._result; } supportsWebP._promise = void 0; supportsWebP._result = void 0; supportsWebP.initialize = function() { if (defined_default(supportsWebP._promise)) { return supportsWebP._promise; } supportsWebP._promise = new Promise((resolve2) => { const image = new Image(); image.onload = function() { supportsWebP._result = image.width > 0 && image.height > 0; resolve2(supportsWebP._result); }; image.onerror = function() { supportsWebP._result = false; resolve2(supportsWebP._result); }; image.src = "data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA"; }); return supportsWebP._promise; }; Object.defineProperties(supportsWebP, { initialized: { get: function() { return defined_default(supportsWebP._result); } } }); var typedArrayTypes = []; if (typeof ArrayBuffer !== "undefined") { typedArrayTypes.push( Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ); if (typeof Uint8ClampedArray !== "undefined") { typedArrayTypes.push(Uint8ClampedArray); } if (typeof Uint8ClampedArray !== "undefined") { typedArrayTypes.push(Uint8ClampedArray); } if (typeof BigInt64Array !== "undefined") { typedArrayTypes.push(BigInt64Array); } if (typeof BigUint64Array !== "undefined") { typedArrayTypes.push(BigUint64Array); } } var FeatureDetection = { isChrome, chromeVersion, isSafari, safariVersion, isWebkit, webkitVersion, isEdge, edgeVersion, isFirefox, firefoxVersion, isWindows, isIPadOrIOS, hardwareConcurrency: theNavigator.hardwareConcurrency ?? 3, supportsPointerEvents, supportsImageRenderingPixelated, supportsWebP, imageRenderingValue, typedArrayTypes }; FeatureDetection.supportsBasis = function(scene) { return FeatureDetection.supportsWebAssembly() && scene.context.supportsBasis; }; FeatureDetection.supportsFullscreen = function() { return Fullscreen_default.supportsFullscreen(); }; FeatureDetection.supportsTypedArrays = function() { return typeof ArrayBuffer !== "undefined"; }; FeatureDetection.supportsBigInt64Array = function() { return typeof BigInt64Array !== "undefined"; }; FeatureDetection.supportsBigUint64Array = function() { return typeof BigUint64Array !== "undefined"; }; FeatureDetection.supportsBigInt = function() { return typeof BigInt !== "undefined"; }; FeatureDetection.supportsWebWorkers = function() { return typeof Worker !== "undefined"; }; FeatureDetection.supportsWebAssembly = function() { return typeof WebAssembly !== "undefined"; }; FeatureDetection.supportsWebgl2 = function(scene) { Check_default.defined("scene", scene); return scene.context.webgl2; }; FeatureDetection.supportsEsmWebWorkers = function() { return !isFirefox() || parseInt(firefoxVersionResult) >= 114; }; var FeatureDetection_default = FeatureDetection; // packages/engine/Source/Core/Color.js function hue2rgb(m1, m2, h) { if (h < 0) { h += 1; } if (h > 1) { h -= 1; } if (h * 6 < 1) { return m1 + (m2 - m1) * 6 * h; } if (h * 2 < 1) { return m2; } if (h * 3 < 2) { return m1 + (m2 - m1) * (2 / 3 - h) * 6; } return m1; } var Color = class _Color { /** * @param {number} [red=1.0] The red component. * @param {number} [green=1.0] The green component. * @param {number} [blue=1.0] The blue component. * @param {number} [alpha=1.0] The alpha component. */ constructor(red, green, blue, alpha) { this.red = red ?? 1; this.green = green ?? 1; this.blue = blue ?? 1; this.alpha = alpha ?? 1; } /** * Creates a Color instance from a {@link Cartesian4}. x, y, z, * and w map to red, green, blue, and alpha, respectively. * * @param {Cartesian4} cartesian The source cartesian. * @param {Color} [result] The object onto which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ static fromCartesian4(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); if (!defined_default(result)) { return new _Color(cartesian11.x, cartesian11.y, cartesian11.z, cartesian11.w); } result.red = cartesian11.x; result.green = cartesian11.y; result.blue = cartesian11.z; result.alpha = cartesian11.w; return result; } /** * Creates a new Color specified using red, green, blue, and alpha values * that are in the range of 0 to 255, converting them internally to a range of 0.0 to 1.0. * * @param {number} [red=255] The red component. * @param {number} [green=255] The green component. * @param {number} [blue=255] The blue component. * @param {number} [alpha=255] The alpha component. * @param {Color} [result] The object onto which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ static fromBytes(red, green, blue, alpha, result) { red = _Color.byteToFloat(red ?? 255); green = _Color.byteToFloat(green ?? 255); blue = _Color.byteToFloat(blue ?? 255); alpha = _Color.byteToFloat(alpha ?? 255); if (!defined_default(result)) { return new _Color(red, green, blue, alpha); } result.red = red; result.green = green; result.blue = blue; result.alpha = alpha; return result; } /** * Creates a new Color that has the same red, green, and blue components * of the specified color, but with the specified alpha value. * * @param {Color} color The base color * @param {number} alpha The new alpha component. * @param {Color} [result] The object onto which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. * * @example const translucentRed = Cesium.Color.fromAlpha(Cesium.Color.RED, 0.9); */ static fromAlpha(color, alpha, result) { Check_default.typeOf.object("color", color); Check_default.typeOf.number("alpha", alpha); if (!defined_default(result)) { return new _Color(color.red, color.green, color.blue, alpha); } result.red = color.red; result.green = color.green; result.blue = color.blue; result.alpha = alpha; return result; } /** * Creates a new Color from a single numeric unsigned 32-bit RGBA value, using the endianness * of the system. * * @param {number} rgba A single numeric unsigned 32-bit RGBA value. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The color object. * * @example * const color = Cesium.Color.fromRgba(0x67ADDFFF); * * @see Color#toRgba */ static fromRgba(rgba, result) { scratchUint32Array[0] = rgba; return _Color.fromBytes( scratchUint8Array[0], scratchUint8Array[1], scratchUint8Array[2], scratchUint8Array[3], result ); } /** * Creates a Color instance from hue, saturation, and lightness. * * @param {number} [hue=0] The hue angle 0...1 * @param {number} [saturation=0] The saturation value 0...1 * @param {number} [lightness=0] The lightness value 0...1 * @param {number} [alpha=1.0] The alpha component 0...1 * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The color object. * * @see {@link http://www.w3.org/TR/css3-color/#hsl-color|CSS color values} */ static fromHsl(hue, saturation, lightness, alpha, result) { hue = (hue ?? 0) % 1; saturation = saturation ?? 0; lightness = lightness ?? 0; alpha = alpha ?? 1; let red = lightness; let green = lightness; let blue = lightness; if (saturation !== 0) { let m2; if (lightness < 0.5) { m2 = lightness * (1 + saturation); } else { m2 = lightness + saturation - lightness * saturation; } const m1 = 2 * lightness - m2; red = hue2rgb(m1, m2, hue + 1 / 3); green = hue2rgb(m1, m2, hue); blue = hue2rgb(m1, m2, hue - 1 / 3); } if (!defined_default(result)) { return new _Color(red, green, blue, alpha); } result.red = red; result.green = green; result.blue = blue; result.alpha = alpha; return result; } /** * Creates a random color using the provided options. For reproducible random colors, you should * call {@link CesiumMath#setRandomNumberSeed} once at the beginning of your application. * * @param {object} [options] Object with the following properties: * @param {number} [options.red] If specified, the red component to use instead of a randomized value. * @param {number} [options.minimumRed=0.0] The maximum red value to generate if none was specified. * @param {number} [options.maximumRed=1.0] The minimum red value to generate if none was specified. * @param {number} [options.green] If specified, the green component to use instead of a randomized value. * @param {number} [options.minimumGreen=0.0] The maximum green value to generate if none was specified. * @param {number} [options.maximumGreen=1.0] The minimum green value to generate if none was specified. * @param {number} [options.blue] If specified, the blue component to use instead of a randomized value. * @param {number} [options.minimumBlue=0.0] The maximum blue value to generate if none was specified. * @param {number} [options.maximumBlue=1.0] The minimum blue value to generate if none was specified. * @param {number} [options.alpha] If specified, the alpha component to use instead of a randomized value. * @param {number} [options.minimumAlpha=0.0] The maximum alpha value to generate if none was specified. * @param {number} [options.maximumAlpha=1.0] The minimum alpha value to generate if none was specified. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The modified result parameter or a new instance if result was undefined. * * @exception {DeveloperError} minimumRed must be less than or equal to maximumRed. * @exception {DeveloperError} minimumGreen must be less than or equal to maximumGreen. * @exception {DeveloperError} minimumBlue must be less than or equal to maximumBlue. * @exception {DeveloperError} minimumAlpha must be less than or equal to maximumAlpha. * * @example * //Create a completely random color * const color = Cesium.Color.fromRandom(); * * //Create a random shade of yellow. * const color1 = Cesium.Color.fromRandom({ * red : 1.0, * green : 1.0, * alpha : 1.0 * }); * * //Create a random bright color. * const color2 = Cesium.Color.fromRandom({ * minimumRed : 0.75, * minimumGreen : 0.75, * minimumBlue : 0.75, * alpha : 1.0 * }); */ static fromRandom(options, result) { options = options ?? Frozen_default.EMPTY_OBJECT; let red = options.red; if (!defined_default(red)) { const minimumRed = options.minimumRed ?? 0; const maximumRed = options.maximumRed ?? 1; Check_default.typeOf.number.lessThanOrEquals( "minimumRed", minimumRed, maximumRed ); red = minimumRed + Math_default.nextRandomNumber() * (maximumRed - minimumRed); } let green = options.green; if (!defined_default(green)) { const minimumGreen = options.minimumGreen ?? 0; const maximumGreen = options.maximumGreen ?? 1; Check_default.typeOf.number.lessThanOrEquals( "minimumGreen", minimumGreen, maximumGreen ); green = minimumGreen + Math_default.nextRandomNumber() * (maximumGreen - minimumGreen); } let blue = options.blue; if (!defined_default(blue)) { const minimumBlue = options.minimumBlue ?? 0; const maximumBlue = options.maximumBlue ?? 1; Check_default.typeOf.number.lessThanOrEquals( "minimumBlue", minimumBlue, maximumBlue ); blue = minimumBlue + Math_default.nextRandomNumber() * (maximumBlue - minimumBlue); } let alpha = options.alpha; if (!defined_default(alpha)) { const minimumAlpha = options.minimumAlpha ?? 0; const maximumAlpha = options.maximumAlpha ?? 1; Check_default.typeOf.number.lessThanOrEquals( "minimumAlpha", minimumAlpha, maximumAlpha ); alpha = minimumAlpha + Math_default.nextRandomNumber() * (maximumAlpha - minimumAlpha); } if (!defined_default(result)) { return new _Color(red, green, blue, alpha); } result.red = red; result.green = green; result.blue = blue; result.alpha = alpha; return result; } /** * Creates a Color instance from a CSS color value. * * @param {string} color The CSS color value in #rgb, #rgba, #rrggbb, #rrggbbaa, rgb(), rgba(), hsl(), or hsla() format. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The color object, or undefined if the string was not a valid CSS color. * * * @example * const cesiumBlue = Cesium.Color.fromCssColorString('#67ADDF'); * const green = Cesium.Color.fromCssColorString('green'); * * @see {@link http://www.w3.org/TR/css3-color|CSS color values} */ static fromCssColorString(color, result) { Check_default.typeOf.string("color", color); if (!defined_default(result)) { result = new _Color(); } color = color.trim(); const namedColor = _Color[color.toUpperCase()]; if (defined_default(namedColor)) { _Color.clone(namedColor, result); return result; } let matches = rgbaMatcher.exec(color); if (matches !== null) { result.red = parseInt(matches[1], 16) / 15; result.green = parseInt(matches[2], 16) / 15; result.blue = parseInt(matches[3], 16) / 15; result.alpha = parseInt(matches[4] ?? "f", 16) / 15; return result; } matches = rrggbbaaMatcher.exec(color); if (matches !== null) { result.red = parseInt(matches[1], 16) / 255; result.green = parseInt(matches[2], 16) / 255; result.blue = parseInt(matches[3], 16) / 255; result.alpha = parseInt(matches[4] ?? "ff", 16) / 255; return result; } matches = rgbParenthesesMatcher.exec(color); if (matches !== null) { result.red = parseFloat(matches[1]) / ("%" === matches[1].substr(-1) ? 100 : 255); result.green = parseFloat(matches[2]) / ("%" === matches[2].substr(-1) ? 100 : 255); result.blue = parseFloat(matches[3]) / ("%" === matches[3].substr(-1) ? 100 : 255); result.alpha = parseFloat(matches[4] ?? "1.0"); return result; } matches = hslParenthesesMatcher.exec(color); if (matches !== null) { return _Color.fromHsl( parseFloat(matches[1]) / 360, parseFloat(matches[2]) / 100, parseFloat(matches[3]) / 100, parseFloat(matches[4] ?? "1.0"), result ); } result = void 0; return result; } /** * Stores the provided instance into the provided array. * * @param {Color} value The value to pack. * @param {number[]|TypedArray} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]|TypedArray} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.red; array[startingIndex++] = value.green; array[startingIndex++] = value.blue; array[startingIndex] = value.alpha; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]|TypedArray} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Color} [result] The object into which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Color(); } result.red = array[startingIndex++]; result.green = array[startingIndex++]; result.blue = array[startingIndex++]; result.alpha = array[startingIndex]; return result; } /** * Converts a 'byte' color component in the range of 0 to 255 into * a 'float' color component in the range of 0 to 1.0. * * @param {number} number The number to be converted. * @returns {number} The converted number. */ static byteToFloat(number) { return number / 255; } /** * Converts a 'float' color component in the range of 0 to 1.0 into * a 'byte' color component in the range of 0 to 255. * * @param {number} number The number to be converted. * @returns {number} The converted number. */ static floatToByte(number) { return number === 1 ? 255 : number * 256 | 0; } /** * Duplicates a Color. * * @param {Color} color The Color to duplicate. * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The modified result parameter or a new instance if result was undefined. (Returns undefined if color is undefined) */ static clone(color, result) { if (!defined_default(color)) { return void 0; } if (!defined_default(result)) { return new _Color(color.red, color.green, color.blue, color.alpha); } result.red = color.red; result.green = color.green; result.blue = color.blue; result.alpha = color.alpha; return result; } /** * Returns true if the first Color equals the second color. * * @param {Color} [left] The first Color to compare for equality. * @param {Color} [right] The second Color to compare for equality. * @returns {boolean} true if the Colors are equal; otherwise, false. */ static equals(left, right) { return left === right || // defined_default(left) && // defined_default(right) && // left.red === right.red && // left.green === right.green && // left.blue === right.blue && // left.alpha === right.alpha; } /** * @private */ static equalsArray(color, array, offset) { return color.red === array[offset] && color.green === array[offset + 1] && color.blue === array[offset + 2] && color.alpha === array[offset + 3]; } /** * Returns a duplicate of a Color instance. * * @param {Color} [result] The object to store the result in, if undefined a new instance will be created. * @returns {Color} The modified result parameter or a new instance if result was undefined. */ clone(result) { return _Color.clone(this, result); } /** * Returns true if this Color equals other. * * @param {Color} [other] The Color to compare for equality. * @returns {boolean} true if the Colors are equal; otherwise, false. */ equals(other) { return _Color.equals(this, other); } /** * Returns true if this Color equals other componentwise within the specified epsilon. * * @param {Color} other The Color to compare for equality. * @param {number} [epsilon=0.0] The epsilon to use for equality testing. * @returns {boolean} true if the Colors are equal within the specified epsilon; otherwise, false. */ equalsEpsilon(other, epsilon) { return this === other || // defined_default(other) && // Math.abs(this.red - other.red) <= epsilon && // Math.abs(this.green - other.green) <= epsilon && // Math.abs(this.blue - other.blue) <= epsilon && // Math.abs(this.alpha - other.alpha) <= epsilon; } /** * Creates a string representing this Color in the format '(red, green, blue, alpha)'. * * @returns {string} A string representing this Color in the format '(red, green, blue, alpha)'. */ toString() { return `(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`; } /** * Creates a string containing the CSS color value for this color. * * @returns {string} The CSS equivalent of this color. * * @see {@link http://www.w3.org/TR/css3-color/#rgba-color|CSS RGB or RGBA color values} */ toCssColorString() { const red = _Color.floatToByte(this.red); const green = _Color.floatToByte(this.green); const blue = _Color.floatToByte(this.blue); if (this.alpha === 1) { return `rgb(${red},${green},${blue})`; } return `rgba(${red},${green},${blue},${this.alpha})`; } /** * Creates a string containing CSS hex string color value for this color. * * @returns {string} The CSS hex string equivalent of this color. */ toCssHexString() { let r2 = _Color.floatToByte(this.red).toString(16); if (r2.length < 2) { r2 = `0${r2}`; } let g = _Color.floatToByte(this.green).toString(16); if (g.length < 2) { g = `0${g}`; } let b = _Color.floatToByte(this.blue).toString(16); if (b.length < 2) { b = `0${b}`; } if (this.alpha < 1) { let hexAlpha = _Color.floatToByte(this.alpha).toString(16); if (hexAlpha.length < 2) { hexAlpha = `0${hexAlpha}`; } return `#${r2}${g}${b}${hexAlpha}`; } return `#${r2}${g}${b}`; } /** * Converts this color to an array of red, green, blue, and alpha values * that are in the range of 0 to 255. * * @param {number[]} [result] The array to store the result in, if undefined a new instance will be created. * @returns {number[]} The modified result parameter or a new instance if result was undefined. */ toBytes(result) { const red = _Color.floatToByte(this.red); const green = _Color.floatToByte(this.green); const blue = _Color.floatToByte(this.blue); const alpha = _Color.floatToByte(this.alpha); if (!defined_default(result)) { return [red, green, blue, alpha]; } result[0] = red; result[1] = green; result[2] = blue; result[3] = alpha; return result; } /** * Converts RGBA values in bytes to a single numeric unsigned 32-bit RGBA value, using the endianness * of the system. * * @returns {number} A single numeric unsigned 32-bit RGBA value. * * @see Color.toRgba */ static bytesToRgba(red, green, blue, alpha) { scratchUint8Array[0] = red; scratchUint8Array[1] = green; scratchUint8Array[2] = blue; scratchUint8Array[3] = alpha; return scratchUint32Array[0]; } /** * Converts this color to a single numeric unsigned 32-bit RGBA value, using the endianness * of the system. * * @returns {number} A single numeric unsigned 32-bit RGBA value. * * * @example * const rgba = Cesium.Color.BLUE.toRgba(); * * @see Color.fromRgba */ toRgba() { return _Color.bytesToRgba( _Color.floatToByte(this.red), _Color.floatToByte(this.green), _Color.floatToByte(this.blue), _Color.floatToByte(this.alpha) ); } /** * Brightens this color by the provided magnitude. * * @param {number} magnitude A positive number indicating the amount to brighten. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. * * @example * const brightBlue = Cesium.Color.BLUE.brighten(0.5, new Cesium.Color()); */ brighten(magnitude, result) { Check_default.typeOf.number("magnitude", magnitude); Check_default.typeOf.number.greaterThanOrEquals("magnitude", magnitude, 0); Check_default.typeOf.object("result", result); magnitude = 1 - magnitude; result.red = 1 - (1 - this.red) * magnitude; result.green = 1 - (1 - this.green) * magnitude; result.blue = 1 - (1 - this.blue) * magnitude; result.alpha = this.alpha; return result; } /** * Darkens this color by the provided magnitude. * * @param {number} magnitude A positive number indicating the amount to darken. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. * * @example * const darkBlue = Cesium.Color.BLUE.darken(0.5, new Cesium.Color()); */ darken(magnitude, result) { Check_default.typeOf.number("magnitude", magnitude); Check_default.typeOf.number.greaterThanOrEquals("magnitude", magnitude, 0); Check_default.typeOf.object("result", result); magnitude = 1 - magnitude; result.red = this.red * magnitude; result.green = this.green * magnitude; result.blue = this.blue * magnitude; result.alpha = this.alpha; return result; } /** * Creates a new Color that has the same red, green, and blue components * as this Color, but with the specified alpha value. * * @param {number} alpha The new alpha component. * @param {Color} [result] The object onto which to store the result. * @returns {Color} The modified result parameter or a new Color instance if one was not provided. * * @example const translucentRed = Cesium.Color.RED.withAlpha(0.9); */ withAlpha(alpha, result) { return _Color.fromAlpha(this, alpha, result); } /** * Computes the componentwise sum of two Colors. * * @param {Color} left The first Color. * @param {Color} right The second Color. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.red = left.red + right.red; result.green = left.green + right.green; result.blue = left.blue + right.blue; result.alpha = left.alpha + right.alpha; return result; } /** * Computes the componentwise difference of two Colors. * * @param {Color} left The first Color. * @param {Color} right The second Color. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.red = left.red - right.red; result.green = left.green - right.green; result.blue = left.blue - right.blue; result.alpha = left.alpha - right.alpha; return result; } /** * Computes the componentwise product of two Colors. * * @param {Color} left The first Color. * @param {Color} right The second Color. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static multiply(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.red = left.red * right.red; result.green = left.green * right.green; result.blue = left.blue * right.blue; result.alpha = left.alpha * right.alpha; return result; } /** * Computes the componentwise quotient of two Colors. * * @param {Color} left The first Color. * @param {Color} right The second Color. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static divide(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.red = left.red / right.red; result.green = left.green / right.green; result.blue = left.blue / right.blue; result.alpha = left.alpha / right.alpha; return result; } /** * Computes the componentwise modulus of two Colors. * * @param {Color} left The first Color. * @param {Color} right The second Color. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static mod(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.red = left.red % right.red; result.green = left.green % right.green; result.blue = left.blue % right.blue; result.alpha = left.alpha % right.alpha; return result; } /** * Computes the linear interpolation or extrapolation at t between the provided colors. * * @param {Color} start The color corresponding to t at 0.0. * @param {Color} end The color corresponding to t at 1.0. * @param {number} t The point along t at which to interpolate. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static lerp(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); result.red = Math_default.lerp(start.red, end.red, t2); result.green = Math_default.lerp(start.green, end.green, t2); result.blue = Math_default.lerp(start.blue, end.blue, t2); result.alpha = Math_default.lerp(start.alpha, end.alpha, t2); return result; } /** * Multiplies the provided Color componentwise by the provided scalar. * * @param {Color} color The Color to be scaled. * @param {number} scalar The scalar to multiply with. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static multiplyByScalar(color, scalar, result) { Check_default.typeOf.object("color", color); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.red = color.red * scalar; result.green = color.green * scalar; result.blue = color.blue * scalar; result.alpha = color.alpha * scalar; return result; } /** * Divides the provided Color componentwise by the provided scalar. * * @param {Color} color The Color to be divided. * @param {number} scalar The scalar to divide with. * @param {Color} result The object onto which to store the result. * @returns {Color} The modified result parameter. */ static divideByScalar(color, scalar, result) { Check_default.typeOf.object("color", color); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.red = color.red / scalar; result.green = color.green / scalar; result.blue = color.blue / scalar; result.alpha = color.alpha / scalar; return result; } }; var scratchArrayBuffer; var scratchUint32Array; var scratchUint8Array; if (FeatureDetection_default.supportsTypedArrays()) { scratchArrayBuffer = new ArrayBuffer(4); scratchUint32Array = new Uint32Array(scratchArrayBuffer); scratchUint8Array = new Uint8Array(scratchArrayBuffer); } var rgbaMatcher = /^#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i; var rrggbbaaMatcher = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i; var rgbParenthesesMatcher = /^rgba?\s*\(\s*([0-9.]+%?)\s*[,\s]+\s*([0-9.]+%?)\s*[,\s]+\s*([0-9.]+%?)(?:\s*[,\s/]+\s*([0-9.]+))?\s*\)$/i; var hslParenthesesMatcher = /^hsla?\s*\(\s*([0-9.]+)\s*[,\s]+\s*([0-9.]+%)\s*[,\s]+\s*([0-9.]+%)(?:\s*[,\s/]+\s*([0-9.]+))?\s*\)$/i; Color.packedLength = 4; Color.ALICEBLUE = Object.freeze(Color.fromCssColorString("#F0F8FF")); Color.ANTIQUEWHITE = Object.freeze(Color.fromCssColorString("#FAEBD7")); Color.AQUA = Object.freeze(Color.fromCssColorString("#00FFFF")); Color.AQUAMARINE = Object.freeze(Color.fromCssColorString("#7FFFD4")); Color.AZURE = Object.freeze(Color.fromCssColorString("#F0FFFF")); Color.BEIGE = Object.freeze(Color.fromCssColorString("#F5F5DC")); Color.BISQUE = Object.freeze(Color.fromCssColorString("#FFE4C4")); Color.BLACK = Object.freeze(Color.fromCssColorString("#000000")); Color.BLANCHEDALMOND = Object.freeze(Color.fromCssColorString("#FFEBCD")); Color.BLUE = Object.freeze(Color.fromCssColorString("#0000FF")); Color.BLUEVIOLET = Object.freeze(Color.fromCssColorString("#8A2BE2")); Color.BROWN = Object.freeze(Color.fromCssColorString("#A52A2A")); Color.BURLYWOOD = Object.freeze(Color.fromCssColorString("#DEB887")); Color.CADETBLUE = Object.freeze(Color.fromCssColorString("#5F9EA0")); Color.CHARTREUSE = Object.freeze(Color.fromCssColorString("#7FFF00")); Color.CHOCOLATE = Object.freeze(Color.fromCssColorString("#D2691E")); Color.CORAL = Object.freeze(Color.fromCssColorString("#FF7F50")); Color.CORNFLOWERBLUE = Object.freeze(Color.fromCssColorString("#6495ED")); Color.CORNSILK = Object.freeze(Color.fromCssColorString("#FFF8DC")); Color.CRIMSON = Object.freeze(Color.fromCssColorString("#DC143C")); Color.CYAN = Object.freeze(Color.fromCssColorString("#00FFFF")); Color.DARKBLUE = Object.freeze(Color.fromCssColorString("#00008B")); Color.DARKCYAN = Object.freeze(Color.fromCssColorString("#008B8B")); Color.DARKGOLDENROD = Object.freeze(Color.fromCssColorString("#B8860B")); Color.DARKGRAY = Object.freeze(Color.fromCssColorString("#A9A9A9")); Color.DARKGREEN = Object.freeze(Color.fromCssColorString("#006400")); Color.DARKGREY = Color.DARKGRAY; Color.DARKKHAKI = Object.freeze(Color.fromCssColorString("#BDB76B")); Color.DARKMAGENTA = Object.freeze(Color.fromCssColorString("#8B008B")); Color.DARKOLIVEGREEN = Object.freeze(Color.fromCssColorString("#556B2F")); Color.DARKORANGE = Object.freeze(Color.fromCssColorString("#FF8C00")); Color.DARKORCHID = Object.freeze(Color.fromCssColorString("#9932CC")); Color.DARKRED = Object.freeze(Color.fromCssColorString("#8B0000")); Color.DARKSALMON = Object.freeze(Color.fromCssColorString("#E9967A")); Color.DARKSEAGREEN = Object.freeze(Color.fromCssColorString("#8FBC8F")); Color.DARKSLATEBLUE = Object.freeze(Color.fromCssColorString("#483D8B")); Color.DARKSLATEGRAY = Object.freeze(Color.fromCssColorString("#2F4F4F")); Color.DARKSLATEGREY = Color.DARKSLATEGRAY; Color.DARKTURQUOISE = Object.freeze(Color.fromCssColorString("#00CED1")); Color.DARKVIOLET = Object.freeze(Color.fromCssColorString("#9400D3")); Color.DEEPPINK = Object.freeze(Color.fromCssColorString("#FF1493")); Color.DEEPSKYBLUE = Object.freeze(Color.fromCssColorString("#00BFFF")); Color.DIMGRAY = Object.freeze(Color.fromCssColorString("#696969")); Color.DIMGREY = Color.DIMGRAY; Color.DODGERBLUE = Object.freeze(Color.fromCssColorString("#1E90FF")); Color.FIREBRICK = Object.freeze(Color.fromCssColorString("#B22222")); Color.FLORALWHITE = Object.freeze(Color.fromCssColorString("#FFFAF0")); Color.FORESTGREEN = Object.freeze(Color.fromCssColorString("#228B22")); Color.FUCHSIA = Object.freeze(Color.fromCssColorString("#FF00FF")); Color.GAINSBORO = Object.freeze(Color.fromCssColorString("#DCDCDC")); Color.GHOSTWHITE = Object.freeze(Color.fromCssColorString("#F8F8FF")); Color.GOLD = Object.freeze(Color.fromCssColorString("#FFD700")); Color.GOLDENROD = Object.freeze(Color.fromCssColorString("#DAA520")); Color.GRAY = Object.freeze(Color.fromCssColorString("#808080")); Color.GREEN = Object.freeze(Color.fromCssColorString("#008000")); Color.GREENYELLOW = Object.freeze(Color.fromCssColorString("#ADFF2F")); Color.GREY = Color.GRAY; Color.HONEYDEW = Object.freeze(Color.fromCssColorString("#F0FFF0")); Color.HOTPINK = Object.freeze(Color.fromCssColorString("#FF69B4")); Color.INDIANRED = Object.freeze(Color.fromCssColorString("#CD5C5C")); Color.INDIGO = Object.freeze(Color.fromCssColorString("#4B0082")); Color.IVORY = Object.freeze(Color.fromCssColorString("#FFFFF0")); Color.KHAKI = Object.freeze(Color.fromCssColorString("#F0E68C")); Color.LAVENDER = Object.freeze(Color.fromCssColorString("#E6E6FA")); Color.LAVENDAR_BLUSH = Object.freeze(Color.fromCssColorString("#FFF0F5")); Color.LAWNGREEN = Object.freeze(Color.fromCssColorString("#7CFC00")); Color.LEMONCHIFFON = Object.freeze(Color.fromCssColorString("#FFFACD")); Color.LIGHTBLUE = Object.freeze(Color.fromCssColorString("#ADD8E6")); Color.LIGHTCORAL = Object.freeze(Color.fromCssColorString("#F08080")); Color.LIGHTCYAN = Object.freeze(Color.fromCssColorString("#E0FFFF")); Color.LIGHTGOLDENRODYELLOW = Object.freeze(Color.fromCssColorString("#FAFAD2")); Color.LIGHTGRAY = Object.freeze(Color.fromCssColorString("#D3D3D3")); Color.LIGHTGREEN = Object.freeze(Color.fromCssColorString("#90EE90")); Color.LIGHTGREY = Color.LIGHTGRAY; Color.LIGHTPINK = Object.freeze(Color.fromCssColorString("#FFB6C1")); Color.LIGHTSEAGREEN = Object.freeze(Color.fromCssColorString("#20B2AA")); Color.LIGHTSKYBLUE = Object.freeze(Color.fromCssColorString("#87CEFA")); Color.LIGHTSLATEGRAY = Object.freeze(Color.fromCssColorString("#778899")); Color.LIGHTSLATEGREY = Color.LIGHTSLATEGRAY; Color.LIGHTSTEELBLUE = Object.freeze(Color.fromCssColorString("#B0C4DE")); Color.LIGHTYELLOW = Object.freeze(Color.fromCssColorString("#FFFFE0")); Color.LIME = Object.freeze(Color.fromCssColorString("#00FF00")); Color.LIMEGREEN = Object.freeze(Color.fromCssColorString("#32CD32")); Color.LINEN = Object.freeze(Color.fromCssColorString("#FAF0E6")); Color.MAGENTA = Object.freeze(Color.fromCssColorString("#FF00FF")); Color.MAROON = Object.freeze(Color.fromCssColorString("#800000")); Color.MEDIUMAQUAMARINE = Object.freeze(Color.fromCssColorString("#66CDAA")); Color.MEDIUMBLUE = Object.freeze(Color.fromCssColorString("#0000CD")); Color.MEDIUMORCHID = Object.freeze(Color.fromCssColorString("#BA55D3")); Color.MEDIUMPURPLE = Object.freeze(Color.fromCssColorString("#9370DB")); Color.MEDIUMSEAGREEN = Object.freeze(Color.fromCssColorString("#3CB371")); Color.MEDIUMSLATEBLUE = Object.freeze(Color.fromCssColorString("#7B68EE")); Color.MEDIUMSPRINGGREEN = Object.freeze(Color.fromCssColorString("#00FA9A")); Color.MEDIUMTURQUOISE = Object.freeze(Color.fromCssColorString("#48D1CC")); Color.MEDIUMVIOLETRED = Object.freeze(Color.fromCssColorString("#C71585")); Color.MIDNIGHTBLUE = Object.freeze(Color.fromCssColorString("#191970")); Color.MINTCREAM = Object.freeze(Color.fromCssColorString("#F5FFFA")); Color.MISTYROSE = Object.freeze(Color.fromCssColorString("#FFE4E1")); Color.MOCCASIN = Object.freeze(Color.fromCssColorString("#FFE4B5")); Color.NAVAJOWHITE = Object.freeze(Color.fromCssColorString("#FFDEAD")); Color.NAVY = Object.freeze(Color.fromCssColorString("#000080")); Color.OLDLACE = Object.freeze(Color.fromCssColorString("#FDF5E6")); Color.OLIVE = Object.freeze(Color.fromCssColorString("#808000")); Color.OLIVEDRAB = Object.freeze(Color.fromCssColorString("#6B8E23")); Color.ORANGE = Object.freeze(Color.fromCssColorString("#FFA500")); Color.ORANGERED = Object.freeze(Color.fromCssColorString("#FF4500")); Color.ORCHID = Object.freeze(Color.fromCssColorString("#DA70D6")); Color.PALEGOLDENROD = Object.freeze(Color.fromCssColorString("#EEE8AA")); Color.PALEGREEN = Object.freeze(Color.fromCssColorString("#98FB98")); Color.PALETURQUOISE = Object.freeze(Color.fromCssColorString("#AFEEEE")); Color.PALEVIOLETRED = Object.freeze(Color.fromCssColorString("#DB7093")); Color.PAPAYAWHIP = Object.freeze(Color.fromCssColorString("#FFEFD5")); Color.PEACHPUFF = Object.freeze(Color.fromCssColorString("#FFDAB9")); Color.PERU = Object.freeze(Color.fromCssColorString("#CD853F")); Color.PINK = Object.freeze(Color.fromCssColorString("#FFC0CB")); Color.PLUM = Object.freeze(Color.fromCssColorString("#DDA0DD")); Color.POWDERBLUE = Object.freeze(Color.fromCssColorString("#B0E0E6")); Color.PURPLE = Object.freeze(Color.fromCssColorString("#800080")); Color.RED = Object.freeze(Color.fromCssColorString("#FF0000")); Color.ROSYBROWN = Object.freeze(Color.fromCssColorString("#BC8F8F")); Color.ROYALBLUE = Object.freeze(Color.fromCssColorString("#4169E1")); Color.SADDLEBROWN = Object.freeze(Color.fromCssColorString("#8B4513")); Color.SALMON = Object.freeze(Color.fromCssColorString("#FA8072")); Color.SANDYBROWN = Object.freeze(Color.fromCssColorString("#F4A460")); Color.SEAGREEN = Object.freeze(Color.fromCssColorString("#2E8B57")); Color.SEASHELL = Object.freeze(Color.fromCssColorString("#FFF5EE")); Color.SIENNA = Object.freeze(Color.fromCssColorString("#A0522D")); Color.SILVER = Object.freeze(Color.fromCssColorString("#C0C0C0")); Color.SKYBLUE = Object.freeze(Color.fromCssColorString("#87CEEB")); Color.SLATEBLUE = Object.freeze(Color.fromCssColorString("#6A5ACD")); Color.SLATEGRAY = Object.freeze(Color.fromCssColorString("#708090")); Color.SLATEGREY = Color.SLATEGRAY; Color.SNOW = Object.freeze(Color.fromCssColorString("#FFFAFA")); Color.SPRINGGREEN = Object.freeze(Color.fromCssColorString("#00FF7F")); Color.STEELBLUE = Object.freeze(Color.fromCssColorString("#4682B4")); Color.TAN = Object.freeze(Color.fromCssColorString("#D2B48C")); Color.TEAL = Object.freeze(Color.fromCssColorString("#008080")); Color.THISTLE = Object.freeze(Color.fromCssColorString("#D8BFD8")); Color.TOMATO = Object.freeze(Color.fromCssColorString("#FF6347")); Color.TURQUOISE = Object.freeze(Color.fromCssColorString("#40E0D0")); Color.VIOLET = Object.freeze(Color.fromCssColorString("#EE82EE")); Color.WHEAT = Object.freeze(Color.fromCssColorString("#F5DEB3")); Color.WHITE = Object.freeze(Color.fromCssColorString("#FFFFFF")); Color.WHITESMOKE = Object.freeze(Color.fromCssColorString("#F5F5F5")); Color.YELLOW = Object.freeze(Color.fromCssColorString("#FFFF00")); Color.YELLOWGREEN = Object.freeze(Color.fromCssColorString("#9ACD32")); Color.TRANSPARENT = Object.freeze(new Color(0, 0, 0, 0)); var Color_default = Color; // packages/engine/Source/Renderer/ClearCommand.js function ClearCommand(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.color = options.color; this.depth = options.depth; this.stencil = options.stencil; this.renderState = options.renderState; this.framebuffer = options.framebuffer; this.owner = options.owner; this.pass = options.pass; } ClearCommand.ALL = Object.freeze( new ClearCommand({ color: new Color_default(0, 0, 0, 0), depth: 1, stencil: 0 }) ); ClearCommand.prototype.execute = function(context, passState) { context.clear(this, passState); }; var ClearCommand_default = ClearCommand; // packages/engine/Source/Renderer/ComputeCommand.js var import_InlineWorkers23 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/Pass.js var import_InlineWorkers22 = __toESM(require_InlineWorkers(), 1); var Pass = { // If you add/modify/remove Pass constants, also change the automatic GLSL constants // that start with 'czm_pass' // // Commands are executed in order by pass up to the translucent pass. // Translucent geometry needs special handling (sorting/OIT). The compute pass // is executed first and the overlay pass is executed last. Both are not sorted // by frustum. ENVIRONMENT: 0, COMPUTE: 1, GLOBE: 2, TERRAIN_CLASSIFICATION: 3, CESIUM_3D_TILE_EDGES: 4, CESIUM_3D_TILE_PLANAR_FILL_ID: 5, CESIUM_3D_TILE: 6, CESIUM_3D_TILE_CLASSIFICATION: 7, CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW: 8, OPAQUE: 9, TRANSLUCENT: 10, VOXELS: 11, GAUSSIAN_SPLATS: 12, CESIUM_3D_TILE_EDGES_DIRECT: 13, OVERLAY: 14, NUMBER_OF_PASSES: 15 }; Object.freeze(Pass); var Pass_default = Pass; // packages/engine/Source/Renderer/ComputeCommand.js function ComputeCommand(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.vertexArray = options.vertexArray; this.fragmentShaderSource = options.fragmentShaderSource; this.shaderProgram = options.shaderProgram; this.uniformMap = options.uniformMap; this.outputTexture = options.outputTexture; this.preExecute = options.preExecute; this.postExecute = options.postExecute; this.canceled = options.canceled; this.persists = options.persists ?? false; this.pass = Pass_default.COMPUTE; this.owner = options.owner; } ComputeCommand.prototype.execute = function(computeEngine) { computeEngine.execute(this); }; var ComputeCommand_default = ComputeCommand; // packages/engine/Source/Renderer/ComputeEngine.js var import_InlineWorkers85 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/BoundingRectangle.js var import_InlineWorkers70 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Cartesian2.js var import_InlineWorkers24 = __toESM(require_InlineWorkers(), 1); var Cartesian2 = class _Cartesian2 { /** * @param {number} [x=0.0] The X component. * @param {number} [y=0.0] The Y component. */ constructor(x, y) { this.x = x ?? 0; this.y = y ?? 0; } /** * Creates a Cartesian2 instance from x and y coordinates. * * @param {number} x The x coordinate. * @param {number} y The y coordinate. * @param {Cartesian2} [result] The object onto which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. */ static fromElements(x, y, result) { if (!defined_default(result)) { return new _Cartesian2(x, y); } result.x = x; result.y = y; return result; } /** * Duplicates a Cartesian2 instance. * * @param {Cartesian2} cartesian The Cartesian to duplicate. * @param {Cartesian2} [result] The object onto which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. (Returns undefined if cartesian is undefined) */ static clone(cartesian11, result) { if (!defined_default(cartesian11)) { return void 0; } if (!defined_default(result)) { return new _Cartesian2(cartesian11.x, cartesian11.y); } result.x = cartesian11.x; result.y = cartesian11.y; return result; } /** * Stores the provided instance into the provided array. * * @param {Cartesian2} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.x; array[startingIndex] = value.y; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Cartesian2} [result] The object into which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Cartesian2(); } result.x = array[startingIndex++]; result.y = array[startingIndex]; return result; } /** * Flattens an array of Cartesian2s into an array of components. * * @param {Cartesian2[]} array The array of cartesians to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 2 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 2) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 2; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 2 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Cartesian2.pack(array[i], result, i * 2); } return result; } /** * Unpacks an array of cartesian components into an array of Cartesian2s. * * @param {number[]} array The array of components to unpack. * @param {Cartesian2[]} [result] The array onto which to store the result. * @returns {Cartesian2[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 2); if (array.length % 2 !== 0) { throw new DeveloperError_default("array length must be a multiple of 2."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 2); } else { result.length = length2 / 2; } for (let i = 0; i < length2; i += 2) { const index = i / 2; result[index] = _Cartesian2.unpack(array, i, result[index]); } return result; } /** * Computes the value of the maximum component for the supplied Cartesian. * * @param {Cartesian2} cartesian The cartesian to use. * @returns {number} The value of the maximum component. */ static maximumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.max(cartesian11.x, cartesian11.y); } /** * Computes the value of the minimum component for the supplied Cartesian. * * @param {Cartesian2} cartesian The cartesian to use. * @returns {number} The value of the minimum component. */ static minimumComponent(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return Math.min(cartesian11.x, cartesian11.y); } /** * Compares two Cartesians and computes a Cartesian which contains the minimum components of the supplied Cartesians. * * @param {Cartesian2} first A cartesian to compare. * @param {Cartesian2} second A cartesian to compare. * @param {Cartesian2} result The object into which to store the result. * @returns {Cartesian2} A cartesian with the minimum components. */ static minimumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.min(first.x, second.x); result.y = Math.min(first.y, second.y); return result; } /** * Compares two Cartesians and computes a Cartesian which contains the maximum components of the supplied Cartesians. * * @param {Cartesian2} first A cartesian to compare. * @param {Cartesian2} second A cartesian to compare. * @param {Cartesian2} result The object into which to store the result. * @returns {Cartesian2} A cartesian with the maximum components. */ static maximumByComponent(first, second, result) { Check_default.typeOf.object("first", first); Check_default.typeOf.object("second", second); Check_default.typeOf.object("result", result); result.x = Math.max(first.x, second.x); result.y = Math.max(first.y, second.y); return result; } /** * Constrain a value to lie between two values. * * @param {Cartesian2} value The value to clamp. * @param {Cartesian2} min The minimum bound. * @param {Cartesian2} max The maximum bound. * @param {Cartesian2} result The object into which to store the result. * @returns {Cartesian2} The clamped value such that min <= result <= max. */ static clamp(value, min3, max3, result) { Check_default.typeOf.object("value", value); Check_default.typeOf.object("min", min3); Check_default.typeOf.object("max", max3); Check_default.typeOf.object("result", result); const x = Math_default.clamp(value.x, min3.x, max3.x); const y = Math_default.clamp(value.y, min3.y, max3.y); result.x = x; result.y = y; return result; } /** * Computes the provided Cartesian's squared magnitude. * * @param {Cartesian2} cartesian The Cartesian instance whose squared magnitude is to be computed. * @returns {number} The squared magnitude. */ static magnitudeSquared(cartesian11) { Check_default.typeOf.object("cartesian", cartesian11); return cartesian11.x * cartesian11.x + cartesian11.y * cartesian11.y; } /** * Computes the Cartesian's magnitude (length). * * @param {Cartesian2} cartesian The Cartesian instance whose magnitude is to be computed. * @returns {number} The magnitude. */ static magnitude(cartesian11) { return Math.sqrt(_Cartesian2.magnitudeSquared(cartesian11)); } /** * Computes the distance between two points. * * @param {Cartesian2} left The first point to compute the distance from. * @param {Cartesian2} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 1.0 * const d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(2.0, 0.0)); */ static distance(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian2.subtract(left, right, distanceScratch3); return _Cartesian2.magnitude(distanceScratch3); } /** * Computes the squared distance between two points. Comparing squared distances * using this function is more efficient than comparing distances using {@link Cartesian2#distance}. * * @param {Cartesian2} left The first point to compute the distance from. * @param {Cartesian2} right The second point to compute the distance to. * @returns {number} The distance between two points. * * @example * // Returns 4.0, not 2.0 * const d = Cesium.Cartesian2.distance(new Cesium.Cartesian2(1.0, 0.0), new Cesium.Cartesian2(3.0, 0.0)); */ static distanceSquared(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian2.subtract(left, right, distanceScratch3); return _Cartesian2.magnitudeSquared(distanceScratch3); } /** * Computes the normalized form of the supplied Cartesian. * * @param {Cartesian2} cartesian The Cartesian to be normalized. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static normalize(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const magnitude = _Cartesian2.magnitude(cartesian11); result.x = cartesian11.x / magnitude; result.y = cartesian11.y / magnitude; if (isNaN(result.x) || isNaN(result.y)) { throw new DeveloperError_default("normalized result is not a number"); } return result; } /** * Computes the dot (scalar) product of two Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @returns {number} The dot product. */ static dot(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.x * right.x + left.y * right.y; } /** * Computes the magnitude of the cross product that would result from implicitly setting the Z coordinate of the input vectors to 0 * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @returns {number} The cross product. */ static cross(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.x * right.y - left.y * right.x; } /** * Computes the componentwise product of two Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static multiplyComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x * right.x; result.y = left.y * right.y; return result; } /** * Computes the componentwise quotient of two Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static divideComponents(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x / right.x; result.y = left.y / right.y; return result; } /** * Computes the componentwise sum of two Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x + right.x; result.y = left.y + right.y; return result; } /** * Computes the componentwise difference of two Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x - right.x; result.y = left.y - right.y; return result; } /** * Multiplies the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian2} cartesian The Cartesian to be scaled. * @param {number} scalar The scalar to multiply with. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static multiplyByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x * scalar; result.y = cartesian11.y * scalar; return result; } /** * Divides the provided Cartesian componentwise by the provided scalar. * * @param {Cartesian2} cartesian The Cartesian to be divided. * @param {number} scalar The scalar to divide by. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static divideByScalar(cartesian11, scalar, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = cartesian11.x / scalar; result.y = cartesian11.y / scalar; return result; } /** * Negates the provided Cartesian. * * @param {Cartesian2} cartesian The Cartesian to be negated. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static negate(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = -cartesian11.x; result.y = -cartesian11.y; return result; } /** * Computes the absolute value of the provided Cartesian. * * @param {Cartesian2} cartesian The Cartesian whose absolute value is to be computed. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static abs(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result.x = Math.abs(cartesian11.x); result.y = Math.abs(cartesian11.y); return result; } /** * Computes the linear interpolation or extrapolation at t using the provided cartesians. * * @param {Cartesian2} start The value corresponding to t at 0.0. * @param {Cartesian2} end The value corresponding to t at 1.0. * @param {number} t The point along t at which to interpolate. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static lerp(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); _Cartesian2.multiplyByScalar(end, t2, lerpScratch3); result = _Cartesian2.multiplyByScalar(start, 1 - t2, result); return _Cartesian2.add(lerpScratch3, result, result); } /** * Returns the angle, in radians, between the provided Cartesians. * * @param {Cartesian2} left The first Cartesian. * @param {Cartesian2} right The second Cartesian. * @returns {number} The angle between the Cartesians. */ static angleBetween(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); _Cartesian2.normalize(left, angleBetweenScratch3); _Cartesian2.normalize(right, angleBetweenScratch22); return Math_default.acosClamped( _Cartesian2.dot(angleBetweenScratch3, angleBetweenScratch22) ); } /** * Returns the axis that is most orthogonal to the provided Cartesian. * * @param {Cartesian2} cartesian The Cartesian on which to find the most orthogonal axis. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The most orthogonal axis. */ static mostOrthogonalAxis(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const f2 = _Cartesian2.normalize(cartesian11, mostOrthogonalAxisScratch3); _Cartesian2.abs(f2, f2); if (f2.x <= f2.y) { result = _Cartesian2.clone(_Cartesian2.UNIT_X, result); } else { result = _Cartesian2.clone(_Cartesian2.UNIT_Y, result); } return result; } /** * Compares the provided Cartesians componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian2} [left] The first Cartesian. * @param {Cartesian2} [right] The second Cartesian. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.x === right.x && left.y === right.y; } /** * @param {Cartesian2} cartesian * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(cartesian11, array, offset) { return cartesian11.x === array[offset] && cartesian11.y === array[offset + 1]; } /** * Compares the provided Cartesians componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian2} [left] The first Cartesian. * @param {Cartesian2} [right] The second Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, relativeEpsilon, absoluteEpsilon) { return left === right || defined_default(left) && defined_default(right) && Math_default.equalsEpsilon( left.x, right.x, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.y, right.y, relativeEpsilon, absoluteEpsilon ); } /** * Duplicates this Cartesian2 instance. * * @param {Cartesian2} [result] The object onto which to store the result. * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if one was not provided. */ clone(result) { return _Cartesian2.clone(this, result); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they are equal, false otherwise. * * @param {Cartesian2} [right] The right hand side Cartesian. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Cartesian2.equals(this, right); } /** * Compares this Cartesian against the provided Cartesian componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Cartesian2} [right] The right hand side Cartesian. * @param {number} [relativeEpsilon=0] The relative epsilon tolerance to use for equality testing. * @param {number} [absoluteEpsilon=relativeEpsilon] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, relativeEpsilon, absoluteEpsilon) { return _Cartesian2.equalsEpsilon( this, right, relativeEpsilon, absoluteEpsilon ); } /** * Creates a string representing this Cartesian in the format '(x, y)'. * * @returns {string} A string representing the provided Cartesian in the format '(x, y)'. */ toString() { return `(${this.x}, ${this.y})`; } }; Cartesian2.fromCartesian3 = Cartesian2.clone; Cartesian2.fromCartesian4 = Cartesian2.clone; Cartesian2.packedLength = 2; Cartesian2.fromArray = Cartesian2.unpack; var distanceScratch3 = new Cartesian2(); var lerpScratch3 = new Cartesian2(); var angleBetweenScratch3 = new Cartesian2(); var angleBetweenScratch22 = new Cartesian2(); var mostOrthogonalAxisScratch3 = new Cartesian2(); Cartesian2.ZERO = Object.freeze(new Cartesian2(0, 0)); Cartesian2.ONE = Object.freeze(new Cartesian2(1, 1)); Cartesian2.UNIT_X = Object.freeze(new Cartesian2(1, 0)); Cartesian2.UNIT_Y = Object.freeze(new Cartesian2(0, 1)); var Cartesian2_default = Cartesian2; // packages/engine/Source/Core/Cartographic.js var import_InlineWorkers26 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/scaleToGeodeticSurface.js var import_InlineWorkers25 = __toESM(require_InlineWorkers(), 1); var scaleToGeodeticSurfaceIntersection = new Cartesian3_default(); var scaleToGeodeticSurfaceGradient = new Cartesian3_default(); function scaleToGeodeticSurface(cartesian11, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, result) { if (!defined_default(cartesian11)) { throw new DeveloperError_default("cartesian is required."); } if (!defined_default(oneOverRadii)) { throw new DeveloperError_default("oneOverRadii is required."); } if (!defined_default(oneOverRadiiSquared)) { throw new DeveloperError_default("oneOverRadiiSquared is required."); } if (!defined_default(centerToleranceSquared)) { throw new DeveloperError_default("centerToleranceSquared is required."); } const positionX = cartesian11.x; const positionY = cartesian11.y; const positionZ = cartesian11.z; const oneOverRadiiX = oneOverRadii.x; const oneOverRadiiY = oneOverRadii.y; const oneOverRadiiZ = oneOverRadii.z; const x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX; const y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY; const z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ; const squaredNorm = x2 + y2 + z2; const ratio = Math.sqrt(1 / squaredNorm); const intersection = Cartesian3_default.multiplyByScalar( cartesian11, ratio, scaleToGeodeticSurfaceIntersection ); if (squaredNorm < centerToleranceSquared) { return !isFinite(ratio) ? void 0 : Cartesian3_default.clone(intersection, result); } const oneOverRadiiSquaredX = oneOverRadiiSquared.x; const oneOverRadiiSquaredY = oneOverRadiiSquared.y; const oneOverRadiiSquaredZ = oneOverRadiiSquared.z; const gradient = scaleToGeodeticSurfaceGradient; gradient.x = intersection.x * oneOverRadiiSquaredX * 2; gradient.y = intersection.y * oneOverRadiiSquaredY * 2; gradient.z = intersection.z * oneOverRadiiSquaredZ * 2; let lambda = (1 - ratio) * Cartesian3_default.magnitude(cartesian11) / (0.5 * Cartesian3_default.magnitude(gradient)); let correction = 0; let func; let denominator; let xMultiplier; let yMultiplier; let zMultiplier; let xMultiplier2; let yMultiplier2; let zMultiplier2; let xMultiplier3; let yMultiplier3; let zMultiplier3; do { lambda -= correction; xMultiplier = 1 / (1 + lambda * oneOverRadiiSquaredX); yMultiplier = 1 / (1 + lambda * oneOverRadiiSquaredY); zMultiplier = 1 / (1 + lambda * oneOverRadiiSquaredZ); xMultiplier2 = xMultiplier * xMultiplier; yMultiplier2 = yMultiplier * yMultiplier; zMultiplier2 = zMultiplier * zMultiplier; xMultiplier3 = xMultiplier2 * xMultiplier; yMultiplier3 = yMultiplier2 * yMultiplier; zMultiplier3 = zMultiplier2 * zMultiplier; func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1; denominator = x2 * xMultiplier3 * oneOverRadiiSquaredX + y2 * yMultiplier3 * oneOverRadiiSquaredY + z2 * zMultiplier3 * oneOverRadiiSquaredZ; const derivative = -2 * denominator; correction = func / derivative; } while (Math.abs(func) > Math_default.EPSILON12); if (!defined_default(result)) { return new Cartesian3_default( positionX * xMultiplier, positionY * yMultiplier, positionZ * zMultiplier ); } result.x = positionX * xMultiplier; result.y = positionY * yMultiplier; result.z = positionZ * zMultiplier; return result; } var scaleToGeodeticSurface_default = scaleToGeodeticSurface; // packages/engine/Source/Core/Cartographic.js var _Cartographic = class _Cartographic { /** * @param {number} [longitude=0.0] The longitude, in radians. * @param {number} [latitude=0.0] The latitude, in radians. * @param {number} [height=0.0] The height, in meters, above the ellipsoid. */ constructor(longitude, latitude, height) { this.longitude = longitude ?? 0; this.latitude = latitude ?? 0; this.height = height ?? 0; } /** * Creates a new Cartographic instance from longitude and latitude * specified in radians. * * @param {number} longitude The longitude, in radians. * @param {number} latitude The latitude, in radians. * @param {number} [height=0.0] The height, in meters, above the ellipsoid. * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. */ static fromRadians(longitude, latitude, height, result) { Check_default.typeOf.number("longitude", longitude); Check_default.typeOf.number("latitude", latitude); height = height ?? 0; if (!defined_default(result)) { return new _Cartographic(longitude, latitude, height); } result.longitude = longitude; result.latitude = latitude; result.height = height; return result; } /** * Creates a new Cartographic instance from longitude and latitude * specified in degrees. The values in the resulting object will * be in radians. * * @param {number} longitude The longitude, in degrees. * @param {number} latitude The latitude, in degrees. * @param {number} [height=0.0] The height, in meters, above the ellipsoid. * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. */ static fromDegrees(longitude, latitude, height, result) { Check_default.typeOf.number("longitude", longitude); Check_default.typeOf.number("latitude", latitude); longitude = Math_default.toRadians(longitude); latitude = Math_default.toRadians(latitude); return _Cartographic.fromRadians(longitude, latitude, height, result); } /** * Creates a new Cartographic instance from a Cartesian position. The values in the * resulting object will be in radians. * * @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid. */ static fromCartesian(cartesian11, ellipsoid, result) { const oneOverRadii = defined_default(ellipsoid) ? ellipsoid.oneOverRadii : _Cartographic._ellipsoidOneOverRadii; const oneOverRadiiSquared = defined_default(ellipsoid) ? ellipsoid.oneOverRadiiSquared : _Cartographic._ellipsoidOneOverRadiiSquared; const centerToleranceSquared = defined_default(ellipsoid) ? ellipsoid._centerToleranceSquared : _Cartographic._ellipsoidCenterToleranceSquared; const p = scaleToGeodeticSurface_default( cartesian11, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, cartesianToCartographicP ); if (!defined_default(p)) { return void 0; } let n2 = Cartesian3_default.multiplyComponents( p, oneOverRadiiSquared, cartesianToCartographicN ); n2 = Cartesian3_default.normalize(n2, n2); const h = Cartesian3_default.subtract(cartesian11, p, cartesianToCartographicH); const longitude = Math.atan2(n2.y, n2.x); const latitude = Math.asin(n2.z); const height = Math_default.sign(Cartesian3_default.dot(h, cartesian11)) * Cartesian3_default.magnitude(h); if (!defined_default(result)) { return new _Cartographic(longitude, latitude, height); } result.longitude = longitude; result.latitude = latitude; result.height = height; return result; } /** * Creates a new Cartesian3 instance from a Cartographic input. The values in the inputted * object should be in radians. * * @param {Cartographic} cartographic Input to be converted into a Cartesian3 output. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid on which the position lies. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The position */ static toCartesian(cartographic2, ellipsoid, result) { Check_default.defined("cartographic", cartographic2); return Cartesian3_default.fromRadians( cartographic2.longitude, cartographic2.latitude, cartographic2.height, ellipsoid, result ); } /** * Duplicates a Cartographic instance. * * @param {Cartographic} cartographic The cartographic to duplicate. * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. (Returns undefined if cartographic is undefined) */ static clone(cartographic2, result) { if (!defined_default(cartographic2)) { return void 0; } if (!defined_default(result)) { return new _Cartographic( cartographic2.longitude, cartographic2.latitude, cartographic2.height ); } result.longitude = cartographic2.longitude; result.latitude = cartographic2.latitude; result.height = cartographic2.height; return result; } /** * Compares the provided cartographics componentwise and returns * true if they are equal, false otherwise. * * @param {Cartographic} [left] The first cartographic. * @param {Cartographic} [right] The second cartographic. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.longitude === right.longitude && left.latitude === right.latitude && left.height === right.height; } /** * Compares the provided cartographics componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Cartographic} [left] The first cartographic. * @param {Cartographic} [right] The second cartographic. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left.longitude - right.longitude) <= epsilon && Math.abs(left.latitude - right.latitude) <= epsilon && Math.abs(left.height - right.height) <= epsilon; } /** * Duplicates this instance. * * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if one was not provided. */ clone(result) { return _Cartographic.clone(this, result); } /** * Compares the provided against this cartographic componentwise and returns * true if they are equal, false otherwise. * * @param {Cartographic} [right] The second cartographic. * @returns {boolean} true if left and right are equal, false otherwise. */ equals(right) { return _Cartographic.equals(this, right); } /** * Compares the provided against this cartographic componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Cartographic} [right] The second cartographic. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ equalsEpsilon(right, epsilon) { return _Cartographic.equalsEpsilon(this, right, epsilon); } /** * Creates a string representing this cartographic in the format '(longitude, latitude, height)'. * * @returns {string} A string representing the provided cartographic in the format '(longitude, latitude, height)'. */ toString() { return `(${this.longitude}, ${this.latitude}, ${this.height})`; } }; // To avoid circular dependencies, these are set by Ellipsoid when Ellipsoid.default is set. __publicField(_Cartographic, "_ellipsoidOneOverRadii", new Cartesian3_default( 1 / 6378137, 1 / 6378137, 1 / 6356752314245179e-9 )); __publicField(_Cartographic, "_ellipsoidOneOverRadiiSquared", new Cartesian3_default( 1 / (6378137 * 6378137), 1 / (6378137 * 6378137), 1 / (6356752314245179e-9 * 6356752314245179e-9) )); __publicField(_Cartographic, "_ellipsoidCenterToleranceSquared", Math_default.EPSILON1); var Cartographic = _Cartographic; Cartographic.ZERO = Object.freeze(new Cartographic(0, 0, 0)); var cartesianToCartographicN = new Cartesian3_default(); var cartesianToCartographicP = new Cartesian3_default(); var cartesianToCartographicH = new Cartesian3_default(); var Cartographic_default = Cartographic; // packages/engine/Source/Core/Ellipsoid.js var import_InlineWorkers27 = __toESM(require_InlineWorkers(), 1); function initialize(ellipsoid, x, y, z2) { x = x ?? 0; y = y ?? 0; z2 = z2 ?? 0; Check_default.typeOf.number.greaterThanOrEquals("x", x, 0); Check_default.typeOf.number.greaterThanOrEquals("y", y, 0); Check_default.typeOf.number.greaterThanOrEquals("z", z2, 0); ellipsoid._radii = new Cartesian3_default(x, y, z2); ellipsoid._radiiSquared = new Cartesian3_default(x * x, y * y, z2 * z2); ellipsoid._radiiToTheFourth = new Cartesian3_default( x * x * x * x, y * y * y * y, z2 * z2 * z2 * z2 ); ellipsoid._oneOverRadii = new Cartesian3_default( x === 0 ? 0 : 1 / x, y === 0 ? 0 : 1 / y, z2 === 0 ? 0 : 1 / z2 ); ellipsoid._oneOverRadiiSquared = new Cartesian3_default( x === 0 ? 0 : 1 / (x * x), y === 0 ? 0 : 1 / (y * y), z2 === 0 ? 0 : 1 / (z2 * z2) ); ellipsoid._minimumRadius = Math.min(x, y, z2); ellipsoid._maximumRadius = Math.max(x, y, z2); ellipsoid._centerToleranceSquared = Math_default.EPSILON1; if (ellipsoid._radiiSquared.z !== 0) { ellipsoid._squaredXOverSquaredZ = ellipsoid._radiiSquared.x / ellipsoid._radiiSquared.z; } } var Ellipsoid = class _Ellipsoid { /** * @param {number} [x=0] The radius in the x direction. * @param {number} [y=0] The radius in the y direction. * @param {number} [z=0] The radius in the z direction. * * @exception {DeveloperError} All radii components must be greater than or equal to zero. */ constructor(x, y, z2) { this._radii = void 0; this._radiiSquared = void 0; this._radiiToTheFourth = void 0; this._oneOverRadii = void 0; this._oneOverRadiiSquared = void 0; this._minimumRadius = void 0; this._maximumRadius = void 0; this._centerToleranceSquared = void 0; this._squaredXOverSquaredZ = void 0; initialize(this, x, y, z2); } /** * Gets the radii of the ellipsoid. * @type {Cartesian3} * @readonly */ get radii() { return this._radii; } /** * Gets the squared radii of the ellipsoid. * @type {Cartesian3} * @readonly */ get radiiSquared() { return this._radiiSquared; } /** * Gets the radii of the ellipsoid raise to the fourth power. * @type {Cartesian3} * @readonly */ get radiiToTheFourth() { return this._radiiToTheFourth; } /** * Gets one over the radii of the ellipsoid. * @type {Cartesian3} * @readonly */ get oneOverRadii() { return this._oneOverRadii; } /** * Gets one over the squared radii of the ellipsoid. * @type {Cartesian3} * @readonly */ get oneOverRadiiSquared() { return this._oneOverRadiiSquared; } /** * Gets the minimum radius of the ellipsoid. * @type {number} * @readonly */ get minimumRadius() { return this._minimumRadius; } /** * Gets the maximum radius of the ellipsoid. * @type {number} * @readonly */ get maximumRadius() { return this._maximumRadius; } /** * Duplicates an Ellipsoid instance. * * @param {Ellipsoid} ellipsoid The ellipsoid to duplicate. * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new * instance should be created. * @returns {Ellipsoid} The cloned Ellipsoid. (Returns undefined if ellipsoid is undefined) */ static clone(ellipsoid, result) { if (!defined_default(ellipsoid)) { return void 0; } const radii = ellipsoid._radii; if (!defined_default(result)) { return new _Ellipsoid(radii.x, radii.y, radii.z); } Cartesian3_default.clone(radii, result._radii); Cartesian3_default.clone(ellipsoid._radiiSquared, result._radiiSquared); Cartesian3_default.clone(ellipsoid._radiiToTheFourth, result._radiiToTheFourth); Cartesian3_default.clone(ellipsoid._oneOverRadii, result._oneOverRadii); Cartesian3_default.clone( ellipsoid._oneOverRadiiSquared, result._oneOverRadiiSquared ); result._minimumRadius = ellipsoid._minimumRadius; result._maximumRadius = ellipsoid._maximumRadius; result._centerToleranceSquared = ellipsoid._centerToleranceSquared; return result; } /** * Computes an Ellipsoid from a Cartesian specifying the radii in x, y, and z directions. * * @param {Cartesian3} [cartesian=Cartesian3.ZERO] The ellipsoid's radius in the x, y, and z directions. * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new * instance should be created. * @returns {Ellipsoid} A new Ellipsoid instance. * * @exception {DeveloperError} All radii components must be greater than or equal to zero. * * @see Ellipsoid.WGS84 * @see Ellipsoid.UNIT_SPHERE */ static fromCartesian3(cartesian11, result) { if (!defined_default(result)) { result = new _Ellipsoid(); } if (!defined_default(cartesian11)) { return result; } initialize(result, cartesian11.x, cartesian11.y, cartesian11.z); return result; } /** * The default ellipsoid used when not otherwise specified. * @type {Ellipsoid} * @example * Cesium.Ellipsoid.default = Cesium.Ellipsoid.MOON; * * // Apollo 11 landing site * const position = Cesium.Cartesian3.fromRadians( * 0.67416, * 23.47315, * ); */ static get default() { return _Ellipsoid._default; } static set default(value) { Check_default.typeOf.object("value", value); _Ellipsoid._default = value; Cartesian3_default._ellipsoidRadiiSquared = value.radiiSquared; Cartographic_default._ellipsoidOneOverRadii = value.oneOverRadii; Cartographic_default._ellipsoidOneOverRadiiSquared = value.oneOverRadiiSquared; Cartographic_default._ellipsoidCenterToleranceSquared = value._centerToleranceSquared; } /** * Duplicates an Ellipsoid instance. * * @param {Ellipsoid} [result] The object onto which to store the result, or undefined if a new * instance should be created. * @returns {Ellipsoid} The cloned Ellipsoid. */ clone(result) { return _Ellipsoid.clone(this, result); } /** * Stores the provided instance into the provided array. * * @param {Ellipsoid} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; Cartesian3_default.pack(value._radii, array, startingIndex); return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Ellipsoid} [result] The object into which to store the result. * @returns {Ellipsoid} The modified result parameter or a new Ellipsoid instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; const radii = Cartesian3_default.unpack(array, startingIndex); return _Ellipsoid.fromCartesian3(radii, result); } /** * Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position. * * @param {Cartographic} cartographic The cartographic position for which to to determine the geodetic normal. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided. */ geodeticSurfaceNormalCartographic(cartographic2, result) { Check_default.typeOf.object("cartographic", cartographic2); const longitude = cartographic2.longitude; const latitude = cartographic2.latitude; const cosLatitude = Math.cos(latitude); const x = cosLatitude * Math.cos(longitude); const y = cosLatitude * Math.sin(longitude); const z2 = Math.sin(latitude); if (!defined_default(result)) { result = new Cartesian3_default(); } result.x = x; result.y = y; result.z = z2; return Cartesian3_default.normalize(result, result); } /** * Computes the normal of the plane tangent to the surface of the ellipsoid at the provided position. * * @param {Cartesian3} cartesian The Cartesian position for which to to determine the surface normal. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided, or undefined if a normal cannot be found. */ geodeticSurfaceNormal(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); if (isNaN(cartesian11.x) || isNaN(cartesian11.y) || isNaN(cartesian11.z)) { throw new DeveloperError_default("cartesian has a NaN component"); } if (Cartesian3_default.equalsEpsilon(cartesian11, Cartesian3_default.ZERO, Math_default.EPSILON14)) { return void 0; } if (!defined_default(result)) { result = new Cartesian3_default(); } result = Cartesian3_default.multiplyComponents( cartesian11, this._oneOverRadiiSquared, result ); return Cartesian3_default.normalize(result, result); } /** * Converts the provided cartographic to Cartesian representation. * * @param {Cartographic} cartographic The cartographic position. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided. * * @example * //Create a Cartographic and determine it's Cartesian representation on a WGS84 ellipsoid. * const position = new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 5000); * const cartesianPosition = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position); */ cartographicToCartesian(cartographic2, result) { const n2 = cartographicToCartesianNormal; const k = cartographicToCartesianK; this.geodeticSurfaceNormalCartographic(cartographic2, n2); Cartesian3_default.multiplyComponents(this._radiiSquared, n2, k); const gamma = Math.sqrt(Cartesian3_default.dot(n2, k)); Cartesian3_default.divideByScalar(k, gamma, k); Cartesian3_default.multiplyByScalar(n2, cartographic2.height, n2); if (!defined_default(result)) { result = new Cartesian3_default(); } return Cartesian3_default.add(k, n2, result); } /** * Converts the provided array of cartographics to an array of Cartesians. * * @param {Cartographic[]} cartographics An array of cartographic positions. * @param {Cartesian3[]} [result] The object onto which to store the result. * @returns {Cartesian3[]} The modified result parameter or a new Array instance if none was provided. * * @example * //Convert an array of Cartographics and determine their Cartesian representation on a WGS84 ellipsoid. * const positions = [new Cesium.Cartographic(Cesium.Math.toRadians(21), Cesium.Math.toRadians(78), 0), * new Cesium.Cartographic(Cesium.Math.toRadians(21.321), Cesium.Math.toRadians(78.123), 100), * new Cesium.Cartographic(Cesium.Math.toRadians(21.645), Cesium.Math.toRadians(78.456), 250)]; * const cartesianPositions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(positions); */ cartographicArrayToCartesianArray(cartographics, result) { Check_default.defined("cartographics", cartographics); const length2 = cartographics.length; if (!defined_default(result)) { result = new Array(length2); } else { result.length = length2; } for (let i = 0; i < length2; i++) { result[i] = this.cartographicToCartesian(cartographics[i], result[i]); } return result; } /** * Converts the provided cartesian to cartographic representation. * The cartesian is undefined at the center of the ellipsoid. * * @param {Cartesian3} cartesian The Cartesian position to convert to cartographic representation. * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter, new Cartographic instance if none was provided, or undefined if the cartesian is at the center of the ellipsoid. * * @example * //Create a Cartesian and determine it's Cartographic representation on a WGS84 ellipsoid. * const position = new Cesium.Cartesian3(17832.12, 83234.52, 952313.73); * const cartographicPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position); */ cartesianToCartographic(cartesian11, result) { const p = this.scaleToGeodeticSurface(cartesian11, cartesianToCartographicP2); if (!defined_default(p)) { return void 0; } const n2 = this.geodeticSurfaceNormal(p, cartesianToCartographicN2); const h = Cartesian3_default.subtract(cartesian11, p, cartesianToCartographicH2); const longitude = Math.atan2(n2.y, n2.x); const latitude = Math.asin(n2.z); const height = Math_default.sign(Cartesian3_default.dot(h, cartesian11)) * Cartesian3_default.magnitude(h); if (!defined_default(result)) { return new Cartographic_default(longitude, latitude, height); } result.longitude = longitude; result.latitude = latitude; result.height = height; return result; } /** * Converts the provided array of cartesians to an array of cartographics. * * @param {Cartesian3[]} cartesians An array of Cartesian positions. * @param {Cartographic[]} [result] The object onto which to store the result. * @returns {Cartographic[]} The modified result parameter or a new Array instance if none was provided. * * @example * //Create an array of Cartesians and determine their Cartographic representation on a WGS84 ellipsoid. * const positions = [new Cesium.Cartesian3(17832.12, 83234.52, 952313.73), * new Cesium.Cartesian3(17832.13, 83234.53, 952313.73), * new Cesium.Cartesian3(17832.14, 83234.54, 952313.73)] * const cartographicPositions = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions); */ cartesianArrayToCartographicArray(cartesians, result) { Check_default.defined("cartesians", cartesians); const length2 = cartesians.length; if (!defined_default(result)) { result = new Array(length2); } else { result.length = length2; } for (let i = 0; i < length2; ++i) { result[i] = this.cartesianToCartographic(cartesians[i], result[i]); } return result; } /** * Scales the provided Cartesian position along the geodetic surface normal * so that it is on the surface of this ellipsoid. If the position is * at the center of the ellipsoid, this function returns undefined. * * @param {Cartesian3} cartesian The Cartesian position to scale. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center. */ scaleToGeodeticSurface(cartesian11, result) { return scaleToGeodeticSurface_default( cartesian11, this._oneOverRadii, this._oneOverRadiiSquared, this._centerToleranceSquared, result ); } /** * Scales the provided Cartesian position along the geocentric surface normal * so that it is on the surface of this ellipsoid. * * @param {Cartesian3} cartesian The Cartesian position to scale. * @param {Cartesian3} [result] The object onto which to store the result. * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided. */ scaleToGeocentricSurface(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); if (!defined_default(result)) { result = new Cartesian3_default(); } const positionX = cartesian11.x; const positionY = cartesian11.y; const positionZ = cartesian11.z; const oneOverRadiiSquared = this._oneOverRadiiSquared; const beta = 1 / Math.sqrt( positionX * positionX * oneOverRadiiSquared.x + positionY * positionY * oneOverRadiiSquared.y + positionZ * positionZ * oneOverRadiiSquared.z ); return Cartesian3_default.multiplyByScalar(cartesian11, beta, result); } /** * Transforms a Cartesian X, Y, Z position to the ellipsoid-scaled space by multiplying * its components by the result of {@link Ellipsoid#oneOverRadii}. * * @param {Cartesian3} position The position to transform. * @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and * return a new instance. * @returns {Cartesian3} The position expressed in the scaled space. The returned instance is the * one passed as the result parameter if it is not undefined, or a new instance of it is. */ transformPositionToScaledSpace(position, result) { if (!defined_default(result)) { result = new Cartesian3_default(); } return Cartesian3_default.multiplyComponents(position, this._oneOverRadii, result); } /** * Transforms a Cartesian X, Y, Z position from the ellipsoid-scaled space by multiplying * its components by the result of {@link Ellipsoid#radii}. * * @param {Cartesian3} position The position to transform. * @param {Cartesian3} [result] The position to which to copy the result, or undefined to create and * return a new instance. * @returns {Cartesian3} The position expressed in the unscaled space. The returned instance is the * one passed as the result parameter if it is not undefined, or a new instance of it is. */ transformPositionFromScaledSpace(position, result) { if (!defined_default(result)) { result = new Cartesian3_default(); } return Cartesian3_default.multiplyComponents(position, this._radii, result); } /** * Compares this Ellipsoid against the provided Ellipsoid componentwise and returns * true if they are equal, false otherwise. * * @param {Ellipsoid} [right] The other Ellipsoid. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return this === right || defined_default(right) && Cartesian3_default.equals(this._radii, right._radii); } /** * Creates a string representing this Ellipsoid in the format '(radii.x, radii.y, radii.z)'. * * @returns {string} A string representing this ellipsoid in the format '(radii.x, radii.y, radii.z)'. */ toString() { return this._radii.toString(); } /** * Computes a point which is the intersection of the surface normal with the z-axis. * * @param {Cartesian3} position the position. must be on the surface of the ellipsoid. * @param {number} [buffer = 0.0] A buffer to subtract from the ellipsoid size when checking if the point is inside the ellipsoid. * In earth case, with common earth datums, there is no need for this buffer since the intersection point is always (relatively) very close to the center. * In WGS84 datum, intersection point is at max z = +-42841.31151331382 (0.673% of z-axis). * Intersection point could be outside the ellipsoid if the ratio of MajorAxis / AxisOfRotation is bigger than the square root of 2 * @param {Cartesian3} [result] The cartesian to which to copy the result, or undefined to create and * return a new instance. * @returns {Cartesian3 | undefined} the intersection point if it's inside the ellipsoid, undefined otherwise * * @exception {DeveloperError} position is required. * @exception {DeveloperError} Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y). * @exception {DeveloperError} Ellipsoid.radii.z must be greater than 0. */ getSurfaceNormalIntersectionWithZAxis(position, buffer2, result) { Check_default.typeOf.object("position", position); if (!Math_default.equalsEpsilon( this._radii.x, this._radii.y, Math_default.EPSILON15 )) { throw new DeveloperError_default( "Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)" ); } Check_default.typeOf.number.greaterThan("Ellipsoid.radii.z", this._radii.z, 0); buffer2 = buffer2 ?? 0; const squaredXOverSquaredZ = this._squaredXOverSquaredZ; if (!defined_default(result)) { result = new Cartesian3_default(); } result.x = 0; result.y = 0; result.z = position.z * (1 - squaredXOverSquaredZ); if (Math.abs(result.z) >= this._radii.z - buffer2) { return void 0; } return result; } /** * Computes the ellipsoid curvatures at a given position on the surface. * * @param {Cartesian3} surfacePosition The position on the ellipsoid surface where curvatures will be calculated. * @param {Cartesian2} [result] The cartesian to which to copy the result, or undefined to create and return a new instance. * @returns {Cartesian2} The local curvature of the ellipsoid surface at the provided position, in east and north directions. * * @exception {DeveloperError} position is required. */ getLocalCurvature(surfacePosition, result) { Check_default.typeOf.object("surfacePosition", surfacePosition); if (!defined_default(result)) { result = new Cartesian2_default(); } const primeVerticalEndpoint = this.getSurfaceNormalIntersectionWithZAxis( surfacePosition, 0, scratchEndpoint ); const primeVerticalRadius = Cartesian3_default.distance( surfacePosition, primeVerticalEndpoint ); const radiusRatio = this.minimumRadius * primeVerticalRadius / this.maximumRadius ** 2; const meridionalRadius = primeVerticalRadius * radiusRatio ** 2; return Cartesian2_default.fromElements( 1 / primeVerticalRadius, 1 / meridionalRadius, result ); } /** * Computes an approximation of the surface area of a rectangle on the surface of an ellipsoid using * Gauss-Legendre 10th order quadrature. * * @param {Rectangle} rectangle The rectangle used for computing the surface area. * @returns {number} The approximate area of the rectangle on the surface of this ellipsoid. */ surfaceArea(rectangle) { Check_default.typeOf.object("rectangle", rectangle); const minLongitude = rectangle.west; let maxLongitude = rectangle.east; const minLatitude = rectangle.south; const maxLatitude = rectangle.north; while (maxLongitude < minLongitude) { maxLongitude += Math_default.TWO_PI; } const radiiSquared = this._radiiSquared; const a22 = radiiSquared.x; const b2 = radiiSquared.y; const c22 = radiiSquared.z; const a2b2 = a22 * b2; return gaussLegendreQuadrature(minLatitude, maxLatitude, function(lat) { const sinPhi = Math.cos(lat); const cosPhi = Math.sin(lat); return Math.cos(lat) * gaussLegendreQuadrature(minLongitude, maxLongitude, function(lon) { const cosTheta = Math.cos(lon); const sinTheta = Math.sin(lon); return Math.sqrt( a2b2 * cosPhi * cosPhi + c22 * (b2 * cosTheta * cosTheta + a22 * sinTheta * sinTheta) * sinPhi * sinPhi ); }); }); } }; Ellipsoid.WGS84 = Object.freeze( new Ellipsoid(6378137, 6378137, 6356752314245179e-9) ); Ellipsoid.UNIT_SPHERE = Object.freeze(new Ellipsoid(1, 1, 1)); Ellipsoid.MOON = Object.freeze( new Ellipsoid( Math_default.LUNAR_RADIUS, Math_default.LUNAR_RADIUS, Math_default.LUNAR_RADIUS ) ); Ellipsoid.MARS = Object.freeze(new Ellipsoid(3396190, 3396190, 3376200)); Ellipsoid._default = Ellipsoid.WGS84; Ellipsoid.packedLength = Cartesian3_default.packedLength; Ellipsoid.prototype.geocentricSurfaceNormal = Cartesian3_default.normalize; var cartographicToCartesianNormal = new Cartesian3_default(); var cartographicToCartesianK = new Cartesian3_default(); var cartesianToCartographicN2 = new Cartesian3_default(); var cartesianToCartographicP2 = new Cartesian3_default(); var cartesianToCartographicH2 = new Cartesian3_default(); var scratchEndpoint = new Cartesian3_default(); var abscissas = [ 0.14887433898163, 0.43339539412925, 0.67940956829902, 0.86506336668898, 0.97390652851717, 0 ]; var weights = [ 0.29552422471475, 0.26926671930999, 0.21908636251598, 0.14945134915058, 0.066671344308684, 0 ]; function gaussLegendreQuadrature(a3, b, func) { Check_default.typeOf.number("a", a3); Check_default.typeOf.number("b", b); Check_default.typeOf.func("func", func); const xMean = 0.5 * (b + a3); const xRange = 0.5 * (b - a3); let sum = 0; for (let i = 0; i < 5; i++) { const dx = xRange * abscissas[i]; sum += weights[i] * (func(xMean + dx) + func(xMean - dx)); } sum *= xRange; return sum; } var Ellipsoid_default = Ellipsoid; // packages/engine/Source/Core/GeographicProjection.js var import_InlineWorkers28 = __toESM(require_InlineWorkers(), 1); var GeographicProjection = class { /** * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid. */ constructor(ellipsoid) { this._ellipsoid = ellipsoid ?? Ellipsoid_default.default; this._semimajorAxis = this._ellipsoid.maximumRadius; this._oneOverSemimajorAxis = 1 / this._semimajorAxis; } /** * Gets the {@link Ellipsoid}. * * @type {Ellipsoid} * @readonly */ get ellipsoid() { return this._ellipsoid; } /** * Projects a set of {@link Cartographic} coordinates, in radians, to map coordinates, in meters. * X and Y are the longitude and latitude, respectively, multiplied by the maximum radius of the * ellipsoid. Z is the unmodified height. * * @param {Cartographic} cartographic The coordinates to project. * @param {Cartesian3} [result] An instance into which to copy the result. If this parameter is * undefined, a new instance is created and returned. * @returns {Cartesian3} The projected coordinates. If the result parameter is not undefined, the * coordinates are copied there and that instance is returned. Otherwise, a new instance is * created and returned. */ project(cartographic2, result) { const semimajorAxis = this._semimajorAxis; const x = cartographic2.longitude * semimajorAxis; const y = cartographic2.latitude * semimajorAxis; const z2 = cartographic2.height; if (!defined_default(result)) { return new Cartesian3_default(x, y, z2); } result.x = x; result.y = y; result.z = z2; return result; } /** * Unprojects a set of projected {@link Cartesian3} coordinates, in meters, to {@link Cartographic} * coordinates, in radians. Longitude and Latitude are the X and Y coordinates, respectively, * divided by the maximum radius of the ellipsoid. Height is the unmodified Z coordinate. * * @param {Cartesian3} cartesian The Cartesian position to unproject with height (z) in meters. * @param {Cartographic} [result] An instance into which to copy the result. If this parameter is * undefined, a new instance is created and returned. * @returns {Cartographic} The unprojected coordinates. If the result parameter is not undefined, the * coordinates are copied there and that instance is returned. Otherwise, a new instance is * created and returned. */ unproject(cartesian11, result) { if (!defined_default(cartesian11)) { throw new DeveloperError_default("cartesian is required"); } const oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis; const longitude = cartesian11.x * oneOverEarthSemimajorAxis; const latitude = cartesian11.y * oneOverEarthSemimajorAxis; const height = cartesian11.z; if (!defined_default(result)) { return new Cartographic_default(longitude, latitude, height); } result.longitude = longitude; result.latitude = latitude; result.height = height; return result; } }; var GeographicProjection_default = GeographicProjection; // packages/engine/Source/Core/Intersect.js var import_InlineWorkers29 = __toESM(require_InlineWorkers(), 1); var Intersect = { /** * Represents that an object is not contained within the frustum. * * @type {number} * @constant */ OUTSIDE: -1, /** * Represents that an object intersects one of the frustum's planes. * * @type {number} * @constant */ INTERSECTING: 0, /** * Represents that an object is fully within the frustum. * * @type {number} * @constant */ INSIDE: 1 }; Object.freeze(Intersect); var Intersect_default = Intersect; // packages/engine/Source/Core/Rectangle.js var import_InlineWorkers69 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Transforms.js var import_InlineWorkers68 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/EarthOrientationParameters.js var import_InlineWorkers62 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/binarySearch.js var import_InlineWorkers30 = __toESM(require_InlineWorkers(), 1); function binarySearch(array, itemToFind, comparator) { Check_default.defined("array", array); Check_default.defined("itemToFind", itemToFind); Check_default.defined("comparator", comparator); let low = 0; let high = array.length - 1; let i; let comparison; while (low <= high) { i = ~~((low + high) / 2); comparison = comparator(array[i], itemToFind); if (comparison < 0) { low = i + 1; continue; } if (comparison > 0) { high = i - 1; continue; } return i; } return ~(high + 1); } var binarySearch_default = binarySearch; // packages/engine/Source/Core/EarthOrientationParametersSample.js var import_InlineWorkers31 = __toESM(require_InlineWorkers(), 1); function EarthOrientationParametersSample(xPoleWander, yPoleWander, xPoleOffset, yPoleOffset, ut1MinusUtc) { this.xPoleWander = xPoleWander; this.yPoleWander = yPoleWander; this.xPoleOffset = xPoleOffset; this.yPoleOffset = yPoleOffset; this.ut1MinusUtc = ut1MinusUtc; } var EarthOrientationParametersSample_default = EarthOrientationParametersSample; // packages/engine/Source/Core/JulianDate.js var import_InlineWorkers37 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/GregorianDate.js var import_InlineWorkers33 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/isLeapYear.js var import_InlineWorkers32 = __toESM(require_InlineWorkers(), 1); function isLeapYear(year) { if (year === null || isNaN(year)) { throw new DeveloperError_default("year is required and must be a number."); } return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; } var isLeapYear_default = isLeapYear; // packages/engine/Source/Core/GregorianDate.js var daysInYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; function GregorianDate(year, month, day, hour, minute, second, millisecond, isLeapSecond) { const minimumYear = 1; const minimumMonth = 1; const minimumDay = 1; const minimumHour = 0; const minimumMinute = 0; const minimumSecond = 0; const minimumMillisecond = 0; year = year ?? minimumYear; month = month ?? minimumMonth; day = day ?? minimumDay; hour = hour ?? minimumHour; minute = minute ?? minimumMinute; second = second ?? minimumSecond; millisecond = millisecond ?? minimumMillisecond; isLeapSecond = isLeapSecond ?? false; validateRange(); validateDate(); this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; this.second = second; this.millisecond = millisecond; this.isLeapSecond = isLeapSecond; function validateRange() { const maximumYear = 9999; const maximumMonth = 12; const maximumDay = 31; const maximumHour = 23; const maximumMinute = 59; const maximumSecond = 59; const excludedMaximumMilisecond = 1e3; Check_default.typeOf.number.greaterThanOrEquals("Year", year, minimumYear); Check_default.typeOf.number.lessThanOrEquals("Year", year, maximumYear); Check_default.typeOf.number.greaterThanOrEquals("Month", month, minimumMonth); Check_default.typeOf.number.lessThanOrEquals("Month", month, maximumMonth); Check_default.typeOf.number.greaterThanOrEquals("Day", day, minimumDay); Check_default.typeOf.number.lessThanOrEquals("Day", day, maximumDay); Check_default.typeOf.number.greaterThanOrEquals("Hour", hour, minimumHour); Check_default.typeOf.number.lessThanOrEquals("Hour", hour, maximumHour); Check_default.typeOf.number.greaterThanOrEquals("Minute", minute, minimumMinute); Check_default.typeOf.number.lessThanOrEquals("Minute", minute, maximumMinute); Check_default.typeOf.bool("IsLeapSecond", isLeapSecond); Check_default.typeOf.number.greaterThanOrEquals("Second", second, minimumSecond); Check_default.typeOf.number.lessThanOrEquals( "Second", second, isLeapSecond ? maximumSecond + 1 : maximumSecond ); Check_default.typeOf.number.greaterThanOrEquals( "Millisecond", millisecond, minimumMillisecond ); Check_default.typeOf.number.lessThan( "Millisecond", millisecond, excludedMaximumMilisecond ); } function validateDate() { const daysInMonth2 = month === 2 && isLeapYear_default(year) ? daysInYear[month - 1] + 1 : daysInYear[month - 1]; if (day > daysInMonth2) { throw new DeveloperError_default("Month and Day represents invalid date"); } } } var GregorianDate_default = GregorianDate; // packages/engine/Source/Core/LeapSecond.js var import_InlineWorkers34 = __toESM(require_InlineWorkers(), 1); function LeapSecond(date, offset) { this.julianDate = date; this.offset = offset; } var LeapSecond_default = LeapSecond; // packages/engine/Source/Core/TimeConstants.js var import_InlineWorkers35 = __toESM(require_InlineWorkers(), 1); var TimeConstants = { /** * The number of seconds in one millisecond: 0.001 * @type {number} * @constant */ SECONDS_PER_MILLISECOND: 1e-3, /** * The number of seconds in one minute: 60. * @type {number} * @constant */ SECONDS_PER_MINUTE: 60, /** * The number of minutes in one hour: 60. * @type {number} * @constant */ MINUTES_PER_HOUR: 60, /** * The number of hours in one day: 24. * @type {number} * @constant */ HOURS_PER_DAY: 24, /** * The number of seconds in one hour: 3600. * @type {number} * @constant */ SECONDS_PER_HOUR: 3600, /** * The number of minutes in one day: 1440. * @type {number} * @constant */ MINUTES_PER_DAY: 1440, /** * The number of seconds in one day, ignoring leap seconds: 86400. * @type {number} * @constant */ SECONDS_PER_DAY: 86400, /** * The number of days in one Julian century: 36525. * @type {number} * @constant */ DAYS_PER_JULIAN_CENTURY: 36525, /** * One trillionth of a second. * @type {number} * @constant */ PICOSECOND: 1e-9, /** * The number of days to subtract from a Julian date to determine the * modified Julian date, which gives the number of days since midnight * on November 17, 1858. * @type {number} * @constant */ MODIFIED_JULIAN_DATE_DIFFERENCE: 24000005e-1 }; Object.freeze(TimeConstants); var TimeConstants_default = TimeConstants; // packages/engine/Source/Core/TimeStandard.js var import_InlineWorkers36 = __toESM(require_InlineWorkers(), 1); var TimeStandard = { /** * Represents the coordinated Universal Time (UTC) time standard. * * UTC is related to TAI according to the relationship * UTC = TAI - deltaT where deltaT is the number of leap * seconds which have been introduced as of the time in TAI. * * @type {number} * @constant */ UTC: 0, /** * Represents the International Atomic Time (TAI) time standard. * TAI is the principal time standard to which the other time standards are related. * * @type {number} * @constant */ TAI: 1 }; Object.freeze(TimeStandard); var TimeStandard_default = TimeStandard; // packages/engine/Source/Core/JulianDate.js var gregorianDateScratch = new GregorianDate_default(); var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; var daysInLeapFebruary = 29; function compareLeapSecondDates(leapSecond, dateToFind) { return JulianDate.compare(leapSecond.julianDate, dateToFind.julianDate); } var binarySearchScratchLeapSecond = new LeapSecond_default(); function convertUtcToTai(julianDate) { binarySearchScratchLeapSecond.julianDate = julianDate; const leapSeconds = JulianDate.leapSeconds; let index = binarySearch_default( leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates ); if (index < 0) { index = ~index; } if (index >= leapSeconds.length) { index = leapSeconds.length - 1; } let offset = leapSeconds[index].offset; if (index > 0) { const difference = JulianDate.secondsDifference( leapSeconds[index].julianDate, julianDate ); if (difference > offset) { index--; offset = leapSeconds[index].offset; } } JulianDate.addSeconds(julianDate, offset, julianDate); } function convertTaiToUtc(julianDate, result) { binarySearchScratchLeapSecond.julianDate = julianDate; const leapSeconds = JulianDate.leapSeconds; let index = binarySearch_default( leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates ); if (index < 0) { index = ~index; } if (index === 0) { return JulianDate.addSeconds(julianDate, -leapSeconds[0].offset, result); } if (index >= leapSeconds.length) { return JulianDate.addSeconds( julianDate, -leapSeconds[index - 1].offset, result ); } const difference = JulianDate.secondsDifference( leapSeconds[index].julianDate, julianDate ); if (difference === 0) { return JulianDate.addSeconds( julianDate, -leapSeconds[index].offset, result ); } if (difference <= 1) { return void 0; } return JulianDate.addSeconds( julianDate, -leapSeconds[index - 1].offset, result ); } function setComponents(wholeDays, secondsOfDay, julianDate) { const extraDays = secondsOfDay / TimeConstants_default.SECONDS_PER_DAY | 0; wholeDays += extraDays; secondsOfDay -= TimeConstants_default.SECONDS_PER_DAY * extraDays; if (secondsOfDay < 0) { wholeDays--; secondsOfDay += TimeConstants_default.SECONDS_PER_DAY; } julianDate.dayNumber = wholeDays; julianDate.secondsOfDay = secondsOfDay; return julianDate; } function computeJulianDateComponents(year, month, day, hour, minute, second, millisecond) { const a3 = (month - 14) / 12 | 0; const b = year + 4800 + a3; let dayNumber = (1461 * b / 4 | 0) + (367 * (month - 2 - 12 * a3) / 12 | 0) - (3 * ((b + 100) / 100 | 0) / 4 | 0) + day - 32075; hour = hour - 12; if (hour < 0) { hour += 24; } const secondsOfDay = second + (hour * TimeConstants_default.SECONDS_PER_HOUR + minute * TimeConstants_default.SECONDS_PER_MINUTE + millisecond * TimeConstants_default.SECONDS_PER_MILLISECOND); if (secondsOfDay >= 43200) { dayNumber -= 1; } return [dayNumber, secondsOfDay]; } var matchCalendarYear = /^(\d{4})$/; var matchCalendarMonth = /^(\d{4})-(\d{2})$/; var matchOrdinalDate = /^(\d{4})-?(\d{3})$/; var matchWeekDate = /^(\d{4})-?W(\d{2})-?(\d{1})?$/; var matchCalendarDate = /^(\d{4})-?(\d{2})-?(\d{2})$/; var utcOffset = /([Z+\-])?(\d{2})?:?(\d{2})?$/; var matchHours = /^(\d{2})(\.\d+)?/.source + utcOffset.source; var matchHoursMinutes = /^(\d{2}):?(\d{2})(\.\d+)?/.source + utcOffset.source; var matchHoursMinutesSeconds = /^(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?/.source + utcOffset.source; var iso8601ErrorMessage = "Invalid ISO 8601 date."; var JulianDate = class _JulianDate { /** * @param {number} [julianDayNumber=0.0] The Julian Day Number representing the number of whole days. Fractional days will also be handled correctly. * @param {number} [secondsOfDay=0.0] The number of seconds into the current Julian Day Number. Fractional seconds, negative seconds and seconds greater than a day will be handled correctly. * @param {TimeStandard} [timeStandard=TimeStandard.UTC] The time standard in which the first two parameters are defined. */ constructor(julianDayNumber, secondsOfDay, timeStandard) { this.dayNumber = void 0; this.secondsOfDay = void 0; julianDayNumber = julianDayNumber ?? 0; secondsOfDay = secondsOfDay ?? 0; timeStandard = timeStandard ?? TimeStandard_default.UTC; const wholeDays = julianDayNumber | 0; secondsOfDay = secondsOfDay + (julianDayNumber - wholeDays) * TimeConstants_default.SECONDS_PER_DAY; setComponents(wholeDays, secondsOfDay, this); if (timeStandard === TimeStandard_default.UTC) { convertUtcToTai(this); } } /** * Creates a new instance from a GregorianDate. * * @param {GregorianDate} date A GregorianDate. * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. * * @exception {DeveloperError} date must be a valid GregorianDate. */ static fromGregorianDate(date, result) { if (!(date instanceof GregorianDate_default)) { throw new DeveloperError_default("date must be a valid GregorianDate."); } const components = computeJulianDateComponents( date.year, date.month, date.day, date.hour, date.minute, date.second, date.millisecond ); if (!defined_default(result)) { return new _JulianDate(components[0], components[1], TimeStandard_default.UTC); } setComponents(components[0], components[1], result); convertUtcToTai(result); return result; } /** * Creates a new instance from a JavaScript Date. * * @param {Date} date A JavaScript Date. * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. * * @exception {DeveloperError} date must be a valid JavaScript Date. */ static fromDate(date, result) { if (!(date instanceof Date) || isNaN(date.getTime())) { throw new DeveloperError_default("date must be a valid JavaScript Date."); } const components = computeJulianDateComponents( date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds() ); if (!defined_default(result)) { return new _JulianDate(components[0], components[1], TimeStandard_default.UTC); } setComponents(components[0], components[1], result); convertUtcToTai(result); return result; } /** * Creates a new instance from a from an {@link http://en.wikipedia.org/wiki/ISO_8601|ISO 8601} date. * This method is superior to Date.parse because it will handle all valid formats defined by the ISO 8601 * specification, including leap seconds and sub-millisecond times, which discarded by most JavaScript implementations. * * @param {string} iso8601String An ISO 8601 date. * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. * * @exception {DeveloperError} Invalid ISO 8601 date. */ static fromIso8601(iso8601String, result) { if (typeof iso8601String !== "string") { throw new DeveloperError_default(iso8601ErrorMessage); } iso8601String = iso8601String.replace(",", "."); let tokens = iso8601String.split("T"); let year; let month = 1; let day = 1; let hour = 0; let minute = 0; let second = 0; let millisecond = 0; const date = tokens[0]; const time = tokens[1]; let tmp2; let inLeapYear; if (!defined_default(date)) { throw new DeveloperError_default(iso8601ErrorMessage); } let dashCount; tokens = date.match(matchCalendarDate); if (tokens !== null) { dashCount = date.split("-").length - 1; if (dashCount > 0 && dashCount !== 2) { throw new DeveloperError_default(iso8601ErrorMessage); } year = +tokens[1]; month = +tokens[2]; day = +tokens[3]; } else { tokens = date.match(matchCalendarMonth); if (tokens !== null) { year = +tokens[1]; month = +tokens[2]; } else { tokens = date.match(matchCalendarYear); if (tokens !== null) { year = +tokens[1]; } else { let dayOfYear; tokens = date.match(matchOrdinalDate); if (tokens !== null) { year = +tokens[1]; dayOfYear = +tokens[2]; inLeapYear = isLeapYear_default(year); if (dayOfYear < 1 || inLeapYear && dayOfYear > 366 || !inLeapYear && dayOfYear > 365) { throw new DeveloperError_default(iso8601ErrorMessage); } } else { tokens = date.match(matchWeekDate); if (tokens !== null) { year = +tokens[1]; const weekNumber = +tokens[2]; const dayOfWeek = +tokens[3] || 0; dashCount = date.split("-").length - 1; if (dashCount > 0 && (!defined_default(tokens[3]) && dashCount !== 1 || defined_default(tokens[3]) && dashCount !== 2)) { throw new DeveloperError_default(iso8601ErrorMessage); } const january4 = new Date(Date.UTC(year, 0, 4)); dayOfYear = weekNumber * 7 + dayOfWeek - january4.getUTCDay() - 3; } else { throw new DeveloperError_default(iso8601ErrorMessage); } } tmp2 = new Date(Date.UTC(year, 0, 1)); tmp2.setUTCDate(dayOfYear); month = tmp2.getUTCMonth() + 1; day = tmp2.getUTCDate(); } } } inLeapYear = isLeapYear_default(year); if (month < 1 || month > 12 || day < 1 || (month !== 2 || !inLeapYear) && day > daysInMonth[month - 1] || inLeapYear && month === 2 && day > daysInLeapFebruary) { throw new DeveloperError_default(iso8601ErrorMessage); } let offsetIndex; if (defined_default(time)) { tokens = time.match(matchHoursMinutesSeconds); if (tokens !== null) { dashCount = time.split(":").length - 1; if (dashCount > 0 && dashCount !== 2 && dashCount !== 3) { throw new DeveloperError_default(iso8601ErrorMessage); } hour = +tokens[1]; minute = +tokens[2]; second = +tokens[3]; millisecond = +(tokens[4] || 0) * 1e3; offsetIndex = 5; } else { tokens = time.match(matchHoursMinutes); if (tokens !== null) { dashCount = time.split(":").length - 1; if (dashCount > 2) { throw new DeveloperError_default(iso8601ErrorMessage); } hour = +tokens[1]; minute = +tokens[2]; second = +(tokens[3] || 0) * 60; offsetIndex = 4; } else { tokens = time.match(matchHours); if (tokens !== null) { hour = +tokens[1]; minute = +(tokens[2] || 0) * 60; offsetIndex = 3; } else { throw new DeveloperError_default(iso8601ErrorMessage); } } } if (minute >= 60 || second >= 61 || hour > 24 || hour === 24 && (minute > 0 || second > 0 || millisecond > 0)) { throw new DeveloperError_default(iso8601ErrorMessage); } const offset = tokens[offsetIndex]; const offsetHours = +tokens[offsetIndex + 1]; const offsetMinutes = +(tokens[offsetIndex + 2] || 0); switch (offset) { case "+": hour = hour - offsetHours; minute = minute - offsetMinutes; break; case "-": hour = hour + offsetHours; minute = minute + offsetMinutes; break; case "Z": break; default: minute = minute + new Date( Date.UTC(year, month - 1, day, hour, minute) ).getTimezoneOffset(); break; } } const isLeapSecond = second === 60; if (isLeapSecond) { second--; } while (minute >= 60) { minute -= 60; hour++; } while (hour >= 24) { hour -= 24; day++; } tmp2 = inLeapYear && month === 2 ? daysInLeapFebruary : daysInMonth[month - 1]; while (day > tmp2) { day -= tmp2; month++; if (month > 12) { month -= 12; year++; } tmp2 = inLeapYear && month === 2 ? daysInLeapFebruary : daysInMonth[month - 1]; } while (minute < 0) { minute += 60; hour--; } while (hour < 0) { hour += 24; day--; } while (day < 1) { month--; if (month < 1) { month += 12; year--; } tmp2 = inLeapYear && month === 2 ? daysInLeapFebruary : daysInMonth[month - 1]; day += tmp2; } const components = computeJulianDateComponents( year, month, day, hour, minute, second, millisecond ); if (!defined_default(result)) { result = new _JulianDate(components[0], components[1], TimeStandard_default.UTC); } else { setComponents(components[0], components[1], result); convertUtcToTai(result); } if (isLeapSecond) { _JulianDate.addSeconds(result, 1, result); } return result; } /** * Creates a new instance that represents the current system time. * This is equivalent to calling JulianDate.fromDate(new Date());. * * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. */ static now(result) { return _JulianDate.fromDate(/* @__PURE__ */ new Date(), result); } /** * Creates a {@link GregorianDate} from the provided instance. * * @param {JulianDate} julianDate The date to be converted. * @param {GregorianDate} [result] An existing instance to use for the result. * @returns {GregorianDate} The modified result parameter or a new instance if none was provided. */ static toGregorianDate(julianDate, result) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } let isLeapSecond = false; let thisUtc = convertTaiToUtc(julianDate, toGregorianDateScratch); if (!defined_default(thisUtc)) { _JulianDate.addSeconds(julianDate, -1, toGregorianDateScratch); thisUtc = convertTaiToUtc(toGregorianDateScratch, toGregorianDateScratch); isLeapSecond = true; } let julianDayNumber = thisUtc.dayNumber; const secondsOfDay = thisUtc.secondsOfDay; if (secondsOfDay >= 43200) { julianDayNumber += 1; } let L = julianDayNumber + 68569 | 0; const N = 4 * L / 146097 | 0; L = L - ((146097 * N + 3) / 4 | 0) | 0; const I = 4e3 * (L + 1) / 1461001 | 0; L = L - (1461 * I / 4 | 0) + 31 | 0; const J2 = 80 * L / 2447 | 0; const day = L - (2447 * J2 / 80 | 0) | 0; L = J2 / 11 | 0; const month = J2 + 2 - 12 * L | 0; const year = 100 * (N - 49) + I + L | 0; let hour = secondsOfDay / TimeConstants_default.SECONDS_PER_HOUR | 0; let remainingSeconds = secondsOfDay - hour * TimeConstants_default.SECONDS_PER_HOUR; const minute = remainingSeconds / TimeConstants_default.SECONDS_PER_MINUTE | 0; remainingSeconds = remainingSeconds - minute * TimeConstants_default.SECONDS_PER_MINUTE; let second = remainingSeconds | 0; const millisecond = (remainingSeconds - second) / TimeConstants_default.SECONDS_PER_MILLISECOND; hour += 12; if (hour > 23) { hour -= 24; } if (isLeapSecond) { second += 1; } if (!defined_default(result)) { return new GregorianDate_default( year, month, day, hour, minute, second, millisecond, isLeapSecond ); } result.year = year; result.month = month; result.day = day; result.hour = hour; result.minute = minute; result.second = second; result.millisecond = millisecond; result.isLeapSecond = isLeapSecond; return result; } /** * Creates a JavaScript Date from the provided instance. * Since JavaScript dates are only accurate to the nearest millisecond and * cannot represent a leap second, consider using {@link JulianDate.toGregorianDate} instead. * If the provided JulianDate is during a leap second, the previous second is used. * * @param {JulianDate} julianDate The date to be converted. * @returns {Date} A new instance representing the provided date. */ static toDate(julianDate) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } const gDate = _JulianDate.toGregorianDate(julianDate, gregorianDateScratch); let second = gDate.second; if (gDate.isLeapSecond) { second -= 1; } return new Date( Date.UTC( gDate.year, gDate.month - 1, gDate.day, gDate.hour, gDate.minute, second, gDate.millisecond ) ); } /** * Creates an ISO8601 representation of the provided date. * * @param {JulianDate} julianDate The date to be converted. * @param {number} [precision] The number of fractional digits used to represent the seconds component. By default, the most precise representation is used. * @returns {string} The ISO8601 representation of the provided date. */ static toIso8601(julianDate, precision) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } const gDate = _JulianDate.toGregorianDate(julianDate, gregorianDateScratch); let year = gDate.year; let month = gDate.month; let day = gDate.day; let hour = gDate.hour; const minute = gDate.minute; const second = gDate.second; const millisecond = gDate.millisecond; if (year === 1e4 && month === 1 && day === 1 && hour === 0 && minute === 0 && second === 0 && millisecond === 0) { year = 9999; month = 12; day = 31; hour = 24; } let millisecondStr; if (!defined_default(precision) && millisecond !== 0) { const millisecondHundreds = millisecond * 0.01; millisecondStr = millisecondHundreds < 1e-6 ? millisecondHundreds.toFixed(20).replace(".", "").replace(/0+$/, "") : millisecondHundreds.toString().replace(".", ""); return `${year.toString().padStart(4, "0")}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}.${millisecondStr}Z`; } if (!defined_default(precision) || precision === 0) { return `${year.toString().padStart(4, "0")}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}Z`; } millisecondStr = (millisecond * 0.01).toFixed(precision).replace(".", "").slice(0, precision); return `${year.toString().padStart(4, "0")}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:${second.toString().padStart(2, "0")}.${millisecondStr}Z`; } /** * Duplicates a JulianDate instance. * * @param {JulianDate} julianDate The date to duplicate. * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. Returns undefined if julianDate is undefined. */ static clone(julianDate, result) { if (!defined_default(julianDate)) { return void 0; } if (!defined_default(result)) { return new _JulianDate( julianDate.dayNumber, julianDate.secondsOfDay, TimeStandard_default.TAI ); } result.dayNumber = julianDate.dayNumber; result.secondsOfDay = julianDate.secondsOfDay; return result; } /** * Compares two instances. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {number} A negative value if left is less than right, a positive value if left is greater than right, or zero if left and right are equal. */ static compare(left, right) { if (!defined_default(left)) { throw new DeveloperError_default("left is required."); } if (!defined_default(right)) { throw new DeveloperError_default("right is required."); } const julianDayNumberDifference = left.dayNumber - right.dayNumber; if (julianDayNumberDifference !== 0) { return julianDayNumberDifference; } return left.secondsOfDay - right.secondsOfDay; } /** * Compares two instances and returns true if they are equal, false otherwise. * * @param {JulianDate} [left] The first instance. * @param {JulianDate} [right] The second instance. * @returns {boolean} true if the dates are equal; otherwise, false. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.dayNumber === right.dayNumber && left.secondsOfDay === right.secondsOfDay; } /** * Compares two instances and returns true if they are within epsilon seconds of * each other. That is, in order for the dates to be considered equal (and for * this function to return true), the absolute value of the difference between them, in * seconds, must be less than epsilon. * * @param {JulianDate} [left] The first instance. * @param {JulianDate} [right] The second instance. * @param {number} [epsilon=0] The maximum number of seconds that should separate the two instances. * @returns {boolean} true if the two dates are within epsilon seconds of each other; otherwise false. */ static equalsEpsilon(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(_JulianDate.secondsDifference(left, right)) <= epsilon; } /** * Computes the total number of whole and fractional days represented by the provided instance. * * @param {JulianDate} julianDate The date. * @returns {number} The Julian date as single floating point number. */ static totalDays(julianDate) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } return julianDate.dayNumber + julianDate.secondsOfDay / TimeConstants_default.SECONDS_PER_DAY; } /** * Computes the difference in seconds between the provided instance. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {number} The difference, in seconds, when subtracting right from left. */ static secondsDifference(left, right) { if (!defined_default(left)) { throw new DeveloperError_default("left is required."); } if (!defined_default(right)) { throw new DeveloperError_default("right is required."); } const dayDifference = (left.dayNumber - right.dayNumber) * TimeConstants_default.SECONDS_PER_DAY; return dayDifference + (left.secondsOfDay - right.secondsOfDay); } /** * Computes the difference in days between the provided instance. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {number} The difference, in days, when subtracting right from left. */ static daysDifference(left, right) { if (!defined_default(left)) { throw new DeveloperError_default("left is required."); } if (!defined_default(right)) { throw new DeveloperError_default("right is required."); } const dayDifference = left.dayNumber - right.dayNumber; const secondDifference = (left.secondsOfDay - right.secondsOfDay) / TimeConstants_default.SECONDS_PER_DAY; return dayDifference + secondDifference; } /** * Computes the number of seconds the provided instance is ahead of UTC. * * @param {JulianDate} julianDate The date. * @returns {number} The number of seconds the provided instance is ahead of UTC */ static computeTaiMinusUtc(julianDate) { binarySearchScratchLeapSecond.julianDate = julianDate; const leapSeconds = _JulianDate.leapSeconds; let index = binarySearch_default( leapSeconds, binarySearchScratchLeapSecond, compareLeapSecondDates ); if (index < 0) { index = ~index; --index; if (index < 0) { index = 0; } } return leapSeconds[index].offset; } /** * Adds the provided number of seconds to the provided date instance. * * @param {JulianDate} julianDate The date. * @param {number} seconds The number of seconds to add or subtract. * @param {JulianDate} result An existing instance to use for the result. * @returns {JulianDate} The modified result parameter. */ static addSeconds(julianDate, seconds, result) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } if (!defined_default(seconds)) { throw new DeveloperError_default("seconds is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } return setComponents( julianDate.dayNumber, julianDate.secondsOfDay + seconds, result ); } /** * Adds the provided number of minutes to the provided date instance. * * @param {JulianDate} julianDate The date. * @param {number} minutes The number of minutes to add or subtract. * @param {JulianDate} result An existing instance to use for the result. * @returns {JulianDate} The modified result parameter. */ static addMinutes(julianDate, minutes, result) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } if (!defined_default(minutes)) { throw new DeveloperError_default("minutes is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const newSecondsOfDay = julianDate.secondsOfDay + minutes * TimeConstants_default.SECONDS_PER_MINUTE; return setComponents(julianDate.dayNumber, newSecondsOfDay, result); } /** * Adds the provided number of hours to the provided date instance. * * @param {JulianDate} julianDate The date. * @param {number} hours The number of hours to add or subtract. * @param {JulianDate} result An existing instance to use for the result. * @returns {JulianDate} The modified result parameter. */ static addHours(julianDate, hours, result) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } if (!defined_default(hours)) { throw new DeveloperError_default("hours is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const newSecondsOfDay = julianDate.secondsOfDay + hours * TimeConstants_default.SECONDS_PER_HOUR; return setComponents(julianDate.dayNumber, newSecondsOfDay, result); } /** * Adds the provided number of days to the provided date instance. * * @param {JulianDate} julianDate The date. * @param {number} days The number of days to add or subtract. * @param {JulianDate} result An existing instance to use for the result. * @returns {JulianDate} The modified result parameter. */ static addDays(julianDate, days, result) { if (!defined_default(julianDate)) { throw new DeveloperError_default("julianDate is required."); } if (!defined_default(days)) { throw new DeveloperError_default("days is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const newJulianDayNumber = julianDate.dayNumber + days; return setComponents(newJulianDayNumber, julianDate.secondsOfDay, result); } /** * Compares the provided instances and returns true if left is earlier than right, false otherwise. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {boolean} true if left is earlier than right, false otherwise. */ static lessThan(left, right) { return _JulianDate.compare(left, right) < 0; } /** * Compares the provided instances and returns true if left is earlier than or equal to right, false otherwise. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {boolean} true if left is earlier than or equal to right, false otherwise. */ static lessThanOrEquals(left, right) { return _JulianDate.compare(left, right) <= 0; } /** * Compares the provided instances and returns true if left is later than right, false otherwise. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {boolean} true if left is later than right, false otherwise. */ static greaterThan(left, right) { return _JulianDate.compare(left, right) > 0; } /** * Compares the provided instances and returns true if left is later than or equal to right, false otherwise. * * @param {JulianDate} left The first instance. * @param {JulianDate} right The second instance. * @returns {boolean} true if left is later than or equal to right, false otherwise. */ static greaterThanOrEquals(left, right) { return _JulianDate.compare(left, right) >= 0; } /** * Duplicates this instance. * * @param {JulianDate} [result] An existing instance to use for the result. * @returns {JulianDate} The modified result parameter or a new instance if none was provided. */ clone(result) { return _JulianDate.clone(this, result); } /** * Compares this and the provided instance and returns true if they are equal, false otherwise. * * @param {JulianDate} [right] The second instance. * @returns {boolean} true if the dates are equal; otherwise, false. */ equals(right) { return _JulianDate.equals(this, right); } /** * Compares this and the provided instance and returns true if they are within epsilon seconds of * each other. That is, in order for the dates to be considered equal (and for * this function to return true), the absolute value of the difference between them, in * seconds, must be less than epsilon. * * @param {JulianDate} [right] The second instance. * @param {number} [epsilon=0] The maximum number of seconds that should separate the two instances. * @returns {boolean} true if the two dates are within epsilon seconds of each other; otherwise false. */ equalsEpsilon(right, epsilon) { return _JulianDate.equalsEpsilon(this, right, epsilon); } /** * Creates a string representing this date in ISO8601 format. * * @returns {string} A string representing this date in ISO8601 format. */ toString() { return _JulianDate.toIso8601(this); } }; var toGregorianDateScratch = new JulianDate(0, 0, TimeStandard_default.TAI); JulianDate.leapSeconds = [ new LeapSecond_default(new JulianDate(2441317, 43210, TimeStandard_default.TAI), 10), // January 1, 1972 00:00:00 UTC new LeapSecond_default(new JulianDate(2441499, 43211, TimeStandard_default.TAI), 11), // July 1, 1972 00:00:00 UTC new LeapSecond_default(new JulianDate(2441683, 43212, TimeStandard_default.TAI), 12), // January 1, 1973 00:00:00 UTC new LeapSecond_default(new JulianDate(2442048, 43213, TimeStandard_default.TAI), 13), // January 1, 1974 00:00:00 UTC new LeapSecond_default(new JulianDate(2442413, 43214, TimeStandard_default.TAI), 14), // January 1, 1975 00:00:00 UTC new LeapSecond_default(new JulianDate(2442778, 43215, TimeStandard_default.TAI), 15), // January 1, 1976 00:00:00 UTC new LeapSecond_default(new JulianDate(2443144, 43216, TimeStandard_default.TAI), 16), // January 1, 1977 00:00:00 UTC new LeapSecond_default(new JulianDate(2443509, 43217, TimeStandard_default.TAI), 17), // January 1, 1978 00:00:00 UTC new LeapSecond_default(new JulianDate(2443874, 43218, TimeStandard_default.TAI), 18), // January 1, 1979 00:00:00 UTC new LeapSecond_default(new JulianDate(2444239, 43219, TimeStandard_default.TAI), 19), // January 1, 1980 00:00:00 UTC new LeapSecond_default(new JulianDate(2444786, 43220, TimeStandard_default.TAI), 20), // July 1, 1981 00:00:00 UTC new LeapSecond_default(new JulianDate(2445151, 43221, TimeStandard_default.TAI), 21), // July 1, 1982 00:00:00 UTC new LeapSecond_default(new JulianDate(2445516, 43222, TimeStandard_default.TAI), 22), // July 1, 1983 00:00:00 UTC new LeapSecond_default(new JulianDate(2446247, 43223, TimeStandard_default.TAI), 23), // July 1, 1985 00:00:00 UTC new LeapSecond_default(new JulianDate(2447161, 43224, TimeStandard_default.TAI), 24), // January 1, 1988 00:00:00 UTC new LeapSecond_default(new JulianDate(2447892, 43225, TimeStandard_default.TAI), 25), // January 1, 1990 00:00:00 UTC new LeapSecond_default(new JulianDate(2448257, 43226, TimeStandard_default.TAI), 26), // January 1, 1991 00:00:00 UTC new LeapSecond_default(new JulianDate(2448804, 43227, TimeStandard_default.TAI), 27), // July 1, 1992 00:00:00 UTC new LeapSecond_default(new JulianDate(2449169, 43228, TimeStandard_default.TAI), 28), // July 1, 1993 00:00:00 UTC new LeapSecond_default(new JulianDate(2449534, 43229, TimeStandard_default.TAI), 29), // July 1, 1994 00:00:00 UTC new LeapSecond_default(new JulianDate(2450083, 43230, TimeStandard_default.TAI), 30), // January 1, 1996 00:00:00 UTC new LeapSecond_default(new JulianDate(2450630, 43231, TimeStandard_default.TAI), 31), // July 1, 1997 00:00:00 UTC new LeapSecond_default(new JulianDate(2451179, 43232, TimeStandard_default.TAI), 32), // January 1, 1999 00:00:00 UTC new LeapSecond_default(new JulianDate(2453736, 43233, TimeStandard_default.TAI), 33), // January 1, 2006 00:00:00 UTC new LeapSecond_default(new JulianDate(2454832, 43234, TimeStandard_default.TAI), 34), // January 1, 2009 00:00:00 UTC new LeapSecond_default(new JulianDate(2456109, 43235, TimeStandard_default.TAI), 35), // July 1, 2012 00:00:00 UTC new LeapSecond_default(new JulianDate(2457204, 43236, TimeStandard_default.TAI), 36), // July 1, 2015 00:00:00 UTC new LeapSecond_default(new JulianDate(2457754, 43237, TimeStandard_default.TAI), 37) // January 1, 2017 00:00:00 UTC ]; var JulianDate_default = JulianDate; // packages/engine/Source/Core/Resource.js var import_InlineWorkers61 = __toESM(require_InlineWorkers(), 1); var import_urijs6 = __toESM(require_URI(), 1); // packages/engine/Source/Core/appendForwardSlash.js var import_InlineWorkers38 = __toESM(require_InlineWorkers(), 1); function appendForwardSlash(url2) { if (url2.length === 0 || url2[url2.length - 1] !== "/") { url2 = `${url2}/`; } return url2; } var appendForwardSlash_default = appendForwardSlash; // packages/engine/Source/Core/clone.js var import_InlineWorkers39 = __toESM(require_InlineWorkers(), 1); function clone(object2, deep) { if (object2 === null || typeof object2 !== "object") { return object2; } deep = deep ?? false; const result = new object2.constructor(); for (const propertyName in object2) { if (object2.hasOwnProperty(propertyName)) { let value = object2[propertyName]; if (deep) { value = clone(value, deep); } result[propertyName] = value; } } return result; } var clone_default = clone; // packages/engine/Source/Core/combine.js var import_InlineWorkers40 = __toESM(require_InlineWorkers(), 1); function combine(object1, object2, deep) { deep = deep ?? false; const result = {}; const object1Defined = defined_default(object1); const object2Defined = defined_default(object2); let property; let object1Value; let object2Value; if (object1Defined) { for (property in object1) { if (object1.hasOwnProperty(property)) { object1Value = object1[property]; if (object2Defined && deep && typeof object1Value === "object" && object2.hasOwnProperty(property)) { object2Value = object2[property]; if (typeof object2Value === "object") { result[property] = combine(object1Value, object2Value, deep); } else { result[property] = object1Value; } } else { result[property] = object1Value; } } } } if (object2Defined) { for (property in object2) { if (object2.hasOwnProperty(property) && !result.hasOwnProperty(property)) { object2Value = object2[property]; result[property] = object2Value; } } } return result; } var combine_default = combine; // packages/engine/Source/Core/defer.js var import_InlineWorkers41 = __toESM(require_InlineWorkers(), 1); function defer() { let resolve2; let reject; const promise = new Promise(function(res, rej) { resolve2 = res; reject = rej; }); return { resolve: resolve2, reject, promise }; } var defer_default = defer; // packages/engine/Source/Core/getAbsoluteUri.js var import_InlineWorkers42 = __toESM(require_InlineWorkers(), 1); var import_urijs = __toESM(require_URI(), 1); function getAbsoluteUri(relative, base) { let documentObject; if (typeof document !== "undefined") { documentObject = document; } return getAbsoluteUri._implementation(relative, base, documentObject); } getAbsoluteUri._implementation = function(relative, base, documentObject) { if (!defined_default(relative)) { throw new DeveloperError_default("relative uri is required."); } if (!defined_default(base)) { if (typeof documentObject === "undefined") { return relative; } base = documentObject.baseURI ?? documentObject.location.href; } const relativeUri = new import_urijs.default(relative); if (relativeUri.scheme() !== "") { return relativeUri.toString(); } return relativeUri.absoluteTo(base).toString(); }; var getAbsoluteUri_default = getAbsoluteUri; // packages/engine/Source/Core/getBaseUri.js var import_InlineWorkers43 = __toESM(require_InlineWorkers(), 1); var import_urijs2 = __toESM(require_URI(), 1); function getBaseUri(uri, includeQuery) { if (!defined_default(uri)) { throw new DeveloperError_default("uri is required."); } let basePath = ""; const i = uri.lastIndexOf("/"); if (i !== -1) { basePath = uri.substring(0, i + 1); } if (!includeQuery) { return basePath; } uri = new import_urijs2.default(uri); if (uri.query().length !== 0) { basePath += `?${uri.query()}`; } if (uri.fragment().length !== 0) { basePath += `#${uri.fragment()}`; } return basePath; } var getBaseUri_default = getBaseUri; // packages/engine/Source/Core/getExtensionFromUri.js var import_InlineWorkers44 = __toESM(require_InlineWorkers(), 1); var import_urijs3 = __toESM(require_URI(), 1); function getExtensionFromUri(uri) { if (!defined_default(uri)) { throw new DeveloperError_default("uri is required."); } const uriObject = new import_urijs3.default(uri); uriObject.normalize(); let path = uriObject.path(); let index = path.lastIndexOf("/"); if (index !== -1) { path = path.substr(index + 1); } index = path.lastIndexOf("."); if (index === -1) { path = ""; } else { path = path.substr(index + 1); } return path; } var getExtensionFromUri_default = getExtensionFromUri; // packages/engine/Source/Core/getImagePixels.js var import_InlineWorkers45 = __toESM(require_InlineWorkers(), 1); var context2DsByWidthAndHeight = {}; function getImagePixels(image, width, height) { if (!defined_default(width)) { width = image.width; } if (!defined_default(height)) { height = image.height; } let context2DsByHeight = context2DsByWidthAndHeight[width]; if (!defined_default(context2DsByHeight)) { context2DsByHeight = {}; context2DsByWidthAndHeight[width] = context2DsByHeight; } let context2d = context2DsByHeight[height]; if (!defined_default(context2d)) { const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; context2d = canvas.getContext("2d", { willReadFrequently: true }); context2d.globalCompositeOperation = "copy"; context2DsByHeight[height] = context2d; } context2d.drawImage(image, 0, 0, width, height); return context2d.getImageData(0, 0, width, height).data; } var getImagePixels_default = getImagePixels; // packages/engine/Source/Core/isBlobUri.js var import_InlineWorkers46 = __toESM(require_InlineWorkers(), 1); var blobUriRegex = /^blob:/i; function isBlobUri(uri) { Check_default.typeOf.string("uri", uri); return blobUriRegex.test(uri); } var isBlobUri_default = isBlobUri; // packages/engine/Source/Core/isCrossOriginUrl.js var import_InlineWorkers47 = __toESM(require_InlineWorkers(), 1); var a; function isCrossOriginUrl(url2) { if (!defined_default(a)) { a = document.createElement("a"); } a.href = window.location.href; const host = a.host; const protocol = a.protocol; a.href = url2; a.href = a.href; return protocol !== a.protocol || host !== a.host; } var isCrossOriginUrl_default = isCrossOriginUrl; // packages/engine/Source/Core/isDataUri.js var import_InlineWorkers48 = __toESM(require_InlineWorkers(), 1); var dataUriRegex = /^data:/i; function isDataUri(uri) { Check_default.typeOf.string("uri", uri); return dataUriRegex.test(uri); } var isDataUri_default = isDataUri; // packages/engine/Source/Core/loadAndExecuteScript.js var import_InlineWorkers49 = __toESM(require_InlineWorkers(), 1); function loadAndExecuteScript(url2) { const script = document.createElement("script"); script.async = true; script.src = url2; return new Promise((resolve2, reject) => { if (window.crossOriginIsolated) { script.setAttribute("crossorigin", "anonymous"); } const head = document.getElementsByTagName("head")[0]; script.onload = function() { script.onload = void 0; head.removeChild(script); resolve2(); }; script.onerror = function(e) { reject(e); }; head.appendChild(script); }); } var loadAndExecuteScript_default = loadAndExecuteScript; // packages/engine/Source/Core/objectToQuery.js var import_InlineWorkers50 = __toESM(require_InlineWorkers(), 1); function objectToQuery(obj) { if (!defined_default(obj)) { throw new DeveloperError_default("obj is required."); } let result = ""; for (const propName in obj) { if (obj.hasOwnProperty(propName)) { const value = obj[propName]; const part = `${encodeURIComponent(propName)}=`; if (Array.isArray(value)) { for (let i = 0, len = value.length; i < len; ++i) { result += `${part + encodeURIComponent(value[i])}&`; } } else { result += `${part + encodeURIComponent(value)}&`; } } } result = result.slice(0, -1); return result; } var objectToQuery_default = objectToQuery; // packages/engine/Source/Core/queryToObject.js var import_InlineWorkers51 = __toESM(require_InlineWorkers(), 1); function queryToObject(queryString) { if (!defined_default(queryString)) { throw new DeveloperError_default("queryString is required."); } const result = {}; if (queryString === "") { return result; } const parts = queryString.replace(/\+/g, "%20").split(/[&;]/); for (let i = 0, len = parts.length; i < len; ++i) { const subparts = parts[i].split("="); const name = decodeURIComponent(subparts[0]); let value = subparts[1]; if (defined_default(value)) { value = decodeURIComponent(value); } else { value = ""; } const resultValue = result[name]; if (typeof resultValue === "string") { result[name] = [resultValue, value]; } else if (Array.isArray(resultValue)) { resultValue.push(value); } else { result[name] = value; } } return result; } var queryToObject_default = queryToObject; // packages/engine/Source/Core/Request.js var import_InlineWorkers54 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/RequestState.js var import_InlineWorkers52 = __toESM(require_InlineWorkers(), 1); var RequestState = { /** * Initial unissued state. * * @type {number} * @constant */ UNISSUED: 0, /** * Issued but not yet active. Will become active when open slots are available. * * @type {number} * @constant */ ISSUED: 1, /** * Actual http request has been sent. * * @type {number} * @constant */ ACTIVE: 2, /** * Request completed successfully. * * @type {number} * @constant */ RECEIVED: 3, /** * Request was cancelled, either explicitly or automatically because of low priority. * * @type {number} * @constant */ CANCELLED: 4, /** * Request failed. * * @type {number} * @constant */ FAILED: 5 }; Object.freeze(RequestState); var RequestState_default = RequestState; // packages/engine/Source/Core/RequestType.js var import_InlineWorkers53 = __toESM(require_InlineWorkers(), 1); var RequestType = { /** * Terrain request. * * @type {number} * @constant */ TERRAIN: 0, /** * Imagery request. * * @type {number} * @constant */ IMAGERY: 1, /** * 3D Tiles request. * * @type {number} * @constant */ TILES3D: 2, /** * Other request. * * @type {number} * @constant */ OTHER: 3 }; Object.freeze(RequestType); var RequestType_default = RequestType; // packages/engine/Source/Core/Request.js function Request(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const throttleByServer = options.throttleByServer ?? false; const throttle = options.throttle ?? false; this.url = options.url; this.requestFunction = options.requestFunction; this.cancelFunction = options.cancelFunction; this.priorityFunction = options.priorityFunction; this.priority = options.priority ?? 0; this.throttle = throttle; this.throttleByServer = throttleByServer; this.type = options.type ?? RequestType_default.OTHER; this.serverKey = options.serverKey; this.state = RequestState_default.UNISSUED; this.deferred = void 0; this.cancelled = false; } Request.prototype.cancel = function() { this.cancelled = true; }; Request.prototype.clone = function(result) { if (!defined_default(result)) { return new Request(this); } result.url = this.url; result.requestFunction = this.requestFunction; result.cancelFunction = this.cancelFunction; result.priorityFunction = this.priorityFunction; result.priority = this.priority; result.throttle = this.throttle; result.throttleByServer = this.throttleByServer; result.type = this.type; result.serverKey = this.serverKey; result.state = RequestState_default.UNISSUED; result.deferred = void 0; result.cancelled = false; return result; }; var Request_default = Request; // packages/engine/Source/Core/RequestErrorEvent.js var import_InlineWorkers56 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/parseResponseHeaders.js var import_InlineWorkers55 = __toESM(require_InlineWorkers(), 1); function parseResponseHeaders(headerString) { const headers = {}; if (!headerString) { return headers; } const headerPairs = headerString.split("\r\n"); for (let i = 0; i < headerPairs.length; ++i) { const headerPair = headerPairs[i]; const index = headerPair.indexOf(": "); if (index > 0) { const key = headerPair.substring(0, index); const val = headerPair.substring(index + 2); headers[key] = val; } } return headers; } var parseResponseHeaders_default = parseResponseHeaders; // packages/engine/Source/Core/RequestErrorEvent.js function RequestErrorEvent(statusCode, response, responseHeaders) { this.statusCode = statusCode; this.response = response; this.responseHeaders = responseHeaders; if (typeof this.responseHeaders === "string") { this.responseHeaders = parseResponseHeaders_default(this.responseHeaders); } } RequestErrorEvent.prototype.toString = function() { let str = "Request has failed."; if (defined_default(this.statusCode)) { str += ` Status Code: ${this.statusCode}`; } return str; }; var RequestErrorEvent_default = RequestErrorEvent; // packages/engine/Source/Core/RequestScheduler.js var import_InlineWorkers59 = __toESM(require_InlineWorkers(), 1); var import_urijs4 = __toESM(require_URI(), 1); // packages/engine/Source/Core/Event.js var import_InlineWorkers57 = __toESM(require_InlineWorkers(), 1); function Event() { this._listeners = /* @__PURE__ */ new Map(); this._toRemove = /* @__PURE__ */ new Map(); this._toAdd = /* @__PURE__ */ new Map(); this._invokingListeners = false; this._listenerCount = 0; } Object.defineProperties(Event.prototype, { /** * The number of listeners currently subscribed to the event. * @memberof Event.prototype * @type {number} * @readonly */ numberOfListeners: { get: function() { return this._listenerCount; } } }); Event.prototype.addEventListener = function(listener, scope) { Check_default.typeOf.func("listener", listener); const event = this; const listenerMap = event._invokingListeners ? event._toAdd : event._listeners; const added = addEventListener(this, listenerMap, listener, scope); if (added) { event._listenerCount++; } return function() { event.removeEventListener(listener, scope); }; }; function addEventListener(event, listenerMap, listener, scope) { if (!listenerMap.has(listener)) { listenerMap.set(listener, /* @__PURE__ */ new Set()); } const scopes = listenerMap.get(listener); if (!scopes.has(scope)) { scopes.add(scope); return true; } return false; } Event.prototype.removeEventListener = function(listener, scope) { Check_default.typeOf.func("listener", listener); const removedFromListeners = removeEventListener( this, this._listeners, listener, scope ); const removedFromToAdd = removeEventListener( this, this._toAdd, listener, scope ); const removed = removedFromListeners || removedFromToAdd; if (removed) { this._listenerCount--; } return removed; }; function removeEventListener(event, listenerMap, listener, scope) { const scopes = listenerMap.get(listener); if (!scopes || !scopes.has(scope)) { return false; } if (event._invokingListeners) { if (!addEventListener(event, event._toRemove, listener, scope)) { return false; } } else { scopes.delete(scope); if (scopes.size === 0) { listenerMap.delete(listener); } } return true; } Event.prototype.raiseEvent = function() { this._invokingListeners = true; for (const [listener, scopes] of this._listeners.entries()) { if (!defined_default(listener)) { continue; } for (const scope of scopes) { listener.apply(scope, arguments); } } this._invokingListeners = false; for (const [listener, scopes] of this._toAdd.entries()) { for (const scope of scopes) { addEventListener(this, this._listeners, listener, scope); } } this._toAdd.clear(); for (const [listener, scopes] of this._toRemove.entries()) { for (const scope of scopes) { removeEventListener(this, this._listeners, listener, scope); } } this._toRemove.clear(); }; var Event_default = Event; // packages/engine/Source/Core/Heap.js var import_InlineWorkers58 = __toESM(require_InlineWorkers(), 1); function Heap(options) { Check_default.typeOf.object("options", options); Check_default.defined("options.comparator", options.comparator); this._comparator = options.comparator; this._array = []; this._length = 0; this._maximumLength = void 0; } Object.defineProperties(Heap.prototype, { /** * Gets the length of the heap. * * @memberof Heap.prototype * * @type {number} * @readonly */ length: { get: function() { return this._length; } }, /** * Gets the internal array. * * @memberof Heap.prototype * * @type {Array} * @readonly */ internalArray: { get: function() { return this._array; } }, /** * Gets and sets the maximum length of the heap. * * @memberof Heap.prototype * * @type {number} */ maximumLength: { get: function() { return this._maximumLength; }, set: function(value) { Check_default.typeOf.number.greaterThanOrEquals("maximumLength", value, 0); const originalLength = this._length; if (value < originalLength) { const array = this._array; for (let i = value; i < originalLength; ++i) { array[i] = void 0; } this._length = value; array.length = value; } this._maximumLength = value; } }, /** * The comparator to use for the heap. If comparator(a, b) is less than 0, sort a to a lower index than b, otherwise sort to a higher index. * * @memberof Heap.prototype * * @type {Heap.ComparatorCallback} */ comparator: { get: function() { return this._comparator; } } }); function swap(array, a3, b) { const temp = array[a3]; array[a3] = array[b]; array[b] = temp; } Heap.prototype.reserve = function(length2) { length2 = length2 ?? this._length; this._array.length = length2; }; Heap.prototype.heapify = function(index) { index = index ?? 0; const length2 = this._length; const comparator = this._comparator; const array = this._array; let candidate; let inserting = true; while (inserting) { const right = 2 * (index + 1); const left = right - 1; if (left < length2 && comparator(array[left], array[index]) < 0) { candidate = left; } else { candidate = index; } if (right < length2 && comparator(array[right], array[candidate]) < 0) { candidate = right; } if (candidate !== index) { swap(array, candidate, index); index = candidate; } else { inserting = false; } } }; Heap.prototype.resort = function() { const length2 = this._length; for (let i = Math.ceil(length2 / 2); i >= 0; --i) { this.heapify(i); } }; Heap.prototype.insert = function(element) { Check_default.defined("element", element); const array = this._array; const comparator = this._comparator; const maximumLength = this._maximumLength; let index = this._length++; if (index < array.length) { array[index] = element; } else { array.push(element); } while (index !== 0) { const parent = Math.floor((index - 1) / 2); if (comparator(array[index], array[parent]) < 0) { swap(array, index, parent); index = parent; } else { break; } } let removedElement; if (defined_default(maximumLength) && this._length > maximumLength) { removedElement = array[maximumLength]; this._length = maximumLength; } return removedElement; }; Heap.prototype.pop = function(index) { index = index ?? 0; if (this._length === 0) { return void 0; } Check_default.typeOf.number.lessThan("index", index, this._length); const array = this._array; const root = array[index]; swap(array, index, --this._length); this.heapify(index); array[this._length] = void 0; return root; }; var Heap_default = Heap; // packages/engine/Source/Core/RequestScheduler.js function sortRequests(a3, b) { return a3.priority - b.priority; } var statistics = { numberOfAttemptedRequests: 0, numberOfActiveRequests: 0, numberOfCancelledRequests: 0, numberOfCancelledActiveRequests: 0, numberOfFailedRequests: 0, numberOfActiveRequestsEver: 0, lastNumberOfActiveRequests: 0 }; var priorityHeapLength = 20; var requestHeap = new Heap_default({ comparator: sortRequests }); requestHeap.maximumLength = priorityHeapLength; requestHeap.reserve(priorityHeapLength); var activeRequests = []; var numberOfActiveRequestsByServer = {}; var pageUri = typeof document !== "undefined" ? new import_urijs4.default(document.location.href) : new import_urijs4.default(); var requestCompletedEvent = new Event_default(); function RequestScheduler() { } RequestScheduler.maximumRequests = 50; RequestScheduler.maximumRequestsPerServer = 18; RequestScheduler.requestsByServer = {}; RequestScheduler.throttleRequests = true; RequestScheduler.debugShowStatistics = false; RequestScheduler.requestCompletedEvent = requestCompletedEvent; Object.defineProperties(RequestScheduler, { /** * Returns the statistics used by the request scheduler. * * @memberof RequestScheduler * * @type {object} * @readonly * @private */ statistics: { get: function() { return statistics; } }, /** * The maximum size of the priority heap. This limits the number of requests that are sorted by priority. Only applies to requests that are not yet active. * * @memberof RequestScheduler * * @type {number} * @default 20 * @private */ priorityHeapLength: { get: function() { return priorityHeapLength; }, set: function(value) { if (value < priorityHeapLength) { while (requestHeap.length > value) { const request = requestHeap.pop(); cancelRequest(request); } } priorityHeapLength = value; requestHeap.maximumLength = value; requestHeap.reserve(value); } } }); function updatePriority(request) { if (defined_default(request.priorityFunction)) { request.priority = request.priorityFunction(); } } RequestScheduler.serverHasOpenSlots = function(serverKey, desiredRequests) { desiredRequests = desiredRequests ?? 1; const maxRequests = RequestScheduler.requestsByServer[serverKey] ?? RequestScheduler.maximumRequestsPerServer; const hasOpenSlotsServer = numberOfActiveRequestsByServer[serverKey] + desiredRequests <= maxRequests; return hasOpenSlotsServer; }; RequestScheduler.heapHasOpenSlots = function(desiredRequests) { const hasOpenSlotsHeap = requestHeap.length + desiredRequests <= priorityHeapLength; return hasOpenSlotsHeap; }; function issueRequest(request) { if (request.state === RequestState_default.UNISSUED) { request.state = RequestState_default.ISSUED; request.deferred = defer_default(); } return request.deferred.promise; } function getRequestReceivedFunction(request) { return function(results) { if (request.state === RequestState_default.CANCELLED) { return; } const deferred = request.deferred; --statistics.numberOfActiveRequests; --numberOfActiveRequestsByServer[request.serverKey]; requestCompletedEvent.raiseEvent(); request.state = RequestState_default.RECEIVED; request.deferred = void 0; deferred.resolve(results); }; } function getRequestFailedFunction(request) { return function(error) { if (request.state === RequestState_default.CANCELLED) { return; } ++statistics.numberOfFailedRequests; --statistics.numberOfActiveRequests; --numberOfActiveRequestsByServer[request.serverKey]; requestCompletedEvent.raiseEvent(error); request.state = RequestState_default.FAILED; request.deferred.reject(error); }; } function startRequest(request) { const promise = issueRequest(request); request.state = RequestState_default.ACTIVE; activeRequests.push(request); ++statistics.numberOfActiveRequests; ++statistics.numberOfActiveRequestsEver; ++numberOfActiveRequestsByServer[request.serverKey]; request.requestFunction().then(getRequestReceivedFunction(request)).catch(getRequestFailedFunction(request)); return promise; } function cancelRequest(request) { const active = request.state === RequestState_default.ACTIVE; request.state = RequestState_default.CANCELLED; ++statistics.numberOfCancelledRequests; if (defined_default(request.deferred)) { const deferred = request.deferred; deferred.promise.catch(() => { }); request.deferred = void 0; deferred.reject(new RuntimeError_default(`Request cancelled: "${request.url}"`)); } if (active) { --statistics.numberOfActiveRequests; --numberOfActiveRequestsByServer[request.serverKey]; ++statistics.numberOfCancelledActiveRequests; } if (defined_default(request.cancelFunction)) { request.cancelFunction(); } } RequestScheduler.update = function() { let i; let request; let removeCount = 0; const activeLength = activeRequests.length; for (i = 0; i < activeLength; ++i) { request = activeRequests[i]; if (request.cancelled) { cancelRequest(request); } if (request.state !== RequestState_default.ACTIVE) { ++removeCount; continue; } if (removeCount > 0) { activeRequests[i - removeCount] = request; } } activeRequests.length -= removeCount; const issuedRequests = requestHeap.internalArray; const issuedLength = requestHeap.length; for (i = 0; i < issuedLength; ++i) { updatePriority(issuedRequests[i]); } requestHeap.resort(); const openSlots = Math.max( RequestScheduler.maximumRequests - activeRequests.length, 0 ); let filledSlots = 0; while (filledSlots < openSlots && requestHeap.length > 0) { request = requestHeap.pop(); if (request.cancelled) { cancelRequest(request); continue; } if (request.throttleByServer && !RequestScheduler.serverHasOpenSlots(request.serverKey)) { cancelRequest(request); continue; } startRequest(request); ++filledSlots; } updateStatistics(); }; RequestScheduler.getServerKey = function(url2) { Check_default.typeOf.string("url", url2); let uri = new import_urijs4.default(url2); if (uri.scheme() === "") { uri = uri.absoluteTo(pageUri); uri.normalize(); } let serverKey = uri.authority(); if (!/:/.test(serverKey)) { serverKey = `${serverKey}:${uri.scheme() === "https" ? "443" : "80"}`; } const length2 = numberOfActiveRequestsByServer[serverKey]; if (!defined_default(length2)) { numberOfActiveRequestsByServer[serverKey] = 0; } return serverKey; }; RequestScheduler.request = function(request) { Check_default.typeOf.object("request", request); Check_default.typeOf.string("request.url", request.url); Check_default.typeOf.func("request.requestFunction", request.requestFunction); if (isDataUri_default(request.url) || isBlobUri_default(request.url)) { requestCompletedEvent.raiseEvent(); request.state = RequestState_default.RECEIVED; return request.requestFunction(); } ++statistics.numberOfAttemptedRequests; if (!defined_default(request.serverKey)) { request.serverKey = RequestScheduler.getServerKey(request.url); } if (RequestScheduler.throttleRequests && request.throttleByServer && !RequestScheduler.serverHasOpenSlots(request.serverKey)) { return void 0; } if (!RequestScheduler.throttleRequests || !request.throttle) { return startRequest(request); } if (activeRequests.length >= RequestScheduler.maximumRequests) { return void 0; } updatePriority(request); const removedRequest = requestHeap.insert(request); if (defined_default(removedRequest)) { if (removedRequest === request) { return void 0; } cancelRequest(removedRequest); } return issueRequest(request); }; function updateStatistics() { if (!RequestScheduler.debugShowStatistics) { return; } if (statistics.numberOfActiveRequests === 0 && statistics.lastNumberOfActiveRequests > 0) { if (statistics.numberOfAttemptedRequests > 0) { console.log( `Number of attempted requests: ${statistics.numberOfAttemptedRequests}` ); statistics.numberOfAttemptedRequests = 0; } if (statistics.numberOfCancelledRequests > 0) { console.log( `Number of cancelled requests: ${statistics.numberOfCancelledRequests}` ); statistics.numberOfCancelledRequests = 0; } if (statistics.numberOfCancelledActiveRequests > 0) { console.log( `Number of cancelled active requests: ${statistics.numberOfCancelledActiveRequests}` ); statistics.numberOfCancelledActiveRequests = 0; } if (statistics.numberOfFailedRequests > 0) { console.log( `Number of failed requests: ${statistics.numberOfFailedRequests}` ); statistics.numberOfFailedRequests = 0; } } statistics.lastNumberOfActiveRequests = statistics.numberOfActiveRequests; } RequestScheduler.clearForSpecs = function() { while (requestHeap.length > 0) { const request = requestHeap.pop(); cancelRequest(request); } const length2 = activeRequests.length; for (let i = 0; i < length2; ++i) { cancelRequest(activeRequests[i]); } activeRequests.length = 0; numberOfActiveRequestsByServer = {}; statistics.numberOfAttemptedRequests = 0; statistics.numberOfActiveRequests = 0; statistics.numberOfCancelledRequests = 0; statistics.numberOfCancelledActiveRequests = 0; statistics.numberOfFailedRequests = 0; statistics.numberOfActiveRequestsEver = 0; statistics.lastNumberOfActiveRequests = 0; }; RequestScheduler.numberOfActiveRequestsByServer = function(serverKey) { return numberOfActiveRequestsByServer[serverKey]; }; RequestScheduler.requestHeap = requestHeap; var RequestScheduler_default = RequestScheduler; // packages/engine/Source/Core/TrustedServers.js var import_InlineWorkers60 = __toESM(require_InlineWorkers(), 1); var import_urijs5 = __toESM(require_URI(), 1); var TrustedServers = {}; var _servers = {}; TrustedServers.add = function(host, port) { if (!defined_default(host)) { throw new DeveloperError_default("host is required."); } if (!defined_default(port) || port <= 0) { throw new DeveloperError_default("port is required to be greater than 0."); } const authority = `${host.toLowerCase()}:${port}`; if (!defined_default(_servers[authority])) { _servers[authority] = true; } }; TrustedServers.remove = function(host, port) { if (!defined_default(host)) { throw new DeveloperError_default("host is required."); } if (!defined_default(port) || port <= 0) { throw new DeveloperError_default("port is required to be greater than 0."); } const authority = `${host.toLowerCase()}:${port}`; if (defined_default(_servers[authority])) { delete _servers[authority]; } }; function getAuthority(url2) { const uri = new import_urijs5.default(url2); uri.normalize(); let authority = uri.authority(); if (authority.length === 0) { return void 0; } uri.authority(authority); if (authority.indexOf("@") !== -1) { const parts = authority.split("@"); authority = parts[1]; } if (authority.indexOf(":") === -1) { let scheme = uri.scheme(); if (scheme.length === 0) { scheme = window.location.protocol; scheme = scheme.substring(0, scheme.length - 1); } if (scheme === "http") { authority += ":80"; } else if (scheme === "https") { authority += ":443"; } else { return void 0; } } return authority; } TrustedServers.contains = function(url2) { if (!defined_default(url2)) { throw new DeveloperError_default("url is required."); } const authority = getAuthority(url2); if (defined_default(authority) && defined_default(_servers[authority])) { return true; } return false; }; TrustedServers.clear = function() { _servers = {}; }; var TrustedServers_default = TrustedServers; // packages/engine/Source/Core/Resource.js var xhrBlobSupported = (function() { try { const xhr = new XMLHttpRequest(); xhr.open("GET", "#", true); xhr.responseType = "blob"; return xhr.responseType === "blob"; } catch (e) { return false; } })(); function Resource(options) { options = options ?? Frozen_default.EMPTY_OBJECT; if (typeof options === "string") { options = { url: options }; } Check_default.typeOf.string("options.url", options.url); this._url = void 0; this._templateValues = defaultClone(options.templateValues, {}); this._queryParameters = defaultClone(options.queryParameters, {}); this.headers = defaultClone(options.headers, {}); this.request = options.request ?? new Request_default(); this.proxy = options.proxy; this.retryCallback = options.retryCallback; this.retryAttempts = options.retryAttempts ?? 0; this._retryCount = 0; const parseUrl2 = options.parseUrl ?? true; if (parseUrl2) { this.parseUrl(options.url, true, true); } else { this._url = options.url; } this._credits = options.credits; } function defaultClone(value, defaultValue) { return defined_default(value) ? clone_default(value) : defaultValue; } Resource.createIfNeeded = function(resource) { if (resource instanceof Resource) { return resource.getDerivedResource({ request: resource.request }); } if (typeof resource !== "string") { return resource; } return new Resource({ url: resource }); }; var supportsImageBitmapOptionsPromise; Resource.supportsImageBitmapOptions = function() { if (defined_default(supportsImageBitmapOptionsPromise)) { return supportsImageBitmapOptionsPromise; } if (typeof createImageBitmap !== "function") { supportsImageBitmapOptionsPromise = Promise.resolve(false); return supportsImageBitmapOptionsPromise; } const imageDataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABGdBTUEAAE4g3rEiDgAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADElEQVQI12Ng6GAAAAEUAIngE3ZiAAAAAElFTkSuQmCC"; supportsImageBitmapOptionsPromise = Resource.fetchBlob({ url: imageDataUri }).then(function(blob) { const imageBitmapOptions = { // 'from-image' is deprecated, new option is 'none'. However, we still need to support older browsers, // and there's no good way to detect support for these options. For now, continue to use 'from-image'. See: https://github.com/CesiumGS/cesium/issues/12846 imageOrientation: "flipY", // default is "from-image" premultiplyAlpha: "none", // default is "default" colorSpaceConversion: "none" // default is "default" }; return Promise.all([ createImageBitmap(blob, imageBitmapOptions), createImageBitmap(blob) ]); }).then(function(imageBitmaps) { const colorWithOptions = getImagePixels_default(imageBitmaps[0]); const colorWithDefaults = getImagePixels_default(imageBitmaps[1]); return colorWithOptions[1] !== colorWithDefaults[1]; }).catch(function() { return false; }); return supportsImageBitmapOptionsPromise; }; Object.defineProperties(Resource, { /** * Returns true if blobs are supported. * * @memberof Resource * @type {boolean} * * @readonly */ isBlobSupported: { get: function() { return xhrBlobSupported; } } }); Object.defineProperties(Resource.prototype, { /** * Query parameters appended to the url. * * @memberof Resource.prototype * @type {object} * * @readonly */ queryParameters: { get: function() { return this._queryParameters; } }, /** * The key/value pairs used to replace template parameters in the url. * * @memberof Resource.prototype * @type {object} * * @readonly */ templateValues: { get: function() { return this._templateValues; } }, /** * The url to the resource with template values replaced, query string appended and encoded by proxy if one was set. * * @memberof Resource.prototype * @type {string} */ url: { get: function() { return this.getUrlComponent(true, true); }, set: function(value) { this.parseUrl(value, false, false); } }, /** * The file extension of the resource. * * @memberof Resource.prototype * @type {string} * * @readonly */ extension: { get: function() { return getExtensionFromUri_default(this._url); } }, /** * True if the Resource refers to a data URI. * * @memberof Resource.prototype * @type {boolean} */ isDataUri: { get: function() { return isDataUri_default(this._url); } }, /** * True if the Resource refers to a blob URI. * * @memberof Resource.prototype * @type {boolean} */ isBlobUri: { get: function() { return isBlobUri_default(this._url); } }, /** * True if the Resource refers to a cross origin URL. * * @memberof Resource.prototype * @type {boolean} */ isCrossOriginUrl: { get: function() { return isCrossOriginUrl_default(this._url); } }, /** * True if the Resource has request headers. This is equivalent to checking if the headers property has any keys. * * @memberof Resource.prototype * @type {boolean} */ hasHeaders: { get: function() { return Object.keys(this.headers).length > 0; } }, /** * Gets the credits required for attribution of an asset. * @private */ credits: { get: function() { return this._credits; } } }); Resource.prototype.toString = function() { return this.getUrlComponent(true, true); }; Resource.prototype.parseUrl = function(url2, merge2, preserveQuery, baseUrl) { let uri = new import_urijs6.default(url2); const query = parseQueryString(uri.query()); this._queryParameters = merge2 ? combineQueryParameters(query, this.queryParameters, preserveQuery) : query; uri.search(""); uri.fragment(""); if (defined_default(baseUrl) && uri.scheme() === "") { uri = uri.absoluteTo(getAbsoluteUri_default(baseUrl)); } this._url = uri.toString(); }; function parseQueryString(queryString) { if (queryString.length === 0) { return {}; } if (queryString.indexOf("=") === -1) { return { [queryString]: void 0 }; } return queryToObject_default(queryString); } function combineQueryParameters(q12, q22, preserveQueryParameters) { if (!preserveQueryParameters) { return combine_default(q12, q22); } const result = clone_default(q12, true); for (const param in q22) { if (q22.hasOwnProperty(param)) { let value = result[param]; const q2Value = q22[param]; if (defined_default(value)) { if (!Array.isArray(value)) { value = result[param] = [value]; } result[param] = value.concat(q2Value); } else { result[param] = Array.isArray(q2Value) ? q2Value.slice() : q2Value; } } } return result; } Resource.prototype.getUrlComponent = function(query, proxy) { if (this.isDataUri) { return this._url; } let url2 = this._url; if (query) { url2 = `${url2}${stringifyQuery(this.queryParameters)}`; } url2 = url2.replace(/%7B/g, "{").replace(/%7D/g, "}"); const templateValues = this._templateValues; if (Object.keys(templateValues).length > 0) { url2 = url2.replace(/{(.*?)}/g, function(match, key) { const replacement = templateValues[key]; if (defined_default(replacement)) { return encodeURIComponent(replacement); } return match; }); } if (proxy && defined_default(this.proxy)) { url2 = this.proxy.getURL(url2); } return url2; }; function stringifyQuery(queryObject) { const keys = Object.keys(queryObject); if (keys.length === 0) { return ""; } if (keys.length === 1 && !defined_default(queryObject[keys[0]])) { return `?${keys[0]}`; } return `?${objectToQuery_default(queryObject)}`; } Resource.prototype.setQueryParameters = function(params, useAsDefault) { if (useAsDefault) { this._queryParameters = combineQueryParameters( this._queryParameters, params, false ); } else { this._queryParameters = combineQueryParameters( params, this._queryParameters, false ); } }; Resource.prototype.appendQueryParameters = function(params) { this._queryParameters = combineQueryParameters( params, this._queryParameters, true ); }; Resource.prototype.setTemplateValues = function(template, useAsDefault) { if (useAsDefault) { this._templateValues = combine_default(this._templateValues, template); } else { this._templateValues = combine_default(template, this._templateValues); } }; Resource.prototype.getDerivedResource = function(options) { const resource = this.clone(); resource._retryCount = 0; if (defined_default(options.url)) { const preserveQuery = options.preserveQueryParameters ?? false; resource.parseUrl(options.url, true, preserveQuery, this._url); } if (defined_default(options.queryParameters)) { resource._queryParameters = combine_default( options.queryParameters, resource.queryParameters ); } if (defined_default(options.templateValues)) { resource._templateValues = combine_default( options.templateValues, resource.templateValues ); } if (defined_default(options.headers)) { resource.headers = combine_default(options.headers, resource.headers); } if (defined_default(options.proxy)) { resource.proxy = options.proxy; } if (defined_default(options.request)) { resource.request = options.request; } if (defined_default(options.retryCallback)) { resource.retryCallback = options.retryCallback; } if (defined_default(options.retryAttempts)) { resource.retryAttempts = options.retryAttempts; } return resource; }; Resource.prototype.retryOnError = function(error) { const retryCallback2 = this.retryCallback; if (typeof retryCallback2 !== "function" || this._retryCount >= this.retryAttempts) { return Promise.resolve(false); } const that = this; return Promise.resolve(retryCallback2(this, error)).then(function(result) { ++that._retryCount; return result; }); }; Resource.prototype.clone = function(result) { if (!defined_default(result)) { return new Resource({ url: this._url, queryParameters: this.queryParameters, templateValues: this.templateValues, headers: this.headers, proxy: this.proxy, retryCallback: this.retryCallback, retryAttempts: this.retryAttempts, request: this.request.clone(), parseUrl: false, credits: defined_default(this.credits) ? this.credits.slice() : void 0 }); } result._url = this._url; result._queryParameters = clone_default(this._queryParameters); result._templateValues = clone_default(this._templateValues); result.headers = clone_default(this.headers); result.proxy = this.proxy; result.retryCallback = this.retryCallback; result.retryAttempts = this.retryAttempts; result._retryCount = 0; result.request = this.request.clone(); return result; }; Resource.prototype.getBaseUri = function(includeQuery) { return getBaseUri_default(this.getUrlComponent(includeQuery), includeQuery); }; Resource.prototype.appendForwardSlash = function() { this._url = appendForwardSlash_default(this._url); }; Resource.prototype.fetchArrayBuffer = function() { return this.fetch({ responseType: "arraybuffer" }); }; Resource.fetchArrayBuffer = function(options) { const resource = new Resource(options); return resource.fetchArrayBuffer(); }; Resource.prototype.fetchBlob = function() { return this.fetch({ responseType: "blob" }); }; Resource.fetchBlob = function(options) { const resource = new Resource(options); return resource.fetchBlob(); }; Resource.prototype.fetchImage = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const preferImageBitmap = options.preferImageBitmap ?? false; const preferBlob = options.preferBlob ?? false; const flipY = options.flipY ?? false; const skipColorSpaceConversion = options.skipColorSpaceConversion ?? false; checkAndResetRequest(this.request); if (!xhrBlobSupported || this.isDataUri || this.isBlobUri || !this.hasHeaders && !preferBlob) { return this._fetchImage({ resource: this, flipY, skipColorSpaceConversion, preferImageBitmap }); } const blobPromise = this.fetchBlob(); if (!defined_default(blobPromise)) { return; } let supportsImageBitmap; let useImageBitmap; let generatedBlobResource; let generatedBlob; return Resource.supportsImageBitmapOptions().then(function(result) { supportsImageBitmap = result; useImageBitmap = supportsImageBitmap && preferImageBitmap; return blobPromise; }).then(function(blob) { if (!defined_default(blob)) { return; } generatedBlob = blob; if (useImageBitmap) { return Resource.createImageBitmapFromBlob(blob, { flipY, premultiplyAlpha: false, skipColorSpaceConversion }); } const blobUrl = window.URL.createObjectURL(blob); generatedBlobResource = new Resource({ url: blobUrl }); return generatedBlobResource._fetchImage({ flipY, skipColorSpaceConversion, preferImageBitmap: false }); }).then(function(image) { if (!defined_default(image)) { return; } image.blob = generatedBlob; if (useImageBitmap) { return image; } window.URL.revokeObjectURL(generatedBlobResource.url); return image; }).catch(function(error) { if (defined_default(generatedBlobResource)) { window.URL.revokeObjectURL(generatedBlobResource.url); } error.blob = generatedBlob; return Promise.reject(error); }); }; Resource.prototype._fetchImage = function(options) { const resource = this; const flipY = options.flipY; const skipColorSpaceConversion = options.skipColorSpaceConversion; const preferImageBitmap = options.preferImageBitmap; const request = resource.request; request.url = resource.url; request.requestFunction = function() { let crossOrigin = false; if (!resource.isDataUri && !resource.isBlobUri) { crossOrigin = resource.isCrossOriginUrl; } const deferred = defer_default(); Resource._Implementations.createImage( request, crossOrigin, deferred, flipY, skipColorSpaceConversion, preferImageBitmap ); return deferred.promise; }; const promise = RequestScheduler_default.request(request); if (!defined_default(promise)) { return; } return promise.catch(function(e) { if (request.state !== RequestState_default.FAILED) { return Promise.reject(e); } return resource.retryOnError(e).then(function(retry) { if (retry) { request.state = RequestState_default.UNISSUED; request.deferred = void 0; return resource._fetchImage({ flipY, skipColorSpaceConversion, preferImageBitmap }); } return Promise.reject(e); }); }); }; Resource.fetchImage = function(options) { const resource = new Resource(options); return resource.fetchImage({ flipY: options.flipY, skipColorSpaceConversion: options.skipColorSpaceConversion, preferBlob: options.preferBlob, preferImageBitmap: options.preferImageBitmap }); }; Resource.prototype.fetchText = function() { return this.fetch({ responseType: "text" }); }; Resource.fetchText = function(options) { const resource = new Resource(options); return resource.fetchText(); }; Resource.prototype.fetchJson = function() { const promise = this.fetch({ responseType: "text", headers: { Accept: "application/json,*/*;q=0.01" } }); if (!defined_default(promise)) { return void 0; } return promise.then(function(value) { if (!defined_default(value)) { return; } return JSON.parse(value); }); }; Resource.fetchJson = function(options) { const resource = new Resource(options); return resource.fetchJson(); }; Resource.prototype.fetchXML = function() { return this.fetch({ responseType: "document", overrideMimeType: "text/xml" }); }; Resource.fetchXML = function(options) { const resource = new Resource(options); return resource.fetchXML(); }; Resource.prototype.fetchJsonp = function(callbackParameterName) { callbackParameterName = callbackParameterName ?? "callback"; checkAndResetRequest(this.request); let functionName; do { functionName = `loadJsonp${Math_default.nextRandomNumber().toString().substring(2, 8)}`; } while (defined_default(window[functionName])); return fetchJsonp(this, callbackParameterName, functionName); }; function fetchJsonp(resource, callbackParameterName, functionName) { const callbackQuery = {}; callbackQuery[callbackParameterName] = functionName; resource.setQueryParameters(callbackQuery); const request = resource.request; const url2 = resource.url; request.url = url2; request.requestFunction = function() { const deferred = defer_default(); window[functionName] = function(data) { deferred.resolve(data); try { delete window[functionName]; } catch (e) { window[functionName] = void 0; } }; Resource._Implementations.loadAndExecuteScript(url2, functionName, deferred); return deferred.promise; }; const promise = RequestScheduler_default.request(request); if (!defined_default(promise)) { return; } return promise.catch(function(e) { if (request.state !== RequestState_default.FAILED) { return Promise.reject(e); } return resource.retryOnError(e).then(function(retry) { if (retry) { request.state = RequestState_default.UNISSUED; request.deferred = void 0; return fetchJsonp(resource, callbackParameterName, functionName); } return Promise.reject(e); }); }); } Resource.fetchJsonp = function(options) { const resource = new Resource(options); return resource.fetchJsonp(options.callbackParameterName); }; Resource.prototype._makeRequest = function(options) { const resource = this; checkAndResetRequest(resource.request); const request = resource.request; const url2 = resource.url; request.url = url2; request.requestFunction = function() { const responseType = options.responseType; const headers = combine_default(options.headers, resource.headers); const overrideMimeType = options.overrideMimeType; const method = options.method; const data = options.data; const deferred = defer_default(); const xhr = Resource._Implementations.loadWithXhr( url2, responseType, method, data, headers, deferred, overrideMimeType ); if (defined_default(xhr) && defined_default(xhr.abort)) { request.cancelFunction = function() { xhr.abort(); }; } return deferred.promise; }; const promise = RequestScheduler_default.request(request); if (!defined_default(promise)) { return; } return promise.then(function(data) { request.cancelFunction = void 0; return data; }).catch(function(e) { request.cancelFunction = void 0; if (request.state !== RequestState_default.FAILED) { return Promise.reject(e); } return resource.retryOnError(e).then(function(retry) { if (retry) { request.state = RequestState_default.UNISSUED; request.deferred = void 0; return resource.fetch(options); } return Promise.reject(e); }); }); }; function checkAndResetRequest(request) { if (request.state === RequestState_default.ISSUED || request.state === RequestState_default.ACTIVE) { throw new RuntimeError_default("The Resource is already being fetched."); } request.state = RequestState_default.UNISSUED; request.deferred = void 0; } var dataUriRegex2 = /^data:(.*?)(;base64)?,(.*)$/; function decodeDataUriText(isBase64, data) { const result = decodeURIComponent(data); if (isBase64) { return atob(result); } return result; } function decodeDataUriArrayBuffer(isBase64, data) { const byteString = decodeDataUriText(isBase64, data); const buffer2 = new ArrayBuffer(byteString.length); const view = new Uint8Array(buffer2); for (let i = 0; i < byteString.length; i++) { view[i] = byteString.charCodeAt(i); } return buffer2; } function decodeDataUri(dataUriRegexResult, responseType) { responseType = responseType ?? ""; const mimeType = dataUriRegexResult[1]; const isBase64 = !!dataUriRegexResult[2]; const data = dataUriRegexResult[3]; let buffer2; let parser3; switch (responseType) { case "": case "text": return decodeDataUriText(isBase64, data); case "arraybuffer": return decodeDataUriArrayBuffer(isBase64, data); case "blob": buffer2 = decodeDataUriArrayBuffer(isBase64, data); return new Blob([buffer2], { type: mimeType }); case "document": parser3 = new DOMParser(); return parser3.parseFromString( decodeDataUriText(isBase64, data), mimeType ); case "json": return JSON.parse(decodeDataUriText(isBase64, data)); default: throw new DeveloperError_default(`Unhandled responseType: ${responseType}`); } } Resource.prototype.fetch = function(options) { options = defaultClone(options, {}); options.method = "GET"; return this._makeRequest(options); }; Resource.fetch = function(options) { const resource = new Resource(options); return resource.fetch({ // Make copy of just the needed fields because headers can be passed to both the constructor and to fetch responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource.prototype.delete = function(options) { options = defaultClone(options, {}); options.method = "DELETE"; return this._makeRequest(options); }; Resource.delete = function(options) { const resource = new Resource(options); return resource.delete({ // Make copy of just the needed fields because headers can be passed to both the constructor and to fetch responseType: options.responseType, overrideMimeType: options.overrideMimeType, data: options.data }); }; Resource.prototype.head = function(options) { options = defaultClone(options, {}); options.method = "HEAD"; return this._makeRequest(options); }; Resource.head = function(options) { const resource = new Resource(options); return resource.head({ // Make copy of just the needed fields because headers can be passed to both the constructor and to fetch responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource.prototype.options = function(options) { options = defaultClone(options, {}); options.method = "OPTIONS"; return this._makeRequest(options); }; Resource.options = function(options) { const resource = new Resource(options); return resource.options({ // Make copy of just the needed fields because headers can be passed to both the constructor and to fetch responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource.prototype.post = function(data, options) { Check_default.defined("data", data); options = defaultClone(options, {}); options.method = "POST"; options.data = data; return this._makeRequest(options); }; Resource.post = function(options) { const resource = new Resource(options); return resource.post(options.data, { // Make copy of just the needed fields because headers can be passed to both the constructor and to post responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource.prototype.put = function(data, options) { Check_default.defined("data", data); options = defaultClone(options, {}); options.method = "PUT"; options.data = data; return this._makeRequest(options); }; Resource.put = function(options) { const resource = new Resource(options); return resource.put(options.data, { // Make copy of just the needed fields because headers can be passed to both the constructor and to post responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource.prototype.patch = function(data, options) { Check_default.defined("data", data); options = defaultClone(options, {}); options.method = "PATCH"; options.data = data; return this._makeRequest(options); }; Resource.patch = function(options) { const resource = new Resource(options); return resource.patch(options.data, { // Make copy of just the needed fields because headers can be passed to both the constructor and to post responseType: options.responseType, overrideMimeType: options.overrideMimeType }); }; Resource._Implementations = {}; Resource._Implementations.loadImageElement = function(url2, crossOrigin, deferred) { const image = new Image(); image.onload = function() { if (image.naturalWidth === 0 && image.naturalHeight === 0 && image.width === 0 && image.height === 0) { image.width = 300; image.height = 150; } deferred.resolve(image); }; image.onerror = function(e) { deferred.reject(e); }; if (crossOrigin) { if (TrustedServers_default.contains(url2)) { image.crossOrigin = "use-credentials"; } else { image.crossOrigin = ""; } } image.src = url2; }; Resource._Implementations.createImage = function(request, crossOrigin, deferred, flipY, skipColorSpaceConversion, preferImageBitmap, headers) { const url2 = request.url; Resource.supportsImageBitmapOptions().then(function(supportsImageBitmap) { if (!(supportsImageBitmap && preferImageBitmap)) { Resource._Implementations.loadImageElement(url2, crossOrigin, deferred); return; } const responseType = "blob"; const method = "GET"; const xhrDeferred = defer_default(); const xhr = Resource._Implementations.loadWithXhr( url2, responseType, method, void 0, headers, xhrDeferred, void 0, void 0, void 0 ); if (defined_default(xhr) && defined_default(xhr.abort)) { request.cancelFunction = function() { xhr.abort(); }; } return xhrDeferred.promise.then(function(blob) { if (!defined_default(blob)) { deferred.reject( new RuntimeError_default( `Successfully retrieved ${url2} but it contained no content.` ) ); return; } return Resource.createImageBitmapFromBlob(blob, { flipY, premultiplyAlpha: false, skipColorSpaceConversion }); }).then(function(image) { deferred.resolve(image); }); }).catch(function(e) { deferred.reject(e); }); }; Resource.createImageBitmapFromBlob = function(blob, options) { Check_default.defined("options", options); Check_default.typeOf.bool("options.flipY", options.flipY); Check_default.typeOf.bool("options.premultiplyAlpha", options.premultiplyAlpha); Check_default.typeOf.bool( "options.skipColorSpaceConversion", options.skipColorSpaceConversion ); return createImageBitmap(blob, { // 'from-image' is deprecated, new option is 'none'. However, we still need to support older browsers, // and there's no good way to detect support for these options. For now, continue to use 'from-image'. See: https://github.com/CesiumGS/cesium/issues/12846 imageOrientation: options.flipY ? "flipY" : "none", premultiplyAlpha: options.premultiplyAlpha ? "premultiply" : "none", colorSpaceConversion: options.skipColorSpaceConversion ? "none" : "default" }); }; function loadWithHttpRequest(url2, responseType, method, data, headers, deferred, overrideMimeType) { fetch(url2, { method, headers }).then(async (response) => { if (!response.ok) { const responseHeaders = {}; response.headers.forEach((value, key) => { responseHeaders[key] = value; }); deferred.reject( new RequestErrorEvent_default(response.status, response, responseHeaders) ); return; } switch (responseType) { case "text": deferred.resolve(response.text()); break; case "json": deferred.resolve(response.json()); break; default: deferred.resolve(new Uint8Array(await response.arrayBuffer()).buffer); break; } }).catch(() => { deferred.reject(new RequestErrorEvent_default()); }); } var noXMLHttpRequest = typeof XMLHttpRequest === "undefined"; Resource._Implementations.loadWithXhr = function(url2, responseType, method, data, headers, deferred, overrideMimeType) { const dataUriRegexResult = dataUriRegex2.exec(url2); if (dataUriRegexResult !== null) { deferred.resolve(decodeDataUri(dataUriRegexResult, responseType)); return; } if (noXMLHttpRequest) { loadWithHttpRequest( url2, responseType, method, data, headers, deferred, overrideMimeType ); return; } const xhr = new XMLHttpRequest(); if (TrustedServers_default.contains(url2)) { xhr.withCredentials = true; } xhr.open(method, url2, true); if (defined_default(overrideMimeType) && defined_default(xhr.overrideMimeType)) { xhr.overrideMimeType(overrideMimeType); } if (defined_default(headers)) { for (const key in headers) { if (headers.hasOwnProperty(key)) { xhr.setRequestHeader(key, headers[key]); } } } if (defined_default(responseType)) { xhr.responseType = responseType; } let localFile = false; if (typeof url2 === "string") { localFile = url2.indexOf("file://") === 0 || typeof window !== "undefined" && window.location.origin === "file://"; } xhr.onload = function() { if ((xhr.status < 200 || xhr.status >= 300) && !(localFile && xhr.status === 0)) { deferred.reject( new RequestErrorEvent_default( xhr.status, xhr.response, xhr.getAllResponseHeaders() ) ); return; } const response = xhr.response; const browserResponseType = xhr.responseType; if (method === "HEAD" || method === "OPTIONS") { const responseHeaderString = xhr.getAllResponseHeaders(); const splitHeaders = responseHeaderString.trim().split(/[\r\n]+/); const responseHeaders = {}; splitHeaders.forEach(function(line) { const parts = line.split(": "); const header = parts.shift(); responseHeaders[header] = parts.join(": "); }); deferred.resolve(responseHeaders); return; } if (xhr.status === 204) { deferred.resolve(void 0); } else if (defined_default(response) && (!defined_default(responseType) || browserResponseType === responseType)) { deferred.resolve(response); } else if (responseType === "json" && typeof response === "string") { try { deferred.resolve(JSON.parse(response)); } catch (e) { deferred.reject(e); } } else if ((browserResponseType === "" || browserResponseType === "document") && defined_default(xhr.responseXML) && xhr.responseXML.hasChildNodes()) { deferred.resolve(xhr.responseXML); } else if ((browserResponseType === "" || browserResponseType === "text") && defined_default(xhr.responseText)) { deferred.resolve(xhr.responseText); } else { deferred.reject( new RuntimeError_default("Invalid XMLHttpRequest response type.") ); } }; xhr.onerror = function(e) { deferred.reject(new RequestErrorEvent_default()); }; xhr.send(data); return xhr; }; Resource._Implementations.loadAndExecuteScript = function(url2, functionName, deferred) { return loadAndExecuteScript_default(url2, functionName).catch(function(e) { deferred.reject(e); }); }; Resource._DefaultImplementations = {}; Resource._DefaultImplementations.createImage = Resource._Implementations.createImage; Resource._DefaultImplementations.loadWithXhr = Resource._Implementations.loadWithXhr; Resource._DefaultImplementations.loadAndExecuteScript = Resource._Implementations.loadAndExecuteScript; Resource.DEFAULT = Object.freeze( new Resource({ url: typeof document === "undefined" ? "" : document.location.href.split("?")[0] }) ); var Resource_default = Resource; // packages/engine/Source/Core/EarthOrientationParameters.js function EarthOrientationParameters(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._dates = void 0; this._samples = void 0; this._dateColumn = -1; this._xPoleWanderRadiansColumn = -1; this._yPoleWanderRadiansColumn = -1; this._ut1MinusUtcSecondsColumn = -1; this._xCelestialPoleOffsetRadiansColumn = -1; this._yCelestialPoleOffsetRadiansColumn = -1; this._taiMinusUtcSecondsColumn = -1; this._columnCount = 0; this._lastIndex = -1; this._addNewLeapSeconds = options.addNewLeapSeconds ?? true; if (defined_default(options.data)) { onDataReady(this, options.data); } else { onDataReady(this, { columnNames: [ "dateIso8601", "modifiedJulianDateUtc", "xPoleWanderRadians", "yPoleWanderRadians", "ut1MinusUtcSeconds", "lengthOfDayCorrectionSeconds", "xCelestialPoleOffsetRadians", "yCelestialPoleOffsetRadians", "taiMinusUtcSeconds" ], samples: [] }); } } EarthOrientationParameters.fromUrl = async function(url2, options) { Check_default.defined("url", url2); options = options ?? Frozen_default.EMPTY_OBJECT; const resource = Resource_default.createIfNeeded(url2); let eopData; try { eopData = await resource.fetchJson(); } catch (e) { throw new RuntimeError_default( `An error occurred while retrieving the EOP data from the URL ${resource.url}.` ); } return new EarthOrientationParameters({ addNewLeapSeconds: options.addNewLeapSeconds, data: eopData }); }; EarthOrientationParameters.NONE = Object.freeze({ compute: function(date, result) { if (!defined_default(result)) { result = new EarthOrientationParametersSample_default(0, 0, 0, 0, 0); } else { result.xPoleWander = 0; result.yPoleWander = 0; result.xPoleOffset = 0; result.yPoleOffset = 0; result.ut1MinusUtc = 0; } return result; } }); EarthOrientationParameters.prototype.compute = function(date, result) { if (!defined_default(this._samples)) { return void 0; } if (!defined_default(result)) { result = new EarthOrientationParametersSample_default(0, 0, 0, 0, 0); } if (this._samples.length === 0) { result.xPoleWander = 0; result.yPoleWander = 0; result.xPoleOffset = 0; result.yPoleOffset = 0; result.ut1MinusUtc = 0; return result; } const dates = this._dates; const lastIndex = this._lastIndex; let before; let after; if (defined_default(lastIndex)) { const previousIndexDate = dates[lastIndex]; const nextIndexDate = dates[lastIndex + 1]; const isAfterPrevious = JulianDate_default.lessThanOrEquals( previousIndexDate, date ); const isAfterLastSample = !defined_default(nextIndexDate); const isBeforeNext = isAfterLastSample || JulianDate_default.greaterThanOrEquals(nextIndexDate, date); if (isAfterPrevious && isBeforeNext) { before = lastIndex; if (!isAfterLastSample && nextIndexDate.equals(date)) { ++before; } after = before + 1; interpolate(this, dates, this._samples, date, before, after, result); return result; } } let index = binarySearch_default(dates, date, JulianDate_default.compare, this._dateColumn); if (index >= 0) { if (index < dates.length - 1 && dates[index + 1].equals(date)) { ++index; } before = index; after = index; } else { after = ~index; before = after - 1; if (before < 0) { before = 0; } } this._lastIndex = before; interpolate(this, dates, this._samples, date, before, after, result); return result; }; function compareLeapSecondDates2(leapSecond, dateToFind) { return JulianDate_default.compare(leapSecond.julianDate, dateToFind); } function onDataReady(eop, eopData) { if (!defined_default(eopData.columnNames)) { throw new RuntimeError_default( "Error in loaded EOP data: The columnNames property is required." ); } if (!defined_default(eopData.samples)) { throw new RuntimeError_default( "Error in loaded EOP data: The samples property is required." ); } const dateColumn = eopData.columnNames.indexOf("modifiedJulianDateUtc"); const xPoleWanderRadiansColumn = eopData.columnNames.indexOf("xPoleWanderRadians"); const yPoleWanderRadiansColumn = eopData.columnNames.indexOf("yPoleWanderRadians"); const ut1MinusUtcSecondsColumn = eopData.columnNames.indexOf("ut1MinusUtcSeconds"); const xCelestialPoleOffsetRadiansColumn = eopData.columnNames.indexOf( "xCelestialPoleOffsetRadians" ); const yCelestialPoleOffsetRadiansColumn = eopData.columnNames.indexOf( "yCelestialPoleOffsetRadians" ); const taiMinusUtcSecondsColumn = eopData.columnNames.indexOf("taiMinusUtcSeconds"); if (dateColumn < 0 || xPoleWanderRadiansColumn < 0 || yPoleWanderRadiansColumn < 0 || ut1MinusUtcSecondsColumn < 0 || xCelestialPoleOffsetRadiansColumn < 0 || yCelestialPoleOffsetRadiansColumn < 0 || taiMinusUtcSecondsColumn < 0) { throw new RuntimeError_default( "Error in loaded EOP data: The columnNames property must include modifiedJulianDateUtc, xPoleWanderRadians, yPoleWanderRadians, ut1MinusUtcSeconds, xCelestialPoleOffsetRadians, yCelestialPoleOffsetRadians, and taiMinusUtcSeconds columns" ); } const samples = eop._samples = eopData.samples; const dates = eop._dates = []; eop._dateColumn = dateColumn; eop._xPoleWanderRadiansColumn = xPoleWanderRadiansColumn; eop._yPoleWanderRadiansColumn = yPoleWanderRadiansColumn; eop._ut1MinusUtcSecondsColumn = ut1MinusUtcSecondsColumn; eop._xCelestialPoleOffsetRadiansColumn = xCelestialPoleOffsetRadiansColumn; eop._yCelestialPoleOffsetRadiansColumn = yCelestialPoleOffsetRadiansColumn; eop._taiMinusUtcSecondsColumn = taiMinusUtcSecondsColumn; eop._columnCount = eopData.columnNames.length; eop._lastIndex = void 0; let lastTaiMinusUtc; const addNewLeapSeconds = eop._addNewLeapSeconds; for (let i = 0, len = samples.length; i < len; i += eop._columnCount) { const mjd = samples[i + dateColumn]; const taiMinusUtc = samples[i + taiMinusUtcSecondsColumn]; const day = mjd + TimeConstants_default.MODIFIED_JULIAN_DATE_DIFFERENCE; const date = new JulianDate_default(day, taiMinusUtc, TimeStandard_default.TAI); dates.push(date); if (addNewLeapSeconds) { if (taiMinusUtc !== lastTaiMinusUtc && defined_default(lastTaiMinusUtc)) { const leapSeconds = JulianDate_default.leapSeconds; const leapSecondIndex = binarySearch_default( leapSeconds, date, compareLeapSecondDates2 ); if (leapSecondIndex < 0) { const leapSecond = new LeapSecond_default(date, taiMinusUtc); leapSeconds.splice(~leapSecondIndex, 0, leapSecond); } } lastTaiMinusUtc = taiMinusUtc; } } } function fillResultFromIndex(eop, samples, index, columnCount, result) { const start = index * columnCount; result.xPoleWander = samples[start + eop._xPoleWanderRadiansColumn]; result.yPoleWander = samples[start + eop._yPoleWanderRadiansColumn]; result.xPoleOffset = samples[start + eop._xCelestialPoleOffsetRadiansColumn]; result.yPoleOffset = samples[start + eop._yCelestialPoleOffsetRadiansColumn]; result.ut1MinusUtc = samples[start + eop._ut1MinusUtcSecondsColumn]; } function linearInterp(dx, y1, y2) { return y1 + dx * (y2 - y1); } function interpolate(eop, dates, samples, date, before, after, result) { const columnCount = eop._columnCount; if (after > dates.length - 1) { result.xPoleWander = 0; result.yPoleWander = 0; result.xPoleOffset = 0; result.yPoleOffset = 0; result.ut1MinusUtc = 0; return result; } const beforeDate = dates[before]; const afterDate = dates[after]; if (beforeDate.equals(afterDate) || date.equals(beforeDate)) { fillResultFromIndex(eop, samples, before, columnCount, result); return result; } else if (date.equals(afterDate)) { fillResultFromIndex(eop, samples, after, columnCount, result); return result; } const factor2 = JulianDate_default.secondsDifference(date, beforeDate) / JulianDate_default.secondsDifference(afterDate, beforeDate); const startBefore = before * columnCount; const startAfter = after * columnCount; let beforeUt1MinusUtc = samples[startBefore + eop._ut1MinusUtcSecondsColumn]; let afterUt1MinusUtc = samples[startAfter + eop._ut1MinusUtcSecondsColumn]; const offsetDifference = afterUt1MinusUtc - beforeUt1MinusUtc; if (offsetDifference > 0.5 || offsetDifference < -0.5) { const beforeTaiMinusUtc = samples[startBefore + eop._taiMinusUtcSecondsColumn]; const afterTaiMinusUtc = samples[startAfter + eop._taiMinusUtcSecondsColumn]; if (beforeTaiMinusUtc !== afterTaiMinusUtc) { if (afterDate.equals(date)) { beforeUt1MinusUtc = afterUt1MinusUtc; } else { afterUt1MinusUtc -= afterTaiMinusUtc - beforeTaiMinusUtc; } } } result.xPoleWander = linearInterp( factor2, samples[startBefore + eop._xPoleWanderRadiansColumn], samples[startAfter + eop._xPoleWanderRadiansColumn] ); result.yPoleWander = linearInterp( factor2, samples[startBefore + eop._yPoleWanderRadiansColumn], samples[startAfter + eop._yPoleWanderRadiansColumn] ); result.xPoleOffset = linearInterp( factor2, samples[startBefore + eop._xCelestialPoleOffsetRadiansColumn], samples[startAfter + eop._xCelestialPoleOffsetRadiansColumn] ); result.yPoleOffset = linearInterp( factor2, samples[startBefore + eop._yCelestialPoleOffsetRadiansColumn], samples[startAfter + eop._yCelestialPoleOffsetRadiansColumn] ); result.ut1MinusUtc = linearInterp( factor2, beforeUt1MinusUtc, afterUt1MinusUtc ); return result; } var EarthOrientationParameters_default = EarthOrientationParameters; // packages/engine/Source/Core/HeadingPitchRoll.js var import_InlineWorkers63 = __toESM(require_InlineWorkers(), 1); function HeadingPitchRoll(heading, pitch, roll) { this.heading = heading ?? 0; this.pitch = pitch ?? 0; this.roll = roll ?? 0; } HeadingPitchRoll.fromQuaternion = function(quaternion, result) { if (!defined_default(quaternion)) { throw new DeveloperError_default("quaternion is required"); } if (!defined_default(result)) { result = new HeadingPitchRoll(); } const test = 2 * (quaternion.w * quaternion.y - quaternion.z * quaternion.x); const denominatorRoll = 1 - 2 * (quaternion.x * quaternion.x + quaternion.y * quaternion.y); const numeratorRoll = 2 * (quaternion.w * quaternion.x + quaternion.y * quaternion.z); const denominatorHeading = 1 - 2 * (quaternion.y * quaternion.y + quaternion.z * quaternion.z); const numeratorHeading = 2 * (quaternion.w * quaternion.z + quaternion.x * quaternion.y); result.heading = -Math.atan2(numeratorHeading, denominatorHeading); result.roll = Math.atan2(numeratorRoll, denominatorRoll); result.pitch = -Math_default.asinClamped(test); return result; }; HeadingPitchRoll.fromDegrees = function(heading, pitch, roll, result) { if (!defined_default(heading)) { throw new DeveloperError_default("heading is required"); } if (!defined_default(pitch)) { throw new DeveloperError_default("pitch is required"); } if (!defined_default(roll)) { throw new DeveloperError_default("roll is required"); } if (!defined_default(result)) { result = new HeadingPitchRoll(); } result.heading = heading * Math_default.RADIANS_PER_DEGREE; result.pitch = pitch * Math_default.RADIANS_PER_DEGREE; result.roll = roll * Math_default.RADIANS_PER_DEGREE; return result; }; HeadingPitchRoll.clone = function(headingPitchRoll, result) { if (!defined_default(headingPitchRoll)) { return void 0; } if (!defined_default(result)) { return new HeadingPitchRoll( headingPitchRoll.heading, headingPitchRoll.pitch, headingPitchRoll.roll ); } result.heading = headingPitchRoll.heading; result.pitch = headingPitchRoll.pitch; result.roll = headingPitchRoll.roll; return result; }; HeadingPitchRoll.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.heading === right.heading && left.pitch === right.pitch && left.roll === right.roll; }; HeadingPitchRoll.equalsEpsilon = function(left, right, relativeEpsilon, absoluteEpsilon) { return left === right || defined_default(left) && defined_default(right) && Math_default.equalsEpsilon( left.heading, right.heading, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.pitch, right.pitch, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( left.roll, right.roll, relativeEpsilon, absoluteEpsilon ); }; HeadingPitchRoll.prototype.clone = function(result) { return HeadingPitchRoll.clone(this, result); }; HeadingPitchRoll.prototype.equals = function(right) { return HeadingPitchRoll.equals(this, right); }; HeadingPitchRoll.prototype.equalsEpsilon = function(right, relativeEpsilon, absoluteEpsilon) { return HeadingPitchRoll.equalsEpsilon( this, right, relativeEpsilon, absoluteEpsilon ); }; HeadingPitchRoll.prototype.toString = function() { return `(${this.heading}, ${this.pitch}, ${this.roll})`; }; var HeadingPitchRoll_default = HeadingPitchRoll; // packages/engine/Source/Core/Iau2006XysData.js var import_InlineWorkers66 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/buildModuleUrl.js var import_InlineWorkers64 = __toESM(require_InlineWorkers(), 1); var import_meta = {}; var cesiumScriptRegex = /((?:.*\/)|^)Cesium\.js(?:\?|\#|$)/; function getBaseUrlFromCesiumScript() { const scripts = document.getElementsByTagName("script"); for (let i = 0, len = scripts.length; i < len; ++i) { const src = scripts[i].getAttribute("src"); const result = cesiumScriptRegex.exec(src); if (result !== null) { return result[1]; } } return void 0; } var a2; function tryMakeAbsolute(url2) { if (typeof document === "undefined") { return url2; } if (!defined_default(a2)) { a2 = document.createElement("a"); } a2.href = url2; return a2.href; } var baseResource; function getCesiumBaseUrl() { if (defined_default(baseResource)) { return baseResource; } let baseUrlString; if (typeof CESIUM_BASE_URL !== "undefined") { baseUrlString = CESIUM_BASE_URL; } else if (defined_default(import_meta?.url)) { baseUrlString = getAbsoluteUri_default(".", import_meta.url); } else if (typeof define === "object" && defined_default(define.amd) && !define.amd.toUrlUndefined && defined_default(__require.toUrl)) { baseUrlString = getAbsoluteUri_default( "..", buildModuleUrl("Core/buildModuleUrl.js") ); } else { baseUrlString = getBaseUrlFromCesiumScript(); } if (!defined_default(baseUrlString)) { throw new DeveloperError_default( "Unable to determine Cesium base URL automatically, try defining a global variable called CESIUM_BASE_URL." ); } baseResource = new Resource_default({ url: tryMakeAbsolute(baseUrlString) }); baseResource.appendForwardSlash(); return baseResource; } function buildModuleUrlFromRequireToUrl(moduleID) { return tryMakeAbsolute(__require.toUrl(`../${moduleID}`)); } function buildModuleUrlFromBaseUrl(moduleID) { const resource = getCesiumBaseUrl().getDerivedResource({ url: moduleID }); return resource.url; } var implementation; function buildModuleUrl(relativeUrl) { if (!defined_default(implementation)) { if (typeof define === "object" && defined_default(define.amd) && !define.amd.toUrlUndefined && defined_default(__require.toUrl)) { implementation = buildModuleUrlFromRequireToUrl; } else { implementation = buildModuleUrlFromBaseUrl; } } const url2 = implementation(relativeUrl); return url2; } buildModuleUrl._cesiumScriptRegex = cesiumScriptRegex; buildModuleUrl._buildModuleUrlFromBaseUrl = buildModuleUrlFromBaseUrl; buildModuleUrl._clearBaseResource = function() { baseResource = void 0; }; buildModuleUrl.setBaseUrl = function(value) { baseResource = Resource_default.DEFAULT.getDerivedResource({ url: value }); }; buildModuleUrl.getCesiumBaseUrl = getCesiumBaseUrl; var buildModuleUrl_default = buildModuleUrl; // packages/engine/Source/Core/Iau2006XysSample.js var import_InlineWorkers65 = __toESM(require_InlineWorkers(), 1); function Iau2006XysSample(x, y, s2) { this.x = x; this.y = y; this.s = s2; } var Iau2006XysSample_default = Iau2006XysSample; // packages/engine/Source/Core/Iau2006XysData.js function Iau2006XysData(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._xysFileUrlTemplate = Resource_default.createIfNeeded( options.xysFileUrlTemplate ); this._interpolationOrder = options.interpolationOrder ?? 9; this._sampleZeroJulianEphemerisDate = options.sampleZeroJulianEphemerisDate ?? 24423965e-1; this._sampleZeroDateTT = new JulianDate_default( this._sampleZeroJulianEphemerisDate, 0, TimeStandard_default.TAI ); this._stepSizeDays = options.stepSizeDays ?? 1; this._samplesPerXysFile = options.samplesPerXysFile ?? 1e3; this._totalSamples = options.totalSamples ?? 27426; this._samples = new Array(this._totalSamples * 3); this._chunkDownloadsInProgress = []; const order = this._interpolationOrder; const denom = this._denominators = new Array(order + 1); const xTable = this._xTable = new Array(order + 1); const stepN = Math.pow(this._stepSizeDays, order); for (let i = 0; i <= order; ++i) { denom[i] = stepN; xTable[i] = i * this._stepSizeDays; for (let j = 0; j <= order; ++j) { if (j !== i) { denom[i] *= i - j; } } denom[i] = 1 / denom[i]; } this._work = new Array(order + 1); this._coef = new Array(order + 1); } var julianDateScratch = new JulianDate_default(0, 0, TimeStandard_default.TAI); function getDaysSinceEpoch(xys, dayTT, secondTT) { const dateTT2 = julianDateScratch; dateTT2.dayNumber = dayTT; dateTT2.secondsOfDay = secondTT; return JulianDate_default.daysDifference(dateTT2, xys._sampleZeroDateTT); } Iau2006XysData.prototype.preload = function(startDayTT, startSecondTT, stopDayTT, stopSecondTT) { const startDaysSinceEpoch = getDaysSinceEpoch( this, startDayTT, startSecondTT ); const stopDaysSinceEpoch = getDaysSinceEpoch(this, stopDayTT, stopSecondTT); let startIndex = startDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2 | 0; if (startIndex < 0) { startIndex = 0; } let stopIndex = stopDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2 | 0 + this._interpolationOrder; if (stopIndex >= this._totalSamples) { stopIndex = this._totalSamples - 1; } const startChunk = startIndex / this._samplesPerXysFile | 0; const stopChunk = stopIndex / this._samplesPerXysFile | 0; const promises = []; for (let i = startChunk; i <= stopChunk; ++i) { promises.push(requestXysChunk(this, i)); } return Promise.all(promises); }; Iau2006XysData.prototype.computeXysRadians = function(dayTT, secondTT, result) { const daysSinceEpoch = getDaysSinceEpoch(this, dayTT, secondTT); if (daysSinceEpoch < 0) { return void 0; } const centerIndex = daysSinceEpoch / this._stepSizeDays | 0; if (centerIndex >= this._totalSamples) { return void 0; } const degree = this._interpolationOrder; let firstIndex = centerIndex - (degree / 2 | 0); if (firstIndex < 0) { firstIndex = 0; } let lastIndex = firstIndex + degree; if (lastIndex >= this._totalSamples) { lastIndex = this._totalSamples - 1; firstIndex = lastIndex - degree; if (firstIndex < 0) { firstIndex = 0; } } let isDataMissing = false; const samples = this._samples; if (!defined_default(samples[firstIndex * 3])) { requestXysChunk(this, firstIndex / this._samplesPerXysFile | 0); isDataMissing = true; } if (!defined_default(samples[lastIndex * 3])) { requestXysChunk(this, lastIndex / this._samplesPerXysFile | 0); isDataMissing = true; } if (isDataMissing) { return void 0; } if (!defined_default(result)) { result = new Iau2006XysSample_default(0, 0, 0); } else { result.x = 0; result.y = 0; result.s = 0; } const x = daysSinceEpoch - firstIndex * this._stepSizeDays; const work = this._work; const denom = this._denominators; const coef = this._coef; const xTable = this._xTable; let i, j; for (i = 0; i <= degree; ++i) { work[i] = x - xTable[i]; } for (i = 0; i <= degree; ++i) { coef[i] = 1; for (j = 0; j <= degree; ++j) { if (j !== i) { coef[i] *= work[j]; } } coef[i] *= denom[i]; let sampleIndex = (firstIndex + i) * 3; result.x += coef[i] * samples[sampleIndex++]; result.y += coef[i] * samples[sampleIndex++]; result.s += coef[i] * samples[sampleIndex]; } return result; }; Iau2006XysData.prototype._updateChunkData = function(index, { samples }) { this._chunkDownloadsInProgress[index] = void 0; const samplesPerFile = this._samplesPerXysFile; const startIndex = index * samplesPerFile * 3; for (let i = 0; i < samples.length; ++i) { this._samples[startIndex + i] = samples[i]; } }; async function requestXysChunkJson(resource, index, xysData) { try { const chunk = await resource.fetchJson(); xysData._updateChunkData(index, chunk); } catch (e) { } } function requestXysChunk(xysData, chunkIndex) { if (defined_default(xysData._chunkDownloadsInProgress[chunkIndex])) { return xysData._chunkDownloadsInProgress[chunkIndex]; } let chunkUrl; const xysFileUrlTemplate = xysData._xysFileUrlTemplate; if (defined_default(xysFileUrlTemplate)) { chunkUrl = xysFileUrlTemplate.getDerivedResource({ templateValues: { 0: chunkIndex } }); } else { chunkUrl = new Resource_default({ url: buildModuleUrl_default(`Assets/IAU2006_XYS/IAU2006_XYS_${chunkIndex}.json`) }); } const promise = requestXysChunkJson(chunkUrl, chunkIndex, xysData); xysData._chunkDownloadsInProgress[chunkIndex] = promise; return promise; } var Iau2006XysData_default = Iau2006XysData; // packages/engine/Source/Core/Quaternion.js var import_InlineWorkers67 = __toESM(require_InlineWorkers(), 1); function Quaternion(x, y, z2, w) { this.x = x ?? 0; this.y = y ?? 0; this.z = z2 ?? 0; this.w = w ?? 0; } var fromAxisAngleScratch = new Cartesian3_default(); Quaternion.fromAxisAngle = function(axis, angle, result) { Check_default.typeOf.object("axis", axis); Check_default.typeOf.number("angle", angle); const halfAngle = angle / 2; const s2 = Math.sin(halfAngle); fromAxisAngleScratch = Cartesian3_default.normalize(axis, fromAxisAngleScratch); const x = fromAxisAngleScratch.x * s2; const y = fromAxisAngleScratch.y * s2; const z2 = fromAxisAngleScratch.z * s2; const w = Math.cos(halfAngle); if (!defined_default(result)) { return new Quaternion(x, y, z2, w); } result.x = x; result.y = y; result.z = z2; result.w = w; return result; }; var fromRotationMatrixNext = [1, 2, 0]; var fromRotationMatrixQuat = new Array(3); Quaternion.fromRotationMatrix = function(matrix, result) { Check_default.typeOf.object("matrix", matrix); let root; let x; let y; let z2; let w; const m00 = matrix[Matrix3_default.COLUMN0ROW0]; const m11 = matrix[Matrix3_default.COLUMN1ROW1]; const m22 = matrix[Matrix3_default.COLUMN2ROW2]; const trace = m00 + m11 + m22; if (trace > 0) { root = Math.sqrt(trace + 1); w = 0.5 * root; root = 0.5 / root; x = (matrix[Matrix3_default.COLUMN1ROW2] - matrix[Matrix3_default.COLUMN2ROW1]) * root; y = (matrix[Matrix3_default.COLUMN2ROW0] - matrix[Matrix3_default.COLUMN0ROW2]) * root; z2 = (matrix[Matrix3_default.COLUMN0ROW1] - matrix[Matrix3_default.COLUMN1ROW0]) * root; } else { const next = fromRotationMatrixNext; let i = 0; if (m11 > m00) { i = 1; } if (m22 > m00 && m22 > m11) { i = 2; } const j = next[i]; const k = next[j]; root = Math.sqrt( matrix[Matrix3_default.getElementIndex(i, i)] - matrix[Matrix3_default.getElementIndex(j, j)] - matrix[Matrix3_default.getElementIndex(k, k)] + 1 ); const quat = fromRotationMatrixQuat; quat[i] = 0.5 * root; root = 0.5 / root; w = (matrix[Matrix3_default.getElementIndex(k, j)] - matrix[Matrix3_default.getElementIndex(j, k)]) * root; quat[j] = (matrix[Matrix3_default.getElementIndex(j, i)] + matrix[Matrix3_default.getElementIndex(i, j)]) * root; quat[k] = (matrix[Matrix3_default.getElementIndex(k, i)] + matrix[Matrix3_default.getElementIndex(i, k)]) * root; x = -quat[0]; y = -quat[1]; z2 = -quat[2]; } if (!defined_default(result)) { return new Quaternion(x, y, z2, w); } result.x = x; result.y = y; result.z = z2; result.w = w; return result; }; var scratchHPRQuaternion = new Quaternion(); var scratchHeadingQuaternion = new Quaternion(); var scratchPitchQuaternion = new Quaternion(); var scratchRollQuaternion = new Quaternion(); Quaternion.fromHeadingPitchRoll = function(headingPitchRoll, result) { Check_default.typeOf.object("headingPitchRoll", headingPitchRoll); scratchRollQuaternion = Quaternion.fromAxisAngle( Cartesian3_default.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion ); scratchPitchQuaternion = Quaternion.fromAxisAngle( Cartesian3_default.UNIT_Y, -headingPitchRoll.pitch, result ); result = Quaternion.multiply( scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion ); scratchHeadingQuaternion = Quaternion.fromAxisAngle( Cartesian3_default.UNIT_Z, -headingPitchRoll.heading, scratchHPRQuaternion ); return Quaternion.multiply(scratchHeadingQuaternion, result, result); }; var sampledQuaternionAxis = new Cartesian3_default(); var sampledQuaternionRotation = new Cartesian3_default(); var sampledQuaternionTempQuaternion = new Quaternion(); var sampledQuaternionQuaternion0 = new Quaternion(); var sampledQuaternionQuaternion0Conjugate = new Quaternion(); Quaternion.packedLength = 4; Quaternion.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.x; array[startingIndex++] = value.y; array[startingIndex++] = value.z; array[startingIndex] = value.w; return array; }; Quaternion.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new Quaternion(); } result.x = array[startingIndex]; result.y = array[startingIndex + 1]; result.z = array[startingIndex + 2]; result.w = array[startingIndex + 3]; return result; }; Quaternion.packedInterpolationLength = 3; Quaternion.convertPackedArrayForInterpolation = function(packedArray, startingIndex, lastIndex, result) { Quaternion.unpack( packedArray, lastIndex * 4, sampledQuaternionQuaternion0Conjugate ); Quaternion.conjugate( sampledQuaternionQuaternion0Conjugate, sampledQuaternionQuaternion0Conjugate ); for (let i = 0, len = lastIndex - startingIndex + 1; i < len; i++) { const offset = i * 3; Quaternion.unpack( packedArray, (startingIndex + i) * 4, sampledQuaternionTempQuaternion ); Quaternion.multiply( sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0Conjugate, sampledQuaternionTempQuaternion ); if (sampledQuaternionTempQuaternion.w < 0) { Quaternion.negate( sampledQuaternionTempQuaternion, sampledQuaternionTempQuaternion ); } Quaternion.computeAxis( sampledQuaternionTempQuaternion, sampledQuaternionAxis ); const angle = Quaternion.computeAngle(sampledQuaternionTempQuaternion); if (!defined_default(result)) { result = []; } result[offset] = sampledQuaternionAxis.x * angle; result[offset + 1] = sampledQuaternionAxis.y * angle; result[offset + 2] = sampledQuaternionAxis.z * angle; } }; Quaternion.unpackInterpolationResult = function(array, sourceArray, firstIndex, lastIndex, result) { if (!defined_default(result)) { result = new Quaternion(); } Cartesian3_default.fromArray(array, 0, sampledQuaternionRotation); const magnitude = Cartesian3_default.magnitude(sampledQuaternionRotation); Quaternion.unpack(sourceArray, lastIndex * 4, sampledQuaternionQuaternion0); if (magnitude === 0) { Quaternion.clone(Quaternion.IDENTITY, sampledQuaternionTempQuaternion); } else { Quaternion.fromAxisAngle( sampledQuaternionRotation, magnitude, sampledQuaternionTempQuaternion ); } return Quaternion.multiply( sampledQuaternionTempQuaternion, sampledQuaternionQuaternion0, result ); }; Quaternion.clone = function(quaternion, result) { if (!defined_default(quaternion)) { return void 0; } if (!defined_default(result)) { return new Quaternion( quaternion.x, quaternion.y, quaternion.z, quaternion.w ); } result.x = quaternion.x; result.y = quaternion.y; result.z = quaternion.z; result.w = quaternion.w; return result; }; Quaternion.conjugate = function(quaternion, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.object("result", result); result.x = -quaternion.x; result.y = -quaternion.y; result.z = -quaternion.z; result.w = quaternion.w; return result; }; Quaternion.magnitudeSquared = function(quaternion) { Check_default.typeOf.object("quaternion", quaternion); return quaternion.x * quaternion.x + quaternion.y * quaternion.y + quaternion.z * quaternion.z + quaternion.w * quaternion.w; }; Quaternion.magnitude = function(quaternion) { return Math.sqrt(Quaternion.magnitudeSquared(quaternion)); }; Quaternion.normalize = function(quaternion, result) { Check_default.typeOf.object("result", result); const inverseMagnitude = 1 / Quaternion.magnitude(quaternion); const x = quaternion.x * inverseMagnitude; const y = quaternion.y * inverseMagnitude; const z2 = quaternion.z * inverseMagnitude; const w = quaternion.w * inverseMagnitude; result.x = x; result.y = y; result.z = z2; result.w = w; return result; }; Quaternion.inverse = function(quaternion, result) { Check_default.typeOf.object("result", result); const magnitudeSquared = Quaternion.magnitudeSquared(quaternion); result = Quaternion.conjugate(quaternion, result); return Quaternion.multiplyByScalar(result, 1 / magnitudeSquared, result); }; Quaternion.add = function(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x + right.x; result.y = left.y + right.y; result.z = left.z + right.z; result.w = left.w + right.w; return result; }; Quaternion.subtract = function(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result.x = left.x - right.x; result.y = left.y - right.y; result.z = left.z - right.z; result.w = left.w - right.w; return result; }; Quaternion.negate = function(quaternion, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.object("result", result); result.x = -quaternion.x; result.y = -quaternion.y; result.z = -quaternion.z; result.w = -quaternion.w; return result; }; Quaternion.dot = function(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w; }; Quaternion.multiply = function(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const leftX = left.x; const leftY = left.y; const leftZ = left.z; const leftW = left.w; const rightX = right.x; const rightY = right.y; const rightZ = right.z; const rightW = right.w; const x = leftW * rightX + leftX * rightW + leftY * rightZ - leftZ * rightY; const y = leftW * rightY - leftX * rightZ + leftY * rightW + leftZ * rightX; const z2 = leftW * rightZ + leftX * rightY - leftY * rightX + leftZ * rightW; const w = leftW * rightW - leftX * rightX - leftY * rightY - leftZ * rightZ; result.x = x; result.y = y; result.z = z2; result.w = w; return result; }; Quaternion.multiplyByScalar = function(quaternion, scalar, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = quaternion.x * scalar; result.y = quaternion.y * scalar; result.z = quaternion.z * scalar; result.w = quaternion.w * scalar; return result; }; Quaternion.divideByScalar = function(quaternion, scalar, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result.x = quaternion.x / scalar; result.y = quaternion.y / scalar; result.z = quaternion.z / scalar; result.w = quaternion.w / scalar; return result; }; Quaternion.computeAxis = function(quaternion, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.object("result", result); const w = quaternion.w; if (Math.abs(w - 1) < Math_default.EPSILON6 || Math.abs(w + 1) < Math_default.EPSILON6) { result.x = 1; result.y = result.z = 0; return result; } const scalar = 1 / Math.sqrt(1 - w * w); result.x = quaternion.x * scalar; result.y = quaternion.y * scalar; result.z = quaternion.z * scalar; return result; }; Quaternion.computeAngle = function(quaternion) { Check_default.typeOf.object("quaternion", quaternion); if (Math.abs(quaternion.w - 1) < Math_default.EPSILON6) { return 0; } return 2 * Math.acos(quaternion.w); }; var lerpScratch4 = new Quaternion(); Quaternion.lerp = function(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); lerpScratch4 = Quaternion.multiplyByScalar(end, t2, lerpScratch4); result = Quaternion.multiplyByScalar(start, 1 - t2, result); return Quaternion.add(lerpScratch4, result, result); }; var slerpEndNegated = new Quaternion(); var slerpScaledP = new Quaternion(); var slerpScaledR = new Quaternion(); Quaternion.slerp = function(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); let dot2 = Quaternion.dot(start, end); let r2 = end; if (dot2 < 0) { dot2 = -dot2; r2 = slerpEndNegated = Quaternion.negate(end, slerpEndNegated); } if (1 - dot2 < Math_default.EPSILON6) { return Quaternion.lerp(start, r2, t2, result); } const theta = Math.acos(dot2); slerpScaledP = Quaternion.multiplyByScalar( start, Math.sin((1 - t2) * theta), slerpScaledP ); slerpScaledR = Quaternion.multiplyByScalar( r2, Math.sin(t2 * theta), slerpScaledR ); result = Quaternion.add(slerpScaledP, slerpScaledR, result); return Quaternion.multiplyByScalar(result, 1 / Math.sin(theta), result); }; Quaternion.log = function(quaternion, result) { Check_default.typeOf.object("quaternion", quaternion); Check_default.typeOf.object("result", result); const theta = Math_default.acosClamped(quaternion.w); let thetaOverSinTheta = 0; if (theta !== 0) { thetaOverSinTheta = theta / Math.sin(theta); } return Cartesian3_default.multiplyByScalar(quaternion, thetaOverSinTheta, result); }; Quaternion.exp = function(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const theta = Cartesian3_default.magnitude(cartesian11); let sinThetaOverTheta = 0; if (theta !== 0) { sinThetaOverTheta = Math.sin(theta) / theta; } result.x = cartesian11.x * sinThetaOverTheta; result.y = cartesian11.y * sinThetaOverTheta; result.z = cartesian11.z * sinThetaOverTheta; result.w = Math.cos(theta); return result; }; var squadScratchCartesian0 = new Cartesian3_default(); var squadScratchCartesian1 = new Cartesian3_default(); var squadScratchQuaternion0 = new Quaternion(); var squadScratchQuaternion1 = new Quaternion(); Quaternion.computeInnerQuadrangle = function(q0, q12, q22, result) { Check_default.typeOf.object("q0", q0); Check_default.typeOf.object("q1", q12); Check_default.typeOf.object("q2", q22); Check_default.typeOf.object("result", result); const qInv = Quaternion.conjugate(q12, squadScratchQuaternion0); Quaternion.multiply(qInv, q22, squadScratchQuaternion1); const cart0 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian0); Quaternion.multiply(qInv, q0, squadScratchQuaternion1); const cart1 = Quaternion.log(squadScratchQuaternion1, squadScratchCartesian1); Cartesian3_default.add(cart0, cart1, cart0); Cartesian3_default.multiplyByScalar(cart0, 0.25, cart0); Cartesian3_default.negate(cart0, cart0); Quaternion.exp(cart0, squadScratchQuaternion0); return Quaternion.multiply(q12, squadScratchQuaternion0, result); }; Quaternion.squad = function(q0, q12, s0, s1, t2, result) { Check_default.typeOf.object("q0", q0); Check_default.typeOf.object("q1", q12); Check_default.typeOf.object("s0", s0); Check_default.typeOf.object("s1", s1); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); const slerp0 = Quaternion.slerp(q0, q12, t2, squadScratchQuaternion0); const slerp1 = Quaternion.slerp(s0, s1, t2, squadScratchQuaternion1); return Quaternion.slerp(slerp0, slerp1, 2 * t2 * (1 - t2), result); }; var fastSlerpScratchQuaternion = new Quaternion(); var opmu = 1.9011074535173003; var u = FeatureDetection_default.supportsTypedArrays() ? new Float32Array(8) : []; var v = FeatureDetection_default.supportsTypedArrays() ? new Float32Array(8) : []; var bT = FeatureDetection_default.supportsTypedArrays() ? new Float32Array(8) : []; var bD = FeatureDetection_default.supportsTypedArrays() ? new Float32Array(8) : []; for (let i = 0; i < 7; ++i) { const s2 = i + 1; const t2 = 2 * s2 + 1; u[i] = 1 / (s2 * t2); v[i] = s2 / t2; } u[7] = opmu / (8 * 17); v[7] = opmu * 8 / 17; Quaternion.fastSlerp = function(start, end, t2, result) { Check_default.typeOf.object("start", start); Check_default.typeOf.object("end", end); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); let x = Quaternion.dot(start, end); let sign3; if (x >= 0) { sign3 = 1; } else { sign3 = -1; x = -x; } const xm1 = x - 1; const d = 1 - t2; const sqrT = t2 * t2; const sqrD = d * d; for (let i = 7; i >= 0; --i) { bT[i] = (u[i] * sqrT - v[i]) * xm1; bD[i] = (u[i] * sqrD - v[i]) * xm1; } const cT = sign3 * t2 * (1 + bT[0] * (1 + bT[1] * (1 + bT[2] * (1 + bT[3] * (1 + bT[4] * (1 + bT[5] * (1 + bT[6] * (1 + bT[7])))))))); const cD = d * (1 + bD[0] * (1 + bD[1] * (1 + bD[2] * (1 + bD[3] * (1 + bD[4] * (1 + bD[5] * (1 + bD[6] * (1 + bD[7])))))))); const temp = Quaternion.multiplyByScalar( start, cD, fastSlerpScratchQuaternion ); Quaternion.multiplyByScalar(end, cT, result); return Quaternion.add(temp, result, result); }; Quaternion.fastSquad = function(q0, q12, s0, s1, t2, result) { Check_default.typeOf.object("q0", q0); Check_default.typeOf.object("q1", q12); Check_default.typeOf.object("s0", s0); Check_default.typeOf.object("s1", s1); Check_default.typeOf.number("t", t2); Check_default.typeOf.object("result", result); const slerp0 = Quaternion.fastSlerp(q0, q12, t2, squadScratchQuaternion0); const slerp1 = Quaternion.fastSlerp(s0, s1, t2, squadScratchQuaternion1); return Quaternion.fastSlerp(slerp0, slerp1, 2 * t2 * (1 - t2), result); }; Quaternion.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.x === right.x && left.y === right.y && left.z === right.z && left.w === right.w; }; Quaternion.equalsEpsilon = function(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left.x - right.x) <= epsilon && Math.abs(left.y - right.y) <= epsilon && Math.abs(left.z - right.z) <= epsilon && Math.abs(left.w - right.w) <= epsilon; }; Quaternion.ZERO = Object.freeze(new Quaternion(0, 0, 0, 0)); Quaternion.IDENTITY = Object.freeze(new Quaternion(0, 0, 0, 1)); Quaternion.prototype.clone = function(result) { return Quaternion.clone(this, result); }; Quaternion.prototype.equals = function(right) { return Quaternion.equals(this, right); }; Quaternion.prototype.equalsEpsilon = function(right, epsilon) { return Quaternion.equalsEpsilon(this, right, epsilon); }; Quaternion.prototype.toString = function() { return `(${this.x}, ${this.y}, ${this.z}, ${this.w})`; }; var Quaternion_default = Quaternion; // packages/engine/Source/Core/Transforms.js var Transforms = {}; var vectorProductLocalFrame = { up: { south: "east", north: "west", west: "south", east: "north" }, down: { south: "west", north: "east", west: "north", east: "south" }, south: { up: "west", down: "east", west: "down", east: "up" }, north: { up: "east", down: "west", west: "up", east: "down" }, west: { up: "north", down: "south", north: "down", south: "up" }, east: { up: "south", down: "north", north: "up", south: "down" } }; var degeneratePositionLocalFrame = { north: [-1, 0, 0], east: [0, 1, 0], up: [0, 0, 1], south: [1, 0, 0], west: [0, -1, 0], down: [0, 0, -1] }; var localFrameToFixedFrameCache = {}; var scratchCalculateCartesian = { east: new Cartesian3_default(), north: new Cartesian3_default(), up: new Cartesian3_default(), west: new Cartesian3_default(), south: new Cartesian3_default(), down: new Cartesian3_default() }; var scratchFirstCartesian = new Cartesian3_default(); var scratchSecondCartesian = new Cartesian3_default(); var scratchThirdCartesian = new Cartesian3_default(); Transforms.localFrameToFixedFrameGenerator = function(firstAxis, secondAxis) { if (!vectorProductLocalFrame.hasOwnProperty(firstAxis) || !vectorProductLocalFrame[firstAxis].hasOwnProperty(secondAxis)) { throw new DeveloperError_default( "firstAxis and secondAxis must be east, north, up, west, south or down." ); } const thirdAxis = vectorProductLocalFrame[firstAxis][secondAxis]; let resultat; const hashAxis = firstAxis + secondAxis; if (defined_default(localFrameToFixedFrameCache[hashAxis])) { resultat = localFrameToFixedFrameCache[hashAxis]; } else { resultat = function(origin, ellipsoid, result) { if (!defined_default(origin)) { throw new DeveloperError_default("origin is required."); } if (isNaN(origin.x) || isNaN(origin.y) || isNaN(origin.z)) { throw new DeveloperError_default("origin has a NaN component"); } if (!defined_default(result)) { result = new Matrix4_default(); } if (Cartesian3_default.equalsEpsilon(origin, Cartesian3_default.ZERO, Math_default.EPSILON14)) { Cartesian3_default.unpack( degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian ); Cartesian3_default.unpack( degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian ); Cartesian3_default.unpack( degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian ); } else if (Math_default.equalsEpsilon(origin.x, 0, Math_default.EPSILON14) && Math_default.equalsEpsilon(origin.y, 0, Math_default.EPSILON14)) { const sign3 = Math_default.sign(origin.z); Cartesian3_default.unpack( degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian ); if (firstAxis !== "east" && firstAxis !== "west") { Cartesian3_default.multiplyByScalar( scratchFirstCartesian, sign3, scratchFirstCartesian ); } Cartesian3_default.unpack( degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian ); if (secondAxis !== "east" && secondAxis !== "west") { Cartesian3_default.multiplyByScalar( scratchSecondCartesian, sign3, scratchSecondCartesian ); } Cartesian3_default.unpack( degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian ); if (thirdAxis !== "east" && thirdAxis !== "west") { Cartesian3_default.multiplyByScalar( scratchThirdCartesian, sign3, scratchThirdCartesian ); } } else { ellipsoid = ellipsoid ?? Ellipsoid_default.default; ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up); const up = scratchCalculateCartesian.up; const east = scratchCalculateCartesian.east; east.x = -origin.y; east.y = origin.x; east.z = 0; Cartesian3_default.normalize(east, scratchCalculateCartesian.east); Cartesian3_default.cross(up, east, scratchCalculateCartesian.north); Cartesian3_default.multiplyByScalar( scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down ); Cartesian3_default.multiplyByScalar( scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west ); Cartesian3_default.multiplyByScalar( scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south ); scratchFirstCartesian = scratchCalculateCartesian[firstAxis]; scratchSecondCartesian = scratchCalculateCartesian[secondAxis]; scratchThirdCartesian = scratchCalculateCartesian[thirdAxis]; } result[0] = scratchFirstCartesian.x; result[1] = scratchFirstCartesian.y; result[2] = scratchFirstCartesian.z; result[3] = 0; result[4] = scratchSecondCartesian.x; result[5] = scratchSecondCartesian.y; result[6] = scratchSecondCartesian.z; result[7] = 0; result[8] = scratchThirdCartesian.x; result[9] = scratchThirdCartesian.y; result[10] = scratchThirdCartesian.z; result[11] = 0; result[12] = origin.x; result[13] = origin.y; result[14] = origin.z; result[15] = 1; return result; }; localFrameToFixedFrameCache[hashAxis] = resultat; } return resultat; }; Transforms.eastNorthUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator( "east", "north" ); Transforms.northEastDownToFixedFrame = Transforms.localFrameToFixedFrameGenerator("north", "east"); Transforms.northUpEastToFixedFrame = Transforms.localFrameToFixedFrameGenerator( "north", "up" ); Transforms.northWestUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator( "north", "west" ); var scratchHPRQuaternion2 = new Quaternion_default(); var scratchScale = new Cartesian3_default(1, 1, 1); var scratchHPRMatrix4 = new Matrix4_default(); Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) { Check_default.typeOf.object("HeadingPitchRoll", headingPitchRoll); fixedFrameTransform = fixedFrameTransform ?? Transforms.eastNorthUpToFixedFrame; const hprQuaternion = Quaternion_default.fromHeadingPitchRoll( headingPitchRoll, scratchHPRQuaternion2 ); const hprMatrix = Matrix4_default.fromTranslationQuaternionRotationScale( Cartesian3_default.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4 ); result = fixedFrameTransform(origin, ellipsoid, result); return Matrix4_default.multiply(result, hprMatrix, result); }; var scratchENUMatrix4 = new Matrix4_default(); var scratchHPRMatrix3 = new Matrix3_default(); Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) { Check_default.typeOf.object("HeadingPitchRoll", headingPitchRoll); const transform3 = Transforms.headingPitchRollToFixedFrame( origin, headingPitchRoll, ellipsoid, fixedFrameTransform, scratchENUMatrix4 ); const rotation = Matrix4_default.getMatrix3(transform3, scratchHPRMatrix3); return Quaternion_default.fromRotationMatrix(rotation, result); }; var noScale = new Cartesian3_default(1, 1, 1); var hprCenterScratch = new Cartesian3_default(); var ffScratch = new Matrix4_default(); var hprTransformScratch = new Matrix4_default(); var hprRotationScratch = new Matrix3_default(); var hprQuaternionScratch = new Quaternion_default(); Transforms.fixedFrameToHeadingPitchRoll = function(transform3, ellipsoid, fixedFrameTransform, result) { Check_default.defined("transform", transform3); ellipsoid = ellipsoid ?? Ellipsoid_default.default; fixedFrameTransform = fixedFrameTransform ?? Transforms.eastNorthUpToFixedFrame; if (!defined_default(result)) { result = new HeadingPitchRoll_default(); } const center = Matrix4_default.getTranslation(transform3, hprCenterScratch); if (Cartesian3_default.equals(center, Cartesian3_default.ZERO)) { result.heading = 0; result.pitch = 0; result.roll = 0; return result; } let toFixedFrame = Matrix4_default.inverseTransformation( fixedFrameTransform(center, ellipsoid, ffScratch), ffScratch ); let transformCopy = Matrix4_default.setScale(transform3, noScale, hprTransformScratch); transformCopy = Matrix4_default.setTranslation( transformCopy, Cartesian3_default.ZERO, transformCopy ); toFixedFrame = Matrix4_default.multiply(toFixedFrame, transformCopy, toFixedFrame); let quaternionRotation = Quaternion_default.fromRotationMatrix( Matrix4_default.getMatrix3(toFixedFrame, hprRotationScratch), hprQuaternionScratch ); quaternionRotation = Quaternion_default.normalize( quaternionRotation, quaternionRotation ); return HeadingPitchRoll_default.fromQuaternion(quaternionRotation, result); }; var gmstConstant0 = 6 * 3600 + 41 * 60 + 50.54841; var gmstConstant1 = 8640184812866e-6; var gmstConstant2 = 0.093104; var gmstConstant3 = -62e-7; var rateCoef = 11772758384668e-32; var wgs84WRPrecessing = 72921158553e-15; var twoPiOverSecondsInDay = Math_default.TWO_PI / 86400; var dateInUtc = new JulianDate_default(); Transforms.computeIcrfToCentralBodyFixedMatrix = function(date, result) { let transformMatrix2 = Transforms.computeIcrfToFixedMatrix(date, result); if (!defined_default(transformMatrix2)) { transformMatrix2 = Transforms.computeTemeToPseudoFixedMatrix(date, result); } return transformMatrix2; }; Transforms.computeTemeToPseudoFixedMatrix = function(date, result) { if (!defined_default(date)) { throw new DeveloperError_default("date is required."); } dateInUtc = JulianDate_default.addSeconds( date, -JulianDate_default.computeTaiMinusUtc(date), dateInUtc ); const utcDayNumber = dateInUtc.dayNumber; const utcSecondsIntoDay = dateInUtc.secondsOfDay; let t2; const diffDays = utcDayNumber - 2451545; if (utcSecondsIntoDay >= 43200) { t2 = (diffDays + 0.5) / TimeConstants_default.DAYS_PER_JULIAN_CENTURY; } else { t2 = (diffDays - 0.5) / TimeConstants_default.DAYS_PER_JULIAN_CENTURY; } const gmst0 = gmstConstant0 + t2 * (gmstConstant1 + t2 * (gmstConstant2 + t2 * gmstConstant3)); const angle = gmst0 * twoPiOverSecondsInDay % Math_default.TWO_PI; const ratio = wgs84WRPrecessing + rateCoef * (utcDayNumber - 24515455e-1); const secondsSinceMidnight = (utcSecondsIntoDay + TimeConstants_default.SECONDS_PER_DAY * 0.5) % TimeConstants_default.SECONDS_PER_DAY; const gha = angle + ratio * secondsSinceMidnight; const cosGha = Math.cos(gha); const sinGha = Math.sin(gha); if (!defined_default(result)) { return new Matrix3_default( cosGha, sinGha, 0, -sinGha, cosGha, 0, 0, 0, 1 ); } result[0] = cosGha; result[1] = -sinGha; result[2] = 0; result[3] = sinGha; result[4] = cosGha; result[5] = 0; result[6] = 0; result[7] = 0; result[8] = 1; return result; }; Transforms.iau2006XysData = new Iau2006XysData_default(); Transforms.earthOrientationParameters = EarthOrientationParameters_default.NONE; var ttMinusTai = 32.184; var j2000ttDays = 2451545; Transforms.preloadIcrfFixed = function(timeInterval) { const startDayTT = timeInterval.start.dayNumber; const startSecondTT = timeInterval.start.secondsOfDay + ttMinusTai; const stopDayTT = timeInterval.stop.dayNumber; const stopSecondTT = timeInterval.stop.secondsOfDay + ttMinusTai; return Transforms.iau2006XysData.preload( startDayTT, startSecondTT, stopDayTT, stopSecondTT ); }; Transforms.computeIcrfToFixedMatrix = function(date, result) { if (!defined_default(date)) { throw new DeveloperError_default("date is required."); } if (!defined_default(result)) { result = new Matrix3_default(); } const fixedToIcrfMtx = Transforms.computeFixedToIcrfMatrix(date, result); if (!defined_default(fixedToIcrfMtx)) { return void 0; } return Matrix3_default.transpose(fixedToIcrfMtx, result); }; var TdtMinusTai = 32.184; var J2000d = 2451545; var scratchHpr = new HeadingPitchRoll_default(); var scratchRotationMatrix = new Matrix3_default(); var dateScratch = new JulianDate_default(); Transforms.computeMoonFixedToIcrfMatrix = function(date, result) { if (!defined_default(date)) { throw new DeveloperError_default("date is required."); } if (!defined_default(result)) { result = new Matrix3_default(); } const secondsTT = JulianDate_default.addSeconds(date, TdtMinusTai, dateScratch); const d = JulianDate_default.totalDays(secondsTT) - J2000d; const e1 = Math_default.toRadians(12.112) - Math_default.toRadians(0.052992) * d; const e2 = Math_default.toRadians(24.224) - Math_default.toRadians(0.105984) * d; const e3 = Math_default.toRadians(227.645) + Math_default.toRadians(13.012) * d; const e4 = Math_default.toRadians(261.105) + Math_default.toRadians(13.340716) * d; const e5 = Math_default.toRadians(358) + Math_default.toRadians(0.9856) * d; scratchHpr.pitch = Math_default.toRadians(270 - 90) - Math_default.toRadians(3.878) * Math.sin(e1) - Math_default.toRadians(0.12) * Math.sin(e2) + Math_default.toRadians(0.07) * Math.sin(e3) - Math_default.toRadians(0.017) * Math.sin(e4); scratchHpr.roll = Math_default.toRadians(66.53 - 90) + Math_default.toRadians(1.543) * Math.cos(e1) + Math_default.toRadians(0.24) * Math.cos(e2) - Math_default.toRadians(0.028) * Math.cos(e3) + Math_default.toRadians(7e-3) * Math.cos(e4); scratchHpr.heading = Math_default.toRadians(244.375 - 90) + Math_default.toRadians(13.17635831) * d + Math_default.toRadians(3.558) * Math.sin(e1) + Math_default.toRadians(0.121) * Math.sin(e2) - Math_default.toRadians(0.064) * Math.sin(e3) + Math_default.toRadians(0.016) * Math.sin(e4) + Math_default.toRadians(0.025) * Math.sin(e5); return Matrix3_default.fromHeadingPitchRoll( scratchHpr, scratchRotationMatrix, result ); }; Transforms.computeIcrfToMoonFixedMatrix = function(date, result) { if (!defined_default(date)) { throw new DeveloperError_default("date is required."); } if (!defined_default(result)) { result = new Matrix3_default(); } const fixedToIcrfMtx = Transforms.computeMoonFixedToIcrfMatrix(date, result); if (!defined_default(fixedToIcrfMtx)) { return void 0; } return Matrix3_default.transpose(fixedToIcrfMtx, result); }; var xysScratch = new Iau2006XysSample_default(0, 0, 0); var eopScratch = new EarthOrientationParametersSample_default( 0, 0, 0, 0, 0, 0 ); var rotation1Scratch = new Matrix3_default(); var rotation2Scratch = new Matrix3_default(); Transforms.computeFixedToIcrfMatrix = function(date, result) { if (!defined_default(date)) { throw new DeveloperError_default("date is required."); } if (!defined_default(result)) { result = new Matrix3_default(); } const eop = Transforms.earthOrientationParameters.compute(date, eopScratch); if (!defined_default(eop)) { return void 0; } const dayTT = date.dayNumber; const secondTT = date.secondsOfDay + ttMinusTai; const xys = Transforms.iau2006XysData.computeXysRadians( dayTT, secondTT, xysScratch ); if (!defined_default(xys)) { return void 0; } const x = xys.x + eop.xPoleOffset; const y = xys.y + eop.yPoleOffset; const a3 = 1 / (1 + Math.sqrt(1 - x * x - y * y)); const rotation1 = rotation1Scratch; rotation1[0] = 1 - a3 * x * x; rotation1[3] = -a3 * x * y; rotation1[6] = x; rotation1[1] = -a3 * x * y; rotation1[4] = 1 - a3 * y * y; rotation1[7] = y; rotation1[2] = -x; rotation1[5] = -y; rotation1[8] = 1 - a3 * (x * x + y * y); const rotation2 = Matrix3_default.fromRotationZ(-xys.s, rotation2Scratch); const matrixQ = Matrix3_default.multiply(rotation1, rotation2, rotation1Scratch); const dateUt1day = date.dayNumber; const dateUt1sec = date.secondsOfDay - JulianDate_default.computeTaiMinusUtc(date) + eop.ut1MinusUtc; const daysSinceJ2000 = dateUt1day - 2451545; const fractionOfDay = dateUt1sec / TimeConstants_default.SECONDS_PER_DAY; let era = 0.779057273264 + fractionOfDay + 0.00273781191135448 * (daysSinceJ2000 + fractionOfDay); era = era % 1 * Math_default.TWO_PI; const earthRotation = Matrix3_default.fromRotationZ(era, rotation2Scratch); const pfToIcrf = Matrix3_default.multiply(matrixQ, earthRotation, rotation1Scratch); const cosxp = Math.cos(eop.xPoleWander); const cosyp = Math.cos(eop.yPoleWander); const sinxp = Math.sin(eop.xPoleWander); const sinyp = Math.sin(eop.yPoleWander); let ttt = dayTT - j2000ttDays + secondTT / TimeConstants_default.SECONDS_PER_DAY; ttt /= 36525; const sp = -47e-6 * ttt * Math_default.RADIANS_PER_DEGREE / 3600; const cossp = Math.cos(sp); const sinsp = Math.sin(sp); const fToPfMtx = rotation2Scratch; fToPfMtx[0] = cosxp * cossp; fToPfMtx[1] = cosxp * sinsp; fToPfMtx[2] = sinxp; fToPfMtx[3] = -cosyp * sinsp + sinyp * sinxp * cossp; fToPfMtx[4] = cosyp * cossp + sinyp * sinxp * sinsp; fToPfMtx[5] = -sinyp * cosxp; fToPfMtx[6] = -sinyp * sinsp - cosyp * sinxp * cossp; fToPfMtx[7] = sinyp * cossp - cosyp * sinxp * sinsp; fToPfMtx[8] = cosyp * cosxp; return Matrix3_default.multiply(pfToIcrf, fToPfMtx, result); }; var pointToWindowCoordinatesTemp = new Cartesian4_default(); Transforms.pointToWindowCoordinates = function(modelViewProjectionMatrix, viewportTransformation, point4, result) { result = Transforms.pointToGLWindowCoordinates( modelViewProjectionMatrix, viewportTransformation, point4, result ); result.y = 2 * viewportTransformation[5] - result.y; return result; }; Transforms.pointToGLWindowCoordinates = function(modelViewProjectionMatrix, viewportTransformation, point4, result) { if (!defined_default(modelViewProjectionMatrix)) { throw new DeveloperError_default("modelViewProjectionMatrix is required."); } if (!defined_default(viewportTransformation)) { throw new DeveloperError_default("viewportTransformation is required."); } if (!defined_default(point4)) { throw new DeveloperError_default("point is required."); } if (!defined_default(result)) { result = new Cartesian2_default(); } const tmp2 = pointToWindowCoordinatesTemp; Matrix4_default.multiplyByVector( modelViewProjectionMatrix, Cartesian4_default.fromElements(point4.x, point4.y, point4.z, 1, tmp2), tmp2 ); Cartesian4_default.multiplyByScalar(tmp2, 1 / tmp2.w, tmp2); Matrix4_default.multiplyByVector(viewportTransformation, tmp2, tmp2); return Cartesian2_default.fromCartesian4(tmp2, result); }; var normalScratch = new Cartesian3_default(); var rightScratch = new Cartesian3_default(); var upScratch = new Cartesian3_default(); Transforms.rotationMatrixFromPositionVelocity = function(position, velocity, ellipsoid, result) { if (!defined_default(position)) { throw new DeveloperError_default("position is required."); } if (!defined_default(velocity)) { throw new DeveloperError_default("velocity is required."); } const normal2 = (ellipsoid ?? Ellipsoid_default.default).geodeticSurfaceNormal( position, normalScratch ); let right = Cartesian3_default.cross(velocity, normal2, rightScratch); if (Cartesian3_default.equalsEpsilon(right, Cartesian3_default.ZERO, Math_default.EPSILON6)) { right = Cartesian3_default.clone(Cartesian3_default.UNIT_X, right); } const up = Cartesian3_default.cross(right, velocity, upScratch); Cartesian3_default.normalize(up, up); Cartesian3_default.cross(velocity, up, right); Cartesian3_default.negate(right, right); Cartesian3_default.normalize(right, right); if (!defined_default(result)) { result = new Matrix3_default(); } result[0] = velocity.x; result[1] = velocity.y; result[2] = velocity.z; result[3] = right.x; result[4] = right.y; result[5] = right.z; result[6] = up.x; result[7] = up.y; result[8] = up.z; return result; }; Transforms.SWIZZLE_3D_TO_2D_MATRIX = Object.freeze( new Matrix4_default( 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 ) ); var scratchCartographic = new Cartographic_default(); var scratchCartesian3Projection = new Cartesian3_default(); var scratchCenter = new Cartesian3_default(); var scratchRotation = new Matrix3_default(); var scratchFromENU = new Matrix4_default(); var scratchToENU = new Matrix4_default(); Transforms.basisTo2D = function(projection, matrix, result) { if (!defined_default(projection)) { throw new DeveloperError_default("projection is required."); } if (!defined_default(matrix)) { throw new DeveloperError_default("matrix is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const rtcCenter = Matrix4_default.getTranslation(matrix, scratchCenter); const ellipsoid = projection.ellipsoid; let projectedPosition2; if (Cartesian3_default.equals(rtcCenter, Cartesian3_default.ZERO)) { projectedPosition2 = Cartesian3_default.clone( Cartesian3_default.ZERO, scratchCartesian3Projection ); } else { const cartographic2 = ellipsoid.cartesianToCartographic( rtcCenter, scratchCartographic ); projectedPosition2 = projection.project( cartographic2, scratchCartesian3Projection ); Cartesian3_default.fromElements( projectedPosition2.z, projectedPosition2.x, projectedPosition2.y, projectedPosition2 ); } const fromENU = Transforms.eastNorthUpToFixedFrame( rtcCenter, ellipsoid, scratchFromENU ); const toENU = Matrix4_default.inverseTransformation(fromENU, scratchToENU); const rotation = Matrix4_default.getMatrix3(matrix, scratchRotation); const local = Matrix4_default.multiplyByMatrix3(toENU, rotation, result); Matrix4_default.multiply(Transforms.SWIZZLE_3D_TO_2D_MATRIX, local, result); Matrix4_default.setTranslation(result, projectedPosition2, result); return result; }; Transforms.ellipsoidTo2DModelMatrix = function(projection, center, result) { if (!defined_default(projection)) { throw new DeveloperError_default("projection is required."); } if (!defined_default(center)) { throw new DeveloperError_default("center is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const ellipsoid = projection.ellipsoid; const fromENU = Transforms.eastNorthUpToFixedFrame( center, ellipsoid, scratchFromENU ); const toENU = Matrix4_default.inverseTransformation(fromENU, scratchToENU); const cartographic2 = ellipsoid.cartesianToCartographic( center, scratchCartographic ); const projectedPosition2 = projection.project( cartographic2, scratchCartesian3Projection ); Cartesian3_default.fromElements( projectedPosition2.z, projectedPosition2.x, projectedPosition2.y, projectedPosition2 ); const translation3 = Matrix4_default.fromTranslation( projectedPosition2, scratchFromENU ); Matrix4_default.multiply(Transforms.SWIZZLE_3D_TO_2D_MATRIX, toENU, result); Matrix4_default.multiply(translation3, result, result); return result; }; var Transforms_default = Transforms; // packages/engine/Source/Core/Rectangle.js var Rectangle = class _Rectangle { /** * @param {number} [west=0.0] The westernmost longitude, in radians, in the range [-Pi, Pi]. * @param {number} [south=0.0] The southernmost latitude, in radians, in the range [-Pi/2, Pi/2]. * @param {number} [east=0.0] The easternmost longitude, in radians, in the range [-Pi, Pi]. * @param {number} [north=0.0] The northernmost latitude, in radians, in the range [-Pi/2, Pi/2]. */ constructor(west, south, east, north) { this.west = west ?? 0; this.south = south ?? 0; this.east = east ?? 0; this.north = north ?? 0; } /** * Gets the width of the rectangle in radians. * @type {number} * @readonly */ get width() { return _Rectangle.computeWidth(this); } /** * Gets the height of the rectangle in radians. * @type {number} * @readonly */ get height() { return _Rectangle.computeHeight(this); } /** * Stores the provided instance into the provided array. * * @param {Rectangle} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.west; array[startingIndex++] = value.south; array[startingIndex++] = value.east; array[startingIndex] = value.north; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Rectangle} [result] The object into which to store the result. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Rectangle(); } result.west = array[startingIndex++]; result.south = array[startingIndex++]; result.east = array[startingIndex++]; result.north = array[startingIndex]; return result; } /** * Computes the width of a rectangle in radians. * @param {Rectangle} rectangle The rectangle to compute the width of. * @returns {number} The width. */ static computeWidth(rectangle) { Check_default.typeOf.object("rectangle", rectangle); let east = rectangle.east; const west = rectangle.west; if (east < west) { east += Math_default.TWO_PI; } return east - west; } /** * Computes the height of a rectangle in radians. * @param {Rectangle} rectangle The rectangle to compute the height of. * @returns {number} The height. */ static computeHeight(rectangle) { Check_default.typeOf.object("rectangle", rectangle); return rectangle.north - rectangle.south; } /** * Creates a rectangle given the boundary longitude and latitude in degrees. * * @param {number} [west=0.0] The westernmost longitude in degrees in the range [-180.0, 180.0]. * @param {number} [south=0.0] The southernmost latitude in degrees in the range [-90.0, 90.0]. * @param {number} [east=0.0] The easternmost longitude in degrees in the range [-180.0, 180.0]. * @param {number} [north=0.0] The northernmost latitude in degrees in the range [-90.0, 90.0]. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. * * @example * const rectangle = Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0); */ static fromDegrees(west, south, east, north, result) { west = Math_default.toRadians(west ?? 0); south = Math_default.toRadians(south ?? 0); east = Math_default.toRadians(east ?? 0); north = Math_default.toRadians(north ?? 0); if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Creates a rectangle given the boundary longitude and latitude in radians. * * @param {number} [west=0.0] The westernmost longitude in radians in the range [-Math.PI, Math.PI]. * @param {number} [south=0.0] The southernmost latitude in radians in the range [-Math.PI/2, Math.PI/2]. * @param {number} [east=0.0] The easternmost longitude in radians in the range [-Math.PI, Math.PI]. * @param {number} [north=0.0] The northernmost latitude in radians in the range [-Math.PI/2, Math.PI/2]. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. * * @example * const rectangle = Cesium.Rectangle.fromRadians(0.0, Math.PI/4, Math.PI/8, 3*Math.PI/4); */ static fromRadians(west, south, east, north, result) { if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west ?? 0; result.south = south ?? 0; result.east = east ?? 0; result.north = north ?? 0; return result; } /** * Creates the smallest possible Rectangle that encloses all positions in the provided array. * * @param {Cartographic[]} cartographics The list of Cartographic instances. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ static fromCartographicArray(cartographics, result) { Check_default.defined("cartographics", cartographics); let west = Number.MAX_VALUE; let east = -Number.MAX_VALUE; let westOverIDL = Number.MAX_VALUE; let eastOverIDL = -Number.MAX_VALUE; let south = Number.MAX_VALUE; let north = -Number.MAX_VALUE; for (let i = 0, len = cartographics.length; i < len; i++) { const position = cartographics[i]; west = Math.min(west, position.longitude); east = Math.max(east, position.longitude); south = Math.min(south, position.latitude); north = Math.max(north, position.latitude); const lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + Math_default.TWO_PI; westOverIDL = Math.min(westOverIDL, lonAdjusted); eastOverIDL = Math.max(eastOverIDL, lonAdjusted); } if (east - west > eastOverIDL - westOverIDL) { west = westOverIDL; east = eastOverIDL; if (east > Math_default.PI) { east = east - Math_default.TWO_PI; } if (west > Math_default.PI) { west = west - Math_default.TWO_PI; } } if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Creates the smallest possible Rectangle that encloses all positions in the provided array. * * @param {Cartesian3[]} cartesians The list of Cartesian instances. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid the cartesians are on. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ static fromCartesianArray(cartesians, ellipsoid, result) { Check_default.defined("cartesians", cartesians); ellipsoid = ellipsoid ?? Ellipsoid_default.default; let west = Number.MAX_VALUE; let east = -Number.MAX_VALUE; let westOverIDL = Number.MAX_VALUE; let eastOverIDL = -Number.MAX_VALUE; let south = Number.MAX_VALUE; let north = -Number.MAX_VALUE; for (let i = 0, len = cartesians.length; i < len; i++) { const position = ellipsoid.cartesianToCartographic(cartesians[i]); west = Math.min(west, position.longitude); east = Math.max(east, position.longitude); south = Math.min(south, position.latitude); north = Math.max(north, position.latitude); const lonAdjusted = position.longitude >= 0 ? position.longitude : position.longitude + Math_default.TWO_PI; westOverIDL = Math.min(westOverIDL, lonAdjusted); eastOverIDL = Math.max(eastOverIDL, lonAdjusted); } if (east - west > eastOverIDL - westOverIDL) { west = westOverIDL; east = eastOverIDL; if (east > Math_default.PI) { east = east - Math_default.TWO_PI; } if (west > Math_default.PI) { west = west - Math_default.TWO_PI; } } if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Create a rectangle from a bounding sphere, ignoring height. * * * @param {BoundingSphere} boundingSphere The bounding sphere. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ static fromBoundingSphere(boundingSphere, ellipsoid, result) { Check_default.typeOf.object("boundingSphere", boundingSphere); const center = boundingSphere.center; const radius = boundingSphere.radius; if (!defined_default(ellipsoid)) { ellipsoid = Ellipsoid_default.default; } if (!defined_default(result)) { result = new _Rectangle(); } if (Cartesian3_default.equals(center, Cartesian3_default.ZERO)) { _Rectangle.clone(_Rectangle.MAX_VALUE, result); return result; } const fromENU = Transforms_default.eastNorthUpToFixedFrame( center, ellipsoid, fromBoundingSphereMatrixScratch ); const east = Matrix4_default.multiplyByPointAsVector( fromENU, Cartesian3_default.UNIT_X, fromBoundingSphereEastScratch ); Cartesian3_default.normalize(east, east); const north = Matrix4_default.multiplyByPointAsVector( fromENU, Cartesian3_default.UNIT_Y, fromBoundingSphereNorthScratch ); Cartesian3_default.normalize(north, north); Cartesian3_default.multiplyByScalar(north, radius, north); Cartesian3_default.multiplyByScalar(east, radius, east); const south = Cartesian3_default.negate(north, fromBoundingSphereSouthScratch); const west = Cartesian3_default.negate(east, fromBoundingSphereWestScratch); const positions = fromBoundingSpherePositionsScratch; let corner = positions[0]; Cartesian3_default.add(center, north, corner); corner = positions[1]; Cartesian3_default.add(center, west, corner); corner = positions[2]; Cartesian3_default.add(center, south, corner); corner = positions[3]; Cartesian3_default.add(center, east, corner); positions[4] = center; return _Rectangle.fromCartesianArray(positions, ellipsoid, result); } /** * Duplicates a Rectangle. * * @param {Rectangle} rectangle The rectangle to clone. * @param {Rectangle} [result] The object onto which to store the result, or undefined if a new instance should be created. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. (Returns undefined if rectangle is undefined) */ static clone(rectangle, result) { if (!defined_default(rectangle)) { return void 0; } if (!defined_default(result)) { return new _Rectangle( rectangle.west, rectangle.south, rectangle.east, rectangle.north ); } result.west = rectangle.west; result.south = rectangle.south; result.east = rectangle.east; result.north = rectangle.north; return result; } /** * Compares the provided Rectangles componentwise and returns * true if they pass an absolute or relative tolerance test, * false otherwise. * * @param {Rectangle} [left] The first Rectangle. * @param {Rectangle} [right] The second Rectangle. * @param {number} [absoluteEpsilon=0] The absolute epsilon tolerance to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, absoluteEpsilon) { absoluteEpsilon = absoluteEpsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left.west - right.west) <= absoluteEpsilon && Math.abs(left.south - right.south) <= absoluteEpsilon && Math.abs(left.east - right.east) <= absoluteEpsilon && Math.abs(left.north - right.north) <= absoluteEpsilon; } /** * Duplicates this Rectangle. * * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ clone(result) { return _Rectangle.clone(this, result); } /** * Compares the provided Rectangle with this Rectangle componentwise and returns * true if they are equal, false otherwise. * * @param {Rectangle} [other] The Rectangle to compare. * @returns {boolean} true if the Rectangles are equal, false otherwise. */ equals(other) { return _Rectangle.equals(this, other); } /** * Compares the provided rectangles and returns true if they are equal, * false otherwise. * * @param {Rectangle} [left] The first Rectangle. * @param {Rectangle} [right] The second Rectangle. * @returns {boolean} true if left and right are equal; otherwise false. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left.west === right.west && left.south === right.south && left.east === right.east && left.north === right.north; } /** * Compares the provided Rectangle with this Rectangle componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Rectangle} [other] The Rectangle to compare. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if the Rectangles are within the provided epsilon, false otherwise. */ equalsEpsilon(other, epsilon) { return _Rectangle.equalsEpsilon(this, other, epsilon); } /** * Checks a Rectangle's properties and throws if they are not in valid ranges. * * @param {Rectangle} rectangle The rectangle to validate * * @exception {DeveloperError} north must be in the interval [-Pi/2, Pi/2]. * @exception {DeveloperError} south must be in the interval [-Pi/2, Pi/2]. * @exception {DeveloperError} east must be in the interval [-Pi, Pi]. * @exception {DeveloperError} west must be in the interval [-Pi, Pi]. * @private */ static _validate(rectangle) { Check_default.typeOf.object("rectangle", rectangle); const north = rectangle.north; Check_default.typeOf.number.greaterThanOrEquals( "north", north, -Math_default.PI_OVER_TWO ); Check_default.typeOf.number.lessThanOrEquals( "north", north, Math_default.PI_OVER_TWO ); const south = rectangle.south; Check_default.typeOf.number.greaterThanOrEquals( "south", south, -Math_default.PI_OVER_TWO ); Check_default.typeOf.number.lessThanOrEquals( "south", south, Math_default.PI_OVER_TWO ); const west = rectangle.west; Check_default.typeOf.number.greaterThanOrEquals("west", west, -Math.PI); Check_default.typeOf.number.lessThanOrEquals("west", west, Math.PI); const east = rectangle.east; Check_default.typeOf.number.greaterThanOrEquals("east", east, -Math.PI); Check_default.typeOf.number.lessThanOrEquals("east", east, Math.PI); } /** * Computes the southwest corner of a rectangle. * * @param {Rectangle} rectangle The rectangle for which to find the corner * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided. */ static southwest(rectangle, result) { Check_default.typeOf.object("rectangle", rectangle); if (!defined_default(result)) { return new Cartographic_default(rectangle.west, rectangle.south); } result.longitude = rectangle.west; result.latitude = rectangle.south; result.height = 0; return result; } /** * Computes the northwest corner of a rectangle. * * @param {Rectangle} rectangle The rectangle for which to find the corner * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided. */ static northwest(rectangle, result) { Check_default.typeOf.object("rectangle", rectangle); if (!defined_default(result)) { return new Cartographic_default(rectangle.west, rectangle.north); } result.longitude = rectangle.west; result.latitude = rectangle.north; result.height = 0; return result; } /** * Computes the northeast corner of a rectangle. * * @param {Rectangle} rectangle The rectangle for which to find the corner * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided. */ static northeast(rectangle, result) { Check_default.typeOf.object("rectangle", rectangle); if (!defined_default(result)) { return new Cartographic_default(rectangle.east, rectangle.north); } result.longitude = rectangle.east; result.latitude = rectangle.north; result.height = 0; return result; } /** * Computes the southeast corner of a rectangle. * * @param {Rectangle} rectangle The rectangle for which to find the corner * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided. */ static southeast(rectangle, result) { Check_default.typeOf.object("rectangle", rectangle); if (!defined_default(result)) { return new Cartographic_default(rectangle.east, rectangle.south); } result.longitude = rectangle.east; result.latitude = rectangle.south; result.height = 0; return result; } /** * Computes the center of a rectangle. * * @param {Rectangle} rectangle The rectangle for which to find the center * @param {Cartographic} [result] The object onto which to store the result. * @returns {Cartographic} The modified result parameter or a new Cartographic instance if none was provided. */ static center(rectangle, result) { Check_default.typeOf.object("rectangle", rectangle); let east = rectangle.east; const west = rectangle.west; if (east < west) { east += Math_default.TWO_PI; } const longitude = Math_default.negativePiToPi((west + east) * 0.5); const latitude = (rectangle.south + rectangle.north) * 0.5; if (!defined_default(result)) { return new Cartographic_default(longitude, latitude); } result.longitude = longitude; result.latitude = latitude; result.height = 0; return result; } /** * Computes the intersection of two rectangles. This function assumes that the rectangle's coordinates are * latitude and longitude in radians and produces a correct intersection, taking into account the fact that * the same angle can be represented with multiple values as well as the wrapping of longitude at the * anti-meridian. For a simple intersection that ignores these factors and can be used with projected * coordinates, see {@link Rectangle.simpleIntersection}. * * @param {Rectangle} rectangle On rectangle to find an intersection * @param {Rectangle} otherRectangle Another rectangle to find an intersection * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection. */ static intersection(rectangle, otherRectangle, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("otherRectangle", otherRectangle); let rectangleEast = rectangle.east; let rectangleWest = rectangle.west; let otherRectangleEast = otherRectangle.east; let otherRectangleWest = otherRectangle.west; if (rectangleEast < rectangleWest && otherRectangleEast > 0) { rectangleEast += Math_default.TWO_PI; } else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0) { otherRectangleEast += Math_default.TWO_PI; } if (rectangleEast < rectangleWest && otherRectangleWest < 0) { otherRectangleWest += Math_default.TWO_PI; } else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0) { rectangleWest += Math_default.TWO_PI; } let west = Math_default.negativePiToPi( Math.max(rectangleWest, otherRectangleWest) ); const east = Math_default.negativePiToPi( Math.min(rectangleEast, otherRectangleEast) ); if (west === Math_default.PI && east < Math_default.PI) { west = -Math_default.PI; } if ((rectangle.west < rectangle.east || otherRectangle.west < otherRectangle.east) && east <= west) { return void 0; } const south = Math.max(rectangle.south, otherRectangle.south); const north = Math.min(rectangle.north, otherRectangle.north); if (south >= north) { return void 0; } if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Computes a simple intersection of two rectangles. Unlike {@link Rectangle.intersection}, this function * does not attempt to put the angular coordinates into a consistent range or to account for crossing the * anti-meridian. As such, it can be used for rectangles where the coordinates are not simply latitude * and longitude (i.e. projected coordinates). * * @param {Rectangle} rectangle On rectangle to find an intersection * @param {Rectangle} otherRectangle Another rectangle to find an intersection * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle|undefined} The modified result parameter, a new Rectangle instance if none was provided or undefined if there is no intersection. */ static simpleIntersection(rectangle, otherRectangle, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("otherRectangle", otherRectangle); const west = Math.max(rectangle.west, otherRectangle.west); const south = Math.max(rectangle.south, otherRectangle.south); const east = Math.min(rectangle.east, otherRectangle.east); const north = Math.min(rectangle.north, otherRectangle.north); if (south >= north || west >= east) { return void 0; } if (!defined_default(result)) { return new _Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Computes a rectangle that is the union of two rectangles. * * @param {Rectangle} rectangle A rectangle to enclose in rectangle. * @param {Rectangle} otherRectangle A rectangle to enclose in a rectangle. * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ static union(rectangle, otherRectangle, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("otherRectangle", otherRectangle); if (!defined_default(result)) { result = new _Rectangle(); } let rectangleEast = rectangle.east; let rectangleWest = rectangle.west; let otherRectangleEast = otherRectangle.east; let otherRectangleWest = otherRectangle.west; if (rectangleEast < rectangleWest && otherRectangleEast > 0) { rectangleEast += Math_default.TWO_PI; } else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0) { otherRectangleEast += Math_default.TWO_PI; } if (rectangleEast < rectangleWest && otherRectangleWest < 0) { otherRectangleWest += Math_default.TWO_PI; } else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0) { rectangleWest += Math_default.TWO_PI; } const west = Math_default.negativePiToPi( Math.min(rectangleWest, otherRectangleWest) ); const east = Math_default.negativePiToPi( Math.max(rectangleEast, otherRectangleEast) ); result.west = west; result.south = Math.min(rectangle.south, otherRectangle.south); result.east = east; result.north = Math.max(rectangle.north, otherRectangle.north); return result; } /** * Computes a rectangle by enlarging the provided rectangle until it contains the provided cartographic. * * @param {Rectangle} rectangle A rectangle to expand. * @param {Cartographic} cartographic A cartographic to enclose in a rectangle. * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if one was not provided. */ static expand(rectangle, cartographic2, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("cartographic", cartographic2); if (!defined_default(result)) { result = new _Rectangle(); } result.west = Math.min(rectangle.west, cartographic2.longitude); result.south = Math.min(rectangle.south, cartographic2.latitude); result.east = Math.max(rectangle.east, cartographic2.longitude); result.north = Math.max(rectangle.north, cartographic2.latitude); return result; } /** * Returns true if the cartographic is on or inside the rectangle, false otherwise. * * @param {Rectangle} rectangle The rectangle * @param {Cartographic} cartographic The cartographic to test. * @returns {boolean} true if the provided cartographic is inside the rectangle, false otherwise. */ static contains(rectangle, cartographic2) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("cartographic", cartographic2); let longitude = cartographic2.longitude; const latitude = cartographic2.latitude; const west = rectangle.west; let east = rectangle.east; if (east < west) { east += Math_default.TWO_PI; if (longitude < 0) { longitude += Math_default.TWO_PI; } } return (longitude > west || Math_default.equalsEpsilon(longitude, west, Math_default.EPSILON14)) && (longitude < east || Math_default.equalsEpsilon(longitude, east, Math_default.EPSILON14)) && latitude >= rectangle.south && latitude <= rectangle.north; } /** * Samples a rectangle so that it includes a list of Cartesian points suitable for passing to * {@link BoundingSphere#fromPoints}. Sampling is necessary to account * for rectangles that cover the poles or cross the equator. * * @param {Rectangle} rectangle The rectangle to subsample. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid to use. * @param {number} [surfaceHeight=0.0] The height of the rectangle above the ellipsoid. * @param {Cartesian3[]} [result] The array of Cartesians onto which to store the result. * @returns {Cartesian3[]} The modified result parameter or a new Array of Cartesians instances if none was provided. */ static subsample(rectangle, ellipsoid, surfaceHeight, result) { Check_default.typeOf.object("rectangle", rectangle); ellipsoid = ellipsoid ?? Ellipsoid_default.default; surfaceHeight = surfaceHeight ?? 0; if (!defined_default(result)) { result = []; } let length2 = 0; const north = rectangle.north; const south = rectangle.south; const east = rectangle.east; const west = rectangle.west; const lla = subsampleLlaScratch; lla.height = surfaceHeight; lla.longitude = west; lla.latitude = north; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; lla.longitude = east; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; lla.latitude = south; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; lla.longitude = west; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; if (north < 0) { lla.latitude = north; } else if (south > 0) { lla.latitude = south; } else { lla.latitude = 0; } for (let i = 1; i < 8; ++i) { lla.longitude = -Math.PI + i * Math_default.PI_OVER_TWO; if (_Rectangle.contains(rectangle, lla)) { result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; } } if (lla.latitude === 0) { lla.longitude = west; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; lla.longitude = east; result[length2] = ellipsoid.cartographicToCartesian(lla, result[length2]); length2++; } result.length = length2; return result; } /** * Computes a subsection of a rectangle from normalized coordinates in the range [0.0, 1.0]. * * @param {Rectangle} rectangle The rectangle to subsection. * @param {number} westLerp The west interpolation factor in the range [0.0, 1.0]. Must be less than or equal to eastLerp. * @param {number} southLerp The south interpolation factor in the range [0.0, 1.0]. Must be less than or equal to northLerp. * @param {number} eastLerp The east interpolation factor in the range [0.0, 1.0]. Must be greater than or equal to westLerp. * @param {number} northLerp The north interpolation factor in the range [0.0, 1.0]. Must be greater than or equal to southLerp. * @param {Rectangle} [result] The object onto which to store the result. * @returns {Rectangle} The modified result parameter or a new Rectangle instance if none was provided. */ static subsection(rectangle, westLerp, southLerp, eastLerp, northLerp, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.number.greaterThanOrEquals("westLerp", westLerp, 0); Check_default.typeOf.number.lessThanOrEquals("westLerp", westLerp, 1); Check_default.typeOf.number.greaterThanOrEquals("southLerp", southLerp, 0); Check_default.typeOf.number.lessThanOrEquals("southLerp", southLerp, 1); Check_default.typeOf.number.greaterThanOrEquals("eastLerp", eastLerp, 0); Check_default.typeOf.number.lessThanOrEquals("eastLerp", eastLerp, 1); Check_default.typeOf.number.greaterThanOrEquals("northLerp", northLerp, 0); Check_default.typeOf.number.lessThanOrEquals("northLerp", northLerp, 1); Check_default.typeOf.number.lessThanOrEquals("westLerp", westLerp, eastLerp); Check_default.typeOf.number.lessThanOrEquals("southLerp", southLerp, northLerp); if (!defined_default(result)) { result = new _Rectangle(); } if (rectangle.west <= rectangle.east) { const width = rectangle.east - rectangle.west; result.west = rectangle.west + westLerp * width; result.east = rectangle.west + eastLerp * width; } else { const width = Math_default.TWO_PI + rectangle.east - rectangle.west; result.west = Math_default.negativePiToPi( rectangle.west + westLerp * width ); result.east = Math_default.negativePiToPi( rectangle.west + eastLerp * width ); } const height = rectangle.north - rectangle.south; result.south = rectangle.south + southLerp * height; result.north = rectangle.south + northLerp * height; if (westLerp === 1) { result.west = rectangle.east; } if (eastLerp === 1) { result.east = rectangle.east; } if (southLerp === 1) { result.south = rectangle.north; } if (northLerp === 1) { result.north = rectangle.north; } return result; } }; Rectangle.packedLength = 4; var fromBoundingSphereMatrixScratch = new Matrix4_default(); var fromBoundingSphereEastScratch = new Cartesian3_default(); var fromBoundingSphereNorthScratch = new Cartesian3_default(); var fromBoundingSphereWestScratch = new Cartesian3_default(); var fromBoundingSphereSouthScratch = new Cartesian3_default(); var fromBoundingSpherePositionsScratch = new Array(5); for (let n2 = 0; n2 < fromBoundingSpherePositionsScratch.length; ++n2) { fromBoundingSpherePositionsScratch[n2] = new Cartesian3_default(); } var subsampleLlaScratch = new Cartographic_default(); Rectangle.MAX_VALUE = Object.freeze( new Rectangle( -Math.PI, -Math_default.PI_OVER_TWO, Math.PI, Math_default.PI_OVER_TWO ) ); var Rectangle_default = Rectangle; // packages/engine/Source/Core/BoundingRectangle.js function BoundingRectangle(x, y, width, height) { this.x = x ?? 0; this.y = y ?? 0; this.width = width ?? 0; this.height = height ?? 0; } BoundingRectangle.packedLength = 4; BoundingRectangle.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.x; array[startingIndex++] = value.y; array[startingIndex++] = value.width; array[startingIndex] = value.height; return array; }; BoundingRectangle.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new BoundingRectangle(); } result.x = array[startingIndex++]; result.y = array[startingIndex++]; result.width = array[startingIndex++]; result.height = array[startingIndex]; return result; }; BoundingRectangle.fromPoints = function(positions, result) { if (!defined_default(result)) { result = new BoundingRectangle(); } if (!defined_default(positions) || positions.length === 0) { result.x = 0; result.y = 0; result.width = 0; result.height = 0; return result; } const length2 = positions.length; let minimumX = positions[0].x; let minimumY = positions[0].y; let maximumX = positions[0].x; let maximumY = positions[0].y; for (let i = 1; i < length2; i++) { const p = positions[i]; const x = p.x; const y = p.y; minimumX = Math.min(x, minimumX); maximumX = Math.max(x, maximumX); minimumY = Math.min(y, minimumY); maximumY = Math.max(y, maximumY); } result.x = minimumX; result.y = minimumY; result.width = maximumX - minimumX; result.height = maximumY - minimumY; return result; }; var defaultProjection = new GeographicProjection_default(); var fromRectangleLowerLeft = new Cartographic_default(); var fromRectangleUpperRight = new Cartographic_default(); BoundingRectangle.fromRectangle = function(rectangle, projection, result) { if (!defined_default(result)) { result = new BoundingRectangle(); } if (!defined_default(rectangle)) { result.x = 0; result.y = 0; result.width = 0; result.height = 0; return result; } defaultProjection._ellipsoid = Ellipsoid_default.default; projection = projection ?? defaultProjection; const lowerLeft = projection.project( Rectangle_default.southwest(rectangle, fromRectangleLowerLeft) ); const upperRight = projection.project( Rectangle_default.northeast(rectangle, fromRectangleUpperRight) ); Cartesian2_default.subtract(upperRight, lowerLeft, upperRight); result.x = lowerLeft.x; result.y = lowerLeft.y; result.width = upperRight.x; result.height = upperRight.y; return result; }; BoundingRectangle.clone = function(rectangle, result) { if (!defined_default(rectangle)) { return void 0; } if (!defined_default(result)) { return new BoundingRectangle( rectangle.x, rectangle.y, rectangle.width, rectangle.height ); } result.x = rectangle.x; result.y = rectangle.y; result.width = rectangle.width; result.height = rectangle.height; return result; }; BoundingRectangle.union = function(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); if (!defined_default(result)) { result = new BoundingRectangle(); } const lowerLeftX = Math.min(left.x, right.x); const lowerLeftY = Math.min(left.y, right.y); const upperRightX = Math.max(left.x + left.width, right.x + right.width); const upperRightY = Math.max(left.y + left.height, right.y + right.height); result.x = lowerLeftX; result.y = lowerLeftY; result.width = upperRightX - lowerLeftX; result.height = upperRightY - lowerLeftY; return result; }; BoundingRectangle.expand = function(rectangle, point4, result) { Check_default.typeOf.object("rectangle", rectangle); Check_default.typeOf.object("point", point4); result = BoundingRectangle.clone(rectangle, result); const width = point4.x - result.x; const height = point4.y - result.y; if (width > result.width) { result.width = width; } else if (width < 0) { result.width -= width; result.x = point4.x; } if (height > result.height) { result.height = height; } else if (height < 0) { result.height -= height; result.y = point4.y; } return result; }; BoundingRectangle.intersect = function(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); const leftX = left.x; const leftY = left.y; const rightX = right.x; const rightY = right.y; if (!(leftX > rightX + right.width || leftX + left.width < rightX || leftY + left.height < rightY || leftY > rightY + right.height)) { return Intersect_default.INTERSECTING; } return Intersect_default.OUTSIDE; }; BoundingRectangle.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.x === right.x && left.y === right.y && left.width === right.width && left.height === right.height; }; BoundingRectangle.prototype.clone = function(result) { return BoundingRectangle.clone(this, result); }; BoundingRectangle.prototype.intersect = function(right) { return BoundingRectangle.intersect(this, right); }; BoundingRectangle.prototype.equals = function(right) { return BoundingRectangle.equals(this, right); }; var BoundingRectangle_default = BoundingRectangle; // packages/engine/Source/Core/PrimitiveType.js var import_InlineWorkers71 = __toESM(require_InlineWorkers(), 1); var PrimitiveType = { /** * Points primitive where each vertex (or index) is a separate point. * * @type {number} * @constant */ POINTS: WebGLConstants_default.POINTS, /** * Lines primitive where each two vertices (or indices) is a line segment. Line segments are not necessarily connected. * * @type {number} * @constant */ LINES: WebGLConstants_default.LINES, /** * Line loop primitive where each vertex (or index) after the first connects a line to * the previous vertex, and the last vertex implicitly connects to the first. * * @type {number} * @constant */ LINE_LOOP: WebGLConstants_default.LINE_LOOP, /** * Line strip primitive where each vertex (or index) after the first connects a line to the previous vertex. * * @type {number} * @constant */ LINE_STRIP: WebGLConstants_default.LINE_STRIP, /** * Triangles primitive where each three vertices (or indices) is a triangle. Triangles do not necessarily share edges. * * @type {number} * @constant */ TRIANGLES: WebGLConstants_default.TRIANGLES, /** * Triangle strip primitive where each vertex (or index) after the first two connect to * the previous two vertices forming a triangle. For example, this can be used to model a wall. * * @type {number} * @constant */ TRIANGLE_STRIP: WebGLConstants_default.TRIANGLE_STRIP, /** * Triangle fan primitive where each vertex (or index) after the first two connect to * the previous vertex and the first vertex forming a triangle. For example, this can be used * to model a cone or circle. * * @type {number} * @constant */ TRIANGLE_FAN: WebGLConstants_default.TRIANGLE_FAN }; PrimitiveType.isLines = function(primitiveType) { return primitiveType === PrimitiveType.LINES || primitiveType === PrimitiveType.LINE_LOOP || primitiveType === PrimitiveType.LINE_STRIP; }; PrimitiveType.isTriangles = function(primitiveType) { return primitiveType === PrimitiveType.TRIANGLES || primitiveType === PrimitiveType.TRIANGLE_STRIP || primitiveType === PrimitiveType.TRIANGLE_FAN; }; PrimitiveType.validate = function(primitiveType) { return primitiveType === PrimitiveType.POINTS || primitiveType === PrimitiveType.LINES || primitiveType === PrimitiveType.LINE_LOOP || primitiveType === PrimitiveType.LINE_STRIP || primitiveType === PrimitiveType.TRIANGLES || primitiveType === PrimitiveType.TRIANGLE_STRIP || primitiveType === PrimitiveType.TRIANGLE_FAN; }; Object.freeze(PrimitiveType); var PrimitiveType_default = PrimitiveType; // packages/engine/Source/Shaders/ViewportQuadVS.js var import_InlineWorkers72 = __toESM(require_InlineWorkers(), 1); var ViewportQuadVS_default = "in vec4 position;\nin vec2 textureCoordinates;\n\nout vec2 v_textureCoordinates;\n\nvoid main() \n{\n gl_Position = position;\n v_textureCoordinates = textureCoordinates;\n}\n"; // packages/engine/Source/Renderer/DrawCommand.js var import_InlineWorkers73 = __toESM(require_InlineWorkers(), 1); var Flags = { CULL: 1, OCCLUDE: 2, EXECUTE_IN_CLOSEST_FRUSTUM: 4, DEBUG_SHOW_BOUNDING_VOLUME: 8, CAST_SHADOWS: 16, RECEIVE_SHADOWS: 32, PICK_ONLY: 64, DEPTH_FOR_TRANSLUCENT_CLASSIFICATION: 128 }; var DrawCommand = class _DrawCommand { /** * @param {DrawCommandOptions} [options] */ constructor(options = Frozen_default.EMPTY_OBJECT) { this._boundingVolume = options.boundingVolume; this._orientedBoundingBox = options.orientedBoundingBox; this._modelMatrix = options.modelMatrix; this._primitiveType = options.primitiveType ?? PrimitiveType_default.TRIANGLES; this._vertexArray = options.vertexArray; this._count = options.count; this._offset = options.offset ?? 0; this._instanceCount = options.instanceCount ?? 0; this._shaderProgram = options.shaderProgram; this._uniformMap = options.uniformMap; this._renderState = options.renderState; this._framebuffer = options.framebuffer; this._pass = options.pass; this._owner = options.owner; this._debugOverlappingFrustums = 0; this._pickId = options.pickId; this._snapId = options.snapId; this._pickMetadataAllowed = options.pickMetadataAllowed === true; this._pickedMetadataInfo = void 0; this._flags = 0; this.cull = options.cull ?? true; this.occlude = options.occlude ?? true; this.executeInClosestFrustum = options.executeInClosestFrustum ?? false; this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false; this.castShadows = options.castShadows ?? false; this.receiveShadows = options.receiveShadows ?? false; this.pickOnly = options.pickOnly ?? false; this.depthForTranslucentClassification = options.depthForTranslucentClassification ?? false; this.dirty = true; this.lastDirtyTime = 0; this.derivedCommands = {}; } /** * The bounding volume of the geometry in world space. This is used for culling and frustum selection. *

* For best rendering performance, use the tightest possible bounding volume. Although * undefined is allowed, always try to provide a bounding volume to * allow the tightest possible near and far planes to be computed for the scene, and * minimize the number of frustums needed. *

* * @type {object} * @default undefined * * @see DrawCommand#debugShowBoundingVolume */ get boundingVolume() { return this._boundingVolume; } set boundingVolume(value) { if (this._boundingVolume !== value) { this._boundingVolume = value; this.dirty = true; } } /** * The oriented bounding box of the geometry in world space. If this is defined, it is used instead of * {@link DrawCommand#boundingVolume} for plane intersection testing. * * @type {OrientedBoundingBox} * @default undefined * * @see DrawCommand#debugShowBoundingVolume */ get orientedBoundingBox() { return this._orientedBoundingBox; } set orientedBoundingBox(value) { if (this._orientedBoundingBox !== value) { this._orientedBoundingBox = value; this.dirty = true; } } /** * When true, the renderer frustum and horizon culls the command based on its {@link DrawCommand#boundingVolume}. * If the command was already culled, set this to false for a performance improvement. * * @type {boolean} * @default true */ get cull() { return hasFlag(this, Flags.CULL); } set cull(value) { if (hasFlag(this, Flags.CULL) !== value) { setFlag(this, Flags.CULL, value); this.dirty = true; } } /** * When true, the horizon culls the command based on its {@link DrawCommand#boundingVolume}. * {@link DrawCommand#cull} must also be true in order for the command to be culled. * * @type {boolean} * @default true */ get occlude() { return hasFlag(this, Flags.OCCLUDE); } set occlude(value) { if (hasFlag(this, Flags.OCCLUDE) !== value) { setFlag(this, Flags.OCCLUDE, value); this.dirty = true; } } /** * The transformation from the geometry in model space to world space. *

* When undefined, the geometry is assumed to be defined in world space. *

* * @type {Matrix4} * @default undefined */ get modelMatrix() { return this._modelMatrix; } set modelMatrix(value) { if (this._modelMatrix !== value) { this._modelMatrix = value; this.dirty = true; } } /** * The type of geometry in the vertex array. * * @type {PrimitiveType} * @default PrimitiveType.TRIANGLES */ get primitiveType() { return this._primitiveType; } set primitiveType(value) { if (this._primitiveType !== value) { this._primitiveType = value; this.dirty = true; } } /** * The vertex array. * * @type {VertexArray} * @default undefined */ get vertexArray() { return this._vertexArray; } set vertexArray(value) { if (this._vertexArray !== value) { this._vertexArray = value; this.dirty = true; } } /** * The number of vertices to draw in the vertex array. * * @type {number} * @default undefined */ get count() { return this._count; } set count(value) { if (this._count !== value) { this._count = value; this.dirty = true; } } /** * The offset to start drawing in the vertex array. * * @type {number} * @default 0 */ get offset() { return this._offset; } set offset(value) { if (this._offset !== value) { this._offset = value; this.dirty = true; } } /** * The number of instances to draw. * * @type {number} * @default 0 */ get instanceCount() { return this._instanceCount; } set instanceCount(value) { if (this._instanceCount !== value) { this._instanceCount = value; this.dirty = true; } } /** * The shader program to apply. * * @type {ShaderProgram} * @default undefined */ get shaderProgram() { return this._shaderProgram; } set shaderProgram(value) { if (this._shaderProgram !== value) { this._shaderProgram = value; this.dirty = true; } } /** * Whether this command should cast shadows when shadowing is enabled. * * @type {boolean} * @default false */ get castShadows() { return hasFlag(this, Flags.CAST_SHADOWS); } set castShadows(value) { if (hasFlag(this, Flags.CAST_SHADOWS) !== value) { setFlag(this, Flags.CAST_SHADOWS, value); this.dirty = true; } } /** * Whether this command should receive shadows when shadowing is enabled. * * @type {boolean} * @default false */ get receiveShadows() { return hasFlag(this, Flags.RECEIVE_SHADOWS); } set receiveShadows(value) { if (hasFlag(this, Flags.RECEIVE_SHADOWS) !== value) { setFlag(this, Flags.RECEIVE_SHADOWS, value); this.dirty = true; } } /** * An object with functions whose names match the uniforms in the shader program * and return values to set those uniforms. * * @type {object} * @default undefined */ get uniformMap() { return this._uniformMap; } set uniformMap(value) { if (this._uniformMap !== value) { this._uniformMap = value; this.dirty = true; } } /** * The render state. * * @type {RenderState} * @default undefined */ get renderState() { return this._renderState; } set renderState(value) { if (this._renderState !== value) { this._renderState = value; this.dirty = true; } } /** * The framebuffer to draw to. * * @type {Framebuffer} * @default undefined */ get framebuffer() { return this._framebuffer; } set framebuffer(value) { if (this._framebuffer !== value) { this._framebuffer = value; this.dirty = true; } } /** * The pass when to render. * * @type {Pass} * @default undefined */ get pass() { return this._pass; } set pass(value) { if (this._pass !== value) { this._pass = value; this.dirty = true; } } /** * Specifies if this command is only to be executed in the frustum closest * to the eye containing the bounding volume. Defaults to false. * * @type {boolean} * @default false */ get executeInClosestFrustum() { return hasFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM); } set executeInClosestFrustum(value) { if (hasFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM) !== value) { setFlag(this, Flags.EXECUTE_IN_CLOSEST_FRUSTUM, value); this.dirty = true; } } /** * The object who created this command. This is useful for debugging command * execution; it allows us to see who created a command when we only have a * reference to the command, and can be used to selectively execute commands * with {@link Scene#debugCommandFilter}. * * @type {object} * @default undefined * * @see Scene#debugCommandFilter */ get owner() { return this._owner; } set owner(value) { if (this._owner !== value) { this._owner = value; this.dirty = true; } } /** * This property is for debugging only; it is not for production use nor is it optimized. *

* Draws the {@link DrawCommand#boundingVolume} for this command, assuming it is a sphere, when the command executes. *

* * @type {boolean} * @default false * * @see DrawCommand#boundingVolume */ get debugShowBoundingVolume() { return hasFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME); } set debugShowBoundingVolume(value) { if (hasFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME) !== value) { setFlag(this, Flags.DEBUG_SHOW_BOUNDING_VOLUME, value); this.dirty = true; } } /** * Used to implement Scene.debugShowFrustums. * @ignore */ get debugOverlappingFrustums() { return this._debugOverlappingFrustums; } set debugOverlappingFrustums(value) { if (this._debugOverlappingFrustums !== value) { this._debugOverlappingFrustums = value; this.dirty = true; } } /** * A GLSL string that will evaluate to a pick id. When undefined, the command will only draw depth * during the pick pass. * * @type {string|undefined} * @default undefined */ get pickId() { return this._pickId; } set pickId(value) { if (this._pickId !== value) { this._pickId = value; this.dirty = true; } } /** * A GLSL string that will evaluate to the float snap payload written during * a snapping pass (see {@link Scene#snap}). When undefined, the * command does not render during a snapping pass. * * @type {string|undefined} * @default undefined */ get snapId() { return this._snapId; } set snapId(value) { if (this._snapId !== value) { this._snapId = value; this.dirty = true; } } /** * Whether metadata picking is allowed. * * This is essentially only set to `true` for draw commands that are * part of a `ModelDrawCommand`, to check whether a derived command * for metadata picking has to be created. * * @type {boolean} * @default undefined * @private */ get pickMetadataAllowed() { return this._pickMetadataAllowed; } /** * Information about picked metadata. * * @type {PickedMetadataInfo|undefined} * @default undefined */ get pickedMetadataInfo() { return this._pickedMetadataInfo; } set pickedMetadataInfo(value) { if (this._pickedMetadataInfo !== value) { this._pickedMetadataInfo = value; this.dirty = true; } } /** * Whether this command should be executed in the pick pass only. * * @type {boolean} * @default false */ get pickOnly() { return hasFlag(this, Flags.PICK_ONLY); } set pickOnly(value) { if (hasFlag(this, Flags.PICK_ONLY) !== value) { setFlag(this, Flags.PICK_ONLY, value); this.dirty = true; } } /** * Whether this command should be derived to draw depth for classification of translucent primitives. * * @type {boolean} * @default false */ get depthForTranslucentClassification() { return hasFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION); } set depthForTranslucentClassification(value) { if (hasFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION) !== value) { setFlag(this, Flags.DEPTH_FOR_TRANSLUCENT_CLASSIFICATION, value); this.dirty = true; } } /** * @param {DrawCommand} command * @param {DrawCommand} result * @returns {DrawCommand} * @private */ static shallowClone(command, result) { if (!defined_default(command)) { return void 0; } if (!defined_default(result)) { result = new _DrawCommand(); } result._boundingVolume = command._boundingVolume; result._orientedBoundingBox = command._orientedBoundingBox; result._modelMatrix = command._modelMatrix; result._primitiveType = command._primitiveType; result._vertexArray = command._vertexArray; result._count = command._count; result._offset = command._offset; result._instanceCount = command._instanceCount; result._shaderProgram = command._shaderProgram; result._uniformMap = command._uniformMap; result._renderState = command._renderState; result._framebuffer = command._framebuffer; result._pass = command._pass; result._owner = command._owner; result._debugOverlappingFrustums = command._debugOverlappingFrustums; result._pickId = command._pickId; result._snapId = command._snapId; result._pickMetadataAllowed = command._pickMetadataAllowed; result._pickedMetadataInfo = command._pickedMetadataInfo; result._flags = command._flags; result.dirty = true; result.lastDirtyTime = 0; return result; } /** * Executes the draw command. * * @param {Context} context The renderer context in which to draw. * @param {PassState} [passState] The state for the current render pass. */ execute(context, passState) { context.draw(this, passState); } }; function hasFlag(command, flag) { return (command._flags & flag) === flag; } function setFlag(command, flag, value) { if (value) { command._flags |= flag; } else { command._flags &= ~flag; } } var DrawCommand_default = DrawCommand; // packages/engine/Source/Renderer/Framebuffer.js var import_InlineWorkers77 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/PixelFormat.js var import_InlineWorkers75 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/PixelDatatype.js var import_InlineWorkers74 = __toESM(require_InlineWorkers(), 1); var PixelDatatype = { UNSIGNED_BYTE: WebGLConstants_default.UNSIGNED_BYTE, UNSIGNED_SHORT: WebGLConstants_default.UNSIGNED_SHORT, UNSIGNED_INT: WebGLConstants_default.UNSIGNED_INT, FLOAT: WebGLConstants_default.FLOAT, HALF_FLOAT: WebGLConstants_default.HALF_FLOAT_OES, UNSIGNED_INT_24_8: WebGLConstants_default.UNSIGNED_INT_24_8, UNSIGNED_SHORT_4_4_4_4: WebGLConstants_default.UNSIGNED_SHORT_4_4_4_4, UNSIGNED_SHORT_5_5_5_1: WebGLConstants_default.UNSIGNED_SHORT_5_5_5_1, UNSIGNED_SHORT_5_6_5: WebGLConstants_default.UNSIGNED_SHORT_5_6_5 }; PixelDatatype.toWebGLConstant = function(pixelDatatype, context) { switch (pixelDatatype) { case PixelDatatype.UNSIGNED_BYTE: return WebGLConstants_default.UNSIGNED_BYTE; case PixelDatatype.UNSIGNED_SHORT: return WebGLConstants_default.UNSIGNED_SHORT; case PixelDatatype.UNSIGNED_INT: return WebGLConstants_default.UNSIGNED_INT; case PixelDatatype.FLOAT: return WebGLConstants_default.FLOAT; case PixelDatatype.HALF_FLOAT: return context.webgl2 ? WebGLConstants_default.HALF_FLOAT : WebGLConstants_default.HALF_FLOAT_OES; case PixelDatatype.UNSIGNED_INT_24_8: return WebGLConstants_default.UNSIGNED_INT_24_8; case PixelDatatype.UNSIGNED_SHORT_4_4_4_4: return WebGLConstants_default.UNSIGNED_SHORT_4_4_4_4; case PixelDatatype.UNSIGNED_SHORT_5_5_5_1: return WebGLConstants_default.UNSIGNED_SHORT_5_5_5_1; case PixelDatatype.UNSIGNED_SHORT_5_6_5: return PixelDatatype.UNSIGNED_SHORT_5_6_5; } }; PixelDatatype.isPacked = function(pixelDatatype) { return pixelDatatype === PixelDatatype.UNSIGNED_INT_24_8 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_4_4_4_4 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_5_5_1 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_6_5; }; PixelDatatype.sizeInBytes = function(pixelDatatype) { switch (pixelDatatype) { case PixelDatatype.UNSIGNED_BYTE: return 1; case PixelDatatype.UNSIGNED_SHORT: case PixelDatatype.UNSIGNED_SHORT_4_4_4_4: case PixelDatatype.UNSIGNED_SHORT_5_5_5_1: case PixelDatatype.UNSIGNED_SHORT_5_6_5: case PixelDatatype.HALF_FLOAT: return 2; case PixelDatatype.UNSIGNED_INT: case PixelDatatype.FLOAT: case PixelDatatype.UNSIGNED_INT_24_8: return 4; } }; PixelDatatype.validate = function(pixelDatatype) { return pixelDatatype === PixelDatatype.UNSIGNED_BYTE || pixelDatatype === PixelDatatype.UNSIGNED_SHORT || pixelDatatype === PixelDatatype.UNSIGNED_INT || pixelDatatype === PixelDatatype.FLOAT || pixelDatatype === PixelDatatype.HALF_FLOAT || pixelDatatype === PixelDatatype.UNSIGNED_INT_24_8 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_4_4_4_4 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_5_5_1 || pixelDatatype === PixelDatatype.UNSIGNED_SHORT_5_6_5; }; PixelDatatype.getTypedArrayConstructor = function(pixelDatatype) { const sizeInBytes = PixelDatatype.sizeInBytes(pixelDatatype); if (sizeInBytes === Uint8Array.BYTES_PER_ELEMENT) { return Uint8Array; } else if (sizeInBytes === Uint16Array.BYTES_PER_ELEMENT) { return Uint16Array; } else if (sizeInBytes === Float32Array.BYTES_PER_ELEMENT && pixelDatatype === PixelDatatype.FLOAT) { return Float32Array; } return Uint32Array; }; Object.freeze(PixelDatatype); var PixelDatatype_default = PixelDatatype; // packages/engine/Source/Core/PixelFormat.js var PixelFormat = { /** * A pixel format containing a depth value. * * @type {number} * @constant */ DEPTH_COMPONENT: WebGLConstants_default.DEPTH_COMPONENT, /** * A pixel format containing a depth and stencil value, most often used with {@link PixelDatatype.UNSIGNED_INT_24_8}. * * @type {number} * @constant */ DEPTH_STENCIL: WebGLConstants_default.DEPTH_STENCIL, /** * A pixel format containing an alpha channel. * * @type {number} * @constant */ ALPHA: WebGLConstants_default.ALPHA, /** * A pixel format containing a red channel * * @type {number} * @constant */ RED: WebGLConstants_default.RED, /** * A pixel format containing red and green channels. * * @type {number} * @constant */ RG: WebGLConstants_default.RG, /** * A pixel format containing red, green, and blue channels. * * @type {number} * @constant */ RGB: WebGLConstants_default.RGB, /** * A pixel format containing red, green, blue, and alpha channels. * * @type {number} * @constant */ RGBA: WebGLConstants_default.RGBA, /** * A pixel format containing a red channel as an integer. * @type {number} * @constant */ RED_INTEGER: WebGLConstants_default.RED_INTEGER, /** * A pixel format containing red and green channels as integers. * @type {number} * @constant */ RG_INTEGER: WebGLConstants_default.RG_INTEGER, /** * A pixel format containing red, green, and blue channels as integers. * @type {number} * @constant */ RGB_INTEGER: WebGLConstants_default.RGB_INTEGER, /** * A pixel format containing red, green, blue, and alpha channels as integers. * @type {number} * @constant */ RGBA_INTEGER: WebGLConstants_default.RGBA_INTEGER, /** * A pixel format containing a luminance (intensity) channel. * * @type {number} * @constant */ LUMINANCE: WebGLConstants_default.LUMINANCE, /** * A pixel format containing luminance (intensity) and alpha channels. * * @type {number} * @constant */ LUMINANCE_ALPHA: WebGLConstants_default.LUMINANCE_ALPHA, /** * A pixel format containing red, green, and blue channels that is DXT1 compressed. * * @type {number} * @constant */ RGB_DXT1: WebGLConstants_default.COMPRESSED_RGB_S3TC_DXT1_EXT, /** * A pixel format containing red, green, blue, and alpha channels that is DXT1 compressed. * * @type {number} * @constant */ RGBA_DXT1: WebGLConstants_default.COMPRESSED_RGBA_S3TC_DXT1_EXT, /** * A pixel format containing red, green, blue, and alpha channels that is DXT3 compressed. * * @type {number} * @constant */ RGBA_DXT3: WebGLConstants_default.COMPRESSED_RGBA_S3TC_DXT3_EXT, /** * A pixel format containing red, green, blue, and alpha channels that is DXT5 compressed. * * @type {number} * @constant */ RGBA_DXT5: WebGLConstants_default.COMPRESSED_RGBA_S3TC_DXT5_EXT, /** * A pixel format containing red, green, and blue channels that is PVR 4bpp compressed. * * @type {number} * @constant */ RGB_PVRTC_4BPPV1: WebGLConstants_default.COMPRESSED_RGB_PVRTC_4BPPV1_IMG, /** * A pixel format containing red, green, and blue channels that is PVR 2bpp compressed. * * @type {number} * @constant */ RGB_PVRTC_2BPPV1: WebGLConstants_default.COMPRESSED_RGB_PVRTC_2BPPV1_IMG, /** * A pixel format containing red, green, blue, and alpha channels that is PVR 4bpp compressed. * * @type {number} * @constant */ RGBA_PVRTC_4BPPV1: WebGLConstants_default.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, /** * A pixel format containing red, green, blue, and alpha channels that is PVR 2bpp compressed. * * @type {number} * @constant */ RGBA_PVRTC_2BPPV1: WebGLConstants_default.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, /** * A pixel format containing red, green, blue, and alpha channels that is ASTC compressed. * * @type {number} * @constant */ RGBA_ASTC: WebGLConstants_default.COMPRESSED_RGBA_ASTC_4x4_WEBGL, /** * A pixel format containing red, green, and blue channels that is ETC1 compressed. * * @type {number} * @constant */ RGB_ETC1: WebGLConstants_default.COMPRESSED_RGB_ETC1_WEBGL, /** * A pixel format containing red, green, and blue channels that is ETC2 compressed. * * @type {number} * @constant */ RGB8_ETC2: WebGLConstants_default.COMPRESSED_RGB8_ETC2, /** * A pixel format containing red, green, blue, and alpha channels that is ETC2 compressed. * * @type {number} * @constant */ RGBA8_ETC2_EAC: WebGLConstants_default.COMPRESSED_RGBA8_ETC2_EAC, /** * A pixel format containing red, green, blue, and alpha channels that is BC7 compressed. * * @type {number} * @constant */ RGBA_BC7: WebGLConstants_default.COMPRESSED_RGBA_BPTC_UNORM }; PixelFormat.componentsLength = function(pixelFormat) { switch (pixelFormat) { case PixelFormat.RGB: case PixelFormat.RGB_INTEGER: return 3; case PixelFormat.RGBA: case PixelFormat.RGBA_INTEGER: return 4; case PixelFormat.LUMINANCE_ALPHA: case PixelFormat.RG: case PixelFormat.RG_INTEGER: return 2; case PixelFormat.ALPHA: case PixelFormat.RED: case PixelFormat.RED_INTEGER: case PixelFormat.LUMINANCE: return 1; default: return 1; } }; PixelFormat.validate = function(pixelFormat) { return pixelFormat === PixelFormat.DEPTH_COMPONENT || pixelFormat === PixelFormat.DEPTH_STENCIL || pixelFormat === PixelFormat.ALPHA || pixelFormat === PixelFormat.RED || pixelFormat === PixelFormat.RG || pixelFormat === PixelFormat.RGB || pixelFormat === PixelFormat.RGBA || pixelFormat === PixelFormat.RED_INTEGER || pixelFormat === PixelFormat.RG_INTEGER || pixelFormat === PixelFormat.RGB_INTEGER || pixelFormat === PixelFormat.RGBA_INTEGER || pixelFormat === PixelFormat.LUMINANCE || pixelFormat === PixelFormat.LUMINANCE_ALPHA || pixelFormat === PixelFormat.RGB_DXT1 || pixelFormat === PixelFormat.RGBA_DXT1 || pixelFormat === PixelFormat.RGBA_DXT3 || pixelFormat === PixelFormat.RGBA_DXT5 || pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1 || pixelFormat === PixelFormat.RGBA_ASTC || pixelFormat === PixelFormat.RGB_ETC1 || pixelFormat === PixelFormat.RGB8_ETC2 || pixelFormat === PixelFormat.RGBA8_ETC2_EAC || pixelFormat === PixelFormat.RGBA_BC7; }; PixelFormat.isColorFormat = function(pixelFormat) { return pixelFormat === PixelFormat.RED || pixelFormat === PixelFormat.ALPHA || pixelFormat === PixelFormat.RGB || pixelFormat === PixelFormat.RGBA || pixelFormat === PixelFormat.LUMINANCE || pixelFormat === PixelFormat.LUMINANCE_ALPHA; }; PixelFormat.isDepthFormat = function(pixelFormat) { return pixelFormat === PixelFormat.DEPTH_COMPONENT || pixelFormat === PixelFormat.DEPTH_STENCIL; }; PixelFormat.isCompressedFormat = function(pixelFormat) { return pixelFormat === PixelFormat.RGB_DXT1 || pixelFormat === PixelFormat.RGBA_DXT1 || pixelFormat === PixelFormat.RGBA_DXT3 || pixelFormat === PixelFormat.RGBA_DXT5 || pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1 || pixelFormat === PixelFormat.RGBA_ASTC || pixelFormat === PixelFormat.RGB_ETC1 || pixelFormat === PixelFormat.RGB8_ETC2 || pixelFormat === PixelFormat.RGBA8_ETC2_EAC || pixelFormat === PixelFormat.RGBA_BC7; }; PixelFormat.isDXTFormat = function(pixelFormat) { return pixelFormat === PixelFormat.RGB_DXT1 || pixelFormat === PixelFormat.RGBA_DXT1 || pixelFormat === PixelFormat.RGBA_DXT3 || pixelFormat === PixelFormat.RGBA_DXT5; }; PixelFormat.isPVRTCFormat = function(pixelFormat) { return pixelFormat === PixelFormat.RGB_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGB_PVRTC_2BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_4BPPV1 || pixelFormat === PixelFormat.RGBA_PVRTC_2BPPV1; }; PixelFormat.isASTCFormat = function(pixelFormat) { return pixelFormat === PixelFormat.RGBA_ASTC; }; PixelFormat.isETC1Format = function(pixelFormat) { return pixelFormat === PixelFormat.RGB_ETC1; }; PixelFormat.isETC2Format = function(pixelFormat) { return pixelFormat === PixelFormat.RGB8_ETC2 || pixelFormat === PixelFormat.RGBA8_ETC2_EAC; }; PixelFormat.isBC7Format = function(pixelFormat) { return pixelFormat === PixelFormat.RGBA_BC7; }; PixelFormat.compressedTextureSizeInBytes = function(pixelFormat, width, height) { switch (pixelFormat) { case PixelFormat.RGB_DXT1: case PixelFormat.RGBA_DXT1: case PixelFormat.RGB_ETC1: case PixelFormat.RGB8_ETC2: return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8; case PixelFormat.RGBA_DXT3: case PixelFormat.RGBA_DXT5: case PixelFormat.RGBA_ASTC: case PixelFormat.RGBA8_ETC2_EAC: return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16; case PixelFormat.RGB_PVRTC_4BPPV1: case PixelFormat.RGBA_PVRTC_4BPPV1: return Math.floor((Math.max(width, 8) * Math.max(height, 8) * 4 + 7) / 8); case PixelFormat.RGB_PVRTC_2BPPV1: case PixelFormat.RGBA_PVRTC_2BPPV1: return Math.floor( (Math.max(width, 16) * Math.max(height, 8) * 2 + 7) / 8 ); case PixelFormat.RGBA_BC7: return Math.ceil(width / 4) * Math.ceil(height / 4) * 16; default: return 0; } }; PixelFormat.textureSizeInBytes = function(pixelFormat, pixelDatatype, width, height) { let componentsLength = PixelFormat.componentsLength(pixelFormat); if (PixelDatatype_default.isPacked(pixelDatatype)) { componentsLength = 1; } return componentsLength * PixelDatatype_default.sizeInBytes(pixelDatatype) * width * height; }; PixelFormat.texture3DSizeInBytes = function(pixelFormat, pixelDatatype, width, height, depth) { let componentsLength = PixelFormat.componentsLength(pixelFormat); if (PixelDatatype_default.isPacked(pixelDatatype)) { componentsLength = 1; } return componentsLength * PixelDatatype_default.sizeInBytes(pixelDatatype) * width * height * depth; }; PixelFormat.alignmentInBytes = function(pixelFormat, pixelDatatype, width) { const mod = PixelFormat.textureSizeInBytes(pixelFormat, pixelDatatype, width, 1) % 4; return mod === 0 ? 4 : mod === 2 ? 2 : 1; }; PixelFormat.createTypedArray = function(pixelFormat, pixelDatatype, width, height) { const constructor = PixelDatatype_default.getTypedArrayConstructor(pixelDatatype); const size = PixelFormat.componentsLength(pixelFormat) * width * height; return new constructor(size); }; PixelFormat.flipY = function(bufferView, pixelFormat, pixelDatatype, width, height) { if (height === 1) { return bufferView; } const flipped = PixelFormat.createTypedArray( pixelFormat, pixelDatatype, width, height ); const numberOfComponents = PixelFormat.componentsLength(pixelFormat); const textureWidth = width * numberOfComponents; for (let i = 0; i < height; ++i) { const row = i * width * numberOfComponents; const flippedRow = (height - i - 1) * width * numberOfComponents; for (let j = 0; j < textureWidth; ++j) { flipped[flippedRow + j] = bufferView[row + j]; } } return flipped; }; PixelFormat.toInternalFormat = function(pixelFormat, pixelDatatype, context) { if (!context.webgl2) { return pixelFormat; } if (pixelFormat === PixelFormat.DEPTH_STENCIL) { return WebGLConstants_default.DEPTH24_STENCIL8; } if (pixelFormat === PixelFormat.DEPTH_COMPONENT) { if (pixelDatatype === PixelDatatype_default.UNSIGNED_SHORT) { return WebGLConstants_default.DEPTH_COMPONENT16; } else if (pixelDatatype === PixelDatatype_default.UNSIGNED_INT) { return WebGLConstants_default.DEPTH_COMPONENT24; } } if (pixelDatatype === PixelDatatype_default.FLOAT) { switch (pixelFormat) { case PixelFormat.RGBA: return WebGLConstants_default.RGBA32F; case PixelFormat.RGB: return WebGLConstants_default.RGB32F; case PixelFormat.RG: return WebGLConstants_default.RG32F; case PixelFormat.RED: return WebGLConstants_default.R32F; } } if (pixelDatatype === PixelDatatype_default.HALF_FLOAT) { switch (pixelFormat) { case PixelFormat.RGBA: return WebGLConstants_default.RGBA16F; case PixelFormat.RGB: return WebGLConstants_default.RGB16F; case PixelFormat.RG: return WebGLConstants_default.RG16F; case PixelFormat.RED: return WebGLConstants_default.R16F; } } if (pixelDatatype === PixelDatatype_default.UNSIGNED_BYTE) { switch (pixelFormat) { case PixelFormat.RGBA: return WebGLConstants_default.RGBA8; case PixelFormat.RGB: return WebGLConstants_default.RGB8; case PixelFormat.RG: return WebGLConstants_default.RG8; case PixelFormat.RED: return WebGLConstants_default.R8; } } if (pixelDatatype === PixelDatatype_default.INT) { switch (pixelFormat) { case PixelFormat.RGBA_INTEGER: return WebGLConstants_default.RGBA32I; case PixelFormat.RGB_INTEGER: return WebGLConstants_default.RGB32I; case PixelFormat.RG_INTEGER: return WebGLConstants_default.RG32I; case PixelFormat.RED_INTEGER: return WebGLConstants_default.R32I; } } if (pixelDatatype === PixelDatatype_default.UNSIGNED_INT) { switch (pixelFormat) { case PixelFormat.RGBA_INTEGER: return WebGLConstants_default.RGBA32UI; case PixelFormat.RGB_INTEGER: return WebGLConstants_default.RGB32UI; case PixelFormat.RG_INTEGER: return WebGLConstants_default.RG32UI; case PixelFormat.RED_INTEGER: return WebGLConstants_default.R32UI; } } return pixelFormat; }; Object.freeze(PixelFormat); var PixelFormat_default = PixelFormat; // packages/engine/Source/Renderer/ContextLimits.js var import_InlineWorkers76 = __toESM(require_InlineWorkers(), 1); var ContextLimits = { _maximumCombinedTextureImageUnits: 0, _maximumCubeMapSize: 0, _maximumFragmentUniformVectors: 0, _maximumTextureImageUnits: 0, _maximumRenderbufferSize: 0, _maximumTextureSize: 0, _maximum3DTextureSize: 0, _maximumVaryingVectors: 0, _maximumVertexAttributes: 0, _maximumVertexTextureImageUnits: 0, _maximumVertexUniformVectors: 0, _minimumAliasedLineWidth: 0, _maximumAliasedLineWidth: 0, _minimumAliasedPointSize: 0, _maximumAliasedPointSize: 0, _maximumViewportWidth: 0, _maximumViewportHeight: 0, _maximumTextureFilterAnisotropy: 0, _maximumDrawBuffers: 0, _maximumColorAttachments: 0, _maximumSamples: 0, _highpFloatSupported: false, _highpIntSupported: false }; Object.defineProperties(ContextLimits, { /** * The maximum number of texture units that can be used from the vertex and fragment * shader with this WebGL implementation. * If both shaders access the same texture unit, this counts as two texture units. * The minimum in WebGL2 contexts is 32, or 8 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_COMBINED_TEXTURE_IMAGE_UNITS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumCombinedTextureImageUnits: { get: function() { return ContextLimits._maximumCombinedTextureImageUnits; } }, /** * The approximate maximum cube map width and height supported by this WebGL implementation. * The minimum in WebGL2 contexts is 2048, but most desktop and laptop implementations will support much larger sizes like 8192. * The minimum in WebGL1 contexts is 16. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_CUBE_MAP_TEXTURE_SIZE. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumCubeMapSize: { get: function() { return ContextLimits._maximumCubeMapSize; } }, /** * The maximum number of vec4, ivec4, and bvec4 * uniforms that can be used by a fragment shader with this WebGL implementation. * The minimum in WebGL2 contexts is 224, or 16 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_FRAGMENT_UNIFORM_VECTORS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumFragmentUniformVectors: { get: function() { return ContextLimits._maximumFragmentUniformVectors; } }, /** * The maximum number of texture units that can be used from the fragment shader with this WebGL implementation. * The minimum in WebGL2 contexts is 16, or 8 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_TEXTURE_IMAGE_UNITS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumTextureImageUnits: { get: function() { return ContextLimits._maximumTextureImageUnits; } }, /** * The maximum renderbuffer width and height supported by this WebGL implementation. * The minimum in WebGL2 contexts is 2048, but most desktop and laptop implementations will support much larger sizes like 8192. * The minimum in WebGL1 contexts is 1. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_RENDERBUFFER_SIZE. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumRenderbufferSize: { get: function() { return ContextLimits._maximumRenderbufferSize; } }, /** * The approximate maximum texture width and height supported by this WebGL implementation. * The minimum in WebGL2 contexts is 2048, but most desktop and laptop implementations will support much larger sizes like 8192. * The minimum in WebGL1 contexts is 64. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_TEXTURE_SIZE. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumTextureSize: { get: function() { return ContextLimits._maximumTextureSize; } }, /** * The approximate maximum texture width, height, and depth supported by this WebGL2 implementation. * The minimum is 256, but most desktop and laptop implementations will support much larger sizes like 2048. * 3D textures are not supported in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_3D_TEXTURE_SIZE. */ maximum3DTextureSize: { get: function() { return ContextLimits._maximum3DTextureSize; } }, /** * The maximum number of vec4 varying variables supported by this WebGL implementation. * The minimum is 15 in WebGL2 contexts, or 8 in WebGL1 contexts. Matrices and arrays count as multiple vec4s. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VARYING_VECTORS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumVaryingVectors: { get: function() { return ContextLimits._maximumVaryingVectors; } }, /** * The maximum number of vec4 vertex attributes supported by this WebGL implementation. * The minimum is 16 in WebGL2 contexts, or 8 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VERTEX_ATTRIBS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumVertexAttributes: { get: function() { return ContextLimits._maximumVertexAttributes; } }, /** * The maximum number of texture units that can be used from the vertex shader with this WebGL implementation. * The minimum is 16 in WebGL2 contexts, or 0 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VERTEX_TEXTURE_IMAGE_UNITS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumVertexTextureImageUnits: { get: function() { return ContextLimits._maximumVertexTextureImageUnits; } }, /** * The maximum number of vec4, ivec4, and bvec4 * uniforms that can be used by a vertex shader with this WebGL implementation. * The minimum is 256 in WebGL2 contexts, or 128 in WebGL1 contexts. * @memberof ContextLimits * @type {number} * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VERTEX_UNIFORM_VECTORS. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGet.xml|glGet in OpenGL ES 2.0} for WebGL1 contexts. */ maximumVertexUniformVectors: { get: function() { return ContextLimits._maximumVertexUniformVectors; } }, /** * The minimum aliased line width, in pixels, supported by this WebGL implementation. It will be at most one. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with ALIASED_LINE_WIDTH_RANGE. * @memberof ContextLimits * @type {number} */ minimumAliasedLineWidth: { get: function() { return ContextLimits._minimumAliasedLineWidth; } }, /** * The maximum aliased line width, in pixels, supported by this WebGL implementation. It will be at least one. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with ALIASED_LINE_WIDTH_RANGE. * @memberof ContextLimits * @type {number} */ maximumAliasedLineWidth: { get: function() { return ContextLimits._maximumAliasedLineWidth; } }, /** * The minimum aliased point size, in pixels, supported by this WebGL implementation. It will be at most one. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with ALIASED_POINT_SIZE_RANGE. * @memberof ContextLimits * @type {number} */ minimumAliasedPointSize: { get: function() { return ContextLimits._minimumAliasedPointSize; } }, /** * The maximum aliased point size, in pixels, supported by this WebGL implementation. It will be at least one. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with ALIASED_POINT_SIZE_RANGE. * @memberof ContextLimits * @type {number} */ maximumAliasedPointSize: { get: function() { return ContextLimits._maximumAliasedPointSize; } }, /** * The maximum supported width of the viewport. It will be at least as large as the visible width of the associated canvas. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VIEWPORT_DIMS. * @memberof ContextLimits * @type {number} */ maximumViewportWidth: { get: function() { return ContextLimits._maximumViewportWidth; } }, /** * The maximum supported height of the viewport. It will be at least as large as the visible height of the associated canvas. * @see {@link https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glGet.xhtml|glGet in OpenGL ES 3.0} with MAX_VIEWPORT_DIMS. * @memberof ContextLimits * @type {number} */ maximumViewportHeight: { get: function() { return ContextLimits._maximumViewportHeight; } }, /** * The maximum degree of anisotropy for texture filtering * @memberof ContextLimits * @type {number} */ maximumTextureFilterAnisotropy: { get: function() { return ContextLimits._maximumTextureFilterAnisotropy; } }, /** * The maximum number of simultaneous outputs that may be written in a fragment shader. * @memberof ContextLimits * @type {number} */ maximumDrawBuffers: { get: function() { return ContextLimits._maximumDrawBuffers; } }, /** * The maximum number of color attachments supported. * @memberof ContextLimits * @type {number} */ maximumColorAttachments: { get: function() { return ContextLimits._maximumColorAttachments; } }, /** * The maximum number of samples supported for multisampling. * @memberof ContextLimits * @type {number} */ maximumSamples: { get: function() { return ContextLimits._maximumSamples; } }, /** * High precision float supported (highp) in fragment shaders. * @memberof ContextLimits * @type {boolean} */ highpFloatSupported: { get: function() { return ContextLimits._highpFloatSupported; } }, /** * High precision int supported (highp) in fragment shaders. * @memberof ContextLimits * @type {boolean} */ highpIntSupported: { get: function() { return ContextLimits._highpIntSupported; } } }); var ContextLimits_default = ContextLimits; // packages/engine/Source/Renderer/Framebuffer.js function attachTexture(framebuffer, attachment, texture) { const gl = framebuffer._gl; gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, texture._target, texture._texture, 0 ); } function attachRenderbuffer(framebuffer, attachment, renderbuffer) { const gl = framebuffer._gl; gl.framebufferRenderbuffer( gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer._getRenderbuffer() ); } function Framebuffer(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const context = options.context; Check_default.defined("options.context", context); const gl = context._gl; const maximumColorAttachments = ContextLimits_default.maximumColorAttachments; this._gl = gl; this._framebuffer = gl.createFramebuffer(); this._colorTextures = []; this._colorRenderbuffers = []; this._activeColorAttachments = []; this._depthTexture = void 0; this._depthRenderbuffer = void 0; this._stencilRenderbuffer = void 0; this._depthStencilTexture = void 0; this._depthStencilRenderbuffer = void 0; this.destroyAttachments = options.destroyAttachments ?? true; if (defined_default(options.colorTextures) && defined_default(options.colorRenderbuffers)) { throw new DeveloperError_default( "Cannot have both color texture and color renderbuffer attachments." ); } if (defined_default(options.depthTexture) && defined_default(options.depthRenderbuffer)) { throw new DeveloperError_default( "Cannot have both a depth texture and depth renderbuffer attachment." ); } if (defined_default(options.depthStencilTexture) && defined_default(options.depthStencilRenderbuffer)) { throw new DeveloperError_default( "Cannot have both a depth-stencil texture and depth-stencil renderbuffer attachment." ); } const depthAttachment = defined_default(options.depthTexture) || defined_default(options.depthRenderbuffer); const depthStencilAttachment = defined_default(options.depthStencilTexture) || defined_default(options.depthStencilRenderbuffer); if (depthAttachment && depthStencilAttachment) { throw new DeveloperError_default( "Cannot have both a depth and depth-stencil attachment." ); } if (defined_default(options.stencilRenderbuffer) && depthStencilAttachment) { throw new DeveloperError_default( "Cannot have both a stencil and depth-stencil attachment." ); } if (depthAttachment && defined_default(options.stencilRenderbuffer)) { throw new DeveloperError_default( "Cannot have both a depth and stencil attachment." ); } this._bind(); if (defined_default(options.colorTextures)) { const textures = options.colorTextures; const length2 = this._colorTextures.length = this._activeColorAttachments.length = textures.length; if (length2 > maximumColorAttachments) { throw new DeveloperError_default( "The number of color attachments exceeds the number supported." ); } for (let i = 0; i < length2; ++i) { const texture = textures[i]; if (!PixelFormat_default.isColorFormat(texture.pixelFormat)) { throw new DeveloperError_default( "The color-texture pixel-format must be a color format." ); } if (texture.pixelDatatype === PixelDatatype_default.FLOAT && !context.colorBufferFloat) { throw new DeveloperError_default( "The color texture pixel datatype is FLOAT and the WebGL implementation does not support the EXT_color_buffer_float or WEBGL_color_buffer_float extensions. See Context.colorBufferFloat." ); } if (texture.pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.colorBufferHalfFloat) { throw new DeveloperError_default( "The color texture pixel datatype is HALF_FLOAT and the WebGL implementation does not support the EXT_color_buffer_half_float extension. See Context.colorBufferHalfFloat." ); } const attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i; attachTexture(this, attachmentEnum, texture); this._activeColorAttachments[i] = attachmentEnum; this._colorTextures[i] = texture; } } if (defined_default(options.colorRenderbuffers)) { const renderbuffers = options.colorRenderbuffers; const length2 = this._colorRenderbuffers.length = this._activeColorAttachments.length = renderbuffers.length; if (length2 > maximumColorAttachments) { throw new DeveloperError_default( "The number of color attachments exceeds the number supported." ); } for (let i = 0; i < length2; ++i) { const renderbuffer = renderbuffers[i]; const attachmentEnum = this._gl.COLOR_ATTACHMENT0 + i; attachRenderbuffer(this, attachmentEnum, renderbuffer); this._activeColorAttachments[i] = attachmentEnum; this._colorRenderbuffers[i] = renderbuffer; } } if (defined_default(options.depthTexture)) { const texture = options.depthTexture; if (texture.pixelFormat !== PixelFormat_default.DEPTH_COMPONENT) { throw new DeveloperError_default( "The depth-texture pixel-format must be DEPTH_COMPONENT." ); } attachTexture(this, this._gl.DEPTH_ATTACHMENT, texture); this._depthTexture = texture; } if (defined_default(options.depthRenderbuffer)) { const renderbuffer = options.depthRenderbuffer; attachRenderbuffer(this, this._gl.DEPTH_ATTACHMENT, renderbuffer); this._depthRenderbuffer = renderbuffer; } if (defined_default(options.stencilRenderbuffer)) { const renderbuffer = options.stencilRenderbuffer; attachRenderbuffer(this, this._gl.STENCIL_ATTACHMENT, renderbuffer); this._stencilRenderbuffer = renderbuffer; } if (defined_default(options.depthStencilTexture)) { const texture = options.depthStencilTexture; if (texture.pixelFormat !== PixelFormat_default.DEPTH_STENCIL) { throw new DeveloperError_default( "The depth-stencil pixel-format must be DEPTH_STENCIL." ); } attachTexture(this, this._gl.DEPTH_STENCIL_ATTACHMENT, texture); this._depthStencilTexture = texture; } if (defined_default(options.depthStencilRenderbuffer)) { const renderbuffer = options.depthStencilRenderbuffer; attachRenderbuffer(this, this._gl.DEPTH_STENCIL_ATTACHMENT, renderbuffer); this._depthStencilRenderbuffer = renderbuffer; } this._unBind(); context._currentFramebuffer = void 0; } Object.defineProperties(Framebuffer.prototype, { /** * The status of the framebuffer. If the status is not WebGLConstants.FRAMEBUFFER_COMPLETE, * a {@link DeveloperError} will be thrown when attempting to render to the framebuffer. * @memberof Framebuffer.prototype * @type {number} */ status: { get: function() { this._bind(); const status = this._gl.checkFramebufferStatus(this._gl.FRAMEBUFFER); this._unBind(); return status; } }, numberOfColorAttachments: { get: function() { return this._activeColorAttachments.length; } }, depthTexture: { get: function() { return this._depthTexture; } }, depthRenderbuffer: { get: function() { return this._depthRenderbuffer; } }, stencilRenderbuffer: { get: function() { return this._stencilRenderbuffer; } }, depthStencilTexture: { get: function() { return this._depthStencilTexture; } }, depthStencilRenderbuffer: { get: function() { return this._depthStencilRenderbuffer; } }, /** * True if the framebuffer has a depth attachment. Depth attachments include * depth and depth-stencil textures, and depth and depth-stencil renderbuffers. When * rendering to a framebuffer, a depth attachment is required for the depth test to have effect. * @memberof Framebuffer.prototype * @type {boolean} */ hasDepthAttachment: { get: function() { return !!(this.depthTexture || this.depthRenderbuffer || this.depthStencilTexture || this.depthStencilRenderbuffer); } } }); Framebuffer.prototype._bind = function() { const gl = this._gl; gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer); }; Framebuffer.prototype._unBind = function() { const gl = this._gl; gl.bindFramebuffer(gl.FRAMEBUFFER, null); }; Framebuffer.prototype.bindDraw = function() { const gl = this._gl; gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._framebuffer); }; Framebuffer.prototype.bindRead = function() { const gl = this._gl; gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this._framebuffer); }; Framebuffer.prototype._getActiveColorAttachments = function() { return this._activeColorAttachments; }; Framebuffer.prototype.getColorTexture = function(index) { if (!defined_default(index) || index < 0 || index >= this._colorTextures.length) { throw new DeveloperError_default( "index is required, must be greater than or equal to zero and must be less than the number of color attachments." ); } return this._colorTextures[index]; }; Framebuffer.prototype.getColorRenderbuffer = function(index) { if (!defined_default(index) || index < 0 || index >= this._colorRenderbuffers.length) { throw new DeveloperError_default( "index is required, must be greater than or equal to zero and must be less than the number of color attachments." ); } return this._colorRenderbuffers[index]; }; Framebuffer.prototype.isDestroyed = function() { return false; }; Framebuffer.prototype.destroy = function() { if (this.destroyAttachments) { const textures = this._colorTextures; for (let i = 0; i < textures.length; ++i) { const texture = textures[i]; if (defined_default(texture)) { texture.destroy(); } } const renderbuffers = this._colorRenderbuffers; for (let i = 0; i < renderbuffers.length; ++i) { const renderbuffer = renderbuffers[i]; if (defined_default(renderbuffer)) { renderbuffer.destroy(); } } this._depthTexture = this._depthTexture && this._depthTexture.destroy(); this._depthRenderbuffer = this._depthRenderbuffer && this._depthRenderbuffer.destroy(); this._stencilRenderbuffer = this._stencilRenderbuffer && this._stencilRenderbuffer.destroy(); this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); this._depthStencilRenderbuffer = this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy(); } this._gl.deleteFramebuffer(this._framebuffer); return destroyObject_default(this); }; var Framebuffer_default = Framebuffer; // packages/engine/Source/Renderer/RenderState.js var import_InlineWorkers80 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/WindingOrder.js var import_InlineWorkers78 = __toESM(require_InlineWorkers(), 1); var WindingOrder = { /** * Vertices are in clockwise order. * * @type {number} * @constant */ CLOCKWISE: WebGLConstants_default.CW, /** * Vertices are in counter-clockwise order. * * @type {number} * @constant */ COUNTER_CLOCKWISE: WebGLConstants_default.CCW }; WindingOrder.validate = function(windingOrder) { return windingOrder === WindingOrder.CLOCKWISE || windingOrder === WindingOrder.COUNTER_CLOCKWISE; }; Object.freeze(WindingOrder); var WindingOrder_default = WindingOrder; // packages/engine/Source/Renderer/freezeRenderState.js var import_InlineWorkers79 = __toESM(require_InlineWorkers(), 1); function freezeRenderState(renderState) { if (typeof renderState !== "object" || renderState === null) { return renderState; } let propName; const propNames = Object.keys(renderState); for (let i = 0; i < propNames.length; i++) { propName = propNames[i]; if (renderState.hasOwnProperty(propName) && propName !== "_applyFunctions") { renderState[propName] = freezeRenderState(renderState[propName]); } } return Object.freeze(renderState); } var freezeRenderState_default = freezeRenderState; // packages/engine/Source/Renderer/RenderState.js function validateBlendEquation(blendEquation) { return blendEquation === WebGLConstants_default.FUNC_ADD || blendEquation === WebGLConstants_default.FUNC_SUBTRACT || blendEquation === WebGLConstants_default.FUNC_REVERSE_SUBTRACT || blendEquation === WebGLConstants_default.MIN || blendEquation === WebGLConstants_default.MAX; } function validateBlendFunction(blendFunction) { return blendFunction === WebGLConstants_default.ZERO || blendFunction === WebGLConstants_default.ONE || blendFunction === WebGLConstants_default.SRC_COLOR || blendFunction === WebGLConstants_default.ONE_MINUS_SRC_COLOR || blendFunction === WebGLConstants_default.DST_COLOR || blendFunction === WebGLConstants_default.ONE_MINUS_DST_COLOR || blendFunction === WebGLConstants_default.SRC_ALPHA || blendFunction === WebGLConstants_default.ONE_MINUS_SRC_ALPHA || blendFunction === WebGLConstants_default.DST_ALPHA || blendFunction === WebGLConstants_default.ONE_MINUS_DST_ALPHA || blendFunction === WebGLConstants_default.CONSTANT_COLOR || blendFunction === WebGLConstants_default.ONE_MINUS_CONSTANT_COLOR || blendFunction === WebGLConstants_default.CONSTANT_ALPHA || blendFunction === WebGLConstants_default.ONE_MINUS_CONSTANT_ALPHA || blendFunction === WebGLConstants_default.SRC_ALPHA_SATURATE; } function validateCullFace(cullFace) { return cullFace === WebGLConstants_default.FRONT || cullFace === WebGLConstants_default.BACK || cullFace === WebGLConstants_default.FRONT_AND_BACK; } function validateDepthFunction(depthFunction) { return depthFunction === WebGLConstants_default.NEVER || depthFunction === WebGLConstants_default.LESS || depthFunction === WebGLConstants_default.EQUAL || depthFunction === WebGLConstants_default.LEQUAL || depthFunction === WebGLConstants_default.GREATER || depthFunction === WebGLConstants_default.NOTEQUAL || depthFunction === WebGLConstants_default.GEQUAL || depthFunction === WebGLConstants_default.ALWAYS; } function validateStencilFunction(stencilFunction) { return stencilFunction === WebGLConstants_default.NEVER || stencilFunction === WebGLConstants_default.LESS || stencilFunction === WebGLConstants_default.EQUAL || stencilFunction === WebGLConstants_default.LEQUAL || stencilFunction === WebGLConstants_default.GREATER || stencilFunction === WebGLConstants_default.NOTEQUAL || stencilFunction === WebGLConstants_default.GEQUAL || stencilFunction === WebGLConstants_default.ALWAYS; } function validateStencilOperation(stencilOperation) { return stencilOperation === WebGLConstants_default.ZERO || stencilOperation === WebGLConstants_default.KEEP || stencilOperation === WebGLConstants_default.REPLACE || stencilOperation === WebGLConstants_default.INCR || stencilOperation === WebGLConstants_default.DECR || stencilOperation === WebGLConstants_default.INVERT || stencilOperation === WebGLConstants_default.INCR_WRAP || stencilOperation === WebGLConstants_default.DECR_WRAP; } function RenderState(renderState) { const rs = renderState ?? Frozen_default.EMPTY_OBJECT; const cull = rs.cull ?? Frozen_default.EMPTY_OBJECT; const polygonOffset = rs.polygonOffset ?? Frozen_default.EMPTY_OBJECT; const scissorTest = rs.scissorTest ?? Frozen_default.EMPTY_OBJECT; const scissorTestRectangle = scissorTest.rectangle ?? Frozen_default.EMPTY_OBJECT; const depthRange = rs.depthRange ?? Frozen_default.EMPTY_OBJECT; const depthTest = rs.depthTest ?? Frozen_default.EMPTY_OBJECT; const colorMask = rs.colorMask ?? Frozen_default.EMPTY_OBJECT; const blending = rs.blending ?? Frozen_default.EMPTY_OBJECT; const blendingColor = blending.color ?? Frozen_default.EMPTY_OBJECT; const stencilTest = rs.stencilTest ?? Frozen_default.EMPTY_OBJECT; const stencilTestFrontOperation = stencilTest.frontOperation ?? Frozen_default.EMPTY_OBJECT; const stencilTestBackOperation = stencilTest.backOperation ?? Frozen_default.EMPTY_OBJECT; const sampleCoverage = rs.sampleCoverage ?? Frozen_default.EMPTY_OBJECT; const viewport = rs.viewport; this.frontFace = rs.frontFace ?? WindingOrder_default.COUNTER_CLOCKWISE; this.cull = { enabled: cull.enabled ?? false, face: cull.face ?? WebGLConstants_default.BACK }; this.lineWidth = rs.lineWidth ?? 1; this.polygonOffset = { enabled: polygonOffset.enabled ?? false, factor: polygonOffset.factor ?? 0, units: polygonOffset.units ?? 0 }; this.scissorTest = { enabled: scissorTest.enabled ?? false, rectangle: BoundingRectangle_default.clone(scissorTestRectangle) }; this.depthRange = { near: depthRange.near ?? 0, far: depthRange.far ?? 1 }; this.depthTest = { enabled: depthTest.enabled ?? false, func: depthTest.func ?? WebGLConstants_default.LESS // func, because function is a JavaScript keyword }; this.colorMask = { red: colorMask.red ?? true, green: colorMask.green ?? true, blue: colorMask.blue ?? true, alpha: colorMask.alpha ?? true }; this.depthMask = rs.depthMask ?? true; this.stencilMask = rs.stencilMask ?? ~0; this.blending = { enabled: blending.enabled ?? false, color: new Color_default( blendingColor.red ?? 0, blendingColor.green ?? 0, blendingColor.blue ?? 0, blendingColor.alpha ?? 0 ), equationRgb: blending.equationRgb ?? WebGLConstants_default.FUNC_ADD, equationAlpha: blending.equationAlpha ?? WebGLConstants_default.FUNC_ADD, functionSourceRgb: blending.functionSourceRgb ?? WebGLConstants_default.ONE, functionSourceAlpha: blending.functionSourceAlpha ?? WebGLConstants_default.ONE, functionDestinationRgb: blending.functionDestinationRgb ?? WebGLConstants_default.ZERO, functionDestinationAlpha: blending.functionDestinationAlpha ?? WebGLConstants_default.ZERO }; this.stencilTest = { enabled: stencilTest.enabled ?? false, frontFunction: stencilTest.frontFunction ?? WebGLConstants_default.ALWAYS, backFunction: stencilTest.backFunction ?? WebGLConstants_default.ALWAYS, reference: stencilTest.reference ?? 0, mask: stencilTest.mask ?? ~0, frontOperation: { fail: stencilTestFrontOperation.fail ?? WebGLConstants_default.KEEP, zFail: stencilTestFrontOperation.zFail ?? WebGLConstants_default.KEEP, zPass: stencilTestFrontOperation.zPass ?? WebGLConstants_default.KEEP }, backOperation: { fail: stencilTestBackOperation.fail ?? WebGLConstants_default.KEEP, zFail: stencilTestBackOperation.zFail ?? WebGLConstants_default.KEEP, zPass: stencilTestBackOperation.zPass ?? WebGLConstants_default.KEEP } }; this.sampleCoverage = { enabled: sampleCoverage.enabled ?? false, value: sampleCoverage.value ?? 1, invert: sampleCoverage.invert ?? false }; this.viewport = defined_default(viewport) ? new BoundingRectangle_default( viewport.x, viewport.y, viewport.width, viewport.height ) : void 0; if (this.lineWidth < ContextLimits_default.minimumAliasedLineWidth || this.lineWidth > ContextLimits_default.maximumAliasedLineWidth) { throw new DeveloperError_default( "renderState.lineWidth is out of range. Check minimumAliasedLineWidth and maximumAliasedLineWidth." ); } if (!WindingOrder_default.validate(this.frontFace)) { throw new DeveloperError_default("Invalid renderState.frontFace."); } if (!validateCullFace(this.cull.face)) { throw new DeveloperError_default("Invalid renderState.cull.face."); } if (this.scissorTest.rectangle.width < 0 || this.scissorTest.rectangle.height < 0) { throw new DeveloperError_default( "renderState.scissorTest.rectangle.width and renderState.scissorTest.rectangle.height must be greater than or equal to zero." ); } if (this.depthRange.near > this.depthRange.far) { throw new DeveloperError_default( "renderState.depthRange.near can not be greater than renderState.depthRange.far." ); } if (this.depthRange.near < 0) { throw new DeveloperError_default( "renderState.depthRange.near must be greater than or equal to zero." ); } if (this.depthRange.far > 1) { throw new DeveloperError_default( "renderState.depthRange.far must be less than or equal to one." ); } if (!validateDepthFunction(this.depthTest.func)) { throw new DeveloperError_default("Invalid renderState.depthTest.func."); } if (this.blending.color.red < 0 || this.blending.color.red > 1 || this.blending.color.green < 0 || this.blending.color.green > 1 || this.blending.color.blue < 0 || this.blending.color.blue > 1 || this.blending.color.alpha < 0 || this.blending.color.alpha > 1) { throw new DeveloperError_default( "renderState.blending.color components must be greater than or equal to zero and less than or equal to one." ); } if (!validateBlendEquation(this.blending.equationRgb)) { throw new DeveloperError_default("Invalid renderState.blending.equationRgb."); } if (!validateBlendEquation(this.blending.equationAlpha)) { throw new DeveloperError_default("Invalid renderState.blending.equationAlpha."); } if (!validateBlendFunction(this.blending.functionSourceRgb)) { throw new DeveloperError_default("Invalid renderState.blending.functionSourceRgb."); } if (!validateBlendFunction(this.blending.functionSourceAlpha)) { throw new DeveloperError_default( "Invalid renderState.blending.functionSourceAlpha." ); } if (!validateBlendFunction(this.blending.functionDestinationRgb)) { throw new DeveloperError_default( "Invalid renderState.blending.functionDestinationRgb." ); } if (!validateBlendFunction(this.blending.functionDestinationAlpha)) { throw new DeveloperError_default( "Invalid renderState.blending.functionDestinationAlpha." ); } if (!validateStencilFunction(this.stencilTest.frontFunction)) { throw new DeveloperError_default("Invalid renderState.stencilTest.frontFunction."); } if (!validateStencilFunction(this.stencilTest.backFunction)) { throw new DeveloperError_default("Invalid renderState.stencilTest.backFunction."); } if (!validateStencilOperation(this.stencilTest.frontOperation.fail)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.frontOperation.fail." ); } if (!validateStencilOperation(this.stencilTest.frontOperation.zFail)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.frontOperation.zFail." ); } if (!validateStencilOperation(this.stencilTest.frontOperation.zPass)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.frontOperation.zPass." ); } if (!validateStencilOperation(this.stencilTest.backOperation.fail)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.backOperation.fail." ); } if (!validateStencilOperation(this.stencilTest.backOperation.zFail)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.backOperation.zFail." ); } if (!validateStencilOperation(this.stencilTest.backOperation.zPass)) { throw new DeveloperError_default( "Invalid renderState.stencilTest.backOperation.zPass." ); } if (defined_default(this.viewport)) { if (this.viewport.width < 0) { throw new DeveloperError_default( "renderState.viewport.width must be greater than or equal to zero." ); } if (this.viewport.height < 0) { throw new DeveloperError_default( "renderState.viewport.height must be greater than or equal to zero." ); } if (this.viewport.width > ContextLimits_default.maximumViewportWidth) { throw new DeveloperError_default( `renderState.viewport.width must be less than or equal to the maximum viewport width (${ContextLimits_default.maximumViewportWidth.toString()}). Check maximumViewportWidth.` ); } if (this.viewport.height > ContextLimits_default.maximumViewportHeight) { throw new DeveloperError_default( `renderState.viewport.height must be less than or equal to the maximum viewport height (${ContextLimits_default.maximumViewportHeight.toString()}). Check maximumViewportHeight.` ); } } this.id = 0; this._applyFunctions = []; } var nextRenderStateId = 0; var renderStateCache = {}; RenderState.fromCache = function(renderState) { const partialKey = JSON.stringify(renderState); let cachedState = renderStateCache[partialKey]; if (defined_default(cachedState)) { ++cachedState.referenceCount; return cachedState.state; } let states = new RenderState(renderState); const fullKey = JSON.stringify(states); cachedState = renderStateCache[fullKey]; if (!defined_default(cachedState)) { states.id = nextRenderStateId++; states = freezeRenderState_default(states); cachedState = { referenceCount: 0, state: states }; renderStateCache[fullKey] = cachedState; } ++cachedState.referenceCount; renderStateCache[partialKey] = { referenceCount: 1, state: cachedState.state }; return cachedState.state; }; RenderState.removeFromCache = function(renderState) { const states = new RenderState(renderState); const fullKey = JSON.stringify(states); const fullCachedState = renderStateCache[fullKey]; const partialKey = JSON.stringify(renderState); const cachedState = renderStateCache[partialKey]; if (defined_default(cachedState)) { --cachedState.referenceCount; if (cachedState.referenceCount === 0) { delete renderStateCache[partialKey]; if (defined_default(fullCachedState)) { --fullCachedState.referenceCount; } } } if (defined_default(fullCachedState) && fullCachedState.referenceCount === 0) { delete renderStateCache[fullKey]; } }; RenderState.getCache = function() { return renderStateCache; }; RenderState.clearCache = function() { renderStateCache = {}; }; function enableOrDisable(gl, glEnum, enable) { if (enable) { gl.enable(glEnum); } else { gl.disable(glEnum); } } function applyFrontFace(gl, renderState) { gl.frontFace(renderState.frontFace); } function applyCull(gl, renderState) { const cull = renderState.cull; const enabled = cull.enabled; enableOrDisable(gl, gl.CULL_FACE, enabled); if (enabled) { gl.cullFace(cull.face); } } function applyLineWidth(gl, renderState) { gl.lineWidth(renderState.lineWidth); } function applyPolygonOffset(gl, renderState) { const polygonOffset = renderState.polygonOffset; const enabled = polygonOffset.enabled; enableOrDisable(gl, gl.POLYGON_OFFSET_FILL, enabled); if (enabled) { gl.polygonOffset(polygonOffset.factor, polygonOffset.units); } } function applyScissorTest(gl, renderState, passState) { const scissorTest = renderState.scissorTest; const enabled = defined_default(passState.scissorTest) ? passState.scissorTest.enabled : scissorTest.enabled; enableOrDisable(gl, gl.SCISSOR_TEST, enabled); if (enabled) { const rectangle = defined_default(passState.scissorTest) ? passState.scissorTest.rectangle : scissorTest.rectangle; gl.scissor(rectangle.x, rectangle.y, rectangle.width, rectangle.height); } } function applyDepthRange(gl, renderState) { const depthRange = renderState.depthRange; gl.depthRange(depthRange.near, depthRange.far); } function applyDepthTest(gl, renderState) { const depthTest = renderState.depthTest; const enabled = depthTest.enabled; enableOrDisable(gl, gl.DEPTH_TEST, enabled); if (enabled) { gl.depthFunc(depthTest.func); } } function applyColorMask(gl, renderState) { const colorMask = renderState.colorMask; gl.colorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha); } function applyDepthMask(gl, renderState) { gl.depthMask(renderState.depthMask); } function applyStencilMask(gl, renderState) { gl.stencilMask(renderState.stencilMask); } function applyBlendingColor(gl, color) { gl.blendColor(color.red, color.green, color.blue, color.alpha); } function applyBlending(gl, renderState, passState) { const blending = renderState.blending; const enabled = defined_default(passState.blendingEnabled) ? passState.blendingEnabled : blending.enabled; enableOrDisable(gl, gl.BLEND, enabled); if (enabled) { applyBlendingColor(gl, blending.color); gl.blendEquationSeparate(blending.equationRgb, blending.equationAlpha); gl.blendFuncSeparate( blending.functionSourceRgb, blending.functionDestinationRgb, blending.functionSourceAlpha, blending.functionDestinationAlpha ); } } function applyStencilTest(gl, renderState) { const stencilTest = renderState.stencilTest; const enabled = stencilTest.enabled; enableOrDisable(gl, gl.STENCIL_TEST, enabled); if (enabled) { const frontFunction = stencilTest.frontFunction; const backFunction = stencilTest.backFunction; const reference = stencilTest.reference; const mask = stencilTest.mask; gl.stencilFunc(frontFunction, reference, mask); gl.stencilFuncSeparate(gl.BACK, backFunction, reference, mask); gl.stencilFuncSeparate(gl.FRONT, frontFunction, reference, mask); const frontOperation = stencilTest.frontOperation; const frontOperationFail = frontOperation.fail; const frontOperationZFail = frontOperation.zFail; const frontOperationZPass = frontOperation.zPass; gl.stencilOpSeparate( gl.FRONT, frontOperationFail, frontOperationZFail, frontOperationZPass ); const backOperation = stencilTest.backOperation; const backOperationFail = backOperation.fail; const backOperationZFail = backOperation.zFail; const backOperationZPass = backOperation.zPass; gl.stencilOpSeparate( gl.BACK, backOperationFail, backOperationZFail, backOperationZPass ); } } function applySampleCoverage(gl, renderState) { const sampleCoverage = renderState.sampleCoverage; const enabled = sampleCoverage.enabled; enableOrDisable(gl, gl.SAMPLE_COVERAGE, enabled); if (enabled) { gl.sampleCoverage(sampleCoverage.value, sampleCoverage.invert); } } var scratchViewport = new BoundingRectangle_default(); function applyViewport(gl, renderState, passState) { let viewport = renderState.viewport ?? passState.viewport; if (!defined_default(viewport)) { viewport = scratchViewport; viewport.width = passState.context.drawingBufferWidth; viewport.height = passState.context.drawingBufferHeight; } passState.context.uniformState.viewport = viewport; gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); } RenderState.apply = function(gl, renderState, passState) { applyFrontFace(gl, renderState); applyCull(gl, renderState); applyLineWidth(gl, renderState); applyPolygonOffset(gl, renderState); applyDepthRange(gl, renderState); applyDepthTest(gl, renderState); applyColorMask(gl, renderState); applyDepthMask(gl, renderState); applyStencilMask(gl, renderState); applyStencilTest(gl, renderState); applySampleCoverage(gl, renderState); applyScissorTest(gl, renderState, passState); applyBlending(gl, renderState, passState); applyViewport(gl, renderState, passState); }; function createFuncs(previousState, nextState) { const funcs = []; if (previousState.frontFace !== nextState.frontFace) { funcs.push(applyFrontFace); } if (previousState.cull.enabled !== nextState.cull.enabled || previousState.cull.face !== nextState.cull.face) { funcs.push(applyCull); } if (previousState.lineWidth !== nextState.lineWidth) { funcs.push(applyLineWidth); } if (previousState.polygonOffset.enabled !== nextState.polygonOffset.enabled || previousState.polygonOffset.factor !== nextState.polygonOffset.factor || previousState.polygonOffset.units !== nextState.polygonOffset.units) { funcs.push(applyPolygonOffset); } if (previousState.depthRange.near !== nextState.depthRange.near || previousState.depthRange.far !== nextState.depthRange.far) { funcs.push(applyDepthRange); } if (previousState.depthTest.enabled !== nextState.depthTest.enabled || previousState.depthTest.func !== nextState.depthTest.func) { funcs.push(applyDepthTest); } if (previousState.colorMask.red !== nextState.colorMask.red || previousState.colorMask.green !== nextState.colorMask.green || previousState.colorMask.blue !== nextState.colorMask.blue || previousState.colorMask.alpha !== nextState.colorMask.alpha) { funcs.push(applyColorMask); } if (previousState.depthMask !== nextState.depthMask) { funcs.push(applyDepthMask); } if (previousState.stencilMask !== nextState.stencilMask) { funcs.push(applyStencilMask); } if (previousState.stencilTest.enabled !== nextState.stencilTest.enabled || previousState.stencilTest.frontFunction !== nextState.stencilTest.frontFunction || previousState.stencilTest.backFunction !== nextState.stencilTest.backFunction || previousState.stencilTest.reference !== nextState.stencilTest.reference || previousState.stencilTest.mask !== nextState.stencilTest.mask || previousState.stencilTest.frontOperation.fail !== nextState.stencilTest.frontOperation.fail || previousState.stencilTest.frontOperation.zFail !== nextState.stencilTest.frontOperation.zFail || previousState.stencilTest.backOperation.fail !== nextState.stencilTest.backOperation.fail || previousState.stencilTest.backOperation.zFail !== nextState.stencilTest.backOperation.zFail || previousState.stencilTest.backOperation.zPass !== nextState.stencilTest.backOperation.zPass) { funcs.push(applyStencilTest); } if (previousState.sampleCoverage.enabled !== nextState.sampleCoverage.enabled || previousState.sampleCoverage.value !== nextState.sampleCoverage.value || previousState.sampleCoverage.invert !== nextState.sampleCoverage.invert) { funcs.push(applySampleCoverage); } return funcs; } RenderState.partialApply = function(gl, previousRenderState, renderState, previousPassState, passState, clear2) { if (previousRenderState !== renderState) { let funcs = renderState._applyFunctions[previousRenderState.id]; if (!defined_default(funcs)) { funcs = createFuncs(previousRenderState, renderState); renderState._applyFunctions[previousRenderState.id] = funcs; } const len = funcs.length; for (let i = 0; i < len; ++i) { funcs[i](gl, renderState); } } const previousScissorTest = defined_default(previousPassState.scissorTest) ? previousPassState.scissorTest : previousRenderState.scissorTest; const scissorTest = defined_default(passState.scissorTest) ? passState.scissorTest : renderState.scissorTest; if (previousScissorTest !== scissorTest || clear2) { applyScissorTest(gl, renderState, passState); } const previousBlendingEnabled = defined_default(previousPassState.blendingEnabled) ? previousPassState.blendingEnabled : previousRenderState.blending.enabled; const blendingEnabled = defined_default(passState.blendingEnabled) ? passState.blendingEnabled : renderState.blending.enabled; if (previousBlendingEnabled !== blendingEnabled || blendingEnabled && previousRenderState.blending !== renderState.blending) { applyBlending(gl, renderState, passState); } if (previousRenderState !== renderState || previousPassState !== passState || previousPassState.context !== passState.context) { applyViewport(gl, renderState, passState); } }; RenderState.getState = function(renderState) { if (!defined_default(renderState)) { throw new DeveloperError_default("renderState is required."); } return { frontFace: renderState.frontFace, cull: { enabled: renderState.cull.enabled, face: renderState.cull.face }, lineWidth: renderState.lineWidth, polygonOffset: { enabled: renderState.polygonOffset.enabled, factor: renderState.polygonOffset.factor, units: renderState.polygonOffset.units }, scissorTest: { enabled: renderState.scissorTest.enabled, rectangle: BoundingRectangle_default.clone(renderState.scissorTest.rectangle) }, depthRange: { near: renderState.depthRange.near, far: renderState.depthRange.far }, depthTest: { enabled: renderState.depthTest.enabled, func: renderState.depthTest.func }, colorMask: { red: renderState.colorMask.red, green: renderState.colorMask.green, blue: renderState.colorMask.blue, alpha: renderState.colorMask.alpha }, depthMask: renderState.depthMask, stencilMask: renderState.stencilMask, blending: { enabled: renderState.blending.enabled, color: Color_default.clone(renderState.blending.color), equationRgb: renderState.blending.equationRgb, equationAlpha: renderState.blending.equationAlpha, functionSourceRgb: renderState.blending.functionSourceRgb, functionSourceAlpha: renderState.blending.functionSourceAlpha, functionDestinationRgb: renderState.blending.functionDestinationRgb, functionDestinationAlpha: renderState.blending.functionDestinationAlpha }, stencilTest: { enabled: renderState.stencilTest.enabled, frontFunction: renderState.stencilTest.frontFunction, backFunction: renderState.stencilTest.backFunction, reference: renderState.stencilTest.reference, mask: renderState.stencilTest.mask, frontOperation: { fail: renderState.stencilTest.frontOperation.fail, zFail: renderState.stencilTest.frontOperation.zFail, zPass: renderState.stencilTest.frontOperation.zPass }, backOperation: { fail: renderState.stencilTest.backOperation.fail, zFail: renderState.stencilTest.backOperation.zFail, zPass: renderState.stencilTest.backOperation.zPass } }, sampleCoverage: { enabled: renderState.sampleCoverage.enabled, value: renderState.sampleCoverage.value, invert: renderState.sampleCoverage.invert }, viewport: defined_default(renderState.viewport) ? BoundingRectangle_default.clone(renderState.viewport) : void 0 }; }; var RenderState_default = RenderState; // packages/engine/Source/Renderer/ShaderProgram.js var import_InlineWorkers84 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/createUniform.js var import_InlineWorkers82 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Matrix2.js var import_InlineWorkers81 = __toESM(require_InlineWorkers(), 1); var Matrix2 = class _Matrix2 { /** * @param {number} [column0Row0=0.0] The value for column 0, row 0. * @param {number} [column1Row0=0.0] The value for column 1, row 0. * @param {number} [column0Row1=0.0] The value for column 0, row 1. * @param {number} [column1Row1=0.0] The value for column 1, row 1. */ constructor(column0Row0, column1Row0, column0Row1, column1Row1) { this[0] = column0Row0 ?? 0; this[1] = column0Row1 ?? 0; this[2] = column1Row0 ?? 0; this[3] = column1Row1 ?? 0; } /** * Stores the provided instance into the provided array. * * @param {Matrix2} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value[0]; array[startingIndex++] = value[1]; array[startingIndex++] = value[2]; array[startingIndex] = value[3]; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {Matrix2} [result] The object into which to store the result. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _Matrix2(); } result[0] = array[startingIndex++]; result[1] = array[startingIndex++]; result[2] = array[startingIndex++]; result[3] = array[startingIndex]; return result; } /** * Flattens an array of Matrix2s into an array of components. The components * are stored in column-major order. * * @param {Matrix2[]} array The array of matrices to pack. * @param {number[]} [result] The array onto which to store the result. If this is a typed array, it must have array.length * 4 components, else a {@link DeveloperError} will be thrown. If it is a regular array, it will be resized to have (array.length * 4) elements. * @returns {number[]} The packed array. */ static packArray(array, result) { Check_default.defined("array", array); const length2 = array.length; const resultLength = length2 * 4; if (!defined_default(result)) { result = new Array(resultLength); } else if (!Array.isArray(result) && result.length !== resultLength) { throw new DeveloperError_default( "If result is a typed array, it must have exactly array.length * 4 elements" ); } else if (result.length !== resultLength) { result.length = resultLength; } for (let i = 0; i < length2; ++i) { _Matrix2.pack(array[i], result, i * 4); } return result; } /** * Unpacks an array of column-major matrix components into an array of Matrix2s. * * @param {number[]} array The array of components to unpack. * @param {Matrix2[]} [result] The array onto which to store the result. * @returns {Matrix2[]} The unpacked array. */ static unpackArray(array, result) { Check_default.defined("array", array); Check_default.typeOf.number.greaterThanOrEquals("array.length", array.length, 4); if (array.length % 4 !== 0) { throw new DeveloperError_default("array length must be a multiple of 4."); } const length2 = array.length; if (!defined_default(result)) { result = new Array(length2 / 4); } else { result.length = length2 / 4; } for (let i = 0; i < length2; i += 4) { const index = i / 4; result[index] = _Matrix2.unpack(array, i, result[index]); } return result; } /** * Duplicates a Matrix2 instance. * * @param {Matrix2} matrix The matrix to duplicate. * @param {Matrix2} [result] The object onto which to store the result. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided. (Returns undefined if matrix is undefined) */ static clone(matrix, result) { if (!defined_default(matrix)) { return void 0; } if (!defined_default(result)) { return new _Matrix2(matrix[0], matrix[2], matrix[1], matrix[3]); } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; return result; } /** * Creates a Matrix2 instance from a column-major order array. * * @param {number[]} values The column-major order array. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided. */ static fromColumnMajorArray(values, result) { Check_default.defined("values", values); return _Matrix2.clone(values, result); } /** * Creates a Matrix2 instance from a row-major order array. * The resulting matrix will be in column-major order. * * @param {number[]} values The row-major order array. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided. */ static fromRowMajorArray(values, result) { Check_default.defined("values", values); if (!defined_default(result)) { return new _Matrix2(values[0], values[1], values[2], values[3]); } result[0] = values[0]; result[1] = values[2]; result[2] = values[1]; result[3] = values[3]; return result; } /** * Computes a Matrix2 instance representing a non-uniform scale. * * @param {Cartesian2} scale The x and y scale factors. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided. * * @example * // Creates * // [7.0, 0.0] * // [0.0, 8.0] * const m = Cesium.Matrix2.fromScale(new Cesium.Cartesian2(7.0, 8.0)); */ static fromScale(scale, result) { Check_default.typeOf.object("scale", scale); if (!defined_default(result)) { return new _Matrix2(scale.x, 0, 0, scale.y); } result[0] = scale.x; result[1] = 0; result[2] = 0; result[3] = scale.y; return result; } /** * Computes a Matrix2 instance representing a uniform scale. * * @param {number} scale The uniform scale factor. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided. * * @example * // Creates * // [2.0, 0.0] * // [0.0, 2.0] * const m = Cesium.Matrix2.fromUniformScale(2.0); */ static fromUniformScale(scale, result) { Check_default.typeOf.number("scale", scale); if (!defined_default(result)) { return new _Matrix2(scale, 0, 0, scale); } result[0] = scale; result[1] = 0; result[2] = 0; result[3] = scale; return result; } /** * Creates a rotation matrix. * * @param {number} angle The angle, in radians, of the rotation. Positive angles are counterclockwise. * @param {Matrix2} [result] The object in which the result will be stored, if undefined a new instance will be created. * @returns {Matrix2} The modified result parameter, or a new Matrix2 instance if one was not provided. * * @example * // Rotate a point 45 degrees counterclockwise. * const p = new Cesium.Cartesian2(5, 6); * const m = Cesium.Matrix2.fromRotation(Cesium.Math.toRadians(45.0)); * const rotated = Cesium.Matrix2.multiplyByVector(m, p, new Cesium.Cartesian2()); */ static fromRotation(angle, result) { Check_default.typeOf.number("angle", angle); const cosAngle = Math.cos(angle); const sinAngle = Math.sin(angle); if (!defined_default(result)) { return new _Matrix2(cosAngle, -sinAngle, sinAngle, cosAngle); } result[0] = cosAngle; result[1] = sinAngle; result[2] = -sinAngle; result[3] = cosAngle; return result; } /** * Creates an Array from the provided Matrix2 instance. * The array will be in column-major order. * * @param {Matrix2} matrix The matrix to use.. * @param {number[]} [result] The Array onto which to store the result. * @returns {number[]} The modified Array parameter or a new Array instance if one was not provided. */ static toArray(matrix, result) { Check_default.typeOf.object("matrix", matrix); if (!defined_default(result)) { return [matrix[0], matrix[1], matrix[2], matrix[3]]; } result[0] = matrix[0]; result[1] = matrix[1]; result[2] = matrix[2]; result[3] = matrix[3]; return result; } /** * Computes the array index of the element at the provided row and column. * * @param {number} row The zero-based index of the row. * @param {number} column The zero-based index of the column. * @returns {number} The index of the element at the provided row and column. * * @exception {DeveloperError} row must be 0 or 1. * @exception {DeveloperError} column must be 0 or 1. * * @example * const myMatrix = new Cesium.Matrix2(); * const column1Row0Index = Cesium.Matrix2.getElementIndex(1, 0); * const column1Row0 = myMatrix[column1Row0Index] * myMatrix[column1Row0Index] = 10.0; */ static getElementIndex(column, row) { Check_default.typeOf.number.greaterThanOrEquals("row", row, 0); Check_default.typeOf.number.lessThanOrEquals("row", row, 1); Check_default.typeOf.number.greaterThanOrEquals("column", column, 0); Check_default.typeOf.number.lessThanOrEquals("column", column, 1); return column * 2 + row; } /** * Retrieves a copy of the matrix column at the provided index as a Cartesian2 instance. * * @param {Matrix2} matrix The matrix to use. * @param {number} index The zero-based index of the column to retrieve. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. * * @exception {DeveloperError} index must be 0 or 1. */ static getColumn(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 1); Check_default.typeOf.object("result", result); const startIndex = index * 2; const x = matrix[startIndex]; const y = matrix[startIndex + 1]; result.x = x; result.y = y; return result; } /** * Computes a new matrix that replaces the specified column in the provided matrix with the provided Cartesian2 instance. * * @param {Matrix2} matrix The matrix to use. * @param {number} index The zero-based index of the column to set. * @param {Cartesian2} cartesian The Cartesian whose values will be assigned to the specified column. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @exception {DeveloperError} index must be 0 or 1. */ static setColumn(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 1); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix2.clone(matrix, result); const startIndex = index * 2; result[startIndex] = cartesian11.x; result[startIndex + 1] = cartesian11.y; return result; } /** * Retrieves a copy of the matrix row at the provided index as a Cartesian2 instance. * * @param {Matrix2} matrix The matrix to use. * @param {number} index The zero-based index of the row to retrieve. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. * * @exception {DeveloperError} index must be 0 or 1. */ static getRow(matrix, index, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 1); Check_default.typeOf.object("result", result); const x = matrix[index]; const y = matrix[index + 2]; result.x = x; result.y = y; return result; } /** * Computes a new matrix that replaces the specified row in the provided matrix with the provided Cartesian2 instance. * * @param {Matrix2} matrix The matrix to use. * @param {number} index The zero-based index of the row to set. * @param {Cartesian2} cartesian The Cartesian whose values will be assigned to the specified row. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @exception {DeveloperError} index must be 0 or 1. */ static setRow(matrix, index, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.lessThanOrEquals("index", index, 1); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); result = _Matrix2.clone(matrix, result); result[index] = cartesian11.x; result[index + 2] = cartesian11.y; return result; } /** * Computes a new matrix that replaces the scale with the provided scale. * This assumes the matrix is an affine transformation. * * @param {Matrix2} matrix The matrix to use. * @param {Cartesian2} scale The scale that replaces the scale of the provided matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @see Matrix2.setUniformScale * @see Matrix2.fromScale * @see Matrix2.fromUniformScale * @see Matrix2.multiplyByScale * @see Matrix2.multiplyByUniformScale * @see Matrix2.getScale */ static setScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix2.getScale(matrix, scaleScratch13); const scaleRatioX = scale.x / existingScale.x; const scaleRatioY = scale.y / existingScale.y; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioY; result[3] = matrix[3] * scaleRatioY; return result; } /** * Computes a new matrix that replaces the scale with the provided uniform scale. * This assumes the matrix is an affine transformation. * * @param {Matrix2} matrix The matrix to use. * @param {number} scale The uniform scale that replaces the scale of the provided matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @see Matrix2.setScale * @see Matrix2.fromScale * @see Matrix2.fromUniformScale * @see Matrix2.multiplyByScale * @see Matrix2.multiplyByUniformScale * @see Matrix2.getScale */ static setUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); const existingScale = _Matrix2.getScale(matrix, scaleScratch23); const scaleRatioX = scale / existingScale.x; const scaleRatioY = scale / existingScale.y; result[0] = matrix[0] * scaleRatioX; result[1] = matrix[1] * scaleRatioX; result[2] = matrix[2] * scaleRatioY; result[3] = matrix[3] * scaleRatioY; return result; } /** * Extracts the non-uniform scale assuming the matrix is an affine transformation. * * @param {Matrix2} matrix The matrix. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. * * @see Matrix2.multiplyByScale * @see Matrix2.multiplyByUniformScale * @see Matrix2.fromScale * @see Matrix2.fromUniformScale * @see Matrix2.setScale * @see Matrix2.setUniformScale */ static getScale(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result.x = Cartesian2_default.magnitude( Cartesian2_default.fromElements(matrix[0], matrix[1], scratchColumn3) ); result.y = Cartesian2_default.magnitude( Cartesian2_default.fromElements(matrix[2], matrix[3], scratchColumn3) ); return result; } /** * Computes the maximum scale assuming the matrix is an affine transformation. * The maximum scale is the maximum length of the column vectors. * * @param {Matrix2} matrix The matrix. * @returns {number} The maximum scale. */ static getMaximumScale(matrix) { _Matrix2.getScale(matrix, scaleScratch33); return Cartesian2_default.maximumComponent(scaleScratch33); } /** * Sets the rotation assuming the matrix is an affine transformation. * * @param {Matrix2} matrix The matrix. * @param {Matrix2} rotation The rotation matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @see Matrix2.fromRotation * @see Matrix2.getRotation */ static setRotation(matrix, rotation, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix2.getScale(matrix, scaleScratch43); result[0] = rotation[0] * scale.x; result[1] = rotation[1] * scale.x; result[2] = rotation[2] * scale.y; result[3] = rotation[3] * scale.y; return result; } /** * Extracts the rotation matrix assuming the matrix is an affine transformation. * * @param {Matrix2} matrix The matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @see Matrix2.setRotation * @see Matrix2.fromRotation */ static getRotation(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const scale = _Matrix2.getScale(matrix, scaleScratch53); result[0] = matrix[0] / scale.x; result[1] = matrix[1] / scale.x; result[2] = matrix[2] / scale.y; result[3] = matrix[3] / scale.y; return result; } /** * Computes the product of two matrices. * * @param {Matrix2} left The first matrix. * @param {Matrix2} right The second matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static multiply(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); const column0Row0 = left[0] * right[0] + left[2] * right[1]; const column1Row0 = left[0] * right[2] + left[2] * right[3]; const column0Row1 = left[1] * right[0] + left[3] * right[1]; const column1Row1 = left[1] * right[2] + left[3] * right[3]; result[0] = column0Row0; result[1] = column0Row1; result[2] = column1Row0; result[3] = column1Row1; return result; } /** * Computes the sum of two matrices. * * @param {Matrix2} left The first matrix. * @param {Matrix2} right The second matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static add(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] + right[0]; result[1] = left[1] + right[1]; result[2] = left[2] + right[2]; result[3] = left[3] + right[3]; return result; } /** * Computes the difference of two matrices. * * @param {Matrix2} left The first matrix. * @param {Matrix2} right The second matrix. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static subtract(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); Check_default.typeOf.object("result", result); result[0] = left[0] - right[0]; result[1] = left[1] - right[1]; result[2] = left[2] - right[2]; result[3] = left[3] - right[3]; return result; } /** * Computes the product of a matrix and a column vector. * * @param {Matrix2} matrix The matrix. * @param {Cartesian2} cartesian The column. * @param {Cartesian2} result The object onto which to store the result. * @returns {Cartesian2} The modified result parameter. */ static multiplyByVector(matrix, cartesian11, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("cartesian", cartesian11); Check_default.typeOf.object("result", result); const x = matrix[0] * cartesian11.x + matrix[2] * cartesian11.y; const y = matrix[1] * cartesian11.x + matrix[3] * cartesian11.y; result.x = x; result.y = y; return result; } /** * Computes the product of a matrix and a scalar. * * @param {Matrix2} matrix The matrix. * @param {number} scalar The number to multiply by. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static multiplyByScalar(matrix, scalar, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scalar", scalar); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scalar; result[1] = matrix[1] * scalar; result[2] = matrix[2] * scalar; result[3] = matrix[3] * scalar; return result; } /** * Computes the product of a matrix times a (non-uniform) scale, as if the scale were a scale matrix. * * @param {Matrix2} matrix The matrix on the left-hand side. * @param {Cartesian2} scale The non-uniform scale on the right-hand side. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * * @example * // Instead of Cesium.Matrix2.multiply(m, Cesium.Matrix2.fromScale(scale), m); * Cesium.Matrix2.multiplyByScale(m, scale, m); * * @see Matrix2.multiplyByUniformScale * @see Matrix2.fromScale * @see Matrix2.fromUniformScale * @see Matrix2.setScale * @see Matrix2.setUniformScale * @see Matrix2.getScale */ static multiplyByScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("scale", scale); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scale.x; result[1] = matrix[1] * scale.x; result[2] = matrix[2] * scale.y; result[3] = matrix[3] * scale.y; return result; } /** * Computes the product of a matrix times a uniform scale, as if the scale were a scale matrix. * * @param {Matrix2} matrix The matrix on the left-hand side. * @param {number} scale The uniform scale on the right-hand side. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. * * @example * // Instead of Cesium.Matrix2.multiply(m, Cesium.Matrix2.fromUniformScale(scale), m); * Cesium.Matrix2.multiplyByUniformScale(m, scale, m); * * @see Matrix2.multiplyByScale * @see Matrix2.fromScale * @see Matrix2.fromUniformScale * @see Matrix2.setScale * @see Matrix2.setUniformScale * @see Matrix2.getScale */ static multiplyByUniformScale(matrix, scale, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.number("scale", scale); Check_default.typeOf.object("result", result); result[0] = matrix[0] * scale; result[1] = matrix[1] * scale; result[2] = matrix[2] * scale; result[3] = matrix[3] * scale; return result; } /** * Creates a negated copy of the provided matrix. * * @param {Matrix2} matrix The matrix to negate. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static negate(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = -matrix[0]; result[1] = -matrix[1]; result[2] = -matrix[2]; result[3] = -matrix[3]; return result; } /** * Computes the transpose of the provided matrix. * * @param {Matrix2} matrix The matrix to transpose. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static transpose(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); const column0Row0 = matrix[0]; const column0Row1 = matrix[2]; const column1Row0 = matrix[1]; const column1Row1 = matrix[3]; result[0] = column0Row0; result[1] = column0Row1; result[2] = column1Row0; result[3] = column1Row1; return result; } /** * Computes a matrix, which contains the absolute (unsigned) values of the provided matrix's elements. * * @param {Matrix2} matrix The matrix with signed elements. * @param {Matrix2} result The object onto which to store the result. * @returns {Matrix2} The modified result parameter. */ static abs(matrix, result) { Check_default.typeOf.object("matrix", matrix); Check_default.typeOf.object("result", result); result[0] = Math.abs(matrix[0]); result[1] = Math.abs(matrix[1]); result[2] = Math.abs(matrix[2]); result[3] = Math.abs(matrix[3]); return result; } /** * Compares the provided matrices componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix2} [left] The first matrix. * @param {Matrix2} [right] The second matrix. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && left[0] === right[0] && left[1] === right[1] && left[2] === right[2] && left[3] === right[3]; } /** * Compares provided matrix and array, starting from a given array offset. * * @param {Matrix2} matrix * @param {number[]} array * @param {number} offset * @ignore */ static equalsArray(matrix, array, offset) { return matrix[0] === array[offset] && matrix[1] === array[offset + 1] && matrix[2] === array[offset + 2] && matrix[3] === array[offset + 3]; } /** * Compares the provided matrices componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix2} [left] The first matrix. * @param {Matrix2} [right] The second matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if left and right are within the provided epsilon, false otherwise. */ static equalsEpsilon(left, right, epsilon) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && Math.abs(left[0] - right[0]) <= epsilon && Math.abs(left[1] - right[1]) <= epsilon && Math.abs(left[2] - right[2]) <= epsilon && Math.abs(left[3] - right[3]) <= epsilon; } /** * Gets the number of items in the collection. * * @type {number} */ get length() { return _Matrix2.packedLength; } /** * Duplicates the provided Matrix2 instance. * * @param {Matrix2} [result] The object onto which to store the result. * @returns {Matrix2} The modified result parameter or a new Matrix2 instance if one was not provided. */ clone(result) { return _Matrix2.clone(this, result); } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are equal, false otherwise. * * @param {Matrix2} [right] The right hand side matrix. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _Matrix2.equals(this, right); } /** * Compares this matrix to the provided matrix componentwise and returns * true if they are within the provided epsilon, * false otherwise. * * @param {Matrix2} [right] The right hand side matrix. * @param {number} [epsilon=0] The epsilon to use for equality testing. * @returns {boolean} true if they are within the provided epsilon, false otherwise. */ equalsEpsilon(right, epsilon) { return _Matrix2.equalsEpsilon(this, right, epsilon); } /** * Creates a string representing this Matrix with each row being * on a separate line and in the format '(column0, column1)'. * * @returns {string} A string representing the provided Matrix with each row being on a separate line and in the format '(column0, column1)'. */ toString() { return `(${this[0]}, ${this[2]}) (${this[1]}, ${this[3]})`; } }; Matrix2.packedLength = 4; Matrix2.fromArray = Matrix2.unpack; Matrix2.IDENTITY = Object.freeze(new Matrix2(1, 0, 0, 1)); Matrix2.ZERO = Object.freeze(new Matrix2(0, 0, 0, 0)); Matrix2.COLUMN0ROW0 = 0; Matrix2.COLUMN0ROW1 = 1; Matrix2.COLUMN1ROW0 = 2; Matrix2.COLUMN1ROW1 = 3; var scaleScratch13 = new Cartesian2_default(); var scaleScratch23 = new Cartesian2_default(); var scratchColumn3 = new Cartesian2_default(); var scaleScratch33 = new Cartesian2_default(); var scaleScratch43 = new Cartesian2_default(); var scaleScratch53 = new Cartesian2_default(); var Matrix2_default = Matrix2; // packages/engine/Source/Renderer/createUniform.js function createUniform(gl, activeUniform, uniformName, location2) { switch (activeUniform.type) { case gl.FLOAT: return new UniformFloat(gl, activeUniform, uniformName, location2); case gl.FLOAT_VEC2: return new UniformFloatVec2(gl, activeUniform, uniformName, location2); case gl.FLOAT_VEC3: return new UniformFloatVec3(gl, activeUniform, uniformName, location2); case gl.FLOAT_VEC4: return new UniformFloatVec4(gl, activeUniform, uniformName, location2); case gl.SAMPLER_2D: case gl.SAMPLER_3D: case gl.SAMPLER_CUBE: return new UniformSampler(gl, activeUniform, uniformName, location2); case gl.UNSIGNED_INT_SAMPLER_2D: return new UniformSampler(gl, activeUniform, uniformName, location2); case gl.INT: case gl.BOOL: return new UniformInt(gl, activeUniform, uniformName, location2); case gl.INT_VEC2: case gl.BOOL_VEC2: return new UniformIntVec2(gl, activeUniform, uniformName, location2); case gl.INT_VEC3: case gl.BOOL_VEC3: return new UniformIntVec3(gl, activeUniform, uniformName, location2); case gl.INT_VEC4: case gl.BOOL_VEC4: return new UniformIntVec4(gl, activeUniform, uniformName, location2); case gl.FLOAT_MAT2: return new UniformMat2(gl, activeUniform, uniformName, location2); case gl.FLOAT_MAT3: return new UniformMat3(gl, activeUniform, uniformName, location2); case gl.FLOAT_MAT4: return new UniformMat4(gl, activeUniform, uniformName, location2); default: throw new RuntimeError_default( `Unrecognized uniform type: ${activeUniform.type} for uniform "${uniformName}".` ); } } var UniformFloat = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = 0; this._gl = gl; this._location = location2; } set() { if (this.value !== this._value) { this._value = this.value; this._gl.uniform1f(this._location, this.value); } } }; var UniformFloatVec2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Cartesian2_default(); this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (!Cartesian2_default.equals(v3, this._value)) { Cartesian2_default.clone(v3, this._value); this._gl.uniform2f(this._location, v3.x, v3.y); } } }; var UniformFloatVec3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = void 0; this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (defined_default(v3.red)) { if (!Color_default.equals(v3, this._value)) { this._value = Color_default.clone(v3, this._value); this._gl.uniform3f(this._location, v3.red, v3.green, v3.blue); } } else if (defined_default(v3.x)) { if (!Cartesian3_default.equals(v3, this._value)) { this._value = Cartesian3_default.clone(v3, this._value); this._gl.uniform3f(this._location, v3.x, v3.y, v3.z); } } else { throw new DeveloperError_default( `Invalid vec3 value for uniform "${this.name}".` ); } } }; var UniformFloatVec4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = void 0; this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (defined_default(v3.red)) { if (!Color_default.equals(v3, this._value)) { this._value = Color_default.clone(v3, this._value); this._gl.uniform4f(this._location, v3.red, v3.green, v3.blue, v3.alpha); } } else if (defined_default(v3.x)) { if (!Cartesian4_default.equals(v3, this._value)) { this._value = Cartesian4_default.clone(v3, this._value); this._gl.uniform4f(this._location, v3.x, v3.y, v3.z, v3.w); } } else { throw new DeveloperError_default( `Invalid vec4 value for uniform "${this.name}".` ); } } }; var UniformSampler = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._gl = gl; this._location = location2; this.textureUnitIndex = void 0; } set() { const gl = this._gl; gl.activeTexture(gl.TEXTURE0 + this.textureUnitIndex); const v3 = this.value; gl.bindTexture(v3._target, v3._texture); } /** * @param {number} textureUnitIndex * @returns {number} */ _setSampler(textureUnitIndex) { this.textureUnitIndex = textureUnitIndex; this._gl.uniform1i(this._location, textureUnitIndex); return textureUnitIndex + 1; } }; var UniformInt = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = 0; this._gl = gl; this._location = location2; } set() { if (this.value !== this._value) { this._value = this.value; this._gl.uniform1i(this._location, this.value); } } }; var UniformIntVec2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Cartesian2_default(); this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (!Cartesian2_default.equals(v3, this._value)) { Cartesian2_default.clone(v3, this._value); this._gl.uniform2i(this._location, v3.x, v3.y); } } }; var UniformIntVec3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Cartesian3_default(); this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (!Cartesian3_default.equals(v3, this._value)) { Cartesian3_default.clone(v3, this._value); this._gl.uniform3i(this._location, v3.x, v3.y, v3.z); } } }; var UniformIntVec4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Cartesian4_default(); this._gl = gl; this._location = location2; } set() { const v3 = this.value; if (!Cartesian4_default.equals(v3, this._value)) { Cartesian4_default.clone(v3, this._value); this._gl.uniform4i(this._location, v3.x, v3.y, v3.z, v3.w); } } }; var scratchUniformArray = new Float32Array(4); var UniformMat2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Matrix2_default(); this._gl = gl; this._location = location2; } set() { if (!Matrix2_default.equalsArray(this.value, this._value, 0)) { Matrix2_default.clone(this.value, this._value); const array = Matrix2_default.toArray(this.value, scratchUniformArray); this._gl.uniformMatrix2fv(this._location, false, array); } } }; var scratchMat3Array = new Float32Array(9); var UniformMat3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Matrix3_default(); this._gl = gl; this._location = location2; } set() { if (!Matrix3_default.equalsArray(this.value, this._value, 0)) { Matrix3_default.clone(this.value, this._value); const array = Matrix3_default.toArray(this.value, scratchMat3Array); this._gl.uniformMatrix3fv(this._location, false, array); } } }; var scratchMat4Array = new Float32Array(16); var UniformMat4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation} location */ constructor(gl, activeUniform, uniformName, location2) { this.name = uniformName; this.value = void 0; this._value = new Matrix4_default(); this._gl = gl; this._location = location2; } set() { if (!Matrix4_default.equalsArray(this.value, this._value, 0)) { Matrix4_default.clone(this.value, this._value); const array = Matrix4_default.toArray(this.value, scratchMat4Array); this._gl.uniformMatrix4fv(this._location, false, array); } } }; var createUniform_default = createUniform; // packages/engine/Source/Renderer/createUniformArray.js var import_InlineWorkers83 = __toESM(require_InlineWorkers(), 1); function createUniformArray(gl, activeUniform, uniformName, locations) { switch (activeUniform.type) { case gl.FLOAT: return new UniformArrayFloat(gl, activeUniform, uniformName, locations); case gl.FLOAT_VEC2: return new UniformArrayFloatVec2( gl, activeUniform, uniformName, locations ); case gl.FLOAT_VEC3: return new UniformArrayFloatVec3( gl, activeUniform, uniformName, locations ); case gl.FLOAT_VEC4: return new UniformArrayFloatVec4( gl, activeUniform, uniformName, locations ); case gl.SAMPLER_2D: case gl.SAMPLER_3D: case gl.SAMPLER_CUBE: return new UniformArraySampler(gl, activeUniform, uniformName, locations); case gl.INT: case gl.BOOL: return new UniformArrayInt(gl, activeUniform, uniformName, locations); case gl.INT_VEC2: case gl.BOOL_VEC2: return new UniformArrayIntVec2(gl, activeUniform, uniformName, locations); case gl.INT_VEC3: case gl.BOOL_VEC3: return new UniformArrayIntVec3(gl, activeUniform, uniformName, locations); case gl.INT_VEC4: case gl.BOOL_VEC4: return new UniformArrayIntVec4(gl, activeUniform, uniformName, locations); case gl.FLOAT_MAT2: return new UniformArrayMat2(gl, activeUniform, uniformName, locations); case gl.FLOAT_MAT3: return new UniformArrayMat3(gl, activeUniform, uniformName, locations); case gl.FLOAT_MAT4: return new UniformArrayMat4(gl, activeUniform, uniformName, locations); default: throw new RuntimeError_default( `Unrecognized uniform type: ${activeUniform.type} for uniform "${uniformName}".` ); } } var UniformArrayFloat = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (v3 !== arraybuffer[i]) { arraybuffer[i] = v3; changed = true; } } if (changed) { this._gl.uniform1fv(this._location, arraybuffer); } } }; var UniformArrayFloatVec2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 2); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Cartesian2_default.equalsArray(v3, arraybuffer, j)) { Cartesian2_default.pack(v3, arraybuffer, j); changed = true; } j += 2; } if (changed) { this._gl.uniform2fv(this._location, arraybuffer); } } }; var UniformArrayFloatVec3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 3); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (defined_default(v3.red)) { if (v3.red !== arraybuffer[j] || v3.green !== arraybuffer[j + 1] || v3.blue !== arraybuffer[j + 2]) { arraybuffer[j] = v3.red; arraybuffer[j + 1] = v3.green; arraybuffer[j + 2] = v3.blue; changed = true; } } else if (defined_default(v3.x)) { if (!Cartesian3_default.equalsArray(v3, arraybuffer, j)) { Cartesian3_default.pack(v3, arraybuffer, j); changed = true; } } else { throw new DeveloperError_default("Invalid vec3 value."); } j += 3; } if (changed) { this._gl.uniform3fv(this._location, arraybuffer); } } }; var UniformArrayFloatVec4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 4); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (defined_default(v3.red)) { if (!Color_default.equalsArray(v3, arraybuffer, j)) { Color_default.pack(v3, arraybuffer, j); changed = true; } } else if (defined_default(v3.x)) { if (!Cartesian4_default.equalsArray(v3, arraybuffer, j)) { Cartesian4_default.pack(v3, arraybuffer, j); changed = true; } } else { throw new DeveloperError_default("Invalid vec4 value."); } j += 4; } if (changed) { this._gl.uniform4fv(this._location, arraybuffer); } } }; var UniformArraySampler = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2); this._gl = gl; this._locations = locations; this.textureUnitIndex = void 0; } set() { const gl = this._gl; const textureUnitIndex = gl.TEXTURE0 + this.textureUnitIndex; const value = this.value; const length2 = value.length; for (let i = 0; i < length2; ++i) { const v3 = value[i]; gl.activeTexture(textureUnitIndex + i); gl.bindTexture(v3._target, v3._texture); } } /** * @param {number} textureUnitIndex * @returns {number} */ _setSampler(textureUnitIndex) { this.textureUnitIndex = textureUnitIndex; const locations = this._locations; const length2 = locations.length; for (let i = 0; i < length2; ++i) { const index = textureUnitIndex + i; this._gl.uniform1i(locations[i], index); } return textureUnitIndex + length2; } }; var UniformArrayInt = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Int32Array(length2); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (v3 !== arraybuffer[i]) { arraybuffer[i] = v3; changed = true; } } if (changed) { this._gl.uniform1iv(this._location, arraybuffer); } } }; var UniformArrayIntVec2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Int32Array(length2 * 2); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Cartesian2_default.equalsArray(v3, arraybuffer, j)) { Cartesian2_default.pack(v3, arraybuffer, j); changed = true; } j += 2; } if (changed) { this._gl.uniform2iv(this._location, arraybuffer); } } }; var UniformArrayIntVec3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Int32Array(length2 * 3); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Cartesian3_default.equalsArray(v3, arraybuffer, j)) { Cartesian3_default.pack(v3, arraybuffer, j); changed = true; } j += 3; } if (changed) { this._gl.uniform3iv(this._location, arraybuffer); } } }; var UniformArrayIntVec4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Int32Array(length2 * 4); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Cartesian4_default.equalsArray(v3, arraybuffer, j)) { Cartesian4_default.pack(v3, arraybuffer, j); changed = true; } j += 4; } if (changed) { this._gl.uniform4iv(this._location, arraybuffer); } } }; var UniformArrayMat2 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 4); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Matrix2_default.equalsArray(v3, arraybuffer, j)) { Matrix2_default.pack(v3, arraybuffer, j); changed = true; } j += 4; } if (changed) { this._gl.uniformMatrix2fv(this._location, false, arraybuffer); } } }; var UniformArrayMat3 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 9); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Matrix3_default.equalsArray(v3, arraybuffer, j)) { Matrix3_default.pack(v3, arraybuffer, j); changed = true; } j += 9; } if (changed) { this._gl.uniformMatrix3fv(this._location, false, arraybuffer); } } }; var UniformArrayMat4 = class { /** * @param {WebGL2RenderingContext} gl * @param {WebGLActiveInfo} activeUniform * @param {string} uniformName * @param {WebGLUniformLocation[]} locations */ constructor(gl, activeUniform, uniformName, locations) { const length2 = locations.length; this.name = uniformName; this.value = new Array(length2); this._value = new Float32Array(length2 * 16); this._gl = gl; this._location = locations[0]; } set() { const value = this.value; const length2 = value.length; const arraybuffer = this._value; let changed = false; let j = 0; for (let i = 0; i < length2; ++i) { const v3 = value[i]; if (!Matrix4_default.equalsArray(v3, arraybuffer, j)) { Matrix4_default.pack(v3, arraybuffer, j); changed = true; } j += 16; } if (changed) { this._gl.uniformMatrix4fv(this._location, false, arraybuffer); } } }; var createUniformArray_default = createUniformArray; // packages/engine/Source/Renderer/ShaderProgram.js var nextShaderProgramId = 0; function ShaderProgram(options) { let vertexShaderText = options.vertexShaderText; let fragmentShaderText = options.fragmentShaderText; if (typeof spector !== "undefined") { vertexShaderText = vertexShaderText.replace(/^#line/gm, "//#line"); fragmentShaderText = fragmentShaderText.replace(/^#line/gm, "//#line"); } const modifiedFS = handleUniformPrecisionMismatches( vertexShaderText, fragmentShaderText ); this._gl = options.gl; this._logShaderCompilation = options.logShaderCompilation; this._debugShaders = options.debugShaders; this._attributeLocations = options.attributeLocations; this._program = void 0; this._numberOfVertexAttributes = void 0; this._vertexAttributes = void 0; this._uniformsByName = void 0; this._uniforms = void 0; this._automaticUniforms = void 0; this._manualUniforms = void 0; this._duplicateUniformNames = modifiedFS.duplicateUniformNames; this._cachedShader = void 0; this.maximumTextureUnitIndex = void 0; this._vertexShaderSource = options.vertexShaderSource; this._vertexShaderText = options.vertexShaderText; this._fragmentShaderSource = options.fragmentShaderSource; this._fragmentShaderText = modifiedFS.fragmentShaderText; this.id = nextShaderProgramId++; } ShaderProgram.fromCache = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); return options.context.shaderCache.getShaderProgram(options); }; ShaderProgram.replaceCache = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); return options.context.shaderCache.replaceShaderProgram(options); }; Object.defineProperties(ShaderProgram.prototype, { /** * GLSL source for the shader program's vertex shader. * @memberof ShaderProgram.prototype * * @type {ShaderSource} * @readonly */ vertexShaderSource: { get: function() { return this._vertexShaderSource; } }, /** * GLSL source for the shader program's fragment shader. * @memberof ShaderProgram.prototype * * @type {ShaderSource} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, vertexAttributes: { get: function() { initialize2(this); return this._vertexAttributes; } }, numberOfVertexAttributes: { get: function() { initialize2(this); return this._numberOfVertexAttributes; } }, allUniforms: { get: function() { initialize2(this); return this._uniformsByName; } } }); function extractUniforms(shaderText) { const uniformNames = []; const uniformLines = shaderText.match(/uniform.*?(?![^{]*})(?=[=\[;])/g); if (defined_default(uniformLines)) { const len = uniformLines.length; for (let i = 0; i < len; i++) { const line = uniformLines[i].trim(); const name = line.slice(line.lastIndexOf(" ") + 1); uniformNames.push(name); } } return uniformNames; } function handleUniformPrecisionMismatches(vertexShaderText, fragmentShaderText) { const duplicateUniformNames = {}; if (!ContextLimits_default.highpFloatSupported || !ContextLimits_default.highpIntSupported) { let i, j; let uniformName; let duplicateName; const vertexShaderUniforms = extractUniforms(vertexShaderText); const fragmentShaderUniforms = extractUniforms(fragmentShaderText); const vertexUniformsCount = vertexShaderUniforms.length; const fragmentUniformsCount = fragmentShaderUniforms.length; for (i = 0; i < vertexUniformsCount; i++) { for (j = 0; j < fragmentUniformsCount; j++) { if (vertexShaderUniforms[i] === fragmentShaderUniforms[j]) { uniformName = vertexShaderUniforms[i]; duplicateName = `czm_mediump_${uniformName}`; const re = new RegExp(`${uniformName}\\b`, "g"); fragmentShaderText = fragmentShaderText.replace(re, duplicateName); duplicateUniformNames[duplicateName] = uniformName; } } } } return { fragmentShaderText, duplicateUniformNames }; } var consolePrefix = "[Cesium WebGL] "; function createAndLinkProgram(gl, shader) { const vsSource = shader._vertexShaderText; const fsSource = shader._fragmentShaderText; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vsSource); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fsSource); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); const attributeLocations8 = shader._attributeLocations; if (defined_default(attributeLocations8)) { for (const attribute in attributeLocations8) { if (attributeLocations8.hasOwnProperty(attribute)) { gl.bindAttribLocation( program, attributeLocations8[attribute], attribute ); } } } gl.linkProgram(program); let log; if (gl.getProgramParameter(program, gl.LINK_STATUS)) { if (shader._logShaderCompilation) { log = gl.getShaderInfoLog(vertexShader); if (defined_default(log) && log.length > 0) { console.log(`${consolePrefix}Vertex shader compile log: ${log}`); } log = gl.getShaderInfoLog(fragmentShader); if (defined_default(log) && log.length > 0) { console.log(`${consolePrefix}Fragment shader compile log: ${log}`); } log = gl.getProgramInfoLog(program); if (defined_default(log) && log.length > 0) { console.log(`${consolePrefix}Shader program link log: ${log}`); } } gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); return program; } let errorMessage; const debugShaders = shader._debugShaders; if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { log = gl.getShaderInfoLog(fragmentShader); console.error(`${consolePrefix}Fragment shader compile log: ${log}`); console.error(`${consolePrefix} Fragment shader source: ${fsSource}`); errorMessage = `Fragment shader failed to compile. Compile log: ${log}`; } else if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { log = gl.getShaderInfoLog(vertexShader); console.error(`${consolePrefix}Vertex shader compile log: ${log}`); console.error(`${consolePrefix} Vertex shader source: ${vsSource}`); errorMessage = `Vertex shader failed to compile. Compile log: ${log}`; } else { log = gl.getProgramInfoLog(program); console.error(`${consolePrefix}Shader program link log: ${log}`); logTranslatedSource(vertexShader, "vertex"); logTranslatedSource(fragmentShader, "fragment"); errorMessage = `Program failed to link. Link log: ${log}`; } gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); gl.deleteProgram(program); throw new RuntimeError_default(errorMessage); function logTranslatedSource(compiledShader, name) { if (!defined_default(debugShaders)) { return; } const translation3 = debugShaders.getTranslatedShaderSource(compiledShader); if (translation3 === "") { console.error(`${consolePrefix}${name} shader translation failed.`); return; } console.error( `${consolePrefix}Translated ${name} shaderSource: ${translation3}` ); } } function findVertexAttributes(gl, program, numberOfAttributes2) { const attributes = {}; for (let i = 0; i < numberOfAttributes2; ++i) { const attr = gl.getActiveAttrib(program, i); const location2 = gl.getAttribLocation(program, attr.name); attributes[attr.name] = { name: attr.name, type: attr.type, index: location2 }; } return attributes; } function findUniforms(gl, program) { const uniformsByName = {}; const uniforms = []; const samplerUniforms = []; const numberOfUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); for (let i = 0; i < numberOfUniforms; ++i) { const activeUniform = gl.getActiveUniform(program, i); const suffix = "[0]"; const uniformName = activeUniform.name.indexOf( suffix, activeUniform.name.length - suffix.length ) !== -1 ? activeUniform.name.slice(0, activeUniform.name.length - 3) : activeUniform.name; if (uniformName.indexOf("gl_") !== 0) { if (activeUniform.name.indexOf("[") < 0) { const location2 = gl.getUniformLocation(program, uniformName); if (location2 !== null) { const uniform = createUniform_default( gl, activeUniform, uniformName, location2 ); uniformsByName[uniformName] = uniform; uniforms.push(uniform); if (uniform._setSampler) { samplerUniforms.push(uniform); } } } else { let uniformArray; let locations; let value; let loc; const indexOfBracket = uniformName.indexOf("["); if (indexOfBracket >= 0) { uniformArray = uniformsByName[uniformName.slice(0, indexOfBracket)]; if (!defined_default(uniformArray)) { continue; } locations = uniformArray._locations; if (locations.length <= 1) { value = uniformArray.value; loc = gl.getUniformLocation(program, uniformName); if (loc !== null) { locations.push(loc); value.push(gl.getUniform(program, loc)); } } } else { locations = []; for (let j = 0; j < activeUniform.size; ++j) { loc = gl.getUniformLocation(program, `${uniformName}[${j}]`); if (loc !== null) { locations.push(loc); } } uniformArray = createUniformArray_default( gl, activeUniform, uniformName, locations ); uniformsByName[uniformName] = uniformArray; uniforms.push(uniformArray); if (uniformArray._setSampler) { samplerUniforms.push(uniformArray); } } } } } return { uniformsByName, uniforms, samplerUniforms }; } function partitionUniforms(shader, uniforms) { const automaticUniforms = []; const manualUniforms = []; for (const uniform in uniforms) { if (uniforms.hasOwnProperty(uniform)) { const uniformObject = uniforms[uniform]; let uniformName = uniform; const duplicateUniform = shader._duplicateUniformNames[uniformName]; if (defined_default(duplicateUniform)) { uniformObject.name = duplicateUniform; uniformName = duplicateUniform; } const automaticUniform = AutomaticUniforms_default[uniformName]; if (defined_default(automaticUniform)) { automaticUniforms.push({ uniform: uniformObject, automaticUniform }); } else { manualUniforms.push(uniformObject); } } } return { automaticUniforms, manualUniforms }; } function setSamplerUniforms(gl, program, samplerUniforms) { gl.useProgram(program); let textureUnitIndex = 0; const length2 = samplerUniforms.length; for (let i = 0; i < length2; ++i) { textureUnitIndex = samplerUniforms[i]._setSampler(textureUnitIndex); } gl.useProgram(null); return textureUnitIndex; } function initialize2(shader) { if (defined_default(shader._program)) { return; } reinitialize(shader); } function reinitialize(shader) { const oldProgram = shader._program; const gl = shader._gl; const program = createAndLinkProgram(gl, shader, shader._debugShaders); const numberOfVertexAttributes = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); const uniforms = findUniforms(gl, program); const partitionedUniforms = partitionUniforms( shader, uniforms.uniformsByName ); shader._program = program; shader._numberOfVertexAttributes = numberOfVertexAttributes; shader._vertexAttributes = findVertexAttributes( gl, program, numberOfVertexAttributes ); shader._uniformsByName = uniforms.uniformsByName; shader._uniforms = uniforms.uniforms; shader._automaticUniforms = partitionedUniforms.automaticUniforms; shader._manualUniforms = partitionedUniforms.manualUniforms; shader.maximumTextureUnitIndex = setSamplerUniforms( gl, program, uniforms.samplerUniforms ); if (oldProgram) { shader._gl.deleteProgram(oldProgram); } if (typeof spector !== "undefined") { shader._program.__SPECTOR_rebuildProgram = function(vertexSourceCode, fragmentSourceCode, onCompiled, onError) { const originalVS = shader._vertexShaderText; const originalFS = shader._fragmentShaderText; const regex = / ! = /g; shader._vertexShaderText = vertexSourceCode.replace(regex, " != "); shader._fragmentShaderText = fragmentSourceCode.replace(regex, " != "); try { reinitialize(shader); onCompiled(shader._program); } catch (e) { shader._vertexShaderText = originalVS; shader._fragmentShaderText = originalFS; const errorMatcher = /(?:Compile|Link) error: ([^]*)/; const match = errorMatcher.exec(e.message); if (match) { onError(match[1]); } else { onError(e.message); } } }; } } ShaderProgram.prototype._bind = function() { initialize2(this); this._gl.useProgram(this._program); }; ShaderProgram.prototype._setUniforms = function(uniformMap2, uniformState, validate2) { let len; let i; if (defined_default(uniformMap2)) { const manualUniforms = this._manualUniforms; len = manualUniforms.length; for (i = 0; i < len; ++i) { const mu = manualUniforms[i]; if (!defined_default(uniformMap2[mu.name])) { throw new DeveloperError_default(`Unknown uniform: ${mu.name}`); } mu.value = uniformMap2[mu.name](); } } const automaticUniforms = this._automaticUniforms; len = automaticUniforms.length; for (i = 0; i < len; ++i) { const au = automaticUniforms[i]; au.uniform.value = au.automaticUniform.getValue(uniformState); } const uniforms = this._uniforms; len = uniforms.length; for (i = 0; i < len; ++i) { uniforms[i].set(); } if (validate2) { const gl = this._gl; const program = this._program; gl.validateProgram(program); if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) { throw new DeveloperError_default( `Program validation failed. Program info log: ${gl.getProgramInfoLog( program )}` ); } } }; ShaderProgram.prototype.isDestroyed = function() { return false; }; ShaderProgram.prototype.destroy = function() { this._cachedShader.cache.releaseShaderProgram(this); return void 0; }; ShaderProgram.prototype.finalDestroy = function() { this._gl.deleteProgram(this._program); return destroyObject_default(this); }; var ShaderProgram_default = ShaderProgram; // packages/engine/Source/Renderer/ComputeEngine.js function ComputeEngine(context) { this._context = context; } var renderStateScratch; var drawCommandScratch = new DrawCommand_default({ primitiveType: PrimitiveType_default.TRIANGLES }); var clearCommandScratch = new ClearCommand_default({ color: new Color_default(0, 0, 0, 0) }); function createFramebuffer(context, outputTexture) { return new Framebuffer_default({ context, colorTextures: [outputTexture], destroyAttachments: false }); } function createViewportQuadShader(context, fragmentShaderSource) { return ShaderProgram_default.fromCache({ context, vertexShaderSource: ViewportQuadVS_default, fragmentShaderSource, attributeLocations: { position: 0, textureCoordinates: 1 } }); } function createRenderState(width, height) { if (!defined_default(renderStateScratch) || renderStateScratch.viewport.width !== width || renderStateScratch.viewport.height !== height) { renderStateScratch = RenderState_default.fromCache({ viewport: new BoundingRectangle_default(0, 0, width, height) }); } return renderStateScratch; } ComputeEngine.prototype.execute = function(computeCommand) { Check_default.defined("computeCommand", computeCommand); if (defined_default(computeCommand.preExecute)) { computeCommand.preExecute(computeCommand); } if (!defined_default(computeCommand.fragmentShaderSource) && !defined_default(computeCommand.shaderProgram)) { throw new DeveloperError_default( "computeCommand.fragmentShaderSource or computeCommand.shaderProgram is required." ); } Check_default.defined("computeCommand.outputTexture", computeCommand.outputTexture); const outputTexture = computeCommand.outputTexture; const width = outputTexture.width; const height = outputTexture.height; const context = this._context; const vertexArray = defined_default(computeCommand.vertexArray) ? computeCommand.vertexArray : context.getViewportQuadVertexArray(); const shaderProgram = defined_default(computeCommand.shaderProgram) ? computeCommand.shaderProgram : createViewportQuadShader(context, computeCommand.fragmentShaderSource); const framebuffer = createFramebuffer(context, outputTexture); const renderState = createRenderState(width, height); const uniformMap2 = computeCommand.uniformMap; const clearCommand = clearCommandScratch; clearCommand.framebuffer = framebuffer; clearCommand.renderState = renderState; clearCommand.execute(context); const drawCommand = drawCommandScratch; drawCommand.vertexArray = vertexArray; drawCommand.renderState = renderState; drawCommand.shaderProgram = shaderProgram; drawCommand.uniformMap = uniformMap2; drawCommand.framebuffer = framebuffer; drawCommand.execute(context); framebuffer.destroy(); if (!computeCommand.persists) { shaderProgram.destroy(); if (defined_default(computeCommand.vertexArray)) { vertexArray.destroy(); } } if (defined_default(computeCommand.postExecute)) { computeCommand.postExecute(outputTexture); } }; ComputeEngine.prototype.isDestroyed = function() { return false; }; ComputeEngine.prototype.destroy = function() { return destroyObject_default(this); }; var ComputeEngine_default = ComputeEngine; // packages/engine/Source/Renderer/Context.js var import_InlineWorkers279 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/ComponentDatatype.js var import_InlineWorkers86 = __toESM(require_InlineWorkers(), 1); var ComponentDatatype = { /** * 8-bit signed byte corresponding to gl.BYTE and the type * of an element in Int8Array. * * @type {number} * @constant */ BYTE: WebGLConstants_default.BYTE, /** * 8-bit unsigned byte corresponding to UNSIGNED_BYTE and the type * of an element in Uint8Array. * * @type {number} * @constant */ UNSIGNED_BYTE: WebGLConstants_default.UNSIGNED_BYTE, /** * 16-bit signed short corresponding to SHORT and the type * of an element in Int16Array. * * @type {number} * @constant */ SHORT: WebGLConstants_default.SHORT, /** * 16-bit unsigned short corresponding to UNSIGNED_SHORT and the type * of an element in Uint16Array. * * @type {number} * @constant */ UNSIGNED_SHORT: WebGLConstants_default.UNSIGNED_SHORT, /** * 32-bit signed int corresponding to INT and the type * of an element in Int32Array. * * @memberOf ComponentDatatype * * @type {number} * @constant */ INT: WebGLConstants_default.INT, /** * 32-bit unsigned int corresponding to UNSIGNED_INT and the type * of an element in Uint32Array. * * @memberOf ComponentDatatype * * @type {number} * @constant */ UNSIGNED_INT: WebGLConstants_default.UNSIGNED_INT, /** * 32-bit floating-point corresponding to FLOAT and the type * of an element in Float32Array. * * @type {number} * @constant */ FLOAT: WebGLConstants_default.FLOAT, /** * 64-bit floating-point corresponding to gl.DOUBLE (in Desktop OpenGL; * this is not supported in WebGL, and is emulated in Cesium via {@link GeometryPipeline.encodeAttribute}) * and the type of an element in Float64Array. * * @memberOf ComponentDatatype * * @type {number} * @constant * @default 0x140A */ DOUBLE: WebGLConstants_default.DOUBLE }; ComponentDatatype.getSizeInBytes = function(componentDatatype) { if (!defined_default(componentDatatype)) { throw new DeveloperError_default("value is required."); } switch (componentDatatype) { case ComponentDatatype.BYTE: return Int8Array.BYTES_PER_ELEMENT; case ComponentDatatype.UNSIGNED_BYTE: return Uint8Array.BYTES_PER_ELEMENT; case ComponentDatatype.SHORT: return Int16Array.BYTES_PER_ELEMENT; case ComponentDatatype.UNSIGNED_SHORT: return Uint16Array.BYTES_PER_ELEMENT; case ComponentDatatype.INT: return Int32Array.BYTES_PER_ELEMENT; case ComponentDatatype.UNSIGNED_INT: return Uint32Array.BYTES_PER_ELEMENT; case ComponentDatatype.FLOAT: return Float32Array.BYTES_PER_ELEMENT; case ComponentDatatype.DOUBLE: return Float64Array.BYTES_PER_ELEMENT; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("componentDatatype is not a valid value."); } }; ComponentDatatype.fromTypedArray = function(array) { if (array instanceof Int8Array) { return ComponentDatatype.BYTE; } if (array instanceof Uint8Array) { return ComponentDatatype.UNSIGNED_BYTE; } if (array instanceof Int16Array) { return ComponentDatatype.SHORT; } if (array instanceof Uint16Array) { return ComponentDatatype.UNSIGNED_SHORT; } if (array instanceof Int32Array) { return ComponentDatatype.INT; } if (array instanceof Uint32Array) { return ComponentDatatype.UNSIGNED_INT; } if (array instanceof Float32Array) { return ComponentDatatype.FLOAT; } if (array instanceof Float64Array) { return ComponentDatatype.DOUBLE; } throw new DeveloperError_default( "array must be an Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, or Float64Array." ); }; ComponentDatatype.validate = function(componentDatatype) { return defined_default(componentDatatype) && (componentDatatype === ComponentDatatype.BYTE || componentDatatype === ComponentDatatype.UNSIGNED_BYTE || componentDatatype === ComponentDatatype.SHORT || componentDatatype === ComponentDatatype.UNSIGNED_SHORT || componentDatatype === ComponentDatatype.INT || componentDatatype === ComponentDatatype.UNSIGNED_INT || componentDatatype === ComponentDatatype.FLOAT || componentDatatype === ComponentDatatype.DOUBLE); }; ComponentDatatype.createTypedArray = function(componentDatatype, valuesOrLength) { if (!defined_default(componentDatatype)) { throw new DeveloperError_default("componentDatatype is required."); } if (!defined_default(valuesOrLength)) { throw new DeveloperError_default("valuesOrLength is required."); } switch (componentDatatype) { case ComponentDatatype.BYTE: return new Int8Array(valuesOrLength); case ComponentDatatype.UNSIGNED_BYTE: return new Uint8Array(valuesOrLength); case ComponentDatatype.SHORT: return new Int16Array(valuesOrLength); case ComponentDatatype.UNSIGNED_SHORT: return new Uint16Array(valuesOrLength); case ComponentDatatype.INT: return new Int32Array(valuesOrLength); case ComponentDatatype.UNSIGNED_INT: return new Uint32Array(valuesOrLength); case ComponentDatatype.FLOAT: return new Float32Array(valuesOrLength); case ComponentDatatype.DOUBLE: return new Float64Array(valuesOrLength); //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("componentDatatype is not a valid value."); } }; ComponentDatatype.createArrayBufferView = function(componentDatatype, buffer2, byteOffset, length2) { if (!defined_default(componentDatatype)) { throw new DeveloperError_default("componentDatatype is required."); } if (!defined_default(buffer2)) { throw new DeveloperError_default("buffer is required."); } byteOffset = byteOffset ?? 0; length2 = length2 ?? (buffer2.byteLength - byteOffset) / ComponentDatatype.getSizeInBytes(componentDatatype); switch (componentDatatype) { case ComponentDatatype.BYTE: return new Int8Array(buffer2, byteOffset, length2); case ComponentDatatype.UNSIGNED_BYTE: return new Uint8Array(buffer2, byteOffset, length2); case ComponentDatatype.SHORT: return new Int16Array(buffer2, byteOffset, length2); case ComponentDatatype.UNSIGNED_SHORT: return new Uint16Array(buffer2, byteOffset, length2); case ComponentDatatype.INT: return new Int32Array(buffer2, byteOffset, length2); case ComponentDatatype.UNSIGNED_INT: return new Uint32Array(buffer2, byteOffset, length2); case ComponentDatatype.FLOAT: return new Float32Array(buffer2, byteOffset, length2); case ComponentDatatype.DOUBLE: return new Float64Array(buffer2, byteOffset, length2); //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("componentDatatype is not a valid value."); } }; ComponentDatatype.fromName = function(name) { switch (name) { case "BYTE": return ComponentDatatype.BYTE; case "UNSIGNED_BYTE": return ComponentDatatype.UNSIGNED_BYTE; case "SHORT": return ComponentDatatype.SHORT; case "UNSIGNED_SHORT": return ComponentDatatype.UNSIGNED_SHORT; case "INT": return ComponentDatatype.INT; case "UNSIGNED_INT": return ComponentDatatype.UNSIGNED_INT; case "FLOAT": return ComponentDatatype.FLOAT; case "DOUBLE": return ComponentDatatype.DOUBLE; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("name is not a valid value."); } }; ComponentDatatype.dequantize = function(value, componentDatatype) { switch (componentDatatype) { case ComponentDatatype.BYTE: return Math.max(value / 127, -1); case ComponentDatatype.UNSIGNED_BYTE: return value / 255; case ComponentDatatype.SHORT: return Math.max(value / 32767, -1); case ComponentDatatype.UNSIGNED_SHORT: return value / 65535; case ComponentDatatype.INT: return Math.max(value / 2147483647, -1); case ComponentDatatype.UNSIGNED_INT: return value / 4294967295; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default( "componentDatatype is not a valid integer type for dequantization." ); } }; Object.freeze(ComponentDatatype); var ComponentDatatype_default = ComponentDatatype; // packages/engine/Source/Core/Geometry.js var import_InlineWorkers88 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/GeometryType.js var import_InlineWorkers87 = __toESM(require_InlineWorkers(), 1); var GeometryType = { NONE: 0, TRIANGLES: 1, LINES: 2, POLYLINES: 3 }; Object.freeze(GeometryType); var GeometryType_default = GeometryType; // packages/engine/Source/Core/Geometry.js function Geometry(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.typeOf.object("options.attributes", options.attributes); this.attributes = options.attributes; this.indices = options.indices; this.primitiveType = options.primitiveType ?? PrimitiveType_default.TRIANGLES; this.boundingSphere = options.boundingSphere; this.geometryType = options.geometryType ?? GeometryType_default.NONE; this.boundingSphereCV = options.boundingSphereCV; this.offsetAttribute = options.offsetAttribute; } Geometry.computeNumberOfVertices = function(geometry) { Check_default.typeOf.object("geometry", geometry); let numberOfVertices = -1; for (const property in geometry.attributes) { if (geometry.attributes.hasOwnProperty(property) && defined_default(geometry.attributes[property]) && defined_default(geometry.attributes[property].values)) { const attribute = geometry.attributes[property]; const num = attribute.values.length / attribute.componentsPerAttribute; if (numberOfVertices !== num && numberOfVertices !== -1) { throw new DeveloperError_default( "All attribute lists must have the same number of attributes." ); } numberOfVertices = num; } } return numberOfVertices; }; var rectangleCenterScratch = new Cartographic_default(); var enuCenterScratch = new Cartesian3_default(); var fixedFrameToEnuScratch = new Matrix4_default(); var boundingRectanglePointsCartographicScratch = [ new Cartographic_default(), new Cartographic_default(), new Cartographic_default() ]; var boundingRectanglePointsEnuScratch = [ new Cartesian2_default(), new Cartesian2_default(), new Cartesian2_default() ]; var points2DScratch = [new Cartesian2_default(), new Cartesian2_default(), new Cartesian2_default()]; var pointEnuScratch = new Cartesian3_default(); var enuRotationScratch = new Quaternion_default(); var enuRotationMatrixScratch = new Matrix4_default(); var rotation2DScratch = new Matrix2_default(); Geometry._textureCoordinateRotationPoints = function(positions, stRotation, ellipsoid, boundingRectangle) { let i; const rectangleCenter = Rectangle_default.center( boundingRectangle, rectangleCenterScratch ); const enuCenter = Cartographic_default.toCartesian( rectangleCenter, ellipsoid, enuCenterScratch ); const enuToFixedFrame = Transforms_default.eastNorthUpToFixedFrame( enuCenter, ellipsoid, fixedFrameToEnuScratch ); const fixedFrameToEnu = Matrix4_default.inverse( enuToFixedFrame, fixedFrameToEnuScratch ); const boundingPointsEnu = boundingRectanglePointsEnuScratch; const boundingPointsCarto = boundingRectanglePointsCartographicScratch; boundingPointsCarto[0].longitude = boundingRectangle.west; boundingPointsCarto[0].latitude = boundingRectangle.south; boundingPointsCarto[1].longitude = boundingRectangle.west; boundingPointsCarto[1].latitude = boundingRectangle.north; boundingPointsCarto[2].longitude = boundingRectangle.east; boundingPointsCarto[2].latitude = boundingRectangle.south; let posEnu = pointEnuScratch; for (i = 0; i < 3; i++) { Cartographic_default.toCartesian(boundingPointsCarto[i], ellipsoid, posEnu); posEnu = Matrix4_default.multiplyByPointAsVector(fixedFrameToEnu, posEnu, posEnu); boundingPointsEnu[i].x = posEnu.x; boundingPointsEnu[i].y = posEnu.y; } const rotation = Quaternion_default.fromAxisAngle( Cartesian3_default.UNIT_Z, -stRotation, enuRotationScratch ); const textureMatrix = Matrix3_default.fromQuaternion( rotation, enuRotationMatrixScratch ); const positionsLength = positions.length; let enuMinX = Number.POSITIVE_INFINITY; let enuMinY = Number.POSITIVE_INFINITY; let enuMaxX = Number.NEGATIVE_INFINITY; let enuMaxY = Number.NEGATIVE_INFINITY; for (i = 0; i < positionsLength; i++) { posEnu = Matrix4_default.multiplyByPointAsVector( fixedFrameToEnu, positions[i], posEnu ); posEnu = Matrix3_default.multiplyByVector(textureMatrix, posEnu, posEnu); enuMinX = Math.min(enuMinX, posEnu.x); enuMinY = Math.min(enuMinY, posEnu.y); enuMaxX = Math.max(enuMaxX, posEnu.x); enuMaxY = Math.max(enuMaxY, posEnu.y); } const toDesiredInComputed = Matrix2_default.fromRotation( stRotation, rotation2DScratch ); const points2D = points2DScratch; points2D[0].x = enuMinX; points2D[0].y = enuMinY; points2D[1].x = enuMinX; points2D[1].y = enuMaxY; points2D[2].x = enuMaxX; points2D[2].y = enuMinY; const boundingEnuMin = boundingPointsEnu[0]; const boundingPointsWidth = boundingPointsEnu[2].x - boundingEnuMin.x; const boundingPointsHeight = boundingPointsEnu[1].y - boundingEnuMin.y; for (i = 0; i < 3; i++) { const point2D = points2D[i]; Matrix2_default.multiplyByVector(toDesiredInComputed, point2D, point2D); point2D.x = (point2D.x - boundingEnuMin.x) / boundingPointsWidth; point2D.y = (point2D.y - boundingEnuMin.y) / boundingPointsHeight; } const minXYCorner = points2D[0]; const maxYCorner = points2D[1]; const maxXCorner = points2D[2]; const result = new Array(6); Cartesian2_default.pack(minXYCorner, result); Cartesian2_default.pack(maxYCorner, result, 2); Cartesian2_default.pack(maxXCorner, result, 4); return result; }; var Geometry_default = Geometry; // packages/engine/Source/Core/GeometryAttribute.js var import_InlineWorkers89 = __toESM(require_InlineWorkers(), 1); function GeometryAttribute(options) { options = options ?? Frozen_default.EMPTY_OBJECT; if (!defined_default(options.componentDatatype)) { throw new DeveloperError_default("options.componentDatatype is required."); } if (!defined_default(options.componentsPerAttribute)) { throw new DeveloperError_default("options.componentsPerAttribute is required."); } if (options.componentsPerAttribute < 1 || options.componentsPerAttribute > 4) { throw new DeveloperError_default( "options.componentsPerAttribute must be between 1 and 4." ); } if (!defined_default(options.values)) { throw new DeveloperError_default("options.values is required."); } this.componentDatatype = options.componentDatatype; this.componentsPerAttribute = options.componentsPerAttribute; this.normalize = options.normalize ?? false; this.values = options.values; } var GeometryAttribute_default = GeometryAttribute; // packages/engine/Source/Core/loadKTX2.js var import_InlineWorkers93 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/KTX2Transcoder.js var import_InlineWorkers92 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/CompressedTextureBuffer.js var import_InlineWorkers90 = __toESM(require_InlineWorkers(), 1); function CompressedTextureBuffer(internalFormat, pixelDatatype, width, height, buffer2) { this._format = internalFormat; this._datatype = pixelDatatype; this._width = width; this._height = height; this._buffer = buffer2; } Object.defineProperties(CompressedTextureBuffer.prototype, { /** * The format of the compressed texture. * @type {PixelFormat} * @readonly * @memberof CompressedTextureBuffer.prototype */ internalFormat: { get: function() { return this._format; } }, /** * The datatype of the compressed texture. * @type {PixelDatatype} * @readonly * @memberof CompressedTextureBuffer.prototype */ pixelDatatype: { get: function() { return this._datatype; } }, /** * The width of the texture. * @type {number} * @readonly * @memberof CompressedTextureBuffer.prototype */ width: { get: function() { return this._width; } }, /** * The height of the texture. * @type {number} * @readonly * @memberof CompressedTextureBuffer.prototype */ height: { get: function() { return this._height; } }, /** * The compressed texture buffer. * @type {Uint8Array} * @readonly * @memberof CompressedTextureBuffer.prototype */ bufferView: { get: function() { return this._buffer; } }, /** * The compressed texture buffer. Alias for bufferView. * @type {Uint8Array} * @readonly * @memberof CompressedTextureBuffer.prototype */ arrayBufferView: { get: function() { return this._buffer; } } }); CompressedTextureBuffer.clone = function(object2) { if (!defined_default(object2)) { return void 0; } return new CompressedTextureBuffer( object2._format, object2._datatype, object2._width, object2._height, object2._buffer ); }; CompressedTextureBuffer.prototype.clone = function() { return CompressedTextureBuffer.clone(this); }; var CompressedTextureBuffer_default = CompressedTextureBuffer; // packages/engine/Source/Core/TaskProcessor.js var import_InlineWorkers91 = __toESM(require_InlineWorkers(), 1); var import_urijs7 = __toESM(require_URI(), 1); function canTransferArrayBuffer() { if (!defined_default(TaskProcessor._canTransferArrayBuffer)) { const worker = createWorker("transferTypedArrayTest"); worker.postMessage = worker.webkitPostMessage ?? worker.postMessage; const value = 99; const array = new Int8Array([value]); try { worker.postMessage( { array }, [array.buffer] ); } catch (e) { TaskProcessor._canTransferArrayBuffer = false; return TaskProcessor._canTransferArrayBuffer; } TaskProcessor._canTransferArrayBuffer = new Promise((resolve2) => { worker.onmessage = function(event) { const array2 = event.data.array; const result = defined_default(array2) && array2[0] === value; resolve2(result); worker.terminate(); TaskProcessor._canTransferArrayBuffer = result; }; }); } return TaskProcessor._canTransferArrayBuffer; } var taskCompletedEvent = new Event_default(); function urlFromScript(script) { let blob; try { blob = new Blob([script], { type: "application/javascript" }); } catch (e) { const BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; const blobBuilder = new BlobBuilder(); blobBuilder.append(script); blob = blobBuilder.getBlob("application/javascript"); } const URL2 = window.URL || window.webkitURL; return URL2.createObjectURL(blob); } function createWorker(url2) { const uri = new import_urijs7.default(url2); const isUri = uri.scheme().length !== 0 && uri.fragment().length === 0; const moduleID = url2.replace(/\.js$/, ""); const options = {}; let workerPath; let crossOriginUrl; if (isCrossOriginUrl_default(url2)) { crossOriginUrl = url2; } else if (!isUri) { const moduleAbsoluteUrl = buildModuleUrl_default( `${TaskProcessor._workerModulePrefix}/${moduleID}.js` ); if (isCrossOriginUrl_default(moduleAbsoluteUrl)) { crossOriginUrl = moduleAbsoluteUrl; } } if (crossOriginUrl) { const script = `import "${crossOriginUrl}";`; workerPath = urlFromScript(script); options.type = "module"; return new Worker(workerPath, options); } if (!isUri && typeof CESIUM_WORKERS !== "undefined") { const script = ` importScripts("${urlFromScript(CESIUM_WORKERS)}"); CesiumWorkers["${moduleID}"](); `; workerPath = urlFromScript(script); return new Worker(workerPath, options); } workerPath = url2; if (!isUri) { workerPath = buildModuleUrl_default( `${TaskProcessor._workerModulePrefix + moduleID}.js` ); } if (!FeatureDetection_default.supportsEsmWebWorkers()) { throw new RuntimeError_default( "This browser is not supported. Please update your browser to continue." ); } options.type = "module"; return new Worker(workerPath, options); } async function getWebAssemblyLoaderConfig(processor, wasmOptions) { const config2 = { modulePath: void 0, wasmBinaryFile: void 0, wasmBinary: void 0 }; if (!FeatureDetection_default.supportsWebAssembly()) { if (!defined_default(wasmOptions.fallbackModulePath)) { throw new RuntimeError_default( `This browser does not support Web Assembly, and no backup module was provided for ${processor._workerPath}` ); } config2.modulePath = buildModuleUrl_default(wasmOptions.fallbackModulePath); return config2; } config2.wasmBinaryFile = buildModuleUrl_default(wasmOptions.wasmBinaryFile); const arrayBuffer = await Resource_default.fetchArrayBuffer({ url: config2.wasmBinaryFile }); config2.wasmBinary = arrayBuffer; return config2; } function TaskProcessor(workerPath, maximumActiveTasks) { this._workerPath = workerPath; this._maximumActiveTasks = maximumActiveTasks ?? Number.POSITIVE_INFINITY; this._activeTasks = 0; this._nextID = 0; this._webAssemblyPromise = void 0; } var createOnmessageHandler = (worker, id, resolve2, reject) => { const listener = ({ data }) => { if (data.id !== id) { return; } if (defined_default(data.error)) { let error = data.error; if (error.name === "RuntimeError") { error = new RuntimeError_default(data.error.message); error.stack = data.error.stack; } else if (error.name === "DeveloperError") { error = new DeveloperError_default(data.error.message); error.stack = data.error.stack; } else if (error.name === "Error") { error = new Error(data.error.message); error.stack = data.error.stack; } taskCompletedEvent.raiseEvent(error); reject(error); } else { taskCompletedEvent.raiseEvent(); resolve2(data.result); } worker.removeEventListener("message", listener); }; return listener; }; var emptyTransferableObjectArray = []; async function runTask(processor, parameters, transferableObjects) { const canTransfer = await Promise.resolve(canTransferArrayBuffer()); if (!defined_default(transferableObjects)) { transferableObjects = emptyTransferableObjectArray; } else if (!canTransfer) { transferableObjects.length = 0; } const id = processor._nextID++; const promise = new Promise((resolve2, reject) => { processor._worker.addEventListener( "message", createOnmessageHandler(processor._worker, id, resolve2, reject) ); }); processor._worker.postMessage( { id, baseUrl: buildModuleUrl_default.getCesiumBaseUrl().url, parameters, canTransferArrayBuffer: canTransfer }, transferableObjects ); return promise; } async function scheduleTask(processor, parameters, transferableObjects) { ++processor._activeTasks; try { const result = await runTask(processor, parameters, transferableObjects); --processor._activeTasks; return result; } catch (error) { --processor._activeTasks; throw error; } } TaskProcessor.prototype.scheduleTask = function(parameters, transferableObjects) { if (!defined_default(this._worker)) { this._worker = createWorker(this._workerPath); } if (this._activeTasks >= this._maximumActiveTasks) { return void 0; } return scheduleTask(this, parameters, transferableObjects); }; TaskProcessor.prototype.initWebAssemblyModule = async function(webAssemblyOptions) { if (defined_default(this._webAssemblyPromise)) { return this._webAssemblyPromise; } const init = async () => { const worker = this._worker = createWorker(this._workerPath); const wasmConfig = await getWebAssemblyLoaderConfig( this, webAssemblyOptions ); const canTransfer = await Promise.resolve(canTransferArrayBuffer()); let transferableObjects; const binary = wasmConfig.wasmBinary; if (defined_default(binary) && canTransfer) { transferableObjects = [binary]; } const promise = new Promise((resolve2, reject) => { worker.onmessage = function({ data }) { if (defined_default(data)) { resolve2(data.result); } else { reject(new RuntimeError_default("Could not configure wasm module")); } }; }); worker.postMessage( { canTransferArrayBuffer: canTransfer, parameters: { webAssemblyConfig: wasmConfig } }, transferableObjects ); return promise; }; this._webAssemblyPromise = init(); return this._webAssemblyPromise; }; TaskProcessor.prototype.isDestroyed = function() { return false; }; TaskProcessor.prototype.destroy = function() { if (defined_default(this._worker)) { this._worker.terminate(); } return destroyObject_default(this); }; TaskProcessor.taskCompletedEvent = taskCompletedEvent; TaskProcessor._defaultWorkerModulePrefix = "Workers/"; TaskProcessor._workerModulePrefix = TaskProcessor._defaultWorkerModulePrefix; TaskProcessor._canTransferArrayBuffer = void 0; var TaskProcessor_default = TaskProcessor; // packages/engine/Source/Core/KTX2Transcoder.js function KTX2Transcoder() { } KTX2Transcoder._transcodeTaskProcessor = new TaskProcessor_default( "transcodeKTX2", Number.POSITIVE_INFINITY // KTX2 transcoding is used in place of Resource.fetchImage, so it can't reject as "just soooo busy right now" ); KTX2Transcoder._readyPromise = void 0; function makeReadyPromise() { const readyPromise = KTX2Transcoder._transcodeTaskProcessor.initWebAssemblyModule({ wasmBinaryFile: "ThirdParty/basis_transcoder.wasm" }).then(function(result) { if (result) { return KTX2Transcoder._transcodeTaskProcessor; } throw new RuntimeError_default("KTX2 transcoder could not be initialized."); }); KTX2Transcoder._readyPromise = readyPromise; } KTX2Transcoder.transcode = function(ktx2Buffer, supportedTargetFormats) { Check_default.defined("supportedTargetFormats", supportedTargetFormats); if (!defined_default(KTX2Transcoder._readyPromise)) { makeReadyPromise(); } return KTX2Transcoder._readyPromise.then(function(taskProcessor3) { let bufferView = ktx2Buffer; if (ktx2Buffer instanceof ArrayBuffer) { bufferView = new Uint8Array(ktx2Buffer); } const parameters = { supportedTargetFormats, ktx2Buffer: bufferView }; return taskProcessor3.scheduleTask(parameters, [bufferView.buffer]); }).then(function(result) { const levelsLength = result.length; const faceKeys = Object.keys(result[0]); for (let i = 0; i < levelsLength; i++) { const faces2 = result[i]; for (let j = 0; j < faceKeys.length; j++) { const face = faces2[faceKeys[j]]; faces2[faceKeys[j]] = new CompressedTextureBuffer_default( face.internalFormat, face.datatype, face.width, face.height, face.levelBuffer ); } } if (faceKeys.length === 1) { for (let i = 0; i < levelsLength; ++i) { result[i] = result[i][faceKeys[0]]; } if (levelsLength === 1) { result = result[0]; } } return result; }).catch(function(error) { throw error; }); }; var KTX2Transcoder_default = KTX2Transcoder; // packages/engine/Source/Core/loadKTX2.js var supportedTranscoderFormats; loadKTX2.setKTX2SupportedFormats = function(s3tc, pvrtc, astc, etc, etc1, bc7) { supportedTranscoderFormats = { s3tc, pvrtc, astc, etc, etc1, bc7 }; }; function loadKTX2(resourceOrUrlOrBuffer) { Check_default.defined("resourceOrUrlOrBuffer", resourceOrUrlOrBuffer); let loadPromise; if (resourceOrUrlOrBuffer instanceof ArrayBuffer || ArrayBuffer.isView(resourceOrUrlOrBuffer)) { loadPromise = Promise.resolve(resourceOrUrlOrBuffer); } else { const resource = Resource_default.createIfNeeded(resourceOrUrlOrBuffer); loadPromise = resource.fetchArrayBuffer(); } return loadPromise.then(function(data) { return KTX2Transcoder_default.transcode(data, supportedTranscoderFormats); }); } var loadKTX2_default = loadKTX2; // packages/engine/Source/Renderer/CubeMap.js var import_InlineWorkers120 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/BoxGeometry.js var import_InlineWorkers99 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/BoundingSphere.js var import_InlineWorkers95 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Interval.js var import_InlineWorkers94 = __toESM(require_InlineWorkers(), 1); function Interval(start, stop2) { this.start = start ?? 0; this.stop = stop2 ?? 0; } var Interval_default = Interval; // packages/engine/Source/Core/BoundingSphere.js var BoundingSphere = class _BoundingSphere { /** * @param {Cartesian3} [center=Cartesian3.ZERO] The center of the bounding sphere. * @param {number} [radius=0.0] The radius of the bounding sphere. */ constructor(center, radius) { this.center = Cartesian3_default.clone(center ?? Cartesian3_default.ZERO); this.radius = radius ?? 0; } /** * Computes a tight-fitting bounding sphere enclosing a list of 3D Cartesian points. * The bounding sphere is computed by running two algorithms, a naive algorithm and * Ritter's algorithm. The smaller of the two spheres is used to ensure a tight fit. * * @param {Cartesian3[]} [positions] An array of points that the bounding sphere will enclose. Each point must have x, y, and z properties. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. * * @see {@link http://help.agi.com/AGIComponents/html/BlogBoundingSphere.htm|Bounding Sphere computation article} */ static fromPoints(positions, result) { if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(positions) || positions.length === 0) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } const currentPos = Cartesian3_default.clone(positions[0], fromPointsCurrentPos); const xMin = Cartesian3_default.clone(currentPos, fromPointsXMin); const yMin = Cartesian3_default.clone(currentPos, fromPointsYMin); const zMin = Cartesian3_default.clone(currentPos, fromPointsZMin); const xMax = Cartesian3_default.clone(currentPos, fromPointsXMax); const yMax = Cartesian3_default.clone(currentPos, fromPointsYMax); const zMax = Cartesian3_default.clone(currentPos, fromPointsZMax); const numPositions = positions.length; let i; for (i = 1; i < numPositions; i++) { Cartesian3_default.clone(positions[i], currentPos); const x = currentPos.x; const y = currentPos.y; const z2 = currentPos.z; if (x < xMin.x) { Cartesian3_default.clone(currentPos, xMin); } if (x > xMax.x) { Cartesian3_default.clone(currentPos, xMax); } if (y < yMin.y) { Cartesian3_default.clone(currentPos, yMin); } if (y > yMax.y) { Cartesian3_default.clone(currentPos, yMax); } if (z2 < zMin.z) { Cartesian3_default.clone(currentPos, zMin); } if (z2 > zMax.z) { Cartesian3_default.clone(currentPos, zMax); } } const xSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(xMax, xMin, fromPointsScratch) ); const ySpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(yMax, yMin, fromPointsScratch) ); const zSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(zMax, zMin, fromPointsScratch) ); let diameter1 = xMin; let diameter2 = xMax; let maxSpan = xSpan; if (ySpan > maxSpan) { maxSpan = ySpan; diameter1 = yMin; diameter2 = yMax; } if (zSpan > maxSpan) { diameter1 = zMin; diameter2 = zMax; } const ritterCenter = fromPointsRitterCenter; ritterCenter.x = (diameter1.x + diameter2.x) * 0.5; ritterCenter.y = (diameter1.y + diameter2.y) * 0.5; ritterCenter.z = (diameter1.z + diameter2.z) * 0.5; let radiusSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(diameter2, ritterCenter, fromPointsScratch) ); let ritterRadius = Math.sqrt(radiusSquared); const minBoxPt = fromPointsMinBoxPt; minBoxPt.x = xMin.x; minBoxPt.y = yMin.y; minBoxPt.z = zMin.z; const maxBoxPt = fromPointsMaxBoxPt; maxBoxPt.x = xMax.x; maxBoxPt.y = yMax.y; maxBoxPt.z = zMax.z; const naiveCenter = Cartesian3_default.midpoint( minBoxPt, maxBoxPt, fromPointsNaiveCenterScratch ); let naiveRadius = 0; for (i = 0; i < numPositions; i++) { Cartesian3_default.clone(positions[i], currentPos); const r2 = Cartesian3_default.magnitude( Cartesian3_default.subtract(currentPos, naiveCenter, fromPointsScratch) ); if (r2 > naiveRadius) { naiveRadius = r2; } const oldCenterToPointSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(currentPos, ritterCenter, fromPointsScratch) ); if (oldCenterToPointSquared > radiusSquared) { const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared); ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5; radiusSquared = ritterRadius * ritterRadius; const oldToNew = oldCenterToPoint - ritterRadius; ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint; ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint; ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint; } } if (ritterRadius < naiveRadius) { Cartesian3_default.clone(ritterCenter, result.center); result.radius = ritterRadius; } else { Cartesian3_default.clone(naiveCenter, result.center); result.radius = naiveRadius; } return result; } /** * Computes a bounding sphere from a rectangle projected in 2D. * * @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere. * @param {MapProjection} [projection=GeographicProjection] The projection used to project the rectangle into 2D. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromRectangle2D(rectangle, projection, result) { return _BoundingSphere.fromRectangleWithHeights2D( rectangle, projection, 0, 0, result ); } /** * Computes a bounding sphere from a rectangle projected in 2D. The bounding sphere accounts for the * object's minimum and maximum heights over the rectangle. * * @param {Rectangle} [rectangle] The rectangle around which to create a bounding sphere. * @param {MapProjection} [projection=GeographicProjection] The projection used to project the rectangle into 2D. * @param {number} [minimumHeight=0.0] The minimum height over the rectangle. * @param {number} [maximumHeight=0.0] The maximum height over the rectangle. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromRectangleWithHeights2D(rectangle, projection, minimumHeight, maximumHeight, result) { if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(rectangle)) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } defaultProjection2._ellipsoid = Ellipsoid_default.default; projection = projection ?? defaultProjection2; Rectangle_default.southwest(rectangle, fromRectangle2DSouthwest); fromRectangle2DSouthwest.height = minimumHeight; Rectangle_default.northeast(rectangle, fromRectangle2DNortheast); fromRectangle2DNortheast.height = maximumHeight; const lowerLeft = projection.project( fromRectangle2DSouthwest, fromRectangle2DLowerLeft ); const upperRight = projection.project( fromRectangle2DNortheast, fromRectangle2DUpperRight ); const width = upperRight.x - lowerLeft.x; const height = upperRight.y - lowerLeft.y; const elevation = upperRight.z - lowerLeft.z; result.radius = Math.sqrt(width * width + height * height + elevation * elevation) * 0.5; const center = result.center; center.x = lowerLeft.x + width * 0.5; center.y = lowerLeft.y + height * 0.5; center.z = lowerLeft.z + elevation * 0.5; return result; } /** * Computes a bounding sphere from a rectangle in 3D. The bounding sphere is created using a subsample of points * on the ellipsoid and contained in the rectangle. It may not be accurate for all rectangles on all types of ellipsoids. * * @param {Rectangle} [rectangle] The valid rectangle used to create a bounding sphere. * @param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid used to determine positions of the rectangle. * @param {number} [surfaceHeight=0.0] The height above the surface of the ellipsoid. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromRectangle3D(rectangle, ellipsoid, surfaceHeight, result) { ellipsoid = ellipsoid ?? Ellipsoid_default.default; surfaceHeight = surfaceHeight ?? 0; if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(rectangle)) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } const positions = Rectangle_default.subsample( rectangle, ellipsoid, surfaceHeight, fromRectangle3DScratch ); return _BoundingSphere.fromPoints(positions, result); } /** * Computes a tight-fitting bounding sphere enclosing a list of 3D points, where the points are * stored in a flat array in X, Y, Z, order. The bounding sphere is computed by running two * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to * ensure a tight fit. * * @param {number[]|TypedArray} [positions] An array of points that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. * @param {Cartesian3} [center=Cartesian3.ZERO] The position to which the positions are relative, which need not be the * origin of the coordinate system. This is useful when the positions are to be used for * relative-to-center (RTC) rendering. * @param {number} [stride=3] The number of array elements per vertex. It must be at least 3, but it may * be higher. Regardless of the value of this parameter, the X coordinate of the first position * is at array index 0, the Y coordinate is at array index 1, and the Z coordinate is at array index * 2. When stride is 3, the X coordinate of the next position then begins at array index 3. If * the stride is 5, however, two array elements are skipped and the next position begins at array * index 5. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. * * @example * // Compute the bounding sphere from 3 positions, each specified relative to a center. * // In addition to the X, Y, and Z coordinates, the points array contains two additional * // elements per point which are ignored for the purpose of computing the bounding sphere. * const center = new Cesium.Cartesian3(1.0, 2.0, 3.0); * const points = [1.0, 2.0, 3.0, 0.1, 0.2, * 4.0, 5.0, 6.0, 0.1, 0.2, * 7.0, 8.0, 9.0, 0.1, 0.2]; * const sphere = Cesium.BoundingSphere.fromVertices(points, center, 5); * * @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article} */ static fromVertices(positions, center, stride, result) { if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(positions) || positions.length === 0) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } center = center ?? Cartesian3_default.ZERO; stride = stride ?? 3; Check_default.typeOf.number.greaterThanOrEquals("stride", stride, 3); const currentPos = fromPointsCurrentPos; currentPos.x = positions[0] + center.x; currentPos.y = positions[1] + center.y; currentPos.z = positions[2] + center.z; const xMin = Cartesian3_default.clone(currentPos, fromPointsXMin); const yMin = Cartesian3_default.clone(currentPos, fromPointsYMin); const zMin = Cartesian3_default.clone(currentPos, fromPointsZMin); const xMax = Cartesian3_default.clone(currentPos, fromPointsXMax); const yMax = Cartesian3_default.clone(currentPos, fromPointsYMax); const zMax = Cartesian3_default.clone(currentPos, fromPointsZMax); const numElements = positions.length; let i; for (i = 0; i < numElements; i += stride) { const x = positions[i] + center.x; const y = positions[i + 1] + center.y; const z2 = positions[i + 2] + center.z; currentPos.x = x; currentPos.y = y; currentPos.z = z2; if (x < xMin.x) { Cartesian3_default.clone(currentPos, xMin); } if (x > xMax.x) { Cartesian3_default.clone(currentPos, xMax); } if (y < yMin.y) { Cartesian3_default.clone(currentPos, yMin); } if (y > yMax.y) { Cartesian3_default.clone(currentPos, yMax); } if (z2 < zMin.z) { Cartesian3_default.clone(currentPos, zMin); } if (z2 > zMax.z) { Cartesian3_default.clone(currentPos, zMax); } } const xSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(xMax, xMin, fromPointsScratch) ); const ySpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(yMax, yMin, fromPointsScratch) ); const zSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(zMax, zMin, fromPointsScratch) ); let diameter1 = xMin; let diameter2 = xMax; let maxSpan = xSpan; if (ySpan > maxSpan) { maxSpan = ySpan; diameter1 = yMin; diameter2 = yMax; } if (zSpan > maxSpan) { diameter1 = zMin; diameter2 = zMax; } const ritterCenter = fromPointsRitterCenter; ritterCenter.x = (diameter1.x + diameter2.x) * 0.5; ritterCenter.y = (diameter1.y + diameter2.y) * 0.5; ritterCenter.z = (diameter1.z + diameter2.z) * 0.5; let radiusSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(diameter2, ritterCenter, fromPointsScratch) ); let ritterRadius = Math.sqrt(radiusSquared); const minBoxPt = fromPointsMinBoxPt; minBoxPt.x = xMin.x; minBoxPt.y = yMin.y; minBoxPt.z = zMin.z; const maxBoxPt = fromPointsMaxBoxPt; maxBoxPt.x = xMax.x; maxBoxPt.y = yMax.y; maxBoxPt.z = zMax.z; const naiveCenter = Cartesian3_default.midpoint( minBoxPt, maxBoxPt, fromPointsNaiveCenterScratch ); let naiveRadius = 0; for (i = 0; i < numElements; i += stride) { currentPos.x = positions[i] + center.x; currentPos.y = positions[i + 1] + center.y; currentPos.z = positions[i + 2] + center.z; const r2 = Cartesian3_default.magnitude( Cartesian3_default.subtract(currentPos, naiveCenter, fromPointsScratch) ); if (r2 > naiveRadius) { naiveRadius = r2; } const oldCenterToPointSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(currentPos, ritterCenter, fromPointsScratch) ); if (oldCenterToPointSquared > radiusSquared) { const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared); ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5; radiusSquared = ritterRadius * ritterRadius; const oldToNew = oldCenterToPoint - ritterRadius; ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint; ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint; ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint; } } if (ritterRadius < naiveRadius) { Cartesian3_default.clone(ritterCenter, result.center); result.radius = ritterRadius; } else { Cartesian3_default.clone(naiveCenter, result.center); result.radius = naiveRadius; } return result; } /** * Computes a tight-fitting bounding sphere enclosing a list of EncodedCartesian3s, where the points are * stored in parallel flat arrays in X, Y, Z, order. The bounding sphere is computed by running two * algorithms, a naive algorithm and Ritter's algorithm. The smaller of the two spheres is used to * ensure a tight fit. * * @param {number[]} [positionsHigh] An array of high bits of the encoded cartesians that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. * @param {number[]} [positionsLow] An array of low bits of the encoded cartesians that the bounding sphere will enclose. Each point * is formed from three elements in the array in the order X, Y, Z. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. * * @see {@link http://blogs.agi.com/insight3d/index.php/2008/02/04/a-bounding/|Bounding Sphere computation article} */ static fromEncodedCartesianVertices(positionsHigh, positionsLow, result) { if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(positionsHigh) || !defined_default(positionsLow) || positionsHigh.length !== positionsLow.length || positionsHigh.length === 0) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } const currentPos = fromPointsCurrentPos; currentPos.x = positionsHigh[0] + positionsLow[0]; currentPos.y = positionsHigh[1] + positionsLow[1]; currentPos.z = positionsHigh[2] + positionsLow[2]; const xMin = Cartesian3_default.clone(currentPos, fromPointsXMin); const yMin = Cartesian3_default.clone(currentPos, fromPointsYMin); const zMin = Cartesian3_default.clone(currentPos, fromPointsZMin); const xMax = Cartesian3_default.clone(currentPos, fromPointsXMax); const yMax = Cartesian3_default.clone(currentPos, fromPointsYMax); const zMax = Cartesian3_default.clone(currentPos, fromPointsZMax); const numElements = positionsHigh.length; let i; for (i = 0; i < numElements; i += 3) { const x = positionsHigh[i] + positionsLow[i]; const y = positionsHigh[i + 1] + positionsLow[i + 1]; const z2 = positionsHigh[i + 2] + positionsLow[i + 2]; currentPos.x = x; currentPos.y = y; currentPos.z = z2; if (x < xMin.x) { Cartesian3_default.clone(currentPos, xMin); } if (x > xMax.x) { Cartesian3_default.clone(currentPos, xMax); } if (y < yMin.y) { Cartesian3_default.clone(currentPos, yMin); } if (y > yMax.y) { Cartesian3_default.clone(currentPos, yMax); } if (z2 < zMin.z) { Cartesian3_default.clone(currentPos, zMin); } if (z2 > zMax.z) { Cartesian3_default.clone(currentPos, zMax); } } const xSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(xMax, xMin, fromPointsScratch) ); const ySpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(yMax, yMin, fromPointsScratch) ); const zSpan = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(zMax, zMin, fromPointsScratch) ); let diameter1 = xMin; let diameter2 = xMax; let maxSpan = xSpan; if (ySpan > maxSpan) { maxSpan = ySpan; diameter1 = yMin; diameter2 = yMax; } if (zSpan > maxSpan) { diameter1 = zMin; diameter2 = zMax; } const ritterCenter = fromPointsRitterCenter; ritterCenter.x = (diameter1.x + diameter2.x) * 0.5; ritterCenter.y = (diameter1.y + diameter2.y) * 0.5; ritterCenter.z = (diameter1.z + diameter2.z) * 0.5; let radiusSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(diameter2, ritterCenter, fromPointsScratch) ); let ritterRadius = Math.sqrt(radiusSquared); const minBoxPt = fromPointsMinBoxPt; minBoxPt.x = xMin.x; minBoxPt.y = yMin.y; minBoxPt.z = zMin.z; const maxBoxPt = fromPointsMaxBoxPt; maxBoxPt.x = xMax.x; maxBoxPt.y = yMax.y; maxBoxPt.z = zMax.z; const naiveCenter = Cartesian3_default.midpoint( minBoxPt, maxBoxPt, fromPointsNaiveCenterScratch ); let naiveRadius = 0; for (i = 0; i < numElements; i += 3) { currentPos.x = positionsHigh[i] + positionsLow[i]; currentPos.y = positionsHigh[i + 1] + positionsLow[i + 1]; currentPos.z = positionsHigh[i + 2] + positionsLow[i + 2]; const r2 = Cartesian3_default.magnitude( Cartesian3_default.subtract(currentPos, naiveCenter, fromPointsScratch) ); if (r2 > naiveRadius) { naiveRadius = r2; } const oldCenterToPointSquared = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(currentPos, ritterCenter, fromPointsScratch) ); if (oldCenterToPointSquared > radiusSquared) { const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared); ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5; radiusSquared = ritterRadius * ritterRadius; const oldToNew = oldCenterToPoint - ritterRadius; ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint; ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint; ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint; } } if (ritterRadius < naiveRadius) { Cartesian3_default.clone(ritterCenter, result.center); result.radius = ritterRadius; } else { Cartesian3_default.clone(naiveCenter, result.center); result.radius = naiveRadius; } return result; } /** * Computes a bounding sphere from the corner points of an axis-aligned bounding box. The sphere * tightly and fully encompasses the box. * * @param {Cartesian3} [corner] The minimum height over the rectangle. * @param {Cartesian3} [oppositeCorner] The maximum height over the rectangle. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. * * @example * // Create a bounding sphere around the unit cube * const sphere = Cesium.BoundingSphere.fromCornerPoints(new Cesium.Cartesian3(-0.5, -0.5, -0.5), new Cesium.Cartesian3(0.5, 0.5, 0.5)); */ static fromCornerPoints(corner, oppositeCorner, result) { Check_default.typeOf.object("corner", corner); Check_default.typeOf.object("oppositeCorner", oppositeCorner); if (!defined_default(result)) { result = new _BoundingSphere(); } const center = Cartesian3_default.midpoint(corner, oppositeCorner, result.center); result.radius = Cartesian3_default.distance(center, oppositeCorner); return result; } /** * Creates a bounding sphere encompassing an ellipsoid. * * @param {Ellipsoid} ellipsoid The ellipsoid around which to create a bounding sphere. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. * * @example * const boundingSphere = Cesium.BoundingSphere.fromEllipsoid(ellipsoid); */ static fromEllipsoid(ellipsoid, result) { Check_default.typeOf.object("ellipsoid", ellipsoid); if (!defined_default(result)) { result = new _BoundingSphere(); } Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = ellipsoid.maximumRadius; return result; } /** * Computes a tight-fitting bounding sphere enclosing the provided array of bounding spheres. * * @param {BoundingSphere[]} [boundingSpheres] The array of bounding spheres. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromBoundingSpheres(boundingSpheres, result) { if (!defined_default(result)) { result = new _BoundingSphere(); } if (!defined_default(boundingSpheres) || boundingSpheres.length === 0) { result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); result.radius = 0; return result; } const length2 = boundingSpheres.length; if (length2 === 1) { return _BoundingSphere.clone(boundingSpheres[0], result); } if (length2 === 2) { return _BoundingSphere.union( boundingSpheres[0], boundingSpheres[1], result ); } const positions = []; let i; for (i = 0; i < length2; i++) { positions.push(boundingSpheres[i].center); } result = _BoundingSphere.fromPoints(positions, result); const center = result.center; let radius = result.radius; for (i = 0; i < length2; i++) { const tmp2 = boundingSpheres[i]; radius = Math.max( radius, Cartesian3_default.distance(center, tmp2.center) + tmp2.radius ); } result.radius = radius; return result; } /** * Computes a tight-fitting bounding sphere enclosing the provided oriented bounding box. * * @param {OrientedBoundingBox} orientedBoundingBox The oriented bounding box. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromOrientedBoundingBox(orientedBoundingBox, result) { Check_default.defined("orientedBoundingBox", orientedBoundingBox); if (!defined_default(result)) { result = new _BoundingSphere(); } const halfAxes = orientedBoundingBox.halfAxes; const u4 = Matrix3_default.getColumn(halfAxes, 0, fromOrientedBoundingBoxScratchU); const v3 = Matrix3_default.getColumn(halfAxes, 1, fromOrientedBoundingBoxScratchV); const w = Matrix3_default.getColumn(halfAxes, 2, fromOrientedBoundingBoxScratchW); Cartesian3_default.add(u4, v3, u4); Cartesian3_default.add(u4, w, u4); result.center = Cartesian3_default.clone(orientedBoundingBox.center, result.center); result.radius = Cartesian3_default.magnitude(u4); return result; } /** * Computes a tight-fitting bounding sphere enclosing the provided affine transformation. * * @param {Matrix4} transformation The affine transformation. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static fromTransformation(transformation, result) { Check_default.typeOf.object("transformation", transformation); if (!defined_default(result)) { result = new _BoundingSphere(); } const center = Matrix4_default.getTranslation( transformation, scratchFromTransformationCenter ); const scale = Matrix4_default.getScale( transformation, scratchFromTransformationScale ); const radius = 0.5 * Cartesian3_default.magnitude(scale); result.center = Cartesian3_default.clone(center, result.center); result.radius = radius; return result; } /** * Duplicates a BoundingSphere instance. * * @param {BoundingSphere} sphere The bounding sphere to duplicate. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. (Returns undefined if sphere is undefined) */ static clone(sphere, result) { if (!defined_default(sphere)) { return void 0; } if (!defined_default(result)) { return new _BoundingSphere(sphere.center, sphere.radius); } result.center = Cartesian3_default.clone(sphere.center, result.center); result.radius = sphere.radius; return result; } /** * Stores the provided instance into the provided array. * * @param {BoundingSphere} value The value to pack. * @param {number[]} array The array to pack into. * @param {number} [startingIndex=0] The index into the array at which to start packing the elements. * * @returns {number[]} The array that was packed into */ static pack(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; const center = value.center; array[startingIndex++] = center.x; array[startingIndex++] = center.y; array[startingIndex++] = center.z; array[startingIndex] = value.radius; return array; } /** * Retrieves an instance from a packed array. * * @param {number[]} array The packed array. * @param {number} [startingIndex=0] The starting index of the element to be unpacked. * @param {BoundingSphere} [result] The object into which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if one was not provided. */ static unpack(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new _BoundingSphere(); } const center = result.center; center.x = array[startingIndex++]; center.y = array[startingIndex++]; center.z = array[startingIndex++]; result.radius = array[startingIndex]; return result; } /** * Computes a bounding sphere that contains both the left and right bounding spheres. * * @param {BoundingSphere} left A sphere to enclose in a bounding sphere. * @param {BoundingSphere} right A sphere to enclose in a bounding sphere. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static union(left, right, result) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); if (!defined_default(result)) { result = new _BoundingSphere(); } const leftCenter = left.center; const leftRadius = left.radius; const rightCenter = right.center; const rightRadius = right.radius; const toRightCenter = Cartesian3_default.subtract( rightCenter, leftCenter, unionScratch ); const centerSeparation = Cartesian3_default.magnitude(toRightCenter); if (leftRadius >= centerSeparation + rightRadius) { left.clone(result); return result; } if (rightRadius >= centerSeparation + leftRadius) { right.clone(result); return result; } const halfDistanceBetweenTangentPoints = (leftRadius + centerSeparation + rightRadius) * 0.5; const center = Cartesian3_default.multiplyByScalar( toRightCenter, (-leftRadius + halfDistanceBetweenTangentPoints) / centerSeparation, unionScratchCenter ); Cartesian3_default.add(center, leftCenter, center); Cartesian3_default.clone(center, result.center); result.radius = halfDistanceBetweenTangentPoints; return result; } /** * Computes a bounding sphere by enlarging the provided sphere to contain the provided point. * * @param {BoundingSphere} sphere A sphere to expand. * @param {Cartesian3} point A point to enclose in a bounding sphere. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static expand(sphere, point4, result) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("point", point4); result = _BoundingSphere.clone(sphere, result); const radius = Cartesian3_default.magnitude( Cartesian3_default.subtract(point4, result.center, expandScratch) ); if (radius > result.radius) { result.radius = radius; } return result; } /** * Determines which side of a plane a sphere is located. * * @param {BoundingSphere} sphere The bounding sphere to test. * @param {Plane} plane The plane to test against. * @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane * the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is * on the opposite side, and {@link Intersect.INTERSECTING} if the sphere * intersects the plane. */ static intersectPlane(sphere, plane) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("plane", plane); const center = sphere.center; const radius = sphere.radius; const normal2 = plane.normal; const distanceToPlane = Cartesian3_default.dot(normal2, center) + plane.distance; if (distanceToPlane < -radius) { return Intersect_default.OUTSIDE; } else if (distanceToPlane < radius) { return Intersect_default.INTERSECTING; } return Intersect_default.INSIDE; } /** * Applies a 4x4 affine transformation matrix to a bounding sphere. * * @param {BoundingSphere} sphere The bounding sphere to apply the transformation to. * @param {Matrix4} transform The transformation matrix to apply to the bounding sphere. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static transform(sphere, transform3, result) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("transform", transform3); if (!defined_default(result)) { result = new _BoundingSphere(); } result.center = Matrix4_default.multiplyByPoint( transform3, sphere.center, result.center ); result.radius = Matrix4_default.getMaximumScale(transform3) * sphere.radius; return result; } /** * Computes the estimated distance squared from the closest point on a bounding sphere to a point. * * @param {BoundingSphere} sphere The sphere. * @param {Cartesian3} cartesian The point * @returns {number} The distance squared from the bounding sphere to the point. Returns 0 if the point is inside the sphere. * * @example * // Sort bounding spheres from back to front * spheres.sort(function(a, b) { * return Cesium.BoundingSphere.distanceSquaredTo(b, camera.positionWC) - Cesium.BoundingSphere.distanceSquaredTo(a, camera.positionWC); * }); */ static distanceSquaredTo(sphere, cartesian11) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("cartesian", cartesian11); const diff = Cartesian3_default.subtract( sphere.center, cartesian11, distanceSquaredToScratch ); const distance2 = Cartesian3_default.magnitude(diff) - sphere.radius; if (distance2 <= 0) { return 0; } return distance2 * distance2; } /** * Applies a 4x4 affine transformation matrix to a bounding sphere where there is no scale * The transformation matrix is not verified to have a uniform scale of 1. * This method is faster than computing the general bounding sphere transform using {@link BoundingSphere.transform}. * * @param {BoundingSphere} sphere The bounding sphere to apply the transformation to. * @param {Matrix4} transform The transformation matrix to apply to the bounding sphere. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. * * @example * const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid); * const boundingSphere = new Cesium.BoundingSphere(); * const newBoundingSphere = Cesium.BoundingSphere.transformWithoutScale(boundingSphere, modelMatrix); */ static transformWithoutScale(sphere, transform3, result) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("transform", transform3); if (!defined_default(result)) { result = new _BoundingSphere(); } result.center = Matrix4_default.multiplyByPoint( transform3, sphere.center, result.center ); result.radius = sphere.radius; return result; } /** * The distances calculated by the vector from the center of the bounding sphere to position projected onto direction * plus/minus the radius of the bounding sphere. *
* If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the * closest and farthest planes from position that intersect the bounding sphere. * * @param {BoundingSphere} sphere The bounding sphere to calculate the distance to. * @param {Cartesian3} position The position to calculate the distance from. * @param {Cartesian3} direction The direction from position. * @param {Interval} [result] A Interval to store the nearest and farthest distances. * @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction. */ static computePlaneDistances(sphere, position, direction2, result) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("position", position); Check_default.typeOf.object("direction", direction2); if (!defined_default(result)) { result = new Interval_default(); } const toCenter = Cartesian3_default.subtract( sphere.center, position, scratchCartesian3 ); const mag = Cartesian3_default.dot(direction2, toCenter); result.start = mag - sphere.radius; result.stop = mag + sphere.radius; return result; } /** * Creates a bounding sphere in 2D from a bounding sphere in 3D world coordinates. * * @param {BoundingSphere} sphere The bounding sphere to transform to 2D. * @param {MapProjection} [projection=GeographicProjection] The projection to 2D. * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ static projectTo2D(sphere, projection, result) { Check_default.typeOf.object("sphere", sphere); projectTo2DProjection._ellipsoid = Ellipsoid_default.default; projection = projection ?? projectTo2DProjection; const ellipsoid = projection.ellipsoid; let center = sphere.center; const radius = sphere.radius; let normal2; if (Cartesian3_default.equals(center, Cartesian3_default.ZERO)) { normal2 = Cartesian3_default.clone(Cartesian3_default.UNIT_X, projectTo2DNormalScratch); } else { normal2 = ellipsoid.geodeticSurfaceNormal( center, projectTo2DNormalScratch ); } const east = Cartesian3_default.cross( Cartesian3_default.UNIT_Z, normal2, projectTo2DEastScratch ); Cartesian3_default.normalize(east, east); const north = Cartesian3_default.cross(normal2, east, projectTo2DNorthScratch); Cartesian3_default.normalize(north, north); Cartesian3_default.multiplyByScalar(normal2, radius, normal2); Cartesian3_default.multiplyByScalar(north, radius, north); Cartesian3_default.multiplyByScalar(east, radius, east); const south = Cartesian3_default.negate(north, projectTo2DSouthScratch); const west = Cartesian3_default.negate(east, projectTo2DWestScratch); const positions = projectTo2DPositionsScratch; let corner = positions[0]; Cartesian3_default.add(normal2, north, corner); Cartesian3_default.add(corner, east, corner); corner = positions[1]; Cartesian3_default.add(normal2, north, corner); Cartesian3_default.add(corner, west, corner); corner = positions[2]; Cartesian3_default.add(normal2, south, corner); Cartesian3_default.add(corner, west, corner); corner = positions[3]; Cartesian3_default.add(normal2, south, corner); Cartesian3_default.add(corner, east, corner); Cartesian3_default.negate(normal2, normal2); corner = positions[4]; Cartesian3_default.add(normal2, north, corner); Cartesian3_default.add(corner, east, corner); corner = positions[5]; Cartesian3_default.add(normal2, north, corner); Cartesian3_default.add(corner, west, corner); corner = positions[6]; Cartesian3_default.add(normal2, south, corner); Cartesian3_default.add(corner, west, corner); corner = positions[7]; Cartesian3_default.add(normal2, south, corner); Cartesian3_default.add(corner, east, corner); const length2 = positions.length; for (let i = 0; i < length2; ++i) { const position = positions[i]; Cartesian3_default.add(center, position, position); const cartographic2 = ellipsoid.cartesianToCartographic( position, projectTo2DCartographicScratch ); projection.project(cartographic2, position); } result = _BoundingSphere.fromPoints(positions, result); center = result.center; const x = center.x; const y = center.y; const z2 = center.z; center.x = z2; center.y = x; center.z = y; return result; } /** * Determines whether or not a sphere is hidden from view by the occluder. * * @param {BoundingSphere} sphere The bounding sphere surrounding the occluded object. * @param {Occluder} occluder The occluder. * @returns {boolean} true if the sphere is not visible; otherwise false. */ static isOccluded(sphere, occluder) { Check_default.typeOf.object("sphere", sphere); Check_default.typeOf.object("occluder", occluder); return !occluder.isBoundingSphereVisible(sphere); } /** * Compares the provided BoundingSphere componentwise and returns * true if they are equal, false otherwise. * * @param {BoundingSphere} [left] The first BoundingSphere. * @param {BoundingSphere} [right] The second BoundingSphere. * @returns {boolean} true if left and right are equal, false otherwise. */ static equals(left, right) { return left === right || defined_default(left) && defined_default(right) && Cartesian3_default.equals(left.center, right.center) && left.radius === right.radius; } /** * Determines which side of a plane the sphere is located. * * @param {Plane} plane The plane to test against. * @returns {Intersect} {@link Intersect.INSIDE} if the entire sphere is on the side of the plane * the normal is pointing, {@link Intersect.OUTSIDE} if the entire sphere is * on the opposite side, and {@link Intersect.INTERSECTING} if the sphere * intersects the plane. */ intersectPlane(plane) { return _BoundingSphere.intersectPlane(this, plane); } /** * Computes the estimated distance squared from the closest point on a bounding sphere to a point. * * @param {Cartesian3} cartesian The point * @returns {number} The estimated distance squared from the bounding sphere to the point. * * @example * // Sort bounding spheres from back to front * spheres.sort(function(a, b) { * return b.distanceSquaredTo(camera.positionWC) - a.distanceSquaredTo(camera.positionWC); * }); */ distanceSquaredTo(cartesian11) { return _BoundingSphere.distanceSquaredTo(this, cartesian11); } /** * The distances calculated by the vector from the center of the bounding sphere to position projected onto direction * plus/minus the radius of the bounding sphere. *
* If you imagine the infinite number of planes with normal direction, this computes the smallest distance to the * closest and farthest planes from position that intersect the bounding sphere. * * @param {Cartesian3} position The position to calculate the distance from. * @param {Cartesian3} direction The direction from position. * @param {Interval} [result] A Interval to store the nearest and farthest distances. * @returns {Interval} The nearest and farthest distances on the bounding sphere from position in direction. */ computePlaneDistances(position, direction2, result) { return _BoundingSphere.computePlaneDistances( this, position, direction2, result ); } /** * Determines whether or not a sphere is hidden from view by the occluder. * * @param {Occluder} occluder The occluder. * @returns {boolean} true if the sphere is not visible; otherwise false. */ isOccluded(occluder) { return _BoundingSphere.isOccluded(this, occluder); } /** * Compares this BoundingSphere against the provided BoundingSphere componentwise and returns * true if they are equal, false otherwise. * * @param {BoundingSphere} [right] The right hand side BoundingSphere. * @returns {boolean} true if they are equal, false otherwise. */ equals(right) { return _BoundingSphere.equals(this, right); } /** * Duplicates this BoundingSphere instance. * * @param {BoundingSphere} [result] The object onto which to store the result. * @returns {BoundingSphere} The modified result parameter or a new BoundingSphere instance if none was provided. */ clone(result) { return _BoundingSphere.clone(this, result); } /** * Computes the radius of the BoundingSphere. * @returns {number} The radius of the BoundingSphere. */ volume() { const radius = this.radius; return volumeConstant * radius * radius * radius; } }; BoundingSphere.packedLength = 4; var fromPointsXMin = new Cartesian3_default(); var fromPointsYMin = new Cartesian3_default(); var fromPointsZMin = new Cartesian3_default(); var fromPointsXMax = new Cartesian3_default(); var fromPointsYMax = new Cartesian3_default(); var fromPointsZMax = new Cartesian3_default(); var fromPointsCurrentPos = new Cartesian3_default(); var fromPointsScratch = new Cartesian3_default(); var fromPointsRitterCenter = new Cartesian3_default(); var fromPointsMinBoxPt = new Cartesian3_default(); var fromPointsMaxBoxPt = new Cartesian3_default(); var fromPointsNaiveCenterScratch = new Cartesian3_default(); var volumeConstant = 4 / 3 * Math_default.PI; var defaultProjection2 = new GeographicProjection_default(); var fromRectangle2DLowerLeft = new Cartesian3_default(); var fromRectangle2DUpperRight = new Cartesian3_default(); var fromRectangle2DSouthwest = new Cartographic_default(); var fromRectangle2DNortheast = new Cartographic_default(); var fromRectangle3DScratch = ( /** @type {Cartesian3[]} */ [] ); var fromOrientedBoundingBoxScratchU = new Cartesian3_default(); var fromOrientedBoundingBoxScratchV = new Cartesian3_default(); var fromOrientedBoundingBoxScratchW = new Cartesian3_default(); var scratchFromTransformationCenter = new Cartesian3_default(); var scratchFromTransformationScale = new Cartesian3_default(); var unionScratch = new Cartesian3_default(); var unionScratchCenter = new Cartesian3_default(); var expandScratch = new Cartesian3_default(); var distanceSquaredToScratch = new Cartesian3_default(); var scratchCartesian3 = new Cartesian3_default(); var projectTo2DNormalScratch = new Cartesian3_default(); var projectTo2DEastScratch = new Cartesian3_default(); var projectTo2DNorthScratch = new Cartesian3_default(); var projectTo2DWestScratch = new Cartesian3_default(); var projectTo2DSouthScratch = new Cartesian3_default(); var projectTo2DCartographicScratch = new Cartographic_default(); var projectTo2DPositionsScratch = new Array(8); for (let n2 = 0; n2 < 8; ++n2) { projectTo2DPositionsScratch[n2] = new Cartesian3_default(); } var projectTo2DProjection = new GeographicProjection_default(); var BoundingSphere_default = BoundingSphere; // packages/engine/Source/Core/GeometryAttributes.js var import_InlineWorkers96 = __toESM(require_InlineWorkers(), 1); function GeometryAttributes(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.position = options.position; this.normal = options.normal; this.st = options.st; this.bitangent = options.bitangent; this.tangent = options.tangent; this.color = options.color; } var GeometryAttributes_default = GeometryAttributes; // packages/engine/Source/Core/GeometryOffsetAttribute.js var import_InlineWorkers97 = __toESM(require_InlineWorkers(), 1); var GeometryOffsetAttribute = { NONE: 0, TOP: 1, ALL: 2 }; Object.freeze(GeometryOffsetAttribute); var GeometryOffsetAttribute_default = GeometryOffsetAttribute; // packages/engine/Source/Core/VertexFormat.js var import_InlineWorkers98 = __toESM(require_InlineWorkers(), 1); function VertexFormat(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.position = options.position ?? false; this.normal = options.normal ?? false; this.st = options.st ?? false; this.bitangent = options.bitangent ?? false; this.tangent = options.tangent ?? false; this.color = options.color ?? false; } VertexFormat.POSITION_ONLY = Object.freeze( new VertexFormat({ position: true }) ); VertexFormat.POSITION_AND_NORMAL = Object.freeze( new VertexFormat({ position: true, normal: true }) ); VertexFormat.POSITION_NORMAL_AND_ST = Object.freeze( new VertexFormat({ position: true, normal: true, st: true }) ); VertexFormat.POSITION_AND_ST = Object.freeze( new VertexFormat({ position: true, st: true }) ); VertexFormat.POSITION_AND_COLOR = Object.freeze( new VertexFormat({ position: true, color: true }) ); VertexFormat.ALL = Object.freeze( new VertexFormat({ position: true, normal: true, st: true, tangent: true, bitangent: true }) ); VertexFormat.DEFAULT = VertexFormat.POSITION_NORMAL_AND_ST; VertexFormat.packedLength = 6; VertexFormat.pack = function(value, array, startingIndex) { if (!defined_default(value)) { throw new DeveloperError_default("value is required"); } if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; array[startingIndex++] = value.position ? 1 : 0; array[startingIndex++] = value.normal ? 1 : 0; array[startingIndex++] = value.st ? 1 : 0; array[startingIndex++] = value.tangent ? 1 : 0; array[startingIndex++] = value.bitangent ? 1 : 0; array[startingIndex] = value.color ? 1 : 0; return array; }; VertexFormat.unpack = function(array, startingIndex, result) { if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new VertexFormat(); } result.position = array[startingIndex++] === 1; result.normal = array[startingIndex++] === 1; result.st = array[startingIndex++] === 1; result.tangent = array[startingIndex++] === 1; result.bitangent = array[startingIndex++] === 1; result.color = array[startingIndex] === 1; return result; }; VertexFormat.clone = function(vertexFormat, result) { if (!defined_default(vertexFormat)) { return void 0; } if (!defined_default(result)) { result = new VertexFormat(); } result.position = vertexFormat.position; result.normal = vertexFormat.normal; result.st = vertexFormat.st; result.tangent = vertexFormat.tangent; result.bitangent = vertexFormat.bitangent; result.color = vertexFormat.color; return result; }; var VertexFormat_default = VertexFormat; // packages/engine/Source/Core/BoxGeometry.js var diffScratch = new Cartesian3_default(); function BoxGeometry(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const min3 = options.minimum; const max3 = options.maximum; Check_default.typeOf.object("min", min3); Check_default.typeOf.object("max", max3); if (defined_default(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute_default.TOP) { throw new DeveloperError_default( "GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry." ); } const vertexFormat = options.vertexFormat ?? VertexFormat_default.DEFAULT; this._minimum = Cartesian3_default.clone(min3); this._maximum = Cartesian3_default.clone(max3); this._vertexFormat = vertexFormat; this._offsetAttribute = options.offsetAttribute; this._workerName = "createBoxGeometry"; } BoxGeometry.fromDimensions = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const dimensions = options.dimensions; Check_default.typeOf.object("dimensions", dimensions); Check_default.typeOf.number.greaterThanOrEquals("dimensions.x", dimensions.x, 0); Check_default.typeOf.number.greaterThanOrEquals("dimensions.y", dimensions.y, 0); Check_default.typeOf.number.greaterThanOrEquals("dimensions.z", dimensions.z, 0); const corner = Cartesian3_default.multiplyByScalar(dimensions, 0.5, new Cartesian3_default()); return new BoxGeometry({ minimum: Cartesian3_default.negate(corner, new Cartesian3_default()), maximum: corner, vertexFormat: options.vertexFormat, offsetAttribute: options.offsetAttribute }); }; BoxGeometry.fromAxisAlignedBoundingBox = function(boundingBox) { Check_default.typeOf.object("boundingBox", boundingBox); return new BoxGeometry({ minimum: boundingBox.minimum, maximum: boundingBox.maximum }); }; BoxGeometry.packedLength = 2 * Cartesian3_default.packedLength + VertexFormat_default.packedLength + 1; BoxGeometry.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; Cartesian3_default.pack(value._minimum, array, startingIndex); Cartesian3_default.pack( value._maximum, array, startingIndex + Cartesian3_default.packedLength ); VertexFormat_default.pack( value._vertexFormat, array, startingIndex + 2 * Cartesian3_default.packedLength ); array[startingIndex + 2 * Cartesian3_default.packedLength + VertexFormat_default.packedLength] = value._offsetAttribute ?? -1; return array; }; var scratchMin = new Cartesian3_default(); var scratchMax = new Cartesian3_default(); var scratchVertexFormat = new VertexFormat_default(); var scratchOptions = { minimum: scratchMin, maximum: scratchMax, vertexFormat: scratchVertexFormat, offsetAttribute: void 0 }; BoxGeometry.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; const min3 = Cartesian3_default.unpack(array, startingIndex, scratchMin); const max3 = Cartesian3_default.unpack( array, startingIndex + Cartesian3_default.packedLength, scratchMax ); const vertexFormat = VertexFormat_default.unpack( array, startingIndex + 2 * Cartesian3_default.packedLength, scratchVertexFormat ); const offsetAttribute = array[startingIndex + 2 * Cartesian3_default.packedLength + VertexFormat_default.packedLength]; if (!defined_default(result)) { scratchOptions.offsetAttribute = offsetAttribute === -1 ? void 0 : offsetAttribute; return new BoxGeometry(scratchOptions); } result._minimum = Cartesian3_default.clone(min3, result._minimum); result._maximum = Cartesian3_default.clone(max3, result._maximum); result._vertexFormat = VertexFormat_default.clone(vertexFormat, result._vertexFormat); result._offsetAttribute = offsetAttribute === -1 ? void 0 : offsetAttribute; return result; }; BoxGeometry.createGeometry = function(boxGeometry) { const min3 = boxGeometry._minimum; const max3 = boxGeometry._maximum; const vertexFormat = boxGeometry._vertexFormat; if (Cartesian3_default.equals(min3, max3)) { return; } const attributes = new GeometryAttributes_default(); let indices; let positions; if (vertexFormat.position && (vertexFormat.st || vertexFormat.normal || vertexFormat.tangent || vertexFormat.bitangent)) { if (vertexFormat.position) { positions = new Float64Array(6 * 4 * 3); positions[0] = min3.x; positions[1] = min3.y; positions[2] = max3.z; positions[3] = max3.x; positions[4] = min3.y; positions[5] = max3.z; positions[6] = max3.x; positions[7] = max3.y; positions[8] = max3.z; positions[9] = min3.x; positions[10] = max3.y; positions[11] = max3.z; positions[12] = min3.x; positions[13] = min3.y; positions[14] = min3.z; positions[15] = max3.x; positions[16] = min3.y; positions[17] = min3.z; positions[18] = max3.x; positions[19] = max3.y; positions[20] = min3.z; positions[21] = min3.x; positions[22] = max3.y; positions[23] = min3.z; positions[24] = max3.x; positions[25] = min3.y; positions[26] = min3.z; positions[27] = max3.x; positions[28] = max3.y; positions[29] = min3.z; positions[30] = max3.x; positions[31] = max3.y; positions[32] = max3.z; positions[33] = max3.x; positions[34] = min3.y; positions[35] = max3.z; positions[36] = min3.x; positions[37] = min3.y; positions[38] = min3.z; positions[39] = min3.x; positions[40] = max3.y; positions[41] = min3.z; positions[42] = min3.x; positions[43] = max3.y; positions[44] = max3.z; positions[45] = min3.x; positions[46] = min3.y; positions[47] = max3.z; positions[48] = min3.x; positions[49] = max3.y; positions[50] = min3.z; positions[51] = max3.x; positions[52] = max3.y; positions[53] = min3.z; positions[54] = max3.x; positions[55] = max3.y; positions[56] = max3.z; positions[57] = min3.x; positions[58] = max3.y; positions[59] = max3.z; positions[60] = min3.x; positions[61] = min3.y; positions[62] = min3.z; positions[63] = max3.x; positions[64] = min3.y; positions[65] = min3.z; positions[66] = max3.x; positions[67] = min3.y; positions[68] = max3.z; positions[69] = min3.x; positions[70] = min3.y; positions[71] = max3.z; attributes.position = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, values: positions }); } if (vertexFormat.normal) { const normals = new Float32Array(6 * 4 * 3); normals[0] = 0; normals[1] = 0; normals[2] = 1; normals[3] = 0; normals[4] = 0; normals[5] = 1; normals[6] = 0; normals[7] = 0; normals[8] = 1; normals[9] = 0; normals[10] = 0; normals[11] = 1; normals[12] = 0; normals[13] = 0; normals[14] = -1; normals[15] = 0; normals[16] = 0; normals[17] = -1; normals[18] = 0; normals[19] = 0; normals[20] = -1; normals[21] = 0; normals[22] = 0; normals[23] = -1; normals[24] = 1; normals[25] = 0; normals[26] = 0; normals[27] = 1; normals[28] = 0; normals[29] = 0; normals[30] = 1; normals[31] = 0; normals[32] = 0; normals[33] = 1; normals[34] = 0; normals[35] = 0; normals[36] = -1; normals[37] = 0; normals[38] = 0; normals[39] = -1; normals[40] = 0; normals[41] = 0; normals[42] = -1; normals[43] = 0; normals[44] = 0; normals[45] = -1; normals[46] = 0; normals[47] = 0; normals[48] = 0; normals[49] = 1; normals[50] = 0; normals[51] = 0; normals[52] = 1; normals[53] = 0; normals[54] = 0; normals[55] = 1; normals[56] = 0; normals[57] = 0; normals[58] = 1; normals[59] = 0; normals[60] = 0; normals[61] = -1; normals[62] = 0; normals[63] = 0; normals[64] = -1; normals[65] = 0; normals[66] = 0; normals[67] = -1; normals[68] = 0; normals[69] = 0; normals[70] = -1; normals[71] = 0; attributes.normal = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: normals }); } if (vertexFormat.st) { const texCoords = new Float32Array(6 * 4 * 2); texCoords[0] = 0; texCoords[1] = 0; texCoords[2] = 1; texCoords[3] = 0; texCoords[4] = 1; texCoords[5] = 1; texCoords[6] = 0; texCoords[7] = 1; texCoords[8] = 1; texCoords[9] = 0; texCoords[10] = 0; texCoords[11] = 0; texCoords[12] = 0; texCoords[13] = 1; texCoords[14] = 1; texCoords[15] = 1; texCoords[16] = 0; texCoords[17] = 0; texCoords[18] = 1; texCoords[19] = 0; texCoords[20] = 1; texCoords[21] = 1; texCoords[22] = 0; texCoords[23] = 1; texCoords[24] = 1; texCoords[25] = 0; texCoords[26] = 0; texCoords[27] = 0; texCoords[28] = 0; texCoords[29] = 1; texCoords[30] = 1; texCoords[31] = 1; texCoords[32] = 1; texCoords[33] = 0; texCoords[34] = 0; texCoords[35] = 0; texCoords[36] = 0; texCoords[37] = 1; texCoords[38] = 1; texCoords[39] = 1; texCoords[40] = 0; texCoords[41] = 0; texCoords[42] = 1; texCoords[43] = 0; texCoords[44] = 1; texCoords[45] = 1; texCoords[46] = 0; texCoords[47] = 1; attributes.st = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 2, values: texCoords }); } if (vertexFormat.tangent) { const tangents = new Float32Array(6 * 4 * 3); tangents[0] = 1; tangents[1] = 0; tangents[2] = 0; tangents[3] = 1; tangents[4] = 0; tangents[5] = 0; tangents[6] = 1; tangents[7] = 0; tangents[8] = 0; tangents[9] = 1; tangents[10] = 0; tangents[11] = 0; tangents[12] = -1; tangents[13] = 0; tangents[14] = 0; tangents[15] = -1; tangents[16] = 0; tangents[17] = 0; tangents[18] = -1; tangents[19] = 0; tangents[20] = 0; tangents[21] = -1; tangents[22] = 0; tangents[23] = 0; tangents[24] = 0; tangents[25] = 1; tangents[26] = 0; tangents[27] = 0; tangents[28] = 1; tangents[29] = 0; tangents[30] = 0; tangents[31] = 1; tangents[32] = 0; tangents[33] = 0; tangents[34] = 1; tangents[35] = 0; tangents[36] = 0; tangents[37] = -1; tangents[38] = 0; tangents[39] = 0; tangents[40] = -1; tangents[41] = 0; tangents[42] = 0; tangents[43] = -1; tangents[44] = 0; tangents[45] = 0; tangents[46] = -1; tangents[47] = 0; tangents[48] = -1; tangents[49] = 0; tangents[50] = 0; tangents[51] = -1; tangents[52] = 0; tangents[53] = 0; tangents[54] = -1; tangents[55] = 0; tangents[56] = 0; tangents[57] = -1; tangents[58] = 0; tangents[59] = 0; tangents[60] = 1; tangents[61] = 0; tangents[62] = 0; tangents[63] = 1; tangents[64] = 0; tangents[65] = 0; tangents[66] = 1; tangents[67] = 0; tangents[68] = 0; tangents[69] = 1; tangents[70] = 0; tangents[71] = 0; attributes.tangent = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: tangents }); } if (vertexFormat.bitangent) { const bitangents = new Float32Array(6 * 4 * 3); bitangents[0] = 0; bitangents[1] = 1; bitangents[2] = 0; bitangents[3] = 0; bitangents[4] = 1; bitangents[5] = 0; bitangents[6] = 0; bitangents[7] = 1; bitangents[8] = 0; bitangents[9] = 0; bitangents[10] = 1; bitangents[11] = 0; bitangents[12] = 0; bitangents[13] = 1; bitangents[14] = 0; bitangents[15] = 0; bitangents[16] = 1; bitangents[17] = 0; bitangents[18] = 0; bitangents[19] = 1; bitangents[20] = 0; bitangents[21] = 0; bitangents[22] = 1; bitangents[23] = 0; bitangents[24] = 0; bitangents[25] = 0; bitangents[26] = 1; bitangents[27] = 0; bitangents[28] = 0; bitangents[29] = 1; bitangents[30] = 0; bitangents[31] = 0; bitangents[32] = 1; bitangents[33] = 0; bitangents[34] = 0; bitangents[35] = 1; bitangents[36] = 0; bitangents[37] = 0; bitangents[38] = 1; bitangents[39] = 0; bitangents[40] = 0; bitangents[41] = 1; bitangents[42] = 0; bitangents[43] = 0; bitangents[44] = 1; bitangents[45] = 0; bitangents[46] = 0; bitangents[47] = 1; bitangents[48] = 0; bitangents[49] = 0; bitangents[50] = 1; bitangents[51] = 0; bitangents[52] = 0; bitangents[53] = 1; bitangents[54] = 0; bitangents[55] = 0; bitangents[56] = 1; bitangents[57] = 0; bitangents[58] = 0; bitangents[59] = 1; bitangents[60] = 0; bitangents[61] = 0; bitangents[62] = 1; bitangents[63] = 0; bitangents[64] = 0; bitangents[65] = 1; bitangents[66] = 0; bitangents[67] = 0; bitangents[68] = 1; bitangents[69] = 0; bitangents[70] = 0; bitangents[71] = 1; attributes.bitangent = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: bitangents }); } indices = new Uint16Array(6 * 2 * 3); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; indices[6] = 4 + 2; indices[7] = 4 + 1; indices[8] = 4 + 0; indices[9] = 4 + 3; indices[10] = 4 + 2; indices[11] = 4 + 0; indices[12] = 8 + 0; indices[13] = 8 + 1; indices[14] = 8 + 2; indices[15] = 8 + 0; indices[16] = 8 + 2; indices[17] = 8 + 3; indices[18] = 12 + 2; indices[19] = 12 + 1; indices[20] = 12 + 0; indices[21] = 12 + 3; indices[22] = 12 + 2; indices[23] = 12 + 0; indices[24] = 16 + 2; indices[25] = 16 + 1; indices[26] = 16 + 0; indices[27] = 16 + 3; indices[28] = 16 + 2; indices[29] = 16 + 0; indices[30] = 20 + 0; indices[31] = 20 + 1; indices[32] = 20 + 2; indices[33] = 20 + 0; indices[34] = 20 + 2; indices[35] = 20 + 3; } else { positions = new Float64Array(8 * 3); positions[0] = min3.x; positions[1] = min3.y; positions[2] = min3.z; positions[3] = max3.x; positions[4] = min3.y; positions[5] = min3.z; positions[6] = max3.x; positions[7] = max3.y; positions[8] = min3.z; positions[9] = min3.x; positions[10] = max3.y; positions[11] = min3.z; positions[12] = min3.x; positions[13] = min3.y; positions[14] = max3.z; positions[15] = max3.x; positions[16] = min3.y; positions[17] = max3.z; positions[18] = max3.x; positions[19] = max3.y; positions[20] = max3.z; positions[21] = min3.x; positions[22] = max3.y; positions[23] = max3.z; attributes.position = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, values: positions }); indices = new Uint16Array(6 * 2 * 3); indices[0] = 4; indices[1] = 5; indices[2] = 6; indices[3] = 4; indices[4] = 6; indices[5] = 7; indices[6] = 1; indices[7] = 0; indices[8] = 3; indices[9] = 1; indices[10] = 3; indices[11] = 2; indices[12] = 1; indices[13] = 6; indices[14] = 5; indices[15] = 1; indices[16] = 2; indices[17] = 6; indices[18] = 2; indices[19] = 3; indices[20] = 7; indices[21] = 2; indices[22] = 7; indices[23] = 6; indices[24] = 3; indices[25] = 0; indices[26] = 4; indices[27] = 3; indices[28] = 4; indices[29] = 7; indices[30] = 0; indices[31] = 1; indices[32] = 5; indices[33] = 0; indices[34] = 5; indices[35] = 4; } const diff = Cartesian3_default.subtract(max3, min3, diffScratch); const radius = Cartesian3_default.magnitude(diff) * 0.5; if (defined_default(boxGeometry._offsetAttribute)) { const length2 = positions.length; const offsetValue = boxGeometry._offsetAttribute === GeometryOffsetAttribute_default.NONE ? 0 : 1; const applyOffset = new Uint8Array(length2 / 3).fill(offsetValue); attributes.applyOffset = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.UNSIGNED_BYTE, componentsPerAttribute: 1, values: applyOffset }); } return new Geometry_default({ attributes, indices, primitiveType: PrimitiveType_default.TRIANGLES, boundingSphere: new BoundingSphere_default(Cartesian3_default.ZERO, radius), offsetAttribute: boxGeometry._offsetAttribute }); }; var unitBoxGeometry; BoxGeometry.getUnitBox = function() { if (!defined_default(unitBoxGeometry)) { unitBoxGeometry = BoxGeometry.createGeometry( BoxGeometry.fromDimensions({ dimensions: new Cartesian3_default(1, 1, 1), vertexFormat: VertexFormat_default.POSITION_ONLY }) ); } return unitBoxGeometry; }; var BoxGeometry_default = BoxGeometry; // packages/engine/Source/Core/GeometryPipeline.js var import_InlineWorkers111 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/AttributeCompression.js var import_InlineWorkers101 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/AttributeType.js var import_InlineWorkers100 = __toESM(require_InlineWorkers(), 1); var AttributeType = { /** * The attribute is a single component. * * @type {string} * @constant */ SCALAR: "SCALAR", /** * The attribute is a two-component vector. * * @type {string} * @constant */ VEC2: "VEC2", /** * The attribute is a three-component vector. * * @type {string} * @constant */ VEC3: "VEC3", /** * The attribute is a four-component vector. * * @type {string} * @constant */ VEC4: "VEC4", /** * The attribute is a 2x2 matrix. * * @type {string} * @constant */ MAT2: "MAT2", /** * The attribute is a 3x3 matrix. * * @type {string} * @constant */ MAT3: "MAT3", /** * The attribute is a 4x4 matrix. * * @type {string} * @constant */ MAT4: "MAT4" }; AttributeType.getMathType = function(attributeType) { switch (attributeType) { case AttributeType.SCALAR: return Number; case AttributeType.VEC2: return Cartesian2_default; case AttributeType.VEC3: return Cartesian3_default; case AttributeType.VEC4: return Cartesian4_default; case AttributeType.MAT2: return Matrix2_default; case AttributeType.MAT3: return Matrix3_default; case AttributeType.MAT4: return Matrix4_default; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("attributeType is not a valid value."); } }; AttributeType.getNumberOfComponents = function(attributeType) { switch (attributeType) { case AttributeType.SCALAR: return 1; case AttributeType.VEC2: return 2; case AttributeType.VEC3: return 3; case AttributeType.VEC4: case AttributeType.MAT2: return 4; case AttributeType.MAT3: return 9; case AttributeType.MAT4: return 16; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("attributeType is not a valid value."); } }; AttributeType.getAttributeLocationCount = function(attributeType) { switch (attributeType) { case AttributeType.SCALAR: case AttributeType.VEC2: case AttributeType.VEC3: case AttributeType.VEC4: return 1; case AttributeType.MAT2: return 2; case AttributeType.MAT3: return 3; case AttributeType.MAT4: return 4; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("attributeType is not a valid value."); } }; AttributeType.getGlslType = function(attributeType) { Check_default.typeOf.string("attributeType", attributeType); switch (attributeType) { case AttributeType.SCALAR: return "float"; case AttributeType.VEC2: return "vec2"; case AttributeType.VEC3: return "vec3"; case AttributeType.VEC4: return "vec4"; case AttributeType.MAT2: return "mat2"; case AttributeType.MAT3: return "mat3"; case AttributeType.MAT4: return "mat4"; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default("attributeType is not a valid value."); } }; Object.freeze(AttributeType); var AttributeType_default = AttributeType; // packages/engine/Source/Core/AttributeCompression.js var RIGHT_SHIFT8 = 1 / 256; var LEFT_SHIFT16 = 65536; var LEFT_SHIFT8 = 256; var AttributeCompression = {}; AttributeCompression.octEncodeInRange = function(vector, rangeMax, result) { Check_default.defined("vector", vector); Check_default.defined("result", result); const magSquared = Cartesian3_default.magnitudeSquared(vector); if (Math.abs(magSquared - 1) > Math_default.EPSILON6) { throw new DeveloperError_default("vector must be normalized."); } result.x = vector.x / (Math.abs(vector.x) + Math.abs(vector.y) + Math.abs(vector.z)); result.y = vector.y / (Math.abs(vector.x) + Math.abs(vector.y) + Math.abs(vector.z)); if (vector.z < 0) { const x = result.x; const y = result.y; result.x = (1 - Math.abs(y)) * Math_default.signNotZero(x); result.y = (1 - Math.abs(x)) * Math_default.signNotZero(y); } result.x = Math_default.toSNorm(result.x, rangeMax); result.y = Math_default.toSNorm(result.y, rangeMax); return result; }; AttributeCompression.octEncode = function(vector, result) { return AttributeCompression.octEncodeInRange(vector, 255, result); }; var octEncodeScratch = new Cartesian2_default(); var uint8ForceArray = new Uint8Array(1); function forceUint8(value) { uint8ForceArray[0] = value; return uint8ForceArray[0]; } AttributeCompression.octEncodeToCartesian4 = function(vector, result) { AttributeCompression.octEncodeInRange(vector, 65535, octEncodeScratch); result.x = forceUint8(octEncodeScratch.x * RIGHT_SHIFT8); result.y = forceUint8(octEncodeScratch.x); result.z = forceUint8(octEncodeScratch.y * RIGHT_SHIFT8); result.w = forceUint8(octEncodeScratch.y); return result; }; AttributeCompression.octDecodeInRange = function(x, y, rangeMax, result) { Check_default.defined("result", result); if (x < 0 || x > rangeMax || y < 0 || y > rangeMax) { throw new DeveloperError_default( `x and y must be unsigned normalized integers between 0 and ${rangeMax}` ); } result.x = Math_default.fromSNorm(x, rangeMax); result.y = Math_default.fromSNorm(y, rangeMax); result.z = 1 - (Math.abs(result.x) + Math.abs(result.y)); if (result.z < 0) { const oldVX = result.x; result.x = (1 - Math.abs(result.y)) * Math_default.signNotZero(oldVX); result.y = (1 - Math.abs(oldVX)) * Math_default.signNotZero(result.y); } return Cartesian3_default.normalize(result, result); }; AttributeCompression.octDecode = function(x, y, result) { return AttributeCompression.octDecodeInRange(x, y, 255, result); }; AttributeCompression.octDecodeFromCartesian4 = function(encoded, result) { Check_default.typeOf.object("encoded", encoded); Check_default.typeOf.object("result", result); const x = encoded.x; const y = encoded.y; const z2 = encoded.z; const w = encoded.w; if (x < 0 || x > 255 || y < 0 || y > 255 || z2 < 0 || z2 > 255 || w < 0 || w > 255) { throw new DeveloperError_default( "x, y, z, and w must be unsigned normalized integers between 0 and 255" ); } const xOct16 = x * LEFT_SHIFT8 + y; const yOct16 = z2 * LEFT_SHIFT8 + w; return AttributeCompression.octDecodeInRange(xOct16, yOct16, 65535, result); }; AttributeCompression.octPackFloat = function(encoded) { Check_default.defined("encoded", encoded); return 256 * encoded.x + encoded.y; }; var scratchEncodeCart2 = new Cartesian2_default(); AttributeCompression.octEncodeFloat = function(vector) { AttributeCompression.octEncode(vector, scratchEncodeCart2); return AttributeCompression.octPackFloat(scratchEncodeCart2); }; AttributeCompression.octDecodeFloat = function(value, result) { Check_default.defined("value", value); const temp = value / 256; const x = Math.floor(temp); const y = (temp - x) * 256; return AttributeCompression.octDecode(x, y, result); }; AttributeCompression.octPack = function(v12, v22, v3, result) { Check_default.defined("v1", v12); Check_default.defined("v2", v22); Check_default.defined("v3", v3); Check_default.defined("result", result); const encoded1 = AttributeCompression.octEncodeFloat(v12); const encoded2 = AttributeCompression.octEncodeFloat(v22); const encoded3 = AttributeCompression.octEncode(v3, scratchEncodeCart2); result.x = 65536 * encoded3.x + encoded1; result.y = 65536 * encoded3.y + encoded2; return result; }; AttributeCompression.octUnpack = function(packed, v12, v22, v3) { Check_default.defined("packed", packed); Check_default.defined("v1", v12); Check_default.defined("v2", v22); Check_default.defined("v3", v3); let temp = packed.x / 65536; const x = Math.floor(temp); const encodedFloat1 = (temp - x) * 65536; temp = packed.y / 65536; const y = Math.floor(temp); const encodedFloat2 = (temp - y) * 65536; AttributeCompression.octDecodeFloat(encodedFloat1, v12); AttributeCompression.octDecodeFloat(encodedFloat2, v22); AttributeCompression.octDecode(x, y, v3); }; AttributeCompression.compressTextureCoordinates = function(textureCoordinates) { Check_default.defined("textureCoordinates", textureCoordinates); const x = textureCoordinates.x * 4095 | 0; const y = textureCoordinates.y * 4095 | 0; return 4096 * x + y; }; AttributeCompression.decompressTextureCoordinates = function(compressed, result) { Check_default.defined("compressed", compressed); Check_default.defined("result", result); const temp = compressed / 4096; const xZeroTo4095 = Math.floor(temp); result.x = xZeroTo4095 / 4095; result.y = (compressed - xZeroTo4095 * 4096) / 4095; return result; }; function zigZagDecode(value) { return value >> 1 ^ -(value & 1); } AttributeCompression.zigZagDeltaDecode = function(uBuffer, vBuffer, heightBuffer) { Check_default.defined("uBuffer", uBuffer); Check_default.defined("vBuffer", vBuffer); Check_default.typeOf.number.equals( "uBuffer.length", "vBuffer.length", uBuffer.length, vBuffer.length ); if (defined_default(heightBuffer)) { Check_default.typeOf.number.equals( "uBuffer.length", "heightBuffer.length", uBuffer.length, heightBuffer.length ); } const count = uBuffer.length; let u4 = 0; let v3 = 0; let height = 0; for (let i = 0; i < count; ++i) { u4 += zigZagDecode(uBuffer[i]); v3 += zigZagDecode(vBuffer[i]); uBuffer[i] = u4; vBuffer[i] = v3; if (defined_default(heightBuffer)) { height += zigZagDecode(heightBuffer[i]); heightBuffer[i] = height; } } }; AttributeCompression.dequantize = function(typedArray, componentDatatype, type, count) { Check_default.defined("typedArray", typedArray); Check_default.defined("componentDatatype", componentDatatype); Check_default.defined("type", type); Check_default.defined("count", count); const componentsPerAttribute = AttributeType_default.getNumberOfComponents(type); let divisor; switch (componentDatatype) { case ComponentDatatype_default.BYTE: divisor = 127; break; case ComponentDatatype_default.UNSIGNED_BYTE: divisor = 255; break; case ComponentDatatype_default.SHORT: divisor = 32767; break; case ComponentDatatype_default.UNSIGNED_SHORT: divisor = 65535; break; case ComponentDatatype_default.INT: divisor = 2147483647; break; case ComponentDatatype_default.UNSIGNED_INT: divisor = 4294967295; break; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default( `Cannot dequantize component datatype: ${componentDatatype}` ); } const dequantizedTypedArray = new Float32Array( count * componentsPerAttribute ); for (let i = 0; i < count; i++) { for (let j = 0; j < componentsPerAttribute; j++) { const index = i * componentsPerAttribute + j; dequantizedTypedArray[index] = Math.max( typedArray[index] / divisor, -1 ); } } return dequantizedTypedArray; }; AttributeCompression.encodeRGB8 = function(color) { Check_default.typeOf.object("color", color); return Math.round(Math_default.clamp(color.red * 255, 0, 255)) * LEFT_SHIFT16 + Math.round(Math_default.clamp(color.green * 255, 0, 255)) * LEFT_SHIFT8 + Math.round(Math_default.clamp(color.blue * 255, 0, 255)); }; AttributeCompression.decodeRGB8 = function(encoded, result) { Check_default.typeOf.number("encoded", encoded); Check_default.typeOf.object("result", result); encoded = Math.floor(encoded); result.red = (encoded >> 16 & 255) / 255; result.green = (encoded >> 8 & 255) / 255; result.blue = (encoded & 255) / 255; return result; }; AttributeCompression.decodeRGB565 = function(typedArray, result) { Check_default.defined("typedArray", typedArray); const expectedLength = typedArray.length * 3; if (defined_default(result)) { Check_default.typeOf.number.equals( "result.length", "typedArray.length * 3", result.length, expectedLength ); } const count = typedArray.length; if (!defined_default(result)) { result = new Float32Array(count * 3); } const mask5 = (1 << 5) - 1; const mask6 = (1 << 6) - 1; const normalize5 = 1 / 31; const normalize6 = 1 / 63; for (let i = 0; i < count; i++) { const value = typedArray[i]; const red = value >> 11; const green = value >> 5 & mask6; const blue = value & mask5; const offset = 3 * i; result[offset] = red * normalize5; result[offset + 1] = green * normalize6; result[offset + 2] = blue * normalize5; } return result; }; var AttributeCompression_default = AttributeCompression; // packages/engine/Source/Core/barycentricCoordinates.js var import_InlineWorkers102 = __toESM(require_InlineWorkers(), 1); var scratchCartesian1 = new Cartesian3_default(); var scratchCartesian2 = new Cartesian3_default(); var scratchCartesian32 = new Cartesian3_default(); function barycentricCoordinates(point4, p0, p1, p2, result) { Check_default.defined("point", point4); Check_default.defined("p0", p0); Check_default.defined("p1", p1); Check_default.defined("p2", p2); if (!defined_default(result)) { result = new Cartesian3_default(); } let v02; let v12; let v22; let dot00; let dot01; let dot02; let dot11; let dot12; if (!defined_default(p0.z)) { if (Cartesian2_default.equalsEpsilon(point4, p0, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_X, result); } if (Cartesian2_default.equalsEpsilon(point4, p1, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_Y, result); } if (Cartesian2_default.equalsEpsilon(point4, p2, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_Z, result); } v02 = Cartesian2_default.subtract(p1, p0, scratchCartesian1); v12 = Cartesian2_default.subtract(p2, p0, scratchCartesian2); v22 = Cartesian2_default.subtract(point4, p0, scratchCartesian32); dot00 = Cartesian2_default.dot(v02, v02); dot01 = Cartesian2_default.dot(v02, v12); dot02 = Cartesian2_default.dot(v02, v22); dot11 = Cartesian2_default.dot(v12, v12); dot12 = Cartesian2_default.dot(v12, v22); } else { if (Cartesian3_default.equalsEpsilon(point4, p0, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_X, result); } if (Cartesian3_default.equalsEpsilon(point4, p1, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_Y, result); } if (Cartesian3_default.equalsEpsilon(point4, p2, Math_default.EPSILON14)) { return Cartesian3_default.clone(Cartesian3_default.UNIT_Z, result); } v02 = Cartesian3_default.subtract(p1, p0, scratchCartesian1); v12 = Cartesian3_default.subtract(p2, p0, scratchCartesian2); v22 = Cartesian3_default.subtract(point4, p0, scratchCartesian32); dot00 = Cartesian3_default.dot(v02, v02); dot01 = Cartesian3_default.dot(v02, v12); dot02 = Cartesian3_default.dot(v02, v22); dot11 = Cartesian3_default.dot(v12, v12); dot12 = Cartesian3_default.dot(v12, v22); } result.y = dot11 * dot02 - dot01 * dot12; result.z = dot00 * dot12 - dot01 * dot02; const q = dot00 * dot11 - dot01 * dot01; if (q === 0) { return void 0; } result.y /= q; result.z /= q; result.x = 1 - result.y - result.z; return result; } var barycentricCoordinates_default = barycentricCoordinates; // packages/engine/Source/Core/EncodedCartesian3.js var import_InlineWorkers103 = __toESM(require_InlineWorkers(), 1); function EncodedCartesian3() { this.high = Cartesian3_default.clone(Cartesian3_default.ZERO); this.low = Cartesian3_default.clone(Cartesian3_default.ZERO); } EncodedCartesian3.encode = function(value, result) { Check_default.typeOf.number("value", value); if (!defined_default(result)) { result = { high: 0, low: 0 }; } let doubleHigh; if (value >= 0) { doubleHigh = Math.floor(value / 65536) * 65536; result.high = doubleHigh; result.low = value - doubleHigh; } else { doubleHigh = Math.floor(-value / 65536) * 65536; result.high = -doubleHigh; result.low = value + doubleHigh; } return result; }; var scratchEncode = { high: 0, low: 0 }; EncodedCartesian3.fromCartesian = function(cartesian11, result) { Check_default.typeOf.object("cartesian", cartesian11); if (!defined_default(result)) { result = new EncodedCartesian3(); } const high = result.high; const low = result.low; EncodedCartesian3.encode(cartesian11.x, scratchEncode); high.x = scratchEncode.high; low.x = scratchEncode.low; EncodedCartesian3.encode(cartesian11.y, scratchEncode); high.y = scratchEncode.high; low.y = scratchEncode.low; EncodedCartesian3.encode(cartesian11.z, scratchEncode); high.z = scratchEncode.high; low.z = scratchEncode.low; return result; }; var encodedP = new EncodedCartesian3(); EncodedCartesian3.writeElements = function(cartesian11, cartesianArray, index) { Check_default.defined("cartesianArray", cartesianArray); Check_default.typeOf.number("index", index); Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); EncodedCartesian3.fromCartesian(cartesian11, encodedP); const high = encodedP.high; const low = encodedP.low; cartesianArray[index] = high.x; cartesianArray[index + 1] = high.y; cartesianArray[index + 2] = high.z; cartesianArray[index + 3] = low.x; cartesianArray[index + 4] = low.y; cartesianArray[index + 5] = low.z; }; var EncodedCartesian3_default = EncodedCartesian3; // packages/engine/Source/Core/IntersectionTests.js var import_InlineWorkers108 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/QuadraticRealPolynomial.js var import_InlineWorkers104 = __toESM(require_InlineWorkers(), 1); var QuadraticRealPolynomial = {}; QuadraticRealPolynomial.computeDiscriminant = function(a3, b, c14) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } const discriminant = b * b - 4 * a3 * c14; return discriminant; }; function addWithCancellationCheck(left, right, tolerance) { const difference = left + right; if (Math_default.sign(left) !== Math_default.sign(right) && Math.abs(difference / Math.max(Math.abs(left), Math.abs(right))) < tolerance) { return 0; } return difference; } QuadraticRealPolynomial.computeRealRoots = function(a3, b, c14) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } let ratio; if (a3 === 0) { if (b === 0) { return []; } return [-c14 / b]; } else if (b === 0) { if (c14 === 0) { return [0, 0]; } const cMagnitude = Math.abs(c14); const aMagnitude = Math.abs(a3); if (cMagnitude < aMagnitude && cMagnitude / aMagnitude < Math_default.EPSILON14) { return [0, 0]; } else if (cMagnitude > aMagnitude && aMagnitude / cMagnitude < Math_default.EPSILON14) { return []; } ratio = -c14 / a3; if (ratio < 0) { return []; } const root = Math.sqrt(ratio); return [-root, root]; } else if (c14 === 0) { ratio = -b / a3; if (ratio < 0) { return [ratio, 0]; } return [0, ratio]; } const b2 = b * b; const four_ac = 4 * a3 * c14; const radicand = addWithCancellationCheck(b2, -four_ac, Math_default.EPSILON14); if (radicand < 0) { return []; } const q = -0.5 * addWithCancellationCheck( b, Math_default.sign(b) * Math.sqrt(radicand), Math_default.EPSILON14 ); if (b > 0) { return [q / a3, c14 / q]; } return [c14 / q, q / a3]; }; var QuadraticRealPolynomial_default = QuadraticRealPolynomial; // packages/engine/Source/Core/QuarticRealPolynomial.js var import_InlineWorkers106 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/CubicRealPolynomial.js var import_InlineWorkers105 = __toESM(require_InlineWorkers(), 1); var CubicRealPolynomial = {}; CubicRealPolynomial.computeDiscriminant = function(a3, b, c14, d) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } if (typeof d !== "number") { throw new DeveloperError_default("d is a required number."); } const a22 = a3 * a3; const b2 = b * b; const c22 = c14 * c14; const d2 = d * d; const discriminant = 18 * a3 * b * c14 * d + b2 * c22 - 27 * a22 * d2 - 4 * (a3 * c22 * c14 + b2 * b * d); return discriminant; }; function computeRealRoots(a3, b, c14, d) { const A = a3; const B = b / 3; const C = c14 / 3; const D = d; const AC = A * C; const BD = B * D; const B2 = B * B; const C2 = C * C; const delta1 = A * C - B2; const delta2 = A * D - B * C; const delta3 = B * D - C2; const discriminant = 4 * delta1 * delta3 - delta2 * delta2; let temp; let temp1; if (discriminant < 0) { let ABar; let CBar; let DBar; if (B2 * BD >= AC * C2) { ABar = A; CBar = delta1; DBar = -2 * B * delta1 + A * delta2; } else { ABar = D; CBar = delta3; DBar = -D * delta2 + 2 * C * delta3; } const s2 = DBar < 0 ? -1 : 1; const temp0 = -s2 * Math.abs(ABar) * Math.sqrt(-discriminant); temp1 = -DBar + temp0; const x = temp1 / 2; const p = x < 0 ? -Math.pow(-x, 1 / 3) : Math.pow(x, 1 / 3); const q = temp1 === temp0 ? -p : -CBar / p; temp = CBar <= 0 ? p + q : -DBar / (p * p + q * q + CBar); if (B2 * BD >= AC * C2) { return [(temp - B) / A]; } return [-D / (temp + C)]; } const CBarA = delta1; const DBarA = -2 * B * delta1 + A * delta2; const CBarD = delta3; const DBarD = -D * delta2 + 2 * C * delta3; const squareRootOfDiscriminant = Math.sqrt(discriminant); const halfSquareRootOf3 = Math.sqrt(3) / 2; let theta = Math.abs(Math.atan2(A * squareRootOfDiscriminant, -DBarA) / 3); temp = 2 * Math.sqrt(-CBarA); let cosine = Math.cos(theta); temp1 = temp * cosine; let temp3 = temp * (-cosine / 2 - halfSquareRootOf3 * Math.sin(theta)); const numeratorLarge = temp1 + temp3 > 2 * B ? temp1 - B : temp3 - B; const denominatorLarge = A; const root1 = numeratorLarge / denominatorLarge; theta = Math.abs(Math.atan2(D * squareRootOfDiscriminant, -DBarD) / 3); temp = 2 * Math.sqrt(-CBarD); cosine = Math.cos(theta); temp1 = temp * cosine; temp3 = temp * (-cosine / 2 - halfSquareRootOf3 * Math.sin(theta)); const numeratorSmall = -D; const denominatorSmall = temp1 + temp3 < 2 * C ? temp1 + C : temp3 + C; const root3 = numeratorSmall / denominatorSmall; const E = denominatorLarge * denominatorSmall; const F = -numeratorLarge * denominatorSmall - denominatorLarge * numeratorSmall; const G = numeratorLarge * numeratorSmall; const root2 = (C * F - B * G) / (-B * F + C * E); if (root1 <= root2) { if (root1 <= root3) { if (root2 <= root3) { return [root1, root2, root3]; } return [root1, root3, root2]; } return [root3, root1, root2]; } if (root1 <= root3) { return [root2, root1, root3]; } if (root2 <= root3) { return [root2, root3, root1]; } return [root3, root2, root1]; } CubicRealPolynomial.computeRealRoots = function(a3, b, c14, d) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } if (typeof d !== "number") { throw new DeveloperError_default("d is a required number."); } let roots; let ratio; if (a3 === 0) { return QuadraticRealPolynomial_default.computeRealRoots(b, c14, d); } else if (b === 0) { if (c14 === 0) { if (d === 0) { return [0, 0, 0]; } ratio = -d / a3; const root = ratio < 0 ? -Math.pow(-ratio, 1 / 3) : Math.pow(ratio, 1 / 3); return [root, root, root]; } else if (d === 0) { roots = QuadraticRealPolynomial_default.computeRealRoots(a3, 0, c14); if (roots.Length === 0) { return [0]; } return [roots[0], 0, roots[1]]; } return computeRealRoots(a3, 0, c14, d); } else if (c14 === 0) { if (d === 0) { ratio = -b / a3; if (ratio < 0) { return [ratio, 0, 0]; } return [0, 0, ratio]; } return computeRealRoots(a3, b, 0, d); } else if (d === 0) { roots = QuadraticRealPolynomial_default.computeRealRoots(a3, b, c14); if (roots.length === 0) { return [0]; } else if (roots[1] <= 0) { return [roots[0], roots[1], 0]; } else if (roots[0] >= 0) { return [0, roots[0], roots[1]]; } return [roots[0], 0, roots[1]]; } return computeRealRoots(a3, b, c14, d); }; var CubicRealPolynomial_default = CubicRealPolynomial; // packages/engine/Source/Core/QuarticRealPolynomial.js var QuarticRealPolynomial = {}; QuarticRealPolynomial.computeDiscriminant = function(a3, b, c14, d, e) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } if (typeof d !== "number") { throw new DeveloperError_default("d is a required number."); } if (typeof e !== "number") { throw new DeveloperError_default("e is a required number."); } const a22 = a3 * a3; const a32 = a22 * a3; const b2 = b * b; const b3 = b2 * b; const c22 = c14 * c14; const c33 = c22 * c14; const d2 = d * d; const d3 = d2 * d; const e2 = e * e; const e3 = e2 * e; const discriminant = b2 * c22 * d2 - 4 * b3 * d3 - 4 * a3 * c33 * d2 + 18 * a3 * b * c14 * d3 - 27 * a22 * d2 * d2 + 256 * a32 * e3 + e * (18 * b3 * c14 * d - 4 * b2 * c33 + 16 * a3 * c22 * c22 - 80 * a3 * b * c22 * d - 6 * a3 * b2 * d2 + 144 * a22 * c14 * d2) + e2 * (144 * a3 * b2 * c14 - 27 * b2 * b2 - 128 * a22 * c22 - 192 * a22 * b * d); return discriminant; }; function original(a3, a22, a1, a0) { const a3Squared = a3 * a3; const p = a22 - 3 * a3Squared / 8; const q = a1 - a22 * a3 / 2 + a3Squared * a3 / 8; const r2 = a0 - a1 * a3 / 4 + a22 * a3Squared / 16 - 3 * a3Squared * a3Squared / 256; const cubicRoots = CubicRealPolynomial_default.computeRealRoots( 1, 2 * p, p * p - 4 * r2, -q * q ); if (cubicRoots.length > 0) { const temp = -a3 / 4; const hSquared = cubicRoots[cubicRoots.length - 1]; if (Math.abs(hSquared) < Math_default.EPSILON14) { const roots = QuadraticRealPolynomial_default.computeRealRoots(1, p, r2); if (roots.length === 2) { const root0 = roots[0]; const root1 = roots[1]; let y; if (root0 >= 0 && root1 >= 0) { const y0 = Math.sqrt(root0); const y1 = Math.sqrt(root1); return [temp - y1, temp - y0, temp + y0, temp + y1]; } else if (root0 >= 0 && root1 < 0) { y = Math.sqrt(root0); return [temp - y, temp + y]; } else if (root0 < 0 && root1 >= 0) { y = Math.sqrt(root1); return [temp - y, temp + y]; } } return []; } else if (hSquared > 0) { const h = Math.sqrt(hSquared); const m = (p + hSquared - q / h) / 2; const n2 = (p + hSquared + q / h) / 2; const roots1 = QuadraticRealPolynomial_default.computeRealRoots(1, h, m); const roots2 = QuadraticRealPolynomial_default.computeRealRoots(1, -h, n2); if (roots1.length !== 0) { roots1[0] += temp; roots1[1] += temp; if (roots2.length !== 0) { roots2[0] += temp; roots2[1] += temp; if (roots1[1] <= roots2[0]) { return [roots1[0], roots1[1], roots2[0], roots2[1]]; } else if (roots2[1] <= roots1[0]) { return [roots2[0], roots2[1], roots1[0], roots1[1]]; } else if (roots1[0] >= roots2[0] && roots1[1] <= roots2[1]) { return [roots2[0], roots1[0], roots1[1], roots2[1]]; } else if (roots2[0] >= roots1[0] && roots2[1] <= roots1[1]) { return [roots1[0], roots2[0], roots2[1], roots1[1]]; } else if (roots1[0] > roots2[0] && roots1[0] < roots2[1]) { return [roots2[0], roots1[0], roots2[1], roots1[1]]; } return [roots1[0], roots2[0], roots1[1], roots2[1]]; } return roots1; } if (roots2.length !== 0) { roots2[0] += temp; roots2[1] += temp; return roots2; } return []; } } return []; } function neumark(a3, a22, a1, a0) { const a1Squared = a1 * a1; const a2Squared = a22 * a22; const a3Squared = a3 * a3; const p = -2 * a22; const q = a1 * a3 + a2Squared - 4 * a0; const r2 = a3Squared * a0 - a1 * a22 * a3 + a1Squared; const cubicRoots = CubicRealPolynomial_default.computeRealRoots(1, p, q, r2); if (cubicRoots.length > 0) { const y = cubicRoots[0]; const temp = a22 - y; const tempSquared = temp * temp; const g1 = a3 / 2; const h1 = temp / 2; const m = tempSquared - 4 * a0; const mError = tempSquared + 4 * Math.abs(a0); const n2 = a3Squared - 4 * y; const nError = a3Squared + 4 * Math.abs(y); let g2; let h2; if (y < 0 || m * nError < n2 * mError) { const squareRootOfN = Math.sqrt(n2); g2 = squareRootOfN / 2; h2 = squareRootOfN === 0 ? 0 : (a3 * h1 - a1) / squareRootOfN; } else { const squareRootOfM = Math.sqrt(m); g2 = squareRootOfM === 0 ? 0 : (a3 * h1 - a1) / squareRootOfM; h2 = squareRootOfM / 2; } let G; let g; if (g1 === 0 && g2 === 0) { G = 0; g = 0; } else if (Math_default.sign(g1) === Math_default.sign(g2)) { G = g1 + g2; g = y / G; } else { g = g1 - g2; G = y / g; } let H; let h; if (h1 === 0 && h2 === 0) { H = 0; h = 0; } else if (Math_default.sign(h1) === Math_default.sign(h2)) { H = h1 + h2; h = a0 / H; } else { h = h1 - h2; H = a0 / h; } const roots1 = QuadraticRealPolynomial_default.computeRealRoots(1, G, H); const roots2 = QuadraticRealPolynomial_default.computeRealRoots(1, g, h); if (roots1.length !== 0) { if (roots2.length !== 0) { if (roots1[1] <= roots2[0]) { return [roots1[0], roots1[1], roots2[0], roots2[1]]; } else if (roots2[1] <= roots1[0]) { return [roots2[0], roots2[1], roots1[0], roots1[1]]; } else if (roots1[0] >= roots2[0] && roots1[1] <= roots2[1]) { return [roots2[0], roots1[0], roots1[1], roots2[1]]; } else if (roots2[0] >= roots1[0] && roots2[1] <= roots1[1]) { return [roots1[0], roots2[0], roots2[1], roots1[1]]; } else if (roots1[0] > roots2[0] && roots1[0] < roots2[1]) { return [roots2[0], roots1[0], roots2[1], roots1[1]]; } return [roots1[0], roots2[0], roots1[1], roots2[1]]; } return roots1; } if (roots2.length !== 0) { return roots2; } } return []; } QuarticRealPolynomial.computeRealRoots = function(a3, b, c14, d, e) { if (typeof a3 !== "number") { throw new DeveloperError_default("a is a required number."); } if (typeof b !== "number") { throw new DeveloperError_default("b is a required number."); } if (typeof c14 !== "number") { throw new DeveloperError_default("c is a required number."); } if (typeof d !== "number") { throw new DeveloperError_default("d is a required number."); } if (typeof e !== "number") { throw new DeveloperError_default("e is a required number."); } if (Math.abs(a3) < Math_default.EPSILON15) { return CubicRealPolynomial_default.computeRealRoots(b, c14, d, e); } const a32 = b / a3; const a22 = c14 / a3; const a1 = d / a3; const a0 = e / a3; let k = a32 < 0 ? 1 : 0; k += a22 < 0 ? k + 1 : k; k += a1 < 0 ? k + 1 : k; k += a0 < 0 ? k + 1 : k; switch (k) { case 0: return original(a32, a22, a1, a0); case 1: return neumark(a32, a22, a1, a0); case 2: return neumark(a32, a22, a1, a0); case 3: return original(a32, a22, a1, a0); case 4: return original(a32, a22, a1, a0); case 5: return neumark(a32, a22, a1, a0); case 6: return original(a32, a22, a1, a0); case 7: return original(a32, a22, a1, a0); case 8: return neumark(a32, a22, a1, a0); case 9: return original(a32, a22, a1, a0); case 10: return original(a32, a22, a1, a0); case 11: return neumark(a32, a22, a1, a0); case 12: return original(a32, a22, a1, a0); case 13: return original(a32, a22, a1, a0); case 14: return original(a32, a22, a1, a0); case 15: return original(a32, a22, a1, a0); default: return void 0; } }; var QuarticRealPolynomial_default = QuarticRealPolynomial; // packages/engine/Source/Core/Ray.js var import_InlineWorkers107 = __toESM(require_InlineWorkers(), 1); var Ray = class _Ray { /** * @param {Cartesian3} [origin=Cartesian3.ZERO] The origin of the ray. * @param {Cartesian3} [direction=Cartesian3.ZERO] The direction of the ray. */ constructor(origin, direction2) { direction2 = Cartesian3_default.clone(direction2 ?? Cartesian3_default.ZERO); if (!Cartesian3_default.equals(direction2, Cartesian3_default.ZERO)) { Cartesian3_default.normalize(direction2, direction2); } this.origin = Cartesian3_default.clone(origin ?? Cartesian3_default.ZERO); this.direction = direction2; } /** * Duplicates a Ray instance. * * @param {Ray} ray The ray to duplicate. * @param {Ray} [result] The object onto which to store the result. * @returns {Ray} The modified result parameter or a new Ray instance if one was not provided. (Returns undefined if ray is undefined) */ static clone(ray, result) { if (!defined_default(ray)) { return void 0; } if (!defined_default(result)) { return new _Ray(ray.origin, ray.direction); } result.origin = Cartesian3_default.clone(ray.origin); result.direction = Cartesian3_default.clone(ray.direction); return result; } /** * Computes the point along the ray given by r(t) = o + t*d, * where o is the origin of the ray and d is the direction. * * @param {Ray} ray The ray. * @param {number} t A scalar value. * @param {Cartesian3} [result] The object in which the result will be stored. * @returns {Cartesian3} The modified result parameter, or a new instance if none was provided. * * @example * //Get the first intersection point of a ray and an ellipsoid. * const intersection = Cesium.IntersectionTests.rayEllipsoid(ray, ellipsoid); * const point = Cesium.Ray.getPoint(ray, intersection.start); */ static getPoint(ray, t2, result) { Check_default.typeOf.object("ray", ray); Check_default.typeOf.number("t", t2); if (!defined_default(result)) { result = new Cartesian3_default(); } result = Cartesian3_default.multiplyByScalar(ray.direction, t2, result); return Cartesian3_default.add(ray.origin, result, result); } }; var Ray_default = Ray; // packages/engine/Source/Core/IntersectionTests.js var IntersectionTests = {}; IntersectionTests.rayPlane = function(ray, plane, result) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(plane)) { throw new DeveloperError_default("plane is required."); } if (!defined_default(result)) { result = new Cartesian3_default(); } const origin = ray.origin; const direction2 = ray.direction; const normal2 = plane.normal; const denominator = Cartesian3_default.dot(normal2, direction2); if (Math.abs(denominator) < Math_default.EPSILON15) { return void 0; } const t2 = (-plane.distance - Cartesian3_default.dot(normal2, origin)) / denominator; if (t2 < 0) { return void 0; } result = Cartesian3_default.multiplyByScalar(direction2, t2, result); return Cartesian3_default.add(origin, result, result); }; var scratchEdge0 = new Cartesian3_default(); var scratchEdge1 = new Cartesian3_default(); var scratchPVec = new Cartesian3_default(); var scratchTVec = new Cartesian3_default(); var scratchQVec = new Cartesian3_default(); IntersectionTests.rayTriangleParametric = function(ray, p0, p1, p2, cullBackFaces) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(p0)) { throw new DeveloperError_default("p0 is required."); } if (!defined_default(p1)) { throw new DeveloperError_default("p1 is required."); } if (!defined_default(p2)) { throw new DeveloperError_default("p2 is required."); } cullBackFaces = cullBackFaces ?? false; const origin = ray.origin; const direction2 = ray.direction; const edge0 = Cartesian3_default.subtract(p1, p0, scratchEdge0); const edge1 = Cartesian3_default.subtract(p2, p0, scratchEdge1); const p = Cartesian3_default.cross(direction2, edge1, scratchPVec); const det = Cartesian3_default.dot(edge0, p); let tvec; let q; let u4; let v3; let t2; if (cullBackFaces) { if (det < Math_default.EPSILON6) { return void 0; } tvec = Cartesian3_default.subtract(origin, p0, scratchTVec); u4 = Cartesian3_default.dot(tvec, p); if (u4 < 0 || u4 > det) { return void 0; } q = Cartesian3_default.cross(tvec, edge0, scratchQVec); v3 = Cartesian3_default.dot(direction2, q); if (v3 < 0 || u4 + v3 > det) { return void 0; } t2 = Cartesian3_default.dot(edge1, q) / det; } else { if (Math.abs(det) < Math_default.EPSILON6) { return void 0; } const invDet = 1 / det; tvec = Cartesian3_default.subtract(origin, p0, scratchTVec); u4 = Cartesian3_default.dot(tvec, p) * invDet; if (u4 < 0 || u4 > 1) { return void 0; } q = Cartesian3_default.cross(tvec, edge0, scratchQVec); v3 = Cartesian3_default.dot(direction2, q) * invDet; if (v3 < 0 || u4 + v3 > 1) { return void 0; } t2 = Cartesian3_default.dot(edge1, q) * invDet; } return t2; }; IntersectionTests.rayTriangle = function(ray, p0, p1, p2, cullBackFaces, result) { const t2 = IntersectionTests.rayTriangleParametric( ray, p0, p1, p2, cullBackFaces ); if (!defined_default(t2) || t2 < 0) { return void 0; } if (!defined_default(result)) { result = new Cartesian3_default(); } Cartesian3_default.multiplyByScalar(ray.direction, t2, result); return Cartesian3_default.add(ray.origin, result, result); }; var scratchLineSegmentTriangleRay = new Ray_default(); IntersectionTests.lineSegmentTriangle = function(v02, v12, p0, p1, p2, cullBackFaces, result) { if (!defined_default(v02)) { throw new DeveloperError_default("v0 is required."); } if (!defined_default(v12)) { throw new DeveloperError_default("v1 is required."); } if (!defined_default(p0)) { throw new DeveloperError_default("p0 is required."); } if (!defined_default(p1)) { throw new DeveloperError_default("p1 is required."); } if (!defined_default(p2)) { throw new DeveloperError_default("p2 is required."); } const ray = scratchLineSegmentTriangleRay; Cartesian3_default.clone(v02, ray.origin); Cartesian3_default.subtract(v12, v02, ray.direction); Cartesian3_default.normalize(ray.direction, ray.direction); const t2 = IntersectionTests.rayTriangleParametric( ray, p0, p1, p2, cullBackFaces ); if (!defined_default(t2) || t2 < 0 || t2 > Cartesian3_default.distance(v02, v12)) { return void 0; } if (!defined_default(result)) { result = new Cartesian3_default(); } Cartesian3_default.multiplyByScalar(ray.direction, t2, result); return Cartesian3_default.add(ray.origin, result, result); }; function solveQuadratic(a3, b, c14, result) { const det = b * b - 4 * a3 * c14; if (det < 0) { return void 0; } else if (det > 0) { const denom = 1 / (2 * a3); const disc = Math.sqrt(det); const root0 = (-b + disc) * denom; const root1 = (-b - disc) * denom; if (root0 < root1) { result.root0 = root0; result.root1 = root1; } else { result.root0 = root1; result.root1 = root0; } return result; } const root = -b / (2 * a3); if (root === 0) { return void 0; } result.root0 = result.root1 = root; return result; } var raySphereRoots = { root0: 0, root1: 0 }; function raySphere(ray, sphere, result) { if (!defined_default(result)) { result = new Interval_default(); } const origin = ray.origin; const direction2 = ray.direction; const center = sphere.center; const radiusSquared = sphere.radius * sphere.radius; const diff = Cartesian3_default.subtract(origin, center, scratchPVec); const a3 = Cartesian3_default.dot(direction2, direction2); const b = 2 * Cartesian3_default.dot(direction2, diff); const c14 = Cartesian3_default.magnitudeSquared(diff) - radiusSquared; const roots = solveQuadratic(a3, b, c14, raySphereRoots); if (!defined_default(roots)) { return void 0; } result.start = roots.root0; result.stop = roots.root1; return result; } IntersectionTests.raySphere = function(ray, sphere, result) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(sphere)) { throw new DeveloperError_default("sphere is required."); } result = raySphere(ray, sphere, result); if (!defined_default(result) || result.stop < 0) { return void 0; } result.start = Math.max(result.start, 0); return result; }; var scratchLineSegmentRay = new Ray_default(); IntersectionTests.lineSegmentSphere = function(p0, p1, sphere, result) { if (!defined_default(p0)) { throw new DeveloperError_default("p0 is required."); } if (!defined_default(p1)) { throw new DeveloperError_default("p1 is required."); } if (!defined_default(sphere)) { throw new DeveloperError_default("sphere is required."); } const ray = scratchLineSegmentRay; Cartesian3_default.clone(p0, ray.origin); const direction2 = Cartesian3_default.subtract(p1, p0, ray.direction); const maxT = Cartesian3_default.magnitude(direction2); Cartesian3_default.normalize(direction2, direction2); result = raySphere(ray, sphere, result); if (!defined_default(result) || result.stop < 0 || result.start > maxT) { return void 0; } result.start = Math.max(result.start, 0); result.stop = Math.min(result.stop, maxT); return result; }; var scratchQ = new Cartesian3_default(); var scratchW = new Cartesian3_default(); IntersectionTests.rayEllipsoid = function(ray, ellipsoid) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(ellipsoid)) { throw new DeveloperError_default("ellipsoid is required."); } const inverseRadii = ellipsoid.oneOverRadii; const q = Cartesian3_default.multiplyComponents(inverseRadii, ray.origin, scratchQ); const w = Cartesian3_default.multiplyComponents( inverseRadii, ray.direction, scratchW ); const q22 = Cartesian3_default.magnitudeSquared(q); const qw = Cartesian3_default.dot(q, w); let difference, w2, product, discriminant, temp; if (q22 > 1) { if (qw >= 0) { return void 0; } const qw2 = qw * qw; difference = q22 - 1; w2 = Cartesian3_default.magnitudeSquared(w); product = w2 * difference; if (qw2 < product) { return void 0; } else if (qw2 > product) { discriminant = qw * qw - product; temp = -qw + Math.sqrt(discriminant); const root0 = temp / w2; const root1 = difference / temp; if (root0 < root1) { return new Interval_default(root0, root1); } return { start: root1, stop: root0 }; } const root = Math.sqrt(difference / w2); return new Interval_default(root, root); } else if (q22 < 1) { difference = q22 - 1; w2 = Cartesian3_default.magnitudeSquared(w); product = w2 * difference; discriminant = qw * qw - product; temp = -qw + Math.sqrt(discriminant); return new Interval_default(0, temp / w2); } if (qw < 0) { w2 = Cartesian3_default.magnitudeSquared(w); return new Interval_default(0, -qw / w2); } return void 0; }; var scratchRayIntervalX = new Interval_default(); var scratchRayIntervalY = new Interval_default(); var scratchRayIntervalZ = new Interval_default(); IntersectionTests.rayAxisAlignedBoundingBox = function(ray, box, result) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(box)) { throw new DeveloperError_default("box is required."); } if (!defined_default(result)) { result = new Interval_default(); } const tx = rayIntervalAlongAABBAxis( ray.origin.x, ray.direction.x, box.minimum.x, box.maximum.x, scratchRayIntervalX ); const ty = rayIntervalAlongAABBAxis( ray.origin.y, ray.direction.y, box.minimum.y, box.maximum.y, scratchRayIntervalY ); const tz = rayIntervalAlongAABBAxis( ray.origin.z, ray.direction.z, box.minimum.z, box.maximum.z, scratchRayIntervalZ ); result.start = tx.start > ty.start ? tx.start : ty.start; result.stop = tx.stop < ty.stop ? tx.stop : ty.stop; if (tx.start > ty.stop || ty.start > tx.stop) { return void 0; } if (result.start > tz.stop || tz.start > result.stop) { return void 0; } if (tz.start > result.start) { result.start = tz.start; } if (tz.stop < result.stop) { result.stop = tz.stop; } return result; }; function rayIntervalAlongAABBAxis(origin, direction2, min3, max3, result) { result.start = (min3 - origin) / direction2; result.stop = (max3 - origin) / direction2; if (result.stop < result.start) { const tmp2 = result.stop; result.stop = result.start; result.start = tmp2; } return result; } function addWithCancellationCheck2(left, right, tolerance) { const difference = left + right; if (Math_default.sign(left) !== Math_default.sign(right) && Math.abs(difference / Math.max(Math.abs(left), Math.abs(right))) < tolerance) { return 0; } return difference; } IntersectionTests.quadraticVectorExpression = function(A, b, c14, x, w) { const xSquared = x * x; const wSquared = w * w; const l2 = (A[Matrix3_default.COLUMN1ROW1] - A[Matrix3_default.COLUMN2ROW2]) * wSquared; const l1 = w * (x * addWithCancellationCheck2( A[Matrix3_default.COLUMN1ROW0], A[Matrix3_default.COLUMN0ROW1], Math_default.EPSILON15 ) + b.y); const l0 = A[Matrix3_default.COLUMN0ROW0] * xSquared + A[Matrix3_default.COLUMN2ROW2] * wSquared + x * b.x + c14; const r1 = wSquared * addWithCancellationCheck2( A[Matrix3_default.COLUMN2ROW1], A[Matrix3_default.COLUMN1ROW2], Math_default.EPSILON15 ); const r0 = w * (x * addWithCancellationCheck2(A[Matrix3_default.COLUMN2ROW0], A[Matrix3_default.COLUMN0ROW2]) + b.z); let cosines; const solutions = []; if (r0 === 0 && r1 === 0) { cosines = QuadraticRealPolynomial_default.computeRealRoots(l2, l1, l0); if (cosines.length === 0) { return solutions; } const cosine0 = cosines[0]; const sine0 = Math.sqrt(Math.max(1 - cosine0 * cosine0, 0)); solutions.push(new Cartesian3_default(x, w * cosine0, w * -sine0)); solutions.push(new Cartesian3_default(x, w * cosine0, w * sine0)); if (cosines.length === 2) { const cosine1 = cosines[1]; const sine1 = Math.sqrt(Math.max(1 - cosine1 * cosine1, 0)); solutions.push(new Cartesian3_default(x, w * cosine1, w * -sine1)); solutions.push(new Cartesian3_default(x, w * cosine1, w * sine1)); } return solutions; } const r0Squared = r0 * r0; const r1Squared = r1 * r1; const l2Squared = l2 * l2; const r0r1 = r0 * r1; const c42 = l2Squared + r1Squared; const c33 = 2 * (l1 * l2 + r0r1); const c22 = 2 * l0 * l2 + l1 * l1 - r1Squared + r0Squared; const c15 = 2 * (l0 * l1 - r0r1); const c0 = l0 * l0 - r0Squared; if (c42 === 0 && c33 === 0 && c22 === 0 && c15 === 0) { return solutions; } cosines = QuarticRealPolynomial_default.computeRealRoots(c42, c33, c22, c15, c0); const length2 = cosines.length; if (length2 === 0) { return solutions; } for (let i = 0; i < length2; ++i) { const cosine = cosines[i]; const cosineSquared = cosine * cosine; const sineSquared = Math.max(1 - cosineSquared, 0); const sine = Math.sqrt(sineSquared); let left; if (Math_default.sign(l2) === Math_default.sign(l0)) { left = addWithCancellationCheck2( l2 * cosineSquared + l0, l1 * cosine, Math_default.EPSILON12 ); } else if (Math_default.sign(l0) === Math_default.sign(l1 * cosine)) { left = addWithCancellationCheck2( l2 * cosineSquared, l1 * cosine + l0, Math_default.EPSILON12 ); } else { left = addWithCancellationCheck2( l2 * cosineSquared + l1 * cosine, l0, Math_default.EPSILON12 ); } const right = addWithCancellationCheck2( r1 * cosine, r0, Math_default.EPSILON15 ); const product = left * right; if (product < 0) { solutions.push(new Cartesian3_default(x, w * cosine, w * sine)); } else if (product > 0) { solutions.push(new Cartesian3_default(x, w * cosine, w * -sine)); } else if (sine !== 0) { solutions.push(new Cartesian3_default(x, w * cosine, w * -sine)); solutions.push(new Cartesian3_default(x, w * cosine, w * sine)); ++i; } else { solutions.push(new Cartesian3_default(x, w * cosine, w * sine)); } } return solutions; }; var firstAxisScratch = new Cartesian3_default(); var secondAxisScratch = new Cartesian3_default(); var thirdAxisScratch = new Cartesian3_default(); var referenceScratch = new Cartesian3_default(); var bCart = new Cartesian3_default(); var bScratch = new Matrix3_default(); var btScratch = new Matrix3_default(); var diScratch = new Matrix3_default(); var dScratch = new Matrix3_default(); var cScratch = new Matrix3_default(); var tempMatrix = new Matrix3_default(); var aScratch = new Matrix3_default(); var sScratch = new Cartesian3_default(); var closestScratch = new Cartesian3_default(); var surfPointScratch = new Cartographic_default(); IntersectionTests.grazingAltitudeLocation = function(ray, ellipsoid) { if (!defined_default(ray)) { throw new DeveloperError_default("ray is required."); } if (!defined_default(ellipsoid)) { throw new DeveloperError_default("ellipsoid is required."); } const position = ray.origin; const direction2 = ray.direction; if (!Cartesian3_default.equals(position, Cartesian3_default.ZERO)) { const normal2 = ellipsoid.geodeticSurfaceNormal(position, firstAxisScratch); if (Cartesian3_default.dot(direction2, normal2) >= 0) { return position; } } const intersects3 = defined_default(this.rayEllipsoid(ray, ellipsoid)); const f2 = ellipsoid.transformPositionToScaledSpace( direction2, firstAxisScratch ); const firstAxis = Cartesian3_default.normalize(f2, f2); const reference = Cartesian3_default.mostOrthogonalAxis(f2, referenceScratch); const secondAxis = Cartesian3_default.normalize( Cartesian3_default.cross(reference, firstAxis, secondAxisScratch), secondAxisScratch ); const thirdAxis = Cartesian3_default.normalize( Cartesian3_default.cross(firstAxis, secondAxis, thirdAxisScratch), thirdAxisScratch ); const B = bScratch; B[0] = firstAxis.x; B[1] = firstAxis.y; B[2] = firstAxis.z; B[3] = secondAxis.x; B[4] = secondAxis.y; B[5] = secondAxis.z; B[6] = thirdAxis.x; B[7] = thirdAxis.y; B[8] = thirdAxis.z; const B_T = Matrix3_default.transpose(B, btScratch); const D_I = Matrix3_default.fromScale(ellipsoid.radii, diScratch); const D = Matrix3_default.fromScale(ellipsoid.oneOverRadii, dScratch); const C = cScratch; C[0] = 0; C[1] = -direction2.z; C[2] = direction2.y; C[3] = direction2.z; C[4] = 0; C[5] = -direction2.x; C[6] = -direction2.y; C[7] = direction2.x; C[8] = 0; const temp = Matrix3_default.multiply( Matrix3_default.multiply(B_T, D, tempMatrix), C, tempMatrix ); const A = Matrix3_default.multiply( Matrix3_default.multiply(temp, D_I, aScratch), B, aScratch ); const b = Matrix3_default.multiplyByVector(temp, position, bCart); const solutions = IntersectionTests.quadraticVectorExpression( A, Cartesian3_default.negate(b, firstAxisScratch), 0, 0, 1 ); let s2; let altitude; const length2 = solutions.length; if (length2 > 0) { let closest = Cartesian3_default.clone(Cartesian3_default.ZERO, closestScratch); let maximumValue = Number.NEGATIVE_INFINITY; for (let i = 0; i < length2; ++i) { s2 = Matrix3_default.multiplyByVector( D_I, Matrix3_default.multiplyByVector(B, solutions[i], sScratch), sScratch ); const v3 = Cartesian3_default.normalize( Cartesian3_default.subtract(s2, position, referenceScratch), referenceScratch ); const dotProduct = Cartesian3_default.dot(v3, direction2); if (dotProduct > maximumValue) { maximumValue = dotProduct; closest = Cartesian3_default.clone(s2, closest); } } const surfacePoint = ellipsoid.cartesianToCartographic( closest, surfPointScratch ); maximumValue = Math_default.clamp(maximumValue, 0, 1); altitude = Cartesian3_default.magnitude( Cartesian3_default.subtract(closest, position, referenceScratch) ) * Math.sqrt(1 - maximumValue * maximumValue); altitude = intersects3 ? -altitude : altitude; surfacePoint.height = altitude; return ellipsoid.cartographicToCartesian(surfacePoint, new Cartesian3_default()); } return void 0; }; var lineSegmentPlaneDifference = new Cartesian3_default(); IntersectionTests.lineSegmentPlane = function(endPoint0, endPoint1, plane, result) { if (!defined_default(endPoint0)) { throw new DeveloperError_default("endPoint0 is required."); } if (!defined_default(endPoint1)) { throw new DeveloperError_default("endPoint1 is required."); } if (!defined_default(plane)) { throw new DeveloperError_default("plane is required."); } if (!defined_default(result)) { result = new Cartesian3_default(); } const difference = Cartesian3_default.subtract( endPoint1, endPoint0, lineSegmentPlaneDifference ); const normal2 = plane.normal; const nDotDiff = Cartesian3_default.dot(normal2, difference); if (Math.abs(nDotDiff) < Math_default.EPSILON6) { return void 0; } const nDotP0 = Cartesian3_default.dot(normal2, endPoint0); const t2 = -(plane.distance + nDotP0) / nDotDiff; if (t2 < 0 || t2 > 1) { return void 0; } Cartesian3_default.multiplyByScalar(difference, t2, result); Cartesian3_default.add(endPoint0, result, result); return result; }; IntersectionTests.trianglePlaneIntersection = function(p0, p1, p2, plane) { if (!defined_default(p0) || !defined_default(p1) || !defined_default(p2) || !defined_default(plane)) { throw new DeveloperError_default("p0, p1, p2, and plane are required."); } const planeNormal = plane.normal; const planeD = plane.distance; const p0Behind = Cartesian3_default.dot(planeNormal, p0) + planeD < 0; const p1Behind = Cartesian3_default.dot(planeNormal, p1) + planeD < 0; const p2Behind = Cartesian3_default.dot(planeNormal, p2) + planeD < 0; let numBehind = 0; numBehind += p0Behind ? 1 : 0; numBehind += p1Behind ? 1 : 0; numBehind += p2Behind ? 1 : 0; let u12, u22; if (numBehind === 1 || numBehind === 2) { u12 = new Cartesian3_default(); u22 = new Cartesian3_default(); } if (numBehind === 1) { if (p0Behind) { IntersectionTests.lineSegmentPlane(p0, p1, plane, u12); IntersectionTests.lineSegmentPlane(p0, p2, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 0, 3, 4, // In front 1, 2, 4, 1, 4, 3 ] }; } else if (p1Behind) { IntersectionTests.lineSegmentPlane(p1, p2, plane, u12); IntersectionTests.lineSegmentPlane(p1, p0, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 1, 3, 4, // In front 2, 0, 4, 2, 4, 3 ] }; } else if (p2Behind) { IntersectionTests.lineSegmentPlane(p2, p0, plane, u12); IntersectionTests.lineSegmentPlane(p2, p1, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 2, 3, 4, // In front 0, 1, 4, 0, 4, 3 ] }; } } else if (numBehind === 2) { if (!p0Behind) { IntersectionTests.lineSegmentPlane(p1, p0, plane, u12); IntersectionTests.lineSegmentPlane(p2, p0, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 1, 2, 4, 1, 4, 3, // In front 0, 3, 4 ] }; } else if (!p1Behind) { IntersectionTests.lineSegmentPlane(p2, p1, plane, u12); IntersectionTests.lineSegmentPlane(p0, p1, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 2, 0, 4, 2, 4, 3, // In front 1, 3, 4 ] }; } else if (!p2Behind) { IntersectionTests.lineSegmentPlane(p0, p2, plane, u12); IntersectionTests.lineSegmentPlane(p1, p2, plane, u22); return { positions: [p0, p1, p2, u12, u22], indices: [ // Behind 0, 1, 4, 0, 4, 3, // In front 2, 3, 4 ] }; } } return void 0; }; var IntersectionTests_default = IntersectionTests; // packages/engine/Source/Core/Plane.js var import_InlineWorkers109 = __toESM(require_InlineWorkers(), 1); function Plane(normal2, distance2) { Check_default.typeOf.object("normal", normal2); if (!Math_default.equalsEpsilon( Cartesian3_default.magnitude(normal2), 1, Math_default.EPSILON6 )) { throw new DeveloperError_default("normal must be normalized."); } Check_default.typeOf.number("distance", distance2); this.normal = Cartesian3_default.clone(normal2); this.distance = distance2; } Plane.fromPointNormal = function(point4, normal2, result) { Check_default.typeOf.object("point", point4); Check_default.typeOf.object("normal", normal2); if (!Math_default.equalsEpsilon( Cartesian3_default.magnitude(normal2), 1, Math_default.EPSILON6 )) { throw new DeveloperError_default("normal must be normalized."); } const distance2 = -Cartesian3_default.dot(normal2, point4); if (!defined_default(result)) { return new Plane(normal2, distance2); } Cartesian3_default.clone(normal2, result.normal); result.distance = distance2; return result; }; var scratchNormal = new Cartesian3_default(); Plane.fromCartesian4 = function(coefficients, result) { Check_default.typeOf.object("coefficients", coefficients); const normal2 = Cartesian3_default.fromCartesian4(coefficients, scratchNormal); const distance2 = coefficients.w; if (!Math_default.equalsEpsilon( Cartesian3_default.magnitude(normal2), 1, Math_default.EPSILON6 )) { throw new DeveloperError_default("normal must be normalized."); } if (!defined_default(result)) { return new Plane(normal2, distance2); } Cartesian3_default.clone(normal2, result.normal); result.distance = distance2; return result; }; Plane.getPointDistance = function(plane, point4) { Check_default.typeOf.object("plane", plane); Check_default.typeOf.object("point", point4); return Cartesian3_default.dot(plane.normal, point4) + plane.distance; }; var scratchCartesian = new Cartesian3_default(); Plane.projectPointOntoPlane = function(plane, point4, result) { Check_default.typeOf.object("plane", plane); Check_default.typeOf.object("point", point4); if (!defined_default(result)) { result = new Cartesian3_default(); } const pointDistance = Plane.getPointDistance(plane, point4); const scaledNormal = Cartesian3_default.multiplyByScalar( plane.normal, pointDistance, scratchCartesian ); return Cartesian3_default.subtract(point4, scaledNormal, result); }; var scratchInverseTranspose = new Matrix4_default(); var scratchPlaneCartesian4 = new Cartesian4_default(); var scratchTransformNormal = new Cartesian3_default(); Plane.transform = function(plane, transform3, result) { Check_default.typeOf.object("plane", plane); Check_default.typeOf.object("transform", transform3); const normal2 = plane.normal; const distance2 = plane.distance; const inverseTranspose2 = Matrix4_default.inverseTranspose( transform3, scratchInverseTranspose ); let planeAsCartesian4 = Cartesian4_default.fromElements( normal2.x, normal2.y, normal2.z, distance2, scratchPlaneCartesian4 ); planeAsCartesian4 = Matrix4_default.multiplyByVector( inverseTranspose2, planeAsCartesian4, planeAsCartesian4 ); const transformedNormal = Cartesian3_default.fromCartesian4( planeAsCartesian4, scratchTransformNormal ); planeAsCartesian4 = Cartesian4_default.divideByScalar( planeAsCartesian4, Cartesian3_default.magnitude(transformedNormal), planeAsCartesian4 ); return Plane.fromCartesian4(planeAsCartesian4, result); }; Plane.clone = function(plane, result) { Check_default.typeOf.object("plane", plane); if (!defined_default(result)) { return new Plane(plane.normal, plane.distance); } Cartesian3_default.clone(plane.normal, result.normal); result.distance = plane.distance; return result; }; Plane.equals = function(left, right) { Check_default.typeOf.object("left", left); Check_default.typeOf.object("right", right); return left.distance === right.distance && Cartesian3_default.equals(left.normal, right.normal); }; Plane.ORIGIN_XY_PLANE = Object.freeze(new Plane(Cartesian3_default.UNIT_Z, 0)); Plane.ORIGIN_YZ_PLANE = Object.freeze(new Plane(Cartesian3_default.UNIT_X, 0)); Plane.ORIGIN_ZX_PLANE = Object.freeze(new Plane(Cartesian3_default.UNIT_Y, 0)); var Plane_default = Plane; // packages/engine/Source/Core/Tipsify.js var import_InlineWorkers110 = __toESM(require_InlineWorkers(), 1); var Tipsify = {}; Tipsify.calculateACMR = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const indices = options.indices; let maximumIndex = options.maximumIndex; const cacheSize = options.cacheSize ?? 24; if (!defined_default(indices)) { throw new DeveloperError_default("indices is required."); } const numIndices = indices.length; if (numIndices < 3 || numIndices % 3 !== 0) { throw new DeveloperError_default("indices length must be a multiple of three."); } if (maximumIndex <= 0) { throw new DeveloperError_default("maximumIndex must be greater than zero."); } if (cacheSize < 3) { throw new DeveloperError_default("cacheSize must be greater than two."); } if (!defined_default(maximumIndex)) { maximumIndex = 0; let currentIndex = 0; let intoIndices = indices[currentIndex]; while (currentIndex < numIndices) { if (intoIndices > maximumIndex) { maximumIndex = intoIndices; } ++currentIndex; intoIndices = indices[currentIndex]; } } const vertexTimeStamps = []; for (let i = 0; i < maximumIndex + 1; i++) { vertexTimeStamps[i] = 0; } let s2 = cacheSize + 1; for (let j = 0; j < numIndices; ++j) { if (s2 - vertexTimeStamps[indices[j]] > cacheSize) { vertexTimeStamps[indices[j]] = s2; ++s2; } } return (s2 - cacheSize + 1) / (numIndices / 3); }; Tipsify.tipsify = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const indices = options.indices; const maximumIndex = options.maximumIndex; const cacheSize = options.cacheSize ?? 24; let cursor; function skipDeadEnd(vertices2, deadEnd2, indices2, maximumIndexPlusOne2) { while (deadEnd2.length >= 1) { const d = deadEnd2[deadEnd2.length - 1]; deadEnd2.splice(deadEnd2.length - 1, 1); if (vertices2[d].numLiveTriangles > 0) { return d; } } while (cursor < maximumIndexPlusOne2) { if (vertices2[cursor].numLiveTriangles > 0) { ++cursor; return cursor - 1; } ++cursor; } return -1; } function getNextVertex(indices2, cacheSize2, oneRing2, vertices2, s3, deadEnd2, maximumIndexPlusOne2) { let n2 = -1; let p; let m = -1; let itOneRing = 0; while (itOneRing < oneRing2.length) { const index2 = oneRing2[itOneRing]; if (vertices2[index2].numLiveTriangles) { p = 0; if (s3 - vertices2[index2].timeStamp + 2 * vertices2[index2].numLiveTriangles <= cacheSize2) { p = s3 - vertices2[index2].timeStamp; } if (p > m || m === -1) { m = p; n2 = index2; } } ++itOneRing; } if (n2 === -1) { return skipDeadEnd(vertices2, deadEnd2, indices2, maximumIndexPlusOne2); } return n2; } if (!defined_default(indices)) { throw new DeveloperError_default("indices is required."); } const numIndices = indices.length; if (numIndices < 3 || numIndices % 3 !== 0) { throw new DeveloperError_default("indices length must be a multiple of three."); } if (maximumIndex <= 0) { throw new DeveloperError_default("maximumIndex must be greater than zero."); } if (cacheSize < 3) { throw new DeveloperError_default("cacheSize must be greater than two."); } let maximumIndexPlusOne = 0; let currentIndex = 0; let intoIndices = indices[currentIndex]; const endIndex = numIndices; if (defined_default(maximumIndex)) { maximumIndexPlusOne = maximumIndex + 1; } else { while (currentIndex < endIndex) { if (intoIndices > maximumIndexPlusOne) { maximumIndexPlusOne = intoIndices; } ++currentIndex; intoIndices = indices[currentIndex]; } if (maximumIndexPlusOne === -1) { return 0; } ++maximumIndexPlusOne; } const vertices = []; let i; for (i = 0; i < maximumIndexPlusOne; i++) { vertices[i] = { numLiveTriangles: 0, timeStamp: 0, vertexTriangles: [] }; } currentIndex = 0; let triangle = 0; while (currentIndex < endIndex) { vertices[indices[currentIndex]].vertexTriangles.push(triangle); ++vertices[indices[currentIndex]].numLiveTriangles; vertices[indices[currentIndex + 1]].vertexTriangles.push(triangle); ++vertices[indices[currentIndex + 1]].numLiveTriangles; vertices[indices[currentIndex + 2]].vertexTriangles.push(triangle); ++vertices[indices[currentIndex + 2]].numLiveTriangles; ++triangle; currentIndex += 3; } let f2 = 0; let s2 = cacheSize + 1; cursor = 1; let oneRing; const deadEnd = []; let vertex; let intoVertices; let currentOutputIndex = 0; const outputIndices = []; const numTriangles = numIndices / 3; const triangleEmitted = []; for (i = 0; i < numTriangles; i++) { triangleEmitted[i] = false; } let index; let limit; while (f2 !== -1) { oneRing = []; intoVertices = vertices[f2]; limit = intoVertices.vertexTriangles.length; for (let k = 0; k < limit; ++k) { triangle = intoVertices.vertexTriangles[k]; if (!triangleEmitted[triangle]) { triangleEmitted[triangle] = true; currentIndex = triangle + triangle + triangle; for (let j = 0; j < 3; ++j) { index = indices[currentIndex]; oneRing.push(index); deadEnd.push(index); outputIndices[currentOutputIndex] = index; ++currentOutputIndex; vertex = vertices[index]; --vertex.numLiveTriangles; if (s2 - vertex.timeStamp > cacheSize) { vertex.timeStamp = s2; ++s2; } ++currentIndex; } } } f2 = getNextVertex( indices, cacheSize, oneRing, vertices, s2, deadEnd, maximumIndexPlusOne ); } return outputIndices; }; var Tipsify_default = Tipsify; // packages/engine/Source/Core/GeometryPipeline.js var GeometryPipeline = {}; function addTriangle(lines, index, i0, i1, i2) { lines[index++] = i0; lines[index++] = i1; lines[index++] = i1; lines[index++] = i2; lines[index++] = i2; lines[index] = i0; } function trianglesToLines(triangles) { const count = triangles.length; const size = count / 3 * 6; const lines = IndexDatatype_default.createTypedArray(count, size); let index = 0; for (let i = 0; i < count; i += 3, index += 6) { addTriangle(lines, index, triangles[i], triangles[i + 1], triangles[i + 2]); } return lines; } function triangleStripToLines(triangles) { const count = triangles.length; if (count >= 3) { const size = (count - 2) * 6; const lines = IndexDatatype_default.createTypedArray(count, size); addTriangle(lines, 0, triangles[0], triangles[1], triangles[2]); let index = 6; for (let i = 3; i < count; ++i, index += 6) { addTriangle( lines, index, triangles[i - 1], triangles[i], triangles[i - 2] ); } return lines; } return new Uint16Array(); } function triangleFanToLines(triangles) { if (triangles.length > 0) { const count = triangles.length - 1; const size = (count - 1) * 6; const lines = IndexDatatype_default.createTypedArray(count, size); const base = triangles[0]; let index = 0; for (let i = 1; i < count; ++i, index += 6) { addTriangle(lines, index, base, triangles[i], triangles[i + 1]); } return lines; } return new Uint16Array(); } GeometryPipeline.toWireframe = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const indices = geometry.indices; if (defined_default(indices)) { switch (geometry.primitiveType) { case PrimitiveType_default.TRIANGLES: geometry.indices = trianglesToLines(indices); break; case PrimitiveType_default.TRIANGLE_STRIP: geometry.indices = triangleStripToLines(indices); break; case PrimitiveType_default.TRIANGLE_FAN: geometry.indices = triangleFanToLines(indices); break; //>>includeStart('debug', pragmas.debug); default: throw new DeveloperError_default( "geometry.primitiveType must be TRIANGLES, TRIANGLE_STRIP, or TRIANGLE_FAN." ); } geometry.primitiveType = PrimitiveType_default.LINES; } return geometry; }; GeometryPipeline.createLineSegmentsForVectors = function(geometry, attributeName, length2) { attributeName = attributeName ?? "normal"; if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } if (!defined_default(geometry.attributes.position)) { throw new DeveloperError_default("geometry.attributes.position is required."); } if (!defined_default(geometry.attributes[attributeName])) { throw new DeveloperError_default( `geometry.attributes must have an attribute with the same name as the attributeName parameter, ${attributeName}.` ); } length2 = length2 ?? 1e4; const positions = geometry.attributes.position.values; const vectors = geometry.attributes[attributeName].values; const positionsLength = positions.length; const newPositions = new Float64Array(2 * positionsLength); let j = 0; for (let i = 0; i < positionsLength; i += 3) { newPositions[j++] = positions[i]; newPositions[j++] = positions[i + 1]; newPositions[j++] = positions[i + 2]; newPositions[j++] = positions[i] + vectors[i] * length2; newPositions[j++] = positions[i + 1] + vectors[i + 1] * length2; newPositions[j++] = positions[i + 2] + vectors[i + 2] * length2; } let newBoundingSphere; const bs = geometry.boundingSphere; if (defined_default(bs)) { newBoundingSphere = new BoundingSphere_default(bs.center, bs.radius + length2); } return new Geometry_default({ attributes: { position: new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, values: newPositions }) }, primitiveType: PrimitiveType_default.LINES, boundingSphere: newBoundingSphere }); }; GeometryPipeline.createAttributeLocations = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const semantics = [ "position", "positionHigh", "positionLow", // From VertexFormat.position - after 2D projection and high-precision encoding "position3DHigh", "position3DLow", "position2DHigh", "position2DLow", // From Primitive "pickColor", // From VertexFormat "normal", "st", "tangent", "bitangent", // For shadow volumes "extrudeDirection", // From compressing texture coordinates and normals "compressedAttributes" ]; const attributes = geometry.attributes; const indices = {}; let j = 0; let i; const len = semantics.length; for (i = 0; i < len; ++i) { const semantic = semantics[i]; if (defined_default(attributes[semantic])) { indices[semantic] = j++; } } for (const name in attributes) { if (attributes.hasOwnProperty(name) && !defined_default(indices[name])) { indices[name] = j++; } } return indices; }; GeometryPipeline.reorderForPreVertexCache = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const numVertices = Geometry_default.computeNumberOfVertices(geometry); const indices = geometry.indices; if (defined_default(indices)) { const indexCrossReferenceOldToNew = new Int32Array(numVertices); for (let i = 0; i < numVertices; i++) { indexCrossReferenceOldToNew[i] = -1; } const indicesIn = indices; const numIndices = indicesIn.length; const indicesOut = IndexDatatype_default.createTypedArray(numVertices, numIndices); let intoIndicesIn = 0; let intoIndicesOut = 0; let nextIndex = 0; let tempIndex; while (intoIndicesIn < numIndices) { tempIndex = indexCrossReferenceOldToNew[indicesIn[intoIndicesIn]]; if (tempIndex !== -1) { indicesOut[intoIndicesOut] = tempIndex; } else { tempIndex = indicesIn[intoIndicesIn]; indexCrossReferenceOldToNew[tempIndex] = nextIndex; indicesOut[intoIndicesOut] = nextIndex; ++nextIndex; } ++intoIndicesIn; ++intoIndicesOut; } geometry.indices = indicesOut; const attributes = geometry.attributes; for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property]) && defined_default(attributes[property].values)) { const attribute = attributes[property]; const elementsIn = attribute.values; let intoElementsIn = 0; const numComponents = attribute.componentsPerAttribute; const elementsOut = ComponentDatatype_default.createTypedArray( attribute.componentDatatype, nextIndex * numComponents ); while (intoElementsIn < numVertices) { const temp = indexCrossReferenceOldToNew[intoElementsIn]; if (temp !== -1) { for (let j = 0; j < numComponents; j++) { elementsOut[numComponents * temp + j] = elementsIn[numComponents * intoElementsIn + j]; } } ++intoElementsIn; } attribute.values = elementsOut; } } } return geometry; }; GeometryPipeline.reorderForPostVertexCache = function(geometry, cacheCapacity) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const indices = geometry.indices; if (geometry.primitiveType === PrimitiveType_default.TRIANGLES && defined_default(indices)) { const numIndices = indices.length; let maximumIndex = 0; for (let j = 0; j < numIndices; j++) { if (indices[j] > maximumIndex) { maximumIndex = indices[j]; } } geometry.indices = Tipsify_default.tipsify({ indices, maximumIndex, cacheSize: cacheCapacity }); } return geometry; }; function copyAttributesDescriptions(attributes) { const newAttributes = {}; for (const attribute in attributes) { if (attributes.hasOwnProperty(attribute) && defined_default(attributes[attribute]) && defined_default(attributes[attribute].values)) { const attr = attributes[attribute]; newAttributes[attribute] = new GeometryAttribute_default({ componentDatatype: attr.componentDatatype, componentsPerAttribute: attr.componentsPerAttribute, normalize: attr.normalize, values: [] }); } } return newAttributes; } function copyVertex(destinationAttributes, sourceAttributes, index) { for (const attribute in sourceAttributes) { if (sourceAttributes.hasOwnProperty(attribute) && defined_default(sourceAttributes[attribute]) && defined_default(sourceAttributes[attribute].values)) { const attr = sourceAttributes[attribute]; for (let k = 0; k < attr.componentsPerAttribute; ++k) { destinationAttributes[attribute].values.push( attr.values[index * attr.componentsPerAttribute + k] ); } } } } GeometryPipeline.fitToUnsignedShortIndices = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } if (defined_default(geometry.indices) && geometry.primitiveType !== PrimitiveType_default.TRIANGLES && geometry.primitiveType !== PrimitiveType_default.LINES && geometry.primitiveType !== PrimitiveType_default.POINTS) { throw new DeveloperError_default( "geometry.primitiveType must equal to PrimitiveType.TRIANGLES, PrimitiveType.LINES, or PrimitiveType.POINTS." ); } const geometries = []; const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (defined_default(geometry.indices) && numberOfVertices >= Math_default.SIXTY_FOUR_KILOBYTES) { let oldToNewIndex = []; let newIndices = []; let currentIndex = 0; let newAttributes = copyAttributesDescriptions(geometry.attributes); const originalIndices = geometry.indices; const numberOfIndices = originalIndices.length; let indicesPerPrimitive; if (geometry.primitiveType === PrimitiveType_default.TRIANGLES) { indicesPerPrimitive = 3; } else if (geometry.primitiveType === PrimitiveType_default.LINES) { indicesPerPrimitive = 2; } else if (geometry.primitiveType === PrimitiveType_default.POINTS) { indicesPerPrimitive = 1; } for (let j = 0; j < numberOfIndices; j += indicesPerPrimitive) { for (let k = 0; k < indicesPerPrimitive; ++k) { const x = originalIndices[j + k]; let i = oldToNewIndex[x]; if (!defined_default(i)) { i = currentIndex++; oldToNewIndex[x] = i; copyVertex(newAttributes, geometry.attributes, x); } newIndices.push(i); } if (currentIndex + indicesPerPrimitive >= Math_default.SIXTY_FOUR_KILOBYTES) { geometries.push( new Geometry_default({ attributes: newAttributes, indices: newIndices, primitiveType: geometry.primitiveType, boundingSphere: geometry.boundingSphere, boundingSphereCV: geometry.boundingSphereCV }) ); oldToNewIndex = []; newIndices = []; currentIndex = 0; newAttributes = copyAttributesDescriptions(geometry.attributes); } } if (newIndices.length !== 0) { geometries.push( new Geometry_default({ attributes: newAttributes, indices: newIndices, primitiveType: geometry.primitiveType, boundingSphere: geometry.boundingSphere, boundingSphereCV: geometry.boundingSphereCV }) ); } } else { geometries.push(geometry); } return geometries; }; var scratchProjectTo2DCartesian3 = new Cartesian3_default(); var scratchProjectTo2DCartographic = new Cartographic_default(); GeometryPipeline.projectTo2D = function(geometry, attributeName, attributeName3D, attributeName2D, projection) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } if (!defined_default(attributeName)) { throw new DeveloperError_default("attributeName is required."); } if (!defined_default(attributeName3D)) { throw new DeveloperError_default("attributeName3D is required."); } if (!defined_default(attributeName2D)) { throw new DeveloperError_default("attributeName2D is required."); } if (!defined_default(geometry.attributes[attributeName])) { throw new DeveloperError_default( `geometry must have attribute matching the attributeName argument: ${attributeName}.` ); } if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype_default.DOUBLE) { throw new DeveloperError_default( "The attribute componentDatatype must be ComponentDatatype.DOUBLE." ); } const attribute = geometry.attributes[attributeName]; projection = defined_default(projection) ? projection : new GeographicProjection_default(); const ellipsoid = projection.ellipsoid; const values3D = attribute.values; const projectedValues = new Float64Array(values3D.length); let index = 0; for (let i = 0; i < values3D.length; i += 3) { const value = Cartesian3_default.fromArray( values3D, i, scratchProjectTo2DCartesian3 ); const lonLat = ellipsoid.cartesianToCartographic( value, scratchProjectTo2DCartographic ); if (!defined_default(lonLat)) { throw new DeveloperError_default( `Could not project point (${value.x}, ${value.y}, ${value.z}) to 2D.` ); } const projectedLonLat = projection.project( lonLat, scratchProjectTo2DCartesian3 ); projectedValues[index++] = projectedLonLat.x; projectedValues[index++] = projectedLonLat.y; projectedValues[index++] = projectedLonLat.z; } geometry.attributes[attributeName3D] = attribute; geometry.attributes[attributeName2D] = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, values: projectedValues }); delete geometry.attributes[attributeName]; return geometry; }; var encodedResult = { high: 0, low: 0 }; GeometryPipeline.encodeAttribute = function(geometry, attributeName, attributeHighName, attributeLowName) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } if (!defined_default(attributeName)) { throw new DeveloperError_default("attributeName is required."); } if (!defined_default(attributeHighName)) { throw new DeveloperError_default("attributeHighName is required."); } if (!defined_default(attributeLowName)) { throw new DeveloperError_default("attributeLowName is required."); } if (!defined_default(geometry.attributes[attributeName])) { throw new DeveloperError_default( `geometry must have attribute matching the attributeName argument: ${attributeName}.` ); } if (geometry.attributes[attributeName].componentDatatype !== ComponentDatatype_default.DOUBLE) { throw new DeveloperError_default( "The attribute componentDatatype must be ComponentDatatype.DOUBLE." ); } const attribute = geometry.attributes[attributeName]; const values = attribute.values; const length2 = values.length; const highValues = new Float32Array(length2); const lowValues = new Float32Array(length2); for (let i = 0; i < length2; ++i) { EncodedCartesian3_default.encode(values[i], encodedResult); highValues[i] = encodedResult.high; lowValues[i] = encodedResult.low; } const componentsPerAttribute = attribute.componentsPerAttribute; geometry.attributes[attributeHighName] = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute, values: highValues }); geometry.attributes[attributeLowName] = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute, values: lowValues }); delete geometry.attributes[attributeName]; return geometry; }; var scratchCartesian33 = new Cartesian3_default(); function transformPoint(matrix, attribute) { if (defined_default(attribute)) { const values = attribute.values; const length2 = values.length; for (let i = 0; i < length2; i += 3) { Cartesian3_default.unpack(values, i, scratchCartesian33); Matrix4_default.multiplyByPoint(matrix, scratchCartesian33, scratchCartesian33); Cartesian3_default.pack(scratchCartesian33, values, i); } } } function transformVector(matrix, attribute) { if (defined_default(attribute)) { const values = attribute.values; const length2 = values.length; for (let i = 0; i < length2; i += 3) { Cartesian3_default.unpack(values, i, scratchCartesian33); Matrix3_default.multiplyByVector(matrix, scratchCartesian33, scratchCartesian33); scratchCartesian33 = Cartesian3_default.normalize( scratchCartesian33, scratchCartesian33 ); Cartesian3_default.pack(scratchCartesian33, values, i); } } } var inverseTranspose = new Matrix4_default(); var normalMatrix = new Matrix3_default(); GeometryPipeline.transformToWorldCoordinates = function(instance) { if (!defined_default(instance)) { throw new DeveloperError_default("instance is required."); } const modelMatrix = instance.modelMatrix; if (Matrix4_default.equals(modelMatrix, Matrix4_default.IDENTITY)) { return instance; } const attributes = instance.geometry.attributes; transformPoint(modelMatrix, attributes.position); transformPoint(modelMatrix, attributes.prevPosition); transformPoint(modelMatrix, attributes.nextPosition); if (defined_default(attributes.normal) || defined_default(attributes.tangent) || defined_default(attributes.bitangent)) { Matrix4_default.inverse(modelMatrix, inverseTranspose); Matrix4_default.transpose(inverseTranspose, inverseTranspose); Matrix4_default.getMatrix3(inverseTranspose, normalMatrix); transformVector(normalMatrix, attributes.normal); transformVector(normalMatrix, attributes.tangent); transformVector(normalMatrix, attributes.bitangent); } const boundingSphere = instance.geometry.boundingSphere; if (defined_default(boundingSphere)) { instance.geometry.boundingSphere = BoundingSphere_default.transform( boundingSphere, modelMatrix, boundingSphere ); } instance.modelMatrix = Matrix4_default.clone(Matrix4_default.IDENTITY); return instance; }; function findAttributesInAllGeometries(instances, propertyName) { const length2 = instances.length; const attributesInAllGeometries = {}; const attributes0 = instances[0][propertyName].attributes; let name; for (name in attributes0) { if (attributes0.hasOwnProperty(name) && defined_default(attributes0[name]) && defined_default(attributes0[name].values)) { const attribute = attributes0[name]; let numberOfComponents = attribute.values.length; let inAllGeometries = true; for (let i = 1; i < length2; ++i) { const otherAttribute = instances[i][propertyName].attributes[name]; if (!defined_default(otherAttribute) || attribute.componentDatatype !== otherAttribute.componentDatatype || attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute || attribute.normalize !== otherAttribute.normalize) { inAllGeometries = false; break; } numberOfComponents += otherAttribute.values.length; } if (inAllGeometries) { attributesInAllGeometries[name] = new GeometryAttribute_default({ componentDatatype: attribute.componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize, values: ComponentDatatype_default.createTypedArray( attribute.componentDatatype, numberOfComponents ) }); } } } return attributesInAllGeometries; } var tempScratch = new Cartesian3_default(); function combineGeometries(instances, propertyName) { const length2 = instances.length; let name; let i; let j; let k; const m = instances[0].modelMatrix; const haveIndices = defined_default(instances[0][propertyName].indices); const primitiveType = instances[0][propertyName].primitiveType; for (i = 1; i < length2; ++i) { if (!Matrix4_default.equals(instances[i].modelMatrix, m)) { throw new DeveloperError_default("All instances must have the same modelMatrix."); } if (defined_default(instances[i][propertyName].indices) !== haveIndices) { throw new DeveloperError_default( "All instance geometries must have an indices or not have one." ); } if (instances[i][propertyName].primitiveType !== primitiveType) { throw new DeveloperError_default( "All instance geometries must have the same primitiveType." ); } } const attributes = findAttributesInAllGeometries(instances, propertyName); let values; let sourceValues; let sourceValuesLength; for (name in attributes) { if (attributes.hasOwnProperty(name)) { values = attributes[name].values; k = 0; for (i = 0; i < length2; ++i) { sourceValues = instances[i][propertyName].attributes[name].values; sourceValuesLength = sourceValues.length; for (j = 0; j < sourceValuesLength; ++j) { values[k++] = sourceValues[j]; } } } } let indices; if (haveIndices) { let numberOfIndices = 0; for (i = 0; i < length2; ++i) { numberOfIndices += instances[i][propertyName].indices.length; } const numberOfVertices = Geometry_default.computeNumberOfVertices( new Geometry_default({ attributes, primitiveType: PrimitiveType_default.POINTS }) ); const destIndices = IndexDatatype_default.createTypedArray( numberOfVertices, numberOfIndices ); let destOffset = 0; let offset = 0; for (i = 0; i < length2; ++i) { const sourceIndices = instances[i][propertyName].indices; const sourceIndicesLen = sourceIndices.length; for (k = 0; k < sourceIndicesLen; ++k) { destIndices[destOffset++] = offset + sourceIndices[k]; } offset += Geometry_default.computeNumberOfVertices(instances[i][propertyName]); } indices = destIndices; } let center = new Cartesian3_default(); let radius = 0; let bs; for (i = 0; i < length2; ++i) { bs = instances[i][propertyName].boundingSphere; if (!defined_default(bs)) { center = void 0; break; } Cartesian3_default.add(bs.center, center, center); } if (defined_default(center)) { Cartesian3_default.divideByScalar(center, length2, center); for (i = 0; i < length2; ++i) { bs = instances[i][propertyName].boundingSphere; const tempRadius = Cartesian3_default.magnitude( Cartesian3_default.subtract(bs.center, center, tempScratch) ) + bs.radius; if (tempRadius > radius) { radius = tempRadius; } } } return new Geometry_default({ attributes, indices, primitiveType, boundingSphere: defined_default(center) ? new BoundingSphere_default(center, radius) : void 0 }); } GeometryPipeline.combineInstances = function(instances) { if (!defined_default(instances) || instances.length < 1) { throw new DeveloperError_default( "instances is required and must have length greater than zero." ); } const instanceGeometry = []; const instanceSplitGeometry = []; const length2 = instances.length; for (let i = 0; i < length2; ++i) { const instance = instances[i]; if (defined_default(instance.geometry)) { instanceGeometry.push(instance); } else if (defined_default(instance.westHemisphereGeometry) && defined_default(instance.eastHemisphereGeometry)) { instanceSplitGeometry.push(instance); } } const geometries = []; if (instanceGeometry.length > 0) { geometries.push(combineGeometries(instanceGeometry, "geometry")); } if (instanceSplitGeometry.length > 0) { geometries.push( combineGeometries(instanceSplitGeometry, "westHemisphereGeometry") ); geometries.push( combineGeometries(instanceSplitGeometry, "eastHemisphereGeometry") ); } return geometries; }; var normal = new Cartesian3_default(); var v0 = new Cartesian3_default(); var v1 = new Cartesian3_default(); var v2 = new Cartesian3_default(); GeometryPipeline.computeNormal = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } if (!defined_default(geometry.attributes.position) || !defined_default(geometry.attributes.position.values)) { throw new DeveloperError_default( "geometry.attributes.position.values is required." ); } if (!defined_default(geometry.indices)) { throw new DeveloperError_default("geometry.indices is required."); } if (geometry.indices.length < 2 || geometry.indices.length % 3 !== 0) { throw new DeveloperError_default( "geometry.indices length must be greater than 0 and be a multiple of 3." ); } if (geometry.primitiveType !== PrimitiveType_default.TRIANGLES) { throw new DeveloperError_default( "geometry.primitiveType must be PrimitiveType.TRIANGLES." ); } const indices = geometry.indices; const attributes = geometry.attributes; const vertices = attributes.position.values; const numVertices = attributes.position.values.length / 3; const numIndices = indices.length; const normalsPerVertex = new Array(numVertices); const normalsPerTriangle = new Array(numIndices / 3); const normalIndices = new Array(numIndices); let i; for (i = 0; i < numVertices; i++) { normalsPerVertex[i] = { indexOffset: 0, count: 0, currentCount: 0 }; } let j = 0; for (i = 0; i < numIndices; i += 3) { const i0 = indices[i]; const i1 = indices[i + 1]; const i2 = indices[i + 2]; const i03 = i0 * 3; const i13 = i1 * 3; const i23 = i2 * 3; v0.x = vertices[i03]; v0.y = vertices[i03 + 1]; v0.z = vertices[i03 + 2]; v1.x = vertices[i13]; v1.y = vertices[i13 + 1]; v1.z = vertices[i13 + 2]; v2.x = vertices[i23]; v2.y = vertices[i23 + 1]; v2.z = vertices[i23 + 2]; normalsPerVertex[i0].count++; normalsPerVertex[i1].count++; normalsPerVertex[i2].count++; Cartesian3_default.subtract(v1, v0, v1); Cartesian3_default.subtract(v2, v0, v2); normalsPerTriangle[j] = Cartesian3_default.cross(v1, v2, new Cartesian3_default()); j++; } let indexOffset = 0; for (i = 0; i < numVertices; i++) { normalsPerVertex[i].indexOffset += indexOffset; indexOffset += normalsPerVertex[i].count; } j = 0; let vertexNormalData; for (i = 0; i < numIndices; i += 3) { vertexNormalData = normalsPerVertex[indices[i]]; let index = vertexNormalData.indexOffset + vertexNormalData.currentCount; normalIndices[index] = j; vertexNormalData.currentCount++; vertexNormalData = normalsPerVertex[indices[i + 1]]; index = vertexNormalData.indexOffset + vertexNormalData.currentCount; normalIndices[index] = j; vertexNormalData.currentCount++; vertexNormalData = normalsPerVertex[indices[i + 2]]; index = vertexNormalData.indexOffset + vertexNormalData.currentCount; normalIndices[index] = j; vertexNormalData.currentCount++; j++; } const normalValues = new Float32Array(numVertices * 3); for (i = 0; i < numVertices; i++) { const i3 = i * 3; vertexNormalData = normalsPerVertex[i]; Cartesian3_default.clone(Cartesian3_default.ZERO, normal); if (vertexNormalData.count > 0) { for (j = 0; j < vertexNormalData.count; j++) { Cartesian3_default.add( normal, normalsPerTriangle[normalIndices[vertexNormalData.indexOffset + j]], normal ); } if (Cartesian3_default.equalsEpsilon(Cartesian3_default.ZERO, normal, Math_default.EPSILON10)) { Cartesian3_default.clone( normalsPerTriangle[normalIndices[vertexNormalData.indexOffset]], normal ); } } if (Cartesian3_default.equalsEpsilon(Cartesian3_default.ZERO, normal, Math_default.EPSILON10)) { normal.z = 1; } Cartesian3_default.normalize(normal, normal); normalValues[i3] = normal.x; normalValues[i3 + 1] = normal.y; normalValues[i3 + 2] = normal.z; } geometry.attributes.normal = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: normalValues }); return geometry; }; var normalScratch2 = new Cartesian3_default(); var normalScale = new Cartesian3_default(); var tScratch = new Cartesian3_default(); GeometryPipeline.computeTangentAndBitangent = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const attributes = geometry.attributes; const indices = geometry.indices; if (!defined_default(attributes.position) || !defined_default(attributes.position.values)) { throw new DeveloperError_default( "geometry.attributes.position.values is required." ); } if (!defined_default(attributes.normal) || !defined_default(attributes.normal.values)) { throw new DeveloperError_default("geometry.attributes.normal.values is required."); } if (!defined_default(attributes.st) || !defined_default(attributes.st.values)) { throw new DeveloperError_default("geometry.attributes.st.values is required."); } if (!defined_default(indices)) { throw new DeveloperError_default("geometry.indices is required."); } if (indices.length < 2 || indices.length % 3 !== 0) { throw new DeveloperError_default( "geometry.indices length must be greater than 0 and be a multiple of 3." ); } if (geometry.primitiveType !== PrimitiveType_default.TRIANGLES) { throw new DeveloperError_default( "geometry.primitiveType must be PrimitiveType.TRIANGLES." ); } const vertices = geometry.attributes.position.values; const normals = geometry.attributes.normal.values; const st = geometry.attributes.st.values; const numVertices = geometry.attributes.position.values.length / 3; const numIndices = indices.length; const tan1 = new Array(numVertices * 3); let i; for (i = 0; i < tan1.length; i++) { tan1[i] = 0; } let i03; let i13; let i23; for (i = 0; i < numIndices; i += 3) { const i0 = indices[i]; const i1 = indices[i + 1]; const i2 = indices[i + 2]; i03 = i0 * 3; i13 = i1 * 3; i23 = i2 * 3; const i02 = i0 * 2; const i12 = i1 * 2; const i22 = i2 * 2; const ux = vertices[i03]; const uy = vertices[i03 + 1]; const uz = vertices[i03 + 2]; const wx = st[i02]; const wy = st[i02 + 1]; const t1 = st[i12 + 1] - wy; const t2 = st[i22 + 1] - wy; const r2 = 1 / ((st[i12] - wx) * t2 - (st[i22] - wx) * t1); const sdirx = (t2 * (vertices[i13] - ux) - t1 * (vertices[i23] - ux)) * r2; const sdiry = (t2 * (vertices[i13 + 1] - uy) - t1 * (vertices[i23 + 1] - uy)) * r2; const sdirz = (t2 * (vertices[i13 + 2] - uz) - t1 * (vertices[i23 + 2] - uz)) * r2; tan1[i03] += sdirx; tan1[i03 + 1] += sdiry; tan1[i03 + 2] += sdirz; tan1[i13] += sdirx; tan1[i13 + 1] += sdiry; tan1[i13 + 2] += sdirz; tan1[i23] += sdirx; tan1[i23 + 1] += sdiry; tan1[i23 + 2] += sdirz; } const tangentValues = new Float32Array(numVertices * 3); const bitangentValues = new Float32Array(numVertices * 3); for (i = 0; i < numVertices; i++) { i03 = i * 3; i13 = i03 + 1; i23 = i03 + 2; const n2 = Cartesian3_default.fromArray(normals, i03, normalScratch2); const t2 = Cartesian3_default.fromArray(tan1, i03, tScratch); const scalar = Cartesian3_default.dot(n2, t2); Cartesian3_default.multiplyByScalar(n2, scalar, normalScale); Cartesian3_default.normalize(Cartesian3_default.subtract(t2, normalScale, t2), t2); tangentValues[i03] = t2.x; tangentValues[i13] = t2.y; tangentValues[i23] = t2.z; Cartesian3_default.normalize(Cartesian3_default.cross(n2, t2, t2), t2); bitangentValues[i03] = t2.x; bitangentValues[i13] = t2.y; bitangentValues[i23] = t2.z; } geometry.attributes.tangent = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: tangentValues }); geometry.attributes.bitangent = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, values: bitangentValues }); return geometry; }; var scratchCartesian22 = new Cartesian2_default(); var toEncode1 = new Cartesian3_default(); var toEncode2 = new Cartesian3_default(); var toEncode3 = new Cartesian3_default(); var encodeResult2 = new Cartesian2_default(); GeometryPipeline.compressVertices = function(geometry) { if (!defined_default(geometry)) { throw new DeveloperError_default("geometry is required."); } const extrudeAttribute = geometry.attributes.extrudeDirection; let i; let numVertices; if (defined_default(extrudeAttribute)) { const extrudeDirections = extrudeAttribute.values; numVertices = extrudeDirections.length / 3; const compressedDirections = new Float32Array(numVertices * 2); let i2 = 0; for (i = 0; i < numVertices; ++i) { Cartesian3_default.fromArray(extrudeDirections, i * 3, toEncode1); if (Cartesian3_default.equals(toEncode1, Cartesian3_default.ZERO)) { i2 += 2; continue; } encodeResult2 = AttributeCompression_default.octEncodeInRange( toEncode1, 65535, encodeResult2 ); compressedDirections[i2++] = encodeResult2.x; compressedDirections[i2++] = encodeResult2.y; } geometry.attributes.compressedAttributes = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 2, values: compressedDirections }); delete geometry.attributes.extrudeDirection; return geometry; } const normalAttribute = geometry.attributes.normal; const stAttribute = geometry.attributes.st; const hasNormal = defined_default(normalAttribute); const hasSt = defined_default(stAttribute); if (!hasNormal && !hasSt) { return geometry; } const tangentAttribute = geometry.attributes.tangent; const bitangentAttribute = geometry.attributes.bitangent; const hasTangent = defined_default(tangentAttribute); const hasBitangent = defined_default(bitangentAttribute); let normals; let st; let tangents; let bitangents; if (hasNormal) { normals = normalAttribute.values; } if (hasSt) { st = stAttribute.values; } if (hasTangent) { tangents = tangentAttribute.values; } if (hasBitangent) { bitangents = bitangentAttribute.values; } const length2 = hasNormal ? normals.length : st.length; const numComponents = hasNormal ? 3 : 2; numVertices = length2 / numComponents; let compressedLength = numVertices; let numCompressedComponents = hasSt && hasNormal ? 2 : 1; numCompressedComponents += hasTangent || hasBitangent ? 1 : 0; compressedLength *= numCompressedComponents; const compressedAttributes = new Float32Array(compressedLength); let normalIndex = 0; for (i = 0; i < numVertices; ++i) { if (hasSt) { Cartesian2_default.fromArray(st, i * 2, scratchCartesian22); compressedAttributes[normalIndex++] = AttributeCompression_default.compressTextureCoordinates(scratchCartesian22); } const index = i * 3; if (hasNormal && defined_default(tangents) && defined_default(bitangents)) { Cartesian3_default.fromArray(normals, index, toEncode1); Cartesian3_default.fromArray(tangents, index, toEncode2); Cartesian3_default.fromArray(bitangents, index, toEncode3); AttributeCompression_default.octPack( toEncode1, toEncode2, toEncode3, scratchCartesian22 ); compressedAttributes[normalIndex++] = scratchCartesian22.x; compressedAttributes[normalIndex++] = scratchCartesian22.y; } else { if (hasNormal) { Cartesian3_default.fromArray(normals, index, toEncode1); compressedAttributes[normalIndex++] = AttributeCompression_default.octEncodeFloat(toEncode1); } if (hasTangent) { Cartesian3_default.fromArray(tangents, index, toEncode1); compressedAttributes[normalIndex++] = AttributeCompression_default.octEncodeFloat(toEncode1); } if (hasBitangent) { Cartesian3_default.fromArray(bitangents, index, toEncode1); compressedAttributes[normalIndex++] = AttributeCompression_default.octEncodeFloat(toEncode1); } } } geometry.attributes.compressedAttributes = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: numCompressedComponents, values: compressedAttributes }); if (hasNormal) { delete geometry.attributes.normal; } if (hasSt) { delete geometry.attributes.st; } if (hasBitangent) { delete geometry.attributes.bitangent; } if (hasTangent) { delete geometry.attributes.tangent; } return geometry; }; function indexTriangles(geometry) { if (defined_default(geometry.indices)) { return geometry; } const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError_default("The number of vertices must be at least three."); } if (numberOfVertices % 3 !== 0) { throw new DeveloperError_default( "The number of vertices must be a multiple of three." ); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, numberOfVertices ); for (let i = 0; i < numberOfVertices; ++i) { indices[i] = i; } geometry.indices = indices; return geometry; } function indexTriangleFan(geometry) { const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError_default("The number of vertices must be at least three."); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, (numberOfVertices - 2) * 3 ); indices[0] = 1; indices[1] = 0; indices[2] = 2; let indicesIndex = 3; for (let i = 3; i < numberOfVertices; ++i) { indices[indicesIndex++] = i - 1; indices[indicesIndex++] = 0; indices[indicesIndex++] = i; } geometry.indices = indices; geometry.primitiveType = PrimitiveType_default.TRIANGLES; return geometry; } function indexTriangleStrip(geometry) { const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 3) { throw new DeveloperError_default("The number of vertices must be at least 3."); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, (numberOfVertices - 2) * 3 ); indices[0] = 0; indices[1] = 1; indices[2] = 2; if (numberOfVertices > 3) { indices[3] = 0; indices[4] = 2; indices[5] = 3; } let indicesIndex = 6; for (let i = 3; i < numberOfVertices - 1; i += 2) { indices[indicesIndex++] = i; indices[indicesIndex++] = i - 1; indices[indicesIndex++] = i + 1; if (i + 2 < numberOfVertices) { indices[indicesIndex++] = i; indices[indicesIndex++] = i + 1; indices[indicesIndex++] = i + 2; } } geometry.indices = indices; geometry.primitiveType = PrimitiveType_default.TRIANGLES; return geometry; } function indexLines(geometry) { if (defined_default(geometry.indices)) { return geometry; } const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError_default("The number of vertices must be at least two."); } if (numberOfVertices % 2 !== 0) { throw new DeveloperError_default("The number of vertices must be a multiple of 2."); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, numberOfVertices ); for (let i = 0; i < numberOfVertices; ++i) { indices[i] = i; } geometry.indices = indices; return geometry; } function indexLineStrip(geometry) { const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError_default("The number of vertices must be at least two."); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, (numberOfVertices - 1) * 2 ); indices[0] = 0; indices[1] = 1; let indicesIndex = 2; for (let i = 2; i < numberOfVertices; ++i) { indices[indicesIndex++] = i - 1; indices[indicesIndex++] = i; } geometry.indices = indices; geometry.primitiveType = PrimitiveType_default.LINES; return geometry; } function indexLineLoop(geometry) { const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); if (numberOfVertices < 2) { throw new DeveloperError_default("The number of vertices must be at least two."); } const indices = IndexDatatype_default.createTypedArray( numberOfVertices, numberOfVertices * 2 ); indices[0] = 0; indices[1] = 1; let indicesIndex = 2; for (let i = 2; i < numberOfVertices; ++i) { indices[indicesIndex++] = i - 1; indices[indicesIndex++] = i; } indices[indicesIndex++] = numberOfVertices - 1; indices[indicesIndex] = 0; geometry.indices = indices; geometry.primitiveType = PrimitiveType_default.LINES; return geometry; } function indexPrimitive(geometry) { switch (geometry.primitiveType) { case PrimitiveType_default.TRIANGLE_FAN: return indexTriangleFan(geometry); case PrimitiveType_default.TRIANGLE_STRIP: return indexTriangleStrip(geometry); case PrimitiveType_default.TRIANGLES: return indexTriangles(geometry); case PrimitiveType_default.LINE_STRIP: return indexLineStrip(geometry); case PrimitiveType_default.LINE_LOOP: return indexLineLoop(geometry); case PrimitiveType_default.LINES: return indexLines(geometry); } return geometry; } function offsetPointFromXZPlane(p, isBehind) { if (Math.abs(p.y) < Math_default.EPSILON6) { if (isBehind) { p.y = -Math_default.EPSILON6; } else { p.y = Math_default.EPSILON6; } } } function offsetTriangleFromXZPlane(p0, p1, p2) { if (p0.y !== 0 && p1.y !== 0 && p2.y !== 0) { offsetPointFromXZPlane(p0, p0.y < 0); offsetPointFromXZPlane(p1, p1.y < 0); offsetPointFromXZPlane(p2, p2.y < 0); return; } const p0y = Math.abs(p0.y); const p1y = Math.abs(p1.y); const p2y = Math.abs(p2.y); let sign3; if (p0y > p1y) { if (p0y > p2y) { sign3 = Math_default.sign(p0.y); } else { sign3 = Math_default.sign(p2.y); } } else if (p1y > p2y) { sign3 = Math_default.sign(p1.y); } else { sign3 = Math_default.sign(p2.y); } const isBehind = sign3 < 0; offsetPointFromXZPlane(p0, isBehind); offsetPointFromXZPlane(p1, isBehind); offsetPointFromXZPlane(p2, isBehind); } var c3 = new Cartesian3_default(); function getXZIntersectionOffsetPoints(p, p1, u12, v12) { Cartesian3_default.add( p, Cartesian3_default.multiplyByScalar( Cartesian3_default.subtract(p1, p, c3), p.y / (p.y - p1.y), c3 ), u12 ); Cartesian3_default.clone(u12, v12); offsetPointFromXZPlane(u12, true); offsetPointFromXZPlane(v12, false); } var u1 = new Cartesian3_default(); var u2 = new Cartesian3_default(); var q1 = new Cartesian3_default(); var q2 = new Cartesian3_default(); var splitTriangleResult = { positions: new Array(7), indices: new Array(3 * 3) }; function splitTriangle(p0, p1, p2) { if (p0.x >= 0 || p1.x >= 0 || p2.x >= 0) { return void 0; } offsetTriangleFromXZPlane(p0, p1, p2); const p0Behind = p0.y < 0; const p1Behind = p1.y < 0; const p2Behind = p2.y < 0; let numBehind = 0; numBehind += p0Behind ? 1 : 0; numBehind += p1Behind ? 1 : 0; numBehind += p2Behind ? 1 : 0; const indices = splitTriangleResult.indices; if (numBehind === 1) { indices[1] = 3; indices[2] = 4; indices[5] = 6; indices[7] = 6; indices[8] = 5; if (p0Behind) { getXZIntersectionOffsetPoints(p0, p1, u1, q1); getXZIntersectionOffsetPoints(p0, p2, u2, q2); indices[0] = 0; indices[3] = 1; indices[4] = 2; indices[6] = 1; } else if (p1Behind) { getXZIntersectionOffsetPoints(p1, p2, u1, q1); getXZIntersectionOffsetPoints(p1, p0, u2, q2); indices[0] = 1; indices[3] = 2; indices[4] = 0; indices[6] = 2; } else if (p2Behind) { getXZIntersectionOffsetPoints(p2, p0, u1, q1); getXZIntersectionOffsetPoints(p2, p1, u2, q2); indices[0] = 2; indices[3] = 0; indices[4] = 1; indices[6] = 0; } } else if (numBehind === 2) { indices[2] = 4; indices[4] = 4; indices[5] = 3; indices[7] = 5; indices[8] = 6; if (!p0Behind) { getXZIntersectionOffsetPoints(p0, p1, u1, q1); getXZIntersectionOffsetPoints(p0, p2, u2, q2); indices[0] = 1; indices[1] = 2; indices[3] = 1; indices[6] = 0; } else if (!p1Behind) { getXZIntersectionOffsetPoints(p1, p2, u1, q1); getXZIntersectionOffsetPoints(p1, p0, u2, q2); indices[0] = 2; indices[1] = 0; indices[3] = 2; indices[6] = 1; } else if (!p2Behind) { getXZIntersectionOffsetPoints(p2, p0, u1, q1); getXZIntersectionOffsetPoints(p2, p1, u2, q2); indices[0] = 0; indices[1] = 1; indices[3] = 0; indices[6] = 2; } } const positions = splitTriangleResult.positions; positions[0] = p0; positions[1] = p1; positions[2] = p2; positions.length = 3; if (numBehind === 1 || numBehind === 2) { positions[3] = u1; positions[4] = u2; positions[5] = q1; positions[6] = q2; positions.length = 7; } return splitTriangleResult; } function updateGeometryAfterSplit(geometry, computeBoundingSphere) { const attributes = geometry.attributes; if (attributes.position.values.length === 0) { return void 0; } for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property]) && defined_default(attributes[property].values)) { const attribute = attributes[property]; attribute.values = ComponentDatatype_default.createTypedArray( attribute.componentDatatype, attribute.values ); } } const numberOfVertices = Geometry_default.computeNumberOfVertices(geometry); geometry.indices = IndexDatatype_default.createTypedArray( numberOfVertices, geometry.indices ); if (computeBoundingSphere) { geometry.boundingSphere = BoundingSphere_default.fromVertices( attributes.position.values ); } return geometry; } function copyGeometryForSplit(geometry) { const attributes = geometry.attributes; const copiedAttributes = {}; for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property]) && defined_default(attributes[property].values)) { const attribute = attributes[property]; copiedAttributes[property] = new GeometryAttribute_default({ componentDatatype: attribute.componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize, values: [] }); } } return new Geometry_default({ attributes: copiedAttributes, indices: [], primitiveType: geometry.primitiveType }); } function updateInstanceAfterSplit(instance, westGeometry, eastGeometry) { const computeBoundingSphere = defined_default(instance.geometry.boundingSphere); westGeometry = updateGeometryAfterSplit(westGeometry, computeBoundingSphere); eastGeometry = updateGeometryAfterSplit(eastGeometry, computeBoundingSphere); if (defined_default(eastGeometry) && !defined_default(westGeometry)) { instance.geometry = eastGeometry; } else if (!defined_default(eastGeometry) && defined_default(westGeometry)) { instance.geometry = westGeometry; } else { instance.westHemisphereGeometry = westGeometry; instance.eastHemisphereGeometry = eastGeometry; instance.geometry = void 0; } } function generateBarycentricInterpolateFunction(CartesianType, numberOfComponents) { const v0Scratch = new CartesianType(); const v1Scratch2 = new CartesianType(); const v2Scratch2 = new CartesianType(); return function(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, normalize2) { const v02 = CartesianType.fromArray( sourceValues, i0 * numberOfComponents, v0Scratch ); const v12 = CartesianType.fromArray( sourceValues, i1 * numberOfComponents, v1Scratch2 ); const v22 = CartesianType.fromArray( sourceValues, i2 * numberOfComponents, v2Scratch2 ); CartesianType.multiplyByScalar(v02, coords.x, v02); CartesianType.multiplyByScalar(v12, coords.y, v12); CartesianType.multiplyByScalar(v22, coords.z, v22); const value = CartesianType.add(v02, v12, v02); CartesianType.add(value, v22, value); if (normalize2) { CartesianType.normalize(value, value); } CartesianType.pack( value, currentValues, insertedIndex * numberOfComponents ); }; } var interpolateAndPackCartesian4 = generateBarycentricInterpolateFunction( Cartesian4_default, 4 ); var interpolateAndPackCartesian3 = generateBarycentricInterpolateFunction( Cartesian3_default, 3 ); var interpolateAndPackCartesian2 = generateBarycentricInterpolateFunction( Cartesian2_default, 2 ); var interpolateAndPackBoolean = function(i0, i1, i2, coords, sourceValues, currentValues, insertedIndex) { const v12 = sourceValues[i0] * coords.x; const v22 = sourceValues[i1] * coords.y; const v3 = sourceValues[i2] * coords.z; currentValues[insertedIndex] = v12 + v22 + v3 > Math_default.EPSILON6 ? 1 : 0; }; var p0Scratch = new Cartesian3_default(); var p1Scratch = new Cartesian3_default(); var p2Scratch = new Cartesian3_default(); var barycentricScratch = new Cartesian3_default(); function computeTriangleAttributes(i0, i1, i2, point4, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, allAttributes, insertedIndex) { if (!defined_default(normals) && !defined_default(tangents) && !defined_default(bitangents) && !defined_default(texCoords) && !defined_default(extrudeDirections) && customAttributesLength === 0) { return; } const p0 = Cartesian3_default.fromArray(positions, i0 * 3, p0Scratch); const p1 = Cartesian3_default.fromArray(positions, i1 * 3, p1Scratch); const p2 = Cartesian3_default.fromArray(positions, i2 * 3, p2Scratch); const coords = barycentricCoordinates_default(point4, p0, p1, p2, barycentricScratch); if (!defined_default(coords)) { return; } if (defined_default(normals)) { interpolateAndPackCartesian3( i0, i1, i2, coords, normals, currentAttributes.normal.values, insertedIndex, true ); } if (defined_default(extrudeDirections)) { const d0 = Cartesian3_default.fromArray(extrudeDirections, i0 * 3, p0Scratch); const d1 = Cartesian3_default.fromArray(extrudeDirections, i1 * 3, p1Scratch); const d2 = Cartesian3_default.fromArray(extrudeDirections, i2 * 3, p2Scratch); Cartesian3_default.multiplyByScalar(d0, coords.x, d0); Cartesian3_default.multiplyByScalar(d1, coords.y, d1); Cartesian3_default.multiplyByScalar(d2, coords.z, d2); let direction2; if (!Cartesian3_default.equals(d0, Cartesian3_default.ZERO) || !Cartesian3_default.equals(d1, Cartesian3_default.ZERO) || !Cartesian3_default.equals(d2, Cartesian3_default.ZERO)) { direction2 = Cartesian3_default.add(d0, d1, d0); Cartesian3_default.add(direction2, d2, direction2); Cartesian3_default.normalize(direction2, direction2); } else { direction2 = p0Scratch; direction2.x = 0; direction2.y = 0; direction2.z = 0; } Cartesian3_default.pack( direction2, currentAttributes.extrudeDirection.values, insertedIndex * 3 ); } if (defined_default(applyOffset)) { interpolateAndPackBoolean( i0, i1, i2, coords, applyOffset, currentAttributes.applyOffset.values, insertedIndex ); } if (defined_default(tangents)) { interpolateAndPackCartesian3( i0, i1, i2, coords, tangents, currentAttributes.tangent.values, insertedIndex, true ); } if (defined_default(bitangents)) { interpolateAndPackCartesian3( i0, i1, i2, coords, bitangents, currentAttributes.bitangent.values, insertedIndex, true ); } if (defined_default(texCoords)) { interpolateAndPackCartesian2( i0, i1, i2, coords, texCoords, currentAttributes.st.values, insertedIndex ); } if (customAttributesLength > 0) { for (let i = 0; i < customAttributesLength; i++) { const attributeName = customAttributeNames[i]; genericInterpolate( i0, i1, i2, coords, insertedIndex, allAttributes[attributeName], currentAttributes[attributeName] ); } } } function genericInterpolate(i0, i1, i2, coords, insertedIndex, sourceAttribute, currentAttribute) { const componentsPerAttribute = sourceAttribute.componentsPerAttribute; const sourceValues = sourceAttribute.values; const currentValues = currentAttribute.values; switch (componentsPerAttribute) { case 4: interpolateAndPackCartesian4( i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false ); break; case 3: interpolateAndPackCartesian3( i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false ); break; case 2: interpolateAndPackCartesian2( i0, i1, i2, coords, sourceValues, currentValues, insertedIndex, false ); break; default: currentValues[insertedIndex] = sourceValues[i0] * coords.x + sourceValues[i1] * coords.y + sourceValues[i2] * coords.z; } } function insertSplitPoint(currentAttributes, currentIndices, currentIndexMap, indices, currentIndex, point4) { const insertIndex = currentAttributes.position.values.length / 3; if (currentIndex !== -1) { const prevIndex = indices[currentIndex]; const newIndex = currentIndexMap[prevIndex]; if (newIndex === -1) { currentIndexMap[prevIndex] = insertIndex; currentAttributes.position.values.push(point4.x, point4.y, point4.z); currentIndices.push(insertIndex); return insertIndex; } currentIndices.push(newIndex); return newIndex; } currentAttributes.position.values.push(point4.x, point4.y, point4.z); currentIndices.push(insertIndex); return insertIndex; } var NAMED_ATTRIBUTES = { position: true, normal: true, bitangent: true, tangent: true, st: true, extrudeDirection: true, applyOffset: true }; function splitLongitudeTriangles(instance) { const geometry = instance.geometry; const attributes = geometry.attributes; const positions = attributes.position.values; const normals = defined_default(attributes.normal) ? attributes.normal.values : void 0; const bitangents = defined_default(attributes.bitangent) ? attributes.bitangent.values : void 0; const tangents = defined_default(attributes.tangent) ? attributes.tangent.values : void 0; const texCoords = defined_default(attributes.st) ? attributes.st.values : void 0; const extrudeDirections = defined_default(attributes.extrudeDirection) ? attributes.extrudeDirection.values : void 0; const applyOffset = defined_default(attributes.applyOffset) ? attributes.applyOffset.values : void 0; const indices = geometry.indices; const customAttributeNames = []; for (const attributeName in attributes) { if (attributes.hasOwnProperty(attributeName) && !NAMED_ATTRIBUTES[attributeName] && defined_default(attributes[attributeName])) { customAttributeNames.push(attributeName); } } const customAttributesLength = customAttributeNames.length; const eastGeometry = copyGeometryForSplit(geometry); const westGeometry = copyGeometryForSplit(geometry); let currentAttributes; let currentIndices; let currentIndexMap; let insertedIndex; let i; const westGeometryIndexMap = []; westGeometryIndexMap.length = positions.length / 3; const eastGeometryIndexMap = []; eastGeometryIndexMap.length = positions.length / 3; for (i = 0; i < westGeometryIndexMap.length; ++i) { westGeometryIndexMap[i] = -1; eastGeometryIndexMap[i] = -1; } const len = indices.length; for (i = 0; i < len; i += 3) { const i0 = indices[i]; const i1 = indices[i + 1]; const i2 = indices[i + 2]; let p0 = Cartesian3_default.fromArray(positions, i0 * 3); let p1 = Cartesian3_default.fromArray(positions, i1 * 3); let p2 = Cartesian3_default.fromArray(positions, i2 * 3); const result = splitTriangle(p0, p1, p2); if (defined_default(result) && result.positions.length > 3) { const resultPositions = result.positions; const resultIndices = result.indices; const resultLength = resultIndices.length; for (let j = 0; j < resultLength; ++j) { const resultIndex = resultIndices[j]; const point4 = resultPositions[resultIndex]; if (point4.y < 0) { currentAttributes = westGeometry.attributes; currentIndices = westGeometry.indices; currentIndexMap = westGeometryIndexMap; } else { currentAttributes = eastGeometry.attributes; currentIndices = eastGeometry.indices; currentIndexMap = eastGeometryIndexMap; } insertedIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, resultIndex < 3 ? i + resultIndex : -1, point4 ); computeTriangleAttributes( i0, i1, i2, point4, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex ); } } else { if (defined_default(result)) { p0 = result.positions[0]; p1 = result.positions[1]; p2 = result.positions[2]; } if (p0.y < 0) { currentAttributes = westGeometry.attributes; currentIndices = westGeometry.indices; currentIndexMap = westGeometryIndexMap; } else { currentAttributes = eastGeometry.attributes; currentIndices = eastGeometry.indices; currentIndexMap = eastGeometryIndexMap; } insertedIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, i, p0 ); computeTriangleAttributes( i0, i1, i2, p0, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex ); insertedIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1 ); computeTriangleAttributes( i0, i1, i2, p1, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex ); insertedIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, i + 2, p2 ); computeTriangleAttributes( i0, i1, i2, p2, positions, normals, tangents, bitangents, texCoords, extrudeDirections, applyOffset, currentAttributes, customAttributeNames, customAttributesLength, attributes, insertedIndex ); } } updateInstanceAfterSplit(instance, westGeometry, eastGeometry); } var xzPlane = Plane_default.fromPointNormal(Cartesian3_default.ZERO, Cartesian3_default.UNIT_Y); var offsetScratch = new Cartesian3_default(); var offsetPointScratch = new Cartesian3_default(); function computeLineAttributes(i0, i1, point4, positions, insertIndex, currentAttributes, applyOffset) { if (!defined_default(applyOffset)) { return; } const p0 = Cartesian3_default.fromArray(positions, i0 * 3, p0Scratch); if (Cartesian3_default.equalsEpsilon(p0, point4, Math_default.EPSILON10)) { currentAttributes.applyOffset.values[insertIndex] = applyOffset[i0]; } else { currentAttributes.applyOffset.values[insertIndex] = applyOffset[i1]; } } function splitLongitudeLines(instance) { const geometry = instance.geometry; const attributes = geometry.attributes; const positions = attributes.position.values; const applyOffset = defined_default(attributes.applyOffset) ? attributes.applyOffset.values : void 0; const indices = geometry.indices; const eastGeometry = copyGeometryForSplit(geometry); const westGeometry = copyGeometryForSplit(geometry); let i; const length2 = indices.length; const westGeometryIndexMap = []; westGeometryIndexMap.length = positions.length / 3; const eastGeometryIndexMap = []; eastGeometryIndexMap.length = positions.length / 3; for (i = 0; i < westGeometryIndexMap.length; ++i) { westGeometryIndexMap[i] = -1; eastGeometryIndexMap[i] = -1; } for (i = 0; i < length2; i += 2) { const i0 = indices[i]; const i1 = indices[i + 1]; const p0 = Cartesian3_default.fromArray(positions, i0 * 3, p0Scratch); const p1 = Cartesian3_default.fromArray(positions, i1 * 3, p1Scratch); let insertIndex; if (Math.abs(p0.y) < Math_default.EPSILON6) { if (p0.y < 0) { p0.y = -Math_default.EPSILON6; } else { p0.y = Math_default.EPSILON6; } } if (Math.abs(p1.y) < Math_default.EPSILON6) { if (p1.y < 0) { p1.y = -Math_default.EPSILON6; } else { p1.y = Math_default.EPSILON6; } } let p0Attributes = eastGeometry.attributes; let p0Indices = eastGeometry.indices; let p0IndexMap = eastGeometryIndexMap; let p1Attributes = westGeometry.attributes; let p1Indices = westGeometry.indices; let p1IndexMap = westGeometryIndexMap; const intersection = IntersectionTests_default.lineSegmentPlane( p0, p1, xzPlane, p2Scratch ); if (defined_default(intersection)) { const offset = Cartesian3_default.multiplyByScalar( Cartesian3_default.UNIT_Y, 5 * Math_default.EPSILON9, offsetScratch ); if (p0.y < 0) { Cartesian3_default.negate(offset, offset); p0Attributes = westGeometry.attributes; p0Indices = westGeometry.indices; p0IndexMap = westGeometryIndexMap; p1Attributes = eastGeometry.attributes; p1Indices = eastGeometry.indices; p1IndexMap = eastGeometryIndexMap; } const offsetPoint = Cartesian3_default.add( intersection, offset, offsetPointScratch ); insertIndex = insertSplitPoint( p0Attributes, p0Indices, p0IndexMap, indices, i, p0 ); computeLineAttributes( i0, i1, p0, positions, insertIndex, p0Attributes, applyOffset ); insertIndex = insertSplitPoint( p0Attributes, p0Indices, p0IndexMap, indices, -1, offsetPoint ); computeLineAttributes( i0, i1, offsetPoint, positions, insertIndex, p0Attributes, applyOffset ); Cartesian3_default.negate(offset, offset); Cartesian3_default.add(intersection, offset, offsetPoint); insertIndex = insertSplitPoint( p1Attributes, p1Indices, p1IndexMap, indices, -1, offsetPoint ); computeLineAttributes( i0, i1, offsetPoint, positions, insertIndex, p1Attributes, applyOffset ); insertIndex = insertSplitPoint( p1Attributes, p1Indices, p1IndexMap, indices, i + 1, p1 ); computeLineAttributes( i0, i1, p1, positions, insertIndex, p1Attributes, applyOffset ); } else { let currentAttributes; let currentIndices; let currentIndexMap; if (p0.y < 0) { currentAttributes = westGeometry.attributes; currentIndices = westGeometry.indices; currentIndexMap = westGeometryIndexMap; } else { currentAttributes = eastGeometry.attributes; currentIndices = eastGeometry.indices; currentIndexMap = eastGeometryIndexMap; } insertIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, i, p0 ); computeLineAttributes( i0, i1, p0, positions, insertIndex, currentAttributes, applyOffset ); insertIndex = insertSplitPoint( currentAttributes, currentIndices, currentIndexMap, indices, i + 1, p1 ); computeLineAttributes( i0, i1, p1, positions, insertIndex, currentAttributes, applyOffset ); } } updateInstanceAfterSplit(instance, westGeometry, eastGeometry); } var cartesian2Scratch0 = new Cartesian2_default(); var cartesian2Scratch1 = new Cartesian2_default(); var cartesian3Scratch0 = new Cartesian3_default(); var cartesian3Scratch2 = new Cartesian3_default(); var cartesian3Scratch3 = new Cartesian3_default(); var cartesian3Scratch4 = new Cartesian3_default(); var cartesian3Scratch5 = new Cartesian3_default(); var cartesian3Scratch6 = new Cartesian3_default(); var cartesian4Scratch0 = new Cartesian4_default(); function updateAdjacencyAfterSplit(geometry) { const attributes = geometry.attributes; const positions = attributes.position.values; const prevPositions = attributes.prevPosition.values; const nextPositions = attributes.nextPosition.values; const length2 = positions.length; for (let j = 0; j < length2; j += 3) { const position = Cartesian3_default.unpack(positions, j, cartesian3Scratch0); if (position.x > 0) { continue; } const prevPosition = Cartesian3_default.unpack( prevPositions, j, cartesian3Scratch2 ); if (position.y < 0 && prevPosition.y > 0 || position.y > 0 && prevPosition.y < 0) { if (j - 3 > 0) { prevPositions[j] = positions[j - 3]; prevPositions[j + 1] = positions[j - 2]; prevPositions[j + 2] = positions[j - 1]; } else { Cartesian3_default.pack(position, prevPositions, j); } } const nextPosition = Cartesian3_default.unpack( nextPositions, j, cartesian3Scratch3 ); if (position.y < 0 && nextPosition.y > 0 || position.y > 0 && nextPosition.y < 0) { if (j + 3 < length2) { nextPositions[j] = positions[j + 3]; nextPositions[j + 1] = positions[j + 4]; nextPositions[j + 2] = positions[j + 5]; } else { Cartesian3_default.pack(position, nextPositions, j); } } } } var offsetScalar = 5 * Math_default.EPSILON9; var coplanarOffset = Math_default.EPSILON6; function splitLongitudePolyline(instance) { const geometry = instance.geometry; const attributes = geometry.attributes; const positions = attributes.position.values; const prevPositions = attributes.prevPosition.values; const nextPositions = attributes.nextPosition.values; const expandAndWidths = attributes.expandAndWidth.values; const texCoords = defined_default(attributes.st) ? attributes.st.values : void 0; const colors = defined_default(attributes.color) ? attributes.color.values : void 0; const eastGeometry = copyGeometryForSplit(geometry); const westGeometry = copyGeometryForSplit(geometry); let i; let j; let index; let intersectionFound = false; const length2 = positions.length / 3; for (i = 0; i < length2; i += 4) { const i0 = i; const i2 = i + 2; const p0 = Cartesian3_default.fromArray(positions, i0 * 3, cartesian3Scratch0); const p2 = Cartesian3_default.fromArray(positions, i2 * 3, cartesian3Scratch2); if (Math.abs(p0.y) < coplanarOffset) { p0.y = coplanarOffset * (p2.y < 0 ? -1 : 1); positions[i * 3 + 1] = p0.y; positions[(i + 1) * 3 + 1] = p0.y; for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) { prevPositions[j] = positions[i * 3]; prevPositions[j + 1] = positions[i * 3 + 1]; prevPositions[j + 2] = positions[i * 3 + 2]; } } if (Math.abs(p2.y) < coplanarOffset) { p2.y = coplanarOffset * (p0.y < 0 ? -1 : 1); positions[(i + 2) * 3 + 1] = p2.y; positions[(i + 3) * 3 + 1] = p2.y; for (j = i0 * 3; j < i0 * 3 + 4 * 3; j += 3) { nextPositions[j] = positions[(i + 2) * 3]; nextPositions[j + 1] = positions[(i + 2) * 3 + 1]; nextPositions[j + 2] = positions[(i + 2) * 3 + 2]; } } let p0Attributes = eastGeometry.attributes; let p0Indices = eastGeometry.indices; let p2Attributes = westGeometry.attributes; let p2Indices = westGeometry.indices; const intersection = IntersectionTests_default.lineSegmentPlane( p0, p2, xzPlane, cartesian3Scratch4 ); if (defined_default(intersection)) { intersectionFound = true; const offset = Cartesian3_default.multiplyByScalar( Cartesian3_default.UNIT_Y, offsetScalar, cartesian3Scratch5 ); if (p0.y < 0) { Cartesian3_default.negate(offset, offset); p0Attributes = westGeometry.attributes; p0Indices = westGeometry.indices; p2Attributes = eastGeometry.attributes; p2Indices = eastGeometry.indices; } const offsetPoint = Cartesian3_default.add( intersection, offset, cartesian3Scratch6 ); p0Attributes.position.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z); p0Attributes.position.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p0Attributes.position.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p0Attributes.prevPosition.values.push( prevPositions[i0 * 3], prevPositions[i0 * 3 + 1], prevPositions[i0 * 3 + 2] ); p0Attributes.prevPosition.values.push( prevPositions[i0 * 3 + 3], prevPositions[i0 * 3 + 4], prevPositions[i0 * 3 + 5] ); p0Attributes.prevPosition.values.push(p0.x, p0.y, p0.z, p0.x, p0.y, p0.z); p0Attributes.nextPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p0Attributes.nextPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p0Attributes.nextPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p0Attributes.nextPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); Cartesian3_default.negate(offset, offset); Cartesian3_default.add(intersection, offset, offsetPoint); p2Attributes.position.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.position.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.position.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z); p2Attributes.prevPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.prevPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.prevPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.prevPosition.values.push( offsetPoint.x, offsetPoint.y, offsetPoint.z ); p2Attributes.nextPosition.values.push(p2.x, p2.y, p2.z, p2.x, p2.y, p2.z); p2Attributes.nextPosition.values.push( nextPositions[i2 * 3], nextPositions[i2 * 3 + 1], nextPositions[i2 * 3 + 2] ); p2Attributes.nextPosition.values.push( nextPositions[i2 * 3 + 3], nextPositions[i2 * 3 + 4], nextPositions[i2 * 3 + 5] ); const ew0 = Cartesian2_default.fromArray( expandAndWidths, i0 * 2, cartesian2Scratch0 ); const width = Math.abs(ew0.y); p0Attributes.expandAndWidth.values.push(-1, width, 1, width); p0Attributes.expandAndWidth.values.push(-1, -width, 1, -width); p2Attributes.expandAndWidth.values.push(-1, width, 1, width); p2Attributes.expandAndWidth.values.push(-1, -width, 1, -width); let t2 = Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(intersection, p0, cartesian3Scratch3) ); t2 /= Cartesian3_default.magnitudeSquared( Cartesian3_default.subtract(p2, p0, cartesian3Scratch3) ); if (defined_default(colors)) { const c0 = Cartesian4_default.fromArray(colors, i0 * 4, cartesian4Scratch0); const c22 = Cartesian4_default.fromArray(colors, i2 * 4, cartesian4Scratch0); const r2 = Math_default.lerp(c0.x, c22.x, t2); const g = Math_default.lerp(c0.y, c22.y, t2); const b = Math_default.lerp(c0.z, c22.z, t2); const a3 = Math_default.lerp(c0.w, c22.w, t2); for (j = i0 * 4; j < i0 * 4 + 2 * 4; ++j) { p0Attributes.color.values.push(colors[j]); } p0Attributes.color.values.push(r2, g, b, a3); p0Attributes.color.values.push(r2, g, b, a3); p2Attributes.color.values.push(r2, g, b, a3); p2Attributes.color.values.push(r2, g, b, a3); for (j = i2 * 4; j < i2 * 4 + 2 * 4; ++j) { p2Attributes.color.values.push(colors[j]); } } if (defined_default(texCoords)) { const s0 = Cartesian2_default.fromArray(texCoords, i0 * 2, cartesian2Scratch0); const s3 = Cartesian2_default.fromArray( texCoords, (i + 3) * 2, cartesian2Scratch1 ); const sx = Math_default.lerp(s0.x, s3.x, t2); for (j = i0 * 2; j < i0 * 2 + 2 * 2; ++j) { p0Attributes.st.values.push(texCoords[j]); } p0Attributes.st.values.push(sx, s0.y); p0Attributes.st.values.push(sx, s3.y); p2Attributes.st.values.push(sx, s0.y); p2Attributes.st.values.push(sx, s3.y); for (j = i2 * 2; j < i2 * 2 + 2 * 2; ++j) { p2Attributes.st.values.push(texCoords[j]); } } index = p0Attributes.position.values.length / 3 - 4; p0Indices.push(index, index + 2, index + 1); p0Indices.push(index + 1, index + 2, index + 3); index = p2Attributes.position.values.length / 3 - 4; p2Indices.push(index, index + 2, index + 1); p2Indices.push(index + 1, index + 2, index + 3); } else { let currentAttributes; let currentIndices; if (p0.y < 0) { currentAttributes = westGeometry.attributes; currentIndices = westGeometry.indices; } else { currentAttributes = eastGeometry.attributes; currentIndices = eastGeometry.indices; } currentAttributes.position.values.push(p0.x, p0.y, p0.z); currentAttributes.position.values.push(p0.x, p0.y, p0.z); currentAttributes.position.values.push(p2.x, p2.y, p2.z); currentAttributes.position.values.push(p2.x, p2.y, p2.z); for (j = i * 3; j < i * 3 + 4 * 3; ++j) { currentAttributes.prevPosition.values.push(prevPositions[j]); currentAttributes.nextPosition.values.push(nextPositions[j]); } for (j = i * 2; j < i * 2 + 4 * 2; ++j) { currentAttributes.expandAndWidth.values.push(expandAndWidths[j]); if (defined_default(texCoords)) { currentAttributes.st.values.push(texCoords[j]); } } if (defined_default(colors)) { for (j = i * 4; j < i * 4 + 4 * 4; ++j) { currentAttributes.color.values.push(colors[j]); } } index = currentAttributes.position.values.length / 3 - 4; currentIndices.push(index, index + 2, index + 1); currentIndices.push(index + 1, index + 2, index + 3); } } if (intersectionFound) { updateAdjacencyAfterSplit(westGeometry); updateAdjacencyAfterSplit(eastGeometry); } updateInstanceAfterSplit(instance, westGeometry, eastGeometry); } GeometryPipeline.splitLongitude = function(instance) { if (!defined_default(instance)) { throw new DeveloperError_default("instance is required."); } const geometry = instance.geometry; const boundingSphere = geometry.boundingSphere; if (defined_default(boundingSphere)) { const minX = boundingSphere.center.x - boundingSphere.radius; if (minX > 0 || BoundingSphere_default.intersectPlane(boundingSphere, Plane_default.ORIGIN_ZX_PLANE) !== Intersect_default.INTERSECTING) { return instance; } } if (geometry.geometryType !== GeometryType_default.NONE) { switch (geometry.geometryType) { case GeometryType_default.POLYLINES: splitLongitudePolyline(instance); break; case GeometryType_default.TRIANGLES: splitLongitudeTriangles(instance); break; case GeometryType_default.LINES: splitLongitudeLines(instance); break; } } else { indexPrimitive(geometry); if (geometry.primitiveType === PrimitiveType_default.TRIANGLES) { splitLongitudeTriangles(instance); } else if (geometry.primitiveType === PrimitiveType_default.LINES) { splitLongitudeLines(instance); } } return instance; }; var GeometryPipeline_default = GeometryPipeline; // packages/engine/Source/Renderer/CubeMapFace.js var import_InlineWorkers112 = __toESM(require_InlineWorkers(), 1); function CubeMapFace(context, texture, textureTarget, targetFace, internalFormat, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY, initialized) { this._context = context; this._texture = texture; this._textureTarget = textureTarget; this._targetFace = targetFace; this._pixelDatatype = pixelDatatype; this._internalFormat = internalFormat; this._pixelFormat = pixelFormat; this._size = size; this._preMultiplyAlpha = preMultiplyAlpha; this._flipY = flipY; this._initialized = initialized; } Object.defineProperties(CubeMapFace.prototype, { pixelFormat: { get: function() { return this._pixelFormat; } }, pixelDatatype: { get: function() { return this._pixelDatatype; } }, _target: { get: function() { return this._targetFace; } } }); CubeMapFace.prototype.copyFrom = function(options) { Check_default.defined("options", options); const { xOffset = 0, yOffset = 0, source, skipColorSpaceConversion = false } = options; Check_default.defined("options.source", source); Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); if (xOffset + source.width > this._size) { throw new DeveloperError_default( "xOffset + options.source.width must be less than or equal to width." ); } if (yOffset + source.height > this._size) { throw new DeveloperError_default( "yOffset + options.source.height must be less than or equal to height." ); } const { width, height } = source; const gl = this._context._gl; const target = this._textureTarget; const targetFace = this._targetFace; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); let arrayBufferView = source.arrayBufferView; const size = this._size; const pixelFormat = this._pixelFormat; const internalFormat = this._internalFormat; const pixelDatatype = this._pixelDatatype; const preMultiplyAlpha = this._preMultiplyAlpha; const flipY = this._flipY; let unpackAlignment = 4; if (defined_default(arrayBufferView)) { unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, width ); } gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } let uploaded = false; if (!this._initialized) { let pixels; if (xOffset === 0 && yOffset === 0 && width === size && height === size) { if (defined_default(arrayBufferView)) { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); if (flipY) { arrayBufferView = PixelFormat_default.flipY( arrayBufferView, pixelFormat, pixelDatatype, size, size ); } pixels = arrayBufferView; } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); pixels = source; } uploaded = true; } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); pixels = PixelFormat_default.createTypedArray( pixelFormat, pixelDatatype, size, size ); } gl.texImage2D( targetFace, 0, internalFormat, size, size, 0, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, this._context), pixels ); this._initialized = true; } if (!uploaded) { if (defined_default(arrayBufferView)) { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); if (flipY) { arrayBufferView = PixelFormat_default.flipY( arrayBufferView, pixelFormat, pixelDatatype, width, height ); } gl.texSubImage2D( targetFace, 0, xOffset, yOffset, width, height, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, this._context), arrayBufferView ); } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); gl.texSubImage2D( targetFace, 0, xOffset, yOffset, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, this._context), source ); } } gl.bindTexture(target, null); }; CubeMapFace.prototype.copyFromFramebuffer = function(xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height) { xOffset = xOffset ?? 0; yOffset = yOffset ?? 0; framebufferXOffset = framebufferXOffset ?? 0; framebufferYOffset = framebufferYOffset ?? 0; width = width ?? this._size; height = height ?? this._size; Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); Check_default.typeOf.number.greaterThanOrEquals( "framebufferXOffset", framebufferXOffset, 0 ); Check_default.typeOf.number.greaterThanOrEquals( "framebufferYOffset", framebufferYOffset, 0 ); if (xOffset + width > this._size) { throw new DeveloperError_default( "xOffset + source.width must be less than or equal to width." ); } if (yOffset + height > this._size) { throw new DeveloperError_default( "yOffset + source.height must be less than or equal to height." ); } if (this._pixelDatatype === PixelDatatype_default.FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT." ); } if (this._pixelDatatype === PixelDatatype_default.HALF_FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is HALF_FLOAT." ); } const gl = this._context._gl; const target = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.copyTexSubImage2D( this._targetFace, 0, xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height ); gl.bindTexture(target, null); this._initialized = true; }; CubeMapFace.prototype.copyMipmapFromFramebuffer = function(xOffset, yOffset, width, height, level) { xOffset = xOffset ?? 0; yOffset = yOffset ?? 0; width = width ?? this._size; height = height ?? this._size; level = level ?? 0; Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); if (xOffset + width > this._size) { throw new DeveloperError_default( "xOffset + source.width must be less than or equal to width." ); } if (yOffset + height > this._size) { throw new DeveloperError_default( "yOffset + source.height must be less than or equal to height." ); } if (this._pixelDatatype === PixelDatatype_default.FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT." ); } if (this._pixelDatatype === PixelDatatype_default.HALF_FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is HALF_FLOAT." ); } const gl = this._context._gl; const target = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.copyTexImage2D( this._targetFace, level, this._internalFormat, xOffset, yOffset, width, height, 0 ); gl.bindTexture(target, null); this._initialized = true; }; var CubeMapFace_default = CubeMapFace; // packages/engine/Source/Renderer/MipmapHint.js var import_InlineWorkers113 = __toESM(require_InlineWorkers(), 1); var MipmapHint = { DONT_CARE: WebGLConstants_default.DONT_CARE, FASTEST: WebGLConstants_default.FASTEST, NICEST: WebGLConstants_default.NICEST, validate: function(mipmapHint) { return mipmapHint === MipmapHint.DONT_CARE || mipmapHint === MipmapHint.FASTEST || mipmapHint === MipmapHint.NICEST; } }; Object.freeze(MipmapHint); var MipmapHint_default = MipmapHint; // packages/engine/Source/Renderer/Sampler.js var import_InlineWorkers117 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/TextureMagnificationFilter.js var import_InlineWorkers114 = __toESM(require_InlineWorkers(), 1); var TextureMagnificationFilter = { /** * Samples the texture by returning the closest pixel. * * @type {number} * @constant */ NEAREST: WebGLConstants_default.NEAREST, /** * Samples the texture through bi-linear interpolation of the four nearest pixels. This produces smoother results than NEAREST filtering. * * @type {number} * @constant */ LINEAR: WebGLConstants_default.LINEAR }; TextureMagnificationFilter.validate = function(textureMagnificationFilter) { return textureMagnificationFilter === TextureMagnificationFilter.NEAREST || textureMagnificationFilter === TextureMagnificationFilter.LINEAR; }; Object.freeze(TextureMagnificationFilter); var TextureMagnificationFilter_default = TextureMagnificationFilter; // packages/engine/Source/Renderer/TextureMinificationFilter.js var import_InlineWorkers115 = __toESM(require_InlineWorkers(), 1); var TextureMinificationFilter = { /** * Samples the texture by returning the closest pixel. * * @type {number} * @constant */ NEAREST: WebGLConstants_default.NEAREST, /** * Samples the texture through bi-linear interpolation of the four nearest pixels. This produces smoother results than NEAREST filtering. * * @type {number} * @constant */ LINEAR: WebGLConstants_default.LINEAR, /** * Selects the nearest mip level and applies nearest sampling within that level. *

* Requires that the texture has a mipmap. The mip level is chosen by the view angle and screen-space size of the texture. *

* * @type {number} * @constant */ NEAREST_MIPMAP_NEAREST: WebGLConstants_default.NEAREST_MIPMAP_NEAREST, /** * Selects the nearest mip level and applies linear sampling within that level. *

* Requires that the texture has a mipmap. The mip level is chosen by the view angle and screen-space size of the texture. *

* * @type {number} * @constant */ LINEAR_MIPMAP_NEAREST: WebGLConstants_default.LINEAR_MIPMAP_NEAREST, /** * Read texture values with nearest sampling from two adjacent mip levels and linearly interpolate the results. *

* This option provides a good balance of visual quality and speed when sampling from a mipmapped texture. *

*

* Requires that the texture has a mipmap. The mip level is chosen by the view angle and screen-space size of the texture. *

* * @type {number} * @constant */ NEAREST_MIPMAP_LINEAR: WebGLConstants_default.NEAREST_MIPMAP_LINEAR, /** * Read texture values with linear sampling from two adjacent mip levels and linearly interpolate the results. *

* This option provides a good balance of visual quality and speed when sampling from a mipmapped texture. *

*

* Requires that the texture has a mipmap. The mip level is chosen by the view angle and screen-space size of the texture. *

* @type {number} * @constant */ LINEAR_MIPMAP_LINEAR: WebGLConstants_default.LINEAR_MIPMAP_LINEAR }; TextureMinificationFilter.validate = function(textureMinificationFilter) { return textureMinificationFilter === TextureMinificationFilter.NEAREST || textureMinificationFilter === TextureMinificationFilter.LINEAR || textureMinificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST || textureMinificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST || textureMinificationFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR || textureMinificationFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR; }; Object.freeze(TextureMinificationFilter); var TextureMinificationFilter_default = TextureMinificationFilter; // packages/engine/Source/Renderer/TextureWrap.js var import_InlineWorkers116 = __toESM(require_InlineWorkers(), 1); var TextureWrap = { CLAMP_TO_EDGE: WebGLConstants_default.CLAMP_TO_EDGE, REPEAT: WebGLConstants_default.REPEAT, MIRRORED_REPEAT: WebGLConstants_default.MIRRORED_REPEAT, validate: function(textureWrap) { return textureWrap === TextureWrap.CLAMP_TO_EDGE || textureWrap === TextureWrap.REPEAT || textureWrap === TextureWrap.MIRRORED_REPEAT; } }; Object.freeze(TextureWrap); var TextureWrap_default = TextureWrap; // packages/engine/Source/Renderer/Sampler.js function Sampler(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const { wrapR = TextureWrap_default.CLAMP_TO_EDGE, wrapS = TextureWrap_default.CLAMP_TO_EDGE, wrapT = TextureWrap_default.CLAMP_TO_EDGE, minificationFilter = TextureMinificationFilter_default.LINEAR, magnificationFilter = TextureMagnificationFilter_default.LINEAR, maximumAnisotropy = 1 } = options; if (!TextureWrap_default.validate(wrapR)) { throw new DeveloperError_default("Invalid sampler.wrapR."); } if (!TextureWrap_default.validate(wrapS)) { throw new DeveloperError_default("Invalid sampler.wrapS."); } if (!TextureWrap_default.validate(wrapT)) { throw new DeveloperError_default("Invalid sampler.wrapT."); } if (!TextureMinificationFilter_default.validate(minificationFilter)) { throw new DeveloperError_default("Invalid sampler.minificationFilter."); } if (!TextureMagnificationFilter_default.validate(magnificationFilter)) { throw new DeveloperError_default("Invalid sampler.magnificationFilter."); } Check_default.typeOf.number.greaterThanOrEquals( "maximumAnisotropy", maximumAnisotropy, 1 ); this._wrapR = wrapR; this._wrapS = wrapS; this._wrapT = wrapT; this._minificationFilter = minificationFilter; this._magnificationFilter = magnificationFilter; this._maximumAnisotropy = maximumAnisotropy; } Object.defineProperties(Sampler.prototype, { wrapR: { get: function() { return this._wrapR; } }, wrapS: { get: function() { return this._wrapS; } }, wrapT: { get: function() { return this._wrapT; } }, minificationFilter: { get: function() { return this._minificationFilter; } }, magnificationFilter: { get: function() { return this._magnificationFilter; } }, maximumAnisotropy: { get: function() { return this._maximumAnisotropy; } } }); Sampler.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left._wrapR === right._wrapR && left._wrapS === right._wrapS && left._wrapT === right._wrapT && left._minificationFilter === right._minificationFilter && left._magnificationFilter === right._magnificationFilter && left._maximumAnisotropy === right._maximumAnisotropy; }; Sampler.NEAREST = Object.freeze( new Sampler({ wrapR: TextureWrap_default.CLAMP_TO_EDGE, wrapS: TextureWrap_default.CLAMP_TO_EDGE, wrapT: TextureWrap_default.CLAMP_TO_EDGE, minificationFilter: TextureMinificationFilter_default.NEAREST, magnificationFilter: TextureMagnificationFilter_default.NEAREST }) ); var Sampler_default = Sampler; // packages/engine/Source/Renderer/VertexArray.js var import_InlineWorkers119 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/assert.js var import_InlineWorkers118 = __toESM(require_InlineWorkers(), 1); function assert(condition, msg) { if (!condition) { throw new DeveloperError_default(msg); } } var assert_default = assert; // packages/engine/Source/Renderer/VertexArray.js function addAttribute(attributes, attribute, index, context) { const hasVertexBuffer = defined_default(attribute.vertexBuffer); const hasValue = defined_default(attribute.value); const componentsPerAttribute = attribute.value ? attribute.value.length : attribute.componentsPerAttribute; if (!hasVertexBuffer && !hasValue) { throw new DeveloperError_default("attribute must have a vertexBuffer or a value."); } if (hasVertexBuffer && hasValue) { throw new DeveloperError_default( "attribute cannot have both a vertexBuffer and a value. It must have either a vertexBuffer property defining per-vertex data or a value property defining data for all vertices." ); } if (componentsPerAttribute !== 1 && componentsPerAttribute !== 2 && componentsPerAttribute !== 3 && componentsPerAttribute !== 4) { if (hasValue) { throw new DeveloperError_default( "attribute.value.length must be in the range [1, 4]." ); } throw new DeveloperError_default( "attribute.componentsPerAttribute must be in the range [1, 4]." ); } if (defined_default(attribute.componentDatatype) && !ComponentDatatype_default.validate(attribute.componentDatatype)) { throw new DeveloperError_default( "attribute must have a valid componentDatatype or not specify it." ); } if (defined_default(attribute.strideInBytes) && attribute.strideInBytes > 255) { throw new DeveloperError_default( "attribute must have a strideInBytes less than or equal to 255 or not specify it." ); } if (defined_default(attribute.instanceDivisor) && attribute.instanceDivisor > 0 && !context.instancedArrays) { throw new DeveloperError_default("instanced arrays is not supported"); } if (defined_default(attribute.instanceDivisor) && attribute.instanceDivisor < 0) { throw new DeveloperError_default( "attribute must have an instanceDivisor greater than or equal to zero" ); } if (defined_default(attribute.instanceDivisor) && hasValue) { throw new DeveloperError_default( "attribute cannot have have an instanceDivisor if it is not backed by a buffer" ); } if (defined_default(attribute.instanceDivisor) && attribute.instanceDivisor > 0 && attribute.index === 0) { throw new DeveloperError_default( "attribute zero cannot have an instanceDivisor greater than 0" ); } const attr = { index: attribute.index ?? index, enabled: attribute.enabled ?? true, vertexBuffer: attribute.vertexBuffer, value: hasValue ? attribute.value.slice(0) : void 0, componentsPerAttribute, componentDatatype: attribute.componentDatatype ?? ComponentDatatype_default.FLOAT, normalize: attribute.normalize ?? false, offsetInBytes: attribute.offsetInBytes ?? 0, strideInBytes: attribute.strideInBytes ?? 0, instanceDivisor: attribute.instanceDivisor ?? 0 }; if (hasVertexBuffer) { attr.vertexAttrib = function(gl) { const index2 = this.index; gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer._getBuffer()); gl.vertexAttribPointer( index2, this.componentsPerAttribute, this.componentDatatype, this.normalize, this.strideInBytes, this.offsetInBytes ); gl.enableVertexAttribArray(index2); if (this.instanceDivisor > 0) { context.glVertexAttribDivisor(index2, this.instanceDivisor); context._vertexAttribDivisors[index2] = this.instanceDivisor; context._previousDrawInstanced = true; } }; attr.disableVertexAttribArray = function(gl) { gl.disableVertexAttribArray(this.index); if (this.instanceDivisor > 0) { context.glVertexAttribDivisor(index, 0); } }; } else { switch (attr.componentsPerAttribute) { case 1: attr.vertexAttrib = function(gl) { gl.vertexAttrib1fv(this.index, this.value); }; break; case 2: attr.vertexAttrib = function(gl) { gl.vertexAttrib2fv(this.index, this.value); }; break; case 3: attr.vertexAttrib = function(gl) { gl.vertexAttrib3fv(this.index, this.value); }; break; case 4: attr.vertexAttrib = function(gl) { gl.vertexAttrib4fv(this.index, this.value); }; break; } attr.disableVertexAttribArray = function(gl) { }; } attributes.push(attr); } function bind(gl, attributes, indexBuffer) { for (let i = 0; i < attributes.length; ++i) { const attribute = attributes[i]; if (attribute.enabled) { attribute.vertexAttrib(gl); } } if (defined_default(indexBuffer)) { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer._getBuffer()); } } function VertexArray(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); Check_default.defined("options.attributes", options.attributes); const context = options.context; const gl = context._gl; const attributes = options.attributes; const indexBuffer = options.indexBuffer; let i; const vaAttributes = []; let numberOfVertices = 1; let hasInstancedAttributes = false; let hasConstantAttributes = false; let length2 = attributes.length; for (i = 0; i < length2; ++i) { addAttribute(vaAttributes, attributes[i], i, context); } length2 = vaAttributes.length; for (i = 0; i < length2; ++i) { const attribute = vaAttributes[i]; if (defined_default(attribute.vertexBuffer) && attribute.instanceDivisor === 0) { const bytes = attribute.strideInBytes || attribute.componentsPerAttribute * ComponentDatatype_default.getSizeInBytes(attribute.componentDatatype); numberOfVertices = attribute.vertexBuffer.sizeInBytes / bytes; break; } } for (i = 0; i < length2; ++i) { if (vaAttributes[i].instanceDivisor > 0) { hasInstancedAttributes = true; } if (defined_default(vaAttributes[i].value)) { hasConstantAttributes = true; } } const uniqueIndices = {}; for (i = 0; i < length2; ++i) { const index = vaAttributes[i].index; if (uniqueIndices[index]) { throw new DeveloperError_default( `Index ${index} is used by more than one attribute.` ); } uniqueIndices[index] = true; } let vao; if (context.vertexArrayObject) { vao = context.glCreateVertexArray(); context.glBindVertexArray(vao); bind(gl, vaAttributes, indexBuffer); context.glBindVertexArray(null); } this._numberOfVertices = numberOfVertices; this._hasInstancedAttributes = hasInstancedAttributes; this._hasConstantAttributes = hasConstantAttributes; this._context = context; this._gl = gl; this._vao = vao; this._attributes = vaAttributes; this._indexBuffer = indexBuffer; } function computeNumberOfVertices(attribute) { return attribute.values.length / attribute.componentsPerAttribute; } function computeAttributeSizeInBytes(attribute) { return ComponentDatatype_default.getSizeInBytes(attribute.componentDatatype) * attribute.componentsPerAttribute; } function interleaveAttributes(attributes) { let j; let name; let attribute; const names = []; for (name in attributes) { if (attributes.hasOwnProperty(name) && defined_default(attributes[name]) && defined_default(attributes[name].values)) { names.push(name); if (attributes[name].componentDatatype === ComponentDatatype_default.DOUBLE) { attributes[name].componentDatatype = ComponentDatatype_default.FLOAT; attributes[name].values = ComponentDatatype_default.createTypedArray( ComponentDatatype_default.FLOAT, attributes[name].values ); } } } let numberOfVertices; const namesLength = names.length; if (namesLength > 0) { numberOfVertices = computeNumberOfVertices(attributes[names[0]]); for (j = 1; j < namesLength; ++j) { const currentNumberOfVertices = computeNumberOfVertices( attributes[names[j]] ); if (currentNumberOfVertices !== numberOfVertices) { throw new RuntimeError_default( `${"Each attribute list must have the same number of vertices. Attribute "}${names[j]} has a different number of vertices (${currentNumberOfVertices.toString()}) than attribute ${names[0]} (${numberOfVertices.toString()}).` ); } } } names.sort(function(left, right) { return ComponentDatatype_default.getSizeInBytes(attributes[right].componentDatatype) - ComponentDatatype_default.getSizeInBytes(attributes[left].componentDatatype); }); let vertexSizeInBytes = 0; const offsetsInBytes = {}; for (j = 0; j < namesLength; ++j) { name = names[j]; attribute = attributes[name]; offsetsInBytes[name] = vertexSizeInBytes; vertexSizeInBytes += computeAttributeSizeInBytes(attribute); } if (vertexSizeInBytes > 0) { const maxComponentSizeInBytes = ComponentDatatype_default.getSizeInBytes( attributes[names[0]].componentDatatype ); const remainder = vertexSizeInBytes % maxComponentSizeInBytes; if (remainder !== 0) { vertexSizeInBytes += maxComponentSizeInBytes - remainder; } const vertexBufferSizeInBytes = numberOfVertices * vertexSizeInBytes; const buffer2 = new ArrayBuffer(vertexBufferSizeInBytes); const views = {}; for (j = 0; j < namesLength; ++j) { name = names[j]; const sizeInBytes = ComponentDatatype_default.getSizeInBytes( attributes[name].componentDatatype ); views[name] = { pointer: ComponentDatatype_default.createTypedArray( attributes[name].componentDatatype, buffer2 ), index: offsetsInBytes[name] / sizeInBytes, // Offset in ComponentType strideInComponentType: vertexSizeInBytes / sizeInBytes }; } for (j = 0; j < numberOfVertices; ++j) { for (let n2 = 0; n2 < namesLength; ++n2) { name = names[n2]; attribute = attributes[name]; const values = attribute.values; const view = views[name]; const pointer = view.pointer; const numberOfComponents = attribute.componentsPerAttribute; for (let k = 0; k < numberOfComponents; ++k) { pointer[view.index + k] = values[j * numberOfComponents + k]; } view.index += view.strideInComponentType; } } return { buffer: buffer2, offsetsInBytes, vertexSizeInBytes }; } return void 0; } VertexArray.fromGeometry = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const context = options.context; const geometry = options.geometry ?? Frozen_default.EMPTY_OBJECT; const bufferUsage = options.bufferUsage ?? BufferUsage_default.DYNAMIC_DRAW; const attributeLocations8 = options.attributeLocations ?? Frozen_default.EMPTY_OBJECT; const interleave = options.interleave ?? false; const createdVAAttributes = options.vertexArrayAttributes; let name; let attribute; let vertexBuffer; const vaAttributes = defined_default(createdVAAttributes) ? createdVAAttributes : []; const attributes = geometry.attributes; if (interleave) { const interleavedAttributes = interleaveAttributes(attributes); if (defined_default(interleavedAttributes)) { vertexBuffer = Buffer_default.createVertexBuffer({ context, typedArray: interleavedAttributes.buffer, usage: bufferUsage }); const offsetsInBytes = interleavedAttributes.offsetsInBytes; const strideInBytes = interleavedAttributes.vertexSizeInBytes; for (name in attributes) { if (attributes.hasOwnProperty(name) && defined_default(attributes[name])) { attribute = attributes[name]; if (defined_default(attribute.values)) { vaAttributes.push({ index: attributeLocations8[name], vertexBuffer, componentDatatype: attribute.componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize, offsetInBytes: offsetsInBytes[name], strideInBytes }); } else { vaAttributes.push({ index: attributeLocations8[name], value: attribute.value, componentDatatype: attribute.componentDatatype, normalize: attribute.normalize }); } } } } } else { for (name in attributes) { if (attributes.hasOwnProperty(name) && defined_default(attributes[name])) { attribute = attributes[name]; let componentDatatype = attribute.componentDatatype; if (componentDatatype === ComponentDatatype_default.DOUBLE) { componentDatatype = ComponentDatatype_default.FLOAT; } let attrProps = {}; if (defined_default(attribute.values)) { vertexBuffer = Buffer_default.createVertexBuffer({ context, typedArray: ComponentDatatype_default.createTypedArray( componentDatatype, attribute.values ), usage: bufferUsage }); attrProps = { index: attributeLocations8[name], vertexBuffer, value: attribute.value, componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize }; } if (defined_default(attribute.typedArray)) { vertexBuffer = Buffer_default.createVertexBuffer({ context, typedArray: attribute.typedArray, usage: bufferUsage }); attrProps = { index: attributeLocations8[name], vertexBuffer, value: void 0, componentDatatype, componentsPerAttribute: AttributeType_default.getNumberOfComponents( attribute.type ), normalize: attribute.normalized, instanceDivisor: attribute.instanceDivisor }; } vaAttributes.push(attrProps); } } } let indexBuffer; const indices = geometry.indices; if (defined_default(indices)) { if (Geometry_default.computeNumberOfVertices(geometry) >= Math_default.SIXTY_FOUR_KILOBYTES && context.elementIndexUint) { indexBuffer = Buffer_default.createIndexBuffer({ context, typedArray: new Uint32Array(indices), usage: bufferUsage, indexDatatype: IndexDatatype_default.UNSIGNED_INT }); } else { indexBuffer = Buffer_default.createIndexBuffer({ context, typedArray: new Uint16Array(indices), usage: bufferUsage, indexDatatype: IndexDatatype_default.UNSIGNED_SHORT }); } } return new VertexArray({ context, attributes: vaAttributes, indexBuffer }); }; Object.defineProperties(VertexArray.prototype, { numberOfAttributes: { get: function() { return this._attributes.length; } }, numberOfVertices: { get: function() { return this._numberOfVertices; } }, indexBuffer: { get: function() { return this._indexBuffer; } } }); VertexArray.prototype.getAttribute = function(index) { Check_default.defined("index", index); return this._attributes[index]; }; function setVertexAttribDivisor(vertexArray) { const context = vertexArray._context; const hasInstancedAttributes = vertexArray._hasInstancedAttributes; if (!hasInstancedAttributes && !context._previousDrawInstanced) { return; } context._previousDrawInstanced = hasInstancedAttributes; const divisors = context._vertexAttribDivisors; const attributes = vertexArray._attributes; const maxAttributes = ContextLimits_default.maximumVertexAttributes; let i; if (hasInstancedAttributes) { const length2 = attributes.length; for (i = 0; i < length2; ++i) { const attribute = attributes[i]; if (attribute.enabled) { const divisor = attribute.instanceDivisor; const index = attribute.index; if (divisor !== divisors[index]) { context.glVertexAttribDivisor(index, divisor); divisors[index] = divisor; } } } } else { for (i = 0; i < maxAttributes; ++i) { if (divisors[i] > 0) { context.glVertexAttribDivisor(i, 0); divisors[i] = 0; } } } } function setConstantAttributes(vertexArray, gl) { const attributes = vertexArray._attributes; const length2 = attributes.length; for (let i = 0; i < length2; ++i) { const attribute = attributes[i]; if (attribute.enabled && defined_default(attribute.value)) { attribute.vertexAttrib(gl); } } } VertexArray.prototype.copyAttributeFromRange = function(attributeIndex, array, vertexOffset, vertexCount) { const attribute = this.getAttribute(attributeIndex); const buffer2 = ( /** @type {Buffer} */ attribute.vertexBuffer ); const elementsPerVertex = attribute.componentsPerAttribute; assert_default(buffer2.sizeInBytes === array.byteLength, "Invalid buffer length"); const ArrayConstructor = ( /** @type {TypedArrayConstructor} */ array.constructor ); const byteOffset = vertexOffset * elementsPerVertex * ArrayConstructor.BYTES_PER_ELEMENT; const rangeArrayView = new ArrayConstructor( /** @type {ArrayBuffer} */ array.buffer, array.byteOffset + byteOffset, vertexCount * elementsPerVertex ); buffer2.copyFromArrayView(rangeArrayView, byteOffset); }; VertexArray.prototype.copyIndexFromRange = function(array, indexOffset, indexCount) { const buffer2 = ( /** @type {Buffer} */ this._indexBuffer ); assert_default(buffer2.sizeInBytes === array.byteLength, "Invalid buffer length"); const ArrayConstructor = ( /** @type {TypedArrayConstructor} */ array.constructor ); const byteOffset = indexOffset * ArrayConstructor.BYTES_PER_ELEMENT; const rangeArrayView = new ArrayConstructor( /** @type {ArrayBuffer} */ array.buffer, array.byteOffset + byteOffset, indexCount ); buffer2.copyFromArrayView(rangeArrayView, byteOffset); }; VertexArray.prototype._bind = function() { if (defined_default(this._vao)) { this._context.glBindVertexArray(this._vao); if (this._context.instancedArrays) { setVertexAttribDivisor(this); } if (this._hasConstantAttributes) { setConstantAttributes(this, this._gl); } } else { bind(this._gl, this._attributes, this._indexBuffer); } }; VertexArray.prototype._unBind = function() { if (defined_default(this._vao)) { this._context.glBindVertexArray(null); } else { const attributes = this._attributes; const gl = this._gl; for (let i = 0; i < attributes.length; ++i) { const attribute = attributes[i]; if (attribute.enabled) { attribute.disableVertexAttribArray(gl); } } if (this._indexBuffer) { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); } } }; VertexArray.prototype.isDestroyed = function() { return false; }; VertexArray.prototype.destroy = function() { const attributes = this._attributes; for (let i = 0; i < attributes.length; ++i) { const vertexBuffer = attributes[i].vertexBuffer; if (defined_default(vertexBuffer) && !vertexBuffer.isDestroyed() && vertexBuffer.vertexArrayDestroyable) { vertexBuffer.destroy(); } } const indexBuffer = this._indexBuffer; if (defined_default(indexBuffer) && !indexBuffer.isDestroyed() && indexBuffer.vertexArrayDestroyable) { indexBuffer.destroy(); } if (defined_default(this._vao)) { this._context.glDeleteVertexArray(this._vao); } return destroyObject_default(this); }; var VertexArray_default = VertexArray; // packages/engine/Source/Renderer/CubeMap.js function CubeMap(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const { context, source, pixelFormat = PixelFormat_default.RGBA, pixelDatatype = PixelDatatype_default.UNSIGNED_BYTE, flipY = true, skipColorSpaceConversion = false, sampler = new Sampler_default() } = options; const preMultiplyAlpha = options.preMultiplyAlpha || pixelFormat === PixelFormat_default.RGB || pixelFormat === PixelFormat_default.LUMINANCE; let { width, height } = options; if (defined_default(source)) { if (!Object.values(CubeMap.FaceName).every( (faceName) => defined_default(source[faceName]) )) { throw new DeveloperError_default( `options.source requires faces ${Object.values(CubeMap.FaceName).join( ", " )}.` ); } ({ width, height } = source.positiveX); for (const faceName of CubeMap.faceNames()) { const face = source[faceName]; if (Number(face.width) !== width || Number(face.height) !== height) { throw new DeveloperError_default( "Each face in options.source must have the same width and height." ); } } } const size = width; if (!defined_default(width) || !defined_default(height)) { throw new DeveloperError_default( "options requires a source field to create an initialized cube map or width and height fields to create a blank cube map." ); } if (width !== height) { throw new DeveloperError_default("Width must equal height."); } if (size <= 0) { throw new DeveloperError_default("Width and height must be greater than zero."); } if (size > ContextLimits_default.maximumCubeMapSize) { throw new DeveloperError_default( `Width and height must be less than or equal to the maximum cube map size (${ContextLimits_default.maximumCubeMapSize}). Check maximumCubeMapSize.` ); } if (!PixelFormat_default.validate(pixelFormat)) { throw new DeveloperError_default("Invalid options.pixelFormat."); } if (PixelFormat_default.isDepthFormat(pixelFormat)) { throw new DeveloperError_default( "options.pixelFormat cannot be DEPTH_COMPONENT or DEPTH_STENCIL." ); } if (!PixelDatatype_default.validate(pixelDatatype)) { throw new DeveloperError_default("Invalid options.pixelDatatype."); } if (pixelDatatype === PixelDatatype_default.FLOAT && !context.floatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension." ); } if (pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.halfFloatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is HALF_FLOAT, this WebGL implementation must support the OES_texture_half_float extension." ); } const sizeInBytes = PixelFormat_default.textureSizeInBytes(pixelFormat, pixelDatatype, size, size) * 6; const internalFormat = PixelFormat_default.toInternalFormat( pixelFormat, pixelDatatype, context ); const gl = context._gl; const textureTarget = gl.TEXTURE_CUBE_MAP; const texture = gl.createTexture(); this._context = context; this._textureFilterAnisotropic = context._textureFilterAnisotropic; this._textureTarget = textureTarget; this._texture = texture; this._pixelFormat = pixelFormat; this._pixelDatatype = pixelDatatype; this._size = size; this._hasMipmap = false; this._sizeInBytes = sizeInBytes; this._preMultiplyAlpha = preMultiplyAlpha; this._flipY = flipY; const initialized = defined_default(source); function constructFace(targetFace) { return new CubeMapFace_default( context, texture, textureTarget, targetFace, internalFormat, pixelFormat, pixelDatatype, size, preMultiplyAlpha, flipY, initialized ); } this._positiveX = constructFace(gl.TEXTURE_CUBE_MAP_POSITIVE_X); this._negativeX = constructFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_X); this._positiveY = constructFace(gl.TEXTURE_CUBE_MAP_POSITIVE_Y); this._negativeY = constructFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y); this._positiveZ = constructFace(gl.TEXTURE_CUBE_MAP_POSITIVE_Z); this._negativeZ = constructFace(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z); this._sampler = sampler; setupSampler(this, sampler); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(textureTarget, texture); if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } for (const faceName of CubeMap.faceNames()) { loadFace(this[faceName], source?.[faceName], 0); } gl.bindTexture(textureTarget, null); } CubeMap.prototype.copyFace = function(frameState, texture, face, mipLevel) { const context = frameState.context; const framebuffer = new Framebuffer_default({ context, colorTextures: [texture], destroyAttachments: false }); framebuffer._bind(); this[face].copyMipmapFromFramebuffer( 0, 0, texture.width, texture.height, mipLevel ?? 0 ); framebuffer._unBind(); framebuffer.destroy(); }; CubeMap.FaceName = Object.freeze({ POSITIVEX: "positiveX", NEGATIVEX: "negativeX", POSITIVEY: "positiveY", NEGATIVEY: "negativeY", POSITIVEZ: "positiveZ", NEGATIVEZ: "negativeZ" }); function* makeFaceNamesIterator() { yield CubeMap.FaceName.POSITIVEX; yield CubeMap.FaceName.NEGATIVEX; yield CubeMap.FaceName.POSITIVEY; yield CubeMap.FaceName.NEGATIVEY; yield CubeMap.FaceName.POSITIVEZ; yield CubeMap.FaceName.NEGATIVEZ; } CubeMap.faceNames = function() { return makeFaceNamesIterator(); }; function loadFace(cubeMapFace, source, mipLevel) { mipLevel = mipLevel ?? 0; const targetFace = cubeMapFace._targetFace; const size = Math.max(Math.floor(cubeMapFace._size / 2 ** mipLevel), 1); const pixelFormat = cubeMapFace._pixelFormat; const pixelDatatype = cubeMapFace._pixelDatatype; const internalFormat = cubeMapFace._internalFormat; const flipY = cubeMapFace._flipY; const preMultiplyAlpha = cubeMapFace._preMultiplyAlpha; const context = cubeMapFace._context; const gl = context._gl; if (!defined_default(source)) { gl.texImage2D( targetFace, mipLevel, internalFormat, size, size, 0, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), null ); return; } let { arrayBufferView } = source; let unpackAlignment = 4; if (defined_default(arrayBufferView)) { unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, size ); } gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); if (defined_default(arrayBufferView)) { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); if (flipY) { arrayBufferView = PixelFormat_default.flipY( arrayBufferView, pixelFormat, pixelDatatype, size, size ); } gl.texImage2D( targetFace, mipLevel, internalFormat, size, size, 0, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), arrayBufferView ); } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); gl.texImage2D( targetFace, mipLevel, internalFormat, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), source ); } } CubeMap.loadFace = loadFace; Object.defineProperties(CubeMap.prototype, { positiveX: { get: function() { return this._positiveX; } }, negativeX: { get: function() { return this._negativeX; } }, positiveY: { get: function() { return this._positiveY; } }, negativeY: { get: function() { return this._negativeY; } }, positiveZ: { get: function() { return this._positiveZ; } }, negativeZ: { get: function() { return this._negativeZ; } }, sampler: { get: function() { return this._sampler; }, set: function(sampler) { setupSampler(this, sampler); this._sampler = sampler; } }, pixelFormat: { get: function() { return this._pixelFormat; } }, pixelDatatype: { get: function() { return this._pixelDatatype; } }, width: { get: function() { return this._size; } }, height: { get: function() { return this._size; } }, sizeInBytes: { get: function() { if (this._hasMipmap) { return Math.floor(this._sizeInBytes * 4 / 3); } return this._sizeInBytes; } }, preMultiplyAlpha: { get: function() { return this._preMultiplyAlpha; } }, flipY: { get: function() { return this._flipY; } }, _target: { get: function() { return this._textureTarget; } } }); CubeMap.getDirection = function(face, result) { switch (face) { case CubeMap.FaceName.POSITIVEX: return Cartesian3_default.clone(Cartesian3_default.UNIT_X, result); case CubeMap.FaceName.NEGATIVEX: return Cartesian3_default.negate(Cartesian3_default.UNIT_X, result); case CubeMap.FaceName.POSITIVEY: return Cartesian3_default.clone(Cartesian3_default.UNIT_Y, result); case CubeMap.FaceName.NEGATIVEY: return Cartesian3_default.negate(Cartesian3_default.UNIT_Y, result); case CubeMap.FaceName.POSITIVEZ: return Cartesian3_default.clone(Cartesian3_default.UNIT_Z, result); case CubeMap.FaceName.NEGATIVEZ: return Cartesian3_default.negate(Cartesian3_default.UNIT_Z, result); } }; function setupSampler(cubeMap, sampler) { let { minificationFilter, magnificationFilter } = sampler; const mipmap = [ TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST, TextureMinificationFilter_default.NEAREST_MIPMAP_LINEAR, TextureMinificationFilter_default.LINEAR_MIPMAP_NEAREST, TextureMinificationFilter_default.LINEAR_MIPMAP_LINEAR ].includes(minificationFilter); const context = cubeMap._context; const pixelDatatype = cubeMap._pixelDatatype; if (pixelDatatype === PixelDatatype_default.FLOAT && !context.textureFloatLinear || pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.textureHalfFloatLinear) { minificationFilter = mipmap ? TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST : TextureMinificationFilter_default.NEAREST; magnificationFilter = TextureMagnificationFilter_default.NEAREST; } const gl = context._gl; const target = cubeMap._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, cubeMap._texture); gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter); gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter); gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS); gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT); if (defined_default(cubeMap._textureFilterAnisotropic)) { gl.texParameteri( target, cubeMap._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy ); } gl.bindTexture(target, null); } CubeMap.prototype.loadMipmaps = function(source, skipColorSpaceConversion) { Check_default.defined("source", source); if (!Array.isArray(source)) { throw new DeveloperError_default(`source must be an array`); } const mipCount = Math.log2(this._size); if (source.length !== mipCount) { throw new DeveloperError_default(`all mip levels must be defined`); } skipColorSpaceConversion = skipColorSpaceConversion ?? false; const gl = this._context._gl; const texture = this._texture; const textureTarget = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(textureTarget, texture); if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } for (let i = 0; i < source.length; i++) { const mipSource = source[i]; const mipLevel = i + 1; for (const faceName of CubeMap.faceNames()) { loadFace(this[faceName], mipSource[faceName], mipLevel); } } gl.bindTexture(textureTarget, null); this._hasMipmap = true; }; CubeMap.prototype.generateMipmap = function(hint) { hint = hint ?? MipmapHint_default.DONT_CARE; if (this._size > 1 && !Math_default.isPowerOfTwo(this._size)) { throw new DeveloperError_default( "width and height must be a power of two to call generateMipmap()." ); } if (!MipmapHint_default.validate(hint)) { throw new DeveloperError_default("hint is invalid."); } this._hasMipmap = true; const gl = this._context._gl; const target = this._textureTarget; gl.hint(gl.GENERATE_MIPMAP_HINT, hint); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.generateMipmap(target); gl.bindTexture(target, null); }; CubeMap.createVertexArray = function(context) { const geometry = BoxGeometry_default.createGeometry( BoxGeometry_default.fromDimensions({ dimensions: new Cartesian3_default(2, 2, 2), vertexFormat: VertexFormat_default.POSITION_ONLY }) ); const attributeLocations8 = this._attributeLocations = GeometryPipeline_default.createAttributeLocations(geometry); return VertexArray_default.fromGeometry({ context, geometry, attributeLocations: attributeLocations8, bufferUsage: BufferUsage_default.STATIC_DRAW }); }; CubeMap.prototype.isDestroyed = function() { return false; }; CubeMap.prototype.destroy = function() { this._context._gl.deleteTexture(this._texture); this._positiveX = destroyObject_default(this._positiveX); this._negativeX = destroyObject_default(this._negativeX); this._positiveY = destroyObject_default(this._positiveY); this._negativeY = destroyObject_default(this._negativeY); this._positiveZ = destroyObject_default(this._positiveZ); this._negativeZ = destroyObject_default(this._negativeZ); return destroyObject_default(this); }; var CubeMap_default = CubeMap; // packages/engine/Source/Renderer/PassState.js var import_InlineWorkers121 = __toESM(require_InlineWorkers(), 1); function PassState(context) { this.context = context; this.framebuffer = void 0; this.blendingEnabled = void 0; this.scissorTest = void 0; this.viewport = void 0; } var PassState_default = PassState; // packages/engine/Source/Renderer/PickId.js var import_InlineWorkers122 = __toESM(require_InlineWorkers(), 1); var PickId = class { /** * @param {Map} pickObjects * @param {number} key * @param {Color} color */ constructor(pickObjects, key, color) { this._pickObjects = pickObjects; this.key = key; this.color = color; } /** @type {object} */ get object() { return this._pickObjects.get(this.key); } set object(value) { this._pickObjects.set(this.key, value); } /** @returns {void} */ destroy() { this._pickObjects.delete(this.key); return void 0; } }; var PickId_default = PickId; // packages/engine/Source/Renderer/ShaderCache.js var import_InlineWorkers269 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/ShaderSource.js var import_InlineWorkers268 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Builtin/CzmBuiltins.js var import_InlineWorkers266 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Builtin/Constants/degreesPerRadian.js var import_InlineWorkers123 = __toESM(require_InlineWorkers(), 1); var degreesPerRadian_default = "/**\n * A built-in GLSL floating-point constant for converting radians to degrees.\n *\n * @alias czm_degreesPerRadian\n * @glslConstant\n *\n * @see CesiumMath.DEGREES_PER_RADIAN\n *\n * @example\n * // GLSL declaration\n * const float czm_degreesPerRadian = ...;\n *\n * // Example\n * float deg = czm_degreesPerRadian * rad;\n */\nconst float czm_degreesPerRadian = 57.29577951308232;\n"; // packages/engine/Source/Shaders/Builtin/Constants/depthRange.js var import_InlineWorkers124 = __toESM(require_InlineWorkers(), 1); var depthRange_default = "/**\n * A built-in GLSL vec2 constant for defining the depth range.\n * This is a workaround to a bug where IE11 does not implement gl_DepthRange.\n *\n * @alias czm_depthRange\n * @glslConstant\n *\n * @example\n * // GLSL declaration\n * float depthRangeNear = czm_depthRange.near;\n * float depthRangeFar = czm_depthRange.far;\n *\n */\nconst czm_depthRangeStruct czm_depthRange = czm_depthRangeStruct(0.0, 1.0);\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon1.js var import_InlineWorkers125 = __toESM(require_InlineWorkers(), 1); var epsilon1_default = "/**\n * 0.1\n *\n * @name czm_epsilon1\n * @glslConstant\n */\nconst float czm_epsilon1 = 0.1;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon2.js var import_InlineWorkers126 = __toESM(require_InlineWorkers(), 1); var epsilon2_default = "/**\n * 0.01\n *\n * @name czm_epsilon2\n * @glslConstant\n */\nconst float czm_epsilon2 = 0.01;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon3.js var import_InlineWorkers127 = __toESM(require_InlineWorkers(), 1); var epsilon3_default = "/**\n * 0.001\n *\n * @name czm_epsilon3\n * @glslConstant\n */\nconst float czm_epsilon3 = 0.001;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon4.js var import_InlineWorkers128 = __toESM(require_InlineWorkers(), 1); var epsilon4_default = "/**\n * 0.0001\n *\n * @name czm_epsilon4\n * @glslConstant\n */\nconst float czm_epsilon4 = 0.0001;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon5.js var import_InlineWorkers129 = __toESM(require_InlineWorkers(), 1); var epsilon5_default = "/**\n * 0.00001\n *\n * @name czm_epsilon5\n * @glslConstant\n */\nconst float czm_epsilon5 = 0.00001;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon6.js var import_InlineWorkers130 = __toESM(require_InlineWorkers(), 1); var epsilon6_default = "/**\n * 0.000001\n *\n * @name czm_epsilon6\n * @glslConstant\n */\nconst float czm_epsilon6 = 0.000001;\n"; // packages/engine/Source/Shaders/Builtin/Constants/epsilon7.js var import_InlineWorkers131 = __toESM(require_InlineWorkers(), 1); var epsilon7_default = "/**\n * 0.0000001\n *\n * @name czm_epsilon7\n * @glslConstant\n */\nconst float czm_epsilon7 = 0.0000001;\n"; // packages/engine/Source/Shaders/Builtin/Constants/infinity.js var import_InlineWorkers132 = __toESM(require_InlineWorkers(), 1); var infinity_default = "/**\n * DOC_TBA\n *\n * @name czm_infinity\n * @glslConstant\n */\nconst float czm_infinity = 5906376272000.0; // Distance from the Sun to Pluto in meters. TODO: What is best given lowp, mediump, and highp?\n"; // packages/engine/Source/Shaders/Builtin/Constants/oneOverPi.js var import_InlineWorkers133 = __toESM(require_InlineWorkers(), 1); var oneOverPi_default = "/**\n * A built-in GLSL floating-point constant for 1/pi.\n *\n * @alias czm_oneOverPi\n * @glslConstant\n *\n * @see CesiumMath.ONE_OVER_PI\n *\n * @example\n * // GLSL declaration\n * const float czm_oneOverPi = ...;\n *\n * // Example\n * float pi = 1.0 / czm_oneOverPi;\n */\nconst float czm_oneOverPi = 0.3183098861837907;\n"; // packages/engine/Source/Shaders/Builtin/Constants/oneOverTwoPi.js var import_InlineWorkers134 = __toESM(require_InlineWorkers(), 1); var oneOverTwoPi_default = "/**\n * A built-in GLSL floating-point constant for 1/2pi.\n *\n * @alias czm_oneOverTwoPi\n * @glslConstant\n *\n * @see CesiumMath.ONE_OVER_TWO_PI\n *\n * @example\n * // GLSL declaration\n * const float czm_oneOverTwoPi = ...;\n *\n * // Example\n * float pi = 2.0 * czm_oneOverTwoPi;\n */\nconst float czm_oneOverTwoPi = 0.15915494309189535;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTile.js var import_InlineWorkers135 = __toESM(require_InlineWorkers(), 1); var passCesium3DTile_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE}\n *\n * @name czm_passCesium3DTile\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTile = 6.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTileClassification.js var import_InlineWorkers136 = __toESM(require_InlineWorkers(), 1); var passCesium3DTileClassification_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_CLASSIFICATION}\n *\n * @name czm_passCesium3DTileClassification\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTileClassification = 7.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTileClassificationIgnoreShow.js var import_InlineWorkers137 = __toESM(require_InlineWorkers(), 1); var passCesium3DTileClassificationIgnoreShow_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW}\n *\n * @name czm_passCesium3DTileClassificationIgnoreShow\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTileClassificationIgnoreShow = 8.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTileEdges.js var import_InlineWorkers138 = __toESM(require_InlineWorkers(), 1); var passCesium3DTileEdges_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_EDGES}\n *\n * @name czm_passCesium3DTileEdges\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTileEdges = 4.0;\n\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTileEdgesDirect.js var import_InlineWorkers139 = __toESM(require_InlineWorkers(), 1); var passCesium3DTileEdgesDirect_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_EDGES_DIRECT}\n *\n * @name czm_passCesium3DTileEdgesDirect\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTileEdgesDirect = 12.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCesium3DTilePlanarFillId.js var import_InlineWorkers140 = __toESM(require_InlineWorkers(), 1); var passCesium3DTilePlanarFillId_default = "/**\n * The automatic GLSL constant for {@link Pass#CESIUM_3D_TILE_PLANAR_FILL_ID}\n *\n * @name czm_passCesium3DTilePlanarFillId\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCesium3DTilePlanarFillId = 5.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passClassification.js var import_InlineWorkers141 = __toESM(require_InlineWorkers(), 1); var passClassification_default = "/**\n * The automatic GLSL constant for {@link Pass#CLASSIFICATION}\n *\n * @name czm_passClassification\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passClassification = 8.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passCompute.js var import_InlineWorkers142 = __toESM(require_InlineWorkers(), 1); var passCompute_default = "/**\n * The automatic GLSL constant for {@link Pass#COMPUTE}\n *\n * @name czm_passCompute\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passCompute = 1.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passEnvironment.js var import_InlineWorkers143 = __toESM(require_InlineWorkers(), 1); var passEnvironment_default = "/**\n * The automatic GLSL constant for {@link Pass#ENVIRONMENT}\n *\n * @name czm_passEnvironment\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passEnvironment = 0.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passGaussianSplats.js var import_InlineWorkers144 = __toESM(require_InlineWorkers(), 1); var passGaussianSplats_default = "/**\n * The automatic GLSL constant for {@link Pass#GAUSSIAN_SPLATS}\n *\n * @name czm_passGaussianSplats\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passGaussianSplats = 12.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passGlobe.js var import_InlineWorkers145 = __toESM(require_InlineWorkers(), 1); var passGlobe_default = "/**\n * The automatic GLSL constant for {@link Pass#GLOBE}\n *\n * @name czm_passGlobe\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passGlobe = 2.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passOpaque.js var import_InlineWorkers146 = __toESM(require_InlineWorkers(), 1); var passOpaque_default = "/**\n * The automatic GLSL constant for {@link Pass#OPAQUE}\n *\n * @name czm_passOpaque\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passOpaque = 9.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passOverlay.js var import_InlineWorkers147 = __toESM(require_InlineWorkers(), 1); var passOverlay_default = "/**\n * The automatic GLSL constant for {@link Pass#OVERLAY}\n *\n * @name czm_passOverlay\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passOverlay = 13.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passTerrainClassification.js var import_InlineWorkers148 = __toESM(require_InlineWorkers(), 1); var passTerrainClassification_default = "/**\n * The automatic GLSL constant for {@link Pass#TERRAIN_CLASSIFICATION}\n *\n * @name czm_passTerrainClassification\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passTerrainClassification = 3.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passTranslucent.js var import_InlineWorkers149 = __toESM(require_InlineWorkers(), 1); var passTranslucent_default = "/**\n * The automatic GLSL constant for {@link Pass#TRANSLUCENT}\n *\n * @name czm_passTranslucent\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passTranslucent = 10.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/passVoxels.js var import_InlineWorkers150 = __toESM(require_InlineWorkers(), 1); var passVoxels_default = "/**\n * The automatic GLSL constant for {@link Pass#VOXELS}\n *\n * @name czm_passVoxels\n * @glslConstant\n *\n * @see czm_pass\n */\nconst float czm_passVoxels = 11.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/pi.js var import_InlineWorkers151 = __toESM(require_InlineWorkers(), 1); var pi_default = "/**\n * A built-in GLSL floating-point constant for Math.PI.\n *\n * @alias czm_pi\n * @glslConstant\n *\n * @see CesiumMath.PI\n *\n * @example\n * // GLSL declaration\n * const float czm_pi = ...;\n *\n * // Example\n * float twoPi = 2.0 * czm_pi;\n */\nconst float czm_pi = 3.141592653589793;\n"; // packages/engine/Source/Shaders/Builtin/Constants/piOverFour.js var import_InlineWorkers152 = __toESM(require_InlineWorkers(), 1); var piOverFour_default = "/**\n * A built-in GLSL floating-point constant for pi/4.\n *\n * @alias czm_piOverFour\n * @glslConstant\n *\n * @see CesiumMath.PI_OVER_FOUR\n *\n * @example\n * // GLSL declaration\n * const float czm_piOverFour = ...;\n *\n * // Example\n * float pi = 4.0 * czm_piOverFour;\n */\nconst float czm_piOverFour = 0.7853981633974483;\n"; // packages/engine/Source/Shaders/Builtin/Constants/piOverSix.js var import_InlineWorkers153 = __toESM(require_InlineWorkers(), 1); var piOverSix_default = "/**\n * A built-in GLSL floating-point constant for pi/6.\n *\n * @alias czm_piOverSix\n * @glslConstant\n *\n * @see CesiumMath.PI_OVER_SIX\n *\n * @example\n * // GLSL declaration\n * const float czm_piOverSix = ...;\n *\n * // Example\n * float pi = 6.0 * czm_piOverSix;\n */\nconst float czm_piOverSix = 0.5235987755982988;\n"; // packages/engine/Source/Shaders/Builtin/Constants/piOverThree.js var import_InlineWorkers154 = __toESM(require_InlineWorkers(), 1); var piOverThree_default = "/**\n * A built-in GLSL floating-point constant for pi/3.\n *\n * @alias czm_piOverThree\n * @glslConstant\n *\n * @see CesiumMath.PI_OVER_THREE\n *\n * @example\n * // GLSL declaration\n * const float czm_piOverThree = ...;\n *\n * // Example\n * float pi = 3.0 * czm_piOverThree;\n */\nconst float czm_piOverThree = 1.0471975511965976;\n"; // packages/engine/Source/Shaders/Builtin/Constants/piOverTwo.js var import_InlineWorkers155 = __toESM(require_InlineWorkers(), 1); var piOverTwo_default = "/**\n * A built-in GLSL floating-point constant for pi/2.\n *\n * @alias czm_piOverTwo\n * @glslConstant\n *\n * @see CesiumMath.PI_OVER_TWO\n *\n * @example\n * // GLSL declaration\n * const float czm_piOverTwo = ...;\n *\n * // Example\n * float pi = 2.0 * czm_piOverTwo;\n */\nconst float czm_piOverTwo = 1.5707963267948966;\n"; // packages/engine/Source/Shaders/Builtin/Constants/radiansPerDegree.js var import_InlineWorkers156 = __toESM(require_InlineWorkers(), 1); var radiansPerDegree_default = "/**\n * A built-in GLSL floating-point constant for converting degrees to radians.\n *\n * @alias czm_radiansPerDegree\n * @glslConstant\n *\n * @see CesiumMath.RADIANS_PER_DEGREE\n *\n * @example\n * // GLSL declaration\n * const float czm_radiansPerDegree = ...;\n *\n * // Example\n * float rad = czm_radiansPerDegree * deg;\n */\nconst float czm_radiansPerDegree = 0.017453292519943295;\n"; // packages/engine/Source/Shaders/Builtin/Constants/sceneMode2D.js var import_InlineWorkers157 = __toESM(require_InlineWorkers(), 1); var sceneMode2D_default = "/**\n * The constant identifier for the 2D {@link SceneMode}\n *\n * @name czm_sceneMode2D\n * @glslConstant\n * @see czm_sceneMode\n * @see czm_sceneModeColumbusView\n * @see czm_sceneMode3D\n * @see czm_sceneModeMorphing\n */\nconst float czm_sceneMode2D = 2.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/sceneMode3D.js var import_InlineWorkers158 = __toESM(require_InlineWorkers(), 1); var sceneMode3D_default = "/**\n * The constant identifier for the 3D {@link SceneMode}\n *\n * @name czm_sceneMode3D\n * @glslConstant\n * @see czm_sceneMode\n * @see czm_sceneMode2D\n * @see czm_sceneModeColumbusView\n * @see czm_sceneModeMorphing\n */\nconst float czm_sceneMode3D = 3.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/sceneModeColumbusView.js var import_InlineWorkers159 = __toESM(require_InlineWorkers(), 1); var sceneModeColumbusView_default = "/**\n * The constant identifier for the Columbus View {@link SceneMode}\n *\n * @name czm_sceneModeColumbusView\n * @glslConstant\n * @see czm_sceneMode\n * @see czm_sceneMode2D\n * @see czm_sceneMode3D\n * @see czm_sceneModeMorphing\n */\nconst float czm_sceneModeColumbusView = 1.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/sceneModeMorphing.js var import_InlineWorkers160 = __toESM(require_InlineWorkers(), 1); var sceneModeMorphing_default = "/**\n * The constant identifier for the Morphing {@link SceneMode}\n *\n * @name czm_sceneModeMorphing\n * @glslConstant\n * @see czm_sceneMode\n * @see czm_sceneMode2D\n * @see czm_sceneModeColumbusView\n * @see czm_sceneMode3D\n */\nconst float czm_sceneModeMorphing = 0.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/solarRadius.js var import_InlineWorkers161 = __toESM(require_InlineWorkers(), 1); var solarRadius_default = "/**\n * A built-in GLSL floating-point constant for one solar radius.\n *\n * @alias czm_solarRadius\n * @glslConstant\n *\n * @see CesiumMath.SOLAR_RADIUS\n *\n * @example\n * // GLSL declaration\n * const float czm_solarRadius = ...;\n */\nconst float czm_solarRadius = 695500000.0;\n"; // packages/engine/Source/Shaders/Builtin/Constants/threePiOver2.js var import_InlineWorkers162 = __toESM(require_InlineWorkers(), 1); var threePiOver2_default = "/**\n * A built-in GLSL floating-point constant for 3pi/2.\n *\n * @alias czm_threePiOver2\n * @glslConstant\n *\n * @see CesiumMath.THREE_PI_OVER_TWO\n *\n * @example\n * // GLSL declaration\n * const float czm_threePiOver2 = ...;\n *\n * // Example\n * float pi = (2.0 / 3.0) * czm_threePiOver2;\n */\nconst float czm_threePiOver2 = 4.71238898038469;\n"; // packages/engine/Source/Shaders/Builtin/Constants/twoPi.js var import_InlineWorkers163 = __toESM(require_InlineWorkers(), 1); var twoPi_default = "/**\n * A built-in GLSL floating-point constant for 2pi.\n *\n * @alias czm_twoPi\n * @glslConstant\n *\n * @see CesiumMath.TWO_PI\n *\n * @example\n * // GLSL declaration\n * const float czm_twoPi = ...;\n *\n * // Example\n * float pi = czm_twoPi / 2.0;\n */\nconst float czm_twoPi = 6.283185307179586;\n"; // packages/engine/Source/Shaders/Builtin/Constants/webMercatorMaxLatitude.js var import_InlineWorkers164 = __toESM(require_InlineWorkers(), 1); var webMercatorMaxLatitude_default = "/**\n * The maximum latitude, in radians, both North and South, supported by a Web Mercator\n * (EPSG:3857) projection. Technically, the Mercator projection is defined\n * for any latitude up to (but not including) 90 degrees, but it makes sense\n * to cut it off sooner because it grows exponentially with increasing latitude.\n * The logic behind this particular cutoff value, which is the one used by\n * Google Maps, Bing Maps, and Esri, is that it makes the projection\n * square. That is, the rectangle is equal in the X and Y directions.\n *\n * The constant value is computed as follows:\n * czm_pi * 0.5 - (2.0 * atan(exp(-czm_pi)))\n *\n * @name czm_webMercatorMaxLatitude\n * @glslConstant\n */\nconst float czm_webMercatorMaxLatitude = 1.4844222297453324;\n"; // packages/engine/Source/Shaders/Builtin/Structs/depthRangeStruct.js var import_InlineWorkers165 = __toESM(require_InlineWorkers(), 1); var depthRangeStruct_default = "/**\n * @name czm_depthRangeStruct\n * @glslStruct\n */\nstruct czm_depthRangeStruct\n{\n float near;\n float far;\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/material.js var import_InlineWorkers166 = __toESM(require_InlineWorkers(), 1); var material_default = "/**\n * Holds material information that can be used for lighting. Returned by all czm_getMaterial functions.\n *\n * @name czm_material\n * @glslStruct\n *\n * @property {vec3} diffuse Incoming light that scatters evenly in all directions.\n * @property {float} specular Intensity of incoming light reflecting in a single direction.\n * @property {float} shininess The sharpness of the specular reflection. Higher values create a smaller, more focused specular highlight.\n * @property {vec3} normal Surface's normal in eye coordinates. It is used for effects such as normal mapping. The default is the surface's unmodified normal.\n * @property {vec3} emission Light emitted by the material equally in all directions. The default is vec3(0.0), which emits no light.\n * @property {float} alpha Alpha of this material. 0.0 is completely transparent; 1.0 is completely opaque.\n */\nstruct czm_material\n{\n vec3 diffuse;\n float specular;\n float shininess;\n vec3 normal;\n vec3 emission;\n float alpha;\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/materialInput.js var import_InlineWorkers167 = __toESM(require_InlineWorkers(), 1); var materialInput_default = "/**\n * Used as input to every material's czm_getMaterial function.\n *\n * @name czm_materialInput\n * @glslStruct\n *\n * @property {float} s 1D texture coordinates.\n * @property {vec2} st 2D texture coordinates.\n * @property {vec3} str 3D texture coordinates.\n * @property {vec3} normalEC Unperturbed surface normal in eye coordinates.\n * @property {mat3} tangentToEyeMatrix Matrix for converting a tangent space normal to eye space.\n * @property {vec3} positionToEyeEC Vector from the fragment to the eye in eye coordinates. The magnitude is the distance in meters from the fragment to the eye.\n * @property {float} height The height of the terrain in meters above or below the ellipsoid. Only available for globe materials.\n * @property {float} slope The slope of the terrain in radians. 0 is flat; pi/2 is vertical. Only available for globe materials.\n * @property {float} aspect The aspect of the terrain in radians. 0 is East, pi/2 is North, pi is West, 3pi/2 is South. Only available for globe materials.\n* @property {float} waterMask The value of the water mask. 0 is land, 1 is water. Only available for globe materials.\n */\nstruct czm_materialInput\n{\n float s;\n vec2 st;\n vec3 str;\n vec3 normalEC;\n mat3 tangentToEyeMatrix;\n vec3 positionToEyeEC;\n float height;\n float slope;\n float aspect;\n float waterMask;\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/modelMaterial.js var import_InlineWorkers168 = __toESM(require_InlineWorkers(), 1); var modelMaterial_default = "/**\n * Struct for representing a material for a {@link Model}. The model\n * rendering pipeline will pass this struct between material, custom shaders,\n * and lighting stages. This is not to be confused with {@link czm_material}\n * which is used by the older Fabric materials system, although they are similar.\n *

\n * All color values (diffuse, specular, emissive) are in linear color space.\n *

\n *\n * @name czm_modelMaterial\n * @glslStruct\n *\n * @property {vec4} baseColor The base color of the material.\n * @property {vec3} diffuse Incoming light that scatters evenly in all directions.\n * @property {float} alpha Alpha of this material. 0.0 is completely transparent; 1.0 is completely opaque.\n * @property {vec3} specular Color of reflected light at normal incidence in PBR materials. This is sometimes referred to as f0 in the literature.\n * @property {float} roughness A number from 0.0 to 1.0 representing how rough the surface is. Values near 0.0 produce glossy surfaces, while values near 1.0 produce rough surfaces.\n * @property {vec3} normalEC Surface's normal in eye coordinates. It is used for effects such as normal mapping. The default is the surface's unmodified normal.\n * @property {float} occlusion Ambient occlusion recieved at this point on the material. 1.0 means fully lit, 0.0 means fully occluded.\n * @property {vec3} emissive Light emitted by the material equally in all directions. The default is vec3(0.0), which emits no light.\n */\nstruct czm_modelMaterial {\n vec4 baseColor;\n vec3 diffuse;\n float alpha;\n vec3 specular;\n float roughness;\n vec3 normalEC;\n float occlusion;\n vec3 emissive;\n#ifdef USE_SPECULAR\n float specularWeight;\n#endif\n#ifdef USE_ANISOTROPY\n vec3 anisotropicT;\n vec3 anisotropicB;\n float anisotropyStrength;\n#endif\n#ifdef USE_CLEARCOAT\n float clearcoatFactor;\n float clearcoatRoughness;\n vec3 clearcoatNormal;\n // Add clearcoatF0 when KHR_materials_ior is implemented\n#endif\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/modelVertexOutput.js var import_InlineWorkers169 = __toESM(require_InlineWorkers(), 1); var modelVertexOutput_default = "/**\n * Struct for representing the output of a custom vertex shader.\n * \n * @name czm_modelVertexOutput\n * @glslStruct\n *\n * @see {@link CustomShader}\n * @see {@link Model}\n *\n * @property {vec3} positionMC The position of the vertex in model coordinates\n * @property {float} pointSize A custom value for gl_PointSize. This is only used for point primitives. \n */\nstruct czm_modelVertexOutput {\n vec3 positionMC;\n float pointSize;\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/ray.js var import_InlineWorkers170 = __toESM(require_InlineWorkers(), 1); var ray_default = "/**\n * DOC_TBA\n *\n * @name czm_ray\n * @glslStruct\n */\nstruct czm_ray\n{\n vec3 origin;\n vec3 direction;\n};\n"; // packages/engine/Source/Shaders/Builtin/Structs/raySegment.js var import_InlineWorkers171 = __toESM(require_InlineWorkers(), 1); var raySegment_default = "/**\n * DOC_TBA\n *\n * @name czm_raySegment\n * @glslStruct\n */\nstruct czm_raySegment\n{\n float start;\n float stop;\n};\n\n/**\n * DOC_TBA\n *\n * @name czm_emptyRaySegment\n * @glslConstant \n */\nconst czm_raySegment czm_emptyRaySegment = czm_raySegment(-czm_infinity, -czm_infinity);\n\n/**\n * DOC_TBA\n *\n * @name czm_fullRaySegment\n * @glslConstant \n */\nconst czm_raySegment czm_fullRaySegment = czm_raySegment(0.0, czm_infinity);\n"; // packages/engine/Source/Shaders/Builtin/Structs/shadowParameters.js var import_InlineWorkers172 = __toESM(require_InlineWorkers(), 1); var shadowParameters_default = "struct czm_shadowParameters\n{\n#ifdef USE_CUBE_MAP_SHADOW\n vec3 texCoords;\n#else\n vec2 texCoords;\n#endif\n\n float depthBias;\n float depth;\n float nDotL;\n vec2 texelStepSize;\n float normalShadingSmooth;\n float darkness;\n};\n"; // packages/engine/Source/Shaders/Builtin/Functions/HSBToRGB.js var import_InlineWorkers173 = __toESM(require_InlineWorkers(), 1); var HSBToRGB_default = "/**\n * Converts an HSB color (hue, saturation, brightness) to RGB\n * HSB <-> RGB conversion with minimal branching: {@link http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl}\n *\n * @name czm_HSBToRGB\n * @glslFunction\n * \n * @param {vec3} hsb The color in HSB.\n *\n * @returns {vec3} The color in RGB.\n *\n * @example\n * vec3 hsb = czm_RGBToHSB(rgb);\n * hsb.z *= 0.1;\n * rgb = czm_HSBToRGB(hsb);\n */\n\nconst vec4 K_HSB2RGB = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n\nvec3 czm_HSBToRGB(vec3 hsb)\n{\n vec3 p = abs(fract(hsb.xxx + K_HSB2RGB.xyz) * 6.0 - K_HSB2RGB.www);\n return hsb.z * mix(K_HSB2RGB.xxx, clamp(p - K_HSB2RGB.xxx, 0.0, 1.0), hsb.y);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/HSLToRGB.js var import_InlineWorkers174 = __toESM(require_InlineWorkers(), 1); var HSLToRGB_default = "/**\n * Converts an HSL color (hue, saturation, lightness) to RGB\n * HSL <-> RGB conversion: {@link http://www.chilliant.com/rgb2hsv.html}\n *\n * @name czm_HSLToRGB\n * @glslFunction\n * \n * @param {vec3} rgb The color in HSL.\n *\n * @returns {vec3} The color in RGB.\n *\n * @example\n * vec3 hsl = czm_RGBToHSL(rgb);\n * hsl.z *= 0.1;\n * rgb = czm_HSLToRGB(hsl);\n */\n\nvec3 hueToRGB(float hue)\n{\n float r = abs(hue * 6.0 - 3.0) - 1.0;\n float g = 2.0 - abs(hue * 6.0 - 2.0);\n float b = 2.0 - abs(hue * 6.0 - 4.0);\n return clamp(vec3(r, g, b), 0.0, 1.0);\n}\n\nvec3 czm_HSLToRGB(vec3 hsl)\n{\n vec3 rgb = hueToRGB(hsl.x);\n float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;\n return (rgb - 0.5) * c + hsl.z;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/RGBToHSB.js var import_InlineWorkers175 = __toESM(require_InlineWorkers(), 1); var RGBToHSB_default = "/**\n * Converts an RGB color to HSB (hue, saturation, brightness)\n * HSB <-> RGB conversion with minimal branching: {@link http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl}\n *\n * @name czm_RGBToHSB\n * @glslFunction\n * \n * @param {vec3} rgb The color in RGB.\n *\n * @returns {vec3} The color in HSB.\n *\n * @example\n * vec3 hsb = czm_RGBToHSB(rgb);\n * hsb.z *= 0.1;\n * rgb = czm_HSBToRGB(hsb);\n */\n\nconst vec4 K_RGB2HSB = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n\nvec3 czm_RGBToHSB(vec3 rgb)\n{\n vec4 p = mix(vec4(rgb.bg, K_RGB2HSB.wz), vec4(rgb.gb, K_RGB2HSB.xy), step(rgb.b, rgb.g));\n vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r));\n\n float d = q.x - min(q.w, q.y);\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + czm_epsilon7)), d / (q.x + czm_epsilon7), q.x);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/RGBToHSL.js var import_InlineWorkers176 = __toESM(require_InlineWorkers(), 1); var RGBToHSL_default = "/**\n * Converts an RGB color to HSL (hue, saturation, lightness)\n * HSL <-> RGB conversion: {@link http://www.chilliant.com/rgb2hsv.html}\n *\n * @name czm_RGBToHSL\n * @glslFunction\n * \n * @param {vec3} rgb The color in RGB.\n *\n * @returns {vec3} The color in HSL.\n *\n * @example\n * vec3 hsl = czm_RGBToHSL(rgb);\n * hsl.z *= 0.1;\n * rgb = czm_HSLToRGB(hsl);\n */\n \nvec3 RGBtoHCV(vec3 rgb)\n{\n // Based on work by Sam Hocevar and Emil Persson\n vec4 p = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0);\n vec4 q = (rgb.r < p.x) ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx);\n float c = q.x - min(q.w, q.y);\n float h = abs((q.w - q.y) / (6.0 * c + czm_epsilon7) + q.z);\n return vec3(h, c, q.x);\n}\n\nvec3 czm_RGBToHSL(vec3 rgb)\n{\n vec3 hcv = RGBtoHCV(rgb);\n float l = hcv.z - hcv.y * 0.5;\n float s = hcv.y / (1.0 - abs(l * 2.0 - 1.0) + czm_epsilon7);\n return vec3(hcv.x, s, l);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/RGBToXYZ.js var import_InlineWorkers177 = __toESM(require_InlineWorkers(), 1); var RGBToXYZ_default = "/**\n * Converts an RGB color to CIE Yxy.\n *

The conversion is described in\n * {@link http://content.gpwiki.org/index.php/D3DBook:High-Dynamic_Range_Rendering#Luminance_Transform|Luminance Transform}\n *

\n * \n * @name czm_RGBToXYZ\n * @glslFunction\n * \n * @param {vec3} rgb The color in RGB.\n *\n * @returns {vec3} The color in CIE Yxy.\n *\n * @example\n * vec3 xyz = czm_RGBToXYZ(rgb);\n * xyz.x = max(xyz.x - luminanceThreshold, 0.0);\n * rgb = czm_XYZToRGB(xyz);\n */\nvec3 czm_RGBToXYZ(vec3 rgb)\n{\n const mat3 RGB2XYZ = mat3(0.4124, 0.2126, 0.0193,\n 0.3576, 0.7152, 0.1192,\n 0.1805, 0.0722, 0.9505);\n vec3 xyz = RGB2XYZ * rgb;\n vec3 Yxy;\n Yxy.r = xyz.g;\n float temp = dot(vec3(1.0), xyz);\n Yxy.gb = xyz.rg / temp;\n return Yxy;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/XYZToRGB.js var import_InlineWorkers178 = __toESM(require_InlineWorkers(), 1); var XYZToRGB_default = "/**\n * Converts a CIE Yxy color to RGB.\n *

The conversion is described in\n * {@link http://content.gpwiki.org/index.php/D3DBook:High-Dynamic_Range_Rendering#Luminance_Transform|Luminance Transform}\n *

\n * \n * @name czm_XYZToRGB\n * @glslFunction\n * \n * @param {vec3} Yxy The color in CIE Yxy.\n *\n * @returns {vec3} The color in RGB.\n *\n * @example\n * vec3 xyz = czm_RGBToXYZ(rgb);\n * xyz.x = max(xyz.x - luminanceThreshold, 0.0);\n * rgb = czm_XYZToRGB(xyz);\n */\nvec3 czm_XYZToRGB(vec3 Yxy)\n{\n const mat3 XYZ2RGB = mat3( 3.2405, -0.9693, 0.0556,\n -1.5371, 1.8760, -0.2040,\n -0.4985, 0.0416, 1.0572);\n vec3 xyz;\n xyz.r = Yxy.r * Yxy.g / Yxy.b;\n xyz.g = Yxy.r;\n xyz.b = Yxy.r * (1.0 - Yxy.g - Yxy.b) / Yxy.b;\n \n return XYZ2RGB * xyz;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/acesTonemapping.js var import_InlineWorkers179 = __toESM(require_InlineWorkers(), 1); var acesTonemapping_default = "// See:\n// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/\n\nvec3 czm_acesTonemapping(vec3 color) {\n float g = 0.985;\n float a = 0.065;\n float b = 0.0001;\n float c = 0.433;\n float d = 0.238;\n\n color = (color * (color + a) - b) / (color * (g * color + c) + d);\n\n color = clamp(color, 0.0, 1.0);\n\n return color;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/alphaWeight.js var import_InlineWorkers180 = __toESM(require_InlineWorkers(), 1); var alphaWeight_default = "/**\n * @private\n */\nfloat czm_alphaWeight(float a)\n{\n float z = (gl_FragCoord.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\n\n // See Weighted Blended Order-Independent Transparency for examples of different weighting functions:\n // http://jcgt.org/published/0002/02/09/\n return pow(a + 0.01, 4.0) + max(1e-2, min(3.0 * 1e3, 0.003 / (1e-5 + pow(abs(z) / 200.0, 4.0))));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/antialias.js var import_InlineWorkers181 = __toESM(require_InlineWorkers(), 1); var antialias_default = "/**\n * Procedural anti-aliasing by blurring two colors that meet at a sharp edge.\n *\n * @name czm_antialias\n * @glslFunction\n *\n * @param {vec4} color1 The color on one side of the edge.\n * @param {vec4} color2 The color on the other side of the edge.\n * @param {vec4} currentcolor The current color, either color1 or color2.\n * @param {float} dist The distance to the edge in texture coordinates.\n * @param {float} [fuzzFactor=0.1] Controls the blurriness between the two colors.\n * @returns {vec4} The anti-aliased color.\n *\n * @example\n * // GLSL declarations\n * vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist, float fuzzFactor);\n * vec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist);\n *\n * // get the color for a material that has a sharp edge at the line y = 0.5 in texture space\n * float dist = abs(textureCoordinates.t - 0.5);\n * vec4 currentColor = mix(bottomColor, topColor, step(0.5, textureCoordinates.t));\n * vec4 color = czm_antialias(bottomColor, topColor, currentColor, dist, 0.1);\n */\nvec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist, float fuzzFactor)\n{\n float val1 = clamp(dist / fuzzFactor, 0.0, 1.0);\n float val2 = clamp((dist - 0.5) / fuzzFactor, 0.0, 1.0);\n val1 = val1 * (1.0 - val2);\n val1 = val1 * val1 * (3.0 - (2.0 * val1));\n val1 = pow(val1, 0.5); //makes the transition nicer\n \n vec4 midColor = (color1 + color2) * 0.5;\n return mix(midColor, currentColor, val1);\n}\n\nvec4 czm_antialias(vec4 color1, vec4 color2, vec4 currentColor, float dist)\n{\n return czm_antialias(color1, color2, currentColor, dist, 0.1);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/applyHSBShift.js var import_InlineWorkers182 = __toESM(require_InlineWorkers(), 1); var applyHSBShift_default = "/**\n * Apply a HSB color shift to an RGB color.\n *\n * @param {vec3} rgb The color in RGB space.\n * @param {vec3} hsbShift The amount to shift each component. The xyz components correspond to hue, saturation, and brightness. Shifting the hue by +/- 1.0 corresponds to shifting the hue by a full cycle. Saturation and brightness are clamped between 0 and 1 after the adjustment\n * @param {bool} ignoreBlackPixels If true, black pixels will be unchanged. This is necessary in some shaders such as atmosphere-related effects.\n *\n * @return {vec3} The RGB color after shifting in HSB space and clamping saturation and brightness to a valid range.\n */\nvec3 czm_applyHSBShift(vec3 rgb, vec3 hsbShift, bool ignoreBlackPixels) {\n // Convert rgb color to hsb\n vec3 hsb = czm_RGBToHSB(rgb);\n\n // Perform hsb shift\n // Hue cycles around so no clamp is needed.\n hsb.x += hsbShift.x; // hue\n hsb.y = clamp(hsb.y + hsbShift.y, 0.0, 1.0); // saturation\n\n // brightness\n //\n // Some shaders such as atmosphere-related effects need to leave black\n // pixels unchanged\n if (ignoreBlackPixels) {\n hsb.z = hsb.z > czm_epsilon7 ? hsb.z + hsbShift.z : 0.0;\n } else {\n hsb.z = hsb.z + hsbShift.z;\n }\n hsb.z = clamp(hsb.z, 0.0, 1.0);\n\n // Convert shifted hsb back to rgb\n return czm_HSBToRGB(hsb);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/approximateSphericalCoordinates.js var import_InlineWorkers183 = __toESM(require_InlineWorkers(), 1); var approximateSphericalCoordinates_default = "/**\n * Approximately computes spherical coordinates given a normal.\n * Uses approximate inverse trigonometry for speed and consistency,\n * since inverse trigonometry can differ from vendor-to-vendor and when compared with the CPU.\n *\n * @name czm_approximateSphericalCoordinates\n * @glslFunction\n *\n * @param {vec3} normal arbitrary-length normal.\n *\n * @returns {vec2} Approximate latitude and longitude spherical coordinates.\n */\nvec2 czm_approximateSphericalCoordinates(vec3 normal) {\n // Project into plane with vertical for latitude\n float latitudeApproximation = czm_fastApproximateAtan(sqrt(normal.x * normal.x + normal.y * normal.y), normal.z);\n float longitudeApproximation = czm_fastApproximateAtan(normal.x, normal.y);\n return vec2(latitudeApproximation, longitudeApproximation);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/approximateTanh.js var import_InlineWorkers184 = __toESM(require_InlineWorkers(), 1); var approximateTanh_default = "/**\n * Compute a rational approximation to tanh(x)\n *\n * @param {float} x A real number input\n * @returns {float} An approximation for tanh(x)\n*/\nfloat czm_approximateTanh(float x) {\n float x2 = x * x;\n return max(-1.0, min(1.0, x * (27.0 + x2) / (27.0 + 9.0 * x2)));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/backFacing.js var import_InlineWorkers185 = __toESM(require_InlineWorkers(), 1); var backFacing_default = "/**\n * Determines if the fragment is back facing\n *\n * @name czm_backFacing\n * @glslFunction \n * \n * @returns {bool} true if the fragment is back facing; otherwise, false.\n */\nbool czm_backFacing()\n{\n // !gl_FrontFacing doesn't work as expected on Mac/Intel so use the more verbose form instead. See https://github.com/CesiumGS/cesium/pull/8494.\n return gl_FrontFacing == false;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/branchFreeTernary.js var import_InlineWorkers186 = __toESM(require_InlineWorkers(), 1); var branchFreeTernary_default = "/**\n * Branchless ternary operator to be used when it's inexpensive to explicitly\n * evaluate both possibilities for a float expression.\n *\n * @name czm_branchFreeTernary\n * @glslFunction\n *\n * @param {bool} comparison A comparison statement\n * @param {float} a Value to return if the comparison is true.\n * @param {float} b Value to return if the comparison is false.\n *\n * @returns {float} equivalent of comparison ? a : b\n */\nfloat czm_branchFreeTernary(bool comparison, float a, float b) {\n float useA = float(comparison);\n return a * useA + b * (1.0 - useA);\n}\n\n/**\n * Branchless ternary operator to be used when it's inexpensive to explicitly\n * evaluate both possibilities for a vec2 expression.\n *\n * @name czm_branchFreeTernary\n * @glslFunction\n *\n * @param {bool} comparison A comparison statement\n * @param {vec2} a Value to return if the comparison is true.\n * @param {vec2} b Value to return if the comparison is false.\n *\n * @returns {vec2} equivalent of comparison ? a : b\n */\nvec2 czm_branchFreeTernary(bool comparison, vec2 a, vec2 b) {\n float useA = float(comparison);\n return a * useA + b * (1.0 - useA);\n}\n\n/**\n * Branchless ternary operator to be used when it's inexpensive to explicitly\n * evaluate both possibilities for a vec3 expression.\n *\n * @name czm_branchFreeTernary\n * @glslFunction\n *\n * @param {bool} comparison A comparison statement\n * @param {vec3} a Value to return if the comparison is true.\n * @param {vec3} b Value to return if the comparison is false.\n *\n * @returns {vec3} equivalent of comparison ? a : b\n */\nvec3 czm_branchFreeTernary(bool comparison, vec3 a, vec3 b) {\n float useA = float(comparison);\n return a * useA + b * (1.0 - useA);\n}\n\n/**\n * Branchless ternary operator to be used when it's inexpensive to explicitly\n * evaluate both possibilities for a vec4 expression.\n *\n * @name czm_branchFreeTernary\n * @glslFunction\n *\n * @param {bool} comparison A comparison statement\n * @param {vec3} a Value to return if the comparison is true.\n * @param {vec3} b Value to return if the comparison is false.\n *\n * @returns {vec3} equivalent of comparison ? a : b\n */\nvec4 czm_branchFreeTernary(bool comparison, vec4 a, vec4 b) {\n float useA = float(comparison);\n return a * useA + b * (1.0 - useA);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/cascadeColor.js var import_InlineWorkers187 = __toESM(require_InlineWorkers(), 1); var cascadeColor_default = "\nvec4 czm_cascadeColor(vec4 weights)\n{\n return vec4(1.0, 0.0, 0.0, 1.0) * weights.x +\n vec4(0.0, 1.0, 0.0, 1.0) * weights.y +\n vec4(0.0, 0.0, 1.0, 1.0) * weights.z +\n vec4(1.0, 0.0, 1.0, 1.0) * weights.w;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/cascadeDistance.js var import_InlineWorkers188 = __toESM(require_InlineWorkers(), 1); var cascadeDistance_default = "\nuniform vec4 shadowMap_cascadeDistances;\n\nfloat czm_cascadeDistance(vec4 weights)\n{\n return dot(shadowMap_cascadeDistances, weights);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/cascadeMatrix.js var import_InlineWorkers189 = __toESM(require_InlineWorkers(), 1); var cascadeMatrix_default = "\nuniform mat4 shadowMap_cascadeMatrices[4];\n\nmat4 czm_cascadeMatrix(vec4 weights)\n{\n return shadowMap_cascadeMatrices[0] * weights.x +\n shadowMap_cascadeMatrices[1] * weights.y +\n shadowMap_cascadeMatrices[2] * weights.z +\n shadowMap_cascadeMatrices[3] * weights.w;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/cascadeWeights.js var import_InlineWorkers190 = __toESM(require_InlineWorkers(), 1); var cascadeWeights_default = "\nuniform vec4 shadowMap_cascadeSplits[2];\n\nvec4 czm_cascadeWeights(float depthEye)\n{\n // One component is set to 1.0 and all others set to 0.0.\n vec4 near = step(shadowMap_cascadeSplits[0], vec4(depthEye));\n vec4 far = step(depthEye, shadowMap_cascadeSplits[1]);\n return near * far;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/clipPolygons.js var import_InlineWorkers191 = __toESM(require_InlineWorkers(), 1); var clipPolygons_default = "float getSignedDistance(vec2 uv, highp sampler2D clippingDistance) {\n float signedDistance = texture(clippingDistance, uv).r;\n return (signedDistance - 0.5) * 2.0;\n}\n\nvoid czm_clipPolygons(highp sampler2D clippingDistance, int extentsLength, vec2 clippingPosition, int regionIndex) {\n // Position is completely outside of polygons bounds\n vec2 rectUv = clippingPosition;\n if (regionIndex < 0 || rectUv.x <= 0.0 || rectUv.y <= 0.0 || rectUv.x >= 1.0 || rectUv.y >= 1.0) {\n #ifdef CLIPPING_INVERSE \n discard;\n #endif\n return;\n }\n\n vec2 clippingDistanceTextureDimensions = vec2(textureSize(clippingDistance, 0));\n vec2 sampleOffset = max(1.0 / clippingDistanceTextureDimensions, vec2(0.005));\n float dimension = float(extentsLength);\n if (extentsLength > 2) {\n dimension = ceil(log2(float(extentsLength)));\n }\n\n vec2 textureOffset = vec2(mod(float(regionIndex), dimension), floor(float(regionIndex) / dimension)) / dimension;\n vec2 uv = textureOffset + rectUv / dimension;\n\n float signedDistance = getSignedDistance(uv, clippingDistance);\n\n #ifdef CLIPPING_INVERSE\n if (signedDistance > 0.0) {\n discard;\n }\n #else\n if (signedDistance < 0.0) {\n discard;\n }\n #endif\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/columbusViewMorph.js var import_InlineWorkers192 = __toESM(require_InlineWorkers(), 1); var columbusViewMorph_default = "/**\n * DOC_TBA\n *\n * @name czm_columbusViewMorph\n * @glslFunction\n */\nvec4 czm_columbusViewMorph(vec4 position2D, vec4 position3D, float time)\n{\n // Just linear for now.\n // We're manually doing the equivalent of a `mix` here because, some GPUs\n // (NVidia GeForce 3070 Ti and Intel Arc A750, to name two), `mix` seems to\n // use an alternate formulation that introduces jitter even when `time` is\n // 0.0 or 1.0. That is, the value of `p` won't be exactly `position2D.xyz`\n // when `time` is 0.0 and it won't be exactly `position3D.xyz` when `time` is\n // 1.0. The \"textbook\" formulation here, while probably a bit slower,\n // does not have this problem.\n vec3 p = position2D.xyz * (1.0 - time) + position3D.xyz * time;\n return vec4(p, 1.0);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/computeAtmosphereColor.js var import_InlineWorkers193 = __toESM(require_InlineWorkers(), 1); var computeAtmosphereColor_default = "/**\n * Compute the atmosphere color, applying Rayleigh and Mie scattering. This\n * builtin uses automatic uniforms so the atmophere settings are synced with the\n * state of the Scene, even in other contexts like Model.\n *\n * @name czm_computeAtmosphereColor\n * @glslFunction\n *\n * @param {vec3} positionWC Position of the fragment in world coords (low precision)\n * @param {vec3} lightDirection Light direction from the sun or other light source.\n * @param {vec3} rayleighColor The Rayleigh scattering color computed by a scattering function\n * @param {vec3} mieColor The Mie scattering color computed by a scattering function\n * @param {float} opacity The opacity computed by a scattering function.\n */\nvec4 czm_computeAtmosphereColor(\n vec3 positionWC,\n vec3 lightDirection,\n vec3 rayleighColor,\n vec3 mieColor,\n float opacity\n) {\n // Setup the primary ray: from the camera position to the vertex position.\n vec3 cameraToPositionWC = positionWC - czm_viewerPositionWC;\n vec3 cameraToPositionWCDirection = normalize(cameraToPositionWC);\n\n float cosAngle = dot(cameraToPositionWCDirection, lightDirection);\n float cosAngleSq = cosAngle * cosAngle;\n\n float G = czm_atmosphereMieAnisotropy;\n float GSq = G * G;\n\n // The Rayleigh phase function.\n float rayleighPhase = 3.0 / (50.2654824574) * (1.0 + cosAngleSq);\n // The Mie phase function.\n float miePhase = 3.0 / (25.1327412287) * ((1.0 - GSq) * (cosAngleSq + 1.0)) / (pow(1.0 + GSq - 2.0 * cosAngle * G, 1.5) * (2.0 + GSq));\n\n // The final color is generated by combining the effects of the Rayleigh and Mie scattering.\n vec3 rayleigh = rayleighPhase * rayleighColor;\n vec3 mie = miePhase * mieColor;\n\n vec3 color = (rayleigh + mie) * czm_atmosphereLightIntensity;\n\n return vec4(color, opacity);\n}\n\n/**\n * Compute the atmosphere color, applying Rayleigh and Mie scattering. This\n * builtin uses automatic uniforms so the atmophere settings are synced with the\n * state of the Scene, even in other contexts like Model.\n *\n * @name czm_computeAtmosphereColor\n * @glslFunction\n *\n * @param {czm_ray} primaryRay Ray from the origin to sky fragment to in world coords (low precision)\n * @param {vec3} lightDirection Light direction from the sun or other light source.\n * @param {vec3} rayleighColor The Rayleigh scattering color computed by a scattering function\n * @param {vec3} mieColor The Mie scattering color computed by a scattering function\n * @param {float} opacity The opacity computed by a scattering function.\n */\nvec4 czm_computeAtmosphereColor(\n czm_ray primaryRay,\n vec3 lightDirection,\n vec3 rayleighColor,\n vec3 mieColor,\n float opacity\n) {\n vec3 direction = normalize(primaryRay.direction);\n\n float cosAngle = dot(direction, lightDirection);\n float cosAngleSq = cosAngle * cosAngle;\n\n float G = czm_atmosphereMieAnisotropy;\n float GSq = G * G;\n\n // The Rayleigh phase function.\n float rayleighPhase = 3.0 / (50.2654824574) * (1.0 + cosAngleSq);\n // The Mie phase function.\n float miePhase = 3.0 / (25.1327412287) * ((1.0 - GSq) * (cosAngleSq + 1.0)) / (pow(1.0 + GSq - 2.0 * cosAngle * G, 1.5) * (2.0 + GSq));\n\n // The final color is generated by combining the effects of the Rayleigh and Mie scattering.\n vec3 rayleigh = rayleighPhase * rayleighColor;\n vec3 mie = miePhase * mieColor;\n\n vec3 color = (rayleigh + mie) * czm_atmosphereLightIntensity;\n\n return vec4(color, opacity);\n}\n\n"; // packages/engine/Source/Shaders/Builtin/Functions/computeGroundAtmosphereScattering.js var import_InlineWorkers194 = __toESM(require_InlineWorkers(), 1); var computeGroundAtmosphereScattering_default = "/**\n * Compute atmosphere scattering for the ground atmosphere and fog. This method\n * uses automatic uniforms so it is always synced with the scene settings.\n *\n * @name czm_computeGroundAtmosphereScattering\n * @glslfunction\n *\n * @param {vec3} positionWC The position of the fragment in world coordinates.\n * @param {vec3} lightDirection The direction of the light to calculate the scattering from.\n * @param {vec3} rayleighColor The variable the Rayleigh scattering will be written to.\n * @param {vec3} mieColor The variable the Mie scattering will be written to.\n * @param {float} opacity The variable the transmittance will be written to.\n */\nvoid czm_computeGroundAtmosphereScattering(vec3 positionWC, vec3 lightDirection, out vec3 rayleighColor, out vec3 mieColor, out float opacity) {\n vec3 cameraToPositionWC = positionWC - czm_viewerPositionWC;\n vec3 cameraToPositionWCDirection = normalize(cameraToPositionWC);\n czm_ray primaryRay = czm_ray(czm_viewerPositionWC, cameraToPositionWCDirection);\n\n float atmosphereInnerRadius = length(positionWC);\n\n czm_computeScattering(\n primaryRay,\n length(cameraToPositionWC),\n lightDirection,\n atmosphereInnerRadius,\n rayleighColor,\n mieColor,\n opacity\n );\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/computePosition.js var import_InlineWorkers195 = __toESM(require_InlineWorkers(), 1); var computePosition_default = "/**\n * Returns a position in model coordinates relative to eye taking into\n * account the current scene mode: 3D, 2D, or Columbus view.\n *

\n * This uses standard position attributes, position3DHigh, \n * position3DLow, position2DHigh, and position2DLow, \n * and should be used when writing a vertex shader for an {@link Appearance}.\n *

\n *\n * @name czm_computePosition\n * @glslFunction\n *\n * @returns {vec4} The position relative to eye.\n *\n * @example\n * vec4 p = czm_computePosition();\n * v_positionEC = (czm_modelViewRelativeToEye * p).xyz;\n * gl_Position = czm_modelViewProjectionRelativeToEye * p;\n *\n * @see czm_translateRelativeToEye\n */\nvec4 czm_computePosition();\n"; // packages/engine/Source/Shaders/Builtin/Functions/computeScattering.js var import_InlineWorkers196 = __toESM(require_InlineWorkers(), 1); var computeScattering_default = "/**\n * This function computes the colors contributed by Rayliegh and Mie scattering on a given ray, as well as\n * the transmittance value for the ray. This function uses automatic uniforms\n * so the atmosphere settings are always synced with the current scene.\n *\n * @name czm_computeScattering\n * @glslfunction\n *\n * @param {czm_ray} primaryRay The ray from the camera to the position.\n * @param {float} primaryRayLength The length of the primary ray.\n * @param {vec3} lightDirection The direction of the light to calculate the scattering from.\n * @param {vec3} rayleighColor The variable the Rayleigh scattering will be written to.\n * @param {vec3} mieColor The variable the Mie scattering will be written to.\n * @param {float} opacity The variable the transmittance will be written to.\n */\nvoid czm_computeScattering(\n czm_ray primaryRay,\n float primaryRayLength,\n vec3 lightDirection,\n float atmosphereInnerRadius,\n out vec3 rayleighColor,\n out vec3 mieColor,\n out float opacity\n) {\n const float ATMOSPHERE_THICKNESS = 111e3; // The thickness of the atmosphere in meters.\n const int PRIMARY_STEPS_MAX = 16; // Maximum number of times the ray from the camera to the world position (primary ray) is sampled.\n const int LIGHT_STEPS_MAX = 4; // Maximum number of times the light is sampled from the light source's intersection with the atmosphere to a sample position on the primary ray.\n\n // Initialize the default scattering amounts to 0.\n rayleighColor = vec3(0.0);\n mieColor = vec3(0.0);\n opacity = 0.0;\n\n float atmosphereOuterRadius = atmosphereInnerRadius + ATMOSPHERE_THICKNESS;\n\n vec3 origin = vec3(0.0);\n\n // Calculate intersection from the camera to the outer ring of the atmosphere.\n czm_raySegment primaryRayAtmosphereIntersect = czm_raySphereIntersectionInterval(primaryRay, origin, atmosphereOuterRadius);\n\n // Return empty colors if no intersection with the atmosphere geometry.\n if (primaryRayAtmosphereIntersect == czm_emptyRaySegment) {\n return;\n }\n\n // To deal with smaller values of PRIMARY_STEPS (e.g. 4)\n // we implement a split strategy: sky or horizon.\n // For performance reasons, instead of a if/else branch\n // a soft choice is implemented through a weight 0.0 <= w_stop_gt_lprl <= 1.0\n float x = 1e-7 * primaryRayAtmosphereIntersect.stop / length(primaryRayLength);\n // Value close to 0.0: close to the horizon\n // Value close to 1.0: above in the sky\n float w_stop_gt_lprl = 0.5 * (1.0 + czm_approximateTanh(x));\n\n // The ray should start from the first intersection with the outer atmopshere, or from the camera position, if it is inside the atmosphere.\n float start_0 = primaryRayAtmosphereIntersect.start;\n primaryRayAtmosphereIntersect.start = max(primaryRayAtmosphereIntersect.start, 0.0);\n // The ray should end at the exit from the atmosphere or at the distance to the vertex, whichever is smaller.\n primaryRayAtmosphereIntersect.stop = min(primaryRayAtmosphereIntersect.stop, length(primaryRayLength));\n\n // For the number of ray steps, distinguish inside or outside atmosphere (outer space)\n // (1) from outer space we have to use more ray steps to get a realistic rendering\n // (2) within atmosphere we need fewer steps for faster rendering\n float x_o_a = start_0 - ATMOSPHERE_THICKNESS; // ATMOSPHERE_THICKNESS used as an ad-hoc constant, no precise meaning here, only the order of magnitude matters\n float w_inside_atmosphere = 1.0 - 0.5 * (1.0 + czm_approximateTanh(x_o_a));\n int PRIMARY_STEPS = PRIMARY_STEPS_MAX - int(w_inside_atmosphere * 12.0); // Number of times the ray from the camera to the world position (primary ray) is sampled.\n int LIGHT_STEPS = LIGHT_STEPS_MAX - int(w_inside_atmosphere * 2.0); // Number of times the light is sampled from the light source's intersection with the atmosphere to a sample position on the primary ray.\n\n // Setup for sampling positions along the ray - starting from the intersection with the outer ring of the atmosphere.\n float rayPositionLength = primaryRayAtmosphereIntersect.start;\n // (1) Outside the atmosphere: constant rayStepLength\n // (2) Inside atmosphere: variable rayStepLength to compensate the rough rendering of the smaller number of ray steps\n float totalRayLength = primaryRayAtmosphereIntersect.stop - rayPositionLength;\n float rayStepLengthIncrease = w_inside_atmosphere * ((1.0 - w_stop_gt_lprl) * totalRayLength / (float(PRIMARY_STEPS * (PRIMARY_STEPS + 1)) / 2.0));\n float rayStepLength = max(1.0 - w_inside_atmosphere, w_stop_gt_lprl) * totalRayLength / max(7.0 * w_inside_atmosphere, float(PRIMARY_STEPS));\n\n vec3 rayleighAccumulation = vec3(0.0);\n vec3 mieAccumulation = vec3(0.0);\n vec2 opticalDepth = vec2(0.0);\n vec2 heightScale = vec2(czm_atmosphereRayleighScaleHeight, czm_atmosphereMieScaleHeight);\n\n // Sample positions on the primary ray.\n for (int i = 0; i < PRIMARY_STEPS_MAX; ++i) {\n\n // The loop should be: for (int i = 0; i < PRIMARY_STEPS; ++i) {...} but WebGL1 cannot\n // loop with non-constant condition, so it has to break early instead\n if (i >= PRIMARY_STEPS) {\n break;\n }\n\n // Calculate sample position along viewpoint ray.\n vec3 samplePosition = primaryRay.origin + primaryRay.direction * (rayPositionLength + rayStepLength);\n\n // Calculate height of sample position above ellipsoid.\n float sampleHeight = length(samplePosition) - atmosphereInnerRadius;\n\n // Calculate and accumulate density of particles at the sample position.\n vec2 sampleDensity = exp(-sampleHeight / heightScale) * rayStepLength;\n opticalDepth += sampleDensity;\n\n // Generate ray from the sample position segment to the light source, up to the outer ring of the atmosphere.\n czm_ray lightRay = czm_ray(samplePosition, lightDirection);\n czm_raySegment lightRayAtmosphereIntersect = czm_raySphereIntersectionInterval(lightRay, origin, atmosphereOuterRadius);\n\n float lightStepLength = lightRayAtmosphereIntersect.stop / float(LIGHT_STEPS);\n float lightPositionLength = 0.0;\n\n vec2 lightOpticalDepth = vec2(0.0);\n\n // Sample positions along the light ray, to accumulate incidence of light on the latest sample segment.\n for (int j = 0; j < LIGHT_STEPS_MAX; ++j) {\n\n // The loop should be: for (int j = 0; i < LIGHT_STEPS; ++j) {...} but WebGL1 cannot\n // loop with non-constant condition, so it has to break early instead\n if (j >= LIGHT_STEPS) {\n break;\n }\n\n // Calculate sample position along light ray.\n vec3 lightPosition = samplePosition + lightDirection * (lightPositionLength + lightStepLength * 0.5);\n\n // Calculate height of the light sample position above ellipsoid.\n float lightHeight = length(lightPosition) - atmosphereInnerRadius;\n\n // Calculate density of photons at the light sample position.\n lightOpticalDepth += exp(-lightHeight / heightScale) * lightStepLength;\n\n // Increment distance on light ray.\n lightPositionLength += lightStepLength;\n }\n\n // Compute attenuation via the primary ray and the light ray.\n vec3 attenuation = exp(-((czm_atmosphereMieCoefficient * (opticalDepth.y + lightOpticalDepth.y)) + (czm_atmosphereRayleighCoefficient * (opticalDepth.x + lightOpticalDepth.x))));\n\n // Accumulate the scattering.\n rayleighAccumulation += sampleDensity.x * attenuation;\n mieAccumulation += sampleDensity.y * attenuation;\n\n // Increment distance on primary ray.\n rayPositionLength += (rayStepLength += rayStepLengthIncrease);\n }\n\n // Compute the scattering amount.\n rayleighColor = czm_atmosphereRayleighCoefficient * rayleighAccumulation;\n mieColor = czm_atmosphereMieCoefficient * mieAccumulation;\n\n // Compute the transmittance i.e. how much light is passing through the atmosphere.\n opacity = length(exp(-((czm_atmosphereMieCoefficient * opticalDepth.y) + (czm_atmosphereRayleighCoefficient * opticalDepth.x))));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/computeTextureTransform.js var import_InlineWorkers197 = __toESM(require_InlineWorkers(), 1); var computeTextureTransform_default = "/**\n * Applies a 2D texture transformation matrix to texture coordinates.\n * This function applies translation, rotation, and scaling transformations\n * as specified by the KHR_texture_transform glTF extension.\n *\n * @name czm_computeTextureTransform\n * @glslFunction\n *\n * @param {vec2} texCoord The texture coordinates to transform.\n * @param {mat3} textureTransform The 3x3 transformation matrix.\n *\n * @returns {vec2} The transformed texture coordinates.\n *\n * @example\n * // GLSL declaration\n * vec2 czm_computeTextureTransform(vec2 texCoord, mat3 textureTransform);\n *\n * // Apply texture transform to UV coordinates\n * vec2 transformedUV = czm_computeTextureTransform(uv, u_textureTransform);\n */\nvec2 czm_computeTextureTransform(vec2 texCoord, mat3 textureTransform)\n{\n return vec2(textureTransform * vec3(texCoord, 1.0));\n}"; // packages/engine/Source/Shaders/Builtin/Functions/cosineAndSine.js var import_InlineWorkers198 = __toESM(require_InlineWorkers(), 1); var cosineAndSine_default = "/**\n * @private\n */\nvec2 cordic(float angle)\n{\n// Scale the vector by the appropriate factor for the 24 iterations to follow.\n vec2 vector = vec2(6.0725293500888267e-1, 0.0);\n// Iteration 1\n float sense = (angle < 0.0) ? -1.0 : 1.0;\n // float factor = sense * 1.0; // 2^-0\n mat2 rotation = mat2(1.0, sense, -sense, 1.0);\n vector = rotation * vector;\n angle -= sense * 7.8539816339744828e-1; // atan(2^-0)\n// Iteration 2\n sense = (angle < 0.0) ? -1.0 : 1.0;\n float factor = sense * 5.0e-1; // 2^-1\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 4.6364760900080609e-1; // atan(2^-1)\n// Iteration 3\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 2.5e-1; // 2^-2\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 2.4497866312686414e-1; // atan(2^-2)\n// Iteration 4\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.25e-1; // 2^-3\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.2435499454676144e-1; // atan(2^-3)\n// Iteration 5\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 6.25e-2; // 2^-4\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 6.2418809995957350e-2; // atan(2^-4)\n// Iteration 6\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 3.125e-2; // 2^-5\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 3.1239833430268277e-2; // atan(2^-5)\n// Iteration 7\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.5625e-2; // 2^-6\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.5623728620476831e-2; // atan(2^-6)\n// Iteration 8\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 7.8125e-3; // 2^-7\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 7.8123410601011111e-3; // atan(2^-7)\n// Iteration 9\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 3.90625e-3; // 2^-8\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 3.9062301319669718e-3; // atan(2^-8)\n// Iteration 10\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.953125e-3; // 2^-9\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.9531225164788188e-3; // atan(2^-9)\n// Iteration 11\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 9.765625e-4; // 2^-10\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 9.7656218955931946e-4; // atan(2^-10)\n// Iteration 12\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 4.8828125e-4; // 2^-11\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 4.8828121119489829e-4; // atan(2^-11)\n// Iteration 13\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 2.44140625e-4; // 2^-12\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 2.4414062014936177e-4; // atan(2^-12)\n// Iteration 14\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.220703125e-4; // 2^-13\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.2207031189367021e-4; // atan(2^-13)\n// Iteration 15\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 6.103515625e-5; // 2^-14\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 6.1035156174208773e-5; // atan(2^-14)\n// Iteration 16\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 3.0517578125e-5; // 2^-15\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 3.0517578115526096e-5; // atan(2^-15)\n// Iteration 17\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.52587890625e-5; // 2^-16\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.5258789061315762e-5; // atan(2^-16)\n// Iteration 18\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 7.62939453125e-6; // 2^-17\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 7.6293945311019700e-6; // atan(2^-17)\n// Iteration 19\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 3.814697265625e-6; // 2^-18\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 3.8146972656064961e-6; // atan(2^-18)\n// Iteration 20\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.9073486328125e-6; // 2^-19\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 1.9073486328101870e-6; // atan(2^-19)\n// Iteration 21\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 9.5367431640625e-7; // 2^-20\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 9.5367431640596084e-7; // atan(2^-20)\n// Iteration 22\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 4.76837158203125e-7; // 2^-21\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 4.7683715820308884e-7; // atan(2^-21)\n// Iteration 23\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 2.384185791015625e-7; // 2^-22\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n angle -= sense * 2.3841857910155797e-7; // atan(2^-22)\n// Iteration 24\n sense = (angle < 0.0) ? -1.0 : 1.0;\n factor = sense * 1.1920928955078125e-7; // 2^-23\n rotation[0][1] = factor;\n rotation[1][0] = -factor;\n vector = rotation * vector;\n// angle -= sense * 1.1920928955078068e-7; // atan(2^-23)\n\n return vector;\n}\n\n/**\n * Computes the cosine and sine of the provided angle using the CORDIC algorithm.\n *\n * @name czm_cosineAndSine\n * @glslFunction\n *\n * @param {float} angle The angle in radians.\n *\n * @returns {vec2} The resulting cosine of the angle (as the x coordinate) and sine of the angle (as the y coordinate).\n *\n * @example\n * vec2 v = czm_cosineAndSine(czm_piOverSix);\n * float cosine = v.x;\n * float sine = v.y;\n */\nvec2 czm_cosineAndSine(float angle)\n{\n if (angle < -czm_piOverTwo || angle > czm_piOverTwo)\n {\n if (angle < 0.0)\n {\n return -cordic(angle + czm_pi);\n }\n else\n {\n return -cordic(angle - czm_pi);\n }\n }\n else\n {\n return cordic(angle);\n }\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/decodeRGB8.js var import_InlineWorkers199 = __toESM(require_InlineWorkers(), 1); var decodeRGB8_default = "/**\n * Decodes RGB values packed into a single float at 8-bit precision. Encoded\n * representation is equivalent to 0xFFFFFF in JavaScript.\n *\n * @name czm_decodeRGB8\n * @glslFunction\n *\n * @param {float} encoded Float-encoded RGB values.\n * @returns {vec4} Decoded RGB values.\n */\nvec4 czm_decodeRGB8(float encoded) {\n const float SHIFT_RIGHT16 = 1.0 / 65536.0;\n const float SHIFT_RIGHT8 = 1.0 / 256.0;\n const float SHIFT_LEFT16 = 65536.0;\n const float SHIFT_LEFT8 = 256.0;\n\n vec4 color = vec4(255.0);\n color.r = floor(encoded * SHIFT_RIGHT16);\n color.g = floor((encoded - color.r * SHIFT_LEFT16) * SHIFT_RIGHT8);\n color.b = floor(encoded - color.r * SHIFT_LEFT16 - color.g * SHIFT_LEFT8);\n return color / 255.0;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/decompressTextureCoordinates.js var import_InlineWorkers200 = __toESM(require_InlineWorkers(), 1); var decompressTextureCoordinates_default = "/**\n * Decompresses texture coordinates that were packed into a single float.\n *\n * @name czm_decompressTextureCoordinates\n * @glslFunction\n *\n * @param {float} encoded The compressed texture coordinates.\n * @returns {vec2} The decompressed texture coordinates.\n */\n vec2 czm_decompressTextureCoordinates(float encoded)\n {\n float temp = encoded / 4096.0;\n float xZeroTo4095 = floor(temp);\n float stx = xZeroTo4095 / 4095.0;\n float sty = (encoded - xZeroTo4095 * 4096.0) / 4095.0;\n return vec2(stx, sty);\n }\n"; // packages/engine/Source/Shaders/Builtin/Functions/depthClamp.js var import_InlineWorkers201 = __toESM(require_InlineWorkers(), 1); var depthClamp_default = "// emulated noperspective\n#if (__VERSION__ == 300 || defined(GL_EXT_frag_depth)) && !defined(LOG_DEPTH)\nout float v_WindowZ;\n#endif\n\n/**\n * Emulates GL_DEPTH_CLAMP, which is not available in WebGL 1 or 2.\n * GL_DEPTH_CLAMP clamps geometry that is outside the near and far planes, \n * capping the shadow volume. More information here: \n * https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_depth_clamp.txt.\n *\n * When GL_EXT_frag_depth is available we emulate GL_DEPTH_CLAMP by ensuring \n * no geometry gets clipped by setting the clip space z value to 0.0 and then\n * sending the unaltered screen space z value (using emulated noperspective\n * interpolation) to the frag shader where it is clamped to [0,1] and then\n * written with gl_FragDepth (see czm_writeDepthClamp). This technique is based on:\n * https://stackoverflow.com/questions/5960757/how-to-emulate-gl-depth-clamp-nv.\n *\n * When GL_EXT_frag_depth is not available, which is the case on some mobile \n * devices, we must attempt to fix this only in the vertex shader. \n * The approach is to clamp the z value to the far plane, which closes the \n * shadow volume but also distorts the geometry, so there can still be artifacts\n * on frustum seams.\n *\n * @name czm_depthClamp\n * @glslFunction\n *\n * @param {vec4} coords The vertex in clip coordinates.\n * @returns {vec4} The modified vertex.\n *\n * @example\n * gl_Position = czm_depthClamp(czm_modelViewProjection * vec4(position, 1.0));\n *\n * @see czm_writeDepthClamp\n */\nvec4 czm_depthClamp(vec4 coords)\n{\n#ifndef LOG_DEPTH\n#if __VERSION__ == 300 || defined(GL_EXT_frag_depth)\n v_WindowZ = (0.5 * (coords.z / coords.w) + 0.5) * coords.w;\n coords.z = 0.0;\n#else\n coords.z = min(coords.z, coords.w);\n#endif\n#endif\n return coords;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/eastNorthUpToEyeCoordinates.js var import_InlineWorkers202 = __toESM(require_InlineWorkers(), 1); var eastNorthUpToEyeCoordinates_default = "/**\n * Computes a 3x3 rotation matrix that transforms vectors from an ellipsoid's east-north-up coordinate system \n * to eye coordinates. In east-north-up coordinates, x points east, y points north, and z points along the \n * surface normal. East-north-up can be used as an ellipsoid's tangent space for operations such as bump mapping.\n *

\n * The ellipsoid is assumed to be centered at the model coordinate's origin.\n *\n * @name czm_eastNorthUpToEyeCoordinates\n * @glslFunction\n *\n * @param {vec3} positionMC The position on the ellipsoid in model coordinates.\n * @param {vec3} normalEC The normalized ellipsoid surface normal, at positionMC, in eye coordinates.\n *\n * @returns {mat3} A 3x3 rotation matrix that transforms vectors from the east-north-up coordinate system to eye coordinates.\n *\n * @example\n * // Transform a vector defined in the east-north-up coordinate \n * // system, (0, 0, 1) which is the surface normal, to eye \n * // coordinates.\n * mat3 m = czm_eastNorthUpToEyeCoordinates(positionMC, normalEC);\n * vec3 normalEC = m * vec3(0.0, 0.0, 1.0);\n */\nmat3 czm_eastNorthUpToEyeCoordinates(vec3 positionMC, vec3 normalEC)\n{\n vec3 tangentMC = normalize(vec3(-positionMC.y, positionMC.x, 0.0)); // normalized surface tangent in model coordinates\n vec3 tangentEC = normalize(czm_normal3D * tangentMC); // normalized surface tangent in eye coordinates\n vec3 bitangentEC = normalize(cross(normalEC, tangentEC)); // normalized surface bitangent in eye coordinates\n\n return mat3(\n tangentEC.x, tangentEC.y, tangentEC.z,\n bitangentEC.x, bitangentEC.y, bitangentEC.z,\n normalEC.x, normalEC.y, normalEC.z);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/ellipsoidContainsPoint.js var import_InlineWorkers203 = __toESM(require_InlineWorkers(), 1); var ellipsoidContainsPoint_default = "/**\n * DOC_TBA\n *\n * @name czm_ellipsoidContainsPoint\n * @glslFunction\n *\n */\nbool czm_ellipsoidContainsPoint(vec3 ellipsoid_inverseRadii, vec3 point)\n{\n vec3 scaled = ellipsoid_inverseRadii * (czm_inverseModelView * vec4(point, 1.0)).xyz;\n return (dot(scaled, scaled) <= 1.0);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/ellipsoidTextureCoordinates.js var import_InlineWorkers204 = __toESM(require_InlineWorkers(), 1); var ellipsoidTextureCoordinates_default = "/**\n * Approximate uv coordinates based on the ellipsoid normal.\n *\n * @name czm_ellipsoidTextureCoordinates\n * @glslFunction\n */\nvec2 czm_ellipsoidTextureCoordinates(vec3 normal)\n{\n return vec2(atan(normal.y, normal.x) * czm_oneOverTwoPi + 0.5, asin(normal.z) * czm_oneOverPi + 0.5);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/equalsEpsilon.js var import_InlineWorkers205 = __toESM(require_InlineWorkers(), 1); var equalsEpsilon_default = "/**\n * Compares left and right componentwise. Returns true\n * if they are within epsilon and false otherwise. The inputs\n * left and right can be floats, vec2s,\n * vec3s, or vec4s.\n *\n * @name czm_equalsEpsilon\n * @glslFunction\n *\n * @param {} left The first vector.\n * @param {} right The second vector.\n * @param {float} epsilon The epsilon to use for equality testing.\n * @returns {bool} true if the components are within epsilon and false otherwise.\n *\n * @example\n * // GLSL declarations\n * bool czm_equalsEpsilon(float left, float right, float epsilon);\n * bool czm_equalsEpsilon(vec2 left, vec2 right, float epsilon);\n * bool czm_equalsEpsilon(vec3 left, vec3 right, float epsilon);\n * bool czm_equalsEpsilon(vec4 left, vec4 right, float epsilon);\n */\nbool czm_equalsEpsilon(vec4 left, vec4 right, float epsilon) {\n return all(lessThanEqual(abs(left - right), vec4(epsilon)));\n}\n\nbool czm_equalsEpsilon(vec3 left, vec3 right, float epsilon) {\n return all(lessThanEqual(abs(left - right), vec3(epsilon)));\n}\n\nbool czm_equalsEpsilon(vec2 left, vec2 right, float epsilon) {\n return all(lessThanEqual(abs(left - right), vec2(epsilon)));\n}\n\nbool czm_equalsEpsilon(float left, float right, float epsilon) {\n return (abs(left - right) <= epsilon);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/eyeOffset.js var import_InlineWorkers206 = __toESM(require_InlineWorkers(), 1); var eyeOffset_default = "/**\n * DOC_TBA\n *\n * @name czm_eyeOffset\n * @glslFunction\n *\n * @param {vec4} positionEC DOC_TBA.\n * @param {vec3} eyeOffset DOC_TBA.\n *\n * @returns {vec4} DOC_TBA.\n */\nvec4 czm_eyeOffset(vec4 positionEC, vec3 eyeOffset)\n{\n // This equation is approximate in x and y.\n vec4 p = positionEC;\n vec4 zEyeOffset = normalize(p) * eyeOffset.z;\n p.xy += eyeOffset.xy + zEyeOffset.xy;\n p.z += zEyeOffset.z;\n return p;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/eyeToWindowCoordinates.js var import_InlineWorkers207 = __toESM(require_InlineWorkers(), 1); var eyeToWindowCoordinates_default = "/**\n * Transforms a position from eye to window coordinates. The transformation\n * from eye to clip coordinates is done using {@link czm_projection}.\n * The transform from normalized device coordinates to window coordinates is\n * done using {@link czm_viewportTransformation}, which assumes a depth range\n * of near = 0 and far = 1.\n *

\n * This transform is useful when there is a need to manipulate window coordinates\n * in a vertex shader as done by {@link BillboardCollection}.\n *\n * @name czm_eyeToWindowCoordinates\n * @glslFunction\n *\n * @param {vec4} position The position in eye coordinates to transform.\n *\n * @returns {vec4} The transformed position in window coordinates.\n *\n * @see czm_modelToWindowCoordinates\n * @see czm_projection\n * @see czm_viewportTransformation\n * @see BillboardCollection\n *\n * @example\n * vec4 positionWC = czm_eyeToWindowCoordinates(positionEC);\n */\nvec4 czm_eyeToWindowCoordinates(vec4 positionEC)\n{\n vec4 q = czm_projection * positionEC; // clip coordinates\n q.xyz /= q.w; // normalized device coordinates\n q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz; // window coordinates\n return q;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/fastApproximateAtan.js var import_InlineWorkers208 = __toESM(require_InlineWorkers(), 1); var fastApproximateAtan_default = `/** * Approxiamtes atan over the range [0, 1]. Safe to flip output for negative input. * * Based on Michal Drobot's approximation from ShaderFastLibs, which in turn is based on * "Efficient approximations for the arctangent function," Rajan, S. Sichun Wang Inkol, R. Joyal, A., May 2006. * Adapted from ShaderFastLibs under MIT License. * * Chosen for the following characteristics over range [0, 1]: * - basically no error at 0 and 1, important for getting around range limit (naive atan2 via atan requires infinite range atan) * - no visible artifacts from first-derivative discontinuities, unlike latitude via range-reduced sqrt asin approximations (at equator) * * The original code is x * (-0.1784 * abs(x) - 0.0663 * x * x + 1.0301); * Removed the abs() in here because it isn't needed, the input range is guaranteed as [0, 1] by how we're approximating atan2. * * @name czm_fastApproximateAtan * @glslFunction * * @param {float} x Value between 0 and 1 inclusive. * * @returns {float} Approximation of atan(x) */ float czm_fastApproximateAtan(float x) { return x * (-0.1784 * x - 0.0663 * x * x + 1.0301); } /** * Approximation of atan2. * * Range reduction math based on nvidia's cg reference implementation for atan2: http://developer.download.nvidia.com/cg/atan2.html * However, we replaced their atan curve with Michael Drobot's (see above). * * @name czm_fastApproximateAtan * @glslFunction * * @param {float} x Value between -1 and 1 inclusive. * @param {float} y Value between -1 and 1 inclusive. * * @returns {float} Approximation of atan2(x, y) */ float czm_fastApproximateAtan(float x, float y) { // atan approximations are usually only reliable over [-1, 1], or, in our case, [0, 1] due to modifications. // So range-reduce using abs and by flipping whether x or y is on top. float t = abs(x); // t used as swap and atan result. float opposite = abs(y); float adjacent = max(t, opposite); opposite = min(t, opposite); t = czm_fastApproximateAtan(opposite / adjacent); // Undo range reduction t = czm_branchFreeTernary(abs(y) > abs(x), czm_piOverTwo - t, t); t = czm_branchFreeTernary(x < 0.0, czm_pi - t, t); t = czm_branchFreeTernary(y < 0.0, -t, t); return t; } `; // packages/engine/Source/Shaders/Builtin/Functions/fog.js var import_InlineWorkers209 = __toESM(require_InlineWorkers(), 1); var fog_default = "/**\n * Gets the color with fog at a distance from the camera.\n *\n * @name czm_fog\n * @glslFunction\n *\n * @param {float} distanceToCamera The distance to the camera in meters.\n * @param {vec3} color The original color.\n * @param {vec3} fogColor The color of the fog.\n *\n * @returns {vec3} The color adjusted for fog at the distance from the camera.\n */\nvec3 czm_fog(float distanceToCamera, vec3 color, vec3 fogColor)\n{\n float scalar = distanceToCamera * czm_fogDensity;\n float fog = 1.0 - exp(-(scalar * scalar));\n return mix(color, fogColor, fog);\n}\n\n/**\n * Gets the color with fog at a distance from the camera.\n *\n * @name czm_fog\n * @glslFunction\n *\n * @param {float} distanceToCamera The distance to the camera in meters.\n * @param {vec3} color The original color.\n * @param {vec3} fogColor The color of the fog.\n * @param {float} fogModifierConstant A constant to modify the appearance of fog.\n *\n * @returns {vec3} The color adjusted for fog at the distance from the camera.\n */\nvec3 czm_fog(float distanceToCamera, vec3 color, vec3 fogColor, float fogModifierConstant)\n{\n float scalar = distanceToCamera * czm_fogDensity;\n float fog = 1.0 - exp(-((fogModifierConstant * scalar + fogModifierConstant) * (scalar * (1.0 + fogModifierConstant))));\n return mix(color, fogColor, fog);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/gammaCorrect.js var import_InlineWorkers210 = __toESM(require_InlineWorkers(), 1); var gammaCorrect_default = "/**\n * Converts a color from RGB space to linear space.\n *\n * @name czm_gammaCorrect\n * @glslFunction\n *\n * @param {vec3} color The color in RGB space.\n * @returns {vec3} The color in linear space.\n */\nvec3 czm_gammaCorrect(vec3 color) {\n#ifdef HDR\n color = pow(color, vec3(czm_gamma));\n#endif\n return color;\n}\n\nvec4 czm_gammaCorrect(vec4 color) {\n#ifdef HDR\n color.rgb = pow(color.rgb, vec3(czm_gamma));\n#endif\n return color;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/geodeticSurfaceNormal.js var import_InlineWorkers211 = __toESM(require_InlineWorkers(), 1); var geodeticSurfaceNormal_default = "/**\n * DOC_TBA\n *\n * @name czm_geodeticSurfaceNormal\n * @glslFunction\n *\n * @param {vec3} positionOnEllipsoid DOC_TBA\n * @param {vec3} ellipsoidCenter DOC_TBA\n * @param {vec3} oneOverEllipsoidRadiiSquared DOC_TBA\n * \n * @returns {vec3} DOC_TBA.\n */\nvec3 czm_geodeticSurfaceNormal(vec3 positionOnEllipsoid, vec3 ellipsoidCenter, vec3 oneOverEllipsoidRadiiSquared)\n{\n return normalize((positionOnEllipsoid - ellipsoidCenter) * oneOverEllipsoidRadiiSquared);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/getDefaultMaterial.js var import_InlineWorkers212 = __toESM(require_InlineWorkers(), 1); var getDefaultMaterial_default = "/**\n * An czm_material with default values. Every material's czm_getMaterial\n * should use this default material as a base for the material it returns.\n * The default normal value is given by materialInput.normalEC.\n *\n * @name czm_getDefaultMaterial\n * @glslFunction\n *\n * @param {czm_materialInput} input The input used to construct the default material.\n *\n * @returns {czm_material} The default material.\n *\n * @see czm_materialInput\n * @see czm_material\n * @see czm_getMaterial\n */\nczm_material czm_getDefaultMaterial(czm_materialInput materialInput)\n{\n czm_material material;\n material.diffuse = vec3(0.0);\n material.specular = 0.0;\n material.shininess = 1.0;\n material.normal = materialInput.normalEC;\n material.emission = vec3(0.0);\n material.alpha = 1.0;\n return material;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/getDynamicAtmosphereLightDirection.js var import_InlineWorkers213 = __toESM(require_InlineWorkers(), 1); var getDynamicAtmosphereLightDirection_default = "/**\n * Select which direction vector to use for dynamic atmosphere lighting based on an enum value\n *\n * @name czm_getDynamicAtmosphereLightDirection\n * @glslfunction\n * @see DynamicAtmosphereLightingType.js\n *\n * @param {vec3} positionWC the position of the vertex/fragment in world coordinates. This is normalized and returned when dynamic lighting is turned off.\n * @param {float} lightEnum The enum value for selecting between light sources.\n * @return {vec3} The normalized light direction vector. Depending on the enum value, it is either positionWC, czm_lightDirectionWC or czm_sunDirectionWC\n */\nvec3 czm_getDynamicAtmosphereLightDirection(vec3 positionWC, float lightEnum) {\n const float NONE = 0.0;\n const float SCENE_LIGHT = 1.0;\n const float SUNLIGHT = 2.0;\n\n vec3 lightDirection =\n positionWC * float(lightEnum == NONE) +\n czm_lightDirectionWC * float(lightEnum == SCENE_LIGHT) +\n czm_sunDirectionWC * float(lightEnum == SUNLIGHT);\n return normalize(lightDirection);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/getLambertDiffuse.js var import_InlineWorkers214 = __toESM(require_InlineWorkers(), 1); var getLambertDiffuse_default = "/**\n * Calculates the intensity of diffusely reflected light.\n *\n * @name czm_getLambertDiffuse\n * @glslFunction\n *\n * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates.\n * @param {vec3} normalEC The surface normal in eye coordinates.\n *\n * @returns {float} The intensity of the diffuse reflection.\n *\n * @see czm_phong\n *\n * @example\n * float diffuseIntensity = czm_getLambertDiffuse(lightDirectionEC, normalEC);\n * float specularIntensity = czm_getSpecular(lightDirectionEC, toEyeEC, normalEC, 200);\n * vec3 color = (diffuseColor * diffuseIntensity) + (specularColor * specularIntensity);\n */\nfloat czm_getLambertDiffuse(vec3 lightDirectionEC, vec3 normalEC)\n{\n return max(dot(lightDirectionEC, normalEC), 0.0);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/getSpecular.js var import_InlineWorkers215 = __toESM(require_InlineWorkers(), 1); var getSpecular_default = "/**\n * Calculates the specular intensity of reflected light.\n *\n * @name czm_getSpecular\n * @glslFunction\n *\n * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates.\n * @param {vec3} toEyeEC Unit vector pointing to the eye position in eye coordinates.\n * @param {vec3} normalEC The surface normal in eye coordinates.\n * @param {float} shininess The sharpness of the specular reflection. Higher values create a smaller, more focused specular highlight.\n *\n * @returns {float} The intensity of the specular highlight.\n *\n * @see czm_phong\n *\n * @example\n * float diffuseIntensity = czm_getLambertDiffuse(lightDirectionEC, normalEC);\n * float specularIntensity = czm_getSpecular(lightDirectionEC, toEyeEC, normalEC, 200);\n * vec3 color = (diffuseColor * diffuseIntensity) + (specularColor * specularIntensity);\n */\nfloat czm_getSpecular(vec3 lightDirectionEC, vec3 toEyeEC, vec3 normalEC, float shininess)\n{\n vec3 toReflectedLight = reflect(-lightDirectionEC, normalEC);\n float specular = max(dot(toReflectedLight, toEyeEC), 0.0);\n\n // pow has undefined behavior if both parameters <= 0.\n // Prevent this by making sure shininess is at least czm_epsilon2.\n return pow(specular, max(shininess, czm_epsilon2));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/getWaterNoise.js var import_InlineWorkers216 = __toESM(require_InlineWorkers(), 1); var getWaterNoise_default = "/**\n * @private\n */\nvec4 czm_getWaterNoise(sampler2D normalMap, vec2 uv, float time, float angleInRadians)\n{\n float cosAngle = cos(angleInRadians);\n float sinAngle = sin(angleInRadians);\n\n // time dependent sampling directions\n vec2 s0 = vec2(1.0/17.0, 0.0);\n vec2 s1 = vec2(-1.0/29.0, 0.0);\n vec2 s2 = vec2(1.0/101.0, 1.0/59.0);\n vec2 s3 = vec2(-1.0/109.0, -1.0/57.0);\n\n // rotate sampling direction by specified angle\n s0 = vec2((cosAngle * s0.x) - (sinAngle * s0.y), (sinAngle * s0.x) + (cosAngle * s0.y));\n s1 = vec2((cosAngle * s1.x) - (sinAngle * s1.y), (sinAngle * s1.x) + (cosAngle * s1.y));\n s2 = vec2((cosAngle * s2.x) - (sinAngle * s2.y), (sinAngle * s2.x) + (cosAngle * s2.y));\n s3 = vec2((cosAngle * s3.x) - (sinAngle * s3.y), (sinAngle * s3.x) + (cosAngle * s3.y));\n\n vec2 uv0 = (uv/103.0) + (time * s0);\n vec2 uv1 = uv/107.0 + (time * s1) + vec2(0.23);\n vec2 uv2 = uv/vec2(897.0, 983.0) + (time * s2) + vec2(0.51);\n vec2 uv3 = uv/vec2(991.0, 877.0) + (time * s3) + vec2(0.71);\n\n uv0 = fract(uv0);\n uv1 = fract(uv1);\n uv2 = fract(uv2);\n uv3 = fract(uv3);\n vec4 noise = (texture(normalMap, uv0)) +\n (texture(normalMap, uv1)) +\n (texture(normalMap, uv2)) +\n (texture(normalMap, uv3));\n\n // average and scale to between -1 and 1\n return ((noise / 4.0) - 0.5) * 2.0;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/hue.js var import_InlineWorkers217 = __toESM(require_InlineWorkers(), 1); var hue_default = "/**\n * Adjusts the hue of a color.\n * \n * @name czm_hue\n * @glslFunction\n * \n * @param {vec3} rgb The color.\n * @param {float} adjustment The amount to adjust the hue of the color in radians.\n *\n * @returns {float} The color with the hue adjusted.\n *\n * @example\n * vec3 adjustHue = czm_hue(color, czm_pi); // The same as czm_hue(color, -czm_pi)\n */\nvec3 czm_hue(vec3 rgb, float adjustment)\n{\n const mat3 toYIQ = mat3(0.299, 0.587, 0.114,\n 0.595716, -0.274453, -0.321263,\n 0.211456, -0.522591, 0.311135);\n const mat3 toRGB = mat3(1.0, 0.9563, 0.6210,\n 1.0, -0.2721, -0.6474,\n 1.0, -1.107, 1.7046);\n \n vec3 yiq = toYIQ * rgb;\n float hue = atan(yiq.z, yiq.y) + adjustment;\n float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);\n \n vec3 color = vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));\n return toRGB * color;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/inverseGamma.js var import_InlineWorkers218 = __toESM(require_InlineWorkers(), 1); var inverseGamma_default = "/**\n * Converts a color in linear space to RGB space.\n *\n * @name czm_inverseGamma\n * @glslFunction\n *\n * @param {vec3} color The color in linear space.\n * @returns {vec3} The color in RGB space.\n */\nvec3 czm_inverseGamma(vec3 color) {\n return pow(color, vec3(1.0 / czm_gamma));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/isEmpty.js var import_InlineWorkers219 = __toESM(require_InlineWorkers(), 1); var isEmpty_default = "/**\n * Determines if a time interval is empty.\n *\n * @name czm_isEmpty\n * @glslFunction \n * \n * @param {czm_raySegment} interval The interval to test.\n * \n * @returns {bool} true if the time interval is empty; otherwise, false.\n *\n * @example\n * bool b0 = czm_isEmpty(czm_emptyRaySegment); // true\n * bool b1 = czm_isEmpty(czm_raySegment(0.0, 1.0)); // false\n * bool b2 = czm_isEmpty(czm_raySegment(1.0, 1.0)); // false, contains 1.0.\n */\nbool czm_isEmpty(czm_raySegment interval)\n{\n return (interval.stop < 0.0);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/isFull.js var import_InlineWorkers220 = __toESM(require_InlineWorkers(), 1); var isFull_default = "/**\n * Determines if a time interval is empty.\n *\n * @name czm_isFull\n * @glslFunction \n * \n * @param {czm_raySegment} interval The interval to test.\n * \n * @returns {bool} true if the time interval is empty; otherwise, false.\n *\n * @example\n * bool b0 = czm_isEmpty(czm_emptyRaySegment); // true\n * bool b1 = czm_isEmpty(czm_raySegment(0.0, 1.0)); // false\n * bool b2 = czm_isEmpty(czm_raySegment(1.0, 1.0)); // false, contains 1.0.\n */\nbool czm_isFull(czm_raySegment interval)\n{\n return (interval.start == 0.0 && interval.stop == czm_infinity);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/latitudeToWebMercatorFraction.js var import_InlineWorkers221 = __toESM(require_InlineWorkers(), 1); var latitudeToWebMercatorFraction_default = "/**\n * Computes the fraction of a Web Wercator rectangle at which a given geodetic latitude is located.\n *\n * @name czm_latitudeToWebMercatorFraction\n * @glslFunction\n *\n * @param {float} latitude The geodetic latitude, in radians.\n * @param {float} southMercatorY The Web Mercator coordinate of the southern boundary of the rectangle.\n * @param {float} oneOverMercatorHeight The total height of the rectangle in Web Mercator coordinates.\n *\n * @returns {float} The fraction of the rectangle at which the latitude occurs. If the latitude is the southern\n * boundary of the rectangle, the return value will be zero. If it is the northern boundary, the return\n * value will be 1.0. Latitudes in between are mapped according to the Web Mercator projection.\n */ \nfloat czm_latitudeToWebMercatorFraction(float latitude, float southMercatorY, float oneOverMercatorHeight)\n{\n float sinLatitude = sin(latitude);\n float mercatorY = 0.5 * log((1.0 + sinLatitude) / (1.0 - sinLatitude));\n \n return (mercatorY - southMercatorY) * oneOverMercatorHeight;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/lineDistance.js var import_InlineWorkers222 = __toESM(require_InlineWorkers(), 1); var lineDistance_default = "/**\n * Computes distance from an point in 2D to a line in 2D.\n *\n * @name czm_lineDistance\n * @glslFunction\n *\n * param {vec2} point1 A point along the line.\n * param {vec2} point2 A point along the line.\n * param {vec2} point A point that may or may not be on the line.\n * returns {float} The distance from the point to the line.\n */\nfloat czm_lineDistance(vec2 point1, vec2 point2, vec2 point) {\n return abs((point2.y - point1.y) * point.x - (point2.x - point1.x) * point.y + point2.x * point1.y - point2.y * point1.x) / distance(point2, point1);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/linearToSrgb.js var import_InlineWorkers223 = __toESM(require_InlineWorkers(), 1); var linearToSrgb_default = "/**\n * Converts a linear RGB color to an sRGB color.\n *\n * @param {vec3|vec4} linearIn The color in linear color space.\n * @returns {vec3|vec4} The color in sRGB color space. The vector type matches the input.\n */\nvec3 czm_linearToSrgb(vec3 linearIn) \n{\n return pow(linearIn, vec3(1.0/2.2));\n}\n\nvec4 czm_linearToSrgb(vec4 linearIn) \n{\n vec3 srgbOut = pow(linearIn.rgb, vec3(1.0/2.2));\n return vec4(srgbOut, linearIn.a);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/luminance.js var import_InlineWorkers224 = __toESM(require_InlineWorkers(), 1); var luminance_default = "/**\n * Computes the luminance of a color. \n *\n * @name czm_luminance\n * @glslFunction\n *\n * @param {vec3} rgb The color.\n * \n * @returns {float} The luminance.\n *\n * @example\n * float light = czm_luminance(vec3(0.0)); // 0.0\n * float dark = czm_luminance(vec3(1.0)); // ~1.0 \n */\nfloat czm_luminance(vec3 rgb)\n{\n // Algorithm from Chapter 10 of Graphics Shaders.\n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n return dot(rgb, W);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/maximumComponent.js var import_InlineWorkers225 = __toESM(require_InlineWorkers(), 1); var maximumComponent_default = "/**\n * Find the maximum component of a vector.\n *\n * @name czm_maximumComponent\n * @glslFunction\n *\n * @param {vec2|vec3|vec4} v The input vector.\n * @returns {float} The value of the largest component.\n */\nfloat czm_maximumComponent(vec2 v)\n{\n return max(v.x, v.y);\n}\nfloat czm_maximumComponent(vec3 v)\n{\n return max(max(v.x, v.y), v.z);\n}\nfloat czm_maximumComponent(vec4 v)\n{\n return max(max(max(v.x, v.y), v.z), v.w);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/metersPerPixel.js var import_InlineWorkers226 = __toESM(require_InlineWorkers(), 1); var metersPerPixel_default = "/**\n * Computes the size of a pixel in meters at a distance from the eye.\n *

\n * Use this version when passing in a custom pixel ratio. For example, passing in 1.0 will return meters per native device pixel.\n *

\n * @name czm_metersPerPixel\n * @glslFunction\n *\n * @param {vec3} positionEC The position to get the meters per pixel in eye coordinates.\n * @param {float} pixelRatio The scaling factor from pixel space to coordinate space\n *\n * @returns {float} The meters per pixel at positionEC.\n */\nfloat czm_metersPerPixel(vec4 positionEC, float pixelRatio)\n{\n float width = czm_viewport.z;\n float height = czm_viewport.w;\n float pixelWidth;\n float pixelHeight;\n\n float top = czm_frustumPlanes.x;\n float bottom = czm_frustumPlanes.y;\n float left = czm_frustumPlanes.z;\n float right = czm_frustumPlanes.w;\n\n if (czm_sceneMode == czm_sceneMode2D || czm_orthographicIn3D == 1.0)\n {\n float frustumWidth = right - left;\n float frustumHeight = top - bottom;\n pixelWidth = frustumWidth / width;\n pixelHeight = frustumHeight / height;\n }\n else\n {\n float distanceToPixel = -positionEC.z;\n float inverseNear = 1.0 / czm_currentFrustum.x;\n float tanTheta = top * inverseNear;\n pixelHeight = 2.0 * distanceToPixel * tanTheta / height;\n tanTheta = right * inverseNear;\n pixelWidth = 2.0 * distanceToPixel * tanTheta / width;\n }\n\n return max(pixelWidth, pixelHeight) * pixelRatio;\n}\n\n/**\n * Computes the size of a pixel in meters at a distance from the eye.\n *

\n * Use this version when scaling by pixel ratio.\n *

\n * @name czm_metersPerPixel\n * @glslFunction\n *\n * @param {vec3} positionEC The position to get the meters per pixel in eye coordinates.\n *\n * @returns {float} The meters per pixel at positionEC.\n */\nfloat czm_metersPerPixel(vec4 positionEC)\n{\n return czm_metersPerPixel(positionEC, czm_pixelRatio);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/modelToWindowCoordinates.js var import_InlineWorkers227 = __toESM(require_InlineWorkers(), 1); var modelToWindowCoordinates_default = "/**\n * Transforms a position from model to window coordinates. The transformation\n * from model to clip coordinates is done using {@link czm_modelViewProjection}.\n * The transform from normalized device coordinates to window coordinates is\n * done using {@link czm_viewportTransformation}, which assumes a depth range\n * of near = 0 and far = 1.\n *

\n * This transform is useful when there is a need to manipulate window coordinates\n * in a vertex shader as done by {@link BillboardCollection}.\n *

\n * This function should not be confused with {@link czm_viewportOrthographic},\n * which is an orthographic projection matrix that transforms from window \n * coordinates to clip coordinates.\n *\n * @name czm_modelToWindowCoordinates\n * @glslFunction\n *\n * @param {vec4} position The position in model coordinates to transform.\n *\n * @returns {vec4} The transformed position in window coordinates.\n *\n * @see czm_eyeToWindowCoordinates\n * @see czm_modelViewProjection\n * @see czm_viewportTransformation\n * @see czm_viewportOrthographic\n * @see BillboardCollection\n *\n * @example\n * vec4 positionWC = czm_modelToWindowCoordinates(positionMC);\n */\nvec4 czm_modelToWindowCoordinates(vec4 position)\n{\n vec4 positionEC = czm_modelView * position;\n vec4 q = czm_projection * positionEC;\n q.xyz /= q.w; // normalized device coordinates\n q.xyz = (czm_viewportTransformation * vec4(q.xyz, 1.0)).xyz; // window coordinates\n return q;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/multiplyWithColorBalance.js var import_InlineWorkers228 = __toESM(require_InlineWorkers(), 1); var multiplyWithColorBalance_default = "/**\n * DOC_TBA\n *\n * @name czm_multiplyWithColorBalance\n * @glslFunction\n */\nvec3 czm_multiplyWithColorBalance(vec3 left, vec3 right)\n{\n // Algorithm from Chapter 10 of Graphics Shaders.\n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n \n vec3 target = left * right;\n float leftLuminance = dot(left, W);\n float rightLuminance = dot(right, W);\n float targetLuminance = dot(target, W);\n \n return ((leftLuminance + rightLuminance) / (2.0 * targetLuminance)) * target;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/nearFarScalar.js var import_InlineWorkers229 = __toESM(require_InlineWorkers(), 1); var nearFarScalar_default = "/**\n * Computes a value that scales with distance. The scaling is clamped at the near and\n * far distances, and does not extrapolate. This function works with the\n * {@link NearFarScalar} JavaScript class.\n *\n * @name czm_nearFarScalar\n * @glslFunction\n *\n * @param {vec4} nearFarScalar A vector with 4 components: Near distance (x), Near value (y), Far distance (z), Far value (w).\n * @param {float} cameraDistSq The square of the current distance from the camera.\n *\n * @returns {float} The value at this distance.\n */\nfloat czm_nearFarScalar(vec4 nearFarScalar, float cameraDistSq)\n{\n float valueAtMin = nearFarScalar.y;\n float valueAtMax = nearFarScalar.w;\n float nearDistanceSq = nearFarScalar.x * nearFarScalar.x;\n float farDistanceSq = nearFarScalar.z * nearFarScalar.z;\n\n float t = (cameraDistSq - nearDistanceSq) / (farDistanceSq - nearDistanceSq);\n\n t = pow(clamp(t, 0.0, 1.0), 0.2);\n\n return mix(valueAtMin, valueAtMax, t);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/octDecode.js var import_InlineWorkers230 = __toESM(require_InlineWorkers(), 1); var octDecode_default = ` /** * Decodes a unit-length vector in 'oct' encoding to a normalized 3-component Cartesian vector. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ * * @name czm_octDecode * @param {vec2} encoded The oct-encoded, unit-length vector * @param {float} range The maximum value of the SNORM range. The encoded vector is stored in log2(rangeMax+1) bits. * @returns {vec3} The decoded and normalized vector */ vec3 czm_octDecode(vec2 encoded, float range) { if (encoded.x == 0.0 && encoded.y == 0.0) { return vec3(0.0, 0.0, 0.0); } encoded = encoded / range * 2.0 - 1.0; vec3 v = vec3(encoded.x, encoded.y, 1.0 - abs(encoded.x) - abs(encoded.y)); if (v.z < 0.0) { v.xy = (1.0 - abs(v.yx)) * czm_signNotZero(v.xy); } return normalize(v); } /** * Decodes a unit-length vector in 'oct' encoding to a normalized 3-component Cartesian vector. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ * * @name czm_octDecode * @param {vec2} encoded The oct-encoded, unit-length vector * @returns {vec3} The decoded and normalized vector */ vec3 czm_octDecode(vec2 encoded) { return czm_octDecode(encoded, 255.0); } /** * Decodes a unit-length vector in 'oct' encoding packed into a floating-point number to a normalized 3-component Cartesian vector. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ * * @name czm_octDecode * @param {float} encoded The oct-encoded, unit-length vector * @returns {vec3} The decoded and normalized vector */ vec3 czm_octDecode(float encoded) { float temp = encoded / 256.0; float x = floor(temp); float y = (temp - x) * 256.0; return czm_octDecode(vec2(x, y)); } /** * Decodes three unit-length vectors in 'oct' encoding packed into two floating-point numbers to normalized 3-component Cartesian vectors. * The 'oct' encoding is described in "A Survey of Efficient Representations of Independent Unit Vectors", * Cigolle et al 2014: http://jcgt.org/published/0003/02/01/ * * @name czm_octDecode * @param {vec2} encoded The packed oct-encoded, unit-length vectors. * @param {vec3} vector1 One decoded and normalized vector. * @param {vec3} vector2 One decoded and normalized vector. * @param {vec3} vector3 One decoded and normalized vector. */ void czm_octDecode(vec2 encoded, out vec3 vector1, out vec3 vector2, out vec3 vector3) { float temp = encoded.x / 65536.0; float x = floor(temp); float encodedFloat1 = (temp - x) * 65536.0; temp = encoded.y / 65536.0; float y = floor(temp); float encodedFloat2 = (temp - y) * 65536.0; vector1 = czm_octDecode(encodedFloat1); vector2 = czm_octDecode(encodedFloat2); vector3 = czm_octDecode(vec2(x, y)); } `; // packages/engine/Source/Shaders/Builtin/Functions/packDepth.js var import_InlineWorkers231 = __toESM(require_InlineWorkers(), 1); var packDepth_default = "/**\n * Packs a depth value into a vec4 that can be represented by unsigned bytes.\n *\n * @name czm_packDepth\n * @glslFunction\n *\n * @param {float} depth The floating-point depth.\n * @returns {vec4} The packed depth.\n */\nvec4 czm_packDepth(float depth)\n{\n // See Aras Pranckevi\u010Dius' post Encoding Floats to RGBA\n // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/\n vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * depth;\n enc = fract(enc);\n enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n return enc;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/pbrLighting.js var import_InlineWorkers232 = __toESM(require_InlineWorkers(), 1); var pbrLighting_default = "vec3 lambertianDiffuse(vec3 diffuseColor)\n{\n return diffuseColor / czm_pi;\n}\n\nvec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH)\n{\n float versine = 1.0 - VdotH;\n // pow(versine, 5.0) is slow. See https://stackoverflow.com/a/68793086/10082269\n float versineSquared = versine * versine;\n return f0 + (f90 - f0) * versineSquared * versineSquared * versine;\n}\n\n#ifdef USE_ANISOTROPY\n/**\n * @param {float} bitangentRoughness Material roughness (along the anisotropy bitangent)\n * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent)\n * @param {vec3} lightDirection The direction from the fragment to the light source, transformed to tangent-bitangent-normal coordinates\n * @param {vec3} viewDirection The direction from the fragment to the camera, transformed to tangent-bitangent-normal coordinates\n */\nfloat smithVisibilityGGX_anisotropic(float bitangentRoughness, float tangentialRoughness, vec3 lightDirection, vec3 viewDirection)\n{\n vec3 roughnessScale = vec3(tangentialRoughness, bitangentRoughness, 1.0);\n float GGXV = lightDirection.z * length(roughnessScale * viewDirection);\n float GGXL = viewDirection.z * length(roughnessScale * lightDirection);\n float v = 0.5 / (GGXV + GGXL);\n return clamp(v, 0.0, 1.0);\n}\n\n/**\n * @param {float} bitangentRoughness Material roughness (along the anisotropy bitangent)\n * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent)\n * @param {vec3} halfwayDirection The unit vector halfway between light and view directions, transformed to tangent-bitangent-normal coordinates\n */\nfloat GGX_anisotropic(float bitangentRoughness, float tangentialRoughness, vec3 halfwayDirection)\n{\n float roughnessSquared = bitangentRoughness * tangentialRoughness;\n vec3 f = halfwayDirection * vec3(bitangentRoughness, tangentialRoughness, roughnessSquared);\n float w2 = roughnessSquared / dot(f, f);\n return roughnessSquared * w2 * w2 / czm_pi;\n}\n#endif\n\n/**\n * Estimate the geometric self-shadowing of the microfacets in a surface,\n * using the Smith Joint GGX visibility function.\n * Note: Vis = G / (4 * NdotL * NdotV)\n * see Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Techniques, 3\n * see Real-Time Rendering. Page 331 to 336.\n * see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)\n *\n * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n * @param {float} NdotL The cosine of the angle between the surface normal and the direction to the light source.\n * @param {float} NdotV The cosine of the angle between the surface normal and the direction to the camera.\n */\nfloat smithVisibilityGGX(float alphaRoughness, float NdotL, float NdotV)\n{\n float alphaRoughnessSq = alphaRoughness * alphaRoughness;\n\n float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);\n float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);\n\n float GGX = GGXV + GGXL;\n if (GGX > 0.0)\n {\n return 0.5 / GGX;\n }\n return 0.0;\n}\n\n/**\n * Estimate the fraction of the microfacets in a surface that are aligned with \n * the halfway vector, which is aligned halfway between the directions from\n * the fragment to the camera and from the fragment to the light source.\n *\n * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n * @param {float} NdotH The cosine of the angle between the surface normal and the halfway vector.\n * @return {float} The fraction of microfacets aligned to the halfway vector.\n */\nfloat GGX(float alphaRoughness, float NdotH)\n{\n float alphaRoughnessSquared = alphaRoughness * alphaRoughness;\n float f = (NdotH * alphaRoughnessSquared - NdotH) * NdotH + 1.0;\n return alphaRoughnessSquared / (czm_pi * f * f);\n}\n\n/**\n * Compute the strength of the specular reflection due to direct lighting.\n *\n * @param {vec3} normal The surface normal.\n * @param {vec3} lightDirection The unit vector pointing from the fragment to the light source.\n * @param {vec3} viewDirection The unit vector pointing from the fragment to the camera.\n * @param {vec3} halfwayDirection The unit vector pointing from the fragment to halfway between the light source and the camera.\n * @param {float} alphaRoughness The roughness of the material, expressed as the square of perceptual roughness.\n * @return {float} The strength of the specular reflection.\n */\nfloat computeDirectSpecularStrength(vec3 normal, vec3 lightDirection, vec3 viewDirection, vec3 halfwayDirection, float alphaRoughness)\n{\n float NdotL = clamp(dot(normal, lightDirection), 0.0, 1.0);\n float NdotV = clamp(dot(normal, viewDirection), 0.0, 1.0);\n float G = smithVisibilityGGX(alphaRoughness, NdotL, NdotV);\n float NdotH = clamp(dot(normal, halfwayDirection), 0.0, 1.0);\n float D = GGX(alphaRoughness, NdotH);\n return G * D;\n}\n\n/**\n * Compute the diffuse and specular contributions using physically based\n * rendering. This function only handles direct lighting.\n *

\n * This function only handles the lighting calculations. Metallic/roughness\n * and specular/glossy must be handled separately. See {@MaterialStageFS}\n *

\n *\n * @name czm_pbrLighting\n * @glslFunction\n *\n * @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position\n * @param {vec3} normalEC The surface normal in eye coordinates\n * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates.\n * @param {czm_modelMaterial} The material properties.\n * @return {vec3} The computed HDR color\n */\nvec3 czm_pbrLighting(vec3 viewDirectionEC, vec3 normalEC, vec3 lightDirectionEC, czm_modelMaterial material)\n{\n vec3 halfwayDirectionEC = normalize(viewDirectionEC + lightDirectionEC);\n float VdotH = clamp(dot(viewDirectionEC, halfwayDirectionEC), 0.0, 1.0);\n float NdotL = clamp(dot(normalEC, lightDirectionEC), 0.001, 1.0);\n\n vec3 f0 = material.specular;\n float reflectance = czm_maximumComponent(f0);\n // Typical dielectrics will have reflectance 0.04, so f90 will be 1.0.\n // In this case, at grazing angle, all incident energy is reflected.\n vec3 f90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n vec3 F = fresnelSchlick2(f0, f90, VdotH);\n\n #if defined(USE_SPECULAR)\n F *= material.specularWeight;\n #endif\n\n float alphaRoughness = material.roughness * material.roughness;\n #ifdef USE_ANISOTROPY\n mat3 tbn = mat3(material.anisotropicT, material.anisotropicB, normalEC);\n vec3 lightDirection = lightDirectionEC * tbn;\n vec3 viewDirection = viewDirectionEC * tbn;\n vec3 halfwayDirection = halfwayDirectionEC * tbn;\n float anisotropyStrength = material.anisotropyStrength;\n float tangentialRoughness = mix(alphaRoughness, 1.0, anisotropyStrength * anisotropyStrength);\n float bitangentRoughness = clamp(alphaRoughness, 0.001, 1.0);\n float G = smithVisibilityGGX_anisotropic(bitangentRoughness, tangentialRoughness, lightDirection, viewDirection);\n float D = GGX_anisotropic(bitangentRoughness, tangentialRoughness, halfwayDirection);\n vec3 specularContribution = F * G * D;\n #else\n float specularStrength = computeDirectSpecularStrength(normalEC, lightDirectionEC, viewDirectionEC, halfwayDirectionEC, alphaRoughness);\n vec3 specularContribution = F * specularStrength;\n #endif\n\n vec3 diffuseColor = material.diffuse;\n // F here represents the specular contribution\n vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(diffuseColor);\n\n // Lo = (diffuse + specular) * Li * NdotL\n return (diffuseContribution + specularContribution) * NdotL;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/pbrNeutralTonemapping.js var import_InlineWorkers233 = __toESM(require_InlineWorkers(), 1); var pbrNeutralTonemapping_default = "// KhronosGroup https://github.com/KhronosGroup/ToneMapping/tree/main/PBR_Neutral\n\n// Input color is non-negative and resides in the Linear Rec. 709 color space.\n// Output color is also Linear Rec. 709, but in the [0, 1] range.\n\nvec3 czm_pbrNeutralTonemapping(vec3 color) {\n const float startCompression = 0.8 - 0.04;\n const float desaturation = 0.15;\n\n float x = min(color.r, min(color.g, color.b));\n float offset = czm_branchFreeTernary(x < 0.08, x - 6.25 * x * x, 0.04);\n color -= offset;\n\n float peak = max(color.r, max(color.g, color.b));\n if (peak < startCompression) return color;\n\n const float d = 1.0 - startCompression;\n float newPeak = 1.0 - d * d / (peak + d - startCompression);\n color *= newPeak / peak;\n\n float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);\n return mix(color, newPeak * vec3(1.0, 1.0, 1.0), g);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/phong.js var import_InlineWorkers234 = __toESM(require_InlineWorkers(), 1); var phong_default = "float czm_private_getLambertDiffuseOfMaterial(vec3 lightDirectionEC, czm_material material)\n{\n return czm_getLambertDiffuse(lightDirectionEC, material.normal);\n}\n\nfloat czm_private_getSpecularOfMaterial(vec3 lightDirectionEC, vec3 toEyeEC, czm_material material)\n{\n return czm_getSpecular(lightDirectionEC, toEyeEC, material.normal, material.shininess);\n}\n\n/**\n * Computes a color using the Phong lighting model.\n *\n * @name czm_phong\n * @glslFunction\n *\n * @param {vec3} toEye A normalized vector from the fragment to the eye in eye coordinates.\n * @param {czm_material} material The fragment's material.\n *\n * @returns {vec4} The computed color.\n *\n * @example\n * vec3 positionToEyeEC = // ...\n * czm_material material = // ...\n * vec3 lightDirectionEC = // ...\n * out_FragColor = czm_phong(normalize(positionToEyeEC), material, lightDirectionEC);\n *\n * @see czm_getMaterial\n */\nvec4 czm_phong(vec3 toEye, czm_material material, vec3 lightDirectionEC)\n{\n // Diffuse from directional light sources at eye (for top-down)\n float diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);\n if (czm_sceneMode == czm_sceneMode3D) {\n // (and horizon views in 3D)\n diffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);\n }\n\n float specular = czm_private_getSpecularOfMaterial(lightDirectionEC, toEye, material);\n\n // Temporary workaround for adding ambient.\n vec3 materialDiffuse = material.diffuse * 0.5;\n\n vec3 ambient = materialDiffuse;\n vec3 color = ambient + material.emission;\n color += materialDiffuse * diffuse * czm_lightColor;\n color += material.specular * specular * czm_lightColor;\n\n return vec4(color, material.alpha);\n}\n\nvec4 czm_private_phong(vec3 toEye, czm_material material, vec3 lightDirectionEC)\n{\n float diffuse = czm_private_getLambertDiffuseOfMaterial(lightDirectionEC, material);\n float specular = czm_private_getSpecularOfMaterial(lightDirectionEC, toEye, material);\n\n vec3 ambient = vec3(0.0);\n vec3 color = ambient + material.emission;\n color += material.diffuse * diffuse * czm_lightColor;\n color += material.specular * specular * czm_lightColor;\n\n return vec4(color, material.alpha);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/planeDistance.js var import_InlineWorkers235 = __toESM(require_InlineWorkers(), 1); var planeDistance_default = "/**\n * Computes distance from a point to a plane.\n *\n * @name czm_planeDistance\n * @glslFunction\n *\n * param {vec4} plane A Plane in Hessian Normal Form. See Plane.js\n * param {vec3} point A point in the same space as the plane.\n * returns {float} The distance from the point to the plane.\n */\nfloat czm_planeDistance(vec4 plane, vec3 point) {\n return (dot(plane.xyz, point) + plane.w);\n}\n\n/**\n * Computes distance from a point to a plane.\n *\n * @name czm_planeDistance\n * @glslFunction\n *\n * param {vec3} planeNormal Normal for a plane in Hessian Normal Form. See Plane.js\n * param {float} planeDistance Distance for a plane in Hessian Normal form. See Plane.js\n * param {vec3} point A point in the same space as the plane.\n * returns {float} The distance from the point to the plane.\n */\nfloat czm_planeDistance(vec3 planeNormal, float planeDistance, vec3 point) {\n return (dot(planeNormal, point) + planeDistance);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/pointAlongRay.js var import_InlineWorkers236 = __toESM(require_InlineWorkers(), 1); var pointAlongRay_default = "/**\n * Computes the point along a ray at the given time. time can be positive, negative, or zero.\n *\n * @name czm_pointAlongRay\n * @glslFunction\n *\n * @param {czm_ray} ray The ray to compute the point along.\n * @param {float} time The time along the ray.\n * \n * @returns {vec3} The point along the ray at the given time.\n * \n * @example\n * czm_ray ray = czm_ray(vec3(0.0), vec3(1.0, 0.0, 0.0)); // origin, direction\n * vec3 v = czm_pointAlongRay(ray, 2.0); // (2.0, 0.0, 0.0)\n */\nvec3 czm_pointAlongRay(czm_ray ray, float time)\n{\n return ray.origin + (time * ray.direction);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/rayEllipsoidIntersectionInterval.js var import_InlineWorkers237 = __toESM(require_InlineWorkers(), 1); var rayEllipsoidIntersectionInterval_default = "/**\n * DOC_TBA\n *\n * @name czm_rayEllipsoidIntersectionInterval\n * @glslFunction\n */\nczm_raySegment czm_rayEllipsoidIntersectionInterval(czm_ray ray, vec3 ellipsoid_center, vec3 ellipsoid_inverseRadii)\n{\n // ray and ellipsoid center in eye coordinates. radii in model coordinates.\n vec3 q = ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ray.origin, 1.0)).xyz;\n vec3 w = ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ray.direction, 0.0)).xyz;\n\n q = q - ellipsoid_inverseRadii * (czm_inverseModelView * vec4(ellipsoid_center, 1.0)).xyz;\n\n float q2 = dot(q, q);\n float qw = dot(q, w);\n\n if (q2 > 1.0) // Outside ellipsoid.\n {\n if (qw >= 0.0) // Looking outward or tangent (0 intersections).\n {\n return czm_emptyRaySegment;\n }\n else // qw < 0.0.\n {\n float qw2 = qw * qw;\n float difference = q2 - 1.0; // Positively valued.\n float w2 = dot(w, w);\n float product = w2 * difference;\n\n if (qw2 < product) // Imaginary roots (0 intersections).\n {\n return czm_emptyRaySegment;\n }\n else if (qw2 > product) // Distinct roots (2 intersections).\n {\n float discriminant = qw * qw - product;\n float temp = -qw + sqrt(discriminant); // Avoid cancellation.\n float root0 = temp / w2;\n float root1 = difference / temp;\n if (root0 < root1)\n {\n czm_raySegment i = czm_raySegment(root0, root1);\n return i;\n }\n else\n {\n czm_raySegment i = czm_raySegment(root1, root0);\n return i;\n }\n }\n else // qw2 == product. Repeated roots (2 intersections).\n {\n float root = sqrt(difference / w2);\n czm_raySegment i = czm_raySegment(root, root);\n return i;\n }\n }\n }\n else if (q2 < 1.0) // Inside ellipsoid (2 intersections).\n {\n float difference = q2 - 1.0; // Negatively valued.\n float w2 = dot(w, w);\n float product = w2 * difference; // Negatively valued.\n float discriminant = qw * qw - product;\n float temp = -qw + sqrt(discriminant); // Positively valued.\n czm_raySegment i = czm_raySegment(0.0, temp / w2);\n return i;\n }\n else // q2 == 1.0. On ellipsoid.\n {\n if (qw < 0.0) // Looking inward.\n {\n float w2 = dot(w, w);\n czm_raySegment i = czm_raySegment(0.0, -qw / w2);\n return i;\n }\n else // qw >= 0.0. Looking outward or tangent.\n {\n return czm_emptyRaySegment;\n }\n }\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/raySphereIntersectionInterval.js var import_InlineWorkers238 = __toESM(require_InlineWorkers(), 1); var raySphereIntersectionInterval_default = "/**\n * Compute the intersection interval of a ray with a sphere.\n *\n * @name czm_raySphereIntersectionInterval\n * @glslFunction\n *\n * @param {czm_ray} ray The ray.\n * @param {vec3} center The center of the sphere.\n * @param {float} radius The radius of the sphere.\n * @return {czm_raySegment} The intersection interval of the ray with the sphere.\n */\nczm_raySegment czm_raySphereIntersectionInterval(czm_ray ray, vec3 center, float radius)\n{\n vec3 o = ray.origin;\n vec3 d = ray.direction;\n\n vec3 oc = o - center;\n\n float a = dot(d, d);\n float b = 2.0 * dot(d, oc);\n float c = dot(oc, oc) - (radius * radius);\n\n float det = (b * b) - (4.0 * a * c);\n\n if (det < 0.0) {\n return czm_emptyRaySegment;\n }\n\n float sqrtDet = sqrt(det);\n\n float t0 = (-b - sqrtDet) / (2.0 * a);\n float t1 = (-b + sqrtDet) / (2.0 * a);\n\n czm_raySegment result = czm_raySegment(t0, t1);\n return result;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/readDepth.js var import_InlineWorkers239 = __toESM(require_InlineWorkers(), 1); var readDepth_default = "float czm_readDepth(sampler2D depthTexture, vec2 texCoords)\n{\n return czm_reverseLogDepth(texture(depthTexture, texCoords).r);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/readNonPerspective.js var import_InlineWorkers240 = __toESM(require_InlineWorkers(), 1); var readNonPerspective_default = "/**\n * Reads a value previously transformed with {@link czm_writeNonPerspective}\n * by dividing it by `w`, the value used in the perspective divide.\n * This function is intended to be called in a fragment shader to access a\n * `varying` that should not be subject to perspective interpolation.\n * For example, screen-space texture coordinates. The value should have been\n * previously written in the vertex shader with a call to\n * {@link czm_writeNonPerspective}.\n *\n * @name czm_readNonPerspective\n * @glslFunction\n *\n * @param {float|vec2|vec3|vec4} value The non-perspective value to be read.\n * @param {float} oneOverW One over the perspective divide value, `w`. Usually this is simply `gl_FragCoord.w`.\n * @returns {float|vec2|vec3|vec4} The usable value.\n */\nfloat czm_readNonPerspective(float value, float oneOverW) {\n return value * oneOverW;\n}\n\nvec2 czm_readNonPerspective(vec2 value, float oneOverW) {\n return value * oneOverW;\n}\n\nvec3 czm_readNonPerspective(vec3 value, float oneOverW) {\n return value * oneOverW;\n}\n\nvec4 czm_readNonPerspective(vec4 value, float oneOverW) {\n return value * oneOverW;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/reverseLogDepth.js var import_InlineWorkers241 = __toESM(require_InlineWorkers(), 1); var reverseLogDepth_default = "float czm_reverseLogDepth(float logZ)\n{\n#ifdef LOG_DEPTH\n float near = czm_currentFrustum.x;\n float far = czm_currentFrustum.y;\n float log2Depth = logZ * czm_log2FarDepthFromNearPlusOne;\n float depthFromNear = exp2(log2Depth) - 1.0;\n return far * (1.0 - near / (depthFromNear + near)) / (far - near);\n#endif\n return logZ;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/round.js var import_InlineWorkers242 = __toESM(require_InlineWorkers(), 1); var round_default = "/**\n * Round a floating point value. This function exists because round() doesn't\n * exist in GLSL 1.00. \n *\n * @param {float|vec2|vec3|vec4} value The value to round\n * @param {float|vec2|vec3|vec3} The rounded value. The type matches the input.\n */\nfloat czm_round(float value) {\n return floor(value + 0.5);\n}\n\nvec2 czm_round(vec2 value) {\n return floor(value + 0.5);\n}\n\nvec3 czm_round(vec3 value) {\n return floor(value + 0.5);\n}\n\nvec4 czm_round(vec4 value) {\n return floor(value + 0.5);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/saturation.js var import_InlineWorkers243 = __toESM(require_InlineWorkers(), 1); var saturation_default = "/**\n * Adjusts the saturation of a color.\n * \n * @name czm_saturation\n * @glslFunction\n * \n * @param {vec3} rgb The color.\n * @param {float} adjustment The amount to adjust the saturation of the color.\n *\n * @returns {float} The color with the saturation adjusted.\n *\n * @example\n * vec3 greyScale = czm_saturation(color, 0.0);\n * vec3 doubleSaturation = czm_saturation(color, 2.0);\n */\nvec3 czm_saturation(vec3 rgb, float adjustment)\n{\n // Algorithm from Chapter 16 of OpenGL Shading Language\n const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n vec3 intensity = vec3(dot(rgb, W));\n return mix(intensity, rgb, adjustment);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/shadowDepthCompare.js var import_InlineWorkers244 = __toESM(require_InlineWorkers(), 1); var shadowDepthCompare_default = "\nfloat czm_sampleShadowMap(highp samplerCube shadowMap, vec3 d)\n{\n return czm_unpackDepth(czm_textureCube(shadowMap, d));\n}\n\nfloat czm_sampleShadowMap(highp sampler2D shadowMap, vec2 uv)\n{\n#ifdef USE_SHADOW_DEPTH_TEXTURE\n return texture(shadowMap, uv).r;\n#else\n return czm_unpackDepth(texture(shadowMap, uv));\n#endif\n}\n\nfloat czm_shadowDepthCompare(samplerCube shadowMap, vec3 uv, float depth)\n{\n return step(depth, czm_sampleShadowMap(shadowMap, uv));\n}\n\nfloat czm_shadowDepthCompare(sampler2D shadowMap, vec2 uv, float depth)\n{\n return step(depth, czm_sampleShadowMap(shadowMap, uv));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/shadowVisibility.js var import_InlineWorkers245 = __toESM(require_InlineWorkers(), 1); var shadowVisibility_default = "\nfloat czm_private_shadowVisibility(float visibility, float nDotL, float normalShadingSmooth, float darkness)\n{\n#ifdef USE_NORMAL_SHADING\n#ifdef USE_NORMAL_SHADING_SMOOTH\n float strength = clamp(nDotL / normalShadingSmooth, 0.0, 1.0);\n#else\n float strength = step(0.0, nDotL);\n#endif\n visibility *= strength;\n#endif\n\n visibility = max(visibility, darkness);\n return visibility;\n}\n\n#ifdef USE_CUBE_MAP_SHADOW\nfloat czm_shadowVisibility(samplerCube shadowMap, czm_shadowParameters shadowParameters)\n{\n float depthBias = shadowParameters.depthBias;\n float depth = shadowParameters.depth;\n float nDotL = shadowParameters.nDotL;\n float normalShadingSmooth = shadowParameters.normalShadingSmooth;\n float darkness = shadowParameters.darkness;\n vec3 uvw = shadowParameters.texCoords;\n\n depth -= depthBias;\n float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);\n return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);\n}\n#else\nfloat czm_shadowVisibility(sampler2D shadowMap, czm_shadowParameters shadowParameters)\n{\n float depthBias = shadowParameters.depthBias;\n float depth = shadowParameters.depth;\n float nDotL = shadowParameters.nDotL;\n float normalShadingSmooth = shadowParameters.normalShadingSmooth;\n float darkness = shadowParameters.darkness;\n vec2 uv = shadowParameters.texCoords;\n\n depth -= depthBias;\n#ifdef USE_SOFT_SHADOWS\n vec2 texelStepSize = shadowParameters.texelStepSize;\n float radius = 1.0;\n float dx0 = -texelStepSize.x * radius;\n float dy0 = -texelStepSize.y * radius;\n float dx1 = texelStepSize.x * radius;\n float dy1 = texelStepSize.y * radius;\n float visibility = (\n czm_shadowDepthCompare(shadowMap, uv, depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy0), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy0), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy0), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, 0.0), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, 0.0), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy1), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy1), depth) +\n czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy1), depth)\n ) * (1.0 / 9.0);\n#else\n float visibility = czm_shadowDepthCompare(shadowMap, uv, depth);\n#endif\n\n return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);\n}\n#endif\n"; // packages/engine/Source/Shaders/Builtin/Functions/signNotZero.js var import_InlineWorkers246 = __toESM(require_InlineWorkers(), 1); var signNotZero_default = "/**\n * Returns 1.0 if the given value is positive or zero, and -1.0 if it is negative. This is similar to the GLSL\n * built-in function sign except that returns 1.0 instead of 0.0 when the input value is 0.0.\n * \n * @name czm_signNotZero\n * @glslFunction\n *\n * @param {} value The value for which to determine the sign.\n * @returns {} 1.0 if the value is positive or zero, -1.0 if the value is negative.\n */\nfloat czm_signNotZero(float value)\n{\n return value >= 0.0 ? 1.0 : -1.0;\n}\n\nvec2 czm_signNotZero(vec2 value)\n{\n return vec2(czm_signNotZero(value.x), czm_signNotZero(value.y));\n}\n\nvec3 czm_signNotZero(vec3 value)\n{\n return vec3(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z));\n}\n\nvec4 czm_signNotZero(vec4 value)\n{\n return vec4(czm_signNotZero(value.x), czm_signNotZero(value.y), czm_signNotZero(value.z), czm_signNotZero(value.w));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/sphericalHarmonics.js var import_InlineWorkers247 = __toESM(require_InlineWorkers(), 1); var sphericalHarmonics_default = "/**\n * Computes a color from the third order spherical harmonic coefficients and a normalized direction vector.\n *

\n * The order of the coefficients is [L00, L1_1, L10, L11, L2_2, L2_1, L20, L21, L22].\n *

\n *\n * @name czm_sphericalHarmonics\n * @glslFunction\n *\n * @param {vec3} normal The normalized direction.\n * @param {vec3[9]} coefficients The third order spherical harmonic coefficients.\n * @returns {vec3} The color at the direction.\n *\n * @see https://graphics.stanford.edu/papers/envmap/envmap.pdf\n */\nvec3 czm_sphericalHarmonics(vec3 normal, vec3 coefficients[9])\n{\n vec3 L00 = coefficients[0];\n vec3 L1_1 = coefficients[1];\n vec3 L10 = coefficients[2];\n vec3 L11 = coefficients[3];\n vec3 L2_2 = coefficients[4];\n vec3 L2_1 = coefficients[5];\n vec3 L20 = coefficients[6];\n vec3 L21 = coefficients[7];\n vec3 L22 = coefficients[8];\n\n float x = normal.x;\n float y = normal.y;\n float z = normal.z;\n\n vec3 L =\n L00\n + L1_1 * y\n + L10 * z\n + L11 * x\n + L2_2 * (y * x)\n + L2_1 * (y * z)\n + L20 * (3.0 * z * z - 1.0)\n + L21 * (z * x)\n + L22 * (x * x - y * y);\n \n return max(L, vec3(0.0));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/srgbToLinear.js var import_InlineWorkers248 = __toESM(require_InlineWorkers(), 1); var srgbToLinear_default = "/**\n * Converts an sRGB color to a linear RGB color.\n *\n * @param {vec3|vec4} srgbIn The color in sRGB space\n * @returns {vec3|vec4} The color in linear color space. The vector type matches the input.\n */\nvec3 czm_srgbToLinear(vec3 srgbIn)\n{\n return pow(srgbIn, vec3(2.2));\n}\n\nvec4 czm_srgbToLinear(vec4 srgbIn) \n{\n vec3 linearOut = pow(srgbIn.rgb, vec3(2.2));\n return vec4(linearOut, srgbIn.a);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/tangentToEyeSpaceMatrix.js var import_InlineWorkers249 = __toESM(require_InlineWorkers(), 1); var tangentToEyeSpaceMatrix_default = "/**\n * Creates a matrix that transforms vectors from tangent space to eye space.\n *\n * @name czm_tangentToEyeSpaceMatrix\n * @glslFunction\n *\n * @param {vec3} normalEC The normal vector in eye coordinates.\n * @param {vec3} tangentEC The tangent vector in eye coordinates.\n * @param {vec3} bitangentEC The bitangent vector in eye coordinates.\n *\n * @returns {mat3} The matrix that transforms from tangent space to eye space.\n *\n * @example\n * mat3 tangentToEye = czm_tangentToEyeSpaceMatrix(normalEC, tangentEC, bitangentEC);\n * vec3 normal = tangentToEye * texture(normalMap, st).xyz;\n */\nmat3 czm_tangentToEyeSpaceMatrix(vec3 normalEC, vec3 tangentEC, vec3 bitangentEC)\n{\n vec3 normal = normalize(normalEC);\n vec3 tangent = normalize(tangentEC);\n vec3 bitangent = normalize(bitangentEC);\n return mat3(tangent.x , tangent.y , tangent.z,\n bitangent.x, bitangent.y, bitangent.z,\n normal.x , normal.y , normal.z);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/textureCube.js var import_InlineWorkers250 = __toESM(require_InlineWorkers(), 1); var textureCube_default = "/**\n * A wrapper around the texture (WebGL2) / textureCube (WebGL1)\n * function to allow for WebGL 1 support.\n * \n * @name czm_textureCube\n * @glslFunction\n *\n * @param {samplerCube} sampler The sampler.\n * @param {vec3} p The coordinate at which to sample the texture.\n */\nvec4 czm_textureCube(samplerCube sampler, vec3 p) {\n#if __VERSION__ == 300\n return texture(sampler, p);\n#else\n return textureCube(sampler, p);\n#endif\n}\n\n/**\n * A wrapper around the textureLod (WebGL2) / textureCube (WebGL1)\n * function to allow for WebGL 1 support in fragment shaders.\n *\n * @name czm_textureCubeLod\n * @glslFunction\n *\n * @param {samplerCube} sampler The sampler.\n * @param {vec3} p The coordinate at which to sample the texture.\n * @param {float} lod The mipmap level from which to sample.\n */\nvec4 czm_textureCube(samplerCube sampler, vec3 p, float lod) {\n#if __VERSION__ == 300\n return textureLod(sampler, p, lod);\n#elif defined(GL_EXT_shader_texture_lod)\n return textureCubeLodEXT(sampler, p, lod);\n#endif\n}"; // packages/engine/Source/Shaders/Builtin/Functions/transformPlane.js var import_InlineWorkers251 = __toESM(require_InlineWorkers(), 1); var transformPlane_default = "/**\n * Transforms a plane.\n * \n * @name czm_transformPlane\n * @glslFunction\n *\n * @param {vec4} plane The plane in Hessian Normal Form.\n * @param {mat4} transform The inverse-transpose of a transformation matrix.\n */\nvec4 czm_transformPlane(vec4 plane, mat4 transform) {\n vec4 transformedPlane = transform * plane;\n // Convert the transformed plane to Hessian Normal Form\n float normalMagnitude = length(transformedPlane.xyz);\n return transformedPlane / normalMagnitude;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/translateRelativeToEye.js var import_InlineWorkers252 = __toESM(require_InlineWorkers(), 1); var translateRelativeToEye_default = "/**\n * Translates a position (or any vec3) that was encoded with {@link EncodedCartesian3},\n * and then provided to the shader as separate high and low bits to\n * be relative to the eye. As shown in the example, the position can then be transformed in eye\n * or clip coordinates using {@link czm_modelViewRelativeToEye} or {@link czm_modelViewProjectionRelativeToEye},\n * respectively.\n *

\n * This technique, called GPU RTE, eliminates jittering artifacts when using large coordinates as\n * described in {@link http://help.agi.com/AGIComponents/html/BlogPrecisionsPrecisions.htm|Precisions, Precisions}.\n *

\n *\n * @name czm_translateRelativeToEye\n * @glslFunction\n *\n * @param {vec3} high The position's high bits.\n * @param {vec3} low The position's low bits.\n * @returns {vec3} The position translated to be relative to the camera's position.\n *\n * @example\n * in vec3 positionHigh;\n * in vec3 positionLow;\n *\n * void main()\n * {\n * vec4 p = czm_translateRelativeToEye(positionHigh, positionLow);\n * gl_Position = czm_modelViewProjectionRelativeToEye * p;\n * }\n *\n * @see czm_modelViewRelativeToEye\n * @see czm_modelViewProjectionRelativeToEye\n * @see czm_computePosition\n * @see EncodedCartesian3\n */\nvec4 czm_translateRelativeToEye(vec3 high, vec3 low)\n{\n vec3 highDifference = high - czm_encodedCameraPositionMCHigh;\n // This check handles the case when NaN values have gotten into `highDifference`.\n // Such a thing could happen on devices running iOS.\n if (length(highDifference) == 0.0) { \n highDifference = vec3(0); \n }\n vec3 lowDifference = low - czm_encodedCameraPositionMCLow;\n\n return vec4(highDifference + lowDifference, 1.0);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/translucentPhong.js var import_InlineWorkers253 = __toESM(require_InlineWorkers(), 1); var translucentPhong_default = "/**\n * @private\n */\nvec4 czm_translucentPhong(vec3 toEye, czm_material material, vec3 lightDirectionEC)\n{\n // Diffuse from directional light sources at eye (for top-down and horizon views)\n float diffuse = czm_getLambertDiffuse(vec3(0.0, 0.0, 1.0), material.normal);\n\n if (czm_sceneMode == czm_sceneMode3D) {\n // (and horizon views in 3D)\n diffuse += czm_getLambertDiffuse(vec3(0.0, 1.0, 0.0), material.normal);\n }\n\n diffuse = clamp(diffuse, 0.0, 1.0);\n\n float specular = czm_getSpecular(lightDirectionEC, toEye, material.normal, material.shininess);\n\n // Temporary workaround for adding ambient.\n vec3 materialDiffuse = material.diffuse * 0.5;\n\n vec3 ambient = materialDiffuse;\n vec3 color = ambient + material.emission;\n color += materialDiffuse * diffuse * czm_lightColor;\n color += material.specular * specular * czm_lightColor;\n\n return vec4(color, material.alpha);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/transpose.js var import_InlineWorkers254 = __toESM(require_InlineWorkers(), 1); var transpose_default = "/**\n * Returns the transpose of the matrix. The input matrix can be\n * a mat2, mat3, or mat4.\n *\n * @name czm_transpose\n * @glslFunction\n *\n * @param {} matrix The matrix to transpose.\n *\n * @returns {} The transposed matrix.\n *\n * @example\n * // GLSL declarations\n * mat2 czm_transpose(mat2 matrix);\n * mat3 czm_transpose(mat3 matrix);\n * mat4 czm_transpose(mat4 matrix);\n *\n * // Transpose a 3x3 rotation matrix to find its inverse.\n * mat3 eastNorthUpToEye = czm_eastNorthUpToEyeCoordinates(\n * positionMC, normalEC);\n * mat3 eyeToEastNorthUp = czm_transpose(eastNorthUpToEye);\n */\nmat2 czm_transpose(mat2 matrix)\n{\n return mat2(\n matrix[0][0], matrix[1][0],\n matrix[0][1], matrix[1][1]);\n}\n\nmat3 czm_transpose(mat3 matrix)\n{\n return mat3(\n matrix[0][0], matrix[1][0], matrix[2][0],\n matrix[0][1], matrix[1][1], matrix[2][1],\n matrix[0][2], matrix[1][2], matrix[2][2]);\n}\n\nmat4 czm_transpose(mat4 matrix)\n{\n return mat4(\n matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],\n matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],\n matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],\n matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/unpackClippingExtents.js var import_InlineWorkers255 = __toESM(require_InlineWorkers(), 1); var unpackClippingExtents_default = "vec2 getLookupUv(vec2 dimensions, int i) {\n int pixY = i / int(dimensions.x);\n int pixX = i - (pixY * int(dimensions.x));\n float pixelWidth = 1.0 / dimensions.x;\n float pixelHeight = 1.0 / dimensions.y;\n float u = (float(pixX) + 0.5) * pixelWidth; // sample from center of pixel\n float v = (float(pixY) + 0.5) * pixelHeight;\n return vec2(u, v);\n}\n\nvec4 czm_unpackClippingExtents(highp sampler2D extentsTexture, int index) {\n vec2 textureDimensions = vec2(textureSize(extentsTexture, 0));\n return texture(extentsTexture, getLookupUv(textureDimensions, index));\n}"; // packages/engine/Source/Shaders/Builtin/Functions/unpackDepth.js var import_InlineWorkers256 = __toESM(require_InlineWorkers(), 1); var unpackDepth_default = "/**\n * Unpacks a vec4 depth value to a float in [0, 1) range.\n *\n * @name czm_unpackDepth\n * @glslFunction\n *\n * @param {vec4} packedDepth The packed depth.\n *\n * @returns {float} The floating-point depth in [0, 1) range.\n */\nfloat czm_unpackDepth(vec4 packedDepth)\n{\n // See Aras Pranckevi\u010Dius' post Encoding Floats to RGBA\n // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/\n return dot(packedDepth, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/unpackFloat.js var import_InlineWorkers257 = __toESM(require_InlineWorkers(), 1); var unpackFloat_default = "/**\n * Unpack an IEEE 754 single-precision float that is packed as a little-endian unsigned normalized vec4.\n *\n * @name czm_unpackFloat\n * @glslFunction\n *\n * @param {vec4} packedFloat The packed float.\n *\n * @returns {float} The floating-point depth in arbitrary range.\n */\nfloat czm_unpackFloat(vec4 packedFloat)\n{\n // Convert to [0.0, 255.0] and round to integer\n packedFloat = floor(packedFloat * 255.0 + 0.5);\n float sign = 1.0 - step(128.0, packedFloat[3]) * 2.0;\n float exponent = 2.0 * mod(packedFloat[3], 128.0) + step(128.0, packedFloat[2]) - 127.0; \n if (exponent == -127.0)\n {\n return 0.0;\n }\n float mantissa = mod(packedFloat[2], 128.0) * 65536.0 + packedFloat[1] * 256.0 + packedFloat[0] + float(0x800000);\n float result = sign * exp2(exponent - 23.0) * mantissa;\n return result;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/unpackTexture.js var import_InlineWorkers258 = __toESM(require_InlineWorkers(), 1); var unpackTexture_default = "/**\n * Useful for reinterpreting texture data as higher-precision values.\n * Only works correctly in WebGL 2, which supports the uint type and bitwise operations.\n *\n * @param {float|vec2|vec3|vec4} 1-4 values from a texture lookup (RGBA channels), normalized to [0.0, 1.0].\n * @return {uint} Raw bits as an unsigned integer.\n*/\nuint czm_unpackTexture(float packedValue) {\n float rounded = czm_round(packedValue * 255.0);\n return uint(rounded);\n}\n\nuint czm_unpackTexture(vec2 packedValue) {\n vec2 rounded = czm_round(packedValue * 255.0);\n uint byte0 = uint(rounded.x);\n uint byte1 = uint(rounded.y);\n return byte0 | (byte1 << 8);\n}\n\nuint czm_unpackTexture(vec3 packedValue) {\n vec3 rounded = czm_round(packedValue * 255.0);\n uint byte0 = uint(rounded.x);\n uint byte1 = uint(rounded.y);\n uint byte2 = uint(rounded.z);\n return byte0 | (byte1 << 8) | (byte2 << 16);\n}\n\nuint czm_unpackTexture(vec4 packedValue) {\n vec4 rounded = czm_round(packedValue * 255.0);\n uint byte0 = uint(rounded.x);\n uint byte1 = uint(rounded.y);\n uint byte2 = uint(rounded.z);\n uint byte3 = uint(rounded.w);\n return byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/unpackUint.js var import_InlineWorkers259 = __toESM(require_InlineWorkers(), 1); var unpackUint_default = "/**\n * Unpack unsigned integers of 1-4 bytes. in WebGL 1, there is no uint type,\n * so the return value is an int.\n *

\n * There are also precision limitations in WebGL 1. highp int is still limited\n * to 24 bits. Above the value of 2^24 = 16777216, precision loss may occur.\n *

\n *\n * @param {float|vec2|vec3|vec4} packed The packed value. For vectors, the components are listed in little-endian order.\n *\n * @return {int} The unpacked value.\n */\n int czm_unpackUint(float packedValue) {\n float rounded = czm_round(packedValue * 255.0);\n return int(rounded);\n }\n\n int czm_unpackUint(vec2 packedValue) {\n vec2 rounded = czm_round(packedValue * 255.0);\n return int(dot(rounded, vec2(1.0, 256.0)));\n }\n\n int czm_unpackUint(vec3 packedValue) {\n vec3 rounded = czm_round(packedValue * 255.0);\n return int(dot(rounded, vec3(1.0, 256.0, 65536.0)));\n }\n\n int czm_unpackUint(vec4 packedValue) {\n vec4 rounded = czm_round(packedValue * 255.0);\n return int(dot(rounded, vec4(1.0, 256.0, 65536.0, 16777216.0)));\n }\n"; // packages/engine/Source/Shaders/Builtin/Functions/valueTransform.js var import_InlineWorkers260 = __toESM(require_InlineWorkers(), 1); var valueTransform_default = "/**\n * Transform metadata values following the EXT_structural_metadata spec\n * by multiplying by scale and adding the offset. Operations are always\n * performed component-wise, even for matrices.\n * \n * @param {float|vec2|vec3|vec4|mat2|mat3|mat4} offset The offset to add\n * @param {float|vec2|vec3|vec4|mat2|mat3|mat4} scale The scale factor to multiply\n * @param {float|vec2|vec3|vec4|mat2|mat3|mat4} value The original value.\n *\n * @return {float|vec2|vec3|vec4|mat2|mat3|mat4} The transformed value of the same scalar/vector/matrix type as the input.\n */\nfloat czm_valueTransform(float offset, float scale, float value) {\n return scale * value + offset;\n}\n\nvec2 czm_valueTransform(vec2 offset, vec2 scale, vec2 value) {\n return scale * value + offset;\n}\n\nvec3 czm_valueTransform(vec3 offset, vec3 scale, vec3 value) {\n return scale * value + offset;\n}\n\nvec4 czm_valueTransform(vec4 offset, vec4 scale, vec4 value) {\n return scale * value + offset;\n}\n\nmat2 czm_valueTransform(mat2 offset, mat2 scale, mat2 value) {\n return matrixCompMult(scale, value) + offset;\n}\n\nmat3 czm_valueTransform(mat3 offset, mat3 scale, mat3 value) {\n return matrixCompMult(scale, value) + offset;\n}\n\nmat4 czm_valueTransform(mat4 offset, mat4 scale, mat4 value) {\n return matrixCompMult(scale, value) + offset;\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/vertexLogDepth.js var import_InlineWorkers261 = __toESM(require_InlineWorkers(), 1); var vertexLogDepth_default = "#ifdef LOG_DEPTH\n// 1.0 at the near plane, increasing linearly from there.\nout float v_depthFromNearPlusOne;\n#ifdef SHADOW_MAP\nout vec3 v_logPositionEC;\n#endif\n#endif\n\nvec4 czm_updatePositionDepth(vec4 coords) {\n#if defined(LOG_DEPTH)\n\n#ifdef SHADOW_MAP\n vec3 logPositionEC = (czm_inverseProjection * coords).xyz;\n v_logPositionEC = logPositionEC;\n#endif\n\n // With the very high far/near ratios used with the logarithmic depth\n // buffer, floating point rounding errors can cause linear depth values\n // to end up on the wrong side of the far plane, even for vertices that\n // are really nowhere near it. Since we always write a correct logarithmic\n // depth value in the fragment shader anyway, we just need to make sure\n // such errors don't cause the primitive to be clipped entirely before\n // we even get to the fragment shader.\n coords.z = clamp(coords.z / coords.w, -1.0, 1.0) * coords.w;\n#endif\n\n return coords;\n}\n\n/**\n * Writes the logarithmic depth to gl_Position using the already computed gl_Position.\n *\n * @name czm_vertexLogDepth\n * @glslFunction\n */\nvoid czm_vertexLogDepth()\n{\n#ifdef LOG_DEPTH\n v_depthFromNearPlusOne = (gl_Position.w - czm_currentFrustum.x) + 1.0;\n gl_Position = czm_updatePositionDepth(gl_Position);\n#endif\n}\n\n/**\n * Writes the logarithmic depth to gl_Position using the provided clip coordinates.\n *

\n * An example use case for this function would be moving the vertex in window coordinates\n * before converting back to clip coordinates. Use the original vertex clip coordinates.\n *

\n * @name czm_vertexLogDepth\n * @glslFunction\n *\n * @param {vec4} clipCoords The vertex in clip coordinates.\n *\n * @example\n * czm_vertexLogDepth(czm_projection * vec4(positionEyeCoordinates, 1.0));\n */\nvoid czm_vertexLogDepth(vec4 clipCoords)\n{\n#ifdef LOG_DEPTH\n v_depthFromNearPlusOne = (clipCoords.w - czm_currentFrustum.x) + 1.0;\n czm_updatePositionDepth(clipCoords);\n#endif\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.js var import_InlineWorkers262 = __toESM(require_InlineWorkers(), 1); var windowToEyeCoordinates_default = "vec4 czm_screenToEyeCoordinates(vec4 screenCoordinate)\n{\n // Reconstruct NDC coordinates\n float x = 2.0 * screenCoordinate.x - 1.0;\n float y = 2.0 * screenCoordinate.y - 1.0;\n float z = (screenCoordinate.z - czm_viewportTransformation[3][2]) / czm_viewportTransformation[2][2];\n vec4 q = vec4(x, y, z, 1.0);\n\n // Reverse the perspective division to obtain clip coordinates.\n q /= screenCoordinate.w;\n\n // Reverse the projection transformation to obtain eye coordinates.\n if (!(czm_inverseProjection == mat4(0.0))) // IE and Edge sometimes do something weird with != between mat4s\n {\n q = czm_inverseProjection * q;\n }\n else\n {\n float top = czm_frustumPlanes.x;\n float bottom = czm_frustumPlanes.y;\n float left = czm_frustumPlanes.z;\n float right = czm_frustumPlanes.w;\n\n float near = czm_currentFrustum.x;\n float far = czm_currentFrustum.y;\n\n q.x = (q.x * (right - left) + left + right) * 0.5;\n q.y = (q.y * (top - bottom) + bottom + top) * 0.5;\n q.z = (q.z * (near - far) - near - far) * 0.5;\n q.w = 1.0;\n }\n\n return q;\n}\n\n/**\n * Transforms a position from window to eye coordinates.\n * The transform from window to normalized device coordinates is done using components\n * of (@link czm_viewport} and {@link czm_viewportTransformation} instead of calculating\n * the inverse of czm_viewportTransformation. The transformation from\n * normalized device coordinates to clip coordinates is done using fragmentCoordinate.w,\n * which is expected to be the scalar used in the perspective divide. The transformation\n * from clip to eye coordinates is done using {@link czm_inverseProjection}.\n *\n * @name czm_windowToEyeCoordinates\n * @glslFunction\n *\n * @param {vec4} fragmentCoordinate The position in window coordinates to transform.\n *\n * @returns {vec4} The transformed position in eye coordinates.\n *\n * @see czm_modelToWindowCoordinates\n * @see czm_eyeToWindowCoordinates\n * @see czm_inverseProjection\n * @see czm_viewport\n * @see czm_viewportTransformation\n *\n * @example\n * vec4 positionEC = czm_windowToEyeCoordinates(gl_FragCoord);\n */\nvec4 czm_windowToEyeCoordinates(vec4 fragmentCoordinate)\n{\n vec2 screenCoordXY = (fragmentCoordinate.xy - czm_viewport.xy) / czm_viewport.zw;\n return czm_screenToEyeCoordinates(vec4(screenCoordXY, fragmentCoordinate.zw));\n}\n\nvec4 czm_screenToEyeCoordinates(vec2 screenCoordinateXY, float depthOrLogDepth)\n{\n // See reverseLogDepth.glsl. This is separate to re-use the pow.\n#if defined(LOG_DEPTH) || defined(LOG_DEPTH_READ_ONLY)\n float near = czm_currentFrustum.x;\n float far = czm_currentFrustum.y;\n float log2Depth = depthOrLogDepth * czm_log2FarDepthFromNearPlusOne;\n float depthFromNear = exp2(log2Depth) - 1.0;\n float depthFromCamera = depthFromNear + near;\n vec4 screenCoord = vec4(screenCoordinateXY, far * (1.0 - near / depthFromCamera) / (far - near), 1.0);\n vec4 eyeCoordinate = czm_screenToEyeCoordinates(screenCoord);\n eyeCoordinate.w = 1.0 / depthFromCamera; // Better precision\n#else\n vec4 screenCoord = vec4(screenCoordinateXY, depthOrLogDepth, 1.0);\n vec4 eyeCoordinate = czm_screenToEyeCoordinates(screenCoord);\n#endif\n return eyeCoordinate;\n}\n\n/**\n * Transforms a position given as window x/y and a depth or a log depth from window to eye coordinates.\n * This function produces more accurate results for window positions with log depth than\n * conventionally unpacking the log depth using czm_reverseLogDepth and using the standard version\n * of czm_windowToEyeCoordinates.\n *\n * @name czm_windowToEyeCoordinates\n * @glslFunction\n *\n * @param {vec2} fragmentCoordinateXY The XY position in window coordinates to transform.\n * @param {float} depthOrLogDepth A depth or log depth for the fragment.\n *\n * @see czm_modelToWindowCoordinates\n * @see czm_eyeToWindowCoordinates\n * @see czm_inverseProjection\n * @see czm_viewport\n * @see czm_viewportTransformation\n *\n * @returns {vec4} The transformed position in eye coordinates.\n */\nvec4 czm_windowToEyeCoordinates(vec2 fragmentCoordinateXY, float depthOrLogDepth)\n{\n vec2 screenCoordXY = (fragmentCoordinateXY.xy - czm_viewport.xy) / czm_viewport.zw;\n return czm_screenToEyeCoordinates(screenCoordXY, depthOrLogDepth);\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/writeDepthClamp.js var import_InlineWorkers263 = __toESM(require_InlineWorkers(), 1); var writeDepthClamp_default = "// emulated noperspective\n#if !defined(LOG_DEPTH)\nin float v_WindowZ;\n#endif\n\n/**\n * Emulates GL_DEPTH_CLAMP. Clamps a fragment to the near and far plane\n * by writing the fragment's depth. See czm_depthClamp for more details.\n *\n * @name czm_writeDepthClamp\n * @glslFunction\n *\n * @example\n * out_FragColor = color;\n * czm_writeDepthClamp();\n *\n * @see czm_depthClamp\n */\nvoid czm_writeDepthClamp()\n{\n#if (!defined(LOG_DEPTH) && (__VERSION__ == 300 || defined(GL_EXT_frag_depth)))\n gl_FragDepth = clamp(v_WindowZ * gl_FragCoord.w, 0.0, 1.0);\n#endif\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/writeLogDepth.js var import_InlineWorkers264 = __toESM(require_InlineWorkers(), 1); var writeLogDepth_default = "#ifdef LOG_DEPTH\nin float v_depthFromNearPlusOne;\n\n#ifdef POLYGON_OFFSET\nuniform vec2 u_polygonOffset;\n#endif\n\n#endif\n\n/**\n * Writes the fragment depth to the logarithmic depth buffer.\n *

\n * Use this when the vertex shader does not call {@link czm_vertexLogDepth}, for example, when\n * ray-casting geometry using a full screen quad.\n *

\n * @name czm_writeLogDepth\n * @glslFunction\n *\n * @param {float} depth The depth coordinate, where 1.0 is on the near plane and\n * depth increases in eye-space units from there\n *\n * @example\n * czm_writeLogDepth((czm_projection * v_positionEyeCoordinates).w + 1.0);\n */\nvoid czm_writeLogDepth(float depth)\n{\n#if (defined(LOG_DEPTH) && (__VERSION__ == 300 || defined(GL_EXT_frag_depth)))\n // Discard the vertex if it's not between the near and far planes.\n // We allow a bit of epsilon on the near plane comparison because a 1.0\n // from the vertex shader (indicating the vertex should be _on_ the near\n // plane) will not necessarily come here as exactly 1.0.\n if (depth <= 0.9999999 || depth > czm_farDepthFromNearPlusOne) {\n discard;\n }\n\n#ifdef POLYGON_OFFSET\n // Polygon offset: m * factor + r * units\n float factor = u_polygonOffset[0];\n float units = u_polygonOffset[1];\n\n#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))\n // This factor doesn't work in IE 10\n if (factor != 0.0) {\n // m = sqrt(dZdX^2 + dZdY^2);\n float x = dFdx(depth);\n float y = dFdy(depth);\n float m = sqrt(x * x + y * y);\n\n // Apply the factor before computing the log depth.\n depth += m * factor;\n }\n#endif\n\n#endif\n\n gl_FragDepth = log2(depth) * czm_oneOverLog2FarDepthFromNearPlusOne;\n\n#ifdef POLYGON_OFFSET\n // Apply the units after the log depth.\n gl_FragDepth += czm_epsilon7 * units;\n#endif\n\n#endif\n}\n\n/**\n * Writes the fragment depth to the logarithmic depth buffer.\n *

\n * Use this when the vertex shader calls {@link czm_vertexLogDepth}.\n *

\n *\n * @name czm_writeLogDepth\n * @glslFunction\n */\nvoid czm_writeLogDepth() {\n#ifdef LOG_DEPTH\n czm_writeLogDepth(v_depthFromNearPlusOne);\n#endif\n}\n"; // packages/engine/Source/Shaders/Builtin/Functions/writeNonPerspective.js var import_InlineWorkers265 = __toESM(require_InlineWorkers(), 1); var writeNonPerspective_default = "/**\n * Transforms a value for non-perspective interpolation by multiplying\n * it by w, the value used in the perspective divide. This function is\n * intended to be called in a vertex shader to compute the value of a\n * `varying` that should not be subject to perspective interpolation.\n * For example, screen-space texture coordinates. The fragment shader\n * must call {@link czm_readNonPerspective} to retrieve the final\n * non-perspective value.\n *\n * @name czm_writeNonPerspective\n * @glslFunction\n *\n * @param {float|vec2|vec3|vec4} value The value to be interpolated without accounting for perspective.\n * @param {float} w The perspective divide value. Usually this is the computed `gl_Position.w`.\n * @returns {float|vec2|vec3|vec4} The transformed value, intended to be stored in a `varying` and read in the\n * fragment shader with {@link czm_readNonPerspective}.\n */\nfloat czm_writeNonPerspective(float value, float w) {\n return value * w;\n}\n\nvec2 czm_writeNonPerspective(vec2 value, float w) {\n return value * w;\n}\n\nvec3 czm_writeNonPerspective(vec3 value, float w) {\n return value * w;\n}\n\nvec4 czm_writeNonPerspective(vec4 value, float w) {\n return value * w;\n}\n"; // packages/engine/Source/Shaders/Builtin/CzmBuiltins.js var CzmBuiltins_default = { czm_degreesPerRadian: degreesPerRadian_default, czm_depthRange: depthRange_default, czm_epsilon1: epsilon1_default, czm_epsilon2: epsilon2_default, czm_epsilon3: epsilon3_default, czm_epsilon4: epsilon4_default, czm_epsilon5: epsilon5_default, czm_epsilon6: epsilon6_default, czm_epsilon7: epsilon7_default, czm_infinity: infinity_default, czm_oneOverPi: oneOverPi_default, czm_oneOverTwoPi: oneOverTwoPi_default, czm_passCesium3DTile: passCesium3DTile_default, czm_passCesium3DTileClassification: passCesium3DTileClassification_default, czm_passCesium3DTileClassificationIgnoreShow: passCesium3DTileClassificationIgnoreShow_default, czm_passCesium3DTileEdges: passCesium3DTileEdges_default, czm_passCesium3DTileEdgesDirect: passCesium3DTileEdgesDirect_default, czm_passCesium3DTilePlanarFillId: passCesium3DTilePlanarFillId_default, czm_passClassification: passClassification_default, czm_passCompute: passCompute_default, czm_passEnvironment: passEnvironment_default, czm_passGaussianSplats: passGaussianSplats_default, czm_passGlobe: passGlobe_default, czm_passOpaque: passOpaque_default, czm_passOverlay: passOverlay_default, czm_passTerrainClassification: passTerrainClassification_default, czm_passTranslucent: passTranslucent_default, czm_passVoxels: passVoxels_default, czm_pi: pi_default, czm_piOverFour: piOverFour_default, czm_piOverSix: piOverSix_default, czm_piOverThree: piOverThree_default, czm_piOverTwo: piOverTwo_default, czm_radiansPerDegree: radiansPerDegree_default, czm_sceneMode2D: sceneMode2D_default, czm_sceneMode3D: sceneMode3D_default, czm_sceneModeColumbusView: sceneModeColumbusView_default, czm_sceneModeMorphing: sceneModeMorphing_default, czm_solarRadius: solarRadius_default, czm_threePiOver2: threePiOver2_default, czm_twoPi: twoPi_default, czm_webMercatorMaxLatitude: webMercatorMaxLatitude_default, czm_depthRangeStruct: depthRangeStruct_default, czm_material: material_default, czm_materialInput: materialInput_default, czm_modelMaterial: modelMaterial_default, czm_modelVertexOutput: modelVertexOutput_default, czm_ray: ray_default, czm_raySegment: raySegment_default, czm_shadowParameters: shadowParameters_default, czm_HSBToRGB: HSBToRGB_default, czm_HSLToRGB: HSLToRGB_default, czm_RGBToHSB: RGBToHSB_default, czm_RGBToHSL: RGBToHSL_default, czm_RGBToXYZ: RGBToXYZ_default, czm_XYZToRGB: XYZToRGB_default, czm_acesTonemapping: acesTonemapping_default, czm_alphaWeight: alphaWeight_default, czm_antialias: antialias_default, czm_applyHSBShift: applyHSBShift_default, czm_approximateSphericalCoordinates: approximateSphericalCoordinates_default, czm_approximateTanh: approximateTanh_default, czm_backFacing: backFacing_default, czm_branchFreeTernary: branchFreeTernary_default, czm_cascadeColor: cascadeColor_default, czm_cascadeDistance: cascadeDistance_default, czm_cascadeMatrix: cascadeMatrix_default, czm_cascadeWeights: cascadeWeights_default, czm_clipPolygons: clipPolygons_default, czm_columbusViewMorph: columbusViewMorph_default, czm_computeAtmosphereColor: computeAtmosphereColor_default, czm_computeGroundAtmosphereScattering: computeGroundAtmosphereScattering_default, czm_computePosition: computePosition_default, czm_computeScattering: computeScattering_default, czm_computeTextureTransform: computeTextureTransform_default, czm_cosineAndSine: cosineAndSine_default, czm_decodeRGB8: decodeRGB8_default, czm_decompressTextureCoordinates: decompressTextureCoordinates_default, czm_depthClamp: depthClamp_default, czm_eastNorthUpToEyeCoordinates: eastNorthUpToEyeCoordinates_default, czm_ellipsoidContainsPoint: ellipsoidContainsPoint_default, czm_ellipsoidTextureCoordinates: ellipsoidTextureCoordinates_default, czm_equalsEpsilon: equalsEpsilon_default, czm_eyeOffset: eyeOffset_default, czm_eyeToWindowCoordinates: eyeToWindowCoordinates_default, czm_fastApproximateAtan: fastApproximateAtan_default, czm_fog: fog_default, czm_gammaCorrect: gammaCorrect_default, czm_geodeticSurfaceNormal: geodeticSurfaceNormal_default, czm_getDefaultMaterial: getDefaultMaterial_default, czm_getDynamicAtmosphereLightDirection: getDynamicAtmosphereLightDirection_default, czm_getLambertDiffuse: getLambertDiffuse_default, czm_getSpecular: getSpecular_default, czm_getWaterNoise: getWaterNoise_default, czm_hue: hue_default, czm_inverseGamma: inverseGamma_default, czm_isEmpty: isEmpty_default, czm_isFull: isFull_default, czm_latitudeToWebMercatorFraction: latitudeToWebMercatorFraction_default, czm_lineDistance: lineDistance_default, czm_linearToSrgb: linearToSrgb_default, czm_luminance: luminance_default, czm_maximumComponent: maximumComponent_default, czm_metersPerPixel: metersPerPixel_default, czm_modelToWindowCoordinates: modelToWindowCoordinates_default, czm_multiplyWithColorBalance: multiplyWithColorBalance_default, czm_nearFarScalar: nearFarScalar_default, czm_octDecode: octDecode_default, czm_packDepth: packDepth_default, czm_pbrLighting: pbrLighting_default, czm_pbrNeutralTonemapping: pbrNeutralTonemapping_default, czm_phong: phong_default, czm_planeDistance: planeDistance_default, czm_pointAlongRay: pointAlongRay_default, czm_rayEllipsoidIntersectionInterval: rayEllipsoidIntersectionInterval_default, czm_raySphereIntersectionInterval: raySphereIntersectionInterval_default, czm_readDepth: readDepth_default, czm_readNonPerspective: readNonPerspective_default, czm_reverseLogDepth: reverseLogDepth_default, czm_round: round_default, czm_saturation: saturation_default, czm_shadowDepthCompare: shadowDepthCompare_default, czm_shadowVisibility: shadowVisibility_default, czm_signNotZero: signNotZero_default, czm_sphericalHarmonics: sphericalHarmonics_default, czm_srgbToLinear: srgbToLinear_default, czm_tangentToEyeSpaceMatrix: tangentToEyeSpaceMatrix_default, czm_textureCube: textureCube_default, czm_transformPlane: transformPlane_default, czm_translateRelativeToEye: translateRelativeToEye_default, czm_translucentPhong: translucentPhong_default, czm_transpose: transpose_default, czm_unpackClippingExtents: unpackClippingExtents_default, czm_unpackDepth: unpackDepth_default, czm_unpackFloat: unpackFloat_default, czm_unpackTexture: unpackTexture_default, czm_unpackUint: unpackUint_default, czm_valueTransform: valueTransform_default, czm_vertexLogDepth: vertexLogDepth_default, czm_windowToEyeCoordinates: windowToEyeCoordinates_default, czm_writeDepthClamp: writeDepthClamp_default, czm_writeLogDepth: writeLogDepth_default, czm_writeNonPerspective: writeNonPerspective_default }; // packages/engine/Source/Renderer/demodernizeShader.js var import_InlineWorkers267 = __toESM(require_InlineWorkers(), 1); function demodernizeShader(input, isFragmentShader) { let output = input; output = output.replaceAll(`version 300 es`, ``); output = output.replaceAll( /(texture\()/g, `texture2D(` // Trailing ')' is included in the match group. ); if (isFragmentShader) { output = output.replaceAll( /\n\s*(in)\s+(vec\d|mat\d|float)/g, ` varying $2` ); if (/out_FragData_(\d+)/.test(output)) { output = `#extension GL_EXT_draw_buffers : enable ${output}`; output = output.replaceAll( /layout\s+\(location\s*=\s*\d+\)\s*out\s+vec4\s+out_FragData_\d+;/g, `` ); output = output.replaceAll(/out_FragData_(\d+)/g, `gl_FragData[$1]`); } output = output.replaceAll( /layout\s+\(location\s*=\s*0\)\s*out\s+vec4\s+out_FragColor;/g, `` ); output = output.replaceAll(/out_FragColor/g, `gl_FragColor`); output = output.replaceAll(/out_FragColor\[(\d+)\]/g, `gl_FragColor[$1]`); if (/gl_FragDepth/.test(output)) { output = `#extension GL_EXT_frag_depth : enable ${output}`; output = output.replaceAll(/gl_FragDepth/g, `gl_FragDepthEXT`); } output = `#ifdef GL_EXT_shader_texture_lod #extension GL_EXT_shader_texture_lod : enable #endif ${output}`; output = `#ifdef GL_OES_standard_derivatives #extension GL_OES_standard_derivatives : enable #endif ${output}`; } else { output = output.replaceAll(/(in)\s+(vec\d|mat\d|float)/g, `attribute $2`); output = output.replaceAll( /(out)\s+(vec\d|mat\d|float)\s+([\w]+);/g, `varying $2 $3;` ); } output = `#version 100 ${output}`; return output; } var demodernizeShader_default = demodernizeShader; // packages/engine/Source/Renderer/ShaderSource.js function removeComments(source) { source = source.replace(/\/\/.*/g, ""); return source.replace(/\/\*\*[\s\S]*?\*\//gm, function(match) { const numberOfLines = match.match(/\n/gm).length; let replacement = ""; for (let lineNumber = 0; lineNumber < numberOfLines; ++lineNumber) { replacement += "\n"; } return replacement; }); } function getDependencyNode(name, glslSource, nodes) { let dependencyNode; for (let i = 0; i < nodes.length; ++i) { if (nodes[i].name === name) { dependencyNode = nodes[i]; } } if (!defined_default(dependencyNode)) { glslSource = removeComments(glslSource); dependencyNode = { name, glslSource, dependsOn: [], requiredBy: [], evaluated: false }; nodes.push(dependencyNode); } return dependencyNode; } function generateDependencies(currentNode, dependencyNodes) { if (currentNode.evaluated) { return; } currentNode.evaluated = true; let czmMatches = currentNode.glslSource.match(/\bczm_[a-zA-Z0-9_]*/g); if (defined_default(czmMatches) && czmMatches !== null) { czmMatches = czmMatches.filter(function(elem, pos) { return czmMatches.indexOf(elem) === pos; }); czmMatches.forEach(function(element) { if (element !== currentNode.name && ShaderSource._czmBuiltinsAndUniforms.hasOwnProperty(element)) { const referencedNode = getDependencyNode( element, ShaderSource._czmBuiltinsAndUniforms[element], dependencyNodes ); currentNode.dependsOn.push(referencedNode); referencedNode.requiredBy.push(currentNode); generateDependencies(referencedNode, dependencyNodes); } }); } } function sortDependencies(dependencyNodes) { const nodesWithoutIncomingEdges = []; const allNodes = []; while (dependencyNodes.length > 0) { const node = dependencyNodes.pop(); allNodes.push(node); if (node.requiredBy.length === 0) { nodesWithoutIncomingEdges.push(node); } } while (nodesWithoutIncomingEdges.length > 0) { const currentNode = nodesWithoutIncomingEdges.shift(); dependencyNodes.push(currentNode); for (let i = 0; i < currentNode.dependsOn.length; ++i) { const referencedNode = currentNode.dependsOn[i]; const index = referencedNode.requiredBy.indexOf(currentNode); referencedNode.requiredBy.splice(index, 1); if (referencedNode.requiredBy.length === 0) { nodesWithoutIncomingEdges.push(referencedNode); } } } const badNodes = []; for (let j = 0; j < allNodes.length; ++j) { if (allNodes[j].requiredBy.length !== 0) { badNodes.push(allNodes[j]); } } if (badNodes.length !== 0) { let message = "A circular dependency was found in the following built-in functions/structs/constants: \n"; for (let k = 0; k < badNodes.length; ++k) { message = `${message + badNodes[k].name} `; } throw new DeveloperError_default(message); } } function getBuiltinsAndAutomaticUniforms(shaderSource) { const dependencyNodes = []; const root = getDependencyNode("main", shaderSource, dependencyNodes); generateDependencies(root, dependencyNodes); sortDependencies(dependencyNodes); let builtinsSource = ""; for (let i = dependencyNodes.length - 1; i >= 0; --i) { builtinsSource = `${builtinsSource + dependencyNodes[i].glslSource} `; } return builtinsSource.replace(root.glslSource, ""); } function combineShader(shaderSource, isFragmentShader, context) { let combinedSources = ""; const sources = shaderSource.sources; if (defined_default(sources)) { for (let i = 0; i < sources.length; ++i) { combinedSources += ` #line 0 ${sources[i]}`; } } combinedSources = removeComments(combinedSources); let version2; combinedSources = combinedSources.replace( /#version\s+(.*?)\n/gm, function(match, group1) { if (defined_default(version2) && version2 !== group1) { throw new DeveloperError_default( `inconsistent versions found: ${version2} and ${group1}` ); } version2 = group1; return "\n"; } ); const extensions = []; combinedSources = combinedSources.replace( /#extension.*\n/gm, function(match) { extensions.push(match); return "\n"; } ); combinedSources = combinedSources.replace( /precision\s(lowp|mediump|highp)\s(float|int);/, "" ); const pickColorQualifier = shaderSource.pickColorQualifier; if (defined_default(pickColorQualifier)) { combinedSources = ShaderSource.createPickFragmentShaderSource( combinedSources, pickColorQualifier ); } let result = ""; const extensionsLength = extensions.length; for (let i = 0; i < extensionsLength; i++) { result += extensions[i]; } if (isFragmentShader) { result += ` #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; precision highp int; #else precision mediump float; precision mediump int; #define highp mediump #endif `; } if (context.webgl2) { result += `precision highp sampler3D; `; } const defines = shaderSource.defines; if (defined_default(defines)) { for (let i = 0, length2 = defines.length; i < length2; ++i) { const define2 = defines[i]; if (define2.length !== 0) { result += `#define ${define2} `; } } } if (context.textureFloatLinear) { result += "#define OES_texture_float_linear\n\n"; } if (context.floatingPointTexture) { result += "#define OES_texture_float\n\n"; } let builtinSources = ""; if (shaderSource.includeBuiltIns) { builtinSources = getBuiltinsAndAutomaticUniforms(combinedSources); } result += "\n#line 0\n"; const combinedShader = builtinSources + combinedSources; if (context.webgl2 && isFragmentShader && !/layout\s*\(location\s*=\s*0\)\s*out\s+vec4\s+out_FragColor;/g.test( combinedShader ) && !/czm_out_FragColor/g.test(combinedShader) && /out_FragColor/g.test(combinedShader)) { result += "layout(location = 0) out vec4 out_FragColor;\n\n"; } result += builtinSources; result += combinedSources; if (!context.webgl2) { result = demodernizeShader_default(result, isFragmentShader); } else { result = `#version 300 es ${result}`; } return result; } function ShaderSource(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const pickColorQualifier = options.pickColorQualifier; if (defined_default(pickColorQualifier) && pickColorQualifier !== "uniform" && pickColorQualifier !== "in") { throw new DeveloperError_default( "options.pickColorQualifier must be 'uniform' or 'in'." ); } this.defines = defined_default(options.defines) ? options.defines.slice(0) : []; this.sources = defined_default(options.sources) ? options.sources.slice(0) : []; this.pickColorQualifier = pickColorQualifier; this.includeBuiltIns = options.includeBuiltIns ?? true; } ShaderSource.prototype.clone = function() { return new ShaderSource({ sources: this.sources, defines: this.defines, pickColorQualifier: this.pickColorQualifier, includeBuiltIns: this.includeBuiltIns }); }; ShaderSource.replaceMain = function(source, renamedMain) { renamedMain = `void ${renamedMain}()`; return source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, renamedMain); }; ShaderSource.prototype.getCacheKey = function() { const sortedDefines = this.defines.slice().sort(); const definesKey = sortedDefines.join(","); const pickKey = this.pickColorQualifier; const builtinsKey = this.includeBuiltIns; const sourcesKey = this.sources.join("\n"); return `${definesKey}:${pickKey}:${builtinsKey}:${sourcesKey}`; }; ShaderSource.prototype.createCombinedVertexShader = function(context) { return combineShader(this, false, context); }; ShaderSource.prototype.createCombinedFragmentShader = function(context) { return combineShader(this, true, context); }; ShaderSource._czmBuiltinsAndUniforms = {}; for (const builtinName in CzmBuiltins_default) { if (CzmBuiltins_default.hasOwnProperty(builtinName)) { ShaderSource._czmBuiltinsAndUniforms[builtinName] = CzmBuiltins_default[builtinName]; } } for (const uniformName in AutomaticUniforms_default) { if (AutomaticUniforms_default.hasOwnProperty(uniformName)) { const uniform = AutomaticUniforms_default[uniformName]; if (typeof uniform.getDeclaration === "function") { ShaderSource._czmBuiltinsAndUniforms[uniformName] = uniform.getDeclaration(uniformName); } } } ShaderSource.createPickVertexShaderSource = function(vertexShaderSource) { const renamedVS = ShaderSource.replaceMain( vertexShaderSource, "czm_old_main" ); const pickMain = "in vec4 pickColor; \nout vec4 czm_pickColor; \nvoid main() \n{ \n czm_old_main(); \n czm_pickColor = pickColor; \n}"; return `${renamedVS} ${pickMain}`; }; ShaderSource.createPickFragmentShaderSource = function(fragmentShaderSource, pickColorQualifier) { const renamedFS = ShaderSource.replaceMain( fragmentShaderSource, "czm_old_main" ); const pickMain = `${pickColorQualifier} vec4 czm_pickColor; void main() { czm_old_main(); if (out_FragColor.a == 0.0) { discard; } out_FragColor = czm_pickColor; }`; return `${renamedFS} ${pickMain}`; }; function containsDefine(shaderSource, define2) { const defines = shaderSource.defines; const definesLength = defines.length; for (let i = 0; i < definesLength; ++i) { if (defines[i] === define2) { return true; } } return false; } function containsString(shaderSource, string) { const sources = shaderSource.sources; const sourcesLength = sources.length; for (let i = 0; i < sourcesLength; ++i) { if (sources[i].indexOf(string) !== -1) { return true; } } return false; } function findFirstString(shaderSource, strings) { const stringsLength = strings.length; for (let i = 0; i < stringsLength; ++i) { const string = strings[i]; if (containsString(shaderSource, string)) { return string; } } return void 0; } var normalVaryingNames = ["v_normalEC", "v_normal"]; ShaderSource.findNormalVarying = function(shaderSource) { if (containsString(shaderSource, "#ifdef HAS_NORMALS")) { if (containsDefine(shaderSource, "HAS_NORMALS")) { return "v_normalEC"; } return void 0; } return findFirstString(shaderSource, normalVaryingNames); }; var positionVaryingNames = ["v_positionEC"]; ShaderSource.findPositionVarying = function(shaderSource) { return findFirstString(shaderSource, positionVaryingNames); }; var ShaderSource_default = ShaderSource; // packages/engine/Source/Renderer/ShaderCache.js function ShaderCache(context) { this._context = context; this._shaders = {}; this._numberOfShaders = 0; this._shadersToRelease = {}; } Object.defineProperties(ShaderCache.prototype, { numberOfShaders: { get: function() { return this._numberOfShaders; } } }); ShaderCache.prototype.replaceShaderProgram = function(options) { if (defined_default(options.shaderProgram)) { options.shaderProgram.destroy(); } return this.getShaderProgram(options); }; function toSortedJson(dictionary) { const sortedKeys = Object.keys(dictionary).sort(); return JSON.stringify(dictionary, sortedKeys); } ShaderCache.prototype.getShaderProgram = function(options) { let vertexShaderSource = options.vertexShaderSource; let fragmentShaderSource = options.fragmentShaderSource; const attributeLocations8 = options.attributeLocations; if (typeof vertexShaderSource === "string") { vertexShaderSource = new ShaderSource_default({ sources: [vertexShaderSource] }); } if (typeof fragmentShaderSource === "string") { fragmentShaderSource = new ShaderSource_default({ sources: [fragmentShaderSource] }); } const vertexShaderKey = vertexShaderSource.getCacheKey(); const fragmentShaderKey = fragmentShaderSource.getCacheKey(); const attributeLocationKey = defined_default(attributeLocations8) ? toSortedJson(attributeLocations8) : ""; const keyword = `${vertexShaderKey}:${fragmentShaderKey}:${attributeLocationKey}`; let cachedShader; if (defined_default(this._shaders[keyword])) { cachedShader = this._shaders[keyword]; delete this._shadersToRelease[keyword]; } else { const context = this._context; const vertexShaderText = vertexShaderSource.createCombinedVertexShader(context); const fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(context); const shaderProgram = new ShaderProgram_default({ gl: context._gl, logShaderCompilation: context.logShaderCompilation, debugShaders: context.debugShaders, vertexShaderSource, vertexShaderText, fragmentShaderSource, fragmentShaderText, attributeLocations: attributeLocations8 }); cachedShader = { cache: this, shaderProgram, keyword, derivedKeywords: [], count: 0 }; shaderProgram._cachedShader = cachedShader; this._shaders[keyword] = cachedShader; ++this._numberOfShaders; } ++cachedShader.count; return cachedShader.shaderProgram; }; ShaderCache.prototype.replaceDerivedShaderProgram = function(shaderProgram, keyword, options) { const cachedShader = shaderProgram._cachedShader; const derivedKeyword = keyword + cachedShader.keyword; const cachedDerivedShader = this._shaders[derivedKeyword]; if (defined_default(cachedDerivedShader)) { destroyShader(this, cachedDerivedShader); const index = cachedShader.derivedKeywords.indexOf(keyword); if (index > -1) { cachedShader.derivedKeywords.splice(index, 1); } } return this.createDerivedShaderProgram(shaderProgram, keyword, options); }; ShaderCache.prototype.getDerivedShaderProgram = function(shaderProgram, keyword) { const cachedShader = shaderProgram._cachedShader; const derivedKeyword = keyword + cachedShader.keyword; const cachedDerivedShader = this._shaders[derivedKeyword]; if (!defined_default(cachedDerivedShader)) { return void 0; } return cachedDerivedShader.shaderProgram; }; ShaderCache.prototype.createDerivedShaderProgram = function(shaderProgram, keyword, options) { const cachedShader = shaderProgram._cachedShader; const derivedKeyword = keyword + cachedShader.keyword; let vertexShaderSource = options.vertexShaderSource; let fragmentShaderSource = options.fragmentShaderSource; const attributeLocations8 = options.attributeLocations; if (typeof vertexShaderSource === "string") { vertexShaderSource = new ShaderSource_default({ sources: [vertexShaderSource] }); } if (typeof fragmentShaderSource === "string") { fragmentShaderSource = new ShaderSource_default({ sources: [fragmentShaderSource] }); } const context = this._context; const vertexShaderText = vertexShaderSource.createCombinedVertexShader(context); const fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(context); const derivedShaderProgram = new ShaderProgram_default({ gl: context._gl, logShaderCompilation: context.logShaderCompilation, debugShaders: context.debugShaders, vertexShaderSource, vertexShaderText, fragmentShaderSource, fragmentShaderText, attributeLocations: attributeLocations8 }); const derivedCachedShader = { cache: this, shaderProgram: derivedShaderProgram, keyword: derivedKeyword, derivedKeywords: [], count: 0 }; cachedShader.derivedKeywords.push(keyword); derivedShaderProgram._cachedShader = derivedCachedShader; this._shaders[derivedKeyword] = derivedCachedShader; return derivedShaderProgram; }; function destroyShader(cache, cachedShader) { const derivedKeywords = cachedShader.derivedKeywords; const length2 = derivedKeywords.length; for (let i = 0; i < length2; ++i) { const keyword = derivedKeywords[i] + cachedShader.keyword; const derivedCachedShader = cache._shaders[keyword]; destroyShader(cache, derivedCachedShader); } delete cache._shaders[cachedShader.keyword]; cachedShader.shaderProgram.finalDestroy(); } ShaderCache.prototype.destroyReleasedShaderPrograms = function() { const shadersToRelease = this._shadersToRelease; for (const keyword in shadersToRelease) { if (shadersToRelease.hasOwnProperty(keyword)) { const cachedShader = shadersToRelease[keyword]; destroyShader(this, cachedShader); --this._numberOfShaders; } } this._shadersToRelease = {}; }; ShaderCache.prototype.releaseShaderProgram = function(shaderProgram) { if (defined_default(shaderProgram)) { const cachedShader = shaderProgram._cachedShader; if (cachedShader && --cachedShader.count === 0) { this._shadersToRelease[cachedShader.keyword] = cachedShader; } } }; ShaderCache.prototype.isDestroyed = function() { return false; }; ShaderCache.prototype.destroy = function() { const shaders = this._shaders; for (const keyword in shaders) { if (shaders.hasOwnProperty(keyword)) { shaders[keyword].shaderProgram.finalDestroy(); } } return destroyObject_default(this); }; var ShaderCache_default = ShaderCache; // packages/engine/Source/Renderer/Texture.js var import_InlineWorkers270 = __toESM(require_InlineWorkers(), 1); function Texture(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const { context, source, pixelFormat = PixelFormat_default.RGBA, pixelDatatype = PixelDatatype_default.UNSIGNED_BYTE, flipY = true, skipColorSpaceConversion = false, sampler = new Sampler_default() } = options; let { width, height } = options; if (defined_default(source)) { if (!defined_default(width)) { width = source.videoWidth ?? source.naturalWidth ?? source.width; } if (!defined_default(height)) { height = source.videoHeight ?? source.naturalHeight ?? source.height; } } const preMultiplyAlpha = options.preMultiplyAlpha || pixelFormat === PixelFormat_default.RGB || pixelFormat === PixelFormat_default.LUMINANCE; const internalFormat = PixelFormat_default.toInternalFormat( pixelFormat, pixelDatatype, context ); const isCompressed = PixelFormat_default.isCompressedFormat(internalFormat); if (!defined_default(width) || !defined_default(height)) { throw new DeveloperError_default( "options requires a source field to create an initialized texture or width and height fields to create a blank texture." ); } Check_default.typeOf.number.greaterThan("width", width, 0); if (width > ContextLimits_default.maximumTextureSize) { throw new DeveloperError_default( `Width must be less than or equal to the maximum texture size (${ContextLimits_default.maximumTextureSize}). Check maximumTextureSize.` ); } Check_default.typeOf.number.greaterThan("height", height, 0); if (height > ContextLimits_default.maximumTextureSize) { throw new DeveloperError_default( `Height must be less than or equal to the maximum texture size (${ContextLimits_default.maximumTextureSize}). Check maximumTextureSize.` ); } if (!PixelFormat_default.validate(pixelFormat)) { throw new DeveloperError_default("Invalid options.pixelFormat."); } if (!isCompressed && !PixelDatatype_default.validate(pixelDatatype)) { throw new DeveloperError_default("Invalid options.pixelDatatype."); } if (pixelFormat === PixelFormat_default.DEPTH_COMPONENT && pixelDatatype !== PixelDatatype_default.UNSIGNED_SHORT && pixelDatatype !== PixelDatatype_default.UNSIGNED_INT) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT, options.pixelDatatype must be UNSIGNED_SHORT or UNSIGNED_INT." ); } if (pixelFormat === PixelFormat_default.DEPTH_STENCIL && pixelDatatype !== PixelDatatype_default.UNSIGNED_INT_24_8) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_STENCIL, options.pixelDatatype must be UNSIGNED_INT_24_8." ); } if (pixelDatatype === PixelDatatype_default.FLOAT && !context.floatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension. Check context.floatingPointTexture." ); } if (pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.halfFloatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is HALF_FLOAT, this WebGL implementation must support the OES_texture_half_float extension. Check context.halfFloatingPointTexture." ); } if (PixelFormat_default.isDepthFormat(pixelFormat)) { if (defined_default(source)) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, source cannot be provided." ); } if (!context.depthTexture) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture." ); } } if (isCompressed) { if (!defined_default(source) || !defined_default(source.arrayBufferView)) { throw new DeveloperError_default( "When options.pixelFormat is compressed, options.source.arrayBufferView must be defined." ); } if (PixelFormat_default.isDXTFormat(internalFormat) && !context.s3tc) { throw new DeveloperError_default( "When options.pixelFormat is S3TC compressed, this WebGL implementation must support the WEBGL_compressed_texture_s3tc extension. Check context.s3tc." ); } else if (PixelFormat_default.isPVRTCFormat(internalFormat) && !context.pvrtc) { throw new DeveloperError_default( "When options.pixelFormat is PVRTC compressed, this WebGL implementation must support the WEBGL_compressed_texture_pvrtc extension. Check context.pvrtc." ); } else if (PixelFormat_default.isASTCFormat(internalFormat) && !context.astc) { throw new DeveloperError_default( "When options.pixelFormat is ASTC compressed, this WebGL implementation must support the WEBGL_compressed_texture_astc extension. Check context.astc." ); } else if (PixelFormat_default.isETC2Format(internalFormat) && !context.etc) { throw new DeveloperError_default( "When options.pixelFormat is ETC2 compressed, this WebGL implementation must support the WEBGL_compressed_texture_etc extension. Check context.etc." ); } else if (PixelFormat_default.isETC1Format(internalFormat) && !context.etc1) { throw new DeveloperError_default( "When options.pixelFormat is ETC1 compressed, this WebGL implementation must support the WEBGL_compressed_texture_etc1 extension. Check context.etc1." ); } else if (PixelFormat_default.isBC7Format(internalFormat) && !context.bc7) { throw new DeveloperError_default( "When options.pixelFormat is BC7 compressed, this WebGL implementation must support the EXT_texture_compression_bptc extension. Check context.bc7." ); } if (PixelFormat_default.compressedTextureSizeInBytes( internalFormat, width, height ) !== source.arrayBufferView.byteLength) { throw new DeveloperError_default( "The byte length of the array buffer is invalid for the compressed texture with the given width and height." ); } } const gl = context._gl; const sizeInBytes = isCompressed ? PixelFormat_default.compressedTextureSizeInBytes(pixelFormat, width, height) : PixelFormat_default.textureSizeInBytes(pixelFormat, pixelDatatype, width, height); this._id = options.id ?? createGuid_default(); this._context = context; this._textureFilterAnisotropic = context._textureFilterAnisotropic; this._textureTarget = gl.TEXTURE_2D; this._texture = gl.createTexture(); this._internalFormat = internalFormat; this._pixelFormat = pixelFormat; this._pixelDatatype = pixelDatatype; this._width = width; this._height = height; this._dimensions = new Cartesian2_default(width, height); this._hasMipmap = false; this._sizeInBytes = sizeInBytes; this._preMultiplyAlpha = preMultiplyAlpha; this._flipY = flipY; this._initialized = false; this._sampler = void 0; this._sampler = sampler; setupSampler2(this, sampler); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(this._textureTarget, this._texture); if (defined_default(source)) { if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } if (defined_default(source.arrayBufferView)) { const isCompressed2 = PixelFormat_default.isCompressedFormat(internalFormat); if (isCompressed2) { loadCompressedBufferSource(this, source); } else { loadBufferSource(this, source); } } else if (defined_default(source.framebuffer)) { loadFramebufferSource(this, source); } else { loadImageSource(this, source); } this._initialized = true; } else { loadNull(this); } gl.bindTexture(this._textureTarget, null); } function loadCompressedBufferSource(texture, source) { const context = texture._context; const gl = context._gl; const textureTarget = texture._textureTarget; const internalFormat = texture._internalFormat; const { width, height } = texture; gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); gl.compressedTexImage2D( textureTarget, 0, internalFormat, width, height, 0, source.arrayBufferView ); if (defined_default(source.mipLevels)) { let mipWidth = width; let mipHeight = height; for (let i = 0; i < source.mipLevels.length; ++i) { mipWidth = nextMipSize(mipWidth); mipHeight = nextMipSize(mipHeight); gl.compressedTexImage2D( textureTarget, i + 1, internalFormat, mipWidth, mipHeight, 0, source.mipLevels[i] ); } } } function loadBufferSource(texture, source) { const context = texture._context; const gl = context._gl; const textureTarget = texture._textureTarget; const internalFormat = texture._internalFormat; const { width, height, pixelFormat, pixelDatatype, flipY } = texture; const unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, width ); gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); let { arrayBufferView } = source; if (flipY) { arrayBufferView = PixelFormat_default.flipY( arrayBufferView, pixelFormat, pixelDatatype, width, height ); } gl.texImage2D( textureTarget, 0, internalFormat, width, height, 0, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), arrayBufferView ); if (defined_default(source.mipLevels)) { let mipWidth = width; let mipHeight = height; for (let i = 0; i < source.mipLevels.length; ++i) { mipWidth = nextMipSize(mipWidth); mipHeight = nextMipSize(mipHeight); gl.texImage2D( textureTarget, i + 1, internalFormat, mipWidth, mipHeight, 0, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), source.mipLevels[i] ); } } } function loadPartialBufferSource(texture, arrayBufferView, xOffset, yOffset, width, height) { const context = texture._context; const gl = context._gl; const { pixelFormat, pixelDatatype } = texture; const unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, width ); gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); if (texture.flipY) { arrayBufferView = PixelFormat_default.flipY( arrayBufferView, pixelFormat, pixelDatatype, width, height ); } gl.texSubImage2D( texture._textureTarget, 0, xOffset, yOffset, width, height, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), arrayBufferView ); } function loadFramebufferSource(texture, source) { const context = texture._context; const gl = context._gl; gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); if (source.framebuffer !== context.defaultFramebuffer) { source.framebuffer._bind(); } gl.copyTexImage2D( texture._textureTarget, 0, texture._internalFormat, source.xOffset, source.yOffset, texture.width, texture.height, 0 ); if (source.framebuffer !== context.defaultFramebuffer) { source.framebuffer._unBind(); } } function loadImageSource(texture, source) { const context = texture._context; const gl = context._gl; gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.preMultiplyAlpha); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); gl.texImage2D( texture._textureTarget, 0, texture._internalFormat, texture.pixelFormat, PixelDatatype_default.toWebGLConstant(texture.pixelDatatype, context), source ); } function loadPartialImageSource(texture, source, xOffset, yOffset) { const context = texture._context; const gl = context._gl; gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.preMultiplyAlpha); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); gl.texSubImage2D( texture._textureTarget, 0, xOffset, yOffset, texture.pixelFormat, PixelDatatype_default.toWebGLConstant(texture.pixelDatatype, context), source ); } function nextMipSize(currentSize) { const nextSize = Math.floor(currentSize / 2) | 0; return Math.max(nextSize, 1); } function loadNull(texture) { const context = texture._context; context._gl.texImage2D( texture._textureTarget, 0, texture._internalFormat, texture._width, texture._height, 0, texture._pixelFormat, PixelDatatype_default.toWebGLConstant(texture._pixelDatatype, context), null ); } Texture.create = function(options) { return new Texture(options); }; Texture.fromFramebuffer = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const context = options.context; const { pixelFormat = PixelFormat_default.RGB, framebufferXOffset = 0, framebufferYOffset = 0, width = context.drawingBufferWidth, height = context.drawingBufferHeight, framebuffer } = options; if (!PixelFormat_default.validate(pixelFormat)) { throw new DeveloperError_default("Invalid pixelFormat."); } if (PixelFormat_default.isDepthFormat(pixelFormat) || PixelFormat_default.isCompressedFormat(pixelFormat)) { throw new DeveloperError_default( "pixelFormat cannot be DEPTH_COMPONENT, DEPTH_STENCIL or a compressed format." ); } Check_default.defined("options.context", context); Check_default.typeOf.number.greaterThanOrEquals( "framebufferXOffset", framebufferXOffset, 0 ); Check_default.typeOf.number.greaterThanOrEquals( "framebufferYOffset", framebufferYOffset, 0 ); if (framebufferXOffset + width > context.drawingBufferWidth) { throw new DeveloperError_default( "framebufferXOffset + width must be less than or equal to drawingBufferWidth" ); } if (framebufferYOffset + height > context.drawingBufferHeight) { throw new DeveloperError_default( "framebufferYOffset + height must be less than or equal to drawingBufferHeight." ); } const texture = new Texture({ context, width, height, pixelFormat, source: { framebuffer: defined_default(framebuffer) ? framebuffer : context.defaultFramebuffer, xOffset: framebufferXOffset, yOffset: framebufferYOffset, width, height } }); return texture; }; Object.defineProperties(Texture.prototype, { /** * A unique id for the texture * @memberof Texture.prototype * @type {string} * @readonly * @private */ id: { get: function() { return this._id; } }, /** * The sampler to use when sampling this texture. * Create a sampler by calling {@link Sampler}. If this * parameter is not specified, a default sampler is used. The default sampler clamps texture * coordinates in both directions, uses linear filtering for both magnification and minification, * and uses a maximum anisotropy of 1.0. * @memberof Texture.prototype * @type {Sampler} * @private */ sampler: { get: function() { return this._sampler; }, set: function(sampler) { setupSampler2(this, sampler); this._sampler = sampler; } }, pixelFormat: { get: function() { return this._pixelFormat; } }, pixelDatatype: { get: function() { return this._pixelDatatype; } }, dimensions: { get: function() { return this._dimensions; } }, preMultiplyAlpha: { get: function() { return this._preMultiplyAlpha; } }, flipY: { get: function() { return this._flipY; } }, width: { get: function() { return this._width; } }, height: { get: function() { return this._height; } }, sizeInBytes: { get: function() { if (this._hasMipmap) { return Math.floor(this._sizeInBytes * 4 / 3); } return this._sizeInBytes; } }, _target: { get: function() { return this._textureTarget; } } }); function setupSampler2(texture, sampler) { let { minificationFilter, magnificationFilter } = sampler; const mipmap = [ TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST, TextureMinificationFilter_default.NEAREST_MIPMAP_LINEAR, TextureMinificationFilter_default.LINEAR_MIPMAP_NEAREST, TextureMinificationFilter_default.LINEAR_MIPMAP_LINEAR ].includes(minificationFilter); const context = texture._context; const pixelFormat = texture._pixelFormat; const pixelDatatype = texture._pixelDatatype; if (pixelDatatype === PixelDatatype_default.FLOAT && !context.textureFloatLinear || pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.textureHalfFloatLinear) { minificationFilter = mipmap ? TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST : TextureMinificationFilter_default.NEAREST; magnificationFilter = TextureMagnificationFilter_default.NEAREST; } if (context.webgl2) { if (PixelFormat_default.isDepthFormat(pixelFormat)) { minificationFilter = TextureMinificationFilter_default.NEAREST; magnificationFilter = TextureMagnificationFilter_default.NEAREST; } } const gl = context._gl; const target = texture._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, texture._texture); gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter); gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter); gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS); gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT); if (defined_default(texture._textureFilterAnisotropic)) { gl.texParameteri( target, texture._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy ); } gl.bindTexture(target, null); } Texture.prototype.copyFrom = function(options) { Check_default.defined("options", options); const { xOffset = 0, yOffset = 0, source, skipColorSpaceConversion = false } = options; Check_default.defined("options.source", source); if (PixelFormat_default.isDepthFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call copyFrom when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL." ); } if (PixelFormat_default.isCompressedFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call copyFrom with a compressed texture pixel format." ); } Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); Check_default.typeOf.number.lessThanOrEquals( "xOffset + options.source.width", xOffset + source.width, this._width ); Check_default.typeOf.number.lessThanOrEquals( "yOffset + options.source.height", yOffset + source.height, this._height ); const context = this._context; const gl = context._gl; const target = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); let { width, height } = source; if (defined_default(source.videoWidth) && defined_default(source.videoHeight)) { width = source.videoWidth; height = source.videoHeight; } else if (defined_default(source.naturalWidth) && defined_default(source.naturalHeight)) { width = source.naturalWidth; height = source.naturalHeight; } if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } let uploaded = false; if (!this._initialized) { if (xOffset === 0 && yOffset === 0 && width === this._width && height === this._height) { if (defined_default(source.arrayBufferView)) { loadBufferSource(this, source); } else { loadImageSource(this, source); } uploaded = true; } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); loadNull(this); } this._initialized = true; } if (!uploaded) { if (defined_default(source.arrayBufferView)) { loadPartialBufferSource( this, source.arrayBufferView, xOffset, yOffset, width, height ); } else { loadPartialImageSource(this, source, xOffset, yOffset); } } gl.bindTexture(target, null); }; Texture.prototype.copyFromFramebuffer = function(xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height) { xOffset = xOffset ?? 0; yOffset = yOffset ?? 0; framebufferXOffset = framebufferXOffset ?? 0; framebufferYOffset = framebufferYOffset ?? 0; width = width ?? this._width; height = height ?? this._height; if (PixelFormat_default.isDepthFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL." ); } if (this._pixelDatatype === PixelDatatype_default.FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is FLOAT." ); } if (this._pixelDatatype === PixelDatatype_default.HALF_FLOAT) { throw new DeveloperError_default( "Cannot call copyFromFramebuffer when the texture pixel data type is HALF_FLOAT." ); } if (PixelFormat_default.isCompressedFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call copyFrom with a compressed texture pixel format." ); } Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); Check_default.typeOf.number.greaterThanOrEquals( "framebufferXOffset", framebufferXOffset, 0 ); Check_default.typeOf.number.greaterThanOrEquals( "framebufferYOffset", framebufferYOffset, 0 ); Check_default.typeOf.number.lessThanOrEquals( "xOffset + width", xOffset + width, this._width ); Check_default.typeOf.number.lessThanOrEquals( "yOffset + height", yOffset + height, this._height ); const gl = this._context._gl; const target = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.copyTexSubImage2D( target, 0, xOffset, yOffset, framebufferXOffset, framebufferYOffset, width, height ); gl.bindTexture(target, null); this._initialized = true; }; Texture.prototype.generateMipmap = function(hint) { hint = hint ?? MipmapHint_default.DONT_CARE; if (PixelFormat_default.isDepthFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call generateMipmap when the texture pixel format is DEPTH_COMPONENT or DEPTH_STENCIL." ); } if (PixelFormat_default.isCompressedFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call generateMipmap with a compressed pixel format." ); } if (!this._context.webgl2) { if (this._width > 1 && !Math_default.isPowerOfTwo(this._width)) { throw new DeveloperError_default( "width must be a power of two to call generateMipmap() in a WebGL1 context." ); } if (this._height > 1 && !Math_default.isPowerOfTwo(this._height)) { throw new DeveloperError_default( "height must be a power of two to call generateMipmap() in a WebGL1 context." ); } } if (!MipmapHint_default.validate(hint)) { throw new DeveloperError_default("hint is invalid."); } this._hasMipmap = true; const gl = this._context._gl; const target = this._textureTarget; gl.hint(gl.GENERATE_MIPMAP_HINT, hint); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.generateMipmap(target); gl.bindTexture(target, null); }; Texture.prototype.isDestroyed = function() { return false; }; Texture.prototype.destroy = function() { this._context._gl.deleteTexture(this._texture); return destroyObject_default(this); }; Texture.defaultColor = Color_default.WHITE; var Texture_default = Texture; // packages/engine/Source/Renderer/TextureCache.js var import_InlineWorkers271 = __toESM(require_InlineWorkers(), 1); function TextureCache() { this._textures = {}; this._numberOfTextures = 0; this._texturesToRelease = {}; } Object.defineProperties(TextureCache.prototype, { numberOfTextures: { get: function() { return this._numberOfTextures; } } }); TextureCache.prototype.getTexture = function(keyword) { const cachedTexture = this._textures[keyword]; if (!defined_default(cachedTexture)) { return void 0; } delete this._texturesToRelease[keyword]; ++cachedTexture.count; return cachedTexture.texture; }; TextureCache.prototype.addTexture = function(keyword, texture) { const cachedTexture = { texture, count: 1 }; texture.finalDestroy = texture.destroy; const that = this; texture.destroy = function() { if (--cachedTexture.count === 0) { that._texturesToRelease[keyword] = cachedTexture; } }; this._textures[keyword] = cachedTexture; ++this._numberOfTextures; }; TextureCache.prototype.destroyReleasedTextures = function() { const texturesToRelease = this._texturesToRelease; for (const keyword in texturesToRelease) { if (texturesToRelease.hasOwnProperty(keyword)) { const cachedTexture = texturesToRelease[keyword]; delete this._textures[keyword]; cachedTexture.texture.finalDestroy(); --this._numberOfTextures; } } this._texturesToRelease = {}; }; TextureCache.prototype.isDestroyed = function() { return false; }; TextureCache.prototype.destroy = function() { const textures = this._textures; for (const keyword in textures) { if (textures.hasOwnProperty(keyword)) { textures[keyword].texture.finalDestroy(); } } return destroyObject_default(this); }; var TextureCache_default = TextureCache; // packages/engine/Source/Renderer/UniformState.js var import_InlineWorkers278 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/OrthographicFrustum.js var import_InlineWorkers274 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/OrthographicOffCenterFrustum.js var import_InlineWorkers273 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/CullingVolume.js var import_InlineWorkers272 = __toESM(require_InlineWorkers(), 1); function CullingVolume(planes) { this.planes = planes ?? []; } var faces = [new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default()]; Cartesian3_default.clone(Cartesian3_default.UNIT_X, faces[0]); Cartesian3_default.clone(Cartesian3_default.UNIT_Y, faces[1]); Cartesian3_default.clone(Cartesian3_default.UNIT_Z, faces[2]); var scratchPlaneCenter = new Cartesian3_default(); var scratchPlaneNormal = new Cartesian3_default(); var scratchPlane = new Plane_default(new Cartesian3_default(1, 0, 0), 0); CullingVolume.fromBoundingSphere = function(boundingSphere, result) { if (!defined_default(boundingSphere)) { throw new DeveloperError_default("boundingSphere is required."); } if (!defined_default(result)) { result = new CullingVolume(); } const length2 = faces.length; const planes = result.planes; planes.length = 2 * length2; const center = boundingSphere.center; const radius = boundingSphere.radius; let planeIndex = 0; for (let i = 0; i < length2; ++i) { const faceNormal = faces[i]; let plane0 = planes[planeIndex]; let plane1 = planes[planeIndex + 1]; if (!defined_default(plane0)) { plane0 = planes[planeIndex] = new Cartesian4_default(); } if (!defined_default(plane1)) { plane1 = planes[planeIndex + 1] = new Cartesian4_default(); } Cartesian3_default.multiplyByScalar(faceNormal, -radius, scratchPlaneCenter); Cartesian3_default.add(center, scratchPlaneCenter, scratchPlaneCenter); plane0.x = faceNormal.x; plane0.y = faceNormal.y; plane0.z = faceNormal.z; plane0.w = -Cartesian3_default.dot(faceNormal, scratchPlaneCenter); Cartesian3_default.multiplyByScalar(faceNormal, radius, scratchPlaneCenter); Cartesian3_default.add(center, scratchPlaneCenter, scratchPlaneCenter); plane1.x = -faceNormal.x; plane1.y = -faceNormal.y; plane1.z = -faceNormal.z; plane1.w = -Cartesian3_default.dot( Cartesian3_default.negate(faceNormal, scratchPlaneNormal), scratchPlaneCenter ); planeIndex += 2; } return result; }; CullingVolume.prototype.computeVisibility = function(boundingVolume) { if (!defined_default(boundingVolume)) { throw new DeveloperError_default("boundingVolume is required."); } const planes = this.planes; let intersecting = false; for (let k = 0, len = planes.length; k < len; ++k) { const result = boundingVolume.intersectPlane( Plane_default.fromCartesian4(planes[k], scratchPlane) ); if (result === Intersect_default.OUTSIDE) { return Intersect_default.OUTSIDE; } else if (result === Intersect_default.INTERSECTING) { intersecting = true; } } return intersecting ? Intersect_default.INTERSECTING : Intersect_default.INSIDE; }; CullingVolume.prototype.computeVisibilityWithPlaneMask = function(boundingVolume, parentPlaneMask) { if (!defined_default(boundingVolume)) { throw new DeveloperError_default("boundingVolume is required."); } if (!defined_default(parentPlaneMask)) { throw new DeveloperError_default("parentPlaneMask is required."); } if (parentPlaneMask === CullingVolume.MASK_OUTSIDE || parentPlaneMask === CullingVolume.MASK_INSIDE) { return parentPlaneMask; } let mask = CullingVolume.MASK_INSIDE; const planes = this.planes; for (let k = 0, len = planes.length; k < len; ++k) { const flag = k < 31 ? 1 << k : 0; if (k < 31 && (parentPlaneMask & flag) === 0) { continue; } const result = boundingVolume.intersectPlane( Plane_default.fromCartesian4(planes[k], scratchPlane) ); if (result === Intersect_default.OUTSIDE) { return CullingVolume.MASK_OUTSIDE; } else if (result === Intersect_default.INTERSECTING) { mask |= flag; } } return mask; }; CullingVolume.MASK_OUTSIDE = 4294967295; CullingVolume.MASK_INSIDE = 0; CullingVolume.MASK_INDETERMINATE = 2147483647; var CullingVolume_default = CullingVolume; // packages/engine/Source/Core/OrthographicOffCenterFrustum.js function OrthographicOffCenterFrustum(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.left = options.left; this._left = void 0; this.right = options.right; this._right = void 0; this.top = options.top; this._top = void 0; this.bottom = options.bottom; this._bottom = void 0; this.near = options.near ?? 1; this._near = this.near; this.far = options.far ?? 5e8; this._far = this.far; this._cullingVolume = new CullingVolume_default(); this._orthographicMatrix = new Matrix4_default(); } function update(frustum) { if (!defined_default(frustum.right) || !defined_default(frustum.left) || !defined_default(frustum.top) || !defined_default(frustum.bottom) || !defined_default(frustum.near) || !defined_default(frustum.far)) { throw new DeveloperError_default( "right, left, top, bottom, near, or far parameters are not set." ); } if (frustum.top !== frustum._top || frustum.bottom !== frustum._bottom || frustum.left !== frustum._left || frustum.right !== frustum._right || frustum.near !== frustum._near || frustum.far !== frustum._far) { if (frustum.left > frustum.right) { throw new DeveloperError_default("right must be greater than left."); } if (frustum.bottom > frustum.top) { throw new DeveloperError_default("top must be greater than bottom."); } if (frustum.near <= 0 || frustum.near > frustum.far) { throw new DeveloperError_default( "near must be greater than zero and less than far." ); } frustum._left = frustum.left; frustum._right = frustum.right; frustum._top = frustum.top; frustum._bottom = frustum.bottom; frustum._near = frustum.near; frustum._far = frustum.far; frustum._orthographicMatrix = Matrix4_default.computeOrthographicOffCenter( frustum.left, frustum.right, frustum.bottom, frustum.top, frustum.near, frustum.far, frustum._orthographicMatrix ); } } Object.defineProperties(OrthographicOffCenterFrustum.prototype, { /** * Gets the orthographic projection matrix computed from the view frustum. * @memberof OrthographicOffCenterFrustum.prototype * @type {Matrix4} * @readonly */ projectionMatrix: { get: function() { update(this); return this._orthographicMatrix; } } }); var getPlanesRight = new Cartesian3_default(); var getPlanesNearCenter = new Cartesian3_default(); var getPlanesPoint = new Cartesian3_default(); var negateScratch = new Cartesian3_default(); OrthographicOffCenterFrustum.prototype.computeCullingVolume = function(position, direction2, up) { if (!defined_default(position)) { throw new DeveloperError_default("position is required."); } if (!defined_default(direction2)) { throw new DeveloperError_default("direction is required."); } if (!defined_default(up)) { throw new DeveloperError_default("up is required."); } const planes = this._cullingVolume.planes; const t2 = this.top; const b = this.bottom; const r2 = this.right; const l2 = this.left; const n2 = this.near; const f2 = this.far; const right = Cartesian3_default.cross(direction2, up, getPlanesRight); Cartesian3_default.normalize(right, right); const nearCenter = getPlanesNearCenter; Cartesian3_default.multiplyByScalar(direction2, n2, nearCenter); Cartesian3_default.add(position, nearCenter, nearCenter); const point4 = getPlanesPoint; Cartesian3_default.multiplyByScalar(right, l2, point4); Cartesian3_default.add(nearCenter, point4, point4); let plane = planes[0]; if (!defined_default(plane)) { plane = planes[0] = new Cartesian4_default(); } plane.x = right.x; plane.y = right.y; plane.z = right.z; plane.w = -Cartesian3_default.dot(right, point4); Cartesian3_default.multiplyByScalar(right, r2, point4); Cartesian3_default.add(nearCenter, point4, point4); plane = planes[1]; if (!defined_default(plane)) { plane = planes[1] = new Cartesian4_default(); } plane.x = -right.x; plane.y = -right.y; plane.z = -right.z; plane.w = -Cartesian3_default.dot(Cartesian3_default.negate(right, negateScratch), point4); Cartesian3_default.multiplyByScalar(up, b, point4); Cartesian3_default.add(nearCenter, point4, point4); plane = planes[2]; if (!defined_default(plane)) { plane = planes[2] = new Cartesian4_default(); } plane.x = up.x; plane.y = up.y; plane.z = up.z; plane.w = -Cartesian3_default.dot(up, point4); Cartesian3_default.multiplyByScalar(up, t2, point4); Cartesian3_default.add(nearCenter, point4, point4); plane = planes[3]; if (!defined_default(plane)) { plane = planes[3] = new Cartesian4_default(); } plane.x = -up.x; plane.y = -up.y; plane.z = -up.z; plane.w = -Cartesian3_default.dot(Cartesian3_default.negate(up, negateScratch), point4); plane = planes[4]; if (!defined_default(plane)) { plane = planes[4] = new Cartesian4_default(); } plane.x = direction2.x; plane.y = direction2.y; plane.z = direction2.z; plane.w = -Cartesian3_default.dot(direction2, nearCenter); Cartesian3_default.multiplyByScalar(direction2, f2, point4); Cartesian3_default.add(position, point4, point4); plane = planes[5]; if (!defined_default(plane)) { plane = planes[5] = new Cartesian4_default(); } plane.x = -direction2.x; plane.y = -direction2.y; plane.z = -direction2.z; plane.w = -Cartesian3_default.dot(Cartesian3_default.negate(direction2, negateScratch), point4); return this._cullingVolume; }; OrthographicOffCenterFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance2, pixelRatio, result) { update(this); if (!defined_default(drawingBufferWidth) || !defined_default(drawingBufferHeight)) { throw new DeveloperError_default( "Both drawingBufferWidth and drawingBufferHeight are required." ); } if (drawingBufferWidth <= 0) { throw new DeveloperError_default("drawingBufferWidth must be greater than zero."); } if (drawingBufferHeight <= 0) { throw new DeveloperError_default("drawingBufferHeight must be greater than zero."); } if (!defined_default(distance2)) { throw new DeveloperError_default("distance is required."); } if (!defined_default(pixelRatio)) { throw new DeveloperError_default("pixelRatio is required."); } if (pixelRatio <= 0) { throw new DeveloperError_default("pixelRatio must be greater than zero."); } if (!defined_default(result)) { throw new DeveloperError_default("A result object is required."); } const frustumWidth = this.right - this.left; const frustumHeight = this.top - this.bottom; const pixelWidth = pixelRatio * frustumWidth / drawingBufferWidth; const pixelHeight = pixelRatio * frustumHeight / drawingBufferHeight; result.x = pixelWidth; result.y = pixelHeight; return result; }; OrthographicOffCenterFrustum.prototype.clone = function(result) { if (!defined_default(result)) { result = new OrthographicOffCenterFrustum(); } result.left = this.left; result.right = this.right; result.top = this.top; result.bottom = this.bottom; result.near = this.near; result.far = this.far; result._left = void 0; result._right = void 0; result._top = void 0; result._bottom = void 0; result._near = void 0; result._far = void 0; return result; }; OrthographicOffCenterFrustum.prototype.equals = function(other) { return defined_default(other) && other instanceof OrthographicOffCenterFrustum && this.right === other.right && this.left === other.left && this.top === other.top && this.bottom === other.bottom && this.near === other.near && this.far === other.far; }; OrthographicOffCenterFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) { return other === this || defined_default(other) && other instanceof OrthographicOffCenterFrustum && Math_default.equalsEpsilon( this.right, other.right, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.left, other.left, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.top, other.top, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.bottom, other.bottom, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.near, other.near, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.far, other.far, relativeEpsilon, absoluteEpsilon ); }; var OrthographicOffCenterFrustum_default = OrthographicOffCenterFrustum; // packages/engine/Source/Core/OrthographicFrustum.js function OrthographicFrustum(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._offCenterFrustum = new OrthographicOffCenterFrustum_default(); this.width = options.width; this._width = void 0; this.aspectRatio = options.aspectRatio; this._aspectRatio = void 0; this.near = options.near ?? 1; this._near = this.near; this.far = options.far ?? 5e8; this._far = this.far; } OrthographicFrustum.packedLength = 4; OrthographicFrustum.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; array[startingIndex++] = value.width; array[startingIndex++] = value.aspectRatio; array[startingIndex++] = value.near; array[startingIndex] = value.far; return array; }; OrthographicFrustum.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new OrthographicFrustum(); } result.width = array[startingIndex++]; result.aspectRatio = array[startingIndex++]; result.near = array[startingIndex++]; result.far = array[startingIndex]; return result; }; function update2(frustum) { if (!defined_default(frustum.width) || !defined_default(frustum.aspectRatio) || !defined_default(frustum.near) || !defined_default(frustum.far)) { throw new DeveloperError_default( "width, aspectRatio, near, or far parameters are not set." ); } const f2 = frustum._offCenterFrustum; if (frustum.width !== frustum._width || frustum.aspectRatio !== frustum._aspectRatio || frustum.near !== frustum._near || frustum.far !== frustum._far) { if (frustum.aspectRatio < 0) { throw new DeveloperError_default("aspectRatio must be positive."); } if (frustum.near < 0 || frustum.near > frustum.far) { throw new DeveloperError_default( "near must be greater than zero and less than far." ); } frustum._aspectRatio = frustum.aspectRatio; frustum._width = frustum.width; frustum._near = frustum.near; frustum._far = frustum.far; const ratio = 1 / frustum.aspectRatio; f2.right = frustum.width * 0.5; f2.left = -f2.right; f2.top = ratio * f2.right; f2.bottom = -f2.top; f2.near = frustum.near; f2.far = frustum.far; } } Object.defineProperties(OrthographicFrustum.prototype, { /** * Gets the orthographic projection matrix computed from the view frustum. * @memberof OrthographicFrustum.prototype * @type {Matrix4} * @readonly */ projectionMatrix: { get: function() { update2(this); return this._offCenterFrustum.projectionMatrix; } }, /** * Gets the underlying {@link OrthographicOffCenterFrustum} * @memberof OrthographicFrustum.prototype * @type {OrthographicOffCenterFrustum} * @readonly * @private */ offCenterFrustum: { get: function() { update2(this); return this._offCenterFrustum; } } }); OrthographicFrustum.prototype.computeCullingVolume = function(position, direction2, up) { update2(this); return this._offCenterFrustum.computeCullingVolume(position, direction2, up); }; OrthographicFrustum.prototype.getPixelDimensions = function(drawingBufferWidth, drawingBufferHeight, distance2, pixelRatio, result) { update2(this); return this._offCenterFrustum.getPixelDimensions( drawingBufferWidth, drawingBufferHeight, distance2, pixelRatio, result ); }; OrthographicFrustum.prototype.clone = function(result) { if (!defined_default(result)) { result = new OrthographicFrustum(); } result.aspectRatio = this.aspectRatio; result.width = this.width; result.near = this.near; result.far = this.far; result._aspectRatio = void 0; result._width = void 0; result._near = void 0; result._far = void 0; this._offCenterFrustum.clone(result._offCenterFrustum); return result; }; OrthographicFrustum.prototype.equals = function(other) { if (!defined_default(other) || !(other instanceof OrthographicFrustum)) { return false; } update2(this); update2(other); return this.width === other.width && this.aspectRatio === other.aspectRatio && this._offCenterFrustum.equals(other._offCenterFrustum); }; OrthographicFrustum.prototype.equalsEpsilon = function(other, relativeEpsilon, absoluteEpsilon) { if (!defined_default(other) || !(other instanceof OrthographicFrustum)) { return false; } update2(this); update2(other); return Math_default.equalsEpsilon( this.width, other.width, relativeEpsilon, absoluteEpsilon ) && Math_default.equalsEpsilon( this.aspectRatio, other.aspectRatio, relativeEpsilon, absoluteEpsilon ) && this._offCenterFrustum.equalsEpsilon( other._offCenterFrustum, relativeEpsilon, absoluteEpsilon ); }; var OrthographicFrustum_default = OrthographicFrustum; // packages/engine/Source/Core/Simon1994PlanetaryPositions.js var import_InlineWorkers275 = __toESM(require_InlineWorkers(), 1); var Simon1994PlanetaryPositions = {}; function computeTdbMinusTtSpice(daysSinceJ2000InTerrestrialTime) { const g = 6.239996 + 0.0172019696544 * daysSinceJ2000InTerrestrialTime; return 1657e-6 * Math.sin(g + 0.01671 * Math.sin(g)); } var TdtMinusTai2 = 32.184; var J2000d2 = 2451545; function taiToTdb(date, result) { result = JulianDate_default.addSeconds(date, TdtMinusTai2, result); const days = JulianDate_default.totalDays(result) - J2000d2; result = JulianDate_default.addSeconds(result, computeTdbMinusTtSpice(days), result); return result; } var epoch = new JulianDate_default(2451545, 0, TimeStandard_default.TAI); var MetersPerKilometer = 1e3; var RadiansPerDegree = Math_default.RADIANS_PER_DEGREE; var RadiansPerArcSecond = Math_default.RADIANS_PER_ARCSECOND; var MetersPerAstronomicalUnit = 14959787e4; var perifocalToEquatorial = new Matrix3_default(); function elementsToCartesian(semimajorAxis, eccentricity, inclination, longitudeOfPerigee, longitudeOfNode, meanLongitude, result) { if (inclination < 0) { inclination = -inclination; longitudeOfNode += Math_default.PI; } if (inclination < 0 || inclination > Math_default.PI) { throw new DeveloperError_default( "The inclination is out of range. Inclination must be greater than or equal to zero and less than or equal to Pi radians." ); } const radiusOfPeriapsis = semimajorAxis * (1 - eccentricity); const argumentOfPeriapsis = longitudeOfPerigee - longitudeOfNode; const rightAscensionOfAscendingNode = longitudeOfNode; const trueAnomaly = meanAnomalyToTrueAnomaly( meanLongitude - longitudeOfPerigee, eccentricity ); const type = chooseOrbit(eccentricity, 0); if (type === "Hyperbolic" && Math.abs(Math_default.negativePiToPi(trueAnomaly)) >= Math.acos(-1 / eccentricity)) { throw new DeveloperError_default( "The true anomaly of the hyperbolic orbit lies outside of the bounds of the hyperbola." ); } perifocalToCartesianMatrix( argumentOfPeriapsis, inclination, rightAscensionOfAscendingNode, perifocalToEquatorial ); const semilatus = radiusOfPeriapsis * (1 + eccentricity); const costheta = Math.cos(trueAnomaly); const sintheta = Math.sin(trueAnomaly); const denom = 1 + eccentricity * costheta; if (denom <= Math_default.Epsilon10) { throw new DeveloperError_default("elements cannot be converted to cartesian"); } const radius = semilatus / denom; if (!defined_default(result)) { result = new Cartesian3_default(radius * costheta, radius * sintheta, 0); } else { result.x = radius * costheta; result.y = radius * sintheta; result.z = 0; } return Matrix3_default.multiplyByVector(perifocalToEquatorial, result, result); } function chooseOrbit(eccentricity, tolerance) { if (eccentricity < 0) { throw new DeveloperError_default("eccentricity cannot be negative."); } if (eccentricity <= tolerance) { return "Circular"; } else if (eccentricity < 1 - tolerance) { return "Elliptical"; } else if (eccentricity <= 1 + tolerance) { return "Parabolic"; } return "Hyperbolic"; } function meanAnomalyToTrueAnomaly(meanAnomaly, eccentricity) { if (eccentricity < 0 || eccentricity >= 1) { throw new DeveloperError_default("eccentricity out of range."); } const eccentricAnomaly = meanAnomalyToEccentricAnomaly( meanAnomaly, eccentricity ); return eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity); } var maxIterationCount = 50; var keplerEqConvergence = Math_default.EPSILON8; function meanAnomalyToEccentricAnomaly(meanAnomaly, eccentricity) { if (eccentricity < 0 || eccentricity >= 1) { throw new DeveloperError_default("eccentricity out of range."); } const revs = Math.floor(meanAnomaly / Math_default.TWO_PI); meanAnomaly -= revs * Math_default.TWO_PI; let iterationValue = meanAnomaly + eccentricity * Math.sin(meanAnomaly) / (1 - Math.sin(meanAnomaly + eccentricity) + Math.sin(meanAnomaly)); let eccentricAnomaly = Number.MAX_VALUE; let count; for (count = 0; count < maxIterationCount && Math.abs(eccentricAnomaly - iterationValue) > keplerEqConvergence; ++count) { eccentricAnomaly = iterationValue; const NRfunction = eccentricAnomaly - eccentricity * Math.sin(eccentricAnomaly) - meanAnomaly; const dNRfunction = 1 - eccentricity * Math.cos(eccentricAnomaly); iterationValue = eccentricAnomaly - NRfunction / dNRfunction; } if (count >= maxIterationCount) { throw new DeveloperError_default("Kepler equation did not converge"); } eccentricAnomaly = iterationValue + revs * Math_default.TWO_PI; return eccentricAnomaly; } function eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity) { if (eccentricity < 0 || eccentricity >= 1) { throw new DeveloperError_default("eccentricity out of range."); } const revs = Math.floor(eccentricAnomaly / Math_default.TWO_PI); eccentricAnomaly -= revs * Math_default.TWO_PI; const trueAnomalyX = Math.cos(eccentricAnomaly) - eccentricity; const trueAnomalyY = Math.sin(eccentricAnomaly) * Math.sqrt(1 - eccentricity * eccentricity); let trueAnomaly = Math.atan2(trueAnomalyY, trueAnomalyX); trueAnomaly = Math_default.zeroToTwoPi(trueAnomaly); if (eccentricAnomaly < 0) { trueAnomaly -= Math_default.TWO_PI; } trueAnomaly += revs * Math_default.TWO_PI; return trueAnomaly; } function perifocalToCartesianMatrix(argumentOfPeriapsis, inclination, rightAscension, result) { if (inclination < 0 || inclination > Math_default.PI) { throw new DeveloperError_default("inclination out of range"); } const cosap = Math.cos(argumentOfPeriapsis); const sinap = Math.sin(argumentOfPeriapsis); const cosi = Math.cos(inclination); const sini = Math.sin(inclination); const cosraan = Math.cos(rightAscension); const sinraan = Math.sin(rightAscension); if (!defined_default(result)) { result = new Matrix3_default( cosraan * cosap - sinraan * sinap * cosi, -cosraan * sinap - sinraan * cosap * cosi, sinraan * sini, sinraan * cosap + cosraan * sinap * cosi, -sinraan * sinap + cosraan * cosap * cosi, -cosraan * sini, sinap * sini, cosap * sini, cosi ); } else { result[0] = cosraan * cosap - sinraan * sinap * cosi; result[1] = sinraan * cosap + cosraan * sinap * cosi; result[2] = sinap * sini; result[3] = -cosraan * sinap - sinraan * cosap * cosi; result[4] = -sinraan * sinap + cosraan * cosap * cosi; result[5] = cosap * sini; result[6] = sinraan * sini; result[7] = -cosraan * sini; result[8] = cosi; } return result; } var semiMajorAxis0 = 1.0000010178 * MetersPerAstronomicalUnit; var meanLongitude0 = 100.46645683 * RadiansPerDegree; var meanLongitude1 = 129597742283429e-5 * RadiansPerArcSecond; var p1u = 16002; var p2u = 21863; var p3u = 32004; var p4u = 10931; var p5u = 14529; var p6u = 16368; var p7u = 15318; var p8u = 32794; var Ca1 = 64 * 1e-7 * MetersPerAstronomicalUnit; var Ca2 = -152 * 1e-7 * MetersPerAstronomicalUnit; var Ca3 = 62 * 1e-7 * MetersPerAstronomicalUnit; var Ca4 = -8 * 1e-7 * MetersPerAstronomicalUnit; var Ca5 = 32 * 1e-7 * MetersPerAstronomicalUnit; var Ca6 = -41 * 1e-7 * MetersPerAstronomicalUnit; var Ca7 = 19 * 1e-7 * MetersPerAstronomicalUnit; var Ca8 = -11 * 1e-7 * MetersPerAstronomicalUnit; var Sa1 = -150 * 1e-7 * MetersPerAstronomicalUnit; var Sa2 = -46 * 1e-7 * MetersPerAstronomicalUnit; var Sa3 = 68 * 1e-7 * MetersPerAstronomicalUnit; var Sa4 = 54 * 1e-7 * MetersPerAstronomicalUnit; var Sa5 = 14 * 1e-7 * MetersPerAstronomicalUnit; var Sa6 = 24 * 1e-7 * MetersPerAstronomicalUnit; var Sa7 = -28 * 1e-7 * MetersPerAstronomicalUnit; var Sa8 = 22 * 1e-7 * MetersPerAstronomicalUnit; var q1u = 10; var q2u = 16002; var q3u = 21863; var q4u = 10931; var q5u = 1473; var q6u = 32004; var q7u = 4387; var q8u = 73; var Cl1 = -325 * 1e-7; var Cl2 = -322 * 1e-7; var Cl3 = -79 * 1e-7; var Cl4 = 232 * 1e-7; var Cl5 = -52 * 1e-7; var Cl6 = 97 * 1e-7; var Cl7 = 55 * 1e-7; var Cl8 = -41 * 1e-7; var Sl1 = -105 * 1e-7; var Sl2 = -137 * 1e-7; var Sl3 = 258 * 1e-7; var Sl4 = 35 * 1e-7; var Sl5 = -116 * 1e-7; var Sl6 = -88 * 1e-7; var Sl7 = -112 * 1e-7; var Sl8 = -80 * 1e-7; var scratchDate = new JulianDate_default(0, 0, TimeStandard_default.TAI); function computeSimonEarthMoonBarycenter(date, result) { taiToTdb(date, scratchDate); const x = scratchDate.dayNumber - epoch.dayNumber + (scratchDate.secondsOfDay - epoch.secondsOfDay) / TimeConstants_default.SECONDS_PER_DAY; const t2 = x / (TimeConstants_default.DAYS_PER_JULIAN_CENTURY * 10); const u4 = 0.3595362 * t2; const semimajorAxis = semiMajorAxis0 + Ca1 * Math.cos(p1u * u4) + Sa1 * Math.sin(p1u * u4) + Ca2 * Math.cos(p2u * u4) + Sa2 * Math.sin(p2u * u4) + Ca3 * Math.cos(p3u * u4) + Sa3 * Math.sin(p3u * u4) + Ca4 * Math.cos(p4u * u4) + Sa4 * Math.sin(p4u * u4) + Ca5 * Math.cos(p5u * u4) + Sa5 * Math.sin(p5u * u4) + Ca6 * Math.cos(p6u * u4) + Sa6 * Math.sin(p6u * u4) + Ca7 * Math.cos(p7u * u4) + Sa7 * Math.sin(p7u * u4) + Ca8 * Math.cos(p8u * u4) + Sa8 * Math.sin(p8u * u4); const meanLongitude = meanLongitude0 + meanLongitude1 * t2 + Cl1 * Math.cos(q1u * u4) + Sl1 * Math.sin(q1u * u4) + Cl2 * Math.cos(q2u * u4) + Sl2 * Math.sin(q2u * u4) + Cl3 * Math.cos(q3u * u4) + Sl3 * Math.sin(q3u * u4) + Cl4 * Math.cos(q4u * u4) + Sl4 * Math.sin(q4u * u4) + Cl5 * Math.cos(q5u * u4) + Sl5 * Math.sin(q5u * u4) + Cl6 * Math.cos(q6u * u4) + Sl6 * Math.sin(q6u * u4) + Cl7 * Math.cos(q7u * u4) + Sl7 * Math.sin(q7u * u4) + Cl8 * Math.cos(q8u * u4) + Sl8 * Math.sin(q8u * u4); const eccentricity = 0.0167086342 - 4203654e-10 * t2; const longitudeOfPerigee = 102.93734808 * RadiansPerDegree + 11612.3529 * RadiansPerArcSecond * t2; const inclination = 469.97289 * RadiansPerArcSecond * t2; const longitudeOfNode = 174.87317577 * RadiansPerDegree - 8679.27034 * RadiansPerArcSecond * t2; return elementsToCartesian( semimajorAxis, eccentricity, inclination, longitudeOfPerigee, longitudeOfNode, meanLongitude, result ); } function computeSimonMoon(date, result) { taiToTdb(date, scratchDate); const x = scratchDate.dayNumber - epoch.dayNumber + (scratchDate.secondsOfDay - epoch.secondsOfDay) / TimeConstants_default.SECONDS_PER_DAY; const t2 = x / TimeConstants_default.DAYS_PER_JULIAN_CENTURY; const t22 = t2 * t2; const t3 = t22 * t2; const t4 = t3 * t2; let semimajorAxis = 383397.7725 + 4e-3 * t2; let eccentricity = 0.055545526 - 16e-9 * t2; const inclinationConstant = 5.15668983 * RadiansPerDegree; let inclinationSecPart = -8e-5 * t2 + 0.02966 * t22 - 42e-6 * t3 - 13e-8 * t4; const longitudeOfPerigeeConstant = 83.35324312 * RadiansPerDegree; let longitudeOfPerigeeSecPart = 146434202669e-4 * t2 - 38.2702 * t22 - 0.045047 * t3 + 21301e-8 * t4; const longitudeOfNodeConstant = 125.04455501 * RadiansPerDegree; let longitudeOfNodeSecPart = -69679193631e-4 * t2 + 6.3602 * t22 + 7625e-6 * t3 - 3586e-8 * t4; const meanLongitudeConstant = 218.31664563 * RadiansPerDegree; let meanLongitudeSecPart = 17325593434847e-4 * t2 - 6.391 * t22 + 6588e-6 * t3 - 3169e-8 * t4; const D = 297.85019547 * RadiansPerDegree + RadiansPerArcSecond * (1602961601209e-3 * t2 - 6.3706 * t22 + 6593e-6 * t3 - 3169e-8 * t4); const F = 93.27209062 * RadiansPerDegree + RadiansPerArcSecond * (17395272628478e-4 * t2 - 12.7512 * t22 - 1037e-6 * t3 + 417e-8 * t4); const l2 = 134.96340251 * RadiansPerDegree + RadiansPerArcSecond * (17179159232178e-4 * t2 + 31.8792 * t22 + 0.051635 * t3 - 2447e-7 * t4); const lprime = 357.52910918 * RadiansPerDegree + RadiansPerArcSecond * (1295965810481e-4 * t2 - 0.5532 * t22 + 136e-6 * t3 - 1149e-8 * t4); const psi = 310.17137918 * RadiansPerDegree - RadiansPerArcSecond * (6967051436e-3 * t2 + 6.2068 * t22 + 7618e-6 * t3 - 3219e-8 * t4); const twoD = 2 * D; const fourD = 4 * D; const sixD = 6 * D; const twol = 2 * l2; const threel = 3 * l2; const fourl = 4 * l2; const twoF = 2 * F; semimajorAxis += 3400.4 * Math.cos(twoD) - 635.6 * Math.cos(twoD - l2) - 235.6 * Math.cos(l2) + 218.1 * Math.cos(twoD - lprime) + 181 * Math.cos(twoD + l2); eccentricity += 0.014216 * Math.cos(twoD - l2) + 8551e-6 * Math.cos(twoD - twol) - 1383e-6 * Math.cos(l2) + 1356e-6 * Math.cos(twoD + l2) - 1147e-6 * Math.cos(fourD - threel) - 914e-6 * Math.cos(fourD - twol) + 869e-6 * Math.cos(twoD - lprime - l2) - 627e-6 * Math.cos(twoD) - 394e-6 * Math.cos(fourD - fourl) + 282e-6 * Math.cos(twoD - lprime - twol) - 279e-6 * Math.cos(D - l2) - 236e-6 * Math.cos(twol) + 231e-6 * Math.cos(fourD) + 229e-6 * Math.cos(sixD - fourl) - 201e-6 * Math.cos(twol - twoF); inclinationSecPart += 486.26 * Math.cos(twoD - twoF) - 40.13 * Math.cos(twoD) + 37.51 * Math.cos(twoF) + 25.73 * Math.cos(twol - twoF) + 19.97 * Math.cos(twoD - lprime - twoF); longitudeOfPerigeeSecPart += -55609 * Math.sin(twoD - l2) - 34711 * Math.sin(twoD - twol) - 9792 * Math.sin(l2) + 9385 * Math.sin(fourD - threel) + 7505 * Math.sin(fourD - twol) + 5318 * Math.sin(twoD + l2) + 3484 * Math.sin(fourD - fourl) - 3417 * Math.sin(twoD - lprime - l2) - 2530 * Math.sin(sixD - fourl) - 2376 * Math.sin(twoD) - 2075 * Math.sin(twoD - threel) - 1883 * Math.sin(twol) - 1736 * Math.sin(sixD - 5 * l2) + 1626 * Math.sin(lprime) - 1370 * Math.sin(sixD - threel); longitudeOfNodeSecPart += -5392 * Math.sin(twoD - twoF) - 540 * Math.sin(lprime) - 441 * Math.sin(twoD) + 423 * Math.sin(twoF) - 288 * Math.sin(twol - twoF); meanLongitudeSecPart += -3332.9 * Math.sin(twoD) + 1197.4 * Math.sin(twoD - l2) - 662.5 * Math.sin(lprime) + 396.3 * Math.sin(l2) - 218 * Math.sin(twoD - lprime); const twoPsi = 2 * psi; const threePsi = 3 * psi; inclinationSecPart += 46.997 * Math.cos(psi) * t2 - 0.614 * Math.cos(twoD - twoF + psi) * t2 + 0.614 * Math.cos(twoD - twoF - psi) * t2 - 0.0297 * Math.cos(twoPsi) * t22 - 0.0335 * Math.cos(psi) * t22 + 12e-4 * Math.cos(twoD - twoF + twoPsi) * t22 - 16e-5 * Math.cos(psi) * t3 + 4e-5 * Math.cos(threePsi) * t3 + 4e-5 * Math.cos(twoPsi) * t3; const perigeeAndMean = 2.116 * Math.sin(psi) * t2 - 0.111 * Math.sin(twoD - twoF - psi) * t2 - 15e-4 * Math.sin(psi) * t22; longitudeOfPerigeeSecPart += perigeeAndMean; meanLongitudeSecPart += perigeeAndMean; longitudeOfNodeSecPart += -520.77 * Math.sin(psi) * t2 + 13.66 * Math.sin(twoD - twoF + psi) * t2 + 1.12 * Math.sin(twoD - psi) * t2 - 1.06 * Math.sin(twoF - psi) * t2 + 0.66 * Math.sin(twoPsi) * t22 + 0.371 * Math.sin(psi) * t22 - 0.035 * Math.sin(twoD - twoF + twoPsi) * t22 - 0.015 * Math.sin(twoD - twoF + psi) * t22 + 14e-4 * Math.sin(psi) * t3 - 11e-4 * Math.sin(threePsi) * t3 - 9e-4 * Math.sin(twoPsi) * t3; semimajorAxis *= MetersPerKilometer; const inclination = inclinationConstant + inclinationSecPart * RadiansPerArcSecond; const longitudeOfPerigee = longitudeOfPerigeeConstant + longitudeOfPerigeeSecPart * RadiansPerArcSecond; const meanLongitude = meanLongitudeConstant + meanLongitudeSecPart * RadiansPerArcSecond; const longitudeOfNode = longitudeOfNodeConstant + longitudeOfNodeSecPart * RadiansPerArcSecond; return elementsToCartesian( semimajorAxis, eccentricity, inclination, longitudeOfPerigee, longitudeOfNode, meanLongitude, result ); } var moonEarthMassRatio = 0.012300034; var factor = moonEarthMassRatio / (moonEarthMassRatio + 1) * -1; function computeSimonEarth(date, result) { result = computeSimonMoon(date, result); return Cartesian3_default.multiplyByScalar(result, factor, result); } var axesTransformation = new Matrix3_default( 1.0000000000000002, 5619723173785822e-31, 4690511510146299e-34, -5154129427414611e-31, 0.9174820620691819, -0.39777715593191376, -223970096136568e-30, 0.39777715593191376, 0.9174820620691819 ); var translation = new Cartesian3_default(); Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame = function(julianDate, result) { if (!defined_default(julianDate)) { julianDate = JulianDate_default.now(); } if (!defined_default(result)) { result = new Cartesian3_default(); } translation = computeSimonEarthMoonBarycenter(julianDate, translation); result = Cartesian3_default.negate(translation, result); computeSimonEarth(julianDate, translation); Cartesian3_default.subtract(result, translation, result); Matrix3_default.multiplyByVector(axesTransformation, result, result); return result; }; Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame = function(julianDate, result) { if (!defined_default(julianDate)) { julianDate = JulianDate_default.now(); } result = computeSimonMoon(julianDate, result); Matrix3_default.multiplyByVector(axesTransformation, result, result); return result; }; var Simon1994PlanetaryPositions_default = Simon1994PlanetaryPositions; // packages/engine/Source/Scene/SceneMode.js var import_InlineWorkers276 = __toESM(require_InlineWorkers(), 1); var SceneMode = { /** * Morphing between mode, e.g., 3D to 2D. * * @type {number} * @constant */ MORPHING: 0, /** * Columbus View mode. A 2.5D perspective view where the map is laid out * flat and objects with non-zero height are drawn above it. * * @type {number} * @constant */ COLUMBUS_VIEW: 1, /** * 2D mode. The map is viewed top-down with an orthographic projection. * * @type {number} * @constant */ SCENE2D: 2, /** * 3D mode. A traditional 3D perspective view of the globe. * * @type {number} * @constant */ SCENE3D: 3 }; SceneMode.getMorphTime = function(value) { if (value === SceneMode.SCENE3D) { return 1; } else if (value === SceneMode.MORPHING) { return void 0; } return 0; }; Object.freeze(SceneMode); var SceneMode_default = SceneMode; // packages/engine/Source/Scene/SunLight.js var import_InlineWorkers277 = __toESM(require_InlineWorkers(), 1); function SunLight(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.color = Color_default.clone(options.color ?? Color_default.WHITE); this.intensity = options.intensity ?? 2; } var SunLight_default = SunLight; // packages/engine/Source/Renderer/UniformState.js function UniformState() { this.globeDepthTexture = void 0; this.edgeIdTexture = void 0; this.edgeColorTexture = void 0; this.edgeDepthTexture = void 0; this.planarFillIdTexture = void 0; this.gamma = void 0; this._viewport = new BoundingRectangle_default(); this._viewportCartesian4 = new Cartesian4_default(); this._viewportDirty = false; this._viewportOrthographicMatrix = Matrix4_default.clone(Matrix4_default.IDENTITY); this._viewportTransformation = Matrix4_default.clone(Matrix4_default.IDENTITY); this._model = Matrix4_default.clone(Matrix4_default.IDENTITY); this._view = Matrix4_default.clone(Matrix4_default.IDENTITY); this._inverseView = Matrix4_default.clone(Matrix4_default.IDENTITY); this._projection = Matrix4_default.clone(Matrix4_default.IDENTITY); this._infiniteProjection = Matrix4_default.clone(Matrix4_default.IDENTITY); this._entireFrustum = new Cartesian2_default(); this._currentFrustum = new Cartesian2_default(); this._frustumPlanes = new Cartesian4_default(); this._farDepthFromNearPlusOne = void 0; this._log2FarDepthFromNearPlusOne = void 0; this._oneOverLog2FarDepthFromNearPlusOne = void 0; this._frameState = void 0; this._temeToPseudoFixed = Matrix3_default.clone(Matrix4_default.IDENTITY); this._view3DDirty = true; this._view3D = new Matrix4_default(); this._inverseView3DDirty = true; this._inverseView3D = new Matrix4_default(); this._inverseModelDirty = true; this._inverseModel = new Matrix4_default(); this._inverseTransposeModelDirty = true; this._inverseTransposeModel = new Matrix3_default(); this._viewRotation = new Matrix3_default(); this._inverseViewRotation = new Matrix3_default(); this._viewRotation3D = new Matrix3_default(); this._inverseViewRotation3D = new Matrix3_default(); this._inverseProjectionDirty = true; this._inverseProjection = new Matrix4_default(); this._modelViewDirty = true; this._modelView = new Matrix4_default(); this._modelView3DDirty = true; this._modelView3D = new Matrix4_default(); this._modelViewRelativeToEyeDirty = true; this._modelViewRelativeToEye = new Matrix4_default(); this._inverseModelViewDirty = true; this._inverseModelView = new Matrix4_default(); this._inverseModelView3DDirty = true; this._inverseModelView3D = new Matrix4_default(); this._viewProjectionDirty = true; this._viewProjection = new Matrix4_default(); this._inverseViewProjectionDirty = true; this._inverseViewProjection = new Matrix4_default(); this._modelViewProjectionDirty = true; this._modelViewProjection = new Matrix4_default(); this._inverseModelViewProjectionDirty = true; this._inverseModelViewProjection = new Matrix4_default(); this._modelViewProjectionRelativeToEyeDirty = true; this._modelViewProjectionRelativeToEye = new Matrix4_default(); this._modelViewInfiniteProjectionDirty = true; this._modelViewInfiniteProjection = new Matrix4_default(); this._normalDirty = true; this._normal = new Matrix3_default(); this._normal3DDirty = true; this._normal3D = new Matrix3_default(); this._inverseNormalDirty = true; this._inverseNormal = new Matrix3_default(); this._inverseNormal3DDirty = true; this._inverseNormal3D = new Matrix3_default(); this._encodedCameraPositionMCDirty = true; this._encodedCameraPositionMC = new EncodedCartesian3_default(); this._cameraPosition = new Cartesian3_default(); this._sunPositionWC = new Cartesian3_default(); this._sunPositionColumbusView = new Cartesian3_default(); this._sunDirectionWC = new Cartesian3_default(); this._sunDirectionEC = new Cartesian3_default(); this._moonDirectionEC = new Cartesian3_default(); this._lightDirectionWC = new Cartesian3_default(); this._lightDirectionEC = new Cartesian3_default(); this._lightColor = new Cartesian3_default(); this._lightColorHdr = new Cartesian3_default(); this._pass = void 0; this._mode = void 0; this._mapProjection = void 0; this._ellipsoid = void 0; this._cameraDirection = new Cartesian3_default(); this._cameraRight = new Cartesian3_default(); this._cameraUp = new Cartesian3_default(); this._frustum2DWidth = 0; this._eyeHeight = 0; this._eyeHeight2D = new Cartesian2_default(); this._eyeEllipsoidNormalEC = new Cartesian3_default(); this._eyeEllipsoidCurvature = new Cartesian2_default(); this._modelToEnu = new Matrix4_default(); this._enuToModel = new Matrix4_default(); this._pixelRatio = 1; this._orthographicIn3D = false; this._backgroundColor = new Color_default(); this._brdfLut = void 0; this._environmentMap = void 0; this._sphericalHarmonicCoefficients = void 0; this._specularEnvironmentMaps = void 0; this._specularEnvironmentMapsMaximumLOD = void 0; this._fogDensity = void 0; this._fogVisualDensityScalar = void 0; this._fogMinimumBrightness = void 0; this._atmosphereHsbShift = void 0; this._atmosphereLightIntensity = void 0; this._atmosphereRayleighCoefficient = new Cartesian3_default(); this._atmosphereRayleighScaleHeight = new Cartesian3_default(); this._atmosphereMieCoefficient = new Cartesian3_default(); this._atmosphereMieScaleHeight = void 0; this._atmosphereMieAnisotropy = void 0; this._atmosphereDynamicLighting = void 0; this._invertClassificationColor = void 0; this._splitPosition = 0; this._pixelSizePerMeter = void 0; this._geometricToleranceOverMeter = void 0; this._minimumDisableDepthTestDistance = void 0; } Object.defineProperties(UniformState.prototype, { /** * @memberof UniformState.prototype * @type {FrameState} * @readonly */ frameState: { get: function() { return this._frameState; } }, /** * @memberof UniformState.prototype * @type {BoundingRectangle} */ viewport: { get: function() { return this._viewport; }, set: function(viewport) { if (!BoundingRectangle_default.equals(viewport, this._viewport)) { BoundingRectangle_default.clone(viewport, this._viewport); const v3 = this._viewport; const vc = this._viewportCartesian4; vc.x = v3.x; vc.y = v3.y; vc.z = v3.width; vc.w = v3.height; this._viewportDirty = true; } } }, /** * @memberof UniformState.prototype * @private */ viewportCartesian4: { get: function() { return this._viewportCartesian4; } }, viewportOrthographic: { get: function() { cleanViewport(this); return this._viewportOrthographicMatrix; } }, viewportTransformation: { get: function() { cleanViewport(this); return this._viewportTransformation; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ model: { get: function() { return this._model; }, set: function(matrix) { Matrix4_default.clone(matrix, this._model); this._modelView3DDirty = true; this._inverseModelView3DDirty = true; this._inverseModelDirty = true; this._inverseTransposeModelDirty = true; this._modelViewDirty = true; this._inverseModelViewDirty = true; this._modelViewRelativeToEyeDirty = true; this._inverseModelViewDirty = true; this._modelViewProjectionDirty = true; this._inverseModelViewProjectionDirty = true; this._modelViewProjectionRelativeToEyeDirty = true; this._modelViewInfiniteProjectionDirty = true; this._normalDirty = true; this._inverseNormalDirty = true; this._normal3DDirty = true; this._inverseNormal3DDirty = true; this._encodedCameraPositionMCDirty = true; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseModel: { get: function() { if (this._inverseModelDirty) { this._inverseModelDirty = false; Matrix4_default.inverse(this._model, this._inverseModel); } return this._inverseModel; } }, /** * @memberof UniformState.prototype * @private */ inverseTransposeModel: { get: function() { const m = this._inverseTransposeModel; if (this._inverseTransposeModelDirty) { this._inverseTransposeModelDirty = false; Matrix4_default.getMatrix3(this.inverseModel, m); Matrix3_default.transpose(m, m); } return m; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ view: { get: function() { return this._view; } }, /** * The 3D view matrix. In 3D mode, this is identical to {@link UniformState#view}, * but in 2D and Columbus View it is a synthetic matrix based on the equivalent position * of the camera in the 3D world. * @memberof UniformState.prototype * @type {Matrix4} */ view3D: { get: function() { updateView3D(this); return this._view3D; } }, /** * The 3x3 rotation matrix of the current view matrix ({@link UniformState#view}). * @memberof UniformState.prototype * @type {Matrix3} */ viewRotation: { get: function() { updateView3D(this); return this._viewRotation; } }, /** * @memberof UniformState.prototype * @type {Matrix3} */ viewRotation3D: { get: function() { updateView3D(this); return this._viewRotation3D; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseView: { get: function() { return this._inverseView; } }, /** * the 4x4 inverse-view matrix that transforms from eye to 3D world coordinates. In 3D mode, this is * identical to {@link UniformState#inverseView}, but in 2D and Columbus View it is a synthetic matrix * based on the equivalent position of the camera in the 3D world. * @memberof UniformState.prototype * @type {Matrix4} */ inverseView3D: { get: function() { updateInverseView3D(this); return this._inverseView3D; } }, /** * @memberof UniformState.prototype * @type {Matrix3} */ inverseViewRotation: { get: function() { return this._inverseViewRotation; } }, /** * The 3x3 rotation matrix of the current 3D inverse-view matrix ({@link UniformState#inverseView3D}). * @memberof UniformState.prototype * @type {Matrix3} */ inverseViewRotation3D: { get: function() { updateInverseView3D(this); return this._inverseViewRotation3D; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ projection: { get: function() { return this._projection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseProjection: { get: function() { cleanInverseProjection(this); return this._inverseProjection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ infiniteProjection: { get: function() { return this._infiniteProjection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ modelView: { get: function() { cleanModelView(this); return this._modelView; } }, /** * The 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#modelView}. In 2D and * Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world. * @memberof UniformState.prototype * @type {Matrix4} */ modelView3D: { get: function() { cleanModelView3D(this); return this._modelView3D; } }, /** * Model-view relative to eye matrix. * * @memberof UniformState.prototype * @type {Matrix4} */ modelViewRelativeToEye: { get: function() { cleanModelViewRelativeToEye(this); return this._modelViewRelativeToEye; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseModelView: { get: function() { cleanInverseModelView(this); return this._inverseModelView; } }, /** * The inverse of the 3D model-view matrix. In 3D mode, this is equivalent to {@link UniformState#inverseModelView}. * In 2D and Columbus View, however, it is a synthetic matrix based on the equivalent position of the camera in the 3D world. * @memberof UniformState.prototype * @type {Matrix4} */ inverseModelView3D: { get: function() { cleanInverseModelView3D(this); return this._inverseModelView3D; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ viewProjection: { get: function() { cleanViewProjection(this); return this._viewProjection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseViewProjection: { get: function() { cleanInverseViewProjection(this); return this._inverseViewProjection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ modelViewProjection: { get: function() { cleanModelViewProjection(this); return this._modelViewProjection; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ inverseModelViewProjection: { get: function() { cleanInverseModelViewProjection(this); return this._inverseModelViewProjection; } }, /** * Model-view-projection relative to eye matrix. * * @memberof UniformState.prototype * @type {Matrix4} */ modelViewProjectionRelativeToEye: { get: function() { cleanModelViewProjectionRelativeToEye(this); return this._modelViewProjectionRelativeToEye; } }, /** * @memberof UniformState.prototype * @type {Matrix4} */ modelViewInfiniteProjection: { get: function() { cleanModelViewInfiniteProjection(this); return this._modelViewInfiniteProjection; } }, /** * A 3x3 normal transformation matrix that transforms normal vectors in model coordinates to * eye coordinates. * @memberof UniformState.prototype * @type {Matrix3} */ normal: { get: function() { cleanNormal(this); return this._normal; } }, /** * A 3x3 normal transformation matrix that transforms normal vectors in 3D model * coordinates to eye coordinates. In 3D mode, this is identical to * {@link UniformState#normal}, but in 2D and Columbus View it represents the normal transformation * matrix as if the camera were at an equivalent location in 3D mode. * @memberof UniformState.prototype * @type {Matrix3} */ normal3D: { get: function() { cleanNormal3D(this); return this._normal3D; } }, /** * An inverse 3x3 normal transformation matrix that transforms normal vectors in model coordinates * to eye coordinates. * @memberof UniformState.prototype * @type {Matrix3} */ inverseNormal: { get: function() { cleanInverseNormal(this); return this._inverseNormal; } }, /** * An inverse 3x3 normal transformation matrix that transforms normal vectors in eye coordinates * to 3D model coordinates. In 3D mode, this is identical to * {@link UniformState#inverseNormal}, but in 2D and Columbus View it represents the normal transformation * matrix as if the camera were at an equivalent location in 3D mode. * @memberof UniformState.prototype * @type {Matrix3} */ inverseNormal3D: { get: function() { cleanInverseNormal3D(this); return this._inverseNormal3D; } }, /** * The near distance (x) and the far distance (y) of the frustum defined by the camera. * This is the largest possible frustum, not an individual frustum used for multi-frustum rendering. * @memberof UniformState.prototype * @type {Cartesian2} */ entireFrustum: { get: function() { return this._entireFrustum; } }, /** * The near distance (x) and the far distance (y) of the frustum defined by the camera. * This is the individual frustum used for multi-frustum rendering. * @memberof UniformState.prototype * @type {Cartesian2} */ currentFrustum: { get: function() { return this._currentFrustum; } }, /** * The distances to the frustum planes. The top, bottom, left and right distances are * the x, y, z, and w components, respectively. * @memberof UniformState.prototype * @type {Cartesian4} */ frustumPlanes: { get: function() { return this._frustumPlanes; } }, /** * The far plane's distance from the near plane, plus 1.0. * * @memberof UniformState.prototype * @type {number} */ farDepthFromNearPlusOne: { get: function() { return this._farDepthFromNearPlusOne; } }, /** * The log2 of {@link UniformState#farDepthFromNearPlusOne}. * * @memberof UniformState.prototype * @type {number} */ log2FarDepthFromNearPlusOne: { get: function() { return this._log2FarDepthFromNearPlusOne; } }, /** * 1.0 divided by {@link UniformState#log2FarDepthFromNearPlusOne}. * * @memberof UniformState.prototype * @type {number} */ oneOverLog2FarDepthFromNearPlusOne: { get: function() { return this._oneOverLog2FarDepthFromNearPlusOne; } }, /** * The height in meters of the eye (camera) above or below the ellipsoid. * @memberof UniformState.prototype * @type {number} */ eyeHeight: { get: function() { return this._eyeHeight; } }, /** * The height (x) and the height squared (y) * in meters of the eye (camera) above the 2D world plane. This uniform is only valid * when the {@link SceneMode} is SCENE2D. * @memberof UniformState.prototype * @type {Cartesian2} */ eyeHeight2D: { get: function() { return this._eyeHeight2D; } }, /** * The ellipsoid surface normal at the camera position, in model coordinates. * @memberof UniformState.prototype * @type {Cartesian3} */ eyeEllipsoidNormalEC: { get: function() { return this._eyeEllipsoidNormalEC; } }, /** * The ellipsoid radii of curvature at the camera position. * The .x component is the prime vertical radius, .y is the meridional. * @memberof UniformState.prototype * @type {Cartesian2} */ eyeEllipsoidCurvature: { get: function() { return this._eyeEllipsoidCurvature; } }, /** * A transform from model coordinates to an east-north-up coordinate system * centered at the position on the ellipsoid below the camera * @memberof UniformState.prototype * @type {Matrix4} */ modelToEnu: { get: function() { return this._modelToEnu; } }, /** * The inverse of {@link UniformState.prototype.modelToEnu} * @memberof UniformState.prototype * @type {Matrix4} */ enuToModel: { get: function() { return this._enuToModel; } }, /** * The sun position in 3D world coordinates at the current scene time. * @memberof UniformState.prototype * @type {Cartesian3} */ sunPositionWC: { get: function() { return this._sunPositionWC; } }, /** * The sun position in 2D world coordinates at the current scene time. * @memberof UniformState.prototype * @type {Cartesian3} */ sunPositionColumbusView: { get: function() { return this._sunPositionColumbusView; } }, /** * A normalized vector to the sun in 3D world coordinates at the current scene time. Even in 2D or * Columbus View mode, this returns the direction to the sun in the 3D scene. * @memberof UniformState.prototype * @type {Cartesian3} */ sunDirectionWC: { get: function() { return this._sunDirectionWC; } }, /** * A normalized vector to the sun in eye coordinates at the current scene time. In 3D mode, this * returns the actual vector from the camera position to the sun position. In 2D and Columbus View, it returns * the vector from the equivalent 3D camera position to the position of the sun in the 3D scene. * @memberof UniformState.prototype * @type {Cartesian3} */ sunDirectionEC: { get: function() { return this._sunDirectionEC; } }, /** * A normalized vector to the moon in eye coordinates at the current scene time. In 3D mode, this * returns the actual vector from the camera position to the moon position. In 2D and Columbus View, it returns * the vector from the equivalent 3D camera position to the position of the moon in the 3D scene. * @memberof UniformState.prototype * @type {Cartesian3} */ moonDirectionEC: { get: function() { return this._moonDirectionEC; } }, /** * A normalized vector to the scene's light source in 3D world coordinates. Even in 2D or * Columbus View mode, this returns the direction to the light in the 3D scene. * @memberof UniformState.prototype * @type {Cartesian3} */ lightDirectionWC: { get: function() { return this._lightDirectionWC; } }, /** * A normalized vector to the scene's light source in eye coordinates. In 3D mode, this * returns the actual vector from the camera position to the light. In 2D and Columbus View, it returns * the vector from the equivalent 3D camera position in the 3D scene. * @memberof UniformState.prototype * @type {Cartesian3} */ lightDirectionEC: { get: function() { return this._lightDirectionEC; } }, /** * The color of light emitted by the scene's light source. This is equivalent to the light * color multiplied by the light intensity limited to a maximum luminance of 1.0 suitable * for non-HDR lighting. * @memberof UniformState.prototype * @type {Cartesian3} */ lightColor: { get: function() { return this._lightColor; } }, /** * The high dynamic range color of light emitted by the scene's light source. This is equivalent to * the light color multiplied by the light intensity suitable for HDR lighting. * @memberof UniformState.prototype * @type {Cartesian3} */ lightColorHdr: { get: function() { return this._lightColorHdr; } }, /** * The high bits of the camera position. * @memberof UniformState.prototype * @type {Cartesian3} */ encodedCameraPositionMCHigh: { get: function() { cleanEncodedCameraPositionMC(this); return this._encodedCameraPositionMC.high; } }, /** * The low bits of the camera position. * @memberof UniformState.prototype * @type {Cartesian3} */ encodedCameraPositionMCLow: { get: function() { cleanEncodedCameraPositionMC(this); return this._encodedCameraPositionMC.low; } }, /** * A 3x3 matrix that transforms from True Equator Mean Equinox (TEME) axes to the * pseudo-fixed axes at the Scene's current time. * @memberof UniformState.prototype * @type {Matrix3} */ temeToPseudoFixedMatrix: { get: function() { return this._temeToPseudoFixed; } }, /** * Gets the scaling factor for transforming from the canvas * pixel space to canvas coordinate space. * @memberof UniformState.prototype * @type {number} */ pixelRatio: { get: function() { return this._pixelRatio; } }, /** * A scalar used to mix a color with the fog color based on the distance to the camera. * @memberof UniformState.prototype * @type {number} */ fogDensity: { get: function() { return this._fogDensity; } }, /** * A scalar used to mix a color with the fog color based on the distance to the camera. * @memberof UniformState.prototype * @type {number} */ fogVisualDensityScalar: { get: function() { return this._fogVisualDensityScalar; } }, /** * A scalar used as a minimum value when brightening fog * @memberof UniformState.prototype * @type {number} */ fogMinimumBrightness: { get: function() { return this._fogMinimumBrightness; } }, /** * A color shift to apply to the atmosphere color in HSB. * @memberof UniformState.prototype * @type {Cartesian3} */ atmosphereHsbShift: { get: function() { return this._atmosphereHsbShift; } }, /** * The intensity of the light that is used for computing the atmosphere color * @memberof UniformState.prototype * @type {number} */ atmosphereLightIntensity: { get: function() { return this._atmosphereLightIntensity; } }, /** * The Rayleigh scattering coefficient used in the atmospheric scattering equations for the sky atmosphere. * @memberof UniformState.prototype * @type {Cartesian3} */ atmosphereRayleighCoefficient: { get: function() { return this._atmosphereRayleighCoefficient; } }, /** * The Rayleigh scale height used in the atmospheric scattering equations for the sky atmosphere, in meters. * @memberof UniformState.prototype * @type {number} */ atmosphereRayleighScaleHeight: { get: function() { return this._atmosphereRayleighScaleHeight; } }, /** * The Mie scattering coefficient used in the atmospheric scattering equations for the sky atmosphere. * @memberof UniformState.prototype * @type {Cartesian3} */ atmosphereMieCoefficient: { get: function() { return this._atmosphereMieCoefficient; } }, /** * The Mie scale height used in the atmospheric scattering equations for the sky atmosphere, in meters. * @memberof UniformState.prototype * @type {number} */ atmosphereMieScaleHeight: { get: function() { return this._atmosphereMieScaleHeight; } }, /** * The anisotropy of the medium to consider for Mie scattering. * @memberof UniformState.prototype * @type {number} */ atmosphereMieAnisotropy: { get: function() { return this._atmosphereMieAnisotropy; } }, /** * Which light source to use for dynamically lighting the atmosphere * * @memberof UniformState.prototype * @type {DynamicAtmosphereLightingType} */ atmosphereDynamicLighting: { get: function() { return this._atmosphereDynamicLighting; } }, /** * A scalar that represents the geometric tolerance per meter * @memberof UniformState.prototype * @type {number} */ geometricToleranceOverMeter: { get: function() { return this._geometricToleranceOverMeter; } }, /** * @memberof UniformState.prototype * @type {Pass} */ pass: { get: function() { return this._pass; } }, /** * The current background color * @memberof UniformState.prototype * @type {Color} */ backgroundColor: { get: function() { return this._backgroundColor; } }, /** * The look up texture used to find the BRDF for a material * @memberof UniformState.prototype * @type {Texture} */ brdfLut: { get: function() { return this._brdfLut; } }, /** * The environment map of the scene * @memberof UniformState.prototype * @type {CubeMap} */ environmentMap: { get: function() { return this._environmentMap; } }, /** * The spherical harmonic coefficients of the scene. * @memberof UniformState.prototype * @type {Cartesian3[]} */ sphericalHarmonicCoefficients: { get: function() { return this._sphericalHarmonicCoefficients; } }, /** * The specular environment cube map of the scene. * @memberof UniformState.prototype * @type {Texture} */ specularEnvironmentMaps: { get: function() { return this._specularEnvironmentMaps; } }, /** * The maximum level-of-detail of the specular environment cube map of the scene. * @memberof UniformState.prototype * @type {number} */ specularEnvironmentMapsMaximumLOD: { get: function() { return this._specularEnvironmentMapsMaximumLOD; } }, /** * The splitter position to use when rendering with a splitter. This will be in pixel coordinates relative to the canvas. * @memberof UniformState.prototype * @type {number} */ splitPosition: { get: function() { return this._splitPosition; } }, /** * The distance from the camera at which to disable the depth test of billboards, labels and points * to, for example, prevent clipping against terrain. When set to zero, the depth test should always * be applied. When less than zero, the depth test should never be applied. * * @memberof UniformState.prototype * @type {number} */ minimumDisableDepthTestDistance: { get: function() { return this._minimumDisableDepthTestDistance; } }, /** * The highlight color of unclassified 3D Tiles. * * @memberof UniformState.prototype * @type {Color} */ invertClassificationColor: { get: function() { return this._invertClassificationColor; } }, /** * Whether or not the current projection is orthographic in 3D. * * @memberOf UniformState.prototype * @type {boolean} */ orthographicIn3D: { get: function() { return this._orthographicIn3D; } }, /** * The current ellipsoid. * * @memberOf UniformState.prototype * @type {Ellipsoid} */ ellipsoid: { get: function() { return this._ellipsoid ?? Ellipsoid_default.default; } } }); function setView(uniformState, matrix) { Matrix4_default.clone(matrix, uniformState._view); Matrix4_default.getMatrix3(matrix, uniformState._viewRotation); uniformState._view3DDirty = true; uniformState._inverseView3DDirty = true; uniformState._modelViewDirty = true; uniformState._modelView3DDirty = true; uniformState._modelViewRelativeToEyeDirty = true; uniformState._inverseModelViewDirty = true; uniformState._inverseModelView3DDirty = true; uniformState._viewProjectionDirty = true; uniformState._inverseViewProjectionDirty = true; uniformState._modelViewProjectionDirty = true; uniformState._modelViewProjectionRelativeToEyeDirty = true; uniformState._modelViewInfiniteProjectionDirty = true; uniformState._normalDirty = true; uniformState._inverseNormalDirty = true; uniformState._normal3DDirty = true; uniformState._inverseNormal3DDirty = true; } function setInverseView(uniformState, matrix) { Matrix4_default.clone(matrix, uniformState._inverseView); Matrix4_default.getMatrix3(matrix, uniformState._inverseViewRotation); } function setProjection(uniformState, matrix) { Matrix4_default.clone(matrix, uniformState._projection); uniformState._inverseProjectionDirty = true; uniformState._viewProjectionDirty = true; uniformState._inverseViewProjectionDirty = true; uniformState._modelViewProjectionDirty = true; uniformState._modelViewProjectionRelativeToEyeDirty = true; } function setInfiniteProjection(uniformState, matrix) { Matrix4_default.clone(matrix, uniformState._infiniteProjection); uniformState._modelViewInfiniteProjectionDirty = true; } var surfacePositionScratch = new Cartesian3_default(); var enuTransformScratch = new Matrix4_default(); function setCamera(uniformState, camera) { Cartesian3_default.clone(camera.positionWC, uniformState._cameraPosition); Cartesian3_default.clone(camera.directionWC, uniformState._cameraDirection); Cartesian3_default.clone(camera.rightWC, uniformState._cameraRight); Cartesian3_default.clone(camera.upWC, uniformState._cameraUp); const ellipsoid = uniformState._ellipsoid; let surfacePosition; const positionCartographic = camera.positionCartographic; if (!defined_default(positionCartographic)) { uniformState._eyeHeight = -ellipsoid.maximumRadius; if (Cartesian3_default.magnitude(camera.positionWC) > 0) { uniformState._eyeEllipsoidNormalEC = Cartesian3_default.normalize( camera.positionWC, uniformState._eyeEllipsoidNormalEC ); } surfacePosition = ellipsoid.scaleToGeodeticSurface( camera.positionWC, surfacePositionScratch ); } else { uniformState._eyeHeight = positionCartographic.height; uniformState._eyeEllipsoidNormalEC = ellipsoid.geodeticSurfaceNormalCartographic( positionCartographic, uniformState._eyeEllipsoidNormalEC ); surfacePosition = Cartesian3_default.fromRadians( positionCartographic.longitude, positionCartographic.latitude, 0, ellipsoid, surfacePositionScratch ); } uniformState._encodedCameraPositionMCDirty = true; if (!defined_default(surfacePosition)) { return; } uniformState._eyeEllipsoidNormalEC = Matrix3_default.multiplyByVector( uniformState._viewRotation, uniformState._eyeEllipsoidNormalEC, uniformState._eyeEllipsoidNormalEC ); const enuToWorld = Transforms_default.eastNorthUpToFixedFrame( surfacePosition, ellipsoid, enuTransformScratch ); uniformState._enuToModel = Matrix4_default.multiplyTransformation( uniformState.inverseModel, enuToWorld, uniformState._enuToModel ); uniformState._modelToEnu = Matrix4_default.inverseTransformation( uniformState._enuToModel, uniformState._modelToEnu ); if (!Math_default.equalsEpsilon( ellipsoid._radii.x, ellipsoid._radii.y, Math_default.EPSILON15 )) { return; } uniformState._eyeEllipsoidCurvature = ellipsoid.getLocalCurvature( surfacePosition, uniformState._eyeEllipsoidCurvature ); } var transformMatrix = new Matrix3_default(); var sunCartographicScratch = new Cartographic_default(); function setSunAndMoonDirections(uniformState, frameState) { Transforms_default.computeIcrfToCentralBodyFixedMatrix( frameState.time, transformMatrix ); let position = Simon1994PlanetaryPositions_default.computeSunPositionInEarthInertialFrame( frameState.time, uniformState._sunPositionWC ); Matrix3_default.multiplyByVector(transformMatrix, position, position); Cartesian3_default.normalize(position, uniformState._sunDirectionWC); position = Matrix3_default.multiplyByVector( uniformState.viewRotation3D, position, uniformState._sunDirectionEC ); Cartesian3_default.normalize(position, position); position = Simon1994PlanetaryPositions_default.computeMoonPositionInEarthInertialFrame( frameState.time, uniformState._moonDirectionEC ); Matrix3_default.multiplyByVector(transformMatrix, position, position); Matrix3_default.multiplyByVector(uniformState.viewRotation3D, position, position); Cartesian3_default.normalize(position, position); const projection = frameState.mapProjection; const ellipsoid = projection.ellipsoid; const sunCartographic = ellipsoid.cartesianToCartographic( uniformState._sunPositionWC, sunCartographicScratch ); projection.project(sunCartographic, uniformState._sunPositionColumbusView); } UniformState.prototype.updateCamera = function(camera) { setView(this, camera.viewMatrix); setInverseView(this, camera.inverseViewMatrix); setCamera(this, camera); this._entireFrustum.x = camera.frustum.near; this._entireFrustum.y = camera.frustum.far; this.updateFrustum(camera.frustum); this._orthographicIn3D = this._mode !== SceneMode_default.SCENE2D && camera.frustum instanceof OrthographicFrustum_default; }; UniformState.prototype.updateFrustum = function(frustum) { setProjection(this, frustum.projectionMatrix); if (defined_default(frustum.infiniteProjectionMatrix)) { setInfiniteProjection(this, frustum.infiniteProjectionMatrix); } this._currentFrustum.x = frustum.near; this._currentFrustum.y = frustum.far; this._farDepthFromNearPlusOne = frustum.far - frustum.near + 1; this._log2FarDepthFromNearPlusOne = Math_default.log2( this._farDepthFromNearPlusOne ); this._oneOverLog2FarDepthFromNearPlusOne = 1 / this._log2FarDepthFromNearPlusOne; const offCenterFrustum = frustum.offCenterFrustum; if (defined_default(offCenterFrustum)) { frustum = offCenterFrustum; } this._frustumPlanes.x = frustum.top; this._frustumPlanes.y = frustum.bottom; this._frustumPlanes.z = frustum.left; this._frustumPlanes.w = frustum.right; }; UniformState.prototype.updatePass = function(pass) { this._pass = pass; }; var EMPTY_ARRAY = []; var defaultLight = new SunLight_default(); UniformState.prototype.update = function(frameState) { this._mode = frameState.mode; this._mapProjection = frameState.mapProjection; this._ellipsoid = frameState.mapProjection.ellipsoid; this._pixelRatio = frameState.pixelRatio; const camera = frameState.camera; this.updateCamera(camera); if (frameState.mode === SceneMode_default.SCENE2D) { this._frustum2DWidth = camera.frustum.right - camera.frustum.left; this._eyeHeight2D.x = this._frustum2DWidth * 0.5; this._eyeHeight2D.y = this._eyeHeight2D.x * this._eyeHeight2D.x; } else { this._frustum2DWidth = 0; this._eyeHeight2D.x = 0; this._eyeHeight2D.y = 0; } setSunAndMoonDirections(this, frameState); const light = frameState.light ?? defaultLight; if (light instanceof SunLight_default) { this._lightDirectionWC = Cartesian3_default.clone( this._sunDirectionWC, this._lightDirectionWC ); this._lightDirectionEC = Cartesian3_default.clone( this._sunDirectionEC, this._lightDirectionEC ); } else { this._lightDirectionWC = Cartesian3_default.normalize( Cartesian3_default.negate(light.direction, this._lightDirectionWC), this._lightDirectionWC ); this._lightDirectionEC = Matrix3_default.multiplyByVector( this.viewRotation3D, this._lightDirectionWC, this._lightDirectionEC ); } const lightColor = light.color; let lightColorHdr = Cartesian3_default.fromElements( lightColor.red, lightColor.green, lightColor.blue, this._lightColorHdr ); lightColorHdr = Cartesian3_default.multiplyByScalar( lightColorHdr, light.intensity, lightColorHdr ); const maximumComponent = Cartesian3_default.maximumComponent(lightColorHdr); if (maximumComponent > 1) { Cartesian3_default.divideByScalar( lightColorHdr, maximumComponent, this._lightColor ); } else { Cartesian3_default.clone(lightColorHdr, this._lightColor); } const brdfLutGenerator = frameState.brdfLutGenerator; const brdfLut = defined_default(brdfLutGenerator) ? brdfLutGenerator.colorTexture : void 0; this._brdfLut = brdfLut; this._environmentMap = frameState.environmentMap ?? frameState.context.defaultCubeMap; this._sphericalHarmonicCoefficients = frameState.sphericalHarmonicCoefficients ?? EMPTY_ARRAY; this._specularEnvironmentMaps = frameState.specularEnvironmentMaps; this._specularEnvironmentMapsMaximumLOD = frameState.specularEnvironmentMapsMaximumLOD; this._fogDensity = frameState.fog.density; this._fogVisualDensityScalar = frameState.fog.visualDensityScalar; this._fogMinimumBrightness = frameState.fog.minimumBrightness; const atmosphere = frameState.atmosphere; if (defined_default(atmosphere)) { this._atmosphereHsbShift = Cartesian3_default.fromElements( atmosphere.hueShift, atmosphere.saturationShift, atmosphere.brightnessShift, this._atmosphereHsbShift ); this._atmosphereLightIntensity = atmosphere.lightIntensity; this._atmosphereRayleighCoefficient = Cartesian3_default.clone( atmosphere.rayleighCoefficient, this._atmosphereRayleighCoefficient ); this._atmosphereRayleighScaleHeight = atmosphere.rayleighScaleHeight; this._atmosphereMieCoefficient = Cartesian3_default.clone( atmosphere.mieCoefficient, this._atmosphereMieCoefficient ); this._atmosphereMieScaleHeight = atmosphere.mieScaleHeight; this._atmosphereMieAnisotropy = atmosphere.mieAnisotropy; this._atmosphereDynamicLighting = atmosphere.dynamicLighting; } this._invertClassificationColor = frameState.invertClassificationColor; this._frameState = frameState; this._temeToPseudoFixed = Transforms_default.computeTemeToPseudoFixedMatrix( frameState.time, this._temeToPseudoFixed ); this._splitPosition = frameState.splitPosition * frameState.context.drawingBufferWidth; const fov = camera.frustum.fov; const viewport = this._viewport; let pixelSizePerMeter; if (defined_default(fov)) { if (viewport.height > viewport.width) { pixelSizePerMeter = Math.tan(0.5 * fov) * 2 / viewport.height; } else { pixelSizePerMeter = Math.tan(0.5 * fov) * 2 / viewport.width; } } else { pixelSizePerMeter = 1 / Math.max(viewport.width, viewport.height); } this._geometricToleranceOverMeter = pixelSizePerMeter * frameState.maximumScreenSpaceError; Color_default.clone(frameState.backgroundColor, this._backgroundColor); this._minimumDisableDepthTestDistance = frameState.minimumDisableDepthTestDistance; this._minimumDisableDepthTestDistance *= this._minimumDisableDepthTestDistance; if (this._minimumDisableDepthTestDistance === Number.POSITIVE_INFINITY) { this._minimumDisableDepthTestDistance = -1; } }; function cleanViewport(uniformState) { if (uniformState._viewportDirty) { const v3 = uniformState._viewport; Matrix4_default.computeOrthographicOffCenter( v3.x, v3.x + v3.width, v3.y, v3.y + v3.height, 0, 1, uniformState._viewportOrthographicMatrix ); Matrix4_default.computeViewportTransformation( v3, 0, 1, uniformState._viewportTransformation ); uniformState._viewportDirty = false; } } function cleanInverseProjection(uniformState) { if (uniformState._inverseProjectionDirty) { uniformState._inverseProjectionDirty = false; if (uniformState._mode !== SceneMode_default.SCENE2D && uniformState._mode !== SceneMode_default.MORPHING && !uniformState._orthographicIn3D) { Matrix4_default.inverse( uniformState._projection, uniformState._inverseProjection ); } else { Matrix4_default.clone(Matrix4_default.ZERO, uniformState._inverseProjection); } } } function cleanModelView(uniformState) { if (uniformState._modelViewDirty) { uniformState._modelViewDirty = false; Matrix4_default.multiplyTransformation( uniformState._view, uniformState._model, uniformState._modelView ); } } function cleanModelView3D(uniformState) { if (uniformState._modelView3DDirty) { uniformState._modelView3DDirty = false; Matrix4_default.multiplyTransformation( uniformState.view3D, uniformState._model, uniformState._modelView3D ); } } function cleanInverseModelView(uniformState) { if (uniformState._inverseModelViewDirty) { uniformState._inverseModelViewDirty = false; Matrix4_default.inverse(uniformState.modelView, uniformState._inverseModelView); } } function cleanInverseModelView3D(uniformState) { if (uniformState._inverseModelView3DDirty) { uniformState._inverseModelView3DDirty = false; Matrix4_default.inverse(uniformState.modelView3D, uniformState._inverseModelView3D); } } function cleanViewProjection(uniformState) { if (uniformState._viewProjectionDirty) { uniformState._viewProjectionDirty = false; Matrix4_default.multiply( uniformState._projection, uniformState._view, uniformState._viewProjection ); } } function cleanInverseViewProjection(uniformState) { if (uniformState._inverseViewProjectionDirty) { uniformState._inverseViewProjectionDirty = false; Matrix4_default.inverse( uniformState.viewProjection, uniformState._inverseViewProjection ); } } function cleanModelViewProjection(uniformState) { if (uniformState._modelViewProjectionDirty) { uniformState._modelViewProjectionDirty = false; Matrix4_default.multiply( uniformState._projection, uniformState.modelView, uniformState._modelViewProjection ); } } function cleanModelViewRelativeToEye(uniformState) { if (uniformState._modelViewRelativeToEyeDirty) { uniformState._modelViewRelativeToEyeDirty = false; const mv = uniformState.modelView; const mvRte = uniformState._modelViewRelativeToEye; mvRte[0] = mv[0]; mvRte[1] = mv[1]; mvRte[2] = mv[2]; mvRte[3] = mv[3]; mvRte[4] = mv[4]; mvRte[5] = mv[5]; mvRte[6] = mv[6]; mvRte[7] = mv[7]; mvRte[8] = mv[8]; mvRte[9] = mv[9]; mvRte[10] = mv[10]; mvRte[11] = mv[11]; mvRte[12] = 0; mvRte[13] = 0; mvRte[14] = 0; mvRte[15] = mv[15]; } } function cleanInverseModelViewProjection(uniformState) { if (uniformState._inverseModelViewProjectionDirty) { uniformState._inverseModelViewProjectionDirty = false; Matrix4_default.inverse( uniformState.modelViewProjection, uniformState._inverseModelViewProjection ); } } function cleanModelViewProjectionRelativeToEye(uniformState) { if (uniformState._modelViewProjectionRelativeToEyeDirty) { uniformState._modelViewProjectionRelativeToEyeDirty = false; Matrix4_default.multiply( uniformState._projection, uniformState.modelViewRelativeToEye, uniformState._modelViewProjectionRelativeToEye ); } } function cleanModelViewInfiniteProjection(uniformState) { if (uniformState._modelViewInfiniteProjectionDirty) { uniformState._modelViewInfiniteProjectionDirty = false; Matrix4_default.multiply( uniformState._infiniteProjection, uniformState.modelView, uniformState._modelViewInfiniteProjection ); } } function cleanNormal(uniformState) { if (uniformState._normalDirty) { uniformState._normalDirty = false; const m = uniformState._normal; Matrix4_default.getMatrix3(uniformState.inverseModelView, m); Matrix3_default.transpose(m, m); } } function cleanNormal3D(uniformState) { if (uniformState._normal3DDirty) { uniformState._normal3DDirty = false; const m = uniformState._normal3D; Matrix4_default.getMatrix3(uniformState.inverseModelView3D, m); Matrix3_default.transpose(m, m); } } function cleanInverseNormal(uniformState) { if (uniformState._inverseNormalDirty) { uniformState._inverseNormalDirty = false; const m = uniformState._inverseNormal; Matrix4_default.getMatrix3(uniformState.modelView, m); Matrix3_default.transpose(m, m); } } function cleanInverseNormal3D(uniformState) { if (uniformState._inverseNormal3DDirty) { uniformState._inverseNormal3DDirty = false; const m = uniformState._inverseNormal3D; Matrix4_default.getMatrix3(uniformState.modelView3D, m); Matrix3_default.transpose(m, m); } } var cameraPositionMC = new Cartesian3_default(); function cleanEncodedCameraPositionMC(uniformState) { if (uniformState._encodedCameraPositionMCDirty) { uniformState._encodedCameraPositionMCDirty = false; Matrix4_default.multiplyByPoint( uniformState.inverseModel, uniformState._cameraPosition, cameraPositionMC ); EncodedCartesian3_default.fromCartesian( cameraPositionMC, uniformState._encodedCameraPositionMC ); } } var view2Dto3DPScratch = new Cartesian3_default(); var view2Dto3DRScratch = new Cartesian3_default(); var view2Dto3DUScratch = new Cartesian3_default(); var view2Dto3DDScratch = new Cartesian3_default(); var view2Dto3DCartographicScratch = new Cartographic_default(); var view2Dto3DCartesian3Scratch = new Cartesian3_default(); var view2Dto3DMatrix4Scratch = new Matrix4_default(); function view2Dto3D(position2D, direction2D, right2D, up2D, frustum2DWidth, mode2, projection, result) { const p = view2Dto3DPScratch; p.x = position2D.y; p.y = position2D.z; p.z = position2D.x; const r2 = view2Dto3DRScratch; r2.x = right2D.y; r2.y = right2D.z; r2.z = right2D.x; const u4 = view2Dto3DUScratch; u4.x = up2D.y; u4.y = up2D.z; u4.z = up2D.x; const d = view2Dto3DDScratch; d.x = direction2D.y; d.y = direction2D.z; d.z = direction2D.x; if (mode2 === SceneMode_default.SCENE2D) { p.z = frustum2DWidth * 0.5; } const cartographic2 = projection.unproject(p, view2Dto3DCartographicScratch); cartographic2.longitude = Math_default.clamp( cartographic2.longitude, -Math.PI, Math.PI ); cartographic2.latitude = Math_default.clamp( cartographic2.latitude, -Math_default.PI_OVER_TWO, Math_default.PI_OVER_TWO ); const ellipsoid = projection.ellipsoid; const position3D = ellipsoid.cartographicToCartesian( cartographic2, view2Dto3DCartesian3Scratch ); const enuToFixed = Transforms_default.eastNorthUpToFixedFrame( position3D, ellipsoid, view2Dto3DMatrix4Scratch ); Matrix4_default.multiplyByPointAsVector(enuToFixed, r2, r2); Matrix4_default.multiplyByPointAsVector(enuToFixed, u4, u4); Matrix4_default.multiplyByPointAsVector(enuToFixed, d, d); if (!defined_default(result)) { result = new Matrix4_default(); } result[0] = r2.x; result[1] = u4.x; result[2] = -d.x; result[3] = 0; result[4] = r2.y; result[5] = u4.y; result[6] = -d.y; result[7] = 0; result[8] = r2.z; result[9] = u4.z; result[10] = -d.z; result[11] = 0; result[12] = -Cartesian3_default.dot(r2, position3D); result[13] = -Cartesian3_default.dot(u4, position3D); result[14] = Cartesian3_default.dot(d, position3D); result[15] = 1; return result; } function updateView3D(that) { if (that._view3DDirty) { if (that._mode === SceneMode_default.SCENE3D) { Matrix4_default.clone(that._view, that._view3D); } else { view2Dto3D( that._cameraPosition, that._cameraDirection, that._cameraRight, that._cameraUp, that._frustum2DWidth, that._mode, that._mapProjection, that._view3D ); } Matrix4_default.getMatrix3(that._view3D, that._viewRotation3D); that._view3DDirty = false; } } function updateInverseView3D(that) { if (that._inverseView3DDirty) { Matrix4_default.inverseTransformation(that.view3D, that._inverseView3D); Matrix4_default.getMatrix3(that._inverseView3D, that._inverseViewRotation3D); that._inverseView3DDirty = false; } } var UniformState_default = UniformState; // packages/engine/Source/Renderer/Context.js function Context(canvas, options) { Check_default.defined("canvas", canvas); const { getWebGLStub, requestWebgl1, webgl: webglOptions = {}, allowTextureFilterAnisotropic = true } = options ?? {}; webglOptions.alpha = webglOptions.alpha ?? false; webglOptions.stencil = webglOptions.stencil ?? true; webglOptions.powerPreference = webglOptions.powerPreference ?? "high-performance"; const glContext = defined_default(getWebGLStub) ? getWebGLStub(canvas, webglOptions) : getWebGLContext(canvas, webglOptions, requestWebgl1); const webgl2Supported = typeof WebGL2RenderingContext !== "undefined"; const webgl2 = webgl2Supported && glContext instanceof WebGL2RenderingContext; this._canvas = canvas; this._originalGLContext = glContext; this._gl = glContext; this._webgl2 = webgl2; this._id = createGuid_default(); this.validateFramebuffer = false; this.validateShaderProgram = false; this.logShaderCompilation = false; this._throwOnWebGLError = false; this._shaderCache = new ShaderCache_default(this); this._textureCache = new TextureCache_default(); const gl = glContext; this._stencilBits = gl.getParameter(gl.STENCIL_BITS); ContextLimits_default._maximumCombinedTextureImageUnits = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); ContextLimits_default._maximumCubeMapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); ContextLimits_default._maximumFragmentUniformVectors = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); ContextLimits_default._maximumTextureImageUnits = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); ContextLimits_default._maximumRenderbufferSize = gl.getParameter( gl.MAX_RENDERBUFFER_SIZE ); ContextLimits_default._maximumTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); ContextLimits_default._maximum3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE); ContextLimits_default._maximumVaryingVectors = gl.getParameter( gl.MAX_VARYING_VECTORS ); ContextLimits_default._maximumVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); ContextLimits_default._maximumVertexTextureImageUnits = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); ContextLimits_default._maximumVertexUniformVectors = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); ContextLimits_default._maximumSamples = this._webgl2 ? gl.getParameter(gl.MAX_SAMPLES) : 0; const aliasedLineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE); ContextLimits_default._minimumAliasedLineWidth = aliasedLineWidthRange[0]; ContextLimits_default._maximumAliasedLineWidth = aliasedLineWidthRange[1]; const aliasedPointSizeRange = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE); ContextLimits_default._minimumAliasedPointSize = aliasedPointSizeRange[0]; ContextLimits_default._maximumAliasedPointSize = aliasedPointSizeRange[1]; const maximumViewportDimensions = gl.getParameter(gl.MAX_VIEWPORT_DIMS); ContextLimits_default._maximumViewportWidth = maximumViewportDimensions[0]; ContextLimits_default._maximumViewportHeight = maximumViewportDimensions[1]; const highpFloat = gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ); ContextLimits_default._highpFloatSupported = highpFloat.precision !== 0; const highpInt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT); ContextLimits_default._highpIntSupported = highpInt.rangeMax !== 0; this._antialias = gl.getContextAttributes().antialias; this._standardDerivatives = !!getExtension(gl, ["OES_standard_derivatives"]); this._blendMinmax = !!getExtension(gl, ["EXT_blend_minmax"]); this._elementIndexUint = !!getExtension(gl, ["OES_element_index_uint"]); this._depthTexture = !!getExtension(gl, [ "WEBGL_depth_texture", "WEBKIT_WEBGL_depth_texture" ]); this._fragDepth = !!getExtension(gl, ["EXT_frag_depth"]); this._debugShaders = getExtension(gl, ["WEBGL_debug_shaders"]); this._textureFloat = !!getExtension(gl, ["OES_texture_float"]); this._textureHalfFloat = !!getExtension(gl, ["OES_texture_half_float"]); this._textureFloatLinear = !!getExtension(gl, ["OES_texture_float_linear"]); this._textureHalfFloatLinear = !!getExtension(gl, [ "OES_texture_half_float_linear" ]); this._supportsTextureLod = !!getExtension(gl, ["EXT_shader_texture_lod"]); this._colorBufferFloat = !!getExtension(gl, [ "EXT_color_buffer_float", "WEBGL_color_buffer_float" ]); this._floatBlend = !!getExtension(gl, ["EXT_float_blend"]); this._colorBufferHalfFloat = !!getExtension(gl, [ "EXT_color_buffer_half_float" ]); this._s3tc = !!getExtension(gl, [ "WEBGL_compressed_texture_s3tc", "MOZ_WEBGL_compressed_texture_s3tc", "WEBKIT_WEBGL_compressed_texture_s3tc" ]); this._pvrtc = !!getExtension(gl, [ "WEBGL_compressed_texture_pvrtc", "WEBKIT_WEBGL_compressed_texture_pvrtc" ]); this._astc = !!getExtension(gl, ["WEBGL_compressed_texture_astc"]); this._etc = !!getExtension(gl, ["WEBG_compressed_texture_etc"]); this._etc1 = !!getExtension(gl, ["WEBGL_compressed_texture_etc1"]); this._bc7 = !!getExtension(gl, ["EXT_texture_compression_bptc"]); loadKTX2_default.setKTX2SupportedFormats( this._s3tc, this._pvrtc, this._astc, this._etc, this._etc1, this._bc7 ); const textureFilterAnisotropic = allowTextureFilterAnisotropic ? getExtension(gl, [ "EXT_texture_filter_anisotropic", "WEBKIT_EXT_texture_filter_anisotropic" ]) : void 0; this._textureFilterAnisotropic = textureFilterAnisotropic; ContextLimits_default._maximumTextureFilterAnisotropy = defined_default( textureFilterAnisotropic ) ? gl.getParameter(textureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 1; let glCreateVertexArray; let glBindVertexArray; let glDeleteVertexArray; let glDrawElementsInstanced; let glDrawArraysInstanced; let glVertexAttribDivisor; let glDrawBuffers; let vertexArrayObject; let instancedArrays; let drawBuffers; if (webgl2) { const that = this; glCreateVertexArray = function() { return that._gl.createVertexArray(); }; glBindVertexArray = function(vao) { that._gl.bindVertexArray(vao); }; glDeleteVertexArray = function(vao) { that._gl.deleteVertexArray(vao); }; glDrawElementsInstanced = function(mode2, count, type, offset, instanceCount) { gl.drawElementsInstanced(mode2, count, type, offset, instanceCount); }; glDrawArraysInstanced = function(mode2, first, count, instanceCount) { gl.drawArraysInstanced(mode2, first, count, instanceCount); }; glVertexAttribDivisor = function(index, divisor) { gl.vertexAttribDivisor(index, divisor); }; glDrawBuffers = function(buffers) { gl.drawBuffers(buffers); }; } else { vertexArrayObject = getExtension(gl, ["OES_vertex_array_object"]); if (defined_default(vertexArrayObject)) { glCreateVertexArray = function() { return vertexArrayObject.createVertexArrayOES(); }; glBindVertexArray = function(vertexArray) { vertexArrayObject.bindVertexArrayOES(vertexArray); }; glDeleteVertexArray = function(vertexArray) { vertexArrayObject.deleteVertexArrayOES(vertexArray); }; } instancedArrays = getExtension(gl, ["ANGLE_instanced_arrays"]); if (defined_default(instancedArrays)) { glDrawElementsInstanced = function(mode2, count, type, offset, instanceCount) { instancedArrays.drawElementsInstancedANGLE( mode2, count, type, offset, instanceCount ); }; glDrawArraysInstanced = function(mode2, first, count, instanceCount) { instancedArrays.drawArraysInstancedANGLE( mode2, first, count, instanceCount ); }; glVertexAttribDivisor = function(index, divisor) { instancedArrays.vertexAttribDivisorANGLE(index, divisor); }; } drawBuffers = getExtension(gl, ["WEBGL_draw_buffers"]); if (defined_default(drawBuffers)) { glDrawBuffers = function(buffers) { drawBuffers.drawBuffersWEBGL(buffers); }; } } this.glCreateVertexArray = glCreateVertexArray; this.glBindVertexArray = glBindVertexArray; this.glDeleteVertexArray = glDeleteVertexArray; this.glDrawElementsInstanced = glDrawElementsInstanced; this.glDrawArraysInstanced = glDrawArraysInstanced; this.glVertexAttribDivisor = glVertexAttribDivisor; this.glDrawBuffers = glDrawBuffers; this._vertexArrayObject = !!vertexArrayObject; this._instancedArrays = !!instancedArrays; this._drawBuffers = !!drawBuffers; ContextLimits_default._maximumDrawBuffers = this.drawBuffers ? gl.getParameter(WebGLConstants_default.MAX_DRAW_BUFFERS) : 1; ContextLimits_default._maximumColorAttachments = this.drawBuffers ? gl.getParameter(WebGLConstants_default.MAX_COLOR_ATTACHMENTS) : 1; this._clearColor = new Color_default(0, 0, 0, 0); this._clearDepth = 1; this._clearStencil = 0; const us = new UniformState_default(); const ps = new PassState_default(this); const rs = RenderState_default.fromCache(); this._defaultPassState = ps; this._defaultRenderState = rs; this._defaultTexture = void 0; this._defaultEmissiveTexture = void 0; this._defaultNormalTexture = void 0; this._defaultCubeMap = void 0; this._us = us; this._currentRenderState = rs; this._currentPassState = ps; this._currentFramebuffer = void 0; this._maxFrameTextureUnitIndex = 0; this._vertexAttribDivisors = []; this._previousDrawInstanced = false; for (let i = 0; i < ContextLimits_default._maximumVertexAttributes; i++) { this._vertexAttribDivisors.push(0); } this._pickObjects = /* @__PURE__ */ new Map(); this._nextPickColor = new Uint32Array(1); this.options = { getWebGLStub, requestWebgl1, webgl: webglOptions, allowTextureFilterAnisotropic }; this.cache = {}; RenderState_default.apply(gl, rs, ps); } function getWebGLContext(canvas, webglOptions, requestWebgl1) { if (typeof WebGLRenderingContext === "undefined") { throw new RuntimeError_default( "The browser does not support WebGL. Visit http://get.webgl.org." ); } const webgl2Supported = typeof WebGL2RenderingContext !== "undefined"; if (!requestWebgl1 && !webgl2Supported) { requestWebgl1 = true; } const contextType = requestWebgl1 ? "webgl" : "webgl2"; const glContext = canvas.getContext(contextType, webglOptions); if (!defined_default(glContext)) { throw new RuntimeError_default( "The browser supports WebGL, but initialization failed." ); } return glContext; } function errorToString(gl, error) { let message = "WebGL Error: "; switch (error) { case gl.INVALID_ENUM: message += "INVALID_ENUM"; break; case gl.INVALID_VALUE: message += "INVALID_VALUE"; break; case gl.INVALID_OPERATION: message += "INVALID_OPERATION"; break; case gl.OUT_OF_MEMORY: message += "OUT_OF_MEMORY"; break; case gl.CONTEXT_LOST_WEBGL: message += "CONTEXT_LOST_WEBGL lost"; break; default: message += `Unknown (${error})`; } return message; } function createErrorMessage(gl, glFunc, glFuncArguments, error) { let message = `${errorToString(gl, error)}: ${glFunc.name}(`; for (let i = 0; i < glFuncArguments.length; ++i) { if (i !== 0) { message += ", "; } message += glFuncArguments[i]; } message += ");"; return message; } function throwOnError(gl, glFunc, glFuncArguments) { const error = gl.getError(); if (error !== gl.NO_ERROR) { throw new RuntimeError_default( createErrorMessage(gl, glFunc, glFuncArguments, error) ); } } function makeGetterSetter(gl, propertyName, logFunction) { return { get: function() { const value = gl[propertyName]; logFunction(gl, `get: ${propertyName}`, value); return gl[propertyName]; }, set: function(value) { gl[propertyName] = value; logFunction(gl, `set: ${propertyName}`, value); } }; } function wrapGL(gl, logFunction) { if (!defined_default(logFunction)) { return gl; } function wrapFunction2(property) { return function() { const result = property.apply(gl, arguments); logFunction(gl, property, arguments); return result; }; } const glWrapper = {}; for (const propertyName in gl) { const property = gl[propertyName]; if (property instanceof Function) { glWrapper[propertyName] = wrapFunction2(property); } else { Object.defineProperty( glWrapper, propertyName, makeGetterSetter(gl, propertyName, logFunction) ); } } return glWrapper; } function getExtension(gl, names) { const length2 = names.length; for (let i = 0; i < length2; ++i) { const extension = gl.getExtension(names[i]); if (extension) { return extension; } } return void 0; } var defaultFramebufferMarker = {}; Object.defineProperties(Context.prototype, { id: { get: function() { return this._id; } }, webgl2: { get: function() { return this._webgl2; } }, canvas: { get: function() { return this._canvas; } }, shaderCache: { get: function() { return this._shaderCache; } }, textureCache: { get: function() { return this._textureCache; } }, uniformState: { get: function() { return this._us; } }, /** * The number of stencil bits per pixel in the default bound framebuffer. The minimum is eight bits. * @memberof Context.prototype * @type {number} * @see {@link https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml|glGet} with STENCIL_BITS. */ stencilBits: { get: function() { return this._stencilBits; } }, /** * true if the WebGL context supports stencil buffers. * Stencil buffers are not supported by all systems. * @memberof Context.prototype * @type {boolean} */ stencilBuffer: { get: function() { return this._stencilBits >= 8; } }, /** * true if the WebGL context supports antialiasing. By default * antialiasing is requested, but it is not supported by all systems. * @memberof Context.prototype * @type {boolean} */ antialias: { get: function() { return this._antialias; } }, /** * true if the WebGL context supports multisample antialiasing. Requires * WebGL2. * @memberof Context.prototype * @type {boolean} */ msaa: { get: function() { return this._webgl2; } }, /** * true if the OES_standard_derivatives extension is supported. This * extension provides access to dFdx, dFdy, and fwidth * functions from GLSL. A shader using these functions still needs to explicitly enable the * extension with #extension GL_OES_standard_derivatives : enable. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/gles/extensions/OES/OES_standard_derivatives.txt|OES_standard_derivatives} */ standardDerivatives: { get: function() { return this._standardDerivatives || this._webgl2; } }, /** * true if the EXT_float_blend extension is supported. This * extension enables blending with 32-bit float values. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_float_blend/} */ floatBlend: { get: function() { return this._floatBlend; } }, /** * true if the EXT_blend_minmax extension is supported. This * extension extends blending capabilities by adding two new blend equations: * the minimum or maximum color components of the source and destination colors. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_blend_minmax/} */ blendMinmax: { get: function() { return this._blendMinmax || this._webgl2; } }, /** * true if the OES_element_index_uint extension is supported. This * extension allows the use of unsigned int indices, which can improve performance by * eliminating batch breaking caused by unsigned short indices. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/|OES_element_index_uint} */ elementIndexUint: { get: function() { return this._elementIndexUint || this._webgl2; } }, /** * true if WEBGL_depth_texture is supported. This extension provides * access to depth textures that, for example, can be attached to framebuffers for shadow mapping. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/|WEBGL_depth_texture} */ depthTexture: { get: function() { return this._depthTexture || this._webgl2; } }, /** * true if OES_texture_float is supported. This extension provides * access to floating point textures that, for example, can be attached to framebuffers for high dynamic range. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_float/} */ floatingPointTexture: { get: function() { return this._webgl2 || this._textureFloat; } }, /** * true if OES_texture_half_float is supported. This extension provides * access to floating point textures that, for example, can be attached to framebuffers for high dynamic range. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/} */ halfFloatingPointTexture: { get: function() { return this._webgl2 || this._textureHalfFloat; } }, /** * true if OES_texture_float_linear is supported. This extension provides * access to linear sampling methods for minification and magnification filters of floating-point textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/} */ textureFloatLinear: { get: function() { return this._textureFloatLinear; } }, /** * true if OES_texture_half_float_linear is supported. This extension provides * access to linear sampling methods for minification and magnification filters of half floating-point textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/OES_texture_half_float_linear/} */ textureHalfFloatLinear: { get: function() { return this._webgl2 && this._textureFloatLinear || !this._webgl2 && this._textureHalfFloatLinear; } }, /** * true if EXT_shader_texture_lod is supported. This extension provides * access to explicit LOD selection in texture sampling functions. * @memberof Context.prototype * @type {boolean} * @see {@link https://registry.khronos.org/webgl/extensions/EXT_shader_texture_lod/} */ supportsTextureLod: { get: function() { return this._webgl2 || this._supportsTextureLod; } }, /** * true if EXT_texture_filter_anisotropic is supported. This extension provides * access to anisotropic filtering for textured surfaces at an oblique angle from the viewer. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/} */ textureFilterAnisotropic: { get: function() { return !!this._textureFilterAnisotropic; } }, /** * true if WEBGL_compressed_texture_s3tc is supported. This extension provides * access to DXT compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/} */ s3tc: { get: function() { return this._s3tc; } }, /** * true if WEBGL_compressed_texture_pvrtc is supported. This extension provides * access to PVR compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/} */ pvrtc: { get: function() { return this._pvrtc; } }, /** * true if WEBGL_compressed_texture_astc is supported. This extension provides * access to ASTC compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/} */ astc: { get: function() { return this._astc; } }, /** * true if WEBGL_compressed_texture_etc is supported. This extension provides * access to ETC compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc/} */ etc: { get: function() { return this._etc; } }, /** * true if WEBGL_compressed_texture_etc1 is supported. This extension provides * access to ETC1 compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/} */ etc1: { get: function() { return this._etc1; } }, /** * true if EXT_texture_compression_bptc is supported. This extension provides * access to BC7 compressed textures. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_bptc/} */ bc7: { get: function() { return this._bc7; } }, /** * true if S3TC, PVRTC, ASTC, ETC, ETC1, or BC7 compression is supported. * @memberof Context.prototype * @type {boolean} */ supportsBasis: { get: function() { return this._s3tc || this._pvrtc || this._astc || this._etc || this._etc1 || this._bc7; } }, /** * true if the OES_vertex_array_object extension is supported. This * extension can improve performance by reducing the overhead of switching vertex arrays. * When enabled, this extension is automatically used by {@link VertexArray}. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/|OES_vertex_array_object} */ vertexArrayObject: { get: function() { return this._vertexArrayObject || this._webgl2; } }, /** * true if the EXT_frag_depth extension is supported. This * extension provides access to the gl_FragDepthEXT built-in output variable * from GLSL fragment shaders. A shader using these functions still needs to explicitly enable the * extension with #extension GL_EXT_frag_depth : enable. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/webgl/extensions/EXT_frag_depth/|EXT_frag_depth} */ fragmentDepth: { get: function() { return this._fragDepth || this._webgl2; } }, /** * true if the ANGLE_instanced_arrays extension is supported. This * extension provides access to instanced rendering. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays} */ instancedArrays: { get: function() { return this._instancedArrays || this._webgl2; } }, /** * true if the EXT_color_buffer_float extension is supported. This * extension makes the gl.RGBA32F format color renderable. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/WEBGL_color_buffer_float/} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/} */ colorBufferFloat: { get: function() { return this._colorBufferFloat; } }, /** * true if the EXT_color_buffer_half_float extension is supported. This * extension makes the format gl.RGBA16F format color renderable. * @memberof Context.prototype * @type {boolean} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_half_float/} * @see {@link https://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float/} */ colorBufferHalfFloat: { get: function() { return this._webgl2 && this._colorBufferFloat || !this._webgl2 && this._colorBufferHalfFloat; } }, /** * true if the WEBGL_draw_buffers extension is supported. This * extensions provides support for multiple render targets. The framebuffer object can have mutiple * color attachments and the GLSL fragment shader can write to the built-in output array gl_FragData. * A shader using this feature needs to explicitly enable the extension with * #extension GL_EXT_draw_buffers : enable. * @memberof Context.prototype * @type {boolean} * @see {@link http://www.khronos.org/registry/webgl/extensions/WEBGL_draw_buffers/|WEBGL_draw_buffers} */ drawBuffers: { get: function() { return this._drawBuffers || this._webgl2; } }, debugShaders: { get: function() { return this._debugShaders; } }, throwOnWebGLError: { get: function() { return this._throwOnWebGLError; }, set: function(value) { this._throwOnWebGLError = value; this._gl = wrapGL( this._originalGLContext, value ? throwOnError : void 0 ); } }, /** * A 1x1 RGBA texture initialized to the color defined by {@link Texture.defaultColor}. * This can be used as a placeholder texture while other textures are downloaded. * @memberof Context.prototype * @type {Texture} */ defaultTexture: { get: function() { if (this._defaultTexture === void 0) { const color = Texture_default.defaultColor; this._defaultTexture = new Texture_default({ context: this, source: { width: 1, height: 1, arrayBufferView: new Uint8Array([ color.red * 255, color.green * 255, color.blue * 255, color.alpha * 255 ]) }, flipY: false }); } return this._defaultTexture; } }, /** * A 1x1 RGB texture initialized to [0, 0, 0] representing a material that is * not emissive. This can be used as a placeholder texture for emissive * textures while other textures are downloaded. * @memberof Context.prototype * @type {Texture} */ defaultEmissiveTexture: { get: function() { if (this._defaultEmissiveTexture === void 0) { this._defaultEmissiveTexture = new Texture_default({ context: this, pixelFormat: PixelFormat_default.RGB, source: { width: 1, height: 1, arrayBufferView: new Uint8Array([0, 0, 0]) }, flipY: false }); } return this._defaultEmissiveTexture; } }, /** * A 1x1 RGBA texture initialized to [128, 128, 255] to encode a tangent * space normal pointing in the +z direction, i.e. (0, 0, 1). This can * be used as a placeholder normal texture while other textures are * downloaded. * @memberof Context.prototype * @type {Texture} */ defaultNormalTexture: { get: function() { if (this._defaultNormalTexture === void 0) { this._defaultNormalTexture = new Texture_default({ context: this, pixelFormat: PixelFormat_default.RGB, source: { width: 1, height: 1, arrayBufferView: new Uint8Array([128, 128, 255]) }, flipY: false }); } return this._defaultNormalTexture; } }, /** * A cube map, where each face is a 1x1 RGBA texture initialized to * [255, 255, 255, 255]. This can be used as a placeholder cube map while * other cube maps are downloaded. * @memberof Context.prototype * @type {CubeMap} */ defaultCubeMap: { get: function() { if (this._defaultCubeMap === void 0) { const face = { width: 1, height: 1, arrayBufferView: new Uint8Array([255, 255, 255, 255]) }; this._defaultCubeMap = new CubeMap_default({ context: this, source: { positiveX: face, negativeX: face, positiveY: face, negativeY: face, positiveZ: face, negativeZ: face }, flipY: false }); } return this._defaultCubeMap; } }, /** * The drawingBufferHeight of the underlying GL context. * @memberof Context.prototype * @type {number} * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferHeight|drawingBufferHeight} */ drawingBufferHeight: { get: function() { return this._gl.drawingBufferHeight; } }, /** * The drawingBufferWidth of the underlying GL context. * @memberof Context.prototype * @type {number} * @see {@link https://www.khronos.org/registry/webgl/specs/1.0/#DOM-WebGLRenderingContext-drawingBufferWidth|drawingBufferWidth} */ drawingBufferWidth: { get: function() { return this._gl.drawingBufferWidth; } }, /** * Gets an object representing the currently bound framebuffer. While this instance is not an actual * {@link Framebuffer}, it is used to represent the default framebuffer in calls to * {@link Texture.fromFramebuffer}. * @memberof Context.prototype * @type {object} */ defaultFramebuffer: { get: function() { return defaultFramebufferMarker; } } }); function validateFramebuffer(context) { if (context.validateFramebuffer) { const gl = context._gl; const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); if (status !== gl.FRAMEBUFFER_COMPLETE) { let message; switch (status) { case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: message = "Framebuffer is not complete. Incomplete attachment: at least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero, or the color attachment point has a non-color-renderable image attached, or the depth attachment point has a non-depth-renderable image attached, or the stencil attachment point has a non-stencil-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. GL_DEPTH_COMPONENT16 is the only depth-renderable format. GL_STENCIL_INDEX8 is the only stencil-renderable format."; break; case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: message = "Framebuffer is not complete. Incomplete dimensions: not all attached images have the same width and height."; break; case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: message = "Framebuffer is not complete. Missing attachment: no images are attached to the framebuffer."; break; case gl.FRAMEBUFFER_UNSUPPORTED: message = "Framebuffer is not complete. Unsupported: the combination of internal formats of the attached images violates an implementation-dependent set of restrictions."; break; } throw new DeveloperError_default(message); } } } function applyRenderState(context, renderState, passState, clear2) { const previousRenderState = context._currentRenderState; const previousPassState = context._currentPassState; context._currentRenderState = renderState; context._currentPassState = passState; RenderState_default.partialApply( context._gl, previousRenderState, renderState, previousPassState, passState, clear2 ); } var scratchBackBufferArray; if (typeof WebGLRenderingContext !== "undefined") { scratchBackBufferArray = [WebGLConstants_default.BACK]; } function bindFramebuffer(context, framebuffer) { if (framebuffer !== context._currentFramebuffer) { context._currentFramebuffer = framebuffer; let buffers = scratchBackBufferArray; if (defined_default(framebuffer)) { framebuffer._bind(); validateFramebuffer(context); buffers = framebuffer._getActiveColorAttachments(); } else { const gl = context._gl; gl.bindFramebuffer(gl.FRAMEBUFFER, null); } if (context.drawBuffers) { context.glDrawBuffers(buffers); } } } var defaultClearCommand = new ClearCommand_default(); Context.prototype.clear = function(clearCommand, passState) { clearCommand = clearCommand ?? defaultClearCommand; passState = passState ?? this._defaultPassState; const gl = this._gl; let bitmask = 0; const c14 = clearCommand.color; const d = clearCommand.depth; const s2 = clearCommand.stencil; if (defined_default(c14)) { if (!Color_default.equals(this._clearColor, c14)) { Color_default.clone(c14, this._clearColor); gl.clearColor(c14.red, c14.green, c14.blue, c14.alpha); } bitmask |= gl.COLOR_BUFFER_BIT; } if (defined_default(d)) { if (d !== this._clearDepth) { this._clearDepth = d; gl.clearDepth(d); } bitmask |= gl.DEPTH_BUFFER_BIT; } if (defined_default(s2)) { if (s2 !== this._clearStencil) { this._clearStencil = s2; gl.clearStencil(s2); } bitmask |= gl.STENCIL_BUFFER_BIT; } const rs = clearCommand.renderState ?? this._defaultRenderState; applyRenderState(this, rs, passState, true); const framebuffer = clearCommand.framebuffer ?? passState.framebuffer; bindFramebuffer(this, framebuffer); gl.clear(bitmask); }; function beginDraw(context, framebuffer, passState, shaderProgram, renderState) { if (defined_default(framebuffer) && renderState.depthTest) { if (renderState.depthTest.enabled && !framebuffer.hasDepthAttachment) { throw new DeveloperError_default( "The depth test can not be enabled (drawCommand.renderState.depthTest.enabled) because the framebuffer (drawCommand.framebuffer) does not have a depth or depth-stencil renderbuffer." ); } } bindFramebuffer(context, framebuffer); applyRenderState(context, renderState, passState, false); shaderProgram._bind(); context._maxFrameTextureUnitIndex = Math.max( context._maxFrameTextureUnitIndex, shaderProgram.maximumTextureUnitIndex ); } function continueDraw(context, drawCommand, shaderProgram, uniformMap2) { const primitiveType = drawCommand._primitiveType; const va = drawCommand._vertexArray; let offset = drawCommand._offset; let count = drawCommand._count; const instanceCount = drawCommand.instanceCount; if (!PrimitiveType_default.validate(primitiveType)) { throw new DeveloperError_default( "drawCommand.primitiveType is required and must be valid." ); } Check_default.defined("drawCommand.vertexArray", va); Check_default.typeOf.number.greaterThanOrEquals("drawCommand.offset", offset, 0); if (defined_default(count)) { Check_default.typeOf.number.greaterThanOrEquals("drawCommand.count", count, 0); } Check_default.typeOf.number.greaterThanOrEquals( "drawCommand.instanceCount", instanceCount, 0 ); if (instanceCount > 0 && !context.instancedArrays) { throw new DeveloperError_default("Instanced arrays extension is not supported"); } context._us.model = drawCommand._modelMatrix ?? Matrix4_default.IDENTITY; shaderProgram._setUniforms( uniformMap2, context._us, context.validateShaderProgram ); va._bind(); const indexBuffer = va.indexBuffer; if (defined_default(indexBuffer)) { offset = offset * indexBuffer.bytesPerIndex; if (defined_default(count)) { count = Math.min(count, indexBuffer.numberOfIndices); } else { count = indexBuffer.numberOfIndices; } if (instanceCount === 0) { context._gl.drawElements( primitiveType, count, indexBuffer.indexDatatype, offset ); } else { context.glDrawElementsInstanced( primitiveType, count, indexBuffer.indexDatatype, offset, instanceCount ); } } else { if (defined_default(count)) { count = Math.min(count, va.numberOfVertices); } else { count = va.numberOfVertices; } if (instanceCount === 0) { context._gl.drawArrays(primitiveType, offset, count); } else { context.glDrawArraysInstanced( primitiveType, offset, count, instanceCount ); } } va._unBind(); } Context.prototype.draw = function(drawCommand, passState, shaderProgram, uniformMap2) { Check_default.defined("drawCommand", drawCommand); Check_default.defined("drawCommand.shaderProgram", drawCommand._shaderProgram); passState = passState ?? this._defaultPassState; const framebuffer = drawCommand._framebuffer ?? passState.framebuffer; const renderState = drawCommand._renderState ?? this._defaultRenderState; shaderProgram = shaderProgram ?? drawCommand._shaderProgram; uniformMap2 = uniformMap2 ?? drawCommand._uniformMap; beginDraw(this, framebuffer, passState, shaderProgram, renderState); continueDraw(this, drawCommand, shaderProgram, uniformMap2); }; Context.prototype.beginFrame = function() { }; Context.prototype.endFrame = function() { const gl = this._gl; gl.useProgram(null); this._currentFramebuffer = void 0; gl.bindFramebuffer(gl.FRAMEBUFFER, null); const buffers = scratchBackBufferArray; if (this.drawBuffers) { this.glDrawBuffers(buffers); } const length2 = this._maxFrameTextureUnitIndex; this._maxFrameTextureUnitIndex = 0; for (let i = 0; i < length2; ++i) { gl.activeTexture(gl.TEXTURE0 + i); gl.bindTexture(gl.TEXTURE_2D, null); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); } }; Context.prototype.readPixelsToPBO = function(readState) { const gl = this._gl; readState = readState ?? Frozen_default.EMPTY_OBJECT; const x = Math.max(readState.x ?? 0, 0); const y = Math.max(readState.y ?? 0, 0); const width = readState.width ?? this.drawingBufferWidth; const height = readState.height ?? this.drawingBufferHeight; const framebuffer = readState.framebuffer; if (!this._webgl2) { throw new DeveloperError_default( "A WebGL 2 context is required to read pixels using a PBO." ); } Check_default.typeOf.number.greaterThan("readState.width", width, 0); Check_default.typeOf.number.greaterThan("readState.height", height, 0); let pixelDatatype = PixelDatatype_default.UNSIGNED_BYTE; let pixelFormat = PixelFormat_default.RGBA; if (defined_default(framebuffer) && framebuffer.numberOfColorAttachments > 0) { pixelDatatype = framebuffer.getColorTexture(0).pixelDatatype; pixelFormat = framebuffer.getColorTexture(0).pixelFormat; } const pixels = Buffer_default.createPixelBuffer({ context: this, sizeInBytes: PixelFormat_default.textureSizeInBytes( pixelFormat, pixelDatatype, width, height ), usage: BufferUsage_default.DYNAMIC_READ }); bindFramebuffer(this, framebuffer); pixels._bind(); gl.readPixels( x, y, width, height, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, this), 0 ); pixels._unBind(); return pixels; }; Context.prototype.readPixels = function(readState) { const gl = this._gl; readState = readState ?? Frozen_default.EMPTY_OBJECT; const x = Math.max(readState.x ?? 0, 0); const y = Math.max(readState.y ?? 0, 0); const width = readState.width ?? this.drawingBufferWidth; const height = readState.height ?? this.drawingBufferHeight; const framebuffer = readState.framebuffer; Check_default.typeOf.number.greaterThan("readState.width", width, 0); Check_default.typeOf.number.greaterThan("readState.height", height, 0); let pixelDatatype = PixelDatatype_default.UNSIGNED_BYTE; let pixelFormat = PixelFormat_default.RGBA; if (defined_default(framebuffer) && framebuffer.numberOfColorAttachments > 0) { pixelDatatype = framebuffer.getColorTexture(0).pixelDatatype; pixelFormat = framebuffer.getColorTexture(0).pixelFormat; } const pixels = PixelFormat_default.createTypedArray( pixelFormat, pixelDatatype, width, height ); bindFramebuffer(this, framebuffer); gl.readPixels( x, y, width, height, PixelFormat_default.RGBA, PixelDatatype_default.toWebGLConstant(pixelDatatype, this), pixels ); return pixels; }; var viewportQuadAttributeLocations = { position: 0, textureCoordinates: 1 }; Context.prototype.getViewportQuadVertexArray = function() { let vertexArray = this.cache.viewportQuad_vertexArray; if (!defined_default(vertexArray)) { const geometry = new Geometry_default({ attributes: { position: new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 2, values: [-1, -1, 1, -1, 1, 1, -1, 1] }), textureCoordinates: new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 2, values: [0, 0, 1, 0, 1, 1, 0, 1] }) }, // Workaround Internet Explorer 11.0.8 lack of TRIANGLE_FAN indices: new Uint16Array([0, 1, 2, 0, 2, 3]), primitiveType: PrimitiveType_default.TRIANGLES }); vertexArray = VertexArray_default.fromGeometry({ context: this, geometry, attributeLocations: viewportQuadAttributeLocations, bufferUsage: BufferUsage_default.STATIC_DRAW, interleave: true }); this.cache.viewportQuad_vertexArray = vertexArray; } return vertexArray; }; Context.prototype.createViewportQuadCommand = function(fragmentShaderSource, overrides) { overrides = overrides ?? Frozen_default.EMPTY_OBJECT; return new DrawCommand_default({ vertexArray: this.getViewportQuadVertexArray(), primitiveType: PrimitiveType_default.TRIANGLES, renderState: overrides.renderState, shaderProgram: ShaderProgram_default.fromCache({ context: this, vertexShaderSource: ViewportQuadVS_default, fragmentShaderSource, attributeLocations: viewportQuadAttributeLocations }), uniformMap: overrides.uniformMap, owner: overrides.owner, framebuffer: overrides.framebuffer, pass: overrides.pass }); }; Context.prototype.getObjectByPickColor = function(pickColor4) { Check_default.defined("pickColor", pickColor4); return this._pickObjects.get(pickColor4); }; Context.prototype.createPickId = function(object2) { Check_default.defined("object", object2); ++this._nextPickColor[0]; const key = this._nextPickColor[0]; if (key === 0) { throw new RuntimeError_default("Out of unique Pick IDs."); } this._pickObjects.set(key, object2); return new PickId_default(this._pickObjects, key, Color_default.fromRgba(key)); }; Context.prototype.isDestroyed = function() { return false; }; Context.prototype.destroy = function() { const cache = this.cache; for (const property in cache) { if (cache.hasOwnProperty(property)) { const propertyValue = cache[property]; if (defined_default(propertyValue.destroy)) { propertyValue.destroy(); } } } this._shaderCache = this._shaderCache.destroy(); this._textureCache = this._textureCache.destroy(); this._defaultTexture = this._defaultTexture && this._defaultTexture.destroy(); this._defaultEmissiveTexture = this._defaultEmissiveTexture && this._defaultEmissiveTexture.destroy(); this._defaultNormalTexture = this._defaultNormalTexture && this._defaultNormalTexture.destroy(); this._defaultCubeMap = this._defaultCubeMap && this._defaultCubeMap.destroy(); return destroyObject_default(this); }; var Context_default = Context; // packages/engine/Source/Renderer/FramebufferManager.js var import_InlineWorkers283 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/MultisampleFramebuffer.js var import_InlineWorkers280 = __toESM(require_InlineWorkers(), 1); function MultisampleFramebuffer(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const { context, width, height, colorRenderbuffers, colorTextures, depthStencilRenderbuffer, depthStencilTexture, destroyAttachments } = options; Check_default.defined("options.context", context); Check_default.defined("options.width", width); Check_default.defined("options.height", height); this._width = width; this._height = height; if (defined_default(colorRenderbuffers) !== defined_default(colorTextures)) { throw new DeveloperError_default( "Both color renderbuffer and texture attachments must be provided." ); } if (defined_default(depthStencilRenderbuffer) !== defined_default(depthStencilTexture)) { throw new DeveloperError_default( "Both depth-stencil renderbuffer and texture attachments must be provided." ); } this._renderFramebuffer = new Framebuffer_default({ context, colorRenderbuffers, depthStencilRenderbuffer, destroyAttachments }); this._colorFramebuffer = new Framebuffer_default({ context, colorTextures, depthStencilTexture, destroyAttachments }); } MultisampleFramebuffer.prototype.getRenderFramebuffer = function() { return this._renderFramebuffer; }; MultisampleFramebuffer.prototype.getColorFramebuffer = function() { return this._colorFramebuffer; }; MultisampleFramebuffer.prototype.blitFramebuffers = function(context, blitStencil) { this._renderFramebuffer.bindRead(); this._colorFramebuffer.bindDraw(); const gl = context._gl; let mask = 0; if (this._colorFramebuffer._colorTextures.length > 0) { mask |= gl.COLOR_BUFFER_BIT; } if (defined_default(this._colorFramebuffer.depthStencilTexture)) { mask |= gl.DEPTH_BUFFER_BIT | (blitStencil ? gl.STENCIL_BUFFER_BIT : 0); } gl.blitFramebuffer( 0, 0, this._width, this._height, 0, 0, this._width, this._height, mask, gl.NEAREST ); gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); }; MultisampleFramebuffer.prototype.isDestroyed = function() { return false; }; MultisampleFramebuffer.prototype.destroy = function() { this._renderFramebuffer.destroy(); this._colorFramebuffer.destroy(); return destroyObject_default(this); }; var MultisampleFramebuffer_default = MultisampleFramebuffer; // packages/engine/Source/Renderer/Renderbuffer.js var import_InlineWorkers282 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/RenderbufferFormat.js var import_InlineWorkers281 = __toESM(require_InlineWorkers(), 1); var RenderbufferFormat = { RGBA4: WebGLConstants_default.RGBA4, RGBA8: WebGLConstants_default.RGBA8, RGBA16F: WebGLConstants_default.RGBA16F, RGBA32F: WebGLConstants_default.RGBA32F, RGB5_A1: WebGLConstants_default.RGB5_A1, RGB565: WebGLConstants_default.RGB565, DEPTH_COMPONENT16: WebGLConstants_default.DEPTH_COMPONENT16, STENCIL_INDEX8: WebGLConstants_default.STENCIL_INDEX8, DEPTH_STENCIL: WebGLConstants_default.DEPTH_STENCIL, DEPTH24_STENCIL8: WebGLConstants_default.DEPTH24_STENCIL8, validate: function(renderbufferFormat) { return renderbufferFormat === RenderbufferFormat.RGBA4 || renderbufferFormat === RenderbufferFormat.RGBA8 || renderbufferFormat === RenderbufferFormat.RGBA16F || renderbufferFormat === RenderbufferFormat.RGBA32F || renderbufferFormat === RenderbufferFormat.RGB5_A1 || renderbufferFormat === RenderbufferFormat.RGB565 || renderbufferFormat === RenderbufferFormat.DEPTH_COMPONENT16 || renderbufferFormat === RenderbufferFormat.STENCIL_INDEX8 || renderbufferFormat === RenderbufferFormat.DEPTH_STENCIL || renderbufferFormat === RenderbufferFormat.DEPTH24_STENCIL8; }, getColorFormat: function(datatype) { if (datatype === WebGLConstants_default.FLOAT) { return RenderbufferFormat.RGBA32F; } else if (datatype === WebGLConstants_default.HALF_FLOAT_OES) { return RenderbufferFormat.RGBA16F; } return RenderbufferFormat.RGBA8; } }; Object.freeze(RenderbufferFormat); var RenderbufferFormat_default = RenderbufferFormat; // packages/engine/Source/Renderer/Renderbuffer.js function Renderbuffer(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const context = options.context; const gl = context._gl; const maximumRenderbufferSize = ContextLimits_default.maximumRenderbufferSize; const format = options.format ?? RenderbufferFormat_default.RGBA4; const width = defined_default(options.width) ? options.width : context.drawingBufferWidth; const height = defined_default(options.height) ? options.height : context.drawingBufferHeight; const numSamples = options.numSamples ?? 1; if (!RenderbufferFormat_default.validate(format)) { throw new DeveloperError_default("Invalid format."); } Check_default.typeOf.number.greaterThan("width", width, 0); if (width > maximumRenderbufferSize) { throw new DeveloperError_default( `Width must be less than or equal to the maximum renderbuffer size (${maximumRenderbufferSize}). Check maximumRenderbufferSize.` ); } Check_default.typeOf.number.greaterThan("height", height, 0); if (height > maximumRenderbufferSize) { throw new DeveloperError_default( `Height must be less than or equal to the maximum renderbuffer size (${maximumRenderbufferSize}). Check maximumRenderbufferSize.` ); } this._gl = gl; this._format = format; this._width = width; this._height = height; this._renderbuffer = this._gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, this._renderbuffer); if (numSamples > 1) { gl.renderbufferStorageMultisample( gl.RENDERBUFFER, numSamples, format, width, height ); } else { gl.renderbufferStorage(gl.RENDERBUFFER, format, width, height); } gl.bindRenderbuffer(gl.RENDERBUFFER, null); } Object.defineProperties(Renderbuffer.prototype, { format: { get: function() { return this._format; } }, width: { get: function() { return this._width; } }, height: { get: function() { return this._height; } } }); Renderbuffer.prototype._getRenderbuffer = function() { return this._renderbuffer; }; Renderbuffer.prototype.isDestroyed = function() { return false; }; Renderbuffer.prototype.destroy = function() { this._gl.deleteRenderbuffer(this._renderbuffer); return destroyObject_default(this); }; var Renderbuffer_default = Renderbuffer; // packages/engine/Source/Renderer/FramebufferManager.js function FramebufferManager(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._numSamples = options.numSamples ?? 1; this._colorAttachmentsLength = options.colorAttachmentsLength ?? 1; this._color = options.color ?? true; this._depth = options.depth ?? false; this._depthStencil = options.depthStencil ?? false; this._supportsDepthTexture = options.supportsDepthTexture ?? false; if (!this._color && !this._depth && !this._depthStencil) { throw new DeveloperError_default( "Must enable at least one type of framebuffer attachment." ); } if (this._depth && this._depthStencil) { throw new DeveloperError_default( "Cannot have both a depth and depth-stencil attachment." ); } this._createColorAttachments = options.createColorAttachments ?? true; this._createDepthAttachments = options.createDepthAttachments ?? true; this._pixelDatatype = options.pixelDatatype; this._pixelFormat = options.pixelFormat; this._width = void 0; this._height = void 0; this._framebuffer = void 0; this._multisampleFramebuffer = void 0; this._colorTextures = void 0; if (this._color) { this._colorTextures = new Array(this._colorAttachmentsLength); this._colorRenderbuffers = new Array(this._colorAttachmentsLength); } this._colorRenderbuffer = void 0; this._depthStencilRenderbuffer = void 0; this._depthStencilTexture = void 0; this._depthRenderbuffer = void 0; this._depthTexture = void 0; this._attachmentsDirty = false; } Object.defineProperties(FramebufferManager.prototype, { framebuffer: { get: function() { if (this._numSamples > 1) { return this._multisampleFramebuffer.getRenderFramebuffer(); } return this._framebuffer; } }, numSamples: { get: function() { return this._numSamples; } }, status: { get: function() { return this.framebuffer.status; } } }); FramebufferManager.prototype.isDirty = function(width, height, numSamples, pixelDatatype, pixelFormat) { numSamples = numSamples ?? 1; const dimensionChanged = this._width !== width || this._height !== height; const samplesChanged = this._numSamples !== numSamples; const pixelChanged = defined_default(pixelDatatype) && this._pixelDatatype !== pixelDatatype || defined_default(pixelFormat) && this._pixelFormat !== pixelFormat; const framebufferDefined = numSamples === 1 ? defined_default(this._framebuffer) : defined_default(this._multisampleFramebuffer); return this._attachmentsDirty || dimensionChanged || samplesChanged || pixelChanged || !framebufferDefined || this._color && !defined_default(this._colorTextures[0]); }; FramebufferManager.prototype.update = function(context, width, height, numSamples, pixelDatatype, pixelFormat) { if (!defined_default(width) || !defined_default(height)) { throw new DeveloperError_default("width and height must be defined."); } numSamples = context.msaa ? numSamples ?? 1 : 1; pixelDatatype = pixelDatatype ?? (this._color ? this._pixelDatatype ?? PixelDatatype_default.UNSIGNED_BYTE : void 0); pixelFormat = pixelFormat ?? (this._color ? this._pixelFormat ?? PixelFormat_default.RGBA : void 0); if (this.isDirty(width, height, numSamples, pixelDatatype, pixelFormat)) { this.destroy(); this._width = width; this._height = height; this._numSamples = numSamples; this._pixelDatatype = pixelDatatype; this._pixelFormat = pixelFormat; this._attachmentsDirty = false; if (this._color && this._createColorAttachments) { for (let i = 0; i < this._colorAttachmentsLength; ++i) { this._colorTextures[i] = new Texture_default({ context, width, height, pixelFormat, pixelDatatype, sampler: Sampler_default.NEAREST }); if (this._numSamples > 1) { const format = RenderbufferFormat_default.getColorFormat(pixelDatatype); this._colorRenderbuffers[i] = new Renderbuffer_default({ context, width, height, format, numSamples: this._numSamples }); } } } if (this._depthStencil && this._createDepthAttachments) { if (this._supportsDepthTexture && context.depthTexture) { this._depthStencilTexture = new Texture_default({ context, width, height, pixelFormat: PixelFormat_default.DEPTH_STENCIL, pixelDatatype: PixelDatatype_default.UNSIGNED_INT_24_8, sampler: Sampler_default.NEAREST }); if (this._numSamples > 1) { this._depthStencilRenderbuffer = new Renderbuffer_default({ context, width, height, format: RenderbufferFormat_default.DEPTH24_STENCIL8, numSamples: this._numSamples }); } } else { this._depthStencilRenderbuffer = new Renderbuffer_default({ context, width, height, format: RenderbufferFormat_default.DEPTH_STENCIL }); } } if (this._depth && this._createDepthAttachments) { if (this._supportsDepthTexture && context.depthTexture) { this._depthTexture = new Texture_default({ context, width, height, pixelFormat: PixelFormat_default.DEPTH_COMPONENT, pixelDatatype: PixelDatatype_default.UNSIGNED_INT, sampler: Sampler_default.NEAREST }); } else { this._depthRenderbuffer = new Renderbuffer_default({ context, width, height, format: RenderbufferFormat_default.DEPTH_COMPONENT16 }); } } if (this._numSamples > 1) { this._multisampleFramebuffer = new MultisampleFramebuffer_default({ context, width: this._width, height: this._height, colorTextures: this._colorTextures, colorRenderbuffers: this._colorRenderbuffers, depthStencilTexture: this._depthStencilTexture, depthStencilRenderbuffer: this._depthStencilRenderbuffer, destroyAttachments: false }); } else { this._framebuffer = new Framebuffer_default({ context, colorTextures: this._colorTextures, depthTexture: this._depthTexture, depthRenderbuffer: this._depthRenderbuffer, depthStencilTexture: this._depthStencilTexture, depthStencilRenderbuffer: this._depthStencilRenderbuffer, destroyAttachments: false }); } } }; FramebufferManager.prototype.getColorTexture = function(index) { index = index ?? 0; if (index >= this._colorAttachmentsLength) { throw new DeveloperError_default( "index must be smaller than total number of color attachments." ); } return this._colorTextures[index]; }; FramebufferManager.prototype.setColorTexture = function(texture, index) { index = index ?? 0; if (this._createColorAttachments) { throw new DeveloperError_default( "createColorAttachments must be false if setColorTexture is called." ); } if (index >= this._colorAttachmentsLength) { throw new DeveloperError_default( "index must be smaller than total number of color attachments." ); } this._attachmentsDirty = texture !== this._colorTextures[index]; this._colorTextures[index] = texture; }; FramebufferManager.prototype.getColorRenderbuffer = function(index) { index = index ?? 0; if (index >= this._colorAttachmentsLength) { throw new DeveloperError_default( "index must be smaller than total number of color attachments." ); } return this._colorRenderbuffers[index]; }; FramebufferManager.prototype.setColorRenderbuffer = function(renderbuffer, index) { index = index ?? 0; if (this._createColorAttachments) { throw new DeveloperError_default( "createColorAttachments must be false if setColorRenderbuffer is called." ); } if (index >= this._colorAttachmentsLength) { throw new DeveloperError_default( "index must be smaller than total number of color attachments." ); } this._attachmentsDirty = renderbuffer !== this._colorRenderbuffers[index]; this._colorRenderbuffers[index] = renderbuffer; }; FramebufferManager.prototype.getDepthRenderbuffer = function() { return this._depthRenderbuffer; }; FramebufferManager.prototype.setDepthRenderbuffer = function(renderbuffer) { if (this._createDepthAttachments) { throw new DeveloperError_default( "createDepthAttachments must be false if setDepthRenderbuffer is called." ); } this._attachmentsDirty = renderbuffer !== this._depthRenderbuffer; this._depthRenderbuffer = renderbuffer; }; FramebufferManager.prototype.getDepthTexture = function() { return this._depthTexture; }; FramebufferManager.prototype.setDepthTexture = function(texture) { if (this._createDepthAttachments) { throw new DeveloperError_default( "createDepthAttachments must be false if setDepthTexture is called." ); } this._attachmentsDirty = texture !== this._depthTexture; this._depthTexture = texture; }; FramebufferManager.prototype.getDepthStencilRenderbuffer = function() { return this._depthStencilRenderbuffer; }; FramebufferManager.prototype.setDepthStencilRenderbuffer = function(renderbuffer) { if (this._createDepthAttachments) { throw new DeveloperError_default( "createDepthAttachments must be false if setDepthStencilRenderbuffer is called." ); } this._attachmentsDirty = renderbuffer !== this._depthStencilRenderbuffer; this._depthStencilRenderbuffer = renderbuffer; }; FramebufferManager.prototype.getDepthStencilTexture = function() { return this._depthStencilTexture; }; FramebufferManager.prototype.setDepthStencilTexture = function(texture) { if (this._createDepthAttachments) { throw new DeveloperError_default( "createDepthAttachments must be false if setDepthStencilTexture is called." ); } this._attachmentsDirty = texture !== this._depthStencilTexture; this._depthStencilTexture = texture; }; FramebufferManager.prototype.prepareTextures = function(context, blitStencil) { if (this._numSamples > 1) { this._multisampleFramebuffer.blitFramebuffers(context, blitStencil); } }; FramebufferManager.prototype.clear = function(context, clearCommand, passState) { const framebuffer = clearCommand.framebuffer; clearCommand.framebuffer = this.framebuffer; clearCommand.execute(context, passState); clearCommand.framebuffer = framebuffer; }; FramebufferManager.prototype.destroyFramebuffer = function() { this._framebuffer = this._framebuffer && this._framebuffer.destroy(); this._multisampleFramebuffer = this._multisampleFramebuffer && this._multisampleFramebuffer.destroy(); }; FramebufferManager.prototype.destroy = function() { if (this._color) { const colorTextures = this._colorTextures; const colorRenderbuffers = this._colorRenderbuffers; for (let i = 0; i < colorTextures.length; ++i) { const texture = colorTextures[i]; if (this._createColorAttachments) { if (defined_default(texture) && !texture.isDestroyed()) { texture.destroy(); } } if (defined_default(texture) && texture.isDestroyed()) { colorTextures[i] = void 0; } const renderbuffer = colorRenderbuffers[i]; if (this._createColorAttachments) { if (defined_default(renderbuffer) && !renderbuffer.isDestroyed()) { renderbuffer.destroy(); } } if (defined_default(renderbuffer) && renderbuffer.isDestroyed()) { colorRenderbuffers[i] = void 0; } } } if (this._depthStencil) { if (this._createDepthAttachments) { this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy(); this._depthStencilRenderbuffer = this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy(); } if (defined_default(this._depthStencilTexture) && this._depthStencilTexture.isDestroyed()) { this._depthStencilTexture = void 0; } if (defined_default(this._depthStencilRenderbuffer) && this._depthStencilRenderbuffer.isDestroyed()) { this._depthStencilRenderbuffer = void 0; } } if (this._depth) { if (this._createDepthAttachments) { this._depthTexture = this._depthTexture && this._depthTexture.destroy(); this._depthRenderbuffer = this._depthRenderbuffer && this._depthRenderbuffer.destroy(); } if (defined_default(this._depthTexture) && this._depthTexture.isDestroyed()) { this._depthTexture = void 0; } if (defined_default(this._depthRenderbuffer) && this._depthRenderbuffer.isDestroyed()) { this._depthRenderbuffer = void 0; } } this.destroyFramebuffer(); }; var FramebufferManager_default = FramebufferManager; // packages/engine/Source/Renderer/ShaderBuilder.js var import_InlineWorkers288 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Renderer/ShaderDestination.js var import_InlineWorkers284 = __toESM(require_InlineWorkers(), 1); var ShaderDestination = { NONE: 0, VERTEX: 1, FRAGMENT: 2, BOTH: 3 }; ShaderDestination.includesVertexShader = function(destination) { Check_default.typeOf.number("destination", destination); return (destination & ShaderDestination.VERTEX) !== 0; }; ShaderDestination.includesFragmentShader = function(destination) { Check_default.typeOf.number("destination", destination); return (destination & ShaderDestination.FRAGMENT) !== 0; }; ShaderDestination.union = function(...destinations) { if (destinations.length === 0) { throw new DeveloperError_default( "ShaderDestination.union requires at least one destination." ); } let result = 0; for (let i = 0; i < destinations.length; i++) { result |= destinations[i]; } return result; }; ShaderDestination.intersection = function(...destinations) { if (destinations.length === 0) { throw new DeveloperError_default( "ShaderDestination.intersection requires at least one destination." ); } let result = destinations[0]; for (let i = 1; i < destinations.length; i++) { result &= destinations[i]; } return result; }; Object.freeze(ShaderDestination); var ShaderDestination_default = ShaderDestination; // packages/engine/Source/Renderer/ShaderStruct.js var import_InlineWorkers285 = __toESM(require_InlineWorkers(), 1); function ShaderStruct(name) { this.name = name; this.fields = []; } ShaderStruct.prototype.addField = function(type, identifier) { const field = ` ${type} ${identifier};`; this.fields.push(field); }; ShaderStruct.prototype.generateGlslLines = function() { let fields = this.fields; if (fields.length === 0) { fields = [" float _empty;"]; } return [].concat(`struct ${this.name}`, "{", fields, "};"); }; var ShaderStruct_default = ShaderStruct; // packages/engine/Source/Renderer/ShaderFunction.js var import_InlineWorkers286 = __toESM(require_InlineWorkers(), 1); function ShaderFunction(signature) { this.signature = signature; this.body = []; } ShaderFunction.prototype.addLines = function(lines) { if (typeof lines !== "string" && !Array.isArray(lines)) { throw new DeveloperError_default( `Expected lines to be a string or an array of strings, actual value was ${lines}` ); } const body = this.body; if (Array.isArray(lines)) { const length2 = lines.length; for (let i = 0; i < length2; i++) { body.push(` ${lines[i]}`); } } else { body.push(` ${lines}`); } }; ShaderFunction.prototype.generateGlslLines = function() { return [].concat(this.signature, "{", this.body, "}"); }; var ShaderFunction_default = ShaderFunction; // packages/engine/Source/Core/addAllToArray.js var import_InlineWorkers287 = __toESM(require_InlineWorkers(), 1); function addAllToArray(target, source) { if (!defined_default(source)) { return; } const sourceLength = source.length; if (sourceLength === 0) { return; } const targetLength = target.length; target.length += sourceLength; for (let i = 0; i < sourceLength; i++) { target[targetLength + i] = source[i]; } } var addAllToArray_default = addAllToArray; // packages/engine/Source/Renderer/ShaderBuilder.js function ShaderBuilder() { this._positionAttributeLine = void 0; this._nextAttributeLocation = 1; this._attributeLocations = {}; this._attributeLines = []; this._structs = {}; this._functions = {}; this._vertexShaderParts = { defineLines: [], uniformLines: [], shaderLines: [], varyingLines: [], // identifiers of structs/functions to include, listed in insertion order structIds: [], functionIds: [] }; this._fragmentShaderParts = { defineLines: [], uniformLines: [], shaderLines: [], varyingLines: [], // identifiers of structs/functions to include, listed in insertion order structIds: [], functionIds: [] }; } Object.defineProperties(ShaderBuilder.prototype, { /** * Get a dictionary of attribute names to the integer location in * the vertex shader. * * @memberof ShaderBuilder.prototype * @type {Object} * @readonly * @private */ attributeLocations: { get: function() { return this._attributeLocations; } } }); ShaderBuilder.prototype.addDefine = function(identifier, value, destination) { Check_default.typeOf.string("identifier", identifier); destination = destination ?? ShaderDestination_default.BOTH; let line = identifier; if (defined_default(value)) { line += ` ${value.toString()}`; } if (ShaderDestination_default.includesVertexShader(destination)) { this._vertexShaderParts.defineLines.push(line); } if (ShaderDestination_default.includesFragmentShader(destination)) { this._fragmentShaderParts.defineLines.push(line); } }; ShaderBuilder.prototype.addStruct = function(structId, structName, destination) { Check_default.typeOf.string("structId", structId); Check_default.typeOf.string("structName", structName); Check_default.typeOf.number("destination", destination); this._structs[structId] = new ShaderStruct_default(structName); if (ShaderDestination_default.includesVertexShader(destination)) { this._vertexShaderParts.structIds.push(structId); } if (ShaderDestination_default.includesFragmentShader(destination)) { this._fragmentShaderParts.structIds.push(structId); } }; ShaderBuilder.prototype.addStructField = function(structId, type, identifier) { Check_default.typeOf.string("structId", structId); Check_default.typeOf.string("type", type); Check_default.typeOf.string("identifier", identifier); this._structs[structId].addField(type, identifier); }; ShaderBuilder.prototype.addFunction = function(functionName, signature, destination) { Check_default.typeOf.string("functionName", functionName); Check_default.typeOf.string("signature", signature); Check_default.typeOf.number("destination", destination); this._functions[functionName] = new ShaderFunction_default(signature); if (ShaderDestination_default.includesVertexShader(destination)) { this._vertexShaderParts.functionIds.push(functionName); } if (ShaderDestination_default.includesFragmentShader(destination)) { this._fragmentShaderParts.functionIds.push(functionName); } }; ShaderBuilder.prototype.addFunctionLines = function(functionName, lines) { Check_default.typeOf.string("functionName", functionName); if (typeof lines !== "string" && !Array.isArray(lines)) { throw new DeveloperError_default( `Expected lines to be a string or an array of strings, actual value was ${lines}` ); } this._functions[functionName].addLines(lines); }; ShaderBuilder.prototype.addUniform = function(type, identifier, destination) { Check_default.typeOf.string("type", type); Check_default.typeOf.string("identifier", identifier); destination = destination ?? ShaderDestination_default.BOTH; const line = `uniform ${type} ${identifier};`; if (ShaderDestination_default.includesVertexShader(destination)) { this._vertexShaderParts.uniformLines.push(line); } if (ShaderDestination_default.includesFragmentShader(destination)) { this._fragmentShaderParts.uniformLines.push(line); } }; ShaderBuilder.prototype.setPositionAttribute = function(type, identifier) { Check_default.typeOf.string("type", type); Check_default.typeOf.string("identifier", identifier); if (defined_default(this._positionAttributeLine)) { throw new DeveloperError_default( "setPositionAttribute() must be called exactly once for the attribute used for gl_Position. For other attributes, use addAttribute()" ); } this._positionAttributeLine = `in ${type} ${identifier};`; this._attributeLocations[identifier] = 0; return 0; }; ShaderBuilder.prototype.addAttribute = function(type, identifier) { Check_default.typeOf.string("type", type); Check_default.typeOf.string("identifier", identifier); const line = `in ${type} ${identifier};`; this._attributeLines.push(line); const location2 = this._nextAttributeLocation; this._attributeLocations[identifier] = location2; this._nextAttributeLocation += getAttributeLocationCount(type); return location2; }; ShaderBuilder.prototype.addVarying = function(type, identifier, qualifier) { Check_default.typeOf.string("type", type); Check_default.typeOf.string("identifier", identifier); qualifier = defined_default(qualifier) ? `${qualifier} ` : ""; const line = `${type} ${identifier};`; this._vertexShaderParts.varyingLines.push(`${qualifier}out ${line}`); this._fragmentShaderParts.varyingLines.push(`${qualifier}in ${line}`); }; ShaderBuilder.prototype.addVertexLines = function(lines) { if (typeof lines !== "string" && !Array.isArray(lines)) { throw new DeveloperError_default( `Expected lines to be a string or an array of strings, actual value was ${lines}` ); } const vertexLines = this._vertexShaderParts.shaderLines; if (Array.isArray(lines)) { addAllToArray_default(vertexLines, lines); } else { vertexLines.push(lines); } }; ShaderBuilder.prototype.addFragmentLines = function(lines) { if (typeof lines !== "string" && !Array.isArray(lines)) { throw new DeveloperError_default( `Expected lines to be a string or an array of strings, actual value was ${lines}` ); } const fragmentLines = this._fragmentShaderParts.shaderLines; if (Array.isArray(lines)) { addAllToArray_default(fragmentLines, lines); } else { fragmentLines.push(lines); } }; ShaderBuilder.prototype.buildShaderProgram = function(context) { Check_default.typeOf.object("context", context); const positionAttribute = defined_default(this._positionAttributeLine) ? [this._positionAttributeLine] : []; const structLines = generateStructLines(this); const functionLines = generateFunctionLines(this); const vertexLines = positionAttribute.concat( this._attributeLines, this._vertexShaderParts.uniformLines, this._vertexShaderParts.varyingLines, structLines.vertexLines, functionLines.vertexLines, this._vertexShaderParts.shaderLines ).join("\n"); const vertexShaderSource = new ShaderSource_default({ defines: this._vertexShaderParts.defineLines, sources: [vertexLines] }); const fragmentLines = this._fragmentShaderParts.uniformLines.concat( this._fragmentShaderParts.varyingLines, structLines.fragmentLines, functionLines.fragmentLines, this._fragmentShaderParts.shaderLines ).join("\n"); const fragmentShaderSource = new ShaderSource_default({ defines: this._fragmentShaderParts.defineLines, sources: [fragmentLines] }); return ShaderProgram_default.fromCache({ context, vertexShaderSource, fragmentShaderSource, attributeLocations: this._attributeLocations }); }; ShaderBuilder.prototype.clone = function() { return clone_default(this, true); }; function generateStructLines(shaderBuilder) { const vertexLines = []; const fragmentLines = []; let i; let structIds = shaderBuilder._vertexShaderParts.structIds; let structId; let struct; let structLines; for (i = 0; i < structIds.length; i++) { structId = structIds[i]; struct = shaderBuilder._structs[structId]; structLines = struct.generateGlslLines(); addAllToArray_default(vertexLines, structLines); } structIds = shaderBuilder._fragmentShaderParts.structIds; for (i = 0; i < structIds.length; i++) { structId = structIds[i]; struct = shaderBuilder._structs[structId]; structLines = struct.generateGlslLines(); addAllToArray_default(fragmentLines, structLines); } return { vertexLines, fragmentLines }; } function getAttributeLocationCount(glslType) { switch (glslType) { case "mat2": return 2; case "mat3": return 3; case "mat4": return 4; default: return 1; } } function generateFunctionLines(shaderBuilder) { const vertexLines = []; const fragmentLines = []; let i; let functionIds = shaderBuilder._vertexShaderParts.functionIds; let functionId; let func; let functionLines; for (i = 0; i < functionIds.length; i++) { functionId = functionIds[i]; func = shaderBuilder._functions[functionId]; functionLines = func.generateGlslLines(); addAllToArray_default(vertexLines, functionLines); } functionIds = shaderBuilder._fragmentShaderParts.functionIds; for (i = 0; i < functionIds.length; i++) { functionId = functionIds[i]; func = shaderBuilder._functions[functionId]; functionLines = func.generateGlslLines(); addAllToArray_default(fragmentLines, functionLines); } return { vertexLines, fragmentLines }; } var ShaderBuilder_default = ShaderBuilder; // packages/engine/Source/Renderer/SharedContext.js var import_InlineWorkers289 = __toESM(require_InlineWorkers(), 1); function SharedContext(options) { this._autoDestroy = options?.autoDestroy ?? true; this._canvas = document.createElement("canvas"); this._context = new Context_default(this._canvas, clone_default(options?.contextOptions)); this._canvases = []; } SharedContext.prototype.createSceneContext = function(canvas) { const context2d = canvas.getContext("2d", { alpha: true }); if (!context2d) { throw new DeveloperError_default( "canvas used with SharedContext must provide a 2d context" ); } if (this._canvases.includes(canvas)) { throw new DeveloperError_default("canvas is already associated with a scene"); } const sharedContext = this; sharedContext._canvases.push(canvas); let isDestroyed = false; const destroy = function() { isDestroyed = true; const index = sharedContext._canvases.indexOf(canvas); if (-1 !== index) { sharedContext._canvases.splice(index, 1); if (sharedContext._autoDestroy && sharedContext._canvases.length === 0) { sharedContext.destroy(); } } }; const beginFrame = function() { const sharedCanvas = sharedContext._context.canvas; const width = this.drawingBufferWidth; if (sharedCanvas.width < width) { sharedCanvas.width = width; } const height = this.drawingBufferHeight; if (sharedCanvas.height < height) { sharedCanvas.height = height; } }; const endFrame = function() { const w = this.drawingBufferWidth; const h = this.drawingBufferHeight; const yOffset = sharedContext._context.canvas.height - h; context2d.drawImage( sharedContext._context.canvas, 0, yOffset, w, h, 0, 0, w, h ); sharedContext._context.endFrame(); }; const proxy = new Proxy(this._context, { get(target, prop, receiver) { if (prop === "isDestroyed") { return function() { return isDestroyed; }; } else if (isDestroyed) { throw new DeveloperError_default( "This object was destroyed, i.e., destroy() was called." ); } switch (prop) { case "_canvas": return canvas; case "destroy": return destroy; case "drawingBufferWidth": return canvas.width; case "drawingBufferHeight": return canvas.height; case "beginFrame": return beginFrame; case "endFrame": return endFrame; default: return Reflect.get(target, prop, receiver); } } }); return proxy; }; SharedContext.prototype.destroy = function() { this._context.destroy(); destroyObject_default(this); }; SharedContext.prototype.isDestroyed = function() { return false; }; var SharedContext_default = SharedContext; // packages/engine/Source/Renderer/Sync.js var import_InlineWorkers290 = __toESM(require_InlineWorkers(), 1); function Sync(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const context = options.context; Check_default.defined("options.context", context); if (!context._webgl2) { throw new DeveloperError_default( "A WebGL 2 context is required to use Sync operations." ); } const gl = context._gl; const sync = gl.fenceSync(WebGLConstants_default.SYNC_GPU_COMMANDS_COMPLETE, 0); this._gl = gl; this._sync = sync; } Sync.create = function(options) { return new Sync(options); }; Sync.prototype.getStatus = function() { const status = this._gl.getSyncParameter( this._sync, WebGLConstants_default.SYNC_STATUS ); return status; }; Sync.prototype.isDestroyed = function() { return false; }; Sync.prototype.destroy = function() { this._gl.deleteSync(this._sync); return destroyObject_default(this); }; Sync.prototype.waitForSignal = async function(scheduleFunction, ttl) { const self2 = this; ttl = ttl ?? 10; function waitForSignal0(resolve2, reject, ttl2) { return () => { const syncStatus = self2.getStatus(); const signaled = syncStatus === WebGLConstants_default.SIGNALED; if (signaled) { resolve2(); } else if (ttl2 <= 0) { reject(new RuntimeError_default("Wait for signal timeout")); } else { scheduleFunction(waitForSignal0(resolve2, reject, ttl2 - 1)); } }; } return new Promise((resolve2, reject) => { scheduleFunction(waitForSignal0(resolve2, reject, ttl)); }); }; var Sync_default = Sync; // packages/engine/Source/Renderer/Texture3D.js var import_InlineWorkers291 = __toESM(require_InlineWorkers(), 1); function Texture3D(options) { options = options ?? Frozen_default.EMPTY_OBJECT; Check_default.defined("options.context", options.context); const { context, source, pixelFormat = PixelFormat_default.RGBA, pixelDatatype = PixelDatatype_default.UNSIGNED_BYTE, flipY = true, skipColorSpaceConversion = false, sampler = new Sampler_default() } = options; if (!context.webgl2 && !defined_default(context.options.getWebGLStub)) { throw new DeveloperError_default( "WebGL1 does not support texture3D. Please use a WebGL2 context." ); } let { width, height, depth } = options; if (defined_default(source)) { if (!defined_default(width)) { width = source.width; } if (!defined_default(height)) { height = source.height; } if (!defined_default(depth)) { depth = source.depth; } } const preMultiplyAlpha = options.preMultiplyAlpha || pixelFormat === PixelFormat_default.RGB || pixelFormat === PixelFormat_default.LUMINANCE; const internalFormat = PixelFormat_default.toInternalFormat( pixelFormat, pixelDatatype, context ); const isCompressed = PixelFormat_default.isCompressedFormat(internalFormat); if (!defined_default(width) || !defined_default(height) || !defined_default(depth)) { throw new DeveloperError_default( "options requires a source field to create an initialized texture3D or width, height and depth fields to create a blank texture3D." ); } Check_default.typeOf.number.greaterThan("width", width, 0); if (width > ContextLimits_default.maximum3DTextureSize) { throw new DeveloperError_default( `Width must be less than or equal to the maximum texture3D size (${ContextLimits_default.maximum3DTextureSize}). Check maximum3DTextureSize.` ); } Check_default.typeOf.number.greaterThan("height", height, 0); if (height > ContextLimits_default.maximum3DTextureSize) { throw new DeveloperError_default( `Height must be less than or equal to the maximum texture3D size (${ContextLimits_default.maximum3DTextureSize}). Check maximum3DTextureSize.` ); } Check_default.typeOf.number.greaterThan("depth", depth, 0); if (depth > ContextLimits_default.maximum3DTextureSize) { throw new DeveloperError_default( `Depth must be less than or equal to the maximum texture3D size (${ContextLimits_default.maximum3DTextureSize}). Check maximum3DTextureSize.` ); } if (!PixelFormat_default.validate(pixelFormat)) { throw new DeveloperError_default("Invalid options.pixelFormat."); } if (!isCompressed && !PixelDatatype_default.validate(pixelDatatype)) { throw new DeveloperError_default("Invalid options.pixelDatatype."); } if (pixelFormat === PixelFormat_default.DEPTH_COMPONENT && pixelDatatype !== PixelDatatype_default.UNSIGNED_SHORT && pixelDatatype !== PixelDatatype_default.UNSIGNED_INT) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT, options.pixelDatatype must be UNSIGNED_SHORT or UNSIGNED_INT." ); } if (pixelFormat === PixelFormat_default.DEPTH_STENCIL && pixelDatatype !== PixelDatatype_default.UNSIGNED_INT_24_8) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_STENCIL, options.pixelDatatype must be UNSIGNED_INT_24_8." ); } if (pixelDatatype === PixelDatatype_default.FLOAT && !context.floatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is FLOAT, this WebGL implementation must support the OES_texture_float extension. Check context.floatingPointTexture." ); } if (pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.halfFloatingPointTexture) { throw new DeveloperError_default( "When options.pixelDatatype is HALF_FLOAT, this WebGL implementation must support the OES_texture_half_float extension. Check context.halfFloatingPointTexture." ); } if (PixelFormat_default.isDepthFormat(pixelFormat)) { if (defined_default(source)) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, source cannot be provided." ); } if (!context.depthTexture) { throw new DeveloperError_default( "When options.pixelFormat is DEPTH_COMPONENT or DEPTH_STENCIL, this WebGL implementation must support WEBGL_depth_texture. Check context.depthTexture." ); } } if (isCompressed) { throw new DeveloperError_default( "Texture3D does not currently support compressed formats." ); } const gl = context._gl; const sizeInBytes = PixelFormat_default.texture3DSizeInBytes( pixelFormat, pixelDatatype, width, height, depth ); this._id = options.id ?? createGuid_default(); this._context = context; this._textureFilterAnisotropic = context._textureFilterAnisotropic; this._textureTarget = gl.TEXTURE_3D; this._texture = gl.createTexture(); this._internalFormat = internalFormat; this._pixelFormat = pixelFormat; this._pixelDatatype = pixelDatatype; this._width = width; this._height = height; this._depth = depth; this._dimensions = new Cartesian3_default(width, height, depth); this._hasMipmap = false; this._sizeInBytes = sizeInBytes; this._preMultiplyAlpha = preMultiplyAlpha; this._flipY = flipY; this._initialized = false; this._sampler = void 0; this._sampler = sampler; setupSampler3(this, sampler); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(this._textureTarget, this._texture); if (defined_default(source)) { if (skipColorSpaceConversion) { gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); } else { gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); } if (!defined_default(source.arrayBufferView)) { throw new DeveloperError_default( "For Texture3D, options.source.arrayBufferView must be defined" ); } loadBufferSource2(this, source); this._initialized = true; } else { loadNull2(this); } gl.bindTexture(this._textureTarget, null); } function loadBufferSource2(texture3D, source) { const context = texture3D._context; const gl = context._gl; const textureTarget = texture3D._textureTarget; const internalFormat = texture3D._internalFormat; const { width, height, depth, pixelFormat, pixelDatatype, flipY } = texture3D; const unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, width ); gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); const { arrayBufferView } = source; if (flipY) { console.warn("texture3D.flipY is not supported."); } let levels = 1; if (source.mipLevels && source.mipLevels.length) { levels = source.mipLevels.length + 1; } gl.texStorage3D(textureTarget, levels, internalFormat, width, height, depth); gl.texSubImage3D( textureTarget, 0, 0, 0, 0, width, height, depth, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), arrayBufferView ); if (levels > 1) { let mipWidth = width; let mipHeight = height; let mipDepth = depth; for (let i = 0; i < source.mipLevels.length; ++i) { mipWidth = nextMipSize2(mipWidth); mipHeight = nextMipSize2(mipHeight); mipDepth = nextMipSize2(mipDepth); gl.texSubImage3D( textureTarget, i + 1, 0, 0, 0, mipWidth, mipHeight, mipDepth, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), source.mipLevels[i] ); } } } Texture3D.prototype.copyFrom = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const { source, xOffset = 0, yOffset = 0, zOffset = 0 } = options; Check_default.defined("options.source", source); Check_default.defined("options.source.arrayBufferView", source.arrayBufferView); if (PixelFormat_default.isCompressedFormat(this._pixelFormat)) { throw new DeveloperError_default( "Unsupported copyFrom with a compressed texture pixel format." ); } Check_default.typeOf.number.greaterThanOrEquals("xOffset", xOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("yOffset", yOffset, 0); Check_default.typeOf.number.greaterThanOrEquals("zOffset", zOffset, 0); Check_default.typeOf.number.lessThanOrEquals( "xOffset + options.source.width", xOffset + source.width, this._width ); Check_default.typeOf.number.lessThanOrEquals( "yOffset + options.source.height", yOffset + source.height, this._height ); Check_default.typeOf.number.lessThanOrEquals( "zOffset + options.source.depth", zOffset + source.depth, this._depth ); const context = this._context; const gl = context._gl; const target = this._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); const { width, height, depth } = source; let uploaded = false; if (!this._initialized) { if (xOffset === 0 && yOffset === 0 && zOffset === 0 && width === this._width && height === this._height && depth === this._depth) { loadBufferSource2(this, source); uploaded = true; } else { gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); loadNull2(this); } this._initialized = true; } if (!uploaded) { loadPartialBufferSource2( this, source.arrayBufferView, xOffset, yOffset, zOffset, width, height, depth ); } gl.bindTexture(target, null); }; function loadPartialBufferSource2(texture3D, arrayBufferView, xOffset, yOffset, zOffset, width, height, depth) { const context = texture3D._context; const gl = context._gl; const { pixelFormat, pixelDatatype } = texture3D; const unpackAlignment = PixelFormat_default.alignmentInBytes( pixelFormat, pixelDatatype, width ); gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); gl.texSubImage3D( texture3D._textureTarget, 0, xOffset, yOffset, zOffset, width, height, depth, pixelFormat, PixelDatatype_default.toWebGLConstant(pixelDatatype, context), arrayBufferView ); } function nextMipSize2(currentSize) { const nextSize = Math.floor(currentSize / 2) | 0; return Math.max(nextSize, 1); } function loadNull2(texture3D) { const context = texture3D._context; context._gl.texImage3D( texture3D._textureTarget, 0, texture3D._internalFormat, texture3D._width, texture3D._height, texture3D._depth, 0, texture3D._pixelFormat, PixelDatatype_default.toWebGLConstant(texture3D._pixelDatatype, context), null ); } Texture3D.create = function(options) { return new Texture3D(options); }; Object.defineProperties(Texture3D.prototype, { /** * A unique id for the texture3D * @memberof Texture3D.prototype * @type {string} * @readonly * @private */ id: { get: function() { return this._id; } }, /** * The sampler to use when sampling this texture3D. * Create a sampler by calling {@link Sampler}. If this * parameter is not specified, a default sampler is used. The default sampler clamps texture3D * coordinates in both directions, uses linear filtering for both magnification and minification, * and uses a maximum anisotropy of 1.0. * @memberof Texture3D.prototype * @type {Sampler} * @private */ sampler: { get: function() { return this._sampler; }, set: function(sampler) { setupSampler3(this, sampler); this._sampler = sampler; } }, pixelFormat: { get: function() { return this._pixelFormat; } }, pixelDatatype: { get: function() { return this._pixelDatatype; } }, dimensions: { get: function() { return this._dimensions; } }, preMultiplyAlpha: { get: function() { return this._preMultiplyAlpha; } }, flipY: { get: function() { return this._flipY; } }, width: { get: function() { return this._width; } }, height: { get: function() { return this._height; } }, depth: { get: function() { return this._depth; } }, sizeInBytes: { get: function() { if (this._hasMipmap) { return Math.floor(this._sizeInBytes * 8 / 7); } return this._sizeInBytes; } }, _target: { get: function() { return this._textureTarget; } } }); function setupSampler3(texture3D, sampler) { let { minificationFilter, magnificationFilter } = sampler; const mipmap = [ TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST, TextureMinificationFilter_default.NEAREST_MIPMAP_LINEAR, TextureMinificationFilter_default.LINEAR_MIPMAP_NEAREST, TextureMinificationFilter_default.LINEAR_MIPMAP_LINEAR ].includes(minificationFilter); const context = texture3D._context; const pixelFormat = texture3D._pixelFormat; const pixelDatatype = texture3D._pixelDatatype; if (pixelDatatype === PixelDatatype_default.FLOAT && !context.textureFloatLinear || pixelDatatype === PixelDatatype_default.HALF_FLOAT && !context.textureHalfFloatLinear) { minificationFilter = mipmap ? TextureMinificationFilter_default.NEAREST_MIPMAP_NEAREST : TextureMinificationFilter_default.NEAREST; magnificationFilter = TextureMagnificationFilter_default.NEAREST; } if (PixelFormat_default.isDepthFormat(pixelFormat)) { minificationFilter = TextureMinificationFilter_default.NEAREST; magnificationFilter = TextureMagnificationFilter_default.NEAREST; } const gl = context._gl; const target = texture3D._textureTarget; gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, texture3D._texture); gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter); gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter); gl.texParameteri(target, gl.TEXTURE_WRAP_R, sampler.wrapR); gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS); gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT); if (defined_default(texture3D._textureFilterAnisotropic)) { gl.texParameteri( target, texture3D._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy ); } gl.bindTexture(target, null); } Texture3D.prototype.generateMipmap = function(hint) { hint = hint ?? MipmapHint_default.DONT_CARE; if (PixelFormat_default.isDepthFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call generateMipmap when the texture3D pixel format is DEPTH_COMPONENT or DEPTH_STENCIL." ); } if (PixelFormat_default.isCompressedFormat(this._pixelFormat)) { throw new DeveloperError_default( "Cannot call generateMipmap with a compressed pixel format." ); } if (!MipmapHint_default.validate(hint)) { throw new DeveloperError_default("hint is invalid."); } this._hasMipmap = true; const gl = this._context._gl; const target = this._textureTarget; gl.hint(gl.GENERATE_MIPMAP_HINT, hint); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, this._texture); gl.generateMipmap(target); gl.bindTexture(target, null); }; Texture3D.prototype.isDestroyed = function() { return false; }; Texture3D.prototype.destroy = function() { this._context._gl.deleteTexture(this._texture); return destroyObject_default(this); }; var Texture3D_default = Texture3D; // packages/engine/Source/Renderer/TextureAtlas.js var import_InlineWorkers293 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/TexturePacker.js var import_InlineWorkers292 = __toESM(require_InlineWorkers(), 1); function TextureNode({ x, y, width, height }) { this.rectangle = new BoundingRectangle_default(x, y, width, height); this.childNode1 = void 0; this.childNode2 = void 0; this.index = void 0; } function TexturePacker({ width, height, borderPadding }) { this._width = width; this._height = height; this._borderPadding = borderPadding; this._root = new TextureNode({ x: borderPadding, y: borderPadding, width: width - 2 * borderPadding, height: height - 2 * borderPadding }); } TexturePacker.prototype.pack = function(index, { width, height }) { Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.typeOf.number.greaterThanOrEquals("image.width", width, 1); Check_default.typeOf.number.greaterThanOrEquals("image.height", height, 1); const node = this._findNode(this._root, { width, height }); if (!defined_default(node)) { return; } node.index = index; return node; }; TexturePacker.prototype._findNode = function(node, { width, height }) { if (!defined_default(node)) { return void 0; } if (!defined_default(node.childNode1) && !defined_default(node.childNode2)) { if (defined_default(node.index)) { return void 0; } const { rectangle } = node; const nodeWidth = rectangle.width; const nodeHeight = rectangle.height; const widthDifference = nodeWidth - width; const heightDifference = nodeHeight - height; if (widthDifference < 0 || heightDifference < 0) { return void 0; } if (widthDifference === 0 && heightDifference === 0) { return node; } const borderPadding = this._borderPadding; if (widthDifference > heightDifference) { node.childNode1 = new TextureNode({ x: rectangle.x, y: rectangle.y, width, height: nodeHeight }); const widthDifferencePadded = widthDifference - borderPadding; if (widthDifferencePadded > 0) { node.childNode2 = new TextureNode({ x: rectangle.x + width + borderPadding, y: rectangle.y, width: widthDifferencePadded, height: nodeHeight }); } return this._findNode(node.childNode1, { width, height }); } node.childNode1 = new TextureNode({ x: rectangle.x, y: rectangle.y, width: nodeWidth, height }); const heightDifferencePadded = heightDifference - borderPadding; if (heightDifferencePadded > 0) { node.childNode2 = new TextureNode({ x: rectangle.x, y: rectangle.y + height + borderPadding, width: nodeWidth, height: heightDifferencePadded }); } return this._findNode(node.childNode1, { width, height }); } return this._findNode(node.childNode1, { width, height }) || this._findNode(node.childNode2, { width, height }); }; var TexturePacker_default = TexturePacker; // packages/engine/Source/Renderer/TextureAtlas.js var defaultInitialDimensions = 16; function TextureAtlas(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const borderWidthInPixels = options.borderWidthInPixels ?? 1; const initialSize = options.initialSize ?? new Cartesian2_default(defaultInitialDimensions, defaultInitialDimensions); Check_default.typeOf.number.greaterThanOrEquals( "options.borderWidthInPixels", borderWidthInPixels, 0 ); Check_default.typeOf.number.greaterThan("options.initialSize.x", initialSize.x, 0); Check_default.typeOf.number.greaterThan("options.initialSize.y", initialSize.y, 0); this._pixelFormat = options.pixelFormat ?? PixelFormat_default.RGBA; this._sampler = options.sampler; this._borderWidthInPixels = borderWidthInPixels; this._initialSize = initialSize; this._texturePacker = void 0; this._rectangles = []; this._subRegions = /* @__PURE__ */ new Map(); this._guid = createGuid_default(); this._imagesToAddQueue = []; this._indexById = /* @__PURE__ */ new Map(); this._indexPromiseById = /* @__PURE__ */ new Map(); this._nextIndex = 0; } Object.defineProperties(TextureAtlas.prototype, { /** * The amount of spacing between adjacent images in pixels. * @memberof TextureAtlas.prototype * @type {number} * @readonly * @private */ borderWidthInPixels: { get: function() { return this._borderWidthInPixels; } }, /** * An array of {@link BoundingRectangle} pixel offset and dimensions for all the images in the texture atlas. * The x and y values of the rectangle correspond to the bottom-left corner of the texture coordinate. * If the index is a subregion of an existing image, thea and y values are specified as offsets relative to the parent. * The coordinates are in the order that the corresponding images were added to the atlas. * @memberof TextureAtlas.prototype * @type {BoundingRectangle[]} * @readonly * @private */ rectangles: { get: function() { return this._rectangles; } }, /** * The texture that all of the images are being written to. The value will be undefined until the first update. * @memberof TextureAtlas.prototype * @type {Texture|undefined} * @readonly * @private */ texture: { get: function() { return this._texture; } }, /** * The pixel format of the texture. * @memberof TextureAtlas.prototype * @type {PixelFormat} * @readonly * @private */ pixelFormat: { get: function() { return this._pixelFormat; } }, /** * The sampler to use when sampling this texture. If undefined, the default sampler is used. * @memberof TextureAtlas.prototype * @type {Sampler|undefined} * @readonly * @private */ sampler: { get: function() { return this._sampler; } }, /** * The number of images in the texture atlas. This value increases * every time addImage or addImageSubRegion is called. * Texture coordinates are subject to change if the texture atlas resizes, so it is * important to check {@link TextureAtlas#guid} before using old values. * @memberof TextureAtlas.prototype * @type {number} * @readonly * @private */ numberOfImages: { get: function() { return this._nextIndex; } }, /** * The atlas' globally unique identifier (GUID). * The GUID changes whenever the texture atlas is modified. * Classes that use a texture atlas should check if the GUID * has changed before processing the atlas data. * @memberof TextureAtlas.prototype * @type {string} * @readonly * @private */ guid: { get: function() { return this._guid; } }, /** * Returns the size in bytes of the texture. * @memberof TextureAtlas.prototype * @type {number} * @readonly * @private */ sizeInBytes: { get: function() { if (!defined_default(this._texture)) { return 0; } return this._texture.sizeInBytes; } } }); TextureAtlas.prototype.computeTextureCoordinates = function(index, result) { Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); const texture = this._texture; const rectangle = this._rectangles[index]; if (!defined_default(result)) { result = new BoundingRectangle_default(); } if (!defined_default(rectangle)) { result.x = 0; result.y = 0; result.width = 0; result.height = 0; return result; } const atlasWidth = texture.width; const atlasHeight = texture.height; const width = rectangle.width; const height = rectangle.height; let x = rectangle.x; let y = rectangle.y; const parentIndex = this._subRegions.get(index); if (defined_default(parentIndex)) { const parentRectangle = this._rectangles[parentIndex]; x += parentRectangle.x; y += parentRectangle.y; } result.x = x / atlasWidth; result.y = y / atlasHeight; result.width = width / atlasWidth; result.height = height / atlasHeight; return result; }; TextureAtlas.prototype._copyFromTexture = function(context, width, height, rectangles) { const pixelFormat = this._pixelFormat; const sampler = this._sampler; const newTexture = new Texture_default({ context, height, width, pixelFormat, sampler }); const gl = context._gl; const target = newTexture._textureTarget; const oldTexture = this._texture; const framebuffer = new Framebuffer_default({ context, colorTextures: [oldTexture], destroyAttachments: false }); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(target, newTexture._texture); framebuffer._bind(); const oldRectangles = this.rectangles; const subRegions = this._subRegions; for (let index = 0; index < oldRectangles.length; ++index) { const rectangle = rectangles[index]; const frameBufferOffset = oldRectangles[index]; if (!defined_default(rectangle) || !defined_default(frameBufferOffset) || defined_default(subRegions.get(index))) { continue; } const { x, y, width: width2, height: height2 } = rectangle; gl.copyTexSubImage2D( target, 0, x, y, frameBufferOffset.x, frameBufferOffset.y, width2, height2 ); } gl.bindTexture(target, null); newTexture._initialized = true; framebuffer._unBind(); framebuffer.destroy(); return newTexture; }; TextureAtlas.prototype._resize = function(context, queueOffset = 0) { const borderPadding = this._borderWidthInPixels; const oldRectangles = this._rectangles; const queue = this._imagesToAddQueue; const oldTexture = this._texture; let width = oldTexture.width; let height = oldTexture.height; const subRegions = this._subRegions; const toPack = oldRectangles.map((image, index) => { return new AddImageRequest({ index, image }); }).filter( (request, index) => defined_default(request.image) && !defined_default(subRegions.get(index)) ); let maxWidth = 0; let maxHeight = 0; let areaQueued = 0; for (let i = queueOffset; i < queue.length; ++i) { const { width: width2, height: height2 } = queue[i].image; maxWidth = Math.max(maxWidth, width2); maxHeight = Math.max(maxHeight, height2); areaQueued += width2 * height2; toPack.push(queue[i]); } width = Math_default.nextPowerOfTwo(Math.max(maxWidth, width)); height = Math_default.nextPowerOfTwo(Math.max(maxHeight, height)); while (areaQueued >= width * height) { if (width > height) { height *= 2; } else { width *= 2; } } toPack.sort( ({ image: imageA }, { image: imageB }) => imageB.height * imageB.width - imageA.height * imageA.width ); const newRectangles = new Array(this._nextIndex); for (const index of this._subRegions.keys()) { if (defined_default(subRegions.get(index))) { newRectangles[index] = oldRectangles[index]; } } let texturePacker, packed = false; while (!packed) { texturePacker = new TexturePacker_default({ height, width, borderPadding }); let i; for (i = 0; i < toPack.length; ++i) { const { index, image } = toPack[i]; if (!defined_default(image)) { continue; } const repackedNode = texturePacker.pack(index, image); if (!defined_default(repackedNode)) { if (width > height) { height *= 2; } else { width *= 2; } break; } newRectangles[index] = repackedNode.rectangle; } packed = i === toPack.length; } this._texturePacker = texturePacker; this._texture = this._copyFromTexture(context, width, height, newRectangles); oldTexture.destroy(); this._rectangles = newRectangles; this._guid = createGuid_default(); }; TextureAtlas.prototype.getImageIndex = function(id) { Check_default.typeOf.string("id", id); return this._indexById.get(id); }; TextureAtlas.prototype._copyImageToTexture = function({ index, image, resolve: resolve2, reject }) { const texture = this._texture; const rectangle = this._rectangles[index]; try { texture.copyFrom({ source: image, xOffset: rectangle.x, yOffset: rectangle.y }); if (defined_default(resolve2)) { resolve2(index); } } catch (e) { if (defined_default(reject)) { reject(e); return; } } }; function AddImageRequest({ index, image, resolve: resolve2, reject }) { this.index = index; this.image = image; this.resolve = resolve2; this.reject = reject; this.rectangle = void 0; } TextureAtlas.prototype._addImage = function(index, image) { Check_default.typeOf.number.greaterThanOrEquals("index", index, 0); Check_default.defined("image", image); return new Promise((resolve2, reject) => { this._imagesToAddQueue.push( new AddImageRequest({ index, image, resolve: resolve2, reject }) ); this._imagesToAddQueue.sort( ({ image: imageA }, { image: imageB }) => imageB.height * imageB.width - imageA.height * imageA.width ); }); }; TextureAtlas.prototype._processImageQueue = function(context) { const queue = this._imagesToAddQueue; if (queue.length === 0) { return false; } this._rectangles.length = this._nextIndex; let i, error; for (i = 0; i < queue.length; ++i) { const imageRequest = queue[i]; const { image, index } = imageRequest; const node = this._texturePacker.pack(index, image); if (!defined_default(node)) { try { this._resize(context, i); } catch (e) { error = e; if (defined_default(imageRequest.reject)) { imageRequest.reject(error); } } break; } this._rectangles[index] = node.rectangle; } if (defined_default(error)) { for (i = i + 1; i < queue.length; ++i) { const { resolve: resolve2 } = queue[i]; if (defined_default(resolve2)) { resolve2(-1); } } queue.length = 0; return false; } for (let i2 = 0; i2 < queue.length; ++i2) { this._copyImageToTexture(queue[i2]); } queue.length = 0; return true; }; TextureAtlas.prototype.update = function(context) { if (!defined_default(this._texture)) { const width = this._initialSize.x; const height = this._initialSize.y; const pixelFormat = this._pixelFormat; const sampler = this._sampler; const borderPadding = this._borderWidthInPixels; this._texture = new Texture_default({ context, width, height, pixelFormat, sampler }); this._texturePacker = new TexturePacker_default({ height, width, borderPadding }); } return this._processImageQueue(context); }; async function resolveImage(image, id) { if (typeof image === "function") { image = image(id); } if (typeof image === "string" || image instanceof Resource_default) { const resource = Resource_default.createIfNeeded(image); image = resource.fetchImage(); } return image; } TextureAtlas.prototype.addImage = function(id, image, width, height) { Check_default.typeOf.string("id", id); Check_default.defined("image", image); let promise = this._indexPromiseById.get(id); let index = this._indexById.get(id); if (defined_default(promise)) { return promise; } if (defined_default(index)) { return index; } index = this._nextIndex++; this._indexById.set(id, index); const resolveAndAddImage = async () => { const resolvedImage = await resolveImage(image, id); Check_default.defined("image", resolvedImage); if (this.isDestroyed() || !defined_default(resolvedImage)) { this._indexPromiseById.delete(id); return -1; } if (defined_default(width)) { resolvedImage.width = width; } if (defined_default(height)) { resolvedImage.height = height; } const imageIndex = await this._addImage(index, resolvedImage); this._indexPromiseById.delete(id); return imageIndex; }; promise = resolveAndAddImage(); this._indexPromiseById.set(id, promise); return promise; }; TextureAtlas.prototype.getCachedImageSubRegion = function(id, subRegion, imageIndex) { const imagePromise = this._indexPromiseById.get(id); for (const [index, parentIndex] of this._subRegions.entries()) { if (imageIndex === parentIndex) { const boundingRegion = this._rectangles[index]; if (boundingRegion.equals(subRegion)) { if (imagePromise) { return imagePromise.then( (resolvedImageIndex) => resolvedImageIndex === -1 ? -1 : index ); } return index; } } } }; TextureAtlas.prototype.addImageSubRegion = function(id, subRegion) { Check_default.typeOf.string("id", id); Check_default.defined("subRegion", subRegion); const imageIndex = this._indexById.get(id); if (!defined_default(imageIndex)) { throw new RuntimeError_default(`image with id "${id}" not found in the atlas.`); } let index = this.getCachedImageSubRegion(id, subRegion, imageIndex); if (defined_default(index)) { return index; } index = this._nextIndex++; this._subRegions.set(index, imageIndex); this._rectangles[index] = subRegion.clone(); const indexPromise = this._indexPromiseById.get(id) ?? Promise.resolve(imageIndex); return indexPromise.then((imageIndex2) => { if (imageIndex2 === -1) { return -1; } const rectangle = this._rectangles[imageIndex2]; Check_default.typeOf.number.lessThanOrEquals( "subRegion.x", subRegion.x, rectangle.width ); Check_default.typeOf.number.lessThanOrEquals( "subRegion.x + subRegion.width", subRegion.x + subRegion.width, rectangle.width ); Check_default.typeOf.number.lessThanOrEquals( "subRegion.y", subRegion.y, rectangle.height ); Check_default.typeOf.number.lessThanOrEquals( "subRegion.y + subRegion.height", subRegion.y + subRegion.height, rectangle.height ); return index; }); }; TextureAtlas.prototype.isDestroyed = function() { return false; }; TextureAtlas.prototype.destroy = function() { this._texture = this._texture && this._texture.destroy(); this._imagesToAddQueue.forEach(({ resolve: resolve2 }) => { if (defined_default(resolve2)) { resolve2(-1); } }); return destroyObject_default(this); }; var TextureAtlas_default = TextureAtlas; // packages/engine/Source/Renderer/VertexArrayFacade.js var import_InlineWorkers294 = __toESM(require_InlineWorkers(), 1); function VertexArrayFacade(context, attributes, sizeInVertices, instanced) { Check_default.defined("context", context); if (!attributes || attributes.length === 0) { throw new DeveloperError_default("At least one attribute is required."); } const attrs = VertexArrayFacade._verifyAttributes(attributes); sizeInVertices = sizeInVertices ?? 0; const precreatedAttributes = []; const attributesByUsage = {}; let attributesForUsage; let usage; const length2 = attrs.length; for (let i = 0; i < length2; ++i) { const attribute = attrs[i]; if (attribute.vertexBuffer) { precreatedAttributes.push(attribute); continue; } usage = attribute.usage; attributesForUsage = attributesByUsage[usage]; if (!defined_default(attributesForUsage)) { attributesForUsage = attributesByUsage[usage] = []; } attributesForUsage.push(attribute); } function compare(left, right) { return ComponentDatatype_default.getSizeInBytes(right.componentDatatype) - ComponentDatatype_default.getSizeInBytes(left.componentDatatype); } this._allBuffers = []; for (usage in attributesByUsage) { if (attributesByUsage.hasOwnProperty(usage)) { attributesForUsage = attributesByUsage[usage]; attributesForUsage.sort(compare); const vertexSizeInBytes = VertexArrayFacade._vertexSizeInBytes(attributesForUsage); const bufferUsage = attributesForUsage[0].usage; const buffer2 = { vertexSizeInBytes, vertexBuffer: void 0, usage: bufferUsage, needsCommit: false, arrayBuffer: void 0, arrayViews: VertexArrayFacade._createArrayViews( attributesForUsage, vertexSizeInBytes ) }; this._allBuffers.push(buffer2); } } this._size = 0; this._instanced = instanced ?? false; this._precreated = precreatedAttributes; this._context = context; this.writers = void 0; this.va = void 0; this.resize(sizeInVertices); } VertexArrayFacade._verifyAttributes = function(attributes) { const attrs = []; for (let i = 0; i < attributes.length; ++i) { const attribute = attributes[i]; const attr = { index: attribute.index ?? i, enabled: attribute.enabled ?? true, componentsPerAttribute: attribute.componentsPerAttribute, componentDatatype: attribute.componentDatatype ?? ComponentDatatype_default.FLOAT, normalize: attribute.normalize ?? false, // There will be either a vertexBuffer or an [optional] usage. vertexBuffer: attribute.vertexBuffer, usage: attribute.usage ?? BufferUsage_default.STATIC_DRAW }; attrs.push(attr); if (attr.componentsPerAttribute !== 1 && attr.componentsPerAttribute !== 2 && attr.componentsPerAttribute !== 3 && attr.componentsPerAttribute !== 4) { throw new DeveloperError_default( "attribute.componentsPerAttribute must be in the range [1, 4]." ); } const datatype = attr.componentDatatype; if (!ComponentDatatype_default.validate(datatype)) { throw new DeveloperError_default( "Attribute must have a valid componentDatatype or not specify it." ); } if (!BufferUsage_default.validate(attr.usage)) { throw new DeveloperError_default( "Attribute must have a valid usage or not specify it." ); } } const uniqueIndices = new Array(attrs.length); for (let j = 0; j < attrs.length; ++j) { const currentAttr = attrs[j]; const index = currentAttr.index; if (uniqueIndices[index]) { throw new DeveloperError_default( `Index ${index} is used by more than one attribute.` ); } uniqueIndices[index] = true; } return attrs; }; VertexArrayFacade._vertexSizeInBytes = function(attributes) { let sizeInBytes = 0; const length2 = attributes.length; for (let i = 0; i < length2; ++i) { const attribute = attributes[i]; sizeInBytes += attribute.componentsPerAttribute * ComponentDatatype_default.getSizeInBytes(attribute.componentDatatype); } const maxComponentSizeInBytes = length2 > 0 ? ComponentDatatype_default.getSizeInBytes(attributes[0].componentDatatype) : 0; const remainder = maxComponentSizeInBytes > 0 ? sizeInBytes % maxComponentSizeInBytes : 0; const padding = remainder === 0 ? 0 : maxComponentSizeInBytes - remainder; sizeInBytes += padding; return sizeInBytes; }; VertexArrayFacade._createArrayViews = function(attributes, vertexSizeInBytes) { const views = []; let offsetInBytes = 0; const length2 = attributes.length; for (let i = 0; i < length2; ++i) { const attribute = attributes[i]; const componentDatatype = attribute.componentDatatype; views.push({ index: attribute.index, enabled: attribute.enabled, componentsPerAttribute: attribute.componentsPerAttribute, componentDatatype, normalize: attribute.normalize, offsetInBytes, vertexSizeInComponentType: vertexSizeInBytes / ComponentDatatype_default.getSizeInBytes(componentDatatype), view: void 0 }); offsetInBytes += attribute.componentsPerAttribute * ComponentDatatype_default.getSizeInBytes(componentDatatype); } return views; }; VertexArrayFacade.prototype.resize = function(sizeInVertices) { this._size = sizeInVertices; const allBuffers = this._allBuffers; this.writers = []; for (let i = 0, len = allBuffers.length; i < len; ++i) { const buffer2 = allBuffers[i]; VertexArrayFacade._resize(buffer2, this._size); VertexArrayFacade._appendWriters(this.writers, buffer2); } destroyVA(this); }; VertexArrayFacade._resize = function(buffer2, size) { if (buffer2.vertexSizeInBytes > 0) { const arrayBuffer = new ArrayBuffer(size * buffer2.vertexSizeInBytes); if (defined_default(buffer2.arrayBuffer)) { const destView = new Uint8Array(arrayBuffer); const sourceView = new Uint8Array(buffer2.arrayBuffer); const sourceLength = sourceView.length; for (let j = 0; j < sourceLength; ++j) { destView[j] = sourceView[j]; } } const views = buffer2.arrayViews; const length2 = views.length; for (let i = 0; i < length2; ++i) { const view = views[i]; view.view = ComponentDatatype_default.createArrayBufferView( view.componentDatatype, arrayBuffer, view.offsetInBytes ); } buffer2.arrayBuffer = arrayBuffer; } }; var createWriters = [ // 1 component per attribute function(buffer2, view, vertexSizeInComponentType) { return function(index, attribute) { view[index * vertexSizeInComponentType] = attribute; buffer2.needsCommit = true; }; }, // 2 component per attribute function(buffer2, view, vertexSizeInComponentType) { return function(index, component0, component1) { const i = index * vertexSizeInComponentType; view[i] = component0; view[i + 1] = component1; buffer2.needsCommit = true; }; }, // 3 component per attribute function(buffer2, view, vertexSizeInComponentType) { return function(index, component0, component1, component2) { const i = index * vertexSizeInComponentType; view[i] = component0; view[i + 1] = component1; view[i + 2] = component2; buffer2.needsCommit = true; }; }, // 4 component per attribute function(buffer2, view, vertexSizeInComponentType) { return function(index, component0, component1, component2, component3) { const i = index * vertexSizeInComponentType; view[i] = component0; view[i + 1] = component1; view[i + 2] = component2; view[i + 3] = component3; buffer2.needsCommit = true; }; } ]; VertexArrayFacade._appendWriters = function(writers, buffer2) { const arrayViews = buffer2.arrayViews; const length2 = arrayViews.length; for (let i = 0; i < length2; ++i) { const arrayView = arrayViews[i]; writers[arrayView.index] = createWriters[arrayView.componentsPerAttribute - 1](buffer2, arrayView.view, arrayView.vertexSizeInComponentType); } }; VertexArrayFacade.prototype.commit = function(indexBuffer) { let recreateVA = false; const allBuffers = this._allBuffers; let buffer2; let i; let length2; for (i = 0, length2 = allBuffers.length; i < length2; ++i) { buffer2 = allBuffers[i]; recreateVA = commit(this, buffer2) || recreateVA; } if (recreateVA || !defined_default(this.va)) { destroyVA(this); const va = this.va = []; const chunkSize = Math_default.SIXTY_FOUR_KILOBYTES - 4; const numberOfVertexArrays = defined_default(indexBuffer) && !this._instanced ? Math.ceil(this._size / chunkSize) : 1; for (let k = 0; k < numberOfVertexArrays; ++k) { let attributes = []; for (i = 0, length2 = allBuffers.length; i < length2; ++i) { buffer2 = allBuffers[i]; const offset = k * (buffer2.vertexSizeInBytes * chunkSize); VertexArrayFacade._appendAttributes( attributes, buffer2, offset, this._instanced ); } attributes = attributes.concat(this._precreated); va.push({ va: new VertexArray_default({ context: this._context, attributes, indexBuffer }), indicesCount: 1.5 * (k !== numberOfVertexArrays - 1 ? chunkSize : this._size % chunkSize) // TODO: not hardcode 1.5, this assumes 6 indices per 4 vertices (as for Billboard quads). }); } } }; function commit(vertexArrayFacade, buffer2) { if (buffer2.needsCommit && buffer2.vertexSizeInBytes > 0) { buffer2.needsCommit = false; const vertexBuffer = buffer2.vertexBuffer; const vertexBufferSizeInBytes = vertexArrayFacade._size * buffer2.vertexSizeInBytes; const vertexBufferDefined = defined_default(vertexBuffer); if (!vertexBufferDefined || vertexBuffer.sizeInBytes < vertexBufferSizeInBytes) { if (vertexBufferDefined) { vertexBuffer.destroy(); } buffer2.vertexBuffer = Buffer_default.createVertexBuffer({ context: vertexArrayFacade._context, typedArray: buffer2.arrayBuffer, usage: buffer2.usage }); buffer2.vertexBuffer.vertexArrayDestroyable = false; return true; } buffer2.vertexBuffer.copyFromArrayView(buffer2.arrayBuffer); } return false; } VertexArrayFacade._appendAttributes = function(attributes, buffer2, vertexBufferOffset, instanced) { const arrayViews = buffer2.arrayViews; const length2 = arrayViews.length; for (let i = 0; i < length2; ++i) { const view = arrayViews[i]; attributes.push({ index: view.index, enabled: view.enabled, componentsPerAttribute: view.componentsPerAttribute, componentDatatype: view.componentDatatype, normalize: view.normalize, vertexBuffer: buffer2.vertexBuffer, offsetInBytes: vertexBufferOffset + view.offsetInBytes, strideInBytes: buffer2.vertexSizeInBytes, instanceDivisor: instanced ? 1 : 0 }); } }; VertexArrayFacade.prototype.subCommit = function(offsetInVertices, lengthInVertices) { if (offsetInVertices < 0 || offsetInVertices >= this._size) { throw new DeveloperError_default( "offsetInVertices must be greater than or equal to zero and less than the vertex array size." ); } if (offsetInVertices + lengthInVertices > this._size) { throw new DeveloperError_default( "offsetInVertices + lengthInVertices cannot exceed the vertex array size." ); } const allBuffers = this._allBuffers; for (let i = 0, len = allBuffers.length; i < len; ++i) { subCommit(allBuffers[i], offsetInVertices, lengthInVertices); } }; function subCommit(buffer2, offsetInVertices, lengthInVertices) { if (buffer2.needsCommit && buffer2.vertexSizeInBytes > 0) { const byteOffset = buffer2.vertexSizeInBytes * offsetInVertices; const byteLength = buffer2.vertexSizeInBytes * lengthInVertices; buffer2.vertexBuffer.copyFromArrayView( new Uint8Array(buffer2.arrayBuffer, byteOffset, byteLength), byteOffset ); } } VertexArrayFacade.prototype.endSubCommits = function() { const allBuffers = this._allBuffers; for (let i = 0, len = allBuffers.length; i < len; ++i) { allBuffers[i].needsCommit = false; } }; function destroyVA(vertexArrayFacade) { const va = vertexArrayFacade.va; if (!defined_default(va)) { return; } const length2 = va.length; for (let i = 0; i < length2; ++i) { va[i].va.destroy(); } vertexArrayFacade.va = void 0; } VertexArrayFacade.prototype.isDestroyed = function() { return false; }; VertexArrayFacade.prototype.destroy = function() { const allBuffers = this._allBuffers; for (let i = 0, len = allBuffers.length; i < len; ++i) { const buffer2 = allBuffers[i]; buffer2.vertexBuffer = buffer2.vertexBuffer && buffer2.vertexBuffer.destroy(); } destroyVA(this); return destroyObject_default(this); }; var VertexArrayFacade_default = VertexArrayFacade; // packages/engine/Source/Renderer/loadCubeMap.js var import_InlineWorkers295 = __toESM(require_InlineWorkers(), 1); function loadCubeMap(context, urls, skipColorSpaceConversion) { Check_default.defined("context", context); Check_default.defined("urls", urls); if (Object.values(CubeMap_default.FaceName).some((faceName) => !defined_default(urls[faceName]))) { throw new DeveloperError_default( "urls must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties." ); } const flipOptions = { flipY: true, skipColorSpaceConversion, preferImageBitmap: true }; const facePromises = [ Resource_default.createIfNeeded(urls.positiveX).fetchImage(flipOptions), Resource_default.createIfNeeded(urls.negativeX).fetchImage(flipOptions), Resource_default.createIfNeeded(urls.positiveY).fetchImage(flipOptions), Resource_default.createIfNeeded(urls.negativeY).fetchImage(flipOptions), Resource_default.createIfNeeded(urls.positiveZ).fetchImage(flipOptions), Resource_default.createIfNeeded(urls.negativeZ).fetchImage(flipOptions) ]; return Promise.all(facePromises).then(function(images) { return new CubeMap_default({ context, source: { positiveX: images[0], negativeX: images[1], positiveY: images[2], negativeY: images[3], positiveZ: images[4], negativeZ: images[5] } }); }); } var loadCubeMap_default = loadCubeMap; // packages/engine/Source/DataSources/BillboardGraphics.js var import_InlineWorkers298 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/createPropertyDescriptor.js var import_InlineWorkers297 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/ConstantProperty.js var import_InlineWorkers296 = __toESM(require_InlineWorkers(), 1); function ConstantProperty(value) { this._value = void 0; this._hasClone = false; this._hasEquals = false; this._definitionChanged = new Event_default(); this.setValue(value); } Object.defineProperties(ConstantProperty.prototype, { /** * Gets a value indicating if this property is constant. * This property always returns true. * @memberof ConstantProperty.prototype * * @type {boolean} * @readonly */ isConstant: { value: true }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is changed whenever setValue is called with data different * than the current value. * @memberof ConstantProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } } }); ConstantProperty.prototype.getValue = function(time, result) { return this._hasClone ? this._value.clone(result) : this._value; }; ConstantProperty.prototype.setValue = function(value) { const oldValue2 = this._value; if (oldValue2 !== value) { const isDefined = defined_default(value); const hasClone = isDefined && typeof value.clone === "function"; const hasEquals = isDefined && typeof value.equals === "function"; const changed = !hasEquals || !value.equals(oldValue2); if (changed) { this._hasClone = hasClone; this._hasEquals = hasEquals; this._value = !hasClone ? value : value.clone(this._value); this._definitionChanged.raiseEvent(this); } } }; ConstantProperty.prototype.equals = function(other) { return this === other || // other instanceof ConstantProperty && // (!this._hasEquals && this._value === other._value || // this._hasEquals && this._value.equals(other._value)); }; ConstantProperty.prototype.valueOf = function() { return this._value; }; ConstantProperty.prototype.toString = function() { return String(this._value); }; var ConstantProperty_default = ConstantProperty; // packages/engine/Source/DataSources/createPropertyDescriptor.js function createProperty(name, privateName, subscriptionName, configurable, createPropertyCallback) { return { configurable, get: function() { return this[privateName]; }, set: function(value) { const oldValue2 = this[privateName]; const subscription = this[subscriptionName]; if (defined_default(subscription)) { subscription(); this[subscriptionName] = void 0; } const hasValue = value !== void 0; if (hasValue && (!defined_default(value) || !defined_default(value.getValue)) && defined_default(createPropertyCallback)) { value = createPropertyCallback(value); } if (oldValue2 !== value) { this[privateName] = value; this._definitionChanged.raiseEvent(this, name, value, oldValue2); } if (defined_default(value) && defined_default(value.definitionChanged)) { this[subscriptionName] = value.definitionChanged.addEventListener( function() { this._definitionChanged.raiseEvent(this, name, value, value); }, this ); } } }; } function createConstantProperty(value) { return new ConstantProperty_default(value); } function createPropertyDescriptor(name, configurable, createPropertyCallback) { return createProperty( name, `_${name.toString()}`, `_${name.toString()}Subscription`, configurable ?? false, createPropertyCallback ?? createConstantProperty ); } var createPropertyDescriptor_default = createPropertyDescriptor; // packages/engine/Source/DataSources/BillboardGraphics.js function BillboardGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._image = void 0; this._imageSubscription = void 0; this._scale = void 0; this._scaleSubscription = void 0; this._pixelOffset = void 0; this._pixelOffsetSubscription = void 0; this._eyeOffset = void 0; this._eyeOffsetSubscription = void 0; this._horizontalOrigin = void 0; this._horizontalOriginSubscription = void 0; this._verticalOrigin = void 0; this._verticalOriginSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._color = void 0; this._colorSubscription = void 0; this._rotation = void 0; this._rotationSubscription = void 0; this._alignedAxis = void 0; this._alignedAxisSubscription = void 0; this._sizeInMeters = void 0; this._sizeInMetersSubscription = void 0; this._width = void 0; this._widthSubscription = void 0; this._height = void 0; this._heightSubscription = void 0; this._scaleByDistance = void 0; this._scaleByDistanceSubscription = void 0; this._translucencyByDistance = void 0; this._translucencyByDistanceSubscription = void 0; this._pixelOffsetScaleByDistance = void 0; this._pixelOffsetScaleByDistanceSubscription = void 0; this._imageSubRegion = void 0; this._imageSubRegionSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._disableDepthTestDistance = void 0; this._disableDepthTestDistanceSubscription = void 0; this._splitDirection = void 0; this._splitDirectionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(BillboardGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof BillboardGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the billboard. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the Image, URI, or Canvas to use for the billboard. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ image: createPropertyDescriptor_default("image"), /** * Gets or sets the numeric Property specifying the uniform scale to apply to the image. * A scale greater than 1.0 enlarges the billboard while a scale less than 1.0 shrinks it. *

*

*
* From left to right in the above image, the scales are 0.5, 1.0, and 2.0. *
*

* @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default 1.0 */ scale: createPropertyDescriptor_default("scale"), /** * Gets or sets the {@link Cartesian2} Property specifying the billboard's pixel offset in screen space * from the origin of this billboard. This is commonly used to align multiple billboards and labels at * the same position, e.g., an image and text. The screen space origin is the top, left corner of the * canvas; x increases from left to right, and y increases from top to bottom. *

*

* * * *
default
b.pixeloffset = new Cartesian2(50, 25);
* The billboard's origin is indicated by the yellow point. *
*

* @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default Cartesian2.ZERO */ pixelOffset: createPropertyDescriptor_default("pixelOffset"), /** * Gets or sets the {@link Cartesian3} Property specifying the billboard's offset in eye coordinates. * Eye coordinates is a left-handed coordinate system, where x points towards the viewer's * right, y points up, and z points into the screen. *

* An eye offset is commonly used to arrange multiple billboards or objects at the same position, e.g., to * arrange a billboard above its corresponding 3D model. *

* Below, the billboard is positioned at the center of the Earth but an eye offset makes it always * appear on top of the Earth regardless of the viewer's or Earth's orientation. *

*

* * * *
* b.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0); *
*

* @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default Cartesian3.ZERO */ eyeOffset: createPropertyDescriptor_default("eyeOffset"), /** * Gets or sets the Property specifying the {@link HorizontalOrigin}. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default HorizontalOrigin.CENTER */ horizontalOrigin: createPropertyDescriptor_default("horizontalOrigin"), /** * Gets or sets the Property specifying the {@link VerticalOrigin}. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default VerticalOrigin.CENTER */ verticalOrigin: createPropertyDescriptor_default("verticalOrigin"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the Property specifying the {@link Color} that is multiplied with the image. * This has two common use cases. First, the same white texture may be used by many different billboards, * each with a different color, to create colored billboards. Second, the color's alpha component can be * used to make the billboard translucent as shown below. An alpha of 0.0 makes the billboard * transparent, and 1.0 makes the billboard opaque. *

*

* * * *
default
alpha : 0.5
*
*

* @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default Color.WHITE */ color: createPropertyDescriptor_default("color"), /** * Gets or sets the numeric Property specifying the rotation of the image * counter clockwise from the alignedAxis. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default 0 */ rotation: createPropertyDescriptor_default("rotation"), /** * Gets or sets the {@link Cartesian3} Property specifying the unit vector axis of rotation * in the fixed frame. When set to Cartesian3.ZERO the rotation is from the top of the screen. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default Cartesian3.ZERO */ alignedAxis: createPropertyDescriptor_default("alignedAxis"), /** * Gets or sets the boolean Property specifying if this billboard's size will be measured in meters. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default false */ sizeInMeters: createPropertyDescriptor_default("sizeInMeters"), /** * Gets or sets the numeric Property specifying the width of the billboard in pixels. * When undefined, the native width is used. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ width: createPropertyDescriptor_default("width"), /** * Gets or sets the numeric Property specifying the height of the billboard in pixels. * When undefined, the native height is used. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ height: createPropertyDescriptor_default("height"), /** * Gets or sets {@link NearFarScalar} Property specifying the scale of the billboard based on the distance from the camera. * A billboard's scale will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the billboard's scale remains clamped to the nearest bound. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ scaleByDistance: createPropertyDescriptor_default("scaleByDistance"), /** * Gets or sets {@link NearFarScalar} Property specifying the translucency of the billboard based on the distance from the camera. * A billboard's translucency will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the billboard's translucency remains clamped to the nearest bound. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ translucencyByDistance: createPropertyDescriptor_default("translucencyByDistance"), /** * Gets or sets {@link NearFarScalar} Property specifying the pixel offset of the billboard based on the distance from the camera. * A billboard's pixel offset will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the billboard's pixel offset remains clamped to the nearest bound. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ pixelOffsetScaleByDistance: createPropertyDescriptor_default( "pixelOffsetScaleByDistance" ), /** * Gets or sets the Property specifying a {@link BoundingRectangle} that defines a * sub-region of the image to use for the billboard, rather than the entire image, * measured in pixels from the bottom-left. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ imageSubRegion: createPropertyDescriptor_default("imageSubRegion"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this billboard will be displayed. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the distance from the camera at which to disable the depth test to, for example, prevent clipping against terrain. * When set to zero, the depth test is always applied. When set to Number.POSITIVE_INFINITY, the depth test is never applied. * @memberof BillboardGraphics.prototype * @type {Property|undefined} */ disableDepthTestDistance: createPropertyDescriptor_default( "disableDepthTestDistance" ), /** * Gets or sets the Property specifying the {@link SplitDirection} of this billboard. * @memberof BillboardGraphics.prototype * @type {Property|undefined} * @default SplitDirection.NONE */ splitDirection: createPropertyDescriptor_default("splitDirection") }); BillboardGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new BillboardGraphics(this); } result.show = this._show; result.image = this._image; result.scale = this._scale; result.pixelOffset = this._pixelOffset; result.eyeOffset = this._eyeOffset; result.horizontalOrigin = this._horizontalOrigin; result.verticalOrigin = this._verticalOrigin; result.heightReference = this._heightReference; result.color = this._color; result.rotation = this._rotation; result.alignedAxis = this._alignedAxis; result.sizeInMeters = this._sizeInMeters; result.width = this._width; result.height = this._height; result.scaleByDistance = this._scaleByDistance; result.translucencyByDistance = this._translucencyByDistance; result.pixelOffsetScaleByDistance = this._pixelOffsetScaleByDistance; result.imageSubRegion = this._imageSubRegion; result.distanceDisplayCondition = this._distanceDisplayCondition; result.disableDepthTestDistance = this._disableDepthTestDistance; result.splitDirection = this._splitDirection; return result; }; BillboardGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this._show ?? source.show; this.image = this._image ?? source.image; this.scale = this._scale ?? source.scale; this.pixelOffset = this._pixelOffset ?? source.pixelOffset; this.eyeOffset = this._eyeOffset ?? source.eyeOffset; this.horizontalOrigin = this._horizontalOrigin ?? source.horizontalOrigin; this.verticalOrigin = this._verticalOrigin ?? source.verticalOrigin; this.heightReference = this._heightReference ?? source.heightReference; this.color = this._color ?? source.color; this.rotation = this._rotation ?? source.rotation; this.alignedAxis = this._alignedAxis ?? source.alignedAxis; this.sizeInMeters = this._sizeInMeters ?? source.sizeInMeters; this.width = this._width ?? source.width; this.height = this._height ?? source.height; this.scaleByDistance = this._scaleByDistance ?? source.scaleByDistance; this.translucencyByDistance = this._translucencyByDistance ?? source.translucencyByDistance; this.pixelOffsetScaleByDistance = this._pixelOffsetScaleByDistance ?? source.pixelOffsetScaleByDistance; this.imageSubRegion = this._imageSubRegion ?? source.imageSubRegion; this.distanceDisplayCondition = this._distanceDisplayCondition ?? source.distanceDisplayCondition; this.disableDepthTestDistance = this._disableDepthTestDistance ?? source.disableDepthTestDistance; this.splitDirection = this.splitDirection ?? source.splitDirection; }; var BillboardGraphics_default = BillboardGraphics; // packages/engine/Source/DataSources/BillboardVisualizer.js var import_InlineWorkers308 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/AssociativeArray.js var import_InlineWorkers299 = __toESM(require_InlineWorkers(), 1); var AssociativeArray = class { constructor() { this._array = []; this._hash = {}; } /** * Gets the number of items in the collection. * * @type {number} */ get length() { return this._array.length; } /** * Gets an unordered array of all values in the collection. * This is a live array that will automatically reflect the values in the collection, * it should not be modified directly. * * @type {Array} */ get values() { return this._array; } /** * Determines if the provided key is in the array. * * @param {string|number} key The key to check. * @returns {boolean} true if the key is in the array, false otherwise. */ contains(key) { if (typeof key !== "string" && typeof key !== "number") { throw new DeveloperError_default("key is required to be a string or number."); } return defined_default(this._hash[key]); } /** * Associates the provided key with the provided value. If the key already * exists, it is overwritten with the new value. * * @param {string|number} key A unique identifier. * @param {T} value The value to associate with the provided key. */ set(key, value) { if (typeof key !== "string" && typeof key !== "number") { throw new DeveloperError_default("key is required to be a string or number."); } const oldValue2 = this._hash[key]; if (value !== oldValue2) { this.remove(key); this._hash[key] = value; this._array.push(value); } } /** * Retrieves the value associated with the provided key. * * @param {string|number} key The key whose value is to be retrieved. * @returns {T} The associated value, or undefined if the key does not exist in the collection. */ get(key) { if (typeof key !== "string" && typeof key !== "number") { throw new DeveloperError_default("key is required to be a string or number."); } return this._hash[key]; } /** * Removes a key-value pair from the collection. * * @param {string|number} key The key to be removed. * @returns {boolean} True if it was removed, false if the key was not in the collection. */ remove(key) { if (defined_default(key) && typeof key !== "string" && typeof key !== "number") { throw new DeveloperError_default("key is required to be a string or number."); } const value = this._hash[key]; const hasValue = defined_default(value); if (hasValue) { const array = this._array; array.splice(array.indexOf(value), 1); delete this._hash[key]; } return hasValue; } /** * Clears the collection. */ removeAll() { const array = this._array; if (array.length > 0) { this._hash = {}; array.length = 0; } } }; var AssociativeArray_default = AssociativeArray; // packages/engine/Source/Core/DistanceDisplayCondition.js var import_InlineWorkers300 = __toESM(require_InlineWorkers(), 1); function DistanceDisplayCondition(near, far) { near = near ?? 0; this._near = near; far = far ?? Number.MAX_VALUE; this._far = far; } Object.defineProperties(DistanceDisplayCondition.prototype, { /** * The smallest distance in the interval where the object is visible. * @memberof DistanceDisplayCondition.prototype * @type {number} * @default 0.0 */ near: { get: function() { return this._near; }, set: function(value) { this._near = value; } }, /** * The largest distance in the interval where the object is visible. * @memberof DistanceDisplayCondition.prototype * @type {number} * @default Number.MAX_VALUE */ far: { get: function() { return this._far; }, set: function(value) { this._far = value; } } }); DistanceDisplayCondition.packedLength = 2; DistanceDisplayCondition.pack = function(value, array, startingIndex) { if (!defined_default(value)) { throw new DeveloperError_default("value is required"); } if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; array[startingIndex++] = value.near; array[startingIndex] = value.far; return array; }; DistanceDisplayCondition.unpack = function(array, startingIndex, result) { if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new DistanceDisplayCondition(); } result.near = array[startingIndex++]; result.far = array[startingIndex]; return result; }; DistanceDisplayCondition.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.near === right.near && left.far === right.far; }; DistanceDisplayCondition.clone = function(value, result) { if (!defined_default(value)) { return void 0; } if (!defined_default(result)) { result = new DistanceDisplayCondition(); } result.near = value.near; result.far = value.far; return result; }; DistanceDisplayCondition.prototype.clone = function(result) { return DistanceDisplayCondition.clone(this, result); }; DistanceDisplayCondition.prototype.equals = function(other) { return DistanceDisplayCondition.equals(this, other); }; var DistanceDisplayCondition_default = DistanceDisplayCondition; // packages/engine/Source/Core/NearFarScalar.js var import_InlineWorkers301 = __toESM(require_InlineWorkers(), 1); function NearFarScalar(near, nearValue, far, farValue) { this.near = near ?? 0; this.nearValue = nearValue ?? 0; this.far = far ?? 1; this.farValue = farValue ?? 0; } NearFarScalar.clone = function(nearFarScalar, result) { if (!defined_default(nearFarScalar)) { return void 0; } if (!defined_default(result)) { return new NearFarScalar( nearFarScalar.near, nearFarScalar.nearValue, nearFarScalar.far, nearFarScalar.farValue ); } result.near = nearFarScalar.near; result.nearValue = nearFarScalar.nearValue; result.far = nearFarScalar.far; result.farValue = nearFarScalar.farValue; return result; }; NearFarScalar.packedLength = 4; NearFarScalar.pack = function(value, array, startingIndex) { if (!defined_default(value)) { throw new DeveloperError_default("value is required"); } if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; array[startingIndex++] = value.near; array[startingIndex++] = value.nearValue; array[startingIndex++] = value.far; array[startingIndex] = value.farValue; return array; }; NearFarScalar.unpack = function(array, startingIndex, result) { if (!defined_default(array)) { throw new DeveloperError_default("array is required"); } startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new NearFarScalar(); } result.near = array[startingIndex++]; result.nearValue = array[startingIndex++]; result.far = array[startingIndex++]; result.farValue = array[startingIndex]; return result; }; NearFarScalar.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.near === right.near && left.nearValue === right.nearValue && left.far === right.far && left.farValue === right.farValue; }; NearFarScalar.prototype.clone = function(result) { return NearFarScalar.clone(this, result); }; NearFarScalar.prototype.equals = function(right) { return NearFarScalar.equals(this, right); }; var NearFarScalar_default = NearFarScalar; // packages/engine/Source/Scene/HeightReference.js var import_InlineWorkers302 = __toESM(require_InlineWorkers(), 1); var HeightReference = { /** * The position is absolute. * @type {number} * @constant */ NONE: 0, /** * The position is clamped to the terrain and 3D Tiles. When clamping to 3D Tilesets such as photorealistic 3D Tiles, ensure the tileset has {@link Cesium3DTileset#enableCollision} set to true. Otherwise, the entity may not be correctly clamped to the tileset surface. * @type {number} * @constant */ CLAMP_TO_GROUND: 1, /** * The position height is the height above the terrain and 3D Tiles. * @type {number} * @constant */ RELATIVE_TO_GROUND: 2, /** * The position is clamped to terain. * @type {number} * @constant */ CLAMP_TO_TERRAIN: 3, /** * The position height is the height above terrain. * @type {number} * @constant */ RELATIVE_TO_TERRAIN: 4, /** * The position is clamped to 3D Tiles. * @type {number} * @constant */ CLAMP_TO_3D_TILE: 5, /** * The position height is the height above 3D Tiles. * @type {number} * @constant */ RELATIVE_TO_3D_TILE: 6 }; Object.freeze(HeightReference); var HeightReference_default = HeightReference; function isHeightReferenceClamp(heightReference) { return heightReference === HeightReference.CLAMP_TO_GROUND || heightReference === HeightReference.CLAMP_TO_3D_TILE || heightReference === HeightReference.CLAMP_TO_TERRAIN; } function isHeightReferenceRelative(heightReference) { return heightReference === HeightReference.RELATIVE_TO_GROUND || heightReference === HeightReference.RELATIVE_TO_3D_TILE || heightReference === HeightReference.RELATIVE_TO_TERRAIN; } // packages/engine/Source/Scene/HorizontalOrigin.js var import_InlineWorkers303 = __toESM(require_InlineWorkers(), 1); var HorizontalOrigin = { /** * The origin is at the horizontal center of the object. * * @type {number} * @constant */ CENTER: 0, /** * The origin is on the left side of the object. * * @type {number} * @constant */ LEFT: 1, /** * The origin is on the right side of the object. * * @type {number} * @constant */ RIGHT: -1 }; Object.freeze(HorizontalOrigin); var HorizontalOrigin_default = HorizontalOrigin; // packages/engine/Source/Scene/VerticalOrigin.js var import_InlineWorkers304 = __toESM(require_InlineWorkers(), 1); var VerticalOrigin = { /** * The origin is at the vertical center between BASELINE and TOP. * * @type {number} * @constant */ CENTER: 0, /** * The origin is at the bottom of the object. * * @type {number} * @constant */ BOTTOM: 1, /** * If the object contains text, the origin is at the baseline of the text, else the origin is at the bottom of the object. * * @type {number} * @constant */ BASELINE: 2, /** * The origin is at the top of the object. * * @type {number} * @constant */ TOP: -1 }; Object.freeze(VerticalOrigin); var VerticalOrigin_default = VerticalOrigin; // packages/engine/Source/DataSources/BoundingSphereState.js var import_InlineWorkers305 = __toESM(require_InlineWorkers(), 1); var BoundingSphereState = Object.freeze({ /** * The BoundingSphere has been computed. * @type BoundingSphereState * @constant */ DONE: 0, /** * The BoundingSphere is still being computed. * @type BoundingSphereState * @constant */ PENDING: 1, /** * The BoundingSphere does not exist. * @type BoundingSphereState * @constant */ FAILED: 2 }); var BoundingSphereState_default = BoundingSphereState; // packages/engine/Source/DataSources/Property.js var import_InlineWorkers306 = __toESM(require_InlineWorkers(), 1); function Property() { DeveloperError_default.throwInstantiationError(); } Object.defineProperties(Property.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof Property.prototype * * @type {boolean} * @readonly */ isConstant: { get: DeveloperError_default.throwInstantiationError }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof Property.prototype * * @type {Event} * @readonly */ definitionChanged: { get: DeveloperError_default.throwInstantiationError } }); Property.prototype.getValue = DeveloperError_default.throwInstantiationError; Property.prototype.equals = DeveloperError_default.throwInstantiationError; Property.equals = function(left, right) { return left === right || defined_default(left) && left.equals(right); }; Property.arrayEquals = function(left, right) { if (left === right) { return true; } if (!defined_default(left) || !defined_default(right) || left.length !== right.length) { return false; } const length2 = left.length; for (let i = 0; i < length2; i++) { if (!Property.equals(left[i], right[i])) { return false; } } return true; }; Property.isConstant = function(property) { return !defined_default(property) || property.isConstant; }; Property.getValueOrUndefined = function(property, time, result) { return defined_default(property) ? property.getValue(time, result) : void 0; }; Property.getValueOrDefault = function(property, time, valueDefault, result) { return defined_default(property) ? property.getValue(time, result) ?? valueDefault : valueDefault; }; Property.getValueOrClonedDefault = function(property, time, valueDefault, result) { let value; if (defined_default(property)) { value = property.getValue(time, result); } if (!defined_default(value)) { value = valueDefault.clone(value); } return value; }; var Property_default = Property; // packages/engine/Source/Scene/SplitDirection.js var import_InlineWorkers307 = __toESM(require_InlineWorkers(), 1); var SplitDirection = { /** * Display the primitive or ImageryLayer to the left of the {@link Scene#splitPosition}. * * @type {number} * @constant */ LEFT: -1, /** * Always display the primitive or ImageryLayer. * * @type {number} * @constant */ NONE: 0, /** * Display the primitive or ImageryLayer to the right of the {@link Scene#splitPosition}. * * @type {number} * @constant */ RIGHT: 1 }; Object.freeze(SplitDirection); var SplitDirection_default = SplitDirection; // packages/engine/Source/DataSources/BillboardVisualizer.js var defaultColor = Color_default.WHITE; var defaultEyeOffset = Cartesian3_default.ZERO; var defaultHeightReference = HeightReference_default.NONE; var defaultPixelOffset = Cartesian2_default.ZERO; var defaultScale = 1; var defaultRotation = 0; var defaultAlignedAxis = Cartesian3_default.ZERO; var defaultHorizontalOrigin = HorizontalOrigin_default.CENTER; var defaultVerticalOrigin = VerticalOrigin_default.CENTER; var defaultSizeInMeters = false; var defaultSplitDirection = SplitDirection_default.NONE; var positionScratch = new Cartesian3_default(); var colorScratch = new Color_default(); var eyeOffsetScratch = new Cartesian3_default(); var pixelOffsetScratch = new Cartesian2_default(); var scaleByDistanceScratch = new NearFarScalar_default(); var translucencyByDistanceScratch = new NearFarScalar_default(); var pixelOffsetScaleByDistanceScratch = new NearFarScalar_default(); var boundingRectangleScratch = new BoundingRectangle_default(); var distanceDisplayConditionScratch = new DistanceDisplayCondition_default(); function EntityData(entity) { this.entity = entity; this.billboard = void 0; this.textureValue = void 0; } function BillboardVisualizer(entityCluster, entityCollection) { if (!defined_default(entityCluster)) { throw new DeveloperError_default("entityCluster is required."); } if (!defined_default(entityCollection)) { throw new DeveloperError_default("entityCollection is required."); } entityCollection.collectionChanged.addEventListener( BillboardVisualizer.prototype._onCollectionChanged, this ); this._cluster = entityCluster; this._entityCollection = entityCollection; this._items = new AssociativeArray_default(); this._onCollectionChanged(entityCollection, entityCollection.values, [], []); } BillboardVisualizer.prototype.update = function(time) { if (!defined_default(time)) { throw new DeveloperError_default("time is required."); } const items = this._items.values; const cluster = this._cluster; for (let i = 0, len = items.length; i < len; i++) { const item = items[i]; const entity = item.entity; const billboardGraphics = entity._billboard; let textureValue; let billboard = item.billboard; let show = entity.isShowing && entity.isAvailable(time) && Property_default.getValueOrDefault(billboardGraphics._show, time, true); let position; if (show) { position = Property_default.getValueOrUndefined( entity._position, time, positionScratch ); textureValue = Property_default.getValueOrUndefined( billboardGraphics._image, time ); show = defined_default(position) && defined_default(textureValue); } if (!show) { returnPrimitive(item, entity, cluster); continue; } if (!Property_default.isConstant(entity._position)) { cluster._clusterDirty = true; } if (!defined_default(billboard)) { billboard = cluster.getBillboard(entity); billboard.id = entity; item.billboard = billboard; item.textureValue = void 0; } billboard.show = show; billboard.position = position; billboard.color = Property_default.getValueOrDefault( billboardGraphics._color, time, defaultColor, colorScratch ); billboard.eyeOffset = Property_default.getValueOrDefault( billboardGraphics._eyeOffset, time, defaultEyeOffset, eyeOffsetScratch ); billboard.heightReference = Property_default.getValueOrDefault( billboardGraphics._heightReference, time, defaultHeightReference ); billboard.pixelOffset = Property_default.getValueOrDefault( billboardGraphics._pixelOffset, time, defaultPixelOffset, pixelOffsetScratch ); billboard.scale = Property_default.getValueOrDefault( billboardGraphics._scale, time, defaultScale ); billboard.rotation = Property_default.getValueOrDefault( billboardGraphics._rotation, time, defaultRotation ); billboard.alignedAxis = Property_default.getValueOrDefault( billboardGraphics._alignedAxis, time, defaultAlignedAxis ); billboard.horizontalOrigin = Property_default.getValueOrDefault( billboardGraphics._horizontalOrigin, time, defaultHorizontalOrigin ); billboard.verticalOrigin = Property_default.getValueOrDefault( billboardGraphics._verticalOrigin, time, defaultVerticalOrigin ); billboard.width = Property_default.getValueOrUndefined( billboardGraphics._width, time ); billboard.height = Property_default.getValueOrUndefined( billboardGraphics._height, time ); billboard.scaleByDistance = Property_default.getValueOrUndefined( billboardGraphics._scaleByDistance, time, scaleByDistanceScratch ); billboard.translucencyByDistance = Property_default.getValueOrUndefined( billboardGraphics._translucencyByDistance, time, translucencyByDistanceScratch ); billboard.pixelOffsetScaleByDistance = Property_default.getValueOrUndefined( billboardGraphics._pixelOffsetScaleByDistance, time, pixelOffsetScaleByDistanceScratch ); billboard.sizeInMeters = Property_default.getValueOrDefault( billboardGraphics._sizeInMeters, time, defaultSizeInMeters ); billboard.distanceDisplayCondition = Property_default.getValueOrUndefined( billboardGraphics._distanceDisplayCondition, time, distanceDisplayConditionScratch ); billboard.disableDepthTestDistance = Property_default.getValueOrUndefined( billboardGraphics._disableDepthTestDistance, time ); billboard.splitDirection = Property_default.getValueOrDefault( billboardGraphics._splitDirection, time, defaultSplitDirection ); if (item.textureValue !== textureValue) { billboard.image = textureValue; item.textureValue = textureValue; } const subRegion = Property_default.getValueOrUndefined( billboardGraphics._imageSubRegion, time, boundingRectangleScratch ); if (defined_default(subRegion)) { billboard.setImageSubRegion(billboard.image, subRegion); } } return true; }; BillboardVisualizer.prototype.getBoundingSphere = function(entity, result) { if (!defined_default(entity)) { throw new DeveloperError_default("entity is required."); } if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const item = this._items.get(entity.id); if (!defined_default(item) || !defined_default(item.billboard)) { return BoundingSphereState_default.FAILED; } const billboard = item.billboard; if (billboard.heightReference === HeightReference_default.NONE) { result.center = Cartesian3_default.clone(billboard.position, result.center); } else { if (!defined_default(billboard._clampedPosition)) { return BoundingSphereState_default.PENDING; } result.center = Cartesian3_default.clone(billboard._clampedPosition, result.center); } result.radius = 0; return BoundingSphereState_default.DONE; }; BillboardVisualizer.prototype.isDestroyed = function() { return false; }; BillboardVisualizer.prototype.destroy = function() { this._entityCollection.collectionChanged.removeEventListener( BillboardVisualizer.prototype._onCollectionChanged, this ); const entities = this._entityCollection.values; for (let i = 0; i < entities.length; i++) { this._cluster.removeBillboard(entities[i]); } return destroyObject_default(this); }; BillboardVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) { let i; let entity; const items = this._items; const cluster = this._cluster; for (i = added.length - 1; i > -1; i--) { entity = added[i]; if (defined_default(entity._billboard) && defined_default(entity._position)) { items.set(entity.id, new EntityData(entity)); } } for (i = changed.length - 1; i > -1; i--) { entity = changed[i]; if (defined_default(entity._billboard) && defined_default(entity._position)) { if (!items.contains(entity.id)) { items.set(entity.id, new EntityData(entity)); } } else { returnPrimitive(items.get(entity.id), entity, cluster); items.remove(entity.id); } } for (i = removed.length - 1; i > -1; i--) { entity = removed[i]; returnPrimitive(items.get(entity.id), entity, cluster); items.remove(entity.id); } }; function returnPrimitive(item, entity, cluster) { if (defined_default(item)) { item.billboard = void 0; cluster.removeBillboard(entity); } } var BillboardVisualizer_default = BillboardVisualizer; // packages/engine/Source/DataSources/BoxGeometryUpdater.js var import_InlineWorkers431 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/BoxOutlineGeometry.js var import_InlineWorkers309 = __toESM(require_InlineWorkers(), 1); var diffScratch2 = new Cartesian3_default(); function BoxOutlineGeometry(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const min3 = options.minimum; const max3 = options.maximum; Check_default.typeOf.object("min", min3); Check_default.typeOf.object("max", max3); if (defined_default(options.offsetAttribute) && options.offsetAttribute === GeometryOffsetAttribute_default.TOP) { throw new DeveloperError_default( "GeometryOffsetAttribute.TOP is not a supported options.offsetAttribute for this geometry." ); } this._min = Cartesian3_default.clone(min3); this._max = Cartesian3_default.clone(max3); this._offsetAttribute = options.offsetAttribute; this._workerName = "createBoxOutlineGeometry"; } BoxOutlineGeometry.fromDimensions = function(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const dimensions = options.dimensions; Check_default.typeOf.object("dimensions", dimensions); Check_default.typeOf.number.greaterThanOrEquals("dimensions.x", dimensions.x, 0); Check_default.typeOf.number.greaterThanOrEquals("dimensions.y", dimensions.y, 0); Check_default.typeOf.number.greaterThanOrEquals("dimensions.z", dimensions.z, 0); const corner = Cartesian3_default.multiplyByScalar(dimensions, 0.5, new Cartesian3_default()); return new BoxOutlineGeometry({ minimum: Cartesian3_default.negate(corner, new Cartesian3_default()), maximum: corner, offsetAttribute: options.offsetAttribute }); }; BoxOutlineGeometry.fromAxisAlignedBoundingBox = function(boundingBox) { Check_default.typeOf.object("boundindBox", boundingBox); return new BoxOutlineGeometry({ minimum: boundingBox.minimum, maximum: boundingBox.maximum }); }; BoxOutlineGeometry.packedLength = 2 * Cartesian3_default.packedLength + 1; BoxOutlineGeometry.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; Cartesian3_default.pack(value._min, array, startingIndex); Cartesian3_default.pack(value._max, array, startingIndex + Cartesian3_default.packedLength); array[startingIndex + Cartesian3_default.packedLength * 2] = value._offsetAttribute ?? -1; return array; }; var scratchMin2 = new Cartesian3_default(); var scratchMax2 = new Cartesian3_default(); var scratchOptions2 = { minimum: scratchMin2, maximum: scratchMax2, offsetAttribute: void 0 }; BoxOutlineGeometry.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; const min3 = Cartesian3_default.unpack(array, startingIndex, scratchMin2); const max3 = Cartesian3_default.unpack( array, startingIndex + Cartesian3_default.packedLength, scratchMax2 ); const offsetAttribute = array[startingIndex + Cartesian3_default.packedLength * 2]; if (!defined_default(result)) { scratchOptions2.offsetAttribute = offsetAttribute === -1 ? void 0 : offsetAttribute; return new BoxOutlineGeometry(scratchOptions2); } result._min = Cartesian3_default.clone(min3, result._min); result._max = Cartesian3_default.clone(max3, result._max); result._offsetAttribute = offsetAttribute === -1 ? void 0 : offsetAttribute; return result; }; BoxOutlineGeometry.createGeometry = function(boxGeometry) { const min3 = boxGeometry._min; const max3 = boxGeometry._max; if (Cartesian3_default.equals(min3, max3)) { return; } const attributes = new GeometryAttributes_default(); const indices = new Uint16Array(12 * 2); const positions = new Float64Array(8 * 3); positions[0] = min3.x; positions[1] = min3.y; positions[2] = min3.z; positions[3] = max3.x; positions[4] = min3.y; positions[5] = min3.z; positions[6] = max3.x; positions[7] = max3.y; positions[8] = min3.z; positions[9] = min3.x; positions[10] = max3.y; positions[11] = min3.z; positions[12] = min3.x; positions[13] = min3.y; positions[14] = max3.z; positions[15] = max3.x; positions[16] = min3.y; positions[17] = max3.z; positions[18] = max3.x; positions[19] = max3.y; positions[20] = max3.z; positions[21] = min3.x; positions[22] = max3.y; positions[23] = max3.z; attributes.position = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, values: positions }); indices[0] = 4; indices[1] = 5; indices[2] = 5; indices[3] = 6; indices[4] = 6; indices[5] = 7; indices[6] = 7; indices[7] = 4; indices[8] = 0; indices[9] = 1; indices[10] = 1; indices[11] = 2; indices[12] = 2; indices[13] = 3; indices[14] = 3; indices[15] = 0; indices[16] = 0; indices[17] = 4; indices[18] = 1; indices[19] = 5; indices[20] = 2; indices[21] = 6; indices[22] = 3; indices[23] = 7; const diff = Cartesian3_default.subtract(max3, min3, diffScratch2); const radius = Cartesian3_default.magnitude(diff) * 0.5; if (defined_default(boxGeometry._offsetAttribute)) { const length2 = positions.length; const offsetValue = boxGeometry._offsetAttribute === GeometryOffsetAttribute_default.NONE ? 0 : 1; const applyOffset = new Uint8Array(length2 / 3).fill(offsetValue); attributes.applyOffset = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.UNSIGNED_BYTE, componentsPerAttribute: 1, values: applyOffset }); } return new Geometry_default({ attributes, indices, primitiveType: PrimitiveType_default.LINES, boundingSphere: new BoundingSphere_default(Cartesian3_default.ZERO, radius), offsetAttribute: boxGeometry._offsetAttribute }); }; var BoxOutlineGeometry_default = BoxOutlineGeometry; // packages/engine/Source/Core/ColorGeometryInstanceAttribute.js var import_InlineWorkers310 = __toESM(require_InlineWorkers(), 1); function ColorGeometryInstanceAttribute(red, green, blue, alpha) { red = red ?? 1; green = green ?? 1; blue = blue ?? 1; alpha = alpha ?? 1; this.value = new Uint8Array([ Color_default.floatToByte(red), Color_default.floatToByte(green), Color_default.floatToByte(blue), Color_default.floatToByte(alpha) ]); } Object.defineProperties(ColorGeometryInstanceAttribute.prototype, { /** * The datatype of each component in the attribute, e.g., individual elements in * {@link ColorGeometryInstanceAttribute#value}. * * @memberof ColorGeometryInstanceAttribute.prototype * * @type {ComponentDatatype} * @readonly * * @default {@link ComponentDatatype.UNSIGNED_BYTE} */ componentDatatype: { get: function() { return ComponentDatatype_default.UNSIGNED_BYTE; } }, /** * The number of components in the attributes, i.e., {@link ColorGeometryInstanceAttribute#value}. * * @memberof ColorGeometryInstanceAttribute.prototype * * @type {number} * @readonly * * @default 4 */ componentsPerAttribute: { get: function() { return 4; } }, /** * When true and componentDatatype is an integer format, * indicate that the components should be mapped to the range [0, 1] (unsigned) * or [-1, 1] (signed) when they are accessed as floating-point for rendering. * * @memberof ColorGeometryInstanceAttribute.prototype * * @type {boolean} * @readonly * * @default true */ normalize: { get: function() { return true; } } }); ColorGeometryInstanceAttribute.fromColor = function(color) { if (!defined_default(color)) { throw new DeveloperError_default("color is required."); } return new ColorGeometryInstanceAttribute( color.red, color.green, color.blue, color.alpha ); }; ColorGeometryInstanceAttribute.toValue = function(color, result) { if (!defined_default(color)) { throw new DeveloperError_default("color is required."); } if (!defined_default(result)) { return new Uint8Array(color.toBytes()); } return color.toBytes(result); }; ColorGeometryInstanceAttribute.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && left.value[0] === right.value[0] && left.value[1] === right.value[1] && left.value[2] === right.value[2] && left.value[3] === right.value[3]; }; var ColorGeometryInstanceAttribute_default = ColorGeometryInstanceAttribute; // packages/engine/Source/Core/DistanceDisplayConditionGeometryInstanceAttribute.js var import_InlineWorkers311 = __toESM(require_InlineWorkers(), 1); function DistanceDisplayConditionGeometryInstanceAttribute(near, far) { near = near ?? 0; far = far ?? Number.MAX_VALUE; if (far <= near) { throw new DeveloperError_default( "far distance must be greater than near distance." ); } this.value = new Float32Array([near, far]); } Object.defineProperties( DistanceDisplayConditionGeometryInstanceAttribute.prototype, { /** * The datatype of each component in the attribute, e.g., individual elements in * {@link DistanceDisplayConditionGeometryInstanceAttribute#value}. * * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype * * @type {ComponentDatatype} * @readonly * * @default {@link ComponentDatatype.FLOAT} */ componentDatatype: { get: function() { return ComponentDatatype_default.FLOAT; } }, /** * The number of components in the attributes, i.e., {@link DistanceDisplayConditionGeometryInstanceAttribute#value}. * * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype * * @type {number} * @readonly * * @default 3 */ componentsPerAttribute: { get: function() { return 2; } }, /** * When true and componentDatatype is an integer format, * indicate that the components should be mapped to the range [0, 1] (unsigned) * or [-1, 1] (signed) when they are accessed as floating-point for rendering. * * @memberof DistanceDisplayConditionGeometryInstanceAttribute.prototype * * @type {boolean} * @readonly * * @default false */ normalize: { get: function() { return false; } } } ); DistanceDisplayConditionGeometryInstanceAttribute.fromDistanceDisplayCondition = function(distanceDisplayCondition) { if (!defined_default(distanceDisplayCondition)) { throw new DeveloperError_default("distanceDisplayCondition is required."); } if (distanceDisplayCondition.far <= distanceDisplayCondition.near) { throw new DeveloperError_default( "distanceDisplayCondition.far distance must be greater than distanceDisplayCondition.near distance." ); } return new DistanceDisplayConditionGeometryInstanceAttribute( distanceDisplayCondition.near, distanceDisplayCondition.far ); }; DistanceDisplayConditionGeometryInstanceAttribute.toValue = function(distanceDisplayCondition, result) { if (!defined_default(distanceDisplayCondition)) { throw new DeveloperError_default("distanceDisplayCondition is required."); } if (!defined_default(result)) { return new Float32Array([ distanceDisplayCondition.near, distanceDisplayCondition.far ]); } result[0] = distanceDisplayCondition.near; result[1] = distanceDisplayCondition.far; return result; }; var DistanceDisplayConditionGeometryInstanceAttribute_default = DistanceDisplayConditionGeometryInstanceAttribute; // packages/engine/Source/Core/GeometryInstance.js var import_InlineWorkers312 = __toESM(require_InlineWorkers(), 1); function GeometryInstance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; if (!defined_default(options.geometry)) { throw new DeveloperError_default("options.geometry is required."); } this.geometry = options.geometry; this.modelMatrix = Matrix4_default.clone(options.modelMatrix ?? Matrix4_default.IDENTITY); this.id = options.id; this.pickPrimitive = options.pickPrimitive; this.attributes = options.attributes ?? {}; this.westHemisphereGeometry = void 0; this.eastHemisphereGeometry = void 0; } var GeometryInstance_default = GeometryInstance; // packages/engine/Source/Core/Iso8601.js var import_InlineWorkers314 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/TimeInterval.js var import_InlineWorkers313 = __toESM(require_InlineWorkers(), 1); function TimeInterval(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.start = defined_default(options.start) ? JulianDate_default.clone(options.start) : new JulianDate_default(); this.stop = defined_default(options.stop) ? JulianDate_default.clone(options.stop) : new JulianDate_default(); this.data = options.data; this.isStartIncluded = options.isStartIncluded ?? true; this.isStopIncluded = options.isStopIncluded ?? true; } Object.defineProperties(TimeInterval.prototype, { /** * Gets whether or not this interval is empty. * @memberof TimeInterval.prototype * @type {boolean} * @readonly */ isEmpty: { get: function() { const stopComparedToStart = JulianDate_default.compare(this.stop, this.start); return stopComparedToStart < 0 || stopComparedToStart === 0 && (!this.isStartIncluded || !this.isStopIncluded); } } }); var scratchInterval = { start: void 0, stop: void 0, isStartIncluded: void 0, isStopIncluded: void 0, data: void 0 }; TimeInterval.fromIso8601 = function(options, result) { Check_default.typeOf.object("options", options); Check_default.typeOf.string("options.iso8601", options.iso8601); const dates = options.iso8601.split("/"); if (dates.length !== 2) { throw new DeveloperError_default( "options.iso8601 is an invalid ISO 8601 interval." ); } const start = JulianDate_default.fromIso8601(dates[0]); const stop2 = JulianDate_default.fromIso8601(dates[1]); const isStartIncluded = options.isStartIncluded ?? true; const isStopIncluded = options.isStopIncluded ?? true; const data = options.data; if (!defined_default(result)) { scratchInterval.start = start; scratchInterval.stop = stop2; scratchInterval.isStartIncluded = isStartIncluded; scratchInterval.isStopIncluded = isStopIncluded; scratchInterval.data = data; return new TimeInterval(scratchInterval); } result.start = start; result.stop = stop2; result.isStartIncluded = isStartIncluded; result.isStopIncluded = isStopIncluded; result.data = data; return result; }; TimeInterval.toIso8601 = function(timeInterval, precision) { Check_default.typeOf.object("timeInterval", timeInterval); return `${JulianDate_default.toIso8601( timeInterval.start, precision )}/${JulianDate_default.toIso8601(timeInterval.stop, precision)}`; }; TimeInterval.clone = function(timeInterval, result) { if (!defined_default(timeInterval)) { return void 0; } if (!defined_default(result)) { return new TimeInterval(timeInterval); } result.start = timeInterval.start; result.stop = timeInterval.stop; result.isStartIncluded = timeInterval.isStartIncluded; result.isStopIncluded = timeInterval.isStopIncluded; result.data = timeInterval.data; return result; }; TimeInterval.equals = function(left, right, dataComparer) { return left === right || defined_default(left) && defined_default(right) && (left.isEmpty && right.isEmpty || left.isStartIncluded === right.isStartIncluded && left.isStopIncluded === right.isStopIncluded && JulianDate_default.equals(left.start, right.start) && JulianDate_default.equals(left.stop, right.stop) && (left.data === right.data || defined_default(dataComparer) && dataComparer(left.data, right.data))); }; TimeInterval.equalsEpsilon = function(left, right, epsilon, dataComparer) { epsilon = epsilon ?? 0; return left === right || defined_default(left) && defined_default(right) && (left.isEmpty && right.isEmpty || left.isStartIncluded === right.isStartIncluded && left.isStopIncluded === right.isStopIncluded && JulianDate_default.equalsEpsilon(left.start, right.start, epsilon) && JulianDate_default.equalsEpsilon(left.stop, right.stop, epsilon) && (left.data === right.data || defined_default(dataComparer) && dataComparer(left.data, right.data))); }; TimeInterval.intersect = function(left, right, result, mergeCallback) { Check_default.typeOf.object("left", left); if (!defined_default(right)) { return TimeInterval.clone(TimeInterval.EMPTY, result); } const leftStart = left.start; const leftStop = left.stop; const rightStart = right.start; const rightStop = right.stop; const intersectsStartRight = JulianDate_default.greaterThanOrEquals(rightStart, leftStart) && JulianDate_default.greaterThanOrEquals(leftStop, rightStart); const intersectsStartLeft = !intersectsStartRight && JulianDate_default.lessThanOrEquals(rightStart, leftStart) && JulianDate_default.lessThanOrEquals(leftStart, rightStop); if (!intersectsStartRight && !intersectsStartLeft) { return TimeInterval.clone(TimeInterval.EMPTY, result); } const leftIsStartIncluded = left.isStartIncluded; const leftIsStopIncluded = left.isStopIncluded; const rightIsStartIncluded = right.isStartIncluded; const rightIsStopIncluded = right.isStopIncluded; const leftLessThanRight = JulianDate_default.lessThan(leftStop, rightStop); if (!defined_default(result)) { result = new TimeInterval(); } result.start = intersectsStartRight ? rightStart : leftStart; result.isStartIncluded = leftIsStartIncluded && rightIsStartIncluded || !JulianDate_default.equals(rightStart, leftStart) && (intersectsStartRight && rightIsStartIncluded || intersectsStartLeft && leftIsStartIncluded); result.stop = leftLessThanRight ? leftStop : rightStop; result.isStopIncluded = leftLessThanRight ? leftIsStopIncluded : leftIsStopIncluded && rightIsStopIncluded || !JulianDate_default.equals(rightStop, leftStop) && rightIsStopIncluded; result.data = defined_default(mergeCallback) ? mergeCallback(left.data, right.data) : left.data; return result; }; TimeInterval.contains = function(timeInterval, julianDate) { Check_default.typeOf.object("timeInterval", timeInterval); Check_default.typeOf.object("julianDate", julianDate); if (timeInterval.isEmpty) { return false; } const startComparedToDate = JulianDate_default.compare( timeInterval.start, julianDate ); if (startComparedToDate === 0) { return timeInterval.isStartIncluded; } const dateComparedToStop = JulianDate_default.compare(julianDate, timeInterval.stop); if (dateComparedToStop === 0) { return timeInterval.isStopIncluded; } return startComparedToDate < 0 && dateComparedToStop < 0; }; TimeInterval.prototype.clone = function(result) { return TimeInterval.clone(this, result); }; TimeInterval.prototype.equals = function(right, dataComparer) { return TimeInterval.equals(this, right, dataComparer); }; TimeInterval.prototype.equalsEpsilon = function(right, epsilon, dataComparer) { return TimeInterval.equalsEpsilon(this, right, epsilon, dataComparer); }; TimeInterval.prototype.toString = function() { return TimeInterval.toIso8601(this); }; TimeInterval.EMPTY = Object.freeze( new TimeInterval({ start: new JulianDate_default(), stop: new JulianDate_default(), isStartIncluded: false, isStopIncluded: false }) ); var TimeInterval_default = TimeInterval; // packages/engine/Source/Core/Iso8601.js var MINIMUM_VALUE = Object.freeze( JulianDate_default.fromIso8601("0000-01-01T00:00:00Z") ); var MAXIMUM_VALUE = Object.freeze( JulianDate_default.fromIso8601("9999-12-31T24:00:00Z") ); var MAXIMUM_INTERVAL = Object.freeze( new TimeInterval_default({ start: MINIMUM_VALUE, stop: MAXIMUM_VALUE }) ); var Iso8601 = { /** * A {@link JulianDate} representing the earliest time representable by an ISO8601 date. * This is equivalent to the date string '0000-01-01T00:00:00Z' * * @type {JulianDate} * @constant */ MINIMUM_VALUE, /** * A {@link JulianDate} representing the latest time representable by an ISO8601 date. * This is equivalent to the date string '9999-12-31T24:00:00Z' * * @type {JulianDate} * @constant */ MAXIMUM_VALUE, /** * A {@link TimeInterval} representing the largest interval representable by an ISO8601 interval. * This is equivalent to the interval string '0000-01-01T00:00:00Z/9999-12-31T24:00:00Z' * * @type {TimeInterval} * @constant */ MAXIMUM_INTERVAL }; var Iso8601_default = Iso8601; // packages/engine/Source/Core/OffsetGeometryInstanceAttribute.js var import_InlineWorkers315 = __toESM(require_InlineWorkers(), 1); function OffsetGeometryInstanceAttribute(x, y, z2) { x = x ?? 0; y = y ?? 0; z2 = z2 ?? 0; this.value = new Float32Array([x, y, z2]); } Object.defineProperties(OffsetGeometryInstanceAttribute.prototype, { /** * The datatype of each component in the attribute, e.g., individual elements in * {@link OffsetGeometryInstanceAttribute#value}. * * @memberof OffsetGeometryInstanceAttribute.prototype * * @type {ComponentDatatype} * @readonly * * @default {@link ComponentDatatype.FLOAT} */ componentDatatype: { get: function() { return ComponentDatatype_default.FLOAT; } }, /** * The number of components in the attributes, i.e., {@link OffsetGeometryInstanceAttribute#value}. * * @memberof OffsetGeometryInstanceAttribute.prototype * * @type {number} * @readonly * * @default 3 */ componentsPerAttribute: { get: function() { return 3; } }, /** * When true and componentDatatype is an integer format, * indicate that the components should be mapped to the range [0, 1] (unsigned) * or [-1, 1] (signed) when they are accessed as floating-point for rendering. * * @memberof OffsetGeometryInstanceAttribute.prototype * * @type {boolean} * @readonly * * @default false */ normalize: { get: function() { return false; } } }); OffsetGeometryInstanceAttribute.fromCartesian3 = function(offset) { Check_default.defined("offset", offset); return new OffsetGeometryInstanceAttribute(offset.x, offset.y, offset.z); }; OffsetGeometryInstanceAttribute.toValue = function(offset, result) { Check_default.defined("offset", offset); if (!defined_default(result)) { result = new Float32Array([offset.x, offset.y, offset.z]); } result[0] = offset.x; result[1] = offset.y; result[2] = offset.z; return result; }; var OffsetGeometryInstanceAttribute_default = OffsetGeometryInstanceAttribute; // packages/engine/Source/Core/ShowGeometryInstanceAttribute.js var import_InlineWorkers316 = __toESM(require_InlineWorkers(), 1); function ShowGeometryInstanceAttribute(show) { show = show ?? true; this.value = ShowGeometryInstanceAttribute.toValue(show); } Object.defineProperties(ShowGeometryInstanceAttribute.prototype, { /** * The datatype of each component in the attribute, e.g., individual elements in * {@link ColorGeometryInstanceAttribute#value}. * * @memberof ShowGeometryInstanceAttribute.prototype * * @type {ComponentDatatype} * @readonly * * @default {@link ComponentDatatype.UNSIGNED_BYTE} */ componentDatatype: { get: function() { return ComponentDatatype_default.UNSIGNED_BYTE; } }, /** * The number of components in the attributes, i.e., {@link ColorGeometryInstanceAttribute#value}. * * @memberof ShowGeometryInstanceAttribute.prototype * * @type {number} * @readonly * * @default 1 */ componentsPerAttribute: { get: function() { return 1; } }, /** * When true and componentDatatype is an integer format, * indicate that the components should be mapped to the range [0, 1] (unsigned) * or [-1, 1] (signed) when they are accessed as floating-point for rendering. * * @memberof ShowGeometryInstanceAttribute.prototype * * @type {boolean} * @readonly * * @default true */ normalize: { get: function() { return false; } } }); ShowGeometryInstanceAttribute.toValue = function(show, result) { if (!defined_default(show)) { throw new DeveloperError_default("show is required."); } if (!defined_default(result)) { return new Uint8Array([show]); } result[0] = show; return result; }; var ShowGeometryInstanceAttribute_default = ShowGeometryInstanceAttribute; // packages/engine/Source/Scene/MaterialAppearance.js var import_InlineWorkers348 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Appearances/AllMaterialAppearanceFS.js var import_InlineWorkers317 = __toESM(require_InlineWorkers(), 1); var AllMaterialAppearanceFS_default = "in vec3 v_positionEC;\nin vec3 v_normalEC;\nin vec3 v_tangentEC;\nin vec3 v_bitangentEC;\nin vec2 v_st;\n\nvoid main()\n{\n vec3 positionToEyeEC = -v_positionEC;\n mat3 tangentToEyeMatrix = czm_tangentToEyeSpaceMatrix(v_normalEC, v_tangentEC, v_bitangentEC);\n\n vec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\n normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\n\n czm_materialInput materialInput;\n materialInput.normalEC = normalEC;\n materialInput.tangentToEyeMatrix = tangentToEyeMatrix;\n materialInput.positionToEyeEC = positionToEyeEC;\n materialInput.st = v_st;\n czm_material material = czm_getMaterial(materialInput);\n\n#ifdef FLAT\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\n out_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n#endif\n}\n"; // packages/engine/Source/Shaders/Appearances/AllMaterialAppearanceVS.js var import_InlineWorkers318 = __toESM(require_InlineWorkers(), 1); var AllMaterialAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 normal;\nin vec3 tangent;\nin vec3 bitangent;\nin vec2 st;\nin float batchId;\n\nout vec3 v_positionEC;\nout vec3 v_normalEC;\nout vec3 v_tangentEC;\nout vec3 v_bitangentEC;\nout vec2 v_st;\n\nvoid main()\n{\n vec4 p = czm_computePosition();\n\n v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates\n v_normalEC = czm_normal * normal; // normal in eye coordinates\n v_tangentEC = czm_normal * tangent; // tangent in eye coordinates\n v_bitangentEC = czm_normal * bitangent; // bitangent in eye coordinates\n v_st = st;\n\n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"; // packages/engine/Source/Shaders/Appearances/BasicMaterialAppearanceFS.js var import_InlineWorkers319 = __toESM(require_InlineWorkers(), 1); var BasicMaterialAppearanceFS_default = "in vec3 v_positionEC;\nin vec3 v_normalEC;\n\nvoid main()\n{\n vec3 positionToEyeEC = -v_positionEC;\n\n vec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\n normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\n\n czm_materialInput materialInput;\n materialInput.normalEC = normalEC;\n materialInput.positionToEyeEC = positionToEyeEC;\n czm_material material = czm_getMaterial(materialInput);\n\n#ifdef FLAT\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\n out_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n#endif\n}\n"; // packages/engine/Source/Shaders/Appearances/BasicMaterialAppearanceVS.js var import_InlineWorkers320 = __toESM(require_InlineWorkers(), 1); var BasicMaterialAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 normal;\nin float batchId;\n\nout vec3 v_positionEC;\nout vec3 v_normalEC;\n\nvoid main()\n{\n vec4 p = czm_computePosition();\n\n v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates\n v_normalEC = czm_normal * normal; // normal in eye coordinates\n\n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"; // packages/engine/Source/Shaders/Appearances/TexturedMaterialAppearanceFS.js var import_InlineWorkers321 = __toESM(require_InlineWorkers(), 1); var TexturedMaterialAppearanceFS_default = "in vec3 v_positionEC;\nin vec3 v_normalEC;\nin vec2 v_st;\n\nvoid main()\n{\n vec3 positionToEyeEC = -v_positionEC;\n\n vec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\n normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\n\n czm_materialInput materialInput;\n materialInput.normalEC = normalEC;\n materialInput.positionToEyeEC = positionToEyeEC;\n materialInput.st = v_st;\n czm_material material = czm_getMaterial(materialInput);\n\n#ifdef FLAT\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else\n out_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n#endif\n}\n"; // packages/engine/Source/Shaders/Appearances/TexturedMaterialAppearanceVS.js var import_InlineWorkers322 = __toESM(require_InlineWorkers(), 1); var TexturedMaterialAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 normal;\nin vec2 st;\nin float batchId;\n\nout vec3 v_positionEC;\nout vec3 v_normalEC;\nout vec2 v_st;\n\nvoid main()\n{\n vec4 p = czm_computePosition();\n\n v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates\n v_normalEC = czm_normal * normal; // normal in eye coordinates\n v_st = st;\n\n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"; // packages/engine/Source/Scene/Appearance.js var import_InlineWorkers327 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/BlendingState.js var import_InlineWorkers325 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/BlendEquation.js var import_InlineWorkers323 = __toESM(require_InlineWorkers(), 1); var BlendEquation = { /** * Pixel values are added componentwise. This is used in additive blending for translucency. * * @type {number} * @constant */ ADD: WebGLConstants_default.FUNC_ADD, /** * Pixel values are subtracted componentwise (source - destination). This is used in alpha blending for translucency. * * @type {number} * @constant */ SUBTRACT: WebGLConstants_default.FUNC_SUBTRACT, /** * Pixel values are subtracted componentwise (destination - source). * * @type {number} * @constant */ REVERSE_SUBTRACT: WebGLConstants_default.FUNC_REVERSE_SUBTRACT, /** * Pixel values are given to the minimum function (min(source, destination)). * * This equation operates on each pixel color component. * * @type {number} * @constant */ MIN: WebGLConstants_default.MIN, /** * Pixel values are given to the maximum function (max(source, destination)). * * This equation operates on each pixel color component. * * @type {number} * @constant */ MAX: WebGLConstants_default.MAX }; Object.freeze(BlendEquation); var BlendEquation_default = BlendEquation; // packages/engine/Source/Scene/BlendFunction.js var import_InlineWorkers324 = __toESM(require_InlineWorkers(), 1); var BlendFunction = { /** * The blend factor is zero. * * @type {number} * @constant */ ZERO: WebGLConstants_default.ZERO, /** * The blend factor is one. * * @type {number} * @constant */ ONE: WebGLConstants_default.ONE, /** * The blend factor is the source color. * * @type {number} * @constant */ SOURCE_COLOR: WebGLConstants_default.SRC_COLOR, /** * The blend factor is one minus the source color. * * @type {number} * @constant */ ONE_MINUS_SOURCE_COLOR: WebGLConstants_default.ONE_MINUS_SRC_COLOR, /** * The blend factor is the destination color. * * @type {number} * @constant */ DESTINATION_COLOR: WebGLConstants_default.DST_COLOR, /** * The blend factor is one minus the destination color. * * @type {number} * @constant */ ONE_MINUS_DESTINATION_COLOR: WebGLConstants_default.ONE_MINUS_DST_COLOR, /** * The blend factor is the source alpha. * * @type {number} * @constant */ SOURCE_ALPHA: WebGLConstants_default.SRC_ALPHA, /** * The blend factor is one minus the source alpha. * * @type {number} * @constant */ ONE_MINUS_SOURCE_ALPHA: WebGLConstants_default.ONE_MINUS_SRC_ALPHA, /** * The blend factor is the destination alpha. * * @type {number} * @constant */ DESTINATION_ALPHA: WebGLConstants_default.DST_ALPHA, /** * The blend factor is one minus the destination alpha. * * @type {number} * @constant */ ONE_MINUS_DESTINATION_ALPHA: WebGLConstants_default.ONE_MINUS_DST_ALPHA, /** * The blend factor is the constant color. * * @type {number} * @constant */ CONSTANT_COLOR: WebGLConstants_default.CONSTANT_COLOR, /** * The blend factor is one minus the constant color. * * @type {number} * @constant */ ONE_MINUS_CONSTANT_COLOR: WebGLConstants_default.ONE_MINUS_CONSTANT_COLOR, /** * The blend factor is the constant alpha. * * @type {number} * @constant */ CONSTANT_ALPHA: WebGLConstants_default.CONSTANT_ALPHA, /** * The blend factor is one minus the constant alpha. * * @type {number} * @constant */ ONE_MINUS_CONSTANT_ALPHA: WebGLConstants_default.ONE_MINUS_CONSTANT_ALPHA, /** * The blend factor is the saturated source alpha. * * @type {number} * @constant */ SOURCE_ALPHA_SATURATE: WebGLConstants_default.SRC_ALPHA_SATURATE }; Object.freeze(BlendFunction); var BlendFunction_default = BlendFunction; // packages/engine/Source/Scene/BlendingState.js var BlendingState = { /** * Blending is disabled. * * @type {object} * @constant */ DISABLED: Object.freeze({ enabled: false }), /** * Blending is enabled using alpha blending, source(source.alpha) + destination(1 - source.alpha). * * @type {object} * @constant */ ALPHA_BLEND: Object.freeze({ enabled: true, equationRgb: BlendEquation_default.ADD, equationAlpha: BlendEquation_default.ADD, functionSourceRgb: BlendFunction_default.SOURCE_ALPHA, functionSourceAlpha: BlendFunction_default.ONE, functionDestinationRgb: BlendFunction_default.ONE_MINUS_SOURCE_ALPHA, functionDestinationAlpha: BlendFunction_default.ONE_MINUS_SOURCE_ALPHA }), /** * Blending is enabled using alpha blending with premultiplied alpha, source + destination(1 - source.alpha). * * @type {object} * @constant */ PRE_MULTIPLIED_ALPHA_BLEND: Object.freeze({ enabled: true, equationRgb: BlendEquation_default.ADD, equationAlpha: BlendEquation_default.ADD, functionSourceRgb: BlendFunction_default.ONE, functionSourceAlpha: BlendFunction_default.ONE, functionDestinationRgb: BlendFunction_default.ONE_MINUS_SOURCE_ALPHA, functionDestinationAlpha: BlendFunction_default.ONE_MINUS_SOURCE_ALPHA }), /** * Blending is enabled using additive blending, source(source.alpha) + destination. * * @type {object} * @constant */ ADDITIVE_BLEND: Object.freeze({ enabled: true, equationRgb: BlendEquation_default.ADD, equationAlpha: BlendEquation_default.ADD, functionSourceRgb: BlendFunction_default.SOURCE_ALPHA, functionSourceAlpha: BlendFunction_default.ONE, functionDestinationRgb: BlendFunction_default.ONE, functionDestinationAlpha: BlendFunction_default.ONE }) }; Object.freeze(BlendingState); var BlendingState_default = BlendingState; // packages/engine/Source/Scene/CullFace.js var import_InlineWorkers326 = __toESM(require_InlineWorkers(), 1); var CullFace = { /** * Front-facing triangles are culled. * * @type {number} * @constant */ FRONT: WebGLConstants_default.FRONT, /** * Back-facing triangles are culled. * * @type {number} * @constant */ BACK: WebGLConstants_default.BACK, /** * Both front-facing and back-facing triangles are culled. * * @type {number} * @constant */ FRONT_AND_BACK: WebGLConstants_default.FRONT_AND_BACK }; Object.freeze(CullFace); var CullFace_default = CullFace; // packages/engine/Source/Scene/Appearance.js function Appearance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.material = options.material; this.translucent = options.translucent ?? true; this._vertexShaderSource = options.vertexShaderSource; this._fragmentShaderSource = options.fragmentShaderSource; this._renderState = options.renderState; this._closed = options.closed ?? false; } Object.defineProperties(Appearance.prototype, { /** * The GLSL source code for the vertex shader. * * @memberof Appearance.prototype * * @type {string} * @readonly */ vertexShaderSource: { get: function() { return this._vertexShaderSource; } }, /** * The GLSL source code for the fragment shader. The full fragment shader * source is built procedurally taking into account the {@link Appearance#material}. * Use {@link Appearance#getFragmentShaderSource} to get the full source. * * @memberof Appearance.prototype * * @type {string} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, /** * The WebGL fixed-function state to use when rendering the geometry. * * @memberof Appearance.prototype * * @type {object} * @readonly */ renderState: { get: function() { return this._renderState; } }, /** * When true, the geometry is expected to be closed. * * @memberof Appearance.prototype * * @type {boolean} * @readonly * * @default false */ closed: { get: function() { return this._closed; } } }); Appearance.prototype.getFragmentShaderSource = function() { const parts = []; if (this.flat) { parts.push("#define FLAT"); } if (this.faceForward) { parts.push("#define FACE_FORWARD"); } if (defined_default(this.material)) { parts.push(this.material.shaderSource); } parts.push(this.fragmentShaderSource); return parts.join("\n"); }; Appearance.prototype.isTranslucent = function() { return defined_default(this.material) && this.material.isTranslucent() || !defined_default(this.material) && this.translucent; }; Appearance.prototype.getRenderState = function() { const translucent = this.isTranslucent(); const rs = clone_default(this.renderState, false); if (translucent) { rs.depthMask = false; rs.blending = BlendingState_default.ALPHA_BLEND; } else { rs.depthMask = true; } return rs; }; Appearance.getDefaultRenderState = function(translucent, closed, existing) { let rs = { depthTest: { enabled: true } }; if (translucent) { rs.depthMask = false; rs.blending = BlendingState_default.ALPHA_BLEND; } if (closed) { rs.cull = { enabled: true, face: CullFace_default.BACK }; } if (defined_default(existing)) { rs = combine_default(existing, rs, true); } return rs; }; var Appearance_default = Appearance; // packages/engine/Source/Scene/Material.js var import_InlineWorkers347 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Materials/AspectRampMaterial.js var import_InlineWorkers328 = __toESM(require_InlineWorkers(), 1); var AspectRampMaterial_default = "uniform sampler2D image;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n vec4 rampColor = texture(image, vec2(materialInput.aspect / (2.0 * czm_pi), 0.5));\n rampColor = czm_gammaCorrect(rampColor);\n material.diffuse = rampColor.rgb;\n material.alpha = rampColor.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/BumpMapMaterial.js var import_InlineWorkers329 = __toESM(require_InlineWorkers(), 1); var BumpMapMaterial_default = "uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n\n vec2 centerPixel = fract(repeat * st);\n float centerBump = texture(image, centerPixel).channel;\n\n float imageWidth = float(imageDimensions.x);\n vec2 rightPixel = fract(repeat * (st + vec2(1.0 / imageWidth, 0.0)));\n float rightBump = texture(image, rightPixel).channel;\n\n float imageHeight = float(imageDimensions.y);\n vec2 leftPixel = fract(repeat * (st + vec2(0.0, 1.0 / imageHeight)));\n float topBump = texture(image, leftPixel).channel;\n\n vec3 normalTangentSpace = normalize(vec3(centerBump - rightBump, centerBump - topBump, clamp(1.0 - strength, 0.1, 1.0)));\n vec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\n\n material.normal = normalEC;\n material.diffuse = vec3(0.01);\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/CheckerboardMaterial.js var import_InlineWorkers330 = __toESM(require_InlineWorkers(), 1); var CheckerboardMaterial_default = "uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n\n // From Stefan Gustavson's Procedural Textures in GLSL in OpenGL Insights\n float b = mod(floor(repeat.s * st.s) + floor(repeat.t * st.t), 2.0); // 0.0 or 1.0\n\n // Find the distance from the closest separator (region between two colors)\n float scaledWidth = fract(repeat.s * st.s);\n scaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\n float scaledHeight = fract(repeat.t * st.t);\n scaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\n float value = min(scaledWidth, scaledHeight);\n\n vec4 currentColor = mix(lightColor, darkColor, b);\n vec4 color = czm_antialias(lightColor, darkColor, currentColor, value, 0.03);\n\n color = czm_gammaCorrect(color);\n material.diffuse = color.rgb;\n material.alpha = color.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/DotMaterial.js var import_InlineWorkers331 = __toESM(require_InlineWorkers(), 1); var DotMaterial_default = "uniform vec4 lightColor;\nuniform vec4 darkColor;\nuniform vec2 repeat;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n // From Stefan Gustavson's Procedural Textures in GLSL in OpenGL Insights\n float b = smoothstep(0.3, 0.32, length(fract(repeat * materialInput.st) - 0.5)); // 0.0 or 1.0\n\n vec4 color = mix(lightColor, darkColor, b);\n color = czm_gammaCorrect(color);\n material.diffuse = color.rgb;\n material.alpha = color.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/ElevationBandMaterial.js var import_InlineWorkers332 = __toESM(require_InlineWorkers(), 1); var ElevationBandMaterial_default = "uniform sampler2D heights;\nuniform sampler2D colors;\n\n// This material expects heights to be sorted from lowest to highest.\n\nfloat getHeight(int idx, float invTexSize)\n{\n vec2 uv = vec2((float(idx) + 0.5) * invTexSize, 0.5);\n#ifdef OES_texture_float\n return texture(heights, uv).x;\n#else\n return czm_unpackFloat(texture(heights, uv));\n#endif\n}\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n float height = materialInput.height;\n float invTexSize = 1.0 / float(heightsDimensions.x);\n\n float minHeight = getHeight(0, invTexSize);\n float maxHeight = getHeight(heightsDimensions.x - 1, invTexSize);\n\n // early-out when outside the height range\n if (height < minHeight || height > maxHeight) {\n material.diffuse = vec3(0.0);\n material.alpha = 0.0;\n return material;\n }\n\n // Binary search to find heights above and below.\n int idxBelow = 0;\n int idxAbove = heightsDimensions.x;\n float heightBelow = minHeight;\n float heightAbove = maxHeight;\n\n // while loop not allowed, so use for loop with max iterations.\n // maxIterations of 16 supports a texture size up to 65536 (2^16).\n const int maxIterations = 16;\n for (int i = 0; i < maxIterations; i++) {\n if (idxBelow >= idxAbove - 1) {\n break;\n }\n\n int idxMid = (idxBelow + idxAbove) / 2;\n float heightTex = getHeight(idxMid, invTexSize);\n\n if (height > heightTex) {\n idxBelow = idxMid;\n heightBelow = heightTex;\n } else {\n idxAbove = idxMid;\n heightAbove = heightTex;\n }\n }\n\n float lerper = heightBelow == heightAbove ? 1.0 : (height - heightBelow) / (heightAbove - heightBelow);\n vec2 colorUv = vec2(invTexSize * (float(idxBelow) + 0.5 + lerper), 0.5);\n vec4 color = texture(colors, colorUv);\n\n // undo preumultiplied alpha\n if (color.a > 0.0) \n {\n color.rgb /= color.a;\n }\n \n color.rgb = czm_gammaCorrect(color.rgb);\n\n material.diffuse = color.rgb;\n material.alpha = color.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/ElevationContourMaterial.js var import_InlineWorkers333 = __toESM(require_InlineWorkers(), 1); var ElevationContourMaterial_default = "uniform vec4 color;\nuniform float spacing;\nuniform float width;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n float distanceToContour = mod(materialInput.height, spacing);\n\n#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))\n float dxc = abs(dFdx(materialInput.height));\n float dyc = abs(dFdy(materialInput.height));\n float dF = max(dxc, dyc) * czm_pixelRatio * width;\n float alpha = (distanceToContour < dF) ? 1.0 : 0.0;\n#else\n // If no derivatives available (IE 10?), use pixel ratio\n float alpha = (distanceToContour < (czm_pixelRatio * width)) ? 1.0 : 0.0;\n#endif\n\n vec4 outColor = czm_gammaCorrect(vec4(color.rgb, alpha * color.a));\n material.diffuse = outColor.rgb;\n material.alpha = outColor.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/ElevationRampMaterial.js var import_InlineWorkers334 = __toESM(require_InlineWorkers(), 1); var ElevationRampMaterial_default = "uniform sampler2D image;\nuniform float minimumHeight;\nuniform float maximumHeight;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n float scaledHeight = clamp((materialInput.height - minimumHeight) / (maximumHeight - minimumHeight), 0.0, 1.0);\n vec4 rampColor = texture(image, vec2(scaledHeight, 0.5));\n rampColor = czm_gammaCorrect(rampColor);\n material.diffuse = rampColor.rgb;\n material.alpha = rampColor.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/FadeMaterial.js var import_InlineWorkers335 = __toESM(require_InlineWorkers(), 1); var FadeMaterial_default = "uniform vec4 fadeInColor;\nuniform vec4 fadeOutColor;\nuniform float maximumDistance;\nuniform bool repeat;\nuniform vec2 fadeDirection;\nuniform vec2 time;\n\nfloat getTime(float t, float coord)\n{\n float scalar = 1.0 / maximumDistance;\n float q = distance(t, coord) * scalar;\n if (repeat)\n {\n float r = distance(t, coord + 1.0) * scalar;\n float s = distance(t, coord - 1.0) * scalar;\n q = min(min(r, s), q);\n }\n return clamp(q, 0.0, 1.0);\n}\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n float s = getTime(time.x, st.s) * fadeDirection.s;\n float t = getTime(time.y, st.t) * fadeDirection.t;\n\n float u = length(vec2(s, t));\n vec4 color = mix(fadeInColor, fadeOutColor, u);\n\n color = czm_gammaCorrect(color);\n material.emission = color.rgb;\n material.alpha = color.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/GridMaterial.js var import_InlineWorkers336 = __toESM(require_InlineWorkers(), 1); var GridMaterial_default = 'uniform vec4 color;\nuniform float cellAlpha;\nuniform vec2 lineCount;\nuniform vec2 lineThickness;\nuniform vec2 lineOffset;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n\n float scaledWidth = fract(lineCount.s * st.s - lineOffset.s);\n scaledWidth = abs(scaledWidth - floor(scaledWidth + 0.5));\n float scaledHeight = fract(lineCount.t * st.t - lineOffset.t);\n scaledHeight = abs(scaledHeight - floor(scaledHeight + 0.5));\n\n float value;\n\n // Fuzz Factor - Controls blurriness of lines\n#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))\n const float fuzz = 1.2;\n vec2 thickness = (lineThickness * czm_pixelRatio) - 1.0;\n\n // From "3D Engine Design for Virtual Globes" by Cozzi and Ring, Listing 4.13.\n vec2 dx = abs(dFdx(st));\n vec2 dy = abs(dFdy(st));\n vec2 dF = vec2(max(dx.s, dy.s), max(dx.t, dy.t)) * lineCount;\n value = min(\n smoothstep(dF.s * thickness.s, dF.s * (fuzz + thickness.s), scaledWidth),\n smoothstep(dF.t * thickness.t, dF.t * (fuzz + thickness.t), scaledHeight));\n#else\n // If no derivatives available (IE 10?), revert to view-dependent fuzz\n const float fuzz = 0.05;\n\n vec2 range = 0.5 - (lineThickness * 0.05);\n value = min(\n 1.0 - smoothstep(range.s, range.s + fuzz, scaledWidth),\n 1.0 - smoothstep(range.t, range.t + fuzz, scaledHeight));\n#endif\n\n // Edges taken from RimLightingMaterial.glsl\n // See http://www.fundza.com/rman_shaders/surface/fake_rim/fake_rim1.html\n float dRim = 1.0 - abs(dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC)));\n float sRim = smoothstep(0.8, 1.0, dRim);\n value *= (1.0 - sRim);\n\n vec4 halfColor;\n halfColor.rgb = color.rgb * 0.5;\n halfColor.a = color.a * (1.0 - ((1.0 - cellAlpha) * value));\n halfColor = czm_gammaCorrect(halfColor);\n material.diffuse = halfColor.rgb;\n material.emission = halfColor.rgb;\n material.alpha = halfColor.a;\n\n return material;\n}\n'; // packages/engine/Source/Shaders/Materials/NormalMapMaterial.js var import_InlineWorkers337 = __toESM(require_InlineWorkers(), 1); var NormalMapMaterial_default = "uniform sampler2D image;\nuniform float strength;\nuniform vec2 repeat;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n \n vec4 textureValue = texture(image, fract(repeat * materialInput.st));\n vec3 normalTangentSpace = textureValue.channels;\n normalTangentSpace.xy = normalTangentSpace.xy * 2.0 - 1.0;\n normalTangentSpace.z = clamp(1.0 - strength, 0.1, 1.0);\n normalTangentSpace = normalize(normalTangentSpace);\n vec3 normalEC = materialInput.tangentToEyeMatrix * normalTangentSpace;\n \n material.normal = normalEC;\n \n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/PolylineArrowMaterial.js var import_InlineWorkers338 = __toESM(require_InlineWorkers(), 1); var PolylineArrowMaterial_default = "uniform vec4 color;\n\nfloat getPointOnLine(vec2 p0, vec2 p1, float x)\n{\n float slope = (p0.y - p1.y) / (p0.x - p1.x);\n return slope * (x - p0.x) + p0.y;\n}\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n\n#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))\n float base = 1.0 - abs(fwidth(st.s)) * 10.0 * czm_pixelRatio;\n#else\n // If no derivatives available (IE 10?), 2.5% of the line will be the arrow head\n float base = 0.975;\n#endif\n\n vec2 center = vec2(1.0, 0.5);\n float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);\n float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);\n\n float halfWidth = 0.15;\n float s = step(0.5 - halfWidth, st.t);\n s *= 1.0 - step(0.5 + halfWidth, st.t);\n s *= 1.0 - step(base, st.s);\n\n float t = step(base, materialInput.st.s);\n t *= 1.0 - step(ptOnUpperLine, st.t);\n t *= step(ptOnLowerLine, st.t);\n\n // Find the distance from the closest separator (region between two colors)\n float dist;\n if (st.s < base)\n {\n float d1 = abs(st.t - (0.5 - halfWidth));\n float d2 = abs(st.t - (0.5 + halfWidth));\n dist = min(d1, d2);\n }\n else\n {\n float d1 = czm_infinity;\n if (st.t < 0.5 - halfWidth && st.t > 0.5 + halfWidth)\n {\n d1 = abs(st.s - base);\n }\n float d2 = abs(st.t - ptOnUpperLine);\n float d3 = abs(st.t - ptOnLowerLine);\n dist = min(min(d1, d2), d3);\n }\n\n vec4 outsideColor = vec4(0.0);\n vec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));\n vec4 outColor = czm_antialias(outsideColor, color, currentColor, dist);\n\n outColor = czm_gammaCorrect(outColor);\n material.diffuse = outColor.rgb;\n material.alpha = outColor.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/PolylineDashMaterial.js var import_InlineWorkers339 = __toESM(require_InlineWorkers(), 1); var PolylineDashMaterial_default = "uniform vec4 color;\nuniform vec4 gapColor;\nuniform float dashLength;\nuniform float dashPattern;\nin float v_polylineAngle;\n\nconst float maskLength = 16.0;\n\nmat2 rotate(float rad) {\n float c = cos(rad);\n float s = sin(rad);\n return mat2(\n c, s,\n -s, c\n );\n}\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy;\n\n // Get the relative position within the dash from 0 to 1\n float dashPosition = fract(pos.x / (dashLength * czm_pixelRatio));\n // Figure out the mask index.\n float maskIndex = floor(dashPosition * maskLength);\n // Test the bit mask.\n float maskTest = floor(dashPattern / pow(2.0, maskIndex));\n vec4 fragColor = (mod(maskTest, 2.0) < 1.0) ? gapColor : color;\n if (fragColor.a < 0.005) { // matches 0/255 and 1/255\n discard;\n }\n\n fragColor = czm_gammaCorrect(fragColor);\n material.emission = fragColor.rgb;\n material.alpha = fragColor.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/PolylineGlowMaterial.js var import_InlineWorkers340 = __toESM(require_InlineWorkers(), 1); var PolylineGlowMaterial_default = "uniform vec4 color;\nuniform float glowPower;\nuniform float taperPower;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n float glow = glowPower / abs(st.t - 0.5) - (glowPower / 0.5);\n\n if (taperPower <= 0.99999) {\n glow *= min(1.0, taperPower / (0.5 - st.s * 0.5) - (taperPower / 0.5));\n }\n\n vec4 fragColor;\n fragColor.rgb = max(vec3(glow - 1.0 + color.rgb), color.rgb);\n fragColor.a = clamp(glow, 0.0, 1.0) * color.a;\n fragColor = czm_gammaCorrect(fragColor);\n\n material.emission = fragColor.rgb;\n material.alpha = fragColor.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/PolylineOutlineMaterial.js var import_InlineWorkers341 = __toESM(require_InlineWorkers(), 1); var PolylineOutlineMaterial_default = "uniform vec4 color;\nuniform vec4 outlineColor;\nuniform float outlineWidth;\n\nin float v_width;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec2 st = materialInput.st;\n float halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width;\n float b = step(0.5 - halfInteriorWidth, st.t);\n b *= 1.0 - step(0.5 + halfInteriorWidth, st.t);\n\n // Find the distance from the closest separator (region between two colors)\n float d1 = abs(st.t - (0.5 - halfInteriorWidth));\n float d2 = abs(st.t - (0.5 + halfInteriorWidth));\n float dist = min(d1, d2);\n\n vec4 currentColor = mix(outlineColor, color, b);\n vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist);\n outColor = czm_gammaCorrect(outColor);\n\n material.diffuse = outColor.rgb;\n material.alpha = outColor.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/RimLightingMaterial.js var import_InlineWorkers342 = __toESM(require_InlineWorkers(), 1); var RimLightingMaterial_default = "uniform vec4 color;\nuniform vec4 rimColor;\nuniform float width;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n // See http://www.fundza.com/rman_shaders/surface/fake_rim/fake_rim1.html\n float d = 1.0 - dot(materialInput.normalEC, normalize(materialInput.positionToEyeEC));\n float s = smoothstep(1.0 - width, 1.0, d);\n\n vec4 outColor = czm_gammaCorrect(color);\n vec4 outRimColor = czm_gammaCorrect(rimColor);\n\n material.diffuse = outColor.rgb;\n material.emission = outRimColor.rgb * s;\n material.alpha = mix(outColor.a, outRimColor.a, s);\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/SlopeRampMaterial.js var import_InlineWorkers343 = __toESM(require_InlineWorkers(), 1); var SlopeRampMaterial_default = "uniform sampler2D image;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n vec4 rampColor = texture(image, vec2(materialInput.slope / (czm_pi / 2.0), 0.5));\n rampColor = czm_gammaCorrect(rampColor);\n material.diffuse = rampColor.rgb;\n material.alpha = rampColor.a;\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/StripeMaterial.js var import_InlineWorkers344 = __toESM(require_InlineWorkers(), 1); var StripeMaterial_default = "uniform vec4 evenColor;\nuniform vec4 oddColor;\nuniform float offset;\nuniform float repeat;\nuniform bool horizontal;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n // Based on the Stripes Fragment Shader in the Orange Book (11.1.2)\n float coord = mix(materialInput.st.s, materialInput.st.t, float(horizontal));\n float value = fract((coord - offset) * (repeat * 0.5));\n float dist = min(value, min(abs(value - 0.5), 1.0 - value));\n\n vec4 currentColor = mix(evenColor, oddColor, step(0.5, value));\n vec4 color = czm_antialias(evenColor, oddColor, currentColor, dist);\n color = czm_gammaCorrect(color);\n\n material.diffuse = color.rgb;\n material.alpha = color.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/WaterMaskMaterial.js var import_InlineWorkers345 = __toESM(require_InlineWorkers(), 1); var WaterMaskMaterial_default = "uniform vec4 waterColor;\nuniform vec4 landColor;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n vec4 outColor = mix(landColor, waterColor, materialInput.waterMask);\n outColor = czm_gammaCorrect(outColor);\n\n material.diffuse = outColor.rgb;\n material.alpha = outColor.a;\n\n return material;\n}\n"; // packages/engine/Source/Shaders/Materials/Water.js var import_InlineWorkers346 = __toESM(require_InlineWorkers(), 1); var Water_default = "// Thanks for the contribution Jonas\n// http://29a.ch/2012/7/19/webgl-terrain-rendering-water-fog\n\nuniform sampler2D specularMap;\nuniform sampler2D normalMap;\nuniform vec4 baseWaterColor;\nuniform vec4 blendColor;\nuniform float frequency;\nuniform float animationSpeed;\nuniform float amplitude;\nuniform float specularIntensity;\nuniform float fadeFactor;\n\nczm_material czm_getMaterial(czm_materialInput materialInput)\n{\n czm_material material = czm_getDefaultMaterial(materialInput);\n\n float time = czm_frameNumber * animationSpeed;\n\n // fade is a function of the distance from the fragment and the frequency of the waves\n float fade = max(1.0, (length(materialInput.positionToEyeEC) / 10000000000.0) * frequency * fadeFactor);\n\n float specularMapValue = texture(specularMap, materialInput.st).r;\n\n // note: not using directional motion at this time, just set the angle to 0.0;\n vec4 noise = czm_getWaterNoise(normalMap, materialInput.st * frequency, time, 0.0);\n vec3 normalTangentSpace = noise.xyz * vec3(1.0, 1.0, (1.0 / amplitude));\n\n // fade out the normal perturbation as we move further from the water surface\n normalTangentSpace.xy /= fade;\n\n // attempt to fade out the normal perturbation as we approach non water areas (low specular map value)\n normalTangentSpace = mix(vec3(0.0, 0.0, 50.0), normalTangentSpace, specularMapValue);\n\n normalTangentSpace = normalize(normalTangentSpace);\n\n // get ratios for alignment of the new normal vector with a vector perpendicular to the tangent plane\n float tsPerturbationRatio = clamp(dot(normalTangentSpace, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);\n\n // fade out water effect as specular map value decreases\n material.alpha = mix(blendColor.a, baseWaterColor.a, specularMapValue) * specularMapValue;\n\n // base color is a blend of the water and non-water color based on the value from the specular map\n // may need a uniform blend factor to better control this\n material.diffuse = mix(blendColor.rgb, baseWaterColor.rgb, specularMapValue);\n\n // diffuse highlights are based on how perturbed the normal is\n material.diffuse += (0.1 * tsPerturbationRatio);\n\n material.diffuse = material.diffuse;\n\n material.normal = normalize(materialInput.tangentToEyeMatrix * normalTangentSpace);\n\n material.specular = specularIntensity;\n material.shininess = 10.0;\n\n return material;\n}\n"; // packages/engine/Source/Scene/Material.js function Material(options) { this.type = void 0; this.shaderSource = void 0; this.materials = void 0; this.uniforms = void 0; this._uniforms = void 0; this.translucent = void 0; this._minificationFilter = options.minificationFilter ?? TextureMinificationFilter_default.LINEAR; this._magnificationFilter = options.magnificationFilter ?? TextureMagnificationFilter_default.LINEAR; this._strict = void 0; this._template = void 0; this._count = void 0; this._texturePaths = {}; this._loadedImages = []; this._loadedCubeMaps = []; this._textures = {}; this._updateFunctions = []; this._defaultTexture = void 0; this._initializationPromises = []; this._initializationError = void 0; initializeMaterial(options, this); Object.defineProperties(this, { type: { value: this.type, writable: false }, /** * The {@link TextureMinificationFilter} to apply to this material's textures. * @memberof Material.prototype * @type {TextureMinificationFilter} * @default TextureMinificationFilter.LINEAR */ minificationFilter: { get: function() { return this._minificationFilter; }, set: function(value) { this._minificationFilter = value; } }, /** * The {@link TextureMagnificationFilter} to apply to this material's textures. * @memberof Material.prototype * @type {TextureMagnificationFilter} * @default TextureMagnificationFilter.LINEAR */ magnificationFilter: { get: function() { return this._magnificationFilter; }, set: function(value) { this._magnificationFilter = value; } } }); if (!defined_default(Material._uniformList[this.type])) { Material._uniformList[this.type] = Object.keys(this._uniforms); } } Material._uniformList = {}; Material.fromType = function(type, uniforms) { if (!defined_default(Material._materialCache.getMaterial(type))) { throw new DeveloperError_default(`material with type '${type}' does not exist.`); } const material4 = new Material({ fabric: { type } }); if (defined_default(uniforms)) { for (const name in uniforms) { if (uniforms.hasOwnProperty(name)) { material4.uniforms[name] = uniforms[name]; } } } return material4; }; Material.fromTypeAsync = async function(type, uniforms) { if (!defined_default(Material._materialCache.getMaterial(type))) { throw new DeveloperError_default(`material with type '${type}' does not exist.`); } const initializationPromises = []; const material4 = new Material({ fabric: { type, uniforms } }); getInitializationPromises(material4, initializationPromises); await Promise.all(initializationPromises); initializationPromises.length = 0; if (defined_default(material4._initializationError)) { throw material4._initializationError; } return material4; }; function getInitializationPromises(material4, initializationPromises) { initializationPromises.push(...material4._initializationPromises); const submaterials = material4.materials; for (const name in submaterials) { if (submaterials.hasOwnProperty(name)) { const submaterial = submaterials[name]; getInitializationPromises(submaterial, initializationPromises); } } } Material.prototype.isTranslucent = function() { if (defined_default(this.translucent)) { if (typeof this.translucent === "function") { return this.translucent(); } return this.translucent; } let translucent = true; const funcs = this._translucentFunctions; const length2 = funcs.length; for (let i = 0; i < length2; ++i) { const func = funcs[i]; if (typeof func === "function") { translucent = translucent && func(); } else { translucent = translucent && func; } if (!translucent) { break; } } return translucent; }; Material.prototype.update = function(context) { this._defaultTexture = context.defaultTexture; let i; let uniformId; const loadedImages = this._loadedImages; let length2 = loadedImages.length; for (i = 0; i < length2; ++i) { const loadedImage = loadedImages[i]; uniformId = loadedImage.id; let image = loadedImage.image; let mipLevels; if (Array.isArray(image)) { mipLevels = image.slice(1, image.length).map(function(mipLevel) { return mipLevel.bufferView; }); image = image[0]; } const sampler = new Sampler_default({ minificationFilter: this._minificationFilter, magnificationFilter: this._magnificationFilter }); let texture; if (defined_default(image.internalFormat)) { texture = new Texture_default({ context, pixelFormat: image.internalFormat, width: image.width, height: image.height, source: { arrayBufferView: image.bufferView, mipLevels }, sampler }); } else { texture = new Texture_default({ context, source: image, sampler }); } const oldTexture = this._textures[uniformId]; if (defined_default(oldTexture) && oldTexture !== this._defaultTexture) { oldTexture.destroy(); } this._textures[uniformId] = texture; const uniformDimensionsName = `${uniformId}Dimensions`; if (this.uniforms.hasOwnProperty(uniformDimensionsName)) { const uniformDimensions = this.uniforms[uniformDimensionsName]; uniformDimensions.x = texture._width; uniformDimensions.y = texture._height; } } loadedImages.length = 0; const loadedCubeMaps = this._loadedCubeMaps; length2 = loadedCubeMaps.length; for (i = 0; i < length2; ++i) { const loadedCubeMap = loadedCubeMaps[i]; uniformId = loadedCubeMap.id; const images = loadedCubeMap.images; const cubeMap = new CubeMap_default({ context, source: { positiveX: images[0], negativeX: images[1], positiveY: images[2], negativeY: images[3], positiveZ: images[4], negativeZ: images[5] }, sampler: new Sampler_default({ minificationFilter: this._minificationFilter, magnificationFilter: this._magnificationFilter }) }); this._textures[uniformId] = cubeMap; } loadedCubeMaps.length = 0; const updateFunctions2 = this._updateFunctions; length2 = updateFunctions2.length; for (i = 0; i < length2; ++i) { updateFunctions2[i](this, context); } const subMaterials = this.materials; for (const name in subMaterials) { if (subMaterials.hasOwnProperty(name)) { subMaterials[name].update(context); } } }; Material.prototype.isDestroyed = function() { return false; }; Material.prototype.destroy = function() { const textures = this._textures; for (const texture in textures) { if (textures.hasOwnProperty(texture)) { const instance = textures[texture]; if (instance !== this._defaultTexture) { instance.destroy(); } } } const materials = this.materials; for (const material4 in materials) { if (materials.hasOwnProperty(material4)) { materials[material4].destroy(); } } return destroyObject_default(this); }; function initializeMaterial(options, result) { options = options ?? Frozen_default.EMPTY_OBJECT; result._strict = options.strict ?? false; result._count = options.count ?? 0; result._template = clone_default(options.fabric ?? Frozen_default.EMPTY_OBJECT); result.fabric = clone_default(options.fabric ?? Frozen_default.EMPTY_OBJECT); result._template.uniforms = clone_default( result._template.uniforms ?? Frozen_default.EMPTY_OBJECT ); result._template.materials = clone_default( result._template.materials ?? Frozen_default.EMPTY_OBJECT ); result.type = defined_default(result._template.type) ? result._template.type : createGuid_default(); result.shaderSource = ""; result.materials = {}; result.uniforms = {}; result._uniforms = {}; result._translucentFunctions = []; let translucent; const cachedMaterial = Material._materialCache.getMaterial(result.type); if (defined_default(cachedMaterial)) { const template = clone_default(cachedMaterial.fabric, true); result._template = combine_default(result._template, template, true); translucent = cachedMaterial.translucent; } checkForTemplateErrors(result); createMethodDefinition(result); createUniforms(result); createSubMaterials(result); if (!defined_default(cachedMaterial)) { Material._materialCache.addMaterial(result.type, result); } const defaultTranslucent = result._translucentFunctions.length === 0 ? true : void 0; translucent = translucent ?? defaultTranslucent; translucent = options.translucent ?? translucent; if (defined_default(translucent)) { if (typeof translucent === "function") { const wrappedTranslucent = function() { return translucent(result); }; result._translucentFunctions.push(wrappedTranslucent); } else { result._translucentFunctions.push(translucent); } } } function checkForValidProperties(object2, properties, result, throwNotFound) { if (defined_default(object2)) { for (const property in object2) { if (object2.hasOwnProperty(property)) { const hasProperty = properties.indexOf(property) !== -1; if (throwNotFound && !hasProperty || !throwNotFound && hasProperty) { result(property, properties); } } } } } function invalidNameError(property, properties) { let errorString = `fabric: property name '${property}' is not valid. It should be `; for (let i = 0; i < properties.length; i++) { const propertyName = `'${properties[i]}'`; errorString += i === properties.length - 1 ? `or ${propertyName}.` : `${propertyName}, `; } throw new DeveloperError_default(errorString); } function duplicateNameError(property, properties) { const errorString = `fabric: uniforms and materials cannot share the same property '${property}'`; throw new DeveloperError_default(errorString); } var templateProperties = [ "type", "materials", "uniforms", "components", "source" ]; var componentProperties = [ "diffuse", "specular", "shininess", "normal", "emission", "alpha" ]; function checkForTemplateErrors(material4) { const template = material4._template; const uniforms = template.uniforms; const materials = template.materials; const components = template.components; if (defined_default(components) && defined_default(template.source)) { throw new DeveloperError_default( "fabric: cannot have source and components in the same template." ); } checkForValidProperties(template, templateProperties, invalidNameError, true); checkForValidProperties( components, componentProperties, invalidNameError, true ); const materialNames = []; for (const property in materials) { if (materials.hasOwnProperty(property)) { materialNames.push(property); } } checkForValidProperties(uniforms, materialNames, duplicateNameError, false); } function isMaterialFused(shaderComponent, material4) { const materials = material4._template.materials; for (const subMaterialId in materials) { if (materials.hasOwnProperty(subMaterialId)) { if (shaderComponent.indexOf(subMaterialId) > -1) { return true; } } } return false; } function createMethodDefinition(material4) { const components = material4._template.components; const source = material4._template.source; if (defined_default(source)) { material4.shaderSource += `${source} `; } else { material4.shaderSource += "czm_material czm_getMaterial(czm_materialInput materialInput)\n{\n"; material4.shaderSource += "czm_material material = czm_getDefaultMaterial(materialInput);\n"; if (defined_default(components)) { const isMultiMaterial = Object.keys(material4._template.materials).length > 0; for (const component in components) { if (components.hasOwnProperty(component)) { if (component === "diffuse" || component === "emission") { const isFusion = isMultiMaterial && isMaterialFused(components[component], material4); const componentSource = isFusion ? components[component] : `czm_gammaCorrect(${components[component]})`; material4.shaderSource += `material.${component} = ${componentSource}; `; } else if (component === "alpha") { material4.shaderSource += `material.alpha = ${components.alpha}; `; } else { material4.shaderSource += `material.${component} = ${components[component]}; `; } } } } material4.shaderSource += "return material;\n}\n"; } } var matrixMap = { mat2: Matrix2_default, mat3: Matrix3_default, mat4: Matrix4_default }; var ktx2Regex = /\.ktx2$/i; function createTexture2DUpdateFunction(uniformId) { let oldUniformValue; return function(material4, context) { const uniforms = material4.uniforms; const uniformValue = uniforms[uniformId]; const uniformChanged = oldUniformValue !== uniformValue; const uniformValueIsDefaultImage = !defined_default(uniformValue) || uniformValue === Material.DefaultImageId; oldUniformValue = uniformValue; let texture = material4._textures[uniformId]; let uniformDimensionsName; let uniformDimensions; if (uniformValue instanceof HTMLVideoElement) { if (uniformValue.readyState >= 2) { if (uniformChanged && defined_default(texture)) { if (texture !== context.defaultTexture) { texture.destroy(); } texture = void 0; } if (!defined_default(texture) || texture === context.defaultTexture) { const sampler = new Sampler_default({ minificationFilter: material4._minificationFilter, magnificationFilter: material4._magnificationFilter }); texture = new Texture_default({ context, source: uniformValue, sampler }); material4._textures[uniformId] = texture; return; } texture.copyFrom({ source: uniformValue }); } else if (!defined_default(texture)) { material4._textures[uniformId] = context.defaultTexture; } return; } if (uniformValue instanceof Texture_default && uniformValue !== texture) { material4._texturePaths[uniformId] = void 0; const tmp2 = material4._textures[uniformId]; if (defined_default(tmp2) && tmp2 !== material4._defaultTexture) { tmp2.destroy(); } material4._textures[uniformId] = uniformValue; uniformDimensionsName = `${uniformId}Dimensions`; if (uniforms.hasOwnProperty(uniformDimensionsName)) { uniformDimensions = uniforms[uniformDimensionsName]; uniformDimensions.x = uniformValue._width; uniformDimensions.y = uniformValue._height; } return; } if (uniformChanged && defined_default(texture) && uniformValueIsDefaultImage) { if (texture !== material4._defaultTexture) { texture.destroy(); } texture = void 0; material4._texturePaths[uniformId] = void 0; } if (!defined_default(texture)) { texture = material4._textures[uniformId] = material4._defaultTexture; uniformDimensionsName = `${uniformId}Dimensions`; if (uniforms.hasOwnProperty(uniformDimensionsName)) { uniformDimensions = uniforms[uniformDimensionsName]; uniformDimensions.x = texture._width; uniformDimensions.y = texture._height; } } if (uniformValueIsDefaultImage) { return; } if ((uniformValue instanceof HTMLCanvasElement || uniformValue instanceof HTMLImageElement || uniformValue instanceof ImageBitmap || uniformValue instanceof OffscreenCanvas) && uniformValue !== material4._texturePaths[uniformId]) { material4._loadedImages.push({ id: uniformId, image: uniformValue }); material4._texturePaths[uniformId] = uniformValue; return; } loadTexture2DImageForUniform(material4, uniformId); }; } function loadTexture2DImageForUniform(material4, uniformId) { const uniforms = material4.uniforms; const uniformValue = uniforms[uniformId]; if (uniformValue === Material.DefaultImageId) { return Promise.resolve(); } const resource = Resource_default.createIfNeeded(uniformValue); if (!(resource instanceof Resource_default)) { return Promise.resolve(); } const oldResource = Resource_default.createIfNeeded( material4._texturePaths[uniformId] ); const uniformHasChanged = !defined_default(oldResource) || oldResource.url !== resource.url; if (!uniformHasChanged) { return Promise.resolve(); } let promise; if (ktx2Regex.test(resource.url)) { promise = loadKTX2_default(resource.url); } else { promise = resource.fetchImage(); } Promise.resolve(promise).then(function(image) { material4._loadedImages.push({ id: uniformId, image }); }).catch(function(error) { material4._initializationError = error; const texture = material4._textures[uniformId]; if (defined_default(texture) && texture !== material4._defaultTexture) { texture.destroy(); } material4._textures[uniformId] = material4._defaultTexture; }); material4._texturePaths[uniformId] = uniformValue; return promise; } function createCubeMapUpdateFunction(uniformId) { return function(material4, context) { const uniformValue = material4.uniforms[uniformId]; if (uniformValue instanceof CubeMap_default) { const tmp2 = material4._textures[uniformId]; if (tmp2 !== material4._defaultTexture) { tmp2.destroy(); } material4._texturePaths[uniformId] = void 0; material4._textures[uniformId] = uniformValue; return; } if (!defined_default(material4._textures[uniformId])) { material4._textures[uniformId] = context.defaultCubeMap; } loadCubeMapImagesForUniform(material4, uniformId); }; } function loadCubeMapImagesForUniform(material4, uniformId) { const uniforms = material4.uniforms; const uniformValue = uniforms[uniformId]; if (uniformValue === Material.DefaultCubeMapId) { return Promise.resolve(); } const path = uniformValue.positiveX + uniformValue.negativeX + uniformValue.positiveY + uniformValue.negativeY + uniformValue.positiveZ + uniformValue.negativeZ; if (path === material4._texturePaths[uniformId]) { return Promise.resolve(); } const promises = [ Resource_default.createIfNeeded(uniformValue.positiveX).fetchImage(), Resource_default.createIfNeeded(uniformValue.negativeX).fetchImage(), Resource_default.createIfNeeded(uniformValue.positiveY).fetchImage(), Resource_default.createIfNeeded(uniformValue.negativeY).fetchImage(), Resource_default.createIfNeeded(uniformValue.positiveZ).fetchImage(), Resource_default.createIfNeeded(uniformValue.negativeZ).fetchImage() ]; const allPromise = Promise.all(promises); allPromise.then(function(images) { material4._loadedCubeMaps.push({ id: uniformId, images }); }).catch(function(error) { material4._initializationError = error; }); material4._texturePaths[uniformId] = path; return allPromise; } function createUniforms(material4) { const uniforms = material4._template.uniforms; for (const uniformId in uniforms) { if (uniforms.hasOwnProperty(uniformId)) { createUniform2(material4, uniformId); } } } function createUniform2(material4, uniformId) { const strict = material4._strict; const materialUniforms = material4._template.uniforms; const uniformValue = materialUniforms[uniformId]; const uniformType = getUniformType(uniformValue); if (!defined_default(uniformType)) { throw new DeveloperError_default( `fabric: uniform '${uniformId}' has invalid type.` ); } let replacedTokenCount; if (uniformType === "channels") { replacedTokenCount = replaceToken(material4, uniformId, uniformValue, false); if (replacedTokenCount === 0 && strict) { throw new DeveloperError_default( `strict: shader source does not use channels '${uniformId}'.` ); } } else { if (uniformType === "sampler2D") { const imageDimensionsUniformName = `${uniformId}Dimensions`; if (getNumberOfTokens(material4, imageDimensionsUniformName) > 0) { materialUniforms[imageDimensionsUniformName] = { type: "ivec3", x: 1, y: 1 }; createUniform2(material4, imageDimensionsUniformName); } } const uniformDeclarationRegex = new RegExp( `uniform\\s+${uniformType}\\s+${uniformId}\\s*;` ); if (!uniformDeclarationRegex.test(material4.shaderSource)) { const uniformDeclaration = `uniform ${uniformType} ${uniformId};`; material4.shaderSource = uniformDeclaration + material4.shaderSource; } const newUniformId = `${uniformId}_${material4._count++}`; replacedTokenCount = replaceToken(material4, uniformId, newUniformId); if (replacedTokenCount === 1 && strict) { throw new DeveloperError_default( `strict: shader source does not use uniform '${uniformId}'.` ); } material4.uniforms[uniformId] = uniformValue; if (uniformType === "sampler2D") { material4._uniforms[newUniformId] = function() { return material4._textures[uniformId]; }; material4._updateFunctions.push(createTexture2DUpdateFunction(uniformId)); material4._initializationPromises.push( loadTexture2DImageForUniform(material4, uniformId) ); } else if (uniformType === "samplerCube") { material4._uniforms[newUniformId] = function() { return material4._textures[uniformId]; }; material4._updateFunctions.push(createCubeMapUpdateFunction(uniformId)); material4._initializationPromises.push( loadCubeMapImagesForUniform(material4, uniformId) ); } else if (uniformType.indexOf("mat") !== -1) { const scratchMatrix8 = new matrixMap[uniformType](); material4._uniforms[newUniformId] = function() { return matrixMap[uniformType].fromColumnMajorArray( material4.uniforms[uniformId], scratchMatrix8 ); }; } else { material4._uniforms[newUniformId] = function() { return material4.uniforms[uniformId]; }; } } } function getUniformType(uniformValue) { let uniformType = uniformValue.type; if (!defined_default(uniformType)) { const type = typeof uniformValue; if (type === "number") { uniformType = "float"; } else if (type === "boolean") { uniformType = "bool"; } else if (type === "string" || uniformValue instanceof Resource_default || uniformValue instanceof HTMLCanvasElement || uniformValue instanceof HTMLImageElement || uniformValue instanceof ImageBitmap || uniformValue instanceof OffscreenCanvas) { if (/^([rgba]){1,4}$/i.test(uniformValue)) { uniformType = "channels"; } else if (uniformValue === Material.DefaultCubeMapId) { uniformType = "samplerCube"; } else { uniformType = "sampler2D"; } } else if (type === "object") { if (Array.isArray(uniformValue)) { if (uniformValue.length === 4 || uniformValue.length === 9 || uniformValue.length === 16) { uniformType = `mat${Math.sqrt(uniformValue.length)}`; } } else { let numAttributes = 0; for (const attribute in uniformValue) { if (uniformValue.hasOwnProperty(attribute)) { numAttributes += 1; } } if (numAttributes >= 2 && numAttributes <= 4) { uniformType = `vec${numAttributes}`; } else if (numAttributes === 6) { uniformType = "samplerCube"; } } } } return uniformType; } function createSubMaterials(material4) { const strict = material4._strict; const subMaterialTemplates = material4._template.materials; for (const subMaterialId in subMaterialTemplates) { if (subMaterialTemplates.hasOwnProperty(subMaterialId)) { const subMaterial = new Material({ strict, fabric: subMaterialTemplates[subMaterialId], count: material4._count }); material4._count = subMaterial._count; material4._uniforms = combine_default( material4._uniforms, subMaterial._uniforms, true ); material4.materials[subMaterialId] = subMaterial; material4._translucentFunctions = material4._translucentFunctions.concat( subMaterial._translucentFunctions ); const originalMethodName = "czm_getMaterial"; const newMethodName = `${originalMethodName}_${material4._count++}`; replaceToken(subMaterial, originalMethodName, newMethodName); material4.shaderSource = subMaterial.shaderSource + material4.shaderSource; const materialMethodCall = `${newMethodName}(materialInput)`; const tokensReplacedCount = replaceToken( material4, subMaterialId, materialMethodCall ); if (tokensReplacedCount === 0 && strict) { throw new DeveloperError_default( `strict: shader source does not use material '${subMaterialId}'.` ); } } } } function replaceToken(material4, token, newToken, excludePeriod) { excludePeriod = excludePeriod ?? true; let count = 0; const suffixChars = "([\\w])?"; const prefixChars = `([\\w${excludePeriod ? "." : ""}])?`; const regExp = new RegExp(prefixChars + token + suffixChars, "g"); material4.shaderSource = material4.shaderSource.replace( regExp, function($0, $1, $2) { if ($1 || $2) { return $0; } count += 1; return newToken; } ); return count; } function getNumberOfTokens(material4, token, excludePeriod) { return replaceToken(material4, token, token, excludePeriod); } Material._materialCache = { _materials: {}, addMaterial: function(type, materialTemplate) { this._materials[type] = materialTemplate; }, getMaterial: function(type) { return this._materials[type]; } }; Material.DefaultImageId = "czm_defaultImage"; Material.DefaultCubeMapId = "czm_defaultCubeMap"; Material.ColorType = "Color"; Material._materialCache.addMaterial(Material.ColorType, { fabric: { type: Material.ColorType, uniforms: { color: new Color_default(1, 0, 0, 0.5) }, components: { diffuse: "color.rgb", alpha: "color.a" } }, translucent: function(material4) { return material4.uniforms.color.alpha < 1; } }); Material.ImageType = "Image"; Material._materialCache.addMaterial(Material.ImageType, { fabric: { type: Material.ImageType, uniforms: { image: Material.DefaultImageId, repeat: new Cartesian2_default(1, 1), color: new Color_default(1, 1, 1, 1) }, components: { diffuse: "texture(image, fract(repeat * materialInput.st)).rgb * color.rgb", alpha: "texture(image, fract(repeat * materialInput.st)).a * color.a" } }, translucent: function(material4) { return material4.uniforms.color.alpha < 1; } }); Material.DiffuseMapType = "DiffuseMap"; Material._materialCache.addMaterial(Material.DiffuseMapType, { fabric: { type: Material.DiffuseMapType, uniforms: { image: Material.DefaultImageId, channels: "rgb", repeat: new Cartesian2_default(1, 1) }, components: { diffuse: "texture(image, fract(repeat * materialInput.st)).channels" } }, translucent: false }); Material.AlphaMapType = "AlphaMap"; Material._materialCache.addMaterial(Material.AlphaMapType, { fabric: { type: Material.AlphaMapType, uniforms: { image: Material.DefaultImageId, channel: "a", repeat: new Cartesian2_default(1, 1) }, components: { alpha: "texture(image, fract(repeat * materialInput.st)).channel" } }, translucent: true }); Material.SpecularMapType = "SpecularMap"; Material._materialCache.addMaterial(Material.SpecularMapType, { fabric: { type: Material.SpecularMapType, uniforms: { image: Material.DefaultImageId, channel: "r", repeat: new Cartesian2_default(1, 1) }, components: { specular: "texture(image, fract(repeat * materialInput.st)).channel" } }, translucent: false }); Material.EmissionMapType = "EmissionMap"; Material._materialCache.addMaterial(Material.EmissionMapType, { fabric: { type: Material.EmissionMapType, uniforms: { image: Material.DefaultImageId, channels: "rgb", repeat: new Cartesian2_default(1, 1) }, components: { emission: "texture(image, fract(repeat * materialInput.st)).channels" } }, translucent: false }); Material.BumpMapType = "BumpMap"; Material._materialCache.addMaterial(Material.BumpMapType, { fabric: { type: Material.BumpMapType, uniforms: { image: Material.DefaultImageId, channel: "r", strength: 0.8, repeat: new Cartesian2_default(1, 1) }, source: BumpMapMaterial_default }, translucent: false }); Material.NormalMapType = "NormalMap"; Material._materialCache.addMaterial(Material.NormalMapType, { fabric: { type: Material.NormalMapType, uniforms: { image: Material.DefaultImageId, channels: "rgb", strength: 0.8, repeat: new Cartesian2_default(1, 1) }, source: NormalMapMaterial_default }, translucent: false }); Material.GridType = "Grid"; Material._materialCache.addMaterial(Material.GridType, { fabric: { type: Material.GridType, uniforms: { color: new Color_default(0, 1, 0, 1), cellAlpha: 0.1, lineCount: new Cartesian2_default(8, 8), lineThickness: new Cartesian2_default(1, 1), lineOffset: new Cartesian2_default(0, 0) }, source: GridMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.color.alpha < 1 || uniforms.cellAlpha < 1; } }); Material.StripeType = "Stripe"; Material._materialCache.addMaterial(Material.StripeType, { fabric: { type: Material.StripeType, uniforms: { horizontal: true, evenColor: new Color_default(1, 1, 1, 0.5), oddColor: new Color_default(0, 0, 1, 0.5), offset: 0, repeat: 5 }, source: StripeMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.evenColor.alpha < 1 || uniforms.oddColor.alpha < 1; } }); Material.CheckerboardType = "Checkerboard"; Material._materialCache.addMaterial(Material.CheckerboardType, { fabric: { type: Material.CheckerboardType, uniforms: { lightColor: new Color_default(1, 1, 1, 0.5), darkColor: new Color_default(0, 0, 0, 0.5), repeat: new Cartesian2_default(5, 5) }, source: CheckerboardMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.lightColor.alpha < 1 || uniforms.darkColor.alpha < 1; } }); Material.DotType = "Dot"; Material._materialCache.addMaterial(Material.DotType, { fabric: { type: Material.DotType, uniforms: { lightColor: new Color_default(1, 1, 0, 0.75), darkColor: new Color_default(0, 1, 1, 0.75), repeat: new Cartesian2_default(5, 5) }, source: DotMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.lightColor.alpha < 1 || uniforms.darkColor.alpha < 1; } }); Material.WaterType = "Water"; Material._materialCache.addMaterial(Material.WaterType, { fabric: { type: Material.WaterType, uniforms: { baseWaterColor: new Color_default(0.2, 0.3, 0.6, 1), blendColor: new Color_default(0, 1, 0.699, 1), specularMap: Material.DefaultImageId, normalMap: Material.DefaultImageId, frequency: 10, animationSpeed: 0.01, amplitude: 1, specularIntensity: 0.5, fadeFactor: 1 }, source: Water_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.baseWaterColor.alpha < 1 || uniforms.blendColor.alpha < 1; } }); Material.RimLightingType = "RimLighting"; Material._materialCache.addMaterial(Material.RimLightingType, { fabric: { type: Material.RimLightingType, uniforms: { color: new Color_default(1, 0, 0, 0.7), rimColor: new Color_default(1, 1, 1, 0.4), width: 0.3 }, source: RimLightingMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.color.alpha < 1 || uniforms.rimColor.alpha < 1; } }); Material.FadeType = "Fade"; Material._materialCache.addMaterial(Material.FadeType, { fabric: { type: Material.FadeType, uniforms: { fadeInColor: new Color_default(1, 0, 0, 1), fadeOutColor: new Color_default(0, 0, 0, 0), maximumDistance: 0.5, repeat: true, fadeDirection: { x: true, y: true }, time: new Cartesian2_default(0.5, 0.5) }, source: FadeMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.fadeInColor.alpha < 1 || uniforms.fadeOutColor.alpha < 1; } }); Material.PolylineArrowType = "PolylineArrow"; Material._materialCache.addMaterial(Material.PolylineArrowType, { fabric: { type: Material.PolylineArrowType, uniforms: { color: new Color_default(1, 1, 1, 1) }, source: PolylineArrowMaterial_default }, translucent: true }); Material.PolylineDashType = "PolylineDash"; Material._materialCache.addMaterial(Material.PolylineDashType, { fabric: { type: Material.PolylineDashType, uniforms: { color: new Color_default(1, 0, 1, 1), gapColor: new Color_default(0, 0, 0, 0), dashLength: 16, dashPattern: 255 }, source: PolylineDashMaterial_default }, translucent: true }); Material.PolylineGlowType = "PolylineGlow"; Material._materialCache.addMaterial(Material.PolylineGlowType, { fabric: { type: Material.PolylineGlowType, uniforms: { color: new Color_default(0, 0.5, 1, 1), glowPower: 0.25, taperPower: 1 }, source: PolylineGlowMaterial_default }, translucent: true }); Material.PolylineOutlineType = "PolylineOutline"; Material._materialCache.addMaterial(Material.PolylineOutlineType, { fabric: { type: Material.PolylineOutlineType, uniforms: { color: new Color_default(1, 1, 1, 1), outlineColor: new Color_default(1, 0, 0, 1), outlineWidth: 1 }, source: PolylineOutlineMaterial_default }, translucent: function(material4) { const uniforms = material4.uniforms; return uniforms.color.alpha < 1 || uniforms.outlineColor.alpha < 1; } }); Material.ElevationContourType = "ElevationContour"; Material._materialCache.addMaterial(Material.ElevationContourType, { fabric: { type: Material.ElevationContourType, uniforms: { spacing: 100, color: new Color_default(1, 0, 0, 1), width: 1 }, source: ElevationContourMaterial_default }, translucent: false }); Material.ElevationRampType = "ElevationRamp"; Material._materialCache.addMaterial(Material.ElevationRampType, { fabric: { type: Material.ElevationRampType, uniforms: { image: Material.DefaultImageId, minimumHeight: 0, maximumHeight: 1e4 }, source: ElevationRampMaterial_default }, translucent: false }); Material.SlopeRampMaterialType = "SlopeRamp"; Material._materialCache.addMaterial(Material.SlopeRampMaterialType, { fabric: { type: Material.SlopeRampMaterialType, uniforms: { image: Material.DefaultImageId }, source: SlopeRampMaterial_default }, translucent: false }); Material.AspectRampMaterialType = "AspectRamp"; Material._materialCache.addMaterial(Material.AspectRampMaterialType, { fabric: { type: Material.AspectRampMaterialType, uniforms: { image: Material.DefaultImageId }, source: AspectRampMaterial_default }, translucent: false }); Material.ElevationBandType = "ElevationBand"; Material._materialCache.addMaterial(Material.ElevationBandType, { fabric: { type: Material.ElevationBandType, uniforms: { heights: Material.DefaultImageId, colors: Material.DefaultImageId }, source: ElevationBandMaterial_default }, translucent: true }); Material.WaterMaskType = "WaterMask"; Material._materialCache.addMaterial(Material.WaterMaskType, { fabric: { type: Material.WaterMaskType, source: WaterMaskMaterial_default, uniforms: { waterColor: new Color_default(1, 1, 1, 1), landColor: new Color_default(0, 0, 0, 0) } }, translucent: false }); var Material_default = Material; // packages/engine/Source/Scene/MaterialAppearance.js function MaterialAppearance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const translucent = options.translucent ?? true; const closed = options.closed ?? false; const materialSupport = options.materialSupport ?? MaterialAppearance.MaterialSupport.TEXTURED; this.material = defined_default(options.material) ? options.material : Material_default.fromType(Material_default.ColorType); this.translucent = translucent; this._vertexShaderSource = options.vertexShaderSource ?? materialSupport.vertexShaderSource; this._fragmentShaderSource = options.fragmentShaderSource ?? materialSupport.fragmentShaderSource; this._renderState = Appearance_default.getDefaultRenderState( translucent, closed, options.renderState ); this._closed = closed; this._materialSupport = materialSupport; this._vertexFormat = materialSupport.vertexFormat; this._flat = options.flat ?? false; this._faceForward = options.faceForward ?? !closed; } Object.defineProperties(MaterialAppearance.prototype, { /** * The GLSL source code for the vertex shader. * * @memberof MaterialAppearance.prototype * * @type {string} * @readonly */ vertexShaderSource: { get: function() { return this._vertexShaderSource; } }, /** * The GLSL source code for the fragment shader. The full fragment shader * source is built procedurally taking into account {@link MaterialAppearance#material}, * {@link MaterialAppearance#flat}, and {@link MaterialAppearance#faceForward}. * Use {@link MaterialAppearance#getFragmentShaderSource} to get the full source. * * @memberof MaterialAppearance.prototype * * @type {string} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, /** * The WebGL fixed-function state to use when rendering the geometry. *

* The render state can be explicitly defined when constructing a {@link MaterialAppearance} * instance, or it is set implicitly via {@link MaterialAppearance#translucent} * and {@link MaterialAppearance#closed}. *

* * @memberof MaterialAppearance.prototype * * @type {object} * @readonly */ renderState: { get: function() { return this._renderState; } }, /** * When true, the geometry is expected to be closed so * {@link MaterialAppearance#renderState} has backface culling enabled. * If the viewer enters the geometry, it will not be visible. * * @memberof MaterialAppearance.prototype * * @type {boolean} * @readonly * * @default false */ closed: { get: function() { return this._closed; } }, /** * The type of materials supported by this instance. This impacts the required * {@link VertexFormat} and the complexity of the vertex and fragment shaders. * * @memberof MaterialAppearance.prototype * * @type {MaterialAppearance.MaterialSupportType} * @readonly * * @default {@link MaterialAppearance.MaterialSupport.TEXTURED} */ materialSupport: { get: function() { return this._materialSupport; } }, /** * The {@link VertexFormat} that this appearance instance is compatible with. * A geometry can have more vertex attributes and still be compatible - at a * potential performance cost - but it can't have less. * * @memberof MaterialAppearance.prototype * * @type VertexFormat * @readonly * * @default {@link MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat} */ vertexFormat: { get: function() { return this._vertexFormat; } }, /** * When true, flat shading is used in the fragment shader, * which means lighting is not taking into account. * * @memberof MaterialAppearance.prototype * * @type {boolean} * @readonly * * @default false */ flat: { get: function() { return this._flat; } }, /** * When true, the fragment shader flips the surface normal * as needed to ensure that the normal faces the viewer to avoid * dark spots. This is useful when both sides of a geometry should be * shaded like {@link WallGeometry}. * * @memberof MaterialAppearance.prototype * * @type {boolean} * @readonly * * @default true */ faceForward: { get: function() { return this._faceForward; } } }); MaterialAppearance.prototype.getFragmentShaderSource = Appearance_default.prototype.getFragmentShaderSource; MaterialAppearance.prototype.isTranslucent = Appearance_default.prototype.isTranslucent; MaterialAppearance.prototype.getRenderState = Appearance_default.prototype.getRenderState; MaterialAppearance.MaterialSupport = { /** * Only basic materials, which require just position and * normal vertex attributes, are supported. * * @type {MaterialAppearance.MaterialSupportType} * @constant */ BASIC: Object.freeze({ vertexFormat: VertexFormat_default.POSITION_AND_NORMAL, vertexShaderSource: BasicMaterialAppearanceVS_default, fragmentShaderSource: BasicMaterialAppearanceFS_default }), /** * Materials with textures, which require position, * normal, and st vertex attributes, * are supported. The vast majority of materials fall into this category. * * @type {MaterialAppearance.MaterialSupportType} * @constant */ TEXTURED: Object.freeze({ vertexFormat: VertexFormat_default.POSITION_NORMAL_AND_ST, vertexShaderSource: TexturedMaterialAppearanceVS_default, fragmentShaderSource: TexturedMaterialAppearanceFS_default }), /** * All materials, including those that work in tangent space, are supported. * This requires position, normal, st, * tangent, and bitangent vertex attributes. * * @type {MaterialAppearance.MaterialSupportType} * @constant */ ALL: Object.freeze({ vertexFormat: VertexFormat_default.ALL, vertexShaderSource: AllMaterialAppearanceVS_default, fragmentShaderSource: AllMaterialAppearanceFS_default }) }; var MaterialAppearance_default = MaterialAppearance; // packages/engine/Source/Scene/PerInstanceColorAppearance.js var import_InlineWorkers353 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Appearances/PerInstanceColorAppearanceFS.js var import_InlineWorkers349 = __toESM(require_InlineWorkers(), 1); var PerInstanceColorAppearanceFS_default = "in vec3 v_positionEC;\nin vec3 v_normalEC;\nin vec4 v_color;\n\nvoid main()\n{\n vec3 positionToEyeEC = -v_positionEC;\n\n vec3 normalEC = normalize(v_normalEC);\n#ifdef FACE_FORWARD\n normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n#endif\n\n vec4 color = czm_gammaCorrect(v_color);\n\n czm_materialInput materialInput;\n materialInput.normalEC = normalEC;\n materialInput.positionToEyeEC = positionToEyeEC;\n czm_material material = czm_getDefaultMaterial(materialInput);\n material.diffuse = color.rgb;\n material.alpha = color.a;\n\n out_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n}\n"; // packages/engine/Source/Shaders/Appearances/PerInstanceColorAppearanceVS.js var import_InlineWorkers350 = __toESM(require_InlineWorkers(), 1); var PerInstanceColorAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 normal;\nin vec4 color;\nin float batchId;\n\nout vec3 v_positionEC;\nout vec3 v_normalEC;\nout vec4 v_color;\n\nvoid main()\n{\n vec4 p = czm_computePosition();\n\n v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates\n v_normalEC = czm_normal * normal; // normal in eye coordinates\n v_color = color;\n\n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"; // packages/engine/Source/Shaders/Appearances/PerInstanceFlatColorAppearanceFS.js var import_InlineWorkers351 = __toESM(require_InlineWorkers(), 1); var PerInstanceFlatColorAppearanceFS_default = "in vec4 v_color;\n\nvoid main()\n{\n out_FragColor = czm_gammaCorrect(v_color);\n}\n"; // packages/engine/Source/Shaders/Appearances/PerInstanceFlatColorAppearanceVS.js var import_InlineWorkers352 = __toESM(require_InlineWorkers(), 1); var PerInstanceFlatColorAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec4 color;\nin float batchId;\n\nout vec4 v_color;\n\nvoid main()\n{\n vec4 p = czm_computePosition();\n\n v_color = color;\n\n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n}\n"; // packages/engine/Source/Scene/PerInstanceColorAppearance.js function PerInstanceColorAppearance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const translucent = options.translucent ?? true; const closed = options.closed ?? false; const flat = options.flat ?? false; const vs = flat ? PerInstanceFlatColorAppearanceVS_default : PerInstanceColorAppearanceVS_default; const fs = flat ? PerInstanceFlatColorAppearanceFS_default : PerInstanceColorAppearanceFS_default; const vertexFormat = flat ? PerInstanceColorAppearance.FLAT_VERTEX_FORMAT : PerInstanceColorAppearance.VERTEX_FORMAT; this.material = void 0; this.translucent = translucent; this._vertexShaderSource = options.vertexShaderSource ?? vs; this._fragmentShaderSource = options.fragmentShaderSource ?? fs; this._renderState = Appearance_default.getDefaultRenderState( translucent, closed, options.renderState ); this._closed = closed; this._vertexFormat = vertexFormat; this._flat = flat; this._faceForward = options.faceForward ?? !closed; } Object.defineProperties(PerInstanceColorAppearance.prototype, { /** * The GLSL source code for the vertex shader. * * @memberof PerInstanceColorAppearance.prototype * * @type {string} * @readonly */ vertexShaderSource: { get: function() { return this._vertexShaderSource; } }, /** * The GLSL source code for the fragment shader. * * @memberof PerInstanceColorAppearance.prototype * * @type {string} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, /** * The WebGL fixed-function state to use when rendering the geometry. *

* The render state can be explicitly defined when constructing a {@link PerInstanceColorAppearance} * instance, or it is set implicitly via {@link PerInstanceColorAppearance#translucent} * and {@link PerInstanceColorAppearance#closed}. *

* * @memberof PerInstanceColorAppearance.prototype * * @type {object} * @readonly */ renderState: { get: function() { return this._renderState; } }, /** * When true, the geometry is expected to be closed so * {@link PerInstanceColorAppearance#renderState} has backface culling enabled. * If the viewer enters the geometry, it will not be visible. * * @memberof PerInstanceColorAppearance.prototype * * @type {boolean} * @readonly * * @default false */ closed: { get: function() { return this._closed; } }, /** * The {@link VertexFormat} that this appearance instance is compatible with. * A geometry can have more vertex attributes and still be compatible - at a * potential performance cost - but it can't have less. * * @memberof PerInstanceColorAppearance.prototype * * @type VertexFormat * @readonly */ vertexFormat: { get: function() { return this._vertexFormat; } }, /** * When true, flat shading is used in the fragment shader, * which means lighting is not taking into account. * * @memberof PerInstanceColorAppearance.prototype * * @type {boolean} * @readonly * * @default false */ flat: { get: function() { return this._flat; } }, /** * When true, the fragment shader flips the surface normal * as needed to ensure that the normal faces the viewer to avoid * dark spots. This is useful when both sides of a geometry should be * shaded like {@link WallGeometry}. * * @memberof PerInstanceColorAppearance.prototype * * @type {boolean} * @readonly * * @default true */ faceForward: { get: function() { return this._faceForward; } } }); PerInstanceColorAppearance.VERTEX_FORMAT = VertexFormat_default.POSITION_AND_NORMAL; PerInstanceColorAppearance.FLAT_VERTEX_FORMAT = VertexFormat_default.POSITION_ONLY; PerInstanceColorAppearance.prototype.getFragmentShaderSource = Appearance_default.prototype.getFragmentShaderSource; PerInstanceColorAppearance.prototype.isTranslucent = Appearance_default.prototype.isTranslucent; PerInstanceColorAppearance.prototype.getRenderState = Appearance_default.prototype.getRenderState; var PerInstanceColorAppearance_default = PerInstanceColorAppearance; // packages/engine/Source/DataSources/ColorMaterialProperty.js var import_InlineWorkers354 = __toESM(require_InlineWorkers(), 1); function ColorMaterialProperty(color) { this._definitionChanged = new Event_default(); this._color = void 0; this._colorSubscription = void 0; this.color = color; } Object.defineProperties(ColorMaterialProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof ColorMaterialProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return Property_default.isConstant(this._color); } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof ColorMaterialProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the {@link Color} {@link Property}. * @memberof ColorMaterialProperty.prototype * @type {Property|undefined} * @default Color.WHITE */ color: createPropertyDescriptor_default("color") }); ColorMaterialProperty.prototype.getType = function(time) { return "Color"; }; var timeScratch = new JulianDate_default(); ColorMaterialProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch); } if (!defined_default(result)) { result = {}; } result.color = Property_default.getValueOrClonedDefault( this._color, time, Color_default.WHITE, result.color ); return result; }; ColorMaterialProperty.prototype.equals = function(other) { return this === other || // other instanceof ColorMaterialProperty && // Property_default.equals(this._color, other._color); }; var ColorMaterialProperty_default = ColorMaterialProperty; // packages/engine/Source/DataSources/DynamicGeometryUpdater.js var import_InlineWorkers381 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/GroundPrimitive.js var import_InlineWorkers379 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/ApproximateTerrainHeights.js var import_InlineWorkers356 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/GeographicTilingScheme.js var import_InlineWorkers355 = __toESM(require_InlineWorkers(), 1); var GeographicTilingScheme = class { /** * @param {object} [options] Object with the following properties: * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.default] The ellipsoid whose surface is being tiled. Defaults to * the default ellipsoid. * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the tiling scheme. * @param {number} [options.numberOfLevelZeroTilesX=2] The number of tiles in the X direction at level zero of * the tile tree. * @param {number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of * the tile tree. */ constructor(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._ellipsoid = options.ellipsoid ?? Ellipsoid_default.default; this._rectangle = options.rectangle ?? Rectangle_default.MAX_VALUE; this._projection = new GeographicProjection_default(this._ellipsoid); this._numberOfLevelZeroTilesX = options.numberOfLevelZeroTilesX ?? 2; this._numberOfLevelZeroTilesY = options.numberOfLevelZeroTilesY ?? 1; } /** * Gets the ellipsoid that is tiled by this tiling scheme. * @type {Ellipsoid} */ get ellipsoid() { return this._ellipsoid; } /** * Gets the rectangle, in radians, covered by this tiling scheme. * @type {Rectangle} */ get rectangle() { return this._rectangle; } /** * Gets the map projection used by this tiling scheme. * @type {MapProjection} */ get projection() { return this._projection; } /** * Gets the total number of tiles in the X direction at a specified level-of-detail. * * @param {number} level The level-of-detail. * @returns {number} The number of tiles in the X direction at the given level. */ getNumberOfXTilesAtLevel(level) { return this._numberOfLevelZeroTilesX << level; } /** * Gets the total number of tiles in the Y direction at a specified level-of-detail. * * @param {number} level The level-of-detail. * @returns {number} The number of tiles in the Y direction at the given level. */ getNumberOfYTilesAtLevel(level) { return this._numberOfLevelZeroTilesY << level; } /** * Transforms a rectangle specified in geodetic radians to the native coordinate system * of this tiling scheme. * * @param {Rectangle} rectangle The rectangle to transform. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result' * is undefined. */ rectangleToNativeRectangle(rectangle, result) { Check_default.defined("rectangle", rectangle); const west = Math_default.toDegrees(rectangle.west); const south = Math_default.toDegrees(rectangle.south); const east = Math_default.toDegrees(rectangle.east); const north = Math_default.toDegrees(rectangle.north); if (!defined_default(result)) { return new Rectangle_default(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates * of the tiling scheme. * * @param {number} x The integer x coordinate of the tile. * @param {number} y The integer y coordinate of the tile. * @param {number} level The tile level-of-detail. Zero is the least detailed. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle * if 'result' is undefined. */ tileXYToNativeRectangle(x, y, level, result) { const rectangleRadians = this.tileXYToRectangle(x, y, level, result); rectangleRadians.west = Math_default.toDegrees(rectangleRadians.west); rectangleRadians.south = Math_default.toDegrees(rectangleRadians.south); rectangleRadians.east = Math_default.toDegrees(rectangleRadians.east); rectangleRadians.north = Math_default.toDegrees(rectangleRadians.north); return rectangleRadians; } /** * Converts tile x, y coordinates and level to a cartographic rectangle in radians. * * @param {number} x The integer x coordinate of the tile. * @param {number} y The integer y coordinate of the tile. * @param {number} level The tile level-of-detail. Zero is the least detailed. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle * if 'result' is undefined. */ tileXYToRectangle(x, y, level, result) { const rectangle = this._rectangle; const xTiles = this.getNumberOfXTilesAtLevel(level); const yTiles = this.getNumberOfYTilesAtLevel(level); const xTileWidth = rectangle.width / xTiles; const west = x * xTileWidth + rectangle.west; const east = (x + 1) * xTileWidth + rectangle.west; const yTileHeight = rectangle.height / yTiles; const north = rectangle.north - y * yTileHeight; const south = rectangle.north - (y + 1) * yTileHeight; if (!defined_default(result)) { result = new Rectangle_default(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; } /** * Calculates the tile x, y coordinates of the tile containing * a given cartographic position. * * @param {Cartographic} position The position. * @param {number} level The tile level-of-detail. Zero is the least detailed. * @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates * if 'result' is undefined. */ positionToTileXY(position, level, result) { const rectangle = this._rectangle; if (!Rectangle_default.contains(rectangle, position)) { return void 0; } const xTiles = this.getNumberOfXTilesAtLevel(level); const yTiles = this.getNumberOfYTilesAtLevel(level); const xTileWidth = rectangle.width / xTiles; const yTileHeight = rectangle.height / yTiles; let longitude = position.longitude; if (rectangle.east < rectangle.west) { longitude += Math_default.TWO_PI; } let xTileCoordinate = (longitude - rectangle.west) / xTileWidth | 0; if (xTileCoordinate >= xTiles) { xTileCoordinate = xTiles - 1; } let yTileCoordinate = (rectangle.north - position.latitude) / yTileHeight | 0; if (yTileCoordinate >= yTiles) { yTileCoordinate = yTiles - 1; } if (!defined_default(result)) { return new Cartesian2_default(xTileCoordinate, yTileCoordinate); } result.x = xTileCoordinate; result.y = yTileCoordinate; return result; } }; var GeographicTilingScheme_default = GeographicTilingScheme; // packages/engine/Source/Core/ApproximateTerrainHeights.js var scratchDiagonalCartesianNE = new Cartesian3_default(); var scratchDiagonalCartesianSW = new Cartesian3_default(); var scratchDiagonalCartographic = new Cartographic_default(); var scratchCenterCartesian = new Cartesian3_default(); var scratchSurfaceCartesian = new Cartesian3_default(); var scratchBoundingSphere = new BoundingSphere_default(); var tilingScheme = new GeographicTilingScheme_default(); var scratchCorners = [ new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default() ]; var scratchTileXY = new Cartesian2_default(); var ApproximateTerrainHeights = {}; ApproximateTerrainHeights.initialize = function() { let initPromise = ApproximateTerrainHeights._initPromise; if (defined_default(initPromise)) { return initPromise; } initPromise = Resource_default.fetchJson( buildModuleUrl_default("Assets/approximateTerrainHeights.json") ).then(function(json) { ApproximateTerrainHeights._terrainHeights = json; }); ApproximateTerrainHeights._initPromise = initPromise; return initPromise; }; ApproximateTerrainHeights.getMinimumMaximumHeights = function(rectangle, ellipsoid) { Check_default.defined("rectangle", rectangle); if (!defined_default(ApproximateTerrainHeights._terrainHeights)) { throw new DeveloperError_default( "You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function" ); } ellipsoid = ellipsoid ?? Ellipsoid_default.default; const xyLevel = getTileXYLevel(rectangle); let minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight; let maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight; if (defined_default(xyLevel)) { const key = `${xyLevel.level}-${xyLevel.x}-${xyLevel.y}`; const heights = ApproximateTerrainHeights._terrainHeights[key]; if (defined_default(heights)) { minTerrainHeight = heights[0]; maxTerrainHeight = heights[1]; } ellipsoid.cartographicToCartesian( Rectangle_default.northeast(rectangle, scratchDiagonalCartographic), scratchDiagonalCartesianNE ); ellipsoid.cartographicToCartesian( Rectangle_default.southwest(rectangle, scratchDiagonalCartographic), scratchDiagonalCartesianSW ); Cartesian3_default.midpoint( scratchDiagonalCartesianSW, scratchDiagonalCartesianNE, scratchCenterCartesian ); const surfacePosition = ellipsoid.scaleToGeodeticSurface( scratchCenterCartesian, scratchSurfaceCartesian ); if (defined_default(surfacePosition)) { const distance2 = Cartesian3_default.distance( scratchCenterCartesian, surfacePosition ); minTerrainHeight = Math.min(minTerrainHeight, -distance2); } else { minTerrainHeight = ApproximateTerrainHeights._defaultMinTerrainHeight; } } minTerrainHeight = Math.max( ApproximateTerrainHeights._defaultMinTerrainHeight, minTerrainHeight ); return { minimumTerrainHeight: minTerrainHeight, maximumTerrainHeight: maxTerrainHeight }; }; ApproximateTerrainHeights.getBoundingSphere = function(rectangle, ellipsoid) { Check_default.defined("rectangle", rectangle); if (!defined_default(ApproximateTerrainHeights._terrainHeights)) { throw new DeveloperError_default( "You must call ApproximateTerrainHeights.initialize and wait for the promise to resolve before using this function" ); } ellipsoid = ellipsoid ?? Ellipsoid_default.default; const xyLevel = getTileXYLevel(rectangle); let maxTerrainHeight = ApproximateTerrainHeights._defaultMaxTerrainHeight; if (defined_default(xyLevel)) { const key = `${xyLevel.level}-${xyLevel.x}-${xyLevel.y}`; const heights = ApproximateTerrainHeights._terrainHeights[key]; if (defined_default(heights)) { maxTerrainHeight = heights[1]; } } const result = BoundingSphere_default.fromRectangle3D(rectangle, ellipsoid, 0); BoundingSphere_default.fromRectangle3D( rectangle, ellipsoid, maxTerrainHeight, scratchBoundingSphere ); return BoundingSphere_default.union(result, scratchBoundingSphere, result); }; function getTileXYLevel(rectangle) { Cartographic_default.fromRadians( rectangle.east, rectangle.north, 0, scratchCorners[0] ); Cartographic_default.fromRadians( rectangle.west, rectangle.north, 0, scratchCorners[1] ); Cartographic_default.fromRadians( rectangle.east, rectangle.south, 0, scratchCorners[2] ); Cartographic_default.fromRadians( rectangle.west, rectangle.south, 0, scratchCorners[3] ); let lastLevelX = 0, lastLevelY = 0; let currentX = 0, currentY = 0; const maxLevel = ApproximateTerrainHeights._terrainHeightsMaxLevel; let i; for (i = 0; i <= maxLevel; ++i) { let failed = false; for (let j = 0; j < 4; ++j) { const corner = scratchCorners[j]; tilingScheme.positionToTileXY(corner, i, scratchTileXY); if (j === 0) { currentX = scratchTileXY.x; currentY = scratchTileXY.y; } else if (currentX !== scratchTileXY.x || currentY !== scratchTileXY.y) { failed = true; break; } } if (failed) { break; } lastLevelX = currentX; lastLevelY = currentY; } if (i === 0) { return void 0; } return { x: lastLevelX, y: lastLevelY, level: i > maxLevel ? maxLevel : i - 1 }; } ApproximateTerrainHeights._terrainHeightsMaxLevel = 6; ApproximateTerrainHeights._defaultMaxTerrainHeight = 9e3; ApproximateTerrainHeights._defaultMinTerrainHeight = -1e5; ApproximateTerrainHeights._terrainHeights = void 0; ApproximateTerrainHeights._initPromise = void 0; Object.defineProperties(ApproximateTerrainHeights, { /** * Determines if the terrain heights are initialized and ready to use. To initialize the terrain heights, * call {@link ApproximateTerrainHeights#initialize} and wait for the returned promise to resolve. * @type {boolean} * @readonly * @memberof ApproximateTerrainHeights */ initialized: { get: function() { return defined_default(ApproximateTerrainHeights._terrainHeights); } } }); var ApproximateTerrainHeights_default = ApproximateTerrainHeights; // packages/engine/Source/Core/OrientedBoundingBox.js var import_InlineWorkers359 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/EllipsoidTangentPlane.js var import_InlineWorkers358 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/AxisAlignedBoundingBox.js var import_InlineWorkers357 = __toESM(require_InlineWorkers(), 1); function AxisAlignedBoundingBox(minimum, maximum, center) { this.minimum = Cartesian3_default.clone(minimum ?? Cartesian3_default.ZERO); this.maximum = Cartesian3_default.clone(maximum ?? Cartesian3_default.ZERO); if (!defined_default(center)) { center = Cartesian3_default.midpoint(this.minimum, this.maximum, new Cartesian3_default()); } else { center = Cartesian3_default.clone(center); } this.center = center; } AxisAlignedBoundingBox.fromCorners = function(minimum, maximum, result) { Check_default.defined("minimum", minimum); Check_default.defined("maximum", maximum); if (!defined_default(result)) { result = new AxisAlignedBoundingBox(); } result.minimum = Cartesian3_default.clone(minimum, result.minimum); result.maximum = Cartesian3_default.clone(maximum, result.maximum); result.center = Cartesian3_default.midpoint(minimum, maximum, result.center); return result; }; AxisAlignedBoundingBox.fromPoints = function(positions, result) { if (!defined_default(result)) { result = new AxisAlignedBoundingBox(); } if (!defined_default(positions) || positions.length === 0) { result.minimum = Cartesian3_default.clone(Cartesian3_default.ZERO, result.minimum); result.maximum = Cartesian3_default.clone(Cartesian3_default.ZERO, result.maximum); result.center = Cartesian3_default.clone(Cartesian3_default.ZERO, result.center); return result; } let minimumX = positions[0].x; let minimumY = positions[0].y; let minimumZ = positions[0].z; let maximumX = positions[0].x; let maximumY = positions[0].y; let maximumZ = positions[0].z; const length2 = positions.length; for (let i = 1; i < length2; i++) { const p = positions[i]; const x = p.x; const y = p.y; const z2 = p.z; minimumX = Math.min(x, minimumX); maximumX = Math.max(x, maximumX); minimumY = Math.min(y, minimumY); maximumY = Math.max(y, maximumY); minimumZ = Math.min(z2, minimumZ); maximumZ = Math.max(z2, maximumZ); } const minimum = result.minimum; minimum.x = minimumX; minimum.y = minimumY; minimum.z = minimumZ; const maximum = result.maximum; maximum.x = maximumX; maximum.y = maximumY; maximum.z = maximumZ; result.center = Cartesian3_default.midpoint(minimum, maximum, result.center); return result; }; AxisAlignedBoundingBox.clone = function(box, result) { if (!defined_default(box)) { return void 0; } if (!defined_default(result)) { return new AxisAlignedBoundingBox(box.minimum, box.maximum, box.center); } result.minimum = Cartesian3_default.clone(box.minimum, result.minimum); result.maximum = Cartesian3_default.clone(box.maximum, result.maximum); result.center = Cartesian3_default.clone(box.center, result.center); return result; }; AxisAlignedBoundingBox.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && Cartesian3_default.equals(left.center, right.center) && Cartesian3_default.equals(left.minimum, right.minimum) && Cartesian3_default.equals(left.maximum, right.maximum); }; var intersectScratch = new Cartesian3_default(); AxisAlignedBoundingBox.intersectPlane = function(box, plane) { Check_default.defined("box", box); Check_default.defined("plane", plane); intersectScratch = Cartesian3_default.subtract( box.maximum, box.minimum, intersectScratch ); const h = Cartesian3_default.multiplyByScalar( intersectScratch, 0.5, intersectScratch ); const normal2 = plane.normal; const e = h.x * Math.abs(normal2.x) + h.y * Math.abs(normal2.y) + h.z * Math.abs(normal2.z); const s2 = Cartesian3_default.dot(box.center, normal2) + plane.distance; if (s2 - e > 0) { return Intersect_default.INSIDE; } if (s2 + e < 0) { return Intersect_default.OUTSIDE; } return Intersect_default.INTERSECTING; }; AxisAlignedBoundingBox.intersectAxisAlignedBoundingBox = function(box, other) { Check_default.defined("box", box); Check_default.defined("other", other); return box.minimum.x <= other.maximum.x && box.maximum.x >= other.minimum.x && box.minimum.y <= other.maximum.y && box.maximum.y >= other.minimum.y && box.minimum.z <= other.maximum.z && box.maximum.z >= other.minimum.z; }; AxisAlignedBoundingBox.prototype.clone = function(result) { return AxisAlignedBoundingBox.clone(this, result); }; AxisAlignedBoundingBox.prototype.intersectPlane = function(plane) { return AxisAlignedBoundingBox.intersectPlane(this, plane); }; AxisAlignedBoundingBox.prototype.intersectAxisAlignedBoundingBox = function(other) { return AxisAlignedBoundingBox.intersectAxisAlignedBoundingBox(this, other); }; AxisAlignedBoundingBox.prototype.equals = function(right) { return AxisAlignedBoundingBox.equals(this, right); }; var AxisAlignedBoundingBox_default = AxisAlignedBoundingBox; // packages/engine/Source/Core/EllipsoidTangentPlane.js var scratchCart4 = new Cartesian4_default(); function EllipsoidTangentPlane(origin, ellipsoid) { Check_default.defined("origin", origin); ellipsoid = ellipsoid ?? Ellipsoid_default.default; origin = ellipsoid.scaleToGeodeticSurface(origin); if (!defined_default(origin)) { throw new DeveloperError_default( "origin must not be at the center of the ellipsoid." ); } const eastNorthUp = Transforms_default.eastNorthUpToFixedFrame(origin, ellipsoid); this._ellipsoid = ellipsoid; this._origin = origin; this._xAxis = Cartesian3_default.fromCartesian4( Matrix4_default.getColumn(eastNorthUp, 0, scratchCart4) ); this._yAxis = Cartesian3_default.fromCartesian4( Matrix4_default.getColumn(eastNorthUp, 1, scratchCart4) ); const normal2 = Cartesian3_default.fromCartesian4( Matrix4_default.getColumn(eastNorthUp, 2, scratchCart4) ); this._plane = Plane_default.fromPointNormal(origin, normal2); } Object.defineProperties(EllipsoidTangentPlane.prototype, { /** * Gets the ellipsoid. * @memberof EllipsoidTangentPlane.prototype * @type {Ellipsoid} */ ellipsoid: { get: function() { return this._ellipsoid; } }, /** * Gets the origin. * @memberof EllipsoidTangentPlane.prototype * @type {Cartesian3} */ origin: { get: function() { return this._origin; } }, /** * Gets the plane which is tangent to the ellipsoid. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Plane} */ plane: { get: function() { return this._plane; } }, /** * Gets the local X-axis (east) of the tangent plane. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ xAxis: { get: function() { return this._xAxis; } }, /** * Gets the local Y-axis (north) of the tangent plane. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ yAxis: { get: function() { return this._yAxis; } }, /** * Gets the local Z-axis (up) of the tangent plane. * @memberof EllipsoidTangentPlane.prototype * @readonly * @type {Cartesian3} */ zAxis: { get: function() { return this._plane.normal; } } }); var tmp = new AxisAlignedBoundingBox_default(); EllipsoidTangentPlane.fromPoints = function(cartesians, ellipsoid) { Check_default.defined("cartesians", cartesians); const box = AxisAlignedBoundingBox_default.fromPoints(cartesians, tmp); return new EllipsoidTangentPlane(box.center, ellipsoid); }; var scratchProjectPointOntoPlaneRay = new Ray_default(); var scratchProjectPointOntoPlaneCartesian3 = new Cartesian3_default(); EllipsoidTangentPlane.prototype.projectPointOntoPlane = function(cartesian11, result) { Check_default.defined("cartesian", cartesian11); const ray = scratchProjectPointOntoPlaneRay; ray.origin = cartesian11; Cartesian3_default.normalize(cartesian11, ray.direction); let intersectionPoint = IntersectionTests_default.rayPlane( ray, this._plane, scratchProjectPointOntoPlaneCartesian3 ); if (!defined_default(intersectionPoint)) { Cartesian3_default.negate(ray.direction, ray.direction); intersectionPoint = IntersectionTests_default.rayPlane( ray, this._plane, scratchProjectPointOntoPlaneCartesian3 ); } if (defined_default(intersectionPoint)) { const v3 = Cartesian3_default.subtract( intersectionPoint, this._origin, intersectionPoint ); const x = Cartesian3_default.dot(this._xAxis, v3); const y = Cartesian3_default.dot(this._yAxis, v3); if (!defined_default(result)) { return new Cartesian2_default(x, y); } result.x = x; result.y = y; return result; } return void 0; }; EllipsoidTangentPlane.prototype.projectPointsOntoPlane = function(cartesians, result) { Check_default.defined("cartesians", cartesians); if (!defined_default(result)) { result = []; } let count = 0; const length2 = cartesians.length; for (let i = 0; i < length2; i++) { const p = this.projectPointOntoPlane(cartesians[i], result[count]); if (defined_default(p)) { result[count] = p; count++; } } result.length = count; return result; }; EllipsoidTangentPlane.prototype.projectPointToNearestOnPlane = function(cartesian11, result) { Check_default.defined("cartesian", cartesian11); if (!defined_default(result)) { result = new Cartesian2_default(); } const ray = scratchProjectPointOntoPlaneRay; ray.origin = cartesian11; Cartesian3_default.clone(this._plane.normal, ray.direction); let intersectionPoint = IntersectionTests_default.rayPlane( ray, this._plane, scratchProjectPointOntoPlaneCartesian3 ); if (!defined_default(intersectionPoint)) { Cartesian3_default.negate(ray.direction, ray.direction); intersectionPoint = IntersectionTests_default.rayPlane( ray, this._plane, scratchProjectPointOntoPlaneCartesian3 ); } const v3 = Cartesian3_default.subtract( intersectionPoint, this._origin, intersectionPoint ); const x = Cartesian3_default.dot(this._xAxis, v3); const y = Cartesian3_default.dot(this._yAxis, v3); result.x = x; result.y = y; return result; }; EllipsoidTangentPlane.prototype.projectPointsToNearestOnPlane = function(cartesians, result) { Check_default.defined("cartesians", cartesians); if (!defined_default(result)) { result = []; } const length2 = cartesians.length; result.length = length2; for (let i = 0; i < length2; i++) { result[i] = this.projectPointToNearestOnPlane(cartesians[i], result[i]); } return result; }; var projectPointsOntoEllipsoidScratch = new Cartesian3_default(); EllipsoidTangentPlane.prototype.projectPointOntoEllipsoid = function(cartesian11, result) { Check_default.defined("cartesian", cartesian11); if (!defined_default(result)) { result = new Cartesian3_default(); } const ellipsoid = this._ellipsoid; const origin = this._origin; const xAxis = this._xAxis; const yAxis = this._yAxis; const tmp2 = projectPointsOntoEllipsoidScratch; Cartesian3_default.multiplyByScalar(xAxis, cartesian11.x, tmp2); result = Cartesian3_default.add(origin, tmp2, result); Cartesian3_default.multiplyByScalar(yAxis, cartesian11.y, tmp2); Cartesian3_default.add(result, tmp2, result); ellipsoid.scaleToGeocentricSurface(result, result); return result; }; EllipsoidTangentPlane.prototype.projectPointsOntoEllipsoid = function(cartesians, result) { Check_default.defined("cartesians", cartesians); const length2 = cartesians.length; if (!defined_default(result)) { result = new Array(length2); } else { result.length = length2; } for (let i = 0; i < length2; ++i) { result[i] = this.projectPointOntoEllipsoid(cartesians[i], result[i]); } return result; }; var EllipsoidTangentPlane_default = EllipsoidTangentPlane; // packages/engine/Source/Core/OrientedBoundingBox.js function OrientedBoundingBox(center, halfAxes) { this.center = Cartesian3_default.clone(center ?? Cartesian3_default.ZERO); this.halfAxes = Matrix3_default.clone(halfAxes ?? Matrix3_default.ZERO); } OrientedBoundingBox.packedLength = Cartesian3_default.packedLength + Matrix3_default.packedLength; OrientedBoundingBox.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); startingIndex = startingIndex ?? 0; Cartesian3_default.pack(value.center, array, startingIndex); Matrix3_default.pack(value.halfAxes, array, startingIndex + Cartesian3_default.packedLength); return array; }; OrientedBoundingBox.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); startingIndex = startingIndex ?? 0; if (!defined_default(result)) { result = new OrientedBoundingBox(); } Cartesian3_default.unpack(array, startingIndex, result.center); Matrix3_default.unpack( array, startingIndex + Cartesian3_default.packedLength, result.halfAxes ); return result; }; var scratchCartesian12 = new Cartesian3_default(); var scratchCartesian23 = new Cartesian3_default(); var scratchCartesian34 = new Cartesian3_default(); var scratchCartesian4 = new Cartesian3_default(); var scratchCartesian5 = new Cartesian3_default(); var scratchCartesian6 = new Cartesian3_default(); var scratchCovarianceResult = new Matrix3_default(); var scratchEigenResult = { unitary: new Matrix3_default(), diagonal: new Matrix3_default() }; OrientedBoundingBox.fromPoints = function(positions, result) { if (!defined_default(result)) { result = new OrientedBoundingBox(); } if (!defined_default(positions) || positions.length === 0) { result.halfAxes = Matrix3_default.ZERO; result.center = Cartesian3_default.ZERO; return result; } let i; const length2 = positions.length; const meanPoint = Cartesian3_default.clone(positions[0], scratchCartesian12); for (i = 1; i < length2; i++) { Cartesian3_default.add(meanPoint, positions[i], meanPoint); } const invLength = 1 / length2; Cartesian3_default.multiplyByScalar(meanPoint, invLength, meanPoint); let exx = 0; let exy = 0; let exz = 0; let eyy = 0; let eyz = 0; let ezz = 0; let p; for (i = 0; i < length2; i++) { p = Cartesian3_default.subtract(positions[i], meanPoint, scratchCartesian23); exx += p.x * p.x; exy += p.x * p.y; exz += p.x * p.z; eyy += p.y * p.y; eyz += p.y * p.z; ezz += p.z * p.z; } exx *= invLength; exy *= invLength; exz *= invLength; eyy *= invLength; eyz *= invLength; ezz *= invLength; const covarianceMatrix = scratchCovarianceResult; covarianceMatrix[0] = exx; covarianceMatrix[1] = exy; covarianceMatrix[2] = exz; covarianceMatrix[3] = exy; covarianceMatrix[4] = eyy; covarianceMatrix[5] = eyz; covarianceMatrix[6] = exz; covarianceMatrix[7] = eyz; covarianceMatrix[8] = ezz; const eigenDecomposition = Matrix3_default.computeEigenDecomposition( covarianceMatrix, scratchEigenResult ); const rotation = Matrix3_default.clone(eigenDecomposition.unitary, result.halfAxes); let v12 = Matrix3_default.getColumn(rotation, 0, scratchCartesian4); let v22 = Matrix3_default.getColumn(rotation, 1, scratchCartesian5); let v3 = Matrix3_default.getColumn(rotation, 2, scratchCartesian6); let u12 = -Number.MAX_VALUE; let u22 = -Number.MAX_VALUE; let u32 = -Number.MAX_VALUE; let l1 = Number.MAX_VALUE; let l2 = Number.MAX_VALUE; let l3 = Number.MAX_VALUE; for (i = 0; i < length2; i++) { p = positions[i]; u12 = Math.max(Cartesian3_default.dot(v12, p), u12); u22 = Math.max(Cartesian3_default.dot(v22, p), u22); u32 = Math.max(Cartesian3_default.dot(v3, p), u32); l1 = Math.min(Cartesian3_default.dot(v12, p), l1); l2 = Math.min(Cartesian3_default.dot(v22, p), l2); l3 = Math.min(Cartesian3_default.dot(v3, p), l3); } v12 = Cartesian3_default.multiplyByScalar(v12, 0.5 * (l1 + u12), v12); v22 = Cartesian3_default.multiplyByScalar(v22, 0.5 * (l2 + u22), v22); v3 = Cartesian3_default.multiplyByScalar(v3, 0.5 * (l3 + u32), v3); const center = Cartesian3_default.add(v12, v22, result.center); Cartesian3_default.add(center, v3, center); const scale = scratchCartesian34; scale.x = u12 - l1; scale.y = u22 - l2; scale.z = u32 - l3; Cartesian3_default.multiplyByScalar(scale, 0.5, scale); Matrix3_default.multiplyByScale(result.halfAxes, scale, result.halfAxes); return result; }; var scratchOffset = new Cartesian3_default(); var scratchScale2 = new Cartesian3_default(); function fromPlaneExtents(planeOrigin, planeXAxis, planeYAxis, planeZAxis, minimumX, maximumX, minimumY, maximumY, minimumZ, maximumZ, result) { if (!defined_default(minimumX) || !defined_default(maximumX) || !defined_default(minimumY) || !defined_default(maximumY) || !defined_default(minimumZ) || !defined_default(maximumZ)) { throw new DeveloperError_default( "all extents (minimum/maximum X/Y/Z) are required." ); } if (!defined_default(result)) { result = new OrientedBoundingBox(); } const halfAxes = result.halfAxes; Matrix3_default.setColumn(halfAxes, 0, planeXAxis, halfAxes); Matrix3_default.setColumn(halfAxes, 1, planeYAxis, halfAxes); Matrix3_default.setColumn(halfAxes, 2, planeZAxis, halfAxes); let centerOffset = scratchOffset; centerOffset.x = (minimumX + maximumX) / 2; centerOffset.y = (minimumY + maximumY) / 2; centerOffset.z = (minimumZ + maximumZ) / 2; const scale = scratchScale2; scale.x = (maximumX - minimumX) / 2; scale.y = (maximumY - minimumY) / 2; scale.z = (maximumZ - minimumZ) / 2; const center = result.center; centerOffset = Matrix3_default.multiplyByVector(halfAxes, centerOffset, centerOffset); Cartesian3_default.add(planeOrigin, centerOffset, center); Matrix3_default.multiplyByScale(halfAxes, scale, halfAxes); return result; } var scratchRectangleCenterCartographic = new Cartographic_default(); var scratchRectangleCenter = new Cartesian3_default(); var scratchPerimeterCartographicNC = new Cartographic_default(); var scratchPerimeterCartographicNW = new Cartographic_default(); var scratchPerimeterCartographicCW = new Cartographic_default(); var scratchPerimeterCartographicSW = new Cartographic_default(); var scratchPerimeterCartographicSC = new Cartographic_default(); var scratchPerimeterCartesianNC = new Cartesian3_default(); var scratchPerimeterCartesianNW = new Cartesian3_default(); var scratchPerimeterCartesianCW = new Cartesian3_default(); var scratchPerimeterCartesianSW = new Cartesian3_default(); var scratchPerimeterCartesianSC = new Cartesian3_default(); var scratchPerimeterProjectedNC = new Cartesian2_default(); var scratchPerimeterProjectedNW = new Cartesian2_default(); var scratchPerimeterProjectedCW = new Cartesian2_default(); var scratchPerimeterProjectedSW = new Cartesian2_default(); var scratchPerimeterProjectedSC = new Cartesian2_default(); var scratchPlaneOrigin = new Cartesian3_default(); var scratchPlaneNormal2 = new Cartesian3_default(); var scratchPlaneXAxis = new Cartesian3_default(); var scratchHorizonCartesian = new Cartesian3_default(); var scratchHorizonProjected = new Cartesian2_default(); var scratchMaxY = new Cartesian3_default(); var scratchMinY = new Cartesian3_default(); var scratchZ = new Cartesian3_default(); var scratchPlane2 = new Plane_default(Cartesian3_default.UNIT_X, 0); OrientedBoundingBox.fromRectangle = function(rectangle, minimumHeight, maximumHeight, ellipsoid, result) { if (!defined_default(rectangle)) { throw new DeveloperError_default("rectangle is required"); } if (rectangle.width < 0 || rectangle.width > Math_default.TWO_PI) { throw new DeveloperError_default("Rectangle width must be between 0 and 2 * pi"); } if (rectangle.height < 0 || rectangle.height > Math_default.PI) { throw new DeveloperError_default("Rectangle height must be between 0 and pi"); } if (defined_default(ellipsoid) && !Math_default.equalsEpsilon( ellipsoid.radii.x, ellipsoid.radii.y, Math_default.EPSILON15 )) { throw new DeveloperError_default( "Ellipsoid must be an ellipsoid of revolution (radii.x == radii.y)" ); } minimumHeight = minimumHeight ?? 0; maximumHeight = maximumHeight ?? 0; ellipsoid = ellipsoid ?? Ellipsoid_default.default; let minX, maxX, minY, maxY, minZ, maxZ, plane; if (rectangle.width <= Math_default.PI) { const tangentPointCartographic = Rectangle_default.center( rectangle, scratchRectangleCenterCartographic ); const tangentPoint = ellipsoid.cartographicToCartesian( tangentPointCartographic, scratchRectangleCenter ); const tangentPlane = new EllipsoidTangentPlane_default(tangentPoint, ellipsoid); plane = tangentPlane.plane; const lonCenter = tangentPointCartographic.longitude; const latCenter = rectangle.south < 0 && rectangle.north > 0 ? 0 : tangentPointCartographic.latitude; const perimeterCartographicNC = Cartographic_default.fromRadians( lonCenter, rectangle.north, maximumHeight, scratchPerimeterCartographicNC ); const perimeterCartographicNW = Cartographic_default.fromRadians( rectangle.west, rectangle.north, maximumHeight, scratchPerimeterCartographicNW ); const perimeterCartographicCW = Cartographic_default.fromRadians( rectangle.west, latCenter, maximumHeight, scratchPerimeterCartographicCW ); const perimeterCartographicSW = Cartographic_default.fromRadians( rectangle.west, rectangle.south, maximumHeight, scratchPerimeterCartographicSW ); const perimeterCartographicSC = Cartographic_default.fromRadians( lonCenter, rectangle.south, maximumHeight, scratchPerimeterCartographicSC ); const perimeterCartesianNC = ellipsoid.cartographicToCartesian( perimeterCartographicNC, scratchPerimeterCartesianNC ); let perimeterCartesianNW = ellipsoid.cartographicToCartesian( perimeterCartographicNW, scratchPerimeterCartesianNW ); const perimeterCartesianCW = ellipsoid.cartographicToCartesian( perimeterCartographicCW, scratchPerimeterCartesianCW ); let perimeterCartesianSW = ellipsoid.cartographicToCartesian( perimeterCartographicSW, scratchPerimeterCartesianSW ); const perimeterCartesianSC = ellipsoid.cartographicToCartesian( perimeterCartographicSC, scratchPerimeterCartesianSC ); const perimeterProjectedNC = tangentPlane.projectPointToNearestOnPlane( perimeterCartesianNC, scratchPerimeterProjectedNC ); const perimeterProjectedNW = tangentPlane.projectPointToNearestOnPlane( perimeterCartesianNW, scratchPerimeterProjectedNW ); const perimeterProjectedCW = tangentPlane.projectPointToNearestOnPlane( perimeterCartesianCW, scratchPerimeterProjectedCW ); const perimeterProjectedSW = tangentPlane.projectPointToNearestOnPlane( perimeterCartesianSW, scratchPerimeterProjectedSW ); const perimeterProjectedSC = tangentPlane.projectPointToNearestOnPlane( perimeterCartesianSC, scratchPerimeterProjectedSC ); minX = Math.min( perimeterProjectedNW.x, perimeterProjectedCW.x, perimeterProjectedSW.x ); maxX = -minX; maxY = Math.max(perimeterProjectedNW.y, perimeterProjectedNC.y); minY = Math.min(perimeterProjectedSW.y, perimeterProjectedSC.y); perimeterCartographicNW.height = perimeterCartographicSW.height = minimumHeight; perimeterCartesianNW = ellipsoid.cartographicToCartesian( perimeterCartographicNW, scratchPerimeterCartesianNW ); perimeterCartesianSW = ellipsoid.cartographicToCartesian( perimeterCartographicSW, scratchPerimeterCartesianSW ); minZ = Math.min( Plane_default.getPointDistance(plane, perimeterCartesianNW), Plane_default.getPointDistance(plane, perimeterCartesianSW) ); maxZ = maximumHeight; return fromPlaneExtents( tangentPlane.origin, tangentPlane.xAxis, tangentPlane.yAxis, tangentPlane.zAxis, minX, maxX, minY, maxY, minZ, maxZ, result ); } const fullyAboveEquator = rectangle.south > 0; const fullyBelowEquator = rectangle.north < 0; const latitudeNearestToEquator = fullyAboveEquator ? rectangle.south : fullyBelowEquator ? rectangle.north : 0; const centerLongitude = Rectangle_default.center( rectangle, scratchRectangleCenterCartographic ).longitude; const planeOrigin = Cartesian3_default.fromRadians( centerLongitude, latitudeNearestToEquator, maximumHeight, ellipsoid, scratchPlaneOrigin ); planeOrigin.z = 0; const isPole = Math.abs(planeOrigin.x) < Math_default.EPSILON10 && Math.abs(planeOrigin.y) < Math_default.EPSILON10; const planeNormal = !isPole ? Cartesian3_default.normalize(planeOrigin, scratchPlaneNormal2) : Cartesian3_default.UNIT_X; const planeYAxis = Cartesian3_default.UNIT_Z; const planeXAxis = Cartesian3_default.cross( planeNormal, planeYAxis, scratchPlaneXAxis ); plane = Plane_default.fromPointNormal(planeOrigin, planeNormal, scratchPlane2); const horizonCartesian = Cartesian3_default.fromRadians( centerLongitude + Math_default.PI_OVER_TWO, latitudeNearestToEquator, maximumHeight, ellipsoid, scratchHorizonCartesian ); maxX = Cartesian3_default.dot( Plane_default.projectPointOntoPlane( plane, horizonCartesian, scratchHorizonProjected ), planeXAxis ); minX = -maxX; maxY = Cartesian3_default.fromRadians( 0, rectangle.north, fullyBelowEquator ? minimumHeight : maximumHeight, ellipsoid, scratchMaxY ).z; minY = Cartesian3_default.fromRadians( 0, rectangle.south, fullyAboveEquator ? minimumHeight : maximumHeight, ellipsoid, scratchMinY ).z; const farZ = Cartesian3_default.fromRadians( rectangle.east, latitudeNearestToEquator, maximumHeight, ellipsoid, scratchZ ); minZ = Plane_default.getPointDistance(plane, farZ); maxZ = 0; return fromPlaneExtents( planeOrigin, planeXAxis, planeYAxis, planeNormal, minX, maxX, minY, maxY, minZ, maxZ, result ); }; OrientedBoundingBox.fromTransformation = function(transformation, result) { Check_default.typeOf.object("transformation", transformation); if (!defined_default(result)) { result = new OrientedBoundingBox(); } result.center = Matrix4_default.getTranslation(transformation, result.center); result.halfAxes = Matrix4_default.getMatrix3(transformation, result.halfAxes); result.halfAxes = Matrix3_default.multiplyByScalar( result.halfAxes, 0.5, result.halfAxes ); return result; }; OrientedBoundingBox.clone = function(box, result) { if (!defined_default(box)) { return void 0; } if (!defined_default(result)) { return new OrientedBoundingBox(box.center, box.halfAxes); } Cartesian3_default.clone(box.center, result.center); Matrix3_default.clone(box.halfAxes, result.halfAxes); return result; }; OrientedBoundingBox.intersectPlane = function(box, plane) { if (!defined_default(box)) { throw new DeveloperError_default("box is required."); } if (!defined_default(plane)) { throw new DeveloperError_default("plane is required."); } const center = box.center; const normal2 = plane.normal; const halfAxes = box.halfAxes; const normalX = normal2.x, normalY = normal2.y, normalZ = normal2.z; const radEffective = Math.abs( normalX * halfAxes[Matrix3_default.COLUMN0ROW0] + normalY * halfAxes[Matrix3_default.COLUMN0ROW1] + normalZ * halfAxes[Matrix3_default.COLUMN0ROW2] ) + Math.abs( normalX * halfAxes[Matrix3_default.COLUMN1ROW0] + normalY * halfAxes[Matrix3_default.COLUMN1ROW1] + normalZ * halfAxes[Matrix3_default.COLUMN1ROW2] ) + Math.abs( normalX * halfAxes[Matrix3_default.COLUMN2ROW0] + normalY * halfAxes[Matrix3_default.COLUMN2ROW1] + normalZ * halfAxes[Matrix3_default.COLUMN2ROW2] ); const distanceToPlane = Cartesian3_default.dot(normal2, center) + plane.distance; if (distanceToPlane <= -radEffective) { return Intersect_default.OUTSIDE; } else if (distanceToPlane >= radEffective) { return Intersect_default.INSIDE; } return Intersect_default.INTERSECTING; }; var scratchCartesianU = new Cartesian3_default(); var scratchCartesianV = new Cartesian3_default(); var scratchCartesianW = new Cartesian3_default(); var scratchValidAxis2 = new Cartesian3_default(); var scratchValidAxis3 = new Cartesian3_default(); var scratchPPrime = new Cartesian3_default(); OrientedBoundingBox.distanceSquaredTo = function(box, cartesian11) { if (!defined_default(box)) { throw new DeveloperError_default("box is required."); } if (!defined_default(cartesian11)) { throw new DeveloperError_default("cartesian is required."); } const offset = Cartesian3_default.subtract(cartesian11, box.center, scratchOffset); const halfAxes = box.halfAxes; let u4 = Matrix3_default.getColumn(halfAxes, 0, scratchCartesianU); let v3 = Matrix3_default.getColumn(halfAxes, 1, scratchCartesianV); let w = Matrix3_default.getColumn(halfAxes, 2, scratchCartesianW); const uHalf = Cartesian3_default.magnitude(u4); const vHalf = Cartesian3_default.magnitude(v3); const wHalf = Cartesian3_default.magnitude(w); let uValid = true; let vValid = true; let wValid = true; if (uHalf > 0) { Cartesian3_default.divideByScalar(u4, uHalf, u4); } else { uValid = false; } if (vHalf > 0) { Cartesian3_default.divideByScalar(v3, vHalf, v3); } else { vValid = false; } if (wHalf > 0) { Cartesian3_default.divideByScalar(w, wHalf, w); } else { wValid = false; } const numberOfDegenerateAxes = !uValid + !vValid + !wValid; let validAxis1; let validAxis2; let validAxis3; if (numberOfDegenerateAxes === 1) { let degenerateAxis = u4; validAxis1 = v3; validAxis2 = w; if (!vValid) { degenerateAxis = v3; validAxis1 = u4; } else if (!wValid) { degenerateAxis = w; validAxis2 = u4; } validAxis3 = Cartesian3_default.cross(validAxis1, validAxis2, scratchValidAxis3); if (degenerateAxis === u4) { u4 = validAxis3; } else if (degenerateAxis === v3) { v3 = validAxis3; } else if (degenerateAxis === w) { w = validAxis3; } } else if (numberOfDegenerateAxes === 2) { validAxis1 = u4; if (vValid) { validAxis1 = v3; } else if (wValid) { validAxis1 = w; } let crossVector = Cartesian3_default.UNIT_Y; if (crossVector.equalsEpsilon(validAxis1, Math_default.EPSILON3)) { crossVector = Cartesian3_default.UNIT_X; } validAxis2 = Cartesian3_default.cross(validAxis1, crossVector, scratchValidAxis2); Cartesian3_default.normalize(validAxis2, validAxis2); validAxis3 = Cartesian3_default.cross(validAxis1, validAxis2, scratchValidAxis3); Cartesian3_default.normalize(validAxis3, validAxis3); if (validAxis1 === u4) { v3 = validAxis2; w = validAxis3; } else if (validAxis1 === v3) { w = validAxis2; u4 = validAxis3; } else if (validAxis1 === w) { u4 = validAxis2; v3 = validAxis3; } } else if (numberOfDegenerateAxes === 3) { u4 = Cartesian3_default.UNIT_X; v3 = Cartesian3_default.UNIT_Y; w = Cartesian3_default.UNIT_Z; } const pPrime = scratchPPrime; pPrime.x = Cartesian3_default.dot(offset, u4); pPrime.y = Cartesian3_default.dot(offset, v3); pPrime.z = Cartesian3_default.dot(offset, w); let distanceSquared = 0; let d; if (pPrime.x < -uHalf) { d = pPrime.x + uHalf; distanceSquared += d * d; } else if (pPrime.x > uHalf) { d = pPrime.x - uHalf; distanceSquared += d * d; } if (pPrime.y < -vHalf) { d = pPrime.y + vHalf; distanceSquared += d * d; } else if (pPrime.y > vHalf) { d = pPrime.y - vHalf; distanceSquared += d * d; } if (pPrime.z < -wHalf) { d = pPrime.z + wHalf; distanceSquared += d * d; } else if (pPrime.z > wHalf) { d = pPrime.z - wHalf; distanceSquared += d * d; } return distanceSquared; }; var scratchCorner = new Cartesian3_default(); var scratchToCenter = new Cartesian3_default(); OrientedBoundingBox.computePlaneDistances = function(box, position, direction2, result) { if (!defined_default(box)) { throw new DeveloperError_default("box is required."); } if (!defined_default(position)) { throw new DeveloperError_default("position is required."); } if (!defined_default(direction2)) { throw new DeveloperError_default("direction is required."); } if (!defined_default(result)) { result = new Interval_default(); } let minDist = Number.POSITIVE_INFINITY; let maxDist = Number.NEGATIVE_INFINITY; const center = box.center; const halfAxes = box.halfAxes; const u4 = Matrix3_default.getColumn(halfAxes, 0, scratchCartesianU); const v3 = Matrix3_default.getColumn(halfAxes, 1, scratchCartesianV); const w = Matrix3_default.getColumn(halfAxes, 2, scratchCartesianW); const corner = Cartesian3_default.add(u4, v3, scratchCorner); Cartesian3_default.add(corner, w, corner); Cartesian3_default.add(corner, center, corner); const toCenter = Cartesian3_default.subtract(corner, position, scratchToCenter); let mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.add(center, u4, corner); Cartesian3_default.add(corner, v3, corner); Cartesian3_default.subtract(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.add(center, u4, corner); Cartesian3_default.subtract(corner, v3, corner); Cartesian3_default.add(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.add(center, u4, corner); Cartesian3_default.subtract(corner, v3, corner); Cartesian3_default.subtract(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.subtract(center, u4, corner); Cartesian3_default.add(corner, v3, corner); Cartesian3_default.add(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.subtract(center, u4, corner); Cartesian3_default.add(corner, v3, corner); Cartesian3_default.subtract(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.subtract(center, u4, corner); Cartesian3_default.subtract(corner, v3, corner); Cartesian3_default.add(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); Cartesian3_default.subtract(center, u4, corner); Cartesian3_default.subtract(corner, v3, corner); Cartesian3_default.subtract(corner, w, corner); Cartesian3_default.subtract(corner, position, toCenter); mag = Cartesian3_default.dot(direction2, toCenter); minDist = Math.min(mag, minDist); maxDist = Math.max(mag, maxDist); result.start = minDist; result.stop = maxDist; return result; }; var scratchXAxis = new Cartesian3_default(); var scratchYAxis = new Cartesian3_default(); var scratchZAxis = new Cartesian3_default(); OrientedBoundingBox.computeCorners = function(box, result) { Check_default.typeOf.object("box", box); if (!defined_default(result)) { result = [ new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default(), new Cartesian3_default() ]; } const center = box.center; const halfAxes = box.halfAxes; const xAxis = Matrix3_default.getColumn(halfAxes, 0, scratchXAxis); const yAxis = Matrix3_default.getColumn(halfAxes, 1, scratchYAxis); const zAxis = Matrix3_default.getColumn(halfAxes, 2, scratchZAxis); Cartesian3_default.clone(center, result[0]); Cartesian3_default.subtract(result[0], xAxis, result[0]); Cartesian3_default.subtract(result[0], yAxis, result[0]); Cartesian3_default.subtract(result[0], zAxis, result[0]); Cartesian3_default.clone(center, result[1]); Cartesian3_default.subtract(result[1], xAxis, result[1]); Cartesian3_default.subtract(result[1], yAxis, result[1]); Cartesian3_default.add(result[1], zAxis, result[1]); Cartesian3_default.clone(center, result[2]); Cartesian3_default.subtract(result[2], xAxis, result[2]); Cartesian3_default.add(result[2], yAxis, result[2]); Cartesian3_default.subtract(result[2], zAxis, result[2]); Cartesian3_default.clone(center, result[3]); Cartesian3_default.subtract(result[3], xAxis, result[3]); Cartesian3_default.add(result[3], yAxis, result[3]); Cartesian3_default.add(result[3], zAxis, result[3]); Cartesian3_default.clone(center, result[4]); Cartesian3_default.add(result[4], xAxis, result[4]); Cartesian3_default.subtract(result[4], yAxis, result[4]); Cartesian3_default.subtract(result[4], zAxis, result[4]); Cartesian3_default.clone(center, result[5]); Cartesian3_default.add(result[5], xAxis, result[5]); Cartesian3_default.subtract(result[5], yAxis, result[5]); Cartesian3_default.add(result[5], zAxis, result[5]); Cartesian3_default.clone(center, result[6]); Cartesian3_default.add(result[6], xAxis, result[6]); Cartesian3_default.add(result[6], yAxis, result[6]); Cartesian3_default.subtract(result[6], zAxis, result[6]); Cartesian3_default.clone(center, result[7]); Cartesian3_default.add(result[7], xAxis, result[7]); Cartesian3_default.add(result[7], yAxis, result[7]); Cartesian3_default.add(result[7], zAxis, result[7]); return result; }; var scratchRotationScale = new Matrix3_default(); OrientedBoundingBox.computeTransformation = function(box, result) { Check_default.typeOf.object("box", box); if (!defined_default(result)) { result = new Matrix4_default(); } const translation3 = box.center; const rotationScale = Matrix3_default.multiplyByUniformScale( box.halfAxes, 2, scratchRotationScale ); return Matrix4_default.fromRotationTranslation(rotationScale, translation3, result); }; var scratchBoundingSphere2 = new BoundingSphere_default(); OrientedBoundingBox.isOccluded = function(box, occluder) { if (!defined_default(box)) { throw new DeveloperError_default("box is required."); } if (!defined_default(occluder)) { throw new DeveloperError_default("occluder is required."); } const sphere = BoundingSphere_default.fromOrientedBoundingBox( box, scratchBoundingSphere2 ); return !occluder.isBoundingSphereVisible(sphere); }; OrientedBoundingBox.prototype.intersectPlane = function(plane) { return OrientedBoundingBox.intersectPlane(this, plane); }; OrientedBoundingBox.prototype.distanceSquaredTo = function(cartesian11) { return OrientedBoundingBox.distanceSquaredTo(this, cartesian11); }; OrientedBoundingBox.prototype.computePlaneDistances = function(position, direction2, result) { return OrientedBoundingBox.computePlaneDistances( this, position, direction2, result ); }; OrientedBoundingBox.prototype.computeCorners = function(result) { return OrientedBoundingBox.computeCorners(this, result); }; OrientedBoundingBox.prototype.computeTransformation = function(result) { return OrientedBoundingBox.computeTransformation(this, result); }; OrientedBoundingBox.prototype.isOccluded = function(occluder) { return OrientedBoundingBox.isOccluded(this, occluder); }; OrientedBoundingBox.equals = function(left, right) { return left === right || defined_default(left) && defined_default(right) && Cartesian3_default.equals(left.center, right.center) && Matrix3_default.equals(left.halfAxes, right.halfAxes); }; OrientedBoundingBox.prototype.clone = function(result) { return OrientedBoundingBox.clone(this, result); }; OrientedBoundingBox.prototype.equals = function(right) { return OrientedBoundingBox.equals(this, right); }; var OrientedBoundingBox_default = OrientedBoundingBox; // packages/engine/Source/Core/VerticalExaggeration.js var import_InlineWorkers360 = __toESM(require_InlineWorkers(), 1); var VerticalExaggeration = {}; VerticalExaggeration.getHeight = function(height, scale, relativeHeight) { if (!Number.isFinite(scale)) { throw new DeveloperError_default("scale must be a finite number."); } if (!Number.isFinite(relativeHeight)) { throw new DeveloperError_default("relativeHeight must be a finite number."); } return (height - relativeHeight) * scale + relativeHeight; }; var scratchCartographic2 = new Cartographic_default(); VerticalExaggeration.getPosition = function(position, ellipsoid, verticalExaggeration, verticalExaggerationRelativeHeight, result) { const cartographic2 = ellipsoid.cartesianToCartographic( position, scratchCartographic2 ); if (!defined_default(cartographic2)) { return Cartesian3_default.clone(position, result); } const newHeight = VerticalExaggeration.getHeight( cartographic2.height, verticalExaggeration, verticalExaggerationRelativeHeight ); return Cartesian3_default.fromRadians( cartographic2.longitude, cartographic2.latitude, newHeight, ellipsoid, result ); }; var VerticalExaggeration_default = VerticalExaggeration; // packages/engine/Source/Scene/ClassificationPrimitive.js var import_InlineWorkers378 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/ShadowVolumeAppearanceVS.js var import_InlineWorkers361 = __toESM(require_InlineWorkers(), 1); var ShadowVolumeAppearanceVS_default = 'in vec3 position3DHigh;\nin vec3 position3DLow;\nin float batchId;\n\n#ifdef EXTRUDED_GEOMETRY\nin vec3 extrudeDirection;\n\nuniform float u_globeMinimumAltitude;\n#endif // EXTRUDED_GEOMETRY\n\n#ifdef PER_INSTANCE_COLOR\nout vec4 v_color;\n#endif // PER_INSTANCE_COLOR\n\n#ifdef TEXTURE_COORDINATES\n#ifdef SPHERICAL\nout vec4 v_sphericalExtents;\n#else // SPHERICAL\nout vec2 v_inversePlaneExtents;\nout vec4 v_westPlane;\nout vec4 v_southPlane;\n#endif // SPHERICAL\nout vec3 v_uvMinAndSphericalLongitudeRotation;\nout vec3 v_uMaxAndInverseDistance;\nout vec3 v_vMaxAndInverseDistance;\n#endif // TEXTURE_COORDINATES\n\nvoid main()\n{\n vec4 position = czm_computePosition();\n\n#ifdef EXTRUDED_GEOMETRY\n float delta = min(u_globeMinimumAltitude, czm_geometricToleranceOverMeter * length(position.xyz));\n delta *= czm_sceneMode == czm_sceneMode3D ? 1.0 : 0.0;\n\n //extrudeDirection is zero for the top layer\n position = position + vec4(extrudeDirection * delta, 0.0);\n#endif\n\n#ifdef TEXTURE_COORDINATES\n#ifdef SPHERICAL\n v_sphericalExtents = czm_batchTable_sphericalExtents(batchId);\n v_uvMinAndSphericalLongitudeRotation.z = czm_batchTable_longitudeRotation(batchId);\n#else // SPHERICAL\n#ifdef COLUMBUS_VIEW_2D\n vec4 planes2D_high = czm_batchTable_planes2D_HIGH(batchId);\n vec4 planes2D_low = czm_batchTable_planes2D_LOW(batchId);\n\n // If the primitive is split across the IDL (planes2D_high.x > planes2D_high.w):\n // - If this vertex is on the east side of the IDL (position3DLow.y > 0.0, comparison with position3DHigh may produce artifacts)\n // - existing "east" is on the wrong side of the world, far away (planes2D_high/low.w)\n // - so set "east" as beyond the eastmost extent of the projection (idlSplitNewPlaneHiLow)\n vec2 idlSplitNewPlaneHiLow = vec2(EAST_MOST_X_HIGH - (WEST_MOST_X_HIGH - planes2D_high.w), EAST_MOST_X_LOW - (WEST_MOST_X_LOW - planes2D_low.w));\n bool idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y > 0.0;\n planes2D_high.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.w);\n planes2D_low.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.w);\n\n // - else, if this vertex is on the west side of the IDL (position3DLow.y < 0.0)\n // - existing "west" is on the wrong side of the world, far away (planes2D_high/low.x)\n // - so set "west" as beyond the westmost extent of the projection (idlSplitNewPlaneHiLow)\n idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y < 0.0;\n idlSplitNewPlaneHiLow = vec2(WEST_MOST_X_HIGH - (EAST_MOST_X_HIGH - planes2D_high.x), WEST_MOST_X_LOW - (EAST_MOST_X_LOW - planes2D_low.x));\n planes2D_high.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.x);\n planes2D_low.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.x);\n\n vec3 southWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.xy), vec3(0.0, planes2D_low.xy))).xyz;\n vec3 northWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.x, planes2D_high.z), vec3(0.0, planes2D_low.x, planes2D_low.z))).xyz;\n vec3 southEastCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.w, planes2D_high.y), vec3(0.0, planes2D_low.w, planes2D_low.y))).xyz;\n#else // COLUMBUS_VIEW_2D\n // 3D case has smaller "plane extents," so planes encoded as a 64 bit position and 2 vec3s for distances/direction\n vec3 southWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(czm_batchTable_southWest_HIGH(batchId), czm_batchTable_southWest_LOW(batchId))).xyz;\n vec3 northWestCorner = czm_normal * czm_batchTable_northward(batchId) + southWestCorner;\n vec3 southEastCorner = czm_normal * czm_batchTable_eastward(batchId) + southWestCorner;\n#endif // COLUMBUS_VIEW_2D\n\n vec3 eastWard = southEastCorner - southWestCorner;\n float eastExtent = length(eastWard);\n eastWard /= eastExtent;\n\n vec3 northWard = northWestCorner - southWestCorner;\n float northExtent = length(northWard);\n northWard /= northExtent;\n\n v_westPlane = vec4(eastWard, -dot(eastWard, southWestCorner));\n v_southPlane = vec4(northWard, -dot(northWard, southWestCorner));\n v_inversePlaneExtents = vec2(1.0 / eastExtent, 1.0 / northExtent);\n#endif // SPHERICAL\n vec4 uvMinAndExtents = czm_batchTable_uvMinAndExtents(batchId);\n vec4 uMaxVmax = czm_batchTable_uMaxVmax(batchId);\n\n v_uMaxAndInverseDistance = vec3(uMaxVmax.xy, uvMinAndExtents.z);\n v_vMaxAndInverseDistance = vec3(uMaxVmax.zw, uvMinAndExtents.w);\n v_uvMinAndSphericalLongitudeRotation.xy = uvMinAndExtents.xy;\n#endif // TEXTURE_COORDINATES\n\n#ifdef PER_INSTANCE_COLOR\n v_color = czm_batchTable_color(batchId);\n#endif\n\n gl_Position = czm_depthClamp(czm_modelViewProjectionRelativeToEye * position);\n}\n'; // packages/engine/Source/Shaders/ShadowVolumeFS.js var import_InlineWorkers362 = __toESM(require_InlineWorkers(), 1); var ShadowVolumeFS_default = "#ifdef VECTOR_TILE\nuniform vec4 u_highlightColor;\n#endif\n\nvoid main(void)\n{\n#ifdef VECTOR_TILE\n out_FragColor = czm_gammaCorrect(u_highlightColor);\n#else\n out_FragColor = vec4(1.0);\n#endif\n czm_writeDepthClamp();\n}\n"; // packages/engine/Source/Scene/ClassificationType.js var import_InlineWorkers363 = __toESM(require_InlineWorkers(), 1); var ClassificationType = { /** * Only terrain will be classified. * * @type {number} * @constant */ TERRAIN: 0, /** * Only 3D Tiles will be classified. * * @type {number} * @constant */ CESIUM_3D_TILE: 1, /** * Both terrain and 3D Tiles will be classified. * * @type {number} * @constant */ BOTH: 2 }; ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES = 3; Object.freeze(ClassificationType); var ClassificationType_default = ClassificationType; // packages/engine/Source/Scene/DepthFunction.js var import_InlineWorkers364 = __toESM(require_InlineWorkers(), 1); var DepthFunction = { /** * The depth test never passes. * * @type {number} * @constant */ NEVER: WebGLConstants_default.NEVER, /** * The depth test passes if the incoming depth is less than the stored depth. * * @type {number} * @constant */ LESS: WebGLConstants_default.LESS, /** * The depth test passes if the incoming depth is equal to the stored depth. * * @type {number} * @constant */ EQUAL: WebGLConstants_default.EQUAL, /** * The depth test passes if the incoming depth is less than or equal to the stored depth. * * @type {number} * @constant */ LESS_OR_EQUAL: WebGLConstants_default.LEQUAL, /** * The depth test passes if the incoming depth is greater than the stored depth. * * @type {number} * @constant */ GREATER: WebGLConstants_default.GREATER, /** * The depth test passes if the incoming depth is not equal to the stored depth. * * @type {number} * @constant */ NOT_EQUAL: WebGLConstants_default.NOTEQUAL, /** * The depth test passes if the incoming depth is greater than or equal to the stored depth. * * @type {number} * @constant */ GREATER_OR_EQUAL: WebGLConstants_default.GEQUAL, /** * The depth test always passes. * * @type {number} * @constant */ ALWAYS: WebGLConstants_default.ALWAYS }; Object.freeze(DepthFunction); var DepthFunction_default = DepthFunction; // packages/engine/Source/Scene/Primitive.js var import_InlineWorkers371 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/subdivideArray.js var import_InlineWorkers365 = __toESM(require_InlineWorkers(), 1); function subdivideArray(array, numberOfArrays) { if (!defined_default(array)) { throw new DeveloperError_default("array is required."); } if (!defined_default(numberOfArrays) || numberOfArrays < 1) { throw new DeveloperError_default("numberOfArrays must be greater than 0."); } const result = []; const len = array.length; let i = 0; while (i < len) { const size = Math.ceil((len - i) / numberOfArrays--); result.push(array.slice(i, i + size)); i += size; } return result; } var subdivideArray_default = subdivideArray; // packages/engine/Source/Scene/BatchTable.js var import_InlineWorkers366 = __toESM(require_InlineWorkers(), 1); function BatchTable(context, attributes, numberOfInstances) { if (!defined_default(context)) { throw new DeveloperError_default("context is required"); } if (!defined_default(attributes)) { throw new DeveloperError_default("attributes is required"); } if (!defined_default(numberOfInstances)) { throw new DeveloperError_default("numberOfInstances is required"); } this._attributes = attributes; this._numberOfInstances = numberOfInstances; if (attributes.length === 0) { return; } const pixelDatatype = getDatatype(attributes); const textureFloatSupported = context.floatingPointTexture; const packFloats = pixelDatatype === PixelDatatype_default.FLOAT && !textureFloatSupported; const offsets = createOffsets(attributes, packFloats); const stride = getStride(offsets, attributes, packFloats); const maxNumberOfInstancesPerRow = Math.floor( ContextLimits_default.maximumTextureSize / stride ); const instancesPerWidth = Math.min( numberOfInstances, maxNumberOfInstancesPerRow ); const width = stride * instancesPerWidth; const height = Math.ceil(numberOfInstances / instancesPerWidth); const stepX = 1 / width; const centerX = stepX * 0.5; const stepY = 1 / height; const centerY = stepY * 0.5; this._textureDimensions = new Cartesian2_default(width, height); this._textureStep = new Cartesian4_default(stepX, centerX, stepY, centerY); this._pixelDatatype = !packFloats ? pixelDatatype : PixelDatatype_default.UNSIGNED_BYTE; this._packFloats = packFloats; this._offsets = offsets; this._stride = stride; this._texture = void 0; const batchLength = 4 * width * height; this._batchValues = pixelDatatype === PixelDatatype_default.FLOAT && !packFloats ? new Float32Array(batchLength) : new Uint8Array(batchLength); this._batchValuesDirty = false; } Object.defineProperties(BatchTable.prototype, { /** * The attribute descriptions. * @memberOf BatchTable.prototype * @type {object[]} * @readonly */ attributes: { get: function() { return this._attributes; } }, /** * The number of instances. * @memberOf BatchTable.prototype * @type {number} * @readonly */ numberOfInstances: { get: function() { return this._numberOfInstances; } } }); function getDatatype(attributes) { let foundFloatDatatype = false; const length2 = attributes.length; for (let i = 0; i < length2; ++i) { if (attributes[i].componentDatatype !== ComponentDatatype_default.UNSIGNED_BYTE) { foundFloatDatatype = true; break; } } return foundFloatDatatype ? PixelDatatype_default.FLOAT : PixelDatatype_default.UNSIGNED_BYTE; } function getAttributeType(attributes, attributeIndex) { const componentsPerAttribute = attributes[attributeIndex].componentsPerAttribute; if (componentsPerAttribute === 2) { return Cartesian2_default; } else if (componentsPerAttribute === 3) { return Cartesian3_default; } else if (componentsPerAttribute === 4) { return Cartesian4_default; } return Number; } function createOffsets(attributes, packFloats) { const offsets = new Array(attributes.length); let currentOffset = 0; const attributesLength = attributes.length; for (let i = 0; i < attributesLength; ++i) { const attribute = attributes[i]; const componentDatatype = attribute.componentDatatype; offsets[i] = currentOffset; if (componentDatatype !== ComponentDatatype_default.UNSIGNED_BYTE && packFloats) { currentOffset += 4; } else { ++currentOffset; } } return offsets; } function getStride(offsets, attributes, packFloats) { const length2 = offsets.length; const lastOffset = offsets[length2 - 1]; const lastAttribute = attributes[length2 - 1]; const componentDatatype = lastAttribute.componentDatatype; if (componentDatatype !== ComponentDatatype_default.UNSIGNED_BYTE && packFloats) { return lastOffset + 4; } return lastOffset + 1; } var scratchPackedFloatCartesian4 = new Cartesian4_default(); function getPackedFloat(array, index, result) { let packed = Cartesian4_default.unpack(array, index, scratchPackedFloatCartesian4); const x = Cartesian4_default.unpackFloat(packed); packed = Cartesian4_default.unpack(array, index + 4, scratchPackedFloatCartesian4); const y = Cartesian4_default.unpackFloat(packed); packed = Cartesian4_default.unpack(array, index + 8, scratchPackedFloatCartesian4); const z2 = Cartesian4_default.unpackFloat(packed); packed = Cartesian4_default.unpack(array, index + 12, scratchPackedFloatCartesian4); const w = Cartesian4_default.unpackFloat(packed); return Cartesian4_default.fromElements(x, y, z2, w, result); } function setPackedAttribute(value, array, index) { let packed = Cartesian4_default.packFloat(value.x, scratchPackedFloatCartesian4); Cartesian4_default.pack(packed, array, index); packed = Cartesian4_default.packFloat(value.y, packed); Cartesian4_default.pack(packed, array, index + 4); packed = Cartesian4_default.packFloat(value.z, packed); Cartesian4_default.pack(packed, array, index + 8); packed = Cartesian4_default.packFloat(value.w, packed); Cartesian4_default.pack(packed, array, index + 12); } var scratchGetAttributeCartesian4 = new Cartesian4_default(); BatchTable.prototype.getBatchedAttribute = function(instanceIndex, attributeIndex, result) { if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { throw new DeveloperError_default("instanceIndex is out of range."); } if (attributeIndex < 0 || attributeIndex >= this._attributes.length) { throw new DeveloperError_default("attributeIndex is out of range"); } const attributes = this._attributes; const offset = this._offsets[attributeIndex]; const stride = this._stride; const index = 4 * stride * instanceIndex + 4 * offset; let value; if (this._packFloats && attributes[attributeIndex].componentDatatype !== PixelDatatype_default.UNSIGNED_BYTE) { value = getPackedFloat( this._batchValues, index, scratchGetAttributeCartesian4 ); } else { value = Cartesian4_default.unpack( this._batchValues, index, scratchGetAttributeCartesian4 ); } const attributeType = getAttributeType(attributes, attributeIndex); if (defined_default(attributeType.fromCartesian4)) { return attributeType.fromCartesian4(value, result); } else if (defined_default(attributeType.clone)) { return attributeType.clone(value, result); } return value.x; }; var setAttributeScratchValues = [ void 0, void 0, new Cartesian2_default(), new Cartesian3_default(), new Cartesian4_default() ]; var setAttributeScratchCartesian4 = new Cartesian4_default(); BatchTable.prototype.setBatchedAttribute = function(instanceIndex, attributeIndex, value) { if (instanceIndex < 0 || instanceIndex >= this._numberOfInstances) { throw new DeveloperError_default("instanceIndex is out of range."); } if (attributeIndex < 0 || attributeIndex >= this._attributes.length) { throw new DeveloperError_default("attributeIndex is out of range"); } if (!defined_default(value)) { throw new DeveloperError_default("value is required."); } const attributes = this._attributes; const result = setAttributeScratchValues[attributes[attributeIndex].componentsPerAttribute]; const currentAttribute = this.getBatchedAttribute( instanceIndex, attributeIndex, result ); const attributeType = getAttributeType(this._attributes, attributeIndex); const entriesEqual = defined_default(attributeType.equals) ? attributeType.equals(currentAttribute, value) : currentAttribute === value; if (entriesEqual) { return; } const attributeValue = setAttributeScratchCartesian4; attributeValue.x = defined_default(value.x) ? value.x : value; attributeValue.y = defined_default(value.y) ? value.y : 0; attributeValue.z = defined_default(value.z) ? value.z : 0; attributeValue.w = defined_default(value.w) ? value.w : 0; const offset = this._offsets[attributeIndex]; const stride = this._stride; const index = 4 * stride * instanceIndex + 4 * offset; if (this._packFloats && attributes[attributeIndex].componentDatatype !== PixelDatatype_default.UNSIGNED_BYTE) { setPackedAttribute(attributeValue, this._batchValues, index); } else { Cartesian4_default.pack(attributeValue, this._batchValues, index); } this._batchValuesDirty = true; }; function createTexture(batchTable, context) { const dimensions = batchTable._textureDimensions; batchTable._texture = new Texture_default({ context, pixelFormat: PixelFormat_default.RGBA, pixelDatatype: batchTable._pixelDatatype, width: dimensions.x, height: dimensions.y, sampler: Sampler_default.NEAREST, flipY: false }); } function updateTexture(batchTable) { const dimensions = batchTable._textureDimensions; batchTable._texture.copyFrom({ source: { width: dimensions.x, height: dimensions.y, arrayBufferView: batchTable._batchValues } }); } BatchTable.prototype.update = function(frameState) { if (defined_default(this._texture) && !this._batchValuesDirty || this._attributes.length === 0) { return; } this._batchValuesDirty = false; if (!defined_default(this._texture)) { createTexture(this, frameState.context); } updateTexture(this); }; BatchTable.prototype.getUniformMapCallback = function() { const that = this; return function(uniformMap2) { if (that._attributes.length === 0) { return uniformMap2; } const batchUniformMap = { batchTexture: function() { return that._texture; }, batchTextureDimensions: function() { return that._textureDimensions; }, batchTextureStep: function() { return that._textureStep; } }; return combine_default(uniformMap2, batchUniformMap); }; }; function getGlslComputeSt(batchTable) { const stride = batchTable._stride; if (batchTable._textureDimensions.y === 1) { return `${"uniform vec4 batchTextureStep; \nvec2 computeSt(float batchId) \n{ \n float stepX = batchTextureStep.x; \n float centerX = batchTextureStep.y; \n float numberOfAttributes = float("}${stride}); return vec2(centerX + (batchId * numberOfAttributes * stepX), 0.5); } `; } return `${"uniform vec4 batchTextureStep; \nuniform vec2 batchTextureDimensions; \nvec2 computeSt(float batchId) \n{ \n float stepX = batchTextureStep.x; \n float centerX = batchTextureStep.y; \n float stepY = batchTextureStep.z; \n float centerY = batchTextureStep.w; \n float numberOfAttributes = float("}${stride}); float xId = mod(batchId * numberOfAttributes, batchTextureDimensions.x); float yId = floor(batchId * numberOfAttributes / batchTextureDimensions.x); return vec2(centerX + (xId * stepX), centerY + (yId * stepY)); } `; } function getComponentType(componentsPerAttribute) { if (componentsPerAttribute === 1) { return "float"; } return `vec${componentsPerAttribute}`; } function getComponentSwizzle(componentsPerAttribute) { if (componentsPerAttribute === 1) { return ".x"; } else if (componentsPerAttribute === 2) { return ".xy"; } else if (componentsPerAttribute === 3) { return ".xyz"; } return ""; } function getGlslAttributeFunction(batchTable, attributeIndex) { const attributes = batchTable._attributes; const attribute = attributes[attributeIndex]; const componentsPerAttribute = attribute.componentsPerAttribute; const functionName = attribute.functionName; const functionReturnType = getComponentType(componentsPerAttribute); const functionReturnValue = getComponentSwizzle(componentsPerAttribute); const offset = batchTable._offsets[attributeIndex]; let glslFunction = `${functionReturnType} ${functionName}(float batchId) { vec2 st = computeSt(batchId); st.x += batchTextureStep.x * float(${offset}); `; if (batchTable._packFloats && attribute.componentDatatype !== PixelDatatype_default.UNSIGNED_BYTE) { glslFunction += "vec4 textureValue; \ntextureValue.x = czm_unpackFloat(texture(batchTexture, st)); \ntextureValue.y = czm_unpackFloat(texture(batchTexture, st + vec2(batchTextureStep.x, 0.0))); \ntextureValue.z = czm_unpackFloat(texture(batchTexture, st + vec2(batchTextureStep.x * 2.0, 0.0))); \ntextureValue.w = czm_unpackFloat(texture(batchTexture, st + vec2(batchTextureStep.x * 3.0, 0.0))); \n"; } else { glslFunction += " vec4 textureValue = texture(batchTexture, st); \n"; } glslFunction += ` ${functionReturnType} value = textureValue${functionReturnValue}; `; if (batchTable._pixelDatatype === PixelDatatype_default.UNSIGNED_BYTE && attribute.componentDatatype === ComponentDatatype_default.UNSIGNED_BYTE && !attribute.normalize) { glslFunction += "value *= 255.0; \n"; } else if (batchTable._pixelDatatype === PixelDatatype_default.FLOAT && attribute.componentDatatype === ComponentDatatype_default.UNSIGNED_BYTE && attribute.normalize) { glslFunction += "value /= 255.0; \n"; } glslFunction += " return value; \n} \n"; return glslFunction; } BatchTable.prototype.getVertexShaderCallback = function() { const attributes = this._attributes; if (attributes.length === 0) { return function(source) { return source; }; } let batchTableShader = "uniform highp sampler2D batchTexture; \n"; batchTableShader += `${getGlslComputeSt(this)} `; const length2 = attributes.length; for (let i = 0; i < length2; ++i) { batchTableShader += getGlslAttributeFunction(this, i); } return function(source) { const mainIndex = source.indexOf("void main"); const beforeMain = source.substring(0, mainIndex); const afterMain = source.substring(mainIndex); return `${beforeMain} ${batchTableShader} ${afterMain}`; }; }; BatchTable.prototype.isDestroyed = function() { return false; }; BatchTable.prototype.destroy = function() { this._texture = this._texture && this._texture.destroy(); return destroyObject_default(this); }; var BatchTable_default = BatchTable; // packages/engine/Source/Scene/PrimitivePipeline.js var import_InlineWorkers368 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/WebMercatorProjection.js var import_InlineWorkers367 = __toESM(require_InlineWorkers(), 1); var WebMercatorProjection = class _WebMercatorProjection { /** * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid. */ constructor(ellipsoid) { this._ellipsoid = ellipsoid ?? Ellipsoid_default.WGS84; this._semimajorAxis = this._ellipsoid.maximumRadius; this._oneOverSemimajorAxis = 1 / this._semimajorAxis; } /** * Gets the {@link Ellipsoid}. * * @type {Ellipsoid} * @readonly */ get ellipsoid() { return this._ellipsoid; } /** * Converts a Mercator angle, in the range -PI to PI, to a geodetic latitude * in the range -PI/2 to PI/2. * * @param {number} mercatorAngle The angle to convert. * @returns {number} The geodetic latitude in radians. */ static mercatorAngleToGeodeticLatitude(mercatorAngle) { return Math_default.PI_OVER_TWO - 2 * Math.atan(Math.exp(-mercatorAngle)); } /** * Converts a geodetic latitude in radians, in the range -PI/2 to PI/2, to a Mercator * angle in the range -PI to PI. * * @param {number} latitude The geodetic latitude in radians. * @returns {number} The Mercator angle. */ static geodeticLatitudeToMercatorAngle(latitude) { if (latitude > _WebMercatorProjection.MaximumLatitude) { latitude = _WebMercatorProjection.MaximumLatitude; } else if (latitude < -_WebMercatorProjection.MaximumLatitude) { latitude = -_WebMercatorProjection.MaximumLatitude; } const sinLatitude = Math.sin(latitude); return 0.5 * Math.log((1 + sinLatitude) / (1 - sinLatitude)); } /** * Converts geodetic ellipsoid coordinates, in radians, to the equivalent Web Mercator * X, Y, Z coordinates expressed in meters and returned in a {@link Cartesian3}. The height * is copied unmodified to the Z coordinate. * * @param {Cartographic} cartographic The cartographic coordinates in radians. * @param {Cartesian3} [result] The instance to which to copy the result, or undefined if a * new instance should be created. * @returns {Cartesian3} The equivalent web mercator X, Y, Z coordinates, in meters. */ project(cartographic2, result) { const semimajorAxis = this._semimajorAxis; const x = cartographic2.longitude * semimajorAxis; const y = _WebMercatorProjection.geodeticLatitudeToMercatorAngle( cartographic2.latitude ) * semimajorAxis; const z2 = cartographic2.height; if (!defined_default(result)) { return new Cartesian3_default(x, y, z2); } result.x = x; result.y = y; result.z = z2; return result; } /** * Converts Web Mercator X, Y coordinates, expressed in meters, to a {@link Cartographic} * containing geodetic ellipsoid coordinates. The Z coordinate is copied unmodified to the * height. * * @param {Cartesian3} cartesian The web mercator Cartesian position to unrproject with height (z) in meters. * @param {Cartographic} [result] The instance to which to copy the result, or undefined if a * new instance should be created. * @returns {Cartographic} The equivalent cartographic coordinates. */ unproject(cartesian11, result) { if (!defined_default(cartesian11)) { throw new DeveloperError_default("cartesian is required"); } const oneOverEarthSemimajorAxis = this._oneOverSemimajorAxis; const longitude = cartesian11.x * oneOverEarthSemimajorAxis; const latitude = _WebMercatorProjection.mercatorAngleToGeodeticLatitude( cartesian11.y * oneOverEarthSemimajorAxis ); const height = cartesian11.z; if (!defined_default(result)) { return new Cartographic_default(longitude, latitude, height); } result.longitude = longitude; result.latitude = latitude; result.height = height; return result; } }; WebMercatorProjection.MaximumLatitude = WebMercatorProjection.mercatorAngleToGeodeticLatitude(Math.PI); var WebMercatorProjection_default = WebMercatorProjection; // packages/engine/Source/Scene/PrimitivePipeline.js function transformToWorldCoordinates(instances, primitiveModelMatrix, scene3DOnly) { let toWorld = !scene3DOnly; const length2 = instances.length; let i; if (!toWorld && length2 > 1) { const modelMatrix = instances[0].modelMatrix; for (i = 1; i < length2; ++i) { if (!Matrix4_default.equals(modelMatrix, instances[i].modelMatrix)) { toWorld = true; break; } } } if (toWorld) { for (i = 0; i < length2; ++i) { if (defined_default(instances[i].geometry)) { GeometryPipeline_default.transformToWorldCoordinates(instances[i]); } } } else { Matrix4_default.multiplyTransformation( primitiveModelMatrix, instances[0].modelMatrix, primitiveModelMatrix ); } } function addGeometryBatchId(geometry, batchId) { const attributes = geometry.attributes; const positionAttr = attributes.position; const numberOfComponents = positionAttr.values.length / positionAttr.componentsPerAttribute; attributes.batchId = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 1, values: new Float32Array(numberOfComponents) }); const values = attributes.batchId.values; for (let j = 0; j < numberOfComponents; ++j) { values[j] = batchId; } } function addBatchIds(instances) { const length2 = instances.length; for (let i = 0; i < length2; ++i) { const instance = instances[i]; if (defined_default(instance.geometry)) { addGeometryBatchId(instance.geometry, i); } else if (defined_default(instance.westHemisphereGeometry) && defined_default(instance.eastHemisphereGeometry)) { addGeometryBatchId(instance.westHemisphereGeometry, i); addGeometryBatchId(instance.eastHemisphereGeometry, i); } } } function geometryPipeline(parameters) { const instances = parameters.instances; const projection = parameters.projection; const uintIndexSupport = parameters.elementIndexUintSupported; const scene3DOnly = parameters.scene3DOnly; const vertexCacheOptimize = parameters.vertexCacheOptimize; const compressVertices = parameters.compressVertices; const modelMatrix = parameters.modelMatrix; let i; let geometry; let primitiveType; let length2 = instances.length; for (i = 0; i < length2; ++i) { if (defined_default(instances[i].geometry)) { primitiveType = instances[i].geometry.primitiveType; break; } } for (i = 1; i < length2; ++i) { if (defined_default(instances[i].geometry) && instances[i].geometry.primitiveType !== primitiveType) { throw new DeveloperError_default( "All instance geometries must have the same primitiveType." ); } } transformToWorldCoordinates(instances, modelMatrix, scene3DOnly); if (!scene3DOnly) { for (i = 0; i < length2; ++i) { if (defined_default(instances[i].geometry)) { GeometryPipeline_default.splitLongitude(instances[i]); } } } addBatchIds(instances); if (vertexCacheOptimize) { for (i = 0; i < length2; ++i) { const instance = instances[i]; if (defined_default(instance.geometry)) { GeometryPipeline_default.reorderForPostVertexCache(instance.geometry); GeometryPipeline_default.reorderForPreVertexCache(instance.geometry); } else if (defined_default(instance.westHemisphereGeometry) && defined_default(instance.eastHemisphereGeometry)) { GeometryPipeline_default.reorderForPostVertexCache( instance.westHemisphereGeometry ); GeometryPipeline_default.reorderForPreVertexCache( instance.westHemisphereGeometry ); GeometryPipeline_default.reorderForPostVertexCache( instance.eastHemisphereGeometry ); GeometryPipeline_default.reorderForPreVertexCache( instance.eastHemisphereGeometry ); } } } let geometries = GeometryPipeline_default.combineInstances(instances); length2 = geometries.length; for (i = 0; i < length2; ++i) { geometry = geometries[i]; const attributes = geometry.attributes; if (!scene3DOnly) { for (const name in attributes) { if (attributes.hasOwnProperty(name) && attributes[name].componentDatatype === ComponentDatatype_default.DOUBLE) { const name3D = `${name}3D`; const name2D = `${name}2D`; GeometryPipeline_default.projectTo2D( geometry, name, name3D, name2D, projection ); if (defined_default(geometry.boundingSphere) && name === "position") { geometry.boundingSphereCV = BoundingSphere_default.fromVertices( geometry.attributes.position2D.values ); } GeometryPipeline_default.encodeAttribute( geometry, name3D, `${name3D}High`, `${name3D}Low` ); GeometryPipeline_default.encodeAttribute( geometry, name2D, `${name2D}High`, `${name2D}Low` ); } } } else { for (const name in attributes) { if (attributes.hasOwnProperty(name) && attributes[name].componentDatatype === ComponentDatatype_default.DOUBLE) { GeometryPipeline_default.encodeAttribute( geometry, name, `${name}3DHigh`, `${name}3DLow` ); } } } if (compressVertices) { GeometryPipeline_default.compressVertices(geometry); } } if (!uintIndexSupport) { let splitGeometries = []; length2 = geometries.length; for (i = 0; i < length2; ++i) { geometry = geometries[i]; splitGeometries = splitGeometries.concat( GeometryPipeline_default.fitToUnsignedShortIndices(geometry) ); } geometries = splitGeometries; } return geometries; } function createPickOffsets(instances, geometryName, geometries, pickOffsets) { let offset; let indexCount; let geometryIndex; const offsetIndex = pickOffsets.length - 1; if (offsetIndex >= 0) { const pickOffset = pickOffsets[offsetIndex]; offset = pickOffset.offset + pickOffset.count; geometryIndex = pickOffset.index; indexCount = geometries[geometryIndex].indices.length; } else { offset = 0; geometryIndex = 0; indexCount = geometries[geometryIndex].indices.length; } const length2 = instances.length; for (let i = 0; i < length2; ++i) { const instance = instances[i]; const geometry = instance[geometryName]; if (!defined_default(geometry)) { continue; } const count = geometry.indices.length; if (offset + count > indexCount) { offset = 0; indexCount = geometries[++geometryIndex].indices.length; } pickOffsets.push({ index: geometryIndex, offset, count }); offset += count; } } function createInstancePickOffsets(instances, geometries) { const pickOffsets = []; createPickOffsets(instances, "geometry", geometries, pickOffsets); createPickOffsets( instances, "westHemisphereGeometry", geometries, pickOffsets ); createPickOffsets( instances, "eastHemisphereGeometry", geometries, pickOffsets ); return pickOffsets; } var PrimitivePipeline = {}; PrimitivePipeline.combineGeometry = function(parameters) { let geometries; let attributeLocations8; const instances = parameters.instances; const length2 = instances.length; let pickOffsets; let offsetInstanceExtend; let hasOffset = false; if (length2 > 0) { geometries = geometryPipeline(parameters); if (geometries.length > 0) { attributeLocations8 = GeometryPipeline_default.createAttributeLocations( geometries[0] ); if (parameters.createPickOffsets) { pickOffsets = createInstancePickOffsets(instances, geometries); } } if (defined_default(instances[0].attributes) && defined_default(instances[0].attributes.offset)) { offsetInstanceExtend = new Array(length2); hasOffset = true; } } const boundingSpheres = new Array(length2); const boundingSpheresCV = new Array(length2); for (let i = 0; i < length2; ++i) { const instance = instances[i]; const geometry = instance.geometry; if (defined_default(geometry)) { boundingSpheres[i] = geometry.boundingSphere; boundingSpheresCV[i] = geometry.boundingSphereCV; if (hasOffset) { offsetInstanceExtend[i] = instance.geometry.offsetAttribute; } } const eastHemisphereGeometry = instance.eastHemisphereGeometry; const westHemisphereGeometry = instance.westHemisphereGeometry; if (defined_default(eastHemisphereGeometry) && defined_default(westHemisphereGeometry)) { if (defined_default(eastHemisphereGeometry.boundingSphere) && defined_default(westHemisphereGeometry.boundingSphere)) { boundingSpheres[i] = BoundingSphere_default.union( eastHemisphereGeometry.boundingSphere, westHemisphereGeometry.boundingSphere ); } if (defined_default(eastHemisphereGeometry.boundingSphereCV) && defined_default(westHemisphereGeometry.boundingSphereCV)) { boundingSpheresCV[i] = BoundingSphere_default.union( eastHemisphereGeometry.boundingSphereCV, westHemisphereGeometry.boundingSphereCV ); } } } return { geometries, modelMatrix: parameters.modelMatrix, attributeLocations: attributeLocations8, pickOffsets, offsetInstanceExtend, boundingSpheres, boundingSpheresCV }; }; function transferGeometry(geometry, transferableObjects) { const attributes = geometry.attributes; for (const name in attributes) { if (attributes.hasOwnProperty(name)) { const attribute = attributes[name]; if (defined_default(attribute) && defined_default(attribute.values)) { transferableObjects.push(attribute.values.buffer); } } } if (defined_default(geometry.indices)) { transferableObjects.push(geometry.indices.buffer); } } function transferGeometries(geometries, transferableObjects) { const length2 = geometries.length; for (let i = 0; i < length2; ++i) { transferGeometry(geometries[i], transferableObjects); } } function countCreateGeometryResults(items) { let count = 1; const length2 = items.length; for (let i = 0; i < length2; i++) { const geometry = items[i]; ++count; if (!defined_default(geometry)) { continue; } const attributes = geometry.attributes; count += 7 + 2 * BoundingSphere_default.packedLength + (defined_default(geometry.indices) ? geometry.indices.length : 0); for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property])) { const attribute = attributes[property]; count += 5 + attribute.values.length; } } } return count; } PrimitivePipeline.packCreateGeometryResults = function(items, transferableObjects) { const packedData = new Float64Array(countCreateGeometryResults(items)); const stringTable = []; const stringHash = {}; const length2 = items.length; let count = 0; packedData[count++] = length2; for (let i = 0; i < length2; i++) { const geometry = items[i]; const validGeometry = defined_default(geometry); packedData[count++] = validGeometry ? 1 : 0; if (!validGeometry) { continue; } packedData[count++] = geometry.primitiveType; packedData[count++] = geometry.geometryType; packedData[count++] = geometry.offsetAttribute ?? -1; const validBoundingSphere = defined_default(geometry.boundingSphere) ? 1 : 0; packedData[count++] = validBoundingSphere; if (validBoundingSphere) { BoundingSphere_default.pack(geometry.boundingSphere, packedData, count); } count += BoundingSphere_default.packedLength; const validBoundingSphereCV = defined_default(geometry.boundingSphereCV) ? 1 : 0; packedData[count++] = validBoundingSphereCV; if (validBoundingSphereCV) { BoundingSphere_default.pack(geometry.boundingSphereCV, packedData, count); } count += BoundingSphere_default.packedLength; const attributes = geometry.attributes; const attributesToWrite = []; for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property])) { attributesToWrite.push(property); if (!defined_default(stringHash[property])) { stringHash[property] = stringTable.length; stringTable.push(property); } } } packedData[count++] = attributesToWrite.length; for (let q = 0; q < attributesToWrite.length; q++) { const name = attributesToWrite[q]; const attribute = attributes[name]; packedData[count++] = stringHash[name]; packedData[count++] = attribute.componentDatatype; packedData[count++] = attribute.componentsPerAttribute; packedData[count++] = attribute.normalize ? 1 : 0; packedData[count++] = attribute.values.length; packedData.set(attribute.values, count); count += attribute.values.length; } const indicesLength = defined_default(geometry.indices) ? geometry.indices.length : 0; packedData[count++] = indicesLength; if (indicesLength > 0) { packedData.set(geometry.indices, count); count += indicesLength; } } transferableObjects.push(packedData.buffer); return { stringTable, packedData }; }; PrimitivePipeline.unpackCreateGeometryResults = function(createGeometryResult) { const stringTable = createGeometryResult.stringTable; const packedGeometry = createGeometryResult.packedData; let i; const result = new Array(packedGeometry[0]); let resultIndex = 0; let packedGeometryIndex = 1; while (packedGeometryIndex < packedGeometry.length) { const valid = packedGeometry[packedGeometryIndex++] === 1; if (!valid) { result[resultIndex++] = void 0; continue; } const primitiveType = packedGeometry[packedGeometryIndex++]; const geometryType = packedGeometry[packedGeometryIndex++]; let offsetAttribute = packedGeometry[packedGeometryIndex++]; if (offsetAttribute === -1) { offsetAttribute = void 0; } let boundingSphere; let boundingSphereCV; const validBoundingSphere = packedGeometry[packedGeometryIndex++] === 1; if (validBoundingSphere) { boundingSphere = BoundingSphere_default.unpack( packedGeometry, packedGeometryIndex ); } packedGeometryIndex += BoundingSphere_default.packedLength; const validBoundingSphereCV = packedGeometry[packedGeometryIndex++] === 1; if (validBoundingSphereCV) { boundingSphereCV = BoundingSphere_default.unpack( packedGeometry, packedGeometryIndex ); } packedGeometryIndex += BoundingSphere_default.packedLength; let length2; let values; let componentsPerAttribute; const attributes = new GeometryAttributes_default(); const numAttributes = packedGeometry[packedGeometryIndex++]; for (i = 0; i < numAttributes; i++) { const name = stringTable[packedGeometry[packedGeometryIndex++]]; const componentDatatype = packedGeometry[packedGeometryIndex++]; componentsPerAttribute = packedGeometry[packedGeometryIndex++]; const normalize2 = packedGeometry[packedGeometryIndex++] !== 0; length2 = packedGeometry[packedGeometryIndex++]; values = ComponentDatatype_default.createTypedArray(componentDatatype, length2); for (let valuesIndex = 0; valuesIndex < length2; valuesIndex++) { values[valuesIndex] = packedGeometry[packedGeometryIndex++]; } attributes[name] = new GeometryAttribute_default({ componentDatatype, componentsPerAttribute, normalize: normalize2, values }); } let indices; length2 = packedGeometry[packedGeometryIndex++]; if (length2 > 0) { const numberOfVertices = values.length / componentsPerAttribute; indices = IndexDatatype_default.createTypedArray(numberOfVertices, length2); for (i = 0; i < length2; i++) { indices[i] = packedGeometry[packedGeometryIndex++]; } } result[resultIndex++] = new Geometry_default({ primitiveType, geometryType, boundingSphere, boundingSphereCV, indices, attributes, offsetAttribute }); } return result; }; function packInstancesForCombine(instances, transferableObjects) { const length2 = instances.length; const packedData = new Float64Array(1 + length2 * 19); let count = 0; packedData[count++] = length2; for (let i = 0; i < length2; i++) { const instance = instances[i]; Matrix4_default.pack(instance.modelMatrix, packedData, count); count += Matrix4_default.packedLength; if (defined_default(instance.attributes) && defined_default(instance.attributes.offset)) { const values = instance.attributes.offset.value; packedData[count] = values[0]; packedData[count + 1] = values[1]; packedData[count + 2] = values[2]; } count += 3; } transferableObjects.push(packedData.buffer); return packedData; } function unpackInstancesForCombine(data) { const packedInstances = data; const result = new Array(packedInstances[0]); let count = 0; let i = 1; while (i < packedInstances.length) { const modelMatrix = Matrix4_default.unpack(packedInstances, i); let attributes; i += Matrix4_default.packedLength; if (defined_default(packedInstances[i])) { attributes = { offset: new OffsetGeometryInstanceAttribute_default( packedInstances[i], packedInstances[i + 1], packedInstances[i + 2] ) }; } i += 3; result[count++] = { modelMatrix, attributes }; } return result; } PrimitivePipeline.packCombineGeometryParameters = function(parameters, transferableObjects) { const createGeometryResults = parameters.createGeometryResults; const length2 = createGeometryResults.length; for (let i = 0; i < length2; i++) { transferableObjects.push(createGeometryResults[i].packedData.buffer); } return { createGeometryResults: parameters.createGeometryResults, packedInstances: packInstancesForCombine( parameters.instances, transferableObjects ), ellipsoid: parameters.ellipsoid, isGeographic: parameters.projection instanceof GeographicProjection_default, elementIndexUintSupported: parameters.elementIndexUintSupported, scene3DOnly: parameters.scene3DOnly, vertexCacheOptimize: parameters.vertexCacheOptimize, compressVertices: parameters.compressVertices, modelMatrix: parameters.modelMatrix, createPickOffsets: parameters.createPickOffsets }; }; PrimitivePipeline.unpackCombineGeometryParameters = function(packedParameters) { const instances = unpackInstancesForCombine(packedParameters.packedInstances); const createGeometryResults = packedParameters.createGeometryResults; const length2 = createGeometryResults.length; let instanceIndex = 0; for (let resultIndex = 0; resultIndex < length2; resultIndex++) { const geometries = PrimitivePipeline.unpackCreateGeometryResults( createGeometryResults[resultIndex] ); const geometriesLength = geometries.length; for (let geometryIndex = 0; geometryIndex < geometriesLength; geometryIndex++) { const geometry = geometries[geometryIndex]; const instance = instances[instanceIndex]; instance.geometry = geometry; ++instanceIndex; } } const ellipsoid = Ellipsoid_default.clone(packedParameters.ellipsoid); const projection = packedParameters.isGeographic ? new GeographicProjection_default(ellipsoid) : new WebMercatorProjection_default(ellipsoid); return { instances, ellipsoid, projection, elementIndexUintSupported: packedParameters.elementIndexUintSupported, scene3DOnly: packedParameters.scene3DOnly, vertexCacheOptimize: packedParameters.vertexCacheOptimize, compressVertices: packedParameters.compressVertices, modelMatrix: Matrix4_default.clone(packedParameters.modelMatrix), createPickOffsets: packedParameters.createPickOffsets }; }; function packBoundingSpheres(boundingSpheres) { const length2 = boundingSpheres.length; const bufferLength = 1 + (BoundingSphere_default.packedLength + 1) * length2; const buffer2 = new Float32Array(bufferLength); let bufferIndex = 0; buffer2[bufferIndex++] = length2; for (let i = 0; i < length2; ++i) { const bs = boundingSpheres[i]; if (!defined_default(bs)) { buffer2[bufferIndex++] = 0; } else { buffer2[bufferIndex++] = 1; BoundingSphere_default.pack(boundingSpheres[i], buffer2, bufferIndex); } bufferIndex += BoundingSphere_default.packedLength; } return buffer2; } function unpackBoundingSpheres(buffer2) { const result = new Array(buffer2[0]); let count = 0; let i = 1; while (i < buffer2.length) { if (buffer2[i++] === 1) { result[count] = BoundingSphere_default.unpack(buffer2, i); } ++count; i += BoundingSphere_default.packedLength; } return result; } PrimitivePipeline.packCombineGeometryResults = function(results, transferableObjects) { if (defined_default(results.geometries)) { transferGeometries(results.geometries, transferableObjects); } const packedBoundingSpheres = packBoundingSpheres(results.boundingSpheres); const packedBoundingSpheresCV = packBoundingSpheres( results.boundingSpheresCV ); transferableObjects.push( packedBoundingSpheres.buffer, packedBoundingSpheresCV.buffer ); return { geometries: results.geometries, attributeLocations: results.attributeLocations, modelMatrix: results.modelMatrix, pickOffsets: results.pickOffsets, offsetInstanceExtend: results.offsetInstanceExtend, boundingSpheres: packedBoundingSpheres, boundingSpheresCV: packedBoundingSpheresCV }; }; PrimitivePipeline.unpackCombineGeometryResults = function(packedResult) { return { geometries: packedResult.geometries, attributeLocations: packedResult.attributeLocations, modelMatrix: packedResult.modelMatrix, pickOffsets: packedResult.pickOffsets, offsetInstanceExtend: packedResult.offsetInstanceExtend, boundingSpheres: unpackBoundingSpheres(packedResult.boundingSpheres), boundingSpheresCV: unpackBoundingSpheres(packedResult.boundingSpheresCV) }; }; var PrimitivePipeline_default = PrimitivePipeline; // packages/engine/Source/Scene/PrimitiveState.js var import_InlineWorkers369 = __toESM(require_InlineWorkers(), 1); var PrimitiveState = { /** * The initial state of a primitive. * * Note that this does NOT mean that the primitive is "ready", as indicated * by the _ready property. It means the opposite: Nothing was * done with the primitive at all. * * For primitives that are created with the asynchronous:true * setting and that are in this state, the update call starts * the creation of the geometry using web workers, and the primitive goes * into the CREATING state. * * For synchronously created primitives, this state never matters. They will * go into the COMBINED (or FAILED) state directly due to a call to the * update function, if they are not yet FAILED, COMBINED, * or COMPLETE. */ READY: 0, /** * The process of creating the primitive geometry is ongoing. * * A primitive can only ever be in this state when it was created * with the asynchronous:true setting. * * It means that web workers are currently creating the geometry * of the primitive. * * When the geometry creation succeeds, then the primitive will go * into the CREATED state. Otherwise, it will go into the FAILED * state. Both will happen asynchronously. * * The update function has to be called regularly * until either of these states is reached. */ CREATING: 1, /** * The geometry for the primitive has been created. * * A primitive can only ever be in this state when it was created * with the asynchronous:true setting. * * It means that web workers have (asynchronously) finished the * creation of the geometry, but further (asynchronous) processing * is necessary: If a primitive is determined to be in this state * during a call to update, an asynchronous process * is triggered to "combine" the geometry, meaning that the primitive * will go into the COMBINING state. */ CREATED: 2, /** * The asynchronous creation of the geometry has been finished, but the * asynchronous process of combining the geometry has not finished yet. * * A primitive can only ever be in this state when it was created * with the asynchronous:true setting. * * It means that whatever is done with * PrimitivePipeline.packCombineGeometryParameters has * not finished yet. When combining the geometry succeeds, the * primitive will go into the COMBINED state. Otherwise, it will * go into the FAILED state. */ COMBINING: 3, /** * The geometry data is in a form that can be uploaded to the GPU. * * For synchronous primitives, this means that the geometry * has been created (synchronously) due to the first call to the * update function. * * For asynchronous primitives, this means that the asynchronous * creation of the geometry and the asynchronous combination of the * geometry have both finished. * * The update function has to be called regularly until * this state is reached. When it is reached, the update * call will cause the transition into the COMPLETE state. */ COMBINED: 4, /** * The geometry has been created and uploaded to the GPU. * * When this state is reached, it eventually causes the _ready * flag of the primitive to become true. * * Note: Setting the ready flag does NOT happen in the * update call: It only happens after rendering the next * frame! * * Note: This state does not mean that nothing has to be done * anymore (so the work is not "complete"). When the primitive is in * this state, the update function still has to be * called regularly. */ COMPLETE: 5, /** * The creation of the primitive failed. * * When this state is reached, it eventually causes the _ready * flag of the primitive to become true. * * Note: Setting the ready flag does NOT happen in the * update call: It only happens after rendering the next * frame! * * This state can be reached when the (synchronous or asynchronous) * creation of the geometry, or the (asynchronous) combination of * the geometry caused any form of error. * * It may or may not imply the presence of the _error property. * When the _error property is present on a FAILED primitive, * this error will be thrown during the update call. When it * is not present for a FAILED primitive, then the update call * will do nothing. */ FAILED: 6 }; Object.freeze(PrimitiveState); var PrimitiveState_default = PrimitiveState; // packages/engine/Source/Scene/ShadowMode.js var import_InlineWorkers370 = __toESM(require_InlineWorkers(), 1); var ShadowMode = { /** * The object does not cast or receive shadows. * * @type {number} * @constant */ DISABLED: 0, /** * The object casts and receives shadows. * * @type {number} * @constant */ ENABLED: 1, /** * The object casts shadows only. * * @type {number} * @constant */ CAST_ONLY: 2, /** * The object receives shadows only. * * @type {number} * @constant */ RECEIVE_ONLY: 3 }; ShadowMode.NUMBER_OF_SHADOW_MODES = 4; ShadowMode.castShadows = function(shadowMode) { return shadowMode === ShadowMode.ENABLED || shadowMode === ShadowMode.CAST_ONLY; }; ShadowMode.receiveShadows = function(shadowMode) { return shadowMode === ShadowMode.ENABLED || shadowMode === ShadowMode.RECEIVE_ONLY; }; ShadowMode.fromCastReceive = function(castShadows, receiveShadows) { if (castShadows && receiveShadows) { return ShadowMode.ENABLED; } else if (castShadows) { return ShadowMode.CAST_ONLY; } else if (receiveShadows) { return ShadowMode.RECEIVE_ONLY; } return ShadowMode.DISABLED; }; Object.freeze(ShadowMode); var ShadowMode_default = ShadowMode; // packages/engine/Source/Scene/Primitive.js function Primitive(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.geometryInstances = options.geometryInstances; this.appearance = options.appearance; this._appearance = void 0; this._material = void 0; this.depthFailAppearance = options.depthFailAppearance; this._depthFailAppearance = void 0; this._depthFailMaterial = void 0; this.modelMatrix = Matrix4_default.clone(options.modelMatrix ?? Matrix4_default.IDENTITY); this._modelMatrix = new Matrix4_default(); this.show = options.show ?? true; this._vertexCacheOptimize = options.vertexCacheOptimize ?? false; this._interleave = options.interleave ?? false; this._releaseGeometryInstances = options.releaseGeometryInstances ?? true; this._allowPicking = options.allowPicking ?? true; this._asynchronous = options.asynchronous ?? true; this._compressVertices = options.compressVertices ?? true; this.cull = options.cull ?? true; this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false; this.rtcCenter = options.rtcCenter; if (defined_default(this.rtcCenter) && (!defined_default(this.geometryInstances) || Array.isArray(this.geometryInstances) && this.geometryInstances.length !== 1)) { throw new DeveloperError_default( "Relative-to-center rendering only supports one geometry instance." ); } this.shadows = options.shadows ?? ShadowMode_default.DISABLED; this._translucent = void 0; this._state = PrimitiveState_default.READY; this._geometries = []; this._error = void 0; this._numberOfInstances = 0; this._boundingSpheres = []; this._boundingSphereWC = []; this._boundingSphereCV = []; this._boundingSphere2D = []; this._boundingSphereMorph = []; this._perInstanceAttributeCache = /* @__PURE__ */ new Map(); this._instanceIds = []; this._lastPerInstanceAttributeIndex = 0; this._va = []; this._attributeLocations = void 0; this._primitiveType = void 0; this._frontFaceRS = void 0; this._backFaceRS = void 0; this._sp = void 0; this._depthFailAppearance = void 0; this._spDepthFail = void 0; this._frontFaceDepthFailRS = void 0; this._backFaceDepthFailRS = void 0; this._pickIds = []; this._colorCommands = []; this._pickCommands = []; this._createBoundingVolumeFunction = options._createBoundingVolumeFunction; this._createRenderStatesFunction = options._createRenderStatesFunction; this._createShaderProgramFunction = options._createShaderProgramFunction; this._createCommandsFunction = options._createCommandsFunction; this._updateAndQueueCommandsFunction = options._updateAndQueueCommandsFunction; this._createPickOffsets = options._createPickOffsets; this._pickOffsets = void 0; this._createGeometryResults = void 0; this._ready = false; this._batchTable = void 0; this._batchTableAttributeIndices = void 0; this._offsetInstanceExtend = void 0; this._batchTableOffsetAttribute2DIndex = void 0; this._batchTableOffsetsUpdated = false; this._instanceBoundingSpheres = void 0; this._instanceBoundingSpheresCV = void 0; this._tempBoundingSpheres = void 0; this._recomputeBoundingSpheres = false; this._batchTableBoundingSpheresUpdated = false; this._batchTableBoundingSphereAttributeIndices = void 0; } Object.defineProperties(Primitive.prototype, { /** * When true, geometry vertices are optimized for the pre and post-vertex-shader caches. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default true */ vertexCacheOptimize: { get: function() { return this._vertexCacheOptimize; } }, /** * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default false */ interleave: { get: function() { return this._interleave; } }, /** * When true, the primitive does not keep a reference to the input geometryInstances to save memory. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default true */ releaseGeometryInstances: { get: function() { return this._releaseGeometryInstances; } }, /** * When true, each geometry instance will only be pickable with {@link Scene#pick}. When false, GPU memory is saved. * * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default true */ allowPicking: { get: function() { return this._allowPicking; } }, /** * Determines if the geometry instances will be created and batched on a web worker. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default true */ asynchronous: { get: function() { return this._asynchronous; } }, /** * When true, geometry vertices are compressed, which will save memory. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @default true */ compressVertices: { get: function() { return this._compressVertices; } }, /** * Determines if the primitive is complete and ready to render. If this property is * true, the primitive will be rendered the next time that {@link Primitive#update} * is called. * * @memberof Primitive.prototype * * @type {boolean} * @readonly * * @example * // Wait for a primitive to become ready before accessing attributes * const removeListener = scene.postRender.addEventListener(() => { * if (!frustumPrimitive.ready) { * return; * } * * const attributes = primitive.getGeometryInstanceAttributes('an id'); * attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.AQUA); * * removeListener(); * }); */ ready: { get: function() { return this._ready; } } }); function getCommonPerInstanceAttributeNames(instances) { const length2 = instances.length; const attributesInAllInstances = []; const attributes0 = instances[0].attributes; let name; for (name in attributes0) { if (attributes0.hasOwnProperty(name) && defined_default(attributes0[name])) { const attribute = attributes0[name]; let inAllInstances = true; for (let i = 1; i < length2; ++i) { const otherAttribute = instances[i].attributes[name]; if (!defined_default(otherAttribute) || attribute.componentDatatype !== otherAttribute.componentDatatype || attribute.componentsPerAttribute !== otherAttribute.componentsPerAttribute || attribute.normalize !== otherAttribute.normalize) { inAllInstances = false; break; } } if (inAllInstances) { attributesInAllInstances.push(name); } } } return attributesInAllInstances; } var scratchGetAttributeCartesian2 = new Cartesian2_default(); var scratchGetAttributeCartesian3 = new Cartesian3_default(); var scratchGetAttributeCartesian42 = new Cartesian4_default(); function getAttributeValue(value) { const componentsPerAttribute = value.length; if (componentsPerAttribute === 1) { return value[0]; } else if (componentsPerAttribute === 2) { return Cartesian2_default.unpack(value, 0, scratchGetAttributeCartesian2); } else if (componentsPerAttribute === 3) { return Cartesian3_default.unpack(value, 0, scratchGetAttributeCartesian3); } else if (componentsPerAttribute === 4) { return Cartesian4_default.unpack(value, 0, scratchGetAttributeCartesian42); } } function createBatchTable(primitive, context) { const geometryInstances = primitive.geometryInstances; const instances = Array.isArray(geometryInstances) ? geometryInstances : [geometryInstances]; const numberOfInstances = instances.length; if (numberOfInstances === 0) { return; } const names = getCommonPerInstanceAttributeNames(instances); const length2 = names.length; const attributes = []; const attributeIndices = {}; const boundingSphereAttributeIndices = {}; let offset2DIndex; const firstInstance = instances[0]; let instanceAttributes = firstInstance.attributes; let i; let name; let attribute; for (i = 0; i < length2; ++i) { name = names[i]; attribute = instanceAttributes[name]; attributeIndices[name] = i; attributes.push({ functionName: `czm_batchTable_${name}`, componentDatatype: attribute.componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize }); } if (names.indexOf("distanceDisplayCondition") !== -1) { attributes.push( { functionName: "czm_batchTable_boundingSphereCenter3DHigh", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3 }, { functionName: "czm_batchTable_boundingSphereCenter3DLow", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3 }, { functionName: "czm_batchTable_boundingSphereCenter2DHigh", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3 }, { functionName: "czm_batchTable_boundingSphereCenter2DLow", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3 }, { functionName: "czm_batchTable_boundingSphereRadius", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 1 } ); boundingSphereAttributeIndices.center3DHigh = attributes.length - 5; boundingSphereAttributeIndices.center3DLow = attributes.length - 4; boundingSphereAttributeIndices.center2DHigh = attributes.length - 3; boundingSphereAttributeIndices.center2DLow = attributes.length - 2; boundingSphereAttributeIndices.radius = attributes.length - 1; } if (names.indexOf("offset") !== -1) { attributes.push({ functionName: "czm_batchTable_offset2D", componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3 }); offset2DIndex = attributes.length - 1; } attributes.push({ functionName: "czm_batchTable_pickColor", componentDatatype: ComponentDatatype_default.UNSIGNED_BYTE, componentsPerAttribute: 4, normalize: true }); const attributesLength = attributes.length; const batchTable = new BatchTable_default(context, attributes, numberOfInstances); for (i = 0; i < numberOfInstances; ++i) { const instance = instances[i]; instanceAttributes = instance.attributes; for (let j = 0; j < length2; ++j) { name = names[j]; attribute = instanceAttributes[name]; const value = getAttributeValue(attribute.value); const attributeIndex = attributeIndices[name]; batchTable.setBatchedAttribute(i, attributeIndex, value); } const pickObject = { primitive: instance.pickPrimitive ?? primitive }; if (defined_default(instance.id)) { pickObject.id = instance.id; } const pickId = context.createPickId(pickObject); primitive._pickIds.push(pickId); const pickColor4 = pickId.color; const color = scratchGetAttributeCartesian42; color.x = Color_default.floatToByte(pickColor4.red); color.y = Color_default.floatToByte(pickColor4.green); color.z = Color_default.floatToByte(pickColor4.blue); color.w = Color_default.floatToByte(pickColor4.alpha); batchTable.setBatchedAttribute(i, attributesLength - 1, color); } primitive._batchTable = batchTable; primitive._batchTableAttributeIndices = attributeIndices; primitive._batchTableBoundingSphereAttributeIndices = boundingSphereAttributeIndices; primitive._batchTableOffsetAttribute2DIndex = offset2DIndex; } function cloneAttribute(attribute) { let clonedValues; if (Array.isArray(attribute.values)) { clonedValues = attribute.values.slice(0); } else { clonedValues = new attribute.values.constructor(attribute.values); } return new GeometryAttribute_default({ componentDatatype: attribute.componentDatatype, componentsPerAttribute: attribute.componentsPerAttribute, normalize: attribute.normalize, values: clonedValues }); } function cloneGeometry(geometry) { const attributes = geometry.attributes; const newAttributes = new GeometryAttributes_default(); for (const property in attributes) { if (attributes.hasOwnProperty(property) && defined_default(attributes[property])) { newAttributes[property] = cloneAttribute(attributes[property]); } } let indices; if (defined_default(geometry.indices)) { const sourceValues = geometry.indices; if (Array.isArray(sourceValues)) { indices = sourceValues.slice(0); } else { indices = new sourceValues.constructor(sourceValues); } } return new Geometry_default({ attributes: newAttributes, indices, primitiveType: geometry.primitiveType, boundingSphere: BoundingSphere_default.clone(geometry.boundingSphere) }); } function cloneInstance(instance, geometry) { return { geometry, attributes: instance.attributes, modelMatrix: Matrix4_default.clone(instance.modelMatrix), pickPrimitive: instance.pickPrimitive, id: instance.id }; } var positionRegex = /in\s+vec(?:3|4)\s+(.*)3DHigh;/g; Primitive._modifyShaderPosition = function(primitive, vertexShaderSource, scene3DOnly) { let match; let forwardDecl = ""; let attributes = ""; let computeFunctions = ""; while ((match = positionRegex.exec(vertexShaderSource)) !== null) { const name = match[1]; const functionName = `vec4 czm_compute${name[0].toUpperCase()}${name.substr( 1 )}()`; if (functionName !== "vec4 czm_computePosition()") { forwardDecl += `${functionName}; `; } if (!defined_default(primitive.rtcCenter)) { if (!scene3DOnly) { attributes += `in vec3 ${name}2DHigh; in vec3 ${name}2DLow; `; computeFunctions += `${functionName} { vec4 p; if (czm_morphTime == 1.0) { p = czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow); } else if (czm_morphTime == 0.0) { p = czm_translateRelativeToEye(${name}2DHigh.zxy, ${name}2DLow.zxy); } else { p = czm_columbusViewMorph( czm_translateRelativeToEye(${name}2DHigh.zxy, ${name}2DLow.zxy), czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow), czm_morphTime); } return p; } `; } else { computeFunctions += `${functionName} { return czm_translateRelativeToEye(${name}3DHigh, ${name}3DLow); } `; } } else { vertexShaderSource = vertexShaderSource.replace( /in\s+vec(?:3|4)\s+position3DHigh;/g, "" ); vertexShaderSource = vertexShaderSource.replace( /in\s+vec(?:3|4)\s+position3DLow;/g, "" ); forwardDecl += "uniform mat4 u_modifiedModelView;\n"; attributes += "in vec4 position;\n"; computeFunctions += `${functionName} { return u_modifiedModelView * position; } `; vertexShaderSource = vertexShaderSource.replace( /czm_modelViewRelativeToEye\s+\*\s+/g, "" ); vertexShaderSource = vertexShaderSource.replace( /czm_modelViewProjectionRelativeToEye/g, "czm_projection" ); } } return [forwardDecl, attributes, vertexShaderSource, computeFunctions].join( "\n" ); }; Primitive._appendShowToShader = function(primitive, vertexShaderSource) { if (!defined_default(primitive._batchTableAttributeIndices.show)) { return vertexShaderSource; } const renamedVS = ShaderSource_default.replaceMain( vertexShaderSource, "czm_non_show_main" ); const showMain = "void main() \n{ \n czm_non_show_main(); \n gl_Position *= czm_batchTable_show(batchId); \n}"; return `${renamedVS} ${showMain}`; }; Primitive._updateColorAttribute = function(primitive, vertexShaderSource, isDepthFail) { if (!defined_default(primitive._batchTableAttributeIndices.color) && !defined_default(primitive._batchTableAttributeIndices.depthFailColor)) { return vertexShaderSource; } if (vertexShaderSource.search(/in\s+vec4\s+color;/g) === -1) { return vertexShaderSource; } if (isDepthFail && !defined_default(primitive._batchTableAttributeIndices.depthFailColor)) { throw new DeveloperError_default( "A depthFailColor per-instance attribute is required when using a depth fail appearance that uses a color attribute." ); } let modifiedVS = vertexShaderSource; modifiedVS = modifiedVS.replace(/in\s+vec4\s+color;/g, ""); if (!isDepthFail) { modifiedVS = modifiedVS.replace( /(\b)color(\b)/g, "$1czm_batchTable_color(batchId)$2" ); } else { modifiedVS = modifiedVS.replace( /(\b)color(\b)/g, "$1czm_batchTable_depthFailColor(batchId)$2" ); } return modifiedVS; }; function appendPickToVertexShader(source) { const renamedVS = ShaderSource_default.replaceMain(source, "czm_non_pick_main"); const pickMain = "out vec4 v_pickColor; \nvoid main() \n{ \n czm_non_pick_main(); \n v_pickColor = czm_batchTable_pickColor(batchId); \n}"; return `${renamedVS} ${pickMain}`; } function appendPickToFragmentShader(source) { return `in vec4 v_pickColor; ${source}`; } Primitive._updatePickColorAttribute = function(source) { let vsPick = source.replace(/in\s+vec4\s+pickColor;/g, ""); vsPick = vsPick.replace( /(\b)pickColor(\b)/g, "$1czm_batchTable_pickColor(batchId)$2" ); return vsPick; }; Primitive._appendOffsetToShader = function(primitive, vertexShaderSource) { if (!defined_default(primitive._batchTableAttributeIndices.offset)) { return vertexShaderSource; } let attr = "in float batchId;\n"; attr += "in float applyOffset;"; let modifiedShader = vertexShaderSource.replace( /in\s+float\s+batchId;/g, attr ); let str = "vec4 $1 = czm_computePosition();\n"; str += " if (czm_sceneMode == czm_sceneMode3D)\n"; str += " {\n"; str += " $1 = $1 + vec4(czm_batchTable_offset(batchId) * applyOffset, 0.0);"; str += " }\n"; str += " else\n"; str += " {\n"; str += " $1 = $1 + vec4(czm_batchTable_offset2D(batchId) * applyOffset, 0.0);"; str += " }\n"; modifiedShader = modifiedShader.replace( /vec4\s+([A-Za-z0-9_]+)\s+=\s+czm_computePosition\(\);/g, str ); return modifiedShader; }; Primitive._appendDistanceDisplayConditionToShader = function(primitive, vertexShaderSource, scene3DOnly) { if (!defined_default(primitive._batchTableAttributeIndices.distanceDisplayCondition)) { return vertexShaderSource; } const renamedVS = ShaderSource_default.replaceMain( vertexShaderSource, "czm_non_distanceDisplayCondition_main" ); let distanceDisplayConditionMain = "void main() \n{ \n czm_non_distanceDisplayCondition_main(); \n vec2 distanceDisplayCondition = czm_batchTable_distanceDisplayCondition(batchId);\n vec3 boundingSphereCenter3DHigh = czm_batchTable_boundingSphereCenter3DHigh(batchId);\n vec3 boundingSphereCenter3DLow = czm_batchTable_boundingSphereCenter3DLow(batchId);\n float boundingSphereRadius = czm_batchTable_boundingSphereRadius(batchId);\n"; if (!scene3DOnly) { distanceDisplayConditionMain += " vec3 boundingSphereCenter2DHigh = czm_batchTable_boundingSphereCenter2DHigh(batchId);\n vec3 boundingSphereCenter2DLow = czm_batchTable_boundingSphereCenter2DLow(batchId);\n vec4 centerRTE;\n if (czm_morphTime == 1.0)\n {\n centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n }\n else if (czm_morphTime == 0.0)\n {\n centerRTE = czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy);\n }\n else\n {\n centerRTE = czm_columbusViewMorph(\n czm_translateRelativeToEye(boundingSphereCenter2DHigh.zxy, boundingSphereCenter2DLow.zxy),\n czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow),\n czm_morphTime);\n }\n"; } else { distanceDisplayConditionMain += " vec4 centerRTE = czm_translateRelativeToEye(boundingSphereCenter3DHigh, boundingSphereCenter3DLow);\n"; } distanceDisplayConditionMain += " float radiusSq = boundingSphereRadius * boundingSphereRadius; \n float distanceSq; \n if (czm_sceneMode == czm_sceneMode2D) \n { \n distanceSq = czm_eyeHeight2D.y - radiusSq; \n } \n else \n { \n distanceSq = dot(centerRTE.xyz, centerRTE.xyz) - radiusSq; \n } \n distanceSq = max(distanceSq, 0.0); \n float nearSq = distanceDisplayCondition.x * distanceDisplayCondition.x; \n float farSq = distanceDisplayCondition.y * distanceDisplayCondition.y; \n float show = (distanceSq >= nearSq && distanceSq <= farSq) ? 1.0 : 0.0; \n gl_Position *= show; \n}"; return `${renamedVS} ${distanceDisplayConditionMain}`; }; function modifyForEncodedNormals(primitive, vertexShaderSource) { if (!primitive.compressVertices) { return vertexShaderSource; } const containsNormal = vertexShaderSource.search(/in\s+vec3\s+normal;/g) !== -1; const containsSt = vertexShaderSource.search(/in\s+vec2\s+st;/g) !== -1; if (!containsNormal && !containsSt) { return vertexShaderSource; } const containsTangent = vertexShaderSource.search(/in\s+vec3\s+tangent;/g) !== -1; const containsBitangent = vertexShaderSource.search(/in\s+vec3\s+bitangent;/g) !== -1; let numComponents = containsSt && containsNormal ? 2 : 1; numComponents += containsTangent || containsBitangent ? 1 : 0; const type = numComponents > 1 ? `vec${numComponents}` : "float"; const attributeName = "compressedAttributes"; const attributeDecl = `in ${type} ${attributeName};`; let globalDecl = ""; let decode = ""; if (containsSt) { globalDecl += "vec2 st;\n"; const stComponent = numComponents > 1 ? `${attributeName}.x` : attributeName; decode += ` st = czm_decompressTextureCoordinates(${stComponent}); `; } if (containsNormal && containsTangent && containsBitangent) { globalDecl += "vec3 normal;\nvec3 tangent;\nvec3 bitangent;\n"; decode += ` czm_octDecode(${attributeName}.${containsSt ? "yz" : "xy"}, normal, tangent, bitangent); `; } else { if (containsNormal) { globalDecl += "vec3 normal;\n"; decode += ` normal = czm_octDecode(${attributeName}${numComponents > 1 ? `.${containsSt ? "y" : "x"}` : ""}); `; } if (containsTangent) { globalDecl += "vec3 tangent;\n"; decode += ` tangent = czm_octDecode(${attributeName}.${containsSt && containsNormal ? "z" : "y"}); `; } if (containsBitangent) { globalDecl += "vec3 bitangent;\n"; decode += ` bitangent = czm_octDecode(${attributeName}.${containsSt && containsNormal ? "z" : "y"}); `; } } let modifiedVS = vertexShaderSource; modifiedVS = modifiedVS.replace(/in\s+vec3\s+normal;/g, ""); modifiedVS = modifiedVS.replace(/in\s+vec2\s+st;/g, ""); modifiedVS = modifiedVS.replace(/in\s+vec3\s+tangent;/g, ""); modifiedVS = modifiedVS.replace(/in\s+vec3\s+bitangent;/g, ""); modifiedVS = ShaderSource_default.replaceMain(modifiedVS, "czm_non_compressed_main"); const compressedMain = `${"void main() \n{ \n"}${decode} czm_non_compressed_main(); }`; return [attributeDecl, globalDecl, modifiedVS, compressedMain].join("\n"); } function depthClampVS(vertexShaderSource) { let modifiedVS = ShaderSource_default.replaceMain( vertexShaderSource, "czm_non_depth_clamp_main" ); modifiedVS += "void main() {\n czm_non_depth_clamp_main();\n gl_Position = czm_depthClamp(gl_Position);}\n"; return modifiedVS; } function depthClampFS(fragmentShaderSource) { let modifiedFS = ShaderSource_default.replaceMain( fragmentShaderSource, "czm_non_depth_clamp_main" ); modifiedFS += "void main() {\n czm_non_depth_clamp_main();\n #if defined(LOG_DEPTH)\n czm_writeLogDepth();\n #else\n czm_writeDepthClamp();\n #endif\n}\n"; return modifiedFS; } function validateShaderMatching(shaderProgram, attributeLocations8) { const shaderAttributes = shaderProgram.vertexAttributes; for (const name in shaderAttributes) { if (shaderAttributes.hasOwnProperty(name)) { if (!defined_default(attributeLocations8[name])) { throw new DeveloperError_default( `Appearance/Geometry mismatch. The appearance requires vertex shader attribute input '${name}', which was not computed as part of the Geometry. Use the appearance's vertexFormat property when constructing the geometry.` ); } } } } function getUniformFunction(uniforms, name) { return function() { return uniforms[name]; }; } var numberOfCreationWorkers = Math.max( FeatureDetection_default.hardwareConcurrency - 1, 1 ); var createGeometryTaskProcessors; var combineGeometryTaskProcessor = new TaskProcessor_default("combineGeometry"); function loadAsynchronous(primitive, frameState) { let instances; let geometry; let i; let j; const instanceIds = primitive._instanceIds; if (primitive._state === PrimitiveState_default.READY) { instances = Array.isArray(primitive.geometryInstances) ? primitive.geometryInstances : [primitive.geometryInstances]; const length2 = primitive._numberOfInstances = instances.length; const promises = []; let subTasks = []; for (i = 0; i < length2; ++i) { geometry = instances[i].geometry; instanceIds.push(instances[i].id); if (defined_default(geometry._workerName) && defined_default(geometry._workerPath) || !defined_default(geometry._workerName) && !defined_default(geometry._workerPath)) { throw new DeveloperError_default( "Must define either _workerName or _workerPath for asynchronous geometry." ); } subTasks.push({ moduleName: geometry._workerName, modulePath: geometry._workerPath, geometry }); } if (!defined_default(createGeometryTaskProcessors)) { createGeometryTaskProcessors = new Array(numberOfCreationWorkers); for (i = 0; i < numberOfCreationWorkers; i++) { createGeometryTaskProcessors[i] = new TaskProcessor_default("createGeometry"); } } let subTask; subTasks = subdivideArray_default(subTasks, numberOfCreationWorkers); for (i = 0; i < subTasks.length; i++) { let packedLength = 0; const workerSubTasks = subTasks[i]; const workerSubTasksLength = workerSubTasks.length; for (j = 0; j < workerSubTasksLength; ++j) { subTask = workerSubTasks[j]; geometry = subTask.geometry; if (defined_default(geometry.constructor.pack)) { subTask.offset = packedLength; packedLength += geometry.constructor.packedLength ?? geometry.packedLength; } } let subTaskTransferableObjects; if (packedLength > 0) { const array = new Float64Array(packedLength); subTaskTransferableObjects = [array.buffer]; for (j = 0; j < workerSubTasksLength; ++j) { subTask = workerSubTasks[j]; geometry = subTask.geometry; if (defined_default(geometry.constructor.pack)) { geometry.constructor.pack(geometry, array, subTask.offset); subTask.geometry = array; } } } promises.push( createGeometryTaskProcessors[i].scheduleTask( { subTasks: subTasks[i] }, subTaskTransferableObjects ) ); } primitive._state = PrimitiveState_default.CREATING; Promise.all(promises).then(function(results) { primitive._createGeometryResults = results; primitive._state = PrimitiveState_default.CREATED; }).catch(function(error) { setReady(primitive, frameState, PrimitiveState_default.FAILED, error); }); } else if (primitive._state === PrimitiveState_default.CREATED) { const transferableObjects = []; instances = Array.isArray(primitive.geometryInstances) ? primitive.geometryInstances : [primitive.geometryInstances]; const scene3DOnly = frameState.scene3DOnly; const projection = frameState.mapProjection; const promise = combineGeometryTaskProcessor.scheduleTask( PrimitivePipeline_default.packCombineGeometryParameters( { createGeometryResults: primitive._createGeometryResults, instances, ellipsoid: projection.ellipsoid, projection, elementIndexUintSupported: frameState.context.elementIndexUint, scene3DOnly, vertexCacheOptimize: primitive.vertexCacheOptimize, compressVertices: primitive.compressVertices, modelMatrix: primitive.modelMatrix, createPickOffsets: primitive._createPickOffsets }, transferableObjects ), transferableObjects ); primitive._createGeometryResults = void 0; primitive._state = PrimitiveState_default.COMBINING; Promise.resolve(promise).then(function(packedResult) { const result = PrimitivePipeline_default.unpackCombineGeometryResults(packedResult); primitive._geometries = result.geometries; primitive._attributeLocations = result.attributeLocations; primitive.modelMatrix = Matrix4_default.clone( result.modelMatrix, primitive.modelMatrix ); primitive._pickOffsets = result.pickOffsets; primitive._offsetInstanceExtend = result.offsetInstanceExtend; primitive._instanceBoundingSpheres = result.boundingSpheres; primitive._instanceBoundingSpheresCV = result.boundingSpheresCV; if (defined_default(primitive._geometries) && primitive._geometries.length > 0) { primitive._recomputeBoundingSpheres = true; primitive._state = PrimitiveState_default.COMBINED; } else { setReady(primitive, frameState, PrimitiveState_default.FAILED, void 0); } }).catch(function(error) { setReady(primitive, frameState, PrimitiveState_default.FAILED, error); }); } } function loadSynchronous(primitive, frameState) { const instances = Array.isArray(primitive.geometryInstances) ? primitive.geometryInstances : [primitive.geometryInstances]; const length2 = primitive._numberOfInstances = instances.length; const clonedInstances = new Array(length2); const instanceIds = primitive._instanceIds; let instance; let i; let geometryIndex = 0; for (i = 0; i < length2; i++) { instance = instances[i]; const geometry = instance.geometry; let createdGeometry; if (defined_default(geometry.attributes) && defined_default(geometry.primitiveType)) { createdGeometry = cloneGeometry(geometry); } else { createdGeometry = geometry.constructor.createGeometry(geometry); } clonedInstances[geometryIndex++] = cloneInstance(instance, createdGeometry); instanceIds.push(instance.id); } clonedInstances.length = geometryIndex; const scene3DOnly = frameState.scene3DOnly; const projection = frameState.mapProjection; const result = PrimitivePipeline_default.combineGeometry({ instances: clonedInstances, ellipsoid: projection.ellipsoid, projection, elementIndexUintSupported: frameState.context.elementIndexUint, scene3DOnly, vertexCacheOptimize: primitive.vertexCacheOptimize, compressVertices: primitive.compressVertices, modelMatrix: primitive.modelMatrix, createPickOffsets: primitive._createPickOffsets }); primitive._geometries = result.geometries; primitive._attributeLocations = result.attributeLocations; primitive.modelMatrix = Matrix4_default.clone( result.modelMatrix, primitive.modelMatrix ); primitive._pickOffsets = result.pickOffsets; primitive._offsetInstanceExtend = result.offsetInstanceExtend; primitive._instanceBoundingSpheres = result.boundingSpheres; primitive._instanceBoundingSpheresCV = result.boundingSpheresCV; if (defined_default(primitive._geometries) && primitive._geometries.length > 0) { primitive._recomputeBoundingSpheres = true; primitive._state = PrimitiveState_default.COMBINED; } else { setReady(primitive, frameState, PrimitiveState_default.FAILED, void 0); } } function recomputeBoundingSpheres(primitive, frameState) { const offsetIndex = primitive._batchTableAttributeIndices.offset; if (!primitive._recomputeBoundingSpheres || !defined_default(offsetIndex)) { primitive._recomputeBoundingSpheres = false; return; } let i; const offsetInstanceExtend = primitive._offsetInstanceExtend; const boundingSpheres = primitive._instanceBoundingSpheres; const length2 = boundingSpheres.length; let newBoundingSpheres = primitive._tempBoundingSpheres; if (!defined_default(newBoundingSpheres)) { newBoundingSpheres = new Array(length2); for (i = 0; i < length2; i++) { newBoundingSpheres[i] = new BoundingSphere_default(); } primitive._tempBoundingSpheres = newBoundingSpheres; } for (i = 0; i < length2; ++i) { let newBS = newBoundingSpheres[i]; const offset = primitive._batchTable.getBatchedAttribute( i, offsetIndex, new Cartesian3_default() ); newBS = boundingSpheres[i].clone(newBS); transformBoundingSphere(newBS, offset, offsetInstanceExtend[i]); } const combinedBS = []; const combinedWestBS = []; const combinedEastBS = []; for (i = 0; i < length2; ++i) { const bs = newBoundingSpheres[i]; const minX = bs.center.x - bs.radius; if (minX > 0 || BoundingSphere_default.intersectPlane(bs, Plane_default.ORIGIN_ZX_PLANE) !== Intersect_default.INTERSECTING) { combinedBS.push(bs); } else { combinedWestBS.push(bs); combinedEastBS.push(bs); } } let resultBS1 = combinedBS[0]; let resultBS2 = combinedEastBS[0]; let resultBS3 = combinedWestBS[0]; for (i = 1; i < combinedBS.length; i++) { resultBS1 = BoundingSphere_default.union(resultBS1, combinedBS[i]); } for (i = 1; i < combinedEastBS.length; i++) { resultBS2 = BoundingSphere_default.union(resultBS2, combinedEastBS[i]); } for (i = 1; i < combinedWestBS.length; i++) { resultBS3 = BoundingSphere_default.union(resultBS3, combinedWestBS[i]); } const result = []; if (defined_default(resultBS1)) { result.push(resultBS1); } if (defined_default(resultBS2)) { result.push(resultBS2); } if (defined_default(resultBS3)) { result.push(resultBS3); } for (i = 0; i < result.length; i++) { const boundingSphere = result[i].clone(primitive._boundingSpheres[i]); primitive._boundingSpheres[i] = boundingSphere; primitive._boundingSphereCV[i] = BoundingSphere_default.projectTo2D( boundingSphere, frameState.mapProjection, primitive._boundingSphereCV[i] ); } Primitive._updateBoundingVolumes( primitive, frameState, primitive.modelMatrix, true ); primitive._recomputeBoundingSpheres = false; } var scratchBoundingSphereCenterEncoded = new EncodedCartesian3_default(); var scratchBoundingSphereCartographic = new Cartographic_default(); var scratchBoundingSphereCenter2D = new Cartesian3_default(); var scratchBoundingSphere3 = new BoundingSphere_default(); function updateBatchTableBoundingSpheres(primitive, frameState) { const hasDistanceDisplayCondition = defined_default( primitive._batchTableAttributeIndices.distanceDisplayCondition ); if (!hasDistanceDisplayCondition || primitive._batchTableBoundingSpheresUpdated) { return; } const indices = primitive._batchTableBoundingSphereAttributeIndices; const center3DHighIndex = indices.center3DHigh; const center3DLowIndex = indices.center3DLow; const center2DHighIndex = indices.center2DHigh; const center2DLowIndex = indices.center2DLow; const radiusIndex = indices.radius; const projection = frameState.mapProjection; const ellipsoid = projection.ellipsoid; const batchTable = primitive._batchTable; const boundingSpheres = primitive._instanceBoundingSpheres; const length2 = boundingSpheres.length; for (let i = 0; i < length2; ++i) { let boundingSphere = boundingSpheres[i]; if (!defined_default(boundingSphere)) { continue; } const modelMatrix = primitive.modelMatrix; if (defined_default(modelMatrix)) { boundingSphere = BoundingSphere_default.transform( boundingSphere, modelMatrix, scratchBoundingSphere3 ); } const center = boundingSphere.center; const radius = boundingSphere.radius; let encodedCenter = EncodedCartesian3_default.fromCartesian( center, scratchBoundingSphereCenterEncoded ); batchTable.setBatchedAttribute(i, center3DHighIndex, encodedCenter.high); batchTable.setBatchedAttribute(i, center3DLowIndex, encodedCenter.low); if (!frameState.scene3DOnly) { const cartographic2 = ellipsoid.cartesianToCartographic( center, scratchBoundingSphereCartographic ); const center2D = projection.project( cartographic2, scratchBoundingSphereCenter2D ); encodedCenter = EncodedCartesian3_default.fromCartesian( center2D, scratchBoundingSphereCenterEncoded ); batchTable.setBatchedAttribute(i, center2DHighIndex, encodedCenter.high); batchTable.setBatchedAttribute(i, center2DLowIndex, encodedCenter.low); } batchTable.setBatchedAttribute(i, radiusIndex, radius); } primitive._batchTableBoundingSpheresUpdated = true; } var offsetScratchCartesian = new Cartesian3_default(); var offsetCenterScratch = new Cartesian3_default(); function updateBatchTableOffsets(primitive, frameState) { const hasOffset = defined_default(primitive._batchTableAttributeIndices.offset); if (!hasOffset || primitive._batchTableOffsetsUpdated || frameState.scene3DOnly) { return; } const index2D = primitive._batchTableOffsetAttribute2DIndex; const projection = frameState.mapProjection; const ellipsoid = projection.ellipsoid; const batchTable = primitive._batchTable; const boundingSpheres = primitive._instanceBoundingSpheres; const length2 = boundingSpheres.length; for (let i = 0; i < length2; ++i) { let boundingSphere = boundingSpheres[i]; if (!defined_default(boundingSphere)) { continue; } const offset = batchTable.getBatchedAttribute( i, primitive._batchTableAttributeIndices.offset ); if (Cartesian3_default.equals(offset, Cartesian3_default.ZERO)) { batchTable.setBatchedAttribute(i, index2D, Cartesian3_default.ZERO); continue; } const modelMatrix = primitive.modelMatrix; if (defined_default(modelMatrix)) { boundingSphere = BoundingSphere_default.transform( boundingSphere, modelMatrix, scratchBoundingSphere3 ); } let center = boundingSphere.center; center = ellipsoid.scaleToGeodeticSurface(center, offsetCenterScratch); let cartographic2 = ellipsoid.cartesianToCartographic( center, scratchBoundingSphereCartographic ); const center2D = projection.project( cartographic2, scratchBoundingSphereCenter2D ); const newPoint = Cartesian3_default.add(offset, center, offsetScratchCartesian); cartographic2 = ellipsoid.cartesianToCartographic(newPoint, cartographic2); const newPointProjected = projection.project( cartographic2, offsetScratchCartesian ); const newVector = Cartesian3_default.subtract( newPointProjected, center2D, offsetScratchCartesian ); const x = newVector.x; newVector.x = newVector.z; newVector.z = newVector.y; newVector.y = x; batchTable.setBatchedAttribute(i, index2D, newVector); } primitive._batchTableOffsetsUpdated = true; } function createVertexArray(primitive, frameState) { const attributeLocations8 = primitive._attributeLocations; const geometries = primitive._geometries; const scene3DOnly = frameState.scene3DOnly; const context = frameState.context; const va = []; const length2 = geometries.length; for (let i = 0; i < length2; ++i) { const geometry = geometries[i]; va.push( VertexArray_default.fromGeometry({ context, geometry, attributeLocations: attributeLocations8, bufferUsage: BufferUsage_default.STATIC_DRAW, interleave: primitive._interleave }) ); if (defined_default(primitive._createBoundingVolumeFunction)) { primitive._createBoundingVolumeFunction(frameState, geometry); } else { primitive._boundingSpheres.push( BoundingSphere_default.clone(geometry.boundingSphere) ); primitive._boundingSphereWC.push(new BoundingSphere_default()); if (!scene3DOnly) { const center = geometry.boundingSphereCV.center; const x = center.x; const y = center.y; const z2 = center.z; center.x = z2; center.y = x; center.z = y; primitive._boundingSphereCV.push( BoundingSphere_default.clone(geometry.boundingSphereCV) ); primitive._boundingSphere2D.push(new BoundingSphere_default()); primitive._boundingSphereMorph.push(new BoundingSphere_default()); } } } primitive._va = va; primitive._primitiveType = geometries[0].primitiveType; if (primitive.releaseGeometryInstances) { primitive.geometryInstances = void 0; } primitive._geometries = void 0; setReady(primitive, frameState, PrimitiveState_default.COMPLETE, void 0); } function createRenderStates(primitive, context, appearance, twoPasses) { let renderState = appearance.getRenderState(); let rs; if (twoPasses) { rs = clone_default(renderState, false); rs.cull = { enabled: true, face: CullFace_default.BACK }; primitive._frontFaceRS = RenderState_default.fromCache(rs); rs.cull.face = CullFace_default.FRONT; primitive._backFaceRS = RenderState_default.fromCache(rs); } else { primitive._frontFaceRS = RenderState_default.fromCache(renderState); primitive._backFaceRS = primitive._frontFaceRS; } rs = clone_default(renderState, false); if (defined_default(primitive._depthFailAppearance)) { rs.depthTest.enabled = false; } if (defined_default(primitive._depthFailAppearance)) { renderState = primitive._depthFailAppearance.getRenderState(); rs = clone_default(renderState, false); rs.depthTest.func = DepthFunction_default.GREATER; if (twoPasses) { rs.cull = { enabled: true, face: CullFace_default.BACK }; primitive._frontFaceDepthFailRS = RenderState_default.fromCache(rs); rs.cull.face = CullFace_default.FRONT; primitive._backFaceDepthFailRS = RenderState_default.fromCache(rs); } else { primitive._frontFaceDepthFailRS = RenderState_default.fromCache(rs); primitive._backFaceDepthFailRS = primitive._frontFaceRS; } } } function createShaderProgram(primitive, frameState, appearance) { const context = frameState.context; const attributeLocations8 = primitive._attributeLocations; let vs = primitive._batchTable.getVertexShaderCallback()( appearance.vertexShaderSource ); vs = Primitive._appendOffsetToShader(primitive, vs); vs = Primitive._appendShowToShader(primitive, vs); vs = Primitive._appendDistanceDisplayConditionToShader( primitive, vs, frameState.scene3DOnly ); vs = appendPickToVertexShader(vs); vs = Primitive._updateColorAttribute(primitive, vs, false); vs = modifyForEncodedNormals(primitive, vs); vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly); let fs = appearance.getFragmentShaderSource(); fs = appendPickToFragmentShader(fs); primitive._sp = ShaderProgram_default.replaceCache({ context, shaderProgram: primitive._sp, vertexShaderSource: vs, fragmentShaderSource: fs, attributeLocations: attributeLocations8 }); validateShaderMatching(primitive._sp, attributeLocations8); if (defined_default(primitive._depthFailAppearance)) { vs = primitive._batchTable.getVertexShaderCallback()( primitive._depthFailAppearance.vertexShaderSource ); vs = Primitive._appendShowToShader(primitive, vs); vs = Primitive._appendDistanceDisplayConditionToShader( primitive, vs, frameState.scene3DOnly ); vs = appendPickToVertexShader(vs); vs = Primitive._updateColorAttribute(primitive, vs, true); vs = modifyForEncodedNormals(primitive, vs); vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly); vs = depthClampVS(vs); fs = primitive._depthFailAppearance.getFragmentShaderSource(); fs = appendPickToFragmentShader(fs); fs = depthClampFS(fs); primitive._spDepthFail = ShaderProgram_default.replaceCache({ context, shaderProgram: primitive._spDepthFail, vertexShaderSource: vs, fragmentShaderSource: fs, attributeLocations: attributeLocations8 }); validateShaderMatching(primitive._spDepthFail, attributeLocations8); } } var modifiedModelViewScratch = new Matrix4_default(); var rtcScratch = new Cartesian3_default(); function getUniforms(primitive, appearance, material4, frameState) { const materialUniformMap = defined_default(material4) ? material4._uniforms : void 0; const appearanceUniformMap = {}; const appearanceUniforms = appearance.uniforms; if (defined_default(appearanceUniforms)) { for (const name in appearanceUniforms) { if (appearanceUniforms.hasOwnProperty(name)) { if (defined_default(materialUniformMap) && defined_default(materialUniformMap[name])) { throw new DeveloperError_default( `Appearance and material have a uniform with the same name: ${name}` ); } appearanceUniformMap[name] = getUniformFunction( appearanceUniforms, name ); } } } let uniforms = combine_default(appearanceUniformMap, materialUniformMap); uniforms = primitive._batchTable.getUniformMapCallback()(uniforms); if (defined_default(primitive.rtcCenter)) { uniforms.u_modifiedModelView = function() { const viewMatrix = frameState.context.uniformState.view; Matrix4_default.multiply( viewMatrix, primitive._modelMatrix, modifiedModelViewScratch ); Matrix4_default.multiplyByPoint( modifiedModelViewScratch, primitive.rtcCenter, rtcScratch ); Matrix4_default.setTranslation( modifiedModelViewScratch, rtcScratch, modifiedModelViewScratch ); return modifiedModelViewScratch; }; } return uniforms; } function createCommands(primitive, appearance, material4, translucent, twoPasses, colorCommands, pickCommands, frameState) { const uniforms = getUniforms(primitive, appearance, material4, frameState); let depthFailUniforms; if (defined_default(primitive._depthFailAppearance)) { depthFailUniforms = getUniforms( primitive, primitive._depthFailAppearance, primitive._depthFailAppearance.material, frameState ); } const pass = translucent ? Pass_default.TRANSLUCENT : Pass_default.OPAQUE; let multiplier = twoPasses ? 2 : 1; multiplier *= defined_default(primitive._depthFailAppearance) ? 2 : 1; colorCommands.length = primitive._va.length * multiplier; const length2 = colorCommands.length; let vaIndex = 0; for (let i = 0; i < length2; ++i) { let colorCommand; if (twoPasses) { colorCommand = colorCommands[i]; if (!defined_default(colorCommand)) { colorCommand = colorCommands[i] = new DrawCommand_default({ owner: primitive, primitiveType: primitive._primitiveType }); } colorCommand.vertexArray = primitive._va[vaIndex]; colorCommand.renderState = primitive._backFaceRS; colorCommand.shaderProgram = primitive._sp; colorCommand.uniformMap = uniforms; colorCommand.pass = pass; ++i; } colorCommand = colorCommands[i]; if (!defined_default(colorCommand)) { colorCommand = colorCommands[i] = new DrawCommand_default({ owner: primitive, primitiveType: primitive._primitiveType }); } colorCommand.vertexArray = primitive._va[vaIndex]; colorCommand.renderState = primitive._frontFaceRS; colorCommand.shaderProgram = primitive._sp; colorCommand.uniformMap = uniforms; colorCommand.pass = pass; if (defined_default(primitive._depthFailAppearance)) { if (twoPasses) { ++i; colorCommand = colorCommands[i]; if (!defined_default(colorCommand)) { colorCommand = colorCommands[i] = new DrawCommand_default({ owner: primitive, primitiveType: primitive._primitiveType }); } colorCommand.vertexArray = primitive._va[vaIndex]; colorCommand.renderState = primitive._backFaceDepthFailRS; colorCommand.shaderProgram = primitive._spDepthFail; colorCommand.uniformMap = depthFailUniforms; colorCommand.pass = pass; } ++i; colorCommand = colorCommands[i]; if (!defined_default(colorCommand)) { colorCommand = colorCommands[i] = new DrawCommand_default({ owner: primitive, primitiveType: primitive._primitiveType }); } colorCommand.vertexArray = primitive._va[vaIndex]; colorCommand.renderState = primitive._frontFaceDepthFailRS; colorCommand.shaderProgram = primitive._spDepthFail; colorCommand.uniformMap = depthFailUniforms; colorCommand.pass = pass; } ++vaIndex; } } Primitive._updateBoundingVolumes = function(primitive, frameState, modelMatrix, forceUpdate) { let i; let length2; let boundingSphere; if (forceUpdate || !Matrix4_default.equals(modelMatrix, primitive._modelMatrix)) { Matrix4_default.clone(modelMatrix, primitive._modelMatrix); length2 = primitive._boundingSpheres.length; for (i = 0; i < length2; ++i) { boundingSphere = primitive._boundingSpheres[i]; if (defined_default(boundingSphere)) { primitive._boundingSphereWC[i] = BoundingSphere_default.transform( boundingSphere, modelMatrix, primitive._boundingSphereWC[i] ); if (!frameState.scene3DOnly) { primitive._boundingSphere2D[i] = BoundingSphere_default.clone( primitive._boundingSphereCV[i], primitive._boundingSphere2D[i] ); primitive._boundingSphereMorph[i] = BoundingSphere_default.union( primitive._boundingSphereWC[i], primitive._boundingSphereCV[i] ); } } } } const pixelSize = primitive.appearance.pixelSize; if (defined_default(pixelSize)) { length2 = primitive._boundingSpheres.length; for (i = 0; i < length2; ++i) { boundingSphere = primitive._boundingSpheres[i]; const boundingSphereWC = primitive._boundingSphereWC[i]; const pixelSizeInMeters = frameState.camera.getPixelSize( boundingSphere, frameState.context.drawingBufferWidth, frameState.context.drawingBufferHeight ); const sizeInMeters = pixelSizeInMeters * pixelSize; boundingSphereWC.radius = boundingSphere.radius + sizeInMeters; } } }; function updateAndQueueCommands(primitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { if (frameState.mode !== SceneMode_default.SCENE3D && !Matrix4_default.equals(modelMatrix, Matrix4_default.IDENTITY)) { throw new DeveloperError_default( "Primitive.modelMatrix is only supported in 3D mode." ); } Primitive._updateBoundingVolumes(primitive, frameState, modelMatrix); let boundingSpheres; if (frameState.mode === SceneMode_default.SCENE3D) { boundingSpheres = primitive._boundingSphereWC; } else if (frameState.mode === SceneMode_default.COLUMBUS_VIEW) { boundingSpheres = primitive._boundingSphereCV; } else if (frameState.mode === SceneMode_default.SCENE2D && defined_default(primitive._boundingSphere2D)) { boundingSpheres = primitive._boundingSphere2D; } else if (defined_default(primitive._boundingSphereMorph)) { boundingSpheres = primitive._boundingSphereMorph; } const commandList = frameState.commandList; const passes = frameState.passes; if (passes.render || passes.pick) { const allowPicking = primitive.allowPicking; const castShadows = ShadowMode_default.castShadows(primitive.shadows); const receiveShadows = ShadowMode_default.receiveShadows(primitive.shadows); const colorLength = colorCommands.length; let factor2 = twoPasses ? 2 : 1; factor2 *= defined_default(primitive._depthFailAppearance) ? 2 : 1; for (let j = 0; j < colorLength; ++j) { const sphereIndex = Math.floor(j / factor2); const colorCommand = colorCommands[j]; colorCommand.modelMatrix = modelMatrix; colorCommand.boundingVolume = boundingSpheres[sphereIndex]; colorCommand.cull = cull; colorCommand.debugShowBoundingVolume = debugShowBoundingVolume2; colorCommand.castShadows = castShadows; colorCommand.receiveShadows = receiveShadows; if (allowPicking) { colorCommand.pickId = "v_pickColor"; } else { colorCommand.pickId = void 0; } commandList.push(colorCommand); } } } Primitive.prototype.update = function(frameState) { if (!defined_default(this.geometryInstances) && this._va.length === 0 || defined_default(this.geometryInstances) && Array.isArray(this.geometryInstances) && this.geometryInstances.length === 0 || !defined_default(this.appearance) || frameState.mode !== SceneMode_default.SCENE3D && frameState.scene3DOnly || !frameState.passes.render && !frameState.passes.pick) { return; } if (defined_default(this._error)) { throw this._error; } if (defined_default(this.rtcCenter) && !frameState.scene3DOnly) { throw new DeveloperError_default( "RTC rendering is only available for 3D only scenes." ); } if (this._state === PrimitiveState_default.FAILED) { return; } const context = frameState.context; if (!defined_default(this._batchTable)) { createBatchTable(this, context); } if (this._batchTable.attributes.length > 0) { if (ContextLimits_default.maximumVertexTextureImageUnits === 0) { throw new RuntimeError_default( "Vertex texture fetch support is required to render primitives with per-instance attributes. The maximum number of vertex texture image units must be greater than zero." ); } this._batchTable.update(frameState); } if (this._state !== PrimitiveState_default.COMPLETE && this._state !== PrimitiveState_default.COMBINED) { if (this.asynchronous) { loadAsynchronous(this, frameState); } else { loadSynchronous(this, frameState); } } if (this._state === PrimitiveState_default.COMBINED) { updateBatchTableBoundingSpheres(this, frameState); updateBatchTableOffsets(this, frameState); createVertexArray(this, frameState); } if (!this.show || this._state !== PrimitiveState_default.COMPLETE) { return; } if (!this._batchTableOffsetsUpdated) { updateBatchTableOffsets(this, frameState); } if (this._recomputeBoundingSpheres) { recomputeBoundingSpheres(this, frameState); } const appearance = this.appearance; const material4 = appearance.material; let createRS = false; let createSP = false; if (this._appearance !== appearance) { this._appearance = appearance; this._material = material4; createRS = true; createSP = true; } else if (this._material !== material4) { this._material = material4; createSP = true; } const depthFailAppearance = this.depthFailAppearance; const depthFailMaterial = defined_default(depthFailAppearance) ? depthFailAppearance.material : void 0; if (this._depthFailAppearance !== depthFailAppearance) { this._depthFailAppearance = depthFailAppearance; this._depthFailMaterial = depthFailMaterial; createRS = true; createSP = true; } else if (this._depthFailMaterial !== depthFailMaterial) { this._depthFailMaterial = depthFailMaterial; createSP = true; } const translucent = this._appearance.isTranslucent(); if (this._translucent !== translucent) { this._translucent = translucent; createRS = true; } if (defined_default(this._material)) { this._material.update(context); } const twoPasses = appearance.closed && translucent; if (createRS) { const rsFunc = this._createRenderStatesFunction ?? createRenderStates; rsFunc(this, context, appearance, twoPasses); } if (createSP) { const spFunc = this._createShaderProgramFunction ?? createShaderProgram; spFunc(this, frameState, appearance); } if (createRS || createSP) { const commandFunc = this._createCommandsFunction ?? createCommands; commandFunc( this, appearance, material4, translucent, twoPasses, this._colorCommands, this._pickCommands, frameState ); } const updateAndQueueCommandsFunc = this._updateAndQueueCommandsFunction ?? updateAndQueueCommands; updateAndQueueCommandsFunc( this, frameState, this._colorCommands, this._pickCommands, this.modelMatrix, this.cull, this.debugShowBoundingVolume, twoPasses ); }; var offsetBoundingSphereScratch1 = new BoundingSphere_default(); var offsetBoundingSphereScratch2 = new BoundingSphere_default(); function transformBoundingSphere(boundingSphere, offset, offsetAttribute) { if (offsetAttribute === GeometryOffsetAttribute_default.TOP) { const origBS = BoundingSphere_default.clone( boundingSphere, offsetBoundingSphereScratch1 ); const offsetBS = BoundingSphere_default.clone( boundingSphere, offsetBoundingSphereScratch2 ); offsetBS.center = Cartesian3_default.add(offsetBS.center, offset, offsetBS.center); boundingSphere = BoundingSphere_default.union(origBS, offsetBS, boundingSphere); } else if (offsetAttribute === GeometryOffsetAttribute_default.ALL) { boundingSphere.center = Cartesian3_default.add( boundingSphere.center, offset, boundingSphere.center ); } return boundingSphere; } function createGetFunction(batchTable, instanceIndex, attributeIndex) { return function() { const attributeValue = batchTable.getBatchedAttribute( instanceIndex, attributeIndex ); const attribute = batchTable.attributes[attributeIndex]; const componentsPerAttribute = attribute.componentsPerAttribute; const value = ComponentDatatype_default.createTypedArray( attribute.componentDatatype, componentsPerAttribute ); if (defined_default(attributeValue.constructor.pack)) { attributeValue.constructor.pack(attributeValue, value, 0); } else { value[0] = attributeValue; } return value; }; } function createSetFunction(batchTable, instanceIndex, attributeIndex, primitive, name) { return function(value) { if (!defined_default(value) || !defined_default(value.length) || value.length < 1 || value.length > 4) { throw new DeveloperError_default( "value must be and array with length between 1 and 4." ); } const attributeValue = getAttributeValue(value); batchTable.setBatchedAttribute( instanceIndex, attributeIndex, attributeValue ); if (name === "offset") { primitive._recomputeBoundingSpheres = true; primitive._batchTableOffsetsUpdated = false; } }; } var offsetScratch2 = new Cartesian3_default(); function createBoundingSphereProperties(primitive, properties, index) { properties.boundingSphere = { get: function() { let boundingSphere = primitive._instanceBoundingSpheres[index]; if (defined_default(boundingSphere)) { boundingSphere = boundingSphere.clone(); const modelMatrix = primitive.modelMatrix; const offset = properties.offset; if (defined_default(offset)) { transformBoundingSphere( boundingSphere, Cartesian3_default.fromArray(offset.get(), 0, offsetScratch2), primitive._offsetInstanceExtend[index] ); } if (defined_default(modelMatrix)) { boundingSphere = BoundingSphere_default.transform( boundingSphere, modelMatrix ); } } return boundingSphere; } }; properties.boundingSphereCV = { get: function() { return primitive._instanceBoundingSpheresCV[index]; } }; } function createPickIdProperty(primitive, properties, index) { properties.pickId = { get: function() { return primitive._pickIds[index]; } }; } Primitive.prototype.getGeometryInstanceAttributes = function(id) { if (!defined_default(id)) { throw new DeveloperError_default("id is required"); } if (!defined_default(this._batchTable)) { throw new DeveloperError_default( "must call update before calling getGeometryInstanceAttributes" ); } let attributes = this._perInstanceAttributeCache.get(id); if (defined_default(attributes)) { return attributes; } let index = -1; const lastIndex = this._lastPerInstanceAttributeIndex; const ids = this._instanceIds; const length2 = ids.length; for (let i = 0; i < length2; ++i) { const curIndex = (lastIndex + i) % length2; if (id === ids[curIndex]) { index = curIndex; break; } } if (index === -1) { return void 0; } const batchTable = this._batchTable; const perInstanceAttributeIndices = this._batchTableAttributeIndices; attributes = {}; const properties = {}; for (const name in perInstanceAttributeIndices) { if (perInstanceAttributeIndices.hasOwnProperty(name)) { const attributeIndex = perInstanceAttributeIndices[name]; properties[name] = { get: createGetFunction(batchTable, index, attributeIndex), set: createSetFunction(batchTable, index, attributeIndex, this, name) }; } } createBoundingSphereProperties(this, properties, index); createPickIdProperty(this, properties, index); Object.defineProperties(attributes, properties); this._lastPerInstanceAttributeIndex = index; this._perInstanceAttributeCache.set(id, attributes); return attributes; }; Primitive.prototype.isDestroyed = function() { return false; }; Primitive.prototype.destroy = function() { let length2; let i; this._sp = this._sp && this._sp.destroy(); this._spDepthFail = this._spDepthFail && this._spDepthFail.destroy(); const va = this._va; length2 = va.length; for (i = 0; i < length2; ++i) { va[i].destroy(); } this._va = void 0; const pickIds = this._pickIds; length2 = pickIds.length; for (i = 0; i < length2; ++i) { pickIds[i].destroy(); } this._pickIds = void 0; this._batchTable = this._batchTable && this._batchTable.destroy(); this._instanceIds = void 0; this._perInstanceAttributeCache = void 0; this._attributeLocations = void 0; return destroyObject_default(this); }; function setReady(primitive, frameState, state, error) { primitive._error = error; primitive._state = state; frameState.afterRender.push(function() { primitive._ready = primitive._state === PrimitiveState_default.COMPLETE || primitive._state === PrimitiveState_default.FAILED; return true; }); } var Primitive_default = Primitive; // packages/engine/Source/Scene/ShadowVolumeAppearance.js var import_InlineWorkers374 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/GeometryInstanceAttribute.js var import_InlineWorkers372 = __toESM(require_InlineWorkers(), 1); function GeometryInstanceAttribute(options) { options = options ?? Frozen_default.EMPTY_OBJECT; if (!defined_default(options.componentDatatype)) { throw new DeveloperError_default("options.componentDatatype is required."); } if (!defined_default(options.componentsPerAttribute)) { throw new DeveloperError_default("options.componentsPerAttribute is required."); } if (options.componentsPerAttribute < 1 || options.componentsPerAttribute > 4) { throw new DeveloperError_default( "options.componentsPerAttribute must be between 1 and 4." ); } if (!defined_default(options.value)) { throw new DeveloperError_default("options.value is required."); } this.componentDatatype = options.componentDatatype; this.componentsPerAttribute = options.componentsPerAttribute; this.normalize = options.normalize ?? false; this.value = options.value; } var GeometryInstanceAttribute_default = GeometryInstanceAttribute; // packages/engine/Source/Shaders/ShadowVolumeAppearanceFS.js var import_InlineWorkers373 = __toESM(require_InlineWorkers(), 1); var ShadowVolumeAppearanceFS_default = "#ifdef TEXTURE_COORDINATES\n#ifdef SPHERICAL\nin vec4 v_sphericalExtents;\n#else // SPHERICAL\nin vec2 v_inversePlaneExtents;\nin vec4 v_westPlane;\nin vec4 v_southPlane;\n#endif // SPHERICAL\nin vec3 v_uvMinAndSphericalLongitudeRotation;\nin vec3 v_uMaxAndInverseDistance;\nin vec3 v_vMaxAndInverseDistance;\n#endif // TEXTURE_COORDINATES\n\n#ifdef PER_INSTANCE_COLOR\nin vec4 v_color;\n#endif\n\n#ifdef NORMAL_EC\nvec3 getEyeCoordinate3FromWindowCoordinate(vec2 fragCoord, float logDepthOrDepth) {\n vec4 eyeCoordinate = czm_windowToEyeCoordinates(fragCoord, logDepthOrDepth);\n return eyeCoordinate.xyz / eyeCoordinate.w;\n}\n\nvec3 vectorFromOffset(vec4 eyeCoordinate, vec2 positiveOffset) {\n vec2 glFragCoordXY = gl_FragCoord.xy;\n // Sample depths at both offset and negative offset\n float upOrRightLogDepth = czm_unpackDepth(texture(czm_globeDepthTexture, (glFragCoordXY + positiveOffset) / czm_viewport.zw));\n float downOrLeftLogDepth = czm_unpackDepth(texture(czm_globeDepthTexture, (glFragCoordXY - positiveOffset) / czm_viewport.zw));\n // Explicitly evaluate both paths\n // Necessary for multifrustum and for edges of the screen\n bvec2 upOrRightInBounds = lessThan(glFragCoordXY + positiveOffset, czm_viewport.zw);\n float useUpOrRight = float(upOrRightLogDepth > 0.0 && upOrRightInBounds.x && upOrRightInBounds.y);\n float useDownOrLeft = float(useUpOrRight == 0.0);\n vec3 upOrRightEC = getEyeCoordinate3FromWindowCoordinate(glFragCoordXY + positiveOffset, upOrRightLogDepth);\n vec3 downOrLeftEC = getEyeCoordinate3FromWindowCoordinate(glFragCoordXY - positiveOffset, downOrLeftLogDepth);\n return (upOrRightEC - (eyeCoordinate.xyz / eyeCoordinate.w)) * useUpOrRight + ((eyeCoordinate.xyz / eyeCoordinate.w) - downOrLeftEC) * useDownOrLeft;\n}\n#endif // NORMAL_EC\n\nvoid main(void)\n{\n#ifdef REQUIRES_EC\n float logDepthOrDepth = czm_unpackDepth(texture(czm_globeDepthTexture, gl_FragCoord.xy / czm_viewport.zw));\n vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, logDepthOrDepth);\n#endif\n\n#ifdef REQUIRES_WC\n vec4 worldCoordinate4 = czm_inverseView * eyeCoordinate;\n vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;\n#endif\n\n#ifdef TEXTURE_COORDINATES\n vec2 uv;\n#ifdef SPHERICAL\n // Treat world coords as a sphere normal for spherical coordinates\n vec2 sphericalLatLong = czm_approximateSphericalCoordinates(worldCoordinate);\n sphericalLatLong.y += v_uvMinAndSphericalLongitudeRotation.z;\n sphericalLatLong.y = czm_branchFreeTernary(sphericalLatLong.y < czm_pi, sphericalLatLong.y, sphericalLatLong.y - czm_twoPi);\n uv.x = (sphericalLatLong.y - v_sphericalExtents.y) * v_sphericalExtents.w;\n uv.y = (sphericalLatLong.x - v_sphericalExtents.x) * v_sphericalExtents.z;\n#else // SPHERICAL\n // Unpack planes and transform to eye space\n uv.x = czm_planeDistance(v_westPlane, eyeCoordinate.xyz / eyeCoordinate.w) * v_inversePlaneExtents.x;\n uv.y = czm_planeDistance(v_southPlane, eyeCoordinate.xyz / eyeCoordinate.w) * v_inversePlaneExtents.y;\n#endif // SPHERICAL\n#endif // TEXTURE_COORDINATES\n\n#ifdef CULL_FRAGMENTS\n // When classifying translucent geometry, logDepthOrDepth == 0.0\n // indicates a region that should not be classified, possibly due to there\n // being opaque pixels there in another buffer.\n if (uv.x <= 0.0 || 1.0 <= uv.x || uv.y <= 0.0 || 1.0 <= uv.y || logDepthOrDepth == 0.0) {\n discard;\n }\n#endif\n\n#ifdef PICK\n out_FragColor.a = 1.0; // Explicitly set the alpha, otherwise this may be discarded by ShaderSource.createPickFragmentShaderSource\n#ifdef CULL_FRAGMENTS\n czm_writeDepthClamp();\n#endif // CULL_FRAGMENTS\n#else // PICK\n\n#ifdef NORMAL_EC\n // Compute normal by sampling adjacent pixels in 2x2 block in screen space\n vec3 downUp = vectorFromOffset(eyeCoordinate, vec2(0.0, 1.0));\n vec3 leftRight = vectorFromOffset(eyeCoordinate, vec2(1.0, 0.0));\n vec3 normalEC = normalize(cross(leftRight, downUp));\n#endif\n\n\n#ifdef PER_INSTANCE_COLOR\n\n vec4 color = czm_gammaCorrect(v_color);\n#ifdef FLAT\n out_FragColor = color;\n#else // FLAT\n czm_materialInput materialInput;\n materialInput.normalEC = normalEC;\n materialInput.positionToEyeEC = -eyeCoordinate.xyz;\n czm_material material = czm_getDefaultMaterial(materialInput);\n material.diffuse = color.rgb;\n material.alpha = color.a;\n\n out_FragColor = czm_phong(normalize(-eyeCoordinate.xyz), material, czm_lightDirectionEC);\n#endif // FLAT\n\n // Premultiply alpha. Required for classification primitives on translucent globe.\n out_FragColor.rgb *= out_FragColor.a;\n\n#else // PER_INSTANCE_COLOR\n\n // Material support.\n // USES_ is distinct from REQUIRES_, because some things are dependencies of each other or\n // dependencies for culling but might not actually be used by the material.\n\n czm_materialInput materialInput;\n\n#ifdef USES_NORMAL_EC\n materialInput.normalEC = normalEC;\n#endif\n\n#ifdef USES_POSITION_TO_EYE_EC\n materialInput.positionToEyeEC = -eyeCoordinate.xyz;\n#endif\n\n#ifdef USES_TANGENT_TO_EYE\n materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(worldCoordinate, normalEC);\n#endif\n\n#ifdef USES_ST\n // Remap texture coordinates from computed (approximately aligned with cartographic space) to the desired\n // texture coordinate system, which typically forms a tight oriented bounding box around the geometry.\n // Shader is provided a set of reference points for remapping.\n materialInput.st.x = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_uMaxAndInverseDistance.xy, uv) * v_uMaxAndInverseDistance.z;\n materialInput.st.y = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_vMaxAndInverseDistance.xy, uv) * v_vMaxAndInverseDistance.z;\n#endif\n\n czm_material material = czm_getMaterial(materialInput);\n\n#ifdef FLAT\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#else // FLAT\n out_FragColor = czm_phong(normalize(-eyeCoordinate.xyz), material, czm_lightDirectionEC);\n#endif // FLAT\n\n // Premultiply alpha. Required for classification primitives on translucent globe.\n out_FragColor.rgb *= out_FragColor.a;\n\n#endif // PER_INSTANCE_COLOR\n czm_writeDepthClamp();\n#endif // PICK\n}\n"; // packages/engine/Source/Scene/ShadowVolumeAppearance.js function ShadowVolumeAppearance(extentsCulling, planarExtents, appearance) { Check_default.typeOf.bool("extentsCulling", extentsCulling); Check_default.typeOf.bool("planarExtents", planarExtents); Check_default.typeOf.object("appearance", appearance); this._projectionExtentDefines = { eastMostYhighDefine: "", eastMostYlowDefine: "", westMostYhighDefine: "", westMostYlowDefine: "" }; const colorShaderDependencies = new ShaderDependencies(); colorShaderDependencies.requiresTextureCoordinates = extentsCulling; colorShaderDependencies.requiresEC = !appearance.flat; const pickShaderDependencies = new ShaderDependencies(); pickShaderDependencies.requiresTextureCoordinates = extentsCulling; if (appearance instanceof PerInstanceColorAppearance_default) { colorShaderDependencies.requiresNormalEC = !appearance.flat; } else { const materialShaderSource = `${appearance.material.shaderSource} ${appearance.fragmentShaderSource}`; colorShaderDependencies.normalEC = materialShaderSource.indexOf("materialInput.normalEC") !== -1 || materialShaderSource.indexOf("czm_getDefaultMaterial") !== -1; colorShaderDependencies.positionToEyeEC = materialShaderSource.indexOf("materialInput.positionToEyeEC") !== -1; colorShaderDependencies.tangentToEyeMatrix = materialShaderSource.indexOf("materialInput.tangentToEyeMatrix") !== -1; colorShaderDependencies.st = materialShaderSource.indexOf("materialInput.st") !== -1; } this._colorShaderDependencies = colorShaderDependencies; this._pickShaderDependencies = pickShaderDependencies; this._appearance = appearance; this._extentsCulling = extentsCulling; this._planarExtents = planarExtents; } ShadowVolumeAppearance.prototype.createFragmentShader = function(columbusView2D) { Check_default.typeOf.bool("columbusView2D", columbusView2D); const appearance = this._appearance; const dependencies = this._colorShaderDependencies; const defines = []; if (!columbusView2D && !this._planarExtents) { defines.push("SPHERICAL"); } if (dependencies.requiresEC) { defines.push("REQUIRES_EC"); } if (dependencies.requiresWC) { defines.push("REQUIRES_WC"); } if (dependencies.requiresTextureCoordinates) { defines.push("TEXTURE_COORDINATES"); } if (this._extentsCulling) { defines.push("CULL_FRAGMENTS"); } if (dependencies.requiresNormalEC) { defines.push("NORMAL_EC"); } if (appearance instanceof PerInstanceColorAppearance_default) { defines.push("PER_INSTANCE_COLOR"); } if (dependencies.normalEC) { defines.push("USES_NORMAL_EC"); } if (dependencies.positionToEyeEC) { defines.push("USES_POSITION_TO_EYE_EC"); } if (dependencies.tangentToEyeMatrix) { defines.push("USES_TANGENT_TO_EYE"); } if (dependencies.st) { defines.push("USES_ST"); } if (appearance.flat) { defines.push("FLAT"); } let materialSource = ""; if (!(appearance instanceof PerInstanceColorAppearance_default)) { materialSource = appearance.material.shaderSource; } return new ShaderSource_default({ defines, sources: [materialSource, ShadowVolumeAppearanceFS_default] }); }; ShadowVolumeAppearance.prototype.createPickFragmentShader = function(columbusView2D) { Check_default.typeOf.bool("columbusView2D", columbusView2D); const dependencies = this._pickShaderDependencies; const defines = ["PICK"]; if (!columbusView2D && !this._planarExtents) { defines.push("SPHERICAL"); } if (dependencies.requiresEC) { defines.push("REQUIRES_EC"); } if (dependencies.requiresWC) { defines.push("REQUIRES_WC"); } if (dependencies.requiresTextureCoordinates) { defines.push("TEXTURE_COORDINATES"); } if (this._extentsCulling) { defines.push("CULL_FRAGMENTS"); } return new ShaderSource_default({ defines, sources: [ShadowVolumeAppearanceFS_default], pickColorQualifier: "in" }); }; ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { Check_default.defined("defines", defines); Check_default.typeOf.string("vertexShaderSource", vertexShaderSource); Check_default.typeOf.bool("columbusView2D", columbusView2D); Check_default.defined("mapProjection", mapProjection); return createShadowVolumeAppearanceVS( this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance, mapProjection, this._projectionExtentDefines ); }; ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { Check_default.defined("defines", defines); Check_default.typeOf.string("vertexShaderSource", vertexShaderSource); Check_default.typeOf.bool("columbusView2D", columbusView2D); Check_default.defined("mapProjection", mapProjection); return createShadowVolumeAppearanceVS( this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, void 0, mapProjection, this._projectionExtentDefines ); }; var longitudeExtentsCartesianScratch = new Cartesian3_default(); var longitudeExtentsCartographicScratch = new Cartographic_default(); var longitudeExtentsEncodeScratch = { high: 0, low: 0 }; function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance, mapProjection, projectionExtentDefines) { const allDefines = defines.slice(); if (projectionExtentDefines.eastMostYhighDefine === "") { const eastMostCartographic = longitudeExtentsCartographicScratch; eastMostCartographic.longitude = Math_default.PI; eastMostCartographic.latitude = 0; eastMostCartographic.height = 0; const eastMostCartesian = mapProjection.project( eastMostCartographic, longitudeExtentsCartesianScratch ); let encoded = EncodedCartesian3_default.encode( eastMostCartesian.x, longitudeExtentsEncodeScratch ); projectionExtentDefines.eastMostYhighDefine = `EAST_MOST_X_HIGH ${encoded.high.toFixed( `${encoded.high}`.length + 1 )}`; projectionExtentDefines.eastMostYlowDefine = `EAST_MOST_X_LOW ${encoded.low.toFixed( `${encoded.low}`.length + 1 )}`; const westMostCartographic = longitudeExtentsCartographicScratch; westMostCartographic.longitude = -Math_default.PI; westMostCartographic.latitude = 0; westMostCartographic.height = 0; const westMostCartesian = mapProjection.project( westMostCartographic, longitudeExtentsCartesianScratch ); encoded = EncodedCartesian3_default.encode( westMostCartesian.x, longitudeExtentsEncodeScratch ); projectionExtentDefines.westMostYhighDefine = `WEST_MOST_X_HIGH ${encoded.high.toFixed( `${encoded.high}`.length + 1 )}`; projectionExtentDefines.westMostYlowDefine = `WEST_MOST_X_LOW ${encoded.low.toFixed( `${encoded.low}`.length + 1 )}`; } if (columbusView2D) { allDefines.push(projectionExtentDefines.eastMostYhighDefine); allDefines.push(projectionExtentDefines.eastMostYlowDefine); allDefines.push(projectionExtentDefines.westMostYhighDefine); allDefines.push(projectionExtentDefines.westMostYlowDefine); } if (defined_default(appearance) && appearance instanceof PerInstanceColorAppearance_default) { allDefines.push("PER_INSTANCE_COLOR"); } if (shaderDependencies.requiresTextureCoordinates) { allDefines.push("TEXTURE_COORDINATES"); if (!(planarExtents || columbusView2D)) { allDefines.push("SPHERICAL"); } if (columbusView2D) { allDefines.push("COLUMBUS_VIEW_2D"); } } return new ShaderSource_default({ defines: allDefines, sources: [vertexShaderSource] }); } function ShaderDependencies() { this._requiresEC = false; this._requiresWC = false; this._requiresNormalEC = false; this._requiresTextureCoordinates = false; this._usesNormalEC = false; this._usesPositionToEyeEC = false; this._usesTangentToEyeMat = false; this._usesSt = false; } Object.defineProperties(ShaderDependencies.prototype, { // Set when assessing final shading (flat vs. phong) and culling using computed texture coordinates requiresEC: { get: function() { return this._requiresEC; }, set: function(value) { this._requiresEC = value || this._requiresEC; } }, requiresWC: { get: function() { return this._requiresWC; }, set: function(value) { this._requiresWC = value || this._requiresWC; this.requiresEC = this._requiresWC; } }, requiresNormalEC: { get: function() { return this._requiresNormalEC; }, set: function(value) { this._requiresNormalEC = value || this._requiresNormalEC; this.requiresEC = this._requiresNormalEC; } }, requiresTextureCoordinates: { get: function() { return this._requiresTextureCoordinates; }, set: function(value) { this._requiresTextureCoordinates = value || this._requiresTextureCoordinates; this.requiresWC = this._requiresTextureCoordinates; } }, // Get/Set when assessing material hookups normalEC: { set: function(value) { this.requiresNormalEC = value; this._usesNormalEC = value; }, get: function() { return this._usesNormalEC; } }, tangentToEyeMatrix: { set: function(value) { this.requiresWC = value; this.requiresNormalEC = value; this._usesTangentToEyeMat = value; }, get: function() { return this._usesTangentToEyeMat; } }, positionToEyeEC: { set: function(value) { this.requiresEC = value; this._usesPositionToEyeEC = value; }, get: function() { return this._usesPositionToEyeEC; } }, st: { set: function(value) { this.requiresTextureCoordinates = value; this._usesSt = value; }, get: function() { return this._usesSt; } } }); function pointLineDistance(point1, point22, point4) { return Math.abs( (point22.y - point1.y) * point4.x - (point22.x - point1.x) * point4.y + point22.x * point1.y - point22.y * point1.x ) / Cartesian2_default.distance(point22, point1); } var points2DScratch2 = [ new Cartesian2_default(), new Cartesian2_default(), new Cartesian2_default(), new Cartesian2_default() ]; function addTextureCoordinateRotationAttributes(attributes, textureCoordinateRotationPoints4) { const points2D = points2DScratch2; const minXYCorner = Cartesian2_default.unpack( textureCoordinateRotationPoints4, 0, points2D[0] ); const maxYCorner = Cartesian2_default.unpack( textureCoordinateRotationPoints4, 2, points2D[1] ); const maxXCorner = Cartesian2_default.unpack( textureCoordinateRotationPoints4, 4, points2D[2] ); attributes.uMaxVmax = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, value: [maxYCorner.x, maxYCorner.y, maxXCorner.x, maxXCorner.y] }); const inverseExtentX = 1 / pointLineDistance(minXYCorner, maxYCorner, maxXCorner); const inverseExtentY = 1 / pointLineDistance(minXYCorner, maxXCorner, maxYCorner); attributes.uvMinAndExtents = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, value: [minXYCorner.x, minXYCorner.y, inverseExtentX, inverseExtentY] }); } var cartographicScratch = new Cartographic_default(); var cornerScratch = new Cartesian3_default(); var northWestScratch = new Cartesian3_default(); var southEastScratch = new Cartesian3_default(); var highLowScratch = { high: 0, low: 0 }; function add2DTextureCoordinateAttributes(rectangle, projection, attributes) { const carto = cartographicScratch; carto.height = 0; carto.longitude = rectangle.west; carto.latitude = rectangle.south; const southWestCorner = projection.project(carto, cornerScratch); carto.latitude = rectangle.north; const northWest = projection.project(carto, northWestScratch); carto.longitude = rectangle.east; carto.latitude = rectangle.south; const southEast = projection.project(carto, southEastScratch); const valuesHigh = [0, 0, 0, 0]; const valuesLow = [0, 0, 0, 0]; let encoded = EncodedCartesian3_default.encode(southWestCorner.x, highLowScratch); valuesHigh[0] = encoded.high; valuesLow[0] = encoded.low; encoded = EncodedCartesian3_default.encode(southWestCorner.y, highLowScratch); valuesHigh[1] = encoded.high; valuesLow[1] = encoded.low; encoded = EncodedCartesian3_default.encode(northWest.y, highLowScratch); valuesHigh[2] = encoded.high; valuesLow[2] = encoded.low; encoded = EncodedCartesian3_default.encode(southEast.x, highLowScratch); valuesHigh[3] = encoded.high; valuesLow[3] = encoded.low; attributes.planes2D_HIGH = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, value: valuesHigh }); attributes.planes2D_LOW = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, value: valuesLow }); } var enuMatrixScratch = new Matrix4_default(); var inverseEnuScratch = new Matrix4_default(); var rectanglePointCartesianScratch = new Cartesian3_default(); var rectangleCenterScratch2 = new Cartographic_default(); var pointsCartographicScratch = [ new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default(), new Cartographic_default() ]; function computeRectangleBounds(rectangle, ellipsoid, height, southWestCornerResult, eastVectorResult, northVectorResult) { const centerCartographic = Rectangle_default.center( rectangle, rectangleCenterScratch2 ); centerCartographic.height = height; const centerCartesian2 = Cartographic_default.toCartesian( centerCartographic, ellipsoid, rectanglePointCartesianScratch ); const enuMatrix = Transforms_default.eastNorthUpToFixedFrame( centerCartesian2, ellipsoid, enuMatrixScratch ); const inverseEnu = Matrix4_default.inverse(enuMatrix, inverseEnuScratch); const west = rectangle.west; const east = rectangle.east; const north = rectangle.north; const south = rectangle.south; const cartographics = pointsCartographicScratch; cartographics[0].latitude = south; cartographics[0].longitude = west; cartographics[1].latitude = north; cartographics[1].longitude = west; cartographics[2].latitude = north; cartographics[2].longitude = east; cartographics[3].latitude = south; cartographics[3].longitude = east; const longitudeCenter = (west + east) * 0.5; const latitudeCenter = (north + south) * 0.5; cartographics[4].latitude = south; cartographics[4].longitude = longitudeCenter; cartographics[5].latitude = north; cartographics[5].longitude = longitudeCenter; cartographics[6].latitude = latitudeCenter; cartographics[6].longitude = west; cartographics[7].latitude = latitudeCenter; cartographics[7].longitude = east; let minX = Number.POSITIVE_INFINITY; let maxX = Number.NEGATIVE_INFINITY; let minY = Number.POSITIVE_INFINITY; let maxY = Number.NEGATIVE_INFINITY; for (let i = 0; i < 8; i++) { cartographics[i].height = height; const pointCartesian = Cartographic_default.toCartesian( cartographics[i], ellipsoid, rectanglePointCartesianScratch ); Matrix4_default.multiplyByPoint(inverseEnu, pointCartesian, pointCartesian); pointCartesian.z = 0; minX = Math.min(minX, pointCartesian.x); maxX = Math.max(maxX, pointCartesian.x); minY = Math.min(minY, pointCartesian.y); maxY = Math.max(maxY, pointCartesian.y); } const southWestCorner = southWestCornerResult; southWestCorner.x = minX; southWestCorner.y = minY; southWestCorner.z = 0; Matrix4_default.multiplyByPoint(enuMatrix, southWestCorner, southWestCorner); const southEastCorner = eastVectorResult; southEastCorner.x = maxX; southEastCorner.y = minY; southEastCorner.z = 0; Matrix4_default.multiplyByPoint(enuMatrix, southEastCorner, southEastCorner); Cartesian3_default.subtract(southEastCorner, southWestCorner, eastVectorResult); const northWestCorner = northVectorResult; northWestCorner.x = minX; northWestCorner.y = maxY; northWestCorner.z = 0; Matrix4_default.multiplyByPoint(enuMatrix, northWestCorner, northWestCorner); Cartesian3_default.subtract(northWestCorner, southWestCorner, northVectorResult); } var eastwardScratch = new Cartesian3_default(); var northwardScratch = new Cartesian3_default(); var encodeScratch = new EncodedCartesian3_default(); ShadowVolumeAppearance.getPlanarTextureCoordinateAttributes = function(boundingRectangle, textureCoordinateRotationPoints4, ellipsoid, projection, height) { Check_default.typeOf.object("boundingRectangle", boundingRectangle); Check_default.defined( "textureCoordinateRotationPoints", textureCoordinateRotationPoints4 ); Check_default.typeOf.object("ellipsoid", ellipsoid); Check_default.typeOf.object("projection", projection); const corner = cornerScratch; const eastward = eastwardScratch; const northward = northwardScratch; computeRectangleBounds( boundingRectangle, ellipsoid, height ?? 0, corner, eastward, northward ); const attributes = {}; addTextureCoordinateRotationAttributes( attributes, textureCoordinateRotationPoints4 ); const encoded = EncodedCartesian3_default.fromCartesian(corner, encodeScratch); attributes.southWest_HIGH = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, normalize: false, value: Cartesian3_default.pack(encoded.high, [0, 0, 0]) }); attributes.southWest_LOW = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, normalize: false, value: Cartesian3_default.pack(encoded.low, [0, 0, 0]) }); attributes.eastward = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, normalize: false, value: Cartesian3_default.pack(eastward, [0, 0, 0]) }); attributes.northward = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 3, normalize: false, value: Cartesian3_default.pack(northward, [0, 0, 0]) }); add2DTextureCoordinateAttributes(boundingRectangle, projection, attributes); return attributes; }; var spherePointScratch = new Cartesian3_default(); function latLongToSpherical(latitude, longitude, ellipsoid, result) { const cartographic2 = cartographicScratch; cartographic2.latitude = latitude; cartographic2.longitude = longitude; cartographic2.height = 0; const spherePoint = Cartographic_default.toCartesian( cartographic2, ellipsoid, spherePointScratch ); const magXY = Math.sqrt( spherePoint.x * spherePoint.x + spherePoint.y * spherePoint.y ); const sphereLatitude = Math_default.fastApproximateAtan2(magXY, spherePoint.z); const sphereLongitude = Math_default.fastApproximateAtan2( spherePoint.x, spherePoint.y ); result.x = sphereLatitude; result.y = sphereLongitude; return result; } var sphericalScratch = new Cartesian2_default(); ShadowVolumeAppearance.getSphericalExtentGeometryInstanceAttributes = function(boundingRectangle, textureCoordinateRotationPoints4, ellipsoid, projection) { Check_default.typeOf.object("boundingRectangle", boundingRectangle); Check_default.defined( "textureCoordinateRotationPoints", textureCoordinateRotationPoints4 ); Check_default.typeOf.object("ellipsoid", ellipsoid); Check_default.typeOf.object("projection", projection); const southWestExtents = latLongToSpherical( boundingRectangle.south, boundingRectangle.west, ellipsoid, sphericalScratch ); let south = southWestExtents.x; let west = southWestExtents.y; const northEastExtents = latLongToSpherical( boundingRectangle.north, boundingRectangle.east, ellipsoid, sphericalScratch ); let north = northEastExtents.x; let east = northEastExtents.y; let rotationRadians = 0; if (west > east) { rotationRadians = Math_default.PI - west; west = -Math_default.PI; east += rotationRadians; } south -= Math_default.EPSILON5; west -= Math_default.EPSILON5; north += Math_default.EPSILON5; east += Math_default.EPSILON5; const longitudeRangeInverse = 1 / (east - west); const latitudeRangeInverse = 1 / (north - south); const attributes = { sphericalExtents: new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, value: [south, west, latitudeRangeInverse, longitudeRangeInverse] }), longitudeRotation: new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 1, normalize: false, value: [rotationRadians] }) }; addTextureCoordinateRotationAttributes( attributes, textureCoordinateRotationPoints4 ); add2DTextureCoordinateAttributes(boundingRectangle, projection, attributes); return attributes; }; ShadowVolumeAppearance.hasAttributesForTextureCoordinatePlanes = function(attributes) { return defined_default(attributes.southWest_HIGH) && defined_default(attributes.southWest_LOW) && defined_default(attributes.northward) && defined_default(attributes.eastward) && defined_default(attributes.planes2D_HIGH) && defined_default(attributes.planes2D_LOW) && defined_default(attributes.uMaxVmax) && defined_default(attributes.uvMinAndExtents); }; ShadowVolumeAppearance.hasAttributesForSphericalExtents = function(attributes) { return defined_default(attributes.sphericalExtents) && defined_default(attributes.longitudeRotation) && defined_default(attributes.planes2D_HIGH) && defined_default(attributes.planes2D_LOW) && defined_default(attributes.uMaxVmax) && defined_default(attributes.uvMinAndExtents); }; function shouldUseSpherical(rectangle) { return Math.max(rectangle.width, rectangle.height) > ShadowVolumeAppearance.MAX_WIDTH_FOR_PLANAR_EXTENTS; } ShadowVolumeAppearance.shouldUseSphericalCoordinates = function(rectangle) { Check_default.typeOf.object("rectangle", rectangle); return shouldUseSpherical(rectangle); }; ShadowVolumeAppearance.MAX_WIDTH_FOR_PLANAR_EXTENTS = Math_default.toRadians(1); var ShadowVolumeAppearance_default = ShadowVolumeAppearance; // packages/engine/Source/Scene/StencilConstants.js var import_InlineWorkers377 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/StencilFunction.js var import_InlineWorkers375 = __toESM(require_InlineWorkers(), 1); var StencilFunction = { /** * The stencil test never passes. * * @type {number} * @constant */ NEVER: WebGLConstants_default.NEVER, /** * The stencil test passes when the masked reference value is less than the masked stencil value. * * @type {number} * @constant */ LESS: WebGLConstants_default.LESS, /** * The stencil test passes when the masked reference value is equal to the masked stencil value. * * @type {number} * @constant */ EQUAL: WebGLConstants_default.EQUAL, /** * The stencil test passes when the masked reference value is less than or equal to the masked stencil value. * * @type {number} * @constant */ LESS_OR_EQUAL: WebGLConstants_default.LEQUAL, /** * The stencil test passes when the masked reference value is greater than the masked stencil value. * * @type {number} * @constant */ GREATER: WebGLConstants_default.GREATER, /** * The stencil test passes when the masked reference value is not equal to the masked stencil value. * * @type {number} * @constant */ NOT_EQUAL: WebGLConstants_default.NOTEQUAL, /** * The stencil test passes when the masked reference value is greater than or equal to the masked stencil value. * * @type {number} * @constant */ GREATER_OR_EQUAL: WebGLConstants_default.GEQUAL, /** * The stencil test always passes. * * @type {number} * @constant */ ALWAYS: WebGLConstants_default.ALWAYS }; Object.freeze(StencilFunction); var StencilFunction_default = StencilFunction; // packages/engine/Source/Scene/StencilOperation.js var import_InlineWorkers376 = __toESM(require_InlineWorkers(), 1); var StencilOperation = { /** * Sets the stencil buffer value to zero. * * @type {number} * @constant */ ZERO: WebGLConstants_default.ZERO, /** * Does not change the stencil buffer. * * @type {number} * @constant */ KEEP: WebGLConstants_default.KEEP, /** * Replaces the stencil buffer value with the reference value. * * @type {number} * @constant */ REPLACE: WebGLConstants_default.REPLACE, /** * Increments the stencil buffer value, clamping to unsigned byte. * * @type {number} * @constant */ INCREMENT: WebGLConstants_default.INCR, /** * Decrements the stencil buffer value, clamping to zero. * * @type {number} * @constant */ DECREMENT: WebGLConstants_default.DECR, /** * Bitwise inverts the existing stencil buffer value. * * @type {number} * @constant */ INVERT: WebGLConstants_default.INVERT, /** * Increments the stencil buffer value, wrapping to zero when exceeding the unsigned byte range. * * @type {number} * @constant */ INCREMENT_WRAP: WebGLConstants_default.INCR_WRAP, /** * Decrements the stencil buffer value, wrapping to the maximum unsigned byte instead of going below zero. * * @type {number} * @constant */ DECREMENT_WRAP: WebGLConstants_default.DECR_WRAP }; Object.freeze(StencilOperation); var StencilOperation_default = StencilOperation; // packages/engine/Source/Scene/StencilConstants.js var StencilConstants = { CESIUM_3D_TILE_MASK: 128, SKIP_LOD_MASK: 112, SKIP_LOD_BIT_SHIFT: 4, CLASSIFICATION_MASK: 15 }; StencilConstants.setCesium3DTileBit = function() { return { enabled: true, frontFunction: StencilFunction_default.ALWAYS, frontOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.KEEP, zPass: StencilOperation_default.REPLACE }, backFunction: StencilFunction_default.ALWAYS, backOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.KEEP, zPass: StencilOperation_default.REPLACE }, reference: StencilConstants.CESIUM_3D_TILE_MASK, mask: StencilConstants.CESIUM_3D_TILE_MASK }; }; var StencilConstants_default = Object.freeze(StencilConstants); // packages/engine/Source/Scene/ClassificationPrimitive.js function ClassificationPrimitive(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const geometryInstances = options.geometryInstances; this.geometryInstances = geometryInstances; this.show = options.show ?? true; this.classificationType = options.classificationType ?? ClassificationType_default.BOTH; this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false; this.debugShowShadowVolume = options.debugShowShadowVolume ?? false; this._debugShowShadowVolume = false; this._extruded = options._extruded ?? false; this._uniformMap = options._uniformMap; this._sp = void 0; this._spStencil = void 0; this._spPick = void 0; this._spColor = void 0; this._spPick2D = void 0; this._spColor2D = void 0; this._rsStencilDepthPass = void 0; this._rsStencilDepthPass3DTiles = void 0; this._rsColorPass = void 0; this._rsPickPass = void 0; this._commandsIgnoreShow = []; this._ready = false; this._primitive = void 0; this._pickPrimitive = options._pickPrimitive; this._hasSphericalExtentsAttribute = false; this._hasPlanarExtentsAttributes = false; this._hasPerColorAttribute = false; this.appearance = options.appearance; this._createBoundingVolumeFunction = options._createBoundingVolumeFunction; this._updateAndQueueCommandsFunction = options._updateAndQueueCommandsFunction; this._usePickOffsets = false; this._primitiveOptions = { geometryInstances: void 0, appearance: void 0, vertexCacheOptimize: options.vertexCacheOptimize ?? false, interleave: options.interleave ?? false, releaseGeometryInstances: options.releaseGeometryInstances ?? true, allowPicking: options.allowPicking ?? true, asynchronous: options.asynchronous ?? true, compressVertices: options.compressVertices ?? true, _createBoundingVolumeFunction: void 0, _createRenderStatesFunction: void 0, _createShaderProgramFunction: void 0, _createCommandsFunction: void 0, _updateAndQueueCommandsFunction: void 0, _createPickOffsets: true }; } Object.defineProperties(ClassificationPrimitive.prototype, { /** * When true, geometry vertices are optimized for the pre and post-vertex-shader caches. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ vertexCacheOptimize: { get: function() { return this._primitiveOptions.vertexCacheOptimize; } }, /** * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default false */ interleave: { get: function() { return this._primitiveOptions.interleave; } }, /** * When true, the primitive does not keep a reference to the input geometryInstances to save memory. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ releaseGeometryInstances: { get: function() { return this._primitiveOptions.releaseGeometryInstances; } }, /** * When true, each geometry instance will only be pickable with {@link Scene#pick}. When false, GPU memory is saved. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ allowPicking: { get: function() { return this._primitiveOptions.allowPicking; } }, /** * Determines if the geometry instances will be created and batched on a web worker. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ asynchronous: { get: function() { return this._primitiveOptions.asynchronous; } }, /** * When true, geometry vertices are compressed, which will save memory. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ compressVertices: { get: function() { return this._primitiveOptions.compressVertices; } }, /** * Determines if the primitive is complete and ready to render. If this property is * true, the primitive will be rendered the next time that {@link ClassificationPrimitive#update} * is called. * * @memberof ClassificationPrimitive.prototype * * @type {boolean} * @readonly */ ready: { get: function() { return this._ready; } }, /** * Returns true if the ClassificationPrimitive needs a separate shader and commands for 2D. * This is because texture coordinates on ClassificationPrimitives are computed differently, * and are used for culling when multiple GeometryInstances are batched in one ClassificationPrimitive. * @memberof ClassificationPrimitive.prototype * @type {boolean} * @readonly * @private */ _needs2DShader: { get: function() { return this._hasPlanarExtentsAttributes || this._hasSphericalExtentsAttribute; } } }); ClassificationPrimitive.isSupported = function(scene) { return scene.context.stencilBuffer; }; function getStencilDepthRenderState(enableStencil, mask3DTiles) { const stencilFunction = mask3DTiles ? StencilFunction_default.EQUAL : StencilFunction_default.ALWAYS; return { colorMask: { red: false, green: false, blue: false, alpha: false }, stencilTest: { enabled: enableStencil, frontFunction: stencilFunction, frontOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.DECREMENT_WRAP, zPass: StencilOperation_default.KEEP }, backFunction: stencilFunction, backOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.INCREMENT_WRAP, zPass: StencilOperation_default.KEEP }, reference: StencilConstants_default.CESIUM_3D_TILE_MASK, mask: StencilConstants_default.CESIUM_3D_TILE_MASK }, stencilMask: StencilConstants_default.CLASSIFICATION_MASK, depthTest: { enabled: true, func: DepthFunction_default.LESS_OR_EQUAL }, depthMask: false }; } function getColorRenderState(enableStencil) { return { stencilTest: { enabled: enableStencil, frontFunction: StencilFunction_default.NOT_EQUAL, frontOperation: { fail: StencilOperation_default.ZERO, zFail: StencilOperation_default.ZERO, zPass: StencilOperation_default.ZERO }, backFunction: StencilFunction_default.NOT_EQUAL, backOperation: { fail: StencilOperation_default.ZERO, zFail: StencilOperation_default.ZERO, zPass: StencilOperation_default.ZERO }, reference: 0, mask: StencilConstants_default.CLASSIFICATION_MASK }, stencilMask: StencilConstants_default.CLASSIFICATION_MASK, depthTest: { enabled: false }, depthMask: false, blending: BlendingState_default.PRE_MULTIPLIED_ALPHA_BLEND }; } var pickRenderState = { stencilTest: { enabled: true, frontFunction: StencilFunction_default.NOT_EQUAL, frontOperation: { fail: StencilOperation_default.ZERO, zFail: StencilOperation_default.ZERO, zPass: StencilOperation_default.ZERO }, backFunction: StencilFunction_default.NOT_EQUAL, backOperation: { fail: StencilOperation_default.ZERO, zFail: StencilOperation_default.ZERO, zPass: StencilOperation_default.ZERO }, reference: 0, mask: StencilConstants_default.CLASSIFICATION_MASK }, stencilMask: StencilConstants_default.CLASSIFICATION_MASK, depthTest: { enabled: false }, depthMask: false }; function createRenderStates2(classificationPrimitive, context, appearance, twoPasses) { if (defined_default(classificationPrimitive._rsStencilDepthPass)) { return; } const stencilEnabled = !classificationPrimitive.debugShowShadowVolume; classificationPrimitive._rsStencilDepthPass = RenderState_default.fromCache( getStencilDepthRenderState(stencilEnabled, false) ); classificationPrimitive._rsStencilDepthPass3DTiles = RenderState_default.fromCache( getStencilDepthRenderState(stencilEnabled, true) ); classificationPrimitive._rsColorPass = RenderState_default.fromCache( getColorRenderState(stencilEnabled, false) ); classificationPrimitive._rsPickPass = RenderState_default.fromCache(pickRenderState); } function modifyForEncodedNormals2(primitive, vertexShaderSource) { if (!primitive.compressVertices) { return vertexShaderSource; } if (vertexShaderSource.search(/in\s+vec3\s+extrudeDirection;/g) !== -1) { const attributeName = "compressedAttributes"; const attributeDecl = `in vec2 ${attributeName};`; const globalDecl = "vec3 extrudeDirection;\n"; const decode = ` extrudeDirection = czm_octDecode(${attributeName}, 65535.0); `; let modifiedVS = vertexShaderSource; modifiedVS = modifiedVS.replace(/in\s+vec3\s+extrudeDirection;/g, ""); modifiedVS = ShaderSource_default.replaceMain( modifiedVS, "czm_non_compressed_main" ); const compressedMain = `${"void main() \n{ \n"}${decode} czm_non_compressed_main(); }`; return [attributeDecl, globalDecl, modifiedVS, compressedMain].join("\n"); } } function createShaderProgram2(classificationPrimitive, frameState) { const context = frameState.context; const primitive = classificationPrimitive._primitive; let vs = ShadowVolumeAppearanceVS_default; vs = classificationPrimitive._primitive._batchTable.getVertexShaderCallback()( vs ); vs = Primitive_default._appendDistanceDisplayConditionToShader(primitive, vs); vs = Primitive_default._modifyShaderPosition( classificationPrimitive, vs, frameState.scene3DOnly ); vs = Primitive_default._updateColorAttribute(primitive, vs); const planarExtents = classificationPrimitive._hasPlanarExtentsAttributes; const cullFragmentsUsingExtents = planarExtents || classificationPrimitive._hasSphericalExtentsAttribute; if (classificationPrimitive._extruded) { vs = modifyForEncodedNormals2(primitive, vs); } const extrudedDefine = classificationPrimitive._extruded ? "EXTRUDED_GEOMETRY" : ""; let vsSource = new ShaderSource_default({ defines: [extrudedDefine], sources: [vs] }); const fsSource = new ShaderSource_default({ sources: [ShadowVolumeFS_default] }); const attributeLocations8 = classificationPrimitive._primitive._attributeLocations; const shadowVolumeAppearance = new ShadowVolumeAppearance_default( cullFragmentsUsingExtents, planarExtents, classificationPrimitive.appearance ); classificationPrimitive._spStencil = ShaderProgram_default.replaceCache({ context, shaderProgram: classificationPrimitive._spStencil, vertexShaderSource: vsSource, fragmentShaderSource: fsSource, attributeLocations: attributeLocations8 }); if (classificationPrimitive._primitive.allowPicking) { let vsPick = ShaderSource_default.createPickVertexShaderSource(vs); vsPick = Primitive_default._appendShowToShader(primitive, vsPick); vsPick = Primitive_default._updatePickColorAttribute(vsPick); const pickFS3D = shadowVolumeAppearance.createPickFragmentShader(false); const pickVS3D = shadowVolumeAppearance.createPickVertexShader( [extrudedDefine], vsPick, false, frameState.mapProjection ); classificationPrimitive._spPick = ShaderProgram_default.replaceCache({ context, shaderProgram: classificationPrimitive._spPick, vertexShaderSource: pickVS3D, fragmentShaderSource: pickFS3D, attributeLocations: attributeLocations8 }); if (cullFragmentsUsingExtents) { let pickProgram2D = context.shaderCache.getDerivedShaderProgram( classificationPrimitive._spPick, "2dPick" ); if (!defined_default(pickProgram2D)) { const pickFS2D = shadowVolumeAppearance.createPickFragmentShader(true); const pickVS2D = shadowVolumeAppearance.createPickVertexShader( [extrudedDefine], vsPick, true, frameState.mapProjection ); pickProgram2D = context.shaderCache.createDerivedShaderProgram( classificationPrimitive._spPick, "2dPick", { vertexShaderSource: pickVS2D, fragmentShaderSource: pickFS2D, attributeLocations: attributeLocations8 } ); } classificationPrimitive._spPick2D = pickProgram2D; } } else { classificationPrimitive._spPick = ShaderProgram_default.fromCache({ context, vertexShaderSource: vsSource, fragmentShaderSource: fsSource, attributeLocations: attributeLocations8 }); } vs = Primitive_default._appendShowToShader(primitive, vs); vsSource = new ShaderSource_default({ defines: [extrudedDefine], sources: [vs] }); classificationPrimitive._sp = ShaderProgram_default.replaceCache({ context, shaderProgram: classificationPrimitive._sp, vertexShaderSource: vsSource, fragmentShaderSource: fsSource, attributeLocations: attributeLocations8 }); const fsColorSource = shadowVolumeAppearance.createFragmentShader(false); const vsColorSource = shadowVolumeAppearance.createVertexShader( [extrudedDefine], vs, false, frameState.mapProjection ); classificationPrimitive._spColor = ShaderProgram_default.replaceCache({ context, shaderProgram: classificationPrimitive._spColor, vertexShaderSource: vsColorSource, fragmentShaderSource: fsColorSource, attributeLocations: attributeLocations8 }); if (cullFragmentsUsingExtents) { let colorProgram2D = context.shaderCache.getDerivedShaderProgram( classificationPrimitive._spColor, "2dColor" ); if (!defined_default(colorProgram2D)) { const fsColorSource2D = shadowVolumeAppearance.createFragmentShader(true); const vsColorSource2D = shadowVolumeAppearance.createVertexShader( [extrudedDefine], vs, true, frameState.mapProjection ); colorProgram2D = context.shaderCache.createDerivedShaderProgram( classificationPrimitive._spColor, "2dColor", { vertexShaderSource: vsColorSource2D, fragmentShaderSource: fsColorSource2D, attributeLocations: attributeLocations8 } ); } classificationPrimitive._spColor2D = colorProgram2D; } } function createColorCommands(classificationPrimitive, colorCommands) { const primitive = classificationPrimitive._primitive; let length2 = primitive._va.length * 2; colorCommands.length = length2; let i; let command; let derivedCommand; let vaIndex = 0; let uniformMap2 = primitive._batchTable.getUniformMapCallback()( classificationPrimitive._uniformMap ); const needs2DShader = classificationPrimitive._needs2DShader; for (i = 0; i < length2; i += 2) { const vertexArray = primitive._va[vaIndex++]; command = colorCommands[i]; if (!defined_default(command)) { command = colorCommands[i] = new DrawCommand_default({ owner: classificationPrimitive, primitiveType: primitive._primitiveType }); } command.vertexArray = vertexArray; command.renderState = classificationPrimitive._rsStencilDepthPass; command.shaderProgram = classificationPrimitive._sp; command.uniformMap = uniformMap2; command.pass = Pass_default.TERRAIN_CLASSIFICATION; derivedCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.tileset ); derivedCommand.renderState = classificationPrimitive._rsStencilDepthPass3DTiles; derivedCommand.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION; command.derivedCommands.tileset = derivedCommand; command = colorCommands[i + 1]; if (!defined_default(command)) { command = colorCommands[i + 1] = new DrawCommand_default({ owner: classificationPrimitive, primitiveType: primitive._primitiveType }); } command.vertexArray = vertexArray; command.renderState = classificationPrimitive._rsColorPass; command.shaderProgram = classificationPrimitive._spColor; command.pass = Pass_default.TERRAIN_CLASSIFICATION; const appearance = classificationPrimitive.appearance; const material4 = appearance.material; if (defined_default(material4)) { uniformMap2 = combine_default(uniformMap2, material4._uniforms); } command.uniformMap = uniformMap2; derivedCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.tileset ); derivedCommand.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION; command.derivedCommands.tileset = derivedCommand; if (needs2DShader) { let derived2DCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.appearance2D ); derived2DCommand.shaderProgram = classificationPrimitive._spColor2D; command.derivedCommands.appearance2D = derived2DCommand; derived2DCommand = DrawCommand_default.shallowClone( derivedCommand, derivedCommand.derivedCommands.appearance2D ); derived2DCommand.shaderProgram = classificationPrimitive._spColor2D; derivedCommand.derivedCommands.appearance2D = derived2DCommand; } } const commandsIgnoreShow = classificationPrimitive._commandsIgnoreShow; const spStencil = classificationPrimitive._spStencil; let commandIndex = 0; length2 = commandsIgnoreShow.length = length2 / 2; for (let j = 0; j < length2; ++j) { const commandIgnoreShow = commandsIgnoreShow[j] = DrawCommand_default.shallowClone( colorCommands[commandIndex], commandsIgnoreShow[j] ); commandIgnoreShow.shaderProgram = spStencil; commandIgnoreShow.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW; commandIndex += 2; } } function createPickCommands(classificationPrimitive, pickCommands) { const usePickOffsets = classificationPrimitive._usePickOffsets; const primitive = classificationPrimitive._primitive; let length2 = primitive._va.length * 2; let pickOffsets; let pickIndex = 0; let pickOffset; if (usePickOffsets) { pickOffsets = primitive._pickOffsets; length2 = pickOffsets.length * 2; } pickCommands.length = length2; let j; let command; let derivedCommand; let vaIndex = 0; const uniformMap2 = primitive._batchTable.getUniformMapCallback()( classificationPrimitive._uniformMap ); const needs2DShader = classificationPrimitive._needs2DShader; for (j = 0; j < length2; j += 2) { let vertexArray = primitive._va[vaIndex++]; if (usePickOffsets) { pickOffset = pickOffsets[pickIndex++]; vertexArray = primitive._va[pickOffset.index]; } command = pickCommands[j]; if (!defined_default(command)) { command = pickCommands[j] = new DrawCommand_default({ owner: classificationPrimitive, primitiveType: primitive._primitiveType, pickOnly: true }); } command.vertexArray = vertexArray; command.renderState = classificationPrimitive._rsStencilDepthPass; command.shaderProgram = classificationPrimitive._sp; command.uniformMap = uniformMap2; command.pass = Pass_default.TERRAIN_CLASSIFICATION; if (usePickOffsets) { command.offset = pickOffset.offset; command.count = pickOffset.count; } derivedCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.tileset ); derivedCommand.renderState = classificationPrimitive._rsStencilDepthPass3DTiles; derivedCommand.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION; command.derivedCommands.tileset = derivedCommand; command = pickCommands[j + 1]; if (!defined_default(command)) { command = pickCommands[j + 1] = new DrawCommand_default({ owner: classificationPrimitive, primitiveType: primitive._primitiveType, pickOnly: true }); } command.vertexArray = vertexArray; command.renderState = classificationPrimitive._rsPickPass; command.shaderProgram = classificationPrimitive._spPick; command.uniformMap = uniformMap2; command.pass = Pass_default.TERRAIN_CLASSIFICATION; if (usePickOffsets) { command.offset = pickOffset.offset; command.count = pickOffset.count; } derivedCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.tileset ); derivedCommand.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION; command.derivedCommands.tileset = derivedCommand; if (needs2DShader) { let derived2DCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.pick2D ); derived2DCommand.shaderProgram = classificationPrimitive._spPick2D; command.derivedCommands.pick2D = derived2DCommand; derived2DCommand = DrawCommand_default.shallowClone( derivedCommand, derivedCommand.derivedCommands.pick2D ); derived2DCommand.shaderProgram = classificationPrimitive._spPick2D; derivedCommand.derivedCommands.pick2D = derived2DCommand; } } } function createCommands2(classificationPrimitive, appearance, material4, translucent, twoPasses, colorCommands, pickCommands) { createColorCommands(classificationPrimitive, colorCommands); createPickCommands(classificationPrimitive, pickCommands); } function boundingVolumeIndex(commandIndex, length2) { return Math.floor(commandIndex % length2 / 2); } function updateAndQueueRenderCommand(command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2) { command.modelMatrix = modelMatrix; command.boundingVolume = boundingVolume; command.cull = cull; command.debugShowBoundingVolume = debugShowBoundingVolume2; frameState.commandList.push(command); } function updateAndQueuePickCommand(command, frameState, modelMatrix, cull, boundingVolume) { command.modelMatrix = modelMatrix; command.boundingVolume = boundingVolume; command.cull = cull; frameState.commandList.push(command); } function updateAndQueueCommands2(classificationPrimitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { const primitive = classificationPrimitive._primitive; Primitive_default._updateBoundingVolumes(primitive, frameState, modelMatrix); let boundingVolumes; if (frameState.mode === SceneMode_default.SCENE3D) { boundingVolumes = primitive._boundingSphereWC; } else if (frameState.mode === SceneMode_default.COLUMBUS_VIEW) { boundingVolumes = primitive._boundingSphereCV; } else if (frameState.mode === SceneMode_default.SCENE2D && defined_default(primitive._boundingSphere2D)) { boundingVolumes = primitive._boundingSphere2D; } else if (defined_default(primitive._boundingSphereMorph)) { boundingVolumes = primitive._boundingSphereMorph; } const classificationType = classificationPrimitive.classificationType; const queueTerrainCommands = classificationType !== ClassificationType_default.CESIUM_3D_TILE; const queue3DTilesCommands = classificationType !== ClassificationType_default.TERRAIN; const passes = frameState.passes; let i; let boundingVolume; let command; if (passes.render) { const colorLength = colorCommands.length; for (i = 0; i < colorLength; ++i) { boundingVolume = boundingVolumes[boundingVolumeIndex(i, colorLength)]; if (queueTerrainCommands) { command = colorCommands[i]; updateAndQueueRenderCommand( command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } if (queue3DTilesCommands) { command = colorCommands[i].derivedCommands.tileset; updateAndQueueRenderCommand( command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } } if (frameState.invertClassification) { const ignoreShowCommands = classificationPrimitive._commandsIgnoreShow; const ignoreShowCommandsLength = ignoreShowCommands.length; for (i = 0; i < ignoreShowCommandsLength; ++i) { boundingVolume = boundingVolumes[i]; command = ignoreShowCommands[i]; updateAndQueueRenderCommand( command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } } } if (passes.pick) { const pickLength = pickCommands.length; const pickOffsets = primitive._pickOffsets; for (i = 0; i < pickLength; ++i) { const pickOffset = pickOffsets[boundingVolumeIndex(i, pickLength)]; boundingVolume = boundingVolumes[pickOffset.index]; if (queueTerrainCommands) { command = pickCommands[i]; updateAndQueuePickCommand( command, frameState, modelMatrix, cull, boundingVolume ); } if (queue3DTilesCommands) { command = pickCommands[i].derivedCommands.tileset; updateAndQueuePickCommand( command, frameState, modelMatrix, cull, boundingVolume ); } } } } ClassificationPrimitive.prototype.update = function(frameState) { if (!defined_default(this._primitive) && !defined_default(this.geometryInstances)) { return; } let appearance = this.appearance; if (defined_default(appearance) && defined_default(appearance.material)) { appearance.material.update(frameState.context); } const that = this; const primitiveOptions = this._primitiveOptions; if (!defined_default(this._primitive)) { const instances = Array.isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances]; const length2 = instances.length; let i; let instance; let attributes; let hasPerColorAttribute = false; let allColorsSame = true; let firstColor; let hasSphericalExtentsAttribute = false; let hasPlanarExtentsAttributes = false; if (length2 > 0) { attributes = instances[0].attributes; hasSphericalExtentsAttribute = ShadowVolumeAppearance_default.hasAttributesForSphericalExtents(attributes); hasPlanarExtentsAttributes = ShadowVolumeAppearance_default.hasAttributesForTextureCoordinatePlanes( attributes ); firstColor = attributes.color; } for (i = 0; i < length2; i++) { instance = instances[i]; const color = instance.attributes.color; if (defined_default(color)) { hasPerColorAttribute = true; } else if (hasPerColorAttribute) { throw new DeveloperError_default( "All GeometryInstances must have color attributes to use per-instance color." ); } allColorsSame = allColorsSame && defined_default(color) && ColorGeometryInstanceAttribute_default.equals(firstColor, color); } if (!allColorsSame && !hasSphericalExtentsAttribute && !hasPlanarExtentsAttributes) { throw new DeveloperError_default( "All GeometryInstances must have the same color attribute except via GroundPrimitives" ); } if (hasPerColorAttribute && !defined_default(appearance)) { appearance = new PerInstanceColorAppearance_default({ flat: true }); this.appearance = appearance; } if (!hasPerColorAttribute && appearance instanceof PerInstanceColorAppearance_default) { throw new DeveloperError_default( "PerInstanceColorAppearance requires color GeometryInstanceAttributes on all GeometryInstances" ); } if (defined_default(appearance.material) && !hasSphericalExtentsAttribute && !hasPlanarExtentsAttributes) { throw new DeveloperError_default( "Materials on ClassificationPrimitives are not supported except via GroundPrimitives" ); } this._usePickOffsets = !hasSphericalExtentsAttribute && !hasPlanarExtentsAttributes; this._hasSphericalExtentsAttribute = hasSphericalExtentsAttribute; this._hasPlanarExtentsAttributes = hasPlanarExtentsAttributes; this._hasPerColorAttribute = hasPerColorAttribute; const geometryInstances = new Array(length2); for (i = 0; i < length2; ++i) { instance = instances[i]; geometryInstances[i] = new GeometryInstance_default({ geometry: instance.geometry, attributes: instance.attributes, modelMatrix: instance.modelMatrix, id: instance.id, pickPrimitive: this._pickPrimitive ?? that }); } primitiveOptions.appearance = appearance; primitiveOptions.geometryInstances = geometryInstances; if (defined_default(this._createBoundingVolumeFunction)) { primitiveOptions._createBoundingVolumeFunction = function(frameState2, geometry) { that._createBoundingVolumeFunction(frameState2, geometry); }; } primitiveOptions._createRenderStatesFunction = function(primitive, context, appearance2, twoPasses) { createRenderStates2(that, context); }; primitiveOptions._createShaderProgramFunction = function(primitive, frameState2, appearance2) { createShaderProgram2(that, frameState2); }; primitiveOptions._createCommandsFunction = function(primitive, appearance2, material4, translucent, twoPasses, colorCommands, pickCommands) { createCommands2( that, void 0, void 0, true, false, colorCommands, pickCommands ); }; if (defined_default(this._updateAndQueueCommandsFunction)) { primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { that._updateAndQueueCommandsFunction( primitive, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses ); }; } else { primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { updateAndQueueCommands2( that, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses ); }; } this._primitive = new Primitive_default(primitiveOptions); } if (this.debugShowShadowVolume && !this._debugShowShadowVolume && this._ready) { this._debugShowShadowVolume = true; this._rsStencilDepthPass = RenderState_default.fromCache( getStencilDepthRenderState(false, false) ); this._rsStencilDepthPass3DTiles = RenderState_default.fromCache( getStencilDepthRenderState(false, true) ); this._rsColorPass = RenderState_default.fromCache(getColorRenderState(false)); } else if (!this.debugShowShadowVolume && this._debugShowShadowVolume) { this._debugShowShadowVolume = false; this._rsStencilDepthPass = RenderState_default.fromCache( getStencilDepthRenderState(true, false) ); this._rsStencilDepthPass3DTiles = RenderState_default.fromCache( getStencilDepthRenderState(true, true) ); this._rsColorPass = RenderState_default.fromCache(getColorRenderState(true)); } if (this._primitive.appearance !== appearance) { if (!this._hasSphericalExtentsAttribute && !this._hasPlanarExtentsAttributes && defined_default(appearance.material)) { throw new DeveloperError_default( "Materials on ClassificationPrimitives are not supported except via GroundPrimitive" ); } if (!this._hasPerColorAttribute && appearance instanceof PerInstanceColorAppearance_default) { throw new DeveloperError_default( "PerInstanceColorAppearance requires color GeometryInstanceAttribute" ); } this._primitive.appearance = appearance; } this._primitive.show = this.show; this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume; this._primitive.update(frameState); frameState.afterRender.push(() => { if (defined_default(this._primitive) && this._primitive.ready) { this._ready = true; if (this.releaseGeometryInstances) { this.geometryInstances = void 0; } } }); }; ClassificationPrimitive.prototype.getGeometryInstanceAttributes = function(id) { if (!defined_default(this._primitive)) { throw new DeveloperError_default( "must call update before calling getGeometryInstanceAttributes" ); } return this._primitive.getGeometryInstanceAttributes(id); }; ClassificationPrimitive.prototype.isDestroyed = function() { return false; }; ClassificationPrimitive.prototype.destroy = function() { this._primitive = this._primitive && this._primitive.destroy(); this._sp = this._sp && this._sp.destroy(); this._spPick = this._spPick && this._spPick.destroy(); this._spColor = this._spColor && this._spColor.destroy(); this._spPick2D = void 0; this._spColor2D = void 0; return destroyObject_default(this); }; var ClassificationPrimitive_default = ClassificationPrimitive; // packages/engine/Source/Scene/GroundPrimitive.js var GroundPrimitiveUniformMap = { u_globeMinimumAltitude: function() { return 55e3; } }; function GroundPrimitive(options) { options = options ?? Frozen_default.EMPTY_OBJECT; let appearance = options.appearance; const geometryInstances = options.geometryInstances; if (!defined_default(appearance) && defined_default(geometryInstances)) { const geometryInstancesArray = Array.isArray(geometryInstances) ? geometryInstances : [geometryInstances]; const geometryInstanceCount = geometryInstancesArray.length; for (let i = 0; i < geometryInstanceCount; i++) { const attributes = geometryInstancesArray[i].attributes; if (defined_default(attributes) && defined_default(attributes.color)) { appearance = new PerInstanceColorAppearance_default({ flat: true }); break; } } } this.appearance = appearance; this.geometryInstances = options.geometryInstances; this.show = options.show ?? true; this.classificationType = options.classificationType ?? ClassificationType_default.BOTH; this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false; this.debugShowShadowVolume = options.debugShowShadowVolume ?? false; this._boundingVolumes = []; this._boundingVolumes2D = []; this._ready = false; this._primitive = void 0; this._maxHeight = void 0; this._minHeight = void 0; this._maxTerrainHeight = ApproximateTerrainHeights_default._defaultMaxTerrainHeight; this._minTerrainHeight = ApproximateTerrainHeights_default._defaultMinTerrainHeight; this._boundingSpheresKeys = []; this._boundingSpheres = []; this._useFragmentCulling = false; this._zIndex = void 0; const that = this; this._classificationPrimitiveOptions = { geometryInstances: void 0, appearance: void 0, vertexCacheOptimize: options.vertexCacheOptimize ?? false, interleave: options.interleave ?? false, releaseGeometryInstances: options.releaseGeometryInstances ?? true, allowPicking: options.allowPicking ?? true, asynchronous: options.asynchronous ?? true, compressVertices: options.compressVertices ?? true, _createBoundingVolumeFunction: void 0, _updateAndQueueCommandsFunction: void 0, _pickPrimitive: that, _extruded: true, _uniformMap: GroundPrimitiveUniformMap }; } Object.defineProperties(GroundPrimitive.prototype, { /** * When true, geometry vertices are optimized for the pre and post-vertex-shader caches. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ vertexCacheOptimize: { get: function() { return this._classificationPrimitiveOptions.vertexCacheOptimize; } }, /** * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default false */ interleave: { get: function() { return this._classificationPrimitiveOptions.interleave; } }, /** * When true, the primitive does not keep a reference to the input geometryInstances to save memory. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ releaseGeometryInstances: { get: function() { return this._classificationPrimitiveOptions.releaseGeometryInstances; } }, /** * When true, each geometry instance will only be pickable with {@link Scene#pick}. When false, GPU memory is saved. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ allowPicking: { get: function() { return this._classificationPrimitiveOptions.allowPicking; } }, /** * Determines if the geometry instances will be created and batched on a web worker. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ asynchronous: { get: function() { return this._classificationPrimitiveOptions.asynchronous; } }, /** * When true, geometry vertices are compressed, which will save memory. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly * * @default true */ compressVertices: { get: function() { return this._classificationPrimitiveOptions.compressVertices; } }, /** * Determines if the primitive is complete and ready to render. If this property is * true, the primitive will be rendered the next time that {@link GroundPrimitive#update} * is called. * * @memberof GroundPrimitive.prototype * * @type {boolean} * @readonly */ ready: { get: function() { return this._ready; } } }); GroundPrimitive.isSupported = ClassificationPrimitive_default.isSupported; function getComputeMaximumHeightFunction(primitive) { return function(granularity, ellipsoid) { const r2 = ellipsoid.maximumRadius; const delta = r2 / Math.cos(granularity * 0.5) - r2; return primitive._maxHeight + delta; }; } function getComputeMinimumHeightFunction(primitive) { return function(granularity, ellipsoid) { return primitive._minHeight; }; } var scratchBVCartesianHigh = new Cartesian3_default(); var scratchBVCartesianLow = new Cartesian3_default(); var scratchBVCartesian = new Cartesian3_default(); var scratchBVCartographic = new Cartographic_default(); var scratchBVRectangle = new Rectangle_default(); function getRectangle(frameState, geometry) { const ellipsoid = frameState.mapProjection.ellipsoid; if (!defined_default(geometry.attributes) || !defined_default(geometry.attributes.position3DHigh)) { if (defined_default(geometry.rectangle)) { return geometry.rectangle; } return void 0; } const highPositions = geometry.attributes.position3DHigh.values; const lowPositions = geometry.attributes.position3DLow.values; const length2 = highPositions.length; let minLat = Number.POSITIVE_INFINITY; let minLon = Number.POSITIVE_INFINITY; let maxLat = Number.NEGATIVE_INFINITY; let maxLon = Number.NEGATIVE_INFINITY; for (let i = 0; i < length2; i += 3) { const highPosition = Cartesian3_default.unpack( highPositions, i, scratchBVCartesianHigh ); const lowPosition = Cartesian3_default.unpack( lowPositions, i, scratchBVCartesianLow ); const position = Cartesian3_default.add( highPosition, lowPosition, scratchBVCartesian ); const cartographic2 = ellipsoid.cartesianToCartographic( position, scratchBVCartographic ); const latitude = cartographic2.latitude; const longitude = cartographic2.longitude; minLat = Math.min(minLat, latitude); minLon = Math.min(minLon, longitude); maxLat = Math.max(maxLat, latitude); maxLon = Math.max(maxLon, longitude); } const rectangle = scratchBVRectangle; rectangle.north = maxLat; rectangle.south = minLat; rectangle.east = maxLon; rectangle.west = minLon; return rectangle; } function setMinMaxTerrainHeights(primitive, rectangle, ellipsoid) { const result = ApproximateTerrainHeights_default.getMinimumMaximumHeights( rectangle, ellipsoid ); primitive._minTerrainHeight = result.minimumTerrainHeight; primitive._maxTerrainHeight = result.maximumTerrainHeight; } function createBoundingVolume(groundPrimitive, frameState, geometry) { const ellipsoid = frameState.mapProjection.ellipsoid; const rectangle = getRectangle(frameState, geometry); const obb = OrientedBoundingBox_default.fromRectangle( rectangle, groundPrimitive._minHeight, groundPrimitive._maxHeight, ellipsoid ); groundPrimitive._boundingVolumes.push(obb); if (!frameState.scene3DOnly) { const projection = frameState.mapProjection; const boundingVolume = BoundingSphere_default.fromRectangleWithHeights2D( rectangle, projection, groundPrimitive._maxHeight, groundPrimitive._minHeight ); Cartesian3_default.fromElements( boundingVolume.center.z, boundingVolume.center.x, boundingVolume.center.y, boundingVolume.center ); groundPrimitive._boundingVolumes2D.push(boundingVolume); } } function boundingVolumeIndex2(commandIndex, length2) { return Math.floor(commandIndex % length2 / 2); } function updateAndQueueRenderCommand2(groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2) { const classificationPrimitive = groundPrimitive._primitive; if (frameState.mode !== SceneMode_default.SCENE3D && command.shaderProgram === classificationPrimitive._spColor && classificationPrimitive._needs2DShader) { command = command.derivedCommands.appearance2D; } command.owner = groundPrimitive; command.modelMatrix = modelMatrix; command.boundingVolume = boundingVolume; command.cull = cull; command.debugShowBoundingVolume = debugShowBoundingVolume2; frameState.commandList.push(command); } function updateAndQueuePickCommand2(groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume) { const classificationPrimitive = groundPrimitive._primitive; if (frameState.mode !== SceneMode_default.SCENE3D && command.shaderProgram === classificationPrimitive._spPick && classificationPrimitive._needs2DShader) { command = command.derivedCommands.pick2D; } command.owner = groundPrimitive; command.modelMatrix = modelMatrix; command.boundingVolume = boundingVolume; command.cull = cull; frameState.commandList.push(command); } function updateAndQueueCommands3(groundPrimitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { let boundingVolumes; if (frameState.mode === SceneMode_default.SCENE3D) { boundingVolumes = groundPrimitive._boundingVolumes; } else { boundingVolumes = groundPrimitive._boundingVolumes2D; } const classificationType = groundPrimitive.classificationType; const queueTerrainCommands = classificationType !== ClassificationType_default.CESIUM_3D_TILE; const queue3DTilesCommands = classificationType !== ClassificationType_default.TERRAIN; const passes = frameState.passes; const classificationPrimitive = groundPrimitive._primitive; let i; let boundingVolume; let command; if (passes.render) { const colorLength = colorCommands.length; for (i = 0; i < colorLength; ++i) { boundingVolume = boundingVolumes[boundingVolumeIndex2(i, colorLength)]; if (queueTerrainCommands) { command = colorCommands[i]; updateAndQueueRenderCommand2( groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } if (queue3DTilesCommands) { command = colorCommands[i].derivedCommands.tileset; updateAndQueueRenderCommand2( groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } } if (frameState.invertClassification) { const ignoreShowCommands = classificationPrimitive._commandsIgnoreShow; const ignoreShowCommandsLength = ignoreShowCommands.length; for (i = 0; i < ignoreShowCommandsLength; ++i) { boundingVolume = boundingVolumes[i]; command = ignoreShowCommands[i]; updateAndQueueRenderCommand2( groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } } } if (passes.pick) { const pickLength = pickCommands.length; let pickOffsets; if (!groundPrimitive._useFragmentCulling) { pickOffsets = classificationPrimitive._primitive._pickOffsets; } for (i = 0; i < pickLength; ++i) { boundingVolume = boundingVolumes[boundingVolumeIndex2(i, pickLength)]; if (!groundPrimitive._useFragmentCulling) { const pickOffset = pickOffsets[boundingVolumeIndex2(i, pickLength)]; boundingVolume = boundingVolumes[pickOffset.index]; } if (queueTerrainCommands) { command = pickCommands[i]; updateAndQueuePickCommand2( groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume ); } if (queue3DTilesCommands) { command = pickCommands[i].derivedCommands.tileset; updateAndQueuePickCommand2( groundPrimitive, command, frameState, modelMatrix, cull, boundingVolume ); } } } } GroundPrimitive.initializeTerrainHeights = function() { return ApproximateTerrainHeights_default.initialize(); }; GroundPrimitive.prototype.update = function(frameState) { if (!defined_default(this._primitive) && !defined_default(this.geometryInstances)) { return; } if (!ApproximateTerrainHeights_default.initialized) { if (!this.asynchronous) { throw new DeveloperError_default( "For synchronous GroundPrimitives, you must call GroundPrimitive.initializeTerrainHeights() and wait for the returned promise to resolve." ); } GroundPrimitive.initializeTerrainHeights(); return; } const that = this; const primitiveOptions = this._classificationPrimitiveOptions; if (!defined_default(this._primitive)) { const ellipsoid = frameState.mapProjection.ellipsoid; let instance; let geometry; let instanceType; const instances = Array.isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances]; const length2 = instances.length; const groundInstances = new Array(length2); let i; let rectangle; for (i = 0; i < length2; ++i) { instance = instances[i]; geometry = instance.geometry; const instanceRectangle = getRectangle(frameState, geometry); if (!defined_default(rectangle)) { rectangle = Rectangle_default.clone(instanceRectangle); } else if (defined_default(instanceRectangle)) { Rectangle_default.union(rectangle, instanceRectangle, rectangle); } const id = instance.id; if (defined_default(id) && defined_default(instanceRectangle)) { const boundingSphere = ApproximateTerrainHeights_default.getBoundingSphere( instanceRectangle, ellipsoid ); this._boundingSpheresKeys.push(id); this._boundingSpheres.push(boundingSphere); } instanceType = geometry.constructor; if (!defined_default(instanceType) || !defined_default(instanceType.createShadowVolume)) { throw new DeveloperError_default( "Not all of the geometry instances have GroundPrimitive support." ); } } setMinMaxTerrainHeights(this, rectangle, ellipsoid); const exaggeration = frameState.verticalExaggeration; const exaggerationRelativeHeight = frameState.verticalExaggerationRelativeHeight; this._minHeight = VerticalExaggeration_default.getHeight( this._minTerrainHeight, exaggeration, exaggerationRelativeHeight ); this._maxHeight = VerticalExaggeration_default.getHeight( this._maxTerrainHeight, exaggeration, exaggerationRelativeHeight ); const useFragmentCulling = GroundPrimitive._supportsMaterials( frameState.context ); this._useFragmentCulling = useFragmentCulling; if (useFragmentCulling) { let attributes; let usePlanarExtents = true; for (i = 0; i < length2; ++i) { instance = instances[i]; geometry = instance.geometry; rectangle = getRectangle(frameState, geometry); if (ShadowVolumeAppearance_default.shouldUseSphericalCoordinates(rectangle)) { usePlanarExtents = false; break; } } for (i = 0; i < length2; ++i) { instance = instances[i]; geometry = instance.geometry; instanceType = geometry.constructor; const boundingRectangle = getRectangle(frameState, geometry); const textureCoordinateRotationPoints4 = geometry.textureCoordinateRotationPoints; if (usePlanarExtents) { attributes = ShadowVolumeAppearance_default.getPlanarTextureCoordinateAttributes( boundingRectangle, textureCoordinateRotationPoints4, ellipsoid, frameState.mapProjection, this._maxHeight ); } else { attributes = ShadowVolumeAppearance_default.getSphericalExtentGeometryInstanceAttributes( boundingRectangle, textureCoordinateRotationPoints4, ellipsoid, frameState.mapProjection ); } const instanceAttributes = instance.attributes; for (const attributeKey in instanceAttributes) { if (instanceAttributes.hasOwnProperty(attributeKey)) { attributes[attributeKey] = instanceAttributes[attributeKey]; } } groundInstances[i] = new GeometryInstance_default({ geometry: instanceType.createShadowVolume( geometry, getComputeMinimumHeightFunction(this), getComputeMaximumHeightFunction(this) ), attributes, id: instance.id }); } } else { for (i = 0; i < length2; ++i) { instance = instances[i]; geometry = instance.geometry; instanceType = geometry.constructor; groundInstances[i] = new GeometryInstance_default({ geometry: instanceType.createShadowVolume( geometry, getComputeMinimumHeightFunction(this), getComputeMaximumHeightFunction(this) ), attributes: instance.attributes, id: instance.id }); } } primitiveOptions.geometryInstances = groundInstances; primitiveOptions.appearance = this.appearance; primitiveOptions._createBoundingVolumeFunction = function(frameState2, geometry2) { createBoundingVolume(that, frameState2, geometry2); }; primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { updateAndQueueCommands3( that, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses ); }; this._primitive = new ClassificationPrimitive_default(primitiveOptions); } this._primitive.appearance = this.appearance; this._primitive.show = this.show; this._primitive.debugShowShadowVolume = this.debugShowShadowVolume; this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume; this._primitive.update(frameState); frameState.afterRender.push(() => { if (!this._ready && defined_default(this._primitive) && this._primitive.ready) { this._ready = true; if (this.releaseGeometryInstances) { this.geometryInstances = void 0; } } }); }; GroundPrimitive.prototype.getBoundingSphere = function(id) { const index = this._boundingSpheresKeys.indexOf(id); if (index !== -1) { return this._boundingSpheres[index]; } return void 0; }; GroundPrimitive.prototype.getGeometryInstanceAttributes = function(id) { if (!defined_default(this._primitive)) { throw new DeveloperError_default( "must call update before calling getGeometryInstanceAttributes" ); } return this._primitive.getGeometryInstanceAttributes(id); }; GroundPrimitive.prototype.isDestroyed = function() { return false; }; GroundPrimitive.prototype.destroy = function() { this._primitive = this._primitive && this._primitive.destroy(); return destroyObject_default(this); }; GroundPrimitive._supportsMaterials = function(context) { return context.depthTexture; }; GroundPrimitive.supportsMaterials = function(scene) { Check_default.typeOf.object("scene", scene); return GroundPrimitive._supportsMaterials(scene.frameState.context); }; var GroundPrimitive_default = GroundPrimitive; // packages/engine/Source/DataSources/MaterialProperty.js var import_InlineWorkers380 = __toESM(require_InlineWorkers(), 1); function MaterialProperty() { DeveloperError_default.throwInstantiationError(); } Object.defineProperties(MaterialProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof MaterialProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: DeveloperError_default.throwInstantiationError }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof MaterialProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: DeveloperError_default.throwInstantiationError } }); MaterialProperty.prototype.getType = DeveloperError_default.throwInstantiationError; MaterialProperty.prototype.getValue = DeveloperError_default.throwInstantiationError; MaterialProperty.prototype.equals = DeveloperError_default.throwInstantiationError; var timeScratch2 = new JulianDate_default(); MaterialProperty.getValue = function(time, materialProperty, material4) { let type; if (!defined_default(time)) { time = JulianDate_default.now(timeScratch2); } if (defined_default(materialProperty)) { type = materialProperty.getType(time); if (defined_default(type)) { if (!defined_default(material4) || material4.type !== type) { material4 = Material_default.fromType(type); } materialProperty.getValue(time, material4.uniforms); return material4; } } if (!defined_default(material4) || material4.type !== Material_default.ColorType) { material4 = Material_default.fromType(Material_default.ColorType); } Color_default.clone(Color_default.WHITE, material4.uniforms.color); return material4; }; var MaterialProperty_default = MaterialProperty; // packages/engine/Source/DataSources/DynamicGeometryUpdater.js function DynamicGeometryUpdater(geometryUpdater, primitives, orderedGroundPrimitives) { Check_default.defined("geometryUpdater", geometryUpdater); Check_default.defined("primitives", primitives); Check_default.defined("orderedGroundPrimitives", orderedGroundPrimitives); this._primitives = primitives; this._orderedGroundPrimitives = orderedGroundPrimitives; this._primitive = void 0; this._outlinePrimitive = void 0; this._geometryUpdater = geometryUpdater; this._options = geometryUpdater._options; this._entity = geometryUpdater._entity; this._material = void 0; } DynamicGeometryUpdater.prototype._isHidden = function(entity, geometry, time) { return !entity.isShowing || !entity.isAvailable(time) || !Property_default.getValueOrDefault(geometry.show, time, true); }; DynamicGeometryUpdater.prototype._setOptions = DeveloperError_default.throwInstantiationError; DynamicGeometryUpdater.prototype.update = function(time) { Check_default.defined("time", time); const geometryUpdater = this._geometryUpdater; const onTerrain = geometryUpdater._onTerrain; const primitives = this._primitives; const orderedGroundPrimitives = this._orderedGroundPrimitives; if (onTerrain) { orderedGroundPrimitives.remove(this._primitive); } else { primitives.removeAndDestroy(this._primitive); primitives.removeAndDestroy(this._outlinePrimitive); this._outlinePrimitive = void 0; } this._primitive = void 0; const entity = this._entity; const geometry = entity[this._geometryUpdater._geometryPropertyName]; this._setOptions(entity, geometry, time); if (this._isHidden(entity, geometry, time)) { return; } const shadows = this._geometryUpdater.shadowsProperty.getValue(time); const options = this._options; if (!defined_default(geometry.fill) || geometry.fill.getValue(time)) { const fillMaterialProperty = geometryUpdater.fillMaterialProperty; const isColorAppearance = fillMaterialProperty instanceof ColorMaterialProperty_default; let appearance; const closed = geometryUpdater._getIsClosed(options); if (isColorAppearance) { appearance = new PerInstanceColorAppearance_default({ closed, flat: onTerrain && !geometryUpdater._supportsMaterialsforEntitiesOnTerrain }); } else { const material4 = MaterialProperty_default.getValue( time, fillMaterialProperty, this._material ); this._material = material4; appearance = new MaterialAppearance_default({ material: material4, translucent: material4.isTranslucent(), closed }); } if (onTerrain) { options.vertexFormat = PerInstanceColorAppearance_default.VERTEX_FORMAT; this._primitive = orderedGroundPrimitives.add( new GroundPrimitive_default({ geometryInstances: this._geometryUpdater.createFillGeometryInstance(time), appearance, asynchronous: false, shadows, classificationType: this._geometryUpdater.classificationTypeProperty.getValue(time) }), Property_default.getValueOrUndefined(this._geometryUpdater.zIndex, time) ); } else { options.vertexFormat = appearance.vertexFormat; const fillInstance = this._geometryUpdater.createFillGeometryInstance(time); if (isColorAppearance) { appearance.translucent = fillInstance.attributes.color.value[3] !== 255; } this._primitive = primitives.add( new Primitive_default({ geometryInstances: fillInstance, appearance, asynchronous: false, shadows }) ); } } if (!onTerrain && defined_default(geometry.outline) && geometry.outline.getValue(time)) { const outlineInstance = this._geometryUpdater.createOutlineGeometryInstance(time); const outlineWidth = Property_default.getValueOrDefault( geometry.outlineWidth, time, 1 ); this._outlinePrimitive = primitives.add( new Primitive_default({ geometryInstances: outlineInstance, appearance: new PerInstanceColorAppearance_default({ flat: true, translucent: outlineInstance.attributes.color.value[3] !== 255, renderState: { lineWidth: geometryUpdater._scene.clampLineWidth(outlineWidth) } }), asynchronous: false, shadows }) ); } }; DynamicGeometryUpdater.prototype.getBoundingSphere = function(result) { if (!defined_default(result)) { throw new DeveloperError_default("result is required."); } const entity = this._entity; const primitive = this._primitive; const outlinePrimitive = this._outlinePrimitive; let attributes; if (defined_default(primitive) && primitive.show && primitive.ready) { attributes = primitive.getGeometryInstanceAttributes(entity); if (defined_default(attributes) && defined_default(attributes.boundingSphere)) { BoundingSphere_default.clone(attributes.boundingSphere, result); return BoundingSphereState_default.DONE; } } if (defined_default(outlinePrimitive) && outlinePrimitive.show && outlinePrimitive.ready) { attributes = outlinePrimitive.getGeometryInstanceAttributes(entity); if (defined_default(attributes) && defined_default(attributes.boundingSphere)) { BoundingSphere_default.clone(attributes.boundingSphere, result); return BoundingSphereState_default.DONE; } } if (defined_default(primitive) && !primitive.ready || defined_default(outlinePrimitive) && !outlinePrimitive.ready) { return BoundingSphereState_default.PENDING; } return BoundingSphereState_default.FAILED; }; DynamicGeometryUpdater.prototype.isDestroyed = function() { return false; }; DynamicGeometryUpdater.prototype.destroy = function() { const primitives = this._primitives; const orderedGroundPrimitives = this._orderedGroundPrimitives; if (this._geometryUpdater._onTerrain) { orderedGroundPrimitives.remove(this._primitive); } else { primitives.removeAndDestroy(this._primitive); } primitives.removeAndDestroy(this._outlinePrimitive); destroyObject_default(this); }; var DynamicGeometryUpdater_default = DynamicGeometryUpdater; // packages/engine/Source/DataSources/GeometryUpdater.js var import_InlineWorkers427 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/oneTimeWarning.js var import_InlineWorkers382 = __toESM(require_InlineWorkers(), 1); var warnings = {}; function oneTimeWarning(identifier, message) { if (!defined_default(identifier)) { throw new DeveloperError_default("identifier is required."); } if (!defined_default(warnings[identifier])) { warnings[identifier] = true; console.warn(message ?? identifier); } } oneTimeWarning.geometryOutlines = "Entity geometry outlines are unsupported on terrain. Outlines will be disabled. To enable outlines, disable geometry terrain clamping by explicitly setting height to 0."; oneTimeWarning.geometryZIndex = "Entity geometry with zIndex are unsupported when height or extrudedHeight are defined. zIndex will be ignored"; oneTimeWarning.geometryHeightReference = "Entity corridor, ellipse, polygon or rectangle with heightReference must also have a defined height. heightReference will be ignored"; oneTimeWarning.geometryExtrudedHeightReference = "Entity corridor, ellipse, polygon or rectangle with extrudedHeightReference must also have a defined extrudedHeight. extrudedHeightReference will be ignored"; var oneTimeWarning_default = oneTimeWarning; // packages/engine/Source/DataSources/Entity.js var import_InlineWorkers426 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/TrackingReferenceFrame.js var import_InlineWorkers383 = __toESM(require_InlineWorkers(), 1); var TrackingReferenceFrame = { /** * Auto-detect algorithm. The reference frame used to track the Entity will * be automatically selected based on its trajectory: near-surface slow moving * objects will be tracked in the entity's local east-north-up reference * frame, while faster objects like satellites will use VVLH (Vehicle Velocity, * Local Horizontal). * * @type {number} * @constant */ AUTODETECT: 0, /** * The entity's local East-North-Up reference frame. * * @type {number} * @constant */ ENU: 1, /** * The entity's inertial reference frame. If entity has no defined orientation * property, it falls back to auto-detect algorithm. * * @type {number} * @constant */ INERTIAL: 2, /** * The entity's inertial reference frame with orientation fixed to its * {@link VelocityOrientationProperty}, ignoring its own orientation. * * @type {number} * @constant */ VELOCITY: 3 }; Object.freeze(TrackingReferenceFrame); var TrackingReferenceFrame_default = TrackingReferenceFrame; // packages/engine/Source/Scene/GroundPolylinePrimitive.js var import_InlineWorkers399 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/GroundPolylineGeometry.js var import_InlineWorkers388 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/ArcType.js var import_InlineWorkers384 = __toESM(require_InlineWorkers(), 1); var ArcType = { /** * Straight line that does not conform to the surface of the ellipsoid. * * @type {number} * @constant */ NONE: 0, /** * Follow geodesic path. * * @type {number} * @constant */ GEODESIC: 1, /** * Follow rhumb or loxodrome path. * * @type {number} * @constant */ RHUMB: 2 }; Object.freeze(ArcType); var ArcType_default = ArcType; // packages/engine/Source/Core/arrayRemoveDuplicates.js var import_InlineWorkers385 = __toESM(require_InlineWorkers(), 1); var removeDuplicatesEpsilon = Math_default.EPSILON10; function arrayRemoveDuplicates(values, equalsEpsilon, wrapAround, removedIndices) { Check_default.defined("equalsEpsilon", equalsEpsilon); if (!defined_default(values)) { return void 0; } wrapAround = wrapAround ?? false; const storeRemovedIndices = defined_default(removedIndices); const length2 = values.length; if (length2 < 2) { return values; } let i; let v02 = values[0]; let v12; let cleanedValues; let lastCleanIndex = 0; let removedIndexLCI = -1; for (i = 1; i < length2; ++i) { v12 = values[i]; if (equalsEpsilon(v02, v12, removeDuplicatesEpsilon)) { if (!defined_default(cleanedValues)) { cleanedValues = values.slice(0, i); lastCleanIndex = i - 1; removedIndexLCI = 0; } if (storeRemovedIndices) { removedIndices.push(i); } } else { if (defined_default(cleanedValues)) { cleanedValues.push(v12); lastCleanIndex = i; if (storeRemovedIndices) { removedIndexLCI = removedIndices.length; } } v02 = v12; } } if (wrapAround && equalsEpsilon(values[0], values[length2 - 1], removeDuplicatesEpsilon)) { if (storeRemovedIndices) { if (defined_default(cleanedValues)) { removedIndices.splice(removedIndexLCI, 0, lastCleanIndex); } else { removedIndices.push(length2 - 1); } } if (defined_default(cleanedValues)) { cleanedValues.length -= 1; } else { cleanedValues = values.slice(0, -1); } } return defined_default(cleanedValues) ? cleanedValues : values; } var arrayRemoveDuplicates_default = arrayRemoveDuplicates; // packages/engine/Source/Core/EllipsoidGeodesic.js var import_InlineWorkers386 = __toESM(require_InlineWorkers(), 1); function setConstants(ellipsoidGeodesic2) { const uSquared = ellipsoidGeodesic2._uSquared; const a3 = ellipsoidGeodesic2._ellipsoid.maximumRadius; const b = ellipsoidGeodesic2._ellipsoid.minimumRadius; const f2 = (a3 - b) / a3; const cosineHeading = Math.cos(ellipsoidGeodesic2._startHeading); const sineHeading = Math.sin(ellipsoidGeodesic2._startHeading); const tanU = (1 - f2) * Math.tan(ellipsoidGeodesic2._start.latitude); const cosineU = 1 / Math.sqrt(1 + tanU * tanU); const sineU = cosineU * tanU; const sigma = Math.atan2(tanU, cosineHeading); const sineAlpha = cosineU * sineHeading; const sineSquaredAlpha = sineAlpha * sineAlpha; const cosineSquaredAlpha = 1 - sineSquaredAlpha; const cosineAlpha = Math.sqrt(cosineSquaredAlpha); const u2Over4 = uSquared / 4; const u4Over16 = u2Over4 * u2Over4; const u6Over64 = u4Over16 * u2Over4; const u8Over256 = u4Over16 * u4Over16; const a0 = 1 + u2Over4 - 3 * u4Over16 / 4 + 5 * u6Over64 / 4 - 175 * u8Over256 / 64; const a1 = 1 - u2Over4 + 15 * u4Over16 / 8 - 35 * u6Over64 / 8; const a22 = 1 - 3 * u2Over4 + 35 * u4Over16 / 4; const a32 = 1 - 5 * u2Over4; const distanceRatio = a0 * sigma - a1 * Math.sin(2 * sigma) * u2Over4 / 2 - a22 * Math.sin(4 * sigma) * u4Over16 / 16 - a32 * Math.sin(6 * sigma) * u6Over64 / 48 - Math.sin(8 * sigma) * 5 * u8Over256 / 512; const constants = ellipsoidGeodesic2._constants; constants.a = a3; constants.b = b; constants.f = f2; constants.cosineHeading = cosineHeading; constants.sineHeading = sineHeading; constants.tanU = tanU; constants.cosineU = cosineU; constants.sineU = sineU; constants.sigma = sigma; constants.sineAlpha = sineAlpha; constants.sineSquaredAlpha = sineSquaredAlpha; constants.cosineSquaredAlpha = cosineSquaredAlpha; constants.cosineAlpha = cosineAlpha; constants.u2Over4 = u2Over4; constants.u4Over16 = u4Over16; constants.u6Over64 = u6Over64; constants.u8Over256 = u8Over256; constants.a0 = a0; constants.a1 = a1; constants.a2 = a22; constants.a3 = a32; constants.distanceRatio = distanceRatio; } function computeC(f2, cosineSquaredAlpha) { return f2 * cosineSquaredAlpha * (4 + f2 * (4 - 3 * cosineSquaredAlpha)) / 16; } function computeDeltaLambda(f2, sineAlpha, cosineSquaredAlpha, sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint) { const C = computeC(f2, cosineSquaredAlpha); return (1 - C) * f2 * sineAlpha * (sigma + C * sineSigma * (cosineTwiceSigmaMidpoint + C * cosineSigma * (2 * cosineTwiceSigmaMidpoint * cosineTwiceSigmaMidpoint - 1))); } function vincentyInverseFormula(ellipsoidGeodesic2, major, minor, firstLongitude, firstLatitude, secondLongitude, secondLatitude) { const eff = (major - minor) / major; const l2 = secondLongitude - firstLongitude; const u12 = Math.atan((1 - eff) * Math.tan(firstLatitude)); const u22 = Math.atan((1 - eff) * Math.tan(secondLatitude)); const cosineU1 = Math.cos(u12); const sineU1 = Math.sin(u12); const cosineU2 = Math.cos(u22); const sineU2 = Math.sin(u22); const cc = cosineU1 * cosineU2; const cs = cosineU1 * sineU2; const ss = sineU1 * sineU2; const sc = sineU1 * cosineU2; let lambda = l2; let lambdaDot; let cosineLambda; let sineLambda; let sigma; let cosineSigma; let sineSigma; let cosineSquaredAlpha; let cosineTwiceSigmaMidpoint; do { cosineLambda = Math.cos(lambda); sineLambda = Math.sin(lambda); const temp = cs - sc * cosineLambda; sineSigma = Math.sqrt( cosineU2 * cosineU2 * sineLambda * sineLambda + temp * temp ); cosineSigma = ss + cc * cosineLambda; sigma = Math.atan2(sineSigma, cosineSigma); let sineAlpha; if (sineSigma === 0) { sineAlpha = 0; cosineSquaredAlpha = 1; } else { sineAlpha = cc * sineLambda / sineSigma; cosineSquaredAlpha = 1 - sineAlpha * sineAlpha; } lambdaDot = lambda; cosineTwiceSigmaMidpoint = cosineSigma - 2 * ss / cosineSquaredAlpha; if (!isFinite(cosineTwiceSigmaMidpoint)) { cosineTwiceSigmaMidpoint = 0; } lambda = l2 + computeDeltaLambda( eff, sineAlpha, cosineSquaredAlpha, sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint ); } while (Math.abs(lambda - lambdaDot) > Math_default.EPSILON12); const uSquared = cosineSquaredAlpha * (major * major - minor * minor) / (minor * minor); const A = 1 + uSquared * (4096 + uSquared * (uSquared * (320 - 175 * uSquared) - 768)) / 16384; const B = uSquared * (256 + uSquared * (uSquared * (74 - 47 * uSquared) - 128)) / 1024; const cosineSquaredTwiceSigmaMidpoint = cosineTwiceSigmaMidpoint * cosineTwiceSigmaMidpoint; const deltaSigma = B * sineSigma * (cosineTwiceSigmaMidpoint + B * (cosineSigma * (2 * cosineSquaredTwiceSigmaMidpoint - 1) - B * cosineTwiceSigmaMidpoint * (4 * sineSigma * sineSigma - 3) * (4 * cosineSquaredTwiceSigmaMidpoint - 3) / 6) / 4); const distance2 = minor * A * (sigma - deltaSigma); const startHeading = Math.atan2( cosineU2 * sineLambda, cs - sc * cosineLambda ); const endHeading = Math.atan2(cosineU1 * sineLambda, cs * cosineLambda - sc); ellipsoidGeodesic2._distance = distance2; ellipsoidGeodesic2._startHeading = startHeading; ellipsoidGeodesic2._endHeading = endHeading; ellipsoidGeodesic2._uSquared = uSquared; } var scratchCart1 = new Cartesian3_default(); var scratchCart2 = new Cartesian3_default(); function computeProperties(ellipsoidGeodesic2, start, end, ellipsoid) { const firstCartesian = Cartesian3_default.normalize( ellipsoid.cartographicToCartesian(start, scratchCart2), scratchCart1 ); const lastCartesian = Cartesian3_default.normalize( ellipsoid.cartographicToCartesian(end, scratchCart2), scratchCart2 ); Check_default.typeOf.number.greaterThanOrEquals( "value", Math.abs( Math.abs(Cartesian3_default.angleBetween(firstCartesian, lastCartesian)) - Math.PI ), 0.0125 ); vincentyInverseFormula( ellipsoidGeodesic2, ellipsoid.maximumRadius, ellipsoid.minimumRadius, start.longitude, start.latitude, end.longitude, end.latitude ); ellipsoidGeodesic2._start = Cartographic_default.clone( start, ellipsoidGeodesic2._start ); ellipsoidGeodesic2._end = Cartographic_default.clone(end, ellipsoidGeodesic2._end); ellipsoidGeodesic2._start.height = 0; ellipsoidGeodesic2._end.height = 0; setConstants(ellipsoidGeodesic2); } function EllipsoidGeodesic(start, end, ellipsoid) { const e = ellipsoid ?? Ellipsoid_default.default; this._ellipsoid = e; this._start = new Cartographic_default(); this._end = new Cartographic_default(); this._constants = {}; this._startHeading = void 0; this._endHeading = void 0; this._distance = void 0; this._uSquared = void 0; if (defined_default(start) && defined_default(end)) { computeProperties(this, start, end, e); } } Object.defineProperties(EllipsoidGeodesic.prototype, { /** * Gets the ellipsoid. * @memberof EllipsoidGeodesic.prototype * @type {Ellipsoid} * @readonly */ ellipsoid: { get: function() { return this._ellipsoid; } }, /** * Gets the surface distance between the start and end point * @memberof EllipsoidGeodesic.prototype * @type {number} * @readonly */ surfaceDistance: { get: function() { Check_default.defined("distance", this._distance); return this._distance; } }, /** * Gets the initial planetodetic point on the path. * @memberof EllipsoidGeodesic.prototype * @type {Cartographic} * @readonly */ start: { get: function() { return this._start; } }, /** * Gets the final planetodetic point on the path. * @memberof EllipsoidGeodesic.prototype * @type {Cartographic} * @readonly */ end: { get: function() { return this._end; } }, /** * Gets the heading at the initial point. * @memberof EllipsoidGeodesic.prototype * @type {number} * @readonly */ startHeading: { get: function() { Check_default.defined("distance", this._distance); return this._startHeading; } }, /** * Gets the heading at the final point. * @memberof EllipsoidGeodesic.prototype * @type {number} * @readonly */ endHeading: { get: function() { Check_default.defined("distance", this._distance); return this._endHeading; } } }); EllipsoidGeodesic.prototype.setEndPoints = function(start, end) { Check_default.defined("start", start); Check_default.defined("end", end); computeProperties(this, start, end, this._ellipsoid); }; EllipsoidGeodesic.prototype.interpolateUsingFraction = function(fraction, result) { return this.interpolateUsingSurfaceDistance( this._distance * fraction, result ); }; EllipsoidGeodesic.prototype.interpolateUsingSurfaceDistance = function(distance2, result) { Check_default.defined("distance", this._distance); const constants = this._constants; const s2 = constants.distanceRatio + distance2 / constants.b; const cosine2S = Math.cos(2 * s2); const cosine4S = Math.cos(4 * s2); const cosine6S = Math.cos(6 * s2); const sine2S = Math.sin(2 * s2); const sine4S = Math.sin(4 * s2); const sine6S = Math.sin(6 * s2); const sine8S = Math.sin(8 * s2); const s22 = s2 * s2; const s3 = s2 * s22; const u8Over256 = constants.u8Over256; const u2Over4 = constants.u2Over4; const u6Over64 = constants.u6Over64; const u4Over16 = constants.u4Over16; let sigma = 2 * s3 * u8Over256 * cosine2S / 3 + s2 * (1 - u2Over4 + 7 * u4Over16 / 4 - 15 * u6Over64 / 4 + 579 * u8Over256 / 64 - (u4Over16 - 15 * u6Over64 / 4 + 187 * u8Over256 / 16) * cosine2S - (5 * u6Over64 / 4 - 115 * u8Over256 / 16) * cosine4S - 29 * u8Over256 * cosine6S / 16) + (u2Over4 / 2 - u4Over16 + 71 * u6Over64 / 32 - 85 * u8Over256 / 16) * sine2S + (5 * u4Over16 / 16 - 5 * u6Over64 / 4 + 383 * u8Over256 / 96) * sine4S - s22 * ((u6Over64 - 11 * u8Over256 / 2) * sine2S + 5 * u8Over256 * sine4S / 2) + (29 * u6Over64 / 96 - 29 * u8Over256 / 16) * sine6S + 539 * u8Over256 * sine8S / 1536; const theta = Math.asin(Math.sin(sigma) * constants.cosineAlpha); const latitude = Math.atan(constants.a / constants.b * Math.tan(theta)); sigma = sigma - constants.sigma; const cosineTwiceSigmaMidpoint = Math.cos(2 * constants.sigma + sigma); const sineSigma = Math.sin(sigma); const cosineSigma = Math.cos(sigma); const cc = constants.cosineU * cosineSigma; const ss = constants.sineU * sineSigma; const lambda = Math.atan2( sineSigma * constants.sineHeading, cc - ss * constants.cosineHeading ); const l2 = lambda - computeDeltaLambda( constants.f, constants.sineAlpha, constants.cosineSquaredAlpha, sigma, sineSigma, cosineSigma, cosineTwiceSigmaMidpoint ); if (defined_default(result)) { result.longitude = this._start.longitude + l2; result.latitude = latitude; result.height = 0; return result; } return new Cartographic_default(this._start.longitude + l2, latitude, 0); }; var EllipsoidGeodesic_default = EllipsoidGeodesic; // packages/engine/Source/Core/EllipsoidRhumbLine.js var import_InlineWorkers387 = __toESM(require_InlineWorkers(), 1); function calculateM(ellipticity, major, latitude) { if (ellipticity === 0) { return major * latitude; } const e2 = ellipticity * ellipticity; const e4 = e2 * e2; const e6 = e4 * e2; const e8 = e6 * e2; const e10 = e8 * e2; const e12 = e10 * e2; const phi = latitude; const sin2Phi = Math.sin(2 * phi); const sin4Phi = Math.sin(4 * phi); const sin6Phi = Math.sin(6 * phi); const sin8Phi = Math.sin(8 * phi); const sin10Phi = Math.sin(10 * phi); const sin12Phi = Math.sin(12 * phi); return major * ((1 - e2 / 4 - 3 * e4 / 64 - 5 * e6 / 256 - 175 * e8 / 16384 - 441 * e10 / 65536 - 4851 * e12 / 1048576) * phi - (3 * e2 / 8 + 3 * e4 / 32 + 45 * e6 / 1024 + 105 * e8 / 4096 + 2205 * e10 / 131072 + 6237 * e12 / 524288) * sin2Phi + (15 * e4 / 256 + 45 * e6 / 1024 + 525 * e8 / 16384 + 1575 * e10 / 65536 + 155925 * e12 / 8388608) * sin4Phi - (35 * e6 / 3072 + 175 * e8 / 12288 + 3675 * e10 / 262144 + 13475 * e12 / 1048576) * sin6Phi + (315 * e8 / 131072 + 2205 * e10 / 524288 + 43659 * e12 / 8388608) * sin8Phi - (693 * e10 / 1310720 + 6237 * e12 / 5242880) * sin10Phi + 1001 * e12 / 8388608 * sin12Phi); } function calculateInverseM(M, ellipticity, major) { const d = M / major; if (ellipticity === 0) { return d; } const d2 = d * d; const d3 = d2 * d; const d4 = d3 * d; const e = ellipticity; const e2 = e * e; const e4 = e2 * e2; const e6 = e4 * e2; const e8 = e6 * e2; const e10 = e8 * e2; const e12 = e10 * e2; const sin2D = Math.sin(2 * d); const cos2D = Math.cos(2 * d); const sin4D = Math.sin(4 * d); const cos4D = Math.cos(4 * d); const sin6D = Math.sin(6 * d); const cos6D = Math.cos(6 * d); const sin8D = Math.sin(8 * d); const cos8D = Math.cos(8 * d); const sin10D = Math.sin(10 * d); const cos10D = Math.cos(10 * d); const sin12D = Math.sin(12 * d); return d + d * e2 / 4 + 7 * d * e4 / 64 + 15 * d * e6 / 256 + 579 * d * e8 / 16384 + 1515 * d * e10 / 65536 + 16837 * d * e12 / 1048576 + (3 * d * e4 / 16 + 45 * d * e6 / 256 - d * (32 * d2 - 561) * e8 / 4096 - d * (232 * d2 - 1677) * e10 / 16384 + d * (399985 - 90560 * d2 + 512 * d4) * e12 / 5242880) * cos2D + (21 * d * e6 / 256 + 483 * d * e8 / 4096 - d * (224 * d2 - 1969) * e10 / 16384 - d * (33152 * d2 - 112599) * e12 / 1048576) * cos4D + (151 * d * e8 / 4096 + 4681 * d * e10 / 65536 + 1479 * d * e12 / 16384 - 453 * d3 * e12 / 32768) * cos6D + (1097 * d * e10 / 65536 + 42783 * d * e12 / 1048576) * cos8D + 8011 * d * e12 / 1048576 * cos10D + (3 * e2 / 8 + 3 * e4 / 16 + 213 * e6 / 2048 - 3 * d2 * e6 / 64 + 255 * e8 / 4096 - 33 * d2 * e8 / 512 + 20861 * e10 / 524288 - 33 * d2 * e10 / 512 + d4 * e10 / 1024 + 28273 * e12 / 1048576 - 471 * d2 * e12 / 8192 + 9 * d4 * e12 / 4096) * sin2D + (21 * e4 / 256 + 21 * e6 / 256 + 533 * e8 / 8192 - 21 * d2 * e8 / 512 + 197 * e10 / 4096 - 315 * d2 * e10 / 4096 + 584039 * e12 / 16777216 - 12517 * d2 * e12 / 131072 + 7 * d4 * e12 / 2048) * sin4D + (151 * e6 / 6144 + 151 * e8 / 4096 + 5019 * e10 / 131072 - 453 * d2 * e10 / 16384 + 26965 * e12 / 786432 - 8607 * d2 * e12 / 131072) * sin6D + (1097 * e8 / 131072 + 1097 * e10 / 65536 + 225797 * e12 / 10485760 - 1097 * d2 * e12 / 65536) * sin8D + (8011 * e10 / 2621440 + 8011 * e12 / 1048576) * sin10D + 293393 * e12 / 251658240 * sin12D; } function calculateSigma(ellipticity, latitude) { if (ellipticity === 0) { return Math.log(Math.tan(0.5 * (Math_default.PI_OVER_TWO + latitude))); } const eSinL = ellipticity * Math.sin(latitude); return Math.log(Math.tan(0.5 * (Math_default.PI_OVER_TWO + latitude))) - ellipticity / 2 * Math.log((1 + eSinL) / (1 - eSinL)); } function calculateHeading(ellipsoidRhumbLine, firstLongitude, firstLatitude, secondLongitude, secondLatitude) { const sigma1 = calculateSigma(ellipsoidRhumbLine._ellipticity, firstLatitude); const sigma2 = calculateSigma( ellipsoidRhumbLine._ellipticity, secondLatitude ); return Math.atan2( Math_default.negativePiToPi(secondLongitude - firstLongitude), sigma2 - sigma1 ); } function calculateArcLength(ellipsoidRhumbLine, major, minor, firstLongitude, firstLatitude, secondLongitude, secondLatitude) { const heading = ellipsoidRhumbLine._heading; const deltaLongitude = secondLongitude - firstLongitude; let distance2; if (Math_default.equalsEpsilon( Math.abs(heading), Math_default.PI_OVER_TWO, Math_default.EPSILON8 )) { if (major === minor) { distance2 = major * Math.cos(firstLatitude) * Math_default.negativePiToPi(deltaLongitude); } else { const sinPhi = Math.sin(firstLatitude); distance2 = major * Math.cos(firstLatitude) * Math_default.negativePiToPi(deltaLongitude) / Math.sqrt(1 - ellipsoidRhumbLine._ellipticitySquared * sinPhi * sinPhi); } } else { const M1 = calculateM( ellipsoidRhumbLine._ellipticity, major, firstLatitude ); const M2 = calculateM( ellipsoidRhumbLine._ellipticity, major, secondLatitude ); distance2 = (M2 - M1) / Math.cos(heading); } return Math.abs(distance2); } var scratchCart12 = new Cartesian3_default(); var scratchCart22 = new Cartesian3_default(); function computeProperties2(ellipsoidRhumbLine, start, end, ellipsoid) { const firstCartesian = Cartesian3_default.normalize( ellipsoid.cartographicToCartesian(start, scratchCart22), scratchCart12 ); const lastCartesian = Cartesian3_default.normalize( ellipsoid.cartographicToCartesian(end, scratchCart22), scratchCart22 ); Check_default.typeOf.number.greaterThanOrEquals( "value", Math.abs( Math.abs(Cartesian3_default.angleBetween(firstCartesian, lastCartesian)) - Math.PI ), 0.0125 ); const major = ellipsoid.maximumRadius; const minor = ellipsoid.minimumRadius; const majorSquared = major * major; const minorSquared = minor * minor; ellipsoidRhumbLine._ellipticitySquared = (majorSquared - minorSquared) / majorSquared; ellipsoidRhumbLine._ellipticity = Math.sqrt( ellipsoidRhumbLine._ellipticitySquared ); ellipsoidRhumbLine._start = Cartographic_default.clone( start, ellipsoidRhumbLine._start ); ellipsoidRhumbLine._start.height = 0; ellipsoidRhumbLine._end = Cartographic_default.clone(end, ellipsoidRhumbLine._end); ellipsoidRhumbLine._end.height = 0; ellipsoidRhumbLine._heading = calculateHeading( ellipsoidRhumbLine, start.longitude, start.latitude, end.longitude, end.latitude ); ellipsoidRhumbLine._distance = calculateArcLength( ellipsoidRhumbLine, ellipsoid.maximumRadius, ellipsoid.minimumRadius, start.longitude, start.latitude, end.longitude, end.latitude ); } function interpolateUsingSurfaceDistance(start, heading, distance2, major, ellipticity, result) { if (distance2 === 0) { return Cartographic_default.clone(start, result); } const ellipticitySquared = ellipticity * ellipticity; let longitude; let latitude; let deltaLongitude; if (Math.abs(Math_default.PI_OVER_TWO - Math.abs(heading)) > Math_default.EPSILON8) { const M1 = calculateM(ellipticity, major, start.latitude); const deltaM = distance2 * Math.cos(heading); const M2 = M1 + deltaM; latitude = calculateInverseM(M2, ellipticity, major); if (Math.abs(heading) < Math_default.EPSILON10) { longitude = Math_default.negativePiToPi(start.longitude); } else { const sigma1 = calculateSigma(ellipticity, start.latitude); const sigma2 = calculateSigma(ellipticity, latitude); deltaLongitude = Math.tan(heading) * (sigma2 - sigma1); longitude = Math_default.negativePiToPi(start.longitude + deltaLongitude); } } else { latitude = start.latitude; let localRad; if (ellipticity === 0) { localRad = major * Math.cos(start.latitude); } else { const sinPhi = Math.sin(start.latitude); localRad = major * Math.cos(start.latitude) / Math.sqrt(1 - ellipticitySquared * sinPhi * sinPhi); } deltaLongitude = distance2 / localRad; if (heading > 0) { longitude = Math_default.negativePiToPi(start.longitude + deltaLongitude); } else { longitude = Math_default.negativePiToPi(start.longitude - deltaLongitude); } } if (defined_default(result)) { result.longitude = longitude; result.latitude = latitude; result.height = 0; return result; } return new Cartographic_default(longitude, latitude, 0); } function EllipsoidRhumbLine(start, end, ellipsoid) { const e = ellipsoid ?? Ellipsoid_default.default; this._ellipsoid = e; this._start = new Cartographic_default(); this._end = new Cartographic_default(); this._heading = void 0; this._distance = void 0; this._ellipticity = void 0; this._ellipticitySquared = void 0; if (defined_default(start) && defined_default(end)) { computeProperties2(this, start, end, e); } } Object.defineProperties(EllipsoidRhumbLine.prototype, { /** * Gets the ellipsoid. * @memberof EllipsoidRhumbLine.prototype * @type {Ellipsoid} * @readonly */ ellipsoid: { get: function() { return this._ellipsoid; } }, /** * Gets the surface distance between the start and end point * @memberof EllipsoidRhumbLine.prototype * @type {number} * @readonly */ surfaceDistance: { get: function() { Check_default.defined("distance", this._distance); return this._distance; } }, /** * Gets the initial planetodetic point on the path. * @memberof EllipsoidRhumbLine.prototype * @type {Cartographic} * @readonly */ start: { get: function() { return this._start; } }, /** * Gets the final planetodetic point on the path. * @memberof EllipsoidRhumbLine.prototype * @type {Cartographic} * @readonly */ end: { get: function() { return this._end; } }, /** * Gets the heading from the start point to the end point. * @memberof EllipsoidRhumbLine.prototype * @type {number} * @readonly */ heading: { get: function() { Check_default.defined("distance", this._distance); return this._heading; } } }); EllipsoidRhumbLine.fromStartHeadingDistance = function(start, heading, distance2, ellipsoid, result) { Check_default.defined("start", start); Check_default.defined("heading", heading); Check_default.defined("distance", distance2); Check_default.typeOf.number.greaterThan("distance", distance2, 0); const e = ellipsoid ?? Ellipsoid_default.default; const major = e.maximumRadius; const minor = e.minimumRadius; const majorSquared = major * major; const minorSquared = minor * minor; const ellipticity = Math.sqrt((majorSquared - minorSquared) / majorSquared); heading = Math_default.negativePiToPi(heading); const end = interpolateUsingSurfaceDistance( start, heading, distance2, e.maximumRadius, ellipticity ); if (!defined_default(result) || defined_default(ellipsoid) && !ellipsoid.equals(result.ellipsoid)) { return new EllipsoidRhumbLine(start, end, e); } result.setEndPoints(start, end); return result; }; EllipsoidRhumbLine.prototype.setEndPoints = function(start, end) { Check_default.defined("start", start); Check_default.defined("end", end); computeProperties2(this, start, end, this._ellipsoid); }; EllipsoidRhumbLine.prototype.interpolateUsingFraction = function(fraction, result) { return this.interpolateUsingSurfaceDistance( fraction * this._distance, result ); }; EllipsoidRhumbLine.prototype.interpolateUsingSurfaceDistance = function(distance2, result) { Check_default.typeOf.number("distance", distance2); if (!defined_default(this._distance) || this._distance === 0) { throw new DeveloperError_default( "EllipsoidRhumbLine must have distinct start and end set." ); } return interpolateUsingSurfaceDistance( this._start, this._heading, distance2, this._ellipsoid.maximumRadius, this._ellipticity, result ); }; EllipsoidRhumbLine.prototype.findIntersectionWithLongitude = function(intersectionLongitude, result) { Check_default.typeOf.number("intersectionLongitude", intersectionLongitude); if (!defined_default(this._distance) || this._distance === 0) { throw new DeveloperError_default( "EllipsoidRhumbLine must have distinct start and end set." ); } const ellipticity = this._ellipticity; const heading = this._heading; const absHeading = Math.abs(heading); const start = this._start; intersectionLongitude = Math_default.negativePiToPi(intersectionLongitude); if (Math_default.equalsEpsilon( Math.abs(intersectionLongitude), Math.PI, Math_default.EPSILON14 )) { intersectionLongitude = Math_default.sign(start.longitude) * Math.PI; } if (!defined_default(result)) { result = new Cartographic_default(); } if (Math.abs(Math_default.PI_OVER_TWO - absHeading) <= Math_default.EPSILON8) { result.longitude = intersectionLongitude; result.latitude = start.latitude; result.height = 0; return result; } else if (Math_default.equalsEpsilon( Math.abs(Math_default.PI_OVER_TWO - absHeading), Math_default.PI_OVER_TWO, Math_default.EPSILON8 )) { if (Math_default.equalsEpsilon( intersectionLongitude, start.longitude, Math_default.EPSILON12 )) { return void 0; } result.longitude = intersectionLongitude; result.latitude = Math_default.PI_OVER_TWO * Math_default.sign(Math_default.PI_OVER_TWO - heading); result.height = 0; return result; } const phi1 = start.latitude; const eSinPhi1 = ellipticity * Math.sin(phi1); const leftComponent = Math.tan(0.5 * (Math_default.PI_OVER_TWO + phi1)) * Math.exp((intersectionLongitude - start.longitude) / Math.tan(heading)); const denominator = (1 + eSinPhi1) / (1 - eSinPhi1); let newPhi = start.latitude; let phi; do { phi = newPhi; const eSinPhi = ellipticity * Math.sin(phi); const numerator = (1 + eSinPhi) / (1 - eSinPhi); newPhi = 2 * Math.atan( leftComponent * Math.pow(numerator / denominator, ellipticity / 2) ) - Math_default.PI_OVER_TWO; } while (!Math_default.equalsEpsilon(newPhi, phi, Math_default.EPSILON12)); result.longitude = intersectionLongitude; result.latitude = newPhi; result.height = 0; return result; }; EllipsoidRhumbLine.prototype.findIntersectionWithLatitude = function(intersectionLatitude, result) { Check_default.typeOf.number("intersectionLatitude", intersectionLatitude); if (!defined_default(this._distance) || this._distance === 0) { throw new DeveloperError_default( "EllipsoidRhumbLine must have distinct start and end set." ); } const ellipticity = this._ellipticity; const heading = this._heading; const start = this._start; if (Math_default.equalsEpsilon( Math.abs(heading), Math_default.PI_OVER_TWO, Math_default.EPSILON8 )) { return; } const sigma1 = calculateSigma(ellipticity, start.latitude); const sigma2 = calculateSigma(ellipticity, intersectionLatitude); const deltaLongitude = Math.tan(heading) * (sigma2 - sigma1); const longitude = Math_default.negativePiToPi(start.longitude + deltaLongitude); if (defined_default(result)) { result.longitude = longitude; result.latitude = intersectionLatitude; result.height = 0; return result; } return new Cartographic_default(longitude, intersectionLatitude, 0); }; var EllipsoidRhumbLine_default = EllipsoidRhumbLine; // packages/engine/Source/Core/GroundPolylineGeometry.js var PROJECTIONS = [GeographicProjection_default, WebMercatorProjection_default]; var PROJECTION_COUNT = PROJECTIONS.length; var MITER_BREAK_SMALL = Math.cos(Math_default.toRadians(30)); var MITER_BREAK_LARGE = Math.cos(Math_default.toRadians(150)); var WALL_INITIAL_MIN_HEIGHT = 0; var WALL_INITIAL_MAX_HEIGHT = 1e3; function GroundPolylineGeometry(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const positions = options.positions; if (!defined_default(positions) || positions.length < 2) { throw new DeveloperError_default("At least two positions are required."); } if (defined_default(options.arcType) && options.arcType !== ArcType_default.GEODESIC && options.arcType !== ArcType_default.RHUMB) { throw new DeveloperError_default( "Valid options for arcType are ArcType.GEODESIC and ArcType.RHUMB." ); } this.width = options.width ?? 1; this._positions = positions; this.granularity = options.granularity ?? 9999; this.loop = options.loop ?? false; this.arcType = options.arcType ?? ArcType_default.GEODESIC; this._ellipsoid = Ellipsoid_default.default; this._projectionIndex = 0; this._workerName = "createGroundPolylineGeometry"; this._scene3DOnly = false; } Object.defineProperties(GroundPolylineGeometry.prototype, { /** * The number of elements used to pack the object into an array. * @memberof GroundPolylineGeometry.prototype * @type {number} * @readonly * @private */ packedLength: { get: function() { return 1 + this._positions.length * 3 + 1 + 1 + 1 + Ellipsoid_default.packedLength + 1 + 1; } } }); GroundPolylineGeometry.setProjectionAndEllipsoid = function(groundPolylineGeometry, mapProjection) { let projectionIndex = 0; for (let i = 0; i < PROJECTION_COUNT; i++) { if (mapProjection instanceof PROJECTIONS[i]) { projectionIndex = i; break; } } groundPolylineGeometry._projectionIndex = projectionIndex; groundPolylineGeometry._ellipsoid = mapProjection.ellipsoid; }; var cart3Scratch1 = new Cartesian3_default(); var cart3Scratch2 = new Cartesian3_default(); var cart3Scratch3 = new Cartesian3_default(); function computeRightNormal(start, end, maxHeight, ellipsoid, result) { const startBottom = getPosition(ellipsoid, start, 0, cart3Scratch1); const startTop = getPosition(ellipsoid, start, maxHeight, cart3Scratch2); const endBottom = getPosition(ellipsoid, end, 0, cart3Scratch3); const up = direction(startTop, startBottom, cart3Scratch2); const forward = direction(endBottom, startBottom, cart3Scratch3); Cartesian3_default.cross(forward, up, result); return Cartesian3_default.normalize(result, result); } var interpolatedCartographicScratch = new Cartographic_default(); var interpolatedBottomScratch = new Cartesian3_default(); var interpolatedTopScratch = new Cartesian3_default(); var interpolatedNormalScratch = new Cartesian3_default(); function interpolateSegment(start, end, minHeight, maxHeight, granularity, arcType, ellipsoid, normalsArray, bottomPositionsArray, topPositionsArray, cartographicsArray) { if (granularity === 0) { return; } let ellipsoidLine; if (arcType === ArcType_default.GEODESIC) { ellipsoidLine = new EllipsoidGeodesic_default(start, end, ellipsoid); } else if (arcType === ArcType_default.RHUMB) { ellipsoidLine = new EllipsoidRhumbLine_default(start, end, ellipsoid); } const surfaceDistance = ellipsoidLine.surfaceDistance; if (surfaceDistance < granularity) { return; } const interpolatedNormal = computeRightNormal( start, end, maxHeight, ellipsoid, interpolatedNormalScratch ); const segments = Math.ceil(surfaceDistance / granularity); const interpointDistance = surfaceDistance / segments; let distanceFromStart = interpointDistance; const pointsToAdd = segments - 1; let packIndex = normalsArray.length; for (let i = 0; i < pointsToAdd; i++) { const interpolatedCartographic = ellipsoidLine.interpolateUsingSurfaceDistance( distanceFromStart, interpolatedCartographicScratch ); const interpolatedBottom = getPosition( ellipsoid, interpolatedCartographic, minHeight, interpolatedBottomScratch ); const interpolatedTop = getPosition( ellipsoid, interpolatedCartographic, maxHeight, interpolatedTopScratch ); Cartesian3_default.pack(interpolatedNormal, normalsArray, packIndex); Cartesian3_default.pack(interpolatedBottom, bottomPositionsArray, packIndex); Cartesian3_default.pack(interpolatedTop, topPositionsArray, packIndex); cartographicsArray.push(interpolatedCartographic.latitude); cartographicsArray.push(interpolatedCartographic.longitude); packIndex += 3; distanceFromStart += interpointDistance; } } var heightlessCartographicScratch = new Cartographic_default(); function getPosition(ellipsoid, cartographic2, height, result) { Cartographic_default.clone(cartographic2, heightlessCartographicScratch); heightlessCartographicScratch.height = height; return Cartographic_default.toCartesian( heightlessCartographicScratch, ellipsoid, result ); } GroundPolylineGeometry.pack = function(value, array, startingIndex) { Check_default.typeOf.object("value", value); Check_default.defined("array", array); let index = startingIndex ?? 0; const positions = value._positions; const positionsLength = positions.length; array[index++] = positionsLength; for (let i = 0; i < positionsLength; ++i) { const cartesian11 = positions[i]; Cartesian3_default.pack(cartesian11, array, index); index += 3; } array[index++] = value.granularity; array[index++] = value.loop ? 1 : 0; array[index++] = value.arcType; Ellipsoid_default.pack(value._ellipsoid, array, index); index += Ellipsoid_default.packedLength; array[index++] = value._projectionIndex; array[index] = value._scene3DOnly ? 1 : 0; return array; }; GroundPolylineGeometry.unpack = function(array, startingIndex, result) { Check_default.defined("array", array); let index = startingIndex ?? 0; const positionsLength = array[index++]; const positions = new Array(positionsLength); for (let i = 0; i < positionsLength; i++) { positions[i] = Cartesian3_default.unpack(array, index); index += 3; } const granularity = array[index++]; const loop = array[index++] === 1; const arcType = array[index++]; const ellipsoid = Ellipsoid_default.unpack(array, index); index += Ellipsoid_default.packedLength; const projectionIndex = array[index++]; const scene3DOnly = array[index] === 1; if (!defined_default(result)) { result = new GroundPolylineGeometry({ positions }); } result._positions = positions; result.granularity = granularity; result.loop = loop; result.arcType = arcType; result._ellipsoid = ellipsoid; result._projectionIndex = projectionIndex; result._scene3DOnly = scene3DOnly; return result; }; function direction(target, origin, result) { Cartesian3_default.subtract(target, origin, result); Cartesian3_default.normalize(result, result); return result; } function tangentDirection(target, origin, up, result) { result = direction(target, origin, result); result = Cartesian3_default.cross(result, up, result); result = Cartesian3_default.normalize(result, result); result = Cartesian3_default.cross(up, result, result); return result; } var toPreviousScratch = new Cartesian3_default(); var toNextScratch = new Cartesian3_default(); var forwardScratch = new Cartesian3_default(); var vertexUpScratch = new Cartesian3_default(); var cosine90 = 0; var cosine180 = -1; function computeVertexMiterNormal(previousBottom, vertexBottom, vertexTop, nextBottom, result) { const up = direction(vertexTop, vertexBottom, vertexUpScratch); const toPrevious = tangentDirection( previousBottom, vertexBottom, up, toPreviousScratch ); const toNext = tangentDirection(nextBottom, vertexBottom, up, toNextScratch); if (Math_default.equalsEpsilon( Cartesian3_default.dot(toPrevious, toNext), cosine180, Math_default.EPSILON5 )) { result = Cartesian3_default.cross(up, toPrevious, result); result = Cartesian3_default.normalize(result, result); return result; } result = Cartesian3_default.add(toNext, toPrevious, result); result = Cartesian3_default.normalize(result, result); const forward = Cartesian3_default.cross(up, result, forwardScratch); if (Cartesian3_default.dot(toNext, forward) < cosine90) { result = Cartesian3_default.negate(result, result); } return result; } var XZ_PLANE = Plane_default.fromPointNormal(Cartesian3_default.ZERO, Cartesian3_default.UNIT_Y); var previousBottomScratch = new Cartesian3_default(); var vertexBottomScratch = new Cartesian3_default(); var vertexTopScratch = new Cartesian3_default(); var nextBottomScratch = new Cartesian3_default(); var vertexNormalScratch = new Cartesian3_default(); var intersectionScratch = new Cartesian3_default(); var cartographicScratch0 = new Cartographic_default(); var cartographicScratch1 = new Cartographic_default(); var cartographicIntersectionScratch = new Cartographic_default(); GroundPolylineGeometry.createGeometry = function(groundPolylineGeometry) { const compute2dAttributes = !groundPolylineGeometry._scene3DOnly; let loop = groundPolylineGeometry.loop; const ellipsoid = groundPolylineGeometry._ellipsoid; const granularity = groundPolylineGeometry.granularity; const arcType = groundPolylineGeometry.arcType; const projection = new PROJECTIONS[groundPolylineGeometry._projectionIndex]( ellipsoid ); const minHeight = WALL_INITIAL_MIN_HEIGHT; const maxHeight = WALL_INITIAL_MAX_HEIGHT; let index; let i; const positions = groundPolylineGeometry._positions; const positionsLength = positions.length; if (positionsLength === 2) { loop = false; } let p0; let p1; let c0; let c14; const rhumbLine = new EllipsoidRhumbLine_default(void 0, void 0, ellipsoid); let intersection; let intersectionCartographic; let intersectionLongitude; const splitPositions = [positions[0]]; for (i = 0; i < positionsLength - 1; i++) { p0 = positions[i]; p1 = positions[i + 1]; intersection = IntersectionTests_default.lineSegmentPlane( p0, p1, XZ_PLANE, intersectionScratch ); if (defined_default(intersection) && !Cartesian3_default.equalsEpsilon(intersection, p0, Math_default.EPSILON7) && !Cartesian3_default.equalsEpsilon(intersection, p1, Math_default.EPSILON7)) { if (groundPolylineGeometry.arcType === ArcType_default.GEODESIC) { splitPositions.push(Cartesian3_default.clone(intersection)); } else if (groundPolylineGeometry.arcType === ArcType_default.RHUMB) { intersectionLongitude = ellipsoid.cartesianToCartographic( intersection, cartographicScratch0 ).longitude; c0 = ellipsoid.cartesianToCartographic(p0, cartographicScratch0); c14 = ellipsoid.cartesianToCartographic(p1, cartographicScratch1); rhumbLine.setEndPoints(c0, c14); intersectionCartographic = rhumbLine.findIntersectionWithLongitude( intersectionLongitude, cartographicIntersectionScratch ); intersection = ellipsoid.cartographicToCartesian( intersectionCartographic, intersectionScratch ); if (defined_default(intersection) && !Cartesian3_default.equalsEpsilon(intersection, p0, Math_default.EPSILON7) && !Cartesian3_default.equalsEpsilon(intersection, p1, Math_default.EPSILON7)) { splitPositions.push(Cartesian3_default.clone(intersection)); } } } splitPositions.push(p1); } if (loop) { p0 = positions[positionsLength - 1]; p1 = positions[0]; intersection = IntersectionTests_default.lineSegmentPlane( p0, p1, XZ_PLANE, intersectionScratch ); if (defined_default(intersection) && !Cartesian3_default.equalsEpsilon(intersection, p0, Math_default.EPSILON7) && !Cartesian3_default.equalsEpsilon(intersection, p1, Math_default.EPSILON7)) { if (groundPolylineGeometry.arcType === ArcType_default.GEODESIC) { splitPositions.push(Cartesian3_default.clone(intersection)); } else if (groundPolylineGeometry.arcType === ArcType_default.RHUMB) { intersectionLongitude = ellipsoid.cartesianToCartographic( intersection, cartographicScratch0 ).longitude; c0 = ellipsoid.cartesianToCartographic(p0, cartographicScratch0); c14 = ellipsoid.cartesianToCartographic(p1, cartographicScratch1); rhumbLine.setEndPoints(c0, c14); intersectionCartographic = rhumbLine.findIntersectionWithLongitude( intersectionLongitude, cartographicIntersectionScratch ); intersection = ellipsoid.cartographicToCartesian( intersectionCartographic, intersectionScratch ); if (defined_default(intersection) && !Cartesian3_default.equalsEpsilon(intersection, p0, Math_default.EPSILON7) && !Cartesian3_default.equalsEpsilon(intersection, p1, Math_default.EPSILON7)) { splitPositions.push(Cartesian3_default.clone(intersection)); } } } } let cartographicsLength = splitPositions.length; let cartographics = new Array(cartographicsLength); for (i = 0; i < cartographicsLength; i++) { const cartographic2 = Cartographic_default.fromCartesian( splitPositions[i], ellipsoid ); cartographic2.height = 0; cartographics[i] = cartographic2; } cartographics = arrayRemoveDuplicates_default( cartographics, Cartographic_default.equalsEpsilon ); cartographicsLength = cartographics.length; if (cartographicsLength < 2) { return void 0; } const cartographicsArray = []; const normalsArray = []; const bottomPositionsArray = []; const topPositionsArray = []; let previousBottom = previousBottomScratch; let vertexBottom = vertexBottomScratch; let vertexTop = vertexTopScratch; let nextBottom = nextBottomScratch; let vertexNormal = vertexNormalScratch; const startCartographic = cartographics[0]; const nextCartographic = cartographics[1]; const prestartCartographic = cartographics[cartographicsLength - 1]; previousBottom = getPosition( ellipsoid, prestartCartographic, minHeight, previousBottom ); nextBottom = getPosition(ellipsoid, nextCartographic, minHeight, nextBottom); vertexBottom = getPosition( ellipsoid, startCartographic, minHeight, vertexBottom ); vertexTop = getPosition(ellipsoid, startCartographic, maxHeight, vertexTop); if (loop) { vertexNormal = computeVertexMiterNormal( previousBottom, vertexBottom, vertexTop, nextBottom, vertexNormal ); } else { vertexNormal = computeRightNormal( startCartographic, nextCartographic, maxHeight, ellipsoid, vertexNormal ); } Cartesian3_default.pack(vertexNormal, normalsArray, 0); Cartesian3_default.pack(vertexBottom, bottomPositionsArray, 0); Cartesian3_default.pack(vertexTop, topPositionsArray, 0); cartographicsArray.push(startCartographic.latitude); cartographicsArray.push(startCartographic.longitude); interpolateSegment( startCartographic, nextCartographic, minHeight, maxHeight, granularity, arcType, ellipsoid, normalsArray, bottomPositionsArray, topPositionsArray, cartographicsArray ); for (i = 1; i < cartographicsLength - 1; ++i) { previousBottom = Cartesian3_default.clone(vertexBottom, previousBottom); vertexBottom = Cartesian3_default.clone(nextBottom, vertexBottom); const vertexCartographic = cartographics[i]; getPosition(ellipsoid, vertexCartographic, maxHeight, vertexTop); getPosition(ellipsoid, cartographics[i + 1], minHeight, nextBottom); computeVertexMiterNormal( previousBottom, vertexBottom, vertexTop, nextBottom, vertexNormal ); index = normalsArray.length; Cartesian3_default.pack(vertexNormal, normalsArray, index); Cartesian3_default.pack(vertexBottom, bottomPositionsArray, index); Cartesian3_default.pack(vertexTop, topPositionsArray, index); cartographicsArray.push(vertexCartographic.latitude); cartographicsArray.push(vertexCartographic.longitude); interpolateSegment( cartographics[i], cartographics[i + 1], minHeight, maxHeight, granularity, arcType, ellipsoid, normalsArray, bottomPositionsArray, topPositionsArray, cartographicsArray ); } const endCartographic = cartographics[cartographicsLength - 1]; const preEndCartographic = cartographics[cartographicsLength - 2]; vertexBottom = getPosition( ellipsoid, endCartographic, minHeight, vertexBottom ); vertexTop = getPosition(ellipsoid, endCartographic, maxHeight, vertexTop); if (loop) { const postEndCartographic = cartographics[0]; previousBottom = getPosition( ellipsoid, preEndCartographic, minHeight, previousBottom ); nextBottom = getPosition( ellipsoid, postEndCartographic, minHeight, nextBottom ); vertexNormal = computeVertexMiterNormal( previousBottom, vertexBottom, vertexTop, nextBottom, vertexNormal ); } else { vertexNormal = computeRightNormal( preEndCartographic, endCartographic, maxHeight, ellipsoid, vertexNormal ); } index = normalsArray.length; Cartesian3_default.pack(vertexNormal, normalsArray, index); Cartesian3_default.pack(vertexBottom, bottomPositionsArray, index); Cartesian3_default.pack(vertexTop, topPositionsArray, index); cartographicsArray.push(endCartographic.latitude); cartographicsArray.push(endCartographic.longitude); if (loop) { interpolateSegment( endCartographic, startCartographic, minHeight, maxHeight, granularity, arcType, ellipsoid, normalsArray, bottomPositionsArray, topPositionsArray, cartographicsArray ); index = normalsArray.length; for (i = 0; i < 3; ++i) { normalsArray[index + i] = normalsArray[i]; bottomPositionsArray[index + i] = bottomPositionsArray[i]; topPositionsArray[index + i] = topPositionsArray[i]; } cartographicsArray.push(startCartographic.latitude); cartographicsArray.push(startCartographic.longitude); } return generateGeometryAttributes( loop, projection, bottomPositionsArray, topPositionsArray, normalsArray, cartographicsArray, compute2dAttributes ); }; var lineDirectionScratch = new Cartesian3_default(); var matrix3Scratch = new Matrix3_default(); var quaternionScratch = new Quaternion_default(); function breakMiter(endGeometryNormal, startBottom, endBottom, endTop) { const lineDirection = direction(endBottom, startBottom, lineDirectionScratch); const dot2 = Cartesian3_default.dot(lineDirection, endGeometryNormal); if (dot2 > MITER_BREAK_SMALL || dot2 < MITER_BREAK_LARGE) { const vertexUp = direction(endTop, endBottom, vertexUpScratch); const angle = dot2 < MITER_BREAK_LARGE ? Math_default.PI_OVER_TWO : -Math_default.PI_OVER_TWO; const quaternion = Quaternion_default.fromAxisAngle( vertexUp, angle, quaternionScratch ); const rotationMatrix = Matrix3_default.fromQuaternion(quaternion, matrix3Scratch); Matrix3_default.multiplyByVector( rotationMatrix, endGeometryNormal, endGeometryNormal ); return true; } return false; } var endPosCartographicScratch = new Cartographic_default(); var normalStartpointScratch = new Cartesian3_default(); var normalEndpointScratch = new Cartesian3_default(); function projectNormal(projection, cartographic2, normal2, projectedPosition2, result) { const position = Cartographic_default.toCartesian( cartographic2, projection._ellipsoid, normalStartpointScratch ); let normalEndpoint = Cartesian3_default.add(position, normal2, normalEndpointScratch); let flipNormal = false; const ellipsoid = projection._ellipsoid; let normalEndpointCartographic = ellipsoid.cartesianToCartographic( normalEndpoint, endPosCartographicScratch ); if (Math.abs(cartographic2.longitude - normalEndpointCartographic.longitude) > Math_default.PI_OVER_TWO) { flipNormal = true; normalEndpoint = Cartesian3_default.subtract( position, normal2, normalEndpointScratch ); normalEndpointCartographic = ellipsoid.cartesianToCartographic( normalEndpoint, endPosCartographicScratch ); } normalEndpointCartographic.height = 0; const normalEndpointProjected = projection.project( normalEndpointCartographic, result ); result = Cartesian3_default.subtract( normalEndpointProjected, projectedPosition2, result ); result.z = 0; result = Cartesian3_default.normalize(result, result); if (flipNormal) { Cartesian3_default.negate(result, result); } return result; } var adjustHeightNormalScratch = new Cartesian3_default(); var adjustHeightOffsetScratch = new Cartesian3_default(); function adjustHeights(bottom, top, minHeight, maxHeight, adjustHeightBottom, adjustHeightTop) { const adjustHeightNormal = Cartesian3_default.subtract( top, bottom, adjustHeightNormalScratch ); Cartesian3_default.normalize(adjustHeightNormal, adjustHeightNormal); const distanceForBottom = minHeight - WALL_INITIAL_MIN_HEIGHT; let adjustHeightOffset = Cartesian3_default.multiplyByScalar( adjustHeightNormal, distanceForBottom, adjustHeightOffsetScratch ); Cartesian3_default.add(bottom, adjustHeightOffset, adjustHeightBottom); const distanceForTop = maxHeight - WALL_INITIAL_MAX_HEIGHT; adjustHeightOffset = Cartesian3_default.multiplyByScalar( adjustHeightNormal, distanceForTop, adjustHeightOffsetScratch ); Cartesian3_default.add(top, adjustHeightOffset, adjustHeightTop); } var nudgeDirectionScratch = new Cartesian3_default(); function nudgeXZ(start, end) { const startToXZdistance = Plane_default.getPointDistance(XZ_PLANE, start); const endToXZdistance = Plane_default.getPointDistance(XZ_PLANE, end); let offset = nudgeDirectionScratch; if (Math_default.equalsEpsilon(startToXZdistance, 0, Math_default.EPSILON2)) { offset = direction(end, start, offset); Cartesian3_default.multiplyByScalar(offset, Math_default.EPSILON2, offset); Cartesian3_default.add(start, offset, start); } else if (Math_default.equalsEpsilon(endToXZdistance, 0, Math_default.EPSILON2)) { offset = direction(start, end, offset); Cartesian3_default.multiplyByScalar(offset, Math_default.EPSILON2, offset); Cartesian3_default.add(end, offset, end); } } function nudgeCartographic(start, end) { const absStartLon = Math.abs(start.longitude); const absEndLon = Math.abs(end.longitude); if (Math_default.equalsEpsilon(absStartLon, Math_default.PI, Math_default.EPSILON11)) { const endSign = Math_default.sign(end.longitude); start.longitude = endSign * (absStartLon - Math_default.EPSILON11); return 1; } else if (Math_default.equalsEpsilon(absEndLon, Math_default.PI, Math_default.EPSILON11)) { const startSign = Math_default.sign(start.longitude); end.longitude = startSign * (absEndLon - Math_default.EPSILON11); return 2; } return 0; } var startCartographicScratch = new Cartographic_default(); var endCartographicScratch = new Cartographic_default(); var segmentStartTopScratch = new Cartesian3_default(); var segmentEndTopScratch = new Cartesian3_default(); var segmentStartBottomScratch = new Cartesian3_default(); var segmentEndBottomScratch = new Cartesian3_default(); var segmentStartNormalScratch = new Cartesian3_default(); var segmentEndNormalScratch = new Cartesian3_default(); var getHeightCartographics = [ startCartographicScratch, endCartographicScratch ]; var getHeightRectangleScratch = new Rectangle_default(); var adjustHeightStartTopScratch = new Cartesian3_default(); var adjustHeightEndTopScratch = new Cartesian3_default(); var adjustHeightStartBottomScratch = new Cartesian3_default(); var adjustHeightEndBottomScratch = new Cartesian3_default(); var segmentStart2DScratch = new Cartesian3_default(); var segmentEnd2DScratch = new Cartesian3_default(); var segmentStartNormal2DScratch = new Cartesian3_default(); var segmentEndNormal2DScratch = new Cartesian3_default(); var offsetScratch3 = new Cartesian3_default(); var startUpScratch = new Cartesian3_default(); var endUpScratch = new Cartesian3_default(); var rightScratch2 = new Cartesian3_default(); var startPlaneNormalScratch = new Cartesian3_default(); var endPlaneNormalScratch = new Cartesian3_default(); var encodeScratch2 = new EncodedCartesian3_default(); var encodeScratch2D = new EncodedCartesian3_default(); var forwardOffset2DScratch = new Cartesian3_default(); var right2DScratch = new Cartesian3_default(); var normalNudgeScratch = new Cartesian3_default(); var scratchBoundingSpheres = [new BoundingSphere_default(), new BoundingSphere_default()]; var REFERENCE_INDICES = [ 0, 2, 1, 0, 3, 2, // right 0, 7, 3, 0, 4, 7, // start 0, 5, 4, 0, 1, 5, // bottom 5, 7, 4, 5, 6, 7, // left 5, 2, 6, 5, 1, 2, // end 3, 6, 2, 3, 7, 6 // top ]; var REFERENCE_INDICES_LENGTH = REFERENCE_INDICES.length; function generateGeometryAttributes(loop, projection, bottomPositionsArray, topPositionsArray, normalsArray, cartographicsArray, compute2dAttributes) { let i; let index; const ellipsoid = projection._ellipsoid; const segmentCount = bottomPositionsArray.length / 3 - 1; const vertexCount = segmentCount * 8; const arraySizeVec4 = vertexCount * 4; const indexCount = segmentCount * 36; const indices = vertexCount > 65535 ? new Uint32Array(indexCount) : new Uint16Array(indexCount); const positionsArray = new Float64Array(vertexCount * 3); const startHiAndForwardOffsetX = new Float32Array(arraySizeVec4); const startLoAndForwardOffsetY = new Float32Array(arraySizeVec4); const startNormalAndForwardOffsetZ = new Float32Array(arraySizeVec4); const endNormalAndTextureCoordinateNormalizationX = new Float32Array( arraySizeVec4 ); const rightNormalAndTextureCoordinateNormalizationY = new Float32Array( arraySizeVec4 ); let startHiLo2D; let offsetAndRight2D; let startEndNormals2D; let texcoordNormalization2D; if (compute2dAttributes) { startHiLo2D = new Float32Array(arraySizeVec4); offsetAndRight2D = new Float32Array(arraySizeVec4); startEndNormals2D = new Float32Array(arraySizeVec4); texcoordNormalization2D = new Float32Array(vertexCount * 2); } const cartographicsLength = cartographicsArray.length / 2; let length2D = 0; const startCartographic = startCartographicScratch; startCartographic.height = 0; const endCartographic = endCartographicScratch; endCartographic.height = 0; let segmentStartCartesian = segmentStartTopScratch; let segmentEndCartesian = segmentEndTopScratch; if (compute2dAttributes) { index = 0; for (i = 1; i < cartographicsLength; i++) { startCartographic.latitude = cartographicsArray[index]; startCartographic.longitude = cartographicsArray[index + 1]; endCartographic.latitude = cartographicsArray[index + 2]; endCartographic.longitude = cartographicsArray[index + 3]; segmentStartCartesian = projection.project( startCartographic, segmentStartCartesian ); segmentEndCartesian = projection.project( endCartographic, segmentEndCartesian ); length2D += Cartesian3_default.distance( segmentStartCartesian, segmentEndCartesian ); index += 2; } } const positionsLength = topPositionsArray.length / 3; segmentEndCartesian = Cartesian3_default.unpack( topPositionsArray, 0, segmentEndCartesian ); let length3D = 0; index = 3; for (i = 1; i < positionsLength; i++) { segmentStartCartesian = Cartesian3_default.clone( segmentEndCartesian, segmentStartCartesian ); segmentEndCartesian = Cartesian3_default.unpack( topPositionsArray, index, segmentEndCartesian ); length3D += Cartesian3_default.distance(segmentStartCartesian, segmentEndCartesian); index += 3; } let j; index = 3; let cartographicsIndex = 0; let vec2sWriteIndex = 0; let vec3sWriteIndex = 0; let vec4sWriteIndex = 0; let miterBroken = false; let endBottom = Cartesian3_default.unpack( bottomPositionsArray, 0, segmentEndBottomScratch ); let endTop = Cartesian3_default.unpack(topPositionsArray, 0, segmentEndTopScratch); let endGeometryNormal = Cartesian3_default.unpack( normalsArray, 0, segmentEndNormalScratch ); if (loop) { const preEndBottom = Cartesian3_default.unpack( bottomPositionsArray, bottomPositionsArray.length - 6, segmentStartBottomScratch ); if (breakMiter(endGeometryNormal, preEndBottom, endBottom, endTop)) { endGeometryNormal = Cartesian3_default.negate( endGeometryNormal, endGeometryNormal ); } } let lengthSoFar3D = 0; let lengthSoFar2D = 0; let sumHeights = 0; for (i = 0; i < segmentCount; i++) { const startBottom = Cartesian3_default.clone(endBottom, segmentStartBottomScratch); const startTop = Cartesian3_default.clone(endTop, segmentStartTopScratch); let startGeometryNormal = Cartesian3_default.clone( endGeometryNormal, segmentStartNormalScratch ); if (miterBroken) { startGeometryNormal = Cartesian3_default.negate( startGeometryNormal, startGeometryNormal ); } endBottom = Cartesian3_default.unpack( bottomPositionsArray, index, segmentEndBottomScratch ); endTop = Cartesian3_default.unpack(topPositionsArray, index, segmentEndTopScratch); endGeometryNormal = Cartesian3_default.unpack( normalsArray, index, segmentEndNormalScratch ); miterBroken = breakMiter(endGeometryNormal, startBottom, endBottom, endTop); startCartographic.latitude = cartographicsArray[cartographicsIndex]; startCartographic.longitude = cartographicsArray[cartographicsIndex + 1]; endCartographic.latitude = cartographicsArray[cartographicsIndex + 2]; endCartographic.longitude = cartographicsArray[cartographicsIndex + 3]; let start2D; let end2D; let startGeometryNormal2D; let endGeometryNormal2D; if (compute2dAttributes) { const nudgeResult = nudgeCartographic(startCartographic, endCartographic); start2D = projection.project(startCartographic, segmentStart2DScratch); end2D = projection.project(endCartographic, segmentEnd2DScratch); const direction2D = direction(end2D, start2D, forwardOffset2DScratch); direction2D.y = Math.abs(direction2D.y); startGeometryNormal2D = segmentStartNormal2DScratch; endGeometryNormal2D = segmentEndNormal2DScratch; if (nudgeResult === 0 || Cartesian3_default.dot(direction2D, Cartesian3_default.UNIT_Y) > MITER_BREAK_SMALL) { startGeometryNormal2D = projectNormal( projection, startCartographic, startGeometryNormal, start2D, segmentStartNormal2DScratch ); endGeometryNormal2D = projectNormal( projection, endCartographic, endGeometryNormal, end2D, segmentEndNormal2DScratch ); } else if (nudgeResult === 1) { endGeometryNormal2D = projectNormal( projection, endCartographic, endGeometryNormal, end2D, segmentEndNormal2DScratch ); startGeometryNormal2D.x = 0; startGeometryNormal2D.y = Math_default.sign( startCartographic.longitude - Math.abs(endCartographic.longitude) ); startGeometryNormal2D.z = 0; } else { startGeometryNormal2D = projectNormal( projection, startCartographic, startGeometryNormal, start2D, segmentStartNormal2DScratch ); endGeometryNormal2D.x = 0; endGeometryNormal2D.y = Math_default.sign( startCartographic.longitude - endCartographic.longitude ); endGeometryNormal2D.z = 0; } } const segmentLength3D = Cartesian3_default.distance(startTop, endTop); const encodedStart = EncodedCartesian3_default.fromCartesian( startBottom, encodeScratch2 ); const forwardOffset = Cartesian3_default.subtract( endBottom, startBottom, offsetScratch3 ); const forward = Cartesian3_default.normalize(forwardOffset, rightScratch2); let startUp = Cartesian3_default.subtract(startTop, startBottom, startUpScratch); startUp = Cartesian3_default.normalize(startUp, startUp); let rightNormal = Cartesian3_default.cross(forward, startUp, rightScratch2); rightNormal = Cartesian3_default.normalize(rightNormal, rightNormal); let startPlaneNormal = Cartesian3_default.cross( startUp, startGeometryNormal, startPlaneNormalScratch ); startPlaneNormal = Cartesian3_default.normalize(startPlaneNormal, startPlaneNormal); let endUp = Cartesian3_default.subtract(endTop, endBottom, endUpScratch); endUp = Cartesian3_default.normalize(endUp, endUp); let endPlaneNormal = Cartesian3_default.cross( endGeometryNormal, endUp, endPlaneNormalScratch ); endPlaneNormal = Cartesian3_default.normalize(endPlaneNormal, endPlaneNormal); const texcoordNormalization3DX = segmentLength3D / length3D; const texcoordNormalization3DY = lengthSoFar3D / length3D; let segmentLength2D = 0; let encodedStart2D; let forwardOffset2D; let right2D; let texcoordNormalization2DX = 0; let texcoordNormalization2DY = 0; if (compute2dAttributes) { segmentLength2D = Cartesian3_default.distance(start2D, end2D); encodedStart2D = EncodedCartesian3_default.fromCartesian( start2D, encodeScratch2D ); forwardOffset2D = Cartesian3_default.subtract( end2D, start2D, forwardOffset2DScratch ); right2D = Cartesian3_default.normalize(forwardOffset2D, right2DScratch); const swap5 = right2D.x; right2D.x = right2D.y; right2D.y = -swap5; texcoordNormalization2DX = segmentLength2D / length2D; texcoordNormalization2DY = lengthSoFar2D / length2D; } for (j = 0; j < 8; j++) { const vec4Index = vec4sWriteIndex + j * 4; const vec2Index = vec2sWriteIndex + j * 2; const wIndex = vec4Index + 3; const rightPlaneSide = j < 4 ? 1 : -1; const topBottomSide = j === 2 || j === 3 || j === 6 || j === 7 ? 1 : -1; Cartesian3_default.pack(encodedStart.high, startHiAndForwardOffsetX, vec4Index); startHiAndForwardOffsetX[wIndex] = forwardOffset.x; Cartesian3_default.pack(encodedStart.low, startLoAndForwardOffsetY, vec4Index); startLoAndForwardOffsetY[wIndex] = forwardOffset.y; Cartesian3_default.pack( startPlaneNormal, startNormalAndForwardOffsetZ, vec4Index ); startNormalAndForwardOffsetZ[wIndex] = forwardOffset.z; Cartesian3_default.pack( endPlaneNormal, endNormalAndTextureCoordinateNormalizationX, vec4Index ); endNormalAndTextureCoordinateNormalizationX[wIndex] = texcoordNormalization3DX * rightPlaneSide; Cartesian3_default.pack( rightNormal, rightNormalAndTextureCoordinateNormalizationY, vec4Index ); let texcoordNormalization = texcoordNormalization3DY * topBottomSide; if (texcoordNormalization === 0 && topBottomSide < 0) { texcoordNormalization = 9; } rightNormalAndTextureCoordinateNormalizationY[wIndex] = texcoordNormalization; if (compute2dAttributes) { startHiLo2D[vec4Index] = encodedStart2D.high.x; startHiLo2D[vec4Index + 1] = encodedStart2D.high.y; startHiLo2D[vec4Index + 2] = encodedStart2D.low.x; startHiLo2D[vec4Index + 3] = encodedStart2D.low.y; startEndNormals2D[vec4Index] = -startGeometryNormal2D.y; startEndNormals2D[vec4Index + 1] = startGeometryNormal2D.x; startEndNormals2D[vec4Index + 2] = endGeometryNormal2D.y; startEndNormals2D[vec4Index + 3] = -endGeometryNormal2D.x; offsetAndRight2D[vec4Index] = forwardOffset2D.x; offsetAndRight2D[vec4Index + 1] = forwardOffset2D.y; offsetAndRight2D[vec4Index + 2] = right2D.x; offsetAndRight2D[vec4Index + 3] = right2D.y; texcoordNormalization2D[vec2Index] = texcoordNormalization2DX * rightPlaneSide; texcoordNormalization = texcoordNormalization2DY * topBottomSide; if (texcoordNormalization === 0 && topBottomSide < 0) { texcoordNormalization = 9; } texcoordNormalization2D[vec2Index + 1] = texcoordNormalization; } } const adjustHeightStartBottom = adjustHeightStartBottomScratch; const adjustHeightEndBottom = adjustHeightEndBottomScratch; const adjustHeightStartTop = adjustHeightStartTopScratch; const adjustHeightEndTop = adjustHeightEndTopScratch; const getHeightsRectangle = Rectangle_default.fromCartographicArray( getHeightCartographics, getHeightRectangleScratch ); const minMaxHeights = ApproximateTerrainHeights_default.getMinimumMaximumHeights( getHeightsRectangle, ellipsoid ); const minHeight = minMaxHeights.minimumTerrainHeight; const maxHeight = minMaxHeights.maximumTerrainHeight; sumHeights += Math.abs(minHeight); sumHeights += Math.abs(maxHeight); adjustHeights( startBottom, startTop, minHeight, maxHeight, adjustHeightStartBottom, adjustHeightStartTop ); adjustHeights( endBottom, endTop, minHeight, maxHeight, adjustHeightEndBottom, adjustHeightEndTop ); let normalNudge = Cartesian3_default.multiplyByScalar( rightNormal, Math_default.EPSILON5, normalNudgeScratch ); Cartesian3_default.add( adjustHeightStartBottom, normalNudge, adjustHeightStartBottom ); Cartesian3_default.add(adjustHeightEndBottom, normalNudge, adjustHeightEndBottom); Cartesian3_default.add(adjustHeightStartTop, normalNudge, adjustHeightStartTop); Cartesian3_default.add(adjustHeightEndTop, normalNudge, adjustHeightEndTop); nudgeXZ(adjustHeightStartBottom, adjustHeightEndBottom); nudgeXZ(adjustHeightStartTop, adjustHeightEndTop); Cartesian3_default.pack(adjustHeightStartBottom, positionsArray, vec3sWriteIndex); Cartesian3_default.pack(adjustHeightEndBottom, positionsArray, vec3sWriteIndex + 3); Cartesian3_default.pack(adjustHeightEndTop, positionsArray, vec3sWriteIndex + 6); Cartesian3_default.pack(adjustHeightStartTop, positionsArray, vec3sWriteIndex + 9); normalNudge = Cartesian3_default.multiplyByScalar( rightNormal, -2 * Math_default.EPSILON5, normalNudgeScratch ); Cartesian3_default.add( adjustHeightStartBottom, normalNudge, adjustHeightStartBottom ); Cartesian3_default.add(adjustHeightEndBottom, normalNudge, adjustHeightEndBottom); Cartesian3_default.add(adjustHeightStartTop, normalNudge, adjustHeightStartTop); Cartesian3_default.add(adjustHeightEndTop, normalNudge, adjustHeightEndTop); nudgeXZ(adjustHeightStartBottom, adjustHeightEndBottom); nudgeXZ(adjustHeightStartTop, adjustHeightEndTop); Cartesian3_default.pack( adjustHeightStartBottom, positionsArray, vec3sWriteIndex + 12 ); Cartesian3_default.pack( adjustHeightEndBottom, positionsArray, vec3sWriteIndex + 15 ); Cartesian3_default.pack(adjustHeightEndTop, positionsArray, vec3sWriteIndex + 18); Cartesian3_default.pack(adjustHeightStartTop, positionsArray, vec3sWriteIndex + 21); cartographicsIndex += 2; index += 3; vec2sWriteIndex += 16; vec3sWriteIndex += 24; vec4sWriteIndex += 32; lengthSoFar3D += segmentLength3D; lengthSoFar2D += segmentLength2D; } index = 0; let indexOffset = 0; for (i = 0; i < segmentCount; i++) { for (j = 0; j < REFERENCE_INDICES_LENGTH; j++) { indices[index + j] = REFERENCE_INDICES[j] + indexOffset; } indexOffset += 8; index += REFERENCE_INDICES_LENGTH; } const boundingSpheres = scratchBoundingSpheres; BoundingSphere_default.fromVertices( bottomPositionsArray, Cartesian3_default.ZERO, 3, boundingSpheres[0] ); BoundingSphere_default.fromVertices( topPositionsArray, Cartesian3_default.ZERO, 3, boundingSpheres[1] ); const boundingSphere = BoundingSphere_default.fromBoundingSpheres(boundingSpheres); boundingSphere.radius += sumHeights / (segmentCount * 2); const attributes = { position: new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.DOUBLE, componentsPerAttribute: 3, normalize: false, values: positionsArray }), startHiAndForwardOffsetX: getVec4GeometryAttribute( startHiAndForwardOffsetX ), startLoAndForwardOffsetY: getVec4GeometryAttribute( startLoAndForwardOffsetY ), startNormalAndForwardOffsetZ: getVec4GeometryAttribute( startNormalAndForwardOffsetZ ), endNormalAndTextureCoordinateNormalizationX: getVec4GeometryAttribute( endNormalAndTextureCoordinateNormalizationX ), rightNormalAndTextureCoordinateNormalizationY: getVec4GeometryAttribute( rightNormalAndTextureCoordinateNormalizationY ) }; if (compute2dAttributes) { attributes.startHiLo2D = getVec4GeometryAttribute(startHiLo2D); attributes.offsetAndRight2D = getVec4GeometryAttribute(offsetAndRight2D); attributes.startEndNormals2D = getVec4GeometryAttribute(startEndNormals2D); attributes.texcoordNormalization2D = new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 2, normalize: false, values: texcoordNormalization2D }); } return new Geometry_default({ attributes, indices, boundingSphere }); } function getVec4GeometryAttribute(typedArray) { return new GeometryAttribute_default({ componentDatatype: ComponentDatatype_default.FLOAT, componentsPerAttribute: 4, normalize: false, values: typedArray }); } GroundPolylineGeometry._projectNormal = projectNormal; var GroundPolylineGeometry_default = GroundPolylineGeometry; // packages/engine/Source/Shaders/PolylineShadowVolumeFS.js var import_InlineWorkers389 = __toESM(require_InlineWorkers(), 1); var PolylineShadowVolumeFS_default = 'in vec4 v_startPlaneNormalEcAndHalfWidth;\nin vec4 v_endPlaneNormalEcAndBatchId;\nin vec4 v_rightPlaneEC; // Technically can compute distance for this here\nin vec4 v_endEcAndStartEcX;\nin vec4 v_texcoordNormalizationAndStartEcYZ;\n\n#ifdef PER_INSTANCE_COLOR\nin vec4 v_color;\n#endif\n\nvoid main(void)\n{\n float logDepthOrDepth = czm_branchFreeTernary(czm_sceneMode == czm_sceneMode2D, gl_FragCoord.z, czm_unpackDepth(texture(czm_globeDepthTexture, gl_FragCoord.xy / czm_viewport.zw)));\n vec3 ecStart = vec3(v_endEcAndStartEcX.w, v_texcoordNormalizationAndStartEcYZ.zw);\n\n // Discard for sky\n if (logDepthOrDepth == 0.0) {\n#ifdef DEBUG_SHOW_VOLUME\n out_FragColor = vec4(1.0, 0.0, 0.0, 0.5);\n return;\n#else // DEBUG_SHOW_VOLUME\n discard;\n#endif // DEBUG_SHOW_VOLUME\n }\n\n vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, logDepthOrDepth);\n eyeCoordinate /= eyeCoordinate.w;\n\n float halfMaxWidth = v_startPlaneNormalEcAndHalfWidth.w * czm_metersPerPixel(eyeCoordinate);\n // Check distance of the eye coordinate against the right-facing plane\n float widthwiseDistance = czm_planeDistance(v_rightPlaneEC, eyeCoordinate.xyz);\n\n // Check eye coordinate against the mitering planes\n float distanceFromStart = czm_planeDistance(v_startPlaneNormalEcAndHalfWidth.xyz, -dot(ecStart, v_startPlaneNormalEcAndHalfWidth.xyz), eyeCoordinate.xyz);\n float distanceFromEnd = czm_planeDistance(v_endPlaneNormalEcAndBatchId.xyz, -dot(v_endEcAndStartEcX.xyz, v_endPlaneNormalEcAndBatchId.xyz), eyeCoordinate.xyz);\n\n if (abs(widthwiseDistance) > halfMaxWidth || distanceFromStart < 0.0 || distanceFromEnd < 0.0) {\n#ifdef DEBUG_SHOW_VOLUME\n out_FragColor = vec4(1.0, 0.0, 0.0, 0.5);\n return;\n#else // DEBUG_SHOW_VOLUME\n discard;\n#endif // DEBUG_SHOW_VOLUME\n }\n\n // Check distance of the eye coordinate against start and end planes with normals in the right plane.\n // For computing unskewed lengthwise texture coordinate.\n // Can also be used for clipping extremely pointy miters, but in practice unnecessary because of miter breaking.\n\n // aligned plane: cross the right plane normal with miter plane normal, then cross the result with right again to point it more "forward"\n vec3 alignedPlaneNormal;\n\n // start aligned plane\n alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_startPlaneNormalEcAndHalfWidth.xyz);\n alignedPlaneNormal = normalize(cross(alignedPlaneNormal, v_rightPlaneEC.xyz));\n distanceFromStart = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, ecStart), eyeCoordinate.xyz);\n\n // end aligned plane\n alignedPlaneNormal = cross(v_rightPlaneEC.xyz, v_endPlaneNormalEcAndBatchId.xyz);\n alignedPlaneNormal = normalize(cross(alignedPlaneNormal, v_rightPlaneEC.xyz));\n distanceFromEnd = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, v_endEcAndStartEcX.xyz), eyeCoordinate.xyz);\n\n#ifdef PER_INSTANCE_COLOR\n out_FragColor = czm_gammaCorrect(v_color);\n#else // PER_INSTANCE_COLOR\n // Clamp - distance to aligned planes may be negative due to mitering,\n // so fragment texture coordinate might be out-of-bounds.\n float s = clamp(distanceFromStart / (distanceFromStart + distanceFromEnd), 0.0, 1.0);\n s = (s * v_texcoordNormalizationAndStartEcYZ.x) + v_texcoordNormalizationAndStartEcYZ.y;\n float t = (widthwiseDistance + halfMaxWidth) / (2.0 * halfMaxWidth);\n\n czm_materialInput materialInput;\n\n materialInput.s = s;\n materialInput.st = vec2(s, t);\n materialInput.str = vec3(s, t, 0.0);\n\n czm_material material = czm_getMaterial(materialInput);\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#endif // PER_INSTANCE_COLOR\n\n // Premultiply alpha. Required for classification primitives on translucent globe.\n out_FragColor.rgb *= out_FragColor.a;\n\n czm_writeDepthClamp();\n}\n'; // packages/engine/Source/Shaders/PolylineShadowVolumeMorphFS.js var import_InlineWorkers390 = __toESM(require_InlineWorkers(), 1); var PolylineShadowVolumeMorphFS_default = "in vec3 v_forwardDirectionEC;\nin vec3 v_texcoordNormalizationAndHalfWidth;\nin float v_batchId;\n\n#ifdef PER_INSTANCE_COLOR\nin vec4 v_color;\n#else\nin vec2 v_alignedPlaneDistances;\nin float v_texcoordT;\n#endif\n\nfloat rayPlaneDistanceUnsafe(vec3 origin, vec3 direction, vec3 planeNormal, float planeDistance) {\n // We don't expect the ray to ever be parallel to the plane\n return (-planeDistance - dot(planeNormal, origin)) / dot(planeNormal, direction);\n}\n\nvoid main(void)\n{\n vec4 eyeCoordinate = gl_FragCoord;\n eyeCoordinate /= eyeCoordinate.w;\n\n#ifdef PER_INSTANCE_COLOR\n out_FragColor = czm_gammaCorrect(v_color);\n#else // PER_INSTANCE_COLOR\n // Use distances for planes aligned with segment to prevent skew in dashing\n float distanceFromStart = rayPlaneDistanceUnsafe(eyeCoordinate.xyz, -v_forwardDirectionEC, v_forwardDirectionEC.xyz, v_alignedPlaneDistances.x);\n float distanceFromEnd = rayPlaneDistanceUnsafe(eyeCoordinate.xyz, v_forwardDirectionEC, -v_forwardDirectionEC.xyz, v_alignedPlaneDistances.y);\n\n // Clamp - distance to aligned planes may be negative due to mitering\n distanceFromStart = max(0.0, distanceFromStart);\n distanceFromEnd = max(0.0, distanceFromEnd);\n\n float s = distanceFromStart / (distanceFromStart + distanceFromEnd);\n s = (s * v_texcoordNormalizationAndHalfWidth.x) + v_texcoordNormalizationAndHalfWidth.y;\n\n czm_materialInput materialInput;\n\n materialInput.s = s;\n materialInput.st = vec2(s, v_texcoordT);\n materialInput.str = vec3(s, v_texcoordT, 0.0);\n\n czm_material material = czm_getMaterial(materialInput);\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#endif // PER_INSTANCE_COLOR\n}\n"; // packages/engine/Source/Shaders/PolylineShadowVolumeMorphVS.js var import_InlineWorkers391 = __toESM(require_InlineWorkers(), 1); var PolylineShadowVolumeMorphVS_default = `in vec3 position3DHigh; in vec3 position3DLow; in vec4 startHiAndForwardOffsetX; in vec4 startLoAndForwardOffsetY; in vec4 startNormalAndForwardOffsetZ; in vec4 endNormalAndTextureCoordinateNormalizationX; in vec4 rightNormalAndTextureCoordinateNormalizationY; in vec4 startHiLo2D; in vec4 offsetAndRight2D; in vec4 startEndNormals2D; in vec2 texcoordNormalization2D; in float batchId; out vec3 v_forwardDirectionEC; out vec3 v_texcoordNormalizationAndHalfWidth; out float v_batchId; // For materials #ifdef WIDTH_VARYING out float v_width; #endif #ifdef ANGLE_VARYING out float v_polylineAngle; #endif #ifdef PER_INSTANCE_COLOR out vec4 v_color; #else out vec2 v_alignedPlaneDistances; out float v_texcoordT; #endif // Morphing planes using SLERP or NLERP doesn't seem to work, so instead draw the material directly on the shadow volume. // Morph views are from very far away and aren't meant to be used precisely, so this should be sufficient. void main() { v_batchId = batchId; // Start position vec4 posRelativeToEye2D = czm_translateRelativeToEye(vec3(0.0, startHiLo2D.xy), vec3(0.0, startHiLo2D.zw)); vec4 posRelativeToEye3D = czm_translateRelativeToEye(startHiAndForwardOffsetX.xyz, startLoAndForwardOffsetY.xyz); vec4 posRelativeToEye = czm_columbusViewMorph(posRelativeToEye2D, posRelativeToEye3D, czm_morphTime); vec3 posEc2D = (czm_modelViewRelativeToEye * posRelativeToEye2D).xyz; vec3 posEc3D = (czm_modelViewRelativeToEye * posRelativeToEye3D).xyz; vec3 startEC = (czm_modelViewRelativeToEye * posRelativeToEye).xyz; // Start plane vec4 startPlane2D; vec4 startPlane3D; startPlane2D.xyz = czm_normal * vec3(0.0, startEndNormals2D.xy); startPlane3D.xyz = czm_normal * startNormalAndForwardOffsetZ.xyz; startPlane2D.w = -dot(startPlane2D.xyz, posEc2D); startPlane3D.w = -dot(startPlane3D.xyz, posEc3D); // Right plane vec4 rightPlane2D; vec4 rightPlane3D; rightPlane2D.xyz = czm_normal * vec3(0.0, offsetAndRight2D.zw); rightPlane3D.xyz = czm_normal * rightNormalAndTextureCoordinateNormalizationY.xyz; rightPlane2D.w = -dot(rightPlane2D.xyz, posEc2D); rightPlane3D.w = -dot(rightPlane3D.xyz, posEc3D); // End position posRelativeToEye2D = posRelativeToEye2D + vec4(0.0, offsetAndRight2D.xy, 0.0); posRelativeToEye3D = posRelativeToEye3D + vec4(startHiAndForwardOffsetX.w, startLoAndForwardOffsetY.w, startNormalAndForwardOffsetZ.w, 0.0); posRelativeToEye = czm_columbusViewMorph(posRelativeToEye2D, posRelativeToEye3D, czm_morphTime); posEc2D = (czm_modelViewRelativeToEye * posRelativeToEye2D).xyz; posEc3D = (czm_modelViewRelativeToEye * posRelativeToEye3D).xyz; vec3 endEC = (czm_modelViewRelativeToEye * posRelativeToEye).xyz; vec3 forwardEc3D = czm_normal * normalize(vec3(startHiAndForwardOffsetX.w, startLoAndForwardOffsetY.w, startNormalAndForwardOffsetZ.w)); vec3 forwardEc2D = czm_normal * normalize(vec3(0.0, offsetAndRight2D.xy)); // End plane vec4 endPlane2D; vec4 endPlane3D; endPlane2D.xyz = czm_normal * vec3(0.0, startEndNormals2D.zw); endPlane3D.xyz = czm_normal * endNormalAndTextureCoordinateNormalizationX.xyz; endPlane2D.w = -dot(endPlane2D.xyz, posEc2D); endPlane3D.w = -dot(endPlane3D.xyz, posEc3D); // Forward direction v_forwardDirectionEC = normalize(endEC - startEC); vec2 cleanTexcoordNormalization2D; cleanTexcoordNormalization2D.x = abs(texcoordNormalization2D.x); cleanTexcoordNormalization2D.y = czm_branchFreeTernary(texcoordNormalization2D.y > 1.0, 0.0, abs(texcoordNormalization2D.y)); vec2 cleanTexcoordNormalization3D; cleanTexcoordNormalization3D.x = abs(endNormalAndTextureCoordinateNormalizationX.w); cleanTexcoordNormalization3D.y = rightNormalAndTextureCoordinateNormalizationY.w; cleanTexcoordNormalization3D.y = czm_branchFreeTernary(cleanTexcoordNormalization3D.y > 1.0, 0.0, abs(cleanTexcoordNormalization3D.y)); v_texcoordNormalizationAndHalfWidth.xy = mix(cleanTexcoordNormalization2D, cleanTexcoordNormalization3D, czm_morphTime); #ifdef PER_INSTANCE_COLOR v_color = czm_batchTable_color(batchId); #else // PER_INSTANCE_COLOR // For computing texture coordinates v_alignedPlaneDistances.x = -dot(v_forwardDirectionEC, startEC); v_alignedPlaneDistances.y = -dot(-v_forwardDirectionEC, endEC); #endif // PER_INSTANCE_COLOR #ifdef WIDTH_VARYING float width = czm_batchTable_width(batchId); float halfWidth = width * 0.5; v_width = width; v_texcoordNormalizationAndHalfWidth.z = halfWidth; #else float halfWidth = 0.5 * czm_batchTable_width(batchId); v_texcoordNormalizationAndHalfWidth.z = halfWidth; #endif // Compute a normal along which to "push" the position out, extending the miter depending on view distance. // Position has already been "pushed" by unit length along miter normal, and miter normals are encoded in the planes. // Decode the normal to use at this specific vertex, push the position back, and then push to where it needs to be. // Since this is morphing, compute both 3D and 2D positions and then blend. // ****** 3D ****** // Check distance to the end plane and start plane, pick the plane that is closer vec4 positionEc3D = czm_modelViewRelativeToEye * czm_translateRelativeToEye(position3DHigh, position3DLow); // w = 1.0, see czm_computePosition float absStartPlaneDistance = abs(czm_planeDistance(startPlane3D, positionEc3D.xyz)); float absEndPlaneDistance = abs(czm_planeDistance(endPlane3D, positionEc3D.xyz)); vec3 planeDirection = czm_branchFreeTernary(absStartPlaneDistance < absEndPlaneDistance, startPlane3D.xyz, endPlane3D.xyz); vec3 upOrDown = normalize(cross(rightPlane3D.xyz, planeDirection)); // Points "up" for start plane, "down" at end plane. vec3 normalEC = normalize(cross(planeDirection, upOrDown)); // In practice, the opposite seems to work too. // Nudge the top vertex upwards to prevent flickering vec3 geodeticSurfaceNormal = normalize(cross(normalEC, forwardEc3D)); geodeticSurfaceNormal *= float(0.0 <= rightNormalAndTextureCoordinateNormalizationY.w && rightNormalAndTextureCoordinateNormalizationY.w <= 1.0); geodeticSurfaceNormal *= MAX_TERRAIN_HEIGHT; positionEc3D.xyz += geodeticSurfaceNormal; // Determine if this vertex is on the "left" or "right" normalEC *= sign(endNormalAndTextureCoordinateNormalizationX.w); // A "perfect" implementation would push along normals according to the angle against forward. // In practice, just pushing the normal out by halfWidth is sufficient for morph views. positionEc3D.xyz += halfWidth * max(0.0, czm_metersPerPixel(positionEc3D)) * normalEC; // prevent artifacts when czm_metersPerPixel is negative (behind camera) // ****** 2D ****** // Check distance to the end plane and start plane, pick the plane that is closer vec4 positionEc2D = czm_modelViewRelativeToEye * czm_translateRelativeToEye(position2DHigh.zxy, position2DLow.zxy); // w = 1.0, see czm_computePosition absStartPlaneDistance = abs(czm_planeDistance(startPlane2D, positionEc2D.xyz)); absEndPlaneDistance = abs(czm_planeDistance(endPlane2D, positionEc2D.xyz)); planeDirection = czm_branchFreeTernary(absStartPlaneDistance < absEndPlaneDistance, startPlane2D.xyz, endPlane2D.xyz); upOrDown = normalize(cross(rightPlane2D.xyz, planeDirection)); // Points "up" for start plane, "down" at end plane. normalEC = normalize(cross(planeDirection, upOrDown)); // In practice, the opposite seems to work too. // Nudge the top vertex upwards to prevent flickering geodeticSurfaceNormal = normalize(cross(normalEC, forwardEc2D)); geodeticSurfaceNormal *= float(0.0 <= texcoordNormalization2D.y && texcoordNormalization2D.y <= 1.0); geodeticSurfaceNormal *= MAX_TERRAIN_HEIGHT; positionEc2D.xyz += geodeticSurfaceNormal; // Determine if this vertex is on the "left" or "right" normalEC *= sign(texcoordNormalization2D.x); #ifndef PER_INSTANCE_COLOR // Use vertex's sidedness to compute its texture coordinate. v_texcoordT = clamp(sign(texcoordNormalization2D.x), 0.0, 1.0); #endif // A "perfect" implementation would push along normals according to the angle against forward. // In practice, just pushing the normal out by halfWidth is sufficient for morph views. positionEc2D.xyz += halfWidth * max(0.0, czm_metersPerPixel(positionEc2D)) * normalEC; // prevent artifacts when czm_metersPerPixel is negative (behind camera) // Blend for actual position gl_Position = czm_projection * mix(positionEc2D, positionEc3D, czm_morphTime); #ifdef ANGLE_VARYING // Approximate relative screen space direction of the line. vec2 approxLineDirection = normalize(vec2(v_forwardDirectionEC.x, -v_forwardDirectionEC.y)); approxLineDirection.y = czm_branchFreeTernary(approxLineDirection.x == 0.0 && approxLineDirection.y == 0.0, -1.0, approxLineDirection.y); v_polylineAngle = czm_fastApproximateAtan(approxLineDirection.x, approxLineDirection.y); #endif } `; // packages/engine/Source/Shaders/PolylineShadowVolumeVS.js var import_InlineWorkers392 = __toESM(require_InlineWorkers(), 1); var PolylineShadowVolumeVS_default = 'in vec3 position3DHigh;\nin vec3 position3DLow;\n\n// In 2D and in 3D, texture coordinate normalization component signs encodes:\n// * X sign - sidedness relative to right plane\n// * Y sign - is negative OR magnitude is greater than 1.0 if vertex is on bottom of volume\n#ifndef COLUMBUS_VIEW_2D\nin vec4 startHiAndForwardOffsetX;\nin vec4 startLoAndForwardOffsetY;\nin vec4 startNormalAndForwardOffsetZ;\nin vec4 endNormalAndTextureCoordinateNormalizationX;\nin vec4 rightNormalAndTextureCoordinateNormalizationY;\n#else\nin vec4 startHiLo2D;\nin vec4 offsetAndRight2D;\nin vec4 startEndNormals2D;\nin vec2 texcoordNormalization2D;\n#endif\n\nin float batchId;\n\nout vec4 v_startPlaneNormalEcAndHalfWidth;\nout vec4 v_endPlaneNormalEcAndBatchId;\nout vec4 v_rightPlaneEC;\nout vec4 v_endEcAndStartEcX;\nout vec4 v_texcoordNormalizationAndStartEcYZ;\n\n// For materials\n#ifdef WIDTH_VARYING\nout float v_width;\n#endif\n#ifdef ANGLE_VARYING\nout float v_polylineAngle;\n#endif\n\n#ifdef PER_INSTANCE_COLOR\nout vec4 v_color;\n#endif\n\nvoid main()\n{\n#ifdef COLUMBUS_VIEW_2D\n vec3 ecStart = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, startHiLo2D.xy), vec3(0.0, startHiLo2D.zw))).xyz;\n\n vec3 forwardDirectionEC = czm_normal * vec3(0.0, offsetAndRight2D.xy);\n vec3 ecEnd = forwardDirectionEC + ecStart;\n forwardDirectionEC = normalize(forwardDirectionEC);\n\n // Right plane\n v_rightPlaneEC.xyz = czm_normal * vec3(0.0, offsetAndRight2D.zw);\n v_rightPlaneEC.w = -dot(v_rightPlaneEC.xyz, ecStart);\n\n // start plane\n vec4 startPlaneEC;\n startPlaneEC.xyz = czm_normal * vec3(0.0, startEndNormals2D.xy);\n startPlaneEC.w = -dot(startPlaneEC.xyz, ecStart);\n\n // end plane\n vec4 endPlaneEC;\n endPlaneEC.xyz = czm_normal * vec3(0.0, startEndNormals2D.zw);\n endPlaneEC.w = -dot(endPlaneEC.xyz, ecEnd);\n\n v_texcoordNormalizationAndStartEcYZ.x = abs(texcoordNormalization2D.x);\n v_texcoordNormalizationAndStartEcYZ.y = texcoordNormalization2D.y;\n\n#else // COLUMBUS_VIEW_2D\n vec3 ecStart = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(startHiAndForwardOffsetX.xyz, startLoAndForwardOffsetY.xyz)).xyz;\n vec3 offset = czm_normal * vec3(startHiAndForwardOffsetX.w, startLoAndForwardOffsetY.w, startNormalAndForwardOffsetZ.w);\n vec3 ecEnd = ecStart + offset;\n\n vec3 forwardDirectionEC = normalize(offset);\n\n // start plane\n vec4 startPlaneEC;\n startPlaneEC.xyz = czm_normal * startNormalAndForwardOffsetZ.xyz;\n startPlaneEC.w = -dot(startPlaneEC.xyz, ecStart);\n\n // end plane\n vec4 endPlaneEC;\n endPlaneEC.xyz = czm_normal * endNormalAndTextureCoordinateNormalizationX.xyz;\n endPlaneEC.w = -dot(endPlaneEC.xyz, ecEnd);\n\n // Right plane\n v_rightPlaneEC.xyz = czm_normal * rightNormalAndTextureCoordinateNormalizationY.xyz;\n v_rightPlaneEC.w = -dot(v_rightPlaneEC.xyz, ecStart);\n\n v_texcoordNormalizationAndStartEcYZ.x = abs(endNormalAndTextureCoordinateNormalizationX.w);\n v_texcoordNormalizationAndStartEcYZ.y = rightNormalAndTextureCoordinateNormalizationY.w;\n\n#endif // COLUMBUS_VIEW_2D\n\n v_endEcAndStartEcX.xyz = ecEnd;\n v_endEcAndStartEcX.w = ecStart.x;\n v_texcoordNormalizationAndStartEcYZ.zw = ecStart.yz;\n\n#ifdef PER_INSTANCE_COLOR\n v_color = czm_batchTable_color(batchId);\n#endif // PER_INSTANCE_COLOR\n\n // Compute a normal along which to "push" the position out, extending the miter depending on view distance.\n // Position has already been "pushed" by unit length along miter normal, and miter normals are encoded in the planes.\n // Decode the normal to use at this specific vertex, push the position back, and then push to where it needs to be.\n vec4 positionRelativeToEye = czm_computePosition();\n\n // Check distance to the end plane and start plane, pick the plane that is closer\n vec4 positionEC = czm_modelViewRelativeToEye * positionRelativeToEye; // w = 1.0, see czm_computePosition\n float absStartPlaneDistance = abs(czm_planeDistance(startPlaneEC, positionEC.xyz));\n float absEndPlaneDistance = abs(czm_planeDistance(endPlaneEC, positionEC.xyz));\n vec3 planeDirection = czm_branchFreeTernary(absStartPlaneDistance < absEndPlaneDistance, startPlaneEC.xyz, endPlaneEC.xyz);\n vec3 upOrDown = normalize(cross(v_rightPlaneEC.xyz, planeDirection)); // Points "up" for start plane, "down" at end plane.\n vec3 normalEC = normalize(cross(planeDirection, upOrDown)); // In practice, the opposite seems to work too.\n\n // Extrude bottom vertices downward for far view distances, like for GroundPrimitives\n upOrDown = cross(forwardDirectionEC, normalEC);\n upOrDown = float(czm_sceneMode == czm_sceneMode3D) * upOrDown;\n upOrDown = float(v_texcoordNormalizationAndStartEcYZ.y > 1.0 || v_texcoordNormalizationAndStartEcYZ.y < 0.0) * upOrDown;\n upOrDown = min(GLOBE_MINIMUM_ALTITUDE, czm_geometricToleranceOverMeter * length(positionRelativeToEye.xyz)) * upOrDown;\n positionEC.xyz += upOrDown;\n\n v_texcoordNormalizationAndStartEcYZ.y = czm_branchFreeTernary(v_texcoordNormalizationAndStartEcYZ.y > 1.0, 0.0, abs(v_texcoordNormalizationAndStartEcYZ.y));\n\n // Determine distance along normalEC to push for a volume of appropriate width.\n // Make volumes about double pixel width for a conservative fit - in practice the\n // extra cost here is minimal compared to the loose volume heights.\n //\n // N = normalEC (guaranteed "right-facing")\n // R = rightEC\n // p = angle between N and R\n // w = distance to push along R if R == N\n // d = distance to push along N\n //\n // N R\n // { p| } * cos(p) = dot(N, R) = w / d\n // d | |w * d = w / dot(N, R)\n // { | }\n // o---------- polyline segment ---->\n //\n float width = czm_batchTable_width(batchId);\n#ifdef WIDTH_VARYING\n v_width = width;\n#endif\n\n v_startPlaneNormalEcAndHalfWidth.xyz = startPlaneEC.xyz;\n v_startPlaneNormalEcAndHalfWidth.w = width * 0.5;\n\n v_endPlaneNormalEcAndBatchId.xyz = endPlaneEC.xyz;\n v_endPlaneNormalEcAndBatchId.w = batchId;\n\n width = width * max(0.0, czm_metersPerPixel(positionEC)); // width = distance to push along R\n width = width / dot(normalEC, v_rightPlaneEC.xyz); // width = distance to push along N\n\n // Determine if this vertex is on the "left" or "right"\n#ifdef COLUMBUS_VIEW_2D\n normalEC *= sign(texcoordNormalization2D.x);\n#else\n normalEC *= sign(endNormalAndTextureCoordinateNormalizationX.w);\n#endif\n\n positionEC.xyz += width * normalEC;\n gl_Position = czm_depthClamp(czm_projection * positionEC);\n\n#ifdef ANGLE_VARYING\n // Approximate relative screen space direction of the line.\n vec2 approxLineDirection = normalize(vec2(forwardDirectionEC.x, -forwardDirectionEC.y));\n approxLineDirection.y = czm_branchFreeTernary(approxLineDirection.x == 0.0 && approxLineDirection.y == 0.0, -1.0, approxLineDirection.y);\n v_polylineAngle = czm_fastApproximateAtan(approxLineDirection.x, approxLineDirection.y);\n#endif\n}\n'; // packages/engine/Source/Scene/PolylineColorAppearance.js var import_InlineWorkers395 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Appearances/PolylineColorAppearanceVS.js var import_InlineWorkers393 = __toESM(require_InlineWorkers(), 1); var PolylineColorAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 prevPosition3DHigh;\nin vec3 prevPosition3DLow;\nin vec3 nextPosition3DHigh;\nin vec3 nextPosition3DLow;\nin vec2 expandAndWidth;\nin vec4 color;\nin float batchId;\n\nout vec4 v_color;\n\nvoid main()\n{\n float expandDir = expandAndWidth.x;\n float width = abs(expandAndWidth.y) + 0.5;\n bool usePrev = expandAndWidth.y < 0.0;\n\n vec4 p = czm_computePosition();\n vec4 prev = czm_computePrevPosition();\n vec4 next = czm_computeNextPosition();\n\n float angle;\n vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle);\n gl_Position = czm_viewportOrthographic * positionWC;\n\n v_color = color;\n}\n"; // packages/engine/Source/Shaders/PolylineCommon.js var import_InlineWorkers394 = __toESM(require_InlineWorkers(), 1); var PolylineCommon_default = "void clipLineSegmentToNearPlane(\n vec3 p0,\n vec3 p1,\n out vec4 positionWC,\n out bool clipped,\n out bool culledByNearPlane,\n out vec4 clippedPositionEC)\n{\n culledByNearPlane = false;\n clipped = false;\n\n vec3 p0ToP1 = p1 - p0;\n float magnitude = length(p0ToP1);\n vec3 direction = normalize(p0ToP1);\n\n // Distance that p0 is behind the near plane. Negative means p0 is\n // in front of the near plane.\n float endPoint0Distance = czm_currentFrustum.x + p0.z;\n\n // Camera looks down -Z.\n // When moving a point along +Z: LESS VISIBLE\n // * Points in front of the camera move closer to the camera.\n // * Points behind the camrea move farther away from the camera.\n // When moving a point along -Z: MORE VISIBLE\n // * Points in front of the camera move farther away from the camera.\n // * Points behind the camera move closer to the camera.\n\n // Positive denominator: -Z, becoming more visible\n // Negative denominator: +Z, becoming less visible\n // Nearly zero: parallel to near plane\n float denominator = -direction.z;\n\n if (endPoint0Distance > 0.0 && abs(denominator) < czm_epsilon7)\n {\n // p0 is behind the near plane and the line to p1 is nearly parallel to\n // the near plane, so cull the segment completely.\n culledByNearPlane = true;\n }\n else if (endPoint0Distance > 0.0)\n {\n // p0 is behind the near plane, and the line to p1 is moving distinctly\n // toward or away from it.\n\n // t = (-plane distance - dot(plane normal, ray origin)) / dot(plane normal, ray direction)\n float t = endPoint0Distance / denominator;\n if (t < 0.0 || t > magnitude)\n {\n // Near plane intersection is not between the two points.\n // We already confirmed p0 is behind the naer plane, so now\n // we know the entire segment is behind it.\n culledByNearPlane = true;\n }\n else\n {\n // Segment crosses the near plane, update p0 to lie exactly on it.\n p0 = p0 + t * direction;\n\n // Numerical noise might put us a bit on the wrong side of the near plane.\n // Don't let that happen.\n p0.z = min(p0.z, -czm_currentFrustum.x);\n\n clipped = true;\n }\n }\n\n clippedPositionEC = vec4(p0, 1.0);\n positionWC = czm_eyeToWindowCoordinates(clippedPositionEC);\n}\n\nvec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, float expandDirection, float width, bool usePrevious, out float angle)\n{\n // expandDirection +1 is to the _left_ when looking from positionEC toward nextEC.\n\n#ifdef POLYLINE_DASH\n // Compute the window coordinates of the points.\n vec4 positionWindow = czm_eyeToWindowCoordinates(positionEC);\n vec4 previousWindow = czm_eyeToWindowCoordinates(prevEC);\n vec4 nextWindow = czm_eyeToWindowCoordinates(nextEC);\n\n // Determine the relative screen space direction of the line.\n vec2 lineDir;\n if (usePrevious) {\n lineDir = normalize(positionWindow.xy - previousWindow.xy);\n }\n else {\n lineDir = normalize(nextWindow.xy - positionWindow.xy);\n }\n angle = atan(lineDir.x, lineDir.y) - 1.570796327; // precomputed atan(1,0)\n\n // Quantize the angle so it doesn't change rapidly between segments.\n angle = floor(angle / czm_piOverFour + 0.5) * czm_piOverFour;\n#endif\n\n vec4 clippedPrevWC, clippedPrevEC;\n bool prevSegmentClipped, prevSegmentCulled;\n clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, clippedPrevWC, prevSegmentClipped, prevSegmentCulled, clippedPrevEC);\n\n vec4 clippedNextWC, clippedNextEC;\n bool nextSegmentClipped, nextSegmentCulled;\n clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, clippedNextWC, nextSegmentClipped, nextSegmentCulled, clippedNextEC);\n\n bool segmentClipped, segmentCulled;\n vec4 clippedPositionWC, clippedPositionEC;\n clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, clippedPositionWC, segmentClipped, segmentCulled, clippedPositionEC);\n\n if (segmentCulled)\n {\n return vec4(0.0, 0.0, 0.0, 1.0);\n }\n\n vec2 directionToPrevWC = normalize(clippedPrevWC.xy - clippedPositionWC.xy);\n vec2 directionToNextWC = normalize(clippedNextWC.xy - clippedPositionWC.xy);\n\n // If a segment was culled, we can't use the corresponding direction\n // computed above. We should never see both of these be true without\n // `segmentCulled` above also being true.\n if (prevSegmentCulled)\n {\n directionToPrevWC = -directionToNextWC;\n }\n else if (nextSegmentCulled)\n {\n directionToNextWC = -directionToPrevWC;\n }\n\n vec2 thisSegmentForwardWC, otherSegmentForwardWC;\n if (usePrevious)\n {\n thisSegmentForwardWC = -directionToPrevWC;\n otherSegmentForwardWC = directionToNextWC;\n }\n else\n {\n thisSegmentForwardWC = directionToNextWC;\n otherSegmentForwardWC = -directionToPrevWC;\n }\n\n vec2 thisSegmentLeftWC = vec2(-thisSegmentForwardWC.y, thisSegmentForwardWC.x);\n\n vec2 leftWC = thisSegmentLeftWC;\n float expandWidth = width * 0.5;\n\n // When lines are split at the anti-meridian, the position may be at the\n // same location as the next or previous position, and we need to handle\n // that to avoid producing NaNs.\n if (!czm_equalsEpsilon(prevEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1) && !czm_equalsEpsilon(nextEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1))\n {\n vec2 otherSegmentLeftWC = vec2(-otherSegmentForwardWC.y, otherSegmentForwardWC.x);\n\n vec2 leftSumWC = thisSegmentLeftWC + otherSegmentLeftWC;\n float leftSumLength = length(leftSumWC);\n leftWC = leftSumLength < czm_epsilon6 ? thisSegmentLeftWC : (leftSumWC / leftSumLength);\n\n // The sine of the angle between the two vectors is given by the formula\n // |a x b| = |a||b|sin(theta)\n // which is\n // float sinAngle = length(cross(vec3(leftWC, 0.0), vec3(-thisSegmentForwardWC, 0.0)));\n // Because the z components of both vectors are zero, the x and y coordinate will be zero.\n // Therefore, the sine of the angle is just the z component of the cross product.\n vec2 u = -thisSegmentForwardWC;\n vec2 v = leftWC;\n float sinAngle = abs(u.x * v.y - u.y * v.x);\n expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);\n }\n\n vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio;\n return vec4(clippedPositionWC.xy + offset, -clippedPositionWC.z, 1.0) * (czm_projection * clippedPositionEC).w;\n}\n\nvec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious, out float angle)\n{\n vec4 positionEC = czm_modelViewRelativeToEye * position;\n vec4 prevEC = czm_modelViewRelativeToEye * previous;\n vec4 nextEC = czm_modelViewRelativeToEye * next;\n return getPolylineWindowCoordinatesEC(positionEC, prevEC, nextEC, expandDirection, width, usePrevious, angle);\n}\n"; // packages/engine/Source/Scene/PolylineColorAppearance.js var defaultVertexShaderSource = `#define CLIP_POLYLINE ${PolylineCommon_default} ${PolylineColorAppearanceVS_default}`; var defaultFragmentShaderSource = PerInstanceFlatColorAppearanceFS_default; function PolylineColorAppearance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const translucent = options.translucent ?? true; const closed = false; const vertexFormat = PolylineColorAppearance.VERTEX_FORMAT; this.material = void 0; this.translucent = translucent; this._vertexShaderSource = options.vertexShaderSource ?? defaultVertexShaderSource; this._fragmentShaderSource = options.fragmentShaderSource ?? defaultFragmentShaderSource; this._renderState = Appearance_default.getDefaultRenderState( translucent, closed, options.renderState ); this._closed = closed; this._vertexFormat = vertexFormat; } Object.defineProperties(PolylineColorAppearance.prototype, { /** * The GLSL source code for the vertex shader. * * @memberof PolylineColorAppearance.prototype * * @type {string} * @readonly */ vertexShaderSource: { get: function() { return this._vertexShaderSource; } }, /** * The GLSL source code for the fragment shader. * * @memberof PolylineColorAppearance.prototype * * @type {string} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, /** * The WebGL fixed-function state to use when rendering the geometry. *

* The render state can be explicitly defined when constructing a {@link PolylineColorAppearance} * instance, or it is set implicitly via {@link PolylineColorAppearance#translucent}. *

* * @memberof PolylineColorAppearance.prototype * * @type {object} * @readonly */ renderState: { get: function() { return this._renderState; } }, /** * When true, the geometry is expected to be closed so * {@link PolylineColorAppearance#renderState} has backface culling enabled. * This is always false for PolylineColorAppearance. * * @memberof PolylineColorAppearance.prototype * * @type {boolean} * @readonly * * @default false */ closed: { get: function() { return this._closed; } }, /** * The {@link VertexFormat} that this appearance instance is compatible with. * A geometry can have more vertex attributes and still be compatible - at a * potential performance cost - but it can't have less. * * @memberof PolylineColorAppearance.prototype * * @type VertexFormat * @readonly * * @default {@link PolylineColorAppearance.VERTEX_FORMAT} */ vertexFormat: { get: function() { return this._vertexFormat; } } }); PolylineColorAppearance.VERTEX_FORMAT = VertexFormat_default.POSITION_ONLY; PolylineColorAppearance.prototype.getFragmentShaderSource = Appearance_default.prototype.getFragmentShaderSource; PolylineColorAppearance.prototype.isTranslucent = Appearance_default.prototype.isTranslucent; PolylineColorAppearance.prototype.getRenderState = Appearance_default.prototype.getRenderState; var PolylineColorAppearance_default = PolylineColorAppearance; // packages/engine/Source/Scene/PolylineMaterialAppearance.js var import_InlineWorkers398 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Shaders/Appearances/PolylineMaterialAppearanceVS.js var import_InlineWorkers396 = __toESM(require_InlineWorkers(), 1); var PolylineMaterialAppearanceVS_default = "in vec3 position3DHigh;\nin vec3 position3DLow;\nin vec3 prevPosition3DHigh;\nin vec3 prevPosition3DLow;\nin vec3 nextPosition3DHigh;\nin vec3 nextPosition3DLow;\nin vec2 expandAndWidth;\nin vec2 st;\nin float batchId;\n\nout float v_width;\nout vec2 v_st;\nout float v_polylineAngle;\n\nvoid main()\n{\n float expandDir = expandAndWidth.x;\n float width = abs(expandAndWidth.y) + 0.5;\n bool usePrev = expandAndWidth.y < 0.0;\n\n vec4 p = czm_computePosition();\n vec4 prev = czm_computePrevPosition();\n vec4 next = czm_computeNextPosition();\n\n float angle;\n vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle);\n gl_Position = czm_viewportOrthographic * positionWC;\n\n v_width = width;\n v_st.s = st.s;\n v_st.t = czm_writeNonPerspective(st.t, gl_Position.w);\n v_polylineAngle = angle;\n}\n"; // packages/engine/Source/Shaders/PolylineFS.js var import_InlineWorkers397 = __toESM(require_InlineWorkers(), 1); var PolylineFS_default = "#ifdef VECTOR_TILE\nuniform vec4 u_highlightColor;\n#endif\n\nin vec2 v_st;\n\nvoid main()\n{\n czm_materialInput materialInput;\n\n vec2 st = v_st;\n st.t = czm_readNonPerspective(st.t, gl_FragCoord.w);\n\n materialInput.s = st.s;\n materialInput.st = st;\n materialInput.str = vec3(st, 0.0);\n\n czm_material material = czm_getMaterial(materialInput);\n out_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n#ifdef VECTOR_TILE\n out_FragColor *= u_highlightColor;\n#endif\n\n czm_writeLogDepth();\n}\n"; // packages/engine/Source/Scene/PolylineMaterialAppearance.js var defaultVertexShaderSource2 = `#define CLIP_POLYLINE ${PolylineCommon_default} ${PolylineMaterialAppearanceVS_default}`; var defaultFragmentShaderSource2 = PolylineFS_default; function PolylineMaterialAppearance(options) { options = options ?? Frozen_default.EMPTY_OBJECT; const translucent = options.translucent ?? true; const closed = false; const vertexFormat = PolylineMaterialAppearance.VERTEX_FORMAT; this.material = defined_default(options.material) ? options.material : Material_default.fromType(Material_default.ColorType); this.translucent = translucent; this._vertexShaderSource = options.vertexShaderSource ?? defaultVertexShaderSource2; this._fragmentShaderSource = options.fragmentShaderSource ?? defaultFragmentShaderSource2; this._renderState = Appearance_default.getDefaultRenderState( translucent, closed, options.renderState ); this._closed = closed; this._vertexFormat = vertexFormat; } Object.defineProperties(PolylineMaterialAppearance.prototype, { /** * The GLSL source code for the vertex shader. * * @memberof PolylineMaterialAppearance.prototype * * @type {string} * @readonly */ vertexShaderSource: { get: function() { let vs = this._vertexShaderSource; if (this.material.shaderSource.search(/in\s+float\s+v_polylineAngle;/g) !== -1) { vs = `#define POLYLINE_DASH ${vs}`; } return vs; } }, /** * The GLSL source code for the fragment shader. * * @memberof PolylineMaterialAppearance.prototype * * @type {string} * @readonly */ fragmentShaderSource: { get: function() { return this._fragmentShaderSource; } }, /** * The WebGL fixed-function state to use when rendering the geometry. *

* The render state can be explicitly defined when constructing a {@link PolylineMaterialAppearance} * instance, or it is set implicitly via {@link PolylineMaterialAppearance#translucent} * and {@link PolylineMaterialAppearance#closed}. *

* * @memberof PolylineMaterialAppearance.prototype * * @type {object} * @readonly */ renderState: { get: function() { return this._renderState; } }, /** * When true, the geometry is expected to be closed so * {@link PolylineMaterialAppearance#renderState} has backface culling enabled. * This is always false for PolylineMaterialAppearance. * * @memberof PolylineMaterialAppearance.prototype * * @type {boolean} * @readonly * * @default false */ closed: { get: function() { return this._closed; } }, /** * The {@link VertexFormat} that this appearance instance is compatible with. * A geometry can have more vertex attributes and still be compatible - at a * potential performance cost - but it can't have less. * * @memberof PolylineMaterialAppearance.prototype * * @type VertexFormat * @readonly * * @default {@link PolylineMaterialAppearance.VERTEX_FORMAT} */ vertexFormat: { get: function() { return this._vertexFormat; } } }); PolylineMaterialAppearance.VERTEX_FORMAT = VertexFormat_default.POSITION_AND_ST; PolylineMaterialAppearance.prototype.getFragmentShaderSource = Appearance_default.prototype.getFragmentShaderSource; PolylineMaterialAppearance.prototype.isTranslucent = Appearance_default.prototype.isTranslucent; PolylineMaterialAppearance.prototype.getRenderState = Appearance_default.prototype.getRenderState; var PolylineMaterialAppearance_default = PolylineMaterialAppearance; // packages/engine/Source/Scene/GroundPolylinePrimitive.js function GroundPolylinePrimitive(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this.geometryInstances = options.geometryInstances; this._hasPerInstanceColors = true; let appearance = options.appearance; if (!defined_default(appearance)) { appearance = new PolylineMaterialAppearance_default(); } this.appearance = appearance; this.show = options.show ?? true; this.classificationType = options.classificationType ?? ClassificationType_default.BOTH; this.debugShowBoundingVolume = options.debugShowBoundingVolume ?? false; this._debugShowShadowVolume = options.debugShowShadowVolume ?? false; this._primitiveOptions = { geometryInstances: void 0, appearance: void 0, vertexCacheOptimize: false, interleave: options.interleave ?? false, releaseGeometryInstances: options.releaseGeometryInstances ?? true, allowPicking: options.allowPicking ?? true, asynchronous: options.asynchronous ?? true, compressVertices: false, _createShaderProgramFunction: void 0, _createCommandsFunction: void 0, _updateAndQueueCommandsFunction: void 0 }; this._zIndex = void 0; this._ready = false; this._primitive = void 0; this._sp = void 0; this._sp2D = void 0; this._spMorph = void 0; this._renderState = getRenderState(false); this._renderState3DTiles = getRenderState(true); this._renderStateMorph = RenderState_default.fromCache({ cull: { enabled: true, face: CullFace_default.FRONT // Geometry is "inverted," so cull front when materials on volume instead of on terrain (morph) }, depthTest: { enabled: true }, blending: BlendingState_default.PRE_MULTIPLIED_ALPHA_BLEND, depthMask: false }); } Object.defineProperties(GroundPolylinePrimitive.prototype, { /** * Determines if geometry vertex attributes are interleaved, which can slightly improve rendering performance. * * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly * * @default false */ interleave: { get: function() { return this._primitiveOptions.interleave; } }, /** * When true, the primitive does not keep a reference to the input geometryInstances to save memory. * * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly * * @default true */ releaseGeometryInstances: { get: function() { return this._primitiveOptions.releaseGeometryInstances; } }, /** * When true, each geometry instance will only be pickable with {@link Scene#pick}. When false, GPU memory is saved. * * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly * * @default true */ allowPicking: { get: function() { return this._primitiveOptions.allowPicking; } }, /** * Determines if the geometry instances will be created and batched on a web worker. * * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly * * @default true */ asynchronous: { get: function() { return this._primitiveOptions.asynchronous; } }, /** * Determines if the primitive is complete and ready to render. If this property is * true, the primitive will be rendered the next time that {@link GroundPolylinePrimitive#update} * is called. * * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly */ ready: { get: function() { return this._ready; } }, /** * This property is for debugging only; it is not for production use nor is it optimized. *

* If true, draws the shadow volume for each geometry in the primitive. *

* * @memberof GroundPolylinePrimitive.prototype * * @type {boolean} * @readonly * * @default false */ debugShowShadowVolume: { get: function() { return this._debugShowShadowVolume; } } }); GroundPolylinePrimitive.initializeTerrainHeights = function() { return ApproximateTerrainHeights_default.initialize(); }; function createShaderProgram3(groundPolylinePrimitive, frameState, appearance) { const context = frameState.context; const primitive = groundPolylinePrimitive._primitive; const attributeLocations8 = primitive._attributeLocations; let vs = primitive._batchTable.getVertexShaderCallback()( PolylineShadowVolumeVS_default ); vs = Primitive_default._appendShowToShader(primitive, vs); vs = Primitive_default._appendDistanceDisplayConditionToShader(primitive, vs); vs = Primitive_default._modifyShaderPosition( groundPolylinePrimitive, vs, frameState.scene3DOnly ); let vsMorph = primitive._batchTable.getVertexShaderCallback()( PolylineShadowVolumeMorphVS_default ); vsMorph = Primitive_default._appendShowToShader(primitive, vsMorph); vsMorph = Primitive_default._appendDistanceDisplayConditionToShader( primitive, vsMorph ); vsMorph = Primitive_default._modifyShaderPosition( groundPolylinePrimitive, vsMorph, frameState.scene3DOnly ); let fs = primitive._batchTable.getVertexShaderCallback()( PolylineShadowVolumeFS_default ); const vsDefines = [ `GLOBE_MINIMUM_ALTITUDE ${frameState.mapProjection.ellipsoid.minimumRadius.toFixed( 1 )}` ]; let colorDefine = ""; let materialShaderSource = ""; if (defined_default(appearance.material)) { materialShaderSource = defined_default(appearance.material) ? appearance.material.shaderSource : ""; if (materialShaderSource.search(/in\s+float\s+v_polylineAngle;/g) !== -1) { vsDefines.push("ANGLE_VARYING"); } if (materialShaderSource.search(/in\s+float\s+v_width;/g) !== -1) { vsDefines.push("WIDTH_VARYING"); } } else { colorDefine = "PER_INSTANCE_COLOR"; } vsDefines.push(colorDefine); const fsDefines = groundPolylinePrimitive.debugShowShadowVolume ? ["DEBUG_SHOW_VOLUME", colorDefine] : [colorDefine]; const vsColor3D = new ShaderSource_default({ defines: vsDefines, sources: [vs] }); const fsColor3D = new ShaderSource_default({ defines: fsDefines, sources: [materialShaderSource, fs] }); groundPolylinePrimitive._sp = ShaderProgram_default.replaceCache({ context, shaderProgram: primitive._sp, vertexShaderSource: vsColor3D, fragmentShaderSource: fsColor3D, attributeLocations: attributeLocations8 }); let colorProgram2D = context.shaderCache.getDerivedShaderProgram( groundPolylinePrimitive._sp, "2dColor" ); if (!defined_default(colorProgram2D)) { const vsColor2D = new ShaderSource_default({ defines: vsDefines.concat(["COLUMBUS_VIEW_2D"]), sources: [vs] }); colorProgram2D = context.shaderCache.createDerivedShaderProgram( groundPolylinePrimitive._sp, "2dColor", { context, shaderProgram: groundPolylinePrimitive._sp2D, vertexShaderSource: vsColor2D, fragmentShaderSource: fsColor3D, attributeLocations: attributeLocations8 } ); } groundPolylinePrimitive._sp2D = colorProgram2D; let colorProgramMorph = context.shaderCache.getDerivedShaderProgram( groundPolylinePrimitive._sp, "MorphColor" ); if (!defined_default(colorProgramMorph)) { const vsColorMorph = new ShaderSource_default({ defines: vsDefines.concat([ `MAX_TERRAIN_HEIGHT ${ApproximateTerrainHeights_default._defaultMaxTerrainHeight.toFixed( 1 )}` ]), sources: [vsMorph] }); fs = primitive._batchTable.getVertexShaderCallback()( PolylineShadowVolumeMorphFS_default ); const fsColorMorph = new ShaderSource_default({ defines: fsDefines, sources: [materialShaderSource, fs] }); colorProgramMorph = context.shaderCache.createDerivedShaderProgram( groundPolylinePrimitive._sp, "MorphColor", { context, shaderProgram: groundPolylinePrimitive._spMorph, vertexShaderSource: vsColorMorph, fragmentShaderSource: fsColorMorph, attributeLocations: attributeLocations8 } ); } groundPolylinePrimitive._spMorph = colorProgramMorph; } function getRenderState(mask3DTiles) { return RenderState_default.fromCache({ cull: { enabled: true // prevent double-draw. Geometry is "inverted" (reversed winding order) so we're drawing backfaces. }, blending: BlendingState_default.PRE_MULTIPLIED_ALPHA_BLEND, depthMask: false, stencilTest: { enabled: mask3DTiles, frontFunction: StencilFunction_default.EQUAL, frontOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.KEEP, zPass: StencilOperation_default.KEEP }, backFunction: StencilFunction_default.EQUAL, backOperation: { fail: StencilOperation_default.KEEP, zFail: StencilOperation_default.KEEP, zPass: StencilOperation_default.KEEP }, reference: StencilConstants_default.CESIUM_3D_TILE_MASK, mask: StencilConstants_default.CESIUM_3D_TILE_MASK } }); } function createCommands3(groundPolylinePrimitive, appearance, material4, translucent, colorCommands, pickCommands) { const primitive = groundPolylinePrimitive._primitive; const length2 = primitive._va.length; colorCommands.length = length2; pickCommands.length = length2; const isPolylineColorAppearance = appearance instanceof PolylineColorAppearance_default; const materialUniforms = isPolylineColorAppearance ? {} : material4._uniforms; const uniformMap2 = primitive._batchTable.getUniformMapCallback()(materialUniforms); for (let i = 0; i < length2; i++) { const vertexArray = primitive._va[i]; let command = colorCommands[i]; if (!defined_default(command)) { command = colorCommands[i] = new DrawCommand_default({ owner: groundPolylinePrimitive, primitiveType: primitive._primitiveType }); } command.vertexArray = vertexArray; command.renderState = groundPolylinePrimitive._renderState; command.shaderProgram = groundPolylinePrimitive._sp; command.uniformMap = uniformMap2; command.pass = Pass_default.TERRAIN_CLASSIFICATION; command.pickId = "czm_batchTable_pickColor(v_endPlaneNormalEcAndBatchId.w)"; const derivedTilesetCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.tileset ); derivedTilesetCommand.renderState = groundPolylinePrimitive._renderState3DTiles; derivedTilesetCommand.pass = Pass_default.CESIUM_3D_TILE_CLASSIFICATION; command.derivedCommands.tileset = derivedTilesetCommand; const derived2DCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.color2D ); derived2DCommand.shaderProgram = groundPolylinePrimitive._sp2D; command.derivedCommands.color2D = derived2DCommand; const derived2DTilesetCommand = DrawCommand_default.shallowClone( derivedTilesetCommand, derivedTilesetCommand.derivedCommands.color2D ); derived2DTilesetCommand.shaderProgram = groundPolylinePrimitive._sp2D; derivedTilesetCommand.derivedCommands.color2D = derived2DTilesetCommand; const derivedMorphCommand = DrawCommand_default.shallowClone( command, command.derivedCommands.colorMorph ); derivedMorphCommand.renderState = groundPolylinePrimitive._renderStateMorph; derivedMorphCommand.shaderProgram = groundPolylinePrimitive._spMorph; derivedMorphCommand.pickId = "czm_batchTable_pickColor(v_batchId)"; command.derivedCommands.colorMorph = derivedMorphCommand; } } function updateAndQueueCommand(groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2) { if (frameState.mode === SceneMode_default.MORPHING) { command = command.derivedCommands.colorMorph; } else if (frameState.mode !== SceneMode_default.SCENE3D) { command = command.derivedCommands.color2D; } command.modelMatrix = modelMatrix; command.boundingVolume = boundingVolume; command.cull = cull; command.debugShowBoundingVolume = debugShowBoundingVolume2; frameState.commandList.push(command); } function updateAndQueueCommands4(groundPolylinePrimitive, frameState, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2) { const primitive = groundPolylinePrimitive._primitive; Primitive_default._updateBoundingVolumes(primitive, frameState, modelMatrix); let boundingSpheres; if (frameState.mode === SceneMode_default.SCENE3D) { boundingSpheres = primitive._boundingSphereWC; } else if (frameState.mode === SceneMode_default.COLUMBUS_VIEW) { boundingSpheres = primitive._boundingSphereCV; } else if (frameState.mode === SceneMode_default.SCENE2D && defined_default(primitive._boundingSphere2D)) { boundingSpheres = primitive._boundingSphere2D; } else if (defined_default(primitive._boundingSphereMorph)) { boundingSpheres = primitive._boundingSphereMorph; } const morphing = frameState.mode === SceneMode_default.MORPHING; const classificationType = groundPolylinePrimitive.classificationType; const queueTerrainCommands = classificationType !== ClassificationType_default.CESIUM_3D_TILE; const queue3DTilesCommands = classificationType !== ClassificationType_default.TERRAIN && !morphing; let command; const passes = frameState.passes; if (passes.render || passes.pick && primitive.allowPicking) { const colorLength = colorCommands.length; for (let j = 0; j < colorLength; ++j) { const boundingVolume = boundingSpheres[j]; if (queueTerrainCommands) { command = colorCommands[j]; updateAndQueueCommand( groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } if (queue3DTilesCommands) { command = colorCommands[j].derivedCommands.tileset; updateAndQueueCommand( groundPolylinePrimitive, command, frameState, modelMatrix, cull, boundingVolume, debugShowBoundingVolume2 ); } } } } GroundPolylinePrimitive.prototype.update = function(frameState) { if (!defined_default(this._primitive) && !defined_default(this.geometryInstances)) { return; } if (!ApproximateTerrainHeights_default.initialized) { if (!this.asynchronous) { throw new DeveloperError_default( "For synchronous GroundPolylinePrimitives, you must call GroundPolylinePrimitives.initializeTerrainHeights() and wait for the returned promise to resolve." ); } GroundPolylinePrimitive.initializeTerrainHeights(); return; } let i; const that = this; const primitiveOptions = this._primitiveOptions; if (!defined_default(this._primitive)) { const geometryInstances = Array.isArray(this.geometryInstances) ? this.geometryInstances : [this.geometryInstances]; const geometryInstancesLength = geometryInstances.length; const groundInstances = new Array(geometryInstancesLength); let attributes; for (i = 0; i < geometryInstancesLength; ++i) { attributes = geometryInstances[i].attributes; if (!defined_default(attributes) || !defined_default(attributes.color)) { this._hasPerInstanceColors = false; break; } } for (i = 0; i < geometryInstancesLength; ++i) { const geometryInstance = geometryInstances[i]; attributes = {}; const instanceAttributes = geometryInstance.attributes; for (const attributeKey in instanceAttributes) { if (instanceAttributes.hasOwnProperty(attributeKey)) { attributes[attributeKey] = instanceAttributes[attributeKey]; } } if (!defined_default(attributes.width)) { attributes.width = new GeometryInstanceAttribute_default({ componentDatatype: ComponentDatatype_default.UNSIGNED_BYTE, componentsPerAttribute: 1, value: [geometryInstance.geometry.width] }); } geometryInstance.geometry._scene3DOnly = frameState.scene3DOnly; GroundPolylineGeometry_default.setProjectionAndEllipsoid( geometryInstance.geometry, frameState.mapProjection ); groundInstances[i] = new GeometryInstance_default({ geometry: geometryInstance.geometry, attributes, id: geometryInstance.id, pickPrimitive: that }); } primitiveOptions.geometryInstances = groundInstances; primitiveOptions.appearance = this.appearance; primitiveOptions._createShaderProgramFunction = function(primitive, frameState2, appearance) { createShaderProgram3(that, frameState2, appearance); }; primitiveOptions._createCommandsFunction = function(primitive, appearance, material4, translucent, twoPasses, colorCommands, pickCommands) { createCommands3( that, appearance, material4, translucent, colorCommands, pickCommands ); }; primitiveOptions._updateAndQueueCommandsFunction = function(primitive, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2, twoPasses) { updateAndQueueCommands4( that, frameState2, colorCommands, pickCommands, modelMatrix, cull, debugShowBoundingVolume2 ); }; this._primitive = new Primitive_default(primitiveOptions); } if (this.appearance instanceof PolylineColorAppearance_default && !this._hasPerInstanceColors) { throw new DeveloperError_default( "All GeometryInstances must have color attributes to use PolylineColorAppearance with GroundPolylinePrimitive." ); } this._primitive.appearance = this.appearance; this._primitive.show = this.show; this._primitive.debugShowBoundingVolume = this.debugShowBoundingVolume; this._primitive.update(frameState); frameState.afterRender.push(() => { if (!this._ready && defined_default(this._primitive) && this._primitive.ready) { this._ready = true; if (this.releaseGeometryInstances) { this.geometryInstances = void 0; } } }); }; GroundPolylinePrimitive.prototype.getGeometryInstanceAttributes = function(id) { if (!defined_default(this._primitive)) { throw new DeveloperError_default( "must call update before calling getGeometryInstanceAttributes" ); } return this._primitive.getGeometryInstanceAttributes(id); }; GroundPolylinePrimitive.isSupported = function(scene) { return scene.frameState.context.depthTexture; }; GroundPolylinePrimitive.prototype.isDestroyed = function() { return false; }; GroundPolylinePrimitive.prototype.destroy = function() { this._primitive = this._primitive && this._primitive.destroy(); this._sp = this._sp && this._sp.destroy(); this._sp2D = void 0; this._spMorph = void 0; return destroyObject_default(this); }; var GroundPolylinePrimitive_default = GroundPolylinePrimitive; // packages/engine/Source/DataSources/BoxGraphics.js var import_InlineWorkers402 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/createMaterialPropertyDescriptor.js var import_InlineWorkers401 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/ImageMaterialProperty.js var import_InlineWorkers400 = __toESM(require_InlineWorkers(), 1); var defaultRepeat = new Cartesian2_default(1, 1); var defaultTransparent = false; var defaultColor2 = Color_default.WHITE; function ImageMaterialProperty(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._definitionChanged = new Event_default(); this._image = void 0; this._imageSubscription = void 0; this._repeat = void 0; this._repeatSubscription = void 0; this._color = void 0; this._colorSubscription = void 0; this._transparent = void 0; this._transparentSubscription = void 0; this.image = options.image; this.repeat = options.repeat; this.color = options.color; this.transparent = options.transparent; } Object.defineProperties(ImageMaterialProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof ImageMaterialProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return Property_default.isConstant(this._image) && Property_default.isConstant(this._repeat); } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof ImageMaterialProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the Property specifying Image, URL, Canvas, or Video to use. * @memberof ImageMaterialProperty.prototype * @type {Property|undefined} */ image: createPropertyDescriptor_default("image"), /** * Gets or sets the {@link Cartesian2} Property specifying the number of times the image repeats in each direction. * @memberof ImageMaterialProperty.prototype * @type {Property|undefined} * @default new Cartesian2(1, 1) */ repeat: createPropertyDescriptor_default("repeat"), /** * Gets or sets the Color Property specifying the desired color applied to the image. * @memberof ImageMaterialProperty.prototype * @type {Property|undefined} * @default 1.0 */ color: createPropertyDescriptor_default("color"), /** * Gets or sets the Boolean Property specifying whether the image has transparency * @memberof ImageMaterialProperty.prototype * @type {Property|undefined} * @default 1.0 */ transparent: createPropertyDescriptor_default("transparent") }); ImageMaterialProperty.prototype.getType = function(time) { return "Image"; }; var timeScratch3 = new JulianDate_default(); ImageMaterialProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch3); } if (!defined_default(result)) { result = {}; } result.image = Property_default.getValueOrUndefined(this._image, time); result.repeat = Property_default.getValueOrClonedDefault( this._repeat, time, defaultRepeat, result.repeat ); result.color = Property_default.getValueOrClonedDefault( this._color, time, defaultColor2, result.color ); if (Property_default.getValueOrDefault(this._transparent, time, defaultTransparent)) { result.color.alpha = Math.min(0.99, result.color.alpha); } return result; }; ImageMaterialProperty.prototype.equals = function(other) { return this === other || other instanceof ImageMaterialProperty && Property_default.equals(this._image, other._image) && Property_default.equals(this._repeat, other._repeat) && Property_default.equals(this._color, other._color) && Property_default.equals(this._transparent, other._transparent); }; var ImageMaterialProperty_default = ImageMaterialProperty; // packages/engine/Source/DataSources/createMaterialPropertyDescriptor.js function createMaterialProperty(value) { if (value instanceof Color_default) { return new ColorMaterialProperty_default(value); } if (typeof value === "string" || value instanceof Resource_default || value instanceof HTMLCanvasElement || value instanceof HTMLVideoElement) { const result = new ImageMaterialProperty_default(); result.image = value; return result; } throw new DeveloperError_default(`Unable to infer material type: ${value}`); } function createMaterialPropertyDescriptor(name, configurable) { return createPropertyDescriptor_default(name, configurable, createMaterialProperty); } var createMaterialPropertyDescriptor_default = createMaterialPropertyDescriptor; // packages/engine/Source/DataSources/BoxGraphics.js function BoxGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._dimensions = void 0; this._dimensionsSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(BoxGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof BoxGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the box. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets {@link Cartesian3} Property property specifying the length, width, and height of the box. * @memberof BoxGraphics.prototype * @type {Property|undefined} */ dimensions: createPropertyDescriptor_default("dimensions"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the boolean Property specifying whether the box is filled with the provided material. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the material used to fill the box. * @memberof BoxGraphics.prototype * @type {MaterialProperty|undefined} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the box is outlined. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof BoxGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the box * casts or receives shadows from light sources. * @memberof BoxGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this box will be displayed. * @memberof BoxGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); BoxGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new BoxGraphics(this); } result.show = this.show; result.dimensions = this.dimensions; result.heightReference = this.heightReference; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; BoxGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.dimensions = this.dimensions ?? source.dimensions; this.heightReference = this.heightReference ?? source.heightReference; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var BoxGraphics_default = BoxGraphics; // packages/engine/Source/DataSources/ConstantPositionProperty.js var import_InlineWorkers405 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/ReferenceFrame.js var import_InlineWorkers403 = __toESM(require_InlineWorkers(), 1); var ReferenceFrame = { /** * The fixed frame. * * @type {number} * @constant */ FIXED: 0, /** * The inertial frame. * * @type {number} * @constant */ INERTIAL: 1 }; Object.freeze(ReferenceFrame); var ReferenceFrame_default = ReferenceFrame; // packages/engine/Source/DataSources/PositionProperty.js var import_InlineWorkers404 = __toESM(require_InlineWorkers(), 1); function PositionProperty() { DeveloperError_default.throwInstantiationError(); } Object.defineProperties(PositionProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof PositionProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: DeveloperError_default.throwInstantiationError }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof PositionProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: DeveloperError_default.throwInstantiationError }, /** * Gets the reference frame that the position is defined in. * @memberof PositionProperty.prototype * @type {ReferenceFrame} */ referenceFrame: { get: DeveloperError_default.throwInstantiationError } }); PositionProperty.prototype.getValue = DeveloperError_default.throwInstantiationError; PositionProperty.prototype.getValueInReferenceFrame = DeveloperError_default.throwInstantiationError; PositionProperty.prototype.equals = DeveloperError_default.throwInstantiationError; var scratchMatrix3 = new Matrix3_default(); PositionProperty.convertToReferenceFrame = function(time, value, inputFrame, outputFrame, result) { if (!defined_default(value)) { return value; } if (!defined_default(result)) { result = new Cartesian3_default(); } if (inputFrame === outputFrame) { return Cartesian3_default.clone(value, result); } const icrfToFixed2 = Transforms_default.computeIcrfToCentralBodyFixedMatrix( time, scratchMatrix3 ); if (inputFrame === ReferenceFrame_default.INERTIAL) { return Matrix3_default.multiplyByVector(icrfToFixed2, value, result); } if (inputFrame === ReferenceFrame_default.FIXED) { return Matrix3_default.multiplyByVector( Matrix3_default.transpose(icrfToFixed2, scratchMatrix3), value, result ); } }; var PositionProperty_default = PositionProperty; // packages/engine/Source/DataSources/ConstantPositionProperty.js function ConstantPositionProperty(value, referenceFrame) { this._definitionChanged = new Event_default(); this._value = Cartesian3_default.clone(value); this._referenceFrame = referenceFrame ?? ReferenceFrame_default.FIXED; } Object.defineProperties(ConstantPositionProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof ConstantPositionProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return !defined_default(this._value) || this._referenceFrame === ReferenceFrame_default.FIXED; } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof ConstantPositionProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets the reference frame in which the position is defined. * @memberof ConstantPositionProperty.prototype * @type {ReferenceFrame} * @default ReferenceFrame.FIXED; */ referenceFrame: { get: function() { return this._referenceFrame; } } }); var timeScratch4 = new JulianDate_default(); ConstantPositionProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch4); } return this.getValueInReferenceFrame(time, ReferenceFrame_default.FIXED, result); }; ConstantPositionProperty.prototype.setValue = function(value, referenceFrame) { let definitionChanged = false; if (!Cartesian3_default.equals(this._value, value)) { definitionChanged = true; this._value = Cartesian3_default.clone(value); } if (defined_default(referenceFrame) && this._referenceFrame !== referenceFrame) { definitionChanged = true; this._referenceFrame = referenceFrame; } if (definitionChanged) { this._definitionChanged.raiseEvent(this); } }; ConstantPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) { if (!defined_default(time)) { throw new DeveloperError_default("time is required."); } if (!defined_default(referenceFrame)) { throw new DeveloperError_default("referenceFrame is required."); } return PositionProperty_default.convertToReferenceFrame( time, this._value, this._referenceFrame, referenceFrame, result ); }; ConstantPositionProperty.prototype.equals = function(other) { return this === other || other instanceof ConstantPositionProperty && Cartesian3_default.equals(this._value, other._value) && this._referenceFrame === other._referenceFrame; }; var ConstantPositionProperty_default = ConstantPositionProperty; // packages/engine/Source/DataSources/CorridorGraphics.js var import_InlineWorkers406 = __toESM(require_InlineWorkers(), 1); function CorridorGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._positions = void 0; this._positionsSubscription = void 0; this._width = void 0; this._widthSubscription = void 0; this._height = void 0; this._heightSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._extrudedHeight = void 0; this._extrudedHeightSubscription = void 0; this._extrudedHeightReference = void 0; this._extrudedHeightReferenceSubscription = void 0; this._cornerType = void 0; this._cornerTypeSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._classificationType = void 0; this._classificationTypeSubscription = void 0; this._zIndex = void 0; this._zIndexSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(CorridorGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof CorridorGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the corridor. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets a Property specifying the array of {@link Cartesian3} positions that define the centerline of the corridor. * @memberof CorridorGraphics.prototype * @type {Property|undefined} */ positions: createPropertyDescriptor_default("positions"), /** * Gets or sets the numeric Property specifying the width of the outline. * @memberof CorridorGraphics.prototype * @type {Property|undefined} */ width: createPropertyDescriptor_default("width"), /** * Gets or sets the numeric Property specifying the altitude of the corridor. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default 0.0 */ height: createPropertyDescriptor_default("height"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the numeric Property specifying the altitude of the corridor extrusion. * Setting this property creates a corridor shaped volume starting at height and ending * at this altitude. * @memberof CorridorGraphics.prototype * @type {Property|undefined} */ extrudedHeight: createPropertyDescriptor_default("extrudedHeight"), /** * Gets or sets the Property specifying the extruded {@link HeightReference}. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ extrudedHeightReference: createPropertyDescriptor_default("extrudedHeightReference"), /** * Gets or sets the {@link CornerType} Property specifying how corners are styled. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default CornerType.ROUNDED */ cornerType: createPropertyDescriptor_default("cornerType"), /** * Gets or sets the numeric Property specifying the sampling distance between each latitude and longitude point. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the corridor is filled with the provided material. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the corridor. * @memberof CorridorGraphics.prototype * @type {MaterialProperty|undefined} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the corridor is outlined. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the corridor * casts or receives shadows from light sources. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this corridor will be displayed. * @memberof CorridorGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the {@link ClassificationType} Property specifying whether this corridor will classify terrain, 3D Tiles, or both when on the ground. * @memberof CorridorGraphics.prototype * @type {Property|undefined} * @default ClassificationType.BOTH */ classificationType: createPropertyDescriptor_default("classificationType"), /** * Gets or sets the zIndex Property specifying the ordering of the corridor. Only has an effect if the coridor is static and neither height or exturdedHeight are specified. * @memberof CorridorGraphics.prototype * @type {ConstantProperty|undefined} * @default 0 */ zIndex: createPropertyDescriptor_default("zIndex") }); CorridorGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new CorridorGraphics(this); } result.show = this.show; result.positions = this.positions; result.width = this.width; result.height = this.height; result.heightReference = this.heightReference; result.extrudedHeight = this.extrudedHeight; result.extrudedHeightReference = this.extrudedHeightReference; result.cornerType = this.cornerType; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; result.classificationType = this.classificationType; result.zIndex = this.zIndex; return result; }; CorridorGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.positions = this.positions ?? source.positions; this.width = this.width ?? source.width; this.height = this.height ?? source.height; this.heightReference = this.heightReference ?? source.heightReference; this.extrudedHeight = this.extrudedHeight ?? source.extrudedHeight; this.extrudedHeightReference = this.extrudedHeightReference ?? source.extrudedHeightReference; this.cornerType = this.cornerType ?? source.cornerType; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.classificationType = this.classificationType ?? source.classificationType; this.zIndex = this.zIndex ?? source.zIndex; }; var CorridorGraphics_default = CorridorGraphics; // packages/engine/Source/DataSources/createRawPropertyDescriptor.js var import_InlineWorkers407 = __toESM(require_InlineWorkers(), 1); function createRawProperty(value) { return value; } function createRawPropertyDescriptor(name, configurable) { return createPropertyDescriptor_default(name, configurable, createRawProperty); } var createRawPropertyDescriptor_default = createRawPropertyDescriptor; // packages/engine/Source/DataSources/CylinderGraphics.js var import_InlineWorkers408 = __toESM(require_InlineWorkers(), 1); function CylinderGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._length = void 0; this._lengthSubscription = void 0; this._topRadius = void 0; this._topRadiusSubscription = void 0; this._bottomRadius = void 0; this._bottomRadiusSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._numberOfVerticalLines = void 0; this._numberOfVerticalLinesSubscription = void 0; this._slices = void 0; this._slicesSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(CylinderGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof CylinderGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the cylinder. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the numeric Property specifying the length of the cylinder. * @memberof CylinderGraphics.prototype * @type {Property|undefined} */ length: createPropertyDescriptor_default("length"), /** * Gets or sets the numeric Property specifying the radius of the top of the cylinder. * @memberof CylinderGraphics.prototype * @type {Property|undefined} */ topRadius: createPropertyDescriptor_default("topRadius"), /** * Gets or sets the numeric Property specifying the radius of the bottom of the cylinder. * @memberof CylinderGraphics.prototype * @type {Property|undefined} */ bottomRadius: createPropertyDescriptor_default("bottomRadius"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the boolean Property specifying whether the cylinder is filled with the provided material. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the cylinder. * @memberof CylinderGraphics.prototype * @type {MaterialProperty|undefined} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the boolean Property specifying whether the cylinder is outlined. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets the Property specifying the number of vertical lines to draw along the perimeter for the outline. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default 16 */ numberOfVerticalLines: createPropertyDescriptor_default("numberOfVerticalLines"), /** * Gets or sets the Property specifying the number of edges around the perimeter of the cylinder. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default 128 */ slices: createPropertyDescriptor_default("slices"), /** * Get or sets the enum Property specifying whether the cylinder * casts or receives shadows from light sources. * @memberof CylinderGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this cylinder will be displayed. * @memberof CylinderGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); CylinderGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new CylinderGraphics(this); } result.show = this.show; result.length = this.length; result.topRadius = this.topRadius; result.bottomRadius = this.bottomRadius; result.heightReference = this.heightReference; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.numberOfVerticalLines = this.numberOfVerticalLines; result.slices = this.slices; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; CylinderGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.length = this.length ?? source.length; this.topRadius = this.topRadius ?? source.topRadius; this.bottomRadius = this.bottomRadius ?? source.bottomRadius; this.heightReference = this.heightReference ?? source.heightReference; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.numberOfVerticalLines = this.numberOfVerticalLines ?? source.numberOfVerticalLines; this.slices = this.slices ?? source.slices; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var CylinderGraphics_default = CylinderGraphics; // packages/engine/Source/DataSources/EllipseGraphics.js var import_InlineWorkers409 = __toESM(require_InlineWorkers(), 1); function EllipseGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._semiMajorAxis = void 0; this._semiMajorAxisSubscription = void 0; this._semiMinorAxis = void 0; this._semiMinorAxisSubscription = void 0; this._height = void 0; this._heightSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._extrudedHeight = void 0; this._extrudedHeightSubscription = void 0; this._extrudedHeightReference = void 0; this._extrudedHeightReferenceSubscription = void 0; this._rotation = void 0; this._rotationSubscription = void 0; this._stRotation = void 0; this._stRotationSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._numberOfVerticalLines = void 0; this._numberOfVerticalLinesSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._classificationType = void 0; this._classificationTypeSubscription = void 0; this._zIndex = void 0; this._zIndexSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(EllipseGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof EllipseGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the ellipse. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the numeric Property specifying the semi-major axis. * @memberof EllipseGraphics.prototype * @type {Property|undefined} */ semiMajorAxis: createPropertyDescriptor_default("semiMajorAxis"), /** * Gets or sets the numeric Property specifying the semi-minor axis. * @memberof EllipseGraphics.prototype * @type {Property|undefined} */ semiMinorAxis: createPropertyDescriptor_default("semiMinorAxis"), /** * Gets or sets the numeric Property specifying the altitude of the ellipse. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default 0.0 */ height: createPropertyDescriptor_default("height"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the numeric Property specifying the altitude of the ellipse extrusion. * Setting this property creates volume starting at height and ending at this altitude. * @memberof EllipseGraphics.prototype * @type {Property|undefined} */ extrudedHeight: createPropertyDescriptor_default("extrudedHeight"), /** * Gets or sets the Property specifying the extruded {@link HeightReference}. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ extrudedHeightReference: createPropertyDescriptor_default("extrudedHeightReference"), /** * Gets or sets the numeric property specifying the rotation of the ellipse counter-clockwise from north. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default 0 */ rotation: createPropertyDescriptor_default("rotation"), /** * Gets or sets the numeric property specifying the rotation of the ellipse texture counter-clockwise from north. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default 0 */ stRotation: createPropertyDescriptor_default("stRotation"), /** * Gets or sets the numeric Property specifying the angular distance between points on the ellipse. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the ellipse is filled with the provided material. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the ellipse. * @memberof EllipseGraphics.prototype * @type {MaterialProperty|undefined} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the ellipse is outlined. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets the numeric Property specifying the number of vertical lines to draw along the perimeter for the outline. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default 16 */ numberOfVerticalLines: createPropertyDescriptor_default("numberOfVerticalLines"), /** * Get or sets the enum Property specifying whether the ellipse * casts or receives shadows from light sources. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this ellipse will be displayed. * @memberof EllipseGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the {@link ClassificationType} Property specifying whether this ellipse will classify terrain, 3D Tiles, or both when on the ground. * @memberof EllipseGraphics.prototype * @type {Property|undefined} * @default ClassificationType.BOTH */ classificationType: createPropertyDescriptor_default("classificationType"), /** * Gets or sets the zIndex Property specifying the ellipse ordering. Only has an effect if the ellipse is constant and neither height or extrudedHeight are specified * @memberof EllipseGraphics.prototype * @type {ConstantProperty|undefined} * @default 0 */ zIndex: createPropertyDescriptor_default("zIndex") }); EllipseGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new EllipseGraphics(this); } result.show = this.show; result.semiMajorAxis = this.semiMajorAxis; result.semiMinorAxis = this.semiMinorAxis; result.height = this.height; result.heightReference = this.heightReference; result.extrudedHeight = this.extrudedHeight; result.extrudedHeightReference = this.extrudedHeightReference; result.rotation = this.rotation; result.stRotation = this.stRotation; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.numberOfVerticalLines = this.numberOfVerticalLines; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; result.classificationType = this.classificationType; result.zIndex = this.zIndex; return result; }; EllipseGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.semiMajorAxis = this.semiMajorAxis ?? source.semiMajorAxis; this.semiMinorAxis = this.semiMinorAxis ?? source.semiMinorAxis; this.height = this.height ?? source.height; this.heightReference = this.heightReference ?? source.heightReference; this.extrudedHeight = this.extrudedHeight ?? source.extrudedHeight; this.extrudedHeightReference = this.extrudedHeightReference ?? source.extrudedHeightReference; this.rotation = this.rotation ?? source.rotation; this.stRotation = this.stRotation ?? source.stRotation; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.numberOfVerticalLines = this.numberOfVerticalLines ?? source.numberOfVerticalLines; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.classificationType = this.classificationType ?? source.classificationType; this.zIndex = this.zIndex ?? source.zIndex; }; var EllipseGraphics_default = EllipseGraphics; // packages/engine/Source/DataSources/EllipsoidGraphics.js var import_InlineWorkers410 = __toESM(require_InlineWorkers(), 1); function EllipsoidGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._radii = void 0; this._radiiSubscription = void 0; this._innerRadii = void 0; this._innerRadiiSubscription = void 0; this._minimumClock = void 0; this._minimumClockSubscription = void 0; this._maximumClock = void 0; this._maximumClockSubscription = void 0; this._minimumCone = void 0; this._minimumConeSubscription = void 0; this._maximumCone = void 0; this._maximumConeSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._stackPartitions = void 0; this._stackPartitionsSubscription = void 0; this._slicePartitions = void 0; this._slicePartitionsSubscription = void 0; this._subdivisions = void 0; this._subdivisionsSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(EllipsoidGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof EllipsoidGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the {@link Cartesian3} {@link Property} specifying the radii of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} */ radii: createPropertyDescriptor_default("radii"), /** * Gets or sets the {@link Cartesian3} {@link Property} specifying the inner radii of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default radii */ innerRadii: createPropertyDescriptor_default("innerRadii"), /** * Gets or sets the Property specifying the minimum clock angle of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 0.0 */ minimumClock: createPropertyDescriptor_default("minimumClock"), /** * Gets or sets the Property specifying the maximum clock angle of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 2*PI */ maximumClock: createPropertyDescriptor_default("maximumClock"), /** * Gets or sets the Property specifying the minimum cone angle of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 0.0 */ minimumCone: createPropertyDescriptor_default("minimumCone"), /** * Gets or sets the Property specifying the maximum cone angle of the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default PI */ maximumCone: createPropertyDescriptor_default("maximumCone"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the boolean Property specifying whether the ellipsoid is filled with the provided material. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the ellipsoid. * @memberof EllipsoidGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the ellipsoid is outlined. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets the Property specifying the number of stacks. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 64 */ stackPartitions: createPropertyDescriptor_default("stackPartitions"), /** * Gets or sets the Property specifying the number of radial slices per 360 degrees. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 64 */ slicePartitions: createPropertyDescriptor_default("slicePartitions"), /** * Gets or sets the Property specifying the number of samples per outline ring, determining the granularity of the curvature. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default 128 */ subdivisions: createPropertyDescriptor_default("subdivisions"), /** * Get or sets the enum Property specifying whether the ellipsoid * casts or receives shadows from light sources. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this ellipsoid will be displayed. * @memberof EllipsoidGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); EllipsoidGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new EllipsoidGraphics(this); } result.show = this.show; result.radii = this.radii; result.innerRadii = this.innerRadii; result.minimumClock = this.minimumClock; result.maximumClock = this.maximumClock; result.minimumCone = this.minimumCone; result.maximumCone = this.maximumCone; result.heightReference = this.heightReference; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.stackPartitions = this.stackPartitions; result.slicePartitions = this.slicePartitions; result.subdivisions = this.subdivisions; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; EllipsoidGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.radii = this.radii ?? source.radii; this.innerRadii = this.innerRadii ?? source.innerRadii; this.minimumClock = this.minimumClock ?? source.minimumClock; this.maximumClock = this.maximumClock ?? source.maximumClock; this.minimumCone = this.minimumCone ?? source.minimumCone; this.maximumCone = this.maximumCone ?? source.maximumCone; this.heightReference = this.heightReference ?? source.heightReference; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.stackPartitions = this.stackPartitions ?? source.stackPartitions; this.slicePartitions = this.slicePartitions ?? source.slicePartitions; this.subdivisions = this.subdivisions ?? source.subdivisions; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var EllipsoidGraphics_default = EllipsoidGraphics; // packages/engine/Source/DataSources/LabelGraphics.js var import_InlineWorkers411 = __toESM(require_InlineWorkers(), 1); function LabelGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._text = void 0; this._textSubscription = void 0; this._font = void 0; this._fontSubscription = void 0; this._style = void 0; this._styleSubscription = void 0; this._scale = void 0; this._scaleSubscription = void 0; this._showBackground = void 0; this._showBackgroundSubscription = void 0; this._backgroundColor = void 0; this._backgroundColorSubscription = void 0; this._backgroundPadding = void 0; this._backgroundPaddingSubscription = void 0; this._pixelOffset = void 0; this._pixelOffsetSubscription = void 0; this._eyeOffset = void 0; this._eyeOffsetSubscription = void 0; this._horizontalOrigin = void 0; this._horizontalOriginSubscription = void 0; this._verticalOrigin = void 0; this._verticalOriginSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._fillColor = void 0; this._fillColorSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._translucencyByDistance = void 0; this._translucencyByDistanceSubscription = void 0; this._pixelOffsetScaleByDistance = void 0; this._pixelOffsetScaleByDistanceSubscription = void 0; this._scaleByDistance = void 0; this._scaleByDistanceSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._disableDepthTestDistance = void 0; this._disableDepthTestDistanceSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(LabelGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof LabelGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the label. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the string Property specifying the text of the label. * Explicit newlines '\n' are supported. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ text: createPropertyDescriptor_default("text"), /** * Gets or sets the string Property specifying the font in CSS syntax. * @memberof LabelGraphics.prototype * @type {Property|undefined} * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/font|CSS font on MDN} */ font: createPropertyDescriptor_default("font"), /** * Gets or sets the Property specifying the {@link LabelStyle}. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ style: createPropertyDescriptor_default("style"), /** * Gets or sets the numeric Property specifying the uniform scale to apply to the image. * A scale greater than 1.0 enlarges the label while a scale less than 1.0 shrinks it. *

*

*
* From left to right in the above image, the scales are 0.5, 1.0, * and 2.0. *
*

* @memberof LabelGraphics.prototype * @type {Property|undefined} * @default 1.0 */ scale: createPropertyDescriptor_default("scale"), /** * Gets or sets the boolean Property specifying the visibility of the background behind the label. * @memberof LabelGraphics.prototype * @type {Property|undefined} * @default false */ showBackground: createPropertyDescriptor_default("showBackground"), /** * Gets or sets the Property specifying the background {@link Color}. * @memberof LabelGraphics.prototype * @type {Property|undefined} * @default new Color(0.165, 0.165, 0.165, 0.8) */ backgroundColor: createPropertyDescriptor_default("backgroundColor"), /** * Gets or sets the {@link Cartesian2} Property specifying the label's horizontal and vertical * background padding in pixels. * @memberof LabelGraphics.prototype * @type {Property|undefined} * @default new Cartesian2(7, 5) */ backgroundPadding: createPropertyDescriptor_default("backgroundPadding"), /** * Gets or sets the {@link Cartesian2} Property specifying the label's pixel offset in screen space * from the origin of this label. This is commonly used to align multiple labels and labels at * the same position, e.g., an image and text. The screen space origin is the top, left corner of the * canvas; x increases from left to right, and y increases from top to bottom. *

*

* * * *
default
l.pixeloffset = new Cartesian2(25, 75);
* The label's origin is indicated by the yellow point. *
*

* @memberof LabelGraphics.prototype * @type {Property|undefined} * @default Cartesian2.ZERO */ pixelOffset: createPropertyDescriptor_default("pixelOffset"), /** * Gets or sets the {@link Cartesian3} Property specifying the label's offset in eye coordinates. * Eye coordinates is a left-handed coordinate system, where x points towards the viewer's * right, y points up, and z points into the screen. *

* An eye offset is commonly used to arrange multiple labels or objects at the same position, e.g., to * arrange a label above its corresponding 3D model. *

* Below, the label is positioned at the center of the Earth but an eye offset makes it always * appear on top of the Earth regardless of the viewer's or Earth's orientation. *

*

* * * *
* l.eyeOffset = new Cartesian3(0.0, 8000000.0, 0.0);

*
*

* @memberof LabelGraphics.prototype * @type {Property|undefined} * @default Cartesian3.ZERO */ eyeOffset: createPropertyDescriptor_default("eyeOffset"), /** * Gets or sets the Property specifying the {@link HorizontalOrigin}. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ horizontalOrigin: createPropertyDescriptor_default("horizontalOrigin"), /** * Gets or sets the Property specifying the {@link VerticalOrigin}. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ verticalOrigin: createPropertyDescriptor_default("verticalOrigin"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof LabelGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the Property specifying the fill {@link Color}. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ fillColor: createPropertyDescriptor_default("fillColor"), /** * Gets or sets the Property specifying the outline {@link Color}. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the outline width. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets {@link NearFarScalar} Property specifying the translucency of the label based on the distance from the camera. * A label's translucency will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the label's translucency remains clamped to the nearest bound. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ translucencyByDistance: createPropertyDescriptor_default("translucencyByDistance"), /** * Gets or sets {@link NearFarScalar} Property specifying the pixel offset of the label based on the distance from the camera. * A label's pixel offset will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the label's pixel offset remains clamped to the nearest bound. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ pixelOffsetScaleByDistance: createPropertyDescriptor_default( "pixelOffsetScaleByDistance" ), /** * Gets or sets near and far scaling properties of a Label based on the label's distance from the camera. * A label's scale will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the label's scale remains clamped to the nearest bound. If undefined, * scaleByDistance will be disabled. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ scaleByDistance: createPropertyDescriptor_default("scaleByDistance"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this label will be displayed. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the distance from the camera at which to disable the depth test to, for example, prevent clipping against terrain. * When set to zero, the depth test is always applied. When set to Number.POSITIVE_INFINITY, the depth test is never applied. * @memberof LabelGraphics.prototype * @type {Property|undefined} */ disableDepthTestDistance: createPropertyDescriptor_default( "disableDepthTestDistance" ) }); LabelGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new LabelGraphics(this); } result.show = this.show; result.text = this.text; result.font = this.font; result.style = this.style; result.scale = this.scale; result.showBackground = this.showBackground; result.backgroundColor = this.backgroundColor; result.backgroundPadding = this.backgroundPadding; result.pixelOffset = this.pixelOffset; result.eyeOffset = this.eyeOffset; result.horizontalOrigin = this.horizontalOrigin; result.verticalOrigin = this.verticalOrigin; result.heightReference = this.heightReference; result.fillColor = this.fillColor; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.translucencyByDistance = this.translucencyByDistance; result.pixelOffsetScaleByDistance = this.pixelOffsetScaleByDistance; result.scaleByDistance = this.scaleByDistance; result.distanceDisplayCondition = this.distanceDisplayCondition; result.disableDepthTestDistance = this.disableDepthTestDistance; return result; }; LabelGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.text = this.text ?? source.text; this.font = this.font ?? source.font; this.style = this.style ?? source.style; this.scale = this.scale ?? source.scale; this.showBackground = this.showBackground ?? source.showBackground; this.backgroundColor = this.backgroundColor ?? source.backgroundColor; this.backgroundPadding = this.backgroundPadding ?? source.backgroundPadding; this.pixelOffset = this.pixelOffset ?? source.pixelOffset; this.eyeOffset = this.eyeOffset ?? source.eyeOffset; this.horizontalOrigin = this.horizontalOrigin ?? source.horizontalOrigin; this.verticalOrigin = this.verticalOrigin ?? source.verticalOrigin; this.heightReference = this.heightReference ?? source.heightReference; this.fillColor = this.fillColor ?? source.fillColor; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.translucencyByDistance = this.translucencyByDistance ?? source.translucencyByDistance; this.pixelOffsetScaleByDistance = this.pixelOffsetScaleByDistance ?? source.pixelOffsetScaleByDistance; this.scaleByDistance = this.scaleByDistance ?? source.scaleByDistance; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.disableDepthTestDistance = this.disableDepthTestDistance ?? source.disableDepthTestDistance; }; var LabelGraphics_default = LabelGraphics; // packages/engine/Source/DataSources/ModelGraphics.js var import_InlineWorkers415 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/NodeTransformationProperty.js var import_InlineWorkers413 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/TranslationRotationScale.js var import_InlineWorkers412 = __toESM(require_InlineWorkers(), 1); var defaultScale2 = new Cartesian3_default(1, 1, 1); var defaultTranslation = Cartesian3_default.ZERO; var defaultRotation2 = Quaternion_default.IDENTITY; function TranslationRotationScale(translation3, rotation, scale) { this.translation = Cartesian3_default.clone(translation3 ?? defaultTranslation); this.rotation = Quaternion_default.clone(rotation ?? defaultRotation2); this.scale = Cartesian3_default.clone(scale ?? defaultScale2); } TranslationRotationScale.prototype.equals = function(right) { return this === right || defined_default(right) && Cartesian3_default.equals(this.translation, right.translation) && Quaternion_default.equals(this.rotation, right.rotation) && Cartesian3_default.equals(this.scale, right.scale); }; var TranslationRotationScale_default = TranslationRotationScale; // packages/engine/Source/DataSources/NodeTransformationProperty.js var defaultNodeTransformation = new TranslationRotationScale_default(); function NodeTransformationProperty(options) { options = options ?? Frozen_default.EMPTY_OBJECT; this._definitionChanged = new Event_default(); this._translation = void 0; this._translationSubscription = void 0; this._rotation = void 0; this._rotationSubscription = void 0; this._scale = void 0; this._scaleSubscription = void 0; this.translation = options.translation; this.rotation = options.rotation; this.scale = options.scale; } Object.defineProperties(NodeTransformationProperty.prototype, { /** * Gets a value indicating if this property is constant. A property is considered * constant if getValue always returns the same result for the current definition. * @memberof NodeTransformationProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return Property_default.isConstant(this._translation) && Property_default.isConstant(this._rotation) && Property_default.isConstant(this._scale); } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof NodeTransformationProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the {@link Cartesian3} Property specifying the (x, y, z) translation to apply to the node. * @memberof NodeTransformationProperty.prototype * @type {Property|undefined} * @default Cartesian3.ZERO */ translation: createPropertyDescriptor_default("translation"), /** * Gets or sets the {@link Quaternion} Property specifying the (x, y, z, w) rotation to apply to the node. * @memberof NodeTransformationProperty.prototype * @type {Property|undefined} * @default Quaternion.IDENTITY */ rotation: createPropertyDescriptor_default("rotation"), /** * Gets or sets the {@link Cartesian3} Property specifying the (x, y, z) scaling to apply to the node. * @memberof NodeTransformationProperty.prototype * @type {Property|undefined} * @default new Cartesian3(1.0, 1.0, 1.0) */ scale: createPropertyDescriptor_default("scale") }); var timeScratch5 = new JulianDate_default(); NodeTransformationProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch5); } if (!defined_default(result)) { result = new TranslationRotationScale_default(); } result.translation = Property_default.getValueOrClonedDefault( this._translation, time, defaultNodeTransformation.translation, result.translation ); result.rotation = Property_default.getValueOrClonedDefault( this._rotation, time, defaultNodeTransformation.rotation, result.rotation ); result.scale = Property_default.getValueOrClonedDefault( this._scale, time, defaultNodeTransformation.scale, result.scale ); return result; }; NodeTransformationProperty.prototype.equals = function(other) { return this === other || other instanceof NodeTransformationProperty && Property_default.equals(this._translation, other._translation) && Property_default.equals(this._rotation, other._rotation) && Property_default.equals(this._scale, other._scale); }; var NodeTransformationProperty_default = NodeTransformationProperty; // packages/engine/Source/DataSources/PropertyBag.js var import_InlineWorkers414 = __toESM(require_InlineWorkers(), 1); function PropertyBag(value, createPropertyCallback) { this._propertyNames = []; this._definitionChanged = new Event_default(); if (defined_default(value)) { this.merge(value, createPropertyCallback); } } Object.defineProperties(PropertyBag.prototype, { /** * Gets the names of all properties registered on this instance. * @memberof PropertyBag.prototype * @type {Array} */ propertyNames: { get: function() { return this._propertyNames; } }, /** * Gets a value indicating if this property is constant. This property * is considered constant if all property items in this object are constant. * @memberof PropertyBag.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { const propertyNames = this._propertyNames; for (let i = 0, len = propertyNames.length; i < len; i++) { if (!Property_default.isConstant(this[propertyNames[i]])) { return false; } } return true; } }, /** * Gets the event that is raised whenever the set of properties contained in this * object changes, or one of the properties itself changes. * * @memberof PropertyBag.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } } }); PropertyBag.prototype.hasProperty = function(propertyName) { return this._propertyNames.indexOf(propertyName) !== -1; }; function createConstantProperty2(value) { return new ConstantProperty_default(value); } PropertyBag.prototype.addProperty = function(propertyName, value, createPropertyCallback) { const propertyNames = this._propertyNames; if (!defined_default(propertyName)) { throw new DeveloperError_default("propertyName is required."); } if (propertyNames.indexOf(propertyName) !== -1) { throw new DeveloperError_default( `${propertyName} is already a registered property.` ); } propertyNames.push(propertyName); Object.defineProperty( this, propertyName, createPropertyDescriptor_default( propertyName, true, createPropertyCallback ?? createConstantProperty2 ) ); if (defined_default(value)) { this[propertyName] = value; } this._definitionChanged.raiseEvent(this); }; PropertyBag.prototype.removeProperty = function(propertyName) { const propertyNames = this._propertyNames; const index = propertyNames.indexOf(propertyName); if (!defined_default(propertyName)) { throw new DeveloperError_default("propertyName is required."); } if (index === -1) { throw new DeveloperError_default(`${propertyName} is not a registered property.`); } this._propertyNames.splice(index, 1); delete this[propertyName]; this._definitionChanged.raiseEvent(this); }; var timeScratch6 = new JulianDate_default(); PropertyBag.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch6); } if (!defined_default(result)) { result = {}; } const propertyNames = this._propertyNames; for (let i = 0, len = propertyNames.length; i < len; i++) { const propertyName = propertyNames[i]; result[propertyName] = Property_default.getValueOrUndefined( this[propertyName], time, result[propertyName] ); } return result; }; PropertyBag.prototype.merge = function(source, createPropertyCallback) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } const propertyNames = this._propertyNames; const sourcePropertyNames = defined_default(source._propertyNames) ? source._propertyNames : Object.keys(source); for (let i = 0, len = sourcePropertyNames.length; i < len; i++) { const name = sourcePropertyNames[i]; const targetProperty = this[name]; const sourceProperty = source[name]; if (targetProperty === void 0 && propertyNames.indexOf(name) === -1) { this.addProperty(name, void 0, createPropertyCallback); } if (sourceProperty !== void 0) { if (targetProperty !== void 0) { if (defined_default(targetProperty) && defined_default(targetProperty.merge)) { targetProperty.merge(sourceProperty); } } else if (defined_default(sourceProperty) && defined_default(sourceProperty.merge) && defined_default(sourceProperty.clone)) { this[name] = sourceProperty.clone(); } else { this[name] = sourceProperty; } } } }; function propertiesEqual(a3, b) { const aPropertyNames = a3._propertyNames; const bPropertyNames = b._propertyNames; const len = aPropertyNames.length; if (len !== bPropertyNames.length) { return false; } for (let aIndex = 0; aIndex < len; ++aIndex) { const name = aPropertyNames[aIndex]; const bIndex = bPropertyNames.indexOf(name); if (bIndex === -1) { return false; } if (!Property_default.equals(a3[name], b[name])) { return false; } } return true; } PropertyBag.prototype.equals = function(other) { return this === other || // other instanceof PropertyBag && // propertiesEqual(this, other); }; var PropertyBag_default = PropertyBag; // packages/engine/Source/DataSources/ModelGraphics.js function createNodeTransformationProperty(value) { return new NodeTransformationProperty_default(value); } function createNodeTransformationPropertyBag(value) { return new PropertyBag_default(value, createNodeTransformationProperty); } function createArticulationStagePropertyBag(value) { return new PropertyBag_default(value); } function createEnvironmentMapPropertyBag(value) { return new PropertyBag_default(value); } function ModelGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._uri = void 0; this._uriSubscription = void 0; this._scale = void 0; this._scaleSubscription = void 0; this._hasVerticalExaggeration = void 0; this._hasVerticalExaggerationSubscription = void 0; this._enableVerticalExaggeration = void 0; this._enableVerticalExaggerationSubscription = void 0; this._minimumPixelSize = void 0; this._minimumPixelSizeSubscription = void 0; this._maximumScale = void 0; this._maximumScaleSubscription = void 0; this._incrementallyLoadTextures = void 0; this._incrementallyLoadTexturesSubscription = void 0; this._runAnimations = void 0; this._runAnimationsSubscription = void 0; this._clampAnimations = void 0; this._clampAnimationsSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._silhouetteColor = void 0; this._silhouetteColorSubscription = void 0; this._silhouetteSize = void 0; this._silhouetteSizeSubscription = void 0; this._color = void 0; this._colorSubscription = void 0; this._colorBlendMode = void 0; this._colorBlendModeSubscription = void 0; this._colorBlendAmount = void 0; this._colorBlendAmountSubscription = void 0; this._imageBasedLightingFactor = void 0; this._imageBasedLightingFactorSubscription = void 0; this._environmentMapOptions = void 0; this._environmentMapOptionsSubscription = void 0; this._lightColor = void 0; this._lightColorSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._nodeTransformations = void 0; this._nodeTransformationsSubscription = void 0; this._articulations = void 0; this._articulationsSubscription = void 0; this._clippingPlanes = void 0; this._clippingPlanesSubscription = void 0; this._customShader = void 0; this._customShaderSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(ModelGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof ModelGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the model. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the string Property specifying the URI of the glTF asset. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ uri: createPropertyDescriptor_default("uri"), /** * Gets or sets the numeric Property specifying a uniform linear scale * for this model. Values greater than 1.0 increase the size of the model while * values less than 1.0 decrease it. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default 1.0 */ scale: createPropertyDescriptor_default("scale"), /** * Gets or sets the boolean Property specifying if the model is exaggerated along the ellipsoid normal when {@link Scene.verticalExaggeration} is set to a value other than 1.0. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default true */ enableVerticalExaggeration: createPropertyDescriptor_default( "enableVerticalExaggeration" ), /** * Gets or sets the numeric Property specifying the approximate minimum * pixel size of the model regardless of zoom. This can be used to ensure that * a model is visible even when the viewer zooms out. When 0.0, * no minimum size is enforced. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default 0.0 */ minimumPixelSize: createPropertyDescriptor_default("minimumPixelSize"), /** * Gets or sets the numeric Property specifying the maximum scale * size of a model. This property is used as an upper limit for * {@link ModelGraphics#minimumPixelSize}. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ maximumScale: createPropertyDescriptor_default("maximumScale"), /** * Get or sets the boolean Property specifying whether textures * may continue to stream in after the model is loaded. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ incrementallyLoadTextures: createPropertyDescriptor_default( "incrementallyLoadTextures" ), /** * Gets or sets the boolean Property specifying if glTF animations should be run. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default true */ runAnimations: createPropertyDescriptor_default("runAnimations"), /** * Gets or sets the boolean Property specifying if glTF animations should hold the last pose for time durations with no keyframes. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default true */ clampAnimations: createPropertyDescriptor_default("clampAnimations"), /** * Get or sets the enum Property specifying whether the model * casts or receives shadows from light sources. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default ShadowMode.ENABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the Property specifying the {@link Color} of the silhouette. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default Color.RED */ silhouetteColor: createPropertyDescriptor_default("silhouetteColor"), /** * Gets or sets the numeric Property specifying the size of the silhouette in pixels. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default 0.0 */ silhouetteSize: createPropertyDescriptor_default("silhouetteSize"), /** * Gets or sets the Property specifying the {@link Color} that blends with the model's rendered color. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default Color.WHITE */ color: createPropertyDescriptor_default("color"), /** * Gets or sets the enum Property specifying how the color blends with the model. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default ColorBlendMode.HIGHLIGHT */ colorBlendMode: createPropertyDescriptor_default("colorBlendMode"), /** * A numeric Property specifying the color strength when the colorBlendMode is MIX. * A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with * any value in-between resulting in a mix of the two. * @memberof ModelGraphics.prototype * @type {Property|undefined} * @default 0.5 */ colorBlendAmount: createPropertyDescriptor_default("colorBlendAmount"), /** * A property specifying the {@link Cartesian2} used to scale the diffuse and specular image-based lighting contribution to the final color. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ imageBasedLightingFactor: createPropertyDescriptor_default( "imageBasedLightingFactor" ), /** * Gets or sets the {@link DynamicEnvironmentMapManager.ConstructorOptions} to apply to this model. This is represented as an {@link PropertyBag}. * @memberof ModelGraphics.prototype * @type {PropertyBag} */ environmentMapOptions: createPropertyDescriptor_default( "environmentMapOptions", void 0, createEnvironmentMapPropertyBag ), /** * A property specifying the {@link Cartesian3} light color when shading the model. When undefined the scene's light color is used instead. * @memberOf ModelGraphics.prototype * @type {Property|undefined} */ lightColor: createPropertyDescriptor_default("lightColor"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this model will be displayed. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the set of node transformations to apply to this model. This is represented as an {@link PropertyBag}, where keys are * names of nodes, and values are {@link TranslationRotationScale} Properties describing the transformation to apply to that node. * The transformation is applied after the node's existing transformation as specified in the glTF, and does not replace the node's existing transformation. * @memberof ModelGraphics.prototype * @type {PropertyBag} */ nodeTransformations: createPropertyDescriptor_default( "nodeTransformations", void 0, createNodeTransformationPropertyBag ), /** * Gets or sets the set of articulation values to apply to this model. This is represented as an {@link PropertyBag}, where keys are * composed as the name of the articulation, a single space, and the name of the stage. * @memberof ModelGraphics.prototype * @type {PropertyBag} */ articulations: createPropertyDescriptor_default( "articulations", void 0, createArticulationStagePropertyBag ), /** * A property specifying the {@link ClippingPlaneCollection} used to selectively disable rendering the model. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ clippingPlanes: createPropertyDescriptor_default("clippingPlanes"), /** * Gets or sets the {@link CustomShader} to apply to this model. When undefined, no custom shader code is used. * @memberof ModelGraphics.prototype * @type {Property|undefined} */ customShader: createPropertyDescriptor_default("customShader") }); ModelGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new ModelGraphics(this); } result.show = this.show; result.uri = this.uri; result.scale = this.scale; result.enableVerticalExaggeration = this.enableVerticalExaggeration; result.minimumPixelSize = this.minimumPixelSize; result.maximumScale = this.maximumScale; result.incrementallyLoadTextures = this.incrementallyLoadTextures; result.runAnimations = this.runAnimations; result.clampAnimations = this.clampAnimations; result.heightReference = this._heightReference; result.silhouetteColor = this.silhouetteColor; result.silhouetteSize = this.silhouetteSize; result.color = this.color; result.colorBlendMode = this.colorBlendMode; result.colorBlendAmount = this.colorBlendAmount; result.imageBasedLightingFactor = this.imageBasedLightingFactor; result.environmentMapOptions = this.environmentMapOptions; result.lightColor = this.lightColor; result.distanceDisplayCondition = this.distanceDisplayCondition; result.nodeTransformations = this.nodeTransformations; result.articulations = this.articulations; result.clippingPlanes = this.clippingPlanes; result.customShader = this.customShader; return result; }; ModelGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.uri = this.uri ?? source.uri; this.scale = this.scale ?? source.scale; this.enableVerticalExaggeration = this.enableVerticalExaggeration ?? source.enableVerticalExaggeration; this.minimumPixelSize = this.minimumPixelSize ?? source.minimumPixelSize; this.maximumScale = this.maximumScale ?? source.maximumScale; this.incrementallyLoadTextures = this.incrementallyLoadTextures ?? source.incrementallyLoadTextures; this.runAnimations = this.runAnimations ?? source.runAnimations; this.clampAnimations = this.clampAnimations ?? source.clampAnimations; this.shadows = this.shadows ?? source.shadows; this.heightReference = this.heightReference ?? source.heightReference; this.silhouetteColor = this.silhouetteColor ?? source.silhouetteColor; this.silhouetteSize = this.silhouetteSize ?? source.silhouetteSize; this.color = this.color ?? source.color; this.colorBlendMode = this.colorBlendMode ?? source.colorBlendMode; this.colorBlendAmount = this.colorBlendAmount ?? source.colorBlendAmount; this.imageBasedLightingFactor = this.imageBasedLightingFactor ?? source.imageBasedLightingFactor; this.environmentMapOptions = this.environmentMapOptions ?? source.environmentMapOptions; this.lightColor = this.lightColor ?? source.lightColor; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.clippingPlanes = this.clippingPlanes ?? source.clippingPlanes; this.customShader = this.customShader ?? source.customShader; const sourceNodeTransformations = source.nodeTransformations; if (defined_default(sourceNodeTransformations)) { const targetNodeTransformations = this.nodeTransformations; if (defined_default(targetNodeTransformations)) { targetNodeTransformations.merge(sourceNodeTransformations); } else { this.nodeTransformations = new PropertyBag_default( sourceNodeTransformations, createNodeTransformationProperty ); } } const sourceArticulations = source.articulations; if (defined_default(sourceArticulations)) { const targetArticulations = this.articulations; if (defined_default(targetArticulations)) { targetArticulations.merge(sourceArticulations); } else { this.articulations = new PropertyBag_default(sourceArticulations); } } }; var ModelGraphics_default = ModelGraphics; // packages/engine/Source/DataSources/Cesium3DTilesetGraphics.js var import_InlineWorkers416 = __toESM(require_InlineWorkers(), 1); function Cesium3DTilesetGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._uri = void 0; this._uriSubscription = void 0; this._maximumScreenSpaceError = void 0; this._maximumScreenSpaceErrorSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(Cesium3DTilesetGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof Cesium3DTilesetGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the model. * @memberof Cesium3DTilesetGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the string Property specifying the URI of the glTF asset. * @memberof Cesium3DTilesetGraphics.prototype * @type {Property|undefined} */ uri: createPropertyDescriptor_default("uri"), /** * Gets or sets the maximum screen space error used to drive level of detail refinement. * @memberof Cesium3DTilesetGraphics.prototype * @type {Property|undefined} */ maximumScreenSpaceError: createPropertyDescriptor_default("maximumScreenSpaceError") }); Cesium3DTilesetGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new Cesium3DTilesetGraphics(this); } result.show = this.show; result.uri = this.uri; result.maximumScreenSpaceError = this.maximumScreenSpaceError; return result; }; Cesium3DTilesetGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.uri = this.uri ?? source.uri; this.maximumScreenSpaceError = this.maximumScreenSpaceError ?? source.maximumScreenSpaceError; }; var Cesium3DTilesetGraphics_default = Cesium3DTilesetGraphics; // packages/engine/Source/DataSources/PathGraphics.js var import_InlineWorkers417 = __toESM(require_InlineWorkers(), 1); function PathGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._leadTime = void 0; this._leadTimeSubscription = void 0; this._trailTime = void 0; this._trailTimeSubscription = void 0; this._width = void 0; this._widthSubscription = void 0; this._resolution = void 0; this._resolutionSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._relativeTo = void 0; this._relativeToSubscription = void 0; this._materialMode = void 0; this._materialModeSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PathGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PathGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the path. * @memberof PathGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the number of seconds in front of the object to show. * @memberof PathGraphics.prototype * @type {Property|undefined} */ leadTime: createPropertyDescriptor_default("leadTime"), /** * Gets or sets the Property specifying the number of seconds behind the object to show. * @memberof PathGraphics.prototype * @type {Property|undefined} */ trailTime: createPropertyDescriptor_default("trailTime"), /** * Gets or sets the numeric Property specifying the width in pixels. * @memberof PathGraphics.prototype * @type {Property|undefined} * @default 1.0 */ width: createPropertyDescriptor_default("width"), /** * Gets or sets the Property specifying the maximum number of seconds to step when sampling the position. * Fractional positive values are allowed; in PORTIONS materialMode, non-positive values fall back to the default resolution of 60 seconds. * @memberof PathGraphics.prototype * @type {Property|undefined} * @default 60 */ resolution: createPropertyDescriptor_default("resolution"), /** * Gets or sets the Property specifying the material used to draw the path. * @memberof PathGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this path will be displayed. * @memberof PathGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the frame in which to visualize the path. Use another entity's id to visualize the path relative to that entity, or use the string values "FIXED" or "INERTIAL" to visualize the path in those reference frames. * @memberof PathGraphics.prototype * @type {Property|undefined} * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy. */ relativeTo: createPropertyDescriptor_default("relativeTo"), materialMode: createPropertyDescriptor_default("materialMode") }); PathGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PathGraphics(this); } result.show = this.show; result.leadTime = this.leadTime; result.trailTime = this.trailTime; result.width = this.width; result.resolution = this.resolution; result.material = this.material; result.distanceDisplayCondition = this.distanceDisplayCondition; result.relativeTo = this.relativeTo; result.materialMode = this.materialMode; return result; }; PathGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.leadTime = this.leadTime ?? source.leadTime; this.trailTime = this.trailTime ?? source.trailTime; this.width = this.width ?? source.width; this.resolution = this.resolution ?? source.resolution; this.material = this.material ?? source.material; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.relativeTo = this.relativeTo ?? source.relativeTo; this.materialMode = this.materialMode ?? source.materialMode; }; var PathGraphics_default = PathGraphics; // packages/engine/Source/DataSources/PlaneGraphics.js var import_InlineWorkers418 = __toESM(require_InlineWorkers(), 1); function PlaneGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._plane = void 0; this._planeSubscription = void 0; this._dimensions = void 0; this._dimensionsSubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PlaneGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PlaneGraphics.prototype * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the plane. * @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the {@link Plane} Property specifying the normal and distance of the plane. * * @memberof PlaneGraphics.prototype * @type {Property|undefined} */ plane: createPropertyDescriptor_default("plane"), /** * Gets or sets the {@link Cartesian2} Property specifying the width and height of the plane. * * @memberof PlaneGraphics.prototype * @type {Property|undefined} */ dimensions: createPropertyDescriptor_default("dimensions"), /** * Gets or sets the boolean Property specifying whether the plane is filled with the provided material. * @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the material used to fill the plane. * @memberof PlaneGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the plane is outlined. * @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the plane * casts or receives shadows from light sources. * @memberof PlaneGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this plane will be displayed. * @memberof PlaneGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); PlaneGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PlaneGraphics(this); } result.show = this.show; result.plane = this.plane; result.dimensions = this.dimensions; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; PlaneGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.plane = this.plane ?? source.plane; this.dimensions = this.dimensions ?? source.dimensions; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var PlaneGraphics_default = PlaneGraphics; // packages/engine/Source/DataSources/PointGraphics.js var import_InlineWorkers419 = __toESM(require_InlineWorkers(), 1); function PointGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._pixelSize = void 0; this._pixelSizeSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._color = void 0; this._colorSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._scaleByDistance = void 0; this._scaleByDistanceSubscription = void 0; this._translucencyByDistance = void 0; this._translucencyByDistanceSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._disableDepthTestDistance = void 0; this._disableDepthTestDistanceSubscription = void 0; this._splitDirection = void 0; this._splitDirectionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PointGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PointGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the point. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the numeric Property specifying the size in pixels. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default 1 */ pixelSize: createPropertyDescriptor_default("pixelSize"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the Property specifying the {@link Color} of the point. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default Color.WHITE */ color: createPropertyDescriptor_default("color"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the the outline width in pixels. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default 0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets the {@link NearFarScalar} Property used to scale the point based on distance. * If undefined, a constant size is used. * @memberof PointGraphics.prototype * @type {Property|undefined} */ scaleByDistance: createPropertyDescriptor_default("scaleByDistance"), /** * Gets or sets {@link NearFarScalar} Property specifying the translucency of the point based on the distance from the camera. * A point's translucency will interpolate between the {@link NearFarScalar#nearValue} and * {@link NearFarScalar#farValue} while the camera distance falls within the lower and upper bounds * of the specified {@link NearFarScalar#near} and {@link NearFarScalar#far}. * Outside of these ranges the points's translucency remains clamped to the nearest bound. * @memberof PointGraphics.prototype * @type {Property|undefined} */ translucencyByDistance: createPropertyDescriptor_default("translucencyByDistance"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this point will be displayed. * @memberof PointGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the distance from the camera at which to disable the depth test to, for example, prevent clipping against terrain. * When set to zero, the depth test is always applied. When set to Number.POSITIVE_INFINITY, the depth test is never applied. * @memberof PointGraphics.prototype * @type {Property|undefined} */ disableDepthTestDistance: createPropertyDescriptor_default( "disableDepthTestDistance" ), /** * Gets or sets the Property specifying the {@link SplitDirection} of this point. * @memberof PointGraphics.prototype * @type {Property|undefined} * @default SplitDirection.NONE */ splitDirection: createPropertyDescriptor_default("splitDirection") }); PointGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PointGraphics(this); } result.show = this.show; result.pixelSize = this.pixelSize; result.heightReference = this.heightReference; result.color = this.color; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.scaleByDistance = this.scaleByDistance; result.translucencyByDistance = this._translucencyByDistance; result.distanceDisplayCondition = this.distanceDisplayCondition; result.disableDepthTestDistance = this.disableDepthTestDistance; result.splitDirection = this.splitDirection; return result; }; PointGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.pixelSize = this.pixelSize ?? source.pixelSize; this.heightReference = this.heightReference ?? source.heightReference; this.color = this.color ?? source.color; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.scaleByDistance = this.scaleByDistance ?? source.scaleByDistance; this.translucencyByDistance = this._translucencyByDistance ?? source.translucencyByDistance; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.disableDepthTestDistance = this.disableDepthTestDistance ?? source.disableDepthTestDistance; this.splitDirection = this.splitDirection ?? source.splitDirection; }; var PointGraphics_default = PointGraphics; // packages/engine/Source/DataSources/PolygonGraphics.js var import_InlineWorkers421 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/PolygonHierarchy.js var import_InlineWorkers420 = __toESM(require_InlineWorkers(), 1); function PolygonHierarchy(positions, holes) { this.positions = defined_default(positions) ? positions : []; this.holes = defined_default(holes) ? holes : []; } var PolygonHierarchy_default = PolygonHierarchy; // packages/engine/Source/DataSources/PolygonGraphics.js function createPolygonHierarchyProperty(value) { if (Array.isArray(value)) { value = new PolygonHierarchy_default(value); } return new ConstantProperty_default(value); } function PolygonGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._hierarchy = void 0; this._hierarchySubscription = void 0; this._height = void 0; this._heightSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._extrudedHeight = void 0; this._extrudedHeightSubscription = void 0; this._extrudedHeightReference = void 0; this._extrudedHeightReferenceSubscription = void 0; this._stRotation = void 0; this._stRotationSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._perPositionHeight = void 0; this._perPositionHeightSubscription = void 0; this._closeTop = void 0; this._closeTopSubscription = void 0; this._closeBottom = void 0; this._closeBottomSubscription = void 0; this._arcType = void 0; this._arcTypeSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._classificationType = void 0; this._classificationTypeSubscription = void 0; this._zIndex = void 0; this._zIndexSubscription = void 0; this._textureCoordinates = void 0; this._textureCoordinatesSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PolygonGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PolygonGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the polygon. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the {@link PolygonHierarchy}. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ hierarchy: createPropertyDescriptor_default( "hierarchy", void 0, createPolygonHierarchyProperty ), /** * Gets or sets the numeric Property specifying the constant altitude of the polygon. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default 0.0 */ height: createPropertyDescriptor_default("height"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the numeric Property specifying the altitude of the polygon extrusion. * If {@link PolygonGraphics#perPositionHeight} is false, the volume starts at {@link PolygonGraphics#height} and ends at this altitude. * If {@link PolygonGraphics#perPositionHeight} is true, the volume starts at the height of each {@link PolygonGraphics#hierarchy} position and ends at this altitude. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ extrudedHeight: createPropertyDescriptor_default("extrudedHeight"), /** * Gets or sets the Property specifying the extruded {@link HeightReference}. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ extrudedHeightReference: createPropertyDescriptor_default("extrudedHeightReference"), /** * Gets or sets the numeric property specifying the rotation of the polygon texture counter-clockwise from north. Only has an effect if textureCoordinates is not defined. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default 0 */ stRotation: createPropertyDescriptor_default("stRotation"), /** * Gets or sets the numeric Property specifying the angular distance between points on the polygon. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the polygon is filled with the provided material. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the polygon. * @memberof PolygonGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the polygon is outlined. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Gets or sets the boolean specifying whether or not the the height of each position is used. * If true, the shape will have non-uniform altitude defined by the height of each {@link PolygonGraphics#hierarchy} position. * If false, the shape will have a constant altitude as specified by {@link PolygonGraphics#height}. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ perPositionHeight: createPropertyDescriptor_default("perPositionHeight"), /** * Gets or sets a boolean specifying whether or not the top of an extruded polygon is included. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ closeTop: createPropertyDescriptor_default("closeTop"), /** * Gets or sets a boolean specifying whether or not the bottom of an extruded polygon is included. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ closeBottom: createPropertyDescriptor_default("closeBottom"), /** * Gets or sets the {@link ArcType} Property specifying the type of lines the polygon edges use. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default ArcType.GEODESIC */ arcType: createPropertyDescriptor_default("arcType"), /** * Get or sets the enum Property specifying whether the polygon * casts or receives shadows from light sources. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polygon will be displayed. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the {@link ClassificationType} Property specifying whether this polygon will classify terrain, 3D Tiles, or both when on the ground. * @memberof PolygonGraphics.prototype * @type {Property|undefined} * @default ClassificationType.BOTH */ classificationType: createPropertyDescriptor_default("classificationType"), /** * Gets or sets the zIndex Prperty specifying the ordering of ground geometry. Only has an effect if the polygon is constant and neither height or extrudedHeight are specified. * @memberof PolygonGraphics.prototype * @type {ConstantProperty|undefined} * @default 0 */ zIndex: createPropertyDescriptor_default("zIndex"), /** * A Property specifying texture coordinates as a {@link PolygonHierarchy} of {@link Cartesian2} points. Has no effect for ground primitives. * @memberof PolygonGraphics.prototype * @type {Property|undefined} */ textureCoordinates: createPropertyDescriptor_default("textureCoordinates") }); PolygonGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PolygonGraphics(this); } result.show = this.show; result.hierarchy = this.hierarchy; result.height = this.height; result.heightReference = this.heightReference; result.extrudedHeight = this.extrudedHeight; result.extrudedHeightReference = this.extrudedHeightReference; result.stRotation = this.stRotation; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.perPositionHeight = this.perPositionHeight; result.closeTop = this.closeTop; result.closeBottom = this.closeBottom; result.arcType = this.arcType; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; result.classificationType = this.classificationType; result.zIndex = this.zIndex; result.textureCoordinates = this.textureCoordinates; return result; }; PolygonGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.hierarchy = this.hierarchy ?? source.hierarchy; this.height = this.height ?? source.height; this.heightReference = this.heightReference ?? source.heightReference; this.extrudedHeight = this.extrudedHeight ?? source.extrudedHeight; this.extrudedHeightReference = this.extrudedHeightReference ?? source.extrudedHeightReference; this.stRotation = this.stRotation ?? source.stRotation; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.perPositionHeight = this.perPositionHeight ?? source.perPositionHeight; this.closeTop = this.closeTop ?? source.closeTop; this.closeBottom = this.closeBottom ?? source.closeBottom; this.arcType = this.arcType ?? source.arcType; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.classificationType = this.classificationType ?? source.classificationType; this.zIndex = this.zIndex ?? source.zIndex; this.textureCoordinates = this.textureCoordinates ?? source.textureCoordinates; }; var PolygonGraphics_default = PolygonGraphics; // packages/engine/Source/DataSources/PolylineGraphics.js var import_InlineWorkers422 = __toESM(require_InlineWorkers(), 1); function PolylineGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._positions = void 0; this._positionsSubscription = void 0; this._width = void 0; this._widthSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._depthFailMaterial = void 0; this._depthFailMaterialSubscription = void 0; this._arcType = void 0; this._arcTypeSubscription = void 0; this._clampToGround = void 0; this._clampToGroundSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this._classificationType = void 0; this._classificationTypeSubscription = void 0; this._zIndex = void 0; this._zIndexSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PolylineGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PolylineGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the polyline. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the array of {@link Cartesian3} * positions that define the line strip. * @memberof PolylineGraphics.prototype * @type {Property|undefined} */ positions: createPropertyDescriptor_default("positions"), /** * Gets or sets the numeric Property specifying the width in pixels. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default 1.0 */ width: createPropertyDescriptor_default("width"), /** * Gets or sets the numeric Property specifying the angular distance between each latitude and longitude if arcType is not ArcType.NONE and clampToGround is false. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default Cesium.Math.RADIANS_PER_DEGREE */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the Property specifying the material used to draw the polyline. * @memberof PolylineGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying the material used to draw the polyline when it fails the depth test. *

* Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported, * there may be artifacts. *

* @memberof PolylineGraphics.prototype * @type {MaterialProperty} * @default undefined */ depthFailMaterial: createMaterialPropertyDescriptor_default("depthFailMaterial"), /** * Gets or sets the {@link ArcType} Property specifying whether the line segments should be great arcs, rhumb lines or linearly connected. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default ArcType.GEODESIC */ arcType: createPropertyDescriptor_default("arcType"), /** * Gets or sets the boolean Property specifying whether the polyline * should be clamped to the ground. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default false */ clampToGround: createPropertyDescriptor_default("clampToGround"), /** * Get or sets the enum Property specifying whether the polyline * casts or receives shadows from light sources. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this polyline will be displayed. * @memberof PolylineGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the {@link ClassificationType} Property specifying whether this polyline will classify terrain, 3D Tiles, or both when on the ground. * @memberof PolylineGraphics.prototype * @type {Property|undefined} * @default ClassificationType.BOTH */ classificationType: createPropertyDescriptor_default("classificationType"), /** * Gets or sets the zIndex Property specifying the ordering of the polyline. Only has an effect if `clampToGround` is true and polylines on terrain is supported. * @memberof PolylineGraphics.prototype * @type {ConstantProperty|undefined} * @default 0 */ zIndex: createPropertyDescriptor_default("zIndex") }); PolylineGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PolylineGraphics(this); } result.show = this.show; result.positions = this.positions; result.width = this.width; result.granularity = this.granularity; result.material = this.material; result.depthFailMaterial = this.depthFailMaterial; result.arcType = this.arcType; result.clampToGround = this.clampToGround; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; result.classificationType = this.classificationType; result.zIndex = this.zIndex; return result; }; PolylineGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.positions = this.positions ?? source.positions; this.width = this.width ?? source.width; this.granularity = this.granularity ?? source.granularity; this.material = this.material ?? source.material; this.depthFailMaterial = this.depthFailMaterial ?? source.depthFailMaterial; this.arcType = this.arcType ?? source.arcType; this.clampToGround = this.clampToGround ?? source.clampToGround; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.classificationType = this.classificationType ?? source.classificationType; this.zIndex = this.zIndex ?? source.zIndex; }; var PolylineGraphics_default = PolylineGraphics; // packages/engine/Source/DataSources/PolylineVolumeGraphics.js var import_InlineWorkers423 = __toESM(require_InlineWorkers(), 1); function PolylineVolumeGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._positions = void 0; this._positionsSubscription = void 0; this._shape = void 0; this._shapeSubscription = void 0; this._cornerType = void 0; this._cornerTypeSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubsription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(PolylineVolumeGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof PolylineVolumeGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the volume. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the array of {@link Cartesian3} positions which define the line strip. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} */ positions: createPropertyDescriptor_default("positions"), /** * Gets or sets the Property specifying the array of {@link Cartesian2} positions which define the shape to be extruded. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} */ shape: createPropertyDescriptor_default("shape"), /** * Gets or sets the {@link CornerType} Property specifying the style of the corners. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default CornerType.ROUNDED */ cornerType: createPropertyDescriptor_default("cornerType"), /** * Gets or sets the numeric Property specifying the angular distance between points on the volume. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the volume is filled with the provided material. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the volume. * @memberof PolylineVolumeGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the volume is outlined. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the volume * casts or receives shadows from light sources. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this volume will be displayed. * @memberof PolylineVolumeGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); PolylineVolumeGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new PolylineVolumeGraphics(this); } result.show = this.show; result.positions = this.positions; result.shape = this.shape; result.cornerType = this.cornerType; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; PolylineVolumeGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.positions = this.positions ?? source.positions; this.shape = this.shape ?? source.shape; this.cornerType = this.cornerType ?? source.cornerType; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var PolylineVolumeGraphics_default = PolylineVolumeGraphics; // packages/engine/Source/DataSources/RectangleGraphics.js var import_InlineWorkers424 = __toESM(require_InlineWorkers(), 1); function RectangleGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._coordinates = void 0; this._coordinatesSubscription = void 0; this._height = void 0; this._heightSubscription = void 0; this._heightReference = void 0; this._heightReferenceSubscription = void 0; this._extrudedHeight = void 0; this._extrudedHeightSubscription = void 0; this._extrudedHeightReference = void 0; this._extrudedHeightReferenceSubscription = void 0; this._rotation = void 0; this._rotationSubscription = void 0; this._stRotation = void 0; this._stRotationSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distancedisplayConditionSubscription = void 0; this._classificationType = void 0; this._classificationTypeSubscription = void 0; this._zIndex = void 0; this._zIndexSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(RectangleGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof RectangleGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the rectangle. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the {@link Rectangle}. * @memberof RectangleGraphics.prototype * @type {Property|undefined} */ coordinates: createPropertyDescriptor_default("coordinates"), /** * Gets or sets the numeric Property specifying the altitude of the rectangle. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default 0.0 */ height: createPropertyDescriptor_default("height"), /** * Gets or sets the Property specifying the {@link HeightReference}. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ heightReference: createPropertyDescriptor_default("heightReference"), /** * Gets or sets the numeric Property specifying the altitude of the rectangle extrusion. * Setting this property creates volume starting at height and ending at this altitude. * @memberof RectangleGraphics.prototype * @type {Property|undefined} */ extrudedHeight: createPropertyDescriptor_default("extrudedHeight"), /** * Gets or sets the Property specifying the extruded {@link HeightReference}. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default HeightReference.NONE */ extrudedHeightReference: createPropertyDescriptor_default("extrudedHeightReference"), /** * Gets or sets the numeric property specifying the rotation of the rectangle clockwise from north. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default 0 */ rotation: createPropertyDescriptor_default("rotation"), /** * Gets or sets the numeric property specifying the rotation of the rectangle texture counter-clockwise from north. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default 0 */ stRotation: createPropertyDescriptor_default("stRotation"), /** * Gets or sets the numeric Property specifying the angular distance between points on the rectangle. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the rectangle is filled with the provided material. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the rectangle. * @memberof RectangleGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the rectangle is outlined. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the rectangle * casts or receives shadows from light sources. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this rectangle will be displayed. * @memberof RectangleGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ), /** * Gets or sets the {@link ClassificationType} Property specifying whether this rectangle will classify terrain, 3D Tiles, or both when on the ground. * @memberof RectangleGraphics.prototype * @type {Property|undefined} * @default ClassificationType.BOTH */ classificationType: createPropertyDescriptor_default("classificationType"), /** * Gets or sets the zIndex Property specifying the ordering of the rectangle. Only has an effect if the rectangle is constant and neither height or extrudedHeight are specified. * @memberof RectangleGraphics.prototype * @type {ConstantProperty|undefined} * @default 0 */ zIndex: createPropertyDescriptor_default("zIndex") }); RectangleGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new RectangleGraphics(this); } result.show = this.show; result.coordinates = this.coordinates; result.height = this.height; result.heightReference = this.heightReference; result.extrudedHeight = this.extrudedHeight; result.extrudedHeightReference = this.extrudedHeightReference; result.rotation = this.rotation; result.stRotation = this.stRotation; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; result.classificationType = this.classificationType; result.zIndex = this.zIndex; return result; }; RectangleGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.coordinates = this.coordinates ?? source.coordinates; this.height = this.height ?? source.height; this.heightReference = this.heightReference ?? source.heightReference; this.extrudedHeight = this.extrudedHeight ?? source.extrudedHeight; this.extrudedHeightReference = this.extrudedHeightReference ?? source.extrudedHeightReference; this.rotation = this.rotation ?? source.rotation; this.stRotation = this.stRotation ?? source.stRotation; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; this.classificationType = this.classificationType ?? source.classificationType; this.zIndex = this.zIndex ?? source.zIndex; }; var RectangleGraphics_default = RectangleGraphics; // packages/engine/Source/DataSources/WallGraphics.js var import_InlineWorkers425 = __toESM(require_InlineWorkers(), 1); function WallGraphics(options) { this._definitionChanged = new Event_default(); this._show = void 0; this._showSubscription = void 0; this._positions = void 0; this._positionsSubscription = void 0; this._minimumHeights = void 0; this._minimumHeightsSubscription = void 0; this._maximumHeights = void 0; this._maximumHeightsSubscription = void 0; this._granularity = void 0; this._granularitySubscription = void 0; this._fill = void 0; this._fillSubscription = void 0; this._material = void 0; this._materialSubscription = void 0; this._outline = void 0; this._outlineSubscription = void 0; this._outlineColor = void 0; this._outlineColorSubscription = void 0; this._outlineWidth = void 0; this._outlineWidthSubscription = void 0; this._shadows = void 0; this._shadowsSubscription = void 0; this._distanceDisplayCondition = void 0; this._distanceDisplayConditionSubscription = void 0; this.merge(options ?? Frozen_default.EMPTY_OBJECT); } Object.defineProperties(WallGraphics.prototype, { /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof WallGraphics.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the boolean Property specifying the visibility of the wall. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default true */ show: createPropertyDescriptor_default("show"), /** * Gets or sets the Property specifying the array of {@link Cartesian3} positions which define the top of the wall. * @memberof WallGraphics.prototype * @type {Property|undefined} */ positions: createPropertyDescriptor_default("positions"), /** * Gets or sets the Property specifying an array of heights to be used for the bottom of the wall instead of the surface of the globe. * If defined, the array must be the same length as {@link Wall#positions}. * @memberof WallGraphics.prototype * @type {Property|undefined} */ minimumHeights: createPropertyDescriptor_default("minimumHeights"), /** * Gets or sets the Property specifying an array of heights to be used for the top of the wall instead of the height of each position. * If defined, the array must be the same length as {@link Wall#positions}. * @memberof WallGraphics.prototype * @type {Property|undefined} */ maximumHeights: createPropertyDescriptor_default("maximumHeights"), /** * Gets or sets the numeric Property specifying the angular distance between points on the wall. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default {CesiumMath.RADIANS_PER_DEGREE} */ granularity: createPropertyDescriptor_default("granularity"), /** * Gets or sets the boolean Property specifying whether the wall is filled with the provided material. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default true */ fill: createPropertyDescriptor_default("fill"), /** * Gets or sets the Property specifying the material used to fill the wall. * @memberof WallGraphics.prototype * @type {MaterialProperty} * @default Color.WHITE */ material: createMaterialPropertyDescriptor_default("material"), /** * Gets or sets the Property specifying whether the wall is outlined. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default false */ outline: createPropertyDescriptor_default("outline"), /** * Gets or sets the Property specifying the {@link Color} of the outline. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default Color.BLACK */ outlineColor: createPropertyDescriptor_default("outlineColor"), /** * Gets or sets the numeric Property specifying the width of the outline. *

* Note: This property will be ignored on all major browsers on Windows platforms. For details, see (@link https://github.com/CesiumGS/cesium/issues/40}. *

* @memberof WallGraphics.prototype * @type {Property|undefined} * @default 1.0 */ outlineWidth: createPropertyDescriptor_default("outlineWidth"), /** * Get or sets the enum Property specifying whether the wall * casts or receives shadows from light sources. * @memberof WallGraphics.prototype * @type {Property|undefined} * @default ShadowMode.DISABLED */ shadows: createPropertyDescriptor_default("shadows"), /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this wall will be displayed. * @memberof WallGraphics.prototype * @type {Property|undefined} */ distanceDisplayCondition: createPropertyDescriptor_default( "distanceDisplayCondition" ) }); WallGraphics.prototype.clone = function(result) { if (!defined_default(result)) { return new WallGraphics(this); } result.show = this.show; result.positions = this.positions; result.minimumHeights = this.minimumHeights; result.maximumHeights = this.maximumHeights; result.granularity = this.granularity; result.fill = this.fill; result.material = this.material; result.outline = this.outline; result.outlineColor = this.outlineColor; result.outlineWidth = this.outlineWidth; result.shadows = this.shadows; result.distanceDisplayCondition = this.distanceDisplayCondition; return result; }; WallGraphics.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.show = this.show ?? source.show; this.positions = this.positions ?? source.positions; this.minimumHeights = this.minimumHeights ?? source.minimumHeights; this.maximumHeights = this.maximumHeights ?? source.maximumHeights; this.granularity = this.granularity ?? source.granularity; this.fill = this.fill ?? source.fill; this.material = this.material ?? source.material; this.outline = this.outline ?? source.outline; this.outlineColor = this.outlineColor ?? source.outlineColor; this.outlineWidth = this.outlineWidth ?? source.outlineWidth; this.shadows = this.shadows ?? source.shadows; this.distanceDisplayCondition = this.distanceDisplayCondition ?? source.distanceDisplayCondition; }; var WallGraphics_default = WallGraphics; // packages/engine/Source/DataSources/Entity.js var cartoScratch = new Cartographic_default(); var ExtraPropertyNames = []; function createConstantPositionProperty(value) { return new ConstantPositionProperty_default(value); } function createPositionPropertyDescriptor(name) { return createPropertyDescriptor_default( name, void 0, createConstantPositionProperty ); } function createPropertyTypeDescriptor(name, Type) { return createPropertyDescriptor_default(name, void 0, function(value) { if (value instanceof Type) { return value; } return new Type(value); }); } function Entity(options) { options = options ?? Frozen_default.EMPTY_OBJECT; let id = options.id; if (!defined_default(id)) { id = createGuid_default(); } this._availability = void 0; this._id = id; this._definitionChanged = new Event_default(); this._name = options.name; this._show = options.show ?? true; this._trackingReferenceFrame = options.trackingReferenceFrame ?? TrackingReferenceFrame_default.AUTODETECT; this._parent = void 0; this._propertyNames = [ "billboard", "box", "corridor", "cylinder", "description", "ellipse", "ellipsoid", "label", "model", "tileset", "orientation", "path", "plane", "point", "polygon", "polyline", "polylineVolume", "position", "properties", "rectangle", "viewFrom", "wall", ...ExtraPropertyNames ]; this._billboard = void 0; this._billboardSubscription = void 0; this._box = void 0; this._boxSubscription = void 0; this._corridor = void 0; this._corridorSubscription = void 0; this._cylinder = void 0; this._cylinderSubscription = void 0; this._description = void 0; this._descriptionSubscription = void 0; this._ellipse = void 0; this._ellipseSubscription = void 0; this._ellipsoid = void 0; this._ellipsoidSubscription = void 0; this._label = void 0; this._labelSubscription = void 0; this._model = void 0; this._modelSubscription = void 0; this._tileset = void 0; this._tilesetSubscription = void 0; this._orientation = void 0; this._orientationSubscription = void 0; this._path = void 0; this._pathSubscription = void 0; this._plane = void 0; this._planeSubscription = void 0; this._point = void 0; this._pointSubscription = void 0; this._polygon = void 0; this._polygonSubscription = void 0; this._polyline = void 0; this._polylineSubscription = void 0; this._polylineVolume = void 0; this._polylineVolumeSubscription = void 0; this._position = void 0; this._positionSubscription = void 0; this._properties = void 0; this._propertiesSubscription = void 0; this._rectangle = void 0; this._rectangleSubscription = void 0; this._viewFrom = void 0; this._viewFromSubscription = void 0; this._wall = void 0; this._wallSubscription = void 0; this._children = []; this.entityCollection = void 0; this.parent = options.parent; this.merge(options); } function updateShow(entity, children, isShowing) { const length2 = children.length; for (let i = 0; i < length2; i++) { const child = children[i]; const childShow = child._show; const oldValue2 = !isShowing && childShow; const newValue = isShowing && childShow; if (oldValue2 !== newValue) { updateShow(child, child._children, isShowing); } } entity._definitionChanged.raiseEvent( entity, "isShowing", isShowing, !isShowing ); } Object.defineProperties(Entity.prototype, { /** * The availability, if any, associated with this object. * If availability is undefined, it is assumed that this object's * other properties will return valid data for any provided time. * If availability exists, the objects other properties will only * provide valid data if queried within the given interval. * @memberof Entity.prototype * @type {TimeIntervalCollection|undefined} */ availability: createRawPropertyDescriptor_default("availability"), /** * Gets the unique ID associated with this object. * @memberof Entity.prototype * @type {string} */ id: { get: function() { return this._id; } }, /** * Gets the event that is raised whenever a property or sub-property is changed or modified. * @memberof Entity.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets or sets the name of the object. The name is intended for end-user * consumption and does not need to be unique. * @memberof Entity.prototype * @type {string|undefined} */ name: createRawPropertyDescriptor_default("name"), /** * Gets or sets whether this entity should be displayed. When set to true, * the entity is only displayed if the parent entity's show property is also true. * @memberof Entity.prototype * @type {boolean} */ show: { get: function() { return this._show; }, set: function(value) { if (!defined_default(value)) { throw new DeveloperError_default("value is required."); } if (value === this._show) { return; } const wasShowing = this.isShowing; this._show = value; const isShowing = this.isShowing; if (wasShowing !== isShowing) { updateShow(this, this._children, isShowing); } this._definitionChanged.raiseEvent(this, "show", value, !value); } }, /** * Gets or sets the entity's tracking reference frame. * @demo {@link https://sandcastle.cesium.com/index.html?id=entity-tracking|Cesium Sandcastle Entity tracking Demo} * * @memberof Entity.prototype * @type {TrackingReferenceFrame} */ trackingReferenceFrame: createRawPropertyDescriptor_default("trackingReferenceFrame"), /** * Gets whether this entity is being displayed, taking into account * the visibility of any ancestor entities. * @memberof Entity.prototype * @type {boolean} */ isShowing: { get: function() { return this._show && (!defined_default(this.entityCollection) || this.entityCollection.show) && (!defined_default(this._parent) || this._parent.isShowing); } }, /** * Gets or sets the parent object. * @memberof Entity.prototype * @type {Entity|undefined} */ parent: { get: function() { return this._parent; }, set: function(value) { const oldValue2 = this._parent; if (oldValue2 === value) { return; } const wasShowing = this.isShowing; if (defined_default(oldValue2)) { const index = oldValue2._children.indexOf(this); oldValue2._children.splice(index, 1); } this._parent = value; if (defined_default(value)) { value._children.push(this); } const isShowing = this.isShowing; if (wasShowing !== isShowing) { updateShow(this, this._children, isShowing); } this._definitionChanged.raiseEvent(this, "parent", value, oldValue2); } }, /** * Gets the names of all properties registered on this instance. * @memberof Entity.prototype * @type {string[]} */ propertyNames: { get: function() { return this._propertyNames; } }, /** * Gets or sets the billboard. * @memberof Entity.prototype * @type {BillboardGraphics|undefined} */ billboard: createPropertyTypeDescriptor("billboard", BillboardGraphics_default), /** * Gets or sets the box. * @memberof Entity.prototype * @type {BoxGraphics|undefined} */ box: createPropertyTypeDescriptor("box", BoxGraphics_default), /** * Gets or sets the corridor. * @memberof Entity.prototype * @type {CorridorGraphics|undefined} */ corridor: createPropertyTypeDescriptor("corridor", CorridorGraphics_default), /** * Gets or sets the cylinder. * @memberof Entity.prototype * @type {CylinderGraphics|undefined} */ cylinder: createPropertyTypeDescriptor("cylinder", CylinderGraphics_default), /** * Gets or sets the description. * @memberof Entity.prototype * @type {Property|undefined} */ description: createPropertyDescriptor_default("description"), /** * Gets or sets the ellipse. * @memberof Entity.prototype * @type {EllipseGraphics|undefined} */ ellipse: createPropertyTypeDescriptor("ellipse", EllipseGraphics_default), /** * Gets or sets the ellipsoid. * @memberof Entity.prototype * @type {EllipsoidGraphics|undefined} */ ellipsoid: createPropertyTypeDescriptor("ellipsoid", EllipsoidGraphics_default), /** * Gets or sets the label. * @memberof Entity.prototype * @type {LabelGraphics|undefined} */ label: createPropertyTypeDescriptor("label", LabelGraphics_default), /** * Gets or sets the model. * @memberof Entity.prototype * @type {ModelGraphics|undefined} */ model: createPropertyTypeDescriptor("model", ModelGraphics_default), /** * Gets or sets the tileset. * @memberof Entity.prototype * @type {Cesium3DTilesetGraphics|undefined} */ tileset: createPropertyTypeDescriptor("tileset", Cesium3DTilesetGraphics_default), /** * Gets or sets the orientation in respect to Earth-fixed-Earth-centered (ECEF). * Defaults to east-north-up at entity position. * @memberof Entity.prototype * @type {Property|undefined} */ orientation: createPropertyDescriptor_default("orientation"), /** * Gets or sets the path. * @memberof Entity.prototype * @type {PathGraphics|undefined} */ path: createPropertyTypeDescriptor("path", PathGraphics_default), /** * Gets or sets the plane. * @memberof Entity.prototype * @type {PlaneGraphics|undefined} */ plane: createPropertyTypeDescriptor("plane", PlaneGraphics_default), /** * Gets or sets the point graphic. * @memberof Entity.prototype * @type {PointGraphics|undefined} */ point: createPropertyTypeDescriptor("point", PointGraphics_default), /** * Gets or sets the polygon. * @memberof Entity.prototype * @type {PolygonGraphics|undefined} */ polygon: createPropertyTypeDescriptor("polygon", PolygonGraphics_default), /** * Gets or sets the polyline. * @memberof Entity.prototype * @type {PolylineGraphics|undefined} */ polyline: createPropertyTypeDescriptor("polyline", PolylineGraphics_default), /** * Gets or sets the polyline volume. * @memberof Entity.prototype * @type {PolylineVolumeGraphics|undefined} */ polylineVolume: createPropertyTypeDescriptor( "polylineVolume", PolylineVolumeGraphics_default ), /** * Gets or sets the bag of arbitrary properties associated with this entity. * @memberof Entity.prototype * @type {PropertyBag|undefined} */ properties: createPropertyTypeDescriptor("properties", PropertyBag_default), /** * Gets or sets the position. * @memberof Entity.prototype * @type {PositionProperty|undefined} */ position: createPositionPropertyDescriptor("position"), /** * Gets or sets the rectangle. * @memberof Entity.prototype * @type {RectangleGraphics|undefined} */ rectangle: createPropertyTypeDescriptor("rectangle", RectangleGraphics_default), /** * Gets or sets the suggested initial offset when tracking this object. * The offset is typically defined in the east-north-up reference frame, * but may be another frame depending on the object's velocity. * @memberof Entity.prototype * @type {Property|undefined} */ viewFrom: createPropertyDescriptor_default("viewFrom"), /** * Gets or sets the wall. * @memberof Entity.prototype * @type {WallGraphics|undefined} */ wall: createPropertyTypeDescriptor("wall", WallGraphics_default) }); Entity.registerEntityType = function(propertyName, Type) { Object.defineProperties(Entity.prototype, { [propertyName]: createPropertyTypeDescriptor(propertyName, Type) }); if (!ExtraPropertyNames.includes(propertyName)) { ExtraPropertyNames.push(propertyName); } }; Entity.prototype.isAvailable = function(time) { if (!defined_default(time)) { throw new DeveloperError_default("time is required."); } const availability = this._availability; return !defined_default(availability) || availability.contains(time); }; Entity.prototype.addProperty = function(propertyName) { const propertyNames = this._propertyNames; if (!defined_default(propertyName)) { throw new DeveloperError_default("propertyName is required."); } if (propertyNames.indexOf(propertyName) !== -1) { throw new DeveloperError_default( `${propertyName} is already a registered property.` ); } if (propertyName in this) { throw new DeveloperError_default(`${propertyName} is a reserved property name.`); } propertyNames.push(propertyName); Object.defineProperty( this, propertyName, createRawPropertyDescriptor_default(propertyName, true) ); }; Entity.prototype.removeProperty = function(propertyName) { const propertyNames = this._propertyNames; const index = propertyNames.indexOf(propertyName); if (!defined_default(propertyName)) { throw new DeveloperError_default("propertyName is required."); } if (index === -1) { throw new DeveloperError_default(`${propertyName} is not a registered property.`); } this._propertyNames.splice(index, 1); delete this[propertyName]; }; Entity.prototype.merge = function(source) { if (!defined_default(source)) { throw new DeveloperError_default("source is required."); } this.name = this.name ?? source.name; this.availability = this.availability ?? source.availability; const propertyNames = this._propertyNames; const sourcePropertyNames = defined_default(source._propertyNames) ? source._propertyNames : Object.keys(source); const propertyNamesLength = sourcePropertyNames.length; for (let i = 0; i < propertyNamesLength; i++) { const name = sourcePropertyNames[i]; if (name === "parent" || name === "name" || name === "availability" || name === "children") { continue; } const targetProperty = this[name]; const sourceProperty = source[name]; if (!defined_default(targetProperty) && propertyNames.indexOf(name) === -1) { this.addProperty(name); } if (defined_default(sourceProperty)) { if (defined_default(targetProperty)) { if (defined_default(targetProperty.merge)) { targetProperty.merge(sourceProperty); } } else if (defined_default(sourceProperty.merge) && defined_default(sourceProperty.clone)) { this[name] = sourceProperty.clone(); } else { this[name] = sourceProperty; } } } }; var matrix3Scratch2 = new Matrix3_default(); var positionScratch2 = new Cartesian3_default(); var orientationScratch = new Quaternion_default(); Entity.prototype.computeModelMatrix = function(time, result) { Check_default.typeOf.object("time", time); const position = Property_default.getValueOrUndefined( this._position, time, positionScratch2 ); if (!defined_default(position)) { return void 0; } const orientation = Property_default.getValueOrUndefined( this._orientation, time, orientationScratch ); if (!defined_default(orientation)) { result = Transforms_default.eastNorthUpToFixedFrame(position, void 0, result); } else { result = Matrix4_default.fromRotationTranslation( Matrix3_default.fromQuaternion(orientation, matrix3Scratch2), position, result ); } return result; }; Entity.prototype.computeModelMatrixForHeightReference = function(time, heightReferenceProperty, heightOffset, ellipsoid, result) { Check_default.typeOf.object("time", time); const heightReference = Property_default.getValueOrDefault( heightReferenceProperty, time, HeightReference_default.NONE ); let position = Property_default.getValueOrUndefined( this._position, time, positionScratch2 ); if (heightReference === HeightReference_default.NONE || !defined_default(position) || Cartesian3_default.equalsEpsilon(position, Cartesian3_default.ZERO, Math_default.EPSILON8)) { return this.computeModelMatrix(time, result); } const carto = ellipsoid.cartesianToCartographic(position, cartoScratch); if (isHeightReferenceClamp(heightReference)) { carto.height = heightOffset; } else { carto.height += heightOffset; } position = ellipsoid.cartographicToCartesian(carto, position); const orientation = Property_default.getValueOrUndefined( this._orientation, time, orientationScratch ); if (!defined_default(orientation)) { result = Transforms_default.eastNorthUpToFixedFrame(position, void 0, result); } else { result = Matrix4_default.fromRotationTranslation( Matrix3_default.fromQuaternion(orientation, matrix3Scratch2), position, result ); } return result; }; Entity.supportsMaterialsforEntitiesOnTerrain = function(scene) { return GroundPrimitive_default.supportsMaterials(scene); }; Entity.supportsPolylinesOnTerrain = function(scene) { return GroundPolylinePrimitive_default.isSupported(scene); }; var Entity_default = Entity; // packages/engine/Source/DataSources/GeometryUpdater.js var defaultMaterial = new ColorMaterialProperty_default(Color_default.WHITE); var defaultShow = new ConstantProperty_default(true); var defaultFill = new ConstantProperty_default(true); var defaultOutline = new ConstantProperty_default(false); var defaultOutlineColor = new ConstantProperty_default(Color_default.BLACK); var defaultShadows = new ConstantProperty_default(ShadowMode_default.DISABLED); var defaultDistanceDisplayCondition = new ConstantProperty_default( new DistanceDisplayCondition_default() ); var defaultClassificationType = new ConstantProperty_default(ClassificationType_default.BOTH); function GeometryUpdater(options) { Check_default.defined("options.entity", options.entity); Check_default.defined("options.scene", options.scene); Check_default.defined("options.geometryOptions", options.geometryOptions); Check_default.defined("options.geometryPropertyName", options.geometryPropertyName); Check_default.defined("options.observedPropertyNames", options.observedPropertyNames); const entity = options.entity; const geometryPropertyName = options.geometryPropertyName; this._entity = entity; this._scene = options.scene; this._fillEnabled = false; this._isClosed = false; this._onTerrain = false; this._dynamic = false; this._outlineEnabled = false; this._geometryChanged = new Event_default(); this._showProperty = void 0; this._materialProperty = void 0; this._showOutlineProperty = void 0; this._outlineColorProperty = void 0; this._outlineWidth = 1; this._shadowsProperty = void 0; this._distanceDisplayConditionProperty = void 0; this._classificationTypeProperty = void 0; this._options = options.geometryOptions; this._geometryPropertyName = geometryPropertyName; this._id = `${geometryPropertyName}-${entity.id}`; this._observedPropertyNames = options.observedPropertyNames; this._supportsMaterialsforEntitiesOnTerrain = Entity_default.supportsMaterialsforEntitiesOnTerrain(options.scene); } Object.defineProperties(GeometryUpdater.prototype, { /** * Gets the unique ID associated with this updater * @memberof GeometryUpdater.prototype * @type {string} * @readonly */ id: { get: function() { return this._id; } }, /** * Gets the entity associated with this geometry. * @memberof GeometryUpdater.prototype * * @type {Entity} * @readonly */ entity: { get: function() { return this._entity; } }, /** * Gets a value indicating if the geometry has a fill component. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ fillEnabled: { get: function() { return this._fillEnabled; } }, /** * Gets a value indicating if fill visibility varies with simulation time. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ hasConstantFill: { get: function() { return !this._fillEnabled || !defined_default(this._entity.availability) && Property_default.isConstant(this._showProperty) && Property_default.isConstant(this._fillProperty); } }, /** * Gets the material property used to fill the geometry. * @memberof GeometryUpdater.prototype * * @type {MaterialProperty} * @readonly */ fillMaterialProperty: { get: function() { return this._materialProperty; } }, /** * Gets a value indicating if the geometry has an outline component. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ outlineEnabled: { get: function() { return this._outlineEnabled; } }, /** * Gets a value indicating if the geometry has an outline component. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ hasConstantOutline: { get: function() { return !this._outlineEnabled || !defined_default(this._entity.availability) && Property_default.isConstant(this._showProperty) && Property_default.isConstant(this._showOutlineProperty); } }, /** * Gets the {@link Color} property for the geometry outline. * @memberof GeometryUpdater.prototype * * @type {Property} * @readonly */ outlineColorProperty: { get: function() { return this._outlineColorProperty; } }, /** * Gets the constant with of the geometry outline, in pixels. * This value is only valid if isDynamic is false. * @memberof GeometryUpdater.prototype * * @type {number} * @readonly */ outlineWidth: { get: function() { return this._outlineWidth; } }, /** * Gets the property specifying whether the geometry * casts or receives shadows from light sources. * @memberof GeometryUpdater.prototype * * @type {Property} * @readonly */ shadowsProperty: { get: function() { return this._shadowsProperty; } }, /** * Gets or sets the {@link DistanceDisplayCondition} Property specifying at what distance from the camera that this geometry will be displayed. * @memberof GeometryUpdater.prototype * * @type {Property} * @readonly */ distanceDisplayConditionProperty: { get: function() { return this._distanceDisplayConditionProperty; } }, /** * Gets or sets the {@link ClassificationType} Property specifying if this geometry will classify terrain, 3D Tiles, or both when on the ground. * @memberof GeometryUpdater.prototype * * @type {Property} * @readonly */ classificationTypeProperty: { get: function() { return this._classificationTypeProperty; } }, /** * Gets a value indicating if the geometry is time-varying. * * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ isDynamic: { get: function() { return this._dynamic; } }, /** * Gets a value indicating if the geometry is closed. * This property is only valid for static geometry. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ isClosed: { get: function() { return this._isClosed; } }, /** * Gets a value indicating if the geometry should be drawn on terrain. * @memberof EllipseGeometryUpdater.prototype * * @type {boolean} * @readonly */ onTerrain: { get: function() { return this._onTerrain; } }, /** * Gets an event that is raised whenever the public properties * of this updater change. * @memberof GeometryUpdater.prototype * * @type {boolean} * @readonly */ geometryChanged: { get: function() { return this._geometryChanged; } } }); GeometryUpdater.prototype.isOutlineVisible = function(time) { const entity = this._entity; const visible = this._outlineEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time); return visible ?? false; }; GeometryUpdater.prototype.isFilled = function(time) { const entity = this._entity; const visible = this._fillEnabled && entity.isAvailable(time) && this._showProperty.getValue(time) && this._fillProperty.getValue(time); return visible ?? false; }; GeometryUpdater.prototype.createFillGeometryInstance = DeveloperError_default.throwInstantiationError; GeometryUpdater.prototype.createOutlineGeometryInstance = DeveloperError_default.throwInstantiationError; GeometryUpdater.prototype.isDestroyed = function() { return false; }; GeometryUpdater.prototype.destroy = function() { destroyObject_default(this); }; GeometryUpdater.prototype._isHidden = function(entity, geometry) { const show = geometry.show; return defined_default(show) && show.isConstant && !show.getValue(Iso8601_default.MINIMUM_VALUE); }; GeometryUpdater.prototype._isOnTerrain = function(entity, geometry) { return false; }; GeometryUpdater.prototype._getIsClosed = function(options) { return true; }; GeometryUpdater.prototype._isDynamic = DeveloperError_default.throwInstantiationError; GeometryUpdater.prototype._setStaticOptions = DeveloperError_default.throwInstantiationError; GeometryUpdater.prototype._onEntityPropertyChanged = function(entity, propertyName, newValue, oldValue2) { if (this._observedPropertyNames.indexOf(propertyName) === -1) { return; } const geometry = this._entity[this._geometryPropertyName]; if (!defined_default(geometry)) { if (this._fillEnabled || this._outlineEnabled) { this._fillEnabled = false; this._outlineEnabled = false; this._geometryChanged.raiseEvent(this); } return; } const fillProperty = geometry.fill; const fillEnabled = defined_default(fillProperty) && fillProperty.isConstant ? fillProperty.getValue(Iso8601_default.MINIMUM_VALUE) : true; const outlineProperty = geometry.outline; let outlineEnabled = defined_default(outlineProperty); if (outlineEnabled && outlineProperty.isConstant) { outlineEnabled = outlineProperty.getValue(Iso8601_default.MINIMUM_VALUE); } if (!fillEnabled && !outlineEnabled) { if (this._fillEnabled || this._outlineEnabled) { this._fillEnabled = false; this._outlineEnabled = false; this._geometryChanged.raiseEvent(this); } return; } const show = geometry.show; if (this._isHidden(entity, geometry)) { if (this._fillEnabled || this._outlineEnabled) { this._fillEnabled = false; this._outlineEnabled = false; this._geometryChanged.raiseEvent(this); } return; } this._materialProperty = geometry.material ?? defaultMaterial; this._fillProperty = fillProperty ?? defaultFill; this._showProperty = show ?? defaultShow; this._showOutlineProperty = geometry.outline ?? defaultOutline; this._outlineColorProperty = outlineEnabled ? geometry.outlineColor ?? defaultOutlineColor : void 0; this._shadowsProperty = geometry.shadows ?? defaultShadows; this._distanceDisplayConditionProperty = geometry.distanceDisplayCondition ?? defaultDistanceDisplayCondition; this._classificationTypeProperty = geometry.classificationType ?? defaultClassificationType; this._fillEnabled = fillEnabled; const onTerrain = this._isOnTerrain(entity, geometry) && (this._supportsMaterialsforEntitiesOnTerrain || this._materialProperty instanceof ColorMaterialProperty_default); if (outlineEnabled && onTerrain) { oneTimeWarning_default(oneTimeWarning_default.geometryOutlines); outlineEnabled = false; } this._onTerrain = onTerrain; this._outlineEnabled = outlineEnabled; if (this._isDynamic(entity, geometry)) { if (!this._dynamic) { this._dynamic = true; this._geometryChanged.raiseEvent(this); } } else { this._setStaticOptions(entity, geometry); this._isClosed = this._getIsClosed(this._options); const outlineWidth = geometry.outlineWidth; this._outlineWidth = defined_default(outlineWidth) ? outlineWidth.getValue(Iso8601_default.MINIMUM_VALUE) : 1; this._dynamic = false; this._geometryChanged.raiseEvent(this); } }; GeometryUpdater.prototype.createDynamicUpdater = function(primitives, groundPrimitives) { Check_default.defined("primitives", primitives); Check_default.defined("groundPrimitives", groundPrimitives); if (!this._dynamic) { throw new DeveloperError_default( "This instance does not represent dynamic geometry." ); } return new this.constructor.DynamicGeometryUpdater( this, primitives, groundPrimitives ); }; var GeometryUpdater_default = GeometryUpdater; // packages/engine/Source/DataSources/heightReferenceOnEntityPropertyChanged.js var import_InlineWorkers430 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/DataSources/CallbackProperty.js var import_InlineWorkers428 = __toESM(require_InlineWorkers(), 1); function CallbackProperty(callback, isConstant) { this._callback = void 0; this._isConstant = void 0; this._definitionChanged = new Event_default(); this.setCallback(callback, isConstant); } Object.defineProperties(CallbackProperty.prototype, { /** * Gets a value indicating if this property is constant. * @memberof CallbackProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return this._isConstant; } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is changed whenever setCallback is called. * @memberof CallbackProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } } }); var timeScratch7 = new JulianDate_default(); CallbackProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch7); } return this._callback(time, result); }; CallbackProperty.prototype.setCallback = function(callback, isConstant) { if (!defined_default(callback)) { throw new DeveloperError_default("callback is required."); } if (!defined_default(isConstant)) { throw new DeveloperError_default("isConstant is required."); } const changed = this._callback !== callback || this._isConstant !== isConstant; this._callback = callback; this._isConstant = isConstant; if (changed) { this._definitionChanged.raiseEvent(this); } }; CallbackProperty.prototype.equals = function(other) { return this === other || other instanceof CallbackProperty && this._callback === other._callback && this._isConstant === other._isConstant; }; var CallbackProperty_default = CallbackProperty; // packages/engine/Source/DataSources/TerrainOffsetProperty.js var import_InlineWorkers429 = __toESM(require_InlineWorkers(), 1); var scratchPosition = new Cartesian3_default(); function TerrainOffsetProperty(scene, positionProperty, heightReferenceProperty, extrudedHeightReferenceProperty) { Check_default.defined("scene", scene); Check_default.defined("positionProperty", positionProperty); this._scene = scene; this._heightReference = heightReferenceProperty; this._extrudedHeightReference = extrudedHeightReferenceProperty; this._positionProperty = positionProperty; this._position = new Cartesian3_default(); this._cartographicPosition = new Cartographic_default(); this._normal = new Cartesian3_default(); this._definitionChanged = new Event_default(); this._terrainHeight = 0; this._removeCallbackFunc = void 0; this._removeEventListener = void 0; this._removeModeListener = void 0; const that = this; if (defined_default(scene.globe)) { this._removeEventListener = scene.terrainProviderChanged.addEventListener( function() { that._updateClamping(); } ); this._removeModeListener = scene.morphComplete.addEventListener( function() { that._updateClamping(); } ); } if (positionProperty.isConstant) { const position = positionProperty.getValue( Iso8601_default.MINIMUM_VALUE, scratchPosition ); if (!defined_default(position) || Cartesian3_default.equals(position, Cartesian3_default.ZERO) || !defined_default(scene.globe)) { return; } this._position = Cartesian3_default.clone(position, this._position); this._updateClamping(); this._normal = scene.ellipsoid.geodeticSurfaceNormal( position, this._normal ); } } Object.defineProperties(TerrainOffsetProperty.prototype, { /** * Gets a value indicating if this property is constant. * @memberof TerrainOffsetProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return false; } }, /** * Gets the event that is raised whenever the definition of this property changes. * @memberof TerrainOffsetProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } } }); TerrainOffsetProperty.prototype._updateClamping = function() { if (defined_default(this._removeCallbackFunc)) { this._removeCallbackFunc(); } const scene = this._scene; const position = this._position; if (Cartesian3_default.equals(position, Cartesian3_default.ZERO)) { this._terrainHeight = 0; return; } const ellipsoid = scene.ellipsoid; const cartographicPosition = ellipsoid.cartesianToCartographic( position, this._cartographicPosition ); const height = scene.getHeight(cartographicPosition, this._heightReference); if (defined_default(height)) { this._terrainHeight = height; } else { this._terrainHeight = 0; } const updateFunction = (clampedPosition) => { this._terrainHeight = clampedPosition.height; this.definitionChanged.raiseEvent(); }; this._removeCallbackFunc = scene.updateHeight( cartographicPosition, updateFunction, this._heightReference ); }; var timeScratch8 = new JulianDate_default(); TerrainOffsetProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch8); } const heightReference = Property_default.getValueOrDefault( this._heightReference, time, HeightReference_default.NONE ); const extrudedHeightReference = Property_default.getValueOrDefault( this._extrudedHeightReference, time, HeightReference_default.NONE ); if (heightReference === HeightReference_default.NONE && !isHeightReferenceRelative(extrudedHeightReference)) { this._position = Cartesian3_default.clone(Cartesian3_default.ZERO, this._position); return Cartesian3_default.clone(Cartesian3_default.ZERO, result); } if (this._positionProperty.isConstant) { return Cartesian3_default.multiplyByScalar( this._normal, this._terrainHeight, result ); } const scene = this._scene; const position = this._positionProperty.getValue(time, scratchPosition); if (!defined_default(position) || Cartesian3_default.equals(position, Cartesian3_default.ZERO) || !defined_default(scene.globe)) { return Cartesian3_default.clone(Cartesian3_default.ZERO, result); } if (Cartesian3_default.equalsEpsilon(this._position, position, Math_default.EPSILON10)) { return Cartesian3_default.multiplyByScalar( this._normal, this._terrainHeight, result ); } this._position = Cartesian3_default.clone(position, this._position); this._updateClamping(); const normal2 = scene.ellipsoid.geodeticSurfaceNormal(position, this._normal); return Cartesian3_default.multiplyByScalar(normal2, this._terrainHeight, result); }; TerrainOffsetProperty.prototype.isDestroyed = function() { return false; }; TerrainOffsetProperty.prototype.destroy = function() { if (defined_default(this._removeEventListener)) { this._removeEventListener(); } if (defined_default(this._removeModeListener)) { this._removeModeListener(); } if (defined_default(this._removeCallbackFunc)) { this._removeCallbackFunc(); } return destroyObject_default(this); }; var TerrainOffsetProperty_default = TerrainOffsetProperty; // packages/engine/Source/DataSources/heightReferenceOnEntityPropertyChanged.js function heightReferenceOnEntityPropertyChanged(entity, propertyName, newValue, oldValue2) { GeometryUpdater_default.prototype._onEntityPropertyChanged.call( this, entity, propertyName, newValue, oldValue2 ); if (this._observedPropertyNames.indexOf(propertyName) === -1) { return; } const geometry = this._entity[this._geometryPropertyName]; if (!defined_default(geometry)) { return; } if (defined_default(this._terrainOffsetProperty)) { this._terrainOffsetProperty.destroy(); this._terrainOffsetProperty = void 0; } const heightReferenceProperty = geometry.heightReference; if (defined_default(heightReferenceProperty)) { const centerPosition = new CallbackProperty_default( this._computeCenter.bind(this), !this._dynamic ); this._terrainOffsetProperty = new TerrainOffsetProperty_default( this._scene, centerPosition, heightReferenceProperty ); } } var heightReferenceOnEntityPropertyChanged_default = heightReferenceOnEntityPropertyChanged; // packages/engine/Source/DataSources/BoxGeometryUpdater.js var defaultOffset = Cartesian3_default.ZERO; var offsetScratch4 = new Cartesian3_default(); var positionScratch3 = new Cartesian3_default(); var scratchColor = new Color_default(); function BoxGeometryOptions(entity) { this.id = entity; this.vertexFormat = void 0; this.dimensions = void 0; this.offsetAttribute = void 0; } function BoxGeometryUpdater(entity, scene) { GeometryUpdater_default.call(this, { entity, scene, geometryOptions: new BoxGeometryOptions(entity), geometryPropertyName: "box", observedPropertyNames: ["availability", "position", "orientation", "box"] }); this._onEntityPropertyChanged(entity, "box", entity.box, void 0); } if (defined_default(Object.create)) { BoxGeometryUpdater.prototype = Object.create(GeometryUpdater_default.prototype); BoxGeometryUpdater.prototype.constructor = BoxGeometryUpdater; } Object.defineProperties(BoxGeometryUpdater.prototype, { /** * Gets the terrain offset property * @type {TerrainOffsetProperty} * @memberof BoxGeometryUpdater.prototype * @readonly * @private */ terrainOffsetProperty: { get: function() { return this._terrainOffsetProperty; } } }); BoxGeometryUpdater.prototype.createFillGeometryInstance = function(time) { Check_default.defined("time", time); if (!this._fillEnabled) { throw new DeveloperError_default( "This instance does not represent a filled geometry." ); } const entity = this._entity; const isAvailable = entity.isAvailable(time); const show = new ShowGeometryInstanceAttribute_default( isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._fillProperty.getValue(time) ); const distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); const distanceDisplayConditionAttribute = DistanceDisplayConditionGeometryInstanceAttribute_default.fromDistanceDisplayCondition( distanceDisplayCondition ); const attributes = { show, distanceDisplayCondition: distanceDisplayConditionAttribute, color: void 0, offset: void 0 }; if (this._materialProperty instanceof ColorMaterialProperty_default) { let currentColor; if (defined_default(this._materialProperty.color) && (this._materialProperty.color.isConstant || isAvailable)) { currentColor = this._materialProperty.color.getValue(time, scratchColor); } if (!defined_default(currentColor)) { currentColor = Color_default.WHITE; } attributes.color = ColorGeometryInstanceAttribute_default.fromColor(currentColor); } if (defined_default(this._options.offsetAttribute)) { attributes.offset = OffsetGeometryInstanceAttribute_default.fromCartesian3( Property_default.getValueOrDefault( this._terrainOffsetProperty, time, defaultOffset, offsetScratch4 ) ); } return new GeometryInstance_default({ id: entity, geometry: BoxGeometry_default.fromDimensions(this._options), modelMatrix: entity.computeModelMatrixForHeightReference( time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.ellipsoid ), attributes }); }; BoxGeometryUpdater.prototype.createOutlineGeometryInstance = function(time) { Check_default.defined("time", time); if (!this._outlineEnabled) { throw new DeveloperError_default( "This instance does not represent an outlined geometry." ); } const entity = this._entity; const isAvailable = entity.isAvailable(time); const outlineColor = Property_default.getValueOrDefault( this._outlineColorProperty, time, Color_default.BLACK, scratchColor ); const distanceDisplayCondition = this._distanceDisplayConditionProperty.getValue(time); const attributes = { show: new ShowGeometryInstanceAttribute_default( isAvailable && entity.isShowing && this._showProperty.getValue(time) && this._showOutlineProperty.getValue(time) ), color: ColorGeometryInstanceAttribute_default.fromColor(outlineColor), distanceDisplayCondition: DistanceDisplayConditionGeometryInstanceAttribute_default.fromDistanceDisplayCondition( distanceDisplayCondition ), offset: void 0 }; if (defined_default(this._options.offsetAttribute)) { attributes.offset = OffsetGeometryInstanceAttribute_default.fromCartesian3( Property_default.getValueOrDefault( this._terrainOffsetProperty, time, defaultOffset, offsetScratch4 ) ); } return new GeometryInstance_default({ id: entity, geometry: BoxOutlineGeometry_default.fromDimensions(this._options), modelMatrix: entity.computeModelMatrixForHeightReference( time, entity.box.heightReference, this._options.dimensions.z * 0.5, this._scene.ellipsoid ), attributes }); }; BoxGeometryUpdater.prototype._computeCenter = function(time, result) { return Property_default.getValueOrUndefined(this._entity.position, time, result); }; BoxGeometryUpdater.prototype._isHidden = function(entity, box) { return !defined_default(box.dimensions) || !defined_default(entity.position) || GeometryUpdater_default.prototype._isHidden.call(this, entity, box); }; BoxGeometryUpdater.prototype._isDynamic = function(entity, box) { return !entity.position.isConstant || !Property_default.isConstant(entity.orientation) || !box.dimensions.isConstant || !Property_default.isConstant(box.outlineWidth); }; BoxGeometryUpdater.prototype._setStaticOptions = function(entity, box) { const heightReference = Property_default.getValueOrDefault( box.heightReference, Iso8601_default.MINIMUM_VALUE, HeightReference_default.NONE ); const options = this._options; options.vertexFormat = this._materialProperty instanceof ColorMaterialProperty_default ? PerInstanceColorAppearance_default.VERTEX_FORMAT : MaterialAppearance_default.MaterialSupport.TEXTURED.vertexFormat; options.dimensions = box.dimensions.getValue( Iso8601_default.MINIMUM_VALUE, options.dimensions ); options.offsetAttribute = heightReference !== HeightReference_default.NONE ? GeometryOffsetAttribute_default.ALL : void 0; }; BoxGeometryUpdater.prototype._onEntityPropertyChanged = heightReferenceOnEntityPropertyChanged_default; BoxGeometryUpdater.DynamicGeometryUpdater = DynamicBoxGeometryUpdater; function DynamicBoxGeometryUpdater(geometryUpdater, primitives, groundPrimitives) { DynamicGeometryUpdater_default.call( this, geometryUpdater, primitives, groundPrimitives ); } if (defined_default(Object.create)) { DynamicBoxGeometryUpdater.prototype = Object.create( DynamicGeometryUpdater_default.prototype ); DynamicBoxGeometryUpdater.prototype.constructor = DynamicBoxGeometryUpdater; } DynamicBoxGeometryUpdater.prototype._isHidden = function(entity, box, time) { const position = Property_default.getValueOrUndefined( entity.position, time, positionScratch3 ); const dimensions = this._options.dimensions; return !defined_default(position) || !defined_default(dimensions) || DynamicGeometryUpdater_default.prototype._isHidden.call(this, entity, box, time); }; DynamicBoxGeometryUpdater.prototype._setOptions = function(entity, box, time) { const heightReference = Property_default.getValueOrDefault( box.heightReference, time, HeightReference_default.NONE ); const options = this._options; options.dimensions = Property_default.getValueOrUndefined( box.dimensions, time, options.dimensions ); options.offsetAttribute = heightReference !== HeightReference_default.NONE ? GeometryOffsetAttribute_default.ALL : void 0; }; var BoxGeometryUpdater_default = BoxGeometryUpdater; // packages/engine/Source/DataSources/CallbackPositionProperty.js var import_InlineWorkers432 = __toESM(require_InlineWorkers(), 1); function CallbackPositionProperty(callback, isConstant, referenceFrame) { this._callback = void 0; this._isConstant = void 0; this._referenceFrame = referenceFrame ?? ReferenceFrame_default.FIXED; this._definitionChanged = new Event_default(); this.setCallback(callback, isConstant); } Object.defineProperties(CallbackPositionProperty.prototype, { /** * Gets a value indicating if this property is constant. * @memberof CallbackPositionProperty.prototype * * @type {boolean} * @readonly */ isConstant: { get: function() { return this._isConstant; } }, /** * Gets the event that is raised whenever the definition of this property changes. * The definition is considered to have changed if a call to getValue would return * a different result for the same time. * @memberof CallbackPositionProperty.prototype * * @type {Event} * @readonly */ definitionChanged: { get: function() { return this._definitionChanged; } }, /** * Gets the reference frame in which the position is defined. * @memberof CallbackPositionProperty.prototype * @type {ReferenceFrame} * @default ReferenceFrame.FIXED; */ referenceFrame: { get: function() { return this._referenceFrame; } } }); var timeScratch9 = new JulianDate_default(); CallbackPositionProperty.prototype.getValue = function(time, result) { if (!defined_default(time)) { time = JulianDate_default.now(timeScratch9); } return this.getValueInReferenceFrame(time, ReferenceFrame_default.FIXED, result); }; CallbackPositionProperty.prototype.setCallback = function(callback, isConstant) { if (!defined_default(callback)) { throw new DeveloperError_default("callback is required."); } if (!defined_default(isConstant)) { throw new DeveloperError_default("isConstant is required."); } const changed = this._callback !== callback || this._isConstant !== isConstant; this._callback = callback; this._isConstant = isConstant; if (changed) { this._definitionChanged.raiseEvent(this); } }; CallbackPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) { if (!defined_default(time)) { throw new DeveloperError_default("time is required."); } if (!defined_default(referenceFrame)) { throw new DeveloperError_default("referenceFrame is required."); } const value = this._callback(time, result); return PositionProperty_default.convertToReferenceFrame( time, value, this._referenceFrame, referenceFrame, result ); }; CallbackPositionProperty.prototype.equals = function(other) { return this === other || other instanceof CallbackPositionProperty && this._callback === other._callback && this._isConstant === other._isConstant && this._referenceFrame === other._referenceFrame; }; var CallbackPositionProperty_default = CallbackPositionProperty; // packages/engine/Source/DataSources/Cesium3DTilesetVisualizer.js var import_InlineWorkers864 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Scene/Cesium3DTileset.js var import_InlineWorkers863 = __toESM(require_InlineWorkers(), 1); // packages/engine/Source/Core/Credit.js var import_InlineWorkers434 = __toESM(require_InlineWorkers(), 1); // node_modules/dompurify/dist/purify.es.mjs var import_InlineWorkers433 = __toESM(require_InlineWorkers(), 1); /*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */ function _arrayLikeToArray(r2, a3) { (null == a3 || a3 > r2.length) && (a3 = r2.length); for (var e = 0, n2 = Array(a3); e < a3; e++) n2[e] = r2[e]; return n2; } function _arrayWithHoles(r2) { if (Array.isArray(r2)) return r2; } function _iterableToArrayLimit(r2, l2) { var t2 = null == r2 ? null : "undefined" != typeof Symbol && r2[Symbol.iterator] || r2["@@iterator"]; if (null != t2) { var e, n2, i, u4, a3 = [], f2 = true, o = false; try { if (i = (t2 = t2.call(r2)).next, 0 === l2) ; else for (; !(f2 = (e = i.call(t2)).done) && (a3.push(e.value), a3.length !== l2); f2 = true) ; } catch (r3) { o = true, n2 = r3; } finally { try { if (!f2 && null != t2.return && (u4 = t2.return(), Object(u4) !== u4)) return; } finally { if (o) throw n2; } } return a3; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(r2, e) { return _arrayWithHoles(r2) || _iterableToArrayLimit(r2, e) || _unsupportedIterableToArray(r2, e) || _nonIterableRest(); } function _unsupportedIterableToArray(r2, a3) { if (r2) { if ("string" == typeof r2) return _arrayLikeToArray(r2, a3); var t2 = {}.toString.call(r2).slice(8, -1); return "Object" === t2 && r2.constructor && (t2 = r2.constructor.name), "Map" === t2 || "Set" === t2 ? Array.from(r2) : "Arguments" === t2 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t2) ? _arrayLikeToArray(r2, a3) : void 0; } } var entries = Object.entries; var setPrototypeOf = Object.setPrototypeOf; var isFrozen = Object.isFrozen; var getPrototypeOf = Object.getPrototypeOf; var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; var freeze = Object.freeze; var seal = Object.seal; var create = Object.create; var _ref = typeof Reflect !== "undefined" && Reflect; var apply = _ref.apply; var construct = _ref.construct; if (!freeze) { freeze = function freeze2(x) { return x; }; } if (!seal) { seal = function seal2(x) { return x; }; } if (!apply) { apply = function apply2(func, thisArg) { for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } return func.apply(thisArg, args); }; } if (!construct) { construct = function construct2(Func) { for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } return new Func(...args); }; } var arrayForEach = unapply(Array.prototype.forEach); var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); var arrayPop = unapply(Array.prototype.pop); var arrayPush = unapply(Array.prototype.push); var arraySplice = unapply(Array.prototype.splice); var arrayIsArray = Array.isArray; var stringToLowerCase = unapply(String.prototype.toLowerCase); var stringToString = unapply(String.prototype.toString); var stringMatch = unapply(String.prototype.match); var stringReplace = unapply(String.prototype.replace); var stringIndexOf = unapply(String.prototype.indexOf); var stringTrim = unapply(String.prototype.trim); var numberToString = unapply(Number.prototype.toString); var booleanToString = unapply(Boolean.prototype.toString); var bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString); var symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString); var objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); var objectToString = unapply(Object.prototype.toString); var regExpTest = unapply(RegExp.prototype.test); var typeErrorCreate = unconstruct(TypeError); function unapply(func) { return function(thisArg) { if (thisArg instanceof RegExp) { thisArg.lastIndex = 0; } for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } return apply(func, thisArg, args); }; } function unconstruct(Func) { return function() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } return construct(Func, args); }; } function addToSet(set2, array) { let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase; if (setPrototypeOf) { setPrototypeOf(set2, null); } if (!arrayIsArray(array)) { return set2; } let l2 = array.length; while (l2--) { let element = array[l2]; if (typeof element === "string") { const lcElement = transformCaseFunc(element); if (lcElement !== element) { if (!isFrozen(array)) { array[l2] = lcElement; } element = lcElement; } } set2[element] = true; } return set2; } function cleanArray(array) { for (let index = 0; index < array.length; index++) { const isPropertyExist = objectHasOwnProperty(array, index); if (!isPropertyExist) { array[index] = null; } } return array; } function clone2(object2) { const newObject = create(null); for (const _ref2 of entries(object2)) { var _ref3 = _slicedToArray(_ref2, 2); const property = _ref3[0]; const value = _ref3[1]; const isPropertyExist = objectHasOwnProperty(object2, property); if (isPropertyExist) { if (arrayIsArray(value)) { newObject[property] = cleanArray(value); } else if (value && typeof value === "object" && value.constructor === Object) { newObject[property] = clone2(value); } else { newObject[property] = value; } } } return newObject; } function stringifyValue(value) { switch (typeof value) { case "string": { return value; } case "number": { return numberToString(value); } case "boolean": { return booleanToString(value); } case "bigint": { return bigintToString ? bigintToString(value) : "0"; } case "symbol": { return symbolToString ? symbolToString(value) : "Symbol()"; } case "undefined": { return objectToString(value); } case "function": case "object": { if (value === null) { return objectToString(value); } const valueAsRecord = value; const valueToString = lookupGetter(valueAsRecord, "toString"); if (typeof valueToString === "function") { const stringified = valueToString(valueAsRecord); return typeof stringified === "string" ? stringified : objectToString(stringified); } return objectToString(value); } default: { return objectToString(value); } } } function lookupGetter(object2, prop) { while (object2 !== null) { const desc = getOwnPropertyDescriptor(object2, prop); if (desc) { if (desc.get) { return unapply(desc.get); } if (typeof desc.value === "function") { return unapply(desc.value); } } object2 = getPrototypeOf(object2); } function fallbackValue() { return null; } return fallbackValue; } function isRegex(value) { try { regExpTest(value, ""); return true; } catch (_unused) { return false; } } var html$1 = freeze(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "search", "section", "select", "shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]); var svg$1 = freeze(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "enterkeyhint", "exportparts", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "inputmode", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "part", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]); var svgFilters = freeze(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]); var svgDisallowed = freeze(["animate", "color-profile", "cursor", "discard", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]); var mathMl$1 = freeze(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover", "mprescripts"]); var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]); var text = freeze(["#text"]); var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "command", "commandfor", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns"]); var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dominant-baseline", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-orientation", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]); var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnalign", "columnlines", "columnspacing", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lquote", "lspace", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]); var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]); var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g); var ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g); var TMPLIT_EXPR = seal(/\${[\w\W]*/g); var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); var ARIA_ATTR = seal(/^aria-[\-\w]+$/); var IS_ALLOWED_URI = seal( /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape ); var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); var ATTR_WHITESPACE = seal( /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex ); var DOCTYPE_NAME = seal(/^html$/i); var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); var ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); var COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); var FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); var SELF_CLOSING_TAG = seal(/\/>/i); var NODE_TYPE = { element: 1, attribute: 2, text: 3, cdataSection: 4, entityReference: 5, // Deprecated entityNode: 6, // Deprecated processingInstruction: 7, comment: 8, document: 9, documentType: 10, documentFragment: 11, notation: 12 // Deprecated }; var getGlobal = function getGlobal2() { return typeof window === "undefined" ? null : window; }; var _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTypes, purifyHostElement) { if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") { return null; } let suffix = null; const ATTR_NAME = "data-tt-policy-suffix"; if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { suffix = purifyHostElement.getAttribute(ATTR_NAME); } const policyName = "dompurify" + (suffix ? "#" + suffix : ""); try { return trustedTypes.createPolicy(policyName, { createHTML(html2) { return html2; }, createScriptURL(scriptUrl) { return scriptUrl; } }); } catch (_) { console.warn("TrustedTypes policy " + policyName + " could not be created."); return null; } }; var _createHooksMap = function _createHooksMap2() { return { afterSanitizeAttributes: [], afterSanitizeElements: [], afterSanitizeShadowDOM: [], beforeSanitizeAttributes: [], beforeSanitizeElements: [], beforeSanitizeShadowDOM: [], uponSanitizeAttribute: [], uponSanitizeElement: [], uponSanitizeShadowNode: [] }; }; var _resolveSetOption = function _resolveSetOption2(cfg, key, fallback, options) { return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone2(options.base) : {}, cfg[key], options.transform) : fallback; }; function createDOMPurify() { let window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); const DOMPurify = (root) => createDOMPurify(root); DOMPurify.version = "3.4.13"; DOMPurify.removed = []; if (!window2 || !window2.document || window2.document.nodeType !== NODE_TYPE.document || !window2.Element) { DOMPurify.isSupported = false; return DOMPurify; } let document2 = window2.document; const originalDocument = document2; const currentScript = originalDocument.currentScript; window2.DocumentFragment; const HTMLTemplateElement = window2.HTMLTemplateElement, Node6 = window2.Node, Element2 = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap; _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap; window2.HTMLFormElement; const DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes; const ElementPrototype = Element2.prototype; const cloneNode = lookupGetter(ElementPrototype, "cloneNode"); const remove4 = lookupGetter(ElementPrototype, "remove"); const getNextSibling = lookupGetter(ElementPrototype, "nextSibling"); const getChildNodes = lookupGetter(ElementPrototype, "childNodes"); const getParentNode = lookupGetter(ElementPrototype, "parentNode"); const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot"); const getAttributes2 = lookupGetter(ElementPrototype, "attributes"); const getNodeType = Node6 && Node6.prototype ? lookupGetter(Node6.prototype, "nodeType") : null; const getNodeName = Node6 && Node6.prototype ? lookupGetter(Node6.prototype, "nodeName") : null; const getOwnerDocument = Node6 && Node6.prototype ? lookupGetter(Node6.prototype, "ownerDocument") : null; if (typeof HTMLTemplateElement === "function") { const template = document2.createElement("template"); if (template.content && template.content.ownerDocument) { document2 = template.content.ownerDocument; } } let trustedTypesPolicy; let emptyHTML = ""; let defaultTrustedTypesPolicy; let defaultTrustedTypesPolicyResolved = false; let IN_TRUSTED_TYPES_POLICY = 0; const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy2() { if (IN_TRUSTED_TYPES_POLICY > 0) { throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted Types" section of the README.'); } }; const _createTrustedHTML = function _createTrustedHTML2(html2) { _assertNotInTrustedTypesPolicy(); IN_TRUSTED_TYPES_POLICY++; try { return trustedTypesPolicy.createHTML(html2); } finally { IN_TRUSTED_TYPES_POLICY--; } }; const _createTrustedScriptURL = function _createTrustedScriptURL2(scriptUrl) { _assertNotInTrustedTypesPolicy(); IN_TRUSTED_TYPES_POLICY++; try { return trustedTypesPolicy.createScriptURL(scriptUrl); } finally { IN_TRUSTED_TYPES_POLICY--; } }; const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy2() { if (!defaultTrustedTypesPolicyResolved) { defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); defaultTrustedTypesPolicyResolved = true; } return defaultTrustedTypesPolicy; }; const _document = document2, implementation2 = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName; const importNode = originalDocument.importNode; let hooks2 = _createHooksMap(); DOMPurify.isSupported = typeof entries === "function" && typeof getParentNode === "function" && implementation2 && implementation2.createHTMLDocument !== void 0; const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT; let IS_ALLOWED_URI$1 = IS_ALLOWED_URI; let ALLOWED_TAGS = null; const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]); let ALLOWED_ATTR = null; const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]); let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { tagNameCheck: { writable: true, configurable: false, enumerable: true, value: null }, attributeNameCheck: { writable: true, configurable: false, enumerable: true, value: null }, allowCustomizedBuiltInElements: { writable: true, configurable: false, enumerable: true, value: false } })); let FORBID_TAGS = null; let FORBID_ATTR = null; const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, { tagCheck: { writable: true, configurable: false, enumerable: true, value: null }, attributeCheck: { writable: true, configurable: false, enumerable: true, value: null } })); let ALLOW_ARIA_ATTR = true; let ALLOW_DATA_ATTR = true; let ALLOW_UNKNOWN_PROTOCOLS = false; let ALLOW_SELF_CLOSE_IN_ATTR = true; let SAFE_FOR_TEMPLATES = false; let SAFE_FOR_XML = true; let WHOLE_DOCUMENT = false; let SET_CONFIG = false; let SET_CONFIG_ALLOWED_TAGS = null; let SET_CONFIG_ALLOWED_ATTR = null; let FORCE_BODY = false; let RETURN_DOM = false; let RETURN_DOM_FRAGMENT = false; let RETURN_TRUSTED_TYPE = false; let SANITIZE_DOM = true; let SANITIZE_NAMED_PROPS = false; const SANITIZE_NAMED_PROPS_PREFIX = "user-content-"; let KEEP_CONTENT = true; let IN_PLACE = false; let USE_PROFILES = {}; let FORBID_CONTENTS = null; const DEFAULT_FORBID_CONTENTS = addToSet({}, [ "annotation-xml", "audio", "colgroup", "desc", "foreignobject", "head", "iframe", "math", "mi", "mn", "mo", "ms", "mtext", "noembed", "noframes", "noscript", "plaintext", "script", // mirrors the selected