Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 06 Nov 2014 13:53:27 +0100
changeset 214389 e25127d1ad196c638af12c5dfbca9bb43babe939
parent 214388 7ebb820f3cca0d8c11c56f54c9e5e4a26b55cdec (current diff)
parent 214319 0c66a9fd9085a228b1e8b248e083892ce58bd69f (diff)
child 214390 b1e482f69d96d2ca59e627eeb101d2f284efecb2
push id27780
push userkwierso@gmail.com
push dateFri, 07 Nov 2014 02:25:05 +0000
treeherdermozilla-central@e6d47abb6a7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
addon-sdk/source/lib/sdk/util/iteration.js
browser/modules/SharedFrame.jsm
browser/modules/test/chrome/chrome.ini
browser/modules/test/chrome/sharedframe.xul
browser/modules/test/chrome/test_sharedframe.xul
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -167,16 +167,17 @@ EXTRA_JS_MODULES.commonjs.diffpatcher.te
     'source/lib/diffpatcher/test/diff.js',
     'source/lib/diffpatcher/test/index.js',
     'source/lib/diffpatcher/test/patch.js',
     'source/lib/diffpatcher/test/tap.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.framescript += [
     'source/lib/framescript/FrameScriptManager.jsm',
+    'source/lib/framescript/LoaderHelper.jsm',
     'source/lib/framescript/tab-events.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.method += [
     'source/lib/method/core.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.node += [
@@ -235,16 +236,18 @@ EXTRA_JS_MODULES.commonjs.sdk.content +=
     'source/lib/sdk/content/content-worker.js',
     'source/lib/sdk/content/content.js',
     'source/lib/sdk/content/events.js',
     'source/lib/sdk/content/loader.js',
     'source/lib/sdk/content/mod.js',
     'source/lib/sdk/content/sandbox.js',
     'source/lib/sdk/content/thumbnail.js',
     'source/lib/sdk/content/utils.js',
+    'source/lib/sdk/content/worker-child.js',
+    'source/lib/sdk/content/worker-parent.js',
     'source/lib/sdk/content/worker.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.core += [
     'source/lib/sdk/core/disposable.js',
     'source/lib/sdk/core/heritage.js',
     'source/lib/sdk/core/namespace.js',
     'source/lib/sdk/core/observer.js',
@@ -424,17 +427,16 @@ EXTRA_JS_MODULES.commonjs.sdk.url += [
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.util += [
     'source/lib/sdk/util/array.js',
     'source/lib/sdk/util/collection.js',
     'source/lib/sdk/util/contract.js',
     'source/lib/sdk/util/deprecate.js',
     'source/lib/sdk/util/dispatcher.js',
-    'source/lib/sdk/util/iteration.js',
     'source/lib/sdk/util/list.js',
     'source/lib/sdk/util/match-pattern.js',
     'source/lib/sdk/util/object.js',
     'source/lib/sdk/util/registry.js',
     'source/lib/sdk/util/rules.js',
     'source/lib/sdk/util/sequence.js',
     'source/lib/sdk/util/uuid.js',
 ]
@@ -448,9 +450,10 @@ EXTRA_JS_MODULES.commonjs.sdk.worker += 
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.zip += [
     'source/lib/sdk/zip/utils.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.toolkit += [
     'source/lib/toolkit/loader.js',
+    'source/lib/toolkit/require.js',
 ]
--- a/addon-sdk/source/lib/dev/volcan.js
+++ b/addon-sdk/source/lib/dev/volcan.js
@@ -40,16 +40,17 @@ exports.Class = Class;
 
 },{}],4:[function(_dereq_,module,exports){
 "use strict";
 
 var Class = _dereq_("./class").Class;
 var TypeSystem = _dereq_("./type-system").TypeSystem;
 var values = _dereq_("./util").values;
 var Promise = _dereq_("es6-promise").Promise;
+var MessageEvent = _dereq_("./event").MessageEvent;
 
 var specification = _dereq_("./specification/core.json");
 
 function recoverActorDescriptions(error) {
   console.warn("Failed to fetch protocol specification (see reason below). " +
                "Using a fallback protocal specification!",
                error);
   return _dereq_("./specification/protocol.json");
@@ -131,17 +132,20 @@ var Client = Class({
           .protocolDescription()
           .catch(recoverActorDescriptions)
           .then(this.typeSystem.registerTypes.bind(this.typeSystem))
           .then(this.onReady.bind(this, this.root), this.onFail);
     } else {
       var actor = this.get(packet.from) || this.root;
       var event = actor.events[packet.type];
       if (event) {
-        actor.dispatchEvent(event.read(packet));
+        var message = new MessageEvent(packet.type, {
+          data: event.read(packet)
+        });
+        actor.dispatchEvent(message);
       } else {
         var index = this.requests.indexOf(actor.id);
         if (index >= 0) {
           var request = this.requests.splice(index, 2).pop();
           if (packet.error)
             request.reject(packet);
           else
             request.resolve(packet);
@@ -202,22 +206,22 @@ var Client = Class({
     if (supervisor)
       this.unsupervise(supervisor, actor);
 
     var workers = this.workersOf(actor)
 
     if (workers) {
       workers.map(this.get).forEach(this.release)
     }
-    this.unergister(actor);
+    this.unregister(actor);
   }
 });
 exports.Client = Client;
 
-},{"./class":3,"./specification/core.json":23,"./specification/protocol.json":24,"./type-system":25,"./util":26,"es6-promise":2}],5:[function(_dereq_,module,exports){
+},{"./class":3,"./event":5,"./specification/core.json":23,"./specification/protocol.json":24,"./type-system":25,"./util":26,"es6-promise":2}],5:[function(_dereq_,module,exports){
 "use strict";
 
 var Symbol = _dereq_("es6-symbol")
 var EventEmitter = _dereq_("events").EventEmitter;
 var Class = _dereq_("./class").Class;
 
 var $bound = Symbol("EventTarget/handleEvent");
 var $emitter = Symbol("EventTarget/emitter");
@@ -424,17 +428,20 @@ EventEmitter.prototype.addListener = fun
     }
 
     if (m && m > 0 && this._events[type].length > m) {
       this._events[type].warned = true;
       console.error('(node) warning: possible EventEmitter memory ' +
                     'leak detected. %d listeners added. ' +
                     'Use emitter.setMaxListeners() to increase limit.',
                     this._events[type].length);
-      console.trace();
+      if (typeof console.trace === 'function') {
+        // not supported in IE 10
+        console.trace();
+      }
     }
   }
 
   return this;
 };
 
 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
 
@@ -932,17 +939,94 @@ module.exports={
         "gcliActor": "gcli",
         "memoryActor": "memory",
         "eventLoopLag": "eventLoopLag",
         "styleSheetsActor": "stylesheets",
         "styleEditorActor": "styleeditor",
 
         "consoleActor": "console",
         "traceActor": "trace"
+      },
+      "methods": [
+         {
+          "name": "attach",
+          "request": {},
+          "response": { "_retval": "json" }
+         }
+      ],
+      "events": {
+        "tabNavigated": {
+           "typeName": "tabNavigated"
+        }
       }
+    },
+    "console": {
+      "category": "actor",
+      "typeName": "console",
+      "methods": [
+        {
+          "name": "evaluateJS",
+          "request": {
+            "text": {
+              "_option": 0,
+              "type": "string"
+            },
+            "url": {
+              "_option": 1,
+              "type": "string"
+            },
+            "bindObjectActor": {
+              "_option": 2,
+              "type": "nullable:string"
+            },
+            "frameActor": {
+              "_option": 2,
+              "type": "nullable:string"
+            },
+            "selectedNodeActor": {
+              "_option": 2,
+              "type": "nullable:string"
+            }
+          },
+          "response": {
+            "_retval": "evaluatejsresponse"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "evaluatejsresponse": {
+      "category": "dict",
+      "typeName": "evaluatejsresponse",
+      "specializations": {
+        "result": "object",
+        "exception": "object",
+        "exceptionMessage": "string",
+        "input": "string"
+      }
+    },
+    "object": {
+      "category": "actor",
+      "typeName": "object",
+      "methods": [
+         {
+           "name": "property",
+           "request": {
+              "name": {
+                "_arg": 0,
+                "type": "string"
+              }
+           },
+           "response": {
+              "descriptor": {
+                "_retval": "json"
+              }
+           }
+         }
+      ]
     }
   }
 }
 
 },{}],24:[function(_dereq_,module,exports){
 module.exports={
   "types": {
     "longstractor": {
@@ -3750,11 +3834,11 @@ var findPath = function(object, key) {
       }
     }
   }
   return path;
 };
 exports.findPath = findPath;
 
 },{}]},{},[1])
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vYnJvd3Nlci9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2Jyb3dzZXIvcHJvbWlzZS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2NsYXNzLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vY2xpZW50LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vZXZlbnQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL2luZGV4LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvaXMtaW1wbGVtZW50ZWQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZC9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9hc3NpZ24vaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvYXNzaWduL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2Fzc2lnbi9zaGltLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2lzLWNhbGxhYmxlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2tleXMvaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qva2V5cy9pcy1pbXBsZW1lbnRlZC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9rZXlzL3NoaW0uanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qvbm9ybWFsaXplLW9wdGlvbnMuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvdmFsaWQtdmFsdWUuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9zdHJpbmcvIy9jb250YWlucy9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L3N0cmluZy8jL2NvbnRhaW5zL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvc3RyaW5nLyMvY29udGFpbnMvc2hpbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL3BvbHlmaWxsLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vc3BlY2lmaWNhdGlvbi9jb3JlLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9zcGVjaWZpY2F0aW9uL3Byb3RvY29sLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi90eXBlLXN5c3RlbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL3V0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1U0E7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsaWVudCA9IHJlcXVpcmUoXCIuLi9jbGllbnRcIikuQ2xpZW50O1xuXG5mdW5jdGlvbiBjb25uZWN0KHBvcnQpIHtcbiAgdmFyIGNsaWVudCA9IG5ldyBDbGllbnQoKTtcbiAgcmV0dXJuIGNsaWVudC5jb25uZWN0KHBvcnQpO1xufVxuZXhwb3J0cy5jb25uZWN0ID0gY29ubmVjdDtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5leHBvcnRzLlByb21pc2UgPSBQcm9taXNlO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBkZXNjcmliZSA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7XG52YXIgQ2xhc3MgPSBmdW5jdGlvbihmaWVsZHMpIHtcbiAgdmFyIG5hbWVzID0gT2JqZWN0LmtleXMoZmllbGRzKTtcbiAgdmFyIGNvbnN0cnVjdG9yID0gbmFtZXMuaW5kZXhPZihcImNvbnN0cnVjdG9yXCIpID49IDAgPyBmaWVsZHMuY29uc3RydWN0b3IgOlxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHt9O1xuICB2YXIgYW5jZXN0b3IgPSBmaWVsZHMuZXh0ZW5kcyB8fCBPYmplY3Q7XG5cbiAgdmFyIGRlc2NyaXB0b3IgPSBuYW1lcy5yZWR1Y2UoZnVuY3Rpb24oZGVzY3JpcHRvciwga2V5KSB7XG4gICAgZGVzY3JpcHRvcltrZXldID0gZGVzY3JpYmUoZmllbGRzLCBrZXkpO1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9LCB7fSk7XG5cbiAgdmFyIHByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYW5jZXN0b3IucHJvdG90eXBlLCBkZXNjcmlwdG9yKTtcblxuICBjb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gIHByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IGNvbnN0cnVjdG9yO1xuXG4gIHJldHVybiBjb25zdHJ1Y3Rvcjtcbn07XG5leHBvcnRzLkNsYXNzID0gQ2xhc3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG52YXIgVHlwZVN5c3RlbSA9IHJlcXVpcmUoXCIuL3R5cGUtc3lzdGVtXCIpLlR5cGVTeXN0ZW07XG52YXIgdmFsdWVzID0gcmVxdWlyZShcIi4vdXRpbFwiKS52YWx1ZXM7XG52YXIgUHJvbWlzZSA9IHJlcXVpcmUoXCJlczYtcHJvbWlzZVwiKS5Qcm9taXNlO1xuXG52YXIgc3BlY2lmaWNhdGlvbiA9IHJlcXVpcmUoXCIuL3NwZWNpZmljYXRpb24vY29yZS5qc29uXCIpO1xuXG5mdW5jdGlvbiByZWNvdmVyQWN0b3JEZXNjcmlwdGlvbnMoZXJyb3IpIHtcbiAgY29uc29sZS53YXJuKFwiRmFpbGVkIHRvIGZldGNoIHByb3RvY29sIHNwZWNpZmljYXRpb24gKHNlZSByZWFzb24gYmVsb3cpLiBcIiArXG4gICAgICAgICAgICAgICBcIlVzaW5nIGEgZmFsbGJhY2sgcHJvdG9jYWwgc3BlY2lmaWNhdGlvbiFcIixcbiAgICAgICAgICAgICAgIGVycm9yKTtcbiAgcmV0dXJuIHJlcXVpcmUoXCIuL3NwZWNpZmljYXRpb24vcHJvdG9jb2wuanNvblwiKTtcbn1cblxuLy8gVHlwZSB0byByZXByZXNlbnQgc3VwZXJ2aXNlciBhY3RvciByZWxhdGlvbnMgdG8gYWN0b3JzIHRoZXkgc3VwZXJ2aXNlXG4vLyBpbiB0ZXJtcyBvZiBsaWZldGltZSBtYW5hZ2VtZW50LlxudmFyIFN1cGVydmlzb3IgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihpZCkge1xuICAgIHRoaXMuaWQgPSBpZDtcbiAgICB0aGlzLndvcmtlcnMgPSBbXTtcbiAgfVxufSk7XG5cbnZhciBUZWxlbWV0cnkgPSBDbGFzcyh7XG4gIGFkZDogZnVuY3Rpb24oaWQsIG1zKSB7XG4gICAgY29uc29sZS5sb2coXCJ0ZWxlbWV0cnk6OlwiLCBpZCwgbXMpXG4gIH1cbn0pO1xuXG4vLyBDb25zaWRlciBtYWtpbmcgY2xpZW50IGEgcm9vdCBhY3Rvci5cblxudmFyIENsaWVudCA9IENsYXNzKHtcbiAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucm9vdCA9IG51bGw7XG4gICAgdGhpcy50ZWxlbWV0cnkgPSBuZXcgVGVsZW1ldHJ5KCk7XG5cbiAgICB0aGlzLnNldHVwQ29ubmVjdGlvbigpO1xuICAgIHRoaXMuc2V0dXBMaWZlTWFuYWdlbWVudCgpO1xuICAgIHRoaXMuc2V0dXBUeXBlU3lzdGVtKCk7XG4gIH0sXG5cbiAgc2V0dXBDb25uZWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlcXVlc3RzID0gW107XG4gIH0sXG4gIHNldHVwTGlmZU1hbmFnZW1lbnQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMuY2FjaGUgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIHRoaXMuZ3JhcGggPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIHRoaXMuZ2V0ID0gdGhpcy5nZXQuYmluZCh0aGlzKTtcbiAgICB0aGlzLnJlbGVhc2UgPSB0aGlzLnJlbGVhc2UuYmluZCh0aGlzKTtcbiAgfSxcbiAgc2V0dXBUeXBlU3lzdGVtOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnR5cGVTeXN0ZW0gPSBuZXcgVHlwZVN5c3RlbSh0aGlzKTtcbiAgICB0aGlzLnR5cGVTeXN0ZW0ucmVnaXN0ZXJUeXBlcyhzcGVjaWZpY2F0aW9uKTtcbiAgfSxcblxuICBjb25uZWN0OiBmdW5jdGlvbihwb3J0KSB7XG4gICAgdmFyIGNsaWVudCA9IHRoaXM7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgY2xpZW50LnBvcnQgPSBwb3J0O1xuICAgICAgcG9ydC5vbm1lc3NhZ2UgPSBjbGllbnQucmVjZWl2ZS5iaW5kKGNsaWVudCk7XG4gICAgICBjbGllbnQub25SZWFkeSA9IHJlc29sdmU7XG4gICAgICBjbGllbnQub25GYWlsID0gcmVqZWN0O1xuXG4gICAgICBwb3J0LnN0YXJ0KCk7XG4gICAgfSk7XG4gIH0sXG4gIHNlbmQ6IGZ1bmN0aW9uKHBhY2tldCkge1xuICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZShwYWNrZXQpO1xuICB9LFxuICByZXF1ZXN0OiBmdW5jdGlvbihwYWNrZXQpIHtcbiAgICB2YXIgY2xpZW50ID0gdGhpcztcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBjbGllbnQucmVxdWVzdHMucHVzaChwYWNrZXQudG8sIHsgcmVzb2x2ZTogcmVzb2x2ZSwgcmVqZWN0OiByZWplY3QgfSk7XG4gICAgICBjbGllbnQuc2VuZChwYWNrZXQpO1xuICAgIH0pO1xuICB9LFxuXG4gIHJlY2VpdmU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgdmFyIHBhY2tldCA9IGV2ZW50LmRhdGE7XG4gICAgaWYgKCF0aGlzLnJvb3QpIHtcbiAgICAgIGlmIChwYWNrZXQuZnJvbSAhPT0gXCJyb290XCIpXG4gICAgICAgIHRocm93IEVycm9yKFwiSW5pdGlhbCBwYWNrZXQgbXVzdCBiZSBmcm9tIHJvb3RcIik7XG4gICAgICBpZiAoIShcImFwcGxpY2F0aW9uVHlwZVwiIGluIHBhY2tldCkpXG4gICAgICAgIHRocm93IEVycm9yKFwiSW5pdGlhbCBwYWNrZXQgbXVzdCBjb250YWluIGFwcGxpY2F0aW9uVHlwZSBmaWVsZFwiKTtcblxuICAgICAgdGhpcy5yb290ID0gdGhpcy50eXBlU3lzdGVtLnJlYWQoXCJyb290XCIsIG51bGwsIFwicm9vdFwiKTtcbiAgICAgIHRoaXMucm9vdFxuICAgICAgICAgIC5wcm90b2NvbERlc2NyaXB0aW9uKClcbiAgICAgICAgICAuY2F0Y2gocmVjb3ZlckFjdG9yRGVzY3JpcHRpb25zKVxuICAgICAgICAgIC50aGVuKHRoaXMudHlwZVN5c3RlbS5yZWdpc3RlclR5cGVzLmJpbmQodGhpcy50eXBlU3lzdGVtKSlcbiAgICAgICAgICAudGhlbih0aGlzLm9uUmVhZHkuYmluZCh0aGlzLCB0aGlzLnJvb3QpLCB0aGlzLm9uRmFpbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBhY3RvciA9IHRoaXMuZ2V0KHBhY2tldC5mcm9tKSB8fCB0aGlzLnJvb3Q7XG4gICAgICB2YXIgZXZlbnQgPSBhY3Rvci5ldmVudHNbcGFja2V0LnR5cGVdO1xuICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgIGFjdG9yLmRpc3BhdGNoRXZlbnQoZXZlbnQucmVhZChwYWNrZXQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBpbmRleCA9IHRoaXMucmVxdWVzdHMuaW5kZXhPZihhY3Rvci5pZCk7XG4gICAgICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICAgICAgdmFyIHJlcXVlc3QgPSB0aGlzLnJlcXVlc3RzLnNwbGljZShpbmRleCwgMikucG9wKCk7XG4gICAgICAgICAgaWYgKHBhY2tldC5lcnJvcilcbiAgICAgICAgICAgIHJlcXVlc3QucmVqZWN0KHBhY2tldCk7XG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmVxdWVzdC5yZXNvbHZlKHBhY2tldCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihFcnJvcihcIlVuZXhwZWN0ZWQgcGFja2V0IFwiICsgSlNPTi5zdHJpbmdpZnkocGFja2V0LCAyLCAyKSksXG4gICAgICAgICAgICAgICAgICAgICAgICBwYWNrZXQsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RzLnNsaWNlKDApKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBnZXQ6IGZ1bmN0aW9uKGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuY2FjaGVbaWRdO1xuICB9LFxuICBzdXBlcnZpc29yT2Y6IGZ1bmN0aW9uKGFjdG9yKSB7XG4gICAgZm9yICh2YXIgaWQgaW4gdGhpcy5ncmFwaCkge1xuICAgICAgaWYgKHRoaXMuZ3JhcGhbaWRdLmluZGV4T2YoYWN0b3IuaWQpID49IDApIHtcbiAgICAgICAgcmV0dXJuIGlkO1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgd29ya2Vyc09mOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIHJldHVybiB0aGlzLmdyYXBoW2FjdG9yLmlkXTtcbiAgfSxcbiAgc3VwZXJ2aXNlOiBmdW5jdGlvbihhY3Rvciwgd29ya2VyKSB7XG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3RvcilcbiAgICBpZiAod29ya2Vycy5pbmRleE9mKHdvcmtlci5pZCkgPCAwKSB7XG4gICAgICB3b3JrZXJzLnB1c2god29ya2VyLmlkKTtcbiAgICB9XG4gIH0sXG4gIHVuc3VwZXJ2aXNlOiBmdW5jdGlvbihhY3Rvciwgd29ya2VyKSB7XG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3Rvcik7XG4gICAgdmFyIGluZGV4ID0gd29ya2Vycy5pbmRleE9mKHdvcmtlci5pZClcbiAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgd29ya2Vycy5zcGxpY2UoaW5kZXgsIDEpXG4gICAgfVxuICB9LFxuXG4gIHJlZ2lzdGVyOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIHZhciByZWdpc3RlcmVkID0gdGhpcy5nZXQoYWN0b3IuaWQpO1xuICAgIGlmICghcmVnaXN0ZXJlZCkge1xuICAgICAgdGhpcy5jYWNoZVthY3Rvci5pZF0gPSBhY3RvcjtcbiAgICAgIHRoaXMuZ3JhcGhbYWN0b3IuaWRdID0gW107XG4gICAgfSBlbHNlIGlmIChyZWdpc3RlcmVkICE9PSBhY3Rvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGlmZmVyZW50IGFjdG9yIHdpdGggc2FtZSBpZCBpcyBhbHJlYWR5IHJlZ2lzdGVyZWRcIik7XG4gICAgfVxuICB9LFxuICB1bnJlZ2lzdGVyOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIGlmICh0aGlzLmdldChhY3Rvci5pZCkpIHtcbiAgICAgIGRlbGV0ZSB0aGlzLmNhY2hlW2FjdG9yLmlkXTtcbiAgICAgIGRlbGV0ZSB0aGlzLmdyYXBoW2FjdG9yLmlkXTtcbiAgICB9XG4gIH0sXG5cbiAgcmVsZWFzZTogZnVuY3Rpb24oYWN0b3IpIHtcbiAgICB2YXIgc3VwZXJ2aXNvciA9IHRoaXMuc3VwZXJ2aXNvck9mKGFjdG9yKTtcbiAgICBpZiAoc3VwZXJ2aXNvcilcbiAgICAgIHRoaXMudW5zdXBlcnZpc2Uoc3VwZXJ2aXNvciwgYWN0b3IpO1xuXG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3RvcilcblxuICAgIGlmICh3b3JrZXJzKSB7XG4gICAgICB3b3JrZXJzLm1hcCh0aGlzLmdldCkuZm9yRWFjaCh0aGlzLnJlbGVhc2UpXG4gICAgfVxuICAgIHRoaXMudW5lcmdpc3RlcihhY3Rvcik7XG4gIH1cbn0pO1xuZXhwb3J0cy5DbGllbnQgPSBDbGllbnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bWJvbCA9IHJlcXVpcmUoXCJlczYtc3ltYm9sXCIpXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKS5FdmVudEVtaXR0ZXI7XG52YXIgQ2xhc3MgPSByZXF1aXJlKFwiLi9jbGFzc1wiKS5DbGFzcztcblxudmFyICRib3VuZCA9IFN5bWJvbChcIkV2ZW50VGFyZ2V0L2hhbmRsZUV2ZW50XCIpO1xudmFyICRlbWl0dGVyID0gU3ltYm9sKFwiRXZlbnRUYXJnZXQvZW1pdHRlclwiKTtcblxuZnVuY3Rpb24gbWFrZUhhbmRsZXIoaGFuZGxlcikge1xuICByZXR1cm4gZnVuY3Rpb24oZXZlbnQpIHtcbiAgICBoYW5kbGVyLmhhbmRsZUV2ZW50KGV2ZW50KTtcbiAgfVxufVxuXG52YXIgRXZlbnRUYXJnZXQgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJGVtaXR0ZXIsIHtcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICB2YWx1ZTogbmV3IEV2ZW50RW1pdHRlcigpXG4gICAgfSk7XG4gIH0sXG4gIGFkZEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGhhbmRsZXIpIHtcbiAgICBpZiAodHlwZW9mKGhhbmRsZXIpID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRoaXNbJGVtaXR0ZXJdLm9uKHR5cGUsIGhhbmRsZXIpO1xuICAgIH1cbiAgICBlbHNlIGlmIChoYW5kbGVyICYmIHR5cGVvZihoYW5kbGVyKSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgaWYgKCFoYW5kbGVyWyRib3VuZF0pIGhhbmRsZXJbJGJvdW5kXSA9IG1ha2VIYW5kbGVyKGhhbmRsZXIpO1xuICAgICAgdGhpc1skZW1pdHRlcl0ub24odHlwZSwgaGFuZGxlclskYm91bmRdKTtcbiAgICB9XG4gIH0sXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGhhbmRsZXIpIHtcbiAgICBpZiAodHlwZW9mKGhhbmRsZXIpID09PSBcImZ1bmN0aW9uXCIpXG4gICAgICB0aGlzWyRlbWl0dGVyXS5yZW1vdmVMaXN0ZW5lcih0eXBlLCBoYW5kbGVyKTtcbiAgICBlbHNlIGlmIChoYW5kbGVyICYmIGhhbmRsZXJbJGJvdW5kXSlcbiAgICAgIHRoaXNbJGVtaXR0ZXJdLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGhhbmRsZXJbJGJvdW5kXSk7XG4gIH0sXG4gIGRpc3BhdGNoRXZlbnQ6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgZXZlbnQudGFyZ2V0ID0gdGhpcztcbiAgICB0aGlzWyRlbWl0dGVyXS5lbWl0KGV2ZW50LnR5cGUsIGV2ZW50KTtcbiAgfVxufSk7XG5leHBvcnRzLkV2ZW50VGFyZ2V0ID0gRXZlbnRUYXJnZXQ7XG5cbnZhciBNZXNzYWdlRXZlbnQgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbih0eXBlLCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICB0aGlzLmRhdGEgPSBvcHRpb25zLmRhdGEgPT09IHZvaWQoMCkgPyBudWxsIDogb3B0aW9ucy5kYXRhO1xuXG4gICAgdGhpcy5sYXN0RXZlbnRJZCA9IG9wdGlvbnMubGFzdEV2ZW50SWQgfHwgXCJcIjtcbiAgICB0aGlzLm9yaWdpbiA9IG9wdGlvbnMub3JpZ2luIHx8IFwiXCI7XG4gICAgdGhpcy5idWJibGVzID0gb3B0aW9ucy5idWJibGVzIHx8IGZhbHNlO1xuICAgIHRoaXMuY2FuY2VsYWJsZSA9IG9wdGlvbnMuY2FuY2VsYWJsZSB8fCBmYWxzZTtcbiAgfSxcbiAgc291cmNlOiBudWxsLFxuICBwb3J0czogbnVsbCxcbiAgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkge1xuICB9LFxuICBzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuICB9LFxuICBzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuICB9XG59KTtcbmV4cG9ydHMuTWVzc2FnZUV2ZW50ID0gTWVzc2FnZUV2ZW50O1xuIiwiLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGFcbi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbi8vIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdFxuLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlXG4vLyBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZFxuLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTU1xuLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRlxuLy8gTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTlxuLy8gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sXG4vLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1Jcbi8vIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEVcbi8vIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuXG5cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgdGhpcy5fZXZlbnRzID0gdGhpcy5fZXZlbnRzIHx8IHt9O1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSB0aGlzLl9tYXhMaXN0ZW5lcnMgfHwgdW5kZWZpbmVkO1xufVxubW9kdWxlLmV4cG9ydHMgPSBFdmVudEVtaXR0ZXI7XG5cbi8vIEJhY2t3YXJkcy1jb21wYXQgd2l0aCBub2RlIDAuMTAueFxuRXZlbnRFbWl0dGVyLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fZXZlbnRzID0gdW5kZWZpbmVkO1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fbWF4TGlzdGVuZXJzID0gdW5kZWZpbmVkO1xuXG4vLyBCeSBkZWZhdWx0IEV2ZW50RW1pdHRlcnMgd2lsbCBwcmludCBhIHdhcm5pbmcgaWYgbW9yZSB0aGFuIDEwIGxpc3RlbmVycyBhcmVcbi8vIGFkZGVkIHRvIGl0LiBUaGlzIGlzIGEgdXNlZnVsIGRlZmF1bHQgd2hpY2ggaGVscHMgZmluZGluZyBtZW1vcnkgbGVha3MuXG5FdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycyA9IDEwO1xuXG4vLyBPYnZpb3VzbHkgbm90IGFsbCBFbWl0dGVycyBzaG91bGQgYmUgbGltaXRlZCB0byAxMC4gVGhpcyBmdW5jdGlvbiBhbGxvd3Ncbi8vIHRoYXQgdG8gYmUgaW5jcmVhc2VkLiBTZXQgdG8gemVybyBmb3IgdW5saW1pdGVkLlxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5zZXRNYXhMaXN0ZW5lcnMgPSBmdW5jdGlvbihuKSB7XG4gIGlmICghaXNOdW1iZXIobikgfHwgbiA8IDAgfHwgaXNOYU4obikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCduIG11c3QgYmUgYSBwb3NpdGl2ZSBudW1iZXInKTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gbjtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBlciwgaGFuZGxlciwgbGVuLCBhcmdzLCBpLCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gSWYgdGhlcmUgaXMgbm8gJ2Vycm9yJyBldmVudCBsaXN0ZW5lciB0aGVuIHRocm93LlxuICBpZiAodHlwZSA9PT0gJ2Vycm9yJykge1xuICAgIGlmICghdGhpcy5fZXZlbnRzLmVycm9yIHx8XG4gICAgICAgIChpc09iamVjdCh0aGlzLl9ldmVudHMuZXJyb3IpICYmICF0aGlzLl9ldmVudHMuZXJyb3IubGVuZ3RoKSkge1xuICAgICAgZXIgPSBhcmd1bWVudHNbMV07XG4gICAgICBpZiAoZXIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aHJvdyBlcjsgLy8gVW5oYW5kbGVkICdlcnJvcicgZXZlbnRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IFR5cGVFcnJvcignVW5jYXVnaHQsIHVuc3BlY2lmaWVkIFwiZXJyb3JcIiBldmVudC4nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVyID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc1VuZGVmaW5lZChoYW5kbGVyKSlcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgaWYgKGlzRnVuY3Rpb24oaGFuZGxlcikpIHtcbiAgICBzd2l0Y2ggKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIC8vIGZhc3QgY2FzZXNcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdLCBhcmd1bWVudHNbMl0pO1xuICAgICAgICBicmVhaztcbiAgICAgIC8vIHNsb3dlclxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbGVuID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICAgICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICAgICAgZm9yIChpID0gMTsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgICAgICBoYW5kbGVyLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc09iamVjdChoYW5kbGVyKSkge1xuICAgIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuOyBpKyspXG4gICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcblxuICAgIGxpc3RlbmVycyA9IGhhbmRsZXIuc2xpY2UoKTtcbiAgICBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBtO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBUbyBhdm9pZCByZWN1cnNpb24gaW4gdGhlIGNhc2UgdGhhdCB0eXBlID09PSBcIm5ld0xpc3RlbmVyXCIhIEJlZm9yZVxuICAvLyBhZGRpbmcgaXQgdG8gdGhlIGxpc3RlbmVycywgZmlyc3QgZW1pdCBcIm5ld0xpc3RlbmVyXCIuXG4gIGlmICh0aGlzLl9ldmVudHMubmV3TGlzdGVuZXIpXG4gICAgdGhpcy5lbWl0KCduZXdMaXN0ZW5lcicsIHR5cGUsXG4gICAgICAgICAgICAgIGlzRnVuY3Rpb24obGlzdGVuZXIubGlzdGVuZXIpID9cbiAgICAgICAgICAgICAgbGlzdGVuZXIubGlzdGVuZXIgOiBsaXN0ZW5lcik7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgLy8gT3B0aW1pemUgdGhlIGNhc2Ugb2Ygb25lIGxpc3RlbmVyLiBEb24ndCBuZWVkIHRoZSBleHRyYSBhcnJheSBvYmplY3QuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdID0gbGlzdGVuZXI7XG4gIGVsc2UgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgLy8gSWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gYXJyYXksIGp1c3QgYXBwZW5kLlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZVxuICAgIC8vIEFkZGluZyB0aGUgc2Vjb25kIGVsZW1lbnQsIG5lZWQgdG8gY2hhbmdlIHRvIGFycmF5LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV0sIGxpc3RlbmVyXTtcblxuICAvLyBDaGVjayBmb3IgbGlzdGVuZXIgbGVha1xuICBpZiAoaXNPYmplY3QodGhpcy5fZXZlbnRzW3R5cGVdKSAmJiAhdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCkge1xuICAgIHZhciBtO1xuICAgIGlmICghaXNVbmRlZmluZWQodGhpcy5fbWF4TGlzdGVuZXJzKSkge1xuICAgICAgbSA9IHRoaXMuX21heExpc3RlbmVycztcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IEV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzO1xuICAgIH1cblxuICAgIGlmIChtICYmIG0gPiAwICYmIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGggPiBtKSB7XG4gICAgICB0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkID0gdHJ1ZTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJyhub2RlKSB3YXJuaW5nOiBwb3NzaWJsZSBFdmVudEVtaXR0ZXIgbWVtb3J5ICcgK1xuICAgICAgICAgICAgICAgICAgICAnbGVhayBkZXRlY3RlZC4gJWQgbGlzdGVuZXJzIGFkZGVkLiAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvIGluY3JlYXNlIGxpbWl0LicsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGgpO1xuICAgICAgY29uc29sZS50cmFjZSgpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICB2YXIgZmlyZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBnKCkge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG5cbiAgICBpZiAoIWZpcmVkKSB7XG4gICAgICBmaXJlZCA9IHRydWU7XG4gICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgfVxuXG4gIGcubGlzdGVuZXIgPSBsaXN0ZW5lcjtcbiAgdGhpcy5vbih0eXBlLCBnKTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vIGVtaXRzIGEgJ3JlbW92ZUxpc3RlbmVyJyBldmVudCBpZmYgdGhlIGxpc3RlbmVyIHdhcyByZW1vdmVkXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIGxpc3QsIHBvc2l0aW9uLCBsZW5ndGgsIGk7XG5cbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgbGlzdCA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgbGVuZ3RoID0gbGlzdC5sZW5ndGg7XG4gIHBvc2l0aW9uID0gLTE7XG5cbiAgaWYgKGxpc3QgPT09IGxpc3RlbmVyIHx8XG4gICAgICAoaXNGdW5jdGlvbihsaXN0Lmxpc3RlbmVyKSAmJiBsaXN0Lmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIGlmICh0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpXG4gICAgICB0aGlzLmVtaXQoJ3JlbW92ZUxpc3RlbmVyJywgdHlwZSwgbGlzdGVuZXIpO1xuXG4gIH0gZWxzZSBpZiAoaXNPYmplY3QobGlzdCkpIHtcbiAgICBmb3IgKGkgPSBsZW5ndGg7IGktLSA+IDA7KSB7XG4gICAgICBpZiAobGlzdFtpXSA9PT0gbGlzdGVuZXIgfHxcbiAgICAgICAgICAobGlzdFtpXS5saXN0ZW5lciAmJiBsaXN0W2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICAgICAgcG9zaXRpb24gPSBpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocG9zaXRpb24gPCAwKVxuICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICBpZiAobGlzdC5sZW5ndGggPT09IDEpIHtcbiAgICAgIGxpc3QubGVuZ3RoID0gMDtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpc3Quc3BsaWNlKHBvc2l0aW9uLCAxKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBrZXksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICByZXR1cm4gdGhpcztcblxuICAvLyBub3QgbGlzdGVuaW5nIGZvciByZW1vdmVMaXN0ZW5lciwgbm8gbmVlZCB0byBlbWl0XG4gIGlmICghdGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApXG4gICAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICBlbHNlIGlmICh0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gZW1pdCByZW1vdmVMaXN0ZW5lciBmb3IgYWxsIGxpc3RlbmVycyBvbiBhbGwgZXZlbnRzXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgZm9yIChrZXkgaW4gdGhpcy5fZXZlbnRzKSB7XG4gICAgICBpZiAoa2V5ID09PSAncmVtb3ZlTGlzdGVuZXInKSBjb250aW51ZTtcbiAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKGtleSk7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCdyZW1vdmVMaXN0ZW5lcicpO1xuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgbGlzdGVuZXJzID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGxpc3RlbmVycykpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVycyk7XG4gIH0gZWxzZSB7XG4gICAgLy8gTElGTyBvcmRlclxuICAgIHdoaWxlIChsaXN0ZW5lcnMubGVuZ3RoKVxuICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbbGlzdGVuZXJzLmxlbmd0aCAtIDFdKTtcbiAgfVxuICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gW107XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24odGhpcy5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSBbdGhpcy5fZXZlbnRzW3R5cGVdXTtcbiAgZWxzZVxuICAgIHJldCA9IHRoaXMuX2V2ZW50c1t0eXBlXS5zbGljZSgpO1xuICByZXR1cm4gcmV0O1xufTtcblxuRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghZW1pdHRlci5fZXZlbnRzIHx8ICFlbWl0dGVyLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gMDtcbiAgZWxzZSBpZiAoaXNGdW5jdGlvbihlbWl0dGVyLl9ldmVudHNbdHlwZV0pKVxuICAgIHJldCA9IDE7XG4gIGVsc2VcbiAgICByZXQgPSBlbWl0dGVyLl9ldmVudHNbdHlwZV0ubGVuZ3RoO1xuICByZXR1cm4gcmV0O1xufTtcblxuZnVuY3Rpb24gaXNGdW5jdGlvbihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdmdW5jdGlvbic7XG59XG5cbmZ1bmN0aW9uIGlzTnVtYmVyKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ251bWJlcic7XG59XG5cbmZ1bmN0aW9uIGlzT2JqZWN0KGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ29iamVjdCcgJiYgYXJnICE9PSBudWxsO1xufVxuXG5mdW5jdGlvbiBpc1VuZGVmaW5lZChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gdm9pZCAwO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpID8gU3ltYm9sIDogcmVxdWlyZSgnLi9wb2x5ZmlsbCcpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblx0dmFyIHN5bWJvbDtcblx0aWYgKHR5cGVvZiBTeW1ib2wgIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcblx0c3ltYm9sID0gU3ltYm9sKCd0ZXN0IHN5bWJvbCcpO1xuXHR0cnkge1xuXHRcdGlmIChTdHJpbmcoc3ltYm9sKSAhPT0gJ1N5bWJvbCAodGVzdCBzeW1ib2wpJykgcmV0dXJuIGZhbHNlO1xuXHR9IGNhdGNoIChlKSB7IHJldHVybiBmYWxzZTsgfVxuXHRpZiAodHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gJ3N5bWJvbCcpIHJldHVybiB0cnVlO1xuXG5cdC8vIFJldHVybiAndHJ1ZScgZm9yIHBvbHlmaWxsc1xuXHRpZiAodHlwZW9mIFN5bWJvbC5pc0NvbmNhdFNwcmVhZGFibGUgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cdGlmICh0eXBlb2YgU3ltYm9sLmlzUmVnRXhwICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC5pdGVyYXRvciAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblx0aWYgKHR5cGVvZiBTeW1ib2wudG9QcmltaXRpdmUgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cdGlmICh0eXBlb2YgU3ltYm9sLnRvU3RyaW5nVGFnICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC51bnNjb3BhYmxlcyAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblxuXHRyZXR1cm4gdHJ1ZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBhc3NpZ24gICAgICAgID0gcmVxdWlyZSgnZXM1LWV4dC9vYmplY3QvYXNzaWduJylcbiAgLCBub3JtYWxpemVPcHRzID0gcmVxdWlyZSgnZXM1LWV4dC9vYmplY3Qvbm9ybWFsaXplLW9wdGlvbnMnKVxuICAsIGlzQ2FsbGFibGUgICAgPSByZXF1aXJlKCdlczUtZXh0L29iamVjdC9pcy1jYWxsYWJsZScpXG4gICwgY29udGFpbnMgICAgICA9IHJlcXVpcmUoJ2VzNS1leHQvc3RyaW5nLyMvY29udGFpbnMnKVxuXG4gICwgZDtcblxuZCA9IG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGRzY3IsIHZhbHVlLyosIG9wdGlvbnMqLykge1xuXHR2YXIgYywgZSwgdywgb3B0aW9ucywgZGVzYztcblx0aWYgKChhcmd1bWVudHMubGVuZ3RoIDwgMikgfHwgKHR5cGVvZiBkc2NyICE9PSAnc3RyaW5nJykpIHtcblx0XHRvcHRpb25zID0gdmFsdWU7XG5cdFx0dmFsdWUgPSBkc2NyO1xuXHRcdGRzY3IgPSBudWxsO1xuXHR9IGVsc2Uge1xuXHRcdG9wdGlvbnMgPSBhcmd1bWVudHNbMl07XG5cdH1cblx0aWYgKGRzY3IgPT0gbnVsbCkge1xuXHRcdGMgPSB3ID0gdHJ1ZTtcblx0XHRlID0gZmFsc2U7XG5cdH0gZWxzZSB7XG5cdFx0YyA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2MnKTtcblx0XHRlID0gY29udGFpbnMuY2FsbChkc2NyLCAnZScpO1xuXHRcdHcgPSBjb250YWlucy5jYWxsKGRzY3IsICd3Jyk7XG5cdH1cblxuXHRkZXNjID0geyB2YWx1ZTogdmFsdWUsIGNvbmZpZ3VyYWJsZTogYywgZW51bWVyYWJsZTogZSwgd3JpdGFibGU6IHcgfTtcblx0cmV0dXJuICFvcHRpb25zID8gZGVzYyA6IGFzc2lnbihub3JtYWxpemVPcHRzKG9wdGlvbnMpLCBkZXNjKTtcbn07XG5cbmQuZ3MgPSBmdW5jdGlvbiAoZHNjciwgZ2V0LCBzZXQvKiwgb3B0aW9ucyovKSB7XG5cdHZhciBjLCBlLCBvcHRpb25zLCBkZXNjO1xuXHRpZiAodHlwZW9mIGRzY3IgIT09ICdzdHJpbmcnKSB7XG5cdFx0b3B0aW9ucyA9IHNldDtcblx0XHRzZXQgPSBnZXQ7XG5cdFx0Z2V0ID0gZHNjcjtcblx0XHRkc2NyID0gbnVsbDtcblx0fSBlbHNlIHtcblx0XHRvcHRpb25zID0gYXJndW1lbnRzWzNdO1xuXHR9XG5cdGlmIChnZXQgPT0gbnVsbCkge1xuXHRcdGdldCA9IHVuZGVmaW5lZDtcblx0fSBlbHNlIGlmICghaXNDYWxsYWJsZShnZXQpKSB7XG5cdFx0b3B0aW9ucyA9IGdldDtcblx0XHRnZXQgPSBzZXQgPSB1bmRlZmluZWQ7XG5cdH0gZWxzZSBpZiAoc2V0ID09IG51bGwpIHtcblx0XHRzZXQgPSB1bmRlZmluZWQ7XG5cdH0gZWxzZSBpZiAoIWlzQ2FsbGFibGUoc2V0KSkge1xuXHRcdG9wdGlvbnMgPSBzZXQ7XG5cdFx0c2V0ID0gdW5kZWZpbmVkO1xuXHR9XG5cdGlmIChkc2NyID09IG51bGwpIHtcblx0XHRjID0gdHJ1ZTtcblx0XHRlID0gZmFsc2U7XG5cdH0gZWxzZSB7XG5cdFx0YyA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2MnKTtcblx0XHRlID0gY29udGFpbnMuY2FsbChkc2NyLCAnZScpO1xuXHR9XG5cblx0ZGVzYyA9IHsgZ2V0OiBnZXQsIHNldDogc2V0LCBjb25maWd1cmFibGU6IGMsIGVudW1lcmFibGU6IGUgfTtcblx0cmV0dXJuICFvcHRpb25zID8gZGVzYyA6IGFzc2lnbihub3JtYWxpemVPcHRzKG9wdGlvbnMpLCBkZXNjKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9pcy1pbXBsZW1lbnRlZCcpKClcblx0PyBPYmplY3QuYXNzaWduXG5cdDogcmVxdWlyZSgnLi9zaGltJyk7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKCkge1xuXHR2YXIgYXNzaWduID0gT2JqZWN0LmFzc2lnbiwgb2JqO1xuXHRpZiAodHlwZW9mIGFzc2lnbiAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuIGZhbHNlO1xuXHRvYmogPSB7IGZvbzogJ3JheicgfTtcblx0YXNzaWduKG9iaiwgeyBiYXI6ICdkd2EnIH0sIHsgdHJ6eTogJ3RyenknIH0pO1xuXHRyZXR1cm4gKG9iai5mb28gKyBvYmouYmFyICsgb2JqLnRyenkpID09PSAncmF6ZHdhdHJ6eSc7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIga2V5cyAgPSByZXF1aXJlKCcuLi9rZXlzJylcbiAgLCB2YWx1ZSA9IHJlcXVpcmUoJy4uL3ZhbGlkLXZhbHVlJylcblxuICAsIG1heCA9IE1hdGgubWF4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChkZXN0LCBzcmMvKiwg4oCmc3JjbiovKSB7XG5cdHZhciBlcnJvciwgaSwgbCA9IG1heChhcmd1bWVudHMubGVuZ3RoLCAyKSwgYXNzaWduO1xuXHRkZXN0ID0gT2JqZWN0KHZhbHVlKGRlc3QpKTtcblx0YXNzaWduID0gZnVuY3Rpb24gKGtleSkge1xuXHRcdHRyeSB7IGRlc3Rba2V5XSA9IHNyY1trZXldOyB9IGNhdGNoIChlKSB7XG5cdFx0XHRpZiAoIWVycm9yKSBlcnJvciA9IGU7XG5cdFx0fVxuXHR9O1xuXHRmb3IgKGkgPSAxOyBpIDwgbDsgKytpKSB7XG5cdFx0c3JjID0gYXJndW1lbnRzW2ldO1xuXHRcdGtleXMoc3JjKS5mb3JFYWNoKGFzc2lnbik7XG5cdH1cblx0aWYgKGVycm9yICE9PSB1bmRlZmluZWQpIHRocm93IGVycm9yO1xuXHRyZXR1cm4gZGVzdDtcbn07XG4iLCIvLyBEZXByZWNhdGVkXG5cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob2JqKSB7IHJldHVybiB0eXBlb2Ygb2JqID09PSAnZnVuY3Rpb24nOyB9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpXG5cdD8gT2JqZWN0LmtleXNcblx0OiByZXF1aXJlKCcuL3NoaW0nKTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG5cdHRyeSB7XG5cdFx0T2JqZWN0LmtleXMoJ3ByaW1pdGl2ZScpO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9IGNhdGNoIChlKSB7IHJldHVybiBmYWxzZTsgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGtleXMgPSBPYmplY3Qua2V5cztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG5cdHJldHVybiBrZXlzKG9iamVjdCA9PSBudWxsID8gb2JqZWN0IDogT2JqZWN0KG9iamVjdCkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoJy4vYXNzaWduJylcblxuICAsIGZvckVhY2ggPSBBcnJheS5wcm90b3R5cGUuZm9yRWFjaFxuICAsIGNyZWF0ZSA9IE9iamVjdC5jcmVhdGUsIGdldFByb3RvdHlwZU9mID0gT2JqZWN0LmdldFByb3RvdHlwZU9mXG5cbiAgLCBwcm9jZXNzO1xuXG5wcm9jZXNzID0gZnVuY3Rpb24gKHNyYywgb2JqKSB7XG5cdHZhciBwcm90byA9IGdldFByb3RvdHlwZU9mKHNyYyk7XG5cdHJldHVybiBhc3NpZ24ocHJvdG8gPyBwcm9jZXNzKHByb3RvLCBvYmopIDogb2JqLCBzcmMpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucy8qLCDigKZvcHRpb25zKi8pIHtcblx0dmFyIHJlc3VsdCA9IGNyZWF0ZShudWxsKTtcblx0Zm9yRWFjaC5jYWxsKGFyZ3VtZW50cywgZnVuY3Rpb24gKG9wdGlvbnMpIHtcblx0XHRpZiAob3B0aW9ucyA9PSBudWxsKSByZXR1cm47XG5cdFx0cHJvY2VzcyhPYmplY3Qob3B0aW9ucyksIHJlc3VsdCk7XG5cdH0pO1xuXHRyZXR1cm4gcmVzdWx0O1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAodmFsdWUpIHtcblx0aWYgKHZhbHVlID09IG51bGwpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgdXNlIG51bGwgb3IgdW5kZWZpbmVkXCIpO1xuXHRyZXR1cm4gdmFsdWU7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpXG5cdD8gU3RyaW5nLnByb3RvdHlwZS5jb250YWluc1xuXHQ6IHJlcXVpcmUoJy4vc2hpbScpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgc3RyID0gJ3JhemR3YXRyenknO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblx0aWYgKHR5cGVvZiBzdHIuY29udGFpbnMgIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcblx0cmV0dXJuICgoc3RyLmNvbnRhaW5zKCdkd2EnKSA9PT0gdHJ1ZSkgJiYgKHN0ci5jb250YWlucygnZm9vJykgPT09IGZhbHNlKSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5kZXhPZiA9IFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc2VhcmNoU3RyaW5nLyosIHBvc2l0aW9uKi8pIHtcblx0cmV0dXJuIGluZGV4T2YuY2FsbCh0aGlzLCBzZWFyY2hTdHJpbmcsIGFyZ3VtZW50c1sxXSkgPiAtMTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBkID0gcmVxdWlyZSgnZCcpXG5cbiAgLCBjcmVhdGUgPSBPYmplY3QuY3JlYXRlLCBkZWZpbmVQcm9wZXJ0aWVzID0gT2JqZWN0LmRlZmluZVByb3BlcnRpZXNcbiAgLCBnZW5lcmF0ZU5hbWUsIFN5bWJvbDtcblxuZ2VuZXJhdGVOYW1lID0gKGZ1bmN0aW9uICgpIHtcblx0dmFyIGNyZWF0ZWQgPSBjcmVhdGUobnVsbCk7XG5cdHJldHVybiBmdW5jdGlvbiAoZGVzYykge1xuXHRcdHZhciBwb3N0Zml4ID0gMDtcblx0XHR3aGlsZSAoY3JlYXRlZFtkZXNjICsgKHBvc3RmaXggfHwgJycpXSkgKytwb3N0Zml4O1xuXHRcdGRlc2MgKz0gKHBvc3RmaXggfHwgJycpO1xuXHRcdGNyZWF0ZWRbZGVzY10gPSB0cnVlO1xuXHRcdHJldHVybiAnQEAnICsgZGVzYztcblx0fTtcbn0oKSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ltYm9sID0gZnVuY3Rpb24gKGRlc2NyaXB0aW9uKSB7XG5cdHZhciBzeW1ib2w7XG5cdGlmICh0aGlzIGluc3RhbmNlb2YgU3ltYm9sKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcignVHlwZUVycm9yOiBTeW1ib2wgaXMgbm90IGEgY29uc3RydWN0b3InKTtcblx0fVxuXHRzeW1ib2wgPSBjcmVhdGUoU3ltYm9sLnByb3RvdHlwZSk7XG5cdGRlc2NyaXB0aW9uID0gKGRlc2NyaXB0aW9uID09PSB1bmRlZmluZWQgPyAnJyA6IFN0cmluZyhkZXNjcmlwdGlvbikpO1xuXHRyZXR1cm4gZGVmaW5lUHJvcGVydGllcyhzeW1ib2wsIHtcblx0XHRfX2Rlc2NyaXB0aW9uX186IGQoJycsIGRlc2NyaXB0aW9uKSxcblx0XHRfX25hbWVfXzogZCgnJywgZ2VuZXJhdGVOYW1lKGRlc2NyaXB0aW9uKSlcblx0fSk7XG59O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTeW1ib2wsIHtcblx0Y3JlYXRlOiBkKCcnLCBTeW1ib2woJ2NyZWF0ZScpKSxcblx0aGFzSW5zdGFuY2U6IGQoJycsIFN5bWJvbCgnaGFzSW5zdGFuY2UnKSksXG5cdGlzQ29uY2F0U3ByZWFkYWJsZTogZCgnJywgU3ltYm9sKCdpc0NvbmNhdFNwcmVhZGFibGUnKSksXG5cdGlzUmVnRXhwOiBkKCcnLCBTeW1ib2woJ2lzUmVnRXhwJykpLFxuXHRpdGVyYXRvcjogZCgnJywgU3ltYm9sKCdpdGVyYXRvcicpKSxcblx0dG9QcmltaXRpdmU6IGQoJycsIFN5bWJvbCgndG9QcmltaXRpdmUnKSksXG5cdHRvU3RyaW5nVGFnOiBkKCcnLCBTeW1ib2woJ3RvU3RyaW5nVGFnJykpLFxuXHR1bnNjb3BhYmxlczogZCgnJywgU3ltYm9sKCd1bnNjb3BhYmxlcycpKVxufSk7XG5cbmRlZmluZVByb3BlcnRpZXMoU3ltYm9sLnByb3RvdHlwZSwge1xuXHRwcm9wZXJUb1N0cmluZzogZChmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuICdTeW1ib2wgKCcgKyB0aGlzLl9fZGVzY3JpcHRpb25fXyArICcpJztcblx0fSksXG5cdHRvU3RyaW5nOiBkKCcnLCBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLl9fbmFtZV9fOyB9KVxufSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoU3ltYm9sLnByb3RvdHlwZSwgU3ltYm9sLnRvUHJpbWl0aXZlLCBkKCcnLFxuXHRmdW5jdGlvbiAoaGludCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoXCJDb252ZXJzaW9uIG9mIHN5bWJvbCBvYmplY3RzIGlzIG5vdCBhbGxvd2VkXCIpO1xuXHR9KSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoU3ltYm9sLnByb3RvdHlwZSwgU3ltYm9sLnRvU3RyaW5nVGFnLCBkKCdjJywgJ1N5bWJvbCcpKTtcbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJ0eXBlc1wiOiB7XG4gICAgXCJyb290XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInJvb3RcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJlY2hvXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwic3RyaW5nXCI6IHsgXCJfYXJnXCI6IDAsIFwidHlwZVwiOiBcInN0cmluZ1wiIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdHJpbmdcIjogeyBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIiB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibGlzdFRhYnNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge30sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7IFwiX3JldHZhbFwiOiBcInRhYmxpc3RcIiB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwcm90b2NvbERlc2NyaXB0aW9uXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHt9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjogeyBcIl9yZXR2YWxcIjogXCJqc29uXCIgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInRhYkxpc3RDaGFuZ2VkXCI6IHt9XG4gICAgICB9XG4gICAgfSxcbiAgICBcInRhYmxpc3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJ0YWJsaXN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwic2VsZWN0ZWRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJ0YWJzXCI6IFwiYXJyYXk6dGFiXCIsXG4gICAgICAgIFwidXJsXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiY29uc29sZUFjdG9yXCI6IFwiY29uc29sZVwiLFxuICAgICAgICBcImluc3BlY3RvckFjdG9yXCI6IFwiaW5zcGVjdG9yXCIsXG4gICAgICAgIFwic3R5bGVTaGVldHNBY3RvclwiOiBcInN0eWxlc2hlZXRzXCIsXG4gICAgICAgIFwic3R5bGVFZGl0b3JBY3RvclwiOiBcInN0eWxlZWRpdG9yXCIsXG4gICAgICAgIFwibWVtb3J5QWN0b3JcIjogXCJtZW1vcnlcIixcbiAgICAgICAgXCJldmVudExvb3BMYWdBY3RvclwiOiBcImV2ZW50TG9vcExhZ1wiLFxuICAgICAgICBcInByZWZlcmVuY2VBY3RvclwiOiBcInByZWZlcmVuY2VcIixcbiAgICAgICAgXCJkZXZpY2VBY3RvclwiOiBcImRldmljZVwiLFxuXG4gICAgICAgIFwicHJvZmlsZXJBY3RvclwiOiBcInByb2ZpbGVyXCIsXG4gICAgICAgIFwiY2hyb21lRGVidWdnZXJcIjogXCJjaHJvbWVEZWJ1Z2dlclwiLFxuICAgICAgICBcIndlYmFwcHNBY3RvclwiOiBcIndlYmFwcHNcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJ0YWJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwidGFiXCIsXG4gICAgICBcImZpZWxkc1wiOiB7XG4gICAgICAgIFwidGl0bGVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJ1cmxcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJvdXRlcldpbmRvd0lEXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiaW5zcGVjdG9yQWN0b3JcIjogXCJpbnNwZWN0b3JcIixcbiAgICAgICAgXCJjYWxsV2F0Y2hlckFjdG9yXCI6IFwiY2FsbC13YXRjaGVyXCIsXG4gICAgICAgIFwiY2FudmFzQWN0b3JcIjogXCJjYW52YXNcIixcbiAgICAgICAgXCJ3ZWJnbEFjdG9yXCI6IFwid2ViZ2xcIixcbiAgICAgICAgXCJ3ZWJhdWRpb0FjdG9yXCI6IFwid2ViYXVkaW9cIixcbiAgICAgICAgXCJzdG9yYWdlQWN0b3JcIjogXCJzdG9yYWdlXCIsXG4gICAgICAgIFwiZ2NsaUFjdG9yXCI6IFwiZ2NsaVwiLFxuICAgICAgICBcIm1lbW9yeUFjdG9yXCI6IFwibWVtb3J5XCIsXG4gICAgICAgIFwiZXZlbnRMb29wTGFnXCI6IFwiZXZlbnRMb29wTGFnXCIsXG4gICAgICAgIFwic3R5bGVTaGVldHNBY3RvclwiOiBcInN0eWxlc2hlZXRzXCIsXG4gICAgICAgIFwic3R5bGVFZGl0b3JBY3RvclwiOiBcInN0eWxlZWRpdG9yXCIsXG5cbiAgICAgICAgXCJjb25zb2xlQWN0b3JcIjogXCJjb25zb2xlXCIsXG4gICAgICAgIFwidHJhY2VBY3RvclwiOiBcInRyYWNlXCJcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJ0eXBlc1wiOiB7XG4gICAgXCJsb25nc3RyYWN0b3JcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibG9uZ3N0cmFjdG9yXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic3Vic3RyaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN1YnN0cmluZ1wiLFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZW5kXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3Vic3RyaW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZWxlYXNlXCIsXG4gICAgICAgICAgXCJyZWxlYXNlXCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic3R5bGVzaGVldFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdHlsZXNoZWV0XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidG9nZ2xlRGlzYWJsZWRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidG9nZ2xlRGlzYWJsZWRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImRpc2FibGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0T3JpZ2luYWxTb3VyY2VzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE9yaWdpbmFsU291cmNlc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwib3JpZ2luYWxTb3VyY2VzXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6YXJyYXk6b3JpZ2luYWxzb3VyY2VcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldE9yaWdpbmFsTG9jYXRpb25cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0T3JpZ2luYWxMb2NhdGlvblwiLFxuICAgICAgICAgICAgXCJsaW5lXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bWJlclwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjb2x1bW5cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwib3JpZ2luYWxsb2NhdGlvbnJlc3BvbnNlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidXBkYXRlXCIsXG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInRyYW5zaXRpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwicHJvcGVydHktY2hhbmdlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwcm9wZXJ0eUNoYW5nZVwiLFxuICAgICAgICAgIFwicHJvcGVydHlcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzdHlsZS1hcHBsaWVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdHlsZUFwcGxpZWRcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcIm9yaWdpbmFsc291cmNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIm9yaWdpbmFsc291cmNlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic3R5bGVzaGVldHNcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3R5bGVzaGVldHNcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdHlsZVNoZWV0c1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRTdHlsZVNoZWV0c1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3R5bGVTaGVldHNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpzdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJhZGRTdHlsZVNoZWV0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFkZFN0eWxlU2hlZXRcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInN0eWxlU2hlZXRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJvcmlnaW5hbGxvY2F0aW9ucmVzcG9uc2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJvcmlnaW5hbGxvY2F0aW9ucmVzcG9uc2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJzb3VyY2VcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJsaW5lXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiY29sdW1uXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZG9tbm9kZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb21ub2RlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0Tm9kZVZhbHVlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE5vZGVWYWx1ZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXROb2RlVmFsdWVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0Tm9kZVZhbHVlXCIsXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRJbWFnZURhdGFcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0SW1hZ2VEYXRhXCIsXG4gICAgICAgICAgICBcIm1heERpbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJpbWFnZURhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1vZGlmeUF0dHJpYnV0ZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibW9kaWZ5QXR0cmlidXRlc1wiLFxuICAgICAgICAgICAgXCJtb2RpZmljYXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Ompzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiYXBwbGllZHN0eWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiYXBwbGllZHN0eWxlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwicnVsZVwiOiBcImRvbXN0eWxlcnVsZSNhY3RvcmlkXCIsXG4gICAgICAgIFwiaW5oZXJpdGVkXCI6IFwibnVsbGFibGU6ZG9tbm9kZSNhY3RvcmlkXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwibWF0Y2hlZHNlbGVjdG9yXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibWF0Y2hlZHNlbGVjdG9yXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwicnVsZVwiOiBcImRvbXN0eWxlcnVsZSNhY3RvcmlkXCIsXG4gICAgICAgIFwic2VsZWN0b3JcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJ2YWx1ZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInN0YXR1c1wiOiBcIm51bWJlclwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcIm1hdGNoZWRzZWxlY3RvcnJlc3BvbnNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibWF0Y2hlZHNlbGVjdG9ycmVzcG9uc2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJydWxlc1wiOiBcImFycmF5OmRvbXN0eWxlcnVsZVwiLFxuICAgICAgICBcInNoZWV0c1wiOiBcImFycmF5OnN0eWxlc2hlZXRcIixcbiAgICAgICAgXCJtYXRjaGVkXCI6IFwiYXJyYXk6bWF0Y2hlZHNlbGVjdG9yXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiYXBwbGllZFN0eWxlc1JldHVyblwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImFwcGxpZWRTdHlsZXNSZXR1cm5cIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJlbnRyaWVzXCI6IFwiYXJyYXk6YXBwbGllZHN0eWxlXCIsXG4gICAgICAgIFwicnVsZXNcIjogXCJhcnJheTpkb21zdHlsZXJ1bGVcIixcbiAgICAgICAgXCJzaGVldHNcIjogXCJhcnJheTpzdHlsZXNoZWV0XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwicGFnZXN0eWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInBhZ2VzdHlsZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldENvbXB1dGVkXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldENvbXB1dGVkXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXJrTWF0Y2hlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm9ubHlNYXRjaGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZmlsdGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiY29tcHV0ZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRNYXRjaGVkU2VsZWN0b3JzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE1hdGNoZWRTZWxlY3RvcnNcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInByb3BlcnR5XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJmaWx0ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibWF0Y2hlZHNlbGVjdG9ycmVzcG9uc2VcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEFwcGxpZWRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0QXBwbGllZFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiaW5oZXJpdGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibWF0Y2hlZFNlbGVjdG9yc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImZpbHRlclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcHBsaWVkU3R5bGVzUmV0dXJuXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRMYXlvdXRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0TGF5b3V0XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJhdXRvTWFyZ2luc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZG9tc3R5bGVydWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRvbXN0eWxlcnVsZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1vZGlmeVByb3BlcnRpZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibW9kaWZ5UHJvcGVydGllc1wiLFxuICAgICAgICAgICAgXCJtb2RpZmljYXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Ompzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInJ1bGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21zdHlsZXJ1bGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImhpZ2hsaWdodGVyXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImhpZ2hsaWdodGVyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2hvd0JveE1vZGVsXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNob3dCb3hNb2RlbFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicmVnaW9uXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWRlQm94TW9kZWxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaGlkZUJveE1vZGVsXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjYW5jZWxQaWNrXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNhbmNlbFBpY2tcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiaW1hZ2VEYXRhXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW1hZ2VEYXRhXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiZGF0YVwiOiBcIm51bGxhYmxlOmxvbmdzdHJpbmdcIixcbiAgICAgICAgXCJzaXplXCI6IFwianNvblwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImRpc2Nvbm5lY3RlZE5vZGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibm9kZVwiOiBcImRvbW5vZGVcIixcbiAgICAgICAgXCJuZXdQYXJlbnRzXCI6IFwiYXJyYXk6ZG9tbm9kZVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcIm5vZGVzXCI6IFwiYXJyYXk6ZG9tbm9kZVwiLFxuICAgICAgICBcIm5ld1BhcmVudHNcIjogXCJhcnJheTpkb21ub2RlXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZG9tbXV0YXRpb25cIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb21tdXRhdGlvblwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge31cbiAgICB9LFxuICAgIFwiZG9tbm9kZWxpc3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9tbm9kZWxpc3RcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpdGVtXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIml0ZW1cIixcbiAgICAgICAgICAgIFwiaXRlbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpdGVtc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpdGVtc1wiLFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpudW1iZXJcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZW5kXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVsZWFzZVwiLFxuICAgICAgICAgIFwicmVsZWFzZVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZWxlYXNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImRvbXRyYXZlcnNhbGFycmF5XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9tdHJhdmVyc2FsYXJyYXlcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJub2Rlc1wiOiBcImFycmF5OmRvbW5vZGVcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJkb213YWxrZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9td2Fsa2VyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVsZWFzZVwiLFxuICAgICAgICAgIFwicmVsZWFzZVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZWxlYXNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNhbmNlbFBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2FuY2VsUGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaGlnaGxpZ2h0XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJkb2N1bWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJkb2N1bWVudFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJkb2N1bWVudEVsZW1lbnRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9jdW1lbnRFbGVtZW50XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBhcmVudHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGFyZW50c1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic2FtZURvY3VtZW50XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZXNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZXRhaW5Ob2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJldGFpbk5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVucmV0YWluTm9kZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bnJldGFpbk5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlbGVhc2VOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJmb3JjZVwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiY2hpbGRyZW5cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2hpbGRyZW5cIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm1heE5vZGVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjZW50ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIndoYXRUb1Nob3dcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9tdHJhdmVyc2FsYXJyYXlcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNpYmxpbmdzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNpYmxpbmdzXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXhOb2Rlc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiY2VudGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3RhcnRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ3aGF0VG9TaG93XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbXRyYXZlcnNhbGFycmF5XCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJuZXh0U2libGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJuZXh0U2libGluZ1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwid2hhdFRvU2hvd1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwcmV2aW91c1NpYmxpbmdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJldmlvdXNTaWJsaW5nXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ3aGF0VG9TaG93XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInF1ZXJ5U2VsZWN0b3JcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicXVlcnlTZWxlY3RvclwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic2VsZWN0b3JcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZGlzY29ubmVjdGVkTm9kZVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicXVlcnlTZWxlY3RvckFsbFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJxdWVyeVNlbGVjdG9yQWxsXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzZWxlY3RvclwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImxpc3RcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21ub2RlbGlzdFwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3VnZ2VzdGlvbnNGb3JRdWVyeVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRTdWdnZXN0aW9uc0ZvclF1ZXJ5XCIsXG4gICAgICAgICAgICBcInF1ZXJ5XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjb21wbGV0aW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzZWxlY3RvclN0YXRlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibGlzdFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiYWRkUHNldWRvQ2xhc3NMb2NrXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFkZFBzZXVkb0NsYXNzTG9ja1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicHNldWRvQ2xhc3NcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmVudHNcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImhpZGVOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImhpZGVOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1bmhpZGVOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInVuaGlkZU5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlbW92ZVBzZXVkb0NsYXNzTG9ja1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZW1vdmVQc2V1ZG9DbGFzc0xvY2tcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBzZXVkb0NsYXNzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJlbnRzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjbGVhclBzZXVkb0NsYXNzTG9ja3NcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2xlYXJQc2V1ZG9DbGFzc0xvY2tzXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpbm5lckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaW5uZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJvdXRlckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwib3V0ZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRPdXRlckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0T3V0ZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVtb3ZlTm9kZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZW1vdmVOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibmV4dFNpYmxpbmdcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpbnNlcnRCZWZvcmVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaW5zZXJ0QmVmb3JlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJlbnRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzaWJsaW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0TXV0YXRpb25zXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE11dGF0aW9uc1wiLFxuICAgICAgICAgICAgXCJjbGVhbnVwXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibXV0YXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYXJyYXk6ZG9tbXV0YXRpb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlzSW5ET01UcmVlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzSW5ET01UcmVlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiYXR0YWNoZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXROb2RlQWN0b3JGcm9tT2JqZWN0QWN0b3JcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Tm9kZUFjdG9yRnJvbU9iamVjdEFjdG9yXCIsXG4gICAgICAgICAgICBcIm9iamVjdEFjdG9ySURcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJub2RlRnJvbnRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwibmV3LW11dGF0aW9uc1wiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwibmV3TXV0YXRpb25zXCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJwaWNrZXItbm9kZS1waWNrZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInBpY2tlck5vZGVQaWNrZWRcIixcbiAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwicGlja2VyLW5vZGUtaG92ZXJlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicGlja2VyTm9kZUhvdmVyZWRcIixcbiAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiaGlnaGxpZ2h0ZXItcmVhZHlcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImhpZ2hsaWdodGVyLXJlYWR5XCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJoaWdobGlnaHRlci1oaWRlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJoaWdobGlnaHRlci1oaWRlXCJcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJpbnNwZWN0b3JcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW5zcGVjdG9yXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0V2Fsa2VyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFdhbGtlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwid2Fsa2VyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9td2Fsa2VyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYWdlU3R5bGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFnZVN0eWxlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwYWdlU3R5bGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJwYWdlc3R5bGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEhpZ2hsaWdodGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEhpZ2hsaWdodGVyXCIsXG4gICAgICAgICAgICBcImF1dG9oaWRlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImhpZ2hsaWd0ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJoaWdobGlnaHRlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0SW1hZ2VEYXRhRnJvbVVSTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRJbWFnZURhdGFGcm9tVVJMXCIsXG4gICAgICAgICAgICBcInVybFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibWF4RGltXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImltYWdlRGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiY2FsbC1zdGFjay1pdGVtXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY2FsbC1zdGFjay1pdGVtXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcImZpbGVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJsaW5lXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY2FsbC1kZXRhaWxzXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY2FsbC1kZXRhaWxzXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwidHlwZVwiOiBcIm51bWJlclwiLFxuICAgICAgICBcIm5hbWVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJzdGFja1wiOiBcImFycmF5OmNhbGwtc3RhY2staXRlbVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImZ1bmN0aW9uLWNhbGxcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZnVuY3Rpb24tY2FsbFwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldERldGFpbHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0RGV0YWlsc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiaW5mb1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImNhbGwtZGV0YWlsc1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiY2FsbC13YXRjaGVyXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImNhbGwtd2F0Y2hlclwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0dXBcIixcbiAgICAgICAgICAgIFwidHJhY2VkR2xvYmFsc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidHJhY2VkRnVuY3Rpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFJlY29yZGluZ1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBlcmZvcm1SZWxvYWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmaW5hbGl6ZVwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZpbmFsaXplXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlzUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzUmVjb3JkaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVzdW1lUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlc3VtZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwYXVzZVJlY29yZGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwYXVzZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiY2FsbHNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpmdW5jdGlvbi1jYWxsXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJlcmFzZVJlY29yZGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJlcmFzZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJzbmFwc2hvdC1pbWFnZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInNuYXBzaG90LWltYWdlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiaW5kZXhcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJ3aWR0aFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImhlaWdodFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImZsaXBwZWRcIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwicGl4ZWxzXCI6IFwidWludDMyLWFycmF5XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic25hcHNob3Qtb3ZlcnZpZXdcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzbmFwc2hvdC1vdmVydmlld1wiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImNhbGxzXCI6IFwiYXJyYXk6ZnVuY3Rpb24tY2FsbFwiLFxuICAgICAgICBcInRodW1ibmFpbHNcIjogXCJhcnJheTpzbmFwc2hvdC1pbWFnZVwiLFxuICAgICAgICBcInNjcmVlbnNob3RcIjogXCJzbmFwc2hvdC1pbWFnZVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImZyYW1lLXNuYXBzaG90XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImZyYW1lLXNuYXBzaG90XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0T3ZlcnZpZXdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0T3ZlcnZpZXdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm92ZXJ2aWV3XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic25hcHNob3Qtb3ZlcnZpZXdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdlbmVyYXRlU2NyZWVuc2hvdEZvclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZW5lcmF0ZVNjcmVlbnNob3RGb3JcIixcbiAgICAgICAgICAgIFwiY2FsbFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJmdW5jdGlvbi1jYWxsXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzY3JlZW5zaG90XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic25hcHNob3QtaW1hZ2VcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImNhbnZhc1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjYW52YXNcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgICBcInJlbG9hZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImZpbmFsaXplXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZmluYWxpemVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiaXNJbml0aWFsaXplZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpc0luaXRpYWxpemVkXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJpbml0aWFsaXplZFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlY29yZEFuaW1hdGlvbkZyYW1lXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlY29yZEFuaW1hdGlvbkZyYW1lXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzbmFwc2hvdFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImZyYW1lLXNuYXBzaG90XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJnbC1zaGFkZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZ2wtc2hhZGVyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjb21waWxlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNvbXBpbGVcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImVycm9yXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6anNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZ2wtcHJvZ3JhbVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJnbC1wcm9ncmFtXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VmVydGV4U2hhZGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFZlcnRleFNoYWRlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic2hhZGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZ2wtc2hhZGVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRGcmFnbWVudFNoYWRlclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRGcmFnbWVudFNoYWRlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic2hhZGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZ2wtc2hhZGVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICAgIFwidGludFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJhcnJheTpudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidW5oaWdobGlnaHRcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bmhpZ2hsaWdodFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJibGFja2JveFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImJsYWNrYm94XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVuYmxhY2tib3hcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bmJsYWNrYm94XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcIndlYmdsXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIndlYmdsXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0dXBcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgICAgXCJyZWxvYWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmaW5hbGl6ZVwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZpbmFsaXplXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFByb2dyYW1zXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFByb2dyYW1zXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwcm9ncmFtc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmdsLXByb2dyYW1cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJwcm9ncmFtLWxpbmtlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicHJvZ3JhbUxpbmtlZFwiLFxuICAgICAgICAgIFwicHJvZ3JhbVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdsLXByb2dyYW1cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJhdWRpb25vZGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiYXVkaW9ub2RlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VHlwZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUeXBlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpc1NvdXJjZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpc1NvdXJjZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0UGFyYW1cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0UGFyYW1cIixcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOnByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZXJyb3JcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYXJhbVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRQYXJhbVwiLFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFBhcmFtRmxhZ3NcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFyYW1GbGFnc1wiLFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImZsYWdzXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6cHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYXJhbXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFyYW1zXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwYXJhbXNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJ3ZWJhdWRpb1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJ3ZWJhdWRpb1wiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0dXBcIixcbiAgICAgICAgICAgIFwicmVsb2FkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZmluYWxpemVcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJmaW5hbGl6ZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwic3RhcnQtY29udGV4dFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3RhcnRDb250ZXh0XCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJjb25uZWN0LW5vZGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImNvbm5lY3ROb2RlXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJkZXN0XCI6IHtcbiAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiZGlzY29ubmVjdC1ub2RlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0Tm9kZVwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiY29ubmVjdC1wYXJhbVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY29ubmVjdFBhcmFtXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcImNoYW5nZS1wYXJhbVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY2hhbmdlUGFyYW1cIixcbiAgICAgICAgICBcInNvdXJjZVwiOiB7XG4gICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImF1ZGlvbm9kZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJjcmVhdGUtbm9kZVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY3JlYXRlTm9kZVwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIFwib2xkLXN0eWxlc2hlZXRcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwib2xkLXN0eWxlc2hlZXRcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZGlzYWJsZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmZXRjaFNvdXJjZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJmZXRjaFNvdXJjZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidXBkYXRlXCIsXG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInRyYW5zaXRpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwicHJvcGVydHktY2hhbmdlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwcm9wZXJ0eUNoYW5nZVwiLFxuICAgICAgICAgIFwicHJvcGVydHlcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzb3VyY2UtbG9hZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic291cmNlTG9hZFwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3R5bGUtYXBwbGllZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3R5bGVBcHBsaWVkXCJcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJzdHlsZWVkaXRvclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdHlsZWVkaXRvclwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm5ld0RvY3VtZW50XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm5ld0RvY3VtZW50XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm5ld1N0eWxlU2hlZXRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibmV3U3R5bGVTaGVldFwiLFxuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3R5bGVTaGVldFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm9sZC1zdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwiZG9jdW1lbnQtbG9hZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiZG9jdW1lbnRMb2FkXCIsXG4gICAgICAgICAgXCJzdHlsZVNoZWV0c1wiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Om9sZC1zdHlsZXNoZWV0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llb2JqZWN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY29va2llb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInZhbHVlXCI6IFwibG9uZ3N0cmluZ1wiLFxuICAgICAgICBcInBhdGhcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJob3N0XCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiaXNEb21haW5cIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwiaXNTZWN1cmVcIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwiaXNIdHRwT25seVwiOiBcImJvb2xlYW5cIixcbiAgICAgICAgXCJjcmVhdGlvblRpbWVcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJsYXN0QWNjZXNzZWRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJleHBpcmVzXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llc3RvcmVvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjb29raWVzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOmNvb2tpZW9iamVjdFwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdG9yYWdlb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInZhbHVlXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VzdG9yZW9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0b3JhZ2VzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOnN0b3JhZ2VvYmplY3RcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJpZGJvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpZGJvYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJuYW1lXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwiZGJcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJvYmplY3RTdG9yZVwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcIm9yaWdpblwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcInZlcnNpb25cIjogXCJudWxsYWJsZTpudW1iZXJcIixcbiAgICAgICAgXCJvYmplY3RTdG9yZXNcIjogXCJudWxsYWJsZTpudW1iZXJcIixcbiAgICAgICAgXCJrZXlQYXRoXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwiYXV0b0luY3JlbWVudFwiOiBcIm51bGxhYmxlOmJvb2xlYW5cIixcbiAgICAgICAgXCJpbmRleGVzXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwidmFsdWVcIjogXCJudWxsYWJsZTpsb25nc3RyaW5nXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiaWRic3RvcmVvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpZGJzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOmlkYm9iamVjdFwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JlVXBkYXRlT2JqZWN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmVVcGRhdGVPYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJjaGFuZ2VkXCI6IFwibnVsbGFibGU6anNvblwiLFxuICAgICAgICBcImRlbGV0ZWRcIjogXCJudWxsYWJsZTpqc29uXCIsXG4gICAgICAgIFwiYWRkZWRcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llc1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjb29raWVzXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiY29va2llc3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImxvY2FsU3RvcmFnZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJsb2NhbFN0b3JhZ2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgICBcImhvc3RcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm5hbWVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcHRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdG9yYWdlc3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcInNlc3Npb25TdG9yYWdlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInNlc3Npb25TdG9yYWdlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RvcmFnZXN0b3Jlb2JqZWN0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJpbmRleGVkREJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW5kZXhlZERCXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiaWRic3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcInN0b3JlbGlzdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0b3JlbGlzdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImNvb2tpZXNcIjogXCJjb29raWVzXCIsXG4gICAgICAgIFwibG9jYWxTdG9yYWdlXCI6IFwibG9jYWxTdG9yYWdlXCIsXG4gICAgICAgIFwic2Vzc2lvblN0b3JhZ2VcIjogXCJzZXNzaW9uU3RvcmFnZVwiLFxuICAgICAgICBcImluZGV4ZWREQlwiOiBcImluZGV4ZWREQlwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmFnZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImxpc3RTdG9yZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibGlzdFN0b3Jlc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0b3JlbGlzdFwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInN0b3Jlcy11cGRhdGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0b3Jlc1VwZGF0ZVwiLFxuICAgICAgICAgIFwiZGF0YVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0b3JlVXBkYXRlT2JqZWN0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3RvcmVzLWNsZWFyZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0b3Jlc0NsZWFyZWRcIixcbiAgICAgICAgICBcImRhdGFcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3RvcmVzLXJlbG9hZGVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdG9yZXNSZWxhb2RlZFwiLFxuICAgICAgICAgIFwiZGF0YVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJnY2xpXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImdjbGlcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzcGVjc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzcGVjc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImV4ZWN1dGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZXhlY3V0ZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdGF0ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdGF0ZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3RhcnRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInJhbmtcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidHlwZXBhcnNlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInR5cGVwYXJzZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidHlwZWluY3JlbWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0eXBlaW5jcmVtZW50XCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInR5cGVkZWNyZW1lbnRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidHlwZWRlY3JlbWVudFwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZWxlY3Rpb25pbmZvXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNlbGVjdGlvbmluZm9cIixcbiAgICAgICAgICAgIFwidHlwZWRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJhY3Rpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwibWVtb3J5XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIm1lbW9yeVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1lYXN1cmVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibWVhc3VyZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImV2ZW50TG9vcExhZ1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJldmVudExvb3BMYWdcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdGFydFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdGFydFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3VjY2Vzc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic3RvcFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdG9wXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJldmVudC1sb29wLWxhZ1wiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiZXZlbnQtbG9vcC1sYWdcIixcbiAgICAgICAgICBcInRpbWVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJudW1iZXJcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJwcmVmZXJlbmNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInByZWZlcmVuY2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRCb29sUHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRCb29sUHJlZlwiLFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0Q2hhclByZWZcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Q2hhclByZWZcIixcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0SW50UHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRJbnRQcmVmXCIsXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEFsbFByZWZzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEFsbFByZWZzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldEJvb2xQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldEJvb2xQcmVmXCIsXG4gICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRDaGFyUHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRDaGFyUHJlZlwiLFxuICAgICAgICAgICAgXCJuYW1lXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0SW50UHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRJbnRQcmVmXCIsXG4gICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjbGVhclVzZXJQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNsZWFyVXNlclByZWZcIixcbiAgICAgICAgICAgIFwibmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZGV2aWNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRldmljZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldERlc2NyaXB0aW9uXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldERlc2NyaXB0aW9uXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFdhbGxwYXBlclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRXYWxscGFwZXJcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2NyZWVuc2hvdFRvRGF0YVVSTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzY3JlZW5zaG90VG9EYXRhVVJMXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImxvbmdzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFJhd1Blcm1pc3Npb25zVGFibGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UmF3UGVybWlzc2lvbnNUYWJsZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH1cbiAgfSxcbiAgXCJmcm9tXCI6IFwicm9vdFwiXG59XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG52YXIgdXRpbCA9IHJlcXVpcmUoXCIuL3V0aWxcIik7XG52YXIga2V5cyA9IHV0aWwua2V5cztcbnZhciB2YWx1ZXMgPSB1dGlsLnZhbHVlcztcbnZhciBwYWlycyA9IHV0aWwucGFpcnM7XG52YXIgcXVlcnkgPSB1dGlsLnF1ZXJ5O1xudmFyIGZpbmRQYXRoID0gdXRpbC5maW5kUGF0aDtcbnZhciBFdmVudFRhcmdldCA9IHJlcXVpcmUoXCIuL2V2ZW50XCIpLkV2ZW50VGFyZ2V0O1xuXG52YXIgVHlwZVN5c3RlbSA9IENsYXNzKHtcbiAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKGNsaWVudCkge1xuICAgIHZhciB0eXBlcyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gICAgdmFyIHNwZWNpZmljYXRpb24gPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuXG4gICAgdGhpcy5zcGVjaWZpY2F0aW9uID0gc3BlY2lmaWNhdGlvbjtcbiAgICB0aGlzLnR5cGVzID0gdHlwZXM7XG5cbiAgICB2YXIgdHlwZUZvciA9IGZ1bmN0aW9uIHR5cGVGb3IodHlwZU5hbWUpIHtcbiAgICAgIHR5cGVOYW1lID0gdHlwZU5hbWUgfHwgXCJwcmltaXRpdmVcIjtcbiAgICAgIGlmICghdHlwZXNbdHlwZU5hbWVdKSB7XG4gICAgICAgIGRlZmluZVR5cGUodHlwZU5hbWUpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHlwZXNbdHlwZU5hbWVdO1xuICAgIH07XG4gICAgdGhpcy50eXBlRm9yID0gdHlwZUZvcjtcblxuICAgIHZhciBkZWZpbmVUeXBlID0gZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgdmFyIHR5cGUgPSB2b2lkKDApO1xuICAgICAgaWYgKHR5cGVvZihkZXNjcmlwdG9yKSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBpZiAoZGVzY3JpcHRvci5pbmRleE9mKFwiOlwiKSA+IDApXG4gICAgICAgICAgdHlwZSA9IG1ha2VDb21wb3VuZFR5cGUoZGVzY3JpcHRvcik7XG4gICAgICAgIGVsc2UgaWYgKGRlc2NyaXB0b3IuaW5kZXhPZihcIiNcIikgPiAwKVxuICAgICAgICAgIHR5cGUgPSBuZXcgQWN0b3JEZXRhaWwoZGVzY3JpcHRvcik7XG4gICAgICAgICAgZWxzZSBpZiAoc3BlY2lmaWNhdGlvbltkZXNjcmlwdG9yXSlcbiAgICAgICAgICAgIHR5cGUgPSBtYWtlQ2F0ZWdvcnlUeXBlKHNwZWNpZmljYXRpb25bZGVzY3JpcHRvcl0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdHlwZSA9IG1ha2VDYXRlZ29yeVR5cGUoZGVzY3JpcHRvcik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlKVxuICAgICAgICB0eXBlc1t0eXBlLm5hbWVdID0gdHlwZTtcbiAgICAgIGVsc2VcbiAgICAgICAgdGhyb3cgVHlwZUVycm9yKFwiSW52YWxpZCB0eXBlOiBcIiArIGRlc2NyaXB0b3IpO1xuICAgIH07XG4gICAgdGhpcy5kZWZpbmVUeXBlID0gZGVmaW5lVHlwZTtcblxuXG4gICAgdmFyIG1ha2VDb21wb3VuZFR5cGUgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgICB2YXIgaW5kZXggPSBuYW1lLmluZGV4T2YoXCI6XCIpO1xuICAgICAgdmFyIGJhc2VUeXBlID0gbmFtZS5zbGljZSgwLCBpbmRleCk7XG4gICAgICB2YXIgc3ViVHlwZSA9IG5hbWUuc2xpY2UoaW5kZXggKyAxKTtcblxuICAgICAgcmV0dXJuIGJhc2VUeXBlID09PSBcImFycmF5XCIgPyBuZXcgQXJyYXlPZihzdWJUeXBlKSA6XG4gICAgICBiYXNlVHlwZSA9PT0gXCJudWxsYWJsZVwiID8gbmV3IE1heWJlKHN1YlR5cGUpIDpcbiAgICAgIG51bGw7XG4gICAgfTtcblxuICAgIHZhciBtYWtlQ2F0ZWdvcnlUeXBlID0gZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgdmFyIGNhdGVnb3J5ID0gZGVzY3JpcHRvci5jYXRlZ29yeTtcbiAgICAgIHJldHVybiBjYXRlZ29yeSA9PT0gXCJkaWN0XCIgPyBuZXcgRGljdGlvbmFyeShkZXNjcmlwdG9yKSA6XG4gICAgICBjYXRlZ29yeSA9PT0gXCJhY3RvclwiID8gbmV3IEFjdG9yKGRlc2NyaXB0b3IpIDpcbiAgICAgIG51bGw7XG4gICAgfTtcblxuICAgIHZhciByZWFkID0gZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQsIHR5cGVOYW1lKSB7XG4gICAgICByZXR1cm4gdHlwZUZvcih0eXBlTmFtZSkucmVhZChpbnB1dCwgY29udGV4dCk7XG4gICAgfVxuICAgIHRoaXMucmVhZCA9IHJlYWQ7XG5cbiAgICB2YXIgd3JpdGUgPSBmdW5jdGlvbihpbnB1dCwgY29udGV4dCwgdHlwZU5hbWUpIHtcbiAgICAgIHJldHVybiB0eXBlRm9yKHR5cGVOYW1lKS53cml0ZShpbnB1dCk7XG4gICAgfTtcbiAgICB0aGlzLndyaXRlID0gd3JpdGU7XG5cblxuICAgIHZhciBUeXBlID0gQ2xhc3Moe1xuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgICAgfSxcbiAgICAgIGdldCBuYW1lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYXRlZ29yeSA/IHRoaXMuY2F0ZWdvcnkgKyBcIjpcIiArIHRoaXMudHlwZSA6XG4gICAgICAgIHRoaXMudHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFR5cGVgIHN1YmNsYXNzIG11c3QgaW1wbGVtZW50IGByZWFkYFwiKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcImBUeXBlYCBzdWJjbGFzcyBtdXN0IGltcGxlbWVudCBgd3JpdGVgXCIpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIFByaW1pdHZlID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogVHlwZSxcbiAgICAgIGNvbnN0dWN0b3I6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQ7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBpbnB1dDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHZhciBNYXliZSA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJudWxsYWJsZVwiLFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQgPT09IG51bGwgPyBudWxsIDpcbiAgICAgICAgaW5wdXQgPT09IHZvaWQoMCkgPyB2b2lkKDApIDpcbiAgICAgICAgcmVhZChpbnB1dCwgY29udGV4dCwgdGhpcy50eXBlKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0ID09PSBudWxsID8gbnVsbCA6XG4gICAgICAgIGlucHV0ID09PSB2b2lkKDApID8gdm9pZCgwKSA6XG4gICAgICAgIHdyaXRlKGlucHV0LCBjb250ZXh0LCB0aGlzLnR5cGUpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIEFycmF5T2YgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBUeXBlLFxuICAgICAgY2F0ZWdvcnk6IFwiYXJyYXlcIixcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbih0eXBlKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIHR5cGUgPSB0aGlzLnR5cGU7XG4gICAgICAgIHJldHVybiBpbnB1dC5tYXAoZnVuY3Rpb24oJCkgeyByZXR1cm4gcmVhZCgkLCBjb250ZXh0LCB0eXBlKSB9KTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIHR5cGUgPSB0aGlzLnR5cGU7XG4gICAgICAgIHJldHVybiBpbnB1dC5tYXAoZnVuY3Rpb24oJCkgeyByZXR1cm4gd3JpdGUoJCwgY29udGV4dCwgdHlwZSkgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgbWFrZUZpZWxkID0gZnVuY3Rpb24gbWFrZUZpZWxkKG5hbWUsIHR5cGUpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgbmFtZSwge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHZhbHVlOiByZWFkKHRoaXMuc3RhdGVbbmFtZV0sIHRoaXMuY29udGV4dCwgdHlwZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gdGhpc1tuYW1lXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgbWFrZUZpZWxkcyA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgIHJldHVybiBwYWlycyhkZXNjcmlwdG9yKS5yZWR1Y2UoZnVuY3Rpb24oZmllbGRzLCBwYWlyKSB7XG4gICAgICAgIHZhciBuYW1lID0gcGFpclswXSwgdHlwZSA9IHBhaXJbMV07XG4gICAgICAgIGZpZWxkc1tuYW1lXSA9IG1ha2VGaWVsZChuYW1lLCB0eXBlKTtcbiAgICAgICAgcmV0dXJuIGZpZWxkcztcbiAgICAgIH0sIHt9KTtcbiAgICB9XG5cbiAgICB2YXIgRGljdGlvbmFyeVR5cGUgPSBDbGFzcyh7fSk7XG5cbiAgICB2YXIgRGljdGlvbmFyeSA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJkaWN0XCIsXG4gICAgICBnZXQgbmFtZSgpIHsgcmV0dXJuIHRoaXMudHlwZTsgfSxcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IGRlc2NyaXB0b3IudHlwZU5hbWU7XG4gICAgICAgIHRoaXMudHlwZXMgPSBkZXNjcmlwdG9yLnNwZWNpYWxpemF0aW9ucztcblxuICAgICAgICB2YXIgcHJvdG8gPSBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh7XG4gICAgICAgICAgZXh0ZW5kczogRGljdGlvbmFyeVR5cGUsXG4gICAgICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKHN0YXRlLCBjb250ZXh0KSB7XG4gICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBzdGF0ZVxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogY29udGV4dFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIG1ha2VGaWVsZHModGhpcy50eXBlcykpO1xuXG4gICAgICAgIHRoaXMuY2xhc3MgPSBuZXcgQ2xhc3MocHJvdG8pO1xuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBuZXcgdGhpcy5jbGFzcyhpbnB1dCwgY29udGV4dCk7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB7fTtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIGlucHV0KSB7XG4gICAgICAgICAgb3V0cHV0W2tleV0gPSB3cml0ZSh2YWx1ZSwgY29udGV4dCwgdHlwZXNba2V5XSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG91dHB1dDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHZhciBtYWtlTWV0aG9kcyA9IGZ1bmN0aW9uKGRlc2NyaXB0b3JzKSB7XG4gICAgICByZXR1cm4gZGVzY3JpcHRvcnMucmVkdWNlKGZ1bmN0aW9uKG1ldGhvZHMsIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgbWV0aG9kc1tkZXNjcmlwdG9yLm5hbWVdID0ge1xuICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgICB2YWx1ZTogbWFrZU1ldGhvZChkZXNjcmlwdG9yKVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gbWV0aG9kcztcbiAgICAgIH0sIHt9KTtcbiAgICB9O1xuXG4gICAgdmFyIG1ha2VFdmVudHMgPSBmdW5jdGlvbihkZXNjcmlwdG9ycykge1xuICAgICAgcmV0dXJuIHBhaXJzKGRlc2NyaXB0b3JzKS5yZWR1Y2UoZnVuY3Rpb24oZXZlbnRzLCBwYWlyKSB7XG4gICAgICAgIHZhciBuYW1lID0gcGFpclswXSwgZGVzY3JpcHRvciA9IHBhaXJbMV07XG4gICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudChuYW1lLCBkZXNjcmlwdG9yKTtcbiAgICAgICAgZXZlbnRzW2V2ZW50LmV2ZW50VHlwZV0gPSBldmVudDtcbiAgICAgICAgcmV0dXJuIGV2ZW50cztcbiAgICAgIH0sIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuICAgIH07XG5cbiAgICB2YXIgQWN0b3IgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBUeXBlLFxuICAgICAgY2F0ZWdvcnk6IFwiYWN0b3JcIixcbiAgICAgIGdldCBuYW1lKCkgeyByZXR1cm4gdGhpcy50eXBlOyB9LFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgICAgdGhpcy50eXBlID0gZGVzY3JpcHRvci50eXBlTmFtZTtcblxuICAgICAgICB2YXIgZXZlbnRzID0gbWFrZUV2ZW50cyhkZXNjcmlwdG9yLmV2ZW50cyB8fCB7fSk7XG4gICAgICAgIHZhciBmaWVsZHMgPSBtYWtlRmllbGRzKGRlc2NyaXB0b3IuZmllbGRzIHx8IHt9KTtcbiAgICAgICAgdmFyIG1ldGhvZHMgPSBtYWtlTWV0aG9kcyhkZXNjcmlwdG9yLm1ldGhvZHMgfHwgW10pO1xuXG5cbiAgICAgICAgdmFyIHByb3RvID0ge1xuICAgICAgICAgIGV4dGVuZHM6IEZyb250LFxuICAgICAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIEZyb250LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBldmVudHM6IGV2ZW50c1xuICAgICAgICB9O1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhwcm90bywgZmllbGRzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMocHJvdG8sIG1ldGhvZHMpO1xuXG4gICAgICAgIHRoaXMuY2xhc3MgPSBDbGFzcyhwcm90byk7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQsIGRldGFpbCkge1xuICAgICAgICB2YXIgc3RhdGUgPSB0eXBlb2YoaW5wdXQpID09PSBcInN0cmluZ1wiID8geyBhY3RvcjogaW5wdXQgfSA6IGlucHV0O1xuXG4gICAgICAgIHZhciBhY3RvciA9IGNsaWVudC5nZXQoc3RhdGUuYWN0b3IpIHx8IG5ldyB0aGlzLmNsYXNzKHN0YXRlLCBjb250ZXh0KTtcbiAgICAgICAgYWN0b3IuZm9ybShzdGF0ZSwgZGV0YWlsLCBjb250ZXh0KTtcblxuICAgICAgICByZXR1cm4gYWN0b3I7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0LCBkZXRhaWwpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0LmlkO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGV4cG9ydHMuQWN0b3IgPSBBY3RvcjtcblxuXG4gICAgdmFyIEFjdG9yRGV0YWlsID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogQWN0b3IsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24obmFtZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBuYW1lLnNwbGl0KFwiI1wiKVxuICAgICAgICB0aGlzLmFjdG9yVHlwZSA9IHBhcnRzWzBdXG4gICAgICAgIHRoaXMuZGV0YWlsID0gcGFydHNbMV07XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVGb3IodGhpcy5hY3RvclR5cGUpLnJlYWQoaW5wdXQsIGNvbnRleHQsIHRoaXMuZGV0YWlsKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVGb3IodGhpcy5hY3RvclR5cGUpLndyaXRlKGlucHV0LCBjb250ZXh0LCB0aGlzLmRldGFpbCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZXhwb3J0cy5BY3RvckRldGFpbCA9IEFjdG9yRGV0YWlsO1xuXG4gICAgdmFyIE1ldGhvZCA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgICB0aGlzLnR5cGUgPSBkZXNjcmlwdG9yLm5hbWU7XG4gICAgICAgIHRoaXMucGF0aCA9IGZpbmRQYXRoKGRlc2NyaXB0b3IucmVzcG9uc2UsIFwiX3JldHZhbFwiKTtcbiAgICAgICAgdGhpcy5yZXNwb25zZVR5cGUgPSB0aGlzLnBhdGggJiYgcXVlcnkoZGVzY3JpcHRvci5yZXNwb25zZSwgdGhpcy5wYXRoKS5fcmV0dmFsO1xuICAgICAgICB0aGlzLnJlcXVlc3RUeXBlID0gZGVzY3JpcHRvci5yZXF1ZXN0LnR5cGU7XG5cbiAgICAgICAgdmFyIHBhcmFtcyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gZGVzY3JpcHRvci5yZXF1ZXN0KSB7XG4gICAgICAgICAgaWYgKGtleSAhPT0gXCJ0eXBlXCIpIHtcbiAgICAgICAgICAgIHZhciBwYXJhbSA9IGRlc2NyaXB0b3IucmVxdWVzdFtrZXldO1xuICAgICAgICAgICAgdmFyIGluZGV4ID0gXCJfYXJnXCIgaW4gcGFyYW0gPyBwYXJhbS5fYXJnIDogcGFyYW0uX29wdGlvbjtcbiAgICAgICAgICAgIHZhciBpc1BhcmFtID0gcGFyYW0uX29wdGlvbiA9PT0gaW5kZXg7XG4gICAgICAgICAgICB2YXIgaXNBcmd1bWVudCA9IHBhcmFtLl9hcmcgPT09IGluZGV4O1xuICAgICAgICAgICAgcGFyYW1zW2luZGV4XSA9IHtcbiAgICAgICAgICAgICAgdHlwZTogcGFyYW0udHlwZSxcbiAgICAgICAgICAgICAga2V5OiBrZXksXG4gICAgICAgICAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgICAgICAgICAgaXNQYXJhbTogaXNQYXJhbSxcbiAgICAgICAgICAgICAgaXNBcmd1bWVudDogaXNBcmd1bWVudFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5wYXJhbXMgPSBwYXJhbXM7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHJlYWQocXVlcnkoaW5wdXQsIHRoaXMucGF0aCksIGNvbnRleHQsIHRoaXMucmVzcG9uc2VUeXBlKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyYW1zLnJlZHVjZShmdW5jdGlvbihyZXN1bHQsIHBhcmFtKSB7XG4gICAgICAgICAgcmVzdWx0W3BhcmFtLmtleV0gPSB3cml0ZShpbnB1dFtwYXJhbS5pbmRleF0sIGNvbnRleHQsIHBhcmFtLnR5cGUpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sIHt0eXBlOiB0aGlzLnR5cGV9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBleHBvcnRzLk1ldGhvZCA9IE1ldGhvZDtcblxuICAgIHZhciBwcm9maWxlciA9IGZ1bmN0aW9uKG1ldGhvZCwgaWQpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHN0YXJ0ID0gbmV3IERhdGUoKTtcbiAgICAgICAgcmV0dXJuIG1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7XG4gICAgICAgICAgdmFyIGVuZCA9IG5ldyBEYXRlKCk7XG4gICAgICAgICAgY2xpZW50LnRlbGVtZXRyeS5hZGQoaWQsICtlbmQgLSBzdGFydCk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgZGVzdHJ1Y3RvciA9IGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykudGhlbihmdW5jdGlvbihyZXN1bHQpIHtcbiAgICAgICAgICBjbGllbnQucmVsZWFzZSh0aGlzKTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIG1ha2VNZXRob2QoZGVzY3JpcHRvcikge1xuICAgICAgdmFyIHR5cGUgPSBuZXcgTWV0aG9kKGRlc2NyaXB0b3IpO1xuICAgICAgdmFyIG1ldGhvZCA9IGRlc2NyaXB0b3Iub25ld2F5ID8gbWFrZVVuaWRpcmVjYXRpb25hbE1ldGhvZChkZXNjcmlwdG9yLCB0eXBlKSA6XG4gICAgICAgICAgICAgICAgICAgbWFrZUJpZGlyZWN0aW9uYWxNZXRob2QoZGVzY3JpcHRvciwgdHlwZSk7XG5cbiAgICAgIGlmIChkZXNjcmlwdG9yLnRlbGVtZXRyeSlcbiAgICAgICAgbWV0aG9kID0gcHJvZmlsZXIobWV0aG9kKTtcbiAgICAgIGlmIChkZXNjcmlwdG9yLnJlbGVhc2UpXG4gICAgICAgIG1ldGhvZCA9IGRlc3RydWN0b3IobWV0aG9kKTtcblxuICAgICAgcmV0dXJuIG1ldGhvZDtcbiAgICB9XG5cbiAgICB2YXIgbWFrZVVuaWRpcmVjYXRpb25hbE1ldGhvZCA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IsIHR5cGUpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHBhY2tldCA9IHR5cGUud3JpdGUoYXJndW1lbnRzLCB0aGlzKTtcbiAgICAgICAgcGFja2V0LnRvID0gdGhpcy5pZDtcbiAgICAgICAgY2xpZW50LnNlbmQocGFja2V0KTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh2b2lkKDApKTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBtYWtlQmlkaXJlY3Rpb25hbE1ldGhvZCA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IsIHR5cGUpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIHZhciBwYWNrZXQgPSB0eXBlLndyaXRlKGFyZ3VtZW50cywgY29udGV4dCk7XG4gICAgICAgIHZhciBjb250ZXh0ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBwYWNrZXQudG8gPSB0aGlzLmlkO1xuICAgICAgICByZXR1cm4gY2xpZW50LnJlcXVlc3QocGFja2V0KS50aGVuKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgICAgICAgIHJldHVybiB0eXBlLnJlYWQocGFja2V0LCBjb250ZXh0KTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgRXZlbnQgPSBDbGFzcyh7XG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24obmFtZSwgZGVzY3JpcHRvcikge1xuICAgICAgICB0aGlzLm5hbWUgPSBkZXNjcmlwdG9yLnR5cGUgfHwgbmFtZTtcbiAgICAgICAgdGhpcy5ldmVudFR5cGUgPSBkZXNjcmlwdG9yLnR5cGUgfHwgbmFtZTtcbiAgICAgICAgdGhpcy50eXBlcyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbiAgICAgICAgdmFyIHR5cGVzID0gdGhpcy50eXBlcztcbiAgICAgICAgZm9yICh2YXIga2V5IGluIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgICBpZiAoa2V5ID09PSBcInR5cGVcIikge1xuICAgICAgICAgICAgdHlwZXNba2V5XSA9IFwic3RyaW5nXCI7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHR5cGVzW2tleV0gPSBkZXNjcmlwdG9yW2tleV0udHlwZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgb3V0cHV0ID0ge307XG4gICAgICAgIHZhciB0eXBlcyA9IHRoaXMudHlwZXM7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiBpbnB1dCkge1xuICAgICAgICAgIG91dHB1dFtrZXldID0gcmVhZChpbnB1dFtrZXldLCBjb250ZXh0LCB0eXBlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgb3V0cHV0ID0ge307XG4gICAgICAgIHZhciB0eXBlcyA9IHRoaXMudHlwZXM7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiB0aGlzLnR5cGVzKSB7XG4gICAgICAgICAgb3V0cHV0W2tleV0gPSB3cml0ZShpbnB1dFtrZXldLCBjb250ZXh0LCB0eXBlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIEZyb250ID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogRXZlbnRUYXJnZXQsXG4gICAgICBFdmVudFRhcmdldDogRXZlbnRUYXJnZXQsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oc3RhdGUpIHtcbiAgICAgICAgdGhpcy5FdmVudFRhcmdldCgpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCAge1xuICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHN0YXRlXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBjbGllbnQucmVnaXN0ZXIodGhpcyk7XG4gICAgICB9LFxuICAgICAgZ2V0IGlkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5hY3RvcjtcbiAgICAgIH0sXG4gICAgICBnZXQgY29udGV4dCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9LFxuICAgICAgZm9ybTogZnVuY3Rpb24oc3RhdGUsIGRldGFpbCwgY29udGV4dCkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZSAhPT0gc3RhdGUpIHtcbiAgICAgICAgICBpZiAoZGV0YWlsKSB7XG4gICAgICAgICAgICB0aGlzLnN0YXRlW2RldGFpbF0gPSBzdGF0ZVtkZXRhaWxdO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYWlycyhzdGF0ZSkuZm9yRWFjaChmdW5jdGlvbihwYWlyKSB7XG4gICAgICAgICAgICAgIHZhciBrZXkgPSBwYWlyWzBdLCB2YWx1ZSA9IHBhaXJbMV07XG4gICAgICAgICAgICAgIHRoaXMuc3RhdGVba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbnRleHQpIHtcbiAgICAgICAgICBjbGllbnQuc3VwZXJ2aXNlKGNvbnRleHQsIHRoaXMpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVxdWVzdFR5cGVzOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIGNsaWVudC5yZXF1ZXN0KHtcbiAgICAgICAgICB0bzogdGhpcy5pZCxcbiAgICAgICAgICB0eXBlOiBcInJlcXVlc3RUeXBlc1wiXG4gICAgICAgIH0pLnRoZW4oZnVuY3Rpb24ocGFja2V0KSB7XG4gICAgICAgICAgcmV0dXJuIHBhY2tldC5yZXF1ZXN0VHlwZXM7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHR5cGVzLnByaW1pdGl2ZSA9IG5ldyBQcmltaXR2ZShcInByaW1pdGl2ZVwiKTtcbiAgICB0eXBlcy5zdHJpbmcgPSBuZXcgUHJpbWl0dmUoXCJzdHJpbmdcIik7XG4gICAgdHlwZXMubnVtYmVyID0gbmV3IFByaW1pdHZlKFwibnVtYmVyXCIpO1xuICAgIHR5cGVzLmJvb2xlYW4gPSBuZXcgUHJpbWl0dmUoXCJib29sZWFuXCIpO1xuICAgIHR5cGVzLmpzb24gPSBuZXcgUHJpbWl0dmUoXCJqc29uXCIpO1xuICAgIHR5cGVzLmFycmF5ID0gbmV3IFByaW1pdHZlKFwiYXJyYXlcIik7XG4gIH0sXG4gIHJlZ2lzdGVyVHlwZXM6IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICB2YXIgc3BlY2lmaWNhdGlvbiA9IHRoaXMuc3BlY2lmaWNhdGlvbjtcbiAgICB2YWx1ZXMoZGVzY3JpcHRvci50eXBlcykuZm9yRWFjaChmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICBzcGVjaWZpY2F0aW9uW2Rlc2NyaXB0b3IudHlwZU5hbWVdID0gZGVzY3JpcHRvcjtcbiAgICB9KTtcbiAgfVxufSk7XG5leHBvcnRzLlR5cGVTeXN0ZW0gPSBUeXBlU3lzdGVtO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBrZXlzID0gT2JqZWN0LmtleXM7XG5leHBvcnRzLmtleXMgPSBrZXlzO1xuXG4vLyBSZXR1cm5zIGFycmF5IG9mIHZhbHVlcyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cbnZhciB2YWx1ZXMgPSBmdW5jdGlvbihvYmplY3QpIHtcbiAgcmV0dXJuIGtleXMob2JqZWN0KS5tYXAoZnVuY3Rpb24oa2V5KSB7XG4gICAgcmV0dXJuIG9iamVjdFtrZXldXG4gIH0pO1xufTtcbmV4cG9ydHMudmFsdWVzID0gdmFsdWVzO1xuXG4vLyBSZXR1cm5zIFtrZXksIHZhbHVlXSBwYWlycyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cbnZhciBwYWlycyA9IGZ1bmN0aW9uKG9iamVjdCkge1xuICByZXR1cm4ga2V5cyhvYmplY3QpLm1hcChmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4gW2tleSwgb2JqZWN0W2tleV1dXG4gIH0pO1xufTtcbmV4cG9ydHMucGFpcnMgPSBwYWlycztcblxuXG4vLyBRdWVyaWVzIGFuIG9iamVjdCBmb3IgdGhlIGZpZWxkIG5lc3RlZCB3aXRoIGluIGl0LlxudmFyIHF1ZXJ5ID0gZnVuY3Rpb24ob2JqZWN0LCBwYXRoKSB7XG4gIHJldHVybiBwYXRoLnJlZHVjZShmdW5jdGlvbihvYmplY3QsIGVudHJ5KSB7XG4gICAgcmV0dXJuIG9iamVjdCAmJiBvYmplY3RbZW50cnldXG4gIH0sIG9iamVjdCk7XG59O1xuZXhwb3J0cy5xdWVyeSA9IHF1ZXJ5O1xuXG52YXIgaXNPYmplY3QgPSBmdW5jdGlvbih4KSB7XG4gIHJldHVybiB4ICYmIHR5cGVvZih4KSA9PT0gXCJvYmplY3RcIlxufVxuXG52YXIgZmluZFBhdGggPSBmdW5jdGlvbihvYmplY3QsIGtleSkge1xuICB2YXIgcGF0aCA9IHZvaWQoMCk7XG4gIGlmIChvYmplY3QgJiYgdHlwZW9mKG9iamVjdCkgPT09IFwib2JqZWN0XCIpIHtcbiAgICB2YXIgbmFtZXMgPSBrZXlzKG9iamVjdCk7XG4gICAgaWYgKG5hbWVzLmluZGV4T2Yoa2V5KSA+PSAwKSB7XG4gICAgICBwYXRoID0gW107XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBpbmRleCA9IDA7XG4gICAgICB2YXIgY291bnQgPSBuYW1lcy5sZW5ndGg7XG4gICAgICB3aGlsZSAoaW5kZXggPCBjb3VudCAmJiAhcGF0aCl7XG4gICAgICAgIHZhciBoZWFkID0gbmFtZXNbaW5kZXhdO1xuICAgICAgICB2YXIgdGFpbCA9IGZpbmRQYXRoKG9iamVjdFtoZWFkXSwga2V5KTtcbiAgICAgICAgcGF0aCA9IHRhaWwgPyBbaGVhZF0uY29uY2F0KHRhaWwpIDogdGFpbDtcbiAgICAgICAgaW5kZXggPSBpbmRleCArIDFcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHBhdGg7XG59O1xuZXhwb3J0cy5maW5kUGF0aCA9IGZpbmRQYXRoO1xuIl19
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vYnJvd3Nlci9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2Jyb3dzZXIvcHJvbWlzZS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2NsYXNzLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vY2xpZW50LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vZXZlbnQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL2luZGV4LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvaXMtaW1wbGVtZW50ZWQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZC9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9hc3NpZ24vaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvYXNzaWduL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2Fzc2lnbi9zaGltLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2lzLWNhbGxhYmxlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2tleXMvaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qva2V5cy9pcy1pbXBsZW1lbnRlZC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9rZXlzL3NoaW0uanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qvbm9ybWFsaXplLW9wdGlvbnMuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvdmFsaWQtdmFsdWUuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9zdHJpbmcvIy9jb250YWlucy9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L3N0cmluZy8jL2NvbnRhaW5zL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvc3RyaW5nLyMvY29udGFpbnMvc2hpbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL3BvbHlmaWxsLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vc3BlY2lmaWNhdGlvbi9jb3JlLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9zcGVjaWZpY2F0aW9uL3Byb3RvY29sLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi90eXBlLXN5c3RlbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL3V0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9TQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsaWVudCA9IHJlcXVpcmUoXCIuLi9jbGllbnRcIikuQ2xpZW50O1xuXG5mdW5jdGlvbiBjb25uZWN0KHBvcnQpIHtcbiAgdmFyIGNsaWVudCA9IG5ldyBDbGllbnQoKTtcbiAgcmV0dXJuIGNsaWVudC5jb25uZWN0KHBvcnQpO1xufVxuZXhwb3J0cy5jb25uZWN0ID0gY29ubmVjdDtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5leHBvcnRzLlByb21pc2UgPSBQcm9taXNlO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBkZXNjcmliZSA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7XG52YXIgQ2xhc3MgPSBmdW5jdGlvbihmaWVsZHMpIHtcbiAgdmFyIG5hbWVzID0gT2JqZWN0LmtleXMoZmllbGRzKTtcbiAgdmFyIGNvbnN0cnVjdG9yID0gbmFtZXMuaW5kZXhPZihcImNvbnN0cnVjdG9yXCIpID49IDAgPyBmaWVsZHMuY29uc3RydWN0b3IgOlxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHt9O1xuICB2YXIgYW5jZXN0b3IgPSBmaWVsZHMuZXh0ZW5kcyB8fCBPYmplY3Q7XG5cbiAgdmFyIGRlc2NyaXB0b3IgPSBuYW1lcy5yZWR1Y2UoZnVuY3Rpb24oZGVzY3JpcHRvciwga2V5KSB7XG4gICAgZGVzY3JpcHRvcltrZXldID0gZGVzY3JpYmUoZmllbGRzLCBrZXkpO1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9LCB7fSk7XG5cbiAgdmFyIHByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYW5jZXN0b3IucHJvdG90eXBlLCBkZXNjcmlwdG9yKTtcblxuICBjb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gIHByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IGNvbnN0cnVjdG9yO1xuXG4gIHJldHVybiBjb25zdHJ1Y3Rvcjtcbn07XG5leHBvcnRzLkNsYXNzID0gQ2xhc3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG52YXIgVHlwZVN5c3RlbSA9IHJlcXVpcmUoXCIuL3R5cGUtc3lzdGVtXCIpLlR5cGVTeXN0ZW07XG52YXIgdmFsdWVzID0gcmVxdWlyZShcIi4vdXRpbFwiKS52YWx1ZXM7XG52YXIgUHJvbWlzZSA9IHJlcXVpcmUoXCJlczYtcHJvbWlzZVwiKS5Qcm9taXNlO1xudmFyIE1lc3NhZ2VFdmVudCA9IHJlcXVpcmUoXCIuL2V2ZW50XCIpLk1lc3NhZ2VFdmVudDtcblxudmFyIHNwZWNpZmljYXRpb24gPSByZXF1aXJlKFwiLi9zcGVjaWZpY2F0aW9uL2NvcmUuanNvblwiKTtcblxuZnVuY3Rpb24gcmVjb3ZlckFjdG9yRGVzY3JpcHRpb25zKGVycm9yKSB7XG4gIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBmZXRjaCBwcm90b2NvbCBzcGVjaWZpY2F0aW9uIChzZWUgcmVhc29uIGJlbG93KS4gXCIgK1xuICAgICAgICAgICAgICAgXCJVc2luZyBhIGZhbGxiYWNrIHByb3RvY2FsIHNwZWNpZmljYXRpb24hXCIsXG4gICAgICAgICAgICAgICBlcnJvcik7XG4gIHJldHVybiByZXF1aXJlKFwiLi9zcGVjaWZpY2F0aW9uL3Byb3RvY29sLmpzb25cIik7XG59XG5cbi8vIFR5cGUgdG8gcmVwcmVzZW50IHN1cGVydmlzZXIgYWN0b3IgcmVsYXRpb25zIHRvIGFjdG9ycyB0aGV5IHN1cGVydmlzZVxuLy8gaW4gdGVybXMgb2YgbGlmZXRpbWUgbWFuYWdlbWVudC5cbnZhciBTdXBlcnZpc29yID0gQ2xhc3Moe1xuICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oaWQpIHtcbiAgICB0aGlzLmlkID0gaWQ7XG4gICAgdGhpcy53b3JrZXJzID0gW107XG4gIH1cbn0pO1xuXG52YXIgVGVsZW1ldHJ5ID0gQ2xhc3Moe1xuICBhZGQ6IGZ1bmN0aW9uKGlkLCBtcykge1xuICAgIGNvbnNvbGUubG9nKFwidGVsZW1ldHJ5OjpcIiwgaWQsIG1zKVxuICB9XG59KTtcblxuLy8gQ29uc2lkZXIgbWFraW5nIGNsaWVudCBhIHJvb3QgYWN0b3IuXG5cbnZhciBDbGllbnQgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJvb3QgPSBudWxsO1xuICAgIHRoaXMudGVsZW1ldHJ5ID0gbmV3IFRlbGVtZXRyeSgpO1xuXG4gICAgdGhpcy5zZXR1cENvbm5lY3Rpb24oKTtcbiAgICB0aGlzLnNldHVwTGlmZU1hbmFnZW1lbnQoKTtcbiAgICB0aGlzLnNldHVwVHlwZVN5c3RlbSgpO1xuICB9LFxuXG4gIHNldHVwQ29ubmVjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5yZXF1ZXN0cyA9IFtdO1xuICB9LFxuICBzZXR1cExpZmVNYW5hZ2VtZW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmNhY2hlID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB0aGlzLmdyYXBoID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB0aGlzLmdldCA9IHRoaXMuZ2V0LmJpbmQodGhpcyk7XG4gICAgdGhpcy5yZWxlYXNlID0gdGhpcy5yZWxlYXNlLmJpbmQodGhpcyk7XG4gIH0sXG4gIHNldHVwVHlwZVN5c3RlbTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy50eXBlU3lzdGVtID0gbmV3IFR5cGVTeXN0ZW0odGhpcyk7XG4gICAgdGhpcy50eXBlU3lzdGVtLnJlZ2lzdGVyVHlwZXMoc3BlY2lmaWNhdGlvbik7XG4gIH0sXG5cbiAgY29ubmVjdDogZnVuY3Rpb24ocG9ydCkge1xuICAgIHZhciBjbGllbnQgPSB0aGlzO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIGNsaWVudC5wb3J0ID0gcG9ydDtcbiAgICAgIHBvcnQub25tZXNzYWdlID0gY2xpZW50LnJlY2VpdmUuYmluZChjbGllbnQpO1xuICAgICAgY2xpZW50Lm9uUmVhZHkgPSByZXNvbHZlO1xuICAgICAgY2xpZW50Lm9uRmFpbCA9IHJlamVjdDtcblxuICAgICAgcG9ydC5zdGFydCgpO1xuICAgIH0pO1xuICB9LFxuICBzZW5kOiBmdW5jdGlvbihwYWNrZXQpIHtcbiAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2UocGFja2V0KTtcbiAgfSxcbiAgcmVxdWVzdDogZnVuY3Rpb24ocGFja2V0KSB7XG4gICAgdmFyIGNsaWVudCA9IHRoaXM7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgY2xpZW50LnJlcXVlc3RzLnB1c2gocGFja2V0LnRvLCB7IHJlc29sdmU6IHJlc29sdmUsIHJlamVjdDogcmVqZWN0IH0pO1xuICAgICAgY2xpZW50LnNlbmQocGFja2V0KTtcbiAgICB9KTtcbiAgfSxcblxuICByZWNlaXZlOiBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciBwYWNrZXQgPSBldmVudC5kYXRhO1xuICAgIGlmICghdGhpcy5yb290KSB7XG4gICAgICBpZiAocGFja2V0LmZyb20gIT09IFwicm9vdFwiKVxuICAgICAgICB0aHJvdyBFcnJvcihcIkluaXRpYWwgcGFja2V0IG11c3QgYmUgZnJvbSByb290XCIpO1xuICAgICAgaWYgKCEoXCJhcHBsaWNhdGlvblR5cGVcIiBpbiBwYWNrZXQpKVxuICAgICAgICB0aHJvdyBFcnJvcihcIkluaXRpYWwgcGFja2V0IG11c3QgY29udGFpbiBhcHBsaWNhdGlvblR5cGUgZmllbGRcIik7XG5cbiAgICAgIHRoaXMucm9vdCA9IHRoaXMudHlwZVN5c3RlbS5yZWFkKFwicm9vdFwiLCBudWxsLCBcInJvb3RcIik7XG4gICAgICB0aGlzLnJvb3RcbiAgICAgICAgICAucHJvdG9jb2xEZXNjcmlwdGlvbigpXG4gICAgICAgICAgLmNhdGNoKHJlY292ZXJBY3RvckRlc2NyaXB0aW9ucylcbiAgICAgICAgICAudGhlbih0aGlzLnR5cGVTeXN0ZW0ucmVnaXN0ZXJUeXBlcy5iaW5kKHRoaXMudHlwZVN5c3RlbSkpXG4gICAgICAgICAgLnRoZW4odGhpcy5vblJlYWR5LmJpbmQodGhpcywgdGhpcy5yb290KSwgdGhpcy5vbkZhaWwpO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgYWN0b3IgPSB0aGlzLmdldChwYWNrZXQuZnJvbSkgfHwgdGhpcy5yb290O1xuICAgICAgdmFyIGV2ZW50ID0gYWN0b3IuZXZlbnRzW3BhY2tldC50eXBlXTtcbiAgICAgIGlmIChldmVudCkge1xuICAgICAgICB2YXIgbWVzc2FnZSA9IG5ldyBNZXNzYWdlRXZlbnQocGFja2V0LnR5cGUsIHtcbiAgICAgICAgICBkYXRhOiBldmVudC5yZWFkKHBhY2tldClcbiAgICAgICAgfSk7XG4gICAgICAgIGFjdG9yLmRpc3BhdGNoRXZlbnQobWVzc2FnZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgaW5kZXggPSB0aGlzLnJlcXVlc3RzLmluZGV4T2YoYWN0b3IuaWQpO1xuICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgICAgIHZhciByZXF1ZXN0ID0gdGhpcy5yZXF1ZXN0cy5zcGxpY2UoaW5kZXgsIDIpLnBvcCgpO1xuICAgICAgICAgIGlmIChwYWNrZXQuZXJyb3IpXG4gICAgICAgICAgICByZXF1ZXN0LnJlamVjdChwYWNrZXQpO1xuICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJlcXVlc3QucmVzb2x2ZShwYWNrZXQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoRXJyb3IoXCJVbmV4cGVjdGVkIHBhY2tldCBcIiArIEpTT04uc3RyaW5naWZ5KHBhY2tldCwgMiwgMikpLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGFja2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0cy5zbGljZSgwKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgZ2V0OiBmdW5jdGlvbihpZCkge1xuICAgIHJldHVybiB0aGlzLmNhY2hlW2lkXTtcbiAgfSxcbiAgc3VwZXJ2aXNvck9mOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIGZvciAodmFyIGlkIGluIHRoaXMuZ3JhcGgpIHtcbiAgICAgIGlmICh0aGlzLmdyYXBoW2lkXS5pbmRleE9mKGFjdG9yLmlkKSA+PSAwKSB7XG4gICAgICAgIHJldHVybiBpZDtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHdvcmtlcnNPZjogZnVuY3Rpb24oYWN0b3IpIHtcbiAgICByZXR1cm4gdGhpcy5ncmFwaFthY3Rvci5pZF07XG4gIH0sXG4gIHN1cGVydmlzZTogZnVuY3Rpb24oYWN0b3IsIHdvcmtlcikge1xuICAgIHZhciB3b3JrZXJzID0gdGhpcy53b3JrZXJzT2YoYWN0b3IpXG4gICAgaWYgKHdvcmtlcnMuaW5kZXhPZih3b3JrZXIuaWQpIDwgMCkge1xuICAgICAgd29ya2Vycy5wdXNoKHdvcmtlci5pZCk7XG4gICAgfVxuICB9LFxuICB1bnN1cGVydmlzZTogZnVuY3Rpb24oYWN0b3IsIHdvcmtlcikge1xuICAgIHZhciB3b3JrZXJzID0gdGhpcy53b3JrZXJzT2YoYWN0b3IpO1xuICAgIHZhciBpbmRleCA9IHdvcmtlcnMuaW5kZXhPZih3b3JrZXIuaWQpXG4gICAgaWYgKGluZGV4ID49IDApIHtcbiAgICAgIHdvcmtlcnMuc3BsaWNlKGluZGV4LCAxKVxuICAgIH1cbiAgfSxcblxuICByZWdpc3RlcjogZnVuY3Rpb24oYWN0b3IpIHtcbiAgICB2YXIgcmVnaXN0ZXJlZCA9IHRoaXMuZ2V0KGFjdG9yLmlkKTtcbiAgICBpZiAoIXJlZ2lzdGVyZWQpIHtcbiAgICAgIHRoaXMuY2FjaGVbYWN0b3IuaWRdID0gYWN0b3I7XG4gICAgICB0aGlzLmdyYXBoW2FjdG9yLmlkXSA9IFtdO1xuICAgIH0gZWxzZSBpZiAocmVnaXN0ZXJlZCAhPT0gYWN0b3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkRpZmZlcmVudCBhY3RvciB3aXRoIHNhbWUgaWQgaXMgYWxyZWFkeSByZWdpc3RlcmVkXCIpO1xuICAgIH1cbiAgfSxcbiAgdW5yZWdpc3RlcjogZnVuY3Rpb24oYWN0b3IpIHtcbiAgICBpZiAodGhpcy5nZXQoYWN0b3IuaWQpKSB7XG4gICAgICBkZWxldGUgdGhpcy5jYWNoZVthY3Rvci5pZF07XG4gICAgICBkZWxldGUgdGhpcy5ncmFwaFthY3Rvci5pZF07XG4gICAgfVxuICB9LFxuXG4gIHJlbGVhc2U6IGZ1bmN0aW9uKGFjdG9yKSB7XG4gICAgdmFyIHN1cGVydmlzb3IgPSB0aGlzLnN1cGVydmlzb3JPZihhY3Rvcik7XG4gICAgaWYgKHN1cGVydmlzb3IpXG4gICAgICB0aGlzLnVuc3VwZXJ2aXNlKHN1cGVydmlzb3IsIGFjdG9yKTtcblxuICAgIHZhciB3b3JrZXJzID0gdGhpcy53b3JrZXJzT2YoYWN0b3IpXG5cbiAgICBpZiAod29ya2Vycykge1xuICAgICAgd29ya2Vycy5tYXAodGhpcy5nZXQpLmZvckVhY2godGhpcy5yZWxlYXNlKVxuICAgIH1cbiAgICB0aGlzLnVucmVnaXN0ZXIoYWN0b3IpO1xuICB9XG59KTtcbmV4cG9ydHMuQ2xpZW50ID0gQ2xpZW50O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW1ib2wgPSByZXF1aXJlKFwiZXM2LXN5bWJvbFwiKVxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCJldmVudHNcIikuRXZlbnRFbWl0dGVyO1xudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG5cbnZhciAkYm91bmQgPSBTeW1ib2woXCJFdmVudFRhcmdldC9oYW5kbGVFdmVudFwiKTtcbnZhciAkZW1pdHRlciA9IFN5bWJvbChcIkV2ZW50VGFyZ2V0L2VtaXR0ZXJcIik7XG5cbmZ1bmN0aW9uIG1ha2VIYW5kbGVyKGhhbmRsZXIpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgaGFuZGxlci5oYW5kbGVFdmVudChldmVudCk7XG4gIH1cbn1cblxudmFyIEV2ZW50VGFyZ2V0ID0gQ2xhc3Moe1xuICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICRlbWl0dGVyLCB7XG4gICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgdmFsdWU6IG5ldyBFdmVudEVtaXR0ZXIoKVxuICAgIH0pO1xuICB9LFxuICBhZGRFdmVudExpc3RlbmVyOiBmdW5jdGlvbih0eXBlLCBoYW5kbGVyKSB7XG4gICAgaWYgKHR5cGVvZihoYW5kbGVyKSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aGlzWyRlbWl0dGVyXS5vbih0eXBlLCBoYW5kbGVyKTtcbiAgICB9XG4gICAgZWxzZSBpZiAoaGFuZGxlciAmJiB0eXBlb2YoaGFuZGxlcikgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGlmICghaGFuZGxlclskYm91bmRdKSBoYW5kbGVyWyRib3VuZF0gPSBtYWtlSGFuZGxlcihoYW5kbGVyKTtcbiAgICAgIHRoaXNbJGVtaXR0ZXJdLm9uKHR5cGUsIGhhbmRsZXJbJGJvdW5kXSk7XG4gICAgfVxuICB9LFxuICByZW1vdmVFdmVudExpc3RlbmVyOiBmdW5jdGlvbih0eXBlLCBoYW5kbGVyKSB7XG4gICAgaWYgKHR5cGVvZihoYW5kbGVyKSA9PT0gXCJmdW5jdGlvblwiKVxuICAgICAgdGhpc1skZW1pdHRlcl0ucmVtb3ZlTGlzdGVuZXIodHlwZSwgaGFuZGxlcik7XG4gICAgZWxzZSBpZiAoaGFuZGxlciAmJiBoYW5kbGVyWyRib3VuZF0pXG4gICAgICB0aGlzWyRlbWl0dGVyXS5yZW1vdmVMaXN0ZW5lcih0eXBlLCBoYW5kbGVyWyRib3VuZF0pO1xuICB9LFxuICBkaXNwYXRjaEV2ZW50OiBmdW5jdGlvbihldmVudCkge1xuICAgIGV2ZW50LnRhcmdldCA9IHRoaXM7XG4gICAgdGhpc1skZW1pdHRlcl0uZW1pdChldmVudC50eXBlLCBldmVudCk7XG4gIH1cbn0pO1xuZXhwb3J0cy5FdmVudFRhcmdldCA9IEV2ZW50VGFyZ2V0O1xuXG52YXIgTWVzc2FnZUV2ZW50ID0gQ2xhc3Moe1xuICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24odHlwZSwgb3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgdGhpcy5kYXRhID0gb3B0aW9ucy5kYXRhID09PSB2b2lkKDApID8gbnVsbCA6IG9wdGlvbnMuZGF0YTtcblxuICAgIHRoaXMubGFzdEV2ZW50SWQgPSBvcHRpb25zLmxhc3RFdmVudElkIHx8IFwiXCI7XG4gICAgdGhpcy5vcmlnaW4gPSBvcHRpb25zLm9yaWdpbiB8fCBcIlwiO1xuICAgIHRoaXMuYnViYmxlcyA9IG9wdGlvbnMuYnViYmxlcyB8fCBmYWxzZTtcbiAgICB0aGlzLmNhbmNlbGFibGUgPSBvcHRpb25zLmNhbmNlbGFibGUgfHwgZmFsc2U7XG4gIH0sXG4gIHNvdXJjZTogbnVsbCxcbiAgcG9ydHM6IG51bGwsXG4gIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbigpIHtcbiAgfSxcbiAgc3RvcFByb3BhZ2F0aW9uOiBmdW5jdGlvbigpIHtcbiAgfSxcbiAgc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uOiBmdW5jdGlvbigpIHtcbiAgfVxufSk7XG5leHBvcnRzLk1lc3NhZ2VFdmVudCA9IE1lc3NhZ2VFdmVudDtcbiIsIi8vIENvcHlyaWdodCBKb3llbnQsIEluYy4gYW5kIG90aGVyIE5vZGUgY29udHJpYnV0b3JzLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhXG4vLyBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4vLyBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbi8vIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbi8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXRcbi8vIHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZVxuLy8gZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWRcbi8vIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1Ncbi8vIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0Zcbi8vIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU5cbi8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLFxuLy8gREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SXG4vLyBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFXG4vLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLlxuXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIHRoaXMuX2V2ZW50cyA9IHRoaXMuX2V2ZW50cyB8fCB7fTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gdGhpcy5fbWF4TGlzdGVuZXJzIHx8IHVuZGVmaW5lZDtcbn1cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xuXG4vLyBCYWNrd2FyZHMtY29tcGF0IHdpdGggbm9kZSAwLjEwLnhcbkV2ZW50RW1pdHRlci5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX2V2ZW50cyA9IHVuZGVmaW5lZDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX21heExpc3RlbmVycyA9IHVuZGVmaW5lZDtcblxuLy8gQnkgZGVmYXVsdCBFdmVudEVtaXR0ZXJzIHdpbGwgcHJpbnQgYSB3YXJuaW5nIGlmIG1vcmUgdGhhbiAxMCBsaXN0ZW5lcnMgYXJlXG4vLyBhZGRlZCB0byBpdC4gVGhpcyBpcyBhIHVzZWZ1bCBkZWZhdWx0IHdoaWNoIGhlbHBzIGZpbmRpbmcgbWVtb3J5IGxlYWtzLlxuRXZlbnRFbWl0dGVyLmRlZmF1bHRNYXhMaXN0ZW5lcnMgPSAxMDtcblxuLy8gT2J2aW91c2x5IG5vdCBhbGwgRW1pdHRlcnMgc2hvdWxkIGJlIGxpbWl0ZWQgdG8gMTAuIFRoaXMgZnVuY3Rpb24gYWxsb3dzXG4vLyB0aGF0IHRvIGJlIGluY3JlYXNlZC4gU2V0IHRvIHplcm8gZm9yIHVubGltaXRlZC5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuc2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24obikge1xuICBpZiAoIWlzTnVtYmVyKG4pIHx8IG4gPCAwIHx8IGlzTmFOKG4pKVxuICAgIHRocm93IFR5cGVFcnJvcignbiBtdXN0IGJlIGEgcG9zaXRpdmUgbnVtYmVyJyk7XG4gIHRoaXMuX21heExpc3RlbmVycyA9IG47XG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgZXIsIGhhbmRsZXIsIGxlbiwgYXJncywgaSwgbGlzdGVuZXJzO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzKVxuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuXG4gIC8vIElmIHRoZXJlIGlzIG5vICdlcnJvcicgZXZlbnQgbGlzdGVuZXIgdGhlbiB0aHJvdy5cbiAgaWYgKHR5cGUgPT09ICdlcnJvcicpIHtcbiAgICBpZiAoIXRoaXMuX2V2ZW50cy5lcnJvciB8fFxuICAgICAgICAoaXNPYmplY3QodGhpcy5fZXZlbnRzLmVycm9yKSAmJiAhdGhpcy5fZXZlbnRzLmVycm9yLmxlbmd0aCkpIHtcbiAgICAgIGVyID0gYXJndW1lbnRzWzFdO1xuICAgICAgaWYgKGVyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXI7IC8vIFVuaGFuZGxlZCAnZXJyb3InIGV2ZW50XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBUeXBlRXJyb3IoJ1VuY2F1Z2h0LCB1bnNwZWNpZmllZCBcImVycm9yXCIgZXZlbnQuJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlciA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNVbmRlZmluZWQoaGFuZGxlcikpXG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGhhbmRsZXIpKSB7XG4gICAgc3dpdGNoIChhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBmYXN0IGNhc2VzXG4gICAgICBjYXNlIDE6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSwgYXJndW1lbnRzWzJdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBzbG93ZXJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgICAgIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0gMSk7XG4gICAgICAgIGZvciAoaSA9IDE7IGkgPCBsZW47IGkrKylcbiAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgaGFuZGxlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaXNPYmplY3QoaGFuZGxlcikpIHtcbiAgICBsZW4gPSBhcmd1bWVudHMubGVuZ3RoO1xuICAgIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0gMSk7XG4gICAgZm9yIChpID0gMTsgaSA8IGxlbjsgaSsrKVxuICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG5cbiAgICBsaXN0ZW5lcnMgPSBoYW5kbGVyLnNsaWNlKCk7XG4gICAgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgbTtcblxuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gVG8gYXZvaWQgcmVjdXJzaW9uIGluIHRoZSBjYXNlIHRoYXQgdHlwZSA9PT0gXCJuZXdMaXN0ZW5lclwiISBCZWZvcmVcbiAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lclwiLlxuICBpZiAodGhpcy5fZXZlbnRzLm5ld0xpc3RlbmVyKVxuICAgIHRoaXMuZW1pdCgnbmV3TGlzdGVuZXInLCB0eXBlLFxuICAgICAgICAgICAgICBpc0Z1bmN0aW9uKGxpc3RlbmVyLmxpc3RlbmVyKSA/XG4gICAgICAgICAgICAgIGxpc3RlbmVyLmxpc3RlbmVyIDogbGlzdGVuZXIpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIC8vIE9wdGltaXplIHRoZSBjYXNlIG9mIG9uZSBsaXN0ZW5lci4gRG9uJ3QgbmVlZCB0aGUgZXh0cmEgYXJyYXkgb2JqZWN0LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVyO1xuICBlbHNlIGlmIChpc09iamVjdCh0aGlzLl9ldmVudHNbdHlwZV0pKVxuICAgIC8vIElmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGFycmF5LCBqdXN0IGFwcGVuZC5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2VcbiAgICAvLyBBZGRpbmcgdGhlIHNlY29uZCBlbGVtZW50LCBuZWVkIHRvIGNoYW5nZSB0byBhcnJheS5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0gPSBbdGhpcy5fZXZlbnRzW3R5cGVdLCBsaXN0ZW5lcl07XG5cbiAgLy8gQ2hlY2sgZm9yIGxpc3RlbmVyIGxlYWtcbiAgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkgJiYgIXRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQpIHtcbiAgICB2YXIgbTtcbiAgICBpZiAoIWlzVW5kZWZpbmVkKHRoaXMuX21heExpc3RlbmVycykpIHtcbiAgICAgIG0gPSB0aGlzLl9tYXhMaXN0ZW5lcnM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSBFdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycztcbiAgICB9XG5cbiAgICBpZiAobSAmJiBtID4gMCAmJiB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoID4gbSkge1xuICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCA9IHRydWU7XG4gICAgICBjb25zb2xlLmVycm9yKCcobm9kZSkgd2FybmluZzogcG9zc2libGUgRXZlbnRFbWl0dGVyIG1lbW9yeSAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2xlYWsgZGV0ZWN0ZWQuICVkIGxpc3RlbmVycyBhZGRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICdVc2UgZW1pdHRlci5zZXRNYXhMaXN0ZW5lcnMoKSB0byBpbmNyZWFzZSBsaW1pdC4nLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoKTtcbiAgICAgIGlmICh0eXBlb2YgY29uc29sZS50cmFjZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBub3Qgc3VwcG9ydGVkIGluIElFIDEwXG4gICAgICAgIGNvbnNvbGUudHJhY2UoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgdmFyIGZpcmVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZygpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGcpO1xuXG4gICAgaWYgKCFmaXJlZCkge1xuICAgICAgZmlyZWQgPSB0cnVlO1xuICAgICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICBnLmxpc3RlbmVyID0gbGlzdGVuZXI7XG4gIHRoaXMub24odHlwZSwgZyk7XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vLyBlbWl0cyBhICdyZW1vdmVMaXN0ZW5lcicgZXZlbnQgaWZmIHRoZSBsaXN0ZW5lciB3YXMgcmVtb3ZlZFxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBsaXN0LCBwb3NpdGlvbiwgbGVuZ3RoLCBpO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldHVybiB0aGlzO1xuXG4gIGxpc3QgPSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIGxlbmd0aCA9IGxpc3QubGVuZ3RoO1xuICBwb3NpdGlvbiA9IC0xO1xuXG4gIGlmIChsaXN0ID09PSBsaXN0ZW5lciB8fFxuICAgICAgKGlzRnVuY3Rpb24obGlzdC5saXN0ZW5lcikgJiYgbGlzdC5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcblxuICB9IGVsc2UgaWYgKGlzT2JqZWN0KGxpc3QpKSB7XG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gPiAwOykge1xuICAgICAgaWYgKGxpc3RbaV0gPT09IGxpc3RlbmVyIHx8XG4gICAgICAgICAgKGxpc3RbaV0ubGlzdGVuZXIgJiYgbGlzdFtpXS5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgICAgIHBvc2l0aW9uID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBvc2l0aW9uIDwgMClcbiAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgaWYgKGxpc3QubGVuZ3RoID09PSAxKSB7XG4gICAgICBsaXN0Lmxlbmd0aCA9IDA7XG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsaXN0LnNwbGljZShwb3NpdGlvbiwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcilcbiAgICAgIHRoaXMuZW1pdCgncmVtb3ZlTGlzdGVuZXInLCB0eXBlLCBsaXN0ZW5lcik7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIga2V5LCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgLy8gbm90IGxpc3RlbmluZyBmb3IgcmVtb3ZlTGlzdGVuZXIsIG5vIG5lZWQgdG8gZW1pdFxuICBpZiAoIXRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcikge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKVxuICAgICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgZWxzZSBpZiAodGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGVtaXQgcmVtb3ZlTGlzdGVuZXIgZm9yIGFsbCBsaXN0ZW5lcnMgb24gYWxsIGV2ZW50c1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGZvciAoa2V5IGluIHRoaXMuX2V2ZW50cykge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlbW92ZUxpc3RlbmVyJykgY29udGludWU7XG4gICAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycyhrZXkpO1xuICAgIH1cbiAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygncmVtb3ZlTGlzdGVuZXInKTtcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNGdW5jdGlvbihsaXN0ZW5lcnMpKSB7XG4gICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnMpO1xuICB9IGVsc2Uge1xuICAgIC8vIExJRk8gb3JkZXJcbiAgICB3aGlsZSAobGlzdGVuZXJzLmxlbmd0aClcbiAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzW2xpc3RlbmVycy5sZW5ndGggLSAxXSk7XG4gIH1cbiAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IFtdO1xuICBlbHNlIGlmIChpc0Z1bmN0aW9uKHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgcmV0ID0gW3RoaXMuX2V2ZW50c1t0eXBlXV07XG4gIGVsc2VcbiAgICByZXQgPSB0aGlzLl9ldmVudHNbdHlwZV0uc2xpY2UoKTtcbiAgcmV0dXJuIHJldDtcbn07XG5cbkV2ZW50RW1pdHRlci5saXN0ZW5lckNvdW50ID0gZnVuY3Rpb24oZW1pdHRlciwgdHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIWVtaXR0ZXIuX2V2ZW50cyB8fCAhZW1pdHRlci5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IDA7XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24oZW1pdHRlci5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSAxO1xuICBlbHNlXG4gICAgcmV0ID0gZW1pdHRlci5fZXZlbnRzW3R5cGVdLmxlbmd0aDtcbiAgcmV0dXJuIHJldDtcbn07XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24oYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnZnVuY3Rpb24nO1xufVxuXG5mdW5jdGlvbiBpc051bWJlcihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdudW1iZXInO1xufVxuXG5mdW5jdGlvbiBpc09iamVjdChhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdvYmplY3QnICYmIGFyZyAhPT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gaXNVbmRlZmluZWQoYXJnKSB7XG4gIHJldHVybiBhcmcgPT09IHZvaWQgMDtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2lzLWltcGxlbWVudGVkJykoKSA/IFN5bWJvbCA6IHJlcXVpcmUoJy4vcG9seWZpbGwnKTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG5cdHZhciBzeW1ib2w7XG5cdGlmICh0eXBlb2YgU3ltYm9sICE9PSAnZnVuY3Rpb24nKSByZXR1cm4gZmFsc2U7XG5cdHN5bWJvbCA9IFN5bWJvbCgndGVzdCBzeW1ib2wnKTtcblx0dHJ5IHtcblx0XHRpZiAoU3RyaW5nKHN5bWJvbCkgIT09ICdTeW1ib2wgKHRlc3Qgc3ltYm9sKScpIHJldHVybiBmYWxzZTtcblx0fSBjYXRjaCAoZSkgeyByZXR1cm4gZmFsc2U7IH1cblx0aWYgKHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPT09ICdzeW1ib2wnKSByZXR1cm4gdHJ1ZTtcblxuXHQvLyBSZXR1cm4gJ3RydWUnIGZvciBwb2x5ZmlsbHNcblx0aWYgKHR5cGVvZiBTeW1ib2wuaXNDb25jYXRTcHJlYWRhYmxlICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC5pc1JlZ0V4cCAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblx0aWYgKHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cdGlmICh0eXBlb2YgU3ltYm9sLnRvUHJpbWl0aXZlICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC50b1N0cmluZ1RhZyAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblx0aWYgKHR5cGVvZiBTeW1ib2wudW5zY29wYWJsZXMgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cblx0cmV0dXJuIHRydWU7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgYXNzaWduICAgICAgICA9IHJlcXVpcmUoJ2VzNS1leHQvb2JqZWN0L2Fzc2lnbicpXG4gICwgbm9ybWFsaXplT3B0cyA9IHJlcXVpcmUoJ2VzNS1leHQvb2JqZWN0L25vcm1hbGl6ZS1vcHRpb25zJylcbiAgLCBpc0NhbGxhYmxlICAgID0gcmVxdWlyZSgnZXM1LWV4dC9vYmplY3QvaXMtY2FsbGFibGUnKVxuICAsIGNvbnRhaW5zICAgICAgPSByZXF1aXJlKCdlczUtZXh0L3N0cmluZy8jL2NvbnRhaW5zJylcblxuICAsIGQ7XG5cbmQgPSBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChkc2NyLCB2YWx1ZS8qLCBvcHRpb25zKi8pIHtcblx0dmFyIGMsIGUsIHcsIG9wdGlvbnMsIGRlc2M7XG5cdGlmICgoYXJndW1lbnRzLmxlbmd0aCA8IDIpIHx8ICh0eXBlb2YgZHNjciAhPT0gJ3N0cmluZycpKSB7XG5cdFx0b3B0aW9ucyA9IHZhbHVlO1xuXHRcdHZhbHVlID0gZHNjcjtcblx0XHRkc2NyID0gbnVsbDtcblx0fSBlbHNlIHtcblx0XHRvcHRpb25zID0gYXJndW1lbnRzWzJdO1xuXHR9XG5cdGlmIChkc2NyID09IG51bGwpIHtcblx0XHRjID0gdyA9IHRydWU7XG5cdFx0ZSA9IGZhbHNlO1xuXHR9IGVsc2Uge1xuXHRcdGMgPSBjb250YWlucy5jYWxsKGRzY3IsICdjJyk7XG5cdFx0ZSA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2UnKTtcblx0XHR3ID0gY29udGFpbnMuY2FsbChkc2NyLCAndycpO1xuXHR9XG5cblx0ZGVzYyA9IHsgdmFsdWU6IHZhbHVlLCBjb25maWd1cmFibGU6IGMsIGVudW1lcmFibGU6IGUsIHdyaXRhYmxlOiB3IH07XG5cdHJldHVybiAhb3B0aW9ucyA/IGRlc2MgOiBhc3NpZ24obm9ybWFsaXplT3B0cyhvcHRpb25zKSwgZGVzYyk7XG59O1xuXG5kLmdzID0gZnVuY3Rpb24gKGRzY3IsIGdldCwgc2V0LyosIG9wdGlvbnMqLykge1xuXHR2YXIgYywgZSwgb3B0aW9ucywgZGVzYztcblx0aWYgKHR5cGVvZiBkc2NyICE9PSAnc3RyaW5nJykge1xuXHRcdG9wdGlvbnMgPSBzZXQ7XG5cdFx0c2V0ID0gZ2V0O1xuXHRcdGdldCA9IGRzY3I7XG5cdFx0ZHNjciA9IG51bGw7XG5cdH0gZWxzZSB7XG5cdFx0b3B0aW9ucyA9IGFyZ3VtZW50c1szXTtcblx0fVxuXHRpZiAoZ2V0ID09IG51bGwpIHtcblx0XHRnZXQgPSB1bmRlZmluZWQ7XG5cdH0gZWxzZSBpZiAoIWlzQ2FsbGFibGUoZ2V0KSkge1xuXHRcdG9wdGlvbnMgPSBnZXQ7XG5cdFx0Z2V0ID0gc2V0ID0gdW5kZWZpbmVkO1xuXHR9IGVsc2UgaWYgKHNldCA9PSBudWxsKSB7XG5cdFx0c2V0ID0gdW5kZWZpbmVkO1xuXHR9IGVsc2UgaWYgKCFpc0NhbGxhYmxlKHNldCkpIHtcblx0XHRvcHRpb25zID0gc2V0O1xuXHRcdHNldCA9IHVuZGVmaW5lZDtcblx0fVxuXHRpZiAoZHNjciA9PSBudWxsKSB7XG5cdFx0YyA9IHRydWU7XG5cdFx0ZSA9IGZhbHNlO1xuXHR9IGVsc2Uge1xuXHRcdGMgPSBjb250YWlucy5jYWxsKGRzY3IsICdjJyk7XG5cdFx0ZSA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2UnKTtcblx0fVxuXG5cdGRlc2MgPSB7IGdldDogZ2V0LCBzZXQ6IHNldCwgY29uZmlndXJhYmxlOiBjLCBlbnVtZXJhYmxlOiBlIH07XG5cdHJldHVybiAhb3B0aW9ucyA/IGRlc2MgOiBhc3NpZ24obm9ybWFsaXplT3B0cyhvcHRpb25zKSwgZGVzYyk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpXG5cdD8gT2JqZWN0LmFzc2lnblxuXHQ6IHJlcXVpcmUoJy4vc2hpbScpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblx0dmFyIGFzc2lnbiA9IE9iamVjdC5hc3NpZ24sIG9iajtcblx0aWYgKHR5cGVvZiBhc3NpZ24gIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcblx0b2JqID0geyBmb286ICdyYXonIH07XG5cdGFzc2lnbihvYmosIHsgYmFyOiAnZHdhJyB9LCB7IHRyenk6ICd0cnp5JyB9KTtcblx0cmV0dXJuIChvYmouZm9vICsgb2JqLmJhciArIG9iai50cnp5KSA9PT0gJ3JhemR3YXRyenknO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGtleXMgID0gcmVxdWlyZSgnLi4va2V5cycpXG4gICwgdmFsdWUgPSByZXF1aXJlKCcuLi92YWxpZC12YWx1ZScpXG5cbiAgLCBtYXggPSBNYXRoLm1heDtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZGVzdCwgc3JjLyosIOKApnNyY24qLykge1xuXHR2YXIgZXJyb3IsIGksIGwgPSBtYXgoYXJndW1lbnRzLmxlbmd0aCwgMiksIGFzc2lnbjtcblx0ZGVzdCA9IE9iamVjdCh2YWx1ZShkZXN0KSk7XG5cdGFzc2lnbiA9IGZ1bmN0aW9uIChrZXkpIHtcblx0XHR0cnkgeyBkZXN0W2tleV0gPSBzcmNba2V5XTsgfSBjYXRjaCAoZSkge1xuXHRcdFx0aWYgKCFlcnJvcikgZXJyb3IgPSBlO1xuXHRcdH1cblx0fTtcblx0Zm9yIChpID0gMTsgaSA8IGw7ICsraSkge1xuXHRcdHNyYyA9IGFyZ3VtZW50c1tpXTtcblx0XHRrZXlzKHNyYykuZm9yRWFjaChhc3NpZ24pO1xuXHR9XG5cdGlmIChlcnJvciAhPT0gdW5kZWZpbmVkKSB0aHJvdyBlcnJvcjtcblx0cmV0dXJuIGRlc3Q7XG59O1xuIiwiLy8gRGVwcmVjYXRlZFxuXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaikgeyByZXR1cm4gdHlwZW9mIG9iaiA9PT0gJ2Z1bmN0aW9uJzsgfTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2lzLWltcGxlbWVudGVkJykoKVxuXHQ/IE9iamVjdC5rZXlzXG5cdDogcmVxdWlyZSgnLi9zaGltJyk7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKCkge1xuXHR0cnkge1xuXHRcdE9iamVjdC5rZXlzKCdwcmltaXRpdmUnKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSBjYXRjaCAoZSkgeyByZXR1cm4gZmFsc2U7IH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBrZXlzID0gT2JqZWN0LmtleXM7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iamVjdCkge1xuXHRyZXR1cm4ga2V5cyhvYmplY3QgPT0gbnVsbCA/IG9iamVjdCA6IE9iamVjdChvYmplY3QpKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKCcuL2Fzc2lnbicpXG5cbiAgLCBmb3JFYWNoID0gQXJyYXkucHJvdG90eXBlLmZvckVhY2hcbiAgLCBjcmVhdGUgPSBPYmplY3QuY3JlYXRlLCBnZXRQcm90b3R5cGVPZiA9IE9iamVjdC5nZXRQcm90b3R5cGVPZlxuXG4gICwgcHJvY2VzcztcblxucHJvY2VzcyA9IGZ1bmN0aW9uIChzcmMsIG9iaikge1xuXHR2YXIgcHJvdG8gPSBnZXRQcm90b3R5cGVPZihzcmMpO1xuXHRyZXR1cm4gYXNzaWduKHByb3RvID8gcHJvY2Vzcyhwcm90bywgb2JqKSA6IG9iaiwgc3JjKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9wdGlvbnMvKiwg4oCmb3B0aW9ucyovKSB7XG5cdHZhciByZXN1bHQgPSBjcmVhdGUobnVsbCk7XG5cdGZvckVhY2guY2FsbChhcmd1bWVudHMsIGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdFx0aWYgKG9wdGlvbnMgPT0gbnVsbCkgcmV0dXJuO1xuXHRcdHByb2Nlc3MoT2JqZWN0KG9wdGlvbnMpLCByZXN1bHQpO1xuXHR9KTtcblx0cmV0dXJuIHJlc3VsdDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHZhbHVlKSB7XG5cdGlmICh2YWx1ZSA9PSBudWxsKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IHVzZSBudWxsIG9yIHVuZGVmaW5lZFwiKTtcblx0cmV0dXJuIHZhbHVlO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2lzLWltcGxlbWVudGVkJykoKVxuXHQ/IFN0cmluZy5wcm90b3R5cGUuY29udGFpbnNcblx0OiByZXF1aXJlKCcuL3NoaW0nKTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHN0ciA9ICdyYXpkd2F0cnp5JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG5cdGlmICh0eXBlb2Ygc3RyLmNvbnRhaW5zICE9PSAnZnVuY3Rpb24nKSByZXR1cm4gZmFsc2U7XG5cdHJldHVybiAoKHN0ci5jb250YWlucygnZHdhJykgPT09IHRydWUpICYmIChzdHIuY29udGFpbnMoJ2ZvbycpID09PSBmYWxzZSkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluZGV4T2YgPSBTdHJpbmcucHJvdG90eXBlLmluZGV4T2Y7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHNlYXJjaFN0cmluZy8qLCBwb3NpdGlvbiovKSB7XG5cdHJldHVybiBpbmRleE9mLmNhbGwodGhpcywgc2VhcmNoU3RyaW5nLCBhcmd1bWVudHNbMV0pID4gLTE7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZCA9IHJlcXVpcmUoJ2QnKVxuXG4gICwgY3JlYXRlID0gT2JqZWN0LmNyZWF0ZSwgZGVmaW5lUHJvcGVydGllcyA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzXG4gICwgZ2VuZXJhdGVOYW1lLCBTeW1ib2w7XG5cbmdlbmVyYXRlTmFtZSA9IChmdW5jdGlvbiAoKSB7XG5cdHZhciBjcmVhdGVkID0gY3JlYXRlKG51bGwpO1xuXHRyZXR1cm4gZnVuY3Rpb24gKGRlc2MpIHtcblx0XHR2YXIgcG9zdGZpeCA9IDA7XG5cdFx0d2hpbGUgKGNyZWF0ZWRbZGVzYyArIChwb3N0Zml4IHx8ICcnKV0pICsrcG9zdGZpeDtcblx0XHRkZXNjICs9IChwb3N0Zml4IHx8ICcnKTtcblx0XHRjcmVhdGVkW2Rlc2NdID0gdHJ1ZTtcblx0XHRyZXR1cm4gJ0BAJyArIGRlc2M7XG5cdH07XG59KCkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bWJvbCA9IGZ1bmN0aW9uIChkZXNjcmlwdGlvbikge1xuXHR2YXIgc3ltYm9sO1xuXHRpZiAodGhpcyBpbnN0YW5jZW9mIFN5bWJvbCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoJ1R5cGVFcnJvcjogU3ltYm9sIGlzIG5vdCBhIGNvbnN0cnVjdG9yJyk7XG5cdH1cblx0c3ltYm9sID0gY3JlYXRlKFN5bWJvbC5wcm90b3R5cGUpO1xuXHRkZXNjcmlwdGlvbiA9IChkZXNjcmlwdGlvbiA9PT0gdW5kZWZpbmVkID8gJycgOiBTdHJpbmcoZGVzY3JpcHRpb24pKTtcblx0cmV0dXJuIGRlZmluZVByb3BlcnRpZXMoc3ltYm9sLCB7XG5cdFx0X19kZXNjcmlwdGlvbl9fOiBkKCcnLCBkZXNjcmlwdGlvbiksXG5cdFx0X19uYW1lX186IGQoJycsIGdlbmVyYXRlTmFtZShkZXNjcmlwdGlvbikpXG5cdH0pO1xufTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoU3ltYm9sLCB7XG5cdGNyZWF0ZTogZCgnJywgU3ltYm9sKCdjcmVhdGUnKSksXG5cdGhhc0luc3RhbmNlOiBkKCcnLCBTeW1ib2woJ2hhc0luc3RhbmNlJykpLFxuXHRpc0NvbmNhdFNwcmVhZGFibGU6IGQoJycsIFN5bWJvbCgnaXNDb25jYXRTcHJlYWRhYmxlJykpLFxuXHRpc1JlZ0V4cDogZCgnJywgU3ltYm9sKCdpc1JlZ0V4cCcpKSxcblx0aXRlcmF0b3I6IGQoJycsIFN5bWJvbCgnaXRlcmF0b3InKSksXG5cdHRvUHJpbWl0aXZlOiBkKCcnLCBTeW1ib2woJ3RvUHJpbWl0aXZlJykpLFxuXHR0b1N0cmluZ1RhZzogZCgnJywgU3ltYm9sKCd0b1N0cmluZ1RhZycpKSxcblx0dW5zY29wYWJsZXM6IGQoJycsIFN5bWJvbCgndW5zY29wYWJsZXMnKSlcbn0pO1xuXG5kZWZpbmVQcm9wZXJ0aWVzKFN5bWJvbC5wcm90b3R5cGUsIHtcblx0cHJvcGVyVG9TdHJpbmc6IGQoZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiAnU3ltYm9sICgnICsgdGhpcy5fX2Rlc2NyaXB0aW9uX18gKyAnKSc7XG5cdH0pLFxuXHR0b1N0cmluZzogZCgnJywgZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fX25hbWVfXzsgfSlcbn0pO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KFN5bWJvbC5wcm90b3R5cGUsIFN5bWJvbC50b1ByaW1pdGl2ZSwgZCgnJyxcblx0ZnVuY3Rpb24gKGhpbnQpIHtcblx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ29udmVyc2lvbiBvZiBzeW1ib2wgb2JqZWN0cyBpcyBub3QgYWxsb3dlZFwiKTtcblx0fSkpO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KFN5bWJvbC5wcm90b3R5cGUsIFN5bWJvbC50b1N0cmluZ1RhZywgZCgnYycsICdTeW1ib2wnKSk7XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gIFwidHlwZXNcIjoge1xuICAgIFwicm9vdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJyb290XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZWNob1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInN0cmluZ1wiOiB7IFwiX2FyZ1wiOiAwLCBcInR5cGVcIjogXCJzdHJpbmdcIiB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3RyaW5nXCI6IHsgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCIgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImxpc3RUYWJzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHt9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjogeyBcIl9yZXR2YWxcIjogXCJ0YWJsaXN0XCIgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicHJvdG9jb2xEZXNjcmlwdGlvblwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7fSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHsgXCJfcmV0dmFsXCI6IFwianNvblwiIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJ0YWJMaXN0Q2hhbmdlZFwiOiB7fVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJ0YWJsaXN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwidGFibGlzdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInNlbGVjdGVkXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwidGFic1wiOiBcImFycmF5OnRhYlwiLFxuICAgICAgICBcInVybFwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcImNvbnNvbGVBY3RvclwiOiBcImNvbnNvbGVcIixcbiAgICAgICAgXCJpbnNwZWN0b3JBY3RvclwiOiBcImluc3BlY3RvclwiLFxuICAgICAgICBcInN0eWxlU2hlZXRzQWN0b3JcIjogXCJzdHlsZXNoZWV0c1wiLFxuICAgICAgICBcInN0eWxlRWRpdG9yQWN0b3JcIjogXCJzdHlsZWVkaXRvclwiLFxuICAgICAgICBcIm1lbW9yeUFjdG9yXCI6IFwibWVtb3J5XCIsXG4gICAgICAgIFwiZXZlbnRMb29wTGFnQWN0b3JcIjogXCJldmVudExvb3BMYWdcIixcbiAgICAgICAgXCJwcmVmZXJlbmNlQWN0b3JcIjogXCJwcmVmZXJlbmNlXCIsXG4gICAgICAgIFwiZGV2aWNlQWN0b3JcIjogXCJkZXZpY2VcIixcblxuICAgICAgICBcInByb2ZpbGVyQWN0b3JcIjogXCJwcm9maWxlclwiLFxuICAgICAgICBcImNocm9tZURlYnVnZ2VyXCI6IFwiY2hyb21lRGVidWdnZXJcIixcbiAgICAgICAgXCJ3ZWJhcHBzQWN0b3JcIjogXCJ3ZWJhcHBzXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwidGFiXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInRhYlwiLFxuICAgICAgXCJmaWVsZHNcIjoge1xuICAgICAgICBcInRpdGxlXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwidXJsXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwib3V0ZXJXaW5kb3dJRFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImluc3BlY3RvckFjdG9yXCI6IFwiaW5zcGVjdG9yXCIsXG4gICAgICAgIFwiY2FsbFdhdGNoZXJBY3RvclwiOiBcImNhbGwtd2F0Y2hlclwiLFxuICAgICAgICBcImNhbnZhc0FjdG9yXCI6IFwiY2FudmFzXCIsXG4gICAgICAgIFwid2ViZ2xBY3RvclwiOiBcIndlYmdsXCIsXG4gICAgICAgIFwid2ViYXVkaW9BY3RvclwiOiBcIndlYmF1ZGlvXCIsXG4gICAgICAgIFwic3RvcmFnZUFjdG9yXCI6IFwic3RvcmFnZVwiLFxuICAgICAgICBcImdjbGlBY3RvclwiOiBcImdjbGlcIixcbiAgICAgICAgXCJtZW1vcnlBY3RvclwiOiBcIm1lbW9yeVwiLFxuICAgICAgICBcImV2ZW50TG9vcExhZ1wiOiBcImV2ZW50TG9vcExhZ1wiLFxuICAgICAgICBcInN0eWxlU2hlZXRzQWN0b3JcIjogXCJzdHlsZXNoZWV0c1wiLFxuICAgICAgICBcInN0eWxlRWRpdG9yQWN0b3JcIjogXCJzdHlsZWVkaXRvclwiLFxuXG4gICAgICAgIFwiY29uc29sZUFjdG9yXCI6IFwiY29uc29sZVwiLFxuICAgICAgICBcInRyYWNlQWN0b3JcIjogXCJ0cmFjZVwiXG4gICAgICB9LFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJhdHRhY2hcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge30sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7IFwiX3JldHZhbFwiOiBcImpzb25cIiB9XG4gICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInRhYk5hdmlnYXRlZFwiOiB7XG4gICAgICAgICAgIFwidHlwZU5hbWVcIjogXCJ0YWJOYXZpZ2F0ZWRcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcImNvbnNvbGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY29uc29sZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImV2YWx1YXRlSlNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ1cmxcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImJpbmRPYmplY3RBY3RvclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZnJhbWVBY3RvclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic2VsZWN0ZWROb2RlQWN0b3JcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6c3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZXZhbHVhdGVqc3Jlc3BvbnNlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJldmFsdWF0ZWpzcmVzcG9uc2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJldmFsdWF0ZWpzcmVzcG9uc2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJyZXN1bHRcIjogXCJvYmplY3RcIixcbiAgICAgICAgXCJleGNlcHRpb25cIjogXCJvYmplY3RcIixcbiAgICAgICAgXCJleGNlcHRpb25NZXNzYWdlXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiaW5wdXRcIjogXCJzdHJpbmdcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwib2JqZWN0XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICAge1xuICAgICAgICAgICBcIm5hbWVcIjogXCJwcm9wZXJ0eVwiLFxuICAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgfSxcbiAgICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICAgIFwiZGVzY3JpcHRvclwiOiB7XG4gICAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgfVxuICAgICAgICAgfVxuICAgICAgXVxuICAgIH1cbiAgfVxufVxuIiwibW9kdWxlLmV4cG9ydHM9e1xuICBcInR5cGVzXCI6IHtcbiAgICBcImxvbmdzdHJhY3RvclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJsb25nc3RyYWN0b3JcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdWJzdHJpbmdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3Vic3RyaW5nXCIsXG4gICAgICAgICAgICBcInN0YXJ0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJlbmRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdWJzdHJpbmdcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlbGVhc2VcIixcbiAgICAgICAgICBcInJlbGVhc2VcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicmVsZWFzZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJzdHlsZXNoZWV0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0eWxlc2hlZXRcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZGlzYWJsZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRUZXh0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFRleHRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRPcmlnaW5hbFNvdXJjZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0T3JpZ2luYWxTb3VyY2VzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJvcmlnaW5hbFNvdXJjZXNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTphcnJheTpvcmlnaW5hbHNvdXJjZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0T3JpZ2luYWxMb2NhdGlvblwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRPcmlnaW5hbExvY2F0aW9uXCIsXG4gICAgICAgICAgICBcImxpbmVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImNvbHVtblwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJvcmlnaW5hbGxvY2F0aW9ucmVzcG9uc2VcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVwZGF0ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidHJhbnNpdGlvblwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJwcm9wZXJ0eS1jaGFuZ2VcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInByb3BlcnR5Q2hhbmdlXCIsXG4gICAgICAgICAgXCJwcm9wZXJ0eVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcInN0eWxlLWFwcGxpZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0eWxlQXBwbGllZFwiXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIFwib3JpZ2luYWxzb3VyY2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwib3JpZ2luYWxzb3VyY2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRUZXh0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFRleHRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJzdHlsZXNoZWV0c1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdHlsZXNoZWV0c1wiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFN0eWxlU2hlZXRzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0eWxlU2hlZXRzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdHlsZVNoZWV0c1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OnN0eWxlc2hlZXRcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImFkZFN0eWxlU2hlZXRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYWRkU3R5bGVTaGVldFwiLFxuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3R5bGVTaGVldFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0eWxlc2hlZXRcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcIm9yaWdpbmFsbG9jYXRpb25yZXNwb25zZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIm9yaWdpbmFsbG9jYXRpb25yZXNwb25zZVwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInNvdXJjZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcImxpbmVcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJjb2x1bW5cIjogXCJudW1iZXJcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJkb21ub2RlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRvbW5vZGVcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXROb2RlVmFsdWVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Tm9kZVZhbHVlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImxvbmdzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldE5vZGVWYWx1ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXROb2RlVmFsdWVcIixcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEltYWdlRGF0YVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRJbWFnZURhdGFcIixcbiAgICAgICAgICAgIFwibWF4RGltXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImltYWdlRGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibW9kaWZ5QXR0cmlidXRlc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJtb2RpZnlBdHRyaWJ1dGVzXCIsXG4gICAgICAgICAgICBcIm1vZGlmaWNhdGlvbnNcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXJyYXk6anNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJhcHBsaWVkc3R5bGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJhcHBsaWVkc3R5bGVcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJydWxlXCI6IFwiZG9tc3R5bGVydWxlI2FjdG9yaWRcIixcbiAgICAgICAgXCJpbmhlcml0ZWRcIjogXCJudWxsYWJsZTpkb21ub2RlI2FjdG9yaWRcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJtYXRjaGVkc2VsZWN0b3JcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJtYXRjaGVkc2VsZWN0b3JcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJydWxlXCI6IFwiZG9tc3R5bGVydWxlI2FjdG9yaWRcIixcbiAgICAgICAgXCJzZWxlY3RvclwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInZhbHVlXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwibWF0Y2hlZHNlbGVjdG9ycmVzcG9uc2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJtYXRjaGVkc2VsZWN0b3JyZXNwb25zZVwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInJ1bGVzXCI6IFwiYXJyYXk6ZG9tc3R5bGVydWxlXCIsXG4gICAgICAgIFwic2hlZXRzXCI6IFwiYXJyYXk6c3R5bGVzaGVldFwiLFxuICAgICAgICBcIm1hdGNoZWRcIjogXCJhcnJheTptYXRjaGVkc2VsZWN0b3JcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJhcHBsaWVkU3R5bGVzUmV0dXJuXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiYXBwbGllZFN0eWxlc1JldHVyblwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImVudHJpZXNcIjogXCJhcnJheTphcHBsaWVkc3R5bGVcIixcbiAgICAgICAgXCJydWxlc1wiOiBcImFycmF5OmRvbXN0eWxlcnVsZVwiLFxuICAgICAgICBcInNoZWV0c1wiOiBcImFycmF5OnN0eWxlc2hlZXRcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJwYWdlc3R5bGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwicGFnZXN0eWxlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0Q29tcHV0ZWRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Q29tcHV0ZWRcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm1hcmtNYXRjaGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib25seU1hdGNoZWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJmaWx0ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJjb21wdXRlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldE1hdGNoZWRTZWxlY3RvcnNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0TWF0Y2hlZFNlbGVjdG9yc1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicHJvcGVydHlcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImZpbHRlclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJtYXRjaGVkc2VsZWN0b3JyZXNwb25zZVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0QXBwbGllZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRBcHBsaWVkXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJpbmhlcml0ZWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXRjaGVkU2VsZWN0b3JzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZmlsdGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFwcGxpZWRTdHlsZXNSZXR1cm5cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldExheW91dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRMYXlvdXRcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImF1dG9NYXJnaW5zXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJkb21zdHlsZXJ1bGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9tc3R5bGVydWxlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibW9kaWZ5UHJvcGVydGllc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJtb2RpZnlQcm9wZXJ0aWVzXCIsXG4gICAgICAgICAgICBcIm1vZGlmaWNhdGlvbnNcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXJyYXk6anNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwicnVsZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbXN0eWxlcnVsZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiaGlnaGxpZ2h0ZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaGlnaGxpZ2h0ZXJcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzaG93Qm94TW9kZWxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2hvd0JveE1vZGVsXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJyZWdpb25cIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImhpZGVCb3hNb2RlbFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJoaWRlQm94TW9kZWxcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicGlja1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwaWNrXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNhbmNlbFBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2FuY2VsUGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJpbWFnZURhdGFcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpbWFnZURhdGFcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJkYXRhXCI6IFwibnVsbGFibGU6bG9uZ3N0cmluZ1wiLFxuICAgICAgICBcInNpemVcIjogXCJqc29uXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZGlzY29ubmVjdGVkTm9kZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJub2RlXCI6IFwiZG9tbm9kZVwiLFxuICAgICAgICBcIm5ld1BhcmVudHNcIjogXCJhcnJheTpkb21ub2RlXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZGlzY29ubmVjdGVkTm9kZUFycmF5XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZGlzY29ubmVjdGVkTm9kZUFycmF5XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibm9kZXNcIjogXCJhcnJheTpkb21ub2RlXCIsXG4gICAgICAgIFwibmV3UGFyZW50c1wiOiBcImFycmF5OmRvbW5vZGVcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJkb21tdXRhdGlvblwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRvbW11dGF0aW9uXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7fVxuICAgIH0sXG4gICAgXCJkb21ub2RlbGlzdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb21ub2RlbGlzdFwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIml0ZW1cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaXRlbVwiLFxuICAgICAgICAgICAgXCJpdGVtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIml0ZW1zXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIml0ZW1zXCIsXG4gICAgICAgICAgICBcInN0YXJ0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJlbmRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6bnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZGlzY29ubmVjdGVkTm9kZUFycmF5XCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZWxlYXNlXCIsXG4gICAgICAgICAgXCJyZWxlYXNlXCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZG9tdHJhdmVyc2FsYXJyYXlcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb210cmF2ZXJzYWxhcnJheVwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcIm5vZGVzXCI6IFwiYXJyYXk6ZG9tbm9kZVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImRvbXdhbGtlclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb213YWxrZXJcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZWxlYXNlXCIsXG4gICAgICAgICAgXCJyZWxlYXNlXCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicGlja1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwaWNrXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZGlzY29ubmVjdGVkTm9kZVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiY2FuY2VsUGlja1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJjYW5jZWxQaWNrXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImhpZ2hsaWdodFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImRvY3VtZW50XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImRvY3VtZW50XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImRvY3VtZW50RWxlbWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJkb2N1bWVudEVsZW1lbnRcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicGFyZW50c1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwYXJlbnRzXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzYW1lRG9jdW1lbnRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJub2Rlc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJldGFpbk5vZGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicmV0YWluTm9kZVwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidW5yZXRhaW5Ob2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInVucmV0YWluTm9kZVwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVsZWFzZU5vZGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicmVsZWFzZU5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImZvcmNlXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjaGlsZHJlblwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJjaGlsZHJlblwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibWF4Tm9kZXNcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImNlbnRlclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInN0YXJ0XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwid2hhdFRvU2hvd1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb210cmF2ZXJzYWxhcnJheVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2libGluZ3NcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2libGluZ3NcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm1heE5vZGVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjZW50ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIndoYXRUb1Nob3dcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9tdHJhdmVyc2FsYXJyYXlcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm5leHRTaWJsaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm5leHRTaWJsaW5nXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ3aGF0VG9TaG93XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInByZXZpb3VzU2libGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwcmV2aW91c1NpYmxpbmdcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIndoYXRUb1Nob3dcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicXVlcnlTZWxlY3RvclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJxdWVyeVNlbGVjdG9yXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzZWxlY3RvclwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJxdWVyeVNlbGVjdG9yQWxsXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInF1ZXJ5U2VsZWN0b3JBbGxcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInNlbGVjdG9yXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibGlzdFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbW5vZGVsaXN0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdWdnZXN0aW9uc0ZvclF1ZXJ5XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN1Z2dlc3Rpb25zRm9yUXVlcnlcIixcbiAgICAgICAgICAgIFwicXVlcnlcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImNvbXBsZXRpbmdcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInNlbGVjdG9yU3RhdGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJsaXN0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYXJyYXk6YXJyYXk6c3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJhZGRQc2V1ZG9DbGFzc0xvY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYWRkUHNldWRvQ2xhc3NMb2NrXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwc2V1ZG9DbGFzc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyZW50c1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiaGlkZU5vZGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaGlkZU5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVuaGlkZU5vZGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidW5oaWRlTm9kZVwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVtb3ZlUHNldWRvQ2xhc3NMb2NrXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbW92ZVBzZXVkb0NsYXNzTG9ja1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicHNldWRvQ2xhc3NcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmVudHNcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNsZWFyUHNldWRvQ2xhc3NMb2Nrc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJjbGVhclBzZXVkb0NsYXNzTG9ja3NcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlubmVySFRNTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpbm5lckhUTUxcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImxvbmdzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm91dGVySFRNTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJvdXRlckhUTUxcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImxvbmdzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldE91dGVySFRNTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRPdXRlckhUTUxcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZW1vdmVOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbW92ZU5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJuZXh0U2libGluZ1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImluc2VydEJlZm9yZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpbnNlcnRCZWZvcmVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmVudFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInNpYmxpbmdcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRNdXRhdGlvbnNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0TXV0YXRpb25zXCIsXG4gICAgICAgICAgICBcImNsZWFudXBcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJtdXRhdGlvbnNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpkb21tdXRhdGlvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiaXNJbkRPTVRyZWVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaXNJbkRPTVRyZWVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJhdHRhY2hlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldE5vZGVBY3RvckZyb21PYmplY3RBY3RvclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXROb2RlQWN0b3JGcm9tT2JqZWN0QWN0b3JcIixcbiAgICAgICAgICAgIFwib2JqZWN0QWN0b3JJRFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm5vZGVGcm9udFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJuZXctbXV0YXRpb25zXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJuZXdNdXRhdGlvbnNcIlxuICAgICAgICB9LFxuICAgICAgICBcInBpY2tlci1ub2RlLXBpY2tlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicGlja2VyTm9kZVBpY2tlZFwiLFxuICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJwaWNrZXItbm9kZS1ob3ZlcmVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwaWNrZXJOb2RlSG92ZXJlZFwiLFxuICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJoaWdobGlnaHRlci1yZWFkeVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiaGlnaGxpZ2h0ZXItcmVhZHlcIlxuICAgICAgICB9LFxuICAgICAgICBcImhpZ2hsaWdodGVyLWhpZGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImhpZ2hsaWdodGVyLWhpZGVcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcImluc3BlY3RvclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpbnNwZWN0b3JcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRXYWxrZXJcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0V2Fsa2VyXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ3YWxrZXJcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb213YWxrZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFBhZ2VTdHlsZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRQYWdlU3R5bGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInBhZ2VTdHlsZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInBhZ2VzdHlsZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0SGlnaGxpZ2h0ZXJcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0SGlnaGxpZ2h0ZXJcIixcbiAgICAgICAgICAgIFwiYXV0b2hpZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiaGlnaGxpZ3RlclwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImhpZ2hsaWdodGVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRJbWFnZURhdGFGcm9tVVJMXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEltYWdlRGF0YUZyb21VUkxcIixcbiAgICAgICAgICAgIFwidXJsXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXhEaW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6bnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiaW1hZ2VEYXRhXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJjYWxsLXN0YWNrLWl0ZW1cIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjYWxsLXN0YWNrLWl0ZW1cIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJuYW1lXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiZmlsZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcImxpbmVcIjogXCJudW1iZXJcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJjYWxsLWRldGFpbHNcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjYWxsLWRldGFpbHNcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInN0YWNrXCI6IFwiYXJyYXk6Y2FsbC1zdGFjay1pdGVtXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZnVuY3Rpb24tY2FsbFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJmdW5jdGlvbi1jYWxsXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0RGV0YWlsc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXREZXRhaWxzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJpbmZvXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiY2FsbC1kZXRhaWxzXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJjYWxsLXdhdGNoZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY2FsbC13YXRjaGVyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0dXBcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgICAgXCJ0cmFjZWRHbG9iYWxzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ0cmFjZWRGdW5jdGlvbnNcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6YXJyYXk6c3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInN0YXJ0UmVjb3JkaW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGVyZm9ybVJlbG9hZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImZpbmFsaXplXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZmluYWxpemVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiaXNSZWNvcmRpbmdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaXNSZWNvcmRpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZXN1bWVSZWNvcmRpbmdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicmVzdW1lUmVjb3JkaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBhdXNlUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInBhdXNlUmVjb3JkaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJjYWxsc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmZ1bmN0aW9uLWNhbGxcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImVyYXNlUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImVyYXNlUmVjb3JkaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcInNuYXBzaG90LWltYWdlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic25hcHNob3QtaW1hZ2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJpbmRleFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcIndpZHRoXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiaGVpZ2h0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZmxpcHBlZFwiOiBcImJvb2xlYW5cIixcbiAgICAgICAgXCJwaXhlbHNcIjogXCJ1aW50MzItYXJyYXlcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJzbmFwc2hvdC1vdmVydmlld1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInNuYXBzaG90LW92ZXJ2aWV3XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiY2FsbHNcIjogXCJhcnJheTpmdW5jdGlvbi1jYWxsXCIsXG4gICAgICAgIFwidGh1bWJuYWlsc1wiOiBcImFycmF5OnNuYXBzaG90LWltYWdlXCIsXG4gICAgICAgIFwic2NyZWVuc2hvdFwiOiBcInNuYXBzaG90LWltYWdlXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZnJhbWUtc25hcHNob3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZnJhbWUtc25hcHNob3RcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRPdmVydmlld1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRPdmVydmlld1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwib3ZlcnZpZXdcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzbmFwc2hvdC1vdmVydmlld1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2VuZXJhdGVTY3JlZW5zaG90Rm9yXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdlbmVyYXRlU2NyZWVuc2hvdEZvclwiLFxuICAgICAgICAgICAgXCJjYWxsXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImZ1bmN0aW9uLWNhbGxcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInNjcmVlbnNob3RcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzbmFwc2hvdC1pbWFnZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiY2FudmFzXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImNhbnZhc1wiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0dXBcIixcbiAgICAgICAgICAgIFwicmVsb2FkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZmluYWxpemVcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJmaW5hbGl6ZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpc0luaXRpYWxpemVkXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzSW5pdGlhbGl6ZWRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImluaXRpYWxpemVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVjb3JkQW5pbWF0aW9uRnJhbWVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicmVjb3JkQW5pbWF0aW9uRnJhbWVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInNuYXBzaG90XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZnJhbWUtc25hcHNob3RcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImdsLXNoYWRlclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJnbC1zaGFkZXJcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRUZXh0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFRleHRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNvbXBpbGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY29tcGlsZVwiLFxuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZXJyb3JcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJnbC1wcm9ncmFtXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImdsLXByb2dyYW1cIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRWZXJ0ZXhTaGFkZXJcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0VmVydGV4U2hhZGVyXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzaGFkZXJcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJnbC1zaGFkZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEZyYWdtZW50U2hhZGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEZyYWdtZW50U2hhZGVyXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzaGFkZXJcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJnbC1zaGFkZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImhpZ2hsaWdodFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImhpZ2hsaWdodFwiLFxuICAgICAgICAgICAgXCJ0aW50XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Om51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1bmhpZ2hsaWdodFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInVuaGlnaGxpZ2h0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImJsYWNrYm94XCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYmxhY2tib3hcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidW5ibGFja2JveFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInVuYmxhY2tib3hcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwid2ViZ2xcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwid2ViZ2xcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgICBcInJlbG9hZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImZpbmFsaXplXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZmluYWxpemVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0UHJvZ3JhbXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UHJvZ3JhbXNcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInByb2dyYW1zXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYXJyYXk6Z2wtcHJvZ3JhbVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInByb2dyYW0tbGlua2VkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwcm9ncmFtTGlua2VkXCIsXG4gICAgICAgICAgXCJwcm9ncmFtXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2wtcHJvZ3JhbVwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcImF1ZGlvbm9kZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJhdWRpb25vZGVcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRUeXBlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFR5cGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlzU291cmNlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzU291cmNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRQYXJhbVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRQYXJhbVwiLFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6cHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJlcnJvclwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFBhcmFtXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFBhcmFtXCIsXG4gICAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOnByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0UGFyYW1GbGFnc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRQYXJhbUZsYWdzXCIsXG4gICAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZmxhZ3NcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFBhcmFtc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRQYXJhbXNcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInBhcmFtc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcIndlYmF1ZGlvXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIndlYmF1ZGlvXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0dXBcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgICAgXCJyZWxvYWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmaW5hbGl6ZVwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZpbmFsaXplXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJzdGFydC1jb250ZXh0XCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdGFydENvbnRleHRcIlxuICAgICAgICB9LFxuICAgICAgICBcImNvbm5lY3Qtbm9kZVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY29ubmVjdE5vZGVcIixcbiAgICAgICAgICBcInNvdXJjZVwiOiB7XG4gICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImF1ZGlvbm9kZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcImRlc3RcIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJkaXNjb25uZWN0LW5vZGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImRpc2Nvbm5lY3ROb2RlXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJjb25uZWN0LXBhcmFtXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJjb25uZWN0UGFyYW1cIixcbiAgICAgICAgICBcInNvdXJjZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImF1ZGlvbm9kZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiY2hhbmdlLXBhcmFtXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJjaGFuZ2VQYXJhbVwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcImNyZWF0ZS1ub2RlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJjcmVhdGVOb2RlXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJvbGQtc3R5bGVzaGVldFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJvbGQtc3R5bGVzaGVldFwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInRvZ2dsZURpc2FibGVkXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInRvZ2dsZURpc2FibGVkXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJkaXNhYmxlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImZldGNoU291cmNlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZldGNoU291cmNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVwZGF0ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidHJhbnNpdGlvblwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJwcm9wZXJ0eS1jaGFuZ2VcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInByb3BlcnR5Q2hhbmdlXCIsXG4gICAgICAgICAgXCJwcm9wZXJ0eVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcInNvdXJjZS1sb2FkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzb3VyY2VMb2FkXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzdHlsZS1hcHBsaWVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdHlsZUFwcGxpZWRcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0eWxlZWRpdG9yXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0eWxlZWRpdG9yXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibmV3RG9jdW1lbnRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibmV3RG9jdW1lbnRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibmV3U3R5bGVTaGVldFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJuZXdTdHlsZVNoZWV0XCIsXG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdHlsZVNoZWV0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwib2xkLXN0eWxlc2hlZXRcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJkb2N1bWVudC1sb2FkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJkb2N1bWVudExvYWRcIixcbiAgICAgICAgICBcInN0eWxlU2hlZXRzXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXJyYXk6b2xkLXN0eWxlc2hlZXRcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJjb29raWVvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjb29raWVvYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJuYW1lXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwidmFsdWVcIjogXCJsb25nc3RyaW5nXCIsXG4gICAgICAgIFwicGF0aFwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcImhvc3RcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJpc0RvbWFpblwiOiBcImJvb2xlYW5cIixcbiAgICAgICAgXCJpc1NlY3VyZVwiOiBcImJvb2xlYW5cIixcbiAgICAgICAgXCJpc0h0dHBPbmx5XCI6IFwiYm9vbGVhblwiLFxuICAgICAgICBcImNyZWF0aW9uVGltZVwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImxhc3RBY2Nlc3NlZFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImV4cGlyZXNcIjogXCJudW1iZXJcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJjb29raWVzdG9yZW9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImNvb2tpZXN0b3Jlb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwidG90YWxcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJvZmZzZXRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJkYXRhXCI6IFwiYXJyYXk6bnVsbGFibGU6Y29va2llb2JqZWN0XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic3RvcmFnZW9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0b3JhZ2VvYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJuYW1lXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwidmFsdWVcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic3RvcmFnZXN0b3Jlb2JqZWN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmFnZXN0b3Jlb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwidG90YWxcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJvZmZzZXRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJkYXRhXCI6IFwiYXJyYXk6bnVsbGFibGU6c3RvcmFnZW9iamVjdFwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImlkYm9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImlkYm9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcIm5hbWVcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJkYlwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcIm9iamVjdFN0b3JlXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwib3JpZ2luXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwidmVyc2lvblwiOiBcIm51bGxhYmxlOm51bWJlclwiLFxuICAgICAgICBcIm9iamVjdFN0b3Jlc1wiOiBcIm51bGxhYmxlOm51bWJlclwiLFxuICAgICAgICBcImtleVBhdGhcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJhdXRvSW5jcmVtZW50XCI6IFwibnVsbGFibGU6Ym9vbGVhblwiLFxuICAgICAgICBcImluZGV4ZXNcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJ2YWx1ZVwiOiBcIm51bGxhYmxlOmxvbmdzdHJpbmdcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJpZGJzdG9yZW9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImlkYnN0b3Jlb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwidG90YWxcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJvZmZzZXRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJkYXRhXCI6IFwiYXJyYXk6bnVsbGFibGU6aWRib2JqZWN0XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic3RvcmVVcGRhdGVPYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdG9yZVVwZGF0ZU9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImNoYW5nZWRcIjogXCJudWxsYWJsZTpqc29uXCIsXG4gICAgICAgIFwiZGVsZXRlZFwiOiBcIm51bGxhYmxlOmpzb25cIixcbiAgICAgICAgXCJhZGRlZFwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJjb29raWVzXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImNvb2tpZXNcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgICBcImhvc3RcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm5hbWVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcHRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJjb29raWVzdG9yZW9iamVjdFwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwibG9jYWxTdG9yYWdlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImxvY2FsU3RvcmFnZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICAgIFwiaG9zdFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibmFtZXNcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6YXJyYXk6c3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm9wdGlvbnNcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6anNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0b3JhZ2VzdG9yZW9iamVjdFwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic2Vzc2lvblN0b3JhZ2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic2Vzc2lvblN0b3JhZ2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgICBcImhvc3RcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm5hbWVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcHRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdG9yYWdlc3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImluZGV4ZWREQlwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpbmRleGVkREJcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgICBcImhvc3RcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm5hbWVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcHRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJpZGJzdG9yZW9iamVjdFwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic3RvcmVsaXN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmVsaXN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiY29va2llc1wiOiBcImNvb2tpZXNcIixcbiAgICAgICAgXCJsb2NhbFN0b3JhZ2VcIjogXCJsb2NhbFN0b3JhZ2VcIixcbiAgICAgICAgXCJzZXNzaW9uU3RvcmFnZVwiOiBcInNlc3Npb25TdG9yYWdlXCIsXG4gICAgICAgIFwiaW5kZXhlZERCXCI6IFwiaW5kZXhlZERCXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic3RvcmFnZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdG9yYWdlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibGlzdFN0b3Jlc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJsaXN0U3RvcmVzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RvcmVsaXN0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwic3RvcmVzLXVwZGF0ZVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3RvcmVzVXBkYXRlXCIsXG4gICAgICAgICAgXCJkYXRhXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RvcmVVcGRhdGVPYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzdG9yZXMtY2xlYXJlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3RvcmVzQ2xlYXJlZFwiLFxuICAgICAgICAgIFwiZGF0YVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzdG9yZXMtcmVsb2FkZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0b3Jlc1JlbGFvZGVkXCIsXG4gICAgICAgICAgXCJkYXRhXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcImdjbGlcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZ2NsaVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNwZWNzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNwZWNzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZXhlY3V0ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJleGVjdXRlXCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInN0YXRlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0YXRlXCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudW1iZXJcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicmFua1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ0eXBlcGFyc2VcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidHlwZXBhcnNlXCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ0eXBlaW5jcmVtZW50XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInR5cGVpbmNyZW1lbnRcIixcbiAgICAgICAgICAgIFwidHlwZWRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidHlwZWRlY3JlbWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0eXBlZGVjcmVtZW50XCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNlbGVjdGlvbmluZm9cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2VsZWN0aW9uaW5mb1wiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImFjdGlvblwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJtZW1vcnlcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibWVtb3J5XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibWVhc3VyZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJtZWFzdXJlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZXZlbnRMb29wTGFnXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImV2ZW50TG9vcExhZ1wiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInN0YXJ0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0YXJ0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdWNjZXNzXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdG9wXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0b3BcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcImV2ZW50LWxvb3AtbGFnXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJldmVudC1sb29wLWxhZ1wiLFxuICAgICAgICAgIFwidGltZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bWJlclwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcInByZWZlcmVuY2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwicHJlZmVyZW5jZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEJvb2xQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEJvb2xQcmVmXCIsXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRDaGFyUHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRDaGFyUHJlZlwiLFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRJbnRQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEludFByZWZcIixcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0QWxsUHJlZnNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0QWxsUHJlZnNcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0Qm9vbFByZWZcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0Qm9vbFByZWZcIixcbiAgICAgICAgICAgIFwibmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldENoYXJQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldENoYXJQcmVmXCIsXG4gICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRJbnRQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldEludFByZWZcIixcbiAgICAgICAgICAgIFwibmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNsZWFyVXNlclByZWZcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2xlYXJVc2VyUHJlZlwiLFxuICAgICAgICAgICAgXCJuYW1lXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJkZXZpY2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZGV2aWNlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0RGVzY3JpcHRpb25cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0RGVzY3JpcHRpb25cIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0V2FsbHBhcGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFdhbGxwYXBlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzY3JlZW5zaG90VG9EYXRhVVJMXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNjcmVlbnNob3RUb0RhdGFVUkxcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0UmF3UGVybWlzc2lvbnNUYWJsZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRSYXdQZXJtaXNzaW9uc1RhYmxlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfVxuICB9LFxuICBcImZyb21cIjogXCJyb290XCJcbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgQ2xhc3MgPSByZXF1aXJlKFwiLi9jbGFzc1wiKS5DbGFzcztcbnZhciB1dGlsID0gcmVxdWlyZShcIi4vdXRpbFwiKTtcbnZhciBrZXlzID0gdXRpbC5rZXlzO1xudmFyIHZhbHVlcyA9IHV0aWwudmFsdWVzO1xudmFyIHBhaXJzID0gdXRpbC5wYWlycztcbnZhciBxdWVyeSA9IHV0aWwucXVlcnk7XG52YXIgZmluZFBhdGggPSB1dGlsLmZpbmRQYXRoO1xudmFyIEV2ZW50VGFyZ2V0ID0gcmVxdWlyZShcIi4vZXZlbnRcIikuRXZlbnRUYXJnZXQ7XG5cbnZhciBUeXBlU3lzdGVtID0gQ2xhc3Moe1xuICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oY2xpZW50KSB7XG4gICAgdmFyIHR5cGVzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICB2YXIgc3BlY2lmaWNhdGlvbiA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbiAgICB0aGlzLnNwZWNpZmljYXRpb24gPSBzcGVjaWZpY2F0aW9uO1xuICAgIHRoaXMudHlwZXMgPSB0eXBlcztcblxuICAgIHZhciB0eXBlRm9yID0gZnVuY3Rpb24gdHlwZUZvcih0eXBlTmFtZSkge1xuICAgICAgdHlwZU5hbWUgPSB0eXBlTmFtZSB8fCBcInByaW1pdGl2ZVwiO1xuICAgICAgaWYgKCF0eXBlc1t0eXBlTmFtZV0pIHtcbiAgICAgICAgZGVmaW5lVHlwZSh0eXBlTmFtZSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0eXBlc1t0eXBlTmFtZV07XG4gICAgfTtcbiAgICB0aGlzLnR5cGVGb3IgPSB0eXBlRm9yO1xuXG4gICAgdmFyIGRlZmluZVR5cGUgPSBmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICB2YXIgdHlwZSA9IHZvaWQoMCk7XG4gICAgICBpZiAodHlwZW9mKGRlc2NyaXB0b3IpID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIGlmIChkZXNjcmlwdG9yLmluZGV4T2YoXCI6XCIpID4gMClcbiAgICAgICAgICB0eXBlID0gbWFrZUNvbXBvdW5kVHlwZShkZXNjcmlwdG9yKTtcbiAgICAgICAgZWxzZSBpZiAoZGVzY3JpcHRvci5pbmRleE9mKFwiI1wiKSA+IDApXG4gICAgICAgICAgdHlwZSA9IG5ldyBBY3RvckRldGFpbChkZXNjcmlwdG9yKTtcbiAgICAgICAgICBlbHNlIGlmIChzcGVjaWZpY2F0aW9uW2Rlc2NyaXB0b3JdKVxuICAgICAgICAgICAgdHlwZSA9IG1ha2VDYXRlZ29yeVR5cGUoc3BlY2lmaWNhdGlvbltkZXNjcmlwdG9yXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0eXBlID0gbWFrZUNhdGVnb3J5VHlwZShkZXNjcmlwdG9yKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHR5cGUpXG4gICAgICAgIHR5cGVzW3R5cGUubmFtZV0gPSB0eXBlO1xuICAgICAgZWxzZVxuICAgICAgICB0aHJvdyBUeXBlRXJyb3IoXCJJbnZhbGlkIHR5cGU6IFwiICsgZGVzY3JpcHRvcik7XG4gICAgfTtcbiAgICB0aGlzLmRlZmluZVR5cGUgPSBkZWZpbmVUeXBlO1xuXG5cbiAgICB2YXIgbWFrZUNvbXBvdW5kVHlwZSA9IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgIHZhciBpbmRleCA9IG5hbWUuaW5kZXhPZihcIjpcIik7XG4gICAgICB2YXIgYmFzZVR5cGUgPSBuYW1lLnNsaWNlKDAsIGluZGV4KTtcbiAgICAgIHZhciBzdWJUeXBlID0gbmFtZS5zbGljZShpbmRleCArIDEpO1xuXG4gICAgICByZXR1cm4gYmFzZVR5cGUgPT09IFwiYXJyYXlcIiA/IG5ldyBBcnJheU9mKHN1YlR5cGUpIDpcbiAgICAgIGJhc2VUeXBlID09PSBcIm51bGxhYmxlXCIgPyBuZXcgTWF5YmUoc3ViVHlwZSkgOlxuICAgICAgbnVsbDtcbiAgICB9O1xuXG4gICAgdmFyIG1ha2VDYXRlZ29yeVR5cGUgPSBmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICB2YXIgY2F0ZWdvcnkgPSBkZXNjcmlwdG9yLmNhdGVnb3J5O1xuICAgICAgcmV0dXJuIGNhdGVnb3J5ID09PSBcImRpY3RcIiA/IG5ldyBEaWN0aW9uYXJ5KGRlc2NyaXB0b3IpIDpcbiAgICAgIGNhdGVnb3J5ID09PSBcImFjdG9yXCIgPyBuZXcgQWN0b3IoZGVzY3JpcHRvcikgOlxuICAgICAgbnVsbDtcbiAgICB9O1xuXG4gICAgdmFyIHJlYWQgPSBmdW5jdGlvbihpbnB1dCwgY29udGV4dCwgdHlwZU5hbWUpIHtcbiAgICAgIHJldHVybiB0eXBlRm9yKHR5cGVOYW1lKS5yZWFkKGlucHV0LCBjb250ZXh0KTtcbiAgICB9XG4gICAgdGhpcy5yZWFkID0gcmVhZDtcblxuICAgIHZhciB3cml0ZSA9IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0LCB0eXBlTmFtZSkge1xuICAgICAgcmV0dXJuIHR5cGVGb3IodHlwZU5hbWUpLndyaXRlKGlucHV0KTtcbiAgICB9O1xuICAgIHRoaXMud3JpdGUgPSB3cml0ZTtcblxuXG4gICAgdmFyIFR5cGUgPSBDbGFzcyh7XG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgICB9LFxuICAgICAgZ2V0IG5hbWUoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhdGVnb3J5ID8gdGhpcy5jYXRlZ29yeSArIFwiOlwiICsgdGhpcy50eXBlIDpcbiAgICAgICAgdGhpcy50eXBlO1xuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJgVHlwZWAgc3ViY2xhc3MgbXVzdCBpbXBsZW1lbnQgYHJlYWRgXCIpO1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFR5cGVgIHN1YmNsYXNzIG11c3QgaW1wbGVtZW50IGB3cml0ZWBcIik7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgUHJpbWl0dmUgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBUeXBlLFxuICAgICAgY29uc3R1Y3RvcjogZnVuY3Rpb24odHlwZSkge1xuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBpbnB1dDtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0O1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIE1heWJlID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogVHlwZSxcbiAgICAgIGNhdGVnb3J5OiBcIm51bGxhYmxlXCIsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24odHlwZSkge1xuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBpbnB1dCA9PT0gbnVsbCA/IG51bGwgOlxuICAgICAgICBpbnB1dCA9PT0gdm9pZCgwKSA/IHZvaWQoMCkgOlxuICAgICAgICByZWFkKGlucHV0LCBjb250ZXh0LCB0aGlzLnR5cGUpO1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQgPT09IG51bGwgPyBudWxsIDpcbiAgICAgICAgaW5wdXQgPT09IHZvaWQoMCkgPyB2b2lkKDApIDpcbiAgICAgICAgd3JpdGUoaW5wdXQsIGNvbnRleHQsIHRoaXMudHlwZSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgQXJyYXlPZiA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJhcnJheVwiLFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgdHlwZSA9IHRoaXMudHlwZTtcbiAgICAgICAgcmV0dXJuIGlucHV0Lm1hcChmdW5jdGlvbigkKSB7IHJldHVybiByZWFkKCQsIGNvbnRleHQsIHR5cGUpIH0pO1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgdHlwZSA9IHRoaXMudHlwZTtcbiAgICAgICAgcmV0dXJuIGlucHV0Lm1hcChmdW5jdGlvbigkKSB7IHJldHVybiB3cml0ZSgkLCBjb250ZXh0LCB0eXBlKSB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHZhciBtYWtlRmllbGQgPSBmdW5jdGlvbiBtYWtlRmllbGQobmFtZSwgdHlwZSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBuYW1lLCB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IGZhbHNlLFxuICAgICAgICAgICAgdmFsdWU6IHJlYWQodGhpcy5zdGF0ZVtuYW1lXSwgdGhpcy5jb250ZXh0LCB0eXBlKVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiB0aGlzW25hbWVdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHZhciBtYWtlRmllbGRzID0gZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgcmV0dXJuIHBhaXJzKGRlc2NyaXB0b3IpLnJlZHVjZShmdW5jdGlvbihmaWVsZHMsIHBhaXIpIHtcbiAgICAgICAgdmFyIG5hbWUgPSBwYWlyWzBdLCB0eXBlID0gcGFpclsxXTtcbiAgICAgICAgZmllbGRzW25hbWVdID0gbWFrZUZpZWxkKG5hbWUsIHR5cGUpO1xuICAgICAgICByZXR1cm4gZmllbGRzO1xuICAgICAgfSwge30pO1xuICAgIH1cblxuICAgIHZhciBEaWN0aW9uYXJ5VHlwZSA9IENsYXNzKHt9KTtcblxuICAgIHZhciBEaWN0aW9uYXJ5ID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogVHlwZSxcbiAgICAgIGNhdGVnb3J5OiBcImRpY3RcIixcbiAgICAgIGdldCBuYW1lKCkgeyByZXR1cm4gdGhpcy50eXBlOyB9LFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgICAgdGhpcy50eXBlID0gZGVzY3JpcHRvci50eXBlTmFtZTtcbiAgICAgICAgdGhpcy50eXBlcyA9IGRlc2NyaXB0b3Iuc3BlY2lhbGl6YXRpb25zO1xuXG4gICAgICAgIHZhciBwcm90byA9IE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHtcbiAgICAgICAgICBleHRlbmRzOiBEaWN0aW9uYXJ5VHlwZSxcbiAgICAgICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oc3RhdGUsIGNvbnRleHQpIHtcbiAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAgICAgICAgICAgc3RhdGU6IHtcbiAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgdmFsdWU6IHN0YXRlXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBjb250ZXh0XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSwgbWFrZUZpZWxkcyh0aGlzLnR5cGVzKSk7XG5cbiAgICAgICAgdGhpcy5jbGFzcyA9IG5ldyBDbGFzcyhwcm90byk7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyB0aGlzLmNsYXNzKGlucHV0LCBjb250ZXh0KTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIG91dHB1dCA9IHt9O1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gaW5wdXQpIHtcbiAgICAgICAgICBvdXRwdXRba2V5XSA9IHdyaXRlKHZhbHVlLCBjb250ZXh0LCB0eXBlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIG1ha2VNZXRob2RzID0gZnVuY3Rpb24oZGVzY3JpcHRvcnMpIHtcbiAgICAgIHJldHVybiBkZXNjcmlwdG9ycy5yZWR1Y2UoZnVuY3Rpb24obWV0aG9kcywgZGVzY3JpcHRvcikge1xuICAgICAgICBtZXRob2RzW2Rlc2NyaXB0b3IubmFtZV0gPSB7XG4gICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgICAgIHZhbHVlOiBtYWtlTWV0aG9kKGRlc2NyaXB0b3IpXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBtZXRob2RzO1xuICAgICAgfSwge30pO1xuICAgIH07XG5cbiAgICB2YXIgbWFrZUV2ZW50cyA9IGZ1bmN0aW9uKGRlc2NyaXB0b3JzKSB7XG4gICAgICByZXR1cm4gcGFpcnMoZGVzY3JpcHRvcnMpLnJlZHVjZShmdW5jdGlvbihldmVudHMsIHBhaXIpIHtcbiAgICAgICAgdmFyIG5hbWUgPSBwYWlyWzBdLCBkZXNjcmlwdG9yID0gcGFpclsxXTtcbiAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KG5hbWUsIGRlc2NyaXB0b3IpO1xuICAgICAgICBldmVudHNbZXZlbnQuZXZlbnRUeXBlXSA9IGV2ZW50O1xuICAgICAgICByZXR1cm4gZXZlbnRzO1xuICAgICAgfSwgT2JqZWN0LmNyZWF0ZShudWxsKSk7XG4gICAgfTtcblxuICAgIHZhciBBY3RvciA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJhY3RvclwiLFxuICAgICAgZ2V0IG5hbWUoKSB7IHJldHVybiB0aGlzLnR5cGU7IH0sXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgICB0aGlzLnR5cGUgPSBkZXNjcmlwdG9yLnR5cGVOYW1lO1xuXG4gICAgICAgIHZhciBldmVudHMgPSBtYWtlRXZlbnRzKGRlc2NyaXB0b3IuZXZlbnRzIHx8IHt9KTtcbiAgICAgICAgdmFyIGZpZWxkcyA9IG1ha2VGaWVsZHMoZGVzY3JpcHRvci5maWVsZHMgfHwge30pO1xuICAgICAgICB2YXIgbWV0aG9kcyA9IG1ha2VNZXRob2RzKGRlc2NyaXB0b3IubWV0aG9kcyB8fCBbXSk7XG5cblxuICAgICAgICB2YXIgcHJvdG8gPSB7XG4gICAgICAgICAgZXh0ZW5kczogRnJvbnQsXG4gICAgICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgRnJvbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIGV2ZW50czogZXZlbnRzXG4gICAgICAgIH07XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHByb3RvLCBmaWVsZHMpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhwcm90bywgbWV0aG9kcyk7XG5cbiAgICAgICAgdGhpcy5jbGFzcyA9IENsYXNzKHByb3RvKTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCwgZGV0YWlsKSB7XG4gICAgICAgIHZhciBzdGF0ZSA9IHR5cGVvZihpbnB1dCkgPT09IFwic3RyaW5nXCIgPyB7IGFjdG9yOiBpbnB1dCB9IDogaW5wdXQ7XG5cbiAgICAgICAgdmFyIGFjdG9yID0gY2xpZW50LmdldChzdGF0ZS5hY3RvcikgfHwgbmV3IHRoaXMuY2xhc3Moc3RhdGUsIGNvbnRleHQpO1xuICAgICAgICBhY3Rvci5mb3JtKHN0YXRlLCBkZXRhaWwsIGNvbnRleHQpO1xuXG4gICAgICAgIHJldHVybiBhY3RvcjtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQsIGRldGFpbCkge1xuICAgICAgICByZXR1cm4gaW5wdXQuaWQ7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZXhwb3J0cy5BY3RvciA9IEFjdG9yO1xuXG5cbiAgICB2YXIgQWN0b3JEZXRhaWwgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBBY3RvcixcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihuYW1lKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IG5hbWUuc3BsaXQoXCIjXCIpXG4gICAgICAgIHRoaXMuYWN0b3JUeXBlID0gcGFydHNbMF1cbiAgICAgICAgdGhpcy5kZXRhaWwgPSBwYXJ0c1sxXTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gdHlwZUZvcih0aGlzLmFjdG9yVHlwZSkucmVhZChpbnB1dCwgY29udGV4dCwgdGhpcy5kZXRhaWwpO1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gdHlwZUZvcih0aGlzLmFjdG9yVHlwZSkud3JpdGUoaW5wdXQsIGNvbnRleHQsIHRoaXMuZGV0YWlsKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBleHBvcnRzLkFjdG9yRGV0YWlsID0gQWN0b3JEZXRhaWw7XG5cbiAgICB2YXIgTWV0aG9kID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogVHlwZSxcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IGRlc2NyaXB0b3IubmFtZTtcbiAgICAgICAgdGhpcy5wYXRoID0gZmluZFBhdGgoZGVzY3JpcHRvci5yZXNwb25zZSwgXCJfcmV0dmFsXCIpO1xuICAgICAgICB0aGlzLnJlc3BvbnNlVHlwZSA9IHRoaXMucGF0aCAmJiBxdWVyeShkZXNjcmlwdG9yLnJlc3BvbnNlLCB0aGlzLnBhdGgpLl9yZXR2YWw7XG4gICAgICAgIHRoaXMucmVxdWVzdFR5cGUgPSBkZXNjcmlwdG9yLnJlcXVlc3QudHlwZTtcblxuICAgICAgICB2YXIgcGFyYW1zID0gW107XG4gICAgICAgIGZvciAodmFyIGtleSBpbiBkZXNjcmlwdG9yLnJlcXVlc3QpIHtcbiAgICAgICAgICBpZiAoa2V5ICE9PSBcInR5cGVcIikge1xuICAgICAgICAgICAgdmFyIHBhcmFtID0gZGVzY3JpcHRvci5yZXF1ZXN0W2tleV07XG4gICAgICAgICAgICB2YXIgaW5kZXggPSBcIl9hcmdcIiBpbiBwYXJhbSA/IHBhcmFtLl9hcmcgOiBwYXJhbS5fb3B0aW9uO1xuICAgICAgICAgICAgdmFyIGlzUGFyYW0gPSBwYXJhbS5fb3B0aW9uID09PSBpbmRleDtcbiAgICAgICAgICAgIHZhciBpc0FyZ3VtZW50ID0gcGFyYW0uX2FyZyA9PT0gaW5kZXg7XG4gICAgICAgICAgICBwYXJhbXNbaW5kZXhdID0ge1xuICAgICAgICAgICAgICB0eXBlOiBwYXJhbS50eXBlLFxuICAgICAgICAgICAgICBrZXk6IGtleSxcbiAgICAgICAgICAgICAgaW5kZXg6IGluZGV4LFxuICAgICAgICAgICAgICBpc1BhcmFtOiBpc1BhcmFtLFxuICAgICAgICAgICAgICBpc0FyZ3VtZW50OiBpc0FyZ3VtZW50XG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnBhcmFtcyA9IHBhcmFtcztcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gcmVhZChxdWVyeShpbnB1dCwgdGhpcy5wYXRoKSwgY29udGV4dCwgdGhpcy5yZXNwb25zZVR5cGUpO1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gdGhpcy5wYXJhbXMucmVkdWNlKGZ1bmN0aW9uKHJlc3VsdCwgcGFyYW0pIHtcbiAgICAgICAgICByZXN1bHRbcGFyYW0ua2V5XSA9IHdyaXRlKGlucHV0W3BhcmFtLmluZGV4XSwgY29udGV4dCwgcGFyYW0udHlwZSk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSwge3R5cGU6IHRoaXMudHlwZX0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGV4cG9ydHMuTWV0aG9kID0gTWV0aG9kO1xuXG4gICAgdmFyIHByb2ZpbGVyID0gZnVuY3Rpb24obWV0aG9kLCBpZCkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgc3RhcnQgPSBuZXcgRGF0ZSgpO1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykudGhlbihmdW5jdGlvbihyZXN1bHQpIHtcbiAgICAgICAgICB2YXIgZW5kID0gbmV3IERhdGUoKTtcbiAgICAgICAgICBjbGllbnQudGVsZW1ldHJ5LmFkZChpZCwgK2VuZCAtIHN0YXJ0KTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBkZXN0cnVjdG9yID0gZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBtZXRob2QuYXBwbHkodGhpcywgYXJndW1lbnRzKS50aGVuKGZ1bmN0aW9uKHJlc3VsdCkge1xuICAgICAgICAgIGNsaWVudC5yZWxlYXNlKHRoaXMpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gbWFrZU1ldGhvZChkZXNjcmlwdG9yKSB7XG4gICAgICB2YXIgdHlwZSA9IG5ldyBNZXRob2QoZGVzY3JpcHRvcik7XG4gICAgICB2YXIgbWV0aG9kID0gZGVzY3JpcHRvci5vbmV3YXkgPyBtYWtlVW5pZGlyZWNhdGlvbmFsTWV0aG9kKGRlc2NyaXB0b3IsIHR5cGUpIDpcbiAgICAgICAgICAgICAgICAgICBtYWtlQmlkaXJlY3Rpb25hbE1ldGhvZChkZXNjcmlwdG9yLCB0eXBlKTtcblxuICAgICAgaWYgKGRlc2NyaXB0b3IudGVsZW1ldHJ5KVxuICAgICAgICBtZXRob2QgPSBwcm9maWxlcihtZXRob2QpO1xuICAgICAgaWYgKGRlc2NyaXB0b3IucmVsZWFzZSlcbiAgICAgICAgbWV0aG9kID0gZGVzdHJ1Y3RvcihtZXRob2QpO1xuXG4gICAgICByZXR1cm4gbWV0aG9kO1xuICAgIH1cblxuICAgIHZhciBtYWtlVW5pZGlyZWNhdGlvbmFsTWV0aG9kID0gZnVuY3Rpb24oZGVzY3JpcHRvciwgdHlwZSkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcGFja2V0ID0gdHlwZS53cml0ZShhcmd1bWVudHMsIHRoaXMpO1xuICAgICAgICBwYWNrZXQudG8gPSB0aGlzLmlkO1xuICAgICAgICBjbGllbnQuc2VuZChwYWNrZXQpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHZvaWQoMCkpO1xuICAgICAgfTtcbiAgICB9O1xuXG4gICAgdmFyIG1ha2VCaWRpcmVjdGlvbmFsTWV0aG9kID0gZnVuY3Rpb24oZGVzY3JpcHRvciwgdHlwZSkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgY29udGV4dCA9IHRoaXMuY29udGV4dDtcbiAgICAgICAgdmFyIHBhY2tldCA9IHR5cGUud3JpdGUoYXJndW1lbnRzLCBjb250ZXh0KTtcbiAgICAgICAgdmFyIGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIHBhY2tldC50byA9IHRoaXMuaWQ7XG4gICAgICAgIHJldHVybiBjbGllbnQucmVxdWVzdChwYWNrZXQpLnRoZW4oZnVuY3Rpb24ocGFja2V0KSB7XG4gICAgICAgICAgcmV0dXJuIHR5cGUucmVhZChwYWNrZXQsIGNvbnRleHQpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBFdmVudCA9IENsYXNzKHtcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihuYW1lLCBkZXNjcmlwdG9yKSB7XG4gICAgICAgIHRoaXMubmFtZSA9IGRlc2NyaXB0b3IudHlwZSB8fCBuYW1lO1xuICAgICAgICB0aGlzLmV2ZW50VHlwZSA9IGRlc2NyaXB0b3IudHlwZSB8fCBuYW1lO1xuICAgICAgICB0aGlzLnR5cGVzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcblxuICAgICAgICB2YXIgdHlwZXMgPSB0aGlzLnR5cGVzO1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gZGVzY3JpcHRvcikge1xuICAgICAgICAgIGlmIChrZXkgPT09IFwidHlwZVwiKSB7XG4gICAgICAgICAgICB0eXBlc1trZXldID0gXCJzdHJpbmdcIjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdHlwZXNba2V5XSA9IGRlc2NyaXB0b3Jba2V5XS50eXBlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB7fTtcbiAgICAgICAgdmFyIHR5cGVzID0gdGhpcy50eXBlcztcbiAgICAgICAgZm9yICh2YXIga2V5IGluIGlucHV0KSB7XG4gICAgICAgICAgb3V0cHV0W2tleV0gPSByZWFkKGlucHV0W2tleV0sIGNvbnRleHQsIHR5cGVzW2tleV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdXRwdXQ7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB7fTtcbiAgICAgICAgdmFyIHR5cGVzID0gdGhpcy50eXBlcztcbiAgICAgICAgZm9yICh2YXIga2V5IGluIHRoaXMudHlwZXMpIHtcbiAgICAgICAgICBvdXRwdXRba2V5XSA9IHdyaXRlKGlucHV0W2tleV0sIGNvbnRleHQsIHR5cGVzW2tleV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdXRwdXQ7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgRnJvbnQgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBFdmVudFRhcmdldCxcbiAgICAgIEV2ZW50VGFyZ2V0OiBFdmVudFRhcmdldCxcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihzdGF0ZSkge1xuICAgICAgICB0aGlzLkV2ZW50VGFyZ2V0KCk7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsICB7XG4gICAgICAgICAgc3RhdGU6IHtcbiAgICAgICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogc3RhdGVcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNsaWVudC5yZWdpc3Rlcih0aGlzKTtcbiAgICAgIH0sXG4gICAgICBnZXQgaWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0YXRlLmFjdG9yO1xuICAgICAgfSxcbiAgICAgIGdldCBjb250ZXh0KCkge1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH0sXG4gICAgICBmb3JtOiBmdW5jdGlvbihzdGF0ZSwgZGV0YWlsLCBjb250ZXh0KSB7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlICE9PSBzdGF0ZSkge1xuICAgICAgICAgIGlmIChkZXRhaWwpIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGVbZGV0YWlsXSA9IHN0YXRlW2RldGFpbF07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBhaXJzKHN0YXRlKS5mb3JFYWNoKGZ1bmN0aW9uKHBhaXIpIHtcbiAgICAgICAgICAgICAgdmFyIGtleSA9IHBhaXJbMF0sIHZhbHVlID0gcGFpclsxXTtcbiAgICAgICAgICAgICAgdGhpcy5zdGF0ZVtrZXldID0gdmFsdWU7XG4gICAgICAgICAgICB9LCB0aGlzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29udGV4dCkge1xuICAgICAgICAgIGNsaWVudC5zdXBlcnZpc2UoY29udGV4dCwgdGhpcyk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZXF1ZXN0VHlwZXM6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gY2xpZW50LnJlcXVlc3Qoe1xuICAgICAgICAgIHRvOiB0aGlzLmlkLFxuICAgICAgICAgIHR5cGU6IFwicmVxdWVzdFR5cGVzXCJcbiAgICAgICAgfSkudGhlbihmdW5jdGlvbihwYWNrZXQpIHtcbiAgICAgICAgICByZXR1cm4gcGFja2V0LnJlcXVlc3RUeXBlcztcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdHlwZXMucHJpbWl0aXZlID0gbmV3IFByaW1pdHZlKFwicHJpbWl0aXZlXCIpO1xuICAgIHR5cGVzLnN0cmluZyA9IG5ldyBQcmltaXR2ZShcInN0cmluZ1wiKTtcbiAgICB0eXBlcy5udW1iZXIgPSBuZXcgUHJpbWl0dmUoXCJudW1iZXJcIik7XG4gICAgdHlwZXMuYm9vbGVhbiA9IG5ldyBQcmltaXR2ZShcImJvb2xlYW5cIik7XG4gICAgdHlwZXMuanNvbiA9IG5ldyBQcmltaXR2ZShcImpzb25cIik7XG4gICAgdHlwZXMuYXJyYXkgPSBuZXcgUHJpbWl0dmUoXCJhcnJheVwiKTtcbiAgfSxcbiAgcmVnaXN0ZXJUeXBlczogZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgIHZhciBzcGVjaWZpY2F0aW9uID0gdGhpcy5zcGVjaWZpY2F0aW9uO1xuICAgIHZhbHVlcyhkZXNjcmlwdG9yLnR5cGVzKS5mb3JFYWNoKGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgIHNwZWNpZmljYXRpb25bZGVzY3JpcHRvci50eXBlTmFtZV0gPSBkZXNjcmlwdG9yO1xuICAgIH0pO1xuICB9XG59KTtcbmV4cG9ydHMuVHlwZVN5c3RlbSA9IFR5cGVTeXN0ZW07XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGtleXMgPSBPYmplY3Qua2V5cztcbmV4cG9ydHMua2V5cyA9IGtleXM7XG5cbi8vIFJldHVybnMgYXJyYXkgb2YgdmFsdWVzIGZvciB0aGUgZ2l2ZW4gb2JqZWN0LlxudmFyIHZhbHVlcyA9IGZ1bmN0aW9uKG9iamVjdCkge1xuICByZXR1cm4ga2V5cyhvYmplY3QpLm1hcChmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4gb2JqZWN0W2tleV1cbiAgfSk7XG59O1xuZXhwb3J0cy52YWx1ZXMgPSB2YWx1ZXM7XG5cbi8vIFJldHVybnMgW2tleSwgdmFsdWVdIHBhaXJzIGZvciB0aGUgZ2l2ZW4gb2JqZWN0LlxudmFyIHBhaXJzID0gZnVuY3Rpb24ob2JqZWN0KSB7XG4gIHJldHVybiBrZXlzKG9iamVjdCkubWFwKGZ1bmN0aW9uKGtleSkge1xuICAgIHJldHVybiBba2V5LCBvYmplY3Rba2V5XV1cbiAgfSk7XG59O1xuZXhwb3J0cy5wYWlycyA9IHBhaXJzO1xuXG5cbi8vIFF1ZXJpZXMgYW4gb2JqZWN0IGZvciB0aGUgZmllbGQgbmVzdGVkIHdpdGggaW4gaXQuXG52YXIgcXVlcnkgPSBmdW5jdGlvbihvYmplY3QsIHBhdGgpIHtcbiAgcmV0dXJuIHBhdGgucmVkdWNlKGZ1bmN0aW9uKG9iamVjdCwgZW50cnkpIHtcbiAgICByZXR1cm4gb2JqZWN0ICYmIG9iamVjdFtlbnRyeV1cbiAgfSwgb2JqZWN0KTtcbn07XG5leHBvcnRzLnF1ZXJ5ID0gcXVlcnk7XG5cbnZhciBpc09iamVjdCA9IGZ1bmN0aW9uKHgpIHtcbiAgcmV0dXJuIHggJiYgdHlwZW9mKHgpID09PSBcIm9iamVjdFwiXG59XG5cbnZhciBmaW5kUGF0aCA9IGZ1bmN0aW9uKG9iamVjdCwga2V5KSB7XG4gIHZhciBwYXRoID0gdm9pZCgwKTtcbiAgaWYgKG9iamVjdCAmJiB0eXBlb2Yob2JqZWN0KSA9PT0gXCJvYmplY3RcIikge1xuICAgIHZhciBuYW1lcyA9IGtleXMob2JqZWN0KTtcbiAgICBpZiAobmFtZXMuaW5kZXhPZihrZXkpID49IDApIHtcbiAgICAgIHBhdGggPSBbXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGluZGV4ID0gMDtcbiAgICAgIHZhciBjb3VudCA9IG5hbWVzLmxlbmd0aDtcbiAgICAgIHdoaWxlIChpbmRleCA8IGNvdW50ICYmICFwYXRoKXtcbiAgICAgICAgdmFyIGhlYWQgPSBuYW1lc1tpbmRleF07XG4gICAgICAgIHZhciB0YWlsID0gZmluZFBhdGgob2JqZWN0W2hlYWRdLCBrZXkpO1xuICAgICAgICBwYXRoID0gdGFpbCA/IFtoZWFkXS5jb25jYXQodGFpbCkgOiB0YWlsO1xuICAgICAgICBpbmRleCA9IGluZGV4ICsgMVxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gcGF0aDtcbn07XG5leHBvcnRzLmZpbmRQYXRoID0gZmluZFBhdGg7XG4iXX0=
 (1)
 });
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/framescript/LoaderHelper.jsm
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
+const { Loader } = Cu.import('resource://gre/modules/commonjs/toolkit/loader.js', {});
+const cpmm = Cc['@mozilla.org/childprocessmessagemanager;1'].getService(Ci.nsISyncMessageSender);
+
+// one Loader instance per addon (per @loader/options to be precise)
+let addons = new Map();
+
+cpmm.addMessageListener('sdk/loader/unload', ({ data: options }) => {
+  let key = JSON.stringify(options);
+  let addon = addons.get(key);
+  if (addon)
+    addon.loader.unload();
+  addons.delete(key);
+})
+
+// create a Loader instance from @loader/options
+function loader(options) {
+  let key = JSON.stringify(options);
+  let addon = addons.get(key) || {};
+  if (!addon.loader) {
+    addon.loader = Loader.Loader(options);
+    addon.require = Loader.Require(addon.loader, { id: 'LoaderHelper' });
+    addons.set(key, addon);
+  }
+  return addon;
+}
+
+const EXPORTED_SYMBOLS = ['loader'];
--- a/addon-sdk/source/lib/framescript/tab-events.js
+++ b/addon-sdk/source/lib/framescript/tab-events.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const observerSvc = Components.classes["@mozilla.org/observer-service;1"].
-                    getService(Components.interfaces.nsIObserverService);
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+const observerSvc = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
 
 // map observer topics to tab event names
 const EVENTS = {
   'content-document-interactive': 'ready',
   'chrome-document-interactive': 'ready',
   'content-document-loaded': 'load',
   'chrome-document-loaded': 'load',
 // 'content-page-shown': 'pageshow', // bug 1024105
@@ -27,8 +27,25 @@ function listener(subject, topic) {
 for (let topic in EVENTS)
   observerSvc.addObserver(listener, topic, false);
 
 // bug 1024105 - content-page-shown notification doesn't pass persisted param
 addEventListener('pageshow', ({ target, type, persisted }) => {
   if (target === content.document)
     sendAsyncMessage('sdk/tab/event', { type, persisted });
 }, true);
+
+
+// workers for windows in this tab
+let keepAlive = new Map();
+
+addMessageListener('sdk/worker/create', ({ data: { options, addon }}) => {
+  options.manager = this;
+  let { loader } = Cu.import(addon.paths[''] + 'framescript/LoaderHelper.jsm', {});
+  let { WorkerChild } = loader(addon).require('sdk/content/worker-child');
+  sendAsyncMessage('sdk/worker/attach', { id: options.id });
+  keepAlive.set(options.id, new WorkerChild(options));
+})
+
+addMessageListener('sdk/worker/event', ({ data: { id, args: [event]}}) => {
+  if (event === 'detach')
+    keepAlive.delete(id);
+})
--- a/addon-sdk/source/lib/sdk/base64.js
+++ b/addon-sdk/source/lib/sdk/base64.js
@@ -24,19 +24,20 @@ function isUTF8(charset) {
   if (type === "string" && charset.toLowerCase() === "utf-8")
     return true;
 
   throw new Error("The charset argument can be only 'utf-8'");
 }
 
 exports.decode = function (data, charset) {
   if (isUTF8(charset))
-		return decodeURIComponent(escape(atob(data)))
+    return decodeURIComponent(escape(atob(data)))
 
-	return atob(data);
+  return atob(data);
 }
 
 exports.encode = function (data, charset) {
   if (isUTF8(charset))
     return btoa(unescape(encodeURIComponent(data)))
 
-	return btoa(data);
+  data = String.fromCharCode(...[(c.charCodeAt(0) & 0xff) for (c of data)]);
+  return btoa(data);
 }
--- a/addon-sdk/source/lib/sdk/clipboard.js
+++ b/addon-sdk/source/lib/sdk/clipboard.js
@@ -3,17 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "stable",
   "engines": {
     // TODO Fennec Support 789757
-    "Firefox": "*"
+    "Firefox": "*",
+    "SeaMonkey": "*"
   }
 };
 
 const { Cc, Ci } = require("chrome");
 const { DataURL } = require("./url");
 const errors = require("./deprecated/errors");
 const apiUtils = require("./deprecated/api-utils");
 /*
--- a/addon-sdk/source/lib/sdk/content/content-worker.js
+++ b/addon-sdk/source/lib/sdk/content/content-worker.js
@@ -275,46 +275,16 @@ Object.freeze({
       postMessage: pipe.emit.bind(null, "message"),
       on: pipe.on.bind(null),
       once: pipe.once.bind(null),
       removeListener: pipe.removeListener.bind(null),
     };
     Object.defineProperty(exports, "self", {
       value: self
     });
-
-    exports.on = function deprecatedOn() {
-      console.error("DEPRECATED: The global `on()` function in content " +
-                    "scripts is deprecated in favor of the `self.on()` " +
-                    "function, which works the same. Replace calls to `on()` " +
-                    "with calls to `self.on()`" +
-                    "For more info on `self.on`, see " +
-                    "<https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/using_postMessage>.");
-      return self.on.apply(null, arguments);
-    };
-
-    // Deprecated use of `onMessage` from globals
-    let onMessage = null;
-    Object.defineProperty(exports, "onMessage", {
-      get: function () onMessage,
-      set: function (v) {
-        if (onMessage)
-          self.removeListener("message", onMessage);
-        console.error("DEPRECATED: The global `onMessage` function in content" +
-                      "scripts is deprecated in favor of the `self.on()` " +
-                      "function. Replace `onMessage = function (data){}` " +
-                      "definitions with calls to `self.on('message', " +
-                      "function (data){})`. " +
-                      "For more info on `self.on`, see " +
-                      "<https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/using_postMessage>.");
-        onMessage = v;
-        if (typeof onMessage == "function")
-          self.on("message", onMessage);
-      }
-    });
   },
 
   injectOptions: function (exports, options) {
     Object.defineProperty( exports.self, "options", { value: JSON.parse( options ) });
   },
 
   inject: function (exports, chromeAPI, emitToChrome, options) {
     let ContentWorker = this;
--- a/addon-sdk/source/lib/sdk/content/thumbnail.js
+++ b/addon-sdk/source/lib/sdk/content/thumbnail.js
@@ -39,8 +39,13 @@ exports.getThumbnailCanvasForWindow = ge
 /**
  * Creates Base64 encoded data URI of the thumbnail for the passed window.
  * @param {Window} window
  * @returns {String}
  */
 exports.getThumbnailURIForWindow = function getThumbnailURIForWindow(window) {
   return getThumbnailCanvasForWindow(window).toDataURL()
 };
+
+// default 80x45 blank when not available
+exports.BLANK = 'data:image/png;base64,' +
+  'iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQ'+
+  'EAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC';
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/content/worker-child.js
@@ -0,0 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+const { merge } = require('../util/object');
+const { Class } = require('../core/heritage');
+const { EventTarget } = require('../event/target');
+const { getInnerId, getByInnerId } = require('../window/utils');
+const { instanceOf, isObject } = require('../lang/type');
+const { on: observe } = require('../system/events');
+const { WorkerSandbox } = require('./sandbox');
+const { Ci } = require('chrome');
+
+const EVENTS = {
+  'chrome-page-shown': 'pageshow',
+  'content-page-shown': 'pageshow',
+  'chrome-page-hidden': 'pagehide',
+  'content-page-hidden': 'pagehide',
+  'inner-window-destroyed': 'detach',
+}
+
+const WorkerChild = Class({
+  implements: [EventTarget],
+  initialize(options) {
+    merge(this, options);
+
+    this.port = EventTarget();
+    this.port.on('*', this.send.bind(this, 'event'));
+    this.on('*', this.send.bind(this));
+
+    this.observe = this.observe.bind(this);
+
+    for (let topic in EVENTS)
+      observe(topic, this.observe);
+
+    this.receive = this.receive.bind(this);
+    this.manager.addMessageListener('sdk/worker/message', this.receive);
+
+    this.sandbox = WorkerSandbox(this, getByInnerId(this.window));
+  },
+  // messages
+  receive({ data: { id, args }}) {
+    if (id !== this.id)
+      return;
+    this.sandbox.emit(...args);
+    if (args[0] === 'detach')
+      this.destroy(args[1]);
+  },
+  send(...args) {
+    args = JSON.parse(JSON.stringify(args, exceptions));
+    if (this.manager.content)
+      this.manager.sendAsyncMessage('sdk/worker/event', { id: this.id, args });
+  },
+  // notifications
+  observe({ type, subject }) {
+    if (!this.sandbox)
+      return;
+    if (subject.defaultView && getInnerId(subject.defaultView) === this.window) {
+      this.sandbox.emitSync(EVENTS[type]);
+      this.send(EVENTS[type]);
+    }
+    if (type === 'inner-window-destroyed' &&
+        subject.QueryInterface(Ci.nsISupportsPRUint64).data === this.window) {
+      this.destroy();
+    }
+  },
+  // detach/destroy: unload and release the sandbox
+  destroy(reason) {
+    if (!this.sandbox)
+      return;
+    if (this.manager.content)
+      this.manager.removeMessageListener('sdk/worker/message', this.receive);
+    this.sandbox.destroy(reason);
+    this.sandbox = null;
+    this.send('detach');
+  }
+})
+exports.WorkerChild = WorkerChild;
+
+// Error instances JSON poorly
+function exceptions(key, value) {
+  if (!isObject(value) || !instanceOf(value, Error))
+    return value;
+  let _errorType = value.constructor.name;
+  let { message, fileName, lineNumber, stack, name } = value;
+  return { _errorType, message, fileName, lineNumber, stack, name };
+}
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/content/worker-parent.js
@@ -0,0 +1,184 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+module.metadata = {
+  "stability": "unstable"
+};
+
+const { emit } = require('../event/core');
+const { omit } = require('../util/object');
+const { Class } = require('../core/heritage');
+const { method } = require('../lang/functional');
+const { getInnerId } = require('../window/utils');
+const { EventTarget } = require('../event/target');
+const { when, ensure } = require('../system/unload');
+const { getTabForWindow } = require('../tabs/helpers');
+const { getTabForContentWindow, getBrowserForTab } = require('../tabs/utils');
+const { isPrivate } = require('../private-browsing/utils');
+const { getFrameElement } = require('../window/utils');
+const { attach, detach, destroy } = require('./utils');
+const { on: observe } = require('../system/events');
+const { uuid } = require('../util/uuid');
+const { Ci, Cc } = require('chrome');
+
+const ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"].
+  getService(Ci.nsIMessageBroadcaster);
+
+// null-out cycles in .modules to make @loader/options JSONable
+const ADDON = omit(require('@loader/options'), ['modules', 'globals']);
+
+const workers = new WeakMap();
+let modelFor = (worker) => workers.get(worker);
+
+const ERR_DESTROYED = "Couldn't find the worker to receive this message. " +
+  "The script may not be initialized yet, or may already have been unloaded.";
+
+const ERR_FROZEN = "The page is currently hidden and can no longer be used " +
+                   "until it is visible again.";
+
+// a handle for communication between content script and addon code
+const Worker = Class({
+  implements: [EventTarget],
+  initialize(options = {}) {
+
+    let model = {
+      inited: false,
+      earlyEvents: [],        // fired before worker was inited
+      frozen: true,           // document is in BFcache, let it go
+      options,
+    };
+    workers.set(this, model);
+
+    ensure(this, 'destroy');
+    this.on('detach', this.detach);
+    EventTarget.prototype.initialize.call(this, options);
+
+    this.receive = this.receive.bind(this);
+
+    model.observe = ({ subject }) => {
+      let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
+      if (model.window && getInnerId(model.window) === id)
+        this.detach();
+    }
+
+    observe('inner-window-destroyed', model.observe);
+
+    this.port = EventTarget();
+    this.port.emit = this.send.bind(this, 'event');
+    this.postMessage = this.send.bind(this, 'message');
+
+    if ('window' in options)
+      attach(this, options.window);
+  },
+  // messages
+  receive({ data: { id, args }}) {
+    let model = modelFor(this);
+    if (id !== model.id || !model.childWorker)
+      return;
+    if (args[0] === 'event')
+      emit(this.port, ...args.slice(1))
+    else
+      emit(this, ...args);
+  },
+  send(...args) {
+    let model = modelFor(this);
+    if (!model.inited) {
+      model.earlyEvents.push(args);
+      return;
+    }
+    if (!model.childWorker && args[0] !== 'detach')
+      throw new Error(ERR_DESTROYED);
+    if (model.frozen && args[0] !== 'detach')
+      throw new Error(ERR_FROZEN);
+    try {
+      model.manager.sendAsyncMessage('sdk/worker/message', { id: model.id, args });
+    } catch (e) {
+      //
+    }
+  },
+  // properties
+  get url() {
+    let { window } = modelFor(this);
+    return window && window.document.location.href;
+  },
+  get contentURL() {
+    let { window } = modelFor(this);
+    return window && window.document.URL;
+  },
+  get tab() {
+    let { window } = modelFor(this);
+    return window && getTabForWindow(window);
+  },
+  toString: () => '[object Worker]',
+  // methods
+  attach: method(attach),
+  detach: method(detach),
+  destroy: method(destroy),
+})
+exports.Worker = Worker;
+
+attach.define(Worker, function(worker, window) {
+  let model = modelFor(worker);
+
+  model.window = window;
+  model.options.window = getInnerId(window);
+  model.id = model.options.id = String(uuid());
+
+  let tab = getTabForContentWindow(window);
+  if (tab) {
+    model.manager = getBrowserForTab(tab).messageManager;
+  } else {
+    model.manager = getFrameElement(window.top).frameLoader.messageManager;
+  }
+
+  model.manager.addMessageListener('sdk/worker/event', worker.receive);
+  model.manager.addMessageListener('sdk/worker/attach', attach);
+
+  model.manager.sendAsyncMessage('sdk/worker/create', {
+    options: model.options,
+    addon: ADDON
+  });
+
+  function attach({ data }) {
+    if (data.id !== model.id)
+      return;
+    model.manager.removeMessageListener('sdk/worker/attach', attach);
+    model.childWorker = true;
+
+    worker.on('pageshow', () => model.frozen = false);
+    worker.on('pagehide', () => model.frozen = true);
+
+    model.inited = true;
+    model.frozen = false;
+
+    model.earlyEvents.forEach(args => worker.send(...args));
+    emit(worker, 'attach', window);
+  }
+})
+
+// unload and release the child worker, release window reference
+detach.define(Worker, function(worker, reason) {
+  let model = modelFor(worker);
+  worker.send('detach', reason);
+  if (!model.childWorker)
+    return;
+
+  model.childWorker = null;
+  model.earlyEvents = [];
+  model.window = null;
+  emit(worker, 'detach');
+  model.manager.removeMessageListener('sdk/worker/event', this.receive);
+})
+
+isPrivate.define(Worker, ({ tab }) => isPrivate(tab));
+
+// unlod worker, release references
+destroy.define(Worker, function(worker, reason) {
+  detach(worker, reason);
+  modelFor(worker).inited = true;
+})
+
+// unload Loaders used for creating WorkerChild instances in each process
+when(() => ppmm.broadcastAsyncMessage('sdk/loader/unload', { data: ADDON }));
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -2,17 +2,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "stable",
   "engines": {
     // TODO Fennec support Bug 788334
-    "Firefox": "*"
+    "Firefox": "*",
+    "SeaMonkey": "*"
   }
 };
 
 const { Class, mix } = require("./core/heritage");
 const { addCollectionProperty } = require("./util/collection");
 const { ns } = require("./core/namespace");
 const { validateOptions, getTypeOf } = require("./deprecated/api-utils");
 const { URL, isValidURI } = require("./url");
--- a/addon-sdk/source/lib/sdk/core/heritage.js
+++ b/addon-sdk/source/lib/sdk/core/heritage.js
@@ -3,17 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "unstable"
 };
 
 var getPrototypeOf = Object.getPrototypeOf;
-var getNames = Object.getOwnPropertyNames;
+var getNames = x => [...Object.getOwnPropertyNames(x),
+                     ...Object.getOwnPropertySymbols(x)];
 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
 var create = Object.create;
 var freeze = Object.freeze;
 var unbind = Function.call.bind(Function.bind, Function.call);
 
 // This shortcut makes sure that we do perform desired operations, even if
 // associated methods have being overridden on the used object.
 var owns = unbind(Object.prototype.hasOwnProperty);
--- a/addon-sdk/source/lib/sdk/core/promise.js
+++ b/addon-sdk/source/lib/sdk/core/promise.js
@@ -53,19 +53,19 @@ let promised = (function() {
     a prototype for a returned promise.
 
     ## Example
 
     var promise = promised(Array)(1, promise(2), promise(3))
     promise.then(console.log) // => [ 1, 2, 3 ]
     **/
 
-    return function promised() {
+    return function promised(...args) {
       // create array of [ f, this, args... ]
-      return concat.apply([ f, this ], arguments).
+      return [f, this, ...args].
         // reduce it via `promisedConcat` to get promised array of fulfillments
         reduce(promisedConcat, resolve([], prototype)).
         // finally map that to promise of `f.apply(this, args...)`
         then(execute);
     };
   };
 })();
 
--- a/addon-sdk/source/lib/sdk/deprecated/cortex.js
+++ b/addon-sdk/source/lib/sdk/deprecated/cortex.js
@@ -3,16 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "deprecated"
 };
 
+const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
+                                ...Object.getOwnPropertySymbols(x)];
+
+
 // `var` is being used in the module in order to make it reusable in
 // environments in which `let` and `const` is not yet supported.
 
 // Returns `object`'s property value, where `name` is a name of the property.
 function get(object, name) {
   return object[name];
 }
 
@@ -41,17 +45,17 @@ function createAliasProperty(object, nam
   // If the original property has a getter and/or setter, bind a
   // corresponding getter/setter in the alias descriptor to the original
   // object, so the `this` object in the getter/setter is the original object
   // rather than the alias.
   if ("get" in property && property.get)
     descriptor.get = property.get.bind(object);
   if ("set" in property && property.set)
     descriptor.set = property.set.bind(object);
-  
+
   // If original property was a value property.
   if ("value" in property) {
     // If original property is a method using it's `object` bounded copy.
     if (typeof property.value === "function") {
       descriptor.value = property.value.bind(object);
       // Also preserving writability of the original property.
       descriptor.writable = property.writable;
     }
@@ -99,14 +103,14 @@ exports.Cortex = function Cortex(object,
   // consumer to define expected behavior `instanceof`. In common case
   // `prototype` argument can be omitted to preserve same behavior of
   // `instanceof` as on original `object`.
   var cortex = Object.create(prototype || Object.getPrototypeOf(object));
   // Creating alias properties on the `cortex` object for all the own
   // properties of the original `object` that are contained in `names` array.
   // If `names` array is not provided then all the properties that don't
   // start with `"_"` are aliased.
-  Object.getOwnPropertyNames(object).forEach(function (name) {
-    if ((!names && "_" !== name.charAt(0)) || (names && ~names.indexOf(name)))
+  getOwnIdentifiers(object).forEach(function (name) {
+    if ((!names && "_" !== name.toString().charAt(0)) || (names && ~names.indexOf(name)))
       defineAlias(object, cortex, name);
   });
   return cortex;
 }
--- a/addon-sdk/source/lib/sdk/deprecated/list.js
+++ b/addon-sdk/source/lib/sdk/deprecated/list.js
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Trait } = require('../deprecated/traits');
-const { iteratorSymbol } = require('../util/iteration');
 
 /**
  * @see https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/util_list
  */
 const Iterable = Trait.compose({
   /**
    * Hash map of key-values to iterate over.
    * Note: That this property can be a getter if you need dynamic behavior.
@@ -111,16 +110,16 @@ const listOptions = {
    */
   __iterator__: function __iterator__(onKeys, onKeyValue) {
     let array = this._keyValueMap.slice(0),
         i = -1;
     for (let element of array)
       yield onKeyValue ? [++i, element] : onKeys ? ++i : element;
   },
 };
-listOptions[iteratorSymbol] = function* iterator() {
+listOptions[Symbol.iterator] = function* iterator() {
   let array = this._keyValueMap.slice(0);
 
   for (let element of array)
     yield element;
 }
 const List = Trait.resolve({ toString: null }).compose(listOptions);
 exports.List = List;
--- a/addon-sdk/source/lib/sdk/deprecated/traits.js
+++ b/addon-sdk/source/lib/sdk/deprecated/traits.js
@@ -1,42 +1,42 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 module.metadata = {
   "stability": "deprecated"
 };
 
 const {
   compose: _compose,
   override: _override,
   resolve: _resolve,
   trait: _trait,
   //create: _create,
   required,
 } = require('./traits/core');
 
-const defineProperties = Object.defineProperties,
-      freeze = Object.freeze,
-      create = Object.create;
+const { getOwnPropertyIdentifiers } = require('../util/object');
+const defineProperties = Object.defineProperties;
+const freeze = Object.freeze;
+const create = Object.create;
 
 /**
  * Work around bug 608959 by defining the _create function here instead of
  * importing it from traits/core.  For docs on this function, see the create
  * function in that module.
  *
  * FIXME: remove this workaround in favor of importing the function once that
  * bug has been fixed.
  */
 function _create(proto, trait) {
   let properties = {},
-      keys = Object.getOwnPropertyNames(trait);
+      keys = getOwnPropertyIdentifiers(trait);
   for (let key of keys) {
     let descriptor = trait[key];
     if (descriptor.required &&
         !Object.prototype.hasOwnProperty.call(proto, key))
       throw new Error('Missing required property: ' + key);
     else if (descriptor.conflict)
       throw new Error('Remaining conflicting property: ' + key);
     else
@@ -67,19 +67,19 @@ function Set(key, value) this[key] = val
 function TraitDescriptor(object)
   (
     'function' == typeof object &&
     (object.prototype == TraitProto || object.prototype instanceof Trait)
   ) ? object._trait(TraitDescriptor) : _trait(object)
 
 function Public(instance, trait) {
   let result = {},
-      keys = Object.getOwnPropertyNames(trait);
+      keys = getOwnPropertyIdentifiers(trait);
   for (let key of keys) {
-    if ('_' === key.charAt(0) && '__iterator__' !== key )
+    if (typeof key === 'string' && '_' === key.charAt(0) && '__iterator__' !== key )
       continue;
     let property = trait[key],
         descriptor = {
           configurable: property.configurable,
           enumerable: property.enumerable
         };
     if (property.get)
       descriptor.get = property.get.bind(instance);
@@ -179,9 +179,8 @@ const Trait = Composition({
   /**
    * Internal property holding public API of this instance.
    */
   _public: { value: null, configurable: true, writable: true },
   toString: { value: function() '[object ' + this.constructor.name + ']' }
 });
 TraitProto = Trait.prototype;
 exports.Trait = Trait;
-
--- a/addon-sdk/source/lib/sdk/deprecated/traits/core.js
+++ b/addon-sdk/source/lib/sdk/deprecated/traits/core.js
@@ -1,25 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 module.metadata = {
   "stability": "deprecated"
 };
 
 // Design inspired by: http://www.traitsjs.org/
 
-// shortcuts
-const getOwnPropertyNames = Object.getOwnPropertyNames,
-      getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor,
-      hasOwn = Object.prototype.hasOwnProperty,
-      _create = Object.create;
+const { getOwnPropertyIdentifiers } = require('../../util/object');
+const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+const hasOwn = Object.prototype.hasOwnProperty;
+const _create = Object.create;
 
 function doPropertiesMatch(object1, object2, name) {
   // If `object1` has property with the given `name`
   return name in object1 ?
          // then `object2` should have it with the same value.
          name in object2 && object1[name] === object2[name] :
          // otherwise `object2` should not have property with the given `name`.
          !(name in object2);
@@ -109,22 +107,22 @@ function Conflict(name) {
  * 'required' properties.
  * @param {Object} object
  *    Set of properties to generate trait from.
  * @returns {Object}
  *    Properties descriptor of all of the `object`'s own properties.
  */
 function trait(properties) {
   let result = {},
-      keys = getOwnPropertyNames(properties);
- for (let key of keys) {
-   let descriptor = getOwnPropertyDescriptor(properties, key);
-   result[key] = (required === descriptor.value) ? Required(key) : descriptor;
- }
- return result;
+      keys = getOwnPropertyIdentifiers(properties);
+  for (let key of keys) {
+    let descriptor = getOwnPropertyDescriptor(properties, key);
+    result[key] = (required === descriptor.value) ? Required(key) : descriptor;
+  }
+  return result;
 }
 exports.Trait = exports.trait = trait;
 
 /**
  * Composes new trait. If two or more traits have own properties with the
  * same name, the new trait will contain a 'conflict' property for that name.
  * 'compose' is a commutative and associative operation, and the order of its
  * arguments is not significant.
@@ -135,17 +133,17 @@ exports.Trait = exports.trait = trait;
  *    New trait containing the combined own properties of all the traits.
  * @example
  *    var newTrait = compose(trait_1, trait_2, ..., trait_N);
  */
 function compose(trait1, trait2) {
   let traits = Array.slice(arguments, 0),
       result = {};
   for (let trait of traits) {
-    let keys = getOwnPropertyNames(trait);
+    let keys = getOwnPropertyIdentifiers(trait);
     for (let key of keys) {
       let descriptor = trait[key];
       // if property already exists and it's not a requirement
       if (hasOwn.call(result, key) && !result[key].required) {
         if (descriptor.required)
           continue;
         if (!areSame(descriptor, result[key]))
           result[key] = Conflict(key);
@@ -169,17 +167,17 @@ exports.compose = compose;
  * @returns {Object}
  * @example
  *    var newTrait = exclude(['name', ...], trait)
  */
 function exclude(keys, trait) {
   let exclusions = Map(keys),
       result = {};
 
-  keys = getOwnPropertyNames(trait);
+  keys = getOwnPropertyIdentifiers(trait);
 
   for (let key of keys) {
     if (!hasOwn.call(exclusions, key) || trait[key].required)
       result[key] = trait[key];
     else
       result[key] = Required(key);
   }
   return result;
@@ -205,17 +203,17 @@ function exclude(keys, trait) {
  *    override(t1,t2)
  *    // is not equivalent to
  *    override(t2,t1)
  */
 function override() {
   let traits = Array.slice(arguments, 0),
       result = {};
   for (let trait of traits) {
-    let keys = getOwnPropertyNames(trait);
+    let keys = getOwnPropertyIdentifiers(trait);
     for (let key of keys) {
       let descriptor = trait[key];
       if (!hasOwn.call(result, key) || result[key].required)
         result[key] = descriptor;
     }
   }
   return result;
 }
@@ -231,17 +229,17 @@ exports.override = override;
  * @param {Object} trait
  *    A trait object
  * @returns {Object}
  * @example
  *    var newTrait = rename(map, trait);
  */
 function rename(map, trait) {
   let result = {},
-      keys = getOwnPropertyNames(trait);
+      keys = getOwnPropertyIdentifiers(trait);
   for (let key of keys) {
     // must be renamed & it's not requirement
     if (hasOwn.call(map, key) && !trait[key].required) {
       let alias = map[key];
       if (hasOwn.call(result, alias) && !result[alias].required)
         result[alias] = Conflict(alias);
       else
         result[alias] = trait[key];
@@ -276,17 +274,17 @@ function rename(map, trait) {
 * @param {Object} trait
 *   A trait object
 * @returns {Object}
 *   Resolved trait with the same own properties as the original trait.
 */
 function resolve(resolutions, trait) {
   let renames = {},
       exclusions = [],
-      keys = getOwnPropertyNames(resolutions);
+      keys = getOwnPropertyIdentifiers(resolutions);
   for (let key of keys) {  // pre-process renamed and excluded properties
     if (resolutions[key])       // old name -> new name
       renames[key] = resolutions[key];
     else                        // name -> undefined
       exclusions.push(key);
   }
   return rename(renames, exclude(exclusions, trait));
 }
@@ -301,22 +299,21 @@ exports.resolve = resolve;
  *    prototype of the completed object
  * @param {Object} trait
  *    trait object to be turned into a complete object
  * @returns {Object}
  *    An object with all of the properties described by the trait.
  */
 function create(proto, trait) {
   let properties = {},
-      keys = getOwnPropertyNames(trait);
+      keys = getOwnPropertyIdentifiers(trait);
   for (let key of keys) {
     let descriptor = trait[key];
     if (descriptor.required && !hasOwn.call(proto, key))
       throw new Error(ERR_REQUIRED + key);
     else if (descriptor.conflict)
       throw new Error(ERR_CONFLICT + key);
     else
       properties[key] = descriptor;
   }
   return _create(proto, properties);
 }
 exports.create = create;
-
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
@@ -21,17 +21,18 @@ const { id } = require("sdk/self");
 const { newURI } = require('sdk/url/utils');
 const { getZipReader } = require("../zip/utils");
 
 const { Cc, Ci, Cu } = require("chrome");
 const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 var ios = Cc['@mozilla.org/network/io-service;1']
           .getService(Ci.nsIIOService);
 
-const TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)?(tests?\/test-[^\.\/]+)\.js$/;
+const CFX_TEST_REGEX = /(([^\/]+\/)(?:lib\/)?)?(tests?\/test-[^\.\/]+)\.js$/;
+const JPM_TEST_REGEX = /^()(tests?\/test-[^\.\/]+)\.js$/;
 
 const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence");
 
 const toFile = x => x.QueryInterface(Ci.nsIFile);
 const isTestFile = ({leafName}) => leafName.substr(0, 5) == "test-" && leafName.substr(-3, 3) == ".js";
 const getFileURI = x => ios.newFileURI(x).spec;
 
 const getDirectoryEntries = file => map(toFile, fromEnumerator(_ => file.directoryEntries));
@@ -46,16 +47,18 @@ const getTestEntries = directory => mapc
 const removeDups = (array) => array.reduce((result, value) => {
   if (value != result[result.length - 1]) {
     result.push(value);
   }
   return result;
 }, []);
 
 const getSuites = function getSuites({ id, filter }) {
+  const TEST_REGEX = isNative ? JPM_TEST_REGEX : CFX_TEST_REGEX;
+
   return getAddon(id).then(addon => {
     let fileURI = addon.getResourceURI("tests/");
     let isPacked = fileURI.scheme == "jar";
     let xpiURI = addon.getResourceURI();
     let file = xpiURI.QueryInterface(Ci.nsIFileURL).file;
     let suites = [];
     let addEntry = (entry) => {
       if (filter(entry) && TEST_REGEX.test(entry)) {
@@ -72,19 +75,23 @@ const getSuites = function getSuites({ i
           addEntry(entry);
         }
         zip.close();
 
         // sort and remove dups
         suites = removeDups(suites.sort());
         return suites;
       })
-    } else {
-      let tests = getTestEntries(file);
-      [...tests].forEach(addEntry);
+    }
+    else {
+      let tests = [...getTestEntries(file)];
+      let rootURI = addon.getResourceURI("/");
+      tests.forEach((entry) => {
+        addEntry(entry.replace(rootURI.spec, ""));
+      });
     }
 
     // sort and remove dups
     suites = removeDups(suites.sort());
     return suites;
   });
 }
 exports.getSuites = getSuites;
@@ -97,17 +104,18 @@ const makeFilters = function makeFilters
   // testName.
   if (options.filter) {
     let colonPos = options.filter.indexOf(':');
     let filterFileRegex, filterNameRegex;
 
     if (colonPos === -1) {
       filterFileRegex = new RegExp(options.filter);
       filterNameRegex = { test: () => true }
-    } else {
+    }
+    else {
       filterFileRegex = new RegExp(options.filter.substr(0, colonPos));
       filterNameRegex = new RegExp(options.filter.substr(colonPos + 1));
     }
 
     return {
       fileFilter: (name) => filterFileRegex.test(name),
       testFilter: (name) => filterNameRegex.test(name)
     }
--- a/addon-sdk/source/lib/sdk/event/core.js
+++ b/addon-sdk/source/lib/sdk/event/core.js
@@ -1,12 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
 const UNCAUGHT_ERROR = 'An error event was emitted for which there was no listener.';
 const BAD_LISTENER = 'The event listener must be a function.';
@@ -75,24 +74,26 @@ exports.once = once;
  * @param {Object} target
  *    Event target object.
  * @param {String} type
  *    The type of event.
  * @params {Object|Number|String|Boolean} args
  *    Arguments that will be passed to listeners.
  */
 function emit (target, type, ...args) {
+  let all = observers(target, '*').length;
   let state = observers(target, type);
   let listeners = state.slice();
   let count = listeners.length;
   let index = 0;
 
-  // If error event and there are no handlers then print error message
-  // into a console.
-  if (count === 0 && type === 'error') console.exception(args[0]);
+  // If error event and there are no handlers (explicit or catch-all)
+  // then print error message to the console.
+  if (count === 0 && type === 'error' && all === 0)
+    console.exception(args[0]);
   while (index < count) {
     try {
       let listener = listeners[index];
       // Dispatch only if listener is still registered.
       if (~state.indexOf(listener))
         listener.apply(target, args);
     }
     catch (error) {
--- a/addon-sdk/source/lib/sdk/event/target.js
+++ b/addon-sdk/source/lib/sdk/event/target.js
@@ -1,12 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 'use strict';
 
 module.metadata = {
   "stability": "stable"
 };
 
 const { on, once, off, setListeners } = require('./core');
 const { method, chainable } = require('../lang/functional/core');
@@ -63,14 +62,13 @@ const EventTarget = Class({
   removeListener: function removeListener(type, listener) {
     // Note: We can't just wrap `off` in `method` as we do it for other methods
     // cause skipping a second or third argument will behave very differently
     // than intended. This way we make sure all arguments are passed and only
     // one listener is removed at most.
     off(this, type, listener);
     return this;
   },
-  off: function(type, listener) {
-    off(this, type, listener);
-    return this;
-  }
+  // but we can wrap `off` here, as the semantics are the same
+  off: chainable(method(off))
+
 });
 exports.EventTarget = EventTarget;
--- a/addon-sdk/source/lib/sdk/l10n/html.js
+++ b/addon-sdk/source/lib/sdk/l10n/html.js
@@ -2,25 +2,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
-const { Ci, Cu } = require("chrome");
+const { Ci } = require("chrome");
 const events = require("../system/events");
 const core = require("./core");
+const { loadSheet, removeSheet } = require("../stylesheet/utils");
 
 const assetsURI = require('../self').data.url();
-const { Services } = Cu.import("resource://gre/modules/Services.jsm");
 
-const hideContentStyle = "data:text/css,:root {visibility: hidden !important;}";
-const hideSheetUri = Services.io.newURI(hideContentStyle, null, null);
+const hideSheetUri = "data:text/css,:root {visibility: hidden !important;}";
 
 // Taken from Gaia:
 // https://github.com/andreasgal/gaia/blob/04fde2640a7f40314643016a5a6c98bf3755f5fd/webapi.js#L1470
 function translateElement(element) {
   element = element || document;
 
   // check all translatable children (= w/ a `data-l10n-id' attribute)
   var children = element.querySelectorAll('*[data-l10n-id]');
@@ -41,21 +40,18 @@ function onDocumentReady2Translate(event
   let document = event.target;
   document.removeEventListener("DOMContentLoaded", onDocumentReady2Translate,
                                false);
 
   translateElement(document);
 
   try {
     // Finally display document when we finished replacing all text content
-    if (document.defaultView) {
-      let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
-                                         .getInterface(Ci.nsIDOMWindowUtils);
-      winUtils.removeSheet(hideSheetUri, winUtils.USER_SHEET);
-    }
+    if (document.defaultView)
+      removeSheet(document.defaultView, hideSheetUri, 'user');
   }
   catch(e) {
     console.exception(e);
   }
 }
 
 function onContentWindow(event) {
   let document = event.subject;
@@ -71,19 +67,17 @@ function onContentWindow(event) {
 
   // Accept only document from this addon
   if (document.location.href.indexOf(assetsURI) !== 0)
     return;
 
   try {
     // First hide content of the document in order to have content blinking
     // between untranslated and translated states
-    let winUtils = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
-                                       .getInterface(Ci.nsIDOMWindowUtils);
-    winUtils.loadSheet(hideSheetUri, winUtils.USER_SHEET);
+    loadSheet(document.defaultView, hideSheetUri, 'user');
   }
   catch(e) {
     console.exception(e);
   }
   // Wait for DOM tree to be built before applying localization
   document.addEventListener("DOMContentLoaded", onDocumentReady2Translate,
                             false);
 }
--- a/addon-sdk/source/lib/sdk/page-mod.js
+++ b/addon-sdk/source/lib/sdk/page-mod.js
@@ -9,21 +9,20 @@ module.metadata = {
 
 const observers = require('./system/events');
 const { contract: loaderContract } = require('./content/loader');
 const { contract } = require('./util/contract');
 const { getAttachEventType, WorkerHost } = require('./content/utils');
 const { Class } = require('./core/heritage');
 const { Disposable } = require('./core/disposable');
 const { WeakReference } = require('./core/reference');
-const { Worker } = require('./content/worker');
+const { Worker } = require('./content/worker-parent');
 const { EventTarget } = require('./event/target');
 const { on, emit, once, setListeners } = require('./event/core');
 const { on: domOn, removeListener: domOff } = require('./dom/events');
-const { pipe } = require('./event/utils');
 const { isRegExp, isUndefined } = require('./lang/type');
 const { merge } = require('./util/object');
 const { windowIterator } = require('./deprecated/window-utils');
 const { isBrowser, getFrames } = require('./window/utils');
 const { getTabs, getTabContentWindow, getTabForContentWindow,
         getURI: getTabURI } = require('./tabs/utils');
 const { ignoreWindow } = require('./private-browsing/utils');
 const { Style } = require("./stylesheet/style");
@@ -109,17 +108,16 @@ const modContract = contract(merge({}, l
  * PageMod constructor (exported below).
  * @constructor
  */
 const PageMod = Class({
   implements: [
     modContract.properties(modelFor),
     EventTarget,
     Disposable,
-    WeakReference
   ],
   extends: WorkerHost(workerFor),
   setup: function PageMod(options) {
     let mod = this;
     let model = modContract(options);
     models.set(this, model);
 
     // Set listeners on {PageMod} itself, not the underlying worker,
@@ -208,21 +206,25 @@ function createWorker (mod, window) {
     contentScriptFile: mod.contentScriptFile,
     contentScriptOptions: mod.contentScriptOptions,
     // Bug 980468: Syntax errors from scripts can happen before the worker
     // can set up an error handler. They are per-mod rather than per-worker
     // so are best handled at the mod level.
     onError: (e) => emit(mod, 'error', e)
   });
   workers.set(mod, worker);
-  pipe(worker, mod);
-  emit(mod, 'attach', worker);
-  once(worker, 'detach', function detach() {
-    worker.destroy();
-  });
+  worker.on('*', (event, ...args) => {
+    // worker's "attach" event passes a window as the argument
+    // page-mod's "attach" event needs a worker
+    if (event === 'attach')
+      emit(mod, event, worker)
+    else 
+      emit(mod, event, ...args);
+  })
+  once(worker, 'detach', () => worker.destroy());
 }
 
 function onContent (mod, window) {
   // not registered yet
   if (!pagemods.has(mod))
     return;
 
   let isTopDocument = window.top === window;
--- a/addon-sdk/source/lib/sdk/panel.js
+++ b/addon-sdk/source/lib/sdk/panel.js
@@ -1,19 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-// The panel module currently supports only Firefox.
+// The panel module currently supports only Firefox and SeaMonkey.
 // See: https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps
 module.metadata = {
   "stability": "stable",
   "engines": {
-    "Firefox": "*"
+    "Firefox": "*",
+    "SeaMonkey": "*"
   }
 };
 
 const { Ci } = require("chrome");
 const { setTimeout } = require('./timers');
 const { isPrivateBrowsingSupported } = require('./self');
 const { isWindowPBSupported } = require('./private-browsing/utils');
 const { Class } = require("./core/heritage");
--- a/addon-sdk/source/lib/sdk/selection.js
+++ b/addon-sdk/source/lib/sdk/selection.js
@@ -2,33 +2,33 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "stable",
   "engines": {
-    "Firefox": "*"
+    "Firefox": "*",
+    "SeaMonkey": "*"
   }
 };
 
 const { Ci, Cc } = require("chrome"),
     { setTimeout } = require("./timers"),
     { emit, off } = require("./event/core"),
     { Class, obscure } = require("./core/heritage"),
     { EventTarget } = require("./event/target"),
     { ns } = require("./core/namespace"),
     { when: unload } = require("./system/unload"),
     { ignoreWindow } = require('./private-browsing/utils'),
     { getTabs, getTabContentWindow, getTabForContentWindow,
       getAllTabContentWindows } = require('./tabs/utils'),
     winUtils = require("./window/utils"),
-    events = require("./system/events"),
-    { iteratorSymbol, forInIterator } = require("./util/iteration");
+    events = require("./system/events");
 
 // The selection types
 const HTML = 0x01,
       TEXT = 0x02,
       DOM  = 0x03; // internal use only
 
 // A more developer-friendly message than the caught exception when is not
 // possible change a selection.
@@ -111,19 +111,22 @@ function* forOfIterator() {
     let sel = Selection(i);
 
     if (sel.text)
       yield Selection(i);
   }
 }
 
 const selectionIteratorOptions = {
-  __iterator__: forInIterator
+  __iterator__: function() {
+      for (let item of this)
+          yield item;
+  }
 }
-selectionIteratorOptions[iteratorSymbol] = forOfIterator;
+selectionIteratorOptions[Symbol.iterator] = forOfIterator;
 const selectionIterator = obscure(selectionIteratorOptions);
 
 /**
  * Returns the most recent focused window.
  * if private browsing window is most recent and not supported,
  * then ignore it and return `null`, because the focused window
  * can't be targeted.
  */
--- a/addon-sdk/source/lib/sdk/self.js
+++ b/addon-sdk/source/lib/sdk/self.js
@@ -25,23 +25,28 @@ const baseURI = readPref("baseURI") || o
 const addonDataURI = baseURI + "data/";
 const metadata = options.metadata || {};
 const permissions = metadata.permissions || {};
 const isPacked = rootURI && rootURI.indexOf("jar:") === 0;
 
 const uri = (path="") =>
   path.contains(":") ? path : addonDataURI + path.replace(/^\.\//, "");
 
+let { preferencesBranch } = options;
+if (/[^\w{@}.-]/.test(preferencesBranch)) {
+  preferencesBranch = id;
+  console.warn("Ignoring preferences-branch (not a valid branch name)");
+}
 
 // Some XPCOM APIs require valid URIs as an argument for certain operations
 // (see `nsILoginManager` for example). This property represents add-on
 // associated unique URI string that can be used for that.
 exports.uri = 'addon:' + id;
 exports.id = id;
-exports.preferencesBranch = options.preferencesBranch || id;
+exports.preferencesBranch = preferencesBranch || id;
 exports.name = name;
 exports.loadReason = loadReason;
 exports.version = version;
 exports.packed = isPacked;
 exports.data = Object.freeze({
   url: uri,
   load: function read(path) {
     return readURISync(uri(path));
--- a/addon-sdk/source/lib/sdk/stylesheet/utils.js
+++ b/addon-sdk/source/lib/sdk/stylesheet/utils.js
@@ -1,22 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 module.metadata =  {
   "stability": "experimental"
 };
 
-const { Cc, Ci } = require("chrome");
-
-const io = Cc['@mozilla.org/network/io-service;1'].
-            getService(Ci.nsIIOService);
+const { Ci } = require("chrome");
 
 const SHEET_TYPE = {
   "agent": "AGENT_SHEET",
   "user": "USER_SHEET",
   "author": "AUTHOR_SHEET"
 };
 
 function getDOMWindowUtils(window) {
@@ -31,44 +27,44 @@ function getDOMWindowUtils(window) {
  * `window` given.
  */
 function loadSheet(window, url, type) {
   if (!(type && type in SHEET_TYPE))
     type = "author";
 
   type = SHEET_TYPE[type];
 
-  if (!(url instanceof Ci.nsIURI))
-    url = io.newURI(url, null, null);
+  if (url instanceof Ci.nsIURI)
+    url = url.spec;
 
   let winUtils = getDOMWindowUtils(window);
   try {
-    winUtils.loadSheet(url, winUtils[type]);
+    winUtils.loadSheetUsingURIString(url, winUtils[type]);
   }
   catch (e) {};
 };
 exports.loadSheet = loadSheet;
 
 /**
  * Remove the document style sheet at `sheetURI` from the list of additional
  * style sheets of the document.  The removal takes effect immediately.
  */
 function removeSheet(window, url, type) {
   if (!(type && type in SHEET_TYPE))
     type = "author";
 
   type = SHEET_TYPE[type];
 
-  if (!(url instanceof Ci.nsIURI))
-    url = io.newURI(url, null, null);
+  if (url instanceof Ci.nsIURI)
+    url = url.spec;
 
   let winUtils = getDOMWindowUtils(window);
 
   try {
-    winUtils.removeSheet(url, winUtils[type]);
+    winUtils.removeSheetUsingURIString(url, winUtils[type]);
   }
   catch (e) {};
 };
 exports.removeSheet = removeSheet;
 
 /**
  * Returns `true` if the `type` given is valid, otherwise `false`.
  * The values currently accepted are: "agent", "user" and "author".
--- a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
@@ -9,16 +9,17 @@ const { tabNS, rawTabNS } = require('./n
 const { EventTarget } = require('../event/target');
 const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL,
         getTabContentWindow, getTabForBrowser, setTabURL, getOwnerWindow,
         getTabContentDocument, getTabContentType, getTabId } = require('./utils');
 const { emit } = require('../event/core');
 const { isPrivate } = require('../private-browsing/utils');
 const { isWindowPrivate } = require('../window/utils');
 const { when: unload } = require('../system/unload');
+const { BLANK } = require('../content/thumbnail');
 const { viewFor } = require('../view/core');
 const { EVENTS } = require('./events');
 
 const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
 
 const Tab = Class({
   extends: EventTarget,
   initialize: function initialize(options) {
@@ -89,17 +90,17 @@ const Tab = Class({
     return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAEklEQVQ4jWNgGAWjYBSMAggAAAQQAAF/TXiOAAAAAElFTkSuQmCC';
   },
 
   getThumbnail: function() {
     // TODO: implement!
     console.error(ERR_FENNEC_MSG);
 
     // return 80x45 blank default
-    return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC';
+    return BLANK;
   },
 
   /**
    * tab's document readyState, or 'uninitialized' if it doesn't even exist yet.
    */
   get readyState() {
     let doc = getTabContentDocument(tabNS(this).tab);
     return doc && doc.readyState || 'uninitialized';
--- a/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-firefox.js
@@ -4,17 +4,17 @@
 'use strict';
 
 const { Trait } = require("../deprecated/traits");
 const { EventEmitter } = require("../deprecated/events");
 const { defer } = require("../lang/functional");
 const { has } = require("../util/array");
 const { each } = require("../util/object");
 const { EVENTS } = require("./events");
-const { getThumbnailURIForWindow } = require("../content/thumbnail");
+const { getThumbnailURIForWindow, BLANK } = require("../content/thumbnail");
 const { getFaviconURIForLocation } = require("../io/data");
 const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle,
         setTabTitle, getTabContentDocument, getTabURL, setTabURL,
         getTabContentType, getTabId } = require('./utils');
 const { isPrivate } = require('../private-browsing/utils');
 const { isWindowPrivate } = require('../window/utils');
 const viewNS = require('../core/namespace').ns();
 const { deprecateUsage } = require('../util/deprecate');
@@ -194,18 +194,25 @@ const TabTrait = Trait.compose(EventEmit
     this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument) :
     undefined,
   set index(value)
     this._tab && this._window.gBrowser.moveTabTo(this._tab, value),
   /**
    * Thumbnail data URI of the page currently loaded in this tab.
    * @type {String}
    */
-  getThumbnail: function getThumbnail()
-    this._tab ? getThumbnailURIForWindow(this._contentWindow) : undefined,
+  getThumbnail() {
+    if (!this._tab)
+      return undefined;
+    if (this._tab.getAttribute('remote')) {
+      console.error('This method is not supported with E10S');
+      return BLANK;
+    }
+    return getThumbnailURIForWindow(this._contentWindow);
+  },
   /**
    * Whether or not tab is pinned (Is an app-tab).
    * @type {Boolean}
    */
   get isPinned() this._tab ? this._tab.pinned : undefined,
   pin: function pin() {
     if (!this._tab)
       return;
--- a/addon-sdk/source/lib/sdk/tabs/worker.js
+++ b/addon-sdk/source/lib/sdk/tabs/worker.js
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
-const ContentWorker = require('../content/worker').Worker;
+const ContentWorker = require('../content/worker-parent').Worker;
 
 function Worker(options, window) {
   options.window = window;
 
   let worker = ContentWorker(options);
   worker.once("detach", function detach() {
     worker.destroy();
   });
--- a/addon-sdk/source/lib/sdk/ui/button/action.js
+++ b/addon-sdk/source/lib/sdk/ui/button/action.js
@@ -103,9 +103,10 @@ on(updateEvents, 'data', ({target: id, w
   render(buttons.get(id), window);
 });
 
 on(actionButtonStateEvents, 'data', ({target, window, state}) => {
   let id = toWidgetId(target.id);
   view.setIcon(id, window, state.icon);
   view.setLabel(id, window, state.label);
   view.setDisabled(id, window, state.disabled);
+  view.setBadge(id, window, state.badge, state.badgeColor);
 });
--- a/addon-sdk/source/lib/sdk/ui/button/contract.js
+++ b/addon-sdk/source/lib/sdk/ui/button/contract.js
@@ -1,24 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 const { contract } = require('../../util/contract');
 const { isLocalURL } = require('../../url');
 const { isNil, isObject, isString } = require('../../lang/type');
-const { required, either, string, boolean, object } = require('../../deprecated/api-utils');
+const { required, either, string, boolean, object, number } = require('../../deprecated/api-utils');
 const { merge } = require('../../util/object');
 const { freeze } = Object;
 
-function isIconSet(icons) {
-  return Object.keys(icons).
-    every(size => String(size >>> 0) === size && isLocalURL(icons[size]))
-}
+const isIconSet = (icons) =>
+  Object.keys(icons).
+    every(size => String(size >>> 0) === size && isLocalURL(icons[size]));
 
 let iconSet = {
   is: either(object, string),
   map: v => isObject(v) ? freeze(merge({}, v)) : v,
   ok: v => (isString(v) && isLocalURL(v)) || (isObject(v) && isIconSet(v)),
   msg: 'The option "icon" must be a local URL or an object with ' +
     'numeric keys / local URL values pair.'
 }
@@ -31,20 +30,32 @@ let id = {
 };
 
 let label = {
   is: string,
   ok: v => isNil(v) || v.trim().length > 0,
   msg: 'The option "label" must be a non empty string'
 }
 
+let badge = {
+  is: either(string, number),
+  msg: 'The option "badge" must be a string or a number'
+}
+
+let badgeColor = {
+  is: string,
+  msg: 'The option "badgeColor" must be a string'
+}
+
 let stateContract = contract({
   label: label,
   icon: iconSet,
-  disabled: boolean
+  disabled: boolean,
+  badge: badge,
+  badgeColor: badgeColor
 });
 
 exports.stateContract = stateContract;
 
 let buttonContract = contract(merge({}, stateContract.rules, {
   id: required(id),
   label: required(label),
   icon: required(iconSet)
--- a/addon-sdk/source/lib/sdk/ui/button/toggle.js
+++ b/addon-sdk/source/lib/sdk/ui/button/toggle.js
@@ -95,16 +95,17 @@ let updateEvents = events.filter(toggleB
 
 on(toggleButtonStateEvents, 'data', ({target, window, state}) => {
   let id = toWidgetId(target.id);
 
   view.setIcon(id, window, state.icon);
   view.setLabel(id, window, state.label);
   view.setDisabled(id, window, state.disabled);
   view.setChecked(id, window, state.checked);
+  view.setBadge(id, window, state.badge, state.badgeColor);
 });
 
 on(clickEvents, 'data', ({target: id, window, checked }) => {
   let button = buttons.get(id);
   let windowState = getStateFor(button, window);
 
   let newWindowState = merge({}, windowState, { checked: checked });
 
--- a/addon-sdk/source/lib/sdk/ui/button/view.js
+++ b/addon-sdk/source/lib/sdk/ui/button/view.js
@@ -10,17 +10,17 @@ module.metadata = {
   }
 };
 
 const { Cu } = require('chrome');
 const { on, off, emit } = require('../../event/core');
 
 const { data } = require('sdk/self');
 
-const { isObject } = require('../../lang/type');
+const { isObject, isNil } = require('../../lang/type');
 
 const { getMostRecentBrowserWindow } = require('../../window/utils');
 const { ignoreWindow } = require('../../private-browsing/utils');
 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
 const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
 
 const { events: viewEvents } = require('./view/events');
 
@@ -109,17 +109,17 @@ function getImage(icon, isInToolbar, pix
 }
 
 function nodeFor(id, window=getMostRecentBrowserWindow()) {
   return customizedWindows.has(window) ? null : getNode(id, window);
 };
 exports.nodeFor = nodeFor;
 
 function create(options) {
-  let { id, label, icon, type } = options;
+  let { id, label, icon, type, badge } = options;
 
   if (views.has(id))
     throw new Error('The ID "' + id + '" seems already used.');
 
   CustomizableUI.createWidget({
     id: id,
     type: 'custom',
     removable: true,
@@ -132,17 +132,17 @@ function create(options) {
       let node = document.createElementNS(XUL_NS, 'toolbarbutton');
 
       let image = getImage(icon, true, window.devicePixelRatio);
 
       if (ignoreWindow(window))
         node.style.display = 'none';
 
       node.setAttribute('id', this.id);
-      node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional');
+      node.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional badged-button');
       node.setAttribute('type', type);
       node.setAttribute('label', label);
       node.setAttribute('tooltiptext', label);
       node.setAttribute('image', image);
       node.setAttribute('sdk-button', 'true');
 
       views.set(id, {
         area: this.currentArea,
@@ -208,15 +208,36 @@ exports.setDisabled = setDisabled;
 function setChecked(id, window, checked) {
   let node = nodeFor(id, window);
 
   if (node)
     node.checked = checked;
 }
 exports.setChecked = setChecked;
 
+function setBadge(id, window, badge, color) {
+  let node = nodeFor(id, window);
+
+  if (node) {
+    // `Array.from` is needed to handle unicode symbol properly:
+    // '𝐀𝐁'.length is 4 where Array.from('𝐀𝐁').length is 2
+    let text = isNil(badge)
+                  ? ''
+                  : Array.from(String(badge)).slice(0, 4).join('');
+
+    node.setAttribute('badge', text);
+
+    let badgeNode = node.ownerDocument.getAnonymousElementByAttribute(node,
+                                        'class', 'toolbarbutton-badge');
+
+    if (badgeNode)
+      badgeNode.style.backgroundColor = isNil(color) ? '' : color;
+  }
+}
+exports.setBadge = setBadge;
+
 function click(id) {
   let node = nodeFor(id);
 
   if (node)
     node.click();
 }
 exports.click = click;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/util/iteration.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-'use strict';
-
-module.metadata = {
-  "stability": "experimental"
-};
-
-// This is known as @@iterator in the ES6 spec. In builds that have ES6
-// Symbols, use Symbol.iterator; otherwise use the legacy method name,
-// "@@iterator".
-const JS_HAS_SYMBOLS = typeof Symbol === "function";
-exports.iteratorSymbol = JS_HAS_SYMBOLS ? Symbol.iterator : "@@iterator";
-
-// An adaptor that, given an object that is iterable with for-of, is
-// suitable for being bound to __iterator__ in order to make the object
-// iterable in the same way via for-in.
-function forInIterator() {
-    for (let item of this)
-        yield item;
-}
-
-exports.forInIterator = forInIterator;
--- a/addon-sdk/source/lib/sdk/util/list.js
+++ b/addon-sdk/source/lib/sdk/util/list.js
@@ -4,17 +4,16 @@
 'use strict';
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Class } = require('../core/heritage');
 const listNS = require('../core/namespace').ns();
-const { iteratorSymbol } = require('../util/iteration');
 
 const listOptions = {
   /**
    * List constructor can take any number of element to populate itself.
    * @params {Object|String|Number} element
    * @example
    *    List(1,2,3).length == 3 // true
    */
@@ -43,18 +42,18 @@ const listOptions = {
    */
   __iterator__: function __iterator__(onKeys, onKeyValue) {
     let array = listNS(this).keyValueMap.slice(0),
                 i = -1;
     for (let element of array)
       yield onKeyValue ? [++i, element] : onKeys ? ++i : element;
   },
 };
-listOptions[iteratorSymbol] = function iterator() {
-    return listNS(this).keyValueMap.slice(0)[iteratorSymbol]();
+listOptions[Symbol.iterator] = function iterator() {
+    return listNS(this).keyValueMap.slice(0)[Symbol.iterator]();
 };
 const List = Class(listOptions);
 exports.List = List;
 
 function addListItem(that, value) {
   let list = listNS(that).keyValueMap,
       index = list.indexOf(value);
 
--- a/addon-sdk/source/lib/sdk/util/object.js
+++ b/addon-sdk/source/lib/sdk/util/object.js
@@ -1,12 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
 
 const { flatten } = require('./array');
 
@@ -31,17 +30,17 @@ const { flatten } = require('./array');
  */
 function merge(source) {
   let descriptor = {};
 
   // `Boolean` converts the first parameter to a boolean value. Any object is
   // converted to `true` where `null` and `undefined` becames `false`. Therefore
   // the `filter` method will keep only objects that are defined and not null.
   Array.slice(arguments, 1).filter(Boolean).forEach(function onEach(properties) {
-    Object.getOwnPropertyNames(properties).forEach(function(name) {
+    getOwnPropertyIdentifiers(properties).forEach(function(name) {
       descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
     });
   });
   return Object.defineProperties(source, descriptor);
 }
 exports.merge = merge;
 
 /**
@@ -80,13 +79,24 @@ exports.safeMerge = safeMerge;
 
 /*
  * Returns a copy of the object without blacklisted properties
  */
 function omit(source, ...values) {
   let copy = {};
   let keys = flatten(values);
   for (let prop in source)
-    if (!~keys.indexOf(prop)) 
+    if (!~keys.indexOf(prop))
       copy[prop] = source[prop];
   return copy;
 }
 exports.omit = omit;
+
+// get object's own property Symbols and/or Names, including nonEnumerables by default
+function getOwnPropertyIdentifiers(object, options = { names: true, symbols: true, nonEnumerables: true }) {
+  const symbols = !options.symbols ? [] :
+                  Object.getOwnPropertySymbols(object);
+  const names = !options.names ? [] :
+                options.nonEnumerables ? Object.getOwnPropertyNames(object) :
+                Object.keys(object);
+  return [...names, ...symbols];
+}
+exports.getOwnPropertyIdentifiers = getOwnPropertyIdentifiers;
--- a/addon-sdk/source/lib/sdk/util/sequence.js
+++ b/addon-sdk/source/lib/sdk/util/sequence.js
@@ -17,23 +17,22 @@ module.metadata = {
 // - `p` stands for "predicate" that is function which returns logical
 //   true or false and is intended to be side effect free.
 // - `x` / `y` single item of the sequence.
 // - `xs` / `ys` sequence of `x` / `y` items where `x` / `y` signifies
 //    type of the items in sequence, so sequence is not of the same item.
 // - `_` used for argument(s) or variable(s) who's values are ignored.
 
 const { complement, flip, identity } = require("../lang/functional");
-const { iteratorSymbol } = require("../util/iteration");
 const { isArray, isArguments, isMap, isSet,
         isString, isBoolean, isNumber } = require("../lang/type");
 
 const Sequence = function Sequence(iterator) {
   if (iterator.isGenerator && iterator.isGenerator())
-    this[iteratorSymbol] = iterator;
+    this[Symbol.iterator] = iterator;
   else
     throw TypeError("Expected generator argument");
 };
 exports.Sequence = Sequence;
 
 const polymorphic = dispatch => x =>
   x === null ? dispatch.null(null) :
   x === void(0) ? dispatch.void(void(0)) :
@@ -211,17 +210,17 @@ const map = (f, ...sequences) => seq(fun
     // define args array that will be recycled on each
     // step to aggregate arguments to be passed to `f`.
     let args = [];
     // define inputs to contain started generators.
     let inputs = [];
 
     let index = 0;
     while (index < count) {
-      inputs[index] = sequences[index][iteratorSymbol]();
+      inputs[index] = sequences[index][Symbol.iterator]();
       index = index + 1;
     }
 
     // Run loop yielding of applying `f` to the set of
     // items at each step until one of the `inputs` is
     // exhausted.
     let done = false;
     while (!done) {
--- a/addon-sdk/source/lib/sdk/windows/loader.js
+++ b/addon-sdk/source/lib/sdk/windows/loader.js
@@ -54,18 +54,21 @@ const WindowLoader = Trait.compose({
    */
   get _window() this.__window,
   set _window(window) {
     let _window = this.__window;
     if (!window) window = null;
 
     if (window !== _window) {
       if (_window) {
-        _window.removeEventListener(ON_UNLOAD, this.__unloadListener, false);
-        _window.removeEventListener(ON_LOAD, this.__loadListener, false);
+        if (this.__unloadListener)
+          _window.removeEventListener(ON_UNLOAD, this.__unloadListener, false);
+
+        if (this.__loadListener)
+          _window.removeEventListener(ON_LOAD, this.__loadListener, false);
       }
 
       if (window) {
         window.addEventListener(
           ON_UNLOAD,
           this.__unloadListener ||
             (this.__unloadListener = this._unloadListener.bind(this))
           ,
@@ -118,9 +121,8 @@ const WindowLoader = Trait.compose({
       || STATE_LOADED != window.document.readyState
     ) return;
     window.removeEventListener(ON_UNLOAD, this.__unloadListener, false);
     this._onUnload(window);
   },
   __unloadListener: null
 });
 exports.WindowLoader = WindowLoader;
-
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -40,22 +40,23 @@ const { notifyObservers } = Cc['@mozilla
                         getService(Ci.nsIObserverService);
 const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const { Reflect } = Cu.import("resource://gre/modules/reflect.jsm", {});
 const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
 const { join: pathJoin, normalize, dirname } = Cu.import("resource://gre/modules/osfile/ospath_unix.jsm");
 
 // Define some shortcuts.
 const bind = Function.call.bind(Function.bind);
-const getOwnPropertyNames = Object.getOwnPropertyNames;
 const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
 const define = Object.defineProperties;
 const prototypeOf = Object.getPrototypeOf;
 const create = Object.create;
 const keys = Object.keys;
+const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
+                                ...Object.getOwnPropertySymbols(x)];
 
 const NODE_MODULES = ["assert", "buffer_ieee754", "buffer", "child_process", "cluster", "console", "constants", "crypto", "_debugger", "dgram", "dns", "domain", "events", "freelist", "fs", "http", "https", "_linklist", "module", "net", "os", "path", "punycode", "querystring", "readline", "repl", "stream", "string_decoder", "sys", "timers", "tls", "tty", "url", "util", "vm", "zlib"];
 
 const COMPONENT_ERROR = '`Components` is not available in this context.\n' +
   'Functionality provided by Components may be available in an SDK\n' +
   'module: https://developer.mozilla.org/en-US/Add-ons/SDK \n\n' +
   'However, if you still need to import Components, you may use the\n' +
   '`chrome` module\'s properties for shortcuts to Component properties:\n\n' +
@@ -79,17 +80,17 @@ function freeze(object) {
       freeze(object);
   }
   return object;
 }
 
 // Returns map of given `object`-s own property descriptors.
 const descriptor = iced(function descriptor(object) {
   let value = {};
-  getOwnPropertyNames(object).forEach(function(name) {
+  getOwnIdentifiers(object).forEach(function(name) {
     value[name] = getOwnPropertyDescriptor(object, name)
   });
   return value;
 });
 exports.descriptor = descriptor;
 
 // Freeze important built-ins so they can't be used by untrusted code as a
 // message passing channel.
@@ -116,17 +117,17 @@ function iced(f) {
 // Defines own properties of given `properties` object on the given
 // target object overriding any existing property with a conflicting name.
 // Returns `target` object. Note we only export this function because it's
 // useful during loader bootstrap when other util modules can't be used &
 // thats only case where this export should be used.
 const override = iced(function override(target, source) {
   let properties = descriptor(target)
   let extension = descriptor(source || {})
-  getOwnPropertyNames(extension).forEach(function(name) {
+  getOwnIdentifiers(extension).forEach(function(name) {
     properties[name] = extension[name];
   });
   return define({}, properties);
 });
 exports.override = override;
 
 function sourceURI(uri) { return String(uri).split(" -> ").pop(); }
 exports.sourceURI = iced(sourceURI);
@@ -289,17 +290,17 @@ const load = iced(function load(loader, 
 
   let sandbox;
   if (loader.sharedGlobalSandbox &&
       loader.sharedGlobalBlacklist.indexOf(module.id) == -1) {
     // Create a new object in this sandbox, that will be used as
     // the scope object for this particular module
     sandbox = new loader.sharedGlobalSandbox.Object();
     // Inject all expected globals in the scope object
-    getOwnPropertyNames(globals).forEach(function(name) {
+    getOwnIdentifiers(globals).forEach(function(name) {
       descriptors[name] = getOwnPropertyDescriptor(globals, name)
     });
     define(sandbox, descriptors);
   } else {
     sandbox = Sandbox({
       name: module.uri,
       prototype: create(globals, descriptors),
       wantXrays: false,
@@ -516,17 +517,17 @@ function sortPaths (paths) {
     sort(function(a, b) { return b.length - a.length }).
     map(function(path) { return [ path, paths[path] ] });
 }
 
 const resolveURI = iced(function resolveURI(id, mapping) {
   let count = mapping.length, index = 0;
 
   // Do not resolve if already a resource URI
-  if (isResourceURI(id)) return normalizeExt(id);
+  if (isAbsoluteURI(id)) return normalizeExt(id);
 
   while (index < count) {
     let [ path, uri ] = mapping[index ++];
     if (id.indexOf(path) === 0)
       return normalizeExt(id.replace(path, uri));
   }
   return void 0; // otherwise we raise a warning, see bug 910304
 });
@@ -839,17 +840,19 @@ const Loader = iced(function Loader(opti
 
   return freeze(create(null, returnObj));
 });
 exports.Loader = Loader;
 
 let isJSONURI = uri => uri.substr(-5) === '.json';
 let isJSMURI = uri => uri.substr(-4) === '.jsm';
 let isJSURI = uri => uri.substr(-3) === '.js';
-let isResourceURI = uri => uri.substr(0, 11) === 'resource://';
+let isAbsoluteURI = uri => uri.indexOf("resource://") >= 0 ||
+                           uri.indexOf("chrome://") >= 0 ||
+                           uri.indexOf("file://") >= 0
 let isRelative = id => id[0] === '.'
 
 const generateMap = iced(function generateMap(options, callback) {
   let { rootURI, resolve, paths } = override({
     paths: {},
     resolve: exports.nodeResolve
   }, options);
 
@@ -923,17 +926,17 @@ function findAllModuleIncludes (uri, opt
 }
 
 // From Substack's detector
 // https://github.com/substack/node-detective
 //
 // Given a resource URI or source, return an array of strings passed into
 // the require statements from the source
 function findModuleIncludes (uri, callback) {
-  let src = isResourceURI(uri) ? readURI(uri) : uri;
+  let src = isAbsoluteURI(uri) ? readURI(uri) : uri;
   let modules = [];
 
   walk(src, function (node) {
     if (isRequire(node))
       modules.push(node.arguments[0].value);
   });
 
   callback(modules);
@@ -974,9 +977,8 @@ function isRequire (node) {
     && node.type === 'CallExpression'
     && c.type === 'Identifier'
     && c.name === 'require'
     && node.arguments.length
    && node.arguments[0].type === 'Literal';
 }
 
 });
-
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/toolkit/require.js
@@ -0,0 +1,54 @@
+const make = (exports, rootURI, components) => {
+  const { Loader: { Loader, Require, Module, main } } =
+        components.utils.import(rootURI + "toolkit/loader.js", {});
+
+  const loader = Loader({
+    id: "toolkit/require",
+    rootURI: rootURI,
+    isNative: true,
+    paths: {
+     "": rootURI,
+     "devtools/": "resource://gre/modules/devtools/"
+    }
+  });
+
+  // Below we define `require` & `require.resolve` that resolve passed
+  // module id relative to the caller URI. This is not perfect but good
+  // enough for common case & there is always an option to pass absolute
+  // id when that
+  // but presumably well enough to cover
+
+  const require = id => {
+    const requirerURI = components.stack.caller.filename;
+    const requirer = Module(requirerURI, requirerURI);
+    return Require(loader, requirer)(id);
+  };
+
+  require.resolve = id => {
+    const requirerURI = components.stack.caller.filename;
+    const requirer = Module(requirerURI, requirerURI);
+    return Require(loader, requirer).resolve(id);
+  };
+
+  exports.require = require;
+}
+
+// If loaded in the context of commonjs module, reload as JSM into an
+// exports object.
+if (typeof(require) === "function" && typeof(module) === "object") {
+  require("chrome").Cu.import(module.uri, module.exports);
+}
+// If loaded in the context of JSM make a loader & require and define
+// new symbols as exported ones.
+else if (typeof(__URI__) === "string" && this["Components"]) {
+  const builtin = Object.keys(this);
+  const uri = __URI__.replace("toolkit/require.js", "");
+  make(this, uri, this["Components"]);
+
+  this.EXPORTED_SYMBOLS = Object.
+                            keys(this).
+                            filter($ => builtin.indexOf($) < 0);
+}
+else {
+  throw Error("Loading require.js in this environment isn't supported")
+}
--- a/addon-sdk/source/python-lib/cuddlefish/packaging.py
+++ b/addon-sdk/source/python-lib/cuddlefish/packaging.py
@@ -396,22 +396,17 @@ def generate_build_for_target(pkg_cfg, t
     if 'id' in target_cfg:
         # NOTE: logic duplicated from buildJID()
         jid = target_cfg['id']
         if not ('@' in jid or jid.startswith('{')):
             jid += '@jetpack'
         build['preferencesBranch'] = jid
 
     if 'preferences-branch' in target_cfg:
-        # check it's a non-empty, valid branch name
-        preferencesBranch = target_cfg['preferences-branch']
-        if re.match('^[\w{@}-]+$', preferencesBranch):
-            build['preferencesBranch'] = preferencesBranch
-        elif not is_running_tests:
-            print >>sys.stderr, "IGNORING preferences-branch (not a valid branch name)"
+        build['preferencesBranch'] = target_cfg['preferences-branch']
 
     return build
 
 def _get_files_in_dir(path):
     data = {}
     files = os.listdir(path)
     for filename in files:
         fullpath = os.path.join(path, filename)
--- a/addon-sdk/source/python-lib/cuddlefish/prefs.py
+++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py
@@ -29,16 +29,19 @@ DEFAULT_COMMON_PREFS = {
     'extensions.enabledScopes' : 5,
     # Disable metadata caching for installed add-ons by default
     'extensions.getAddons.cache.enabled' : False,
     # Disable intalling any distribution add-ons
     'extensions.installDistroAddons' : False,
     # Allow installing extensions dropped into the profile folder
     'extensions.autoDisableScopes' : 10,
 
+    # shut up some warnings on `about:` page
+    'app.releaseNotesURL': 'http://localhost/app-dummy/',
+    'app.vendorURL': 'http://localhost/app-dummy/'
 }
 
 DEFAULT_NO_CONNECTIONS_PREFS = {
     'toolkit.telemetry.enabled': False,
     'app.update.auto' : False,
     'app.update.url': 'http://localhost/app-dummy/update',
     'media.gmp-gmpopenh264.autoupdate' : False,
     'media.gmp-manager.cert.checkAttributes' : False,
--- a/addon-sdk/source/test/addons/curly-id/lib/main.js
+++ b/addon-sdk/source/test/addons/curly-id/lib/main.js
@@ -12,21 +12,16 @@ exports.testCurlyID = function(assert) {
   assert.equal(id, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'curly ID is curly');
   assert.equal(simple.prefs.test13, 26, 'test13 is 26');
 
   simple.prefs.test14 = '15';
   assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), '15', 'test14 is 15');
   assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), simple.prefs.test14, 'simple test14 also 15');
 }
 
-exports.testInvalidPreferencesBranch = function(assert) {
-  assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
-  assert.equal(preferencesBranch, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'preferences-branch is {34a1eae1-c20a-464f-9b0e-000000000000}');
-}
-
 // from `/test/test-self.js`, adapted to `sdk/test/assert` API
 exports.testSelfID = function*(assert) {
   assert.equal(typeof(id), 'string', 'self.id is a string');
   assert.ok(id.length > 0, 'self.id not empty');
 
   let addon = yield getAddonByID(id);
   assert.ok(addon, 'found addon with self.id');
 }
--- a/addon-sdk/source/test/addons/curly-id/package.json
+++ b/addon-sdk/source/test/addons/curly-id/package.json
@@ -3,12 +3,10 @@
     "fullName": "curly ID test",
     "author": "Tomislav Jovanovic",
 
     "preferences": [{
         "name": "test13",
         "type": "integer",
         "title": "test13",
         "value": 26
-    }],
-
-    "preferences-branch": "invalid^branch*name"
+    }]
 }
--- a/addon-sdk/source/test/addons/standard-id/lib/main.js
+++ b/addon-sdk/source/test/addons/standard-id/lib/main.js
@@ -14,21 +14,16 @@ exports.testStandardID = function(assert
 
   assert.equal(simple.prefs.test13, 26, 'test13 is 26');
 
   simple.prefs.test14 = '15';
   assert.equal(service.get('extensions.standard-id@jetpack.test14'), '15', 'test14 is 15');
   assert.equal(service.get('extensions.standard-id@jetpack.test14'), simple.prefs.test14, 'simple test14 also 15');
 }
 
-exports.testInvalidPreferencesBranch = function(assert) {
-  assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
-  assert.equal(preferencesBranch, 'standard-id@jetpack', 'preferences-branch is standard-id@jetpack');
-}
-
 // from `/test/test-self.js`, adapted to `sdk/test/assert` API
 exports.testSelfID = function*(assert) {
   assert.equal(typeof(id), 'string', 'self.id is a string');
   assert.ok(id.length > 0, 'self.id not empty');
   let addon = yield getAddonByID(id);
   assert.ok(addon, 'found addon with self.id');
 }
 
--- a/addon-sdk/source/test/addons/standard-id/package.json
+++ b/addon-sdk/source/test/addons/standard-id/package.json
@@ -3,12 +3,10 @@
     "fullName": "standard ID test",
     "author": "Tomislav Jovanovic",
 
     "preferences": [{
         "name": "test13",
         "type": "integer",
         "title": "test13",
         "value": 26
-    }],
-
-    "preferences-branch": "invalid^branch*name"
+    }]
 }
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/addon-sdk/data/border-style.css
@@ -0,0 +1,1 @@
+div { border-style: dashed; }
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/addon-sdk/data/test-contentScriptFile.js
@@ -0,0 +1,5 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+self.postMessage("msg from contentScriptFile");
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/addon-sdk/data/test.html
@@ -0,0 +1,13 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>foo</title>
+  </head>
+  <body>
+    <p>bar</p>
+  </body>
+</html>
--- a/addon-sdk/source/test/jetpack-package.ini
+++ b/addon-sdk/source/test/jetpack-package.ini
@@ -32,16 +32,17 @@ support-files =
 [test-clipboard.js]
 [test-collection.js]
 [test-commonjs-test-adapter.js]
 [test-content-events.js]
 [test-content-loader.js]
 [test-content-script.js]
 [test-content-symbiont.js]
 [test-content-worker.js]
+[test-content-worker-parent.js]
 [test-context-menu.js]
 [test-cortex.js]
 [test-cuddlefish.js]
 # Cuddlefish loader is unsupported
 skip-if = true
 [test-deprecate.js]
 [test-deprecated-list.js]
 [test-dev-panel.js]
--- a/addon-sdk/source/test/pagemod-test-helpers.js
+++ b/addon-sdk/source/test/pagemod-test-helpers.js
@@ -1,66 +1,52 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 "use strict";
 
-const {Cc,Ci} = require("chrome");
-const timer = require("sdk/timers");
-const xulApp = require("sdk/system/xul-app");
+const { Cc, Ci } = require("chrome");
+const { setTimeout } = require("sdk/timers");
 const { Loader } = require("sdk/test/loader");
 const { openTab, getBrowserForTab, closeTab } = require("sdk/tabs/utils");
-const self = require("sdk/self");
 const { merge } = require("sdk/util/object");
+const httpd = require("./lib/httpd");
 
-/**
- * A helper function that creates a PageMod, then opens the specified URL
- * and checks the effect of the page mod on 'onload' event via testCallback.
- */
+const PORT = 8099;
+const PATH = '/test-contentScriptWhen.html';
+
+// an evil function enables the creation of tests
+// that depend on delicate event timing. do not use.
 exports.testPageMod = function testPageMod(assert, done, testURL, pageModOptions,
                                            testCallback, timeout) {
-  if (!xulApp.versionInRange(xulApp.platformVersion, "1.9.3a3", "*") &&
-      !xulApp.versionInRange(xulApp.platformVersion, "1.9.2.7", "1.9.2.*")) {
-    assert.pass("Note: not testing PageMod, as it doesn't work on this platform version");
-    return null;
-  }
 
   var wm = Cc['@mozilla.org/appshell/window-mediator;1']
            .getService(Ci.nsIWindowMediator);
   var browserWindow = wm.getMostRecentWindow("navigator:browser");
-  if (!browserWindow) {
-    assert.pass("page-mod tests: could not find the browser window, so " +
-              "will not run. Use -a firefox to run the pagemod tests.")
-    return null;
-  }
 
-  let loader = Loader(module, null, null, {
-    modules: {
-      "sdk/self": merge({}, self, {
-        data: merge({}, self.data, require("./fixtures"))
-      })
-    }
-  });
+  let options = merge({}, require('@loader/options'),
+                      { prefixURI: require('./fixtures').url() });
+
+  let loader = Loader(module, null, options);
   let pageMod = loader.require("sdk/page-mod");
 
   var pageMods = [new pageMod.PageMod(opts) for each(opts in pageModOptions)];
 
   let newTab = openTab(browserWindow, testURL, {
     inBackground: false
   });
   var b = getBrowserForTab(newTab);
 
   function onPageLoad() {
     b.removeEventListener("load", onPageLoad, true);
     // Delay callback execute as page-mod content scripts may be executed on
     // load event. So page-mod actions may not be already done.
     // If we delay even more contentScriptWhen:'end', we may want to modify
     // this code again.
-    timer.setTimeout(testCallback, 0,
+    setTimeout(testCallback, timeout,
       b.contentWindow.wrappedJSObject, 
       function () {
         pageMods.forEach(function(mod) mod.destroy());
         // XXX leaks reported if we don't close the tab?
         closeTab(newTab);
         loader.unload();
         done();
       }
@@ -71,28 +57,55 @@ exports.testPageMod = function testPageM
   return pageMods;
 }
 
 /**
  * helper function that creates a PageMod and calls back the appropriate handler
  * based on the value of document.readyState at the time contentScript is attached
  */
 exports.handleReadyState = function(url, contentScriptWhen, callbacks) {
-  const { PageMod } = Loader(module).require('sdk/page-mod');
+  const loader = Loader(module);
+  const { PageMod } = loader.require('sdk/page-mod');
 
   let pagemod = PageMod({
     include: url,
     attachTo: ['existing', 'top'],
     contentScriptWhen: contentScriptWhen,
     contentScript: "self.postMessage(document.readyState)",
     onAttach: worker => {
       let { tab } = worker;
       worker.on('message', readyState => {
-        pagemod.destroy();
         // generate event name from `readyState`, e.g. `"loading"` becomes `onLoading`.
         let type = 'on' + readyState[0].toUpperCase() + readyState.substr(1);
 
         if (type in callbacks)
           callbacks[type](tab); 
+
+        pagemod.destroy();
+        loader.unload();
       })
     }
   });
 }
+
+// serves a slow page which takes 1.5 seconds to load,
+// 0.5 seconds in each readyState: uninitialized, loading, interactive.
+exports.contentScriptWhenServer = function() {
+  const URL = 'http://localhost:' + PORT + PATH;
+
+  const HTML = `/* polyglot js
+    <script src="${URL}"></script>
+    delay both the "DOMContentLoaded"
+    <script async src="${URL}"></script>
+    and "load" events */`;
+
+  let srv = httpd.startServerAsync(PORT);
+
+  srv.registerPathHandler(PATH, (_, response) => {
+    response.processAsync();
+    response.setHeader('Content-Type', 'text/html', false);
+    setTimeout(_ => response.finish(), 500);
+    response.write(HTML);
+  })
+
+  srv.URL = URL;
+  return srv;
+}
--- a/addon-sdk/source/test/test-base64.js
+++ b/addon-sdk/source/test/test-base64.js
@@ -4,17 +4,18 @@
 
 "use strict";
 
 const base64 = require("sdk/base64");
 
 const text = "Awesome!";
 const b64text = "QXdlc29tZSE=";
 
-const utf8text = "βœ“ Γ  la mode";
+const utf8text = "\u2713 Γ  la mode";
+const badutf8text = "\u0013 Γ  la mode";
 const b64utf8text = "4pyTIMOgIGxhIG1vZGU=";
 
 exports["test base64.encode"] = function (assert) {
   assert.equal(base64.encode(text), b64text, "encode correctly")
 }
 
 exports["test base64.decode"] = function (assert) {
   assert.equal(base64.decode(b64text), text, "decode correctly")
@@ -61,15 +62,15 @@ exports["test base64.decode with wrong c
   assert.throws(function() {
     base64.decode(utf8text, 8);
   }, "The charset argument can be only 'utf-8'");
 
 }
 
 exports["test encode/decode Unicode without utf-8 as charset"] = function (assert) {
 
-  assert.notEqual(base64.decode(base64.encode(utf8text)), utf8text,
-    "Unicode strings needs 'utf-8' charset"
+  assert.equal(base64.decode(base64.encode(utf8text)), badutf8text,
+    "Unicode strings needs 'utf-8' charset or will be mangled"
   );
 
 }
 
 require("test").run(exports);
--- a/addon-sdk/source/test/test-content-script.js
+++ b/addon-sdk/source/test/test-content-script.js
@@ -552,17 +552,18 @@ exports["test Collections 2"] = createPr
       assert(inputs.length == 3, "inputs.length is correct");
       assert(body.childNodes[0] == inputs[0], "body.childNodes[0] is correct");
       assert(body.childNodes[1] == inputs[1], "body.childNodes[1] is correct");
       assert(body.childNodes[2] == inputs[2], "body.childNodes[2] is correct");
       let count = 0;
       for(let i in body.childNodes) {
         count++;
       }
-      assert(count == 6, "body.childNodes is iterable");
+
+      assert(count >= 3, "body.childNodes is iterable");
       done();
     }
   );
 
 });
 
 exports["test XMLHttpRequest"] = createProxyTest("", function (helper) {
 
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-content-worker-parent.js
@@ -0,0 +1,982 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Skipping due to window creation being unsupported in Fennec
+module.metadata = {
+  engines: {
+    'Firefox': '*'
+  }
+};
+
+const { Cc, Ci } = require("chrome");
+const { on } = require("sdk/event/core");
+const { setTimeout } = require("sdk/timers");
+const { LoaderWithHookedConsole } = require("sdk/test/loader");
+const { Worker } = require("sdk/content/worker-parent");
+const { close } = require("sdk/window/helpers");
+const { set: setPref } = require("sdk/preferences/service");
+const { isArray } = require("sdk/lang/type");
+const { URL } = require('sdk/url');
+const fixtures = require("./fixtures");
+const system = require("sdk/system/events");
+
+const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
+
+const DEFAULT_CONTENT_URL = "data:text/html;charset=utf-8,foo";
+
+const WINDOW_SCRIPT_URL = "data:text/html;charset=utf-8," +
+                          "<script>window.addEventListener('message', function (e) {" +
+                          "  if (e.data === 'from -> content-script')" +
+                          "    window.postMessage('from -> window', '*');" +
+                          "});</script>";
+
+function makeWindow() {
+  let content =
+    "<?xml version=\"1.0\"?>" +
+    "<window " +
+    "xmlns=\"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul\">" +
+    "<script>var documentValue=true;</script>" +
+    "</window>";
+  var url = "data:application/vnd.mozilla.xul+xml;charset=utf-8," +
+            encodeURIComponent(content);
+  var features = ["chrome", "width=10", "height=10"];
+
+  return Cc["@mozilla.org/embedcomp/window-watcher;1"].
+         getService(Ci.nsIWindowWatcher).
+         openWindow(null, url, null, features.join(","), null);
+}
+
+// Listen for only first one occurence of DOM event
+function listenOnce(node, eventName, callback) {
+  node.addEventListener(eventName, function onevent(event) {
+    node.removeEventListener(eventName, onevent, true);
+    callback(node);
+  }, true);
+}
+
+// Load a given url in a given browser and fires the callback when it is loaded
+function loadAndWait(browser, url, callback) {
+  listenOnce(browser, "load", callback);
+  // We have to wait before calling `loadURI` otherwise, if we call
+  // `loadAndWait` during browser load event, the history will be broken
+  setTimeout(function () {
+    browser.loadURI(url);
+  }, 0);
+}
+
+// Returns a test function that will automatically open a new chrome window
+// with a <browser> element loaded on a given content URL
+// The callback receive 3 arguments:
+// - test: reference to the jetpack test object
+// - browser: a reference to the <browser> xul node
+// - done: a callback to call when test is over
+function WorkerTest(url, callback) {
+  return function testFunction(assert, done) {
+    let chromeWindow = makeWindow();
+    chromeWindow.addEventListener("load", function onload() {
+      chromeWindow.removeEventListener("load", onload, true);
+      let browser = chromeWindow.document.createElement("browser");
+      browser.setAttribute("type", "content");
+      chromeWindow.document.documentElement.appendChild(browser);
+      // Wait for about:blank load event ...
+      listenOnce(browser, "load", function onAboutBlankLoad() {
+        // ... before loading the expected doc and waiting for its load event
+        loadAndWait(browser, url, function onDocumentLoaded() {
+          callback(assert, browser, function onTestDone() {
+
+            close(chromeWindow).then(done);
+          });
+        });
+      });
+    }, true);
+  };
+}
+
+exports["test:sample"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    assert.notEqual(browser.contentWindow.location.href, "about:blank",
+                        "window is now on the right document");
+
+    let window = browser.contentWindow
+    let worker =  Worker({
+      window: window,
+      contentScript: "new " + function WorkerScope() {
+        // window is accessible
+        let myLocation = window.location.toString();
+        self.on("message", function(data) {
+          if (data == "hi!")
+            self.postMessage("bye!");
+        });
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        assert.equal("bye!", msg);
+        assert.equal(worker.url, window.location.href,
+                         "worker.url still works");
+        done();
+      }
+    });
+
+    assert.equal(worker.url, window.location.href,
+                     "worker.url works");
+    assert.equal(worker.contentURL, window.location.href,
+                     "worker.contentURL works");
+    worker.postMessage("hi!");
+  }
+);
+
+exports["test:emit"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          // Validate self.on and self.emit
+          self.port.on("addon-to-content", function (data) {
+            self.port.emit("content-to-addon", data);
+          });
+
+          // Check for global pollution
+          //if (typeof on != "undefined")
+          //  self.postMessage("`on` is in globals");
+          if (typeof once != "undefined")
+            self.postMessage("`once` is in globals");
+          if (typeof emit != "undefined")
+            self.postMessage("`emit` is in globals");
+
+        },
+        onMessage: function(msg) {
+          assert.fail("Got an unexpected message : "+msg);
+        }
+      });
+
+    // Validate worker.port
+    worker.port.on("content-to-addon", function (data) {
+      assert.equal(data, "event data");
+      done();
+    });
+    worker.port.emit("addon-to-content", "event data");
+  }
+);
+
+exports["test:emit hack message"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          // Validate self.port
+          self.port.on("message", function (data) {
+            self.port.emit("message", data);
+          });
+          // We should not receive message on self, but only on self.port
+          self.on("message", function (data) {
+            self.postMessage("message", data);
+          });
+        },
+        onError: function(e) {
+          assert.fail("Got exception: "+e);
+        }
+      });
+
+    worker.port.on("message", function (data) {
+      assert.equal(data, "event data");
+      done();
+    });
+    worker.on("message", function (data) {
+      assert.fail("Got an unexpected message : "+msg);
+    });
+    worker.port.emit("message", "event data");
+  }
+);
+
+exports["test:n-arguments emit"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let repeat = 0;
+    let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          // Validate self.on and self.emit
+          self.port.on("addon-to-content", function (a1, a2, a3) {
+            self.port.emit("content-to-addon", a1, a2, a3);
+          });
+        }
+      });
+
+    // Validate worker.port
+    worker.port.on("content-to-addon", function (arg1, arg2, arg3) {
+      if (!repeat++) {
+        this.emit("addon-to-content", "first argument", "second", "third");
+      } else {
+        assert.equal(arg1, "first argument");
+        assert.equal(arg2, "second");
+        assert.equal(arg3, "third");
+        done();
+      }
+    });
+    worker.port.emit("addon-to-content", "first argument", "second", "third");
+  }
+);
+
+exports["test:post-json-values-only"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          self.on("message", function (message) {
+            self.postMessage([ message.fun === undefined,
+                               typeof message.w,
+                               message.w && "port" in message.w,
+                               message.w._url,
+                               Array.isArray(message.array),
+                               JSON.stringify(message.array)]);
+          });
+        }
+      });
+
+    // Validate worker.onMessage
+    let array = [1, 2, 3];
+    worker.on("message", function (message) {
+      assert.ok(message[0], "function becomes undefined");
+      assert.equal(message[1], "object", "object stays object");
+      assert.ok(message[2], "object's attributes are enumerable");
+      assert.equal(message[3], DEFAULT_CONTENT_URL,
+                       "jsonable attributes are accessible");
+      // See bug 714891, Arrays may be broken over compartements:
+      assert.ok(message[4], "Array keeps being an array");
+      assert.equal(message[5], JSON.stringify(array),
+                       "Array is correctly serialized");
+      done();
+    });
+    // Add a new url property sa the Class function used by
+    // Worker doesn't set enumerables to true for non-functions
+    worker._url = DEFAULT_CONTENT_URL;
+
+    worker.postMessage({ fun: function () {}, w: worker, array: array });
+  }
+);
+
+exports["test:emit-json-values-only"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          // Validate self.on and self.emit
+          self.port.on("addon-to-content", function (fun, w, obj, array) {
+            self.port.emit("content-to-addon", [
+                            fun === null,
+                            typeof w,
+                            "port" in w,
+                            w._url,
+                            "fun" in obj,
+                            Object.keys(obj.dom).length,
+                            Array.isArray(array),
+                            JSON.stringify(array)
+                          ]);
+          });
+        }
+      });
+
+    // Validate worker.port
+    let array = [1, 2, 3];
+    worker.port.on("content-to-addon", function (result) {
+      assert.ok(result[0], "functions become null");
+      assert.equal(result[1], "object", "objects stay objects");
+      assert.ok(result[2], "object's attributes are enumerable");
+      assert.equal(result[3], DEFAULT_CONTENT_URL,
+                       "json attribute is accessible");
+      assert.ok(!result[4], "function as object attribute is removed");
+      assert.equal(result[5], 0, "DOM nodes are converted into empty object");
+      // See bug 714891, Arrays may be broken over compartments:
+      assert.ok(result[6], "Array keeps being an array");
+      assert.equal(result[7], JSON.stringify(array),
+                       "Array is correctly serialized");
+      done();
+    });
+
+    let obj = {
+      fun: function () {},
+      dom: browser.contentWindow.document.createElement("div")
+    };
+    // Add a new url property sa the Class function used by
+    // Worker doesn't set enumerables to true for non-functions
+    worker._url = DEFAULT_CONTENT_URL;
+    worker.port.emit("addon-to-content", function () {}, worker, obj, array);
+  }
+);
+
+exports["test:content is wrapped"] = WorkerTest(
+  "data:text/html;charset=utf-8,<script>var documentValue=true;</script>",
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        self.postMessage(!window.documentValue);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        assert.ok(msg,
+          "content script has a wrapped access to content document");
+        done();
+      }
+    });
+  }
+);
+
+// ContentWorker is not for chrome
+/* 
+exports["test:chrome is unwrapped"] = function(assert, done) {
+  let window = makeWindow();
+
+  listenOnce(window, "load", function onload() {
+
+    let worker =  Worker({
+      window: window,
+      contentScript: "new " + function WorkerScope() {
+        self.postMessage(window.documentValue);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        assert.ok(msg,
+          "content script has an unwrapped access to chrome document");
+        close(window).then(done);
+      }
+    });
+
+  });
+}
+*/
+
+exports["test:nothing is leaked to content script"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        self.postMessage([
+          "ContentWorker" in window,
+          "UNWRAP_ACCESS_KEY" in window,
+          "getProxyForObject" in window
+        ]);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(list) {
+        assert.ok(!list[0], "worker API contrustor isn't leaked");
+        assert.ok(!list[1], "Proxy API stuff isn't leaked 1/2");
+        assert.ok(!list[2], "Proxy API stuff isn't leaked 2/2");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:ensure console.xxx works in cs"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    const EXPECTED = ["time", "log", "info", "warn", "error", "error", "timeEnd"];
+
+    let calls = [];
+    let levels = [];
+
+    system.on('console-api-log-event', onMessage);
+
+    function onMessage({ subject }) {
+      calls.push(subject.wrappedJSObject.arguments[0]);
+      levels.push(subject.wrappedJSObject.level);
+    }
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        console.time("time");
+        console.log("log");
+        console.info("info");
+        console.warn("warn");
+        console.error("error");
+        console.debug("debug");
+        console.exception("error");
+        console.timeEnd("timeEnd");
+        self.postMessage();
+      },
+      onMessage: function() {
+        system.off('console-api-log-event', onMessage);
+
+        assert.equal(JSON.stringify(calls),
+          JSON.stringify(EXPECTED),
+          "console methods have been called successfully, in expected order");
+
+        assert.equal(JSON.stringify(levels),
+          JSON.stringify(EXPECTED),
+          "console messages have correct log levels, in expected order");
+
+        done();
+      }
+    });
+  }
+);
+
+exports["test:setTimeout works with string argument"] = WorkerTest(
+  "data:text/html;charset=utf-8,<script>var docVal=5;</script>",
+  function(assert, browser, done) {
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function ContentScriptScope() {
+        // must use "window.scVal" instead of "var csVal"
+        // since we are inside ContentScriptScope function.
+        // i'm NOT putting code-in-string inside code-in-string </YO DAWG>
+        window.csVal = 13;
+        setTimeout("self.postMessage([" +
+                      "csVal, " +
+                      "window.docVal, " +
+                      "'ContentWorker' in window, " +
+                      "'UNWRAP_ACCESS_KEY' in window, " +
+                      "'getProxyForObject' in window, " +
+                    "])", 1);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function([csVal, docVal, chrome1, chrome2, chrome3]) {
+        // test timer code is executed in the correct context
+        assert.equal(csVal, 13, "accessing content-script values");
+        assert.notEqual(docVal, 5, "can't access document values (directly)");
+        assert.ok(!chrome1 && !chrome2 && !chrome3, "nothing is leaked from chrome");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:setInterval works with string argument"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let count = 0;
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "setInterval('self.postMessage(1)', 50)",
+      contentScriptWhen: "ready",
+      onMessage: function(one) {
+        count++;
+        assert.equal(one, 1, "got " + count + " message(s) from setInterval");
+        if (count >= 3) done();
+      }
+    });
+  }
+);
+
+exports["test:setInterval async Errors passed to .onError"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let count = 0;
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "setInterval(() => { throw Error('ubik') }, 50)",
+      contentScriptWhen: "ready",
+      onError: function(err) {
+        count++;
+        assert.equal(err.message, "ubik",
+            "error (corectly) propagated  " + count + " time(s)");
+        if (count >= 3) done();
+      }
+    });
+  }
+);
+
+exports["test:setTimeout throws array, passed to .onError"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "setTimeout(function() { throw ['array', 42] }, 1)",
+      contentScriptWhen: "ready",
+      onError: function(arr) {
+        assert.ok(isArray(arr),
+            "the type of thrown/propagated object is array");
+        assert.ok(arr.length==2,
+            "the propagated thrown array is the right length");
+        assert.equal(arr[1], 42,
+            "element inside the thrown array correctly propagated");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:setTimeout string arg with SyntaxError to .onError"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "setTimeout('syntax 123 error', 1)",
+      contentScriptWhen: "ready",
+      onError: function(err) {
+        assert.equal(err.name, "SyntaxError",
+            "received SyntaxError thrown from bad code in string argument to setTimeout");
+        assert.ok('fileName' in err,
+            "propagated SyntaxError contains a fileName property");
+        assert.ok('stack' in err,
+            "propagated SyntaxError contains a stack property");
+        assert.equal(err.message, "missing ; before statement",
+            "propagated SyntaxError has the correct (helpful) message");
+        assert.equal(err.lineNumber, 1,
+            "propagated SyntaxError was thrown on the right lineNumber");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:setTimeout can't be cancelled by content"] = WorkerTest(
+  "data:text/html;charset=utf-8,<script>var documentValue=true;</script>",
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        let id = setTimeout(function () {
+          self.postMessage("timeout");
+        }, 100);
+        unsafeWindow.eval("clearTimeout("+id+");");
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        assert.ok(msg,
+          "content didn't managed to cancel our setTimeout");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:clearTimeout"] = WorkerTest(
+  "data:text/html;charset=utf-8,clear timeout",
+  function(assert, browser, done) {
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        let id1 = setTimeout(function() {
+          self.postMessage("failed");
+        }, 10);
+        let id2 = setTimeout(function() {
+          self.postMessage("done");
+        }, 100);
+        clearTimeout(id1);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        if (msg === "failed") {
+          assert.fail("failed to cancel timer");
+        } else {
+          assert.pass("timer cancelled");
+          done();
+        }
+      }
+    });
+  }
+);
+
+exports["test:clearInterval"] = WorkerTest(
+  "data:text/html;charset=utf-8,clear timeout",
+  function(assert, browser, done) {
+    let called = 0;
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        let id = setInterval(function() {
+          self.postMessage("intreval")
+          clearInterval(id)
+          setTimeout(function() {
+            self.postMessage("done")
+          }, 100)
+        }, 10);
+      },
+      contentScriptWhen: "ready",
+      onMessage: function(msg) {
+        if (msg === "intreval") {
+          called = called + 1;
+          if (called > 1) assert.fail("failed to cancel timer");
+        } else {
+          assert.pass("interval cancelled");
+          done();
+        }
+      }
+    });
+  }
+)
+
+exports["test:setTimeout are unregistered on content unload"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let originalWindow = browser.contentWindow;
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        document.title = "ok";
+        let i = 0;
+        setInterval(function () {
+          document.title = i++;
+        }, 10);
+      },
+      contentScriptWhen: "ready"
+    });
+
+    // Change location so that content script is destroyed,
+    // and all setTimeout/setInterval should be unregistered.
+    // Wait some cycles in order to execute some intervals.
+    setTimeout(function () {
+      // Bug 689621: Wait for the new document load so that we are sure that
+      // previous document cancelled its intervals
+      let url2 = "data:text/html;charset=utf-8,<title>final</title>";
+      loadAndWait(browser, url2, function onload() {
+        let titleAfterLoad = originalWindow.document.title;
+        // Wait additional cycles to verify that intervals are really cancelled
+        setTimeout(function () {
+          assert.equal(browser.contentDocument.title, "final",
+                           "New document has not been modified");
+          assert.equal(originalWindow.document.title, titleAfterLoad,
+                           "Nor previous one");
+
+          done();
+        }, 100);
+      });
+    }, 100);
+  }
+);
+
+exports['test:check window attribute in iframes'] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    // Create a first iframe and wait for its loading
+    let contentWin = browser.contentWindow;
+    let contentDoc = contentWin.document;
+    let iframe = contentDoc.createElement("iframe");
+    contentDoc.body.appendChild(iframe);
+
+    listenOnce(iframe, "load", function onload() {
+
+      // Create a second iframe inside the first one and wait for its loading
+      let iframeDoc = iframe.contentWindow.document;
+      let subIframe = iframeDoc.createElement("iframe");
+      iframeDoc.body.appendChild(subIframe);
+
+      listenOnce(subIframe, "load", function onload() {
+        subIframe.removeEventListener("load", onload, true);
+
+        // And finally create a worker against this second iframe
+        let worker =  Worker({
+          window: subIframe.contentWindow,
+          contentScript: 'new ' + function WorkerScope() {
+            self.postMessage([
+              window.top !== window,
+              frameElement,
+              window.parent !== window,
+              top.location.href,
+              parent.location.href,
+            ]);
+          },
+          onMessage: function(msg) {
+            assert.ok(msg[0], "window.top != window");
+            assert.ok(msg[1], "window.frameElement is defined");
+            assert.ok(msg[2], "window.parent != window");
+            assert.equal(msg[3], contentWin.location.href,
+                             "top.location refers to the toplevel content doc");
+            assert.equal(msg[4], iframe.contentWindow.location.href,
+                             "parent.location refers to the first iframe doc");
+            done();
+          }
+        });
+
+      });
+      subIframe.setAttribute("src", "data:text/html;charset=utf-8,bar");
+
+    });
+    iframe.setAttribute("src", "data:text/html;charset=utf-8,foo");
+  }
+);
+
+exports['test:check window attribute in toplevel documents'] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: 'new ' + function WorkerScope() {
+        self.postMessage([
+          window.top === window,
+          frameElement,
+          window.parent === window
+        ]);
+      },
+      onMessage: function(msg) {
+        assert.ok(msg[0], "window.top == window");
+        assert.ok(!msg[1], "window.frameElement is null");
+        assert.ok(msg[2], "window.parent == window");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:check worker API with page history"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let url2 = "data:text/html;charset=utf-8,bar";
+
+    loadAndWait(browser, url2, function () {
+      let worker =  Worker({
+        window: browser.contentWindow,
+        contentScript: "new " + function WorkerScope() {
+          // Just before the content script is disable, we register a timeout
+          // that will be disable until the page gets visible again
+          self.on("pagehide", function () {
+            setTimeout(function () {
+              self.postMessage("timeout restored");
+            }, 0);
+          });
+        },
+        contentScriptWhen: "start"
+      });
+
+      // postMessage works correctly when the page is visible
+      worker.postMessage("ok");
+
+      // We have to wait before going back into history,
+      // otherwise `goBack` won't do anything.
+      setTimeout(function () {
+        browser.goBack();
+      }, 0);
+
+      // Wait for the document to be hidden
+      browser.addEventListener("pagehide", function onpagehide() {
+        browser.removeEventListener("pagehide", onpagehide, false);
+        // Now any event sent to this worker should throw
+
+        setTimeout(_ => {
+          assert.throws(
+              function () { worker.postMessage("data"); },
+              /The page is currently hidden and can no longer be used/,
+              "postMessage should throw when the page is hidden in history"
+              );
+
+          assert.throws(
+              function () { worker.port.emit("event"); },
+              /The page is currently hidden and can no longer be used/,
+              "port.emit should throw when the page is hidden in history"
+              );
+        })
+
+        // Display the page with attached content script back in order to resume
+        // its timeout and receive the expected message.
+        // We have to delay this in order to not break the history.
+        // We delay for a non-zero amount of time in order to ensure that we
+        // do not receive the message immediatly, so that the timeout is
+        // actually disabled
+        setTimeout(function () {
+          worker.on("message", function (data) {
+            assert.ok(data, "timeout restored");
+            done();
+          });
+          browser.goForward();
+        }, 500);
+
+      }, false);
+    });
+
+  }
+);
+
+exports['test:conentScriptFile as URL instance'] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+
+    let url = new URL(fixtures.url("test-contentScriptFile.js"));
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScriptFile: url,
+      onMessage: function(msg) {
+        assert.equal(msg, "msg from contentScriptFile",
+            "received a wrong message from contentScriptFile");
+        done();
+      }
+    });
+  }
+);
+
+exports["test:worker events"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function (assert, browser, done) {
+    let window = browser.contentWindow;
+    let events = [];
+    let worker = Worker({
+      window: window,
+      contentScript: 'new ' + function WorkerScope() {
+        self.postMessage('start');
+      },
+      onAttach: win => {
+        events.push('attach');
+        assert.pass('attach event called when attached');
+        assert.equal(window, win, 'attach event passes in attached window');
+      },
+      onError: err => {
+        assert.equal(err.message, 'Custom',
+          'Error passed into error event');
+        worker.detach();
+      },
+      onMessage: msg => {
+        assert.pass('`onMessage` handles postMessage')
+        throw new Error('Custom');
+      },
+      onDetach: _ => {
+        assert.pass('`onDetach` called when worker detached');
+        done();
+      }
+    });
+    // `attach` event is called synchronously during instantiation,
+    // so we can't listen to that, TODO FIX?
+    //  worker.on('attach', obj => console.log('attach', obj));
+  }
+);
+
+exports["test:onDetach in contentScript on destroy"] = WorkerTest(
+  "data:text/html;charset=utf-8,foo#detach",
+  function(assert, browser, done) {
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: 'new ' + function WorkerScope() {
+        self.port.on('detach', function(reason) {
+          window.location.hash += '!' + reason;
+        })
+      },
+    });
+    browser.contentWindow.addEventListener('hashchange', _ => {
+      assert.equal(browser.contentWindow.location.hash, '#detach!',
+                   "location.href is as expected");
+      done();
+    })
+    worker.destroy();
+  }
+);
+
+exports["test:onDetach in contentScript on unload"] = WorkerTest(
+  "data:text/html;charset=utf-8,foo#detach",
+  function(assert, browser, done) {
+    let { loader } = LoaderWithHookedConsole(module);
+    let worker = loader.require("sdk/content/worker-parent").Worker({
+      window: browser.contentWindow,
+      contentScript: 'new ' + function WorkerScope() {
+        self.port.on('detach', function(reason) {
+          window.location.hash += '!' + reason;
+        })
+      },
+    });
+    browser.contentWindow.addEventListener('hashchange', _ => {
+      assert.equal(browser.contentWindow.location.hash, '#detach!shutdown',
+                   "location.href is as expected");
+      done();
+    })
+    loader.unload('shutdown');
+  }
+);
+
+exports["test:console method log functions properly"] = WorkerTest(
+  DEFAULT_CONTENT_URL,
+  function(assert, browser, done) {
+    let logs = [];
+
+    system.on('console-api-log-event', onMessage);
+
+    function onMessage({ subject }) {
+      logs.push(clean(subject.wrappedJSObject.arguments[0]));
+    }
+
+    let clean = message =>
+          message.trim().
+          replace(/[\r\n]/g, " ").
+          replace(/ +/g, " ");
+
+    let worker =  Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        console.log(Function);
+        console.log((foo) => foo * foo);
+        console.log(function foo(bar) { return bar + bar });
+
+        self.postMessage();
+      },
+      onMessage: () => {
+        system.off('console-api-log-event', onMessage);
+
+        assert.deepEqual(logs, [
+          "function Function() { [native code] }",
+          "(foo) => foo * foo",
+          "function foo(bar) { \"use strict\"; return bar + bar }"
+        ]);
+
+        done();
+      }
+    });
+  }
+);
+
+exports["test:global postMessage"] = WorkerTest(
+  WINDOW_SCRIPT_URL,
+  function(assert, browser, done) {
+    let contentScript = "window.addEventListener('message', function (e) {" +
+                        "  if (e.data === 'from -> window')" +
+                        "    self.port.emit('response', e.data, e.origin);" +
+                        "});" +
+                        "postMessage('from -> content-script', '*');";
+    let { loader } = LoaderWithHookedConsole(module);
+    let worker =  loader.require("sdk/content/worker-parent").Worker({
+      window: browser.contentWindow,
+      contentScriptWhen: "ready",
+      contentScript: contentScript
+    });
+
+    worker.port.on("response", (data, origin) => {
+      assert.equal(data, "from -> window", "Communication from content-script to window completed");
+      done();
+    });
+});
+
+exports["test:destroy unbinds listeners from port"] = WorkerTest(
+  "data:text/html;charset=utf-8,portdestroyer",
+  function(assert, browser, done) {
+    let destroyed = false;
+    let worker = Worker({
+      window: browser.contentWindow,
+      contentScript: "new " + function WorkerScope() {
+        self.port.emit("destroy");
+        setInterval(self.port.emit, 10, "ping");
+      },
+      onDestroy: done
+    });
+    worker.port.on("ping", () => {
+      if (destroyed) {
+        assert.fail("Should not call events on port after destroy.");
+      }
+    });
+    worker.port.on("destroy", () => {
+      destroyed = true;
+      worker.destroy();
+      assert.pass("Worker destroyed, waiting for no future listeners handling events.");
+      setTimeout(done, 500);
+    });
+  }
+);
+
+
+require("test").run(exports);
--- a/addon-sdk/source/test/test-event-core.js
+++ b/addon-sdk/source/test/test-event-core.js
@@ -1,12 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 'use strict';
 
 const { on, once, off, emit, count } = require('sdk/event/core');
 const { LoaderWithHookedConsole } = require("sdk/test/loader");
 
 exports['test add a listener'] = function(assert) {
   let events = [ { name: 'event#1' }, 'event#2' ];
   let target = { name: 'target' };
@@ -194,27 +193,45 @@ exports['test unhandled exceptions'] = f
   assert.ok(~String(messages[1].msg).indexOf('Draax!'),
             'error in error handler is logged');
 };
 
 exports['test unhandled errors'] = function(assert) {
   let exceptions = [];
   let { loader, messages } = LoaderWithHookedConsole(module);
 
-  let { emit, on } = loader.require('sdk/event/core');
+  let { emit } = loader.require('sdk/event/core');
   let target = {};
   let boom = Error('Boom!');
 
   emit(target, 'error', boom);
   assert.equal(messages.length, 1, 'Error was logged');
   assert.equal(messages[0].type, 'exception', 'The console message is exception');
   assert.ok(~String(messages[0].msg).indexOf('Boom!'),
             'unhandled exception is logged');
 };
 
+exports['test piped errors'] = function(assert) {
+  let exceptions = [];
+  let { loader, messages } = LoaderWithHookedConsole(module);
+
+  let { emit } = loader.require('sdk/event/core');
+  let { pipe } = loader.require('sdk/event/utils');
+  let target = {};
+  let second = {};
+
+  pipe(target, second);
+  emit(target, 'error', 'piped!');
+
+  assert.equal(messages.length, 1, 'error logged only once, ' +
+               'considered "handled" on `target` by the catch-all pipe');
+  assert.equal(messages[0].type, 'exception', 'The console message is exception');
+  assert.ok(~String(messages[0].msg).indexOf('piped!'),
+            'unhandled (piped) exception is logged on `second` target');
+};
 
 exports['test count'] = function(assert) {
   let target = {};
 
   assert.equal(count(target, 'foo'), 0, 'no listeners for "foo" events');
   on(target, 'foo', function() {});
   assert.equal(count(target, 'foo'), 1, 'listener registered');
   on(target, 'foo', function() {}, 2, 'another listener registered');
@@ -237,9 +254,9 @@ exports['test listen to all events'] = f
   assert.deepEqual(actual[1], ['foo', 'hello'],
     'wildcard listener called');
 
   emit(target, 'bar', 'goodbye');
   assert.deepEqual(actual[2], ['bar', 'goodbye'],
     'wildcard listener called for unbound event name');
 };
 
-require('test').run(exports);
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-event-target.js
+++ b/addon-sdk/source/test/test-event-target.js
@@ -1,12 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 'use strict';
 
 const { emit } = require('sdk/event/core');
 const { EventTarget } = require('sdk/event/target');
 const { Loader } = require('sdk/test/loader');
 
 exports['test add a listener'] = function(assert) {
   let events = [ { name: 'event#1' }, 'event#2' ];
@@ -110,25 +109,44 @@ exports['test remove a listener'] = func
   target.on('message', function listener() {
     actual.push(1);
     target.on('message', function() {
       target.removeListener('message', listener);
       actual.push(2);
     })
   });
 
-  target.off('message'); // must do nothing.
   emit(target, 'message');
   assert.deepEqual([ 1 ], actual, 'first listener called');
   emit(target, 'message');
   assert.deepEqual([ 1, 1, 2 ], actual, 'second listener called');
   emit(target, 'message');
   assert.deepEqual([ 1, 1, 2, 2, 2 ], actual, 'first listener removed');
 };
 
+exports['test .off() removes all listeners'] = function(assert) {
+  let target = EventTarget();
+  let actual = [];
+  target.on('message', function listener() {
+    actual.push(1);
+    target.on('message', function() {
+      target.removeListener('message', listener);
+      actual.push(2);
+    })
+  });
+
+  emit(target, 'message');
+  assert.deepEqual([ 1 ], actual, 'first listener called');
+  emit(target, 'message');
+  assert.deepEqual([ 1, 1, 2 ], actual, 'second listener called');
+  target.off();
+  emit(target, 'message');
+  assert.deepEqual([ 1, 1, 2 ], actual, 'target.off() removed all listeners');
+};
+
 exports['test error handling'] = function(assert) {
   let target = EventTarget();
   let error = Error('boom!');
 
   target.on('message', function() { throw error; })
   target.on('error', function(boom) {
     assert.equal(boom, error, 'thrown exception causes error event');
   });
@@ -196,10 +214,9 @@ exports['test target is chainable'] = fu
   }).on('error', function (error) {
     assert.equal(error, boom, 'error handled in chained event');
     done();
   });
 
   emit(emitter, 'data', 'message');
 };
 
-require('test').run(exports);
-
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -1,35 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { PageMod } = require("sdk/page-mod");
-const { testPageMod, handleReadyState } = require("./pagemod-test-helpers");
+const { testPageMod, handleReadyState, contentScriptWhenServer } = require("./pagemod-test-helpers");
 const { Loader } = require('sdk/test/loader');
 const tabs = require("sdk/tabs");
 const { setTimeout } = require("sdk/timers");
 const { Cc, Ci, Cu } = require("chrome");
-const {
-  open,
-  getFrames,
-  getMostRecentBrowserWindow,
-  getInnerId
-} = require('sdk/window/utils');
+const system = require("sdk/system/events");
+const { open, getFrames, getMostRecentBrowserWindow, getInnerId } = require('sdk/window/utils');
 const { getTabContentWindow, getActiveTab, setTabURL, openTab, closeTab } = require('sdk/tabs/utils');
 const xulApp = require("sdk/system/xul-app");
 const { isPrivateBrowsingSupported } = require('sdk/self');
 const { isPrivate } = require('sdk/private-browsing');
 const { openWebpage } = require('./private-browsing/helper');
 const { isTabPBSupported, isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
 const promise = require("sdk/core/promise");
 const { pb } = require('./private-browsing/helper');
 const { URL } = require("sdk/url");
-const { LoaderWithHookedConsole } = require('sdk/test/loader');
 
 const { waitUntil } = require("sdk/test/utils");
 const data = require("./fixtures");
 
 const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const { require: devtoolsRequire } = devtools;
 const contentGlobals = devtoolsRequire("devtools/server/content-globals");
 
@@ -59,17 +54,18 @@ exports.testPageMod1 = function(assert, 
     }],
     function(win, done) {
       assert.equal(
         win.document.body.getAttribute("JEP-107"),
         "worked",
         "PageMod.onReady test"
       );
       done();
-    }
+    },
+    100
   );
 };
 
 exports.testPageMod2 = function(assert, done) {
   testPageMod(assert, done, "about:", [{
       include: "about:*",
       contentScript: [
         'new ' + function contentScript() {
@@ -91,17 +87,19 @@ exports.testPageMod2 = function(assert, 
                        "true",
                        "PageMod test #2: first script has run");
       assert.equal(win.document.documentElement.getAttribute("second"),
                        "true",
                        "PageMod test #2: second script has run");
       assert.equal("AUQLUE" in win, false,
                        "PageMod test #2: scripts get a wrapped window");
       done();
-    });
+    },
+    100
+  );
 };
 
 exports.testPageModIncludes = function(assert, done) {
   var asserts = [];
   function createPageModTest(include, expectedMatch) {
     // Create an 'onload' test function...
     asserts.push(function(test, win) {
       var matches = include in win.localStorage;
@@ -617,187 +615,181 @@ exports.testContentScriptWhenDefault = f
 
   assert.equal(pagemod.contentScriptWhen, 'end', "Default contentScriptWhen is 'end'");
   pagemod.destroy();
 }
 
 // test timing for all 3 contentScriptWhen options (start, ready, end)
 // for new pages, or tabs opened after PageMod is created
 exports.testContentScriptWhenForNewTabs = function(assert, done) {
-  const url = "data:text/html;charset=utf-8,testContentScriptWhenForNewTabs";
-
+  let srv = contentScriptWhenServer();
+  let url = srv.URL + '?ForNewTabs';
   let count = 0;
 
   handleReadyState(url, 'start', {
     onLoading: (tab) => {
       assert.pass("PageMod is attached while document is loading");
-      if (++count === 3)
-        tab.close(done);
+      checkDone(++count, tab, srv, done);
     },
     onInteractive: () => assert.fail("onInteractive should not be called with 'start'."),
     onComplete: () => assert.fail("onComplete should not be called with 'start'."),
   });
 
   handleReadyState(url, 'ready', {
     onInteractive: (tab) => {
       assert.pass("PageMod is attached while document is interactive");
-      if (++count === 3)
-        tab.close(done);
+      checkDone(++count, tab, srv, done);
     },
     onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
     onComplete: () => assert.fail("onComplete should not be called with 'ready'."),
   });
 
   handleReadyState(url, 'end', {
     onComplete: (tab) => {
       assert.pass("PageMod is attached when document is complete");
-      if (++count === 3)
-        tab.close(done);
+      checkDone(++count, tab, srv, done);
     },
     onLoading: () => assert.fail("onLoading should not be called with 'end'."),
     onInteractive: () => assert.fail("onInteractive should not be called with 'end'."),
   });
 
   tabs.open(url);
 }
 
 // test timing for all 3 contentScriptWhen options (start, ready, end)
 // for PageMods created right as the tab is created (in tab.onOpen)
 exports.testContentScriptWhenOnTabOpen = function(assert, done) {
-  const url = "data:text/html;charset=utf-8,testContentScriptWhenOnTabOpen";
+  let srv = contentScriptWhenServer();
+  let url = srv.URL + '?OnTabOpen';
+  let count = 0;
 
   tabs.open({
     url: url,
     onOpen: function(tab) {
-      let count = 0;
 
       handleReadyState(url, 'start', {
         onLoading: () => {
           assert.pass("PageMod is attached while document is loading");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onInteractive: () => assert.fail("onInteractive should not be called with 'start'."),
         onComplete: () => assert.fail("onComplete should not be called with 'start'."),
       });
 
       handleReadyState(url, 'ready', {
         onInteractive: () => {
           assert.pass("PageMod is attached while document is interactive");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
         onComplete: () => assert.fail("onComplete should not be called with 'ready'."),
       });
 
       handleReadyState(url, 'end', {
         onComplete: () => {
           assert.pass("PageMod is attached when document is complete");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'end'."),
         onInteractive: () => assert.fail("onInteractive should not be called with 'end'."),
       });
 
     }
   });
 }
 
 // test timing for all 3 contentScriptWhen options (start, ready, end)
 // for PageMods created while the tab is interactive (in tab.onReady)
 exports.testContentScriptWhenOnTabReady = function(assert, done) {
-  // need a bit bigger document to get the right timing of events with e10s
-  let iframeURL = 'data:text/html;charset=utf-8,testContentScriptWhenOnTabReady';
-  let iframe = '<iframe src="' + iframeURL + '" />';
-  let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframe);
+  let srv = contentScriptWhenServer();
+  let url = srv.URL + '?OnTabReady';
+  let count = 0;
+
   tabs.open({
     url: url,
     onReady: function(tab) {
-      let count = 0;
 
       handleReadyState(url, 'start', {
         onInteractive: () => {
           assert.pass("PageMod is attached while document is interactive");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'start'."),
         onComplete: () => assert.fail("onComplete should not be called with 'start'."),
       });
 
       handleReadyState(url, 'ready', {
         onInteractive: () => {
           assert.pass("PageMod is attached while document is interactive");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
         onComplete: () => assert.fail("onComplete should not be called with 'ready'."),
       });
 
       handleReadyState(url, 'end', {
         onComplete: () => {
           assert.pass("PageMod is attached when document is complete");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'end'."),
         onInteractive: () => assert.fail("onInteractive should not be called with 'end'."),
       });
 
     }
   });
 }
 
 // test timing for all 3 contentScriptWhen options (start, ready, end)
 // for PageMods created after a tab has completed loading (in tab.onLoad)
 exports.testContentScriptWhenOnTabLoad = function(assert, done) {
-  const url = "data:text/html;charset=utf-8,testContentScriptWhenOnTabLoad";
+  let srv = contentScriptWhenServer();
+  let url = srv.URL + '?OnTabLoad';
+  let count = 0;
 
   tabs.open({
     url: url,
     onLoad: function(tab) {
-      let count = 0;
 
       handleReadyState(url, 'start', {
         onComplete: () => {
           assert.pass("PageMod is attached when document is complete");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'start'."),
         onInteractive: () => assert.fail("onInteractive should not be called with 'start'."),
       });
 
       handleReadyState(url, 'ready', {
         onComplete: () => {
           assert.pass("PageMod is attached when document is complete");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'ready'."),
         onInteractive: () => assert.fail("onInteractive should not be called with 'ready'."),
       });
 
       handleReadyState(url, 'end', {
         onComplete: () => {
           assert.pass("PageMod is attached when document is complete");
-          if (++count === 3)
-            tab.close(done);
+          checkDone(++count, tab, srv, done);
         },
         onLoading: () => assert.fail("onLoading should not be called with 'end'."),
         onInteractive: () => assert.fail("onInteractive should not be called with 'end'."),
       });
 
     }
   });
 }
 
+function checkDone(count, tab, srv, done) {
+  if (count === 3)
+    tab.close(_ => srv.stop(done));
+}
+
 exports.testTabWorkerOnMessage = function(assert, done) {
   let { browserWindows } = require("sdk/windows");
   let tabs = require("sdk/tabs");
   let { PageMod } = require("sdk/page-mod");
 
   let url1 = "data:text/html;charset=utf-8,<title>tab1</title><h1>worker1.tab</h1>";
   let url2 = "data:text/html;charset=utf-8,<title>tab2</title><h1>worker2.tab</h1>";
   let worker1 = null;
@@ -1058,17 +1050,17 @@ exports.testPageModCss = function(assert
       contentStyle: "div { height: 100px; }",
       contentStyleFile: [data.url("include-file.css"), "./border-style.css"]
     }],
     function(win, done) {
       let div = win.document.querySelector("div");
 
       assert.equal(div.clientHeight, 100,
         "PageMod contentStyle worked");
-   
+
       assert.equal(div.offsetHeight, 120,
         "PageMod contentStyleFile worked");
 
       assert.equal(win.getComputedStyle(div).borderTopStyle, "dashed",
         "PageMod contentStyleFile with relative path worked");
 
       done();
     }
@@ -1139,24 +1131,24 @@ exports.testPageModCssDestroy = function
 
       assert.equal(
         style.width,
         "100px",
         "PageMod contentStyle worked"
       );
 
       pageMod.destroy();
+
       assert.equal(
         style.width,
         "200px",
         "PageMod contentStyle is removed after destroy"
       );
 
       done();
-
     }
   );
 };
 
 exports.testPageModCssAutomaticDestroy = function(assert, done) {
   let loader = Loader(module);
 
   let pageMod = loader.require("sdk/page-mod").PageMod({
@@ -1189,17 +1181,16 @@ exports.testPageModCssAutomaticDestroy =
       );
 
       tab.close(done);
     }
   });
 };
 
 exports.testPageModContentScriptFile = function(assert, done) {
-
   testPageMod(assert, done, "about:license", [{
       include: "about:*",
       contentScriptWhen: "start",
       contentScriptFile: "./test-contentScriptFile.js",
       onMessage: message => {
         assert.equal(message, "msg from contentScriptFile",
           "PageMod contentScriptFile with relative path worked");
       }
@@ -1372,35 +1363,36 @@ exports.testIFramePostMessage = function
       });
     }
   });
 };
 
 exports.testEvents = function(assert, done) {
   let content = "<script>\n new " + function DocumentScope() {
     window.addEventListener("ContentScriptEvent", function () {
-      window.receivedEvent = true;
+      window.document.body.setAttribute("receivedEvent", true);
     }, false);
   } + "\n</script>";
   let url = "data:text/html;charset=utf-8," + encodeURIComponent(content);
   testPageMod(assert, done, url, [{
       include: "data:*",
       contentScript: 'new ' + function WorkerScope() {
         let evt = document.createEvent("Event");
         evt.initEvent("ContentScriptEvent", true, true);
         document.body.dispatchEvent(evt);
       }
     }],
     function(win, done) {
       assert.ok(
-        win.receivedEvent,
+        win.document.body.getAttribute("receivedEvent"),
         "Content script sent an event and document received it"
       );
       done();
-    }
+    },
+    100
   );
 };
 
 exports["test page-mod on private tab"] = function (assert, done) {
   let fail = assert.fail.bind(assert);
 
   let privateUri = "data:text/html;charset=utf-8," +
                    "<iframe src=\"data:text/html;charset=utf-8,frame\" />";
@@ -1643,39 +1635,44 @@ exports.testDetachOnUnload = function(as
     url: TEST_URL,
     onOpen: t => tab = t
   })
 }
 
 exports.testConsole = function(assert, done) {
   let innerID;
   const TEST_URL = 'data:text/html;charset=utf-8,console';
-  const { loader } = LoaderWithHookedConsole(module, onMessage);
-  const { PageMod } = loader.require('sdk/page-mod');
-  const system = require("sdk/system/events");
 
   let seenMessage = false;
-  function onMessage(type, msg, msgID) {
+
+  system.on('console-api-log-event', onMessage);
+
+  function onMessage({ subject: { wrappedJSObject: msg }}) {
+    if (msg.arguments[0] !== "Hello from the page mod")
+      return;
     seenMessage = true;
-    innerID = msgID;
+    innerID = msg.innerID;
   }
 
   let mod = PageMod({
     include: TEST_URL,
     contentScriptWhen: "ready",
     contentScript: Isolate(function() {
       console.log("Hello from the page mod");
       self.port.emit("done");
     }),
     onAttach: function(worker) {
       worker.port.on("done", function() {
         let window = getTabContentWindow(tab);
         let id = getInnerId(window);
         assert.ok(seenMessage, "Should have seen the console message");
         assert.equal(innerID, id, "Should have seen the right inner ID");
+
+        system.off('console-api-log-event', onMessage);
+        mod.destroy();
         closeTab(tab);
         done();
       });
     },
   });
 
   let tab = openTab(getMostRecentBrowserWindow(), TEST_URL);
 }
@@ -1699,13 +1696,14 @@ exports.testSyntaxErrorInContentScript =
     }],
 
     function(win, done) {
       assert.ok(attached, "The worker was attached.");
       assert.notStrictEqual(hitError, null, "The syntax error was reported.");
       if (hitError)
         assert.equal(hitError.name, "SyntaxError", "The error thrown should be a SyntaxError");
       done();
-    }
+    },
+    300
   );
 };
 
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-panel.js
+++ b/addon-sdk/source/test/test-panel.js
@@ -670,17 +670,17 @@ exports["test console.log in Panel"] = f
   function onMessage(type, message) {
     assert.equal(type, 'log', 'console.log() works');
     assert.equal(message, text, 'console.log() works');
     panel.destroy();
     done();
   }
 };
 
-if (isWindowPBSupported) {
+/*if (isWindowPBSupported) {
   exports.testPanelDoesNotShowInPrivateWindowNoAnchor = function(assert, done) {
     let { loader } = LoaderWithHookedConsole(module, ignorePassingDOMNodeWarning);
     let { Panel } = loader.require("sdk/panel");
     let browserWindow = getMostRecentBrowserWindow();
 
     assert.equal(isPrivate(browserWindow), false, 'open window is not private');
 
     let panel = Panel({
@@ -778,17 +778,17 @@ if (isWindowPBSupported) {
       }).
       then(close).
       then(function() {
         assert.pass('private window was closed');
       }).
       then(testShowPanel.bind(null, assert, panel)).
       then(done, assert.fail.bind(assert));
   }
-}
+}*/
 
 function testShowPanel(assert, panel) {
   let { promise, resolve } = defer();
 
   assert.ok(!panel.isShowing, 'the panel is not showing [1]');
 
   panel.once('show', function() {
     assert.ok(panel.isShowing, 'the panel is showing');
--- a/addon-sdk/source/test/test-promise.js
+++ b/addon-sdk/source/test/test-promise.js
@@ -216,17 +216,17 @@ exports['test promised with promise args
 
   sum(11, deferred.promise).then(function(actual) {
     assert.equal(actual, 11 + 24, 'resolved as expected');
   }).catch(assert.fail).then(done);
 
   deferred.resolve(24);
 };
 
-exports['test promised error handleing'] = function(assert, done) {
+exports['test promised error handling'] = function(assert, done) {
   let expected = Error('boom');
   let f = promised(function() {
     throw expected;
   });
 
   f().then(function() {
     assert.fail('should reject');
   }, function(actual) {
@@ -288,16 +288,28 @@ exports['test promises are always async'
  */
 exports['test promised are not greedy'] = function(assert, done) {
   let runs = 0;
   promised(() => ++runs)()
     .catch(assert.fail).then(done);
   assert.equal(runs, 0, 'promised does not run task right away');
 };
 
+exports['test promised does not flatten arrays'] = function(assert, done) {
+  let p = promised(function(empty, one, two, nested) {
+    assert.equal(empty.length, 0, "first argument is empty");
+    assert.deepEqual(one, ['one'], "second has one");
+    assert.deepEqual(two, ['two', 'more'], "third has two more");
+    assert.deepEqual(nested, [[]], "forth is properly nested");
+    done();
+  });
+
+  p([], ['one'], ['two', 'more'], [[]]);
+};
+
 exports['test arrays should not flatten'] = function(assert, done) {
   let a = defer();
   let b = defer();
 
   let combine = promised(function(str, arr) {
     assert.equal(str, 'Hello', 'Array was not flattened');
     assert.deepEqual(arr, [ 'my', 'friend' ]);
   });
--- a/addon-sdk/source/test/test-self.js
+++ b/addon-sdk/source/test/test-self.js
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const xulApp = require("sdk/system/xul-app");
 const self = require("sdk/self");
-const { Loader, main, unload } = require("toolkit/loader");
+const { Loader, main, unload, override } = require("toolkit/loader");
+const { PlainTextConsole } = require("sdk/console/plain-text");
+const { Loader: CustomLoader } = require("sdk/test/loader");
 const loaderOptions = require("@loader/options");
 
 exports.testSelf = function(assert) {
   // Likewise, we can't assert anything about the full URL, because that
   // depends on self.id . We can only assert that it ends in the right
   // thing.
   var url = self.data.url("test-content-symbiont.js");
   assert.equal(typeof(url), "string", "self.data.url('x') returns string");
@@ -47,9 +49,31 @@ exports.testSelfHandlesLackingLoaderOpti
   assert.pass("No errors thrown when including sdk/self without loader options");
   assert.equal(self.isPrivateBrowsingSupported, false,
     "safely checks sdk/self.isPrivateBrowsingSupported");
   assert.equal(self.packed, false,
     "safely checks sdk/self.packed");
   unload(loader);
 };
 
+exports.testPreferencesBranch = function (assert) {
+  let options = override(loaderOptions, {
+    preferencesBranch: 'human-readable',
+  });
+  let loader = CustomLoader(module, { }, options);
+  let { preferencesBranch } = loader.require('sdk/self');
+  assert.equal(preferencesBranch, 'human-readable',
+    'preferencesBranch is human-readable');
+}
+
+exports.testInvalidPreferencesBranch = function (assert) {
+  let console = new PlainTextConsole(_ => void _);
+  let options = override(loaderOptions, {
+    preferencesBranch: 'invalid^branch*name',
+    id: 'simple@jetpack'
+  });
+  let loader = CustomLoader(module, { console }, options);
+  let { preferencesBranch } = loader.require('sdk/self');
+  assert.equal(preferencesBranch, 'simple@jetpack',
+    'invalid preferencesBranch value ignored');
+}
+
 require("sdk/test").run(exports);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-shared-require.js
@@ -0,0 +1,35 @@
+"use strict";
+
+const { Cu } = require("chrome");
+
+const requireURI = require.resolve("toolkit/require.js");
+
+
+
+const jsm = Cu.import(requireURI, {});
+
+exports.testRequire = assert => {
+  assert.equal(typeof(jsm.require), "function",
+               "require is a function");
+  assert.equal(typeof(jsm.require.resolve), "function",
+               "require.resolve is a function");
+
+  assert.equal(typeof(jsm.require("method/core")), "function",
+               "can import modules that aren't under sdk");
+
+  assert.equal(typeof(jsm.require("sdk/base64").encode), "function",
+               "can import module from sdk");
+};
+
+const required = require("toolkit/require")
+
+exports.testSameRequire = (assert) => {
+  assert.equal(jsm.require("method/core"),
+               required.require("method/core"),
+               "jsm and module return same instance");
+
+  assert.equal(jsm.require, required.require,
+               "require function is same in both contexts");
+};
+
+require("test").run(exports)
--- a/addon-sdk/source/test/test-tabs-common.js
+++ b/addon-sdk/source/test/test-tabs-common.js
@@ -45,39 +45,37 @@ exports.testTabCounts = function(assert,
     }
   });
 };
 
 exports.testTabRelativePath = function(assert, done) {
   const { merge } = require("sdk/util/object");
   const self = require("sdk/self");
 
-  let loader = Loader(module, null, null, {
-    modules: {
-      "sdk/self": merge({}, self, {
-        data: merge({}, self.data, fixtures)
-      })
-    }
-  });
+  const options = merge({}, require('@loader/options'),
+                        { prefixURI: require('./fixtures').url() });
+
+  let loader = Loader(module, null, options);
 
   let tabs = loader.require("sdk/tabs");
 
   tabs.open({
     url: "./test.html",
     onReady: (tab) => {
       assert.equal(tab.title, "foo",
         "tab opened a document with relative path");
 
       tab.attach({
         contentScriptFile: "./test-contentScriptFile.js",
         onMessage: (message) => {
           assert.equal(message, "msg from contentScriptFile",
             "Tab attach a contentScriptFile with relative path worked");
 
           tab.close(done);
+          loader.unload();
         }
       });
     }
   });
 };
 
 // TEST: tabs.activeTab getter
 exports.testActiveTab_getter = function(assert, done) {
--- a/addon-sdk/source/test/test-traits-core.js
+++ b/addon-sdk/source/test/test-traits-core.js
@@ -1,19 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 const ERR_CONFLICT = 'Remaining conflicting property: ',
       ERR_REQUIRED = 'Missing required property: ';
 
+const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
+                                ...Object.getOwnPropertySymbols(x)];
+
+
 function assertSametrait(assert, trait1, trait2) {
-  let names1 = Object.getOwnPropertyNames(trait1),
-      names2 = Object.getOwnPropertyNames(trait2);
+  let names1 = getOwnIdentifiers(trait1),
+      names2 = getOwnIdentifiers(trait2);
 
   assert.equal(
     names1.length,
     names2.length,
     'equal traits must have same amount of properties'
   );
 
   for (let i = 0; i < names1.length; i++) {
@@ -733,17 +737,17 @@ exports['test:create simple'] = function
     Object.prototype,
     Object.getPrototypeOf(o1),
     'o1 prototype'
   );
   assert.equal(1, o1.a, 'o1.a');
   assert.equal(1, o1.b(), 'o1.b()');
   assert.equal(
     2,
-    Object.getOwnPropertyNames(o1).length,
+    getOwnIdentifiers(o1).length,
     'Object.keys(o1).length === 2'
   );
 };
 
 exports['test:create with Array.prototype'] = function(assert) {
   let o2 = create(Array.prototype, trait({}));
   assert.equal(
     Array.prototype,
--- a/addon-sdk/source/test/test-ui-action-button.js
+++ b/addon-sdk/source/test/test-ui-action-button.js
@@ -11,21 +11,27 @@ module.metadata = {
 
 const { Cu } = require('chrome');
 const { Loader } = require('sdk/test/loader');
 const { data } = require('sdk/self');
 const { open, focus, close } = require('sdk/window/helpers');
 const { setTimeout } = require('sdk/timers');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { partial } = require('sdk/lang/functional');
+const { wait } = require('./event/helpers');
+const { gc } = require('sdk/test/memory');
 
 const openBrowserWindow = partial(open, null, {features: {toolbar: true}});
 const openPrivateBrowserWindow = partial(open, null,
   {features: {toolbar: true, private: true}});
 
+const badgeNodeFor = (node) =>
+  node.ownerDocument.getAnonymousElementByAttribute(node,
+                                      'class', 'toolbarbutton-badge');
+
 function getWidget(buttonId, window = getMostRecentBrowserWindow()) {
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   const { AREA_NAVBAR } = CustomizableUI;
 
   let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR).
     filter((id) => id.startsWith('action-button--') && id.endsWith(buttonId));
 
   if (widgets.length === 0)
@@ -102,16 +108,26 @@ exports['test basic constructor validati
     'throws on no valid icon given');
 
   // Test wrong icon: '../' is not allowed
   assert.throws(
     () => ActionButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}),
     /^The option "icon"/,
     'throws on no valid icon given');
 
+  assert.throws(
+    () => ActionButton({ id: 'my-button', label: 'button', icon: './i.png', badge: true}),
+    /^The option "badge"/,
+    'throws on no valid badge given');
+
+  assert.throws(
+    () => ActionButton({ id: 'my-button', label: 'button', icon: './i.png', badgeColor: true}),
+    /^The option "badgeColor"/,
+    'throws on no valid badge given');
+
   loader.unload();
 };
 
 exports['test button added'] = function(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   let button = ActionButton({
@@ -132,16 +148,19 @@ exports['test button added'] = function(
     'label is set');
 
   assert.equal(button.label, node.getAttribute('tooltiptext'),
     'tooltip is set');
 
   assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
     'icon is set');
 
+  assert.equal("", node.getAttribute('badge'),
+    'badge attribute is empty');
+
   loader.unload();
 }
 
 exports['test button added with resource URI'] = function(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   let button = ActionButton({
@@ -237,17 +256,17 @@ exports['test button removed on dispose'
 
 exports['test button global state updated'] = function(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   let button = ActionButton({
     id: 'my-button-4',
     label: 'my button',
-    icon: './icon.png'
+    icon: './icon.png',
   });
 
   // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
   // was removed or it's not in the UX build yet
 
   let { node, id: widgetId } = getWidget(button.id);
 
   // check read-only properties
@@ -278,16 +297,29 @@ exports['test button global state update
     'node image is updated');
 
   button.disabled = true;
   assert.equal(button.disabled, true,
     'disabled is updated');
   assert.equal(node.getAttribute('disabled'), 'true',
     'node disabled is updated');
 
+  button.badge = '+2';
+  button.badgeColor = 'blue';
+
+  assert.equal(button.badge, '+2',
+    'badge is updated');
+  assert.equal(node.getAttribute('bagde'), '',
+    'node badge is updated');
+
+  assert.equal(button.badgeColor, 'blue',
+    'badgeColor is updated');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
+    'badge color is updated');
+
   // TODO: test validation on update
 
   loader.unload();
 }
 
 exports['test button global state set and get with state method'] = function(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
@@ -307,308 +339,389 @@ exports['test button global state set an
     'icon is correct');
   assert.equal(state.disabled, false,
     'disabled is correct');
 
   // set the new button's state
   button.state(button, {
     label: 'New label',
     icon: './new-icon.png',
-    disabled: true
+    disabled: true,
+    badge: '+2',
+    badgeColor: 'blue'
   });
 
   assert.equal(button.label, 'New label',
     'label is updated');
   assert.equal(button.icon, './new-icon.png',
     'icon is updated');
   assert.equal(button.disabled, true,
     'disabled is updated');
+  assert.equal(button.badge, '+2',
+    'badge is updated');
+  assert.equal(button.badgeColor, 'blue',
+    'badgeColor is updated');
 
   loader.unload();
 }
 
-exports['test button global state updated on multiple windows'] = function(assert, done) {
+exports['test button global state updated on multiple windows'] = function*(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   let button = ActionButton({
     id: 'my-button-5',
     label: 'my button',
     icon: './icon.png'
   });
 
   let nodes = [getWidget(button.id).node];
 
-  openBrowserWindow().then(window => {
-    nodes.push(getWidget(button.id, window).node);
+  let window = yield openBrowserWindow();
+
+  nodes.push(getWidget(button.id, window).node);
 
-    button.label = 'New label';
-    button.icon = './new-icon.png';
-    button.disabled = true;
+  button.label = 'New label';
+  button.icon = './new-icon.png';
+  button.disabled = true;
+  button.badge = '+10';
+  button.badgeColor = 'green';
 
-    for (let node of nodes) {
-      assert.equal(node.getAttribute('label'), 'New label',
-        'node label is updated');
-      assert.equal(node.getAttribute('tooltiptext'), 'New label',
-        'node tooltip is updated');
+  for (let node of nodes) {
+    assert.equal(node.getAttribute('label'), 'New label',
+      'node label is updated');
+    assert.equal(node.getAttribute('tooltiptext'), 'New label',
+      'node tooltip is updated');
 
-      assert.equal(button.icon, './new-icon.png',
-        'icon is updated');
-      assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
-        'node image is updated');
+    assert.equal(button.icon, './new-icon.png',
+      'icon is updated');
+    assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
+      'node image is updated');
+
+    assert.equal(button.disabled, true,
+      'disabled is updated');
+    assert.equal(node.getAttribute('disabled'), 'true',
+      'node disabled is updated');
 
-      assert.equal(button.disabled, true,
-        'disabled is updated');
-      assert.equal(node.getAttribute('disabled'), 'true',
-        'node disabled is updated');
-    };
+    assert.equal(button.badge, '+10',
+      'badge is updated')
+    assert.equal(button.badgeColor, 'green',
+      'badgeColor is updated')
+    assert.equal(node.getAttribute('badge'), '+10',
+      'node badge is updated')
+    assert.equal(badgeNodeFor(node).style.backgroundColor, 'green',
+      'node badge color is updated')
+  };
 
-    return window;
-  }).
-  then(close).
-  then(loader.unload).
-  then(done, assert.fail);
+  yield close(window);
+
+  loader.unload();
 };
 
-exports['test button window state'] = function(assert, done) {
+exports['test button window state'] = function*(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
 
   let button = ActionButton({
     id: 'my-button-6',
     label: 'my button',
-    icon: './icon.png'
+    icon: './icon.png',
+    badge: '+1',
+    badgeColor: 'red'
   });
 
   let mainWindow = browserWindows.activeWindow;
   let nodes = [getWidget(button.id).node];
 
-  openBrowserWindow().then(focus).then(window => {
-    let node;
-    let state;
+  let window = yield openBrowserWindow().then(focus);
+
+  nodes.push(getWidget(button.id, window).node);
+
+  let { activeWindow } = browserWindows;
 
-    nodes.push(getWidget(button.id, window).node);
-
-    let { activeWindow } = browserWindows;
+  button.state(activeWindow, {
+    label: 'New label',
+    icon: './new-icon.png',
+    disabled: true,
+    badge: '+2',
+    badgeColor : 'green'
+  });
 
-    button.state(activeWindow, {
-      label: 'New label',
-      icon: './new-icon.png',
-      disabled: true
-    });
+  // check the states
 
-    // check the states
+  assert.equal(button.label, 'my button',
+    'global label unchanged');
+  assert.equal(button.icon, './icon.png',
+    'global icon unchanged');
+  assert.equal(button.disabled, false,
+    'global disabled unchanged');
+  assert.equal(button.badge, '+1',
+    'global badge unchanged');
+  assert.equal(button.badgeColor, 'red',
+    'global badgeColor unchanged');
+
+  let state = button.state(mainWindow);
 
-    assert.equal(button.label, 'my button',
-      'global label unchanged');
-    assert.equal(button.icon, './icon.png',
-      'global icon unchanged');
-    assert.equal(button.disabled, false,
-      'global disabled unchanged');
+  assert.equal(state.label, 'my button',
+    'previous window label unchanged');
+  assert.equal(state.icon, './icon.png',
+    'previous window icon unchanged');
+  assert.equal(state.disabled, false,
+    'previous window disabled unchanged');
+  assert.deepEqual(button.badge, '+1',
+    'previouswindow badge unchanged');
+  assert.deepEqual(button.badgeColor, 'red',
+    'previous window badgeColor unchanged');
 
-    state = button.state(mainWindow);
+  state = button.state(activeWindow);
 
-    assert.equal(state.label, 'my button',
-      'previous window label unchanged');
-    assert.equal(state.icon, './icon.png',
-      'previous window icon unchanged');
-    assert.equal(state.disabled, false,
-      'previous window disabled unchanged');
-
-    state = button.state(activeWindow);
+  assert.equal(state.label, 'New label',
+    'active window label updated');
+  assert.equal(state.icon, './new-icon.png',
+    'active window icon updated');
+  assert.equal(state.disabled, true,
+    'active disabled updated');
+  assert.equal(state.badge, '+2',
+    'active badge updated');
+  assert.equal(state.badgeColor, 'green',
+    'active badgeColor updated');
 
-    assert.equal(state.label, 'New label',
-      'active window label updated');
-    assert.equal(state.icon, './new-icon.png',
-      'active window icon updated');
-    assert.equal(state.disabled, true,
-      'active disabled updated');
+  // change the global state, only the windows without a state are affected
 
-    // change the global state, only the windows without a state are affected
-
-    button.label = 'A good label';
+  button.label = 'A good label';
+  button.badge = '+3';
 
-    assert.equal(button.label, 'A good label',
-      'global label updated');
-    assert.equal(button.state(mainWindow).label, 'A good label',
-      'previous window label updated');
-    assert.equal(button.state(activeWindow).label, 'New label',
-      'active window label unchanged');
-
-    // delete the window state will inherits the global state again
-
-    button.state(activeWindow, null);
+  assert.equal(button.label, 'A good label',
+    'global label updated');
+  assert.equal(button.state(mainWindow).label, 'A good label',
+    'previous window label updated');
+  assert.equal(button.state(activeWindow).label, 'New label',
+    'active window label unchanged');
+  assert.equal(button.state(activeWindow).badge, '+2',
+    'active badge unchanged');
+  assert.equal(button.state(activeWindow).badgeColor, 'green',
+    'active badgeColor unchanged');
+  assert.equal(button.state(mainWindow).badge, '+3',
+    'previous window badge updated');
+  assert.equal(button.state(mainWindow).badgeColor, 'red',
+    'previous window badgeColor unchanged');
 
-    assert.equal(button.state(activeWindow).label, 'A good label',
-      'active window label inherited');
+  // delete the window state will inherits the global state again
+
+  button.state(activeWindow, null);
+
+  state = button.state(activeWindow);
 
-    // check the nodes properties
-    node = nodes[0];
-    state = button.state(mainWindow);
+  assert.equal(state.label, 'A good label',
+    'active window label inherited');
+  assert.equal(state.badge, '+3',
+    'previous window badge inherited');
+  assert.equal(button.badgeColor, 'red',
+    'previous window badgeColor inherited');
 
-    assert.equal(node.getAttribute('label'), state.label,
-      'node label is correct');
-    assert.equal(node.getAttribute('tooltiptext'), state.label,
-      'node tooltip is correct');
+  // check the nodes properties
+  let node = nodes[0];
+
+  state = button.state(mainWindow);
 
-    assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-      'node image is correct');
-    assert.equal(node.hasAttribute('disabled'), state.disabled,
-      'disabled is correct');
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
 
-    node = nodes[1];
-    state = button.state(activeWindow);
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute("badge"), state.badge,
+    'badge is correct');
+
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  node = nodes[1];
+  state = button.state(activeWindow);
 
-    assert.equal(node.getAttribute('label'), state.label,
-      'node label is correct');
-    assert.equal(node.getAttribute('tooltiptext'), state.label,
-      'node tooltip is correct');
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
 
-    assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-      'node image is correct');
-    assert.equal(node.hasAttribute('disabled'), state.disabled,
-      'disabled is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute('badge'), state.badge,
+    'badge is correct');
 
-    return window;
-  }).
-  then(close).
-  then(loader.unload).
-  then(done, assert.fail);
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  yield close(window);
+
+  loader.unload();
 };
 
 
-exports['test button tab state'] = function(assert, done) {
+exports['test button tab state'] = function*(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
   let tabs = loader.require('sdk/tabs');
 
   let button = ActionButton({
     id: 'my-button-7',
     label: 'my button',
     icon: './icon.png'
   });
 
   let mainTab = tabs.activeTab;
   let node = getWidget(button.id).node;
 
-  tabs.open({
-    url: 'about:blank',
-    onActivate: function onActivate(tab) {
-      tab.removeListener('activate', onActivate);
-
-      let { activeWindow } = browserWindows;
-      // set window state
-      button.state(activeWindow, {
-        label: 'Window label',
-        icon: './window-icon.png'
-      });
+  tabs.open('about:blank');
 
-      // set previous active tab state
-      button.state(mainTab, {
-        label: 'Tab label',
-        icon: './tab-icon.png',
-      });
+  yield wait(tabs, 'ready');
 
-      // set current active tab state
-      button.state(tab, {
-        icon: './another-tab-icon.png',
-        disabled: true
-      });
-
-      // check the states
+  let tab = tabs.activeTab;
+  let { activeWindow } = browserWindows;
 
-      Cu.schedulePreciseGC(() => {
-        let state;
-
-        assert.equal(button.label, 'my button',
-          'global label unchanged');
-        assert.equal(button.icon, './icon.png',
-          'global icon unchanged');
-        assert.equal(button.disabled, false,
-          'global disabled unchanged');
-
-        state = button.state(mainTab);
-
-        assert.equal(state.label, 'Tab label',
-          'previous tab label updated');
-        assert.equal(state.icon, './tab-icon.png',
-          'previous tab icon updated');
-        assert.equal(state.disabled, false,
-          'previous tab disabled unchanged');
-
-        state = button.state(tab);
-
-        assert.equal(state.label, 'Window label',
-          'active tab inherited from window state');
-        assert.equal(state.icon, './another-tab-icon.png',
-          'active tab icon updated');
-        assert.equal(state.disabled, true,
-          'active disabled updated');
+  // set window state
+  button.state(activeWindow, {
+    label: 'Window label',
+    icon: './window-icon.png',
+    badge: 'win',
+    badgeColor: 'blue'
+  });
 
-        // change the global state
-        button.icon = './good-icon.png';
-
-        // delete the tab state
-        button.state(tab, null);
-
-        assert.equal(button.icon, './good-icon.png',
-          'global icon updated');
-        assert.equal(button.state(mainTab).icon, './tab-icon.png',
-          'previous tab icon unchanged');
-        assert.equal(button.state(tab).icon, './window-icon.png',
-          'tab icon inherited from window');
-
-        // delete the window state
-        button.state(activeWindow, null);
-
-        assert.equal(button.state(tab).icon, './good-icon.png',
-          'tab icon inherited from global');
-
-        // check the node properties
-
-        state = button.state(tabs.activeTab);
+  // set previous active tab state
+  button.state(mainTab, {
+    label: 'Tab label',
+    icon: './tab-icon.png',
+    badge: 'tab',
+    badgeColor: 'red'
+  });
 
-        assert.equal(node.getAttribute('label'), state.label,
-          'node label is correct');
-        assert.equal(node.getAttribute('tooltiptext'), state.label,
-          'node tooltip is correct');
-        assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-          'node image is correct');
-        assert.equal(node.hasAttribute('disabled'), state.disabled,
-          'disabled is correct');
-
-        tabs.once('activate', () => {
-          // This is made in order to avoid to check the node before it
-          // is updated, need a better check
-          setTimeout(() => {
-            let state = button.state(mainTab);
-
-            assert.equal(node.getAttribute('label'), state.label,
-              'node label is correct');
-            assert.equal(node.getAttribute('tooltiptext'), state.label,
-              'node tooltip is correct');
-            assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-              'node image is correct');
-            assert.equal(node.hasAttribute('disabled'), state.disabled,
-              'disabled is correct');
-
-            tab.close(() => {
-              loader.unload();
-              done();
-            });
-          }, 500);
-        });
-
-        mainTab.activate();
-      });
-    }
+  // set current active tab state
+  button.state(tab, {
+    icon: './another-tab-icon.png',
+    disabled: true,
+    badge: 't1',
+    badgeColor: 'green'
   });
 
+  // check the states, be sure they won't be gc'ed
+  yield gc();
+
+  assert.equal(button.label, 'my button',
+    'global label unchanged');
+  assert.equal(button.icon, './icon.png',
+    'global icon unchanged');
+  assert.equal(button.disabled, false,
+    'global disabled unchanged');
+  assert.equal(button.badge, undefined,
+    'global badge unchanged')
+
+  let state = button.state(mainTab);
+
+  assert.equal(state.label, 'Tab label',
+    'previous tab label updated');
+  assert.equal(state.icon, './tab-icon.png',
+    'previous tab icon updated');
+  assert.equal(state.disabled, false,
+    'previous tab disabled unchanged');
+  assert.equal(state.badge, 'tab',
+    'previous tab badge unchanged')
+  assert.equal(state.badgeColor, 'red',
+    'previous tab badgeColor unchanged')
+
+  state = button.state(tab);
+
+  assert.equal(state.label, 'Window label',
+    'active tab inherited from window state');
+  assert.equal(state.icon, './another-tab-icon.png',
+    'active tab icon updated');
+  assert.equal(state.disabled, true,
+    'active disabled updated');
+  assert.equal(state.badge, 't1',
+    'active badge updated');
+  assert.equal(state.badgeColor, 'green',
+    'active badgeColor updated');
+
+  // change the global state
+  button.icon = './good-icon.png';
+
+  // delete the tab state
+  button.state(tab, null);
+
+  assert.equal(button.icon, './good-icon.png',
+    'global icon updated');
+  assert.equal(button.state(mainTab).icon, './tab-icon.png',
+    'previous tab icon unchanged');
+  assert.equal(button.state(tab).icon, './window-icon.png',
+    'tab icon inherited from window');
+  assert.equal(button.state(mainTab).badge, 'tab',
+    'previous tab badge is unchaged');
+  assert.equal(button.state(tab).badge, 'win',
+    'tab badge is inherited from window');
+
+  // delete the window state
+  button.state(activeWindow, null);
+
+  state = button.state(tab);
+
+  assert.equal(state.icon, './good-icon.png',
+    'tab icon inherited from global');
+  assert.equal(state.badge, undefined,
+    'tab badge inherited from global');
+  assert.equal(state.badgeColor, undefined,
+    'tab badgeColor inherited from global');
+
+  // check the node properties
+  yield wait();
+
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'node disabled is correct');
+  assert.equal(node.getAttribute('badge'), '',
+    'badge text is correct');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, '',
+    'badge color is correct');
+
+  mainTab.activate();
+
+  yield wait(tabs, 'activate');
+
+  // This is made in order to avoid to check the node before it
+  // is updated, need a better check
+  yield wait();
+
+  state = button.state(mainTab);
+
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute('badge'), state.badge,
+    'badge text is correct');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  tab.close(loader.unload);
+
+  loader.unload();
 };
 
 exports['test button click'] = function*(assert) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
 
   let labels = [];
@@ -639,17 +752,16 @@ exports['test button click'] = function*
     'button click works');
 
   yield close(window);
 
   loader.unload();
 }
 
 exports['test button icon set'] = function(assert) {
-  let size;
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   // Test remote icon set
   assert.throws(
     () => ActionButton({
       id: 'my-button-10',
@@ -670,17 +782,17 @@ exports['test button icon set'] = functi
       '32': './icon32.png',
       '64': './icon64.png'
     }
   });
 
   let { node, id: widgetId } = getWidget(button.id);
   let { devicePixelRatio } = node.ownerDocument.defaultView;
 
-  size = 16 * devicePixelRatio;
+  let size = 16 * devicePixelRatio;
 
   assert.equal(node.getAttribute('image'), data.url(button.icon[size].substr(2)),
     'the icon is set properly in navbar');
 
   size = 32 * devicePixelRatio;
 
   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_PANEL);
 
@@ -692,17 +804,17 @@ exports['test button icon set'] = functi
   // button is moved manually from navbar to panel. I believe it has to do
   // with `addWidgetToArea` method, because even with a `timeout` the issue
   // persist.
   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
 
   loader.unload();
 }
 
-exports['test button icon se with only one option'] = function(assert) {
+exports['test button icon set with only one option'] = function(assert) {
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
 
   // Test remote icon set
   assert.throws(
     () => ActionButton({
       id: 'my-button-10',
@@ -755,16 +867,21 @@ exports['test button state validation'] 
 
   let state = button.state(button);
 
   assert.throws(
     () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
     /^The option "icon"/,
     'throws on remote icon given');
 
+  assert.throws(
+    () => button.state(button, { badge: true } ),
+    /^The option "badge"/,
+    'throws on wrong badge value given');
+
   loader.unload();
 };
 
 exports['test button are not in private windows'] = function(assert, done) {
   let loader = Loader(module);
   let { ActionButton } = loader.require('sdk/ui');
   let{ isPrivate } = loader.require('sdk/private-browsing');
   let { browserWindows } = loader.require('sdk/windows');
@@ -934,9 +1051,82 @@ exports['test button after destroy'] = f
   assert.throws(
     () => button.state(activeTab).label,
     /^The state cannot be set or get/,
     'window state label cannot se get after destroy');
 
   loader.unload();
 };
 
+exports['test button badge property'] = function(assert) {
+  let loader = Loader(module);
+  let { ActionButton } = loader.require('sdk/ui');
+
+  let button = ActionButton({
+    id: 'my-button-18',
+    label: 'my button',
+    icon: './icon.png',
+    badge: 123456
+  });
+
+  assert.equal(button.badge, 123456,
+    'badge is set');
+
+  assert.equal(button.badgeColor, undefined,
+    'badge color is not set');
+
+  let { node } = getWidget(button.id);
+  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let badgeNode = badgeNodeFor(node);
+
+  assert.equal('1234', node.getAttribute('badge'),
+    'badge text is displayed up to four characters');
+
+  assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(217, 0, 0)',
+    'badge color is the default one');
+
+  button.badge = '危機';
+
+  assert.equal(button.badge, '危機',
+    'badge is properly set');
+
+  assert.equal('危機', node.getAttribute('badge'),
+    'badge text is displayed');
+
+  button.badge = '🐢🐰🐹';
+
+  assert.equal(button.badge, '🐢🐰🐹',
+    'badge is properly set');
+
+  assert.equal('🐢🐰🐹', node.getAttribute('badge'),
+    'badge text is displayed');
+
+  loader.unload();
+}
+exports['test button badge color'] = function(assert) {
+  let loader = Loader(module);
+  let { ActionButton } = loader.require('sdk/ui');
+
+  let button = ActionButton({
+    id: 'my-button-19',
+    label: 'my button',
+    icon: './icon.png',
+    badge: '+1',
+    badgeColor: 'blue'
+  });
+
+  assert.equal(button.badgeColor, 'blue',
+    'badge color is set');
+
+  let { node } = getWidget(button.id);
+  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let badgeNode = badgeNodeFor(node);
+
+  assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
+    'badge color is displayed properly');
+  assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(0, 0, 255)',
+    'badge color overrides the default one');
+
+  loader.unload();
+}
+
+
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-ui-toggle-button.js
+++ b/addon-sdk/source/test/test-ui-toggle-button.js
@@ -11,21 +11,27 @@ module.metadata = {
 
 const { Cu } = require('chrome');
 const { Loader } = require('sdk/test/loader');
 const { data } = require('sdk/self');
 const { open, focus, close } = require('sdk/window/helpers');
 const { setTimeout } = require('sdk/timers');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { partial } = require('sdk/lang/functional');
+const { wait } = require('./event/helpers');
+const { gc } = require('sdk/test/memory');
 
 const openBrowserWindow = partial(open, null, {features: {toolbar: true}});
 const openPrivateBrowserWindow = partial(open, null,
   {features: {toolbar: true, private: true}});
 
+const badgeNodeFor = (node) =>
+  node.ownerDocument.getAnonymousElementByAttribute(node,
+                                      'class', 'toolbarbutton-badge');
+
 function getWidget(buttonId, window = getMostRecentBrowserWindow()) {
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   const { AREA_NAVBAR } = CustomizableUI;
 
   let widgets = CustomizableUI.getWidgetIdsInArea(AREA_NAVBAR).
     filter((id) => id.startsWith('toggle-button--') && id.endsWith(buttonId));
 
   if (widgets.length === 0)
@@ -102,56 +108,59 @@ exports['test basic constructor validati
     'throws on no valid icon given');
 
   // Test wrong icon: '../' is not allowed
   assert.throws(
     () => ToggleButton({ id: 'my-button', label: 'my button', icon: '../icon.png'}),
     /^The option "icon"/,
     'throws on no valid icon given');
 
-  // Test wrong checked
   assert.throws(
-    () => ToggleButton({
-      id: 'my-button', label: 'my button', icon: './icon.png', checked: 'yes'}),
-    /^The option "checked"/,
-    'throws on no valid checked value given');
+    () => ToggleButton({ id: 'my-button', label: 'button', icon: './i.png', badge: true}),
+    /^The option "badge"/,
+    'throws on no valid badge given');
+
+  assert.throws(
+    () => ToggleButton({ id: 'my-button', label: 'button', icon: './i.png', badgeColor: true}),
+    /^The option "badgeColor"/,
+    'throws on no valid badge given');
 
   loader.unload();
 };
 
 exports['test button added'] = function(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   let button = ToggleButton({
     id: 'my-button-1',
     label: 'my button',
     icon: './icon.png'
   });
 
   // check defaults
-  assert.equal(button.checked, false,
-    'checked is set to default `false` value');
-
   assert.equal(button.disabled, false,
     'disabled is set to default `false` value');
 
   let { node } = getWidget(button.id);
 
   assert.ok(!!node, 'The button is in the navbar');
 
   assert.equal(button.label, node.getAttribute('label'),
     'label is set');
 
   assert.equal(button.label, node.getAttribute('tooltiptext'),
     'tooltip is set');
 
   assert.equal(data.url(button.icon.substr(2)), node.getAttribute('image'),
     'icon is set');
 
+  assert.equal("", node.getAttribute('badge'),
+    'badge attribute is empty');
+
   loader.unload();
 }
 
 exports['test button added with resource URI'] = function(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   let button = ToggleButton({
@@ -247,17 +256,17 @@ exports['test button removed on dispose'
 
 exports['test button global state updated'] = function(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   let button = ToggleButton({
     id: 'my-button-4',
     label: 'my button',
-    icon: './icon.png'
+    icon: './icon.png',
   });
 
   // Tried to use `getWidgetIdsInArea` but seems undefined, not sure if it
   // was removed or it's not in the UX build yet
 
   let { node, id: widgetId } = getWidget(button.id);
 
   // check read-only properties
@@ -288,373 +297,468 @@ exports['test button global state update
     'node image is updated');
 
   button.disabled = true;
   assert.equal(button.disabled, true,
     'disabled is updated');
   assert.equal(node.getAttribute('disabled'), 'true',
     'node disabled is updated');
 
+  button.badge = '+2';
+  button.badgeColor = 'blue';
+
+  assert.equal(button.badge, '+2',
+    'badge is updated');
+  assert.equal(node.getAttribute('bagde'), '',
+    'node badge is updated');
+
+  assert.equal(button.badgeColor, 'blue',
+    'badgeColor is updated');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
+    'badge color is updated');
+
   // TODO: test validation on update
 
   loader.unload();
 }
 
 exports['test button global state set and get with state method'] = function(assert) {
-  let state;
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   let button = ToggleButton({
     id: 'my-button-16',
     label: 'my button',
     icon: './icon.png'
   });
 
   // read the button's state
-  state = button.state(button);
+  let state = button.state(button);
 
   assert.equal(state.label, 'my button',
     'label is correct');
   assert.equal(state.icon, './icon.png',
     'icon is correct');
   assert.equal(state.disabled, false,
     'disabled is correct');
 
   // set the new button's state
   button.state(button, {
     label: 'New label',
     icon: './new-icon.png',
-    disabled: true
+    disabled: true,
+    badge: '+2',
+    badgeColor: 'blue'
   });
 
   assert.equal(button.label, 'New label',
     'label is updated');
   assert.equal(button.icon, './new-icon.png',
     'icon is updated');
   assert.equal(button.disabled, true,
     'disabled is updated');
+  assert.equal(button.badge, '+2',
+    'badge is updated');
+  assert.equal(button.badgeColor, 'blue',
+    'badgeColor is updated');
 
   loader.unload();
-};
+}
 
-exports['test button global state updated on multiple windows'] = function(assert, done) {
+exports['test button global state updated on multiple windows'] = function*(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   let button = ToggleButton({
     id: 'my-button-5',
     label: 'my button',
     icon: './icon.png'
   });
 
   let nodes = [getWidget(button.id).node];
 
-  openBrowserWindow().then(window => {
-    nodes.push(getWidget(button.id, window).node);
+  let window = yield openBrowserWindow();
+
+  nodes.push(getWidget(button.id, window).node);
 
-    button.label = 'New label';
-    button.icon = './new-icon.png';
-    button.disabled = true;
+  button.label = 'New label';
+  button.icon = './new-icon.png';
+  button.disabled = true;
+  button.badge = '+10';
+  button.badgeColor = 'green';
 
-    for (let node of nodes) {
-      assert.equal(node.getAttribute('label'), 'New label',
-        'node label is updated');
-      assert.equal(node.getAttribute('tooltiptext'), 'New label',
-        'node tooltip is updated');
+  for (let node of nodes) {
+    assert.equal(node.getAttribute('label'), 'New label',
+      'node label is updated');
+    assert.equal(node.getAttribute('tooltiptext'), 'New label',
+      'node tooltip is updated');
 
-      assert.equal(button.icon, './new-icon.png',
-        'icon is updated');
-      assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
-        'node image is updated');
+    assert.equal(button.icon, './new-icon.png',
+      'icon is updated');
+    assert.equal(node.getAttribute('image'), data.url('new-icon.png'),
+      'node image is updated');
+
+    assert.equal(button.disabled, true,
+      'disabled is updated');
+    assert.equal(node.getAttribute('disabled'), 'true',
+      'node disabled is updated');
 
-      assert.equal(button.disabled, true,
-        'disabled is updated');
-      assert.equal(node.getAttribute('disabled'), 'true',
-        'node disabled is updated');
-    };
+    assert.equal(button.badge, '+10',
+      'badge is updated')
+    assert.equal(button.badgeColor, 'green',
+      'badgeColor is updated')
+    assert.equal(node.getAttribute('badge'), '+10',
+      'node badge is updated')
+    assert.equal(badgeNodeFor(node).style.backgroundColor, 'green',
+      'node badge color is updated')
+  };
 
-    return window;
-  }).
-  then(close).
-  then(loader.unload).
-  then(done, assert.fail);
+  yield close(window);
+
+  loader.unload();
 };
 
-exports['test button window state'] = function(assert, done) {
-  let state;
+exports['test button window state'] = function*(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
 
   let button = ToggleButton({
     id: 'my-button-6',
     label: 'my button',
-    icon: './icon.png'
+    icon: './icon.png',
+    badge: '+1',
+    badgeColor: 'red'
   });
 
   let mainWindow = browserWindows.activeWindow;
   let nodes = [getWidget(button.id).node];
 
-  openBrowserWindow().then(focus).then(window => {
-    nodes.push(getWidget(button.id, window).node);
+  let window = yield openBrowserWindow().then(focus);
+
+  nodes.push(getWidget(button.id, window).node);
+
+  let { activeWindow } = browserWindows;
 
-    let { activeWindow } = browserWindows;
+  button.state(activeWindow, {
+    label: 'New label',
+    icon: './new-icon.png',
+    disabled: true,
+    badge: '+2',
+    badgeColor : 'green'
+  });
 
-    button.state(activeWindow, {
-      label: 'New label',
-      icon: './new-icon.png',
-      disabled: true
-    });
+  // check the states
 
-    // check the states
+  assert.equal(button.label, 'my button',
+    'global label unchanged');
+  assert.equal(button.icon, './icon.png',
+    'global icon unchanged');
+  assert.equal(button.disabled, false,
+    'global disabled unchanged');
+  assert.equal(button.badge, '+1',
+    'global badge unchanged');
+  assert.equal(button.badgeColor, 'red',
+    'global badgeColor unchanged');
 
-    assert.equal(button.label, 'my button',
-      'global label unchanged');
-    assert.equal(button.icon, './icon.png',
-      'global icon unchanged');
-    assert.equal(button.disabled, false,
-      'global disabled unchanged');
+  let state = button.state(mainWindow);
 
-    state = button.state(mainWindow);
+  assert.equal(state.label, 'my button',
+    'previous window label unchanged');
+  assert.equal(state.icon, './icon.png',
+    'previous window icon unchanged');
+  assert.equal(state.disabled, false,
+    'previous window disabled unchanged');
+  assert.deepEqual(button.badge, '+1',
+    'previouswindow badge unchanged');
+  assert.deepEqual(button.badgeColor, 'red',
+    'previous window badgeColor unchanged');
 
-    assert.equal(state.label, 'my button',
-      'previous window label unchanged');
-    assert.equal(state.icon, './icon.png',
-      'previous window icon unchanged');
-    assert.equal(state.disabled, false,
-      'previous window disabled unchanged');
-
-    state = button.state(activeWindow);
+  state = button.state(activeWindow);
 
-    assert.equal(state.label, 'New label',
-      'active window label updated');
-    assert.equal(state.icon, './new-icon.png',
-      'active window icon updated');
-    assert.equal(state.disabled, true,
-      'active disabled updated');
+  assert.equal(state.label, 'New label',
+    'active window label updated');
+  assert.equal(state.icon, './new-icon.png',
+    'active window icon updated');
+  assert.equal(state.disabled, true,
+    'active disabled updated');
+  assert.equal(state.badge, '+2',
+    'active badge updated');
+  assert.equal(state.badgeColor, 'green',
+    'active badgeColor updated');
 
-    // change the global state, only the windows without a state are affected
+  // change the global state, only the windows without a state are affected
 
-    button.label = 'A good label';
+  button.label = 'A good label';
+  button.badge = '+3';
 
-    assert.equal(button.label, 'A good label',
-      'global label updated');
-    assert.equal(button.state(mainWindow).label, 'A good label',
-      'previous window label updated');
-    assert.equal(button.state(activeWindow).label, 'New label',
-      'active window label unchanged');
-
-    // delete the window state will inherits the global state again
-
-    button.state(activeWindow, null);
+  assert.equal(button.label, 'A good label',
+    'global label updated');
+  assert.equal(button.state(mainWindow).label, 'A good label',
+    'previous window label updated');
+  assert.equal(button.state(activeWindow).label, 'New label',
+    'active window label unchanged');
+  assert.equal(button.state(activeWindow).badge, '+2',
+    'active badge unchanged');
+  assert.equal(button.state(activeWindow).badgeColor, 'green',
+    'active badgeColor unchanged');
+  assert.equal(button.state(mainWindow).badge, '+3',
+    'previous window badge updated');
+  assert.equal(button.state(mainWindow).badgeColor, 'red',
+    'previous window badgeColor unchanged');
 
-    assert.equal(button.state(activeWindow).label, 'A good label',
-      'active window label inherited');
+  // delete the window state will inherits the global state again
+
+  button.state(activeWindow, null);
+
+  state = button.state(activeWindow);
 
-    // check the nodes properties
-    let node = nodes[0];
-    state = button.state(mainWindow);
+  assert.equal(state.label, 'A good label',
+    'active window label inherited');
+  assert.equal(state.badge, '+3',
+    'previous window badge inherited');
+  assert.equal(button.badgeColor, 'red',
+    'previous window badgeColor inherited');
 
-    assert.equal(node.getAttribute('label'), state.label,
-      'node label is correct');
-    assert.equal(node.getAttribute('tooltiptext'), state.label,
-      'node tooltip is correct');
+  // check the nodes properties
+  let node = nodes[0];
+
+  state = button.state(mainWindow);
 
-    assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-      'node image is correct');
-    assert.equal(node.hasAttribute('disabled'), state.disabled,
-      'disabled is correct');
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
 
-    node = nodes[1];
-    state = button.state(activeWindow);
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute("badge"), state.badge,
+    'badge is correct');
+
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  node = nodes[1];
+  state = button.state(activeWindow);
 
-    assert.equal(node.getAttribute('label'), state.label,
-      'node label is correct');
-    assert.equal(node.getAttribute('tooltiptext'), state.label,
-      'node tooltip is correct');
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
 
-    assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-      'node image is correct');
-    assert.equal(node.hasAttribute('disabled'), state.disabled,
-      'disabled is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute('badge'), state.badge,
+    'badge is correct');
 
-    return window;
-  }).
-  then(close).
-  then(loader.unload).
-  then(done, assert.fail);
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  yield close(window);
+
+  loader.unload();
 };
 
 
-exports['test button tab state'] = function(assert, done) {
+exports['test button tab state'] = function*(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
   let tabs = loader.require('sdk/tabs');
 
   let button = ToggleButton({
     id: 'my-button-7',
     label: 'my button',
     icon: './icon.png'
   });
 
   let mainTab = tabs.activeTab;
   let node = getWidget(button.id).node;
 
-  tabs.open({
-    url: 'about:blank',
-    onActivate: function onActivate(tab) {
-      tab.removeListener('activate', onActivate);
-
-      let { activeWindow } = browserWindows;
-      // set window state
-      button.state(activeWindow, {
-        label: 'Window label',
-        icon: './window-icon.png'
-      });
+  tabs.open('about:blank');
 
-      // set previous active tab state
-      button.state(mainTab, {
-        label: 'Tab label',
-        icon: './tab-icon.png',
-      });
+  yield wait(tabs, 'ready');
 
-      // set current active tab state
-      button.state(tab, {
-        icon: './another-tab-icon.png',
-        disabled: true
-      });
-
-      // check the states
+  let tab = tabs.activeTab;
+  let { activeWindow } = browserWindows;
 
-      Cu.schedulePreciseGC(() => {
-        let state;
-
-        assert.equal(button.label, 'my button',
-          'global label unchanged');
-        assert.equal(button.icon, './icon.png',
-          'global icon unchanged');
-        assert.equal(button.disabled, false,
-          'global disabled unchanged');
-
-        state = button.state(mainTab);
-
-        assert.equal(state.label, 'Tab label',
-          'previous tab label updated');
-        assert.equal(state.icon, './tab-icon.png',
-          'previous tab icon updated');
-        assert.equal(state.disabled, false,
-          'previous tab disabled unchanged');
-
-        state = button.state(tab);
-
-        assert.equal(state.label, 'Window label',
-          'active tab inherited from window state');
-        assert.equal(state.icon, './another-tab-icon.png',
-          'active tab icon updated');
-        assert.equal(state.disabled, true,
-          'active disabled updated');
+  // set window state
+  button.state(activeWindow, {
+    label: 'Window label',
+    icon: './window-icon.png',
+    badge: 'win',
+    badgeColor: 'blue'
+  });
 
-        // change the global state
-        button.icon = './good-icon.png';
-
-        // delete the tab state
-        button.state(tab, null);
-
-        assert.equal(button.icon, './good-icon.png',
-          'global icon updated');
-        assert.equal(button.state(mainTab).icon, './tab-icon.png',
-          'previous tab icon unchanged');
-        assert.equal(button.state(tab).icon, './window-icon.png',
-          'tab icon inherited from window');
-
-        // delete the window state
-        button.state(activeWindow, null);
-
-        assert.equal(button.state(tab).icon, './good-icon.png',
-          'tab icon inherited from global');
-
-        // check the node properties
-
-        state = button.state(tabs.activeTab);
+  // set previous active tab state
+  button.state(mainTab, {
+    label: 'Tab label',
+    icon: './tab-icon.png',
+    badge: 'tab',
+    badgeColor: 'red'
+  });
 
-        assert.equal(node.getAttribute('label'), state.label,
-          'node label is correct');
-        assert.equal(node.getAttribute('tooltiptext'), state.label,
-          'node tooltip is correct');
-        assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-          'node image is correct');
-        assert.equal(node.hasAttribute('disabled'), state.disabled,
-          'disabled is correct');
-
-        tabs.once('activate', () => {
-          // This is made in order to avoid to check the node before it
-          // is updated, need a better check
-          setTimeout(() => {
-            let state = button.state(mainTab);
-
-            assert.equal(node.getAttribute('label'), state.label,
-              'node label is correct');
-            assert.equal(node.getAttribute('tooltiptext'), state.label,
-              'node tooltip is correct');
-            assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
-              'node image is correct');
-            assert.equal(node.hasAttribute('disabled'), state.disabled,
-              'disabled is correct');
-
-            tab.close(() => {
-              loader.unload();
-              done();
-            });
-          }, 500);
-        });
-
-        mainTab.activate();
-      });
-    }
+  // set current active tab state
+  button.state(tab, {
+    icon: './another-tab-icon.png',
+    disabled: true,
+    badge: 't1',
+    badgeColor: 'green'
   });
 
+  // check the states, be sure they won't be gc'ed
+  yield gc();
+
+  assert.equal(button.label, 'my button',
+    'global label unchanged');
+  assert.equal(button.icon, './icon.png',
+    'global icon unchanged');
+  assert.equal(button.disabled, false,
+    'global disabled unchanged');
+  assert.equal(button.badge, undefined,
+    'global badge unchanged')
+
+  let state = button.state(mainTab);
+
+  assert.equal(state.label, 'Tab label',
+    'previous tab label updated');
+  assert.equal(state.icon, './tab-icon.png',
+    'previous tab icon updated');
+  assert.equal(state.disabled, false,
+    'previous tab disabled unchanged');
+  assert.equal(state.badge, 'tab',
+    'previous tab badge unchanged')
+  assert.equal(state.badgeColor, 'red',
+    'previous tab badgeColor unchanged')
+
+  state = button.state(tab);
+
+  assert.equal(state.label, 'Window label',
+    'active tab inherited from window state');
+  assert.equal(state.icon, './another-tab-icon.png',
+    'active tab icon updated');
+  assert.equal(state.disabled, true,
+    'active disabled updated');
+  assert.equal(state.badge, 't1',
+    'active badge updated');
+  assert.equal(state.badgeColor, 'green',
+    'active badgeColor updated');
+
+  // change the global state
+  button.icon = './good-icon.png';
+
+  // delete the tab state
+  button.state(tab, null);
+
+  assert.equal(button.icon, './good-icon.png',
+    'global icon updated');
+  assert.equal(button.state(mainTab).icon, './tab-icon.png',
+    'previous tab icon unchanged');
+  assert.equal(button.state(tab).icon, './window-icon.png',
+    'tab icon inherited from window');
+  assert.equal(button.state(mainTab).badge, 'tab',
+    'previous tab badge is unchaged');
+  assert.equal(button.state(tab).badge, 'win',
+    'tab badge is inherited from window');
+
+  // delete the window state
+  button.state(activeWindow, null);
+
+  state = button.state(tab);
+
+  assert.equal(state.icon, './good-icon.png',
+    'tab icon inherited from global');
+  assert.equal(state.badge, undefined,
+    'tab badge inherited from global');
+  assert.equal(state.badgeColor, undefined,
+    'tab badgeColor inherited from global');
+
+  // check the node properties
+  yield wait();
+
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'node disabled is correct');
+  assert.equal(node.getAttribute('badge'), '',
+    'badge text is correct');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, '',
+    'badge color is correct');
+
+  mainTab.activate();
+
+  yield wait(tabs, 'activate');
+
+  // This is made in order to avoid to check the node before it
+  // is updated, need a better check
+  yield wait();
+
+  state = button.state(mainTab);
+
+  assert.equal(node.getAttribute('label'), state.label,
+    'node label is correct');
+  assert.equal(node.getAttribute('tooltiptext'), state.label,
+    'node tooltip is correct');
+  assert.equal(node.getAttribute('image'), data.url(state.icon.substr(2)),
+    'node image is correct');
+  assert.equal(node.hasAttribute('disabled'), state.disabled,
+    'disabled is correct');
+  assert.equal(node.getAttribute('badge'), state.badge,
+    'badge text is correct');
+  assert.equal(badgeNodeFor(node).style.backgroundColor, state.badgeColor,
+    'badge color is correct');
+
+  tab.close(loader.unload);
+
+  loader.unload();
 };
 
-exports['test button click'] = function(assert, done) {
+exports['test button click'] = function*(assert) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
 
   let labels = [];
 
   let button = ToggleButton({
     id: 'my-button-8',
     label: 'my button',
     icon: './icon.png',
     onClick: ({label}) => labels.push(label)
   });
 
   let mainWindow = browserWindows.activeWindow;
   let chromeWindow = getMostRecentBrowserWindow();
 
-  openBrowserWindow().then(focus).then(window => {
-    button.state(mainWindow, { label: 'nothing' });
-    button.state(mainWindow.tabs.activeTab, { label: 'foo'})
-    button.state(browserWindows.activeWindow, { label: 'bar' });
+  let window = yield openBrowserWindow().then(focus);
 
-    button.click();
+  button.state(mainWindow, { label: 'nothing' });
+  button.state(mainWindow.tabs.activeTab, { label: 'foo'})
+  button.state(browserWindows.activeWindow, { label: 'bar' });
+
+  button.click();
 
-    focus(chromeWindow).then(() => {
-      button.click();
+  yield focus(chromeWindow);
 
-      assert.deepEqual(labels, ['bar', 'foo'],
-        'button click works');
+  button.click();
 
-      close(window).
-        then(loader.unload).
-        then(done, assert.fail);
-    });
-  }).then(null, assert.fail);
+  assert.deepEqual(labels, ['bar', 'foo'],
+    'button click works');
+
+  yield close(window);
+
+  loader.unload();
 }
 
 exports['test button icon set'] = function(assert) {
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   // Test remote icon set
@@ -700,17 +804,17 @@ exports['test button icon set'] = functi
   // button is moved manually from navbar to panel. I believe it has to do
   // with `addWidgetToArea` method, because even with a `timeout` the issue
   // persist.
   CustomizableUI.addWidgetToArea(widgetId, CustomizableUI.AREA_NAVBAR);
 
   loader.unload();
 }
 
-exports['test button icon se with only one option'] = function(assert) {
+exports['test button icon set with only one option'] = function(assert) {
   const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
 
   // Test remote icon set
   assert.throws(
     () => ToggleButton({
       id: 'my-button-10',
@@ -763,16 +867,21 @@ exports['test button state validation'] 
 
   let state = button.state(button);
 
   assert.throws(
     () => button.state(button, { icon: 'http://www.mozilla.org/favicon.ico' }),
     /^The option "icon"/,
     'throws on remote icon given');
 
+  assert.throws(
+    () => button.state(button, { badge: true } ),
+    /^The option "badge"/,
+    'throws on wrong badge value given');
+
   loader.unload();
 };
 
 exports['test button are not in private windows'] = function(assert, done) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
   let{ isPrivate } = loader.require('sdk/private-browsing');
   let { browserWindows } = loader.require('sdk/windows');
@@ -942,16 +1051,89 @@ exports['test button after destroy'] = f
   assert.throws(
     () => button.state(activeTab).label,
     /^The state cannot be set or get/,
     'window state label cannot se get after destroy');
 
   loader.unload();
 };
 
+exports['test button badge property'] = function(assert) {
+  let loader = Loader(module);
+  let { ToggleButton } = loader.require('sdk/ui');
+
+  let button = ToggleButton({
+    id: 'my-button-18',
+    label: 'my button',
+    icon: './icon.png',
+    badge: 123456
+  });
+
+  assert.equal(button.badge, 123456,
+    'badge is set');
+
+  assert.equal(button.badgeColor, undefined,
+    'badge color is not set');
+
+  let { node } = getWidget(button.id);
+  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let badgeNode = badgeNodeFor(node);
+
+  assert.equal('1234', node.getAttribute('badge'),
+    'badge text is displayed up to four characters');
+
+  assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(217, 0, 0)',
+    'badge color is the default one');
+
+  button.badge = '危機';
+
+  assert.equal(button.badge, '危機',
+    'badge is properly set');
+
+  assert.equal('危機', node.getAttribute('badge'),
+    'badge text is displayed');
+
+  button.badge = '🐢🐰🐹';
+
+  assert.equal(button.badge, '🐢🐰🐹',
+    'badge is properly set');
+
+  assert.equal('🐢🐰🐹', node.getAttribute('badge'),
+    'badge text is displayed');
+
+  loader.unload();
+}
+exports['test button badge color'] = function(assert) {
+  let loader = Loader(module);
+  let { ToggleButton } = loader.require('sdk/ui');
+
+  let button = ToggleButton({
+    id: 'my-button-19',
+    label: 'my button',
+    icon: './icon.png',
+    badge: '+1',
+    badgeColor: 'blue'
+  });
+
+  assert.equal(button.badgeColor, 'blue',
+    'badge color is set');
+
+  let { node } = getWidget(button.id);
+  let { getComputedStyle } = node.ownerDocument.defaultView;
+  let badgeNode = badgeNodeFor(node);
+
+  assert.equal(badgeNodeFor(node).style.backgroundColor, 'blue',
+    'badge color is displayed properly');
+  assert.equal(getComputedStyle(badgeNode).backgroundColor, 'rgb(0, 0, 255)',
+    'badge color overrides the default one');
+
+  loader.unload();
+}
+
+// toggle button only
 exports['test button checked'] = function(assert, done) {
   let loader = Loader(module);
   let { ToggleButton } = loader.require('sdk/ui');
   let { browserWindows } = loader.require('sdk/windows');
 
   let events = [];
 
   let button = ToggleButton({
--- a/addon-sdk/source/test/traits/assert.js
+++ b/addon-sdk/source/test/traits/assert.js
@@ -1,16 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var BaseAssert = require("sdk/test/assert").Assert;
 
+const getOwnIdentifiers = x => [...Object.getOwnPropertyNames(x),
+                                ...Object.getOwnPropertySymbols(x)];
+
 /**
  * Whether or not given property descriptors are equivalent. They are
  * equivalent either if both are marked as "conflict" or "required" property
  * or if all the properties of descriptors are equal.
  * @param {Object} actual
  * @param {Object} expected
  */
 function equivalentDescriptors(actual, expected) {
@@ -47,33 +50,33 @@ function equivalentSets(source, target) 
 
 /**
  * Finds name of the property from `source` property descriptor map, that
  * is not equivalent of the name named property in the `target` property
  * descriptor map. If not found `null` is returned instead.
  */
 function findNonEquivalentPropertyName(source, target) {
   var value = null;
-  Object.getOwnPropertyNames(source).some(function(key) {
+  getOwnIdentifiers(source).some(function(key) {
     var areEquivalent = false;
     if (!equivalentDescriptors(source[key], target[key])) {
       value = key;
       areEquivalent = true;
     }
     return areEquivalent;
   });
   return value;
 }
 
 var AssertDescriptor = {
   equalTraits: {
     value: function equivalentTraits(actual, expected, message) {
       var difference;
-      var actualKeys = Object.getOwnPropertyNames(actual);
-      var expectedKeys = Object.getOwnPropertyNames(expected);
+      var actualKeys = getOwnIdentifiers(actual);
+      var expectedKeys = getOwnIdentifiers(expected);
 
       if (equivalentSets(actualKeys, expectedKeys)) {
         this.fail({
           operator: "equalTraits",
           message: "Traits define different properties",
           actual: actualKeys.sort().join(","),
           expected: expectedKeys.sort().join(","),
         });
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "b07dbb49ec85f2f3e89fa49ae7623ad3341ef956", 
+    "revision": "ffd04882bee583854df71365f243fa9f287803a2", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7918024c737c4570cacd784f267e28737ae05dea"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="068b9711277b06c7d633517f9e1fcb5624bb39b3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ad276e6d4ec40ae2ac214e42c6c81cfc8cd86c3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -3,23 +3,21 @@
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 // the "exported" symbols
 let SocialUI,
     SocialFlyout,
     SocialMarks,
     SocialShare,
     SocialSidebar,
-    SocialStatus;
+    SocialStatus,
+    SocialActivationListener;
 
 (function() {
 
-XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame",
-  "resource:///modules/SharedFrame.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame",
   "resource:///modules/PanelFrame.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() {
   let tmp = {};
   Cu.import("resource:///modules/Social.jsm", tmp);
   return tmp.OpenGraphBuilder;
 });
@@ -68,18 +66,18 @@ SocialUI = {
     Services.obs.addObserver(this, "social:frameworker-error", false);
     Services.obs.addObserver(this, "social:providers-changed", false);
     Services.obs.addObserver(this, "social:provider-reload", false);
     Services.obs.addObserver(this, "social:provider-enabled", false);
     Services.obs.addObserver(this, "social:provider-disabled", false);
 
     Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
 
-    gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler.bind(this), true, true);
     CustomizableUI.addListener(this);
+    SocialActivationListener.init();
 
     // menupopups that list social providers. we only populate them when shown,
     // and if it has not been done already.
     document.getElementById("viewSidebarMenu").addEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
     document.getElementById("social-statusarea-popup").addEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
 
     Social.init().then((update) => {
       if (update)
@@ -103,16 +101,17 @@ SocialUI = {
     Services.obs.removeObserver(this, "social:frameworker-error");
     Services.obs.removeObserver(this, "social:providers-changed");
     Services.obs.removeObserver(this, "social:provider-reload");
     Services.obs.removeObserver(this, "social:provider-enabled");
     Services.obs.removeObserver(this, "social:provider-disabled");
 
     Services.prefs.removeObserver("social.toast-notifications.enabled", this);
     CustomizableUI.removeListener(this);
+    SocialActivationListener.uninit();
 
     document.getElementById("viewSidebarMenu").removeEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
     document.getElementById("social-statusarea-popup").removeEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
 
     this._initialized = false;
   },
 
   observe: function SocialUI_observe(subject, topic, data) {
@@ -169,105 +168,16 @@ SocialUI = {
   _providersChanged: function() {
     SocialSidebar.clearProviderMenus();
     SocialSidebar.update();
     SocialShare.populateProviderMenu();
     SocialStatus.populateToolbarPalette();
     SocialMarks.populateToolbarPalette();
   },
 
-  // This handles "ActivateSocialFeature" events fired against content documents
-  // in this window.  If this activation happens from within Firefox, such as
-  // about:home or the share panel, we bypass the enable prompt. Any website
-  // activation, such as from the activations directory or a providers website
-  // will still get the prompt.
-  _activationEventHandler: function SocialUI_activationHandler(e, options={}) {
-    let targetDoc;
-    let node;
-    if (e.target instanceof HTMLDocument) {
-      // version 0 support
-      targetDoc = e.target;
-      node = targetDoc.documentElement
-    } else {
-      targetDoc = e.target.ownerDocument;
-      node = e.target;
-    }
-    if (!(targetDoc instanceof HTMLDocument))
-      return;
-
-    // The share panel iframe will not match "content" so it passes a bypass
-    // flag
-    if (!options.bypassContentCheck && targetDoc.defaultView != content)
-      return;
-
-    // If we are in PB mode, we silently do nothing (bug 829404 exists to
-    // do something sensible here...)
-    if (PrivateBrowsingUtils.isWindowPrivate(window))
-      return;
-
-    // If the last event was received < 1s ago, ignore this one
-    let now = Date.now();
-    if (now - Social.lastEventReceived < 1000)
-      return;
-    Social.lastEventReceived = now;
-
-    // We only want to activate if it is as a result of user input.
-    let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-    if (!dwu.isHandlingUserInput) {
-      Cu.reportError("attempt to activate provider without user input from " + targetDoc.nodePrincipal.origin);
-      return;
-    }
-
-    let data = node.getAttribute("data-service");
-    if (data) {
-      try {
-        data = JSON.parse(data);
-      } catch(e) {
-        Cu.reportError("Social Service manifest parse error: "+e);
-        return;
-      }
-    }
-    Social.installProvider(targetDoc, data, function(manifest) {
-      Social.activateFromOrigin(manifest.origin, function(provider) {
-        if (provider.sidebarURL) {
-          SocialSidebar.show(provider.origin);
-        }
-        if (provider.shareURL) {
-          // Ensure that the share button is somewhere usable.
-          // SocialShare.shareButton may return null if it is in the menu-panel
-          // and has never been visible, so we check the widget directly. If
-          // there is no area for the widget we move it into the toolbar.
-          let widget = CustomizableUI.getWidget("social-share-button");
-          if (!widget.areaType) {
-            CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
-            // ensure correct state
-            SocialUI.onCustomizeEnd(window);
-          }
-
-          // make this new provider the selected provider. If the panel hasn't
-          // been opened, we need to make the frame first.
-          SocialShare._createFrame();
-          SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
-          SocialShare.iframe.setAttribute('origin', provider.origin);
-          // get the right button selected
-          SocialShare.populateProviderMenu();
-          if (SocialShare.panel.state == "open") {
-            SocialShare.sharePage(provider.origin);
-          }
-        }
-        if (provider.postActivationURL) {
-          // if activated from an open share panel, we load the landing page in
-          // a background tab
-          gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"});
-        }
-      });
-    }, options);
-  },
-
   showLearnMore: function() {
     let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "social-api";
     openUILinkIn(url, "tab");
   },
 
   closeSocialPanelForLinkTraversal: function (target, linkNode) {
     // No need to close the panel if this traversal was not retargeted
     if (target == "" || target == "_self")
@@ -351,16 +261,78 @@ SocialUI = {
     goSetCommandEnabled("Social:PageShareOrMark", this.canShareOrMarkPage(gBrowser.currentURI));
     if (!SocialUI.enabled)
       return;
     // larger update that may change button icons
     SocialMarks.update();
   }
 }
 
+// message manager handlers
+SocialActivationListener = {
+  init: function() {
+    messageManager.addMessageListener("Social:Activation", this);
+  },
+  uninit: function() {
+    messageManager.removeMessageListener("Social:Activation", this);
+  },
+  receiveMessage: function(aMessage) {
+    let data = aMessage.json;
+    let browser = aMessage.target;
+    data.window = window;
+    // if the source if the message is the share panel, we do a one-click
+    // installation. The source of activations is controlled by the
+    // social.directories preference
+    let options;
+    if (browser == SocialShare.iframe && Services.prefs.getBoolPref("social.share.activationPanelEnabled")) {
+      options = { bypassContentCheck: true, bypassInstallPanel: true };
+    }
+
+    // If we are in PB mode, we silently do nothing (bug 829404 exists to
+    // do something sensible here...)
+    if (PrivateBrowsingUtils.isWindowPrivate(window))
+      return;
+    Social.installProvider(data, function(manifest) {
+      Social.activateFromOrigin(manifest.origin, function(provider) {
+        if (provider.sidebarURL) {
+          SocialSidebar.show(provider.origin);
+        }
+        if (provider.shareURL) {
+          // Ensure that the share button is somewhere usable.
+          // SocialShare.shareButton may return null if it is in the menu-panel
+          // and has never been visible, so we check the widget directly. If
+          // there is no area for the widget we move it into the toolbar.
+          let widget = CustomizableUI.getWidget("social-share-button");
+          if (!widget.areaType) {
+            CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
+            // ensure correct state
+            SocialUI.onCustomizeEnd(window);
+          }
+
+          // make this new provider the selected provider. If the panel hasn't
+          // been opened, we need to make the frame first.
+          SocialShare._createFrame();
+          SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
+          SocialShare.iframe.setAttribute('origin', provider.origin);
+          // get the right button selected
+          SocialShare.populateProviderMenu();
+          if (SocialShare.panel.state == "open") {
+            SocialShare.sharePage(provider.origin);
+          }
+        }
+        if (provider.postActivationURL) {
+          // if activated from an open share panel, we load the landing page in
+          // a background tab
+          gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"});
+        }
+      });
+    }, options);
+  }
+}
+
 SocialFlyout = {
   get panel() {
     return document.getElementById("social-flyout-panel");
   },
 
   get iframe() {
     if (!this.panel.firstChild)
       this._createFrame();
@@ -512,25 +484,18 @@ SocialShare = {
   get iframe() {
     // first element is our menu vbox.
     if (this.panel.childElementCount == 1)
       return null;
     else
       return this.panel.lastChild;
   },
 
-  _activationHandler: function(event) {
-    if (!Services.prefs.getBoolPref("social.share.activationPanelEnabled"))
-      return;
-    SocialUI._activationEventHandler(event, { bypassContentCheck: true, bypassInstallPanel: true });
-  },
-
   uninit: function () {
     if (this.iframe) {
-      this.iframe.removeEventListener("ActivateSocialFeature", this._activationHandler, true, true);
       this.iframe.remove();
     }
   },
 
   _createFrame: function() {
     let panel = this.panel;
     if (this.iframe)
       return;
@@ -539,17 +504,20 @@ SocialShare = {
     let iframe = document.createElement("browser");
     iframe.setAttribute("type", "content");
     iframe.setAttribute("class", "social-share-frame");
     iframe.setAttribute("context", "contentAreaContextMenu");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
     iframe.setAttribute("disableglobalhistory", "true");
     iframe.setAttribute("flex", "1");
     panel.appendChild(iframe);
-    this.iframe.addEventListener("ActivateSocialFeature", this._activationHandler, true, true);
+    iframe.addEventListener("DOMContentLoaded", function _firstload() {
+      iframe.removeEventListener("DOMContentLoaded", _firstload, true);
+      iframe.messageManager.loadFrameScript("chrome://browser/content/content.js", true);
+    }, true);
     this.populateProviderMenu();
   },
 
   getSelectedProvider: function() {
     let provider;
     let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
     if (lastProviderOrigin) {
       provider = Social._getProviderFromOrigin(lastProviderOrigin);
@@ -666,28 +634,41 @@ SocialShare = {
                                 gBrowser.currentURI;
     if (!SocialUI.canShareOrMarkPage(sharedURI))
       return;
 
     // the point of this action type is that we can use existing share
     // endpoints (e.g. oexchange) that do not support additional
     // socialapi functionality.  One tweak is that we shoot an event
     // containing the open graph data.
+    let _dataFn;
     if (!pageData || sharedURI == gBrowser.currentURI) {
-      pageData = OpenGraphBuilder.getData(gBrowser);
-      if (graphData) {
-        // overwrite data retreived from page with data given to us as a param
-        for (let p in graphData) {
-          pageData[p] = graphData[p];
+      messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => {
+        messageManager.removeMessageListener("Social:PageDataResult", _dataFn);
+        let pageData = msg.json;
+        if (graphData) {
+          // overwrite data retreived from page with data given to us as a param
+          for (let p in graphData) {
+            pageData[p] = graphData[p];
+          }
         }
-      }
+        this.sharePage(providerOrigin, pageData, target);
+      });
+      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetPageData");
+      return;
     }
     // if this is a share of a selected item, get any microdata
     if (!pageData.microdata && target) {
-      pageData.microdata = OpenGraphBuilder.getMicrodata(gBrowser, target);
+      messageManager.addMessageListener("Social:PageDataResult", _dataFn = (msg) => {
+        messageManager.removeMessageListener("Social:PageDataResult", _dataFn);
+        pageData.microdata = msg.data;
+        this.sharePage(providerOrigin, pageData, target);
+      });
+      gBrowser.selectedBrowser.messageManager.sendAsyncMessage("Social:GetMicrodata", null, target);
+      return;
     }
     this.currentShare = pageData;
 
     let provider;
     if (providerOrigin)
       provider = Social._getProviderFromOrigin(providerOrigin);
     else
       provider = this.getSelectedProvider();
@@ -1262,17 +1243,16 @@ SocialStatus = {
       document.getElementById("social-notification-panel").hidePopup();
     this._removeFrame(origin);
   },
 
   _removeFrame: function(origin) {
     let notificationFrameId = "social-status-" + origin;
     let frame = document.getElementById(notificationFrameId);
     if (frame) {
-      SharedFrame.forgetGroup(frame.id);
       frame.parentNode.removeChild(frame);
     }
   },
 
   get _toolbarHelper() {
     delete this._toolbarHelper;
     this._toolbarHelper = new ToolbarHelper("social-status-button",
                                             CreateSocialStatusWidget,
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3967,17 +3967,17 @@ var XULBrowserWindow = {
       return true;
 
     let browser = aDocShell.QueryInterface(Ci.nsIDocShellTreeItem)
                            .sameTypeRootTreeItem
                            .QueryInterface(Ci.nsIDocShell)
                            .chromeEventHandler;
 
     // Ignore loads that aren't in the main tabbrowser
-    if (browser.localName != "browser" || browser.getTabBrowser() != gBrowser)
+    if (browser.localName != "browser" || !browser.getTabBrowser || browser.getTabBrowser() != gBrowser)
       return true;
 
     if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
       E10SUtils.redirectLoad(aDocShell, aURI, aReferrer);
       return false;
     }
 
     return true;
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -832,16 +832,76 @@ if (Services.appinfo.processType == Serv
 addEventListener("pageshow", function(event) {
   if (event.target == content.document) {
     sendAsyncMessage("PageVisibility:Show", {
       persisted: event.persisted,
     });
   }
 });
 
+let SocialMessenger = {
+  init: function() {
+    addMessageListener("Social:GetPageData", this);
+    addMessageListener("Social:GetMicrodata", this);
+
+    XPCOMUtils.defineLazyGetter(this, "og", function() {
+      let tmp = {};
+      Cu.import("resource:///modules/Social.jsm", tmp);
+      return tmp.OpenGraphBuilder;
+    });
+  },
+  receiveMessage: function(aMessage) {
+    switch(aMessage.name) {
+      case "Social:GetPageData":
+        sendAsyncMessage("Social:PageDataResult", this.og.getData(content.document));
+        break;
+      case "Social:GetMicrodata":
+        let target = aMessage.objects;
+        sendAsyncMessage("Social:PageDataResult", this.og.getMicrodata(content.document, target));
+        break;