mage-engine 3.25.0 → 3.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/mage.js +1277 -1200
  2. package/eslint.config.js +1 -1
  3. package/package.json +1 -1
package/dist/mage.js CHANGED
@@ -53720,74 +53720,7 @@ const LIGHT_NOT_FOUND = `${PREFIX} This light was not created properly.`;
53720
53720
  const LIGHT_HOLDER_MODEL_NOT_FOUND = `${PREFIX} This light holder model can't be found.`;
53721
53721
  const SOUND_HOLDER_MODEL_NOT_FOUND = `${PREFIX} This sound holder model can't be found.`;
53722
53722
  const LABEL_DOMELEMENT_MISSING = `${PREFIX} Could not create Label, domElement is missing. Did you forget to set the this.element ref on your component?`;
53723
- const NO_VALID_LEVEL_DATA_PROVIDED = `${PREFIX} No valid level data (json or url) provided`;/*
53724
- A dynamic script that can be attached to an entity.
53725
- This is a script that needs to be updated during the game loop.
53726
- */
53727
- let BaseScript = /*#__PURE__*/function () {
53728
- function BaseScript(name) {
53729
- _classCallCheck(this, BaseScript);
53730
- this.__name = name || this.constructor.name;
53731
- this.hasStarted = false;
53732
- this.isDisposed = false;
53733
- this.options = {};
53734
- }
53735
- return _createClass(BaseScript, [{
53736
- key: "__check",
53737
- value: function __check() {
53738
- return true;
53739
- }
53740
- }, {
53741
- key: "__isStatic",
53742
- value: function __isStatic() {
53743
- return false;
53744
- }
53745
- }, {
53746
- key: "__hasStarted",
53747
- value: function __hasStarted() {
53748
- return this.hasStarted;
53749
- }
53750
- }, {
53751
- key: "__isDisposed",
53752
- value: function __isDisposed() {
53753
- return this.isDisposed;
53754
- }
53755
- }, {
53756
- key: "__setStartedFlag",
53757
- value: function __setStartedFlag(flag) {
53758
- this.hasStarted = flag;
53759
- }
53760
- }, {
53761
- key: "__setDisposedFlag",
53762
- value: function __setDisposedFlag(flag) {
53763
- this.isDisposed = flag;
53764
- }
53765
- }, {
53766
- key: "getName",
53767
- value: function getName() {
53768
- return this.__name;
53769
- }
53770
- }, {
53771
- key: "start",
53772
- value: function start(element, options) {}
53773
- }, {
53774
- key: "update",
53775
- value: function update(dt) {}
53776
- }, {
53777
- key: "physicsUpdate",
53778
- value: function physicsUpdate(dt) {}
53779
- }, {
53780
- key: "onDispose",
53781
- value: function onDispose() {}
53782
- }, {
53783
- key: "toJSON",
53784
- value: function toJSON(parseJSON = false) {
53785
- return {
53786
- name: this.name()
53787
- };
53788
- }
53789
- }]);
53790
- }();/**!
53723
+ const NO_VALID_LEVEL_DATA_PROVIDED = `${PREFIX} No valid level data (json or url) provided`;/**!
53791
53724
  * hotkeys-js v3.13.7
53792
53725
  * A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.
53793
53726
  *
@@ -54695,7 +54628,7 @@ const createElementFromSelector = (selector, type = "div", style = DEFAULT_FULL_
54695
54628
  try {
54696
54629
  const win = window || global.window;
54697
54630
  return win;
54698
- } catch (e) {
54631
+ } catch {
54699
54632
  return null;
54700
54633
  }
54701
54634
  };const DEFAULT_HEIGHT$3 = 600;
@@ -55029,14 +54962,14 @@ var Config$1 = new Config();let Universe = /*#__PURE__*/function () {
55029
54962
  // @deprecated - indexing is now handled inside set()
55030
54963
  }, {
55031
54964
  key: "storeUUIDToElementNameReference",
55032
- value: function storeUUIDToElementNameReference(uuid, name) {
54965
+ value: function storeUUIDToElementNameReference(_uuid, _name) {
55033
54966
  // no-op: set() handles name indexing
55034
54967
  }
55035
54968
 
55036
54969
  // @deprecated - use updateNameIndex() instead
55037
54970
  }, {
55038
54971
  key: "replaceUUIDToElementNameReference",
55039
- value: function replaceUUIDToElementNameReference(uuid, newName) {
54972
+ value: function replaceUUIDToElementNameReference(_uuid, _newName) {
55040
54973
  // no-op: use updateNameIndex() instead
55041
54974
  }
55042
54975
  }, {
@@ -55595,7 +55528,7 @@ const isAbsoluteURL$3 = path => {
55595
55528
  try {
55596
55529
  new URL(path);
55597
55530
  return true;
55598
- } catch (_) {
55531
+ } catch {
55599
55532
  return false;
55600
55533
  }
55601
55534
  };
@@ -55786,7 +55719,7 @@ function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
55786
55719
  url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
55787
55720
  return new Worker(url, options);
55788
55721
  };
55789
- }var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIGNvbnN0IExJQlJBUllfTkFNRSA9ICJhbW1vLmpzIjsKICAgIGNvbnN0IFRZUEVTID0gewogICAgICBCT1g6ICJCT1giLAogICAgICBTUEhFUkU6ICJTUEhFUkUiLAogICAgICBWRUhJQ0xFOiAiVkVISUNMRSIsCiAgICAgIE1FU0g6ICJNRVNIIiwKICAgICAgUExBWUVSOiAiUExBWUVSIgogICAgfTsKICAgIGNvbnN0IERFRkFVTFRfVkVISUNMRV9TVEFURSA9IHsKICAgICAgdmVoaWNsZVN0ZWVyaW5nOiAwLAogICAgICBhY2NlbGVyYXRpb246IGZhbHNlLAogICAgICBicmVha2luZzogZmFsc2UsCiAgICAgIHJpZ2h0OiBmYWxzZSwKICAgICAgbGVmdDogZmFsc2UKICAgIH07CiAgICBjb25zdCBERUZBVUxUX1JJR0lEQk9EWV9TVEFURSA9IHsKICAgICAgdmVsb2NpdHk6IHsKICAgICAgICB4OiAwLAogICAgICAgIHk6IDAsCiAgICAgICAgejogMAogICAgICB9LAogICAgICBtb3ZlbWVudDogewogICAgICAgIGZvcndhcmQ6IGZhbHNlLAogICAgICAgIGJhY2t3YXJkczogZmFsc2UsCiAgICAgICAgbGVmdDogZmFsc2UsCiAgICAgICAgcmlnaHQ6IGZhbHNlCiAgICAgIH0sCiAgICAgIGRpcmVjdGlvbjogewogICAgICAgIHg6IDAsCiAgICAgICAgeTogMCwKICAgICAgICB6OiAwCiAgICAgIH0KICAgIH07CiAgICBjb25zdCBERUZBVUxUX1NDQUxFID0gewogICAgICB4OiAxLAogICAgICB5OiAxLAogICAgICB6OiAxCiAgICB9OwogICAgY29uc3QgREVGQVVMVF9MSU5FQVJfVkVMT0NJVFkgPSB7CiAgICAgIHg6IDAsCiAgICAgIHk6IDAsCiAgICAgIHo6IDAKICAgIH07CiAgICBjb25zdCBERUZBVUxUX0lNUFVMU0UgPSB7CiAgICAgIHg6IDAsCiAgICAgIHk6IDAsCiAgICAgIHo6IDAKICAgIH07CiAgICBjb25zdCBESVNBQkxFX0RFQUNUSVZBVElPTiA9IDQ7CiAgICBjb25zdCBHUkFWSVRZID0gewogICAgICB4OiAwLAogICAgICB5OiAtMTAsCiAgICAgIHo6IDAKICAgIH07CiAgICBjb25zdCBGUk9OVF9MRUZUID0gMDsKICAgIGNvbnN0IEZST05UX1JJR0hUID0gMTsKICAgIGNvbnN0IEJBQ0tfTEVGVCA9IDI7CiAgICBjb25zdCBCQUNLX1JJR0hUID0gMzsKICAgIGNvbnN0IERFRkFVTFRfU1RFRVJJTkdfSU5DUkVNRU5UID0gMC4wNDsKICAgIGNvbnN0IERFRkFVTFRfU1RFRVJJTkdfQ0xBTVAgPSAwLjU7CiAgICBjb25zdCBERUZBVUxUX01BWF9FTkdJTkVfRk9SQ0UgPSAyMDAwOwogICAgY29uc3QgREVGQVVMVF9NQVhfQlJFQUtJTkdfRk9SQ0UgPSAxMDA7CiAgICBjb25zdCBFWFBMT1NJT05fU0laRVMgPSB7CiAgICAgIFNNQUxMOiA0LAogICAgICBNRURJVU06IDYsCiAgICAgIExBUkdFOiA4LAogICAgICBNQVNTSVZFOiAxMgogICAgfTsKICAgIGNvbnN0IEVYUExPU0lPTl9TVFJFTkdUSFMgPSB7CiAgICAgIFZFUllfV0VBSzogMiwKICAgICAgV0VBSzogNCwKICAgICAgTUVESVVNOiA4LAogICAgICBMQVJHRTogMTYsCiAgICAgIE1BU1NJVkU6IDMyLAogICAgICBPS19OTzogNjQKICAgIH07CgogICAgY29uc3QgUEhZU0lDU19FVkVOVFMgPSB7CiAgICAgIERJU1BBVENIOiAicGh5c2ljczpkaXNwYXRjaCIsCiAgICAgIFRFUk1JTkFURTogInBoeXNpY3M6dGVybWluYXRlIiwKICAgICAgTE9BRDogewogICAgICAgIEFNTU86ICJwaHlzaWNzOmxvYWQ6YW1tbyIKICAgICAgfSwKICAgICAgUkVBRFk6ICJwaHlzaWNzOnJlYWR5IiwKICAgICAgSU5JVDogInBoeXNpY3M6aW5pdCIsCiAgICAgIFVQREFURTogInBoeXNpY3M6dXBkYXRlIiwKICAgICAgQUREOiB7CiAgICAgICAgQk9YOiAicGh5c2ljczphZGQ6Ym94IiwKICAgICAgICBWRUhJQ0xFOiAicGh5c2ljczphZGQ6dmVoaWNsZSIsCiAgICAgICAgTU9ERUw6ICJwaHlzaWNzOmFkZDptb2RlbCIsCiAgICAgICAgUExBWUVSOiAicGh5c2ljczphZGQ6cGxheWVyIiwKICAgICAgICBTUEhFUkU6ICJwaHlzaWNzOmFkZDpzcGhlcmUiCiAgICAgIH0sCiAgICAgIEVMRU1FTlQ6IHsKICAgICAgICBESVNQT1NFOiAicGh5c2ljczplbGVtZW50OmRpc3Bvc2UiLAogICAgICAgIENPTExJU0lPTjogInBoeXNpY3M6ZWxlbWVudDpjb2xsaXNpb24iLAogICAgICAgIFVQREFURTogInBoeXNpY3M6ZWxlbWVudDp1cGRhdGUiLAogICAgICAgIENSRUFURUQ6ICJwaHlzaWNzOmVsZW1lbnQ6Y3JlYXRlZCIsCiAgICAgICAgU0VUOiB7CiAgICAgICAgICBQT1NJVElPTjogInBoeXNpY3M6ZWxlbWVudDpzZXQ6cG9zaXRpb24iLAogICAgICAgICAgUVVBVEVSTklPTjogInBoeXNpY3M6ZWxlbWVudDpzZXQ6cXVhdGVybmlvbiIsCiAgICAgICAgICBMSU5FQVJfVkVMT0NJVFk6ICJwaHlzaWNzOmVsZW1lbnQ6c2V0OmxpbmVhcl92ZWxvY2l0eSIKICAgICAgICB9LAogICAgICAgIFJFU0VUOiAicGh5c2ljczplbGVtZW50OnJlc2V0IiwKICAgICAgICBBUFBMWTogewogICAgICAgICAgSU1QVUxTRTogInBoeXNpY3M6ZWxlbWVudDphcHBseTppbXB1bHNlIgogICAgICAgIH0KICAgICAgfSwKICAgICAgVkVISUNMRTogewogICAgICAgIFNFVDogewogICAgICAgICAgUE9TSVRJT046ICJwaHlzaWNzOnZlaGljbGU6c2V0OnBvc2l0aW9uIiwKICAgICAgICAgIFFVQVRFUk5JT046ICJwaHlzaWNzOnZlaGljbGU6c2V0OnF1YXRlcm5pb24iCiAgICAgICAgfSwKICAgICAgICBSRVNFVDogInBoeXNpY3M6dmVoaWNsZTpyZXNldCIsCiAgICAgICAgU1BFRUQ6ICJwaHlzaWNzOnZlaGljbGU6c3BlZWQiLAogICAgICAgIERJUkVDVElPTjogInBoeXNpY3M6dmVoaWNsZTpkaXJlY3Rpb24iCiAgICAgIH0sCiAgICAgIEVGRkVDVFM6IHsKICAgICAgICBFWFBMT1NJT046ICJwaHlzaWNzOmVmZmVjdHM6ZXhwbG9zaW9uIgogICAgICB9CiAgICB9OwoKICAgIGZ1bmN0aW9uIF9jbGFzc0NhbGxDaGVjayhhLCBuKSB7CiAgICAgIGlmICghKGEgaW5zdGFuY2VvZiBuKSkgdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIik7CiAgICB9CiAgICBmdW5jdGlvbiBfZGVmaW5lUHJvcGVydGllcyhlLCByKSB7CiAgICAgIGZvciAodmFyIHQgPSAwOyB0IDwgci5sZW5ndGg7IHQrKykgewogICAgICAgIHZhciBvID0gclt0XTsKICAgICAgICBvLmVudW1lcmFibGUgPSBvLmVudW1lcmFibGUgfHwgITEsIG8uY29uZmlndXJhYmxlID0gITAsICJ2YWx1ZSIgaW4gbyAmJiAoby53cml0YWJsZSA9ICEwKSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIF90b1Byb3BlcnR5S2V5KG8ua2V5KSwgbyk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9jcmVhdGVDbGFzcyhlLCByLCB0KSB7CiAgICAgIHJldHVybiByICYmIF9kZWZpbmVQcm9wZXJ0aWVzKGUucHJvdG90eXBlLCByKSwgdCAmJiBfZGVmaW5lUHJvcGVydGllcyhlLCB0KSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICJwcm90b3R5cGUiLCB7CiAgICAgICAgd3JpdGFibGU6ICExCiAgICAgIH0pLCBlOwogICAgfQogICAgZnVuY3Rpb24gX2RlZmluZVByb3BlcnR5KGUsIHIsIHQpIHsKICAgICAgcmV0dXJuIChyID0gX3RvUHJvcGVydHlLZXkocikpIGluIGUgPyBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgciwgewogICAgICAgIHZhbHVlOiB0LAogICAgICAgIGVudW1lcmFibGU6ICEwLAogICAgICAgIGNvbmZpZ3VyYWJsZTogITAsCiAgICAgICAgd3JpdGFibGU6ICEwCiAgICAgIH0pIDogZVtyXSA9IHQsIGU7CiAgICB9CiAgICBmdW5jdGlvbiBfdG9QcmltaXRpdmUodCwgcikgewogICAgICBpZiAoIm9iamVjdCIgIT0gdHlwZW9mIHQgfHwgIXQpIHJldHVybiB0OwogICAgICB2YXIgZSA9IHRbU3ltYm9sLnRvUHJpbWl0aXZlXTsKICAgICAgaWYgKHZvaWQgMCAhPT0gZSkgewogICAgICAgIHZhciBpID0gZS5jYWxsKHQsIHIgfHwgImRlZmF1bHQiKTsKICAgICAgICBpZiAoIm9iamVjdCIgIT0gdHlwZW9mIGkpIHJldHVybiBpOwogICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIkBAdG9QcmltaXRpdmUgbXVzdCByZXR1cm4gYSBwcmltaXRpdmUgdmFsdWUuIik7CiAgICAgIH0KICAgICAgcmV0dXJuICgic3RyaW5nIiA9PT0gciA/IFN0cmluZyA6IE51bWJlcikodCk7CiAgICB9CiAgICBmdW5jdGlvbiBfdG9Qcm9wZXJ0eUtleSh0KSB7CiAgICAgIHZhciBpID0gX3RvUHJpbWl0aXZlKHQsICJzdHJpbmciKTsKICAgICAgcmV0dXJuICJzeW1ib2wiID09IHR5cGVvZiBpID8gaSA6IGkgKyAiIjsKICAgIH0KCiAgICBsZXQgRGlzcGF0Y2hlciA9IC8qI19fUFVSRV9fKi9fY3JlYXRlQ2xhc3MoZnVuY3Rpb24gRGlzcGF0Y2hlcigpIHsKICAgICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIERpc3BhdGNoZXIpOwogICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInNlbmRQaHlzaWNzVXBkYXRlIiwgZHQgPT4gcG9zdE1lc3NhZ2UoewogICAgICAgIGV2ZW50OiBQSFlTSUNTX0VWRU5UUy5VUERBVEUsCiAgICAgICAgZHQKICAgICAgfSkpOwogICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInNlbmRSZWFkeUV2ZW50IiwgKCkgPT4gcG9zdE1lc3NhZ2UoewogICAgICAgIGV2ZW50OiBQSFlTSUNTX0VWRU5UUy5SRUFEWQogICAgICB9KSk7CiAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAic2VuZFRlcm1pbmF0ZUV2ZW50IiwgKCkgPT4gcG9zdE1lc3NhZ2UoewogICAgICAgIGV2ZW50OiBQSFlTSUNTX0VWRU5UUy5URVJNSU5BVEUKICAgICAgfSkpOwogICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInNlbmRCb2R5VXBkYXRlIiwgKHV1aWQsIHBvc2l0aW9uLCByb3RhdGlvbiwgZHQsIGV4dHJhRGF0YSkgPT4gcG9zdE1lc3NhZ2UoewogICAgICAgIGV2ZW50OiBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULlVQREFURSwKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uOiB7CiAgICAgICAgICB4OiBwb3NpdGlvbi54KCksCiAgICAgICAgICB5OiBwb3NpdGlvbi55KCksCiAgICAgICAgICB6OiBwb3NpdGlvbi56KCkKICAgICAgICB9LAogICAgICAgIHF1YXRlcm5pb246IHsKICAgICAgICAgIHg6IHJvdGF0aW9uLngoKSwKICAgICAgICAgIHk6IHJvdGF0aW9uLnkoKSwKICAgICAgICAgIHo6IHJvdGF0aW9uLnooKSwKICAgICAgICAgIHc6IHJvdGF0aW9uLncoKQogICAgICAgIH0sCiAgICAgICAgLi4uZXh0cmFEYXRhLAogICAgICAgIGR0CiAgICAgIH0pKTsKICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzZW5kRGlzcGF0Y2hFdmVudCIsICh1dWlkLCBldmVudE5hbWUsIGV2ZW50RGF0YSkgPT4gcG9zdE1lc3NhZ2UoewogICAgICAgIGV2ZW50OiBQSFlTSUNTX0VWRU5UUy5ESVNQQVRDSCwKICAgICAgICB1dWlkLAogICAgICAgIGV2ZW50TmFtZSwKICAgICAgICBldmVudERhdGEKICAgICAgfSkpOwogICAgfSk7CiAgICB2YXIgZGlzcGF0Y2hlciA9IG5ldyBEaXNwYXRjaGVyKCk7CgogICAgY29uc3QgYXBwbHlNYXRyaXg0VG9WZWN0b3IzID0gKHsKICAgICAgeCA9IDAsCiAgICAgIHkgPSAwLAogICAgICB6ID0gMAogICAgfSwgbWF0cml4ID0gW10pID0+IHsKICAgICAgY29uc3QgdyA9IDEgLyAobWF0cml4WzNdICogeCArIG1hdHJpeFs3XSAqIHkgKyBtYXRyaXhbMTFdICogeiArIG1hdHJpeFsxNV0pOwogICAgICByZXR1cm4gewogICAgICAgIHg6IChtYXRyaXhbMF0gKiB4ICsgbWF0cml4WzRdICogeSArIG1hdHJpeFs4XSAqIHogKyBtYXRyaXhbMTJdKSAqIHcsCiAgICAgICAgeTogKG1hdHJpeFsxXSAqIHggKyBtYXRyaXhbNV0gKiB5ICsgbWF0cml4WzldICogeiArIG1hdHJpeFsxM10pICogdywKICAgICAgICB6OiAobWF0cml4WzJdICogeCArIG1hdHJpeFs2XSAqIHkgKyBtYXRyaXhbMTBdICogeiArIG1hdHJpeFsxNF0pICogdwogICAgICB9OwogICAgfTsKCiAgICBjb25zdCBjcmVhdGVSaWdpZEJvZHkgPSAoc2hhcGUsIG9wdGlvbnMpID0+IHsKICAgICAgY29uc3QgewogICAgICAgIHV1aWQsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgcXVhdGVybmlvbiwKICAgICAgICBtYXNzLAogICAgICAgIGZyaWN0aW9uLAogICAgICAgIHJlc3RpdHV0aW9uID0gMC45LAogICAgICAgIGRhbXBpbmcgPSB7CiAgICAgICAgICBsaW5lYXI6IDAuMiwKICAgICAgICAgIGFuZ3VsYXI6IDAuMgogICAgICAgIH0KICAgICAgfSA9IG9wdGlvbnM7CiAgICAgIGNvbnN0IHRyYW5zZm9ybSA9IG5ldyBBbW1vLmJ0VHJhbnNmb3JtKCk7CiAgICAgIHRyYW5zZm9ybS5zZXRJZGVudGl0eSgpOwogICAgICB0cmFuc2Zvcm0uc2V0T3JpZ2luKG5ldyBBbW1vLmJ0VmVjdG9yMyhwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBwb3NpdGlvbi56KSk7CiAgICAgIHRyYW5zZm9ybS5zZXRSb3RhdGlvbihuZXcgQW1tby5idFF1YXRlcm5pb24ocXVhdGVybmlvbi54LCBxdWF0ZXJuaW9uLnksIHF1YXRlcm5pb24ueiwgcXVhdGVybmlvbi53KSk7CiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gbmV3IEFtbW8uYnREZWZhdWx0TW90aW9uU3RhdGUodHJhbnNmb3JtKTsKICAgICAgY29uc3QgbG9jYWxJbmVydGlhID0gbmV3IEFtbW8uYnRWZWN0b3IzKDAsIDAsIDApOwogICAgICBzaGFwZS5jYWxjdWxhdGVMb2NhbEluZXJ0aWEobWFzcywgbG9jYWxJbmVydGlhKTsKICAgICAgY29uc3QgcmJJbmZvID0gbmV3IEFtbW8uYnRSaWdpZEJvZHlDb25zdHJ1Y3Rpb25JbmZvKG1hc3MsIG1vdGlvblN0YXRlLCBzaGFwZSwgbG9jYWxJbmVydGlhKTsKICAgICAgY29uc3QgYm9keSA9IG5ldyBBbW1vLmJ0UmlnaWRCb2R5KHJiSW5mbyk7CiAgICAgIGlmIChtYXNzID4gMCkgewogICAgICAgIGJvZHkuc2V0RnJpY3Rpb24oZnJpY3Rpb24pOwogICAgICAgIGJvZHkuc2V0UmVzdGl0dXRpb24ocmVzdGl0dXRpb24pOwogICAgICAgIGJvZHkuc2V0RGFtcGluZyhkYW1waW5nLmxpbmVhciwgZGFtcGluZy5hbmd1bGFyKTsKICAgICAgICBib2R5LnNldEFjdGl2YXRpb25TdGF0ZShESVNBQkxFX0RFQUNUSVZBVElPTik7CiAgICAgIH0KCiAgICAgIC8vIHN0b3JpbmcgdXVpZCBmb3IgZnV0dXJlIHJlZmVyZW5jZQogICAgICBib2R5LnV1aWQgPSB1dWlkOwogICAgICB3b3JsZC5hZGRSaWdpZEJvZHkoYm9keSk7CiAgICAgIHJldHVybiBib2R5OwogICAgfTsKICAgIGNvbnN0IGFkZE1vZGVsID0gb3B0aW9ucyA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHZlcnRpY2VzLAogICAgICAgIG1hdHJpY2VzLAogICAgICAgIGluZGV4ZXMsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgcXVhdGVybmlvbiwKICAgICAgICBtYXNzID0gMCwKICAgICAgICBmcmljdGlvbiA9IDIKICAgICAgfSA9IG9wdGlvbnM7CiAgICAgIGNvbnN0IHNjYWxlID0gREVGQVVMVF9TQ0FMRTsKICAgICAgY29uc3QgYnRhID0gbmV3IEFtbW8uYnRWZWN0b3IzKCk7CiAgICAgIGNvbnN0IGJ0YiA9IG5ldyBBbW1vLmJ0VmVjdG9yMygpOwogICAgICBjb25zdCBidGMgPSBuZXcgQW1tby5idFZlY3RvcjMoKTsKICAgICAgY29uc3QgdHJpTWVzaCA9IG5ldyBBbW1vLmJ0VHJpYW5nbGVNZXNoKHRydWUsIGZhbHNlKTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkrKykgewogICAgICAgIGNvbnN0IGNvbXBvbmVudHMgPSB2ZXJ0aWNlc1tpXTsKICAgICAgICBjb25zdCBpbmRleCA9IGluZGV4ZXNbaV0gPyBpbmRleGVzW2ldIDogbnVsbDsKICAgICAgICBjb25zdCBtYXRyaXggPSBBcnJheS5mcm9tKG1hdHJpY2VzW2ldKTsKICAgICAgICBpZiAoaW5kZXgpIHsKICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgaW5kZXgubGVuZ3RoOyBqICs9IDMpIHsKICAgICAgICAgICAgY29uc3QgYWkgPSBpbmRleFtqXSAqIDM7CiAgICAgICAgICAgIGNvbnN0IGJpID0gaW5kZXhbaiArIDFdICogMzsKICAgICAgICAgICAgY29uc3QgY2kgPSBpbmRleFtqICsgMl0gKiAzOwogICAgICAgICAgICBjb25zdCB2YSA9IGFwcGx5TWF0cml4NFRvVmVjdG9yMyh7CiAgICAgICAgICAgICAgeDogY29tcG9uZW50c1thaV0sCiAgICAgICAgICAgICAgeTogY29tcG9uZW50c1thaSArIDFdLAogICAgICAgICAgICAgIHo6IGNvbXBvbmVudHNbYWkgKyAyXQogICAgICAgICAgICB9LCBtYXRyaXgpOwogICAgICAgICAgICBjb25zdCB2YiA9IGFwcGx5TWF0cml4NFRvVmVjdG9yMyh7CiAgICAgICAgICAgICAgeDogY29tcG9uZW50c1tiaV0sCiAgICAgICAgICAgICAgeTogY29tcG9uZW50c1tiaSArIDFdLAogICAgICAgICAgICAgIHo6IGNvbXBvbmVudHNbYmkgKyAyXQogICAgICAgICAgICB9LCBtYXRyaXgpOwogICAgICAgICAgICBjb25zdCB2YyA9IGFwcGx5TWF0cml4NFRvVmVjdG9yMyh7CiAgICAgICAgICAgICAgeDogY29tcG9uZW50c1tjaV0sCiAgICAgICAgICAgICAgeTogY29tcG9uZW50c1tjaSArIDFdLAogICAgICAgICAgICAgIHo6IGNvbXBvbmVudHNbY2kgKyAyXQogICAgICAgICAgICB9LCBtYXRyaXgpOwogICAgICAgICAgICBidGEuc2V0VmFsdWUodmEueCwgdmEueSwgdmEueik7CiAgICAgICAgICAgIGJ0Yi5zZXRWYWx1ZSh2Yi54LCB2Yi55LCB2Yi56KTsKICAgICAgICAgICAgYnRjLnNldFZhbHVlKHZjLngsIHZjLnksIHZjLnopOwogICAgICAgICAgICB0cmlNZXNoLmFkZFRyaWFuZ2xlKGJ0YSwgYnRiLCBidGMsIGZhbHNlKTsKICAgICAgICAgIH0KICAgICAgICB9IGVsc2UgewogICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBjb21wb25lbnRzLmxlbmd0aDsgaiArPSA5KSB7CiAgICAgICAgICAgIGNvbnN0IHZhID0gYXBwbHlNYXRyaXg0VG9WZWN0b3IzKHsKICAgICAgICAgICAgICB4OiBjb21wb25lbnRzW2ogKyAwXSwKICAgICAgICAgICAgICB5OiBjb21wb25lbnRzW2ogKyAxXSwKICAgICAgICAgICAgICB6OiBjb21wb25lbnRzW2ogKyAyXQogICAgICAgICAgICB9LCBtYXRyaXgpOwogICAgICAgICAgICBjb25zdCB2YiA9IGFwcGx5TWF0cml4NFRvVmVjdG9yMyh7CiAgICAgICAgICAgICAgeDogY29tcG9uZW50c1tqICsgM10sCiAgICAgICAgICAgICAgeTogY29tcG9uZW50c1tqICsgNF0sCiAgICAgICAgICAgICAgejogY29tcG9uZW50c1tqICsgNV0KICAgICAgICAgICAgfSwgbWF0cml4KTsKICAgICAgICAgICAgY29uc3QgdmMgPSBhcHBseU1hdHJpeDRUb1ZlY3RvcjMoewogICAgICAgICAgICAgIHg6IGNvbXBvbmVudHNbaiArIDZdLAogICAgICAgICAgICAgIHk6IGNvbXBvbmVudHNbaiArIDddLAogICAgICAgICAgICAgIHo6IGNvbXBvbmVudHNbaiArIDhdCiAgICAgICAgICAgIH0sIG1hdHJpeCk7CiAgICAgICAgICAgIGJ0YS5zZXRWYWx1ZSh2YS54LCB2YS55LCB2YS56KTsKICAgICAgICAgICAgYnRiLnNldFZhbHVlKHZiLngsIHZiLnksIHZiLnopOwogICAgICAgICAgICBidGMuc2V0VmFsdWUodmMueCwgdmMueSwgdmMueik7CiAgICAgICAgICAgIHRyaU1lc2guYWRkVHJpYW5nbGUoYnRhLCBidGIsIGJ0YywgZmFsc2UpOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICBjb25zdCBsb2NhbFNjYWxlID0gbmV3IEFtbW8uYnRWZWN0b3IzKHNjYWxlLngsIHNjYWxlLnksIHNjYWxlLnopOwogICAgICB0cmlNZXNoLnNldFNjYWxpbmcobG9jYWxTY2FsZSk7CiAgICAgIEFtbW8uZGVzdHJveShsb2NhbFNjYWxlKTsKICAgICAgY29uc3QgY29sbGlzaW9uU2hhcGUgPSBuZXcgQW1tby5idEJ2aFRyaWFuZ2xlTWVzaFNoYXBlKHRyaU1lc2gsIHRydWUsIHRydWUpOwogICAgICBjb2xsaXNpb25TaGFwZS5yZXNvdXJjZXMgPSBbdHJpTWVzaF07CiAgICAgIEFtbW8uZGVzdHJveShidGEpOwogICAgICBBbW1vLmRlc3Ryb3koYnRiKTsKICAgICAgQW1tby5kZXN0cm95KGJ0Yyk7CiAgICAgIGNvbnN0IGJvZHkgPSBjcmVhdGVSaWdpZEJvZHkoY29sbGlzaW9uU2hhcGUsIHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcywKICAgICAgICBmcmljdGlvbgogICAgICB9KTsKICAgICAgd29ybGQuYWRkRWxlbWVudCh7CiAgICAgICAgdXVpZCwKICAgICAgICBib2R5LAogICAgICAgIHR5cGU6IFRZUEVTLk1FU0gsCiAgICAgICAgc3RhdGU6IERFRkFVTFRfUklHSURCT0RZX1NUQVRFCiAgICAgIH0pOwogICAgfTsKICAgIGNvbnN0IGFkZEJveCA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICB3aWR0aCwKICAgICAgICBsZW5ndGgsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcyA9IDAsCiAgICAgICAgZnJpY3Rpb24gPSAyCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBnZW9tZXRyeSA9IG5ldyBBbW1vLmJ0Qm94U2hhcGUobmV3IEFtbW8uYnRWZWN0b3IzKHdpZHRoICogMC41LCBoZWlnaHQgKiAwLjUsIGxlbmd0aCAqIDAuNSkpOwogICAgICBjb25zdCBib2R5ID0gY3JlYXRlUmlnaWRCb2R5KGdlb21ldHJ5LCB7CiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIG1hc3MsCiAgICAgICAgZnJpY3Rpb24KICAgICAgfSk7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHV1aWQsCiAgICAgICAgYm9keSwKICAgICAgICB0eXBlOiBUWVBFUy5CT1gsCiAgICAgICAgc3RhdGU6IERFRkFVTFRfUklHSURCT0RZX1NUQVRFCiAgICAgIH0pOwogICAgfTsKICAgIGNvbnN0IGFkZFNwaGVyZSA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICByYWRpdXMsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgcXVhdGVybmlvbiwKICAgICAgICBtYXNzID0gMCwKICAgICAgICBmcmljdGlvbiA9IDIKICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IGdlb21ldHJ5ID0gbmV3IEFtbW8uYnRTcGhlcmVTaGFwZShyYWRpdXMpOwogICAgICBjb25zdCBib2R5ID0gY3JlYXRlUmlnaWRCb2R5KGdlb21ldHJ5LCB7CiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIG1hc3MsCiAgICAgICAgZnJpY3Rpb24KICAgICAgfSk7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHV1aWQsCiAgICAgICAgYm9keSwKICAgICAgICB0eXBlOiBUWVBFUy5TUEhFUkUsCiAgICAgICAgc3RhdGU6IERFRkFVTFRfUklHSURCT0RZX1NUQVRFCiAgICAgIH0pOwogICAgfTsKICAgIGNvbnN0IHNldExpbmVhclZlbG9jaXR5ID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHZlbG9jaXR5ID0gREVGQVVMVF9MSU5FQVJfVkVMT0NJVFkKICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IHsKICAgICAgICBib2R5CiAgICAgIH0gPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IGJvZHkuZ2V0TW90aW9uU3RhdGUoKTsKICAgICAgaWYgKG1vdGlvblN0YXRlKSB7CiAgICAgICAgY29uc3QgbGluZWFyVmVsb2NpdHkgPSBuZXcgQW1tby5idFZlY3RvcjModmVsb2NpdHkueCwgdmVsb2NpdHkueSwgdmVsb2NpdHkueik7CiAgICAgICAgYm9keS5zZXRMaW5lYXJWZWxvY2l0eShsaW5lYXJWZWxvY2l0eSk7CiAgICAgICAgQW1tby5kZXN0cm95KGxpbmVhclZlbG9jaXR5KTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHNldFBvc2l0aW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYm9keQogICAgICB9ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgYm9keS5nZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB0cmFuc2Zvcm0uc2V0T3JpZ2luKG5ldyBBbW1vLmJ0VmVjdG9yMyhwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBwb3NpdGlvbi56KSk7CiAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgLy8gQWxzbyB1cGRhdGUgbW90aW9uIHN0YXRlIHNvIHN0YXRpYyBib2RpZXMgKG1hc3M9MCkgcmVmbGVjdCB0aGUgY2hhbmdlCiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBtb3Rpb25TdGF0ZS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgcmVzZXRFbGVtZW50ID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24KICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IHsKICAgICAgICBib2R5CiAgICAgIH0gPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIHRyYW5zZm9ybS5zZXRPcmlnaW4obmV3IEFtbW8uYnRWZWN0b3IzKHBvc2l0aW9uLngsIHBvc2l0aW9uLnksIHBvc2l0aW9uLnopKTsKICAgICAgdHJhbnNmb3JtLnNldFJvdGF0aW9uKG5ldyBBbW1vLmJ0UXVhdGVybmlvbihxdWF0ZXJuaW9uLngsIHF1YXRlcm5pb24ueSwgcXVhdGVybmlvbi56LCBxdWF0ZXJuaW9uLncpKTsKICAgICAgYm9keS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICAvLyBBbHNvIHVwZGF0ZSBtb3Rpb24gc3RhdGUgc28gc3RhdGljIGJvZGllcyAobWFzcz0wKSByZWZsZWN0IHRoZSBjaGFuZ2UKICAgICAgY29uc3QgbW90aW9uU3RhdGUgPSBib2R5LmdldE1vdGlvblN0YXRlKCk7CiAgICAgIGlmIChtb3Rpb25TdGF0ZSkgewogICAgICAgIG1vdGlvblN0YXRlLnNldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIH0KICAgIH07CiAgICBjb25zdCBhcHBseUltcHVzZSA9ICh7CiAgICAgIHV1aWQsCiAgICAgIGltcHVsc2UgPSBERUZBVUxUX0lNUFVMU0UKICAgIH0pID0+IHsKICAgICAgY29uc3QgewogICAgICAgIGJvZHkKICAgICAgfSA9IHdvcmxkLmdldEVsZW1lbnQodXVpZCk7CiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBjb25zdCBpbXB1bHNlVmVjdG9yID0gbmV3IEFtbW8uYnRWZWN0b3IzKGltcHVsc2UueCwgaW1wdWxzZS55LCBpbXB1bHNlLnopOwogICAgICAgIGJvZHkuYXBwbHlDZW50cmFsSW1wdWxzZShpbXB1bHNlVmVjdG9yKTsKICAgICAgICBBbW1vLmRlc3Ryb3koaW1wdWxzZVZlY3Rvcik7CiAgICAgIH0KICAgIH07CiAgICBjb25zdCBzZXRRdWF0ZXJuaW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHF1YXRlcm5pb24KICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IHsKICAgICAgICBib2R5CiAgICAgIH0gPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIHRyYW5zZm9ybS5zZXRSb3RhdGlvbihuZXcgQW1tby5idFF1YXRlcm5pb24ocXVhdGVybmlvbi54LCBxdWF0ZXJuaW9uLnksIHF1YXRlcm5pb24ueiwgcXVhdGVybmlvbi53KSk7CiAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgLy8gQWxzbyB1cGRhdGUgbW90aW9uIHN0YXRlIHNvIHN0YXRpYyBib2RpZXMgKG1hc3M9MCkgcmVmbGVjdCB0aGUgY2hhbmdlCiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBtb3Rpb25TdGF0ZS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgaGFuZGxlRWxlbWVudFVwZGF0ZSA9ICh7CiAgICAgIGJvZHksCiAgICAgIHV1aWQsCiAgICAgIHN0YXRlID0gREVGQVVMVF9SSUdJREJPRFlfU1RBVEUKICAgIH0sIGR0KSA9PiB7CiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICAgIG1vdGlvblN0YXRlLmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgbGV0IG9yaWdpbiA9IHRyYW5zZm9ybS5nZXRPcmlnaW4oKTsKICAgICAgICBsZXQgcm90YXRpb24gPSB0cmFuc2Zvcm0uZ2V0Um90YXRpb24oKTsKICAgICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHV1aWQsIG9yaWdpbiwgcm90YXRpb24sIGR0KTsKICAgICAgICBBbW1vLmRlc3Ryb3kodHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKCiAgICBjb25zdCBhZGRQbGF5ZXIgPSBkYXRhID0+IHsKICAgICAgY29uc3QgewogICAgICAgIHV1aWQsCiAgICAgICAgd2lkdGgsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcywKICAgICAgICBmcmljdGlvbgogICAgICB9ID0gZGF0YTsKICAgICAgY29uc3QgY2Fwc3VsZSA9IG5ldyBBbW1vLmJ0Q2Fwc3VsZVNoYXBlKHdpZHRoLCBoZWlnaHQpOwogICAgICBjb25zdCBib2R5ID0gY3JlYXRlUmlnaWRCb2R5KGNhcHN1bGUsIHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcywKICAgICAgICBmcmljdGlvbiwKICAgICAgICByZXN0aXR1dGlvbjogMCwKICAgICAgICAvLyBubyBib3VuY2luZyBmb3IgcGxheWVyIGNoYXJhY3RlcnMKICAgICAgICBkYW1waW5nOiB7CiAgICAgICAgICBsaW5lYXI6IDAsCiAgICAgICAgICBhbmd1bGFyOiAwCiAgICAgICAgfSAvLyB3ZSBoYW5kbGUgZGFtcGluZyBvdXJzZWx2ZXMKICAgICAgfSk7CgogICAgICAvLyBkaXNhYmxpbmcgcm90YXRpb24gZm9yIGNvbGxpc2lvbnMKICAgICAgYm9keS5zZXRBbmd1bGFyRmFjdG9yKDApOwoKICAgICAgLy8gc3RvcmUgbWFzcyBmb3IgaW1wdWxzZSBjYWxjdWxhdGlvbnMKICAgICAgYm9keS5fbWFzcyA9IG1hc3M7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHV1aWQsCiAgICAgICAgYm9keSwKICAgICAgICB0eXBlOiBUWVBFUy5QTEFZRVIsCiAgICAgICAgc3RhdGU6IERFRkFVTFRfUklHSURCT0RZX1NUQVRFCiAgICAgIH0pOwogICAgfTsKICAgIGNvbnN0IGhhbmRsZVBsYXllclVwZGF0ZSA9ICh7CiAgICAgIGJvZHksCiAgICAgIHV1aWQsCiAgICAgIHN0YXRlID0gREVGQVVMVF9SSUdJREJPRFlfU1RBVEUKICAgIH0sIGR0KSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICBtb3ZlbWVudCwKICAgICAgICBjYW1lcmFEaXJlY3Rpb24sCiAgICAgICAganVtcCwKICAgICAgICBqdW1wU3BlZWQsCiAgICAgICAgc3BlZWQ6IG1vdmVTcGVlZAogICAgICB9ID0gc3RhdGU7CiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAoIW1vdGlvblN0YXRlKSByZXR1cm47CiAgICAgIGNvbnN0IGNoYXJhY3RlclNwZWVkID0gbW92ZVNwZWVkIHx8IDU7CgogICAgICAvLyBKdW1wIOKAlCBhcHBseSBhIG9uZS10aW1lIGltcHVsc2UsIHRoZW4gY2xlYXIgdGhlIGZsYWcgc28gaXQgZG9lc24ndCByZXBlYXQKICAgICAgLy8gYXBwbHlDZW50cmFsSW1wdWxzZSB1c2VzIGtnwrdtL3MsIHNvIG11bHRpcGx5IGJ5IG1hc3MgdG8gZ2V0IGRlc2lyZWQgdmVsb2NpdHkgY2hhbmdlCiAgICAgIGlmIChqdW1wICYmIGp1bXBTcGVlZCkgewogICAgICAgIGNvbnN0IG1hc3MgPSBib2R5Ll9tYXNzIHx8IDgwOwogICAgICAgIGNvbnN0IGltcHVsc2UgPSBuZXcgQW1tby5idFZlY3RvcjMoMCwganVtcFNwZWVkICogbWFzcywgMCk7CiAgICAgICAgYm9keS5hcHBseUNlbnRyYWxJbXB1bHNlKGltcHVsc2UpOwogICAgICAgIEFtbW8uZGVzdHJveShpbXB1bHNlKTsKCiAgICAgICAgLy8gQ2xlYXIgdGhlIGp1bXAgZmxhZyBzbyBpdCBvbmx5IGZpcmVzIG9uY2UKICAgICAgICBzdGF0ZS5qdW1wID0gZmFsc2U7CiAgICAgIH0KICAgICAgY29uc3QgaXNNb3ZpbmcgPSBtb3ZlbWVudCAmJiAobW92ZW1lbnQuZm9yd2FyZCB8fCBtb3ZlbWVudC5iYWNrd2FyZHMgfHwgbW92ZW1lbnQubGVmdCB8fCBtb3ZlbWVudC5yaWdodCk7CiAgICAgIGNvbnN0IGxpbmVhclZlbG9jaXR5ID0gYm9keS5nZXRMaW5lYXJWZWxvY2l0eSgpOwogICAgICBjb25zdCBjdXJyZW50WSA9IGxpbmVhclZlbG9jaXR5LnkoKTsgLy8gcHJlc2VydmUgdmVydGljYWwgdmVsb2NpdHkgKGdyYXZpdHkgKyBqdW1wKQoKICAgICAgaWYgKGlzTW92aW5nICYmIGNhbWVyYURpcmVjdGlvbikgewogICAgICAgIC8vIENvbXB1dGUgY2FtZXJhLXJlbGF0aXZlIG1vdmVtZW50IGRpcmVjdGlvbgogICAgICAgIGxldCBtb3ZlWCA9IDA7CiAgICAgICAgbGV0IG1vdmVaID0gMDsKICAgICAgICBpZiAobW92ZW1lbnQuZm9yd2FyZCkgewogICAgICAgICAgbW92ZVggKz0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgICBtb3ZlWiArPSBjYW1lcmFEaXJlY3Rpb24uejsKICAgICAgICB9CiAgICAgICAgaWYgKG1vdmVtZW50LmJhY2t3YXJkcykgewogICAgICAgICAgbW92ZVggLT0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgICBtb3ZlWiAtPSBjYW1lcmFEaXJlY3Rpb24uejsKICAgICAgICB9CiAgICAgICAgaWYgKG1vdmVtZW50LmxlZnQpIHsKICAgICAgICAgIG1vdmVYICs9IGNhbWVyYURpcmVjdGlvbi56OwogICAgICAgICAgbW92ZVogLT0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgfQogICAgICAgIGlmIChtb3ZlbWVudC5yaWdodCkgewogICAgICAgICAgbW92ZVggLT0gY2FtZXJhRGlyZWN0aW9uLno7CiAgICAgICAgICBtb3ZlWiArPSBjYW1lcmFEaXJlY3Rpb24ueDsKICAgICAgICB9CgogICAgICAgIC8vIE5vcm1hbGl6ZSBkaXJlY3Rpb24KICAgICAgICBjb25zdCBsZW4gPSBNYXRoLnNxcnQobW92ZVggKiBtb3ZlWCArIG1vdmVaICogbW92ZVopOwogICAgICAgIGlmIChsZW4gPiAwKSB7CiAgICAgICAgICBtb3ZlWCAvPSBsZW47CiAgICAgICAgICBtb3ZlWiAvPSBsZW47CiAgICAgICAgfQoKICAgICAgICAvLyBTZXQgaG9yaXpvbnRhbCB2ZWxvY2l0eSBkaXJlY3RseSBmb3IgcmVzcG9uc2l2ZSBtb3ZlbWVudAogICAgICAgIGxpbmVhclZlbG9jaXR5LnNldFgobW92ZVggKiBjaGFyYWN0ZXJTcGVlZCk7CiAgICAgICAgbGluZWFyVmVsb2NpdHkuc2V0Wihtb3ZlWiAqIGNoYXJhY3RlclNwZWVkKTsKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBEYW1wZW4gaG9yaXpvbnRhbCB2ZWxvY2l0eSB3aGVuIG5vdCBtb3ZpbmcKICAgICAgICBsaW5lYXJWZWxvY2l0eS5zZXRYKGxpbmVhclZlbG9jaXR5LngoKSAqIDAuODUpOwogICAgICAgIGxpbmVhclZlbG9jaXR5LnNldFoobGluZWFyVmVsb2NpdHkueigpICogMC44NSk7CiAgICAgIH0KCiAgICAgIC8vIFByZXNlcnZlIHZlcnRpY2FsIHZlbG9jaXR5IOKAlCBsZXQgZ3Jhdml0eSBhbmQgaW1wdWxzZXMgaGFuZGxlIFkKICAgICAgbGluZWFyVmVsb2NpdHkuc2V0WShjdXJyZW50WSk7CiAgICAgIGJvZHkuc2V0TGluZWFyVmVsb2NpdHkobGluZWFyVmVsb2NpdHkpOwoKICAgICAgLy8gUmVhZCB0aGUgY3VycmVudCB0cmFuc2Zvcm0gKGFzIHVwZGF0ZWQgYnkgdGhlIHBoeXNpY3Mgc3RlcCkKICAgICAgLy8gRG8gTk9UIHdyaXRlIGl0IGJhY2sg4oCUIGxldCB0aGUgc2ltdWxhdGlvbiBvd24gdGhlIHBvc2l0aW9uCiAgICAgIGNvbnN0IHRyYW5zZm9ybSA9IG5ldyBBbW1vLmJ0VHJhbnNmb3JtKCk7CiAgICAgIG1vdGlvblN0YXRlLmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIGNvbnN0IG9yaWdpbiA9IHRyYW5zZm9ybS5nZXRPcmlnaW4oKTsKICAgICAgY29uc3Qgcm90YXRpb24gPSB0cmFuc2Zvcm0uZ2V0Um90YXRpb24oKTsKICAgICAgY29uc3QgZ3JvdW5kZWQgPSBNYXRoLmFicyhjdXJyZW50WSkgPCAwLjU7CiAgICAgIGRpc3BhdGNoZXIuc2VuZEJvZHlVcGRhdGUodXVpZCwgb3JpZ2luLCByb3RhdGlvbiwgZHQsIHsKICAgICAgICBncm91bmRlZAogICAgICB9KTsKICAgICAgQW1tby5kZXN0cm95KHRyYW5zZm9ybSk7CiAgICB9OwoKICAgIGNvbnN0IHJlcXVlc3ROZXh0RnJhbWUgPSBzZWxmLnJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBzZWxmLndlYmtpdFJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBzZWxmLm1velJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBzZWxmLm9SZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgc2VsZi5tc1JlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBmdW5jdGlvbiAoY2FsbGJhY2ssIGVsZW1lbnQpIHsKICAgICAgc2VsZi5zZXRUaW1lb3V0KGNhbGxiYWNrLCAxMDAwIC8gMTIwKTsKICAgIH07CiAgICBsZXQgQ2xvY2sgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkgewogICAgICBmdW5jdGlvbiBDbG9jaygpIHsKICAgICAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgQ2xvY2spOwogICAgICAgIHRoaXMudGltZXN0YW1wID0gbnVsbDsKICAgICAgfQogICAgICByZXR1cm4gX2NyZWF0ZUNsYXNzKENsb2NrLCBbewogICAgICAgIGtleTogImdldERlbHRhIiwKICAgICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0RGVsdGEoKSB7CiAgICAgICAgICBjb25zdCB0aW1lID0gRGF0ZS5ub3coKTsKICAgICAgICAgIGlmICh0aGlzLnRpbWVzdGFtcCkgewogICAgICAgICAgICBjb25zdCBkZWx0YSA9IHRpbWUgLSB0aGlzLnRpbWVzdGFtcDsKICAgICAgICAgICAgdGhpcy50aW1lc3RhbXAgPSB0aW1lOwogICAgICAgICAgICByZXR1cm4gZGVsdGE7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aGlzLnRpbWVzdGFtcCA9IHRpbWU7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfV0pOwogICAgfSgpOwogICAgbGV0IFdvcmxkID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHsKICAgICAgZnVuY3Rpb24gV29ybGQoKSB7CiAgICAgICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIFdvcmxkKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImluaXQiLCBvcHRpb25zID0+IHsKICAgICAgICAgIGNvbnN0IHsKICAgICAgICAgICAgZ3Jhdml0eSA9IEdSQVZJVFkKICAgICAgICAgIH0gPSBvcHRpb25zOwogICAgICAgICAgdGhpcy5jb2xsaXNpb25Db25maWd1cmF0aW9uID0gbmV3IEFtbW8uYnREZWZhdWx0Q29sbGlzaW9uQ29uZmlndXJhdGlvbigpOwogICAgICAgICAgdGhpcy5kaXNwYXRjaGVyID0gbmV3IEFtbW8uYnRDb2xsaXNpb25EaXNwYXRjaGVyKHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbik7CiAgICAgICAgICB0aGlzLmJyb2FkcGhhc2UgPSBuZXcgQW1tby5idERidnRCcm9hZHBoYXNlKCk7CiAgICAgICAgICB0aGlzLnNvbHZlciA9IG5ldyBBbW1vLmJ0U2VxdWVudGlhbEltcHVsc2VDb25zdHJhaW50U29sdmVyKCk7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQgPSBuZXcgQW1tby5idERpc2NyZXRlRHluYW1pY3NXb3JsZCh0aGlzLmRpc3BhdGNoZXIsIHRoaXMuYnJvYWRwaGFzZSwgdGhpcy5zb2x2ZXIsIHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbik7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuc2V0R3Jhdml0eShuZXcgQW1tby5idFZlY3RvcjMoZ3Jhdml0eS54LCBncmF2aXR5LnksIGdyYXZpdHkueikpOwoKICAgICAgICAgIC8vIHRoaXMgaXMgbmVlZGVkIGZvciBnaG9zdE9iamVjdCBjb2xsaXNpb25zCiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuZ2V0QnJvYWRwaGFzZSgpLmdldE92ZXJsYXBwaW5nUGFpckNhY2hlKCkuc2V0SW50ZXJuYWxHaG9zdFBhaXJDYWxsYmFjayhuZXcgQW1tby5idEdob3N0UGFpckNhbGxiYWNrKCkpOwogICAgICAgICAgdGhpcy5pbml0aWFsaXNlZCA9IHRydWU7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJyZW1vdmVFbGVtZW50IiwgdXVpZCA9PiB7CiAgICAgICAgICBpZiAodGhpcy5oYXNFbGVtZW50KHV1aWQpKSB7CiAgICAgICAgICAgIHRoaXMuZWxlbWVudHNbdXVpZF0uZGVsZXRlZCA9IHRydWU7CiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJyZW1vdmVEZWxldGVkRWxlbWVudHMiLCAoKSA9PiBPYmplY3Qua2V5cyh0aGlzLmVsZW1lbnRzKS5maWx0ZXIodXVpZCA9PiB0aGlzLmVsZW1lbnRzW3V1aWRdLmRlbGV0ZWQpLmZvckVhY2godXVpZCA9PiB7CiAgICAgICAgICBkZWxldGUgdGhpcy5lbGVtZW50c1t1dWlkXTsKICAgICAgICB9KSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJoYXNFbGVtZW50IiwgdXVpZCA9PiB7CiAgICAgICAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcy5lbGVtZW50cykuaW5jbHVkZXModXVpZCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJnZXRFbGVtZW50IiwgdXVpZCA9PiB0aGlzLmVsZW1lbnRzW3V1aWRdKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImlzSW5pdGlhbGlzZWQiLCAoKSA9PiB0aGlzLmluaXRpYWxpc2VkKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImdldER5bmFtaWNzV29ybGQiLCAoKSA9PiB0aGlzLmR5bmFtaWNzV29ybGQpOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkUmlnaWRCb2R5IiwgYm9keSA9PiB7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuYWRkUmlnaWRCb2R5KGJvZHkpOwogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkQWN0aW9uIiwgYWN0aW9uID0+IHsKICAgICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZC5hZGRBY3Rpb24oYWN0aW9uKTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImFkZENvbGxpc2lvbk9iamVjdCIsIGNvbGxpc2lvbk9iamVjdCA9PiB7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuYWRkQ29sbGlzaW9uT2JqZWN0KGNvbGxpc2lvbk9iamVjdCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzdGVwU2ltdWxhdGlvbiIsIGR0ID0+IHsKICAgICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZC5zdGVwU2ltdWxhdGlvbihkdCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzaW11bGF0ZSIsICgpID0+IHsKICAgICAgICAgIGNvbnN0IGR0ID0gdGhpcy5jbG9jay5nZXREZWx0YSgpIC8gMTAwMDsKICAgICAgICAgIHRoaXMuc3RlcFNpbXVsYXRpb24oZHQpOwogICAgICAgICAgT2JqZWN0LmtleXModGhpcy5lbGVtZW50cykuZm9yRWFjaCh1dWlkID0+IHsKICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgICAgICAgaWYgKGVsZW1lbnQpIHsKICAgICAgICAgICAgICBzd2l0Y2ggKGVsZW1lbnQudHlwZSkgewogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5CT1g6CiAgICAgICAgICAgICAgICBjYXNlIFRZUEVTLlNQSEVSRToKICAgICAgICAgICAgICAgIGNhc2UgVFlQRVMuTUVTSDoKICAgICAgICAgICAgICAgICAgaGFuZGxlRWxlbWVudFVwZGF0ZShlbGVtZW50LCBkdCk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5QTEFZRVI6CiAgICAgICAgICAgICAgICAgIGhhbmRsZVBsYXllclVwZGF0ZShlbGVtZW50LCBkdCk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5WRUhJQ0xFOgogICAgICAgICAgICAgICAgICBoYW5kbGVWZWhpY2xlVXBkYXRlKGVsZW1lbnQsIGR0KTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9KTsKICAgICAgICAgIHRoaXMuY2FsY3VsYXRlQ29sbGlzaW9ucygpOwogICAgICAgICAgdGhpcy5yZW1vdmVEZWxldGVkRWxlbWVudHMoKTsKICAgICAgICAgIGRpc3BhdGNoZXIuc2VuZFBoeXNpY3NVcGRhdGUoZHQpOwogICAgICAgICAgdGhpcy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWVJZCA9IHJlcXVlc3ROZXh0RnJhbWUodGhpcy5zaW11bGF0ZS5iaW5kKHRoaXMpKTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImNhbGN1bGF0ZUNvbGxpc2lvbnMiLCAoKSA9PiB7CiAgICAgICAgICBsZXQgYW1tb0Rpc3BhdGNoZXIgPSB0aGlzLmR5bmFtaWNzV29ybGQuZ2V0RGlzcGF0Y2hlcigpOwogICAgICAgICAgbGV0IG51bU1hbmlmb2xkcyA9IGFtbW9EaXNwYXRjaGVyLmdldE51bU1hbmlmb2xkcygpOwogICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1NYW5pZm9sZHM7IGkrKykgewogICAgICAgICAgICBsZXQgY29udGFjdE1hbmlmb2xkID0gYW1tb0Rpc3BhdGNoZXIuZ2V0TWFuaWZvbGRCeUluZGV4SW50ZXJuYWwoaSk7CiAgICAgICAgICAgIGxldCByYjAgPSBBbW1vLmNhc3RPYmplY3QoY29udGFjdE1hbmlmb2xkLmdldEJvZHkwKCksIEFtbW8uYnRSaWdpZEJvZHkpOwogICAgICAgICAgICBsZXQgcmIxID0gQW1tby5jYXN0T2JqZWN0KGNvbnRhY3RNYW5pZm9sZC5nZXRCb2R5MSgpLCBBbW1vLmJ0UmlnaWRCb2R5KTsKICAgICAgICAgICAgbGV0IG51bUNvbnRhY3RzID0gY29udGFjdE1hbmlmb2xkLmdldE51bUNvbnRhY3RzKCk7CgogICAgICAgICAgICAvLyB0aGlzIGl0ZXJhdGlvbiBkb2Vzbid0IGhhdmUgdXVpZHMKICAgICAgICAgICAgaWYgKCFyYjAudXVpZCB8fCAhcmIxLnV1aWQpIGNvbnRpbnVlOwogICAgICAgICAgICBsZXQgY29udGFjdHMgPSBbXTsKICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBudW1Db250YWN0czsgaisrKSB7CiAgICAgICAgICAgICAgbGV0IGNvbnRhY3RQb2ludCA9IGNvbnRhY3RNYW5pZm9sZC5nZXRDb250YWN0UG9pbnQoaik7CiAgICAgICAgICAgICAgbGV0IGRpc3RhbmNlID0gY29udGFjdFBvaW50LmdldERpc3RhbmNlKCk7CiAgICAgICAgICAgICAgaWYgKGRpc3RhbmNlID4gMC4wKSBjb250aW51ZTsKICAgICAgICAgICAgICBsZXQgdmVsb2NpdHkwID0gcmIwLmdldExpbmVhclZlbG9jaXR5KCk7CiAgICAgICAgICAgICAgbGV0IHZlbG9jaXR5MSA9IHJiMS5nZXRMaW5lYXJWZWxvY2l0eSgpOwogICAgICAgICAgICAgIGxldCB3b3JsZFBvczAgPSBjb250YWN0UG9pbnQuZ2V0X21fcG9zaXRpb25Xb3JsZE9uQSgpOwogICAgICAgICAgICAgIGxldCB3b3JsZFBvczEgPSBjb250YWN0UG9pbnQuZ2V0X21fcG9zaXRpb25Xb3JsZE9uQigpOwogICAgICAgICAgICAgIGxldCBsb2NhbFBvczAgPSBjb250YWN0UG9pbnQuZ2V0X21fbG9jYWxQb2ludEEoKTsKICAgICAgICAgICAgICBsZXQgbG9jYWxQb3MxID0gY29udGFjdFBvaW50LmdldF9tX2xvY2FsUG9pbnRCKCk7CiAgICAgICAgICAgICAgY29udGFjdHMucHVzaCh7CiAgICAgICAgICAgICAgICBkaXN0YW5jZSwKICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBbewogICAgICAgICAgICAgICAgICB1dWlkOiByYjAudXVpZCwKICAgICAgICAgICAgICAgICAgdmVsb2NpdHk6IHsKICAgICAgICAgICAgICAgICAgICB4OiB2ZWxvY2l0eTAueCgpLAogICAgICAgICAgICAgICAgICAgIHk6IHZlbG9jaXR5MC55KCksCiAgICAgICAgICAgICAgICAgICAgejogdmVsb2NpdHkwLnooKQogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICB3b3JsZFBvczogewogICAgICAgICAgICAgICAgICAgIHg6IHdvcmxkUG9zMC54KCksCiAgICAgICAgICAgICAgICAgICAgeTogd29ybGRQb3MwLnkoKSwKICAgICAgICAgICAgICAgICAgICB6OiB3b3JsZFBvczAueigpCiAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgIGxvY2FsUG9zOiB7CiAgICAgICAgICAgICAgICAgICAgeDogbG9jYWxQb3MwLngoKSwKICAgICAgICAgICAgICAgICAgICB5OiBsb2NhbFBvczAueSgpLAogICAgICAgICAgICAgICAgICAgIHo6IGxvY2FsUG9zMC56KCkKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSwgewogICAgICAgICAgICAgICAgICB1dWlkOiByYjEudXVpZCwKICAgICAgICAgICAgICAgICAgdmVsb2NpdHk6IHsKICAgICAgICAgICAgICAgICAgICB4OiB2ZWxvY2l0eTEueCgpLAogICAgICAgICAgICAgICAgICAgIHk6IHZlbG9jaXR5MS55KCksCiAgICAgICAgICAgICAgICAgICAgejogdmVsb2NpdHkxLnooKQogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICB3b3JsZFBvczogewogICAgICAgICAgICAgICAgICAgIHg6IHdvcmxkUG9zMS54KCksCiAgICAgICAgICAgICAgICAgICAgeTogd29ybGRQb3MxLnkoKSwKICAgICAgICAgICAgICAgICAgICB6OiB3b3JsZFBvczEueigpCiAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgIGxvY2FsUG9zOiB7CiAgICAgICAgICAgICAgICAgICAgeDogbG9jYWxQb3MxLngoKSwKICAgICAgICAgICAgICAgICAgICB5OiBsb2NhbFBvczEueSgpLAogICAgICAgICAgICAgICAgICAgIHo6IGxvY2FsUG9zMS56KCkKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfV0KICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkaXNwYXRjaGVyLnNlbmREaXNwYXRjaEV2ZW50KHJiMC51dWlkLCBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULkNPTExJU0lPTiwgewogICAgICAgICAgICAgIGNvbnRhY3RzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkaXNwYXRjaGVyLnNlbmREaXNwYXRjaEV2ZW50KHJiMS51dWlkLCBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULkNPTExJU0lPTiwgewogICAgICAgICAgICAgIGNvbnRhY3RzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkRWxlbWVudCIsIGRhdGEgPT4gewogICAgICAgICAgdGhpcy5lbGVtZW50c1tkYXRhLnV1aWRdID0gZGF0YTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInVwZGF0ZUJvZHlTdGF0ZSIsICh7CiAgICAgICAgICB1dWlkLAogICAgICAgICAgc3RhdGUKICAgICAgICB9KSA9PiB7CiAgICAgICAgICBpZiAodGhpcy5oYXNFbGVtZW50KHV1aWQpKSB7CiAgICAgICAgICAgIHRoaXMuZWxlbWVudHNbdXVpZF0uc3RhdGUgPSB7CiAgICAgICAgICAgICAgLi4udGhpcy5lbGVtZW50c1t1dWlkXS5zdGF0ZSwKICAgICAgICAgICAgICAuLi5zdGF0ZQogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAidGVybWluYXRlIiwgKCkgPT4gewogICAgICAgICAgQW1tby5kZXN0cm95KHRoaXMuZHluYW1pY3NXb3JsZCk7CiAgICAgICAgICBBbW1vLmRlc3Ryb3kodGhpcy5zb2x2ZXIpOwogICAgICAgICAgQW1tby5kZXN0cm95KHRoaXMuZGlzcGF0Y2hlcik7CiAgICAgICAgICBBbW1vLmRlc3Ryb3kodGhpcy5jb2xsaXNpb25Db25maWd1cmF0aW9uKTsKICAgICAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMucmVxdWVzdEFuaW1hdGlvbkZyYW1lSWQpOwogICAgICAgICAgZGlzcGF0Y2hlci5zZW5kVGVybWluYXRlRXZlbnQoKTsKICAgICAgICB9KTsKICAgICAgICB0aGlzLmVsZW1lbnRzID0ge307CiAgICAgICAgdGhpcy5pbml0aWFsaXNlZCA9IGZhbHNlOwogICAgICAgIHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbiA9IHVuZGVmaW5lZDsKICAgICAgICB0aGlzLmRpc3BhdGNoZXIgPSB1bmRlZmluZWQ7CiAgICAgICAgdGhpcy5icm9hZHBoYXNlID0gdW5kZWZpbmVkOwogICAgICAgIHRoaXMuc29sdmVyID0gdW5kZWZpbmVkOwogICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZCA9IHVuZGVmaW5lZDsKICAgICAgICB0aGlzLnJlcXVlc3RBbmltYXRpb25GcmFtZUlkID0gbnVsbDsKICAgICAgICB0aGlzLmNsb2NrID0gbmV3IENsb2NrKCk7CiAgICAgIH0KICAgICAgcmV0dXJuIF9jcmVhdGVDbGFzcyhXb3JsZCwgW3sKICAgICAgICBrZXk6ICJkaXNwb3NlQm9keSIsCiAgICAgICAgdmFsdWU6IGZ1bmN0aW9uIGRpc3Bvc2VCb2R5KHsKICAgICAgICAgIHV1aWQKICAgICAgICB9KSB7CiAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50KHV1aWQpOwogICAgICAgICAgdGhpcy5keW5hbWljc1dvcmxkLnJlbW92ZVJpZ2lkQm9keShlbGVtZW50LmJvZHkpOwogICAgICAgICAgdGhpcy5yZW1vdmVFbGVtZW50KHV1aWQpOwogICAgICAgICAgZGlzcGF0Y2hlci5zZW5kRWxlbWVudERpc3Bvc2VkKHsKICAgICAgICAgICAgdXVpZAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9XSk7CiAgICB9KCk7CiAgICB2YXIgd29ybGQgPSBuZXcgV29ybGQoKTsKCiAgICBjb25zdCBERUZBVUxUX1JPTExfSU5GTFVFTkNFID0gMC4yOwogICAgY29uc3QgREVGQVVMVF9GUklDVElPTiA9IDEwMDA7CiAgICBjb25zdCBERUZBVUxUX01BU1MgPSA4MDA7CiAgICBjb25zdCBhZGRWZWhpY2xlID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIHV1aWQsCiAgICAgICAgd2hlZWxzLAogICAgICAgIG1hc3MgPSBERUZBVUxUX01BU1MsCiAgICAgICAgd2lkdGggPSAxLjgsCiAgICAgICAgaGVpZ2h0ID0gMC42LAogICAgICAgIGxlbmd0aCA9IDQsCiAgICAgICAgZnJpY3Rpb24gPSBERUZBVUxUX0ZSSUNUSU9OLAogICAgICAgIHJvbGxJbmZsdWVuY2UgPSBERUZBVUxUX1JPTExfSU5GTFVFTkNFLAogICAgICAgIHdoZWVsc09wdGlvbnMgPSB7fSwKICAgICAgICBzdXNwZW5zaW9ucyA9IHt9CiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYmFjayA9IHt9LAogICAgICAgIGZyb250ID0ge30KICAgICAgfSA9IHdoZWVsc09wdGlvbnM7CiAgICAgIGNvbnN0IHsKICAgICAgICBheGlzUG9zaXRpb246IGF4aXNQb3NpdGlvbkJhY2sgPSAtMSwKICAgICAgICByYWRpdXM6IHdoZWVsUmFkaXVzQmFjayA9IDAuNCwKICAgICAgICBoYWxmVHJhY2s6IHdoZWVsSGFsZlRyYWNrQmFjayA9IDEsCiAgICAgICAgYXhpc0hlaWdodDogd2hlZWxBeGlzSGVpZ2h0QmFjayA9IDAuMwogICAgICB9ID0gYmFjazsKICAgICAgY29uc3QgewogICAgICAgIGF4aXNQb3NpdGlvbjogYXhpc1Bvc2l0aW9uRnJvbnQgPSAxLjcsCiAgICAgICAgcmFkaXVzOiB3aGVlbFJhZGl1c0Zyb250ID0gMC40LAogICAgICAgIGhhbGZUcmFjazogd2hlZWxIYWxmVHJhY2tGcm9udCA9IDEsCiAgICAgICAgYXhpc0hlaWdodDogd2hlZWxBeGlzSGVpZ2h0RnJvbnQgPSAwLjMKICAgICAgfSA9IGZyb250OwogICAgICBjb25zdCB7CiAgICAgICAgc3RpZmZuZXNzID0gMjAuMCwKICAgICAgICBkYW1waW5nID0gMi4zLAogICAgICAgIGNvbXByZXNzaW9uID0gNC40LAogICAgICAgIHJlc3RMZW5ndGggPSAwLjYKICAgICAgfSA9IHN1c3BlbnNpb25zOwoKICAgICAgLy8gQ2hhc3NpcwogICAgICBjb25zdCBnZW9tZXRyeSA9IG5ldyBBbW1vLmJ0Qm94U2hhcGUobmV3IEFtbW8uYnRWZWN0b3IzKHdpZHRoICogMC41LCBoZWlnaHQgKiAwLjUsIGxlbmd0aCAqIDAuNSkpOwogICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICB0cmFuc2Zvcm0uc2V0SWRlbnRpdHkoKTsKICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IG5ldyBBbW1vLmJ0RGVmYXVsdE1vdGlvblN0YXRlKHRyYW5zZm9ybSk7CiAgICAgIGNvbnN0IGxvY2FsSW5lcnRpYSA9IG5ldyBBbW1vLmJ0VmVjdG9yMygwLCAwLCAwKTsKICAgICAgZ2VvbWV0cnkuY2FsY3VsYXRlTG9jYWxJbmVydGlhKG1hc3MsIGxvY2FsSW5lcnRpYSk7CiAgICAgIGNvbnN0IGNoYXNzaXMgPSBuZXcgQW1tby5idFJpZ2lkQm9keShuZXcgQW1tby5idFJpZ2lkQm9keUNvbnN0cnVjdGlvbkluZm8obWFzcywgbW90aW9uU3RhdGUsIGdlb21ldHJ5LCBsb2NhbEluZXJ0aWEpKTsKICAgICAgY2hhc3Npcy5zZXRBY3RpdmF0aW9uU3RhdGUoRElTQUJMRV9ERUFDVElWQVRJT04pOwogICAgICB3b3JsZC5hZGRSaWdpZEJvZHkoY2hhc3Npcyk7CgogICAgICAvLyBSYXljYXN0IFZlaGljbGUKICAgICAgY29uc3QgdHVuaW5nID0gbmV3IEFtbW8uYnRWZWhpY2xlVHVuaW5nKCk7CiAgICAgIGNvbnN0IHJheUNhc3RlciA9IG5ldyBBbW1vLmJ0RGVmYXVsdFZlaGljbGVSYXljYXN0ZXIod29ybGQuZ2V0RHluYW1pY3NXb3JsZCgpKTsKICAgICAgY29uc3QgdmVoaWNsZSA9IG5ldyBBbW1vLmJ0UmF5Y2FzdFZlaGljbGUodHVuaW5nLCBjaGFzc2lzLCByYXlDYXN0ZXIpOwogICAgICB2ZWhpY2xlLnNldENvb3JkaW5hdGVTeXN0ZW0oMCwgMSwgMik7CiAgICAgIHdvcmxkLmFkZEFjdGlvbih2ZWhpY2xlKTsKICAgICAgY29uc3Qgd2hlZWxEaXJlY3Rpb25DUzAgPSBuZXcgQW1tby5idFZlY3RvcjMoMCwgLTEsIDApOwogICAgICBjb25zdCB3aGVlbEF4bGVDUyA9IG5ldyBBbW1vLmJ0VmVjdG9yMygtMSwgMCwgMCk7CiAgICAgIGNvbnN0IGFkZFdoZWVsID0gKGlzRnJvbnQsIHBvcywgcmFkaXVzKSA9PiB7CiAgICAgICAgdmFyIHdoZWVsSW5mbyA9IHZlaGljbGUuYWRkV2hlZWwocG9zLCB3aGVlbERpcmVjdGlvbkNTMCwgd2hlZWxBeGxlQ1MsIHJlc3RMZW5ndGgsIHJhZGl1cywgdHVuaW5nLCBpc0Zyb250KTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fc3VzcGVuc2lvblN0aWZmbmVzcyhzdGlmZm5lc3MpOwogICAgICAgIHdoZWVsSW5mby5zZXRfbV93aGVlbHNEYW1waW5nUmVsYXhhdGlvbihkYW1waW5nKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fd2hlZWxzRGFtcGluZ0NvbXByZXNzaW9uKGNvbXByZXNzaW9uKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fZnJpY3Rpb25TbGlwKGZyaWN0aW9uKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fcm9sbEluZmx1ZW5jZShyb2xsSW5mbHVlbmNlKTsKICAgICAgfTsKICAgICAgYWRkV2hlZWwodHJ1ZSwgbmV3IEFtbW8uYnRWZWN0b3IzKHdoZWVsSGFsZlRyYWNrRnJvbnQsIHdoZWVsQXhpc0hlaWdodEZyb250LCBheGlzUG9zaXRpb25Gcm9udCksIHdoZWVsUmFkaXVzRnJvbnQpOwogICAgICBhZGRXaGVlbCh0cnVlLCBuZXcgQW1tby5idFZlY3RvcjMoLXdoZWVsSGFsZlRyYWNrRnJvbnQsIHdoZWVsQXhpc0hlaWdodEZyb250LCBheGlzUG9zaXRpb25Gcm9udCksIHdoZWVsUmFkaXVzRnJvbnQpOwogICAgICBhZGRXaGVlbChmYWxzZSwgbmV3IEFtbW8uYnRWZWN0b3IzKC13aGVlbEhhbGZUcmFja0JhY2ssIHdoZWVsQXhpc0hlaWdodEJhY2ssIGF4aXNQb3NpdGlvbkJhY2spLCB3aGVlbFJhZGl1c0JhY2spOwogICAgICBhZGRXaGVlbChmYWxzZSwgbmV3IEFtbW8uYnRWZWN0b3IzKHdoZWVsSGFsZlRyYWNrQmFjaywgd2hlZWxBeGlzSGVpZ2h0QmFjaywgYXhpc1Bvc2l0aW9uQmFjayksIHdoZWVsUmFkaXVzQmFjayk7CiAgICAgIHZlaGljbGUudXVpZCA9IHV1aWQ7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHR5cGU6IFRZUEVTLlZFSElDTEUsCiAgICAgICAgdXVpZCwKICAgICAgICB2ZWhpY2xlOiB2ZWhpY2xlLAogICAgICAgIHdoZWVscywKICAgICAgICBvcHRpb25zOiBkYXRhLAogICAgICAgIHN0YXRlOiBERUZBVUxUX1ZFSElDTEVfU1RBVEUKICAgICAgfSk7CiAgICB9OwogICAgY29uc3Qgc2V0VmVoaWNsZVBvc2l0aW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBlbGVtZW50ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gVFlQRVMuVkVISUNMRSkgewogICAgICAgIGNvbnN0IGJvZHkgPSBlbGVtZW50LnZlaGljbGUuZ2V0UmlnaWRCb2R5KCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHNldFZlaGljbGVRdWF0ZXJuaW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHF1YXRlcm5pb24KICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IGVsZW1lbnQgPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICBpZiAoZWxlbWVudC50eXBlID09PSBUWVBFUy5WRUhJQ0xFKSB7CiAgICAgICAgY29uc3QgYm9keSA9IGVsZW1lbnQudmVoaWNsZS5nZXRSaWdpZEJvZHkoKTsKICAgICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICAgIGJvZHkuZ2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHJlc2V0VmVoaWNsZSA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIHBvc2l0aW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBlbGVtZW50ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gVFlQRVMuVkVISUNMRSkgewogICAgICAgIGNvbnN0IGJvZHkgPSBlbGVtZW50LnZlaGljbGUuZ2V0UmlnaWRCb2R5KCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgdHJhbnNmb3JtLnNldElkZW50aXR5KCk7CiAgICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICAgIHRyYW5zZm9ybS5zZXRSb3RhdGlvbihuZXcgQW1tby5idFF1YXRlcm5pb24ocXVhdGVybmlvbi54LCBxdWF0ZXJuaW9uLnksIHF1YXRlcm5pb24ueiwgcXVhdGVybmlvbi53KSk7CiAgICAgICAgYm9keS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgaGFuZGxlVmVoaWNsZVVwZGF0ZSA9ICh7CiAgICAgIHZlaGljbGUsCiAgICAgIHdoZWVscywKICAgICAgdXVpZCwKICAgICAgc3RhdGUgPSBERUZBVUxUX1ZFSElDTEVfU1RBVEUsCiAgICAgIG9wdGlvbnMgPSB7fQogICAgfSwgZHQpID0+IHsKICAgICAgbGV0IGJyZWFraW5nRm9yY2UgPSAwOwogICAgICBsZXQgZW5naW5lRm9yY2UgPSAwOwogICAgICBjb25zdCB7CiAgICAgICAgc3RlZXJpbmdDbGFtcCA9IERFRkFVTFRfU1RFRVJJTkdfQ0xBTVAsCiAgICAgICAgc3RlZXJpbmdJbmNyZW1lbnQgPSBERUZBVUxUX1NURUVSSU5HX0lOQ1JFTUVOVCwKICAgICAgICBtYXhFbmdpbmVGb3JjZSA9IERFRkFVTFRfTUFYX0VOR0lORV9GT1JDRSwKICAgICAgICBtYXhCcmVha2luZ0ZvcmNlID0gREVGQVVMVF9NQVhfQlJFQUtJTkdfRk9SQ0UKICAgICAgfSA9IG9wdGlvbnM7CiAgICAgIGlmIChzdGF0ZS5hY2NlbGVyYXRpb24pIHsKICAgICAgICBpZiAoc3BlZWQgPCAtMSkgYnJlYWtpbmdGb3JjZSA9IG1heEJyZWFraW5nRm9yY2U7ZWxzZSBlbmdpbmVGb3JjZSA9IG1heEVuZ2luZUZvcmNlOwogICAgICB9CiAgICAgIGlmIChzdGF0ZS5icmFraW5nKSB7CiAgICAgICAgaWYgKHNwZWVkID4gMSkgYnJlYWtpbmdGb3JjZSA9IG1heEJyZWFraW5nRm9yY2U7ZWxzZSBlbmdpbmVGb3JjZSA9IC1tYXhFbmdpbmVGb3JjZSAvIDI7CiAgICAgIH0KICAgICAgaWYgKHN0YXRlLmxlZnQpIHsKICAgICAgICBpZiAoc3RhdGUudmVoaWNsZVN0ZWVyaW5nIDwgc3RlZXJpbmdDbGFtcCkgc3RhdGUudmVoaWNsZVN0ZWVyaW5nICs9IHN0ZWVyaW5nSW5jcmVtZW50OwogICAgICB9IGVsc2UgewogICAgICAgIGlmIChzdGF0ZS5yaWdodCkgewogICAgICAgICAgaWYgKHN0YXRlLnZlaGljbGVTdGVlcmluZyA+IC1zdGVlcmluZ0NsYW1wKSBzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgLT0gc3RlZXJpbmdJbmNyZW1lbnQ7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmIChzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgPCAtc3RlZXJpbmdJbmNyZW1lbnQpIHN0YXRlLnZlaGljbGVTdGVlcmluZyArPSBzdGVlcmluZ0luY3JlbWVudDtlbHNlIHsKICAgICAgICAgICAgaWYgKHN0YXRlLnZlaGljbGVTdGVlcmluZyA+IHN0ZWVyaW5nSW5jcmVtZW50KSBzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgLT0gc3RlZXJpbmdJbmNyZW1lbnQ7ZWxzZSB7CiAgICAgICAgICAgICAgc3RhdGUudmVoaWNsZVN0ZWVyaW5nID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICB2ZWhpY2xlLmFwcGx5RW5naW5lRm9yY2UoZW5naW5lRm9yY2UsIEJBQ0tfTEVGVCk7CiAgICAgIHZlaGljbGUuYXBwbHlFbmdpbmVGb3JjZShlbmdpbmVGb3JjZSwgQkFDS19SSUdIVCk7CiAgICAgIHZlaGljbGUuc2V0QnJha2UoYnJlYWtpbmdGb3JjZSAvIDIsIEZST05UX0xFRlQpOwogICAgICB2ZWhpY2xlLnNldEJyYWtlKGJyZWFraW5nRm9yY2UgLyAyLCBGUk9OVF9SSUdIVCk7CiAgICAgIHZlaGljbGUuc2V0QnJha2UoYnJlYWtpbmdGb3JjZSwgQkFDS19MRUZUKTsKICAgICAgdmVoaWNsZS5zZXRCcmFrZShicmVha2luZ0ZvcmNlLCBCQUNLX1JJR0hUKTsKICAgICAgdmVoaWNsZS5zZXRTdGVlcmluZ1ZhbHVlKHN0YXRlLnZlaGljbGVTdGVlcmluZywgRlJPTlRfTEVGVCk7CiAgICAgIHZlaGljbGUuc2V0U3RlZXJpbmdWYWx1ZShzdGF0ZS52ZWhpY2xlU3RlZXJpbmcsIEZST05UX1JJR0hUKTsKICAgICAgbGV0IHRtLCBwLCBxLCBpOwogICAgICBjb25zdCBuID0gdmVoaWNsZS5nZXROdW1XaGVlbHMoKTsKICAgICAgZm9yIChpID0gMDsgaSA8IG47IGkrKykgewogICAgICAgIHZlaGljbGUudXBkYXRlV2hlZWxUcmFuc2Zvcm0oaSwgdHJ1ZSk7CiAgICAgICAgdG0gPSB2ZWhpY2xlLmdldFdoZWVsVHJhbnNmb3JtV1MoaSk7CiAgICAgICAgcCA9IHRtLmdldE9yaWdpbigpOwogICAgICAgIHEgPSB0bS5nZXRSb3RhdGlvbigpOwogICAgICAgIGNvbnN0IHdoZWVsVVVJRCA9IHdoZWVsc1tpXTsKICAgICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHdoZWVsVVVJRCwgcCwgcSwgZHQpOwogICAgICB9CiAgICAgIHRtID0gdmVoaWNsZS5nZXRDaGFzc2lzV29ybGRUcmFuc2Zvcm0oKTsKICAgICAgcCA9IHRtLmdldE9yaWdpbigpOwogICAgICBxID0gdG0uZ2V0Um90YXRpb24oKTsKICAgICAgY29uc3QgZGlyZWN0aW9uID0gdmVoaWNsZS5nZXRGb3J3YXJkVmVjdG9yKCk7CiAgICAgIGNvbnN0IHNwZWVkID0gdmVoaWNsZS5nZXRDdXJyZW50U3BlZWRLbUhvdXIoKTsKICAgICAgY29uc3QgZXh0cmFEYXRhID0gewogICAgICAgIGRpcmVjdGlvbjogewogICAgICAgICAgeDogZGlyZWN0aW9uLngoKSwKICAgICAgICAgIHk6IGRpcmVjdGlvbi55KCksCiAgICAgICAgICB6OiBkaXJlY3Rpb24ueigpCiAgICAgICAgfSwKICAgICAgICBzcGVlZAogICAgICB9OwogICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHV1aWQsIHAsIHEsIGR0LCBleHRyYURhdGEpOwogICAgICB3b3JsZC51cGRhdGVCb2R5U3RhdGUodXVpZCwgc3RhdGUpOwogICAgfTsKCiAgICBjb25zdCBjcmVhdGVHaG9zdENvbGxpZGVyID0gKHJhZGl1cywgcG9zaXRpb24pID0+IHsKICAgICAgY29uc3QgZ2hvc3RDb2xsaWRlciA9IG5ldyBBbW1vLmJ0R2hvc3RPYmplY3QoKTsKICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgZ2hvc3RDb2xsaWRlci5zZXRDb2xsaXNpb25TaGFwZShuZXcgQW1tby5idFNwaGVyZVNoYXBlKHJhZGl1cykpOwogICAgICBnaG9zdENvbGxpZGVyLmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIHRyYW5zZm9ybS5zZXRJZGVudGl0eSgpOwogICAgICB0cmFuc2Zvcm0uc2V0T3JpZ2luKHBvc2l0aW9uKTsKICAgICAgdHJhbnNmb3JtLnNldFJvdGF0aW9uKG5ldyBBbW1vLmJ0UXVhdGVybmlvbigwLCAwLCAwLCAxKSk7CiAgICAgIGdob3N0Q29sbGlkZXIuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgcmV0dXJuIHsKICAgICAgICBnaG9zdENvbGxpZGVyLAogICAgICAgIHRyYW5zZm9ybQogICAgICB9OwogICAgfTsKICAgIGNvbnN0IGZvckVhY2hHaG9zdENvbGxpc2lvbiA9IChnaG9zdENvbGxpZGVyLCBmb3JFYWNoQ2FsbGJhY2sgPSAoKSA9PiB7fSkgPT4gewogICAgICBjb25zdCBjb2xsaXNpb25zID0gZ2hvc3RDb2xsaWRlci5nZXROdW1PdmVybGFwcGluZ09iamVjdHMoKTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xsaXNpb25zOyBpKyspIHsKICAgICAgICBjb25zdCBvYmplY3QgPSBBbW1vLmNhc3RPYmplY3QoZ2hvc3RDb2xsaWRlci5nZXRPdmVybGFwcGluZ09iamVjdChpKSwgQW1tby5idFJpZ2lkQm9keSk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBvYmplY3QuZ2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgICBmb3JFYWNoQ2FsbGJhY2sob2JqZWN0LCB0cmFuc2Zvcm0sIGkpOwogICAgICAgIEFtbW8uZGVzdHJveSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgZ2V0RXhwbG9zaW9uUG9zaXRpb24gPSAodXVpZCwgcG9zaXRpb24pID0+IHsKICAgICAgbGV0IGV4cGxvc2lvblBvc2l0aW9uID0gcG9zaXRpb247CiAgICAgIGlmICghZXhwbG9zaW9uUG9zaXRpb24pIHsKICAgICAgICBjb25zdCB7CiAgICAgICAgICBib2R5CiAgICAgICAgfSA9IHdvcmxkLmdldEVsZW1lbnQodXVpZCk7CiAgICAgICAgY29uc3QgbW90aW9uU3RhdGUgPSBib2R5LmdldE1vdGlvblN0YXRlKCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBtb3Rpb25TdGF0ZS5nZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICAgIGV4cGxvc2lvblBvc2l0aW9uID0gdHJhbnNmb3JtLmdldE9yaWdpbigpOwogICAgICB9CiAgICAgIHJldHVybiBleHBsb3Npb25Qb3NpdGlvbjsKICAgIH07CiAgICBjb25zdCBnZXRFeHBsb3Npb25JbXB1bHNlID0gKHBvc2l0aW9uLCBleHBsb3Npb25Qb3NpdGlvbiwgc3RyZW5ndGgpID0+IHsKICAgICAgY29uc3QgZGlzdGFuY2UgPSBwb3NpdGlvbi5vcF9zdWIoZXhwbG9zaW9uUG9zaXRpb24pOwogICAgICBkaXN0YW5jZS5ub3JtYWxpemUoKTsKICAgICAgY29uc3QgaW1wdWxzZSA9IGRpc3RhbmNlLm9wX211bChzdHJlbmd0aCk7CiAgICAgIGltcHVsc2Uuc2V0WShpbXB1bHNlLnkoKSArIHN0cmVuZ3RoKTsKICAgICAgcmV0dXJuIGltcHVsc2U7CiAgICB9OwogICAgY29uc3QgY3JlYXRlRXhwbG9zaW9uID0gKHsKICAgICAgdXVpZCwKICAgICAgcG9zaXRpb24sCiAgICAgIHJhZGl1cyA9IEVYUExPU0lPTl9TSVpFUy5TTUFMTCwKICAgICAgc3RyZW5ndGggPSBFWFBMT1NJT05fU1RSRU5HVEhTLk1FRElVTQogICAgfSkgPT4gewogICAgICB0cnkgewogICAgICAgIGNvbnN0IGV4cGxvc2lvblBvc2l0aW9uID0gZ2V0RXhwbG9zaW9uUG9zaXRpb24odXVpZCwgcG9zaXRpb24pOwogICAgICAgIGNvbnN0IHsKICAgICAgICAgIGdob3N0Q29sbGlkZXIsCiAgICAgICAgICB0cmFuc2Zvcm0KICAgICAgICB9ID0gY3JlYXRlR2hvc3RDb2xsaWRlcihyYWRpdXMsIGV4cGxvc2lvblBvc2l0aW9uKTsKICAgICAgICB3b3JsZC5hZGRDb2xsaXNpb25PYmplY3QoZ2hvc3RDb2xsaWRlcik7CiAgICAgICAgZm9yRWFjaEdob3N0Q29sbGlzaW9uKGdob3N0Q29sbGlkZXIsIChvYmplY3QsIG9iamVjdFRyYW5zZm9ybSkgPT4gewogICAgICAgICAgY29uc3Qgb3JpZ2luID0gb2JqZWN0VHJhbnNmb3JtLmdldE9yaWdpbigpOwogICAgICAgICAgb2JqZWN0LmFjdGl2YXRlKHRydWUpOwogICAgICAgICAgb2JqZWN0LmFwcGx5Q2VudHJhbEltcHVsc2UoZ2V0RXhwbG9zaW9uSW1wdWxzZShvcmlnaW4sIGV4cGxvc2lvblBvc2l0aW9uLCBzdHJlbmd0aCkpOwogICAgICAgIH0pOwogICAgICAgIHdvcmxkLmdldER5bmFtaWNzV29ybGQoKS5yZW1vdmVDb2xsaXNpb25PYmplY3QoZ2hvc3RDb2xsaWRlcik7CiAgICAgICAgQW1tby5kZXN0cm95KGdob3N0Q29sbGlkZXIpOwogICAgICAgIEFtbW8uZGVzdHJveSh0cmFuc2Zvcm0pOwogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgY29uc29sZS5sb2coZSk7CiAgICAgIH0KICAgIH07CgogICAgY29uc3QgaGFuZGxlTG9hZEV2ZW50ID0gb3B0aW9ucyA9PiBBbW1vID0+IHsKICAgICAgc2VsZi5BbW1vID0gQW1tbzsKICAgICAgb25tZXNzYWdlID0gKHsKICAgICAgICBkYXRhCiAgICAgIH0pID0+IHsKICAgICAgICBzd2l0Y2ggKGRhdGEuZXZlbnQpIHsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuQURELkJPWDoKICAgICAgICAgICAgYWRkQm94KGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuQURELlNQSEVSRToKICAgICAgICAgICAgYWRkU3BoZXJlKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuQURELlZFSElDTEU6CiAgICAgICAgICAgIGFkZFZlaGljbGUoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5BREQuTU9ERUw6CiAgICAgICAgICAgIGFkZE1vZGVsKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuQURELlBMQVlFUjoKICAgICAgICAgICAgYWRkUGxheWVyKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5TRVQuTElORUFSX1ZFTE9DSVRZOgogICAgICAgICAgICBzZXRMaW5lYXJWZWxvY2l0eShkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVMRU1FTlQuUkVTRVQ6CiAgICAgICAgICAgIHJlc2V0RWxlbWVudChkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVMRU1FTlQuU0VULlBPU0lUSU9OOgogICAgICAgICAgICBzZXRQb3NpdGlvbihkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVMRU1FTlQuU0VULlFVQVRFUk5JT046CiAgICAgICAgICAgIHNldFF1YXRlcm5pb24oZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5WRUhJQ0xFLlNFVC5QT1NJVElPTjoKICAgICAgICAgICAgc2V0VmVoaWNsZVBvc2l0aW9uKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuVkVISUNMRS5TRVQuUVVBVEVSTklPTjoKICAgICAgICAgICAgc2V0VmVoaWNsZVF1YXRlcm5pb24oZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5WRUhJQ0xFLlJFU0VUOgogICAgICAgICAgICByZXNldFZlaGljbGUoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULkFQUExZLklNUFVMU0U6CiAgICAgICAgICAgIGFwcGx5SW1wdXNlKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5VUERBVEU6CiAgICAgICAgICAgIHdvcmxkLnVwZGF0ZUJvZHlTdGF0ZShkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVMRU1FTlQuRElTUE9TRToKICAgICAgICAgICAgd29ybGQuZGlzcG9zZUJvZHkoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5FRkZFQ1RTLkVYUExPU0lPTjoKICAgICAgICAgICAgY3JlYXRlRXhwbG9zaW9uKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuVEVSTUlOQVRFOgogICAgICAgICAgICB3b3JsZC50ZXJtaW5hdGUoKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICB9OwogICAgICB3b3JsZC5pbml0KG9wdGlvbnMpOwogICAgICBkaXNwYXRjaGVyLnNlbmRSZWFkeUV2ZW50KCk7CiAgICAgIHdvcmxkLnNpbXVsYXRlKCk7CiAgICB9OwogICAgY29uc3QgbG9hZEFtbW8gPSBvcHRpb25zID0+IHsKICAgICAgY29uc3Qgc2NyaXB0VXJsID0gb3B0aW9ucy5ob3N0ICsgIi8iICsgKG9wdGlvbnMucGF0aCB8fCBMSUJSQVJZX05BTUUpOwogICAgICBpbXBvcnRTY3JpcHRzKHNjcmlwdFVybCk7CiAgICAgIEFtbW8oKS50aGVuKGhhbmRsZUxvYWRFdmVudChvcHRpb25zKSk7CiAgICB9OwogICAgb25tZXNzYWdlID0gKHsKICAgICAgZGF0YQogICAgfSkgPT4gewogICAgICBzd2l0Y2ggKGRhdGEuZXZlbnQpIHsKICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkxPQUQuQU1NTzoKICAgICAgICAgIGxvYWRBbW1vKGRhdGEpOwogICAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgIH07Cgp9KSgpOwoK', null, false);
55722
+ }var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICAgJ3VzZSBzdHJpY3QnOwoKICAgIGNvbnN0IExJQlJBUllfTkFNRSA9ICJhbW1vLmpzIjsKICAgIGNvbnN0IFRZUEVTID0gewogICAgICBCT1g6ICJCT1giLAogICAgICBTUEhFUkU6ICJTUEhFUkUiLAogICAgICBWRUhJQ0xFOiAiVkVISUNMRSIsCiAgICAgIE1FU0g6ICJNRVNIIiwKICAgICAgUExBWUVSOiAiUExBWUVSIgogICAgfTsKICAgIGNvbnN0IERFRkFVTFRfVkVISUNMRV9TVEFURSA9IHsKICAgICAgdmVoaWNsZVN0ZWVyaW5nOiAwLAogICAgICBhY2NlbGVyYXRpb246IGZhbHNlLAogICAgICBicmVha2luZzogZmFsc2UsCiAgICAgIHJpZ2h0OiBmYWxzZSwKICAgICAgbGVmdDogZmFsc2UKICAgIH07CiAgICBjb25zdCBERUZBVUxUX1JJR0lEQk9EWV9TVEFURSA9IHsKICAgICAgdmVsb2NpdHk6IHsKICAgICAgICB4OiAwLAogICAgICAgIHk6IDAsCiAgICAgICAgejogMAogICAgICB9LAogICAgICBtb3ZlbWVudDogewogICAgICAgIGZvcndhcmQ6IGZhbHNlLAogICAgICAgIGJhY2t3YXJkczogZmFsc2UsCiAgICAgICAgbGVmdDogZmFsc2UsCiAgICAgICAgcmlnaHQ6IGZhbHNlCiAgICAgIH0sCiAgICAgIGRpcmVjdGlvbjogewogICAgICAgIHg6IDAsCiAgICAgICAgeTogMCwKICAgICAgICB6OiAwCiAgICAgIH0KICAgIH07CiAgICBjb25zdCBERUZBVUxUX1NDQUxFID0gewogICAgICB4OiAxLAogICAgICB5OiAxLAogICAgICB6OiAxCiAgICB9OwogICAgY29uc3QgREVGQVVMVF9MSU5FQVJfVkVMT0NJVFkgPSB7CiAgICAgIHg6IDAsCiAgICAgIHk6IDAsCiAgICAgIHo6IDAKICAgIH07CiAgICBjb25zdCBERUZBVUxUX0lNUFVMU0UgPSB7CiAgICAgIHg6IDAsCiAgICAgIHk6IDAsCiAgICAgIHo6IDAKICAgIH07CiAgICBjb25zdCBESVNBQkxFX0RFQUNUSVZBVElPTiA9IDQ7CiAgICBjb25zdCBHUkFWSVRZID0gewogICAgICB4OiAwLAogICAgICB5OiAtOS44LAogICAgICB6OiAwCiAgICB9OwogICAgY29uc3QgRlJPTlRfTEVGVCA9IDA7CiAgICBjb25zdCBGUk9OVF9SSUdIVCA9IDE7CiAgICBjb25zdCBCQUNLX0xFRlQgPSAyOwogICAgY29uc3QgQkFDS19SSUdIVCA9IDM7CiAgICBjb25zdCBERUZBVUxUX1NURUVSSU5HX0lOQ1JFTUVOVCA9IDAuMDQ7CiAgICBjb25zdCBERUZBVUxUX1NURUVSSU5HX0NMQU1QID0gMC41OwogICAgY29uc3QgREVGQVVMVF9NQVhfRU5HSU5FX0ZPUkNFID0gMjAwMDsKICAgIGNvbnN0IERFRkFVTFRfTUFYX0JSRUFLSU5HX0ZPUkNFID0gMTAwOwogICAgY29uc3QgRVhQTE9TSU9OX1NJWkVTID0gewogICAgICBTTUFMTDogNCwKICAgICAgTUVESVVNOiA2LAogICAgICBMQVJHRTogOCwKICAgICAgTUFTU0lWRTogMTIKICAgIH07CiAgICBjb25zdCBFWFBMT1NJT05fU1RSRU5HVEhTID0gewogICAgICBWRVJZX1dFQUs6IDIsCiAgICAgIFdFQUs6IDQsCiAgICAgIE1FRElVTTogOCwKICAgICAgTEFSR0U6IDE2LAogICAgICBNQVNTSVZFOiAzMiwKICAgICAgT0tfTk86IDY0CiAgICB9OwoKICAgIGZ1bmN0aW9uIF9jbGFzc0NhbGxDaGVjayhhLCBuKSB7CiAgICAgIGlmICghKGEgaW5zdGFuY2VvZiBuKSkgdGhyb3cgbmV3IFR5cGVFcnJvcigiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uIik7CiAgICB9CiAgICBmdW5jdGlvbiBfZGVmaW5lUHJvcGVydGllcyhlLCByKSB7CiAgICAgIGZvciAodmFyIHQgPSAwOyB0IDwgci5sZW5ndGg7IHQrKykgewogICAgICAgIHZhciBvID0gclt0XTsKICAgICAgICBvLmVudW1lcmFibGUgPSBvLmVudW1lcmFibGUgfHwgITEsIG8uY29uZmlndXJhYmxlID0gITAsICJ2YWx1ZSIgaW4gbyAmJiAoby53cml0YWJsZSA9ICEwKSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIF90b1Byb3BlcnR5S2V5KG8ua2V5KSwgbyk7CiAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIF9jcmVhdGVDbGFzcyhlLCByLCB0KSB7CiAgICAgIHJldHVybiByICYmIF9kZWZpbmVQcm9wZXJ0aWVzKGUucHJvdG90eXBlLCByKSwgdCAmJiBfZGVmaW5lUHJvcGVydGllcyhlLCB0KSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsICJwcm90b3R5cGUiLCB7CiAgICAgICAgd3JpdGFibGU6ICExCiAgICAgIH0pLCBlOwogICAgfQogICAgZnVuY3Rpb24gX2RlZmluZVByb3BlcnR5KGUsIHIsIHQpIHsKICAgICAgcmV0dXJuIChyID0gX3RvUHJvcGVydHlLZXkocikpIGluIGUgPyBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgciwgewogICAgICAgIHZhbHVlOiB0LAogICAgICAgIGVudW1lcmFibGU6ICEwLAogICAgICAgIGNvbmZpZ3VyYWJsZTogITAsCiAgICAgICAgd3JpdGFibGU6ICEwCiAgICAgIH0pIDogZVtyXSA9IHQsIGU7CiAgICB9CiAgICBmdW5jdGlvbiBfdG9QcmltaXRpdmUodCwgcikgewogICAgICBpZiAoIm9iamVjdCIgIT0gdHlwZW9mIHQgfHwgIXQpIHJldHVybiB0OwogICAgICB2YXIgZSA9IHRbU3ltYm9sLnRvUHJpbWl0aXZlXTsKICAgICAgaWYgKHZvaWQgMCAhPT0gZSkgewogICAgICAgIHZhciBpID0gZS5jYWxsKHQsIHIgfHwgImRlZmF1bHQiKTsKICAgICAgICBpZiAoIm9iamVjdCIgIT0gdHlwZW9mIGkpIHJldHVybiBpOwogICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIkBAdG9QcmltaXRpdmUgbXVzdCByZXR1cm4gYSBwcmltaXRpdmUgdmFsdWUuIik7CiAgICAgIH0KICAgICAgcmV0dXJuICgic3RyaW5nIiA9PT0gciA/IFN0cmluZyA6IE51bWJlcikodCk7CiAgICB9CiAgICBmdW5jdGlvbiBfdG9Qcm9wZXJ0eUtleSh0KSB7CiAgICAgIHZhciBpID0gX3RvUHJpbWl0aXZlKHQsICJzdHJpbmciKTsKICAgICAgcmV0dXJuICJzeW1ib2wiID09IHR5cGVvZiBpID8gaSA6IGkgKyAiIjsKICAgIH0KCiAgICBjb25zdCBQSFlTSUNTX0VWRU5UUyA9IHsKICAgICAgRElTUEFUQ0g6ICJwaHlzaWNzOmRpc3BhdGNoIiwKICAgICAgVEVSTUlOQVRFOiAicGh5c2ljczp0ZXJtaW5hdGUiLAogICAgICBMT0FEOiB7CiAgICAgICAgQU1NTzogInBoeXNpY3M6bG9hZDphbW1vIgogICAgICB9LAogICAgICBSRUFEWTogInBoeXNpY3M6cmVhZHkiLAogICAgICBJTklUOiAicGh5c2ljczppbml0IiwKICAgICAgVVBEQVRFOiAicGh5c2ljczp1cGRhdGUiLAogICAgICBBREQ6IHsKICAgICAgICBCT1g6ICJwaHlzaWNzOmFkZDpib3giLAogICAgICAgIFZFSElDTEU6ICJwaHlzaWNzOmFkZDp2ZWhpY2xlIiwKICAgICAgICBNT0RFTDogInBoeXNpY3M6YWRkOm1vZGVsIiwKICAgICAgICBQTEFZRVI6ICJwaHlzaWNzOmFkZDpwbGF5ZXIiLAogICAgICAgIFNQSEVSRTogInBoeXNpY3M6YWRkOnNwaGVyZSIKICAgICAgfSwKICAgICAgRUxFTUVOVDogewogICAgICAgIERJU1BPU0U6ICJwaHlzaWNzOmVsZW1lbnQ6ZGlzcG9zZSIsCiAgICAgICAgQ09MTElTSU9OOiAicGh5c2ljczplbGVtZW50OmNvbGxpc2lvbiIsCiAgICAgICAgVVBEQVRFOiAicGh5c2ljczplbGVtZW50OnVwZGF0ZSIsCiAgICAgICAgQ1JFQVRFRDogInBoeXNpY3M6ZWxlbWVudDpjcmVhdGVkIiwKICAgICAgICBTRVQ6IHsKICAgICAgICAgIFBPU0lUSU9OOiAicGh5c2ljczplbGVtZW50OnNldDpwb3NpdGlvbiIsCiAgICAgICAgICBRVUFURVJOSU9OOiAicGh5c2ljczplbGVtZW50OnNldDpxdWF0ZXJuaW9uIiwKICAgICAgICAgIExJTkVBUl9WRUxPQ0lUWTogInBoeXNpY3M6ZWxlbWVudDpzZXQ6bGluZWFyX3ZlbG9jaXR5IgogICAgICAgIH0sCiAgICAgICAgUkVTRVQ6ICJwaHlzaWNzOmVsZW1lbnQ6cmVzZXQiLAogICAgICAgIEFQUExZOiB7CiAgICAgICAgICBJTVBVTFNFOiAicGh5c2ljczplbGVtZW50OmFwcGx5OmltcHVsc2UiCiAgICAgICAgfQogICAgICB9LAogICAgICBWRUhJQ0xFOiB7CiAgICAgICAgU0VUOiB7CiAgICAgICAgICBQT1NJVElPTjogInBoeXNpY3M6dmVoaWNsZTpzZXQ6cG9zaXRpb24iLAogICAgICAgICAgUVVBVEVSTklPTjogInBoeXNpY3M6dmVoaWNsZTpzZXQ6cXVhdGVybmlvbiIKICAgICAgICB9LAogICAgICAgIFJFU0VUOiAicGh5c2ljczp2ZWhpY2xlOnJlc2V0IiwKICAgICAgICBTUEVFRDogInBoeXNpY3M6dmVoaWNsZTpzcGVlZCIsCiAgICAgICAgRElSRUNUSU9OOiAicGh5c2ljczp2ZWhpY2xlOmRpcmVjdGlvbiIKICAgICAgfSwKICAgICAgRUZGRUNUUzogewogICAgICAgIEVYUExPU0lPTjogInBoeXNpY3M6ZWZmZWN0czpleHBsb3Npb24iCiAgICAgIH0KICAgIH07CgogICAgbGV0IERpc3BhdGNoZXIgPSAvKiNfX1BVUkVfXyovX2NyZWF0ZUNsYXNzKGZ1bmN0aW9uIERpc3BhdGNoZXIoKSB7CiAgICAgIF9jbGFzc0NhbGxDaGVjayh0aGlzLCBEaXNwYXRjaGVyKTsKICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzZW5kUGh5c2ljc1VwZGF0ZSIsIGR0ID0+IHBvc3RNZXNzYWdlKHsKICAgICAgICBldmVudDogUEhZU0lDU19FVkVOVFMuVVBEQVRFLAogICAgICAgIGR0CiAgICAgIH0pKTsKICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzZW5kUmVhZHlFdmVudCIsICgpID0+IHBvc3RNZXNzYWdlKHsKICAgICAgICBldmVudDogUEhZU0lDU19FVkVOVFMuUkVBRFkKICAgICAgfSkpOwogICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInNlbmRUZXJtaW5hdGVFdmVudCIsICgpID0+IHBvc3RNZXNzYWdlKHsKICAgICAgICBldmVudDogUEhZU0lDU19FVkVOVFMuVEVSTUlOQVRFCiAgICAgIH0pKTsKICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzZW5kQm9keVVwZGF0ZSIsICh1dWlkLCBwb3NpdGlvbiwgcm90YXRpb24sIGR0LCBleHRyYURhdGEpID0+IHBvc3RNZXNzYWdlKHsKICAgICAgICBldmVudDogUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5VUERBVEUsCiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbjogewogICAgICAgICAgeDogcG9zaXRpb24ueCgpLAogICAgICAgICAgeTogcG9zaXRpb24ueSgpLAogICAgICAgICAgejogcG9zaXRpb24ueigpCiAgICAgICAgfSwKICAgICAgICBxdWF0ZXJuaW9uOiB7CiAgICAgICAgICB4OiByb3RhdGlvbi54KCksCiAgICAgICAgICB5OiByb3RhdGlvbi55KCksCiAgICAgICAgICB6OiByb3RhdGlvbi56KCksCiAgICAgICAgICB3OiByb3RhdGlvbi53KCkKICAgICAgICB9LAogICAgICAgIC4uLmV4dHJhRGF0YSwKICAgICAgICBkdAogICAgICB9KSk7CiAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAic2VuZERpc3BhdGNoRXZlbnQiLCAodXVpZCwgZXZlbnROYW1lLCBldmVudERhdGEpID0+IHBvc3RNZXNzYWdlKHsKICAgICAgICBldmVudDogUEhZU0lDU19FVkVOVFMuRElTUEFUQ0gsCiAgICAgICAgdXVpZCwKICAgICAgICBldmVudE5hbWUsCiAgICAgICAgZXZlbnREYXRhCiAgICAgIH0pKTsKICAgIH0pOwogICAgdmFyIGRpc3BhdGNoZXIgPSBuZXcgRGlzcGF0Y2hlcigpOwoKICAgIGNvbnN0IGFwcGx5TWF0cml4NFRvVmVjdG9yMyA9ICh7CiAgICAgIHggPSAwLAogICAgICB5ID0gMCwKICAgICAgeiA9IDAKICAgIH0sIG1hdHJpeCA9IFtdKSA9PiB7CiAgICAgIGNvbnN0IHcgPSAxIC8gKG1hdHJpeFszXSAqIHggKyBtYXRyaXhbN10gKiB5ICsgbWF0cml4WzExXSAqIHogKyBtYXRyaXhbMTVdKTsKICAgICAgcmV0dXJuIHsKICAgICAgICB4OiAobWF0cml4WzBdICogeCArIG1hdHJpeFs0XSAqIHkgKyBtYXRyaXhbOF0gKiB6ICsgbWF0cml4WzEyXSkgKiB3LAogICAgICAgIHk6IChtYXRyaXhbMV0gKiB4ICsgbWF0cml4WzVdICogeSArIG1hdHJpeFs5XSAqIHogKyBtYXRyaXhbMTNdKSAqIHcsCiAgICAgICAgejogKG1hdHJpeFsyXSAqIHggKyBtYXRyaXhbNl0gKiB5ICsgbWF0cml4WzEwXSAqIHogKyBtYXRyaXhbMTRdKSAqIHcKICAgICAgfTsKICAgIH07CgogICAgY29uc3QgY3JlYXRlUmlnaWRCb2R5ID0gKHNoYXBlLCBvcHRpb25zKSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcywKICAgICAgICBmcmljdGlvbiwKICAgICAgICByZXN0aXR1dGlvbiA9IDAuOSwKICAgICAgICBkYW1waW5nID0gewogICAgICAgICAgbGluZWFyOiAwLjIsCiAgICAgICAgICBhbmd1bGFyOiAwLjIKICAgICAgICB9CiAgICAgIH0gPSBvcHRpb25zOwogICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICB0cmFuc2Zvcm0uc2V0SWRlbnRpdHkoKTsKICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IG5ldyBBbW1vLmJ0RGVmYXVsdE1vdGlvblN0YXRlKHRyYW5zZm9ybSk7CiAgICAgIGNvbnN0IGxvY2FsSW5lcnRpYSA9IG5ldyBBbW1vLmJ0VmVjdG9yMygwLCAwLCAwKTsKICAgICAgc2hhcGUuY2FsY3VsYXRlTG9jYWxJbmVydGlhKG1hc3MsIGxvY2FsSW5lcnRpYSk7CiAgICAgIGNvbnN0IHJiSW5mbyA9IG5ldyBBbW1vLmJ0UmlnaWRCb2R5Q29uc3RydWN0aW9uSW5mbyhtYXNzLCBtb3Rpb25TdGF0ZSwgc2hhcGUsIGxvY2FsSW5lcnRpYSk7CiAgICAgIGNvbnN0IGJvZHkgPSBuZXcgQW1tby5idFJpZ2lkQm9keShyYkluZm8pOwogICAgICBpZiAobWFzcyA+IDApIHsKICAgICAgICBib2R5LnNldEZyaWN0aW9uKGZyaWN0aW9uKTsKICAgICAgICBib2R5LnNldFJlc3RpdHV0aW9uKHJlc3RpdHV0aW9uKTsKICAgICAgICBib2R5LnNldERhbXBpbmcoZGFtcGluZy5saW5lYXIsIGRhbXBpbmcuYW5ndWxhcik7CiAgICAgICAgYm9keS5zZXRBY3RpdmF0aW9uU3RhdGUoRElTQUJMRV9ERUFDVElWQVRJT04pOwogICAgICB9CgogICAgICAvLyBzdG9yaW5nIHV1aWQgZm9yIGZ1dHVyZSByZWZlcmVuY2UKICAgICAgYm9keS51dWlkID0gdXVpZDsKICAgICAgd29ybGQuYWRkUmlnaWRCb2R5KGJvZHkpOwogICAgICByZXR1cm4gYm9keTsKICAgIH07CiAgICBjb25zdCBhZGRNb2RlbCA9IG9wdGlvbnMgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICB2ZXJ0aWNlcywKICAgICAgICBtYXRyaWNlcywKICAgICAgICBpbmRleGVzLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcyA9IDAsCiAgICAgICAgZnJpY3Rpb24gPSAyCiAgICAgIH0gPSBvcHRpb25zOwogICAgICBjb25zdCBzY2FsZSA9IERFRkFVTFRfU0NBTEU7CiAgICAgIGNvbnN0IGJ0YSA9IG5ldyBBbW1vLmJ0VmVjdG9yMygpOwogICAgICBjb25zdCBidGIgPSBuZXcgQW1tby5idFZlY3RvcjMoKTsKICAgICAgY29uc3QgYnRjID0gbmV3IEFtbW8uYnRWZWN0b3IzKCk7CiAgICAgIGNvbnN0IHRyaU1lc2ggPSBuZXcgQW1tby5idFRyaWFuZ2xlTWVzaCh0cnVlLCBmYWxzZSk7CiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdmVydGljZXMubGVuZ3RoOyBpKyspIHsKICAgICAgICBjb25zdCBjb21wb25lbnRzID0gdmVydGljZXNbaV07CiAgICAgICAgY29uc3QgaW5kZXggPSBpbmRleGVzW2ldID8gaW5kZXhlc1tpXSA6IG51bGw7CiAgICAgICAgY29uc3QgbWF0cml4ID0gQXJyYXkuZnJvbShtYXRyaWNlc1tpXSk7CiAgICAgICAgaWYgKGluZGV4KSB7CiAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGluZGV4Lmxlbmd0aDsgaiArPSAzKSB7CiAgICAgICAgICAgIGNvbnN0IGFpID0gaW5kZXhbal0gKiAzOwogICAgICAgICAgICBjb25zdCBiaSA9IGluZGV4W2ogKyAxXSAqIDM7CiAgICAgICAgICAgIGNvbnN0IGNpID0gaW5kZXhbaiArIDJdICogMzsKICAgICAgICAgICAgY29uc3QgdmEgPSBhcHBseU1hdHJpeDRUb1ZlY3RvcjMoewogICAgICAgICAgICAgIHg6IGNvbXBvbmVudHNbYWldLAogICAgICAgICAgICAgIHk6IGNvbXBvbmVudHNbYWkgKyAxXSwKICAgICAgICAgICAgICB6OiBjb21wb25lbnRzW2FpICsgMl0KICAgICAgICAgICAgfSwgbWF0cml4KTsKICAgICAgICAgICAgY29uc3QgdmIgPSBhcHBseU1hdHJpeDRUb1ZlY3RvcjMoewogICAgICAgICAgICAgIHg6IGNvbXBvbmVudHNbYmldLAogICAgICAgICAgICAgIHk6IGNvbXBvbmVudHNbYmkgKyAxXSwKICAgICAgICAgICAgICB6OiBjb21wb25lbnRzW2JpICsgMl0KICAgICAgICAgICAgfSwgbWF0cml4KTsKICAgICAgICAgICAgY29uc3QgdmMgPSBhcHBseU1hdHJpeDRUb1ZlY3RvcjMoewogICAgICAgICAgICAgIHg6IGNvbXBvbmVudHNbY2ldLAogICAgICAgICAgICAgIHk6IGNvbXBvbmVudHNbY2kgKyAxXSwKICAgICAgICAgICAgICB6OiBjb21wb25lbnRzW2NpICsgMl0KICAgICAgICAgICAgfSwgbWF0cml4KTsKICAgICAgICAgICAgYnRhLnNldFZhbHVlKHZhLngsIHZhLnksIHZhLnopOwogICAgICAgICAgICBidGIuc2V0VmFsdWUodmIueCwgdmIueSwgdmIueik7CiAgICAgICAgICAgIGJ0Yy5zZXRWYWx1ZSh2Yy54LCB2Yy55LCB2Yy56KTsKICAgICAgICAgICAgdHJpTWVzaC5hZGRUcmlhbmdsZShidGEsIGJ0YiwgYnRjLCBmYWxzZSk7CiAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgY29tcG9uZW50cy5sZW5ndGg7IGogKz0gOSkgewogICAgICAgICAgICBjb25zdCB2YSA9IGFwcGx5TWF0cml4NFRvVmVjdG9yMyh7CiAgICAgICAgICAgICAgeDogY29tcG9uZW50c1tqICsgMF0sCiAgICAgICAgICAgICAgeTogY29tcG9uZW50c1tqICsgMV0sCiAgICAgICAgICAgICAgejogY29tcG9uZW50c1tqICsgMl0KICAgICAgICAgICAgfSwgbWF0cml4KTsKICAgICAgICAgICAgY29uc3QgdmIgPSBhcHBseU1hdHJpeDRUb1ZlY3RvcjMoewogICAgICAgICAgICAgIHg6IGNvbXBvbmVudHNbaiArIDNdLAogICAgICAgICAgICAgIHk6IGNvbXBvbmVudHNbaiArIDRdLAogICAgICAgICAgICAgIHo6IGNvbXBvbmVudHNbaiArIDVdCiAgICAgICAgICAgIH0sIG1hdHJpeCk7CiAgICAgICAgICAgIGNvbnN0IHZjID0gYXBwbHlNYXRyaXg0VG9WZWN0b3IzKHsKICAgICAgICAgICAgICB4OiBjb21wb25lbnRzW2ogKyA2XSwKICAgICAgICAgICAgICB5OiBjb21wb25lbnRzW2ogKyA3XSwKICAgICAgICAgICAgICB6OiBjb21wb25lbnRzW2ogKyA4XQogICAgICAgICAgICB9LCBtYXRyaXgpOwogICAgICAgICAgICBidGEuc2V0VmFsdWUodmEueCwgdmEueSwgdmEueik7CiAgICAgICAgICAgIGJ0Yi5zZXRWYWx1ZSh2Yi54LCB2Yi55LCB2Yi56KTsKICAgICAgICAgICAgYnRjLnNldFZhbHVlKHZjLngsIHZjLnksIHZjLnopOwogICAgICAgICAgICB0cmlNZXNoLmFkZFRyaWFuZ2xlKGJ0YSwgYnRiLCBidGMsIGZhbHNlKTsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgICAgY29uc3QgbG9jYWxTY2FsZSA9IG5ldyBBbW1vLmJ0VmVjdG9yMyhzY2FsZS54LCBzY2FsZS55LCBzY2FsZS56KTsKICAgICAgdHJpTWVzaC5zZXRTY2FsaW5nKGxvY2FsU2NhbGUpOwogICAgICBBbW1vLmRlc3Ryb3kobG9jYWxTY2FsZSk7CiAgICAgIGNvbnN0IGNvbGxpc2lvblNoYXBlID0gbmV3IEFtbW8uYnRCdmhUcmlhbmdsZU1lc2hTaGFwZSh0cmlNZXNoLCB0cnVlLCB0cnVlKTsKICAgICAgY29sbGlzaW9uU2hhcGUucmVzb3VyY2VzID0gW3RyaU1lc2hdOwogICAgICBBbW1vLmRlc3Ryb3koYnRhKTsKICAgICAgQW1tby5kZXN0cm95KGJ0Yik7CiAgICAgIEFtbW8uZGVzdHJveShidGMpOwogICAgICBjb25zdCBib2R5ID0gY3JlYXRlUmlnaWRCb2R5KGNvbGxpc2lvblNoYXBlLCB7CiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIG1hc3MsCiAgICAgICAgZnJpY3Rpb24KICAgICAgfSk7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHV1aWQsCiAgICAgICAgYm9keSwKICAgICAgICB0eXBlOiBUWVBFUy5NRVNILAogICAgICAgIHN0YXRlOiBERUZBVUxUX1JJR0lEQk9EWV9TVEFURQogICAgICB9KTsKICAgIH07CiAgICBjb25zdCBhZGRCb3ggPSBkYXRhID0+IHsKICAgICAgY29uc3QgewogICAgICAgIHV1aWQsCiAgICAgICAgd2lkdGgsCiAgICAgICAgbGVuZ3RoLAogICAgICAgIGhlaWdodCwKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIG1hc3MgPSAwLAogICAgICAgIGZyaWN0aW9uID0gMgogICAgICB9ID0gZGF0YTsKICAgICAgY29uc3QgZ2VvbWV0cnkgPSBuZXcgQW1tby5idEJveFNoYXBlKG5ldyBBbW1vLmJ0VmVjdG9yMyh3aWR0aCAqIDAuNSwgaGVpZ2h0ICogMC41LCBsZW5ndGggKiAwLjUpKTsKICAgICAgY29uc3QgYm9keSA9IGNyZWF0ZVJpZ2lkQm9keShnZW9tZXRyeSwgewogICAgICAgIHV1aWQsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgcXVhdGVybmlvbiwKICAgICAgICBtYXNzLAogICAgICAgIGZyaWN0aW9uCiAgICAgIH0pOwogICAgICB3b3JsZC5hZGRFbGVtZW50KHsKICAgICAgICB1dWlkLAogICAgICAgIGJvZHksCiAgICAgICAgdHlwZTogVFlQRVMuQk9YLAogICAgICAgIHN0YXRlOiBERUZBVUxUX1JJR0lEQk9EWV9TVEFURQogICAgICB9KTsKICAgIH07CiAgICBjb25zdCBhZGRTcGhlcmUgPSBkYXRhID0+IHsKICAgICAgY29uc3QgewogICAgICAgIHV1aWQsCiAgICAgICAgcmFkaXVzLAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIHF1YXRlcm5pb24sCiAgICAgICAgbWFzcyA9IDAsCiAgICAgICAgZnJpY3Rpb24gPSAyCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBnZW9tZXRyeSA9IG5ldyBBbW1vLmJ0U3BoZXJlU2hhcGUocmFkaXVzKTsKICAgICAgY29uc3QgYm9keSA9IGNyZWF0ZVJpZ2lkQm9keShnZW9tZXRyeSwgewogICAgICAgIHV1aWQsCiAgICAgICAgcG9zaXRpb24sCiAgICAgICAgcXVhdGVybmlvbiwKICAgICAgICBtYXNzLAogICAgICAgIGZyaWN0aW9uCiAgICAgIH0pOwogICAgICB3b3JsZC5hZGRFbGVtZW50KHsKICAgICAgICB1dWlkLAogICAgICAgIGJvZHksCiAgICAgICAgdHlwZTogVFlQRVMuU1BIRVJFLAogICAgICAgIHN0YXRlOiBERUZBVUxUX1JJR0lEQk9EWV9TVEFURQogICAgICB9KTsKICAgIH07CiAgICBjb25zdCBzZXRMaW5lYXJWZWxvY2l0eSA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICB2ZWxvY2l0eSA9IERFRkFVTFRfTElORUFSX1ZFTE9DSVRZCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYm9keQogICAgICB9ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgY29uc3QgbW90aW9uU3RhdGUgPSBib2R5LmdldE1vdGlvblN0YXRlKCk7CiAgICAgIGlmIChtb3Rpb25TdGF0ZSkgewogICAgICAgIGNvbnN0IGxpbmVhclZlbG9jaXR5ID0gbmV3IEFtbW8uYnRWZWN0b3IzKHZlbG9jaXR5LngsIHZlbG9jaXR5LnksIHZlbG9jaXR5LnopOwogICAgICAgIGJvZHkuc2V0TGluZWFyVmVsb2NpdHkobGluZWFyVmVsb2NpdHkpOwogICAgICAgIEFtbW8uZGVzdHJveShsaW5lYXJWZWxvY2l0eSk7CiAgICAgIH0KICAgIH07CiAgICBjb25zdCBzZXRQb3NpdGlvbiA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbgogICAgICB9ID0gZGF0YTsKICAgICAgY29uc3QgewogICAgICAgIGJvZHkKICAgICAgfSA9IHdvcmxkLmdldEVsZW1lbnQodXVpZCk7CiAgICAgIGNvbnN0IHRyYW5zZm9ybSA9IG5ldyBBbW1vLmJ0VHJhbnNmb3JtKCk7CiAgICAgIGJvZHkuZ2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICBib2R5LnNldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIC8vIEFsc28gdXBkYXRlIG1vdGlvbiBzdGF0ZSBzbyBzdGF0aWMgYm9kaWVzIChtYXNzPTApIHJlZmxlY3QgdGhlIGNoYW5nZQogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IGJvZHkuZ2V0TW90aW9uU3RhdGUoKTsKICAgICAgaWYgKG1vdGlvblN0YXRlKSB7CiAgICAgICAgbW90aW9uU3RhdGUuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHJlc2V0RWxlbWVudCA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYm9keQogICAgICB9ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgYm9keS5nZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB0cmFuc2Zvcm0uc2V0T3JpZ2luKG5ldyBBbW1vLmJ0VmVjdG9yMyhwb3NpdGlvbi54LCBwb3NpdGlvbi55LCBwb3NpdGlvbi56KSk7CiAgICAgIHRyYW5zZm9ybS5zZXRSb3RhdGlvbihuZXcgQW1tby5idFF1YXRlcm5pb24ocXVhdGVybmlvbi54LCBxdWF0ZXJuaW9uLnksIHF1YXRlcm5pb24ueiwgcXVhdGVybmlvbi53KSk7CiAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgLy8gQWxzbyB1cGRhdGUgbW90aW9uIHN0YXRlIHNvIHN0YXRpYyBib2RpZXMgKG1hc3M9MCkgcmVmbGVjdCB0aGUgY2hhbmdlCiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBtb3Rpb25TdGF0ZS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgYXBwbHlJbXB1c2UgPSAoewogICAgICB1dWlkLAogICAgICBpbXB1bHNlID0gREVGQVVMVF9JTVBVTFNFCiAgICB9KSA9PiB7CiAgICAgIHRyeSB7CiAgICAgICAgY29uc3QgZWxlbWVudCA9IHdvcmxkLmdldEVsZW1lbnQodXVpZCk7CiAgICAgICAgaWYgKCFlbGVtZW50KSB7CiAgICAgICAgICBjb25zb2xlLndhcm4oIltQaHlzaWNzIFdvcmtlcl0gYXBwbHlJbXB1bHNlOiBlbGVtZW50IG5vdCBmb3VuZCBmb3IgdXVpZDoiLCB1dWlkKTsKICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgY29uc3QgewogICAgICAgICAgYm9keQogICAgICAgIH0gPSBlbGVtZW50OwogICAgICAgIGlmICghYm9keSkgewogICAgICAgICAgY29uc29sZS53YXJuKCJbUGh5c2ljcyBXb3JrZXJdIGFwcGx5SW1wdWxzZTogYm9keSBpcyBudWxsIGZvciB1dWlkOiIsIHV1aWQpOwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBib2R5LmFjdGl2YXRlKHRydWUpOwogICAgICAgIGNvbnN0IGJ0SW1wdWxzZSA9IG5ldyBBbW1vLmJ0VmVjdG9yMyhpbXB1bHNlLngsIGltcHVsc2UueSwgaW1wdWxzZS56KTsKICAgICAgICBib2R5LmFwcGx5Q2VudHJhbEltcHVsc2UoYnRJbXB1bHNlKTsKICAgICAgICBBbW1vLmRlc3Ryb3koYnRJbXB1bHNlKTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIGNvbnNvbGUuZXJyb3IoIltQaHlzaWNzIFdvcmtlcl0gYXBwbHlJbXB1bHNlIGVycm9yOiIsIGUpOwogICAgICB9CiAgICB9OwogICAgY29uc3Qgc2V0UXVhdGVybmlvbiA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICBxdWF0ZXJuaW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYm9keQogICAgICB9ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgYm9keS5nZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICBib2R5LnNldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIC8vIEFsc28gdXBkYXRlIG1vdGlvbiBzdGF0ZSBzbyBzdGF0aWMgYm9kaWVzIChtYXNzPTApIHJlZmxlY3QgdGhlIGNoYW5nZQogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IGJvZHkuZ2V0TW90aW9uU3RhdGUoKTsKICAgICAgaWYgKG1vdGlvblN0YXRlKSB7CiAgICAgICAgbW90aW9uU3RhdGUuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IGhhbmRsZUVsZW1lbnRVcGRhdGUgPSAoewogICAgICBib2R5LAogICAgICB1dWlkLAogICAgICBzdGF0ZTogX3N0YXRlID0gREVGQVVMVF9SSUdJREJPRFlfU1RBVEUKICAgIH0sIGR0KSA9PiB7CiAgICAgIC8vIFN0YXRpYyBib2RpZXMgKG1hc3M9MCkgbmV2ZXIgbW92ZSDigJQgc2tpcCBzZW5kaW5nIHVwZGF0ZXMgc28gdGhlCiAgICAgIC8vIHZpc3VhbCBwb3NpdGlvbiBzdGF5cyBleGFjdGx5IHdoZXJlIHRoZSBhdXRob3IgcGxhY2VkIGl0LgogICAgICBpZiAoYm9keS5pc1N0YXRpY09iamVjdCgpKSByZXR1cm47CiAgICAgIGNvbnN0IG1vdGlvblN0YXRlID0gYm9keS5nZXRNb3Rpb25TdGF0ZSgpOwogICAgICBpZiAobW90aW9uU3RhdGUpIHsKICAgICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICAgIG1vdGlvblN0YXRlLmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgbGV0IG9yaWdpbiA9IHRyYW5zZm9ybS5nZXRPcmlnaW4oKTsKICAgICAgICBsZXQgcm90YXRpb24gPSB0cmFuc2Zvcm0uZ2V0Um90YXRpb24oKTsKICAgICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHV1aWQsIG9yaWdpbiwgcm90YXRpb24sIGR0KTsKICAgICAgICBBbW1vLmRlc3Ryb3kodHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKCiAgICBjb25zdCBhZGRQbGF5ZXIgPSBkYXRhID0+IHsKICAgICAgY29uc3QgewogICAgICAgIHV1aWQsCiAgICAgICAgd2lkdGgsCiAgICAgICAgaGVpZ2h0LAogICAgICAgIHBvc2l0aW9uLAogICAgICAgIG1hc3MsCiAgICAgICAgZnJpY3Rpb24sCiAgICAgICAgb3JpZ2luT2Zmc2V0ID0gewogICAgICAgICAgeDogMCwKICAgICAgICAgIHk6IDAsCiAgICAgICAgICB6OiAwCiAgICAgICAgfQogICAgICB9ID0gZGF0YTsKCiAgICAgIC8vIGJ0Q2Fwc3VsZVNoYXBlIGV4cGVjdHMgKHJhZGl1cywgY3lsaW5kZXJIZWlnaHQpIOKAlCB1c2UgaGFsZi13aWR0aCBhcwogICAgICAvLyByYWRpdXMgc28gdGhlIGNhcHN1bGUgd3JhcHMgdGhlIGJvdW5kaW5nIGJveCBjb3JyZWN0bHkuCiAgICAgIGNvbnN0IHJhZGl1cyA9IHdpZHRoICogMC41OwogICAgICBjb25zdCBjYXBzdWxlID0gbmV3IEFtbW8uYnRDYXBzdWxlU2hhcGUocmFkaXVzLCBoZWlnaHQpOwoKICAgICAgLy8gQWx3YXlzIGNyZWF0ZSB0aGUgcGxheWVyIGJvZHkgdXByaWdodCAoaWRlbnRpdHkgcXVhdGVybmlvbikuCiAgICAgIC8vIFRoZSB2aXN1YWwgcm90YXRpb24gaXMgZHJpdmVuIGJ5IHRoZSBjb250cm9sLCBub3QgYnkgcGh5c2ljcy4KICAgICAgY29uc3QgdXByaWdodFF1YXRlcm5pb24gPSB7CiAgICAgICAgeDogMCwKICAgICAgICB5OiAwLAogICAgICAgIHo6IDAsCiAgICAgICAgdzogMQogICAgICB9OwoKICAgICAgLy8gUG9zaXRpb24gdGhlIGNhcHN1bGUgYXQgdGhlIG1vZGVsJ3MgQUFCQiBjZW50cmUgc28gaXQgd3JhcHMgdGhlCiAgICAgIC8vIHZpc3VhbCBtZXNoIGNvcnJlY3RseS4gIG9yaWdpbk9mZnNldCBpcyB0aGUgdmVjdG9yIGZyb20gdGhlIG1vZGVsJ3MKICAgICAgLy8gb3JpZ2luIHRvIGl0cyBBQUJCIGNlbnRyZSDigJQgY29tcHV0ZWQgb24gdGhlIG1haW4gdGhyZWFkIHdoZXJlCiAgICAgIC8vIFRocmVlLmpzIGdlb21ldHJ5IGlzIGF2YWlsYWJsZS4KICAgICAgY29uc3QgY2Fwc3VsZVBvc2l0aW9uID0gewogICAgICAgIHg6IHBvc2l0aW9uLnggKyBvcmlnaW5PZmZzZXQueCwKICAgICAgICB5OiBwb3NpdGlvbi55ICsgb3JpZ2luT2Zmc2V0LnksCiAgICAgICAgejogcG9zaXRpb24ueiArIG9yaWdpbk9mZnNldC56CiAgICAgIH07CiAgICAgIGNvbnN0IGJvZHkgPSBjcmVhdGVSaWdpZEJvZHkoY2Fwc3VsZSwgewogICAgICAgIHV1aWQsCiAgICAgICAgcG9zaXRpb246IGNhcHN1bGVQb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uOiB1cHJpZ2h0UXVhdGVybmlvbiwKICAgICAgICBtYXNzLAogICAgICAgIGZyaWN0aW9uLAogICAgICAgIHJlc3RpdHV0aW9uOiAwLAogICAgICAgIGRhbXBpbmc6IHsKICAgICAgICAgIGxpbmVhcjogMC4xLAogICAgICAgICAgYW5ndWxhcjogMQogICAgICAgIH0KICAgICAgfSk7CgogICAgICAvLyBEaXNhYmxlIHJvdGF0aW9uIG9uIGFsbCBheGVzIOKAlCB0aGUgdmlzdWFsIHJvdGF0aW9uIGlzIGRyaXZlbiBieSB0aGUgY29udHJvbC4KICAgICAgLy8gVXNlIGJ0VmVjdG9yMyBpbnN0ZWFkIG9mIHNjYWxhciBmb3IgY29tcGF0aWJpbGl0eSBhY3Jvc3MgQW1tby5qcyBidWlsZHMuCiAgICAgIGNvbnN0IHplcm9Bbmd1bGFyID0gbmV3IEFtbW8uYnRWZWN0b3IzKDAsIDAsIDApOwogICAgICBib2R5LnNldEFuZ3VsYXJGYWN0b3IoemVyb0FuZ3VsYXIpOwogICAgICBBbW1vLmRlc3Ryb3koemVyb0FuZ3VsYXIpOwoKICAgICAgLy8gRW5hYmxlIGNvbnRpbnVvdXMgY29sbGlzaW9uIGRldGVjdGlvbiB0byBwcmV2ZW50IHR1bm5lbGluZyBhdCBoaWdoIHNwZWVkcy4KICAgICAgYm9keS5zZXRDY2RNb3Rpb25UaHJlc2hvbGQocmFkaXVzICogMC41KTsKICAgICAgYm9keS5zZXRDY2RTd2VwdFNwaGVyZVJhZGl1cyhyYWRpdXMgKiAwLjgpOwoKICAgICAgLy8gU3RvcmUgZm9yIHVzZSBpbiBoYW5kbGVQbGF5ZXJVcGRhdGUg4oCUIG9mZnNldCBpcyBzdWJ0cmFjdGVkIHdoZW4KICAgICAgLy8gc2VuZGluZyBwb3NpdGlvbiBiYWNrIHNvIHRoZSB2aXN1YWwgc3RheXMgYXQgdGhlIG1vZGVsIG9yaWdpbi4KICAgICAgYm9keS5fbWFzcyA9IG1hc3M7CiAgICAgIGJvZHkuX29yaWdpbk9mZnNldCA9IG9yaWdpbk9mZnNldDsKICAgICAgd29ybGQuYWRkRWxlbWVudCh7CiAgICAgICAgdXVpZCwKICAgICAgICBib2R5LAogICAgICAgIHR5cGU6IFRZUEVTLlBMQVlFUiwKICAgICAgICBzdGF0ZTogREVGQVVMVF9SSUdJREJPRFlfU1RBVEUKICAgICAgfSk7CiAgICB9OwogICAgY29uc3QgaGFuZGxlUGxheWVyVXBkYXRlID0gKHsKICAgICAgYm9keSwKICAgICAgdXVpZCwKICAgICAgc3RhdGUgPSBERUZBVUxUX1JJR0lEQk9EWV9TVEFURQogICAgfSwgZHQpID0+IHsKICAgICAgY29uc3QgewogICAgICAgIG1vdmVtZW50LAogICAgICAgIGNhbWVyYURpcmVjdGlvbiwKICAgICAgICBqdW1wLAogICAgICAgIGp1bXBTcGVlZCwKICAgICAgICBzcGVlZDogbW92ZVNwZWVkCiAgICAgIH0gPSBzdGF0ZTsKICAgICAgY29uc3QgbW90aW9uU3RhdGUgPSBib2R5LmdldE1vdGlvblN0YXRlKCk7CiAgICAgIGlmICghbW90aW9uU3RhdGUpIHJldHVybjsKCiAgICAgIC8vIEZvcmNlLWNsZWFyIGFuZ3VsYXIgdmVsb2NpdHkgZXZlcnkgdGljay4gVGhlIHBsYXllciBjYXBzdWxlIG11c3Qgc3RheQogICAgICAvLyB1cHJpZ2h0IOKAlCByb3RhdGlvbiBpcyBoYW5kbGVkIHZpc3VhbGx5IGJ5IHRoZSBjb250cm9sLCBub3QgYnkgcGh5c2ljcy4KICAgICAgY29uc3QgemVyb0FuZ1ZlbCA9IG5ldyBBbW1vLmJ0VmVjdG9yMygwLCAwLCAwKTsKICAgICAgYm9keS5zZXRBbmd1bGFyVmVsb2NpdHkoemVyb0FuZ1ZlbCk7CiAgICAgIEFtbW8uZGVzdHJveSh6ZXJvQW5nVmVsKTsKCiAgICAgIC8vIEZvcmNlIHRoZSBwaHlzaWNzIGJvZHkgcm90YXRpb24gdG8gaWRlbnRpdHkgKHVwcmlnaHQpIGV2ZXJ5IHRpY2suCiAgICAgIC8vIENvbnRhY3QgZm9yY2VzIGNhbiBzdGlsbCByb3RhdGUgdGhlIGNhcHN1bGUgaW4gc29tZSBBbW1vLmpzIGJ1aWxkcwogICAgICAvLyBldmVuIHdpdGggYW5ndWxhckZhY3Rvcj0oMCwwLDApLiBXZSBtdXN0IHJlc2V0IEJPVEggdGhlIGJvZHkgd29ybGQKICAgICAgLy8gdHJhbnNmb3JtIEFORCB0aGUgbW90aW9uU3RhdGUg4oCUIHRoZXkgY2FuIGRpdmVyZ2UuCiAgICAgIGNvbnN0IHdvcmxkVHJhbnNmb3JtID0gYm9keS5nZXRXb3JsZFRyYW5zZm9ybSgpOwogICAgICBjb25zdCB1cHJpZ2h0UXVhdCA9IG5ldyBBbW1vLmJ0UXVhdGVybmlvbigwLCAwLCAwLCAxKTsKICAgICAgd29ybGRUcmFuc2Zvcm0uc2V0Um90YXRpb24odXByaWdodFF1YXQpOwogICAgICBib2R5LnNldFdvcmxkVHJhbnNmb3JtKHdvcmxkVHJhbnNmb3JtKTsKICAgICAgbW90aW9uU3RhdGUuc2V0V29ybGRUcmFuc2Zvcm0od29ybGRUcmFuc2Zvcm0pOwogICAgICBBbW1vLmRlc3Ryb3kodXByaWdodFF1YXQpOwogICAgICBjb25zdCBjaGFyYWN0ZXJTcGVlZCA9IG1vdmVTcGVlZCB8fCA1OwoKICAgICAgLy8gSnVtcCDigJQgYXBwbHkgYSBvbmUtdGltZSBpbXB1bHNlLCB0aGVuIGNsZWFyIHRoZSBmbGFnIHNvIGl0IGRvZXNuJ3QgcmVwZWF0CiAgICAgIGlmIChqdW1wICYmIGp1bXBTcGVlZCkgewogICAgICAgIGNvbnN0IG1hc3MgPSBib2R5Ll9tYXNzIHx8IDgwOwogICAgICAgIGNvbnN0IGltcHVsc2UgPSBuZXcgQW1tby5idFZlY3RvcjMoMCwganVtcFNwZWVkICogbWFzcywgMCk7CiAgICAgICAgYm9keS5hcHBseUNlbnRyYWxJbXB1bHNlKGltcHVsc2UpOwogICAgICAgIEFtbW8uZGVzdHJveShpbXB1bHNlKTsKICAgICAgICBzdGF0ZS5qdW1wID0gZmFsc2U7CiAgICAgIH0KICAgICAgY29uc3QgaXNNb3ZpbmcgPSBtb3ZlbWVudCAmJiAobW92ZW1lbnQuZm9yd2FyZCB8fCBtb3ZlbWVudC5iYWNrd2FyZHMgfHwgbW92ZW1lbnQubGVmdCB8fCBtb3ZlbWVudC5yaWdodCk7CiAgICAgIGNvbnN0IGxpbmVhclZlbG9jaXR5ID0gYm9keS5nZXRMaW5lYXJWZWxvY2l0eSgpOwogICAgICBjb25zdCBjdXJyZW50WSA9IGxpbmVhclZlbG9jaXR5LnkoKTsKICAgICAgaWYgKGlzTW92aW5nICYmIGNhbWVyYURpcmVjdGlvbikgewogICAgICAgIC8vIENvbXB1dGUgY2FtZXJhLXJlbGF0aXZlIG1vdmVtZW50IGRpcmVjdGlvbgogICAgICAgIGxldCBtb3ZlWCA9IDA7CiAgICAgICAgbGV0IG1vdmVaID0gMDsKICAgICAgICBpZiAobW92ZW1lbnQuZm9yd2FyZCkgewogICAgICAgICAgbW92ZVggKz0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgICBtb3ZlWiArPSBjYW1lcmFEaXJlY3Rpb24uejsKICAgICAgICB9CiAgICAgICAgaWYgKG1vdmVtZW50LmJhY2t3YXJkcykgewogICAgICAgICAgbW92ZVggLT0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgICBtb3ZlWiAtPSBjYW1lcmFEaXJlY3Rpb24uejsKICAgICAgICB9CiAgICAgICAgaWYgKG1vdmVtZW50LmxlZnQpIHsKICAgICAgICAgIG1vdmVYICs9IGNhbWVyYURpcmVjdGlvbi56OwogICAgICAgICAgbW92ZVogLT0gY2FtZXJhRGlyZWN0aW9uLng7CiAgICAgICAgfQogICAgICAgIGlmIChtb3ZlbWVudC5yaWdodCkgewogICAgICAgICAgbW92ZVggLT0gY2FtZXJhRGlyZWN0aW9uLno7CiAgICAgICAgICBtb3ZlWiArPSBjYW1lcmFEaXJlY3Rpb24ueDsKICAgICAgICB9CgogICAgICAgIC8vIE5vcm1hbGl6ZSBkaXJlY3Rpb24KICAgICAgICBjb25zdCBsZW4gPSBNYXRoLnNxcnQobW92ZVggKiBtb3ZlWCArIG1vdmVaICogbW92ZVopOwogICAgICAgIGlmIChsZW4gPiAwKSB7CiAgICAgICAgICBtb3ZlWCAvPSBsZW47CiAgICAgICAgICBtb3ZlWiAvPSBsZW47CiAgICAgICAgfQoKICAgICAgICAvLyBTZXQgaG9yaXpvbnRhbCB2ZWxvY2l0eSBkaXJlY3RseSBmb3IgcmVzcG9uc2l2ZSBtb3ZlbWVudAogICAgICAgIGNvbnN0IG5ld1ZlbCA9IG5ldyBBbW1vLmJ0VmVjdG9yMyhtb3ZlWCAqIGNoYXJhY3RlclNwZWVkLCBjdXJyZW50WSwgbW92ZVogKiBjaGFyYWN0ZXJTcGVlZCk7CiAgICAgICAgYm9keS5zZXRMaW5lYXJWZWxvY2l0eShuZXdWZWwpOwogICAgICAgIEFtbW8uZGVzdHJveShuZXdWZWwpOwogICAgICB9IGVsc2UgewogICAgICAgIC8vIFdoZW4gaWRsZSwgb25seSBkYW1wZW4gaWYgdGhlcmUncyBtZWFuaW5nZnVsIGhvcml6b250YWwgdmVsb2NpdHkuCiAgICAgICAgLy8gQXZvaWQgdG91Y2hpbmcgdGhlIHZlbG9jaXR5IGV2ZXJ5IGZyYW1lIHRvIGxldCB0aGUgc29sdmVyCiAgICAgICAgLy8gaGFuZGxlIGZsb29yIGNvbnRhY3Qgd2l0aG91dCBpbnRlcmZlcmVuY2UuCiAgICAgICAgY29uc3QgdnggPSBsaW5lYXJWZWxvY2l0eS54KCk7CiAgICAgICAgY29uc3QgdnogPSBsaW5lYXJWZWxvY2l0eS56KCk7CiAgICAgICAgaWYgKE1hdGguYWJzKHZ4KSA+IDAuMDEgfHwgTWF0aC5hYnModnopID4gMC4wMSkgewogICAgICAgICAgY29uc3QgbmV3VmVsID0gbmV3IEFtbW8uYnRWZWN0b3IzKHZ4ICogMC44NSwgY3VycmVudFksIHZ6ICogMC44NSk7CiAgICAgICAgICBib2R5LnNldExpbmVhclZlbG9jaXR5KG5ld1ZlbCk7CiAgICAgICAgICBBbW1vLmRlc3Ryb3kobmV3VmVsKTsKICAgICAgICB9CiAgICAgICAgLy8gT3RoZXJ3aXNlIGxldCBwaHlzaWNzIGhhbmRsZSBldmVyeXRoaW5nIOKAlCBkb24ndCBvdmVycmlkZSB2ZWxvY2l0eQogICAgICB9CgogICAgICAvLyBSZWFkIGZyb20gdGhlIGJvZHkncyB3b3JsZCB0cmFuc2Zvcm0gKG5vdCBtb3Rpb25TdGF0ZSkgYmVjYXVzZSB3ZQogICAgICAvLyBtYWludGFpbiBpdCBkaXJlY3RseSBhYm92ZSDigJQgcG9zaXRpb24gY29tZXMgZnJvbSBwaHlzaWNzLCByb3RhdGlvbgogICAgICAvLyBpcyBhbHdheXMgaWRlbnRpdHkuCiAgICAgIGNvbnN0IGZpbmFsVHJhbnNmb3JtID0gYm9keS5nZXRXb3JsZFRyYW5zZm9ybSgpOwogICAgICBjb25zdCBvcmlnaW4gPSBmaW5hbFRyYW5zZm9ybS5nZXRPcmlnaW4oKTsKICAgICAgY29uc3Qgcm90YXRpb24gPSBmaW5hbFRyYW5zZm9ybS5nZXRSb3RhdGlvbigpOwogICAgICBjb25zdCBncm91bmRlZCA9IE1hdGguYWJzKGN1cnJlbnRZKSA8IDAuNTsKCiAgICAgIC8vIFRoZSBwaHlzaWNzIGNhcHN1bGUgaXMgb2Zmc2V0IHVwd2FyZCBzbyBpdHMgYm90dG9tIGFsaWducyB3aXRoIHRoZQogICAgICAvLyBjaGFyYWN0ZXIncyBmZWV0LiAgU3VidHJhY3QgdGhlIG9mZnNldCBiZWZvcmUgc2VuZGluZyB0aGUgcG9zaXRpb24KICAgICAgLy8gYmFjayBzbyB0aGUgdmlzdWFsIHN0YXlzIGF0IHRoZSBmZWV0LCBub3QgdGhlIGNhcHN1bGUgY2VudHJlLgogICAgICAvLyBTdWJ0cmFjdCB0aGUgb3JpZ2luIG9mZnNldCBzbyB0aGUgcG9zaXRpb24gbWFwcyBiYWNrIHRvIG1vZGVsLW9yaWdpbgogICAgICAvLyBzcGFjZSAodGhlIHZpc3VhbCdzIHRyYW5zZm9ybSBvcmlnaW4pLCBub3QgdGhlIEFBQkIgY2VudHJlLgogICAgICBjb25zdCBvZmYgPSBib2R5Ll9vcmlnaW5PZmZzZXQgfHwgewogICAgICAgIHg6IDAsCiAgICAgICAgeTogMCwKICAgICAgICB6OiAwCiAgICAgIH07CiAgICAgIGNvbnN0IGFkanVzdGVkT3JpZ2luID0gbmV3IEFtbW8uYnRWZWN0b3IzKG9yaWdpbi54KCkgLSBvZmYueCwgb3JpZ2luLnkoKSAtIG9mZi55LCBvcmlnaW4ueigpIC0gb2ZmLnopOwogICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHV1aWQsIGFkanVzdGVkT3JpZ2luLCByb3RhdGlvbiwgZHQsIHsKICAgICAgICBncm91bmRlZAogICAgICB9KTsKICAgICAgQW1tby5kZXN0cm95KGFkanVzdGVkT3JpZ2luKTsKICAgIH07CgogICAgY29uc3QgcmVxdWVzdE5leHRGcmFtZSA9IHNlbGYucmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHNlbGYud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHNlbGYubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHNlbGYub1JlcXVlc3RBbmltYXRpb25GcmFtZSB8fCBzZWxmLm1zUmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IGZ1bmN0aW9uIChjYWxsYmFjaywgX2VsZW1lbnQpIHsKICAgICAgc2VsZi5zZXRUaW1lb3V0KGNhbGxiYWNrLCAxMDAwIC8gMTIwKTsKICAgIH07CiAgICBsZXQgQ2xvY2sgPSAvKiNfX1BVUkVfXyovZnVuY3Rpb24gKCkgewogICAgICBmdW5jdGlvbiBDbG9jaygpIHsKICAgICAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgQ2xvY2spOwogICAgICAgIHRoaXMudGltZXN0YW1wID0gbnVsbDsKICAgICAgfQogICAgICByZXR1cm4gX2NyZWF0ZUNsYXNzKENsb2NrLCBbewogICAgICAgIGtleTogImdldERlbHRhIiwKICAgICAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0RGVsdGEoKSB7CiAgICAgICAgICBjb25zdCB0aW1lID0gRGF0ZS5ub3coKTsKICAgICAgICAgIGlmICh0aGlzLnRpbWVzdGFtcCkgewogICAgICAgICAgICBjb25zdCBkZWx0YSA9IHRpbWUgLSB0aGlzLnRpbWVzdGFtcDsKICAgICAgICAgICAgdGhpcy50aW1lc3RhbXAgPSB0aW1lOwogICAgICAgICAgICByZXR1cm4gZGVsdGE7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB0aGlzLnRpbWVzdGFtcCA9IHRpbWU7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfV0pOwogICAgfSgpOwogICAgbGV0IFdvcmxkID0gLyojX19QVVJFX18qL2Z1bmN0aW9uICgpIHsKICAgICAgZnVuY3Rpb24gV29ybGQoKSB7CiAgICAgICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIFdvcmxkKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImluaXQiLCBvcHRpb25zID0+IHsKICAgICAgICAgIGNvbnN0IHsKICAgICAgICAgICAgZ3Jhdml0eSA9IEdSQVZJVFkKICAgICAgICAgIH0gPSBvcHRpb25zOwogICAgICAgICAgdGhpcy5jb2xsaXNpb25Db25maWd1cmF0aW9uID0gbmV3IEFtbW8uYnREZWZhdWx0Q29sbGlzaW9uQ29uZmlndXJhdGlvbigpOwogICAgICAgICAgdGhpcy5kaXNwYXRjaGVyID0gbmV3IEFtbW8uYnRDb2xsaXNpb25EaXNwYXRjaGVyKHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbik7CiAgICAgICAgICB0aGlzLmJyb2FkcGhhc2UgPSBuZXcgQW1tby5idERidnRCcm9hZHBoYXNlKCk7CiAgICAgICAgICB0aGlzLnNvbHZlciA9IG5ldyBBbW1vLmJ0U2VxdWVudGlhbEltcHVsc2VDb25zdHJhaW50U29sdmVyKCk7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQgPSBuZXcgQW1tby5idERpc2NyZXRlRHluYW1pY3NXb3JsZCh0aGlzLmRpc3BhdGNoZXIsIHRoaXMuYnJvYWRwaGFzZSwgdGhpcy5zb2x2ZXIsIHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbik7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuc2V0R3Jhdml0eShuZXcgQW1tby5idFZlY3RvcjMoZ3Jhdml0eS54LCBncmF2aXR5LnksIGdyYXZpdHkueikpOwoKICAgICAgICAgIC8vIHRoaXMgaXMgbmVlZGVkIGZvciBnaG9zdE9iamVjdCBjb2xsaXNpb25zCiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuZ2V0QnJvYWRwaGFzZSgpLmdldE92ZXJsYXBwaW5nUGFpckNhY2hlKCkuc2V0SW50ZXJuYWxHaG9zdFBhaXJDYWxsYmFjayhuZXcgQW1tby5idEdob3N0UGFpckNhbGxiYWNrKCkpOwogICAgICAgICAgdGhpcy5pbml0aWFsaXNlZCA9IHRydWU7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJyZW1vdmVFbGVtZW50IiwgdXVpZCA9PiB7CiAgICAgICAgICBpZiAodGhpcy5oYXNFbGVtZW50KHV1aWQpKSB7CiAgICAgICAgICAgIHRoaXMuZWxlbWVudHNbdXVpZF0uZGVsZXRlZCA9IHRydWU7CiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJyZW1vdmVEZWxldGVkRWxlbWVudHMiLCAoKSA9PiBPYmplY3Qua2V5cyh0aGlzLmVsZW1lbnRzKS5maWx0ZXIodXVpZCA9PiB0aGlzLmVsZW1lbnRzW3V1aWRdLmRlbGV0ZWQpLmZvckVhY2godXVpZCA9PiB7CiAgICAgICAgICBkZWxldGUgdGhpcy5lbGVtZW50c1t1dWlkXTsKICAgICAgICB9KSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJoYXNFbGVtZW50IiwgdXVpZCA9PiB7CiAgICAgICAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcy5lbGVtZW50cykuaW5jbHVkZXModXVpZCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJnZXRFbGVtZW50IiwgdXVpZCA9PiB0aGlzLmVsZW1lbnRzW3V1aWRdKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImlzSW5pdGlhbGlzZWQiLCAoKSA9PiB0aGlzLmluaXRpYWxpc2VkKTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImdldER5bmFtaWNzV29ybGQiLCAoKSA9PiB0aGlzLmR5bmFtaWNzV29ybGQpOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkUmlnaWRCb2R5IiwgYm9keSA9PiB7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuYWRkUmlnaWRCb2R5KGJvZHkpOwogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkQWN0aW9uIiwgYWN0aW9uID0+IHsKICAgICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZC5hZGRBY3Rpb24oYWN0aW9uKTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImFkZENvbGxpc2lvbk9iamVjdCIsIGNvbGxpc2lvbk9iamVjdCA9PiB7CiAgICAgICAgICB0aGlzLmR5bmFtaWNzV29ybGQuYWRkQ29sbGlzaW9uT2JqZWN0KGNvbGxpc2lvbk9iamVjdCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzdGVwU2ltdWxhdGlvbiIsIGR0ID0+IHsKICAgICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZC5zdGVwU2ltdWxhdGlvbihkdCk7CiAgICAgICAgfSk7CiAgICAgICAgX2RlZmluZVByb3BlcnR5KHRoaXMsICJzaW11bGF0ZSIsICgpID0+IHsKICAgICAgICAgIGNvbnN0IGR0ID0gdGhpcy5jbG9jay5nZXREZWx0YSgpIC8gMTAwMDsKICAgICAgICAgIHRoaXMuc3RlcFNpbXVsYXRpb24oZHQpOwogICAgICAgICAgT2JqZWN0LmtleXModGhpcy5lbGVtZW50cykuZm9yRWFjaCh1dWlkID0+IHsKICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgICAgICAgaWYgKGVsZW1lbnQpIHsKICAgICAgICAgICAgICBzd2l0Y2ggKGVsZW1lbnQudHlwZSkgewogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5CT1g6CiAgICAgICAgICAgICAgICBjYXNlIFRZUEVTLlNQSEVSRToKICAgICAgICAgICAgICAgIGNhc2UgVFlQRVMuTUVTSDoKICAgICAgICAgICAgICAgICAgaGFuZGxlRWxlbWVudFVwZGF0ZShlbGVtZW50LCBkdCk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5QTEFZRVI6CiAgICAgICAgICAgICAgICAgIGhhbmRsZVBsYXllclVwZGF0ZShlbGVtZW50LCBkdCk7CiAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBUWVBFUy5WRUhJQ0xFOgogICAgICAgICAgICAgICAgICBoYW5kbGVWZWhpY2xlVXBkYXRlKGVsZW1lbnQsIGR0KTsKICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9KTsKICAgICAgICAgIHRoaXMuY2FsY3VsYXRlQ29sbGlzaW9ucygpOwogICAgICAgICAgdGhpcy5yZW1vdmVEZWxldGVkRWxlbWVudHMoKTsKICAgICAgICAgIGRpc3BhdGNoZXIuc2VuZFBoeXNpY3NVcGRhdGUoZHQpOwogICAgICAgICAgdGhpcy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWVJZCA9IHJlcXVlc3ROZXh0RnJhbWUodGhpcy5zaW11bGF0ZS5iaW5kKHRoaXMpKTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgImNhbGN1bGF0ZUNvbGxpc2lvbnMiLCAoKSA9PiB7CiAgICAgICAgICBsZXQgYW1tb0Rpc3BhdGNoZXIgPSB0aGlzLmR5bmFtaWNzV29ybGQuZ2V0RGlzcGF0Y2hlcigpOwogICAgICAgICAgbGV0IG51bU1hbmlmb2xkcyA9IGFtbW9EaXNwYXRjaGVyLmdldE51bU1hbmlmb2xkcygpOwogICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1NYW5pZm9sZHM7IGkrKykgewogICAgICAgICAgICBsZXQgY29udGFjdE1hbmlmb2xkID0gYW1tb0Rpc3BhdGNoZXIuZ2V0TWFuaWZvbGRCeUluZGV4SW50ZXJuYWwoaSk7CiAgICAgICAgICAgIGxldCByYjAgPSBBbW1vLmNhc3RPYmplY3QoY29udGFjdE1hbmlmb2xkLmdldEJvZHkwKCksIEFtbW8uYnRSaWdpZEJvZHkpOwogICAgICAgICAgICBsZXQgcmIxID0gQW1tby5jYXN0T2JqZWN0KGNvbnRhY3RNYW5pZm9sZC5nZXRCb2R5MSgpLCBBbW1vLmJ0UmlnaWRCb2R5KTsKICAgICAgICAgICAgbGV0IG51bUNvbnRhY3RzID0gY29udGFjdE1hbmlmb2xkLmdldE51bUNvbnRhY3RzKCk7CgogICAgICAgICAgICAvLyB0aGlzIGl0ZXJhdGlvbiBkb2Vzbid0IGhhdmUgdXVpZHMKICAgICAgICAgICAgaWYgKCFyYjAudXVpZCB8fCAhcmIxLnV1aWQpIGNvbnRpbnVlOwogICAgICAgICAgICBsZXQgY29udGFjdHMgPSBbXTsKICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBudW1Db250YWN0czsgaisrKSB7CiAgICAgICAgICAgICAgbGV0IGNvbnRhY3RQb2ludCA9IGNvbnRhY3RNYW5pZm9sZC5nZXRDb250YWN0UG9pbnQoaik7CiAgICAgICAgICAgICAgbGV0IGRpc3RhbmNlID0gY29udGFjdFBvaW50LmdldERpc3RhbmNlKCk7CiAgICAgICAgICAgICAgaWYgKGRpc3RhbmNlID4gMC4wKSBjb250aW51ZTsKICAgICAgICAgICAgICBsZXQgdmVsb2NpdHkwID0gcmIwLmdldExpbmVhclZlbG9jaXR5KCk7CiAgICAgICAgICAgICAgbGV0IHZlbG9jaXR5MSA9IHJiMS5nZXRMaW5lYXJWZWxvY2l0eSgpOwogICAgICAgICAgICAgIGxldCB3b3JsZFBvczAgPSBjb250YWN0UG9pbnQuZ2V0X21fcG9zaXRpb25Xb3JsZE9uQSgpOwogICAgICAgICAgICAgIGxldCB3b3JsZFBvczEgPSBjb250YWN0UG9pbnQuZ2V0X21fcG9zaXRpb25Xb3JsZE9uQigpOwogICAgICAgICAgICAgIGxldCBsb2NhbFBvczAgPSBjb250YWN0UG9pbnQuZ2V0X21fbG9jYWxQb2ludEEoKTsKICAgICAgICAgICAgICBsZXQgbG9jYWxQb3MxID0gY29udGFjdFBvaW50LmdldF9tX2xvY2FsUG9pbnRCKCk7CiAgICAgICAgICAgICAgY29udGFjdHMucHVzaCh7CiAgICAgICAgICAgICAgICBkaXN0YW5jZSwKICAgICAgICAgICAgICAgIGVsZW1lbnRzOiBbewogICAgICAgICAgICAgICAgICB1dWlkOiByYjAudXVpZCwKICAgICAgICAgICAgICAgICAgdmVsb2NpdHk6IHsKICAgICAgICAgICAgICAgICAgICB4OiB2ZWxvY2l0eTAueCgpLAogICAgICAgICAgICAgICAgICAgIHk6IHZlbG9jaXR5MC55KCksCiAgICAgICAgICAgICAgICAgICAgejogdmVsb2NpdHkwLnooKQogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICB3b3JsZFBvczogewogICAgICAgICAgICAgICAgICAgIHg6IHdvcmxkUG9zMC54KCksCiAgICAgICAgICAgICAgICAgICAgeTogd29ybGRQb3MwLnkoKSwKICAgICAgICAgICAgICAgICAgICB6OiB3b3JsZFBvczAueigpCiAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgIGxvY2FsUG9zOiB7CiAgICAgICAgICAgICAgICAgICAgeDogbG9jYWxQb3MwLngoKSwKICAgICAgICAgICAgICAgICAgICB5OiBsb2NhbFBvczAueSgpLAogICAgICAgICAgICAgICAgICAgIHo6IGxvY2FsUG9zMC56KCkKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfSwgewogICAgICAgICAgICAgICAgICB1dWlkOiByYjEudXVpZCwKICAgICAgICAgICAgICAgICAgdmVsb2NpdHk6IHsKICAgICAgICAgICAgICAgICAgICB4OiB2ZWxvY2l0eTEueCgpLAogICAgICAgICAgICAgICAgICAgIHk6IHZlbG9jaXR5MS55KCksCiAgICAgICAgICAgICAgICAgICAgejogdmVsb2NpdHkxLnooKQogICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICB3b3JsZFBvczogewogICAgICAgICAgICAgICAgICAgIHg6IHdvcmxkUG9zMS54KCksCiAgICAgICAgICAgICAgICAgICAgeTogd29ybGRQb3MxLnkoKSwKICAgICAgICAgICAgICAgICAgICB6OiB3b3JsZFBvczEueigpCiAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgIGxvY2FsUG9zOiB7CiAgICAgICAgICAgICAgICAgICAgeDogbG9jYWxQb3MxLngoKSwKICAgICAgICAgICAgICAgICAgICB5OiBsb2NhbFBvczEueSgpLAogICAgICAgICAgICAgICAgICAgIHo6IGxvY2FsUG9zMS56KCkKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfV0KICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgfQogICAgICAgICAgICBkaXNwYXRjaGVyLnNlbmREaXNwYXRjaEV2ZW50KHJiMC51dWlkLCBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULkNPTExJU0lPTiwgewogICAgICAgICAgICAgIGNvbnRhY3RzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgICBkaXNwYXRjaGVyLnNlbmREaXNwYXRjaEV2ZW50KHJiMS51dWlkLCBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULkNPTExJU0lPTiwgewogICAgICAgICAgICAgIGNvbnRhY3RzCiAgICAgICAgICAgIH0pOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAiYWRkRWxlbWVudCIsIGRhdGEgPT4gewogICAgICAgICAgdGhpcy5lbGVtZW50c1tkYXRhLnV1aWRdID0gZGF0YTsKICAgICAgICB9KTsKICAgICAgICBfZGVmaW5lUHJvcGVydHkodGhpcywgInVwZGF0ZUJvZHlTdGF0ZSIsICh7CiAgICAgICAgICB1dWlkLAogICAgICAgICAgc3RhdGUKICAgICAgICB9KSA9PiB7CiAgICAgICAgICBpZiAodGhpcy5oYXNFbGVtZW50KHV1aWQpKSB7CiAgICAgICAgICAgIHRoaXMuZWxlbWVudHNbdXVpZF0uc3RhdGUgPSB7CiAgICAgICAgICAgICAgLi4udGhpcy5lbGVtZW50c1t1dWlkXS5zdGF0ZSwKICAgICAgICAgICAgICAuLi5zdGF0ZQogICAgICAgICAgICB9OwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIF9kZWZpbmVQcm9wZXJ0eSh0aGlzLCAidGVybWluYXRlIiwgKCkgPT4gewogICAgICAgICAgQW1tby5kZXN0cm95KHRoaXMuZHluYW1pY3NXb3JsZCk7CiAgICAgICAgICBBbW1vLmRlc3Ryb3kodGhpcy5zb2x2ZXIpOwogICAgICAgICAgQW1tby5kZXN0cm95KHRoaXMuZGlzcGF0Y2hlcik7CiAgICAgICAgICBBbW1vLmRlc3Ryb3kodGhpcy5jb2xsaXNpb25Db25maWd1cmF0aW9uKTsKICAgICAgICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHRoaXMucmVxdWVzdEFuaW1hdGlvbkZyYW1lSWQpOwogICAgICAgICAgZGlzcGF0Y2hlci5zZW5kVGVybWluYXRlRXZlbnQoKTsKICAgICAgICB9KTsKICAgICAgICB0aGlzLmVsZW1lbnRzID0ge307CiAgICAgICAgdGhpcy5pbml0aWFsaXNlZCA9IGZhbHNlOwogICAgICAgIHRoaXMuY29sbGlzaW9uQ29uZmlndXJhdGlvbiA9IHVuZGVmaW5lZDsKICAgICAgICB0aGlzLmRpc3BhdGNoZXIgPSB1bmRlZmluZWQ7CiAgICAgICAgdGhpcy5icm9hZHBoYXNlID0gdW5kZWZpbmVkOwogICAgICAgIHRoaXMuc29sdmVyID0gdW5kZWZpbmVkOwogICAgICAgIHRoaXMuZHluYW1pY3NXb3JsZCA9IHVuZGVmaW5lZDsKICAgICAgICB0aGlzLnJlcXVlc3RBbmltYXRpb25GcmFtZUlkID0gbnVsbDsKICAgICAgICB0aGlzLmNsb2NrID0gbmV3IENsb2NrKCk7CiAgICAgIH0KICAgICAgcmV0dXJuIF9jcmVhdGVDbGFzcyhXb3JsZCwgW3sKICAgICAgICBrZXk6ICJkaXNwb3NlQm9keSIsCiAgICAgICAgdmFsdWU6IGZ1bmN0aW9uIGRpc3Bvc2VCb2R5KHsKICAgICAgICAgIHV1aWQKICAgICAgICB9KSB7CiAgICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5nZXRFbGVtZW50KHV1aWQpOwogICAgICAgICAgdGhpcy5keW5hbWljc1dvcmxkLnJlbW92ZVJpZ2lkQm9keShlbGVtZW50LmJvZHkpOwogICAgICAgICAgdGhpcy5yZW1vdmVFbGVtZW50KHV1aWQpOwogICAgICAgICAgZGlzcGF0Y2hlci5zZW5kRWxlbWVudERpc3Bvc2VkKHsKICAgICAgICAgICAgdXVpZAogICAgICAgICAgfSk7CiAgICAgICAgfQogICAgICB9XSk7CiAgICB9KCk7CiAgICB2YXIgd29ybGQgPSBuZXcgV29ybGQoKTsKCiAgICBjb25zdCBERUZBVUxUX1JPTExfSU5GTFVFTkNFID0gMC4yOwogICAgY29uc3QgREVGQVVMVF9GUklDVElPTiA9IDEwMDA7CiAgICBjb25zdCBERUZBVUxUX01BU1MgPSA4MDA7CiAgICBjb25zdCBhZGRWZWhpY2xlID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICBwb3NpdGlvbiwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIHV1aWQsCiAgICAgICAgd2hlZWxzLAogICAgICAgIG1hc3MgPSBERUZBVUxUX01BU1MsCiAgICAgICAgd2lkdGggPSAxLjgsCiAgICAgICAgaGVpZ2h0ID0gMC42LAogICAgICAgIGxlbmd0aCA9IDQsCiAgICAgICAgZnJpY3Rpb24gPSBERUZBVUxUX0ZSSUNUSU9OLAogICAgICAgIHJvbGxJbmZsdWVuY2UgPSBERUZBVUxUX1JPTExfSU5GTFVFTkNFLAogICAgICAgIHdoZWVsc09wdGlvbnMgPSB7fSwKICAgICAgICBzdXNwZW5zaW9ucyA9IHt9CiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCB7CiAgICAgICAgYmFjayA9IHt9LAogICAgICAgIGZyb250ID0ge30KICAgICAgfSA9IHdoZWVsc09wdGlvbnM7CiAgICAgIGNvbnN0IHsKICAgICAgICBheGlzUG9zaXRpb246IGF4aXNQb3NpdGlvbkJhY2sgPSAtMSwKICAgICAgICByYWRpdXM6IHdoZWVsUmFkaXVzQmFjayA9IDAuNCwKICAgICAgICBoYWxmVHJhY2s6IHdoZWVsSGFsZlRyYWNrQmFjayA9IDEsCiAgICAgICAgYXhpc0hlaWdodDogd2hlZWxBeGlzSGVpZ2h0QmFjayA9IDAuMwogICAgICB9ID0gYmFjazsKICAgICAgY29uc3QgewogICAgICAgIGF4aXNQb3NpdGlvbjogYXhpc1Bvc2l0aW9uRnJvbnQgPSAxLjcsCiAgICAgICAgcmFkaXVzOiB3aGVlbFJhZGl1c0Zyb250ID0gMC40LAogICAgICAgIGhhbGZUcmFjazogd2hlZWxIYWxmVHJhY2tGcm9udCA9IDEsCiAgICAgICAgYXhpc0hlaWdodDogd2hlZWxBeGlzSGVpZ2h0RnJvbnQgPSAwLjMKICAgICAgfSA9IGZyb250OwogICAgICBjb25zdCB7CiAgICAgICAgc3RpZmZuZXNzID0gMjAuMCwKICAgICAgICBkYW1waW5nID0gMi4zLAogICAgICAgIGNvbXByZXNzaW9uID0gNC40LAogICAgICAgIHJlc3RMZW5ndGggPSAwLjYKICAgICAgfSA9IHN1c3BlbnNpb25zOwoKICAgICAgLy8gQ2hhc3NpcwogICAgICBjb25zdCBnZW9tZXRyeSA9IG5ldyBBbW1vLmJ0Qm94U2hhcGUobmV3IEFtbW8uYnRWZWN0b3IzKHdpZHRoICogMC41LCBoZWlnaHQgKiAwLjUsIGxlbmd0aCAqIDAuNSkpOwogICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICB0cmFuc2Zvcm0uc2V0SWRlbnRpdHkoKTsKICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICBjb25zdCBtb3Rpb25TdGF0ZSA9IG5ldyBBbW1vLmJ0RGVmYXVsdE1vdGlvblN0YXRlKHRyYW5zZm9ybSk7CiAgICAgIGNvbnN0IGxvY2FsSW5lcnRpYSA9IG5ldyBBbW1vLmJ0VmVjdG9yMygwLCAwLCAwKTsKICAgICAgZ2VvbWV0cnkuY2FsY3VsYXRlTG9jYWxJbmVydGlhKG1hc3MsIGxvY2FsSW5lcnRpYSk7CiAgICAgIGNvbnN0IGNoYXNzaXMgPSBuZXcgQW1tby5idFJpZ2lkQm9keShuZXcgQW1tby5idFJpZ2lkQm9keUNvbnN0cnVjdGlvbkluZm8obWFzcywgbW90aW9uU3RhdGUsIGdlb21ldHJ5LCBsb2NhbEluZXJ0aWEpKTsKICAgICAgY2hhc3Npcy5zZXRBY3RpdmF0aW9uU3RhdGUoRElTQUJMRV9ERUFDVElWQVRJT04pOwogICAgICB3b3JsZC5hZGRSaWdpZEJvZHkoY2hhc3Npcyk7CgogICAgICAvLyBSYXljYXN0IFZlaGljbGUKICAgICAgY29uc3QgdHVuaW5nID0gbmV3IEFtbW8uYnRWZWhpY2xlVHVuaW5nKCk7CiAgICAgIGNvbnN0IHJheUNhc3RlciA9IG5ldyBBbW1vLmJ0RGVmYXVsdFZlaGljbGVSYXljYXN0ZXIod29ybGQuZ2V0RHluYW1pY3NXb3JsZCgpKTsKICAgICAgY29uc3QgdmVoaWNsZSA9IG5ldyBBbW1vLmJ0UmF5Y2FzdFZlaGljbGUodHVuaW5nLCBjaGFzc2lzLCByYXlDYXN0ZXIpOwogICAgICB2ZWhpY2xlLnNldENvb3JkaW5hdGVTeXN0ZW0oMCwgMSwgMik7CiAgICAgIHdvcmxkLmFkZEFjdGlvbih2ZWhpY2xlKTsKICAgICAgY29uc3Qgd2hlZWxEaXJlY3Rpb25DUzAgPSBuZXcgQW1tby5idFZlY3RvcjMoMCwgLTEsIDApOwogICAgICBjb25zdCB3aGVlbEF4bGVDUyA9IG5ldyBBbW1vLmJ0VmVjdG9yMygtMSwgMCwgMCk7CiAgICAgIGNvbnN0IGFkZFdoZWVsID0gKGlzRnJvbnQsIHBvcywgcmFkaXVzKSA9PiB7CiAgICAgICAgdmFyIHdoZWVsSW5mbyA9IHZlaGljbGUuYWRkV2hlZWwocG9zLCB3aGVlbERpcmVjdGlvbkNTMCwgd2hlZWxBeGxlQ1MsIHJlc3RMZW5ndGgsIHJhZGl1cywgdHVuaW5nLCBpc0Zyb250KTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fc3VzcGVuc2lvblN0aWZmbmVzcyhzdGlmZm5lc3MpOwogICAgICAgIHdoZWVsSW5mby5zZXRfbV93aGVlbHNEYW1waW5nUmVsYXhhdGlvbihkYW1waW5nKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fd2hlZWxzRGFtcGluZ0NvbXByZXNzaW9uKGNvbXByZXNzaW9uKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fZnJpY3Rpb25TbGlwKGZyaWN0aW9uKTsKICAgICAgICB3aGVlbEluZm8uc2V0X21fcm9sbEluZmx1ZW5jZShyb2xsSW5mbHVlbmNlKTsKICAgICAgfTsKICAgICAgYWRkV2hlZWwodHJ1ZSwgbmV3IEFtbW8uYnRWZWN0b3IzKHdoZWVsSGFsZlRyYWNrRnJvbnQsIHdoZWVsQXhpc0hlaWdodEZyb250LCBheGlzUG9zaXRpb25Gcm9udCksIHdoZWVsUmFkaXVzRnJvbnQpOwogICAgICBhZGRXaGVlbCh0cnVlLCBuZXcgQW1tby5idFZlY3RvcjMoLXdoZWVsSGFsZlRyYWNrRnJvbnQsIHdoZWVsQXhpc0hlaWdodEZyb250LCBheGlzUG9zaXRpb25Gcm9udCksIHdoZWVsUmFkaXVzRnJvbnQpOwogICAgICBhZGRXaGVlbChmYWxzZSwgbmV3IEFtbW8uYnRWZWN0b3IzKC13aGVlbEhhbGZUcmFja0JhY2ssIHdoZWVsQXhpc0hlaWdodEJhY2ssIGF4aXNQb3NpdGlvbkJhY2spLCB3aGVlbFJhZGl1c0JhY2spOwogICAgICBhZGRXaGVlbChmYWxzZSwgbmV3IEFtbW8uYnRWZWN0b3IzKHdoZWVsSGFsZlRyYWNrQmFjaywgd2hlZWxBeGlzSGVpZ2h0QmFjaywgYXhpc1Bvc2l0aW9uQmFjayksIHdoZWVsUmFkaXVzQmFjayk7CiAgICAgIHZlaGljbGUudXVpZCA9IHV1aWQ7CiAgICAgIHdvcmxkLmFkZEVsZW1lbnQoewogICAgICAgIHR5cGU6IFRZUEVTLlZFSElDTEUsCiAgICAgICAgdXVpZCwKICAgICAgICB2ZWhpY2xlOiB2ZWhpY2xlLAogICAgICAgIHdoZWVscywKICAgICAgICBvcHRpb25zOiBkYXRhLAogICAgICAgIHN0YXRlOiBERUZBVUxUX1ZFSElDTEVfU1RBVEUKICAgICAgfSk7CiAgICB9OwogICAgY29uc3Qgc2V0VmVoaWNsZVBvc2l0aW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHBvc2l0aW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBlbGVtZW50ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gVFlQRVMuVkVISUNMRSkgewogICAgICAgIGNvbnN0IGJvZHkgPSBlbGVtZW50LnZlaGljbGUuZ2V0UmlnaWRCb2R5KCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHNldFZlaGljbGVRdWF0ZXJuaW9uID0gZGF0YSA9PiB7CiAgICAgIGNvbnN0IHsKICAgICAgICB1dWlkLAogICAgICAgIHF1YXRlcm5pb24KICAgICAgfSA9IGRhdGE7CiAgICAgIGNvbnN0IGVsZW1lbnQgPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICBpZiAoZWxlbWVudC50eXBlID09PSBUWVBFUy5WRUhJQ0xFKSB7CiAgICAgICAgY29uc3QgYm9keSA9IGVsZW1lbnQudmVoaWNsZS5nZXRSaWdpZEJvZHkoKTsKICAgICAgICBjb25zdCB0cmFuc2Zvcm0gPSBuZXcgQW1tby5idFRyYW5zZm9ybSgpOwogICAgICAgIGJvZHkuZ2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgICB0cmFuc2Zvcm0uc2V0Um90YXRpb24obmV3IEFtbW8uYnRRdWF0ZXJuaW9uKHF1YXRlcm5pb24ueCwgcXVhdGVybmlvbi55LCBxdWF0ZXJuaW9uLnosIHF1YXRlcm5pb24udykpOwogICAgICAgIGJvZHkuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgfQogICAgfTsKICAgIGNvbnN0IHJlc2V0VmVoaWNsZSA9IGRhdGEgPT4gewogICAgICBjb25zdCB7CiAgICAgICAgdXVpZCwKICAgICAgICBxdWF0ZXJuaW9uLAogICAgICAgIHBvc2l0aW9uCiAgICAgIH0gPSBkYXRhOwogICAgICBjb25zdCBlbGVtZW50ID0gd29ybGQuZ2V0RWxlbWVudCh1dWlkKTsKICAgICAgaWYgKGVsZW1lbnQudHlwZSA9PT0gVFlQRVMuVkVISUNMRSkgewogICAgICAgIGNvbnN0IGJvZHkgPSBlbGVtZW50LnZlaGljbGUuZ2V0UmlnaWRCb2R5KCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBib2R5LmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgICAgdHJhbnNmb3JtLnNldElkZW50aXR5KCk7CiAgICAgICAgdHJhbnNmb3JtLnNldE9yaWdpbihuZXcgQW1tby5idFZlY3RvcjMocG9zaXRpb24ueCwgcG9zaXRpb24ueSwgcG9zaXRpb24ueikpOwogICAgICAgIHRyYW5zZm9ybS5zZXRSb3RhdGlvbihuZXcgQW1tby5idFF1YXRlcm5pb24ocXVhdGVybmlvbi54LCBxdWF0ZXJuaW9uLnksIHF1YXRlcm5pb24ueiwgcXVhdGVybmlvbi53KSk7CiAgICAgICAgYm9keS5zZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgaGFuZGxlVmVoaWNsZVVwZGF0ZSA9ICh7CiAgICAgIHZlaGljbGUsCiAgICAgIHdoZWVscywKICAgICAgdXVpZCwKICAgICAgc3RhdGUgPSBERUZBVUxUX1ZFSElDTEVfU1RBVEUsCiAgICAgIG9wdGlvbnMgPSB7fQogICAgfSwgZHQpID0+IHsKICAgICAgbGV0IGJyZWFraW5nRm9yY2UgPSAwOwogICAgICBsZXQgZW5naW5lRm9yY2UgPSAwOwogICAgICBjb25zdCB7CiAgICAgICAgc3RlZXJpbmdDbGFtcCA9IERFRkFVTFRfU1RFRVJJTkdfQ0xBTVAsCiAgICAgICAgc3RlZXJpbmdJbmNyZW1lbnQgPSBERUZBVUxUX1NURUVSSU5HX0lOQ1JFTUVOVCwKICAgICAgICBtYXhFbmdpbmVGb3JjZSA9IERFRkFVTFRfTUFYX0VOR0lORV9GT1JDRSwKICAgICAgICBtYXhCcmVha2luZ0ZvcmNlID0gREVGQVVMVF9NQVhfQlJFQUtJTkdfRk9SQ0UKICAgICAgfSA9IG9wdGlvbnM7CiAgICAgIGlmIChzdGF0ZS5hY2NlbGVyYXRpb24pIHsKICAgICAgICBpZiAoc3BlZWQgPCAtMSkgYnJlYWtpbmdGb3JjZSA9IG1heEJyZWFraW5nRm9yY2U7ZWxzZSBlbmdpbmVGb3JjZSA9IG1heEVuZ2luZUZvcmNlOwogICAgICB9CiAgICAgIGlmIChzdGF0ZS5icmFraW5nKSB7CiAgICAgICAgaWYgKHNwZWVkID4gMSkgYnJlYWtpbmdGb3JjZSA9IG1heEJyZWFraW5nRm9yY2U7ZWxzZSBlbmdpbmVGb3JjZSA9IC1tYXhFbmdpbmVGb3JjZSAvIDI7CiAgICAgIH0KICAgICAgaWYgKHN0YXRlLmxlZnQpIHsKICAgICAgICBpZiAoc3RhdGUudmVoaWNsZVN0ZWVyaW5nIDwgc3RlZXJpbmdDbGFtcCkgc3RhdGUudmVoaWNsZVN0ZWVyaW5nICs9IHN0ZWVyaW5nSW5jcmVtZW50OwogICAgICB9IGVsc2UgewogICAgICAgIGlmIChzdGF0ZS5yaWdodCkgewogICAgICAgICAgaWYgKHN0YXRlLnZlaGljbGVTdGVlcmluZyA+IC1zdGVlcmluZ0NsYW1wKSBzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgLT0gc3RlZXJpbmdJbmNyZW1lbnQ7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGlmIChzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgPCAtc3RlZXJpbmdJbmNyZW1lbnQpIHN0YXRlLnZlaGljbGVTdGVlcmluZyArPSBzdGVlcmluZ0luY3JlbWVudDtlbHNlIHsKICAgICAgICAgICAgaWYgKHN0YXRlLnZlaGljbGVTdGVlcmluZyA+IHN0ZWVyaW5nSW5jcmVtZW50KSBzdGF0ZS52ZWhpY2xlU3RlZXJpbmcgLT0gc3RlZXJpbmdJbmNyZW1lbnQ7ZWxzZSB7CiAgICAgICAgICAgICAgc3RhdGUudmVoaWNsZVN0ZWVyaW5nID0gMDsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgICB2ZWhpY2xlLmFwcGx5RW5naW5lRm9yY2UoZW5naW5lRm9yY2UsIEJBQ0tfTEVGVCk7CiAgICAgIHZlaGljbGUuYXBwbHlFbmdpbmVGb3JjZShlbmdpbmVGb3JjZSwgQkFDS19SSUdIVCk7CiAgICAgIHZlaGljbGUuc2V0QnJha2UoYnJlYWtpbmdGb3JjZSAvIDIsIEZST05UX0xFRlQpOwogICAgICB2ZWhpY2xlLnNldEJyYWtlKGJyZWFraW5nRm9yY2UgLyAyLCBGUk9OVF9SSUdIVCk7CiAgICAgIHZlaGljbGUuc2V0QnJha2UoYnJlYWtpbmdGb3JjZSwgQkFDS19MRUZUKTsKICAgICAgdmVoaWNsZS5zZXRCcmFrZShicmVha2luZ0ZvcmNlLCBCQUNLX1JJR0hUKTsKICAgICAgdmVoaWNsZS5zZXRTdGVlcmluZ1ZhbHVlKHN0YXRlLnZlaGljbGVTdGVlcmluZywgRlJPTlRfTEVGVCk7CiAgICAgIHZlaGljbGUuc2V0U3RlZXJpbmdWYWx1ZShzdGF0ZS52ZWhpY2xlU3RlZXJpbmcsIEZST05UX1JJR0hUKTsKICAgICAgbGV0IHRtLCBwLCBxLCBpOwogICAgICBjb25zdCBuID0gdmVoaWNsZS5nZXROdW1XaGVlbHMoKTsKICAgICAgZm9yIChpID0gMDsgaSA8IG47IGkrKykgewogICAgICAgIHZlaGljbGUudXBkYXRlV2hlZWxUcmFuc2Zvcm0oaSwgdHJ1ZSk7CiAgICAgICAgdG0gPSB2ZWhpY2xlLmdldFdoZWVsVHJhbnNmb3JtV1MoaSk7CiAgICAgICAgcCA9IHRtLmdldE9yaWdpbigpOwogICAgICAgIHEgPSB0bS5nZXRSb3RhdGlvbigpOwogICAgICAgIGNvbnN0IHdoZWVsVVVJRCA9IHdoZWVsc1tpXTsKICAgICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHdoZWVsVVVJRCwgcCwgcSwgZHQpOwogICAgICB9CiAgICAgIHRtID0gdmVoaWNsZS5nZXRDaGFzc2lzV29ybGRUcmFuc2Zvcm0oKTsKICAgICAgcCA9IHRtLmdldE9yaWdpbigpOwogICAgICBxID0gdG0uZ2V0Um90YXRpb24oKTsKICAgICAgY29uc3QgZGlyZWN0aW9uID0gdmVoaWNsZS5nZXRGb3J3YXJkVmVjdG9yKCk7CiAgICAgIGNvbnN0IHNwZWVkID0gdmVoaWNsZS5nZXRDdXJyZW50U3BlZWRLbUhvdXIoKTsKICAgICAgY29uc3QgZXh0cmFEYXRhID0gewogICAgICAgIGRpcmVjdGlvbjogewogICAgICAgICAgeDogZGlyZWN0aW9uLngoKSwKICAgICAgICAgIHk6IGRpcmVjdGlvbi55KCksCiAgICAgICAgICB6OiBkaXJlY3Rpb24ueigpCiAgICAgICAgfSwKICAgICAgICBzcGVlZAogICAgICB9OwogICAgICBkaXNwYXRjaGVyLnNlbmRCb2R5VXBkYXRlKHV1aWQsIHAsIHEsIGR0LCBleHRyYURhdGEpOwogICAgICB3b3JsZC51cGRhdGVCb2R5U3RhdGUodXVpZCwgc3RhdGUpOwogICAgfTsKCiAgICBjb25zdCBjcmVhdGVHaG9zdENvbGxpZGVyID0gKHJhZGl1cywgcG9zaXRpb24pID0+IHsKICAgICAgY29uc3QgZ2hvc3RDb2xsaWRlciA9IG5ldyBBbW1vLmJ0R2hvc3RPYmplY3QoKTsKICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgZ2hvc3RDb2xsaWRlci5zZXRDb2xsaXNpb25TaGFwZShuZXcgQW1tby5idFNwaGVyZVNoYXBlKHJhZGl1cykpOwogICAgICBnaG9zdENvbGxpZGVyLmdldFdvcmxkVHJhbnNmb3JtKHRyYW5zZm9ybSk7CiAgICAgIHRyYW5zZm9ybS5zZXRJZGVudGl0eSgpOwogICAgICB0cmFuc2Zvcm0uc2V0T3JpZ2luKHBvc2l0aW9uKTsKICAgICAgdHJhbnNmb3JtLnNldFJvdGF0aW9uKG5ldyBBbW1vLmJ0UXVhdGVybmlvbigwLCAwLCAwLCAxKSk7CiAgICAgIGdob3N0Q29sbGlkZXIuc2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgcmV0dXJuIHsKICAgICAgICBnaG9zdENvbGxpZGVyLAogICAgICAgIHRyYW5zZm9ybQogICAgICB9OwogICAgfTsKICAgIGNvbnN0IGZvckVhY2hHaG9zdENvbGxpc2lvbiA9IChnaG9zdENvbGxpZGVyLCBmb3JFYWNoQ2FsbGJhY2sgPSAoKSA9PiB7fSkgPT4gewogICAgICBjb25zdCBjb2xsaXNpb25zID0gZ2hvc3RDb2xsaWRlci5nZXROdW1PdmVybGFwcGluZ09iamVjdHMoKTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb2xsaXNpb25zOyBpKyspIHsKICAgICAgICBjb25zdCBvYmplY3QgPSBBbW1vLmNhc3RPYmplY3QoZ2hvc3RDb2xsaWRlci5nZXRPdmVybGFwcGluZ09iamVjdChpKSwgQW1tby5idFJpZ2lkQm9keSk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBvYmplY3QuZ2V0V29ybGRUcmFuc2Zvcm0odHJhbnNmb3JtKTsKICAgICAgICBmb3JFYWNoQ2FsbGJhY2sob2JqZWN0LCB0cmFuc2Zvcm0sIGkpOwogICAgICAgIEFtbW8uZGVzdHJveSh0cmFuc2Zvcm0pOwogICAgICB9CiAgICB9OwogICAgY29uc3QgZ2V0RXhwbG9zaW9uUG9zaXRpb24gPSAodXVpZCwgcG9zaXRpb24pID0+IHsKICAgICAgbGV0IGV4cGxvc2lvblBvc2l0aW9uID0gcG9zaXRpb247CiAgICAgIGlmICghZXhwbG9zaW9uUG9zaXRpb24pIHsKICAgICAgICBjb25zdCB7CiAgICAgICAgICBib2R5CiAgICAgICAgfSA9IHdvcmxkLmdldEVsZW1lbnQodXVpZCk7CiAgICAgICAgY29uc3QgbW90aW9uU3RhdGUgPSBib2R5LmdldE1vdGlvblN0YXRlKCk7CiAgICAgICAgY29uc3QgdHJhbnNmb3JtID0gbmV3IEFtbW8uYnRUcmFuc2Zvcm0oKTsKICAgICAgICBtb3Rpb25TdGF0ZS5nZXRXb3JsZFRyYW5zZm9ybSh0cmFuc2Zvcm0pOwogICAgICAgIGV4cGxvc2lvblBvc2l0aW9uID0gdHJhbnNmb3JtLmdldE9yaWdpbigpOwogICAgICB9CiAgICAgIHJldHVybiBleHBsb3Npb25Qb3NpdGlvbjsKICAgIH07CiAgICBjb25zdCBnZXRFeHBsb3Npb25JbXB1bHNlID0gKHBvc2l0aW9uLCBleHBsb3Npb25Qb3NpdGlvbiwgc3RyZW5ndGgpID0+IHsKICAgICAgLy8gQ2FsY3VsYXRlIGRpcmVjdGlvbiB2ZWN0b3IgV0lUSE9VVCBtdXRhdGluZyB0aGUgaW5wdXQgYnRWZWN0b3IzIG9iamVjdHMuCiAgICAgIC8vIG9wX3N1Yi9vcF9tdWwgbXV0YXRlIGluIHBsYWNlIGluIEFtbW8uanMsIHdoaWNoIHdvdWxkIGNvcnJ1cHQgdGhlIGJvZHkncyB0cmFuc2Zvcm0gb3JpZ2luLgogICAgICBjb25zdCBkeCA9IHBvc2l0aW9uLngoKSAtIGV4cGxvc2lvblBvc2l0aW9uLngoKTsKICAgICAgY29uc3QgZHkgPSBwb3NpdGlvbi55KCkgLSBleHBsb3Npb25Qb3NpdGlvbi55KCk7CiAgICAgIGNvbnN0IGR6ID0gcG9zaXRpb24ueigpIC0gZXhwbG9zaW9uUG9zaXRpb24ueigpOwogICAgICBsZXQgbGVuZ3RoID0gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5ICsgZHogKiBkeik7CgogICAgICAvLyBJZiB0aGUgb2JqZWN0IGlzIGF0IHRoZSBleHBsb3Npb24gY2VudGVyLCBwdXNoIGl0IHN0cmFpZ2h0IHVwIGluc3RlYWQgb2YKICAgICAgLy8gcHJvZHVjaW5nIGFuIHVuc3RhYmxlIG5lYXItemVybyBub3JtYWxpemF0aW9uLgogICAgICBpZiAobGVuZ3RoIDwgMC4wMDEpIHsKICAgICAgICBjb25zdCBpbXB1bHNlID0gbmV3IEFtbW8uYnRWZWN0b3IzKDAsIHN0cmVuZ3RoICogMiwgMCk7CiAgICAgICAgcmV0dXJuIGltcHVsc2U7CiAgICAgIH0KCiAgICAgIC8vIE5vcm1hbGl6ZSBkaXJlY3Rpb24KICAgICAgY29uc3QgbnggPSBkeCAvIGxlbmd0aDsKICAgICAgY29uc3QgbnkgPSBkeSAvIGxlbmd0aDsKICAgICAgY29uc3QgbnogPSBkeiAvIGxlbmd0aDsKCiAgICAgIC8vIFNjYWxlIGJ5IHN0cmVuZ3RoIGFuZCBhZGQgdXB3YXJkIGJpYXMKICAgICAgY29uc3QgaW1wdWxzZSA9IG5ldyBBbW1vLmJ0VmVjdG9yMyhueCAqIHN0cmVuZ3RoLCBueSAqIHN0cmVuZ3RoICsgc3RyZW5ndGgsIG56ICogc3RyZW5ndGgpOwogICAgICByZXR1cm4gaW1wdWxzZTsKICAgIH07CiAgICBjb25zdCBjcmVhdGVFeHBsb3Npb24gPSAoewogICAgICB1dWlkLAogICAgICBwb3NpdGlvbiwKICAgICAgcmFkaXVzID0gRVhQTE9TSU9OX1NJWkVTLlNNQUxMLAogICAgICBzdHJlbmd0aCA9IEVYUExPU0lPTl9TVFJFTkdUSFMuTUVESVVNCiAgICB9KSA9PiB7CiAgICAgIHRyeSB7CiAgICAgICAgLy8gR2V0IHRoZSBzb3VyY2UgYm9keSdzIEFtbW8gcG9pbnRlciBzbyB3ZSBjYW4gcmVsaWFibHkgc2tpcCBpdC4KICAgICAgICAvLyBBbW1vLmNhc3RPYmplY3QoKSBjcmVhdGVzIG5ldyBKUyB3cmFwcGVycywgc28gY3VzdG9tIHByb3BlcnRpZXMgbGlrZQogICAgICAgIC8vIC51dWlkIHNldCBvbiB0aGUgb3JpZ2luYWwgd3JhcHBlciBhcmUgTk9UIGF2YWlsYWJsZSBvbiBjYXN0IHJlc3VsdHMuCiAgICAgICAgLy8gV2UgY29tcGFyZSB0aGUgdW5kZXJseWluZyBDKysgcG9pbnRlciBpbnN0ZWFkLgogICAgICAgIGNvbnN0IHNvdXJjZUVsZW1lbnQgPSB3b3JsZC5nZXRFbGVtZW50KHV1aWQpOwogICAgICAgIGNvbnN0IHNvdXJjZUJvZHlQdHIgPSBzb3VyY2VFbGVtZW50ICYmIHNvdXJjZUVsZW1lbnQuYm9keSA/IHNvdXJjZUVsZW1lbnQuYm9keS5hIHx8IHNvdXJjZUVsZW1lbnQuYm9keS5wdHIgOiBudWxsOwogICAgICAgIGNvbnN0IGV4cGxvc2lvblBvc2l0aW9uID0gZ2V0RXhwbG9zaW9uUG9zaXRpb24odXVpZCwgcG9zaXRpb24pOwogICAgICAgIGNvbnN0IHsKICAgICAgICAgIGdob3N0Q29sbGlkZXIsCiAgICAgICAgICB0cmFuc2Zvcm0KICAgICAgICB9ID0gY3JlYXRlR2hvc3RDb2xsaWRlcihyYWRpdXMsIGV4cGxvc2lvblBvc2l0aW9uKTsKICAgICAgICB3b3JsZC5hZGRDb2xsaXNpb25PYmplY3QoZ2hvc3RDb2xsaWRlcik7CgogICAgICAgIC8vIEZvcmNlIGEgY29sbGlzaW9uIGRldGVjdGlvbiBwYXNzIHNvIHRoZSBnaG9zdCBjb2xsaWRlciBkaXNjb3ZlcnMKICAgICAgICAvLyBvdmVybGFwcGluZyBib2RpZXMuIFdpdGhvdXQgdGhpcywgZ2V0TnVtT3ZlcmxhcHBpbmdPYmplY3RzKCkgcmV0dXJucyAwCiAgICAgICAgLy8gYmVjYXVzZSBidEdob3N0UGFpckNhbGxiYWNrIG9ubHkgdXBkYXRlcyBkdXJpbmcgYSBzaW11bGF0aW9uIHN0ZXAuCiAgICAgICAgd29ybGQuZ2V0RHluYW1pY3NXb3JsZCgpLnBlcmZvcm1EaXNjcmV0ZUNvbGxpc2lvbkRldGVjdGlvbigpOwogICAgICAgIGZvckVhY2hHaG9zdENvbGxpc2lvbihnaG9zdENvbGxpZGVyLCAob2JqZWN0LCBvYmplY3RUcmFuc2Zvcm0pID0+IHsKICAgICAgICAgIC8vIFNraXAgdGhlIHNvdXJjZSBlbnRpdHkgdXNpbmcgcG9pbnRlciBjb21wYXJpc29uLgogICAgICAgICAgY29uc3Qgb2JqZWN0UHRyID0gb2JqZWN0LmEgfHwgb2JqZWN0LnB0cjsKICAgICAgICAgIGlmIChzb3VyY2VCb2R5UHRyICYmIG9iamVjdFB0ciA9PT0gc291cmNlQm9keVB0cikgcmV0dXJuOwogICAgICAgICAgY29uc3Qgb3JpZ2luID0gb2JqZWN0VHJhbnNmb3JtLmdldE9yaWdpbigpOwogICAgICAgICAgb2JqZWN0LmFjdGl2YXRlKHRydWUpOwogICAgICAgICAgY29uc3QgaW1wdWxzZSA9IGdldEV4cGxvc2lvbkltcHVsc2Uob3JpZ2luLCBleHBsb3Npb25Qb3NpdGlvbiwgc3RyZW5ndGgpOwogICAgICAgICAgb2JqZWN0LmFwcGx5Q2VudHJhbEltcHVsc2UoaW1wdWxzZSk7CiAgICAgICAgICBBbW1vLmRlc3Ryb3koaW1wdWxzZSk7CiAgICAgICAgfSk7CiAgICAgICAgd29ybGQuZ2V0RHluYW1pY3NXb3JsZCgpLnJlbW92ZUNvbGxpc2lvbk9iamVjdChnaG9zdENvbGxpZGVyKTsKICAgICAgICBBbW1vLmRlc3Ryb3koZ2hvc3RDb2xsaWRlcik7CiAgICAgICAgQW1tby5kZXN0cm95KHRyYW5zZm9ybSk7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBjb25zb2xlLmVycm9yKCJbUGh5c2ljcyBXb3JrZXJdIGNyZWF0ZUV4cGxvc2lvbiBlcnJvcjoiLCBlKTsKICAgICAgfQogICAgfTsKCiAgICBjb25zdCBoYW5kbGVMb2FkRXZlbnQgPSBvcHRpb25zID0+IEFtbW8gPT4gewogICAgICBzZWxmLkFtbW8gPSBBbW1vOwogICAgICBvbm1lc3NhZ2UgPSAoewogICAgICAgIGRhdGEKICAgICAgfSkgPT4gewogICAgICAgIHN3aXRjaCAoZGF0YS5ldmVudCkgewogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5BREQuQk9YOgogICAgICAgICAgICBhZGRCb3goZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5BREQuU1BIRVJFOgogICAgICAgICAgICBhZGRTcGhlcmUoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5BREQuVkVISUNMRToKICAgICAgICAgICAgYWRkVmVoaWNsZShkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkFERC5NT0RFTDoKICAgICAgICAgICAgYWRkTW9kZWwoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5BREQuUExBWUVSOgogICAgICAgICAgICBhZGRQbGF5ZXIoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULlNFVC5MSU5FQVJfVkVMT0NJVFk6CiAgICAgICAgICAgIHNldExpbmVhclZlbG9jaXR5KGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5SRVNFVDoKICAgICAgICAgICAgcmVzZXRFbGVtZW50KGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5TRVQuUE9TSVRJT046CiAgICAgICAgICAgIHNldFBvc2l0aW9uKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5TRVQuUVVBVEVSTklPTjoKICAgICAgICAgICAgc2V0UXVhdGVybmlvbihkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLlZFSElDTEUuU0VULlBPU0lUSU9OOgogICAgICAgICAgICBzZXRWZWhpY2xlUG9zaXRpb24oZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5WRUhJQ0xFLlNFVC5RVUFURVJOSU9OOgogICAgICAgICAgICBzZXRWZWhpY2xlUXVhdGVybmlvbihkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLlZFSElDTEUuUkVTRVQ6CiAgICAgICAgICAgIHJlc2V0VmVoaWNsZShkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVMRU1FTlQuQVBQTFkuSU1QVUxTRToKICAgICAgICAgICAgYXBwbHlJbXB1c2UoZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5FTEVNRU5ULlVQREFURToKICAgICAgICAgICAgd29ybGQudXBkYXRlQm9keVN0YXRlKGRhdGEpOwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuRUxFTUVOVC5ESVNQT1NFOgogICAgICAgICAgICB3b3JsZC5kaXNwb3NlQm9keShkYXRhKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICBjYXNlIFBIWVNJQ1NfRVZFTlRTLkVGRkVDVFMuRVhQTE9TSU9OOgogICAgICAgICAgICBjcmVhdGVFeHBsb3Npb24oZGF0YSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgY2FzZSBQSFlTSUNTX0VWRU5UUy5URVJNSU5BVEU6CiAgICAgICAgICAgIHdvcmxkLnRlcm1pbmF0ZSgpOwogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgIH07CiAgICAgIHdvcmxkLmluaXQob3B0aW9ucyk7CiAgICAgIGRpc3BhdGNoZXIuc2VuZFJlYWR5RXZlbnQoKTsKICAgICAgd29ybGQuc2ltdWxhdGUoKTsKICAgIH07CiAgICBjb25zdCBsb2FkQW1tbyA9IG9wdGlvbnMgPT4gewogICAgICBjb25zdCBzY3JpcHRVcmwgPSBvcHRpb25zLmhvc3QgKyAiLyIgKyAob3B0aW9ucy5wYXRoIHx8IExJQlJBUllfTkFNRSk7CiAgICAgIGltcG9ydFNjcmlwdHMoc2NyaXB0VXJsKTsKICAgICAgQW1tbygpLnRoZW4oaGFuZGxlTG9hZEV2ZW50KG9wdGlvbnMpKTsKICAgIH07CiAgICBvbm1lc3NhZ2UgPSAoewogICAgICBkYXRhCiAgICB9KSA9PiB7CiAgICAgIHN3aXRjaCAoZGF0YS5ldmVudCkgewogICAgICAgIGNhc2UgUEhZU0lDU19FVkVOVFMuTE9BRC5BTU1POgogICAgICAgICAgbG9hZEFtbW8oZGF0YSk7CiAgICAgICAgICBicmVhazsKICAgICAgfQogICAgfTsKCn0pKCk7Cgo=', null, false);
55790
55723
  /* eslint-enable */const PHYSICS_EVENTS = {
55791
55724
  DISPATCH: "physics:dispatch",
55792
55725
  TERMINATE: "physics:terminate",
@@ -55941,7 +55874,7 @@ const TYPES = {
55941
55874
  MESH: "MESH",
55942
55875
  PLAYER: "PLAYER"
55943
55876
  };
55944
- const COLLIDER_TYPES$1 = {
55877
+ const COLLIDER_TYPES$2 = {
55945
55878
  BOX: "BOX",
55946
55879
  VEHICLE: "VEHICLE",
55947
55880
  PLAYER: "PLAYER",
@@ -56006,7 +55939,7 @@ const DEFAULT_IMPULSE = {
56006
55939
  const DISABLE_DEACTIVATION = 4;
56007
55940
  const GRAVITY = {
56008
55941
  x: 0,
56009
- y: -10,
55942
+ y: -9.8,
56010
55943
  z: 0
56011
55944
  };
56012
55945
  const FRONT_LEFT = 0;
@@ -56030,7 +55963,7 @@ const EXPLOSION_STRENGTHS = {
56030
55963
  LARGE: 16,
56031
55964
  MASSIVE: 32,
56032
55965
  OK_NO: 64
56033
- };var PHYSICS_CONSTANTS=/*#__PURE__*/Object.freeze({__proto__:null,LIBRARY_NAME:LIBRARY_NAME,TYPES:TYPES,COLLIDER_TYPES:COLLIDER_TYPES$1,DEFAULT_VEHICLE_STATE:DEFAULT_VEHICLE_STATE,DEFAULT_RIGIDBODY_STATE:DEFAULT_RIGIDBODY_STATE,DEFAULT_SCALE:DEFAULT_SCALE$1,DEFAULT_QUATERNION:DEFAULT_QUATERNION,DEFAULT_POSITION:DEFAULT_POSITION$8,DEFAULT_LINEAR_VELOCITY:DEFAULT_LINEAR_VELOCITY,DEFAULT_ANGULAR_VELOCITY:DEFAULT_ANGULAR_VELOCITY,DEFAULT_IMPULSE:DEFAULT_IMPULSE,DISABLE_DEACTIVATION:DISABLE_DEACTIVATION,GRAVITY:GRAVITY,FRONT_LEFT:FRONT_LEFT,FRONT_RIGHT:FRONT_RIGHT,BACK_LEFT:BACK_LEFT,BACK_RIGHT:BACK_RIGHT,DEFAULT_STEERING_INCREMENT:DEFAULT_STEERING_INCREMENT,DEFAULT_STEERING_CLAMP:DEFAULT_STEERING_CLAMP,DEFAULT_MAX_ENGINE_FORCE:DEFAULT_MAX_ENGINE_FORCE,DEFAULT_MAX_BREAKING_FORCE:DEFAULT_MAX_BREAKING_FORCE,EXPLOSION_SIZES:EXPLOSION_SIZES,EXPLOSION_STRENGTHS:EXPLOSION_STRENGTHS});const DEFAULT_DESCRIPTION$1 = {
55966
+ };var PHYSICS_CONSTANTS=/*#__PURE__*/Object.freeze({__proto__:null,LIBRARY_NAME:LIBRARY_NAME,TYPES:TYPES,COLLIDER_TYPES:COLLIDER_TYPES$2,DEFAULT_VEHICLE_STATE:DEFAULT_VEHICLE_STATE,DEFAULT_RIGIDBODY_STATE:DEFAULT_RIGIDBODY_STATE,DEFAULT_SCALE:DEFAULT_SCALE$1,DEFAULT_QUATERNION:DEFAULT_QUATERNION,DEFAULT_POSITION:DEFAULT_POSITION$8,DEFAULT_LINEAR_VELOCITY:DEFAULT_LINEAR_VELOCITY,DEFAULT_ANGULAR_VELOCITY:DEFAULT_ANGULAR_VELOCITY,DEFAULT_IMPULSE:DEFAULT_IMPULSE,DISABLE_DEACTIVATION:DISABLE_DEACTIVATION,GRAVITY:GRAVITY,FRONT_LEFT:FRONT_LEFT,FRONT_RIGHT:FRONT_RIGHT,BACK_LEFT:BACK_LEFT,BACK_RIGHT:BACK_RIGHT,DEFAULT_STEERING_INCREMENT:DEFAULT_STEERING_INCREMENT,DEFAULT_STEERING_CLAMP:DEFAULT_STEERING_CLAMP,DEFAULT_MAX_ENGINE_FORCE:DEFAULT_MAX_ENGINE_FORCE,DEFAULT_MAX_BREAKING_FORCE:DEFAULT_MAX_BREAKING_FORCE,EXPLOSION_SIZES:EXPLOSION_SIZES,EXPLOSION_STRENGTHS:EXPLOSION_STRENGTHS});const DEFAULT_DESCRIPTION$1 = {
56034
55967
  mass: 1,
56035
55968
  friction: 1,
56036
55969
  quaternion: DEFAULT_QUATERNION,
@@ -56041,24 +55974,24 @@ const DEFAULT_BOX_DESCRIPTION = {
56041
55974
  width: 2,
56042
55975
  length: 2,
56043
55976
  height: 2,
56044
- collider: COLLIDER_TYPES$1.BOX
55977
+ collider: COLLIDER_TYPES$2.BOX
56045
55978
  };
56046
55979
  const DEFAULT_SPHERE_DESCRIPTION = {
56047
55980
  ...DEFAULT_DESCRIPTION$1,
56048
55981
  radius: 2,
56049
- collider: COLLIDER_TYPES$1.SPHERE
55982
+ collider: COLLIDER_TYPES$2.SPHERE
56050
55983
  };
56051
55984
  const DEFAULT_PLAYER_DESCRIPTION = {
56052
55985
  ...DEFAULT_DESCRIPTION$1,
56053
55986
  width: 0.5,
56054
55987
  height: 1.8,
56055
- collider: COLLIDER_TYPES$1.PLAYER
55988
+ collider: COLLIDER_TYPES$2.PLAYER
56056
55989
  };
56057
55990
  const mapColliderTypeToAddEvent$1 = type => ({
56058
- [COLLIDER_TYPES$1.BOX]: PHYSICS_EVENTS.ADD.BOX,
56059
- [COLLIDER_TYPES$1.VEHICLE]: PHYSICS_EVENTS.ADD.VEHICLE,
56060
- [COLLIDER_TYPES$1.PLAYER]: PHYSICS_EVENTS.ADD.PLAYER,
56061
- [COLLIDER_TYPES$1.SPHERE]: PHYSICS_EVENTS.ADD.SPHERE
55991
+ [COLLIDER_TYPES$2.BOX]: PHYSICS_EVENTS.ADD.BOX,
55992
+ [COLLIDER_TYPES$2.VEHICLE]: PHYSICS_EVENTS.ADD.VEHICLE,
55993
+ [COLLIDER_TYPES$2.PLAYER]: PHYSICS_EVENTS.ADD.PLAYER,
55994
+ [COLLIDER_TYPES$2.SPHERE]: PHYSICS_EVENTS.ADD.SPHERE
56062
55995
  })[type] || PHYSICS_EVENTS.ADD.BOX;
56063
55996
  const extractBoundingBox = body => {
56064
55997
  body.geometry.computeBoundingBox();
@@ -56114,7 +56047,7 @@ const parseBoundingBoxSize = (boundingBox = {}) => {
56114
56047
  y: sizeY,
56115
56048
  z: sizeZ
56116
56049
  };
56117
- } catch (e) {
56050
+ } catch {
56118
56051
  console.log(BOUNDINGBOX_NOT_AVAILABLE);
56119
56052
  return {
56120
56053
  x: 1,
@@ -56144,6 +56077,10 @@ const extractPositionAndQuaternion$1 = element => {
56144
56077
  }
56145
56078
  };
56146
56079
  };
56080
+
56081
+ // Original bounding-box path — uses the pre-computed element.boundingBox
56082
+ // which comes from evaluateBoundingBox() during postBodyCreation().
56083
+ // Reliable for individual elements whose bounding box is already computed.
56147
56084
  const extractBoxDescription = element => {
56148
56085
  const scale = element.getScale();
56149
56086
  const size = parseBoundingBoxSize(element.boundingBox);
@@ -56155,6 +56092,33 @@ const extractBoxDescription = element => {
56155
56092
  ...extractPositionAndQuaternion$1(element)
56156
56093
  };
56157
56094
  };
56095
+
56096
+ // World-space AABB path — uses Box3.setFromObject() to compute the full
56097
+ // bounding box of the entire object hierarchy including child transforms.
56098
+ // More accurate for imported models whose geometry may be offset from the
56099
+ // element origin, but can produce unexpected results for complex hierarchies.
56100
+ const extractWorldBoxDescription = element => {
56101
+ const body = element.getBody();
56102
+ const worldBox = new Box3().setFromObject(body);
56103
+ const worldSize = new Vector3$1();
56104
+ worldBox.getSize(worldSize);
56105
+
56106
+ // Fall back to the legacy path if the world box is degenerate.
56107
+ if (worldSize.x === 0 && worldSize.y === 0 && worldSize.z === 0) {
56108
+ return extractBoxDescription(element);
56109
+ }
56110
+ return {
56111
+ width: worldSize.x,
56112
+ height: worldSize.y,
56113
+ length: worldSize.z,
56114
+ size: {
56115
+ x: worldSize.x,
56116
+ y: worldSize.y,
56117
+ z: worldSize.z
56118
+ },
56119
+ ...extractPositionAndQuaternion$1(element)
56120
+ };
56121
+ };
56158
56122
  const extractSphereDescription = element => {
56159
56123
  const radius = element.boundingSphere.radius;
56160
56124
  return {
@@ -56162,9 +56126,12 @@ const extractSphereDescription = element => {
56162
56126
  ...extractPositionAndQuaternion$1(element)
56163
56127
  };
56164
56128
  };
56129
+
56130
+ // Static box colliders use the world-space AABB so imported models get
56131
+ // correctly sized colliders even when their geometry is offset.
56165
56132
  const getBoxDescriptionForElement$1 = element => ({
56166
56133
  ...DEFAULT_BOX_DESCRIPTION,
56167
- ...extractBoxDescription(element)
56134
+ ...extractWorldBoxDescription(element)
56168
56135
  });
56169
56136
  const getSphereDescriptionForElement = element => ({
56170
56137
  ...DEFAULT_SPHERE_DESCRIPTION,
@@ -56174,10 +56141,10 @@ const getPlayerDescriptionForElement = element => ({
56174
56141
  ...DEFAULT_PLAYER_DESCRIPTION,
56175
56142
  ...extractBoxDescription(element)
56176
56143
  });
56177
- const mapColliderTypeToDescription$1 = (colliderType = COLLIDER_TYPES$1.BOX) => ({
56178
- [COLLIDER_TYPES$1.BOX]: getBoxDescriptionForElement$1,
56179
- [COLLIDER_TYPES$1.SPHERE]: getSphereDescriptionForElement,
56180
- [COLLIDER_TYPES$1.PLAYER]: getPlayerDescriptionForElement
56144
+ const mapColliderTypeToDescription$1 = (colliderType = COLLIDER_TYPES$2.BOX) => ({
56145
+ [COLLIDER_TYPES$2.BOX]: getBoxDescriptionForElement$1,
56146
+ [COLLIDER_TYPES$2.SPHERE]: getSphereDescriptionForElement,
56147
+ [COLLIDER_TYPES$2.PLAYER]: getPlayerDescriptionForElement
56181
56148
  })[colliderType] || getBoxDescriptionForElement$1;
56182
56149
  const iterateGeometries$1 = function () {
56183
56150
  const inverse = new Matrix4();
@@ -56213,7 +56180,7 @@ const convertAmmoVector = ({
56213
56180
  z: x
56214
56181
  });var physicsUtils=/*#__PURE__*/Object.freeze({__proto__:null,DEFAULT_DESCRIPTION:DEFAULT_DESCRIPTION$1,mapColliderTypeToAddEvent:mapColliderTypeToAddEvent$1,extractBoundingBox:extractBoundingBox,extractBiggestBoundingBox:extractBiggestBoundingBox,extractBoundingSphere:extractBoundingSphere,extractBiggestBoundingSphere:extractBiggestBoundingSphere,parseBoundingBoxSize:parseBoundingBoxSize,extractPositionAndQuaternion:extractPositionAndQuaternion$1,extractBoxDescription:extractBoxDescription,extractSphereDescription:extractSphereDescription,getBoxDescriptionForElement:getBoxDescriptionForElement$1,getSphereDescriptionForElement:getSphereDescriptionForElement,getPlayerDescriptionForElement:getPlayerDescriptionForElement,mapColliderTypeToDescription:mapColliderTypeToDescription$1,iterateGeometries:iterateGeometries$1,convertAmmoVector:convertAmmoVector});const getHostURL = () => `${document.location.protocol}//${document.location.host}`;
56215
56182
  const {
56216
- COLLIDER_TYPES
56183
+ COLLIDER_TYPES: COLLIDER_TYPES$1
56217
56184
  } = PHYSICS_CONSTANTS;
56218
56185
  const {
56219
56186
  getBoxDescriptionForElement,
@@ -56485,7 +56452,7 @@ let Physics = /*#__PURE__*/function (_EventDispatcher) {
56485
56452
  }
56486
56453
  }, {
56487
56454
  key: "storeElement",
56488
- value: function storeElement(element, options) {
56455
+ value: function storeElement(element, _options) {
56489
56456
  if (!this.hasElement(element)) {
56490
56457
  const uuid = element.uuid();
56491
56458
  this.elements.push(uuid);
@@ -56546,7 +56513,7 @@ let Physics = /*#__PURE__*/function (_EventDispatcher) {
56546
56513
  value: function add(element, options = {}) {
56547
56514
  if (Config$1.physics().enabled) {
56548
56515
  const {
56549
- colliderType = COLLIDER_TYPES.BOX
56516
+ colliderType = COLLIDER_TYPES$1.BOX
56550
56517
  } = options;
56551
56518
  const uuid = element.uuid();
56552
56519
  const description = {
@@ -58982,7 +58949,10 @@ let FirstPersonControl = /*#__PURE__*/function (_EventDispatcher) {
58982
58949
  }
58983
58950
  }
58984
58951
  }]);
58985
- }(EventDispatcher);const CHANGE_EVENT = {
58952
+ }(EventDispatcher);const {
58953
+ COLLIDER_TYPES
58954
+ } = PHYSICS_CONSTANTS;
58955
+ const CHANGE_EVENT = {
58986
58956
  type: "change"
58987
58957
  };
58988
58958
  const LOCK_EVENT = {
@@ -58999,31 +58969,42 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
58999
58969
  _defineProperty$1(_this, "hasPhysicsEnabled", () => _this.options.physicsEnabled);
59000
58970
  const {
59001
58971
  distance = 5,
59002
- heightOffset = 2,
58972
+ // cameraHeight: how far above the character the camera sits
58973
+ cameraHeight = options.heightOffset ?? 2,
59003
58974
  sensitivity = 0.002,
59004
58975
  target = null,
59005
58976
  physicsEnabled = false,
59006
58977
  speed = 2,
59007
58978
  jumpSpeed = 2,
59008
58979
  mass = 100,
59009
- height = 1.8,
58980
+ // groundLevel: the Y coordinate of the floor (non-physics mode only)
58981
+ groundLevel = options.height ?? 0.5,
59010
58982
  slowDownFactor = 20,
59011
58983
  minPolarAngle = 0.1,
59012
- maxPolarAngle = Math.PI / 2 - 0.1
58984
+ maxPolarAngle = Math.PI / 2 - 0.1,
58985
+ // originOffset: offset from the model origin to the desired capsule
58986
+ // centre. Adjust this if the character sinks into or floats above
58987
+ // the ground. Positive Y moves the capsule up relative to the model.
58988
+ originOffset = {
58989
+ x: 0,
58990
+ y: 0,
58991
+ z: 0
58992
+ }
59013
58993
  } = options;
59014
58994
  _this.options = {
59015
58995
  distance,
59016
- heightOffset,
58996
+ cameraHeight,
59017
58997
  sensitivity,
59018
58998
  target,
59019
58999
  physicsEnabled,
59020
59000
  speed,
59021
59001
  jumpSpeed,
59022
59002
  mass,
59023
- height,
59003
+ groundLevel,
59024
59004
  slowDownFactor,
59025
59005
  minPolarAngle,
59026
- maxPolarAngle
59006
+ maxPolarAngle,
59007
+ originOffset
59027
59008
  };
59028
59009
  _this.camera = camera;
59029
59010
  _this.character = target;
@@ -59042,9 +59023,8 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59042
59023
  _this.movement.right = false;
59043
59024
  _this.canJump = false;
59044
59025
 
59045
- // For non-physics mode
59026
+ // For non-physics mode (gravity/jump only — horizontal movement is direct)
59046
59027
  _this.velocity = new Vector3$1();
59047
- _this.direction = new Vector3$1();
59048
59028
 
59049
59029
  // Character facing direction (Y-axis rotation only)
59050
59030
  _this.characterQuaternion = new Quaternion();
@@ -59070,6 +59050,31 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59070
59050
  document.addEventListener("keyup", this._onKeyUp, false);
59071
59051
  document.addEventListener("pointerlockchange", this._onPointerlockChange, false);
59072
59052
  document.addEventListener("pointerlockerror", this._onPointerlockError, false);
59053
+
59054
+ // In non-physics mode, use the character's starting Y as ground level
59055
+ // when no explicit value was provided, so it doesn't free-fall on start.
59056
+ if (!this.hasPhysicsEnabled() && this.character) {
59057
+ const startY = this.character.getPosition().y;
59058
+ if (this.options.groundLevel === 0.5 && startY > 1) {
59059
+ this.options.groundLevel = startY;
59060
+ }
59061
+ // Start grounded so the first jump works
59062
+ this.canJump = true;
59063
+ }
59064
+ if (this.hasPhysicsEnabled() && this.character) {
59065
+ this.addCharacterToPhysics();
59066
+ }
59067
+ }
59068
+ }, {
59069
+ key: "addCharacterToPhysics",
59070
+ value: function addCharacterToPhysics() {
59071
+ if (!Physics$1.hasElement(this.character)) {
59072
+ this.character.enablePhysics({
59073
+ colliderType: COLLIDER_TYPES.PLAYER,
59074
+ mass: this.options.mass,
59075
+ originOffset: this.options.originOffset
59076
+ });
59077
+ }
59073
59078
  }
59074
59079
  }, {
59075
59080
  key: "dispose",
@@ -59115,6 +59120,19 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59115
59120
  } else {
59116
59121
  this.dispatchEvent(UNLOCK_EVENT);
59117
59122
  this.isLocked = false;
59123
+
59124
+ // Clear movement flags so the physics worker stops applying velocity.
59125
+ this.movement.forward = false;
59126
+ this.movement.backwards = false;
59127
+ this.movement.left = false;
59128
+ this.movement.right = false;
59129
+ this.hasMovementInput = false;
59130
+ this.wantsJump = false;
59131
+
59132
+ // Send a final "idle" update to the worker to halt the character.
59133
+ if (this.hasPhysicsEnabled()) {
59134
+ this.sendBodyUpdate();
59135
+ }
59118
59136
  }
59119
59137
  }
59120
59138
  }, {
@@ -59229,12 +59247,12 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59229
59247
  const targetPos = target.getPosition();
59230
59248
  const {
59231
59249
  distance,
59232
- heightOffset
59250
+ cameraHeight
59233
59251
  } = this.options;
59234
59252
 
59235
59253
  // Camera offset: behind and above the character
59236
59254
  const offsetX = -Math.sin(this.theta) * Math.cos(this.phi) * distance;
59237
- const offsetY = Math.sin(this.phi) * distance + heightOffset;
59255
+ const offsetY = Math.sin(this.phi) * distance + cameraHeight;
59238
59256
  const offsetZ = -Math.cos(this.theta) * Math.cos(this.phi) * distance;
59239
59257
  this.camera.setPosition({
59240
59258
  x: targetPos.x + offsetX,
@@ -59245,7 +59263,7 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59245
59263
  // Look at the character (slightly above center)
59246
59264
  this.camera.lookAt({
59247
59265
  x: targetPos.x,
59248
- y: targetPos.y + heightOffset * 0.5,
59266
+ y: targetPos.y + cameraHeight * 0.5,
59249
59267
  z: targetPos.z
59250
59268
  });
59251
59269
  }
@@ -59293,28 +59311,12 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59293
59311
  }
59294
59312
  }
59295
59313
 
59296
- // --- Direction/Velocity (non-physics mode) ---
59297
- }, {
59298
- key: "updateDirection",
59299
- value: function updateDirection() {
59300
- this.direction.z = Number(this.movement.forward) - Number(this.movement.backwards);
59301
- this.direction.x = Number(this.movement.right) - Number(this.movement.left);
59302
- this.direction.normalize();
59303
- }
59304
- }, {
59305
- key: "updateVelocity",
59306
- value: function updateVelocity(dt) {
59307
- this.velocity.x -= this.velocity.x * this.options.slowDownFactor * dt;
59308
- this.velocity.z -= this.velocity.z * this.options.slowDownFactor * dt;
59309
-
59310
- // Gravity is acceleration (9.8 m/s²), not force — mass is irrelevant here
59311
- this.velocity.y -= 9.8 * dt;
59312
- if (this.movement.forward || this.movement.backwards) this.velocity.z -= this.direction.z * this.options.speed * dt;
59313
- if (this.movement.left || this.movement.right) this.velocity.x -= this.direction.x * this.options.speed * dt;
59314
- }
59314
+ // --- Movement (non-physics mode) ---
59315
59315
 
59316
59316
  /**
59317
- * Move the character directly using camera-relative directions (non-physics mode).
59317
+ * Move the character using camera-relative directions (non-physics mode).
59318
+ * Uses direct velocity (matching the physics mode feel) instead of
59319
+ * acceleration, so movement is responsive and predictable.
59318
59320
  */
59319
59321
  }, {
59320
59322
  key: "moveCharacter",
@@ -59322,22 +59324,47 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59322
59324
  const character = this.getCharacter();
59323
59325
  const pos = character.getPosition();
59324
59326
  const cameraForward = this.getCameraForwardXZ();
59327
+ const speed = this.options.speed;
59328
+ const isMoving = this.movement.forward || this.movement.backwards || this.movement.left || this.movement.right;
59329
+ if (isMoving) {
59330
+ // Compute camera-relative movement direction (same logic as physics worker)
59331
+ let moveX = 0;
59332
+ let moveZ = 0;
59333
+ if (this.movement.forward) {
59334
+ moveX += cameraForward.x;
59335
+ moveZ += cameraForward.z;
59336
+ }
59337
+ if (this.movement.backwards) {
59338
+ moveX -= cameraForward.x;
59339
+ moveZ -= cameraForward.z;
59340
+ }
59341
+ if (this.movement.left) {
59342
+ moveX += cameraForward.z;
59343
+ moveZ -= cameraForward.x;
59344
+ }
59345
+ if (this.movement.right) {
59346
+ moveX -= cameraForward.z;
59347
+ moveZ += cameraForward.x;
59348
+ }
59325
59349
 
59326
- // Forward/back along camera direction
59327
- let dx = cameraForward.x * (-this.velocity.z * dt);
59328
- let dz = cameraForward.z * (-this.velocity.z * dt);
59329
-
59330
- // Strafe perpendicular to camera direction
59331
- dx += -cameraForward.z * (-this.velocity.x * dt);
59332
- dz += cameraForward.x * (-this.velocity.x * dt);
59333
- pos.x += dx;
59334
- pos.z += dz;
59350
+ // Normalize so diagonal movement isn't faster
59351
+ const len = Math.sqrt(moveX * moveX + moveZ * moveZ);
59352
+ if (len > 0) {
59353
+ moveX /= len;
59354
+ moveZ /= len;
59355
+ }
59356
+ pos.x += moveX * speed * dt;
59357
+ pos.z += moveZ * speed * dt;
59358
+ }
59335
59359
 
59336
- // Vertical (gravity/jump)
59360
+ // Gravity
59361
+ this.velocity.y -= 9.8 * dt;
59337
59362
  pos.y += this.velocity.y * dt;
59338
- if (pos.y < this.options.height) {
59363
+
59364
+ // Ground clamp
59365
+ if (pos.y <= this.options.groundLevel) {
59366
+ pos.y = this.options.groundLevel;
59339
59367
  this.velocity.y = 0;
59340
- pos.y = this.options.height;
59341
59368
  this.canJump = true;
59342
59369
  }
59343
59370
  character.setPosition(pos);
@@ -59355,7 +59382,6 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59355
59382
  w
59356
59383
  } = this.characterQuaternion;
59357
59384
  const state = {
59358
- direction: this.direction,
59359
59385
  movement: this.movement,
59360
59386
  quaternion: {
59361
59387
  x: 0,
@@ -59364,7 +59390,7 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59364
59390
  w
59365
59391
  },
59366
59392
  cameraDirection,
59367
- speed: this.options.speed * 2,
59393
+ speed: this.options.speed,
59368
59394
  walkSpeed: this.options.speed
59369
59395
  };
59370
59396
 
@@ -59391,14 +59417,12 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59391
59417
  this.canJump = true;
59392
59418
  }
59393
59419
 
59394
- // Apply visual rotation after physics has overwritten it.
59395
- // Physics uses angularFactor=0 so the body never rotates;
59396
- // we drive rotation visually from the control input.
59397
- if (this.hasMovementInput) {
59398
- const body = this.character.getBody();
59399
- body.quaternion.set(this.characterQuaternion.x, this.characterQuaternion.y, this.characterQuaternion.z, this.characterQuaternion.w);
59400
- body.updateMatrixWorld(true);
59401
- }
59420
+ // Always override the quaternion from physics player rotation
59421
+ // is purely visual and driven by the control, not by physics.
59422
+ // This prevents any physics rotation drift from affecting the visual.
59423
+ const body = this.character.getBody();
59424
+ body.quaternion.set(this.characterQuaternion.x, this.characterQuaternion.y, this.characterQuaternion.z, this.characterQuaternion.w);
59425
+ body.updateMatrixWorld(true);
59402
59426
  }
59403
59427
  }
59404
59428
 
@@ -59407,10 +59431,8 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59407
59431
  key: "update",
59408
59432
  value: function update(dt) {
59409
59433
  if (this.isLocked) {
59410
- this.updateDirection();
59411
59434
  this.updateCharacterRotation();
59412
59435
  if (!this.hasPhysicsEnabled()) {
59413
- this.updateVelocity(dt);
59414
59436
  this.moveCharacter(dt);
59415
59437
  } else {
59416
59438
  this.sendBodyUpdate();
@@ -59663,9 +59685,6 @@ let ThirdPersonControl = /*#__PURE__*/function (_EventDispatcher) {
59663
59685
  }
59664
59686
  _inherits(FlyControl, _EventDispatcher);
59665
59687
  return _createClass(FlyControl, [{
59666
- key: "update",
59667
- value: function update() {}
59668
- }, {
59669
59688
  key: "physicsUpdate",
59670
59689
  value: function physicsUpdate() {}
59671
59690
  }]);
@@ -60172,7 +60191,7 @@ var Controls$1 = new Controls();let Scene = /*#__PURE__*/function () {
60172
60191
  }
60173
60192
  }, {
60174
60193
  key: "toJSON",
60175
- value: function toJSON(parseJSON = false) {
60194
+ value: function toJSON(_parseJSON = false) {
60176
60195
  return {
60177
60196
  name: this.getName(),
60178
60197
  uuid: this.uuid(),
@@ -60368,7 +60387,7 @@ let Features = /*#__PURE__*/function () {
60368
60387
  key: "setUpPolyfills",
60369
60388
  value: function setUpPolyfills() {
60370
60389
  const frameRate = Config$1.screen().frameRate;
60371
- window.requestNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, element) {
60390
+ window.requestNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, _element) {
60372
60391
  window.setTimeout(callback, 1000 / frameRate);
60373
60392
  };
60374
60393
  }
@@ -60440,7 +60459,7 @@ let Features = /*#__PURE__*/function () {
60440
60459
  name: FEATURES.WEBGL
60441
60460
  };
60442
60461
  }
60443
- } catch (e) {
60462
+ } catch {
60444
60463
  return {
60445
60464
  success: false,
60446
60465
  name: FEATURES.WEBGL
@@ -60463,7 +60482,7 @@ let Features = /*#__PURE__*/function () {
60463
60482
  name: FEATURES.WEBAUDIOAPI
60464
60483
  };
60465
60484
  }
60466
- } catch (e) {
60485
+ } catch {
60467
60486
  return {
60468
60487
  success: false,
60469
60488
  name: FEATURES.WEBAUDIOAPI
@@ -60486,7 +60505,7 @@ let Features = /*#__PURE__*/function () {
60486
60505
  name: FEATURES.WEBWORKER
60487
60506
  };
60488
60507
  }
60489
- } catch (e) {
60508
+ } catch {
60490
60509
  return {
60491
60510
  success: false,
60492
60511
  name: FEATURES.WEBWORKER
@@ -60500,13 +60519,13 @@ let Features = /*#__PURE__*/function () {
60500
60519
  let xhr = null;
60501
60520
  try {
60502
60521
  xhr = new XMLHttpRequest();
60503
- } catch (e) {}
60522
+ } catch {}
60504
60523
  try {
60505
60524
  xhr = new ActiveXObject("Microsoft.XMLHTTP");
60506
- } catch (e) {}
60525
+ } catch {}
60507
60526
  try {
60508
60527
  xhr = new ActiveXObject("Msxml2.XMLHTTP");
60509
- } catch (e) {}
60528
+ } catch {}
60510
60529
  if (xhr) {
60511
60530
  return {
60512
60531
  success: true,
@@ -60518,7 +60537,7 @@ let Features = /*#__PURE__*/function () {
60518
60537
  name: FEATURES.AJAX
60519
60538
  };
60520
60539
  }
60521
- } catch (e) {
60540
+ } catch {
60522
60541
  return {
60523
60542
  success: false,
60524
60543
  name: FEATURES.AJAX
@@ -60540,7 +60559,7 @@ let Features = /*#__PURE__*/function () {
60540
60559
  name: FEATURES.GAMEPADAPI
60541
60560
  };
60542
60561
  }
60543
- } catch (e) {
60562
+ } catch {
60544
60563
  return {
60545
60564
  success: false,
60546
60565
  name: FEATURES.GAMEPADAPI
@@ -60562,7 +60581,7 @@ let Features = /*#__PURE__*/function () {
60562
60581
  name: FEATURES.MEMORY
60563
60582
  };
60564
60583
  }
60565
- } catch (e) {
60584
+ } catch {
60566
60585
  return {
60567
60586
  success: false,
60568
60587
  name: FEATURES.MEMORY
@@ -61249,7 +61268,7 @@ function applyMiddleware() {
61249
61268
 
61250
61269
  var thunk = createThunkMiddleware();
61251
61270
  thunk.withExtraArgument = createThunkMiddleware;var name = "mage-engine";
61252
- var version$1 = "3.25.0";
61271
+ var version$1 = "3.25.1";
61253
61272
  var description = "A WebGL Javascript Game Engine, built on top of THREE.js and many other libraries.";
61254
61273
  var main = "dist/mage.js";
61255
61274
  var author$1 = {
@@ -61357,7 +61376,7 @@ var packageJSON = {
61357
61376
  };const DEFAULT_STATE$5 = {
61358
61377
  mage: packageJSON.version
61359
61378
  };
61360
- var info = (state = DEFAULT_STATE$5, action = {}) => {
61379
+ var info = (state = DEFAULT_STATE$5, _action = {}) => {
61361
61380
  return state;
61362
61381
  };const DEFAULT_STATE$4 = {
61363
61382
  error: false,
@@ -61549,7 +61568,7 @@ const getState = () => {
61549
61568
  }
61550
61569
  };
61551
61570
  const getStore = () => store;
61552
- const handleSubscriptions = (...args) => subscribers.forEach(subscriber => {
61571
+ const handleSubscriptions = (..._args) => subscribers.forEach(subscriber => {
61553
61572
  if (subscriber.onStateChange) {
61554
61573
  subscriber.onStateChange(getState(), latestAction);
61555
61574
  }
@@ -61913,525 +61932,77 @@ let Input = /*#__PURE__*/function (_EventDispatcher) {
61913
61932
  }
61914
61933
  }]);
61915
61934
  }(EventDispatcher);
61916
- var Input$1 = new Input();var support = {
61917
- searchParams: 'URLSearchParams' in self,
61918
- iterable: 'Symbol' in self && 'iterator' in Symbol,
61919
- blob:
61920
- 'FileReader' in self &&
61921
- 'Blob' in self &&
61922
- (function() {
61923
- try {
61924
- new Blob();
61925
- return true
61926
- } catch (e) {
61927
- return false
61928
- }
61929
- })(),
61930
- formData: 'FormData' in self,
61931
- arrayBuffer: 'ArrayBuffer' in self
61932
- };
61933
-
61934
- function isDataView(obj) {
61935
- return obj && DataView.prototype.isPrototypeOf(obj)
61936
- }
61937
-
61938
- if (support.arrayBuffer) {
61939
- var viewClasses = [
61940
- '[object Int8Array]',
61941
- '[object Uint8Array]',
61942
- '[object Uint8ClampedArray]',
61943
- '[object Int16Array]',
61944
- '[object Uint16Array]',
61945
- '[object Int32Array]',
61946
- '[object Uint32Array]',
61947
- '[object Float32Array]',
61948
- '[object Float64Array]'
61949
- ];
61950
-
61951
- var isArrayBufferView =
61952
- ArrayBuffer.isView ||
61953
- function(obj) {
61954
- return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
61955
- };
61956
- }
61957
-
61958
- function normalizeName(name) {
61959
- if (typeof name !== 'string') {
61960
- name = String(name);
61961
- }
61962
- if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
61963
- throw new TypeError('Invalid character in header field name')
61964
- }
61965
- return name.toLowerCase()
61966
- }
61967
-
61968
- function normalizeValue(value) {
61969
- if (typeof value !== 'string') {
61970
- value = String(value);
61971
- }
61972
- return value
61973
- }
61974
-
61975
- // Build a destructive iterator for the value list
61976
- function iteratorFor(items) {
61977
- var iterator = {
61978
- next: function() {
61979
- var value = items.shift();
61980
- return {done: value === undefined, value: value}
61981
- }
61982
- };
61983
-
61984
- if (support.iterable) {
61985
- iterator[Symbol.iterator] = function() {
61986
- return iterator
61987
- };
61988
- }
61989
-
61990
- return iterator
61991
- }
61992
-
61993
- function Headers(headers) {
61994
- this.map = {};
61995
-
61996
- if (headers instanceof Headers) {
61997
- headers.forEach(function(value, name) {
61998
- this.append(name, value);
61999
- }, this);
62000
- } else if (Array.isArray(headers)) {
62001
- headers.forEach(function(header) {
62002
- this.append(header[0], header[1]);
62003
- }, this);
62004
- } else if (headers) {
62005
- Object.getOwnPropertyNames(headers).forEach(function(name) {
62006
- this.append(name, headers[name]);
62007
- }, this);
61935
+ var Input$1 = new Input();/*
61936
+ A dynamic script that can be attached to an entity.
61937
+ This is a script that needs to be updated during the game loop.
61938
+ */
61939
+ let BaseScript = /*#__PURE__*/function () {
61940
+ function BaseScript(name) {
61941
+ _classCallCheck(this, BaseScript);
61942
+ this.__name = name || this.constructor.name;
61943
+ this.hasStarted = false;
61944
+ this.isDisposed = false;
61945
+ this.options = {};
62008
61946
  }
62009
- }
62010
-
62011
- Headers.prototype.append = function(name, value) {
62012
- name = normalizeName(name);
62013
- value = normalizeValue(value);
62014
- var oldValue = this.map[name];
62015
- this.map[name] = oldValue ? oldValue + ', ' + value : value;
62016
- };
62017
-
62018
- Headers.prototype['delete'] = function(name) {
62019
- delete this.map[normalizeName(name)];
62020
- };
62021
-
62022
- Headers.prototype.get = function(name) {
62023
- name = normalizeName(name);
62024
- return this.has(name) ? this.map[name] : null
62025
- };
62026
-
62027
- Headers.prototype.has = function(name) {
62028
- return this.map.hasOwnProperty(normalizeName(name))
62029
- };
62030
-
62031
- Headers.prototype.set = function(name, value) {
62032
- this.map[normalizeName(name)] = normalizeValue(value);
62033
- };
62034
-
62035
- Headers.prototype.forEach = function(callback, thisArg) {
62036
- for (var name in this.map) {
62037
- if (this.map.hasOwnProperty(name)) {
62038
- callback.call(thisArg, this.map[name], name, this);
61947
+ return _createClass(BaseScript, [{
61948
+ key: "__check",
61949
+ value: function __check() {
61950
+ return true;
62039
61951
  }
62040
- }
62041
- };
62042
-
62043
- Headers.prototype.keys = function() {
62044
- var items = [];
62045
- this.forEach(function(value, name) {
62046
- items.push(name);
62047
- });
62048
- return iteratorFor(items)
62049
- };
62050
-
62051
- Headers.prototype.values = function() {
62052
- var items = [];
62053
- this.forEach(function(value) {
62054
- items.push(value);
62055
- });
62056
- return iteratorFor(items)
62057
- };
62058
-
62059
- Headers.prototype.entries = function() {
62060
- var items = [];
62061
- this.forEach(function(value, name) {
62062
- items.push([name, value]);
62063
- });
62064
- return iteratorFor(items)
62065
- };
62066
-
62067
- if (support.iterable) {
62068
- Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
62069
- }
62070
-
62071
- function consumed(body) {
62072
- if (body.bodyUsed) {
62073
- return Promise.reject(new TypeError('Already read'))
62074
- }
62075
- body.bodyUsed = true;
62076
- }
62077
-
62078
- function fileReaderReady(reader) {
62079
- return new Promise(function(resolve, reject) {
62080
- reader.onload = function() {
62081
- resolve(reader.result);
62082
- };
62083
- reader.onerror = function() {
62084
- reject(reader.error);
62085
- };
62086
- })
62087
- }
62088
-
62089
- function readBlobAsArrayBuffer(blob) {
62090
- var reader = new FileReader();
62091
- var promise = fileReaderReady(reader);
62092
- reader.readAsArrayBuffer(blob);
62093
- return promise
62094
- }
62095
-
62096
- function readBlobAsText(blob) {
62097
- var reader = new FileReader();
62098
- var promise = fileReaderReady(reader);
62099
- reader.readAsText(blob);
62100
- return promise
62101
- }
62102
-
62103
- function readArrayBufferAsText(buf) {
62104
- var view = new Uint8Array(buf);
62105
- var chars = new Array(view.length);
62106
-
62107
- for (var i = 0; i < view.length; i++) {
62108
- chars[i] = String.fromCharCode(view[i]);
62109
- }
62110
- return chars.join('')
62111
- }
62112
-
62113
- function bufferClone(buf) {
62114
- if (buf.slice) {
62115
- return buf.slice(0)
62116
- } else {
62117
- var view = new Uint8Array(buf.byteLength);
62118
- view.set(new Uint8Array(buf));
62119
- return view.buffer
62120
- }
62121
- }
62122
-
62123
- function Body() {
62124
- this.bodyUsed = false;
62125
-
62126
- this._initBody = function(body) {
62127
- this._bodyInit = body;
62128
- if (!body) {
62129
- this._bodyText = '';
62130
- } else if (typeof body === 'string') {
62131
- this._bodyText = body;
62132
- } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
62133
- this._bodyBlob = body;
62134
- } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
62135
- this._bodyFormData = body;
62136
- } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
62137
- this._bodyText = body.toString();
62138
- } else if (support.arrayBuffer && support.blob && isDataView(body)) {
62139
- this._bodyArrayBuffer = bufferClone(body.buffer);
62140
- // IE 10-11 can't handle a DataView body.
62141
- this._bodyInit = new Blob([this._bodyArrayBuffer]);
62142
- } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
62143
- this._bodyArrayBuffer = bufferClone(body);
62144
- } else {
62145
- this._bodyText = body = Object.prototype.toString.call(body);
61952
+ }, {
61953
+ key: "__isStatic",
61954
+ value: function __isStatic() {
61955
+ return false;
62146
61956
  }
62147
-
62148
- if (!this.headers.get('content-type')) {
62149
- if (typeof body === 'string') {
62150
- this.headers.set('content-type', 'text/plain;charset=UTF-8');
62151
- } else if (this._bodyBlob && this._bodyBlob.type) {
62152
- this.headers.set('content-type', this._bodyBlob.type);
62153
- } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
62154
- this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
62155
- }
61957
+ }, {
61958
+ key: "__hasStarted",
61959
+ value: function __hasStarted() {
61960
+ return this.hasStarted;
62156
61961
  }
62157
- };
62158
-
62159
- if (support.blob) {
62160
- this.blob = function() {
62161
- var rejected = consumed(this);
62162
- if (rejected) {
62163
- return rejected
62164
- }
62165
-
62166
- if (this._bodyBlob) {
62167
- return Promise.resolve(this._bodyBlob)
62168
- } else if (this._bodyArrayBuffer) {
62169
- return Promise.resolve(new Blob([this._bodyArrayBuffer]))
62170
- } else if (this._bodyFormData) {
62171
- throw new Error('could not read FormData body as blob')
62172
- } else {
62173
- return Promise.resolve(new Blob([this._bodyText]))
62174
- }
62175
- };
62176
-
62177
- this.arrayBuffer = function() {
62178
- if (this._bodyArrayBuffer) {
62179
- return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
62180
- } else {
62181
- return this.blob().then(readBlobAsArrayBuffer)
62182
- }
62183
- };
62184
- }
62185
-
62186
- this.text = function() {
62187
- var rejected = consumed(this);
62188
- if (rejected) {
62189
- return rejected
61962
+ }, {
61963
+ key: "__isDisposed",
61964
+ value: function __isDisposed() {
61965
+ return this.isDisposed;
62190
61966
  }
62191
-
62192
- if (this._bodyBlob) {
62193
- return readBlobAsText(this._bodyBlob)
62194
- } else if (this._bodyArrayBuffer) {
62195
- return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
62196
- } else if (this._bodyFormData) {
62197
- throw new Error('could not read FormData body as text')
62198
- } else {
62199
- return Promise.resolve(this._bodyText)
61967
+ }, {
61968
+ key: "__setStartedFlag",
61969
+ value: function __setStartedFlag(flag) {
61970
+ this.hasStarted = flag;
62200
61971
  }
62201
- };
62202
-
62203
- if (support.formData) {
62204
- this.formData = function() {
62205
- return this.text().then(decode)
62206
- };
62207
- }
62208
-
62209
- this.json = function() {
62210
- return this.text().then(JSON.parse)
62211
- };
62212
-
62213
- return this
62214
- }
62215
-
62216
- // HTTP methods whose capitalization should be normalized
62217
- var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
62218
-
62219
- function normalizeMethod(method) {
62220
- var upcased = method.toUpperCase();
62221
- return methods.indexOf(upcased) > -1 ? upcased : method
62222
- }
62223
-
62224
- function Request(input, options) {
62225
- options = options || {};
62226
- var body = options.body;
62227
-
62228
- if (input instanceof Request) {
62229
- if (input.bodyUsed) {
62230
- throw new TypeError('Already read')
61972
+ }, {
61973
+ key: "__setDisposedFlag",
61974
+ value: function __setDisposedFlag(flag) {
61975
+ this.isDisposed = flag;
62231
61976
  }
62232
- this.url = input.url;
62233
- this.credentials = input.credentials;
62234
- if (!options.headers) {
62235
- this.headers = new Headers(input.headers);
61977
+ }, {
61978
+ key: "getName",
61979
+ value: function getName() {
61980
+ return this.__name;
62236
61981
  }
62237
- this.method = input.method;
62238
- this.mode = input.mode;
62239
- this.signal = input.signal;
62240
- if (!body && input._bodyInit != null) {
62241
- body = input._bodyInit;
62242
- input.bodyUsed = true;
61982
+ }, {
61983
+ key: "start",
61984
+ value: function start(_element, _options) {}
61985
+ }, {
61986
+ key: "update",
61987
+ value: function update(_dt) {}
61988
+ }, {
61989
+ key: "physicsUpdate",
61990
+ value: function physicsUpdate(_dt) {}
61991
+ }, {
61992
+ key: "onDispose",
61993
+ value: function onDispose() {}
61994
+ }, {
61995
+ key: "toJSON",
61996
+ value: function toJSON(_parseJSON = false) {
61997
+ return {
61998
+ name: this.name()
61999
+ };
62243
62000
  }
62244
- } else {
62245
- this.url = String(input);
62246
- }
62247
-
62248
- this.credentials = options.credentials || this.credentials || 'same-origin';
62249
- if (options.headers || !this.headers) {
62250
- this.headers = new Headers(options.headers);
62251
- }
62252
- this.method = normalizeMethod(options.method || this.method || 'GET');
62253
- this.mode = options.mode || this.mode || null;
62254
- this.signal = options.signal || this.signal;
62255
- this.referrer = null;
62256
-
62257
- if ((this.method === 'GET' || this.method === 'HEAD') && body) {
62258
- throw new TypeError('Body not allowed for GET or HEAD requests')
62259
- }
62260
- this._initBody(body);
62261
- }
62262
-
62263
- Request.prototype.clone = function() {
62264
- return new Request(this, {body: this._bodyInit})
62265
- };
62266
-
62267
- function decode(body) {
62268
- var form = new FormData();
62269
- body
62270
- .trim()
62271
- .split('&')
62272
- .forEach(function(bytes) {
62273
- if (bytes) {
62274
- var split = bytes.split('=');
62275
- var name = split.shift().replace(/\+/g, ' ');
62276
- var value = split.join('=').replace(/\+/g, ' ');
62277
- form.append(decodeURIComponent(name), decodeURIComponent(value));
62278
- }
62279
- });
62280
- return form
62281
- }
62282
-
62283
- function parseHeaders(rawHeaders) {
62284
- var headers = new Headers();
62285
- // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
62286
- // https://tools.ietf.org/html/rfc7230#section-3.2
62287
- var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
62288
- preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
62289
- var parts = line.split(':');
62290
- var key = parts.shift().trim();
62291
- if (key) {
62292
- var value = parts.join(':').trim();
62293
- headers.append(key, value);
62294
- }
62295
- });
62296
- return headers
62297
- }
62298
-
62299
- Body.call(Request.prototype);
62300
-
62301
- function Response(bodyInit, options) {
62302
- if (!options) {
62303
- options = {};
62304
- }
62305
-
62306
- this.type = 'default';
62307
- this.status = options.status === undefined ? 200 : options.status;
62308
- this.ok = this.status >= 200 && this.status < 300;
62309
- this.statusText = 'statusText' in options ? options.statusText : 'OK';
62310
- this.headers = new Headers(options.headers);
62311
- this.url = options.url || '';
62312
- this._initBody(bodyInit);
62313
- }
62314
-
62315
- Body.call(Response.prototype);
62316
-
62317
- Response.prototype.clone = function() {
62318
- return new Response(this._bodyInit, {
62319
- status: this.status,
62320
- statusText: this.statusText,
62321
- headers: new Headers(this.headers),
62322
- url: this.url
62323
- })
62324
- };
62325
-
62326
- Response.error = function() {
62327
- var response = new Response(null, {status: 0, statusText: ''});
62328
- response.type = 'error';
62329
- return response
62330
- };
62331
-
62332
- var redirectStatuses = [301, 302, 303, 307, 308];
62333
-
62334
- Response.redirect = function(url, status) {
62335
- if (redirectStatuses.indexOf(status) === -1) {
62336
- throw new RangeError('Invalid status code')
62337
- }
62338
-
62339
- return new Response(null, {status: status, headers: {location: url}})
62340
- };
62341
-
62342
- var DOMException = self.DOMException;
62343
- try {
62344
- new DOMException();
62345
- } catch (err) {
62346
- DOMException = function(message, name) {
62347
- this.message = message;
62348
- this.name = name;
62349
- var error = Error(message);
62350
- this.stack = error.stack;
62351
- };
62352
- DOMException.prototype = Object.create(Error.prototype);
62353
- DOMException.prototype.constructor = DOMException;
62354
- }
62355
-
62356
- function fetch$1(input, init) {
62357
- return new Promise(function(resolve, reject) {
62358
- var request = new Request(input, init);
62359
-
62360
- if (request.signal && request.signal.aborted) {
62361
- return reject(new DOMException('Aborted', 'AbortError'))
62362
- }
62363
-
62364
- var xhr = new XMLHttpRequest();
62365
-
62366
- function abortXhr() {
62367
- xhr.abort();
62368
- }
62369
-
62370
- xhr.onload = function() {
62371
- var options = {
62372
- status: xhr.status,
62373
- statusText: xhr.statusText,
62374
- headers: parseHeaders(xhr.getAllResponseHeaders() || '')
62375
- };
62376
- options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
62377
- var body = 'response' in xhr ? xhr.response : xhr.responseText;
62378
- resolve(new Response(body, options));
62379
- };
62380
-
62381
- xhr.onerror = function() {
62382
- reject(new TypeError('Network request failed'));
62383
- };
62384
-
62385
- xhr.ontimeout = function() {
62386
- reject(new TypeError('Network request failed'));
62387
- };
62388
-
62389
- xhr.onabort = function() {
62390
- reject(new DOMException('Aborted', 'AbortError'));
62391
- };
62392
-
62393
- xhr.open(request.method, request.url, true);
62394
-
62395
- if (request.credentials === 'include') {
62396
- xhr.withCredentials = true;
62397
- } else if (request.credentials === 'omit') {
62398
- xhr.withCredentials = false;
62399
- }
62400
-
62401
- if ('responseType' in xhr && support.blob) {
62402
- xhr.responseType = 'blob';
62403
- }
62404
-
62405
- request.headers.forEach(function(value, name) {
62406
- xhr.setRequestHeader(name, value);
62407
- });
62408
-
62409
- if (request.signal) {
62410
- request.signal.addEventListener('abort', abortXhr);
62411
-
62412
- xhr.onreadystatechange = function() {
62413
- // DONE (success or failure)
62414
- if (xhr.readyState === 4) {
62415
- request.signal.removeEventListener('abort', abortXhr);
62416
- }
62417
- };
62418
- }
62419
-
62420
- xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
62421
- })
62422
- }
62423
-
62424
- fetch$1.polyfill = true;
62425
-
62426
- if (!self.fetch) {
62427
- self.fetch = fetch$1;
62428
- self.Headers = Headers;
62429
- self.Request = Request;
62430
- self.Response = Response;
62431
- }let BaseCar = /*#__PURE__*/function (_BaseScript) {
62432
- function BaseCar() {
62433
- _classCallCheck(this, BaseCar);
62434
- return _callSuper(this, BaseCar, ["BaseCar"]);
62001
+ }]);
62002
+ }();let BaseCar = /*#__PURE__*/function (_BaseScript) {
62003
+ function BaseCar() {
62004
+ _classCallCheck(this, BaseCar);
62005
+ return _callSuper(this, BaseCar, ["BaseCar"]);
62435
62006
  }
62436
62007
  _inherits(BaseCar, _BaseScript);
62437
62008
  return _createClass(BaseCar, [{
@@ -62443,7 +62014,6 @@ if (!self.fetch) {
62443
62014
  brakingKey = "s",
62444
62015
  rightKey = "d",
62445
62016
  leftKey = "a",
62446
- debug = false,
62447
62017
  autostart = true,
62448
62018
  ...physicsOptions
62449
62019
  } = options;
@@ -62492,7 +62062,7 @@ if (!self.fetch) {
62492
62062
  }
62493
62063
  }, {
62494
62064
  key: "update",
62495
- value: function update(dt) {
62065
+ value: function update(_dt) {
62496
62066
  if (this.engineStarted) {
62497
62067
  this.handleInput();
62498
62068
  this.sendCarUpdate();
@@ -62574,7 +62144,7 @@ let SmoothCarFollow = /*#__PURE__*/function (_BaseScript) {
62574
62144
  let Scripts = /*#__PURE__*/function () {
62575
62145
  function Scripts() {
62576
62146
  _classCallCheck(this, Scripts);
62577
- _defineProperty$1(this, "load", (scripts, level) => {
62147
+ _defineProperty$1(this, "load", (scripts, _level) => {
62578
62148
  this.scripts = scripts;
62579
62149
  const keys = Object.keys(scripts);
62580
62150
  if (!keys.length) {
@@ -62698,7 +62268,7 @@ var vivify_1 = vivify;// returns a copy of the original map without the specifie
62698
62268
 
62699
62269
  const omit = (keys, map) => keys.reduce((acc, key) => {
62700
62270
  const {
62701
- [key]: value,
62271
+ [key]: _value,
62702
62272
  ...rest
62703
62273
  } = acc;
62704
62274
  return rest;
@@ -63349,7 +62919,7 @@ let CascadeShadowMaps = /*#__PURE__*/function () {
63349
62919
  }
63350
62920
  }, {
63351
62921
  key: "update",
63352
- value: function update(dt) {
62922
+ value: function update(_dt) {
63353
62923
  if (this.isUsingCascadeShadowMaps()) {
63354
62924
  this.csm.update();
63355
62925
  }
@@ -64479,7 +64049,7 @@ const tweenTo = (origin, target, options = {}) => new Promise(resolve => {
64479
64049
  value: function equals(entity) {
64480
64050
  try {
64481
64051
  return entity.uuid ? this.uuid() === entity.uuid() : false;
64482
- } catch (e) {
64052
+ } catch {
64483
64053
  return false;
64484
64054
  }
64485
64055
  }
@@ -64953,7 +64523,7 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
64953
64523
  _defineProperty$1(_this, "createRayColliderFromVector", ({
64954
64524
  type,
64955
64525
  vector
64956
- }, near, far, offset, debug) => {
64526
+ }, near, far, offset, _debug) => {
64957
64527
  const parsedOffset = {
64958
64528
  ...DEFAULT_COLLIDER_OFFSET,
64959
64529
  ...offset
@@ -65401,8 +64971,8 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
65401
64971
  }, {
65402
64972
  key: "setPhysicsState",
65403
64973
  value: function setPhysicsState({
65404
- dt,
65405
- event,
64974
+ dt: _dt,
64975
+ event: _event,
65406
64976
  ...data
65407
64977
  } = {}) {
65408
64978
  populateMap(this.physicsState, data);
@@ -65415,16 +64985,9 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
65415
64985
  }, {
65416
64986
  key: "enablePhysics",
65417
64987
  value: function enablePhysics(options = {}) {
65418
- const {
65419
- mass
65420
- } = options;
65421
64988
  this.setPhysicsOptions(options);
65422
64989
  if (Config$1.physics().enabled) {
65423
- if (this.isModel() && mass === 0) {
65424
- Physics$1.addModel(this, options);
65425
- } else {
65426
- Physics$1.add(this, options);
65427
- }
64990
+ Physics$1.add(this, options);
65428
64991
  }
65429
64992
  }
65430
64993
  }, {
@@ -73283,7 +72846,7 @@ const isAbsoluteURL$2 = path => {
73283
72846
  try {
73284
72847
  new URL(path);
73285
72848
  return true;
73286
- } catch (_) {
72849
+ } catch {
73287
72850
  return false;
73288
72851
  }
73289
72852
  };
@@ -73362,7 +72925,7 @@ let Audio = /*#__PURE__*/function () {
73362
72925
  return new Promise(resolve => {
73363
72926
  request.open("GET", resolvedPath, true);
73364
72927
  request.responseType = "arraybuffer";
73365
- request.onreadystatechange = e => {
72928
+ request.onreadystatechange = _e => {
73366
72929
  if (request.readyState === 4) {
73367
72930
  if (request.status === 200) {
73368
72931
  this.context.decodeAudioData(request.response, buffer => {
@@ -85513,7 +85076,7 @@ const isAbsoluteURL = path => {
85513
85076
  try {
85514
85077
  new URL(path);
85515
85078
  return true;
85516
- } catch (_) {
85079
+ } catch {
85517
85080
  return false;
85518
85081
  }
85519
85082
  };
@@ -85525,7 +85088,7 @@ const isAbsoluteURL = path => {
85525
85088
  const isURL = path => {
85526
85089
  try {
85527
85090
  return new URL(path);
85528
- } catch (_) {
85091
+ } catch {
85529
85092
  return false;
85530
85093
  }
85531
85094
  };
@@ -91292,7 +90855,7 @@ let OutlineEffect = /*#__PURE__*/function () {
91292
90855
  }
91293
90856
  }, {
91294
90857
  key: "render",
91295
- value: function render(scene, camera, dt) {
90858
+ value: function render(scene, camera, _dt) {
91296
90859
  let renderTarget;
91297
90860
  let forceClear = false;
91298
90861
  if (arguments[3] !== undefined) {
@@ -91602,7 +91165,7 @@ var Proton = three_proton_min.exports;const PARTICLE_EMITTER_TYPES = {
91602
91165
  }
91603
91166
  }, {
91604
91167
  key: "emit",
91605
- value: function emit(...options) {
91168
+ value: function emit(..._options) {
91606
91169
  return this;
91607
91170
  }
91608
91171
  }, {
@@ -92926,7 +92489,6 @@ let Trail = /*#__PURE__*/function (_ParticleEmitterGroup) {
92926
92489
  TRAIL: "trail"
92927
92490
  };
92928
92491
  const {
92929
- SINGLE,
92930
92492
  GROUP
92931
92493
  } = PARTICLE_EMITTER_TYPES;
92932
92494
  let Particles = /*#__PURE__*/function () {
@@ -93077,7 +92639,7 @@ let Level = /*#__PURE__*/function (_EventDispatcher) {
93077
92639
  var _this;
93078
92640
  _classCallCheck(this, Level);
93079
92641
  _this = _callSuper(this, Level);
93080
- _defineProperty$1(_this, "onStateChange", state => {});
92642
+ _defineProperty$1(_this, "onStateChange", _state => {});
93081
92643
  _defineProperty$1(_this, "cancelNextAnimationFrame", () => cancelAnimationFrame(_this.requestAnimationFrameId));
93082
92644
  _defineProperty$1(_this, "init", () => {
93083
92645
  Scene$1.create(_this.getName());
@@ -93281,104 +92843,619 @@ let Storage = /*#__PURE__*/function () {
93281
92843
  }
93282
92844
  }]);
93283
92845
  }();
93284
- var storage = new Storage();let Light$1 = /*#__PURE__*/function (_Entity) {
93285
- function Light({
93286
- color,
93287
- intensity,
93288
- name: _name
93289
- }) {
93290
- var _this;
93291
- _classCallCheck(this, Light);
93292
- _this = _callSuper(this, Light, [{
93293
- name: _name
93294
- }]);
93295
- _defineProperty$1(_this, "addHolder", (name = "lightholder", size = 0.05) => {
93296
- const holderSprite = new HelperSprite(size, size, name, {
93297
- name
93298
- });
93299
- if (holderSprite) {
93300
- holderSprite.setSizeAttenuation(false);
93301
- holderSprite.setDepthTest(false);
93302
- holderSprite.setDepthWrite(false);
93303
- holderSprite.setSerializable(false);
93304
- holderSprite.setPosition(_this.getPosition());
93305
- holderSprite.addTags([TAGS.HELPER, TAGS.LIGHTS.HELPER, TAGS.LIGHTS.HOLDER, name]);
93306
- holderSprite.setHelperTarget(_this);
93307
- _this.holder = holderSprite;
93308
- return true;
93309
- } else {
93310
- console.warn(LIGHT_HOLDER_MODEL_NOT_FOUND);
93311
- return false;
93312
- }
93313
- });
93314
- _defineProperty$1(_this, "addTargetHolder", (name = "targetholder", size = 0.05) => {
93315
- const targetSprite = new HelperSprite(size, size, name, {
93316
- name
93317
- });
93318
- if (targetSprite) {
93319
- targetSprite.setSizeAttenuation(false);
93320
- targetSprite.setDepthTest(false);
93321
- targetSprite.setDepthWrite(false);
93322
- targetSprite.setSerializable(false);
93323
- targetSprite.setPosition(_this.getTarget().getPosition());
93324
- targetSprite.addTags([TAGS.LIGHTS.HELPER, TAGS.LIGHTS.TARGET, name]);
93325
- targetSprite.setHelperTarget(_this);
93326
- targetSprite.getBody().add(_this.getBody().target);
93327
- _this.targetHolder = targetSprite;
92846
+ var storage = new Storage();var support = {
92847
+ searchParams: 'URLSearchParams' in self,
92848
+ iterable: 'Symbol' in self && 'iterator' in Symbol,
92849
+ blob:
92850
+ 'FileReader' in self &&
92851
+ 'Blob' in self &&
92852
+ (function() {
92853
+ try {
92854
+ new Blob();
92855
+ return true
92856
+ } catch (e) {
92857
+ return false
93328
92858
  }
93329
- });
93330
- _this.color = color;
93331
- _this.intensity = intensity;
93332
- _this.name = _name || generateRandomName("Light");
93333
- _this.isLightOn = false;
93334
- _this.body = undefined;
92859
+ })(),
92860
+ formData: 'FormData' in self,
92861
+ arrayBuffer: 'ArrayBuffer' in self
92862
+ };
93335
92863
 
93336
- // helper body for this light
93337
- _this.isUsingHelper = undefined;
93338
- // holder body representing the light
93339
- _this.holder = undefined;
93340
- // target body for the light (only used by directional light)
93341
- _this.target = undefined;
93342
- _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93343
- _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT);
93344
- Lights$1.add(_this);
93345
- return _this;
92864
+ function isDataView(obj) {
92865
+ return obj && DataView.prototype.isPrototypeOf(obj)
92866
+ }
92867
+
92868
+ if (support.arrayBuffer) {
92869
+ var viewClasses = [
92870
+ '[object Int8Array]',
92871
+ '[object Uint8Array]',
92872
+ '[object Uint8ClampedArray]',
92873
+ '[object Int16Array]',
92874
+ '[object Uint16Array]',
92875
+ '[object Int32Array]',
92876
+ '[object Uint32Array]',
92877
+ '[object Float32Array]',
92878
+ '[object Float64Array]'
92879
+ ];
92880
+
92881
+ var isArrayBufferView =
92882
+ ArrayBuffer.isView ||
92883
+ function(obj) {
92884
+ return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
92885
+ };
92886
+ }
92887
+
92888
+ function normalizeName(name) {
92889
+ if (typeof name !== 'string') {
92890
+ name = String(name);
93346
92891
  }
93347
- _inherits(Light, _Entity);
93348
- return _createClass(Light, [{
93349
- key: "addToScene",
93350
- value: function addToScene() {
93351
- if (this.hasBody()) {
93352
- Scene$1.add(this.body, this);
93353
- // When a new light is added to the scene, all materials need
93354
- // their shaders recompiled so THREE.js picks up the updated
93355
- // shadow-casting light count (NUM_DIR_LIGHT_SHADOWS, etc.).
93356
- Scene$1.updateChildren();
93357
- }
93358
- }
93359
- }, {
93360
- key: "usingHelper",
93361
- value: function usingHelper() {
93362
- return !!this.isUsingHelper;
92892
+ if (/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(name)) {
92893
+ throw new TypeError('Invalid character in header field name')
92894
+ }
92895
+ return name.toLowerCase()
92896
+ }
92897
+
92898
+ function normalizeValue(value) {
92899
+ if (typeof value !== 'string') {
92900
+ value = String(value);
92901
+ }
92902
+ return value
92903
+ }
92904
+
92905
+ // Build a destructive iterator for the value list
92906
+ function iteratorFor(items) {
92907
+ var iterator = {
92908
+ next: function() {
92909
+ var value = items.shift();
92910
+ return {done: value === undefined, value: value}
93363
92911
  }
93364
- }, {
93365
- key: "hasHolder",
93366
- value: function hasHolder() {
93367
- return !!this.holder;
92912
+ };
92913
+
92914
+ if (support.iterable) {
92915
+ iterator[Symbol.iterator] = function() {
92916
+ return iterator
92917
+ };
92918
+ }
92919
+
92920
+ return iterator
92921
+ }
92922
+
92923
+ function Headers(headers) {
92924
+ this.map = {};
92925
+
92926
+ if (headers instanceof Headers) {
92927
+ headers.forEach(function(value, name) {
92928
+ this.append(name, value);
92929
+ }, this);
92930
+ } else if (Array.isArray(headers)) {
92931
+ headers.forEach(function(header) {
92932
+ this.append(header[0], header[1]);
92933
+ }, this);
92934
+ } else if (headers) {
92935
+ Object.getOwnPropertyNames(headers).forEach(function(name) {
92936
+ this.append(name, headers[name]);
92937
+ }, this);
92938
+ }
92939
+ }
92940
+
92941
+ Headers.prototype.append = function(name, value) {
92942
+ name = normalizeName(name);
92943
+ value = normalizeValue(value);
92944
+ var oldValue = this.map[name];
92945
+ this.map[name] = oldValue ? oldValue + ', ' + value : value;
92946
+ };
92947
+
92948
+ Headers.prototype['delete'] = function(name) {
92949
+ delete this.map[normalizeName(name)];
92950
+ };
92951
+
92952
+ Headers.prototype.get = function(name) {
92953
+ name = normalizeName(name);
92954
+ return this.has(name) ? this.map[name] : null
92955
+ };
92956
+
92957
+ Headers.prototype.has = function(name) {
92958
+ return this.map.hasOwnProperty(normalizeName(name))
92959
+ };
92960
+
92961
+ Headers.prototype.set = function(name, value) {
92962
+ this.map[normalizeName(name)] = normalizeValue(value);
92963
+ };
92964
+
92965
+ Headers.prototype.forEach = function(callback, thisArg) {
92966
+ for (var name in this.map) {
92967
+ if (this.map.hasOwnProperty(name)) {
92968
+ callback.call(thisArg, this.map[name], name, this);
93368
92969
  }
93369
- }, {
93370
- key: "hasTarget",
93371
- value: function hasTarget() {
93372
- return false;
92970
+ }
92971
+ };
92972
+
92973
+ Headers.prototype.keys = function() {
92974
+ var items = [];
92975
+ this.forEach(function(value, name) {
92976
+ items.push(name);
92977
+ });
92978
+ return iteratorFor(items)
92979
+ };
92980
+
92981
+ Headers.prototype.values = function() {
92982
+ var items = [];
92983
+ this.forEach(function(value) {
92984
+ items.push(value);
92985
+ });
92986
+ return iteratorFor(items)
92987
+ };
92988
+
92989
+ Headers.prototype.entries = function() {
92990
+ var items = [];
92991
+ this.forEach(function(value, name) {
92992
+ items.push([name, value]);
92993
+ });
92994
+ return iteratorFor(items)
92995
+ };
92996
+
92997
+ if (support.iterable) {
92998
+ Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
92999
+ }
93000
+
93001
+ function consumed(body) {
93002
+ if (body.bodyUsed) {
93003
+ return Promise.reject(new TypeError('Already read'))
93004
+ }
93005
+ body.bodyUsed = true;
93006
+ }
93007
+
93008
+ function fileReaderReady(reader) {
93009
+ return new Promise(function(resolve, reject) {
93010
+ reader.onload = function() {
93011
+ resolve(reader.result);
93012
+ };
93013
+ reader.onerror = function() {
93014
+ reject(reader.error);
93015
+ };
93016
+ })
93017
+ }
93018
+
93019
+ function readBlobAsArrayBuffer(blob) {
93020
+ var reader = new FileReader();
93021
+ var promise = fileReaderReady(reader);
93022
+ reader.readAsArrayBuffer(blob);
93023
+ return promise
93024
+ }
93025
+
93026
+ function readBlobAsText(blob) {
93027
+ var reader = new FileReader();
93028
+ var promise = fileReaderReady(reader);
93029
+ reader.readAsText(blob);
93030
+ return promise
93031
+ }
93032
+
93033
+ function readArrayBufferAsText(buf) {
93034
+ var view = new Uint8Array(buf);
93035
+ var chars = new Array(view.length);
93036
+
93037
+ for (var i = 0; i < view.length; i++) {
93038
+ chars[i] = String.fromCharCode(view[i]);
93039
+ }
93040
+ return chars.join('')
93041
+ }
93042
+
93043
+ function bufferClone(buf) {
93044
+ if (buf.slice) {
93045
+ return buf.slice(0)
93046
+ } else {
93047
+ var view = new Uint8Array(buf.byteLength);
93048
+ view.set(new Uint8Array(buf));
93049
+ return view.buffer
93050
+ }
93051
+ }
93052
+
93053
+ function Body() {
93054
+ this.bodyUsed = false;
93055
+
93056
+ this._initBody = function(body) {
93057
+ this._bodyInit = body;
93058
+ if (!body) {
93059
+ this._bodyText = '';
93060
+ } else if (typeof body === 'string') {
93061
+ this._bodyText = body;
93062
+ } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
93063
+ this._bodyBlob = body;
93064
+ } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
93065
+ this._bodyFormData = body;
93066
+ } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
93067
+ this._bodyText = body.toString();
93068
+ } else if (support.arrayBuffer && support.blob && isDataView(body)) {
93069
+ this._bodyArrayBuffer = bufferClone(body.buffer);
93070
+ // IE 10-11 can't handle a DataView body.
93071
+ this._bodyInit = new Blob([this._bodyArrayBuffer]);
93072
+ } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
93073
+ this._bodyArrayBuffer = bufferClone(body);
93074
+ } else {
93075
+ this._bodyText = body = Object.prototype.toString.call(body);
93373
93076
  }
93374
- }, {
93375
- key: "getPosition",
93376
- value: function getPosition() {
93377
- return {
93378
- x: this.body.position.x,
93379
- y: this.body.position.y,
93380
- z: this.body.position.z
93381
- };
93077
+
93078
+ if (!this.headers.get('content-type')) {
93079
+ if (typeof body === 'string') {
93080
+ this.headers.set('content-type', 'text/plain;charset=UTF-8');
93081
+ } else if (this._bodyBlob && this._bodyBlob.type) {
93082
+ this.headers.set('content-type', this._bodyBlob.type);
93083
+ } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
93084
+ this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
93085
+ }
93086
+ }
93087
+ };
93088
+
93089
+ if (support.blob) {
93090
+ this.blob = function() {
93091
+ var rejected = consumed(this);
93092
+ if (rejected) {
93093
+ return rejected
93094
+ }
93095
+
93096
+ if (this._bodyBlob) {
93097
+ return Promise.resolve(this._bodyBlob)
93098
+ } else if (this._bodyArrayBuffer) {
93099
+ return Promise.resolve(new Blob([this._bodyArrayBuffer]))
93100
+ } else if (this._bodyFormData) {
93101
+ throw new Error('could not read FormData body as blob')
93102
+ } else {
93103
+ return Promise.resolve(new Blob([this._bodyText]))
93104
+ }
93105
+ };
93106
+
93107
+ this.arrayBuffer = function() {
93108
+ if (this._bodyArrayBuffer) {
93109
+ return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
93110
+ } else {
93111
+ return this.blob().then(readBlobAsArrayBuffer)
93112
+ }
93113
+ };
93114
+ }
93115
+
93116
+ this.text = function() {
93117
+ var rejected = consumed(this);
93118
+ if (rejected) {
93119
+ return rejected
93120
+ }
93121
+
93122
+ if (this._bodyBlob) {
93123
+ return readBlobAsText(this._bodyBlob)
93124
+ } else if (this._bodyArrayBuffer) {
93125
+ return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
93126
+ } else if (this._bodyFormData) {
93127
+ throw new Error('could not read FormData body as text')
93128
+ } else {
93129
+ return Promise.resolve(this._bodyText)
93130
+ }
93131
+ };
93132
+
93133
+ if (support.formData) {
93134
+ this.formData = function() {
93135
+ return this.text().then(decode)
93136
+ };
93137
+ }
93138
+
93139
+ this.json = function() {
93140
+ return this.text().then(JSON.parse)
93141
+ };
93142
+
93143
+ return this
93144
+ }
93145
+
93146
+ // HTTP methods whose capitalization should be normalized
93147
+ var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
93148
+
93149
+ function normalizeMethod(method) {
93150
+ var upcased = method.toUpperCase();
93151
+ return methods.indexOf(upcased) > -1 ? upcased : method
93152
+ }
93153
+
93154
+ function Request(input, options) {
93155
+ options = options || {};
93156
+ var body = options.body;
93157
+
93158
+ if (input instanceof Request) {
93159
+ if (input.bodyUsed) {
93160
+ throw new TypeError('Already read')
93161
+ }
93162
+ this.url = input.url;
93163
+ this.credentials = input.credentials;
93164
+ if (!options.headers) {
93165
+ this.headers = new Headers(input.headers);
93166
+ }
93167
+ this.method = input.method;
93168
+ this.mode = input.mode;
93169
+ this.signal = input.signal;
93170
+ if (!body && input._bodyInit != null) {
93171
+ body = input._bodyInit;
93172
+ input.bodyUsed = true;
93173
+ }
93174
+ } else {
93175
+ this.url = String(input);
93176
+ }
93177
+
93178
+ this.credentials = options.credentials || this.credentials || 'same-origin';
93179
+ if (options.headers || !this.headers) {
93180
+ this.headers = new Headers(options.headers);
93181
+ }
93182
+ this.method = normalizeMethod(options.method || this.method || 'GET');
93183
+ this.mode = options.mode || this.mode || null;
93184
+ this.signal = options.signal || this.signal;
93185
+ this.referrer = null;
93186
+
93187
+ if ((this.method === 'GET' || this.method === 'HEAD') && body) {
93188
+ throw new TypeError('Body not allowed for GET or HEAD requests')
93189
+ }
93190
+ this._initBody(body);
93191
+ }
93192
+
93193
+ Request.prototype.clone = function() {
93194
+ return new Request(this, {body: this._bodyInit})
93195
+ };
93196
+
93197
+ function decode(body) {
93198
+ var form = new FormData();
93199
+ body
93200
+ .trim()
93201
+ .split('&')
93202
+ .forEach(function(bytes) {
93203
+ if (bytes) {
93204
+ var split = bytes.split('=');
93205
+ var name = split.shift().replace(/\+/g, ' ');
93206
+ var value = split.join('=').replace(/\+/g, ' ');
93207
+ form.append(decodeURIComponent(name), decodeURIComponent(value));
93208
+ }
93209
+ });
93210
+ return form
93211
+ }
93212
+
93213
+ function parseHeaders(rawHeaders) {
93214
+ var headers = new Headers();
93215
+ // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
93216
+ // https://tools.ietf.org/html/rfc7230#section-3.2
93217
+ var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
93218
+ preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
93219
+ var parts = line.split(':');
93220
+ var key = parts.shift().trim();
93221
+ if (key) {
93222
+ var value = parts.join(':').trim();
93223
+ headers.append(key, value);
93224
+ }
93225
+ });
93226
+ return headers
93227
+ }
93228
+
93229
+ Body.call(Request.prototype);
93230
+
93231
+ function Response(bodyInit, options) {
93232
+ if (!options) {
93233
+ options = {};
93234
+ }
93235
+
93236
+ this.type = 'default';
93237
+ this.status = options.status === undefined ? 200 : options.status;
93238
+ this.ok = this.status >= 200 && this.status < 300;
93239
+ this.statusText = 'statusText' in options ? options.statusText : 'OK';
93240
+ this.headers = new Headers(options.headers);
93241
+ this.url = options.url || '';
93242
+ this._initBody(bodyInit);
93243
+ }
93244
+
93245
+ Body.call(Response.prototype);
93246
+
93247
+ Response.prototype.clone = function() {
93248
+ return new Response(this._bodyInit, {
93249
+ status: this.status,
93250
+ statusText: this.statusText,
93251
+ headers: new Headers(this.headers),
93252
+ url: this.url
93253
+ })
93254
+ };
93255
+
93256
+ Response.error = function() {
93257
+ var response = new Response(null, {status: 0, statusText: ''});
93258
+ response.type = 'error';
93259
+ return response
93260
+ };
93261
+
93262
+ var redirectStatuses = [301, 302, 303, 307, 308];
93263
+
93264
+ Response.redirect = function(url, status) {
93265
+ if (redirectStatuses.indexOf(status) === -1) {
93266
+ throw new RangeError('Invalid status code')
93267
+ }
93268
+
93269
+ return new Response(null, {status: status, headers: {location: url}})
93270
+ };
93271
+
93272
+ var DOMException = self.DOMException;
93273
+ try {
93274
+ new DOMException();
93275
+ } catch (err) {
93276
+ DOMException = function(message, name) {
93277
+ this.message = message;
93278
+ this.name = name;
93279
+ var error = Error(message);
93280
+ this.stack = error.stack;
93281
+ };
93282
+ DOMException.prototype = Object.create(Error.prototype);
93283
+ DOMException.prototype.constructor = DOMException;
93284
+ }
93285
+
93286
+ function fetch$1(input, init) {
93287
+ return new Promise(function(resolve, reject) {
93288
+ var request = new Request(input, init);
93289
+
93290
+ if (request.signal && request.signal.aborted) {
93291
+ return reject(new DOMException('Aborted', 'AbortError'))
93292
+ }
93293
+
93294
+ var xhr = new XMLHttpRequest();
93295
+
93296
+ function abortXhr() {
93297
+ xhr.abort();
93298
+ }
93299
+
93300
+ xhr.onload = function() {
93301
+ var options = {
93302
+ status: xhr.status,
93303
+ statusText: xhr.statusText,
93304
+ headers: parseHeaders(xhr.getAllResponseHeaders() || '')
93305
+ };
93306
+ options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
93307
+ var body = 'response' in xhr ? xhr.response : xhr.responseText;
93308
+ resolve(new Response(body, options));
93309
+ };
93310
+
93311
+ xhr.onerror = function() {
93312
+ reject(new TypeError('Network request failed'));
93313
+ };
93314
+
93315
+ xhr.ontimeout = function() {
93316
+ reject(new TypeError('Network request failed'));
93317
+ };
93318
+
93319
+ xhr.onabort = function() {
93320
+ reject(new DOMException('Aborted', 'AbortError'));
93321
+ };
93322
+
93323
+ xhr.open(request.method, request.url, true);
93324
+
93325
+ if (request.credentials === 'include') {
93326
+ xhr.withCredentials = true;
93327
+ } else if (request.credentials === 'omit') {
93328
+ xhr.withCredentials = false;
93329
+ }
93330
+
93331
+ if ('responseType' in xhr && support.blob) {
93332
+ xhr.responseType = 'blob';
93333
+ }
93334
+
93335
+ request.headers.forEach(function(value, name) {
93336
+ xhr.setRequestHeader(name, value);
93337
+ });
93338
+
93339
+ if (request.signal) {
93340
+ request.signal.addEventListener('abort', abortXhr);
93341
+
93342
+ xhr.onreadystatechange = function() {
93343
+ // DONE (success or failure)
93344
+ if (xhr.readyState === 4) {
93345
+ request.signal.removeEventListener('abort', abortXhr);
93346
+ }
93347
+ };
93348
+ }
93349
+
93350
+ xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
93351
+ })
93352
+ }
93353
+
93354
+ fetch$1.polyfill = true;
93355
+
93356
+ if (!self.fetch) {
93357
+ self.fetch = fetch$1;
93358
+ self.Headers = Headers;
93359
+ self.Request = Request;
93360
+ self.Response = Response;
93361
+ }let Light$1 = /*#__PURE__*/function (_Entity) {
93362
+ function Light({
93363
+ color,
93364
+ intensity,
93365
+ name: _name
93366
+ }) {
93367
+ var _this;
93368
+ _classCallCheck(this, Light);
93369
+ _this = _callSuper(this, Light, [{
93370
+ name: _name
93371
+ }]);
93372
+ _defineProperty$1(_this, "addHolder", (name = "lightholder", size = 0.05) => {
93373
+ const holderSprite = new HelperSprite(size, size, name, {
93374
+ name
93375
+ });
93376
+ if (holderSprite) {
93377
+ holderSprite.setSizeAttenuation(false);
93378
+ holderSprite.setDepthTest(false);
93379
+ holderSprite.setDepthWrite(false);
93380
+ holderSprite.setSerializable(false);
93381
+ holderSprite.setPosition(_this.getPosition());
93382
+ holderSprite.addTags([TAGS.HELPER, TAGS.LIGHTS.HELPER, TAGS.LIGHTS.HOLDER, name]);
93383
+ holderSprite.setHelperTarget(_this);
93384
+ _this.holder = holderSprite;
93385
+ return true;
93386
+ } else {
93387
+ console.warn(LIGHT_HOLDER_MODEL_NOT_FOUND);
93388
+ return false;
93389
+ }
93390
+ });
93391
+ _defineProperty$1(_this, "addTargetHolder", (name = "targetholder", size = 0.05) => {
93392
+ const targetSprite = new HelperSprite(size, size, name, {
93393
+ name
93394
+ });
93395
+ if (targetSprite) {
93396
+ targetSprite.setSizeAttenuation(false);
93397
+ targetSprite.setDepthTest(false);
93398
+ targetSprite.setDepthWrite(false);
93399
+ targetSprite.setSerializable(false);
93400
+ targetSprite.setPosition(_this.getTarget().getPosition());
93401
+ targetSprite.addTags([TAGS.LIGHTS.HELPER, TAGS.LIGHTS.TARGET, name]);
93402
+ targetSprite.setHelperTarget(_this);
93403
+ targetSprite.getBody().add(_this.getBody().target);
93404
+ _this.targetHolder = targetSprite;
93405
+ }
93406
+ });
93407
+ _this.color = color;
93408
+ _this.intensity = intensity;
93409
+ _this.name = _name || generateRandomName("Light");
93410
+ _this.isLightOn = false;
93411
+ _this.body = undefined;
93412
+
93413
+ // helper body for this light
93414
+ _this.isUsingHelper = undefined;
93415
+ // holder body representing the light
93416
+ _this.holder = undefined;
93417
+ // target body for the light (only used by directional light)
93418
+ _this.target = undefined;
93419
+ _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93420
+ _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT);
93421
+ Lights$1.add(_this);
93422
+ return _this;
93423
+ }
93424
+ _inherits(Light, _Entity);
93425
+ return _createClass(Light, [{
93426
+ key: "addToScene",
93427
+ value: function addToScene() {
93428
+ if (this.hasBody()) {
93429
+ Scene$1.add(this.body, this);
93430
+ // When a new light is added to the scene, all materials need
93431
+ // their shaders recompiled so THREE.js picks up the updated
93432
+ // shadow-casting light count (NUM_DIR_LIGHT_SHADOWS, etc.).
93433
+ Scene$1.updateChildren();
93434
+ }
93435
+ }
93436
+ }, {
93437
+ key: "usingHelper",
93438
+ value: function usingHelper() {
93439
+ return !!this.isUsingHelper;
93440
+ }
93441
+ }, {
93442
+ key: "hasHolder",
93443
+ value: function hasHolder() {
93444
+ return !!this.holder;
93445
+ }
93446
+ }, {
93447
+ key: "hasTarget",
93448
+ value: function hasTarget() {
93449
+ return false;
93450
+ }
93451
+ }, {
93452
+ key: "getPosition",
93453
+ value: function getPosition() {
93454
+ return {
93455
+ x: this.body.position.x,
93456
+ y: this.body.position.y,
93457
+ z: this.body.position.z
93458
+ };
93382
93459
  }
93383
93460
  }, {
93384
93461
  key: "setPosition",
@@ -93695,408 +93772,408 @@ let PointLight$1 = /*#__PURE__*/function (_Light) {
93695
93772
  this.isUsingHelper = true;
93696
93773
  }
93697
93774
  }, {
93698
- key: "update",
93699
- value: function update(dt) {
93700
- _superPropGet(PointLight, "update", this, 3)([dt]);
93701
- if (this.usingHelper()) {
93702
- this.helper.update();
93703
- this.shadowHelper.update();
93704
- }
93705
- if (this.hasHolder()) {
93706
- this.setPosition(this.holder.getPosition(), {
93707
- updateHolder: false
93708
- });
93709
- }
93710
- }
93711
- }, {
93712
- key: "toJSON",
93713
- value: function toJSON(parseJSON) {
93714
- return {
93715
- ..._superPropGet(PointLight, "toJSON", this, 3)([parseJSON]),
93716
- distance: this.getDistance(),
93717
- decay: this.getDecay(),
93718
- bias: this.getBias(),
93719
- mapSize: this.getMapSize(),
93720
- shadowCamera: this.getShadowCameraNearFar()
93721
- };
93722
- }
93723
- }], [{
93724
- key: "create",
93725
- value: function create(data = {}) {
93726
- const {
93727
- color,
93728
- intensity,
93729
- name,
93730
- position,
93731
- distance,
93732
- decay,
93733
- bias,
93734
- mapSize,
93735
- shadowCamera
93736
- } = data;
93737
- const {
93738
- near,
93739
- far
93740
- } = shadowCamera || {};
93741
- return new PointLight({
93742
- color,
93743
- intensity,
93744
- name,
93745
- position,
93746
- distance,
93747
- decay,
93748
- near,
93749
- far,
93750
- mapSize,
93751
- bias
93752
- });
93753
- }
93754
- }]);
93755
- }(Light$1);const DEFAULT_POSITION$6 = {
93756
- x: 0,
93757
- y: 0,
93758
- z: 0
93759
- };
93760
- const DEFAULT_INTENSITY$8 = 0.5;
93761
- const WHITE$6 = 0xffffff;
93762
- let AmbientLight$1 = /*#__PURE__*/function (_Light) {
93763
- function AmbientLight(options = {}) {
93764
- var _this;
93765
- _classCallCheck(this, AmbientLight);
93766
- const {
93767
- color = WHITE$6,
93768
- intensity = DEFAULT_INTENSITY$8,
93769
- name = generateRandomName("AmbientLight")
93770
- } = options;
93771
- _this = _callSuper(this, AmbientLight, [{
93772
- color,
93773
- intensity,
93774
- name
93775
- }]);
93776
- _this.options = options;
93777
- _this.setLight({
93778
- color,
93779
- intensity
93780
- });
93781
- _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93782
- _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT);
93783
- _this.setName(name);
93784
- return _this;
93785
- }
93786
- _inherits(AmbientLight, _Light);
93787
- return _createClass(AmbientLight, [{
93788
- key: "setLight",
93789
- value: function setLight({
93790
- light,
93791
- color = WHITE$6,
93792
- intensity = DEFAULT_INTENSITY$8
93793
- }) {
93794
- if (light) {
93795
- this.setBody({
93796
- body: light
93797
- });
93798
- } else {
93799
- this.setBody({
93800
- body: new AmbientLight$2(color, intensity)
93801
- });
93802
- }
93803
- if (this.hasBody()) {
93804
- this.postLightCreation();
93805
- }
93806
- }
93807
- }, {
93808
- key: "postLightCreation",
93809
- value: function postLightCreation() {
93810
- const {
93811
- position = DEFAULT_POSITION$6
93812
- } = this.options;
93813
- this.setPosition(position);
93814
- this.addToScene();
93815
- }
93816
- }, {
93817
- key: "addHelpers",
93818
- value: function addHelpers({
93819
- holderName = "ambientlightholder",
93820
- holderSize = 0.05
93821
- } = {}) {
93822
- this.addHolder(holderName, holderSize);
93823
- this.isUsingHelper = true;
93824
- }
93825
- }, {
93826
- key: "update",
93827
- value: function update(dt) {
93828
- _superPropGet(AmbientLight, "update", this, 3)([dt]);
93829
- if (this.usingHelper()) {
93830
- this.setPosition(this.holder.getPosition(), {
93831
- updateHolder: false
93832
- });
93833
- }
93834
- }
93835
- }], [{
93836
- key: "create",
93837
- value: function create(data = {}) {
93838
- const {
93839
- color,
93840
- intensity,
93841
- name,
93842
- position
93843
- } = data;
93844
- return new AmbientLight({
93845
- color,
93846
- intensity,
93847
- name,
93848
- position
93849
- });
93850
- }
93851
- }]);
93852
- }(Light$1);const DEFAULT_NEAR$4 = 0.1;
93853
- const DEFAULT_FAR$4 = 100;
93854
- const DEFAULT_POSITION$5 = {
93855
- x: 0,
93856
- y: 0,
93857
- z: 0
93858
- };
93859
- const DEFAULT_INTENSITY$7 = 0.5;
93860
- const DEFAULT_MAP_SIZE$4 = 2048;
93861
- const DEFAULT_BIAS$4 = -0.0001;
93862
- const WHITE$5 = 0xffffff;
93863
- const GREEN$4 = 0x2ecc71;
93864
- const DEFAULT_SPOTLIGHT_ANGLE$1 = 0.32;
93865
- const DEFAULT_SPOTLIGHT_PENUMBRA$1 = 0.5;
93866
- const DEFAULT_SPOTLIGHT_DECAY$1 = 2;
93867
- let SpotLight$1 = /*#__PURE__*/function (_Light) {
93868
- function SpotLight(options = {}) {
93869
- var _this;
93870
- _classCallCheck(this, SpotLight);
93871
- const {
93872
- color = WHITE$5,
93873
- intensity = DEFAULT_INTENSITY$7,
93874
- name = generateRandomName("SpotLight"),
93875
- distance = DEFAULT_FAR$4,
93876
- angle = DEFAULT_SPOTLIGHT_ANGLE$1,
93877
- penumbra = DEFAULT_SPOTLIGHT_PENUMBRA$1,
93878
- decay = DEFAULT_SPOTLIGHT_DECAY$1
93879
- } = options;
93880
- _this = _callSuper(this, SpotLight, [{
93881
- color,
93882
- intensity,
93883
- name
93884
- }]);
93885
- _defineProperty$1(_this, "setShadowCameraNearFar", (near = DEFAULT_NEAR$4, far = DEFAULT_FAR$4) => {
93886
- _this.near = near;
93887
- _this.far = far;
93888
- const d = _this.far / 2;
93889
- _this.getBody().shadow.camera.left = -d;
93890
- _this.getBody().shadow.camera.right = d;
93891
- _this.getBody().shadow.camera.top = d;
93892
- _this.getBody().shadow.camera.bottom = -d;
93893
- _this.getBody().shadow.camera.near = near;
93894
- _this.getBody().shadow.camera.far = far;
93895
- _this.getBody().shadow.camera.updateProjectionMatrix();
93896
- });
93897
- _defineProperty$1(_this, "setBias", (bias = DEFAULT_BIAS$4) => {
93898
- _this.bias = bias;
93899
- _this.getBody().shadow.bias = bias;
93900
- });
93901
- _this.options = options;
93902
- _this.setLight({
93903
- color,
93904
- intensity,
93905
- distance,
93906
- angle,
93907
- penumbra,
93908
- decay
93909
- });
93910
- _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93911
- _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.SPOT);
93912
- _this.setName(name);
93913
- return _this;
93914
- }
93915
- _inherits(SpotLight, _Light);
93916
- return _createClass(SpotLight, [{
93775
+ key: "update",
93776
+ value: function update(dt) {
93777
+ _superPropGet(PointLight, "update", this, 3)([dt]);
93778
+ if (this.usingHelper()) {
93779
+ this.helper.update();
93780
+ this.shadowHelper.update();
93781
+ }
93782
+ if (this.hasHolder()) {
93783
+ this.setPosition(this.holder.getPosition(), {
93784
+ updateHolder: false
93785
+ });
93786
+ }
93787
+ }
93788
+ }, {
93789
+ key: "toJSON",
93790
+ value: function toJSON(parseJSON) {
93791
+ return {
93792
+ ..._superPropGet(PointLight, "toJSON", this, 3)([parseJSON]),
93793
+ distance: this.getDistance(),
93794
+ decay: this.getDecay(),
93795
+ bias: this.getBias(),
93796
+ mapSize: this.getMapSize(),
93797
+ shadowCamera: this.getShadowCameraNearFar()
93798
+ };
93799
+ }
93800
+ }], [{
93801
+ key: "create",
93802
+ value: function create(data = {}) {
93803
+ const {
93804
+ color,
93805
+ intensity,
93806
+ name,
93807
+ position,
93808
+ distance,
93809
+ decay,
93810
+ bias,
93811
+ mapSize,
93812
+ shadowCamera
93813
+ } = data;
93814
+ const {
93815
+ near,
93816
+ far
93817
+ } = shadowCamera || {};
93818
+ return new PointLight({
93819
+ color,
93820
+ intensity,
93821
+ name,
93822
+ position,
93823
+ distance,
93824
+ decay,
93825
+ near,
93826
+ far,
93827
+ mapSize,
93828
+ bias
93829
+ });
93830
+ }
93831
+ }]);
93832
+ }(Light$1);const DEFAULT_POSITION$6 = {
93833
+ x: 0,
93834
+ y: 0,
93835
+ z: 0
93836
+ };
93837
+ const DEFAULT_INTENSITY$8 = 0.5;
93838
+ const WHITE$6 = 0xffffff;
93839
+ let AmbientLight$1 = /*#__PURE__*/function (_Light) {
93840
+ function AmbientLight(options = {}) {
93841
+ var _this;
93842
+ _classCallCheck(this, AmbientLight);
93843
+ const {
93844
+ color = WHITE$6,
93845
+ intensity = DEFAULT_INTENSITY$8,
93846
+ name = generateRandomName("AmbientLight")
93847
+ } = options;
93848
+ _this = _callSuper(this, AmbientLight, [{
93849
+ color,
93850
+ intensity,
93851
+ name
93852
+ }]);
93853
+ _this.options = options;
93854
+ _this.setLight({
93855
+ color,
93856
+ intensity
93857
+ });
93858
+ _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93859
+ _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT);
93860
+ _this.setName(name);
93861
+ return _this;
93862
+ }
93863
+ _inherits(AmbientLight, _Light);
93864
+ return _createClass(AmbientLight, [{
93865
+ key: "setLight",
93866
+ value: function setLight({
93867
+ light,
93868
+ color = WHITE$6,
93869
+ intensity = DEFAULT_INTENSITY$8
93870
+ }) {
93871
+ if (light) {
93872
+ this.setBody({
93873
+ body: light
93874
+ });
93875
+ } else {
93876
+ this.setBody({
93877
+ body: new AmbientLight$2(color, intensity)
93878
+ });
93879
+ }
93880
+ if (this.hasBody()) {
93881
+ this.postLightCreation();
93882
+ }
93883
+ }
93884
+ }, {
93885
+ key: "postLightCreation",
93886
+ value: function postLightCreation() {
93887
+ const {
93888
+ position = DEFAULT_POSITION$6
93889
+ } = this.options;
93890
+ this.setPosition(position);
93891
+ this.addToScene();
93892
+ }
93893
+ }, {
93894
+ key: "addHelpers",
93895
+ value: function addHelpers({
93896
+ holderName = "ambientlightholder",
93897
+ holderSize = 0.05
93898
+ } = {}) {
93899
+ this.addHolder(holderName, holderSize);
93900
+ this.isUsingHelper = true;
93901
+ }
93902
+ }, {
93903
+ key: "update",
93904
+ value: function update(dt) {
93905
+ _superPropGet(AmbientLight, "update", this, 3)([dt]);
93906
+ if (this.usingHelper()) {
93907
+ this.setPosition(this.holder.getPosition(), {
93908
+ updateHolder: false
93909
+ });
93910
+ }
93911
+ }
93912
+ }], [{
93913
+ key: "create",
93914
+ value: function create(data = {}) {
93915
+ const {
93916
+ color,
93917
+ intensity,
93918
+ name,
93919
+ position
93920
+ } = data;
93921
+ return new AmbientLight({
93922
+ color,
93923
+ intensity,
93924
+ name,
93925
+ position
93926
+ });
93927
+ }
93928
+ }]);
93929
+ }(Light$1);const DEFAULT_NEAR$4 = 0.1;
93930
+ const DEFAULT_FAR$4 = 100;
93931
+ const DEFAULT_POSITION$5 = {
93932
+ x: 0,
93933
+ y: 0,
93934
+ z: 0
93935
+ };
93936
+ const DEFAULT_INTENSITY$7 = 0.5;
93937
+ const DEFAULT_MAP_SIZE$4 = 2048;
93938
+ const DEFAULT_BIAS$4 = -0.0001;
93939
+ const WHITE$5 = 0xffffff;
93940
+ const GREEN$4 = 0x2ecc71;
93941
+ const DEFAULT_SPOTLIGHT_ANGLE$1 = 0.32;
93942
+ const DEFAULT_SPOTLIGHT_PENUMBRA$1 = 0.5;
93943
+ const DEFAULT_SPOTLIGHT_DECAY$1 = 2;
93944
+ let SpotLight$1 = /*#__PURE__*/function (_Light) {
93945
+ function SpotLight(options = {}) {
93946
+ var _this;
93947
+ _classCallCheck(this, SpotLight);
93948
+ const {
93949
+ color = WHITE$5,
93950
+ intensity = DEFAULT_INTENSITY$7,
93951
+ name = generateRandomName("SpotLight"),
93952
+ distance = DEFAULT_FAR$4,
93953
+ angle = DEFAULT_SPOTLIGHT_ANGLE$1,
93954
+ penumbra = DEFAULT_SPOTLIGHT_PENUMBRA$1,
93955
+ decay = DEFAULT_SPOTLIGHT_DECAY$1
93956
+ } = options;
93957
+ _this = _callSuper(this, SpotLight, [{
93958
+ color,
93959
+ intensity,
93960
+ name
93961
+ }]);
93962
+ _defineProperty$1(_this, "setShadowCameraNearFar", (near = DEFAULT_NEAR$4, far = DEFAULT_FAR$4) => {
93963
+ _this.near = near;
93964
+ _this.far = far;
93965
+ const d = _this.far / 2;
93966
+ _this.getBody().shadow.camera.left = -d;
93967
+ _this.getBody().shadow.camera.right = d;
93968
+ _this.getBody().shadow.camera.top = d;
93969
+ _this.getBody().shadow.camera.bottom = -d;
93970
+ _this.getBody().shadow.camera.near = near;
93971
+ _this.getBody().shadow.camera.far = far;
93972
+ _this.getBody().shadow.camera.updateProjectionMatrix();
93973
+ });
93974
+ _defineProperty$1(_this, "setBias", (bias = DEFAULT_BIAS$4) => {
93975
+ _this.bias = bias;
93976
+ _this.getBody().shadow.bias = bias;
93977
+ });
93978
+ _this.options = options;
93979
+ _this.setLight({
93980
+ color,
93981
+ intensity,
93982
+ distance,
93983
+ angle,
93984
+ penumbra,
93985
+ decay
93986
+ });
93987
+ _this.setEntityType(ENTITY_TYPES.LIGHT.TYPE);
93988
+ _this.setEntitySubtype(ENTITY_TYPES.LIGHT.SUBTYPES.SPOT);
93989
+ _this.setName(name);
93990
+ return _this;
93991
+ }
93992
+ _inherits(SpotLight, _Light);
93993
+ return _createClass(SpotLight, [{
93994
+ key: "setLight",
93995
+ value: function setLight({
93996
+ light,
93997
+ color = WHITE$5,
93998
+ intensity = DEFAULT_INTENSITY$7,
93999
+ distance,
94000
+ angle,
94001
+ penumbra,
94002
+ decay
94003
+ }) {
94004
+ if (light) {
94005
+ this.setBody({
94006
+ body: light
94007
+ });
94008
+ } else {
94009
+ this.setBody({
94010
+ body: new SpotLight$2(color, intensity)
94011
+ });
94012
+ this.setDistance(distance);
94013
+ this.setAngle(angle);
94014
+ this.setPenumbra(penumbra);
94015
+ this.setDecay(decay);
94016
+ }
94017
+ if (this.hasBody()) {
94018
+ this.postLightCreation();
94019
+ }
94020
+ }
94021
+ }, {
94022
+ key: "postLightCreation",
94023
+ value: function postLightCreation() {
94024
+ const {
94025
+ position = DEFAULT_POSITION$5
94026
+ } = this.options;
94027
+ const emptyTarget = new Element$1({
94028
+ body: new Object3D()
94029
+ });
94030
+ emptyTarget.setEntitySubtype(ENTITY_TYPES.MESH.SUBTYPES.TARGET);
94031
+ this.setPosition(position);
94032
+ this.setTarget(emptyTarget);
94033
+ this.setLightShadows();
94034
+ this.addToScene();
94035
+ }
94036
+ }, {
94037
+ key: "setLightShadows",
94038
+ value: function setLightShadows() {
94039
+ const {
94040
+ near = DEFAULT_NEAR$4,
94041
+ far = DEFAULT_FAR$4,
94042
+ mapSize = DEFAULT_MAP_SIZE$4,
94043
+ bias = DEFAULT_BIAS$4
94044
+ } = this.options;
94045
+ if (Config$1.lights().shadows) {
94046
+ this.setCastShadow(true);
94047
+ this.setMapSize(mapSize);
94048
+ this.setShadowCameraNearFar(near, far);
94049
+ this.setBias(bias);
94050
+ }
94051
+ }
94052
+ }, {
94053
+ key: "setDistance",
94054
+ value: function setDistance(distance = DEFAULT_FAR$4) {
94055
+ this.distance = distance;
94056
+ this.getBody().distance = distance;
94057
+ }
94058
+ }, {
94059
+ key: "getDistance",
94060
+ value: function getDistance() {
94061
+ return this.distance;
94062
+ }
94063
+ }, {
94064
+ key: "setAngle",
94065
+ value: function setAngle(angle = DEFAULT_SPOTLIGHT_ANGLE$1) {
94066
+ this.angle = angle;
94067
+ this.getBody().angle = angle;
94068
+ }
94069
+ }, {
94070
+ key: "getAngle",
94071
+ value: function getAngle() {
94072
+ return this.angle;
94073
+ }
94074
+ }, {
94075
+ key: "setPenumbra",
94076
+ value: function setPenumbra(penumbra = DEFAULT_SPOTLIGHT_PENUMBRA$1) {
94077
+ this.penumbra = penumbra;
94078
+ this.getBody().penumbra = penumbra;
94079
+ }
94080
+ }, {
94081
+ key: "getPenumbra",
94082
+ value: function getPenumbra() {
94083
+ return this.penumbra;
94084
+ }
94085
+ }, {
94086
+ key: "setDecay",
94087
+ value: function setDecay(decay = DEFAULT_SPOTLIGHT_DECAY$1) {
94088
+ this.decay = decay;
94089
+ this.getBody().decay = decay;
94090
+ }
94091
+ }, {
94092
+ key: "getDecay",
94093
+ value: function getDecay() {
94094
+ return this.decay;
94095
+ }
94096
+ }, {
94097
+ key: "getShadowCameraNearFar",
94098
+ value: function getShadowCameraNearFar() {
94099
+ return {
94100
+ near: this.near,
94101
+ far: this.far
94102
+ };
94103
+ }
94104
+ }, {
94105
+ key: "setMapSize",
94106
+ value: function setMapSize(mapSize = DEFAULT_MAP_SIZE$4) {
94107
+ this.mapSize = mapSize;
94108
+ this.getBody().shadow.mapSize.height = mapSize;
94109
+ this.getBody().shadow.mapSize.width = mapSize;
94110
+ }
94111
+ }, {
94112
+ key: "getMapSize",
94113
+ value: function getMapSize() {
94114
+ return this.mapSize;
94115
+ }
94116
+ }, {
94117
+ key: "getBias",
94118
+ value: function getBias() {
94119
+ return this.bias;
94120
+ }
94121
+ }, {
94122
+ key: "setTarget",
94123
+ value: function setTarget(target) {
94124
+ this.target = target;
94125
+ this.getBody().target = target.getBody();
94126
+ Scene$1.add(this.getBody().target, null, false);
94127
+ }
94128
+ }, {
94129
+ key: "getTarget",
94130
+ value: function getTarget() {
94131
+ return this.target;
94132
+ }
94133
+ }, {
94134
+ key: "addHelpers",
94135
+ value: function addHelpers({
94136
+ holderName = "spotlightholder",
94137
+ holderSize = 0.05,
94138
+ targetHolderName = "targetholder",
94139
+ targetHolderSize = 0.05
94140
+ } = {}) {
94141
+ this.helper = new SpotLightHelper(this.getBody(), GREEN$4);
94142
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
94143
+
94144
+ // Set to layer 1 ONLY so mirrors don't render light helpers
94145
+ // Disable depth test so helpers always render on top of sky/water
94146
+ const setMaterialDepth = material => {
94147
+ if (!material) return;
94148
+ const mats = Array.isArray(material) ? material : [material];
94149
+ mats.forEach(mat => {
94150
+ mat.depthTest = false;
94151
+ mat.depthWrite = false;
94152
+ mat.transparent = true;
94153
+ mat.needsUpdate = true;
94154
+ });
94155
+ };
94156
+ [this.helper, this.shadowHelper].forEach(helper => {
94157
+ helper.layers.set(1);
94158
+ helper.renderOrder = 999;
94159
+ setMaterialDepth(helper.material);
94160
+ helper.traverse(child => {
94161
+ child.layers.set(1);
94162
+ child.renderOrder = 999;
94163
+ setMaterialDepth(child.material);
94164
+ });
94165
+ });
94166
+ Scene$1.add(this.helper, null, false);
94167
+ Scene$1.add(this.shadowHelper, null, false);
94168
+ this.addHolder(holderName, holderSize);
94169
+ this.addTargetHolder(targetHolderName, targetHolderSize);
94170
+ this.isUsingHelper = true;
94171
+ }
94172
+ }, {
93917
94173
  key: "hasTarget",
93918
94174
  value: function hasTarget() {
93919
94175
  return !!this.target;
93920
94176
  }
93921
- }, {
93922
- key: "setLight",
93923
- value: function setLight({
93924
- light,
93925
- color = WHITE$5,
93926
- intensity = DEFAULT_INTENSITY$7,
93927
- distance,
93928
- angle,
93929
- penumbra,
93930
- decay
93931
- }) {
93932
- if (light) {
93933
- this.setBody({
93934
- body: light
93935
- });
93936
- } else {
93937
- this.setBody({
93938
- body: new SpotLight$2(color, intensity)
93939
- });
93940
- this.setDistance(distance);
93941
- this.setAngle(angle);
93942
- this.setPenumbra(penumbra);
93943
- this.setDecay(decay);
93944
- }
93945
- if (this.hasBody()) {
93946
- this.postLightCreation();
93947
- }
93948
- }
93949
- }, {
93950
- key: "postLightCreation",
93951
- value: function postLightCreation() {
93952
- const {
93953
- position = DEFAULT_POSITION$5
93954
- } = this.options;
93955
- const emptyTarget = new Element$1({
93956
- body: new Object3D()
93957
- });
93958
- emptyTarget.setEntitySubtype(ENTITY_TYPES.MESH.SUBTYPES.TARGET);
93959
- this.setPosition(position);
93960
- this.setTarget(emptyTarget);
93961
- this.setLightShadows();
93962
- this.addToScene();
93963
- }
93964
- }, {
93965
- key: "setLightShadows",
93966
- value: function setLightShadows() {
93967
- const {
93968
- near = DEFAULT_NEAR$4,
93969
- far = DEFAULT_FAR$4,
93970
- mapSize = DEFAULT_MAP_SIZE$4,
93971
- bias = DEFAULT_BIAS$4
93972
- } = this.options;
93973
- if (Config$1.lights().shadows) {
93974
- this.setCastShadow(true);
93975
- this.setMapSize(mapSize);
93976
- this.setShadowCameraNearFar(near, far);
93977
- this.setBias(bias);
93978
- }
93979
- }
93980
- }, {
93981
- key: "setDistance",
93982
- value: function setDistance(distance = DEFAULT_FAR$4) {
93983
- this.distance = distance;
93984
- this.getBody().distance = distance;
93985
- }
93986
- }, {
93987
- key: "getDistance",
93988
- value: function getDistance() {
93989
- return this.distance;
93990
- }
93991
- }, {
93992
- key: "setAngle",
93993
- value: function setAngle(angle = DEFAULT_SPOTLIGHT_ANGLE$1) {
93994
- this.angle = angle;
93995
- this.getBody().angle = angle;
93996
- }
93997
- }, {
93998
- key: "getAngle",
93999
- value: function getAngle() {
94000
- return this.angle;
94001
- }
94002
- }, {
94003
- key: "setPenumbra",
94004
- value: function setPenumbra(penumbra = DEFAULT_SPOTLIGHT_PENUMBRA$1) {
94005
- this.penumbra = penumbra;
94006
- this.getBody().penumbra = penumbra;
94007
- }
94008
- }, {
94009
- key: "getPenumbra",
94010
- value: function getPenumbra() {
94011
- return this.penumbra;
94012
- }
94013
- }, {
94014
- key: "setDecay",
94015
- value: function setDecay(decay = DEFAULT_SPOTLIGHT_DECAY$1) {
94016
- this.decay = decay;
94017
- this.getBody().decay = decay;
94018
- }
94019
- }, {
94020
- key: "getDecay",
94021
- value: function getDecay() {
94022
- return this.decay;
94023
- }
94024
- }, {
94025
- key: "getShadowCameraNearFar",
94026
- value: function getShadowCameraNearFar() {
94027
- return {
94028
- near: this.near,
94029
- far: this.far
94030
- };
94031
- }
94032
- }, {
94033
- key: "setMapSize",
94034
- value: function setMapSize(mapSize = DEFAULT_MAP_SIZE$4) {
94035
- this.mapSize = mapSize;
94036
- this.getBody().shadow.mapSize.height = mapSize;
94037
- this.getBody().shadow.mapSize.width = mapSize;
94038
- }
94039
- }, {
94040
- key: "getMapSize",
94041
- value: function getMapSize() {
94042
- return this.mapSize;
94043
- }
94044
- }, {
94045
- key: "getBias",
94046
- value: function getBias() {
94047
- return this.bias;
94048
- }
94049
- }, {
94050
- key: "setTarget",
94051
- value: function setTarget(target) {
94052
- this.target = target;
94053
- this.getBody().target = target.getBody();
94054
- Scene$1.add(this.getBody().target, null, false);
94055
- }
94056
- }, {
94057
- key: "getTarget",
94058
- value: function getTarget() {
94059
- return this.target;
94060
- }
94061
- }, {
94062
- key: "addHelpers",
94063
- value: function addHelpers({
94064
- holderName = "spotlightholder",
94065
- holderSize = 0.05,
94066
- targetHolderName = "targetholder",
94067
- targetHolderSize = 0.05
94068
- } = {}) {
94069
- this.helper = new SpotLightHelper(this.getBody(), GREEN$4);
94070
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
94071
-
94072
- // Set to layer 1 ONLY so mirrors don't render light helpers
94073
- // Disable depth test so helpers always render on top of sky/water
94074
- const setMaterialDepth = material => {
94075
- if (!material) return;
94076
- const mats = Array.isArray(material) ? material : [material];
94077
- mats.forEach(mat => {
94078
- mat.depthTest = false;
94079
- mat.depthWrite = false;
94080
- mat.transparent = true;
94081
- mat.needsUpdate = true;
94082
- });
94083
- };
94084
- [this.helper, this.shadowHelper].forEach(helper => {
94085
- helper.layers.set(1);
94086
- helper.renderOrder = 999;
94087
- setMaterialDepth(helper.material);
94088
- helper.traverse(child => {
94089
- child.layers.set(1);
94090
- child.renderOrder = 999;
94091
- setMaterialDepth(child.material);
94092
- });
94093
- });
94094
- Scene$1.add(this.helper, null, false);
94095
- Scene$1.add(this.shadowHelper, null, false);
94096
- this.addHolder(holderName, holderSize);
94097
- this.addTargetHolder(targetHolderName, targetHolderSize);
94098
- this.isUsingHelper = true;
94099
- }
94100
94177
  }, {
94101
94178
  key: "update",
94102
94179
  value: function update(dt) {
@@ -96372,7 +96449,7 @@ let Importer = /*#__PURE__*/function () {
96372
96449
  try {
96373
96450
  // Pass the relative assetPath - resolveAssetPath in Images will add the base URL
96374
96451
  await Images$1.loadAssetByPath(assetPath, id, Images$1.currentLevel);
96375
- } catch (e) {
96452
+ } catch {
96376
96453
  console.warn(`[Mage] Failed to load texture: ${id} from ${assetPath}`);
96377
96454
  }
96378
96455
  }
@@ -97018,7 +97095,7 @@ let Importer = /*#__PURE__*/function () {
97018
97095
  this.store[path] = Level;
97019
97096
  }
97020
97097
  return true;
97021
- } catch (e) {
97098
+ } catch {
97022
97099
  return false;
97023
97100
  }
97024
97101
  }
@@ -98065,9 +98142,9 @@ const getSphereHitbox = element => {
98065
98142
  sphere.setWireframeLineWidth(2);
98066
98143
  return sphere;
98067
98144
  };
98068
- const mapColliderTypeToHitbox = (colliderType = COLLIDER_TYPES$1.BOX) => ({
98069
- [COLLIDER_TYPES$1.BOX]: getBoxHitbox,
98070
- [COLLIDER_TYPES$1.SPHERE]: getSphereHitbox
98145
+ const mapColliderTypeToHitbox = (colliderType = COLLIDER_TYPES$2.BOX) => ({
98146
+ [COLLIDER_TYPES$2.BOX]: getBoxHitbox,
98147
+ [COLLIDER_TYPES$2.SPHERE]: getSphereHitbox
98071
98148
  })[colliderType] || getBoxHitbox;
98072
98149
  const addHitBox = element => {
98073
98150
  const colliderType = element.getPhysicsOptions("colliderType");
@@ -98768,11 +98845,6 @@ let SpotLight = /*#__PURE__*/function (_Light) {
98768
98845
  }
98769
98846
  _inherits(SpotLight, _Light);
98770
98847
  return _createClass(SpotLight, [{
98771
- key: "hasTarget",
98772
- value: function hasTarget() {
98773
- return !!this.target;
98774
- }
98775
- }, {
98776
98848
  key: "setLight",
98777
98849
  value: function setLight({
98778
98850
  light,
@@ -98951,6 +99023,11 @@ let SpotLight = /*#__PURE__*/function (_Light) {
98951
99023
  this.addTargetHolder(targetHolderName, targetHolderSize);
98952
99024
  this.isUsingHelper = true;
98953
99025
  }
99026
+ }, {
99027
+ key: "hasTarget",
99028
+ value: function hasTarget() {
99029
+ return !!this.target;
99030
+ }
98954
99031
  }, {
98955
99032
  key: "update",
98956
99033
  value: function update(dt) {