From 4aaca6c799827fc7ab24857566fc48417df6da4e Mon Sep 17 00:00:00 2001 From: Erik Vold Date: Thu, 17 Jul 2014 13:54:21 -0700 Subject: [PATCH] Bug 1040336 - Uplift Add-on SDK to Firefox r=me --HG-- rename : addon-sdk/source/test/fixtures/css-include-file.css => addon-sdk/source/test/fixtures/include-file.css --- .../source/examples/actor-repl/README.md | 3 + .../actor-repl/data/codemirror-compressed.js | 5 + .../examples/actor-repl/data/codemirror.css | 264 ++ .../examples/actor-repl/data/index.html | 108 + .../source/examples/actor-repl/data/main.css | 117 + .../source/examples/actor-repl/data/robot.png | Bin 0 -> 4184 bytes addon-sdk/source/examples/actor-repl/index.js | 37 + .../source/examples/actor-repl/package.json | 10 + .../examples/debug-client/data/client.js | 816 ++++ .../examples/debug-client/data/index.html | 50 + .../examples/debug-client/data/plugin.png | Bin 0 -> 3819 bytes .../source/examples/debug-client/data/task.js | 28 + .../source/examples/debug-client/index.js | 33 + .../source/examples/debug-client/package.json | 10 + addon-sdk/source/lib/dev/debuggee.js | 95 + addon-sdk/source/lib/dev/frame-script.js | 115 + addon-sdk/source/lib/dev/panel.js | 223 + addon-sdk/source/lib/dev/ports.js | 64 + addon-sdk/source/lib/dev/toolbox.js | 75 + addon-sdk/source/lib/dev/utils.js | 38 + addon-sdk/source/lib/dev/volcan.js | 3760 +++++++++++++++++ addon-sdk/source/lib/sdk/addon/runner.js | 4 +- addon-sdk/source/lib/sdk/content/loader.js | 79 +- addon-sdk/source/lib/sdk/content/sandbox.js | 12 +- addon-sdk/source/lib/sdk/content/utils.js | 9 +- addon-sdk/source/lib/sdk/context-menu.js | 30 +- .../source/lib/sdk/deprecated/api-utils.js | 3 + .../lib/sdk/deprecated/unit-test-finder.js | 16 +- addon-sdk/source/lib/sdk/dom/events.js | 36 +- addon-sdk/source/lib/sdk/event/utils.js | 7 +- addon-sdk/source/lib/sdk/l10n.js | 17 +- addon-sdk/source/lib/sdk/l10n/json/core.js | 1 + .../source/lib/sdk/l10n/properties/core.js | 4 + addon-sdk/source/lib/sdk/messaging.js | 12 + addon-sdk/source/lib/sdk/notifications.js | 10 +- addon-sdk/source/lib/sdk/page-worker.js | 17 +- addon-sdk/source/lib/sdk/panel.js | 4 +- addon-sdk/source/lib/sdk/panel/utils.js | 7 +- addon-sdk/source/lib/sdk/self.js | 2 +- addon-sdk/source/lib/sdk/stylesheet/style.js | 18 +- addon-sdk/source/lib/sdk/tabs/common.js | 10 +- addon-sdk/source/lib/sdk/ui/sidebar.js | 8 +- addon-sdk/source/lib/sdk/ui/sidebar/view.js | 18 +- addon-sdk/source/lib/sdk/util/contract.js | 12 +- .../source/lib/sdk/windows/tabs-fennec.js | 5 +- .../source/lib/sdk/windows/tabs-firefox.js | 2 +- .../cuddlefish/tests/test_licenses.py | 3 + .../app-extension/locale/en-GB.properties | 6 + .../test/addons/l10n-properties/main.js | 14 + .../test/addons/l10n/locale/en-GB.properties | 6 + addon-sdk/source/test/addons/l10n/main.js | 15 +- .../addons/privileged-panel/data/index.html | 3 - .../test/addons/privileged-panel/main.js | 34 - .../test/addons/privileged-panel/package.json | 3 - addon-sdk/source/test/fixtures.js | 8 +- .../source/test/fixtures/border-style.css | 1 + ...{css-include-file.css => include-file.css} | 0 .../fixtures/test-sidebar-addon-global.html | 14 +- addon-sdk/source/test/pagemod-test-helpers.js | 10 +- addon-sdk/source/test/test-content-loader.js | 112 +- addon-sdk/source/test/test-context-menu.js | 43 +- addon-sdk/source/test/test-dev-panel.js | 236 ++ .../source/test/test-l10n-plural-rules.js | 1 + addon-sdk/source/test/test-page-mod.js | 37 +- addon-sdk/source/test/test-page-worker.js | 27 + addon-sdk/source/test/test-panel.js | 103 +- addon-sdk/source/test/test-tabs-common.js | 32 + addon-sdk/source/test/test-ui-sidebar.js | 42 + addon-sdk/source/test/test-widget.js | 8 +- .../test/windows/test-firefox-windows.js | 27 + 70 files changed, 6705 insertions(+), 274 deletions(-) create mode 100644 addon-sdk/source/examples/actor-repl/README.md create mode 100644 addon-sdk/source/examples/actor-repl/data/codemirror-compressed.js create mode 100644 addon-sdk/source/examples/actor-repl/data/codemirror.css create mode 100644 addon-sdk/source/examples/actor-repl/data/index.html create mode 100644 addon-sdk/source/examples/actor-repl/data/main.css create mode 100644 addon-sdk/source/examples/actor-repl/data/robot.png create mode 100644 addon-sdk/source/examples/actor-repl/index.js create mode 100644 addon-sdk/source/examples/actor-repl/package.json create mode 100644 addon-sdk/source/examples/debug-client/data/client.js create mode 100644 addon-sdk/source/examples/debug-client/data/index.html create mode 100644 addon-sdk/source/examples/debug-client/data/plugin.png create mode 100644 addon-sdk/source/examples/debug-client/data/task.js create mode 100644 addon-sdk/source/examples/debug-client/index.js create mode 100644 addon-sdk/source/examples/debug-client/package.json create mode 100644 addon-sdk/source/lib/dev/debuggee.js create mode 100644 addon-sdk/source/lib/dev/frame-script.js create mode 100644 addon-sdk/source/lib/dev/panel.js create mode 100644 addon-sdk/source/lib/dev/ports.js create mode 100644 addon-sdk/source/lib/dev/toolbox.js create mode 100644 addon-sdk/source/lib/dev/utils.js create mode 100644 addon-sdk/source/lib/dev/volcan.js create mode 100644 addon-sdk/source/lib/sdk/messaging.js delete mode 100644 addon-sdk/source/test/addons/privileged-panel/data/index.html delete mode 100644 addon-sdk/source/test/addons/privileged-panel/main.js delete mode 100644 addon-sdk/source/test/addons/privileged-panel/package.json create mode 100644 addon-sdk/source/test/fixtures/border-style.css rename addon-sdk/source/test/fixtures/{css-include-file.css => include-file.css} (100%) create mode 100644 addon-sdk/source/test/test-dev-panel.js diff --git a/addon-sdk/source/examples/actor-repl/README.md b/addon-sdk/source/examples/actor-repl/README.md new file mode 100644 index 000000000000..5228719e950b --- /dev/null +++ b/addon-sdk/source/examples/actor-repl/README.md @@ -0,0 +1,3 @@ +# Actor REPL + +Simple REPL for a Firefox debugging protocol. diff --git a/addon-sdk/source/examples/actor-repl/data/codemirror-compressed.js b/addon-sdk/source/examples/actor-repl/data/codemirror-compressed.js new file mode 100644 index 000000000000..6d8e4bf71908 --- /dev/null +++ b/addon-sdk/source/examples/actor-repl/data/codemirror-compressed.js @@ -0,0 +1,5 @@ +window.CodeMirror=function(){"use strict";function z(a,c){if(!(this instanceof z))return new z(a,c);this.options=c=c||{};for(var d in fd)!c.hasOwnProperty(d)&&fd.hasOwnProperty(d)&&(c[d]=fd[d]);M(c);var e="string"==typeof c.value?0:c.value.first,f=this.display=A(a,e);f.wrapper.CodeMirror=this,J(this),c.autofocus&&!r&&Qb(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,draggingText:!1,highlight:new jf},H(this),c.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap");var g=c.value;"string"==typeof g&&(g=new te(c.value,c.mode)),Ib(this,xe)(this,g),b&&setTimeout(tf(Pb,this,!0),20),Tb(this);var h;try{h=document.activeElement==f.input}catch(i){}h||c.autofocus&&!r?setTimeout(tf(rc,this),20):sc(this),Ib(this,function(){for(var a in ed)ed.propertyIsEnumerable(a)&&ed[a](this,c[a],hd);for(var b=0;bb.maxLineLength&&(b.maxLineLength=d,b.maxLine=a)})}function M(a){var b=pf(a.gutters,"CodeMirror-linenumbers");-1==b&&a.lineNumbers?a.gutters=a.gutters.concat(["CodeMirror-linenumbers"]):b>-1&&!a.lineNumbers&&(a.gutters=a.gutters.slice(0),a.gutters.splice(b,1))}function N(a){var b=a.display,c=a.doc.height,d=c+jb(b);b.sizer.style.minHeight=b.heightForcer.style.top=d+"px",b.gutters.style.height=Math.max(d,b.scroller.clientHeight-gf)+"px";var e=Math.max(d,b.scroller.scrollHeight),f=b.scroller.scrollWidth>b.scroller.clientWidth+1,g=e>b.scroller.clientHeight+1;g?(b.scrollbarV.style.display="block",b.scrollbarV.style.bottom=f?Hf(b.measure)+"px":"0",b.scrollbarV.firstChild.style.height=Math.max(0,e-b.scroller.clientHeight+b.scrollbarV.clientHeight)+"px"):(b.scrollbarV.style.display="",b.scrollbarV.firstChild.style.height="0"),f?(b.scrollbarH.style.display="block",b.scrollbarH.style.right=g?Hf(b.measure)+"px":"0",b.scrollbarH.firstChild.style.width=b.scroller.scrollWidth-b.scroller.clientWidth+b.scrollbarH.clientWidth+"px"):(b.scrollbarH.style.display="",b.scrollbarH.firstChild.style.width="0"),f&&g?(b.scrollbarFiller.style.display="block",b.scrollbarFiller.style.height=b.scrollbarFiller.style.width=Hf(b.measure)+"px"):b.scrollbarFiller.style.display="",f&&a.options.coverGutterNextToScrollbar&&a.options.fixedGutter?(b.gutterFiller.style.display="block",b.gutterFiller.style.height=Hf(b.measure)+"px",b.gutterFiller.style.width=b.gutters.offsetWidth+"px"):b.gutterFiller.style.display="",n&&0===Hf(b.measure)&&(b.scrollbarV.style.minWidth=b.scrollbarH.style.minHeight=o?"18px":"12px",b.scrollbarV.style.pointerEvents=b.scrollbarH.style.pointerEvents="none")}function O(a,b,c){var d=a.scroller.scrollTop,e=a.wrapper.clientHeight;"number"==typeof c?d=c:c&&(d=c.top,e=c.bottom-c.top),d=Math.floor(d-ib(a));var f=Math.ceil(d+e);return{from:De(b,d),to:De(b,f)}}function P(a){var b=a.display;if(b.alignWidgets||b.gutters.firstChild&&a.options.fixedGutter){for(var c=S(b)-b.scroller.scrollLeft+a.doc.scrollLeft,d=b.gutters.offsetWidth,e=c+"px",f=b.lineDiv.firstChild;f;f=f.nextSibling)if(f.alignable)for(var g=0,h=f.alignable;g=a.display.showingFrom&&h.to<=a.display.showingTo)break}return g&&(bf(a,"update",a),(a.display.showingFrom!=e||a.display.showingTo!=f)&&bf(a,"viewportChange",a,a.display.showingFrom,a.display.showingTo)),g}function U(a,b,c,d){var e=a.display,f=a.doc;if(!e.wrapper.offsetWidth)return e.showingFrom=e.showingTo=f.first,e.viewOffset=0,void 0;if(!(!d&&0==b.length&&c.from>e.showingFrom&&c.tol&&e.showingTo-l<20&&(l=Math.min(j,e.showingTo)),y)for(k=Ce(Rd(f,ye(f,k)));j>l&&Sd(f,ye(f,l));)++l;var m=[{from:Math.max(e.showingFrom,f.first),to:Math.min(e.showingTo,j)}];if(m=m[0].from>=m[0].to?[]:X(m,b),y)for(var i=0;in.from)){m.splice(i--,1);break}n.to=p}for(var q=0,i=0;il&&(n.to=l),n.from>=n.to?m.splice(i--,1):q+=n.to-n.from}if(!d&&q==l-k&&k==e.showingFrom&&l==e.showingTo)return W(a),void 0;m.sort(function(a,b){return a.from-b.from});try{var r=document.activeElement}catch(s){}.7*(l-k)>q&&(e.lineDiv.style.display="none"),Z(a,k,l,m,h),e.lineDiv.style.display="",r&&document.activeElement!=r&&r.offsetHeight&&r.focus();var t=k!=e.showingFrom||l!=e.showingTo||e.lastSizeC!=e.wrapper.clientHeight;return t&&(e.lastSizeC=e.wrapper.clientHeight,eb(a,400)),e.showingFrom=k,e.showingTo=l,e.gutters.style.height="",V(a),W(a),!0}}function V(a){for(var f,b=a.display,d=b.lineDiv.offsetTop,e=b.lineDiv.firstChild;e;e=e.nextSibling)if(e.lineObj){if(c){var g=e.offsetTop+e.offsetHeight;f=g-d,d=g}else{var h=Df(e);f=h.bottom-h.top}var i=e.lineObj.height-f;if(2>f&&(f=Db(b)),i>.001||-.001>i){Be(e.lineObj,f);var j=e.lineObj.widgets;if(j)for(var k=0;kc;++c){for(var e=b[c],f=[],g=e.diff||0,h=0,i=a.length;i>h;++h){var j=a[h];e.to<=j.from&&e.diff?f.push({from:j.from+g,to:j.to+g}):e.to<=j.from||e.from>=j.to?f.push(j):(e.from>j.from&&f.push({from:j.from,to:e.from}),e.ton){for(;k.lineObj!=b;)k=l(k);i&&n>=e&&k.lineNumber&&Cf(k.lineNumber,R(a.options,n)),k=k.nextSibling}else{if(b.widgets)for(var s,q=0,r=k;r&&20>q;++q,r=r.nextSibling)if(r.lineObj==b&&/div/i.test(r.nodeName)){s=r;break}var t=$(a,b,n,f,s);if(t!=s)j.insertBefore(t,k);else{for(;k!=s;)k=l(k);k=k.nextSibling}t.lineObj=b}++n});k;)k=l(k)}function $(a,b,d,e,f){var k,g=ie(a,b),h=g.pre,i=b.gutterMarkers,j=a.display,l=g.bgClass?g.bgClass+" "+(b.bgClass||""):b.bgClass;if(!(a.options.lineNumbers||i||l||b.wrapClass||b.widgets))return h;if(f){f.alignable=null;for(var q,m=!0,n=0,o=null,p=f.firstChild;p;p=q)if(q=p.nextSibling,/\bCodeMirror-linewidget\b/.test(p.className)){for(var r=0;rb&&(b=0),e.appendChild(zf("div",null,"CodeMirror-selected","position: absolute; left: "+a+"px; top: "+b+"px; width: "+(null==c?h-a:c)+"px; height: "+(d-b)+"px"))}function j(b,d,e){function m(c,d){return xb(a,Gc(b,c),"div",f,d)}var k,l,f=ye(c,b),j=f.text.length;return Of(Fe(f),d||0,null==e?j:e,function(a,b,c){var n,o,p,f=m(a,"left");if(a==b)n=f,o=p=f.left;else{if(n=m(b-1,"right"),"rtl"==c){var q=f;f=n,n=q}o=f.left,p=n.right}null==d&&0==a&&(o=g),n.top-f.top>3&&(i(o,f.top,null,f.bottom),o=g,f.bottoml.bottom||n.bottom==l.bottom&&n.right>l.right)&&(l=n),g+1>o&&(o=g),i(o,n.top,p-o,n.bottom)}),{start:k,end:l}}var b=a.display,c=a.doc,d=a.doc.sel,e=document.createDocumentFragment(),f=kb(a.display),g=f.left,h=b.lineSpace.offsetWidth-f.right;if(d.from.line==d.to.line)j(d.from.line,d.from.ch,d.to.ch);else{var k=ye(c,d.from.line),l=ye(c,d.to.line),m=Rd(c,k)==Rd(c,l),n=j(d.from.line,d.from.ch,m?k.text.length:null).end,o=j(d.to.line,m?0:null,d.to.ch).start;m&&(n.top0&&(b.blinker=setInterval(function(){b.cursor.style.visibility=b.otherCursor.style.visibility=(c=!c)?"":"hidden"},a.options.cursorBlinkRate))}}function eb(a,b){a.doc.mode.startState&&a.doc.frontier=a.display.showingTo)){var f,c=+new Date+a.options.workTime,d=nd(b.mode,hb(a,b.frontier)),e=[];b.iter(b.frontier,Math.min(b.first+b.size,a.display.showingTo+500),function(g){if(b.frontier>=a.display.showingFrom){var h=g.styles;g.styles=ce(a,g,d,!0);for(var i=!h||h.length!=g.styles.length,j=0;!i&&jc?(eb(a,a.options.workDelay),!0):void 0}),e.length&&Ib(a,function(){for(var a=0;ag;--h){if(h<=f.first)return f.first;var i=ye(f,h-1);if(i.stateAfter&&(!c||h<=f.frontier))return h;var j=kf(i.text,null,a.options.tabSize);(null==e||d>j)&&(e=h-1,d=j)}return e}function hb(a,b,c){var d=a.doc,e=a.display;if(!d.mode.startState)return!0;var f=gb(a,b,c),g=f>d.first&&ye(d,f-1).stateAfter;return g=g?nd(d.mode,g):od(d.mode),d.iter(f,b,function(c){ee(a,c.text,g);var h=f==b-1||0==f%5||f>=e.showingFrom&&ff&&0==h&&(f=1)}return e=h>c?"left":c>h?"right":e,"left"==e&&i.leftSide?i=i.leftSide:"right"==e&&i.rightSide&&(i=i.rightSide),{left:c>h?i.right:i.left,right:h>c?i.left:i.right,top:i.top,bottom:i.bottom}}function mb(a,b){for(var c=a.display.measureLineCache,d=0;ds&&(c=s),0>b&&(b=0);for(var d=q.length-2;d>=0;d-=2){var e=q[d],f=q[d+1];if(!(e>c||b>f)&&(b>=e&&f>=c||e>=b&&c>=f||Math.min(c,f)-Math.max(b,e)>=c-b>>1)){q[d]=Math.min(b,e),q[d+1]=Math.max(c,f);break}}return 0>d&&(d=q.length,q.push(b,c)),{left:a.left-p.left,right:a.right-p.left,top:d,bottom:null}}function u(a){a.bottom=q[a.top+1],a.top=q[a.top]}if(!a.options.lineWrapping&&e.text.length>=a.options.crudeMeasuringFrom)return qb(a,e);var f=a.display,g=sf(e.text.length),h=ie(a,e,g,!0).pre;if(b&&!c&&!a.options.lineWrapping&&h.childNodes.length>100){for(var i=document.createDocumentFragment(),j=10,k=h.childNodes.length,l=0,m=Math.ceil(k/j);m>l;++l){for(var n=zf("div",null,null,"display: inline-block"),o=0;j>o&&k;++o)n.appendChild(h.firstChild),--k;i.appendChild(n)}h.appendChild(i)}Bf(f.measure,h);var p=Df(f.lineDiv),q=[],r=sf(e.text.length),s=h.offsetHeight;d&&f.measure.first!=h&&Bf(f.measure,h);for(var v,l=0;l1&&(x=r[l]=t(y[0]),x.rightSide=t(y[y.length-1]))}x||(x=r[l]=t(Df(w))),v.measureRight&&(x.right=Df(v.measureRight).left-p.left),v.leftSide&&(x.leftSide=t(Df(v.leftSide)))}Af(a.display.measure);for(var v,l=0;l=a.options.crudeMeasuringFrom)return lb(a,b,b.text.length,f&&f.measure,"right").right;var g=ie(a,b,null,!0).pre,h=g.appendChild(Jf(a.display.measure));Bf(a.display.measure,g);var i=Df(h);return 0==i.right&&0==i.bottom&&(h=g.appendChild(zf("span","\xa0")),i=Df(h)),i.left-Df(a.display.lineDiv).left}function sb(a){a.display.measureLineCache.length=a.display.measureLineCachePos=0,a.display.cachedCharWidth=a.display.cachedTextHeight=a.display.cachedPaddingH=null,a.options.lineWrapping||(a.display.maxLineChanged=!0),a.display.lineNumChars=null}function tb(){return window.pageXOffset||(document.documentElement||document.body).scrollLeft}function ub(){return window.pageYOffset||(document.documentElement||document.body).scrollTop}function vb(a,b,c,d){if(b.widgets)for(var e=0;ec.from?f(a-1):f(a,d)}d=d||ye(a.doc,b.line),e||(e=ob(a,d));var h=Fe(d),i=b.ch;if(!h)return f(i);var j=Xf(h,i),k=g(i,j);return null!=Wf&&(k.other=g(i,Wf)),k}function zb(a,b,c,d){var e=new Gc(a,b);return e.xRel=d,c&&(e.outside=!0),e}function Ab(a,b,c){var d=a.doc;if(c+=a.display.viewOffset,0>c)return zb(d.first,0,!0,-1);var e=De(d,c),f=d.first+d.size-1;if(e>f)return zb(d.first+d.size-1,ye(d,f).text.length,!0,1);for(0>b&&(b=0);;){var g=ye(d,e),h=Bb(a,g,e,b,c),i=Pd(g),j=i&&i.find();if(!i||!(h.ch>j.from.ch||h.ch==j.from.ch&&h.xRel>0))return h;e=j.to.line}}function Bb(a,b,c,d,e){function j(d){var e=yb(a,Gc(c,d),"line",b,i);return g=!0,f>e.bottom?e.left-h:fq)return zb(c,n,r,1);for(;;){if(k?n==m||n==Zf(b,m,1):1>=n-m){for(var s=o>d||q-d>=d-o?m:n,t=d-(s==m?o:q);yf(b.text.charAt(s));)++s;var u=zb(c,s,s==m?p:r,0>t?-1:t?1:0);return u}var v=Math.ceil(l/2),w=m+v;if(k){w=m;for(var x=0;v>x;++x)w=Zf(b,w,1)}var y=j(w);y>d?(n=w,q=y,(r=g)&&(q+=1e3),l=v):(m=w,o=y,p=g,l-=v)}}function Db(a){if(null!=a.cachedTextHeight)return a.cachedTextHeight;if(null==Cb){Cb=zf("pre");for(var b=0;49>b;++b)Cb.appendChild(document.createTextNode("x")),Cb.appendChild(zf("br"));Cb.appendChild(document.createTextNode("x"))}Bf(a.measure,Cb);var c=Cb.offsetHeight/50;return c>3&&(a.cachedTextHeight=c),Af(a.measure),c||1}function Eb(a){if(null!=a.cachedCharWidth)return a.cachedCharWidth;var b=zf("span","x"),c=zf("pre",[b]);Bf(a.measure,c);var d=b.offsetWidth;return d>2&&(a.cachedCharWidth=d),d||10}function Gb(a){a.curOp={changes:[],forceUpdate:!1,updateInput:null,userSelChange:null,textChanged:null,selectionChanged:!1,cursorActivity:!1,updateMaxLine:!1,updateScrollPos:!1,id:++Fb},af++||(_e=[])}function Hb(a){var b=a.curOp,c=a.doc,d=a.display;if(a.curOp=null,b.updateMaxLine&&L(a),d.maxLineChanged&&!a.options.lineWrapping&&d.maxLine){var e=rb(a,d.maxLine);d.sizer.style.minWidth=Math.max(0,e+3)+"px",d.maxLineChanged=!1;var f=Math.max(0,d.sizer.offsetLeft+d.sizer.offsetWidth-d.scroller.clientWidth);fj&&c.charCodeAt(j)==h.charCodeAt(j);)++j;var l=f.from,m=f.to,n=h.slice(j);j-1){$c(a,f.head.line,"smart");break}}return h.length>1e3||h.indexOf("\n")>-1?b.value=a.display.prevInput="":a.display.prevInput=h,i&&Hb(a),a.state.pasteIncoming=a.state.cutIncoming=!1,!0}function Pb(a,b){var c,e,f=a.doc;if(Hc(f.sel.from,f.sel.to))b&&(a.display.prevInput=a.display.input.value="",g&&!d&&(a.display.inputHasSelection=null));else{a.display.prevInput="",c=Mf&&(f.sel.to.line-f.sel.from.line>100||(e=a.getSelection()).length>1e3);var h=c?"-":e||a.getSelection();a.display.input.value=h,a.state.focused&&of(a.display.input),g&&!d&&(a.display.inputHasSelection=h)}a.display.inaccurateSelection=c}function Qb(a){"nocursor"==a.options.readOnly||r&&document.activeElement==a.display.input||a.display.input.focus()}function Rb(a){a.state.focused||(Qb(a),rc(a))}function Sb(a){return a.options.readOnly||a.doc.cantEdit}function Tb(a){function e(){a.state.focused&&setTimeout(tf(Qb,a),0)}function i(){null==f&&(f=setTimeout(function(){f=null,c.cachedCharWidth=c.cachedTextHeight=c.cachedPaddingH=Gf=null,sb(a),Kb(a,tf(Lb,a))},100))}function j(){for(var a=c.wrapper.parentNode;a&&a!=document.body;a=a.parentNode);a?setTimeout(j,5e3):Ze(window,"resize",i)}function k(b){cf(a,b)||a.options.onDragEvent&&a.options.onDragEvent(a,Re(b))||Ve(b)}function l(b){c.inaccurateSelection&&(c.prevInput="",c.inaccurateSelection=!1,c.input.value=a.getSelection(),of(c.input)),"cut"==b.type&&(a.state.cutIncoming=!0)}var c=a.display;Ye(c.scroller,"mousedown",Ib(a,Yb)),b?Ye(c.scroller,"dblclick",Ib(a,function(b){if(!cf(a,b)){var c=Vb(a,b);if(c&&!_b(a,b)&&!Ub(a.display,b)){Se(b);var d=cd(ye(a.doc,c.line).text,c);Pc(a.doc,d.from,d.to)}}})):Ye(c.scroller,"dblclick",function(b){cf(a,b)||Se(b)}),Ye(c.lineSpace,"selectstart",function(a){Ub(c,a)||Se(a)}),w||Ye(c.scroller,"contextmenu",function(b){uc(a,b)}),Ye(c.scroller,"scroll",function(){c.scroller.clientHeight&&(dc(a,c.scroller.scrollTop),ec(a,c.scroller.scrollLeft,!0),$e(a,"scroll",a))}),Ye(c.scrollbarV,"scroll",function(){c.scroller.clientHeight&&dc(a,c.scrollbarV.scrollTop)}),Ye(c.scrollbarH,"scroll",function(){c.scroller.clientHeight&&ec(a,c.scrollbarH.scrollLeft)}),Ye(c.scroller,"mousewheel",function(b){hc(a,b)}),Ye(c.scroller,"DOMMouseScroll",function(b){hc(a,b)}),Ye(c.scrollbarH,"mousedown",e),Ye(c.scrollbarV,"mousedown",e),Ye(c.wrapper,"scroll",function(){c.wrapper.scrollTop=c.wrapper.scrollLeft=0});var f;Ye(window,"resize",i),setTimeout(j,5e3),Ye(c.input,"keyup",Ib(a,nc)),Ye(c.input,"input",function(){g&&!d&&a.display.inputHasSelection&&(a.display.inputHasSelection=null),Nb(a)}),Ye(c.input,"keydown",Ib(a,pc)),Ye(c.input,"keypress",Ib(a,qc)),Ye(c.input,"focus",tf(rc,a)),Ye(c.input,"blur",tf(sc,a)),a.options.dragDrop&&(Ye(c.scroller,"dragstart",function(b){cc(a,b)}),Ye(c.scroller,"dragenter",k),Ye(c.scroller,"dragover",k),Ye(c.scroller,"drop",Ib(a,bc))),Ye(c.scroller,"paste",function(b){Ub(c,b)||(Qb(a),Nb(a))}),Ye(c.input,"paste",function(){if(h&&!a.state.fakedLastChar&&!(new Date-a.state.lastMiddleDown<200)){var b=c.input.selectionStart,d=c.input.selectionEnd; +c.input.value+="$",c.input.selectionStart=b,c.input.selectionEnd=d,a.state.fakedLastChar=!0}a.state.pasteIncoming=!0,Nb(a)}),Ye(c.input,"cut",l),Ye(c.input,"copy",l),m&&Ye(c.sizer,"mouseup",function(){document.activeElement==c.input&&c.input.blur(),Qb(a)})}function Ub(a,b){for(var c=We(b);c!=a.wrapper;c=c.parentNode)if(!c||c.ignoreEvents||c.parentNode==a.sizer&&c!=a.mover)return!0}function Vb(a,b,c){var d=a.display;if(!c){var e=We(b);if(e==d.scrollbarH||e==d.scrollbarH.firstChild||e==d.scrollbarV||e==d.scrollbarV.firstChild||e==d.scrollbarFiller||e==d.gutterFiller)return null}var f,g,h=Df(d.lineSpace);try{f=b.clientX,g=b.clientY}catch(b){return null}return Ab(a,f-h.left,g-h.top)}function Yb(a){function t(a){if(!Hc(s,a)){if(s=a,"single"==m)return Pc(c.doc,Mc(i,k),a),void 0;if(q=Mc(i,q),r=Mc(i,r),"double"==m){var b=cd(ye(i,a.line).text,a);Ic(a,q)?Pc(c.doc,b.from,r):Pc(c.doc,q,b.to)}else"triple"==m&&(Ic(a,q)?Pc(c.doc,r,Mc(i,Gc(a.line,0))):Pc(c.doc,q,Mc(i,Gc(a.line+1,0))))}}function x(a){var b=++v,d=Vb(c,a,!0);if(d)if(Hc(d,o)){var g=a.clientYu.bottom?20:0;g&&setTimeout(Ib(c,function(){v==b&&(f.scroller.scrollTop+=g,x(a))}),50)}else{Rb(c),o=d,t(d);var e=O(f,i);(d.line>=e.to||d.linel-400&&Hc(Xb.pos,k))m="triple",Se(a),setTimeout(tf(Qb,c),20),dd(c,k.line);else if(Wb&&Wb.time>l-400&&Hc(Wb.pos,k)){m="double",Xb={time:l,pos:k},Se(a);var n=cd(ye(i,k.line).text,k);Pc(c.doc,n.from,n.to)}else Wb={time:l,pos:k};var o=k;if(c.options.dragDrop&&Ef&&!Sb(c)&&!Hc(j.from,j.to)&&!Ic(k,j.from)&&!Ic(j.to,k)&&"single"==m){var p=Ib(c,function(e){h&&(f.scroller.draggable=!1),c.state.draggingText=!1,Ze(document,"mouseup",p),Ze(f.scroller,"drop",p),Math.abs(a.clientX-e.clientX)+Math.abs(a.clientY-e.clientY)<10&&(Se(e),Pc(c.doc,k),Qb(c),b&&!d&&setTimeout(function(){document.body.focus(),Qb(c)},20))});return h&&(f.scroller.draggable=!0),c.state.draggingText=p,f.scroller.dragDrop&&f.scroller.dragDrop(),Ye(document,"mouseup",p),Ye(f.scroller,"drop",p),void 0}Se(a),"single"==m&&Pc(c.doc,Mc(i,k));var q=j.from,r=j.to,s=k,u=Df(f.wrapper),v=0,z=Ib(c,function(a){(g&&!e?a.buttons:Xe(a))?x(a):y(a)}),A=Ib(c,y);Ye(document,"mousemove",z),Ye(document,"mouseup",A)}}}function Zb(a,b,c,d,e){try{var f=b.clientX,g=b.clientY}catch(b){return!1}if(f>=Math.floor(Df(a.display.gutters).right))return!1;d&&Se(b);var h=a.display,i=Df(h.lineDiv);if(g>i.bottom||!ef(a,c))return Ue(b);g-=i.top-h.viewOffset;for(var j=0;j=f){var l=De(a.doc,g),m=a.options.gutters[j];return e(a,c,a,l,m,b),Ue(b)}}}function $b(a,b){return ef(a,"gutterContextMenu")?Zb(a,b,"gutterContextMenu",!1,$e):!1}function _b(a,b){return Zb(a,b,"gutterClick",!0,bf)}function bc(a){var b=this;if(!(cf(b,a)||Ub(b.display,a)||b.options.onDragEvent&&b.options.onDragEvent(b,Re(a)))){Se(a),g&&(ac=+new Date);var c=Vb(b,a,!0),d=a.dataTransfer.files;if(c&&!Sb(b))if(d&&d.length&&window.FileReader&&window.File)for(var e=d.length,f=Array(e),h=0,i=function(a,d){var g=new FileReader;g.onload=function(){f[d]=g.result,++h==e&&(c=Mc(b.doc,c),zc(b.doc,{from:c,to:c,text:Kf(f.join("\n")),origin:"paste"},"around"))},g.readAsText(a)},j=0;e>j;++j)i(d[j],j);else{if(b.state.draggingText&&!Ic(c,b.doc.sel.from)&&!Ic(b.doc.sel.to,c))return b.state.draggingText(a),setTimeout(tf(Qb,b),20),void 0;try{var f=a.dataTransfer.getData("Text");if(f){var k=b.doc.sel.from,l=b.doc.sel.to;Rc(b.doc,c,c),b.state.draggingText&&Fc(b.doc,"",k,l,"paste"),b.replaceSelection(f,null,"paste"),Qb(b)}}catch(a){}}}}function cc(a,b){if(g&&(!a.state.draggingText||+new Date-ac<100))return Ve(b),void 0;if(!cf(a,b)&&!Ub(a.display,b)){var c=a.getSelection();if(b.dataTransfer.setData("Text",c),b.dataTransfer.setDragImage&&!l){var d=zf("img",null,null,"position: fixed; left: 0; top: 0;");d.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",k&&(d.width=d.height=1,a.display.wrapper.appendChild(d),d._top=d.offsetTop),b.dataTransfer.setDragImage(d,0,0),k&&d.parentNode.removeChild(d)}}}function dc(b,c){Math.abs(b.doc.scrollTop-c)<2||(b.doc.scrollTop=c,a||T(b,[],c),b.display.scroller.scrollTop!=c&&(b.display.scroller.scrollTop=c),b.display.scrollbarV.scrollTop!=c&&(b.display.scrollbarV.scrollTop=c),a&&T(b,[]),eb(b,100))}function ec(a,b,c){(c?b==a.doc.scrollLeft:Math.abs(a.doc.scrollLeft-b)<2)||(b=Math.min(b,a.display.scroller.scrollWidth-a.display.scroller.clientWidth),a.doc.scrollLeft=b,P(a),a.display.scroller.scrollLeft!=b&&(a.display.scroller.scrollLeft=b),a.display.scrollbarH.scrollLeft!=b&&(a.display.scrollbarH.scrollLeft=b))}function hc(b,c){var d=c.wheelDeltaX,e=c.wheelDeltaY;null==d&&c.detail&&c.axis==c.HORIZONTAL_AXIS&&(d=c.detail),null==e&&c.detail&&c.axis==c.VERTICAL_AXIS?e=c.detail:null==e&&(e=c.wheelDelta);var f=b.display,g=f.scroller;if(d&&g.scrollWidth>g.clientWidth||e&&g.scrollHeight>g.clientHeight){if(e&&s&&h)for(var i=c.target;i!=g;i=i.parentNode)if(i.lineObj){b.display.currentWheelTarget=i;break}if(d&&!a&&!k&&null!=gc)return e&&dc(b,Math.max(0,Math.min(g.scrollTop+e*gc,g.scrollHeight-g.clientHeight))),ec(b,Math.max(0,Math.min(g.scrollLeft+d*gc,g.scrollWidth-g.clientWidth))),Se(c),f.wheelStartX=null,void 0;if(e&&null!=gc){var j=e*gc,l=b.doc.scrollTop,m=l+f.wrapper.clientHeight;0>j?l=Math.max(0,l+j-50):m=Math.min(b.doc.height,m+j+50),T(b,[],{top:l,bottom:m})}20>fc&&(null==f.wheelStartX?(f.wheelStartX=g.scrollLeft,f.wheelStartY=g.scrollTop,f.wheelDX=d,f.wheelDY=e,setTimeout(function(){if(null!=f.wheelStartX){var a=g.scrollLeft-f.wheelStartX,b=g.scrollTop-f.wheelStartY,c=b&&f.wheelDY&&b/f.wheelDY||a&&f.wheelDX&&a/f.wheelDX;f.wheelStartX=f.wheelStartY=null,c&&(gc=(gc*fc+c)/(fc+1),++fc)}},200)):(f.wheelDX+=d,f.wheelDY+=e))}}function ic(a,b,c){if("string"==typeof b&&(b=pd[b],!b))return!1;a.display.pollingFast&&Ob(a)&&(a.display.pollingFast=!1);var d=a.doc,e=d.sel.shift,f=!1;try{Sb(a)&&(a.state.suppressEdits=!0),c&&(d.sel.shift=!1),f=b(a)!=hf}finally{d.sel.shift=e,a.state.suppressEdits=!1}return f}function jc(a){var b=a.state.keyMaps.slice(0);return a.options.extraKeys&&b.push(a.options.extraKeys),b.push(a.options.keyMap),b}function lc(a,b){var c=rd(a.options.keyMap),e=c.auto;clearTimeout(kc),e&&!td(b)&&(kc=setTimeout(function(){rd(a.options.keyMap)==c&&(a.options.keyMap=e.call?e.call(null,a):e,G(a))},50));var f=ud(b,!0),g=!1;if(!f)return!1;var h=jc(a);return g=b.shiftKey?sd("Shift-"+f,h,function(b){return ic(a,b,!0)})||sd(f,h,function(b){return("string"==typeof b?/^go[A-Z]/.test(b):b.motion)?ic(a,b):void 0}):sd(f,h,function(b){return ic(a,b)}),g&&(Se(b),db(a),d&&(b.oldKeyCode=b.keyCode,b.keyCode=0),bf(a,"keyHandled",a,f,b)),g}function mc(a,b,c){var d=sd("'"+c+"'",jc(a),function(b){return ic(a,b,!0)});return d&&(Se(b),db(a),bf(a,"keyHandled",a,"'"+c+"'",b)),d}function nc(a){var b=this;cf(b,a)||b.options.onKeyEvent&&b.options.onKeyEvent(b,Re(a))||16==a.keyCode&&(b.doc.sel.shift=!1)}function pc(a){var c=this;if(Rb(c),!(cf(c,a)||c.options.onKeyEvent&&c.options.onKeyEvent(c,Re(a)))){b&&27==a.keyCode&&(a.returnValue=!1);var d=a.keyCode;c.doc.sel.shift=16==d||a.shiftKey;var e=lc(c,a);k&&(oc=e?d:null,!e&&88==d&&!Mf&&(s?a.metaKey:a.ctrlKey)&&c.replaceSelection(""))}}function qc(a){var b=this;if(!(cf(b,a)||b.options.onKeyEvent&&b.options.onKeyEvent(b,Re(a)))){var c=a.keyCode,e=a.charCode;if(k&&c==oc)return oc=null,Se(a),void 0;if(!(k&&(!a.which||a.which<10)||m)||!lc(b,a)){var f=String.fromCharCode(null==e?c:e);mc(b,a,f)||(g&&!d&&(b.display.inputHasSelection=null),Nb(b))}}}function rc(a){"nocursor"!=a.options.readOnly&&(a.state.focused||($e(a,"focus",a),a.state.focused=!0,-1==a.display.wrapper.className.search(/\bCodeMirror-focused\b/)&&(a.display.wrapper.className+=" CodeMirror-focused"),a.curOp||(Pb(a,!0),h&&setTimeout(tf(Pb,a,!0),0))),Mb(a),db(a))}function sc(a){a.state.focused&&($e(a,"blur",a),a.state.focused=!1,a.display.wrapper.className=a.display.wrapper.className.replace(" CodeMirror-focused","")),clearInterval(a.display.blinker),setTimeout(function(){a.state.focused||(a.doc.sel.shift=!1)},150)}function uc(a,b){function l(){if(null!=c.input.selectionStart){var a=c.input.value="\u200b"+(Hc(e.from,e.to)?"":c.input.value);c.prevInput="\u200b",c.input.selectionStart=1,c.input.selectionEnd=a.length}}function m(){if(c.inputDiv.style.position="relative",c.input.style.cssText=j,d&&(c.scrollbarV.scrollTop=c.scroller.scrollTop=h),Mb(a),null!=c.input.selectionStart){(!g||d)&&l(),clearTimeout(tc);var b=0,e=function(){"\u200b"==c.prevInput&&0==c.input.selectionStart?Ib(a,pd.selectAll)(a):b++<10?tc=setTimeout(e,500):Pb(a)};tc=setTimeout(e,200)}}if(!cf(a,b,"contextmenu")){var c=a.display,e=a.doc.sel;if(!Ub(c,b)&&!$b(a,b)){var f=Vb(a,b),h=c.scroller.scrollTop;if(f&&!k){var i=a.options.resetSelectionOnContextMenu;i&&(Hc(e.from,e.to)||Ic(f,e.from)||!Ic(f,e.to))&&Ib(a,Rc)(a.doc,f,f);var j=c.input.style.cssText;if(c.inputDiv.style.position="absolute",c.input.style.cssText="position: fixed; width: 30px; height: 30px; top: "+(b.clientY-5)+"px; left: "+(b.clientX-5)+"px; z-index: 1000; background: transparent; outline: none;"+"border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);",Qb(a),Pb(a,!0),Hc(e.from,e.to)&&(c.input.value=c.prevInput=" "),g&&!d&&l(),w){Ve(b);var n=function(){Ze(window,"mouseup",n),setTimeout(m,20)};Ye(window,"mouseup",n)}else setTimeout(m,50)}}}}function wc(a,b,c){if(!Ic(b.from,c))return Mc(a,c);var d=b.text.length-1-(b.to.line-b.from.line);if(c.line>b.to.line+d){var e=c.line-d,f=a.first+a.size-1;return e>f?Gc(f,ye(a,f).text.length):Nc(c,ye(a,e).text.length)}if(c.line==b.to.line+d)return Nc(c,nf(b.text).length+(1==b.text.length?b.from.ch:0)+ye(a,b.to.line).text.length-b.to.ch);var g=c.line-b.from.line;return Nc(c,b.text[g].length+(g?0:b.from.ch))}function xc(a,b,c){if(c&&"object"==typeof c)return{anchor:wc(a,b,c.anchor),head:wc(a,b,c.head)};if("start"==c)return{anchor:b.from,head:b.from};var d=vc(b);if("around"==c)return{anchor:b.from,head:d};if("end"==c)return{anchor:d,head:d};var e=function(a){if(Ic(a,b.from))return a;if(!Ic(b.to,a))return d;var c=a.line+b.text.length-(b.to.line-b.from.line)-1,e=a.ch;return a.line==b.to.line&&(e+=d.ch-b.to.ch),Gc(c,e)};return{anchor:e(a.sel.anchor),head:e(a.sel.head)}}function yc(a,b,c){var d={canceled:!1,from:b.from,to:b.to,text:b.text,origin:b.origin,cancel:function(){this.canceled=!0}};return c&&(d.update=function(b,c,d,e){b&&(this.from=Mc(a,b)),c&&(this.to=Mc(a,c)),d&&(this.text=d),void 0!==e&&(this.origin=e)}),$e(a,"beforeChange",a,d),a.cm&&$e(a.cm,"beforeChange",a.cm,d),d.canceled?null:{from:d.from,to:d.to,text:d.text,origin:d.origin}}function zc(a,b,c,d){if(a.cm){if(!a.cm.curOp)return Ib(a.cm,zc)(a,b,c,d);if(a.cm.state.suppressEdits)return}if(!(ef(a,"beforeChange")||a.cm&&ef(a.cm,"beforeChange"))||(b=yc(a,b,!0))){var e=x&&!d&&Jd(a,b.from,b.to);if(e){for(var f=e.length-1;f>=1;--f)Ac(a,{from:e[f].from,to:e[f].to,text:[""]});e.length&&Ac(a,{from:e[0].from,to:e[0].to,text:b.text},c)}else Ac(a,b,c)}}function Ac(a,b,c){if(1!=b.text.length||""!=b.text[0]||!Hc(b.from,b.to)){var d=xc(a,b,c);Je(a,b,d,a.cm?a.cm.curOp.id:0/0),Dc(a,b,d,Gd(a,b));var e=[];we(a,function(a,c){c||-1!=pf(e,a.history)||(Pe(a.history,b),e.push(a.history)),Dc(a,b,null,Gd(a,b))})}}function Bc(a,b){if(!a.cm||!a.cm.state.suppressEdits){var c=a.history,d=("undo"==b?c.done:c.undone).pop();if(d){var e={changes:[],anchorBefore:d.anchorAfter,headBefore:d.headAfter,anchorAfter:d.anchorBefore,headAfter:d.headBefore,generation:c.generation};("undo"==b?c.undone:c.done).push(e),c.generation=d.generation||++c.maxGeneration;for(var f=ef(a,"beforeChange")||a.cm&&ef(a.cm,"beforeChange"),g=d.changes.length-1;g>=0;--g){var h=d.changes[g];if(h.origin=b,f&&!yc(a,h,!1))return("undo"==b?c.done:c.undone).length=0,void 0;e.changes.push(Ie(a,h));var i=g?xc(a,h,null):{anchor:d.anchorBefore,head:d.headBefore};Dc(a,h,i,Id(a,h));var j=[];we(a,function(a,b){b||-1!=pf(j,a.history)||(Pe(a.history,h),j.push(a.history)),Dc(a,h,null,Id(a,h))})}}}}function Cc(a,b){function c(a){return Gc(a.line+b,a.ch)}a.first+=b,a.cm&&Lb(a.cm,a.first,a.first,b),a.sel.head=c(a.sel.head),a.sel.anchor=c(a.sel.anchor),a.sel.from=c(a.sel.from),a.sel.to=c(a.sel.to)}function Dc(a,b,c,d){if(a.cm&&!a.cm.curOp)return Ib(a.cm,Dc)(a,b,c,d);if(b.to.linea.lastLine())){if(b.from.linef&&(b={from:b.from,to:Gc(f,ye(a,f).text.length),text:[b.text[0]],origin:b.origin}),b.removed=ze(a,b.from,b.to),c||(c=xc(a,b,null)),a.cm?Ec(a.cm,b,d,c):pe(a,b,d,c)}}function Ec(a,b,c,d){var e=a.doc,f=a.display,g=b.from,h=b.to,i=!1,j=g.line;a.options.lineWrapping||(j=Ce(Rd(e,ye(e,g.line))),e.iter(j,h.line+1,function(a){return a==f.maxLine?(i=!0,!0):void 0})),Ic(e.sel.head,b.from)||Ic(b.to,e.sel.head)||(a.curOp.cursorActivity=!0),pe(e,b,c,d,E(a)),a.options.lineWrapping||(e.iter(j,g.line+b.text.length,function(a){var b=K(e,a);b>f.maxLineLength&&(f.maxLine=a,f.maxLineLength=b,f.maxLineChanged=!0,i=!1)}),i&&(a.curOp.updateMaxLine=!0)),e.frontier=Math.min(e.frontier,g.line),eb(a,400);var k=b.text.length-(h.line-g.line)-1;if(Lb(a,g.line,h.line+1,k),ef(a,"change")){var l={from:g,to:h,text:b.text,removed:b.removed,origin:b.origin};if(a.curOp.textChanged){for(var m=a.curOp.textChanged;m.next;m=m.next);m.next=l}else a.curOp.textChanged=l}}function Fc(a,b,c,d,e){if(d||(d=c),Ic(d,c)){var f=d;d=c,c=f}"string"==typeof b&&(b=Kf(b)),zc(a,{from:c,to:d,text:b,origin:e},null)}function Gc(a,b){return this instanceof Gc?(this.line=a,this.ch=b,void 0):new Gc(a,b)}function Hc(a,b){return a.line==b.line&&a.ch==b.ch}function Ic(a,b){return a.linec?Gc(c,ye(a,c).text.length):Nc(b,ye(a,b.line).text.length)}function Nc(a,b){var c=a.ch;return null==c||c>b?Gc(a.line,b):0>c?Gc(a.line,0):a}function Oc(a,b){return b>=a.first&&b=f.ch:j.to>f.ch))){if(d&&($e(k,"beforeCursorEnter"),k.explicitlyCleared)){if(h.markedSpans){--i;continue}break}if(!k.atomic)continue;var l=k.find()[0>g?"from":"to"];if(Hc(l,f)&&(l.ch+=g,l.ch<0?l=l.line>a.first?Mc(a,Gc(l.line-1)):null:l.ch>h.text.length&&(l=l.line(window.innerHeight||document.documentElement.clientHeight)&&(e=!1),null!=e&&!p){var f=zf("div","\u200b",null,"position: absolute; top: "+(b.top-c.viewOffset)+"px; height: "+(b.bottom-b.top+gf)+"px; left: "+b.left+"px; width: 2px;");a.display.lineSpace.appendChild(f),f.scrollIntoView(e),a.display.lineSpace.removeChild(f)}}}function Vc(a,b,c,d){for(null==d&&(d=0);;){var e=!1,f=yb(a,b),g=c&&c!=b?yb(a,c):f,h=Xc(a,Math.min(f.left,g.left),Math.min(f.top,g.top)-d,Math.max(f.left,g.left),Math.max(f.bottom,g.bottom)+d),i=a.doc.scrollTop,j=a.doc.scrollLeft;if(null!=h.scrollTop&&(dc(a,h.scrollTop),Math.abs(a.doc.scrollTop-i)>1&&(e=!0)),null!=h.scrollLeft&&(ec(a,h.scrollLeft),Math.abs(a.doc.scrollLeft-j)>1&&(e=!0)),!e)return f}}function Wc(a,b,c,d,e){var f=Xc(a,b,c,d,e);null!=f.scrollTop&&dc(a,f.scrollTop),null!=f.scrollLeft&&ec(a,f.scrollLeft)}function Xc(a,b,c,d,e){var f=a.display,g=Db(a.display);0>c&&(c=0);var h=f.scroller.clientHeight-gf,i=f.scroller.scrollTop,j={},k=a.doc.height+jb(f),l=g>c,m=e>k-g;if(i>c)j.scrollTop=l?0:c;else if(e>i+h){var n=Math.min(c,(m?k:e)-h);n!=i&&(j.scrollTop=n)}var o=f.scroller.clientWidth-gf,p=f.scroller.scrollLeft;b+=f.gutters.offsetWidth,d+=f.gutters.offsetWidth;var q=f.gutters.offsetWidth,r=q+10>b;return p+q>b||r?(r&&(b=0),j.scrollLeft=Math.max(0,b-10-q)):d>o+p-3&&(j.scrollLeft=d+10-o),j}function Yc(a,b,c){a.curOp.updateScrollPos={scrollLeft:null==b?a.doc.scrollLeft:b,scrollTop:null==c?a.doc.scrollTop:c}}function Zc(a,b,c){var d=a.curOp.updateScrollPos||(a.curOp.updateScrollPos={scrollLeft:a.doc.scrollLeft,scrollTop:a.doc.scrollTop}),e=a.display.scroller;d.scrollTop=Math.max(0,Math.min(e.scrollHeight-e.clientHeight,d.scrollTop+c)),d.scrollLeft=Math.max(0,Math.min(e.scrollWidth-e.clientWidth,d.scrollLeft+b))}function $c(a,b,c,d){var f,e=a.doc;null==c&&(c="add"),"smart"==c&&(a.doc.mode.indent?f=hb(a,b):c="prev");var g=a.options.tabSize,h=ye(e,b),i=kf(h.text,null,g);h.stateAfter&&(h.stateAfter=null);var k,j=h.text.match(/^\s*/)[0];if(d||/\S/.test(h.text)){if("smart"==c&&(k=a.doc.mode.indent(f,h.text.slice(j.length),h.text),k==hf)){if(!d)return;c="prev"}}else k=0,c="not";"prev"==c?k=b>e.first?kf(ye(e,b-1).text,null,g):0:"add"==c?k=i+a.options.indentUnit:"subtract"==c?k=i-a.options.indentUnit:"number"==typeof c&&(k=i+c),k=Math.max(0,k);var l="",m=0;if(a.options.indentWithTabs)for(var n=Math.floor(k/g);n;--n)m+=g,l+=" ";k>m&&(l+=mf(k-m)),l!=j?Fc(a.doc,l,Gc(b,0),Gc(b,j.length),"+input"):e.sel.head.line==b&&e.sel.head.ch=a.first+a.size?j=!1:(f=b,i=ye(a,b))}function l(a){var b=(e?Zf:$f)(i,g,c,!0);if(null==b){if(a||!k())return j=!1;g=e?(0>c?Sf:Rf)(i):0>c?i.text.length:0}else g=b;return!0}var f=b.line,g=b.ch,h=c,i=ye(a,f),j=!0;if("char"==d)l();else if("column"==d)l(!0);else if("word"==d||"group"==d)for(var m=null,n="group"==d,o=!0;!(0>c)||l(!o);o=!1){var p=i.text.charAt(g)||"\n",q=vf(p)?"w":n&&"\n"==p?"n":!n||/\s/.test(p)?null:"p";if(!n||o||q||(q="s"),m&&m!=q){0>c&&(c=1,l());break}if(q&&(m=q),c>0&&!l(!o))break}var r=Tc(a,Gc(f,g),h,!0);return j||(r.hitSide=!0),r}function bd(a,b,c,d){var g,e=a.doc,f=b.left;if("page"==d){var h=Math.min(a.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight);g=b.top+c*(h-(0>c?1.5:.5)*Db(a.display))}else"line"==d&&(g=c>0?b.bottom+3:b.top-3);for(;;){var i=Ab(a,f,g);if(!i.outside)break;if(0>c?0>=g:g>=e.height){i.hitSide=!0;break}g+=5*c}return i}function cd(a,b){var c=b.ch,d=b.ch;if(a){(b.xRel<0||d==a.length)&&c?--c:++d;for(var e=a.charAt(c),f=vf(e)?vf:/\s/.test(e)?function(a){return/\s/.test(a)}:function(a){return!/\s/.test(a)&&!vf(a)};c>0&&f(a.charAt(c-1));)--c;for(;dg;++g){var i=d(f[g]);if(i)return i}return!1}for(var e=0;e=b:f.to>b);(e||(e=[])).push({from:f.from,to:i?null:f.to,marker:g})}}return e}function Fd(a,b,c){if(a)for(var e,d=0;d=b:f.to>b);if(h||f.from==b&&"bookmark"==g.type&&(!c||f.marker.insertLeft)){var i=null==f.from||(g.inclusiveLeft?f.from<=b:f.from0&&h)for(var l=0;ll;++l)o.push(q);o.push(i)}return o}function Hd(a){for(var b=0;b=0&&0>=l||0>=k&&l>=0)&&(0>=k&&(Jc(j.to,c)||Ld(i.marker)-Kd(e))>0||k>=0&&(Jc(j.from,d)||Kd(i.marker)-Ld(e))<0))return!0}}}function Rd(a,b){for(var c;c=Od(b);)b=ye(a,c.find().from.line);return b}function Sd(a,b){var c=y&&b.markedSpans;if(c)for(var d,e=0;ea.options.maxHighlightLength?(g=!1,f&&ee(a,b,d,j.pos),j.pos=b.length,k=null):k=c.token(j,d),a.options.addModeClass){var l=z.innerMode(c,d).mode.name;l&&(k="m-"+(k?l+" "+k:l))}g&&i==k||(hi;){var d=e[h];d>a&&e.splice(h,1,a,e[h+1],d),h+=2,i=Math.min(a,d)}if(b)if(g.opaque)e.splice(c,h-c,a,b),h=c+2;else for(;h>c;c+=2){var f=e[c+1];e[c+1]=f?f+" "+b:b}})}return e}function de(a,b){return b.styles&&b.styles[0]==a.state.modeGen||(b.styles=ce(a,b,b.stateAfter=hb(a,Ce(b)))),b.styles}function ee(a,b,c,d){var e=a.doc.mode,f=new vd(b,a.options.tabSize);for(f.start=f.pos=d||0,""==b&&e.blankLine&&e.blankLine(c);!f.eol()&&f.pos<=a.options.maxHighlightLength;)e.token(f,c),f.start=f.pos}function he(a,b){if(!a)return null;for(;;){var c=a.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!c)break;a=a.slice(0,c.index)+a.slice(c.index+c[0].length);var d=c[1]?"bgClass":"textClass";null==b[d]?b[d]=c[2]:new RegExp("(?:^|s)"+c[2]+"(?:$|s)").test(b[d])||(b[d]+=" "+c[2])}if(/^\s*$/.test(a))return null;var e=b.cm.options.addModeClass?ge:fe;return e[a]||(e[a]=a.replace(/\S+/g,"cm-$&"))}function ie(a,b,c,d){for(var e,f=b,i=!0;e=Od(f);)f=ye(a.doc,e.find().from.line);var j={pre:zf("pre"),col:0,pos:0,measure:null,measuredSomething:!1,cm:a,copyWidgets:d};do{f.text&&(i=!1),j.measure=f==b&&c,j.pos=0,j.addToken=j.measure?le:ke,(g||h)&&a.getOption("lineWrapping")&&(j.addToken=me(j.addToken));var k=oe(f,j,de(a,f));c&&f==b&&!j.measuredSomething&&(c[0]=j.pre.appendChild(Jf(a.display.measure)),j.measuredSomething=!0),k&&(f=ye(a.doc,k.to.line))}while(k);!c||j.measuredSomething||c[0]||(c[0]=j.pre.appendChild(i?zf("span","\xa0"):Jf(a.display.measure))),j.pre.firstChild||Sd(a.doc,b)||j.pre.appendChild(document.createTextNode("\xa0"));var l;if(c&&g&&(l=Fe(f))){var m=l.length-1;l[m].from==l[m].to&&--m;var n=l[m],o=l[m-1];if(n.from+1==n.to&&o&&n.leveli)?(null!=t.to&&l>t.to&&(l=t.to,n=""),u.className&&(m+=" "+u.className),u.startStyle&&t.from==i&&(o+=" "+u.startStyle),u.endStyle&&t.to==l&&(n+=" "+u.endStyle),u.title&&!p&&(p=u.title),u.collapsed&&(!q||Md(q.marker,u)<0)&&(q=t)):t.from>i&&l>t.from&&(l=t.from),"bookmark"==u.type&&t.from==i&&u.replacedWith&&r.push(u)}if(q&&(q.from||0)==i&&(ne(b,(null==q.to?h:q.to)-i,q.marker,null==q.from),null==q.to))return q.marker.find();if(!q&&r.length)for(var s=0;s=h)break;for(var v=Math.min(h,l);;){if(j){var w=i+j.length;if(!q){var x=w>v?j.slice(0,v-i):j;b.addToken(b,x,k?k+m:m,o,i+x.length==l?n:"",p)}if(w>=v){j=j.slice(v-i),i=v;break}i=w,o=""}j=e.slice(f,f=c[g++]),k=he(c[g++],b)}}else for(var g=1;gp;++p)r.push(new $d(j[p],f(p),e));r.push(new $d(m+k.text.slice(i.ch),n,e)),g(k,k.text.slice(0,h.ch)+j[0],f(0)),a.insert(h.line+1,r)}else if(1==j.length)g(k,k.text.slice(0,h.ch)+j[0]+l.text.slice(i.ch),f(0)),a.remove(h.line+1,o);else{g(k,k.text.slice(0,h.ch)+j[0],f(0)),g(l,m+l.text.slice(i.ch),n);for(var p=1,q=j.length-1,r=[];q>p;++p)r.push(new $d(j[p],f(p),e));o>1&&a.remove(h.line+1,o-1),a.insert(h.line+1,r)}else{for(var p=0,q=j.length-1,r=[];q>p;++p)r.push(new $d(j[p],f(p),e));g(l,l.text,n),o&&a.remove(h.line,o),r.length&&a.insert(h.line,r)}bf(a,"change",a,b),Rc(a,d.anchor,d.head,null,!0)}function qe(a){this.lines=a,this.parent=null;for(var b=0,c=a.length,d=0;c>b;++b)a[b].parent=this,d+=a[b].height;this.height=d}function re(a){this.children=a;for(var b=0,c=0,d=0,e=a.length;e>d;++d){var f=a[d];b+=f.chunkSize(),c+=f.height,f.parent=this}this.size=b,this.height=c,this.parent=null}function we(a,b,c){function d(a,e,f){if(a.linked)for(var g=0;gb){a=d;break}b-=e}return a.lines[b]}function ze(a,b,c){var d=[],e=b.line;return a.iter(b.line,c.line+1,function(a){var f=a.text;e==c.line&&(f=f.slice(0,c.ch)),e==b.line&&(f=f.slice(b.ch)),d.push(f),++e}),d}function Ae(a,b,c){var d=[];return a.iter(b,c,function(a){d.push(a.text)}),d}function Be(a,b){for(var c=b-a.height,d=a;d;d=d.parent)d.height+=c}function Ce(a){if(null==a.parent)return null;for(var b=a.parent,c=pf(b.lines,a),d=b.parent;d;b=d,d=d.parent)for(var e=0;d.children[e]!=b;++e)c+=d.children[e].chunkSize();return c+b.first}function De(a,b){var c=a.first;a:do{for(var d=0,e=a.children.length;e>d;++d){var f=a.children[d],g=f.height;if(g>b){a=f;continue a}b-=g,c+=f.chunkSize()}return c}while(!a.lines);for(var d=0,e=a.lines.length;e>d;++d){var h=a.lines[d],i=h.height;if(i>b)break;b-=i}return c+d}function Ee(a,b){b=Rd(a.doc,b);for(var c=0,d=b.parent,e=0;ef-a.cm.options.historyEventDelay||"*"==b.origin.charAt(0)))){var h=nf(g.changes);Hc(b.from,b.to)&&Hc(b.from,h.to)?h.to=vc(b):g.changes.push(Ie(a,b)),g.anchorAfter=c.anchor,g.headAfter=c.head}else for(g={changes:[Ie(a,b)],generation:e.generation,anchorBefore:a.sel.anchor,headBefore:a.sel.head,anchorAfter:c.anchor,headAfter:c.head},e.done.push(g);e.done.length>e.undoDepth;)e.done.shift();e.generation=++e.maxGeneration,e.lastTime=f,e.lastOp=d,e.lastOrigin=b.origin,h||$e(a,"historyAdded")}function Ke(a){if(!a)return null;for(var c,b=0;b-1&&(nf(g)[k]=i[k],delete i[k])}}return d}function Ne(a,b,c,d){c0}function ff(a){a.prototype.on=function(a,b){Ye(this,a,b)},a.prototype.off=function(a,b){Ze(this,a,b)}}function jf(){this.id=null}function kf(a,b,c,d,e){null==b&&(b=a.search(/[^\s\u00a0]/),-1==b&&(b=a.length));for(var f=d||0,g=e||0;b>f;++f)" "==a.charAt(f)?g+=c-g%c:++g;return g}function mf(a){for(;lf.length<=a;)lf.push(nf(lf)+" ");return lf[a]}function nf(a){return a[a.length-1]}function of(a){if(q)a.selectionStart=0,a.selectionEnd=a.value.length;else try{a.select()}catch(b){}}function pf(a,b){if(a.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;++c)if(a[c]==b)return c;return-1}function qf(a,b){function c(){}c.prototype=a;var d=new c;return b&&rf(b,d),d}function rf(a,b){b||(b={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b}function sf(a){for(var b=[],c=0;a>c;++c)b.push(void 0);return b}function tf(a){var b=Array.prototype.slice.call(arguments,1);return function(){return a.apply(null,b)}}function vf(a){return/\w/.test(a)||a>"\x80"&&(a.toUpperCase()!=a.toLowerCase()||uf.test(a))}function wf(a){for(var b in a)if(a.hasOwnProperty(b)&&a[b])return!1;return!0}function yf(a){return a.charCodeAt(0)>=768&&xf.test(a)}function zf(a,b,c,d){var e=document.createElement(a);if(c&&(e.className=c),d&&(e.style.cssText=d),"string"==typeof b)Cf(e,b);else if(b)for(var f=0;f0;--b)a.removeChild(a.firstChild);return a}function Bf(a,b){return Af(a).appendChild(b)}function Cf(a,b){d?(a.innerHTML="",a.appendChild(document.createTextNode(b))):a.textContent=b}function Df(a){return a.getBoundingClientRect()}function Ff(){return!1}function Hf(a){if(null!=Gf)return Gf;var b=zf("div",null,null,"width: 50px; height: 50px; overflow-x: scroll");return Bf(a,b),b.offsetWidth&&(Gf=b.offsetHeight-b.clientHeight),Gf||0}function Jf(a){if(null==If){var b=zf("span","\u200b");Bf(a,zf("span",[b,document.createTextNode("x")])),0!=a.firstChild.offsetHeight&&(If=b.offsetWidth<=1&&b.offsetHeight>2&&!c)}return If?zf("span","\u200b"):zf("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px")}function Of(a,b,c,d){if(!a)return d(b,c,"ltr");for(var e=!1,f=0;fb||b==c&&g.to==b)&&(d(Math.max(g.from,b),Math.min(g.to,c),1==g.level?"rtl":"ltr"),e=!0)}e||d(b,c,"ltr")}function Pf(a){return a.level%2?a.to:a.from}function Qf(a){return a.level%2?a.from:a.to}function Rf(a){var b=Fe(a);return b?Pf(b[0]):0}function Sf(a){var b=Fe(a);return b?Qf(nf(b)):a.text.length}function Tf(a,b){var c=ye(a.doc,b),d=Rd(a.doc,c);d!=c&&(b=Ce(d));var e=Fe(d),f=e?e[0].level%2?Sf(d):Rf(d):0;return Gc(b,f)}function Uf(a,b){for(var c,d;c=Pd(d=ye(a.doc,b));)b=c.find().to.line;var e=Fe(d),f=e?e[0].level%2?Rf(d):Sf(d):d.text.length;return Gc(b,f)}function Vf(a,b,c){var d=a[0].level;return b==d?!0:c==d?!1:c>b}function Xf(a,b){Wf=null;for(var d,c=0;cb)return c;if(e.from==b||e.to==b){if(null!=d)return Vf(a,e.level,a[d].level)?(e.from!=e.to&&(Wf=d),c):(e.from!=e.to&&(Wf=c),d);d=c}}return d}function Yf(a,b,c,d){if(!d)return b+c;do b+=c;while(b>0&&yf(a.text.charAt(b)));return b}function Zf(a,b,c,d){var e=Fe(a);if(!e)return $f(a,b,c,d);for(var f=Xf(e,b),g=e[f],h=Yf(a,b,g.level%2?-c:c,d);;){if(h>g.from&&h0==g.level%2?g.to:g.from);if(g=e[f+=c],!g)return null;h=c>0==g.level%2?Yf(a,g.to,-1,d):Yf(a,g.from,1,d)}}function $f(a,b,c,d){var e=b+c;if(d)for(;e>0&&yf(a.text.charAt(e));)e+=c;return 0>e||e>a.text.length?null:e}var a=/gecko\/\d/i.test(navigator.userAgent),b=/MSIE \d/.test(navigator.userAgent),c=b&&(null==document.documentMode||document.documentMode<8),d=b&&(null==document.documentMode||document.documentMode<9),e=b&&(null==document.documentMode||document.documentMode<10),f=/Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent),g=b||f,h=/WebKit\//.test(navigator.userAgent),i=h&&/Qt\/\d+\.\d+/.test(navigator.userAgent),j=/Chrome\//.test(navigator.userAgent),k=/Opera\//.test(navigator.userAgent),l=/Apple Computer/.test(navigator.vendor),m=/KHTML\//.test(navigator.userAgent),n=/Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent),o=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent),p=/PhantomJS/.test(navigator.userAgent),q=/AppleWebKit/.test(navigator.userAgent)&&/Mobile\/\w+/.test(navigator.userAgent),r=q||/Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent),s=q||/Mac/.test(navigator.platform),t=/win/i.test(navigator.platform),u=k&&navigator.userAgent.match(/Version\/(\d*\.\d*)/);u&&(u=Number(u[1])),u&&u>=15&&(k=!1,h=!0);var Cb,Wb,Xb,v=s&&(i||k&&(null==u||12.11>u)),w=a||g&&!d,x=!1,y=!1,Fb=0,ac=0,fc=0,gc=null;g?gc=-.53:a?gc=15:j?gc=-.7:l&&(gc=-1/3);var kc,tc,oc=null,vc=z.changeEnd=function(a){return a.text?Gc(a.from.line+a.text.length-1,nf(a.text).length+(1==a.text.length?a.from.ch:0)):a.to};z.Pos=Gc,z.prototype={constructor:z,focus:function(){window.focus(),Qb(this),Nb(this)},setOption:function(a,b){var c=this.options,d=c[a];(c[a]!=b||"mode"==a)&&(c[a]=b,ed.hasOwnProperty(a)&&Ib(this,ed[a])(this,b,d))},getOption:function(a){return this.options[a]},getDoc:function(){return this.doc},addKeyMap:function(a,b){this.state.keyMaps[b?"push":"unshift"](a)},removeKeyMap:function(a){for(var b=this.state.keyMaps,c=0;c=d;++d)$c(this,d,a)}),getTokenAt:function(a,b){var c=this.doc;a=Mc(c,a);for(var d=hb(this,a.line,b),e=this.doc.mode,f=ye(c,a.line),g=new vd(f.text,this.options.tabSize);g.pos>1;if((f?b[2*f-1]:0)>=e)d=f;else{if(!(b[2*f+1]d&&(a=d,c=!0);var e=ye(this.doc,a);return vb(this,ye(this.doc,a),{top:0,left:0},b||"page").top+(c?e.height:0)},defaultTextHeight:function(){return Db(this.display)},defaultCharWidth:function(){return Eb(this.display)},setGutterMarker:Ib(null,function(a,b,c){return _c(this,a,function(a){var d=a.gutterMarkers||(a.gutterMarkers={});return d[b]=c,!c&&wf(d)&&(a.gutterMarkers=null),!0})}),clearGutter:Ib(null,function(a){var b=this,c=b.doc,d=c.first;c.iter(function(c){c.gutterMarkers&&c.gutterMarkers[a]&&(c.gutterMarkers[a]=null,Lb(b,d,d+1),wf(c.gutterMarkers)&&(c.gutterMarkers=null)),++d})}),addLineClass:Ib(null,function(a,b,c){return _c(this,a,function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"wrapClass";if(a[d]){if(new RegExp("(?:^|\\s)"+c+"(?:$|\\s)").test(a[d]))return!1;a[d]+=" "+c}else a[d]=c;return!0})}),removeLineClass:Ib(null,function(a,b,c){return _c(this,a,function(a){var d="text"==b?"textClass":"background"==b?"bgClass":"wrapClass",e=a[d];if(!e)return!1;if(null==c)a[d]=null;else{var f=e.match(new RegExp("(?:^|\\s+)"+c+"(?:$|\\s+)"));if(!f)return!1;var g=f.index+f[0].length;a[d]=e.slice(0,f.index)+(f.index&&g!=e.length?" ":"")+e.slice(g)||null}return!0})}),addLineWidget:Ib(null,function(a,b,c){return Zd(this,a,b,c)}),removeLineWidget:function(a){a.clear()},lineInfo:function(a){if("number"==typeof a){if(!Oc(this.doc,a))return null;var b=a;if(a=ye(this.doc,a),!a)return null}else{var b=Ce(a);if(null==b)return null}return{line:b,handle:a,text:a.text,gutterMarkers:a.gutterMarkers,textClass:a.textClass,bgClass:a.bgClass,wrapClass:a.wrapClass,widgets:a.widgets}},getViewport:function(){return{from:this.display.showingFrom,to:this.display.showingTo}},addWidget:function(a,b,c,d,e){var f=this.display;a=yb(this,Mc(this.doc,a));var g=a.bottom,h=a.left;if(b.style.position="absolute",f.sizer.appendChild(b),"over"==d)g=a.top;else if("above"==d||"near"==d){var i=Math.max(f.wrapper.clientHeight,this.doc.height),j=Math.max(f.sizer.clientWidth,f.lineSpace.clientWidth);("above"==d||a.bottom+b.offsetHeight>i)&&a.top>b.offsetHeight?g=a.top-b.offsetHeight:a.bottom+b.offsetHeight<=i&&(g=a.bottom),h+b.offsetWidth>j&&(h=j-b.offsetWidth)}b.style.top=g+"px",b.style.left=b.style.right="","right"==e?(h=f.sizer.clientWidth-b.offsetWidth,b.style.right="0px"):("left"==e?h=0:"middle"==e&&(h=(f.sizer.clientWidth-b.offsetWidth)/2),b.style.left=h+"px"),c&&Wc(this,h,g,h+b.offsetWidth,g+b.offsetHeight)},triggerOnKeyDown:Ib(null,pc),triggerOnKeyPress:Ib(null,qc),triggerOnKeyUp:Ib(null,nc),execCommand:function(a){return pd.hasOwnProperty(a)?pd[a](this):void 0},findPosH:function(a,b,c,d){var e=1;0>b&&(e=-1,b=-b);for(var f=0,g=Mc(this.doc,a);b>f&&(g=ad(this.doc,g,e,c,d),!g.hitSide);++f);return g},moveH:Ib(null,function(a,b){var d,c=this.doc.sel;d=c.shift||c.extend||Hc(c.from,c.to)?ad(this.doc,c.head,a,b,this.options.rtlMoveVisually):0>a?c.from:c.to,Pc(this.doc,d,d,a)}),deleteH:Ib(null,function(a,b){var c=this.doc.sel;Hc(c.from,c.to)?Fc(this.doc,"",c.from,ad(this.doc,c.head,a,b,!1),"+delete"):Fc(this.doc,"",c.from,c.to,"+delete"),this.curOp.userSelChange=!0}),findPosV:function(a,b,c,d){var e=1,f=d;0>b&&(e=-1,b=-b);for(var g=0,h=Mc(this.doc,a);b>g;++g){var i=yb(this,h,"div");if(null==f?f=i.left:i.left=f,h=bd(this,i,e,c),h.hitSide)break}return h},moveV:Ib(null,function(a,b){var d,e,c=this.doc.sel;if(c.shift||c.extend||Hc(c.from,c.to)){var f=yb(this,c.head,"div");null!=c.goalColumn&&(f.left=c.goalColumn),d=bd(this,f,a,b),"page"==b&&Zc(this,0,xb(this,d,"div").top-f.top),e=f.left}else d=0>a?c.from:c.to;Pc(this.doc,d,d,a),null!=e&&(c.goalColumn=e)}),toggleOverwrite:function(a){(null==a||a!=this.state.overwrite)&&((this.state.overwrite=!this.state.overwrite)?this.display.cursor.className+=" CodeMirror-overwrite":this.display.cursor.className=this.display.cursor.className.replace(" CodeMirror-overwrite",""),$e(this,"overwriteToggle",this,this.state.overwrite))},hasFocus:function(){return document.activeElement==this.display.input},scrollTo:Ib(null,function(a,b){Yc(this,a,b)}),getScrollInfo:function(){var a=this.display.scroller,b=gf;return{left:a.scrollLeft,top:a.scrollTop,height:a.scrollHeight-b,width:a.scrollWidth-b,clientHeight:a.clientHeight-b,clientWidth:a.clientWidth-b}},scrollIntoView:Ib(null,function(a,b){null==a?a={from:this.doc.sel.head,to:null}:"number"==typeof a?a={from:Gc(a,0),to:null}:null==a.from&&(a={from:a,to:null}),a.to||(a.to=a.from),b||(b=0);var c=a;null!=a.from.line&&(this.curOp.scrollToPos={from:a.from,to:a.to,margin:b},c={from:yb(this,a.from),to:yb(this,a.to)});var d=Xc(this,Math.min(c.from.left,c.to.left),Math.min(c.from.top,c.to.top)-b,Math.max(c.from.right,c.to.right),Math.max(c.from.bottom,c.to.bottom)+b);Yc(this,d.scrollLeft,d.scrollTop)}),setSize:Ib(null,function(a,b){function c(a){return"number"==typeof a||/^\d+$/.test(String(a))?a+"px":a}null!=a&&(this.display.wrapper.style.width=c(a)),null!=b&&(this.display.wrapper.style.height=c(b)),this.options.lineWrapping&&(this.display.measureLineCache.length=this.display.measureLineCachePos=0),this.curOp.forceUpdate=!0,$e(this,"refresh",this)}),operation:function(a){return Kb(this,a)},refresh:Ib(null,function(){var a=this.display.cachedTextHeight;sb(this),Yc(this,this.doc.scrollLeft,this.doc.scrollTop),Lb(this),(null==a||Math.abs(a-Db(this.display))>.5)&&F(this),$e(this,"refresh",this)}),swapDoc:Ib(null,function(a){var b=this.doc;return b.cm=null,xe(this,a),sb(this),Pb(this,!0),Yc(this,a.scrollLeft,a.scrollTop),bf(this,"swapDoc",this,b),b}),getInputField:function(){return this.display.input},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},ff(z);var ed=z.optionHandlers={},fd=z.defaults={},hd=z.Init={toString:function(){return"CodeMirror.Init"}};gd("value","",function(a,b){a.setValue(b)},!0),gd("mode",null,function(a,b){a.doc.modeOption=b,B(a)},!0),gd("indentUnit",2,B,!0),gd("indentWithTabs",!1),gd("smartIndent",!0),gd("tabSize",4,function(a){C(a),sb(a),Lb(a)},!0),gd("specialChars",/[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g,function(a,b){a.options.specialChars=new RegExp(b.source+(b.test(" ")?"":"| "),"g"),a.refresh()},!0),gd("specialCharPlaceholder",je,function(a){a.refresh()},!0),gd("electricChars",!0),gd("rtlMoveVisually",!t),gd("wholeLineUpdateBefore",!0),gd("theme","default",function(a){H(a),I(a)},!0),gd("keyMap","default",G),gd("extraKeys",null),gd("onKeyEvent",null),gd("onDragEvent",null),gd("lineWrapping",!1,D,!0),gd("gutters",[],function(a){M(a.options),I(a)},!0),gd("fixedGutter",!0,function(a,b){a.display.gutters.style.left=b?S(a.display)+"px":"0",a.refresh()},!0),gd("coverGutterNextToScrollbar",!1,N,!0),gd("lineNumbers",!1,function(a){M(a.options),I(a)},!0),gd("firstLineNumber",1,I,!0),gd("lineNumberFormatter",function(a){return a},I,!0),gd("showCursorWhenSelecting",!1,ab,!0),gd("resetSelectionOnContextMenu",!0),gd("readOnly",!1,function(a,b){"nocursor"==b?(sc(a),a.display.input.blur(),a.display.disabled=!0):(a.display.disabled=!1,b||Pb(a,!0))}),gd("disableInput",!1,function(a,b){b||Pb(a,!0)},!0),gd("dragDrop",!0),gd("cursorBlinkRate",530),gd("cursorScrollMargin",0),gd("cursorHeight",1),gd("workTime",100),gd("workDelay",100),gd("flattenSpans",!0,C,!0),gd("addModeClass",!1,C,!0),gd("pollInterval",100),gd("undoDepth",40,function(a,b){a.doc.history.undoDepth=b}),gd("historyEventDelay",500),gd("viewportMargin",10,function(a){a.refresh()},!0),gd("maxHighlightLength",1e4,C,!0),gd("crudeMeasuringFrom",1e4),gd("moveInputWithCursor",!0,function(a,b){b||(a.display.inputDiv.style.top=a.display.inputDiv.style.left=0)}),gd("tabindex",null,function(a,b){a.display.input.tabIndex=b||""}),gd("autofocus",null);var id=z.modes={},jd=z.mimeModes={};z.defineMode=function(a,b){if(z.defaults.mode||"null"==a||(z.defaults.mode=a),arguments.length>2){b.dependencies=[];for(var c=2;c0&&b.ch=this.string.length},sol:function(){return this.pos==this.lineStart},peek:function(){return this.string.charAt(this.pos)||void 0},next:function(){return this.posb},eatSpace:function(){for(var a=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>a},skipToEnd:function(){this.pos=this.string.length},skipTo:function(a){var b=this.string.indexOf(a,this.pos);return b>-1?(this.pos=b,!0):void 0},backUp:function(a){this.pos-=a},column:function(){return this.lastColumnPos0?null:(f&&b!==!1&&(this.pos+=f[0].length),f)}var d=function(a){return c?a.toLowerCase():a},e=this.string.substr(this.pos,a.length);return d(e)==d(a)?(b!==!1&&(this.pos+=a.length),!0):void 0},current:function(){return this.string.slice(this.start,this.pos)},hideFirstChars:function(a,b){this.lineStart+=a;try{return b()}finally{this.lineStart-=a}}},z.StringStream=vd,z.TextMarker=wd,ff(wd),wd.prototype.clear=function(){if(!this.explicitlyCleared){var a=this.doc.cm,b=a&&!a.curOp;if(b&&Gb(a),ef(this,"clear")){var c=this.find();c&&bf(this,"clear",c.from,c.to)}for(var d=null,e=null,f=0;fa.display.maxLineLength&&(a.display.maxLine=i,a.display.maxLineLength=j,a.display.maxLineChanged=!0)}null!=d&&a&&Lb(a,d,e+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,a&&Sc(a)),bf(a,"markerCleared",a,this),b&&Hb(a)}},wd.prototype.find=function(a){for(var b,c,d=0;d=b.display.showingFrom&&a.linec;++c){var e=this.lines[c];this.height-=e.height,ae(e),bf(e,"delete")}this.lines.splice(a,b)},collapse:function(a){a.splice.apply(a,[a.length,0].concat(this.lines))},insertInner:function(a,b,c){this.height+=c,this.lines=this.lines.slice(0,a).concat(b).concat(this.lines.slice(a));for(var d=0,e=b.length;e>d;++d)b[d].parent=this},iterN:function(a,b,c){for(var d=a+b;d>a;++a)if(c(this.lines[a]))return!0}},re.prototype={chunkSize:function(){return this.size},removeInner:function(a,b){this.size-=b;for(var c=0;ca){var f=Math.min(b,e-a),g=d.height;if(d.removeInner(a,f),this.height-=g-d.height,e==f&&(this.children.splice(c--,1),d.parent=null),0==(b-=f))break;a=0}else a-=e}if(this.size-b<25){var h=[];this.collapse(h),this.children=[new qe(h)],this.children[0].parent=this}},collapse:function(a){for(var b=0,c=this.children.length;c>b;++b)this.children[b].collapse(a)},insertInner:function(a,b,c){this.size+=b.length,this.height+=c;for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>=a){if(f.insertInner(a,b,c),f.lines&&f.lines.length>50){for(;f.lines.length>50;){var h=f.lines.splice(f.lines.length-25,25),i=new qe(h);f.height-=i.height,this.children.splice(d+1,0,i),i.parent=this}this.maybeSpill()}break}a-=g}},maybeSpill:function(){if(!(this.children.length<=10)){var a=this;do{var b=a.children.splice(a.children.length-5,5),c=new re(b);if(a.parent){a.size-=c.size,a.height-=c.height;var e=pf(a.parent.children,a);a.parent.children.splice(e+1,0,c)}else{var d=new re(a.children);d.parent=a,a.children=[d,c],a=d}c.parent=a.parent}while(a.children.length>10);a.parent.maybeSpill()}},iterN:function(a,b,c){for(var d=0,e=this.children.length;e>d;++d){var f=this.children[d],g=f.chunkSize();if(g>a){var h=Math.min(b,g-a);if(f.iterN(a,h,c))return!0;if(0==(b-=h))break;a=0}else a-=g}}};var se=0,te=z.Doc=function(a,b,c){if(!(this instanceof te))return new te(a,b,c);null==c&&(c=0),re.call(this,[new qe([new $d("",null)])]),this.first=c,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.history=Ge(),this.cleanGeneration=1,this.frontier=c;var d=Gc(c,0);this.sel={from:d,to:d,head:d,anchor:d,shift:!1,extend:!1,goalColumn:null},this.id=++se,this.modeOption=b,"string"==typeof a&&(a=Kf(a)),pe(this,{from:d,to:d,text:a},null,{head:d,anchor:d})};te.prototype=qf(re.prototype,{constructor:te,iter:function(a,b,c){c?this.iterN(a-this.first,b-a,c):this.iterN(this.first,this.first+this.size,a)},insert:function(a,b){for(var c=0,d=0,e=b.length;e>d;++d)c+=b[d].height;this.insertInner(a-this.first,b,c)},remove:function(a,b){this.removeInner(a-this.first,b)},getValue:function(a){var b=Ae(this,this.first,this.first+this.size);return a===!1?b:b.join(a||"\n")},setValue:function(a){var b=Gc(this.first,0),c=this.first+this.size-1;zc(this,{from:b,to:Gc(c,ye(this,c).text.length),text:Kf(a),origin:"setValue"},{head:b,anchor:b},!0)},replaceRange:function(a,b,c,d){b=Mc(this,b),c=c?Mc(this,c):b,Fc(this,a,b,c,d)},getRange:function(a,b,c){var d=ze(this,Mc(this,a),Mc(this,b));return c===!1?d:d.join(c||"\n")},getLine:function(a){var b=this.getLineHandle(a);return b&&b.text},setLine:function(a,b){Oc(this,a)&&Fc(this,b,Gc(a,0),Mc(this,Gc(a)))},removeLine:function(a){a?Fc(this,"",Mc(this,Gc(a-1)),Mc(this,Gc(a))):Fc(this,"",Gc(0,0),Mc(this,Gc(1,0)))},getLineHandle:function(a){return Oc(this,a)?ye(this,a):void 0},getLineNumber:function(a){return Ce(a)},getLineHandleVisualStart:function(a){return"number"==typeof a&&(a=ye(this,a)),Rd(this,a)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(a){return Mc(this,a)},getCursor:function(a){var c,b=this.sel;return c=null==a||"head"==a?b.head:"anchor"==a?b.anchor:"end"==a||a===!1?b.to:b.from,Kc(c)},somethingSelected:function(){return!Hc(this.sel.head,this.sel.anchor)},setCursor:Jb(function(a,b,c){var d=Mc(this,"number"==typeof a?Gc(a,b||0):a);c?Pc(this,d):Rc(this,d,d)}),setSelection:Jb(function(a,b,c){Rc(this,Mc(this,a),Mc(this,b||a),c)}),extendSelection:Jb(function(a,b,c){Pc(this,Mc(this,a),b&&Mc(this,b),c)}),getSelection:function(a){return this.getRange(this.sel.from,this.sel.to,a)},replaceSelection:function(a,b,c){zc(this,{from:this.sel.from,to:this.sel.to,text:Kf(a),origin:c},b||"around")},undo:Jb(function(){Bc(this,"undo")}),redo:Jb(function(){Bc(this,"redo")}),setExtending:function(a){this.sel.extend=a},historySize:function(){var a=this.history;return{undo:a.done.length,redo:a.undone.length}},clearHistory:function(){this.history=Ge(this.history.maxGeneration)},markClean:function(){this.cleanGeneration=this.changeGeneration(!0)},changeGeneration:function(a){return a&&(this.history.lastOp=this.history.lastOrigin=null),this.history.generation},isClean:function(a){return this.history.generation==(a||this.cleanGeneration)},getHistory:function(){return{done:Me(this.history.done),undone:Me(this.history.undone)}},setHistory:function(a){var b=this.history=Ge(this.history.maxGeneration);b.done=a.done.slice(0),b.undone=a.undone.slice(0)},markText:function(a,b,c){return yd(this,Mc(this,a),Mc(this,b),c,"range")},setBookmark:function(a,b){var c={replacedWith:b&&(null==b.nodeType?b.widget:b),insertLeft:b&&b.insertLeft,clearWhenEmpty:!1};return a=Mc(this,a),yd(this,a,a,c,"bookmark")},findMarksAt:function(a){a=Mc(this,a);var b=[],c=ye(this,a.line).markedSpans;if(c)for(var d=0;d=a.ch)&&b.push(e.marker.parent||e.marker)}return b},findMarks:function(a,b){a=Mc(this,a),b=Mc(this,b);var c=[],d=a.line;return this.iter(a.line,b.line+1,function(e){var f=e.markedSpans;if(f)for(var g=0;gh.to||null==h.from&&d!=a.line||d==b.line&&h.from>b.ch||c.push(h.marker.parent||h.marker)}++d}),c},getAllMarks:function(){var a=[];return this.iter(function(b){var c=b.markedSpans;if(c)for(var d=0;da?(b=a,!0):(a-=e,++c,void 0)}),Mc(this,Gc(c,b))},indexFromPos:function(a){a=Mc(this,a);var b=a.ch;return a.lineb&&(b=a.from),null!=a.to&&a.to=8208&&8212>=c}:h&&(Ff=function(a,b){if(b>1&&45==a.charCodeAt(b-1)){if(/\w/.test(a.charAt(b-2))&&/[^\-?\.]/.test(a.charAt(b)))return!0;if(b>2&&/[\d\.,]/.test(a.charAt(b-2))&&/[\d\.,]/.test(a.charAt(b)))return!1}return/[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|\u2026[\w~`@#$%\^&*(_=+{[><]/.test(a.slice(b-1,b+1))});var Gf,If,Kf=3!="\n\nb".split(/\n/).length?function(a){for(var b=0,c=[],d=a.length;d>=b;){var e=a.indexOf("\n",b);-1==e&&(e=a.length);var f=a.slice(b,"\r"==a.charAt(e-1)?e-1:e),g=f.indexOf("\r");-1!=g?(c.push(f.slice(0,g)),b+=g+1):(c.push(f),b=e+1)}return c}:function(a){return a.split(/\r\n?|\n/)};z.splitLines=Kf;var Lf=window.getSelection?function(a){try{return a.selectionStart!=a.selectionEnd}catch(b){return!1}}:function(a){try{var b=a.ownerDocument.selection.createRange()}catch(c){}return b&&b.parentElement()==a?0!=b.compareEndPoints("StartToEnd",b):!1},Mf=function(){var a=zf("div");return"oncopy"in a?!0:(a.setAttribute("oncopy","return;"),"function"==typeof a.oncopy)}(),Nf={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",61:"=",91:"Mod",92:"Mod",93:"Mod",107:"=",109:"-",127:"Delete",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"};z.keyNames=Nf,function(){for(var a=0;10>a;a++)Nf[a+48]=Nf[a+96]=String(a);for(var a=65;90>=a;a++)Nf[a]=String.fromCharCode(a);for(var a=1;12>=a;a++)Nf[a+111]=Nf[a+63235]="F"+a}();var Wf,_f=function(){function c(c){return 255>=c?a.charAt(c):c>=1424&&1524>=c?"R":c>=1536&&1791>=c?b.charAt(c-1536):c>=1792&&2220>=c?"r":"L"}var a="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL",b="rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr",d=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,e=/[stwN]/,f=/[LRr]/,g=/[Lb1n]/,h=/[1n]/,i="L";return function(a){if(!d.test(a))return!1;for(var l,b=a.length,j=[],k=0;b>k;++k)j.push(l=c(a.charCodeAt(k)));for(var k=0,m=i;b>k;++k){var l=j[k];"m"==l?j[k]=m:m=l}for(var k=0,n=i;b>k;++k){var l=j[k];"1"==l&&"r"==n?j[k]="n":f.test(l)&&(n=l,"r"==l&&(j[k]="R"))}for(var k=1,m=j[0];b-1>k;++k){var l=j[k];"+"==l&&"1"==m&&"1"==j[k+1]?j[k]="1":","!=l||m!=j[k+1]||"1"!=m&&"n"!=m||(j[k]=m),m=l}for(var k=0;b>k;++k){var l=j[k];if(","==l)j[k]="N";else if("%"==l){for(var o=k+1;b>o&&"%"==j[o];++o);for(var p=k&&"!"==j[k-1]||b>o&&"1"==j[o]?"1":"N",q=k;o>q;++q)j[q]=p;k=o-1}}for(var k=0,n=i;b>k;++k){var l=j[k];"L"==n&&"1"==l?j[k]="L":f.test(l)&&(n=l)}for(var k=0;b>k;++k)if(e.test(j[k])){for(var o=k+1;b>o&&e.test(j[o]);++o);for(var r="L"==(k?j[k-1]:i),s="L"==(b>o?j[o]:i),p=r||s?"L":"R",q=k;o>q;++q)j[q]=p;k=o-1}for(var u,t=[],k=0;b>k;)if(g.test(j[k])){var v=k;for(++k;b>k&&g.test(j[k]);++k);t.push({from:v,to:k,level:0})}else{var w=k,x=t.length;for(++k;b>k&&"L"!=j[k];++k);for(var q=w;k>q;)if(h.test(j[q])){q>w&&t.splice(x,0,{from:w,to:q,level:1});var y=q;for(++q;k>q&&h.test(j[q]);++q);t.splice(x,0,{from:y,to:q,level:2}),w=q}else++q;k>w&&t.splice(x,0,{from:w,to:k,level:1})}return 1==t[0].level&&(u=a.match(/^\s+/))&&(t[0].from=u[0].length,t.unshift({from:0,to:u[0].length,level:0})),1==nf(t).level&&(u=a.match(/\s+$/))&&(nf(t).to-=u[0].length,t.push({from:b-u[0].length,to:b,level:0})),t[0].level!=nf(t).level&&t.push({from:b,to:b,level:t[0].level}),t}}();return z.version="3.22.1",z}(),CodeMirror.defineMode("javascript",function(a,b){function k(a){for(var c,b=!1,d=!1;null!=(c=a.next());){if(!b){if("/"==c&&!d)return;"["==c?d=!0:d&&"]"==c&&(d=!1)}b=!b&&"\\"==c}}function n(a,b,c){return l=a,m=c,b}function o(a,b){var c=a.next();if('"'==c||"'"==c)return b.tokenize=p(c),b.tokenize(a,b);if("."==c&&a.match(/^\d+(?:[eE][+\-]?\d+)?/))return n("number","number");if("."==c&&a.match(".."))return n("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(c))return n(c);if("="==c&&a.eat(">"))return n("=>","operator");if("0"==c&&a.eat(/x/i))return a.eatWhile(/[\da-f]/i),n("number","number");if(/\d/.test(c))return a.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/),n("number","number");if("/"==c)return a.eat("*")?(b.tokenize=q,q(a,b)):a.eat("/")?(a.skipToEnd(),n("comment","comment")):"operator"==b.lastType||"keyword c"==b.lastType||"sof"==b.lastType||/^[\[{}\(,;:]$/.test(b.lastType)?(k(a),a.eatWhile(/[gimy]/),n("regexp","string-2")):(a.eatWhile(i),n("operator","operator",a.current()));if("`"==c)return b.tokenize=r,r(a,b);if("#"==c)return a.skipToEnd(),n("error","error");if(i.test(c))return a.eatWhile(i),n("operator","operator",a.current());a.eatWhile(/[\w\$_]/);var d=a.current(),e=h.propertyIsEnumerable(d)&&h[d];return e&&"."!=b.lastType?n(e.type,e.style,d):n("variable","variable",d)}function p(a){return function(b,c){var f,d=!1;if(e&&"@"==b.peek()&&b.match(j))return c.tokenize=o,n("jsonld-keyword","meta");for(;null!=(f=b.next())&&(f!=a||d);)d=!d&&"\\"==f;return d||(c.tokenize=o),n("string","string")}}function q(a,b){for(var d,c=!1;d=a.next();){if("/"==d&&c){b.tokenize=o;break}c="*"==d}return n("comment","comment")}function r(a,b){for(var d,c=!1;null!=(d=a.next());){if(!c&&("`"==d||"$"==d&&a.eat("{"))){b.tokenize=o;break}c=!c&&"\\"==d}return n("quasi","string-2",a.current())}function t(a,b){b.fatArrowAt&&(b.fatArrowAt=null);var c=a.string.indexOf("=>",a.start);if(!(0>c)){for(var d=0,e=!1,f=c-1;f>=0;--f){var g=a.string.charAt(f),h=s.indexOf(g);if(h>=0&&3>h){if(!d){++f;break}if(0==--d)break}else if(h>=3&&6>h)++d;else if(/[$\w]/.test(g))e=!0;else if(e&&!d){++f;break}}e&&!d&&(b.fatArrowAt=f)}}function v(a,b,c,d,e,f){this.indented=a,this.column=b,this.type=c,this.prev=e,this.info=f,null!=d&&(this.align=d)}function w(a,b){for(var c=a.localVars;c;c=c.next)if(c.name==b)return!0;for(var d=a.context;d;d=d.prev)for(var c=d.vars;c;c=c.next)if(c.name==b)return!0}function x(a,b,c,d,e){var g=a.cc;for(y.state=a,y.stream=e,y.marked=null,y.cc=g,a.lexical.hasOwnProperty("align")||(a.lexical.align=!0);;){var h=g.length?g.pop():f?J:I;if(h(c,d)){for(;g.length&&g[g.length-1].lex;)g.pop()();return y.marked?y.marked:"variable"==c&&w(a,d)?"variable-2":b}}}function z(){for(var a=arguments.length-1;a>=0;a--)y.cc.push(arguments[a])}function A(){return z.apply(null,arguments),!0}function B(a){function c(b){for(var c=b;c;c=c.next)if(c.name==a)return!0;return!1}var d=y.state;if(d.context){if(y.marked="def",c(d.localVars))return;d.localVars={name:a,next:d.localVars}}else{if(c(d.globalVars))return;b.globalVars&&(d.globalVars={name:a,next:d.globalVars})}}function D(){y.state.context={prev:y.state.context,vars:y.state.localVars},y.state.localVars=C}function E(){y.state.localVars=y.state.context.vars,y.state.context=y.state.context.prev}function F(a,b){var c=function(){var c=y.state,d=c.indented;"stat"==c.lexical.type&&(d=c.lexical.indented),c.lexical=new v(d,y.stream.column(),a,null,c.lexical,b)};return c.lex=!0,c}function G(){var a=y.state;a.lexical.prev&&(")"==a.lexical.type&&(a.indented=a.lexical.indented),a.lexical=a.lexical.prev)}function H(a){return function(b){return b==a?A():";"==a?z():A(arguments.callee)}}function I(a,b){return"var"==a?A(F("vardef",b.length),cb,H(";"),G):"keyword a"==a?A(F("form"),J,I,G):"keyword b"==a?A(F("form"),I,G):"{"==a?A(F("}"),_,G):";"==a?A():"if"==a?A(F("form"),J,I,G,hb):"function"==a?A(nb):"for"==a?A(F("form"),ib,I,G):"variable"==a?A(F("stat"),U):"switch"==a?A(F("form"),J,F("}","switch"),H("{"),_,G,G):"case"==a?A(J,H(":")):"default"==a?A(H(":")):"catch"==a?A(F("form"),D,H("("),ob,H(")"),I,G,E):"module"==a?A(F("form"),D,sb,E,G):"class"==a?A(F("form"),pb,rb,G):"export"==a?A(F("form"),tb,G):"import"==a?A(F("form"),ub,G):z(F("stat"),J,H(";"),G)}function J(a){return L(a,!1)}function K(a){return L(a,!0)}function L(a,b){if(y.state.fatArrowAt==y.stream.start){var c=b?T:S;if("("==a)return A(D,F(")"),Z(db,")"),G,H("=>"),c,E);if("variable"==a)return z(D,db,H("=>"),c,E)}var d=b?P:O;return u.hasOwnProperty(a)?A(d):"function"==a?A(nb):"keyword c"==a?A(b?N:M):"("==a?A(F(")"),M,zb,H(")"),G,d):"operator"==a||"spread"==a?A(b?K:J):"["==a?A(F("]"),xb,G,d):"{"==a?$(W,"}",null,d):A()}function M(a){return a.match(/[;\}\)\],]/)?z():z(J)}function N(a){return a.match(/[;\}\)\],]/)?z():z(K)}function O(a,b){return","==a?A(J):P(a,b,!1)}function P(a,b,c){var d=0==c?O:P,e=0==c?J:K;return"=>"==b?A(D,c?T:S,E):"operator"==a?/\+\+|--/.test(b)?A(d):"?"==b?A(J,H(":"),e):A(e):"quasi"==a?(y.cc.push(d),Q(b)):";"!=a?"("==a?$(K,")","call",d):"."==a?A(V,d):"["==a?A(F("]"),M,H("]"),G,d):void 0:void 0}function Q(a){return"${"!=a.slice(a.length-2)?A():A(J,R)}function R(a){return"}"==a?(y.marked="string-2",y.state.tokenize=r,A()):void 0}function S(a){return t(y.stream,y.state),"{"==a?z(I):z(J)}function T(a){return t(y.stream,y.state),"{"==a?z(I):z(K)}function U(a){return":"==a?A(G,I):z(O,H(";"),G)}function V(a){return"variable"==a?(y.marked="property",A()):void 0}function W(a,b){if("variable"==a){if(y.marked="property","get"==b||"set"==b)return A(X)}else if("number"==a||"string"==a)y.marked=e?"property":a+" property";else if("["==a)return A(J,H("]"),Y);return u.hasOwnProperty(a)?A(Y):void 0}function X(a){return"variable"!=a?z(Y):(y.marked="property",A(nb))}function Y(a){return":"==a?A(K):"("==a?z(nb):void 0}function Z(a,b){function c(d){if(","==d){var e=y.state.lexical;return"call"==e.info&&(e.pos=(e.pos||0)+1),A(a,c)}return d==b?A():A(H(b))}return function(d){return d==b?A():z(a,c)}}function $(a,b,c){for(var d=3;d!?|~^]/,j=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/,s="([{}])",u={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,"this":!0,"jsonld-keyword":!0},y={state:null,column:null,marked:null,cc:null},C={name:"this",next:{name:"arguments"}};return G.lex=!0,{startState:function(a){var d={tokenize:o,lastType:"sof",cc:[],lexical:new v((a||0)-c,0,"block",!1),localVars:b.localVars,context:b.localVars&&{vars:b.localVars},indented:0};return b.globalVars&&(d.globalVars=b.globalVars),d},token:function(a,b){if(a.sol()&&(b.lexical.hasOwnProperty("align")||(b.lexical.align=!1),b.indented=a.indentation(),t(a,b)),b.tokenize!=q&&a.eatSpace())return null;var c=b.tokenize(a,b);return"comment"==l?c:(b.lastType="operator"!=l||"++"!=m&&"--"!=m?l:"incdec",x(b,c,l,m,a))},indent:function(a,e){if(a.tokenize==q)return CodeMirror.Pass;if(a.tokenize!=o)return 0;for(var f=e&&e.charAt(0),g=a.lexical,h=a.cc.length-1;h>=0;--h){var i=a.cc[h];if(i==G)g=g.prev;else if(i!=hb)break}"stat"==g.type&&"}"==f&&(g=g.prev),d&&")"==g.type&&"stat"==g.prev.type&&(g=g.prev);var j=g.type,k=f==j;return"vardef"==j?g.indented+("operator"==a.lastType||","==a.lastType?g.info+1:0):"form"==j&&"{"==f?g.indented:"form"==j?g.indented+c:"stat"==j?g.indented+("operator"==a.lastType||","==a.lastType?d||c:0):"switch"!=g.info||k||0==b.doubleIndentSwitch?g.align?g.column+(k?0:1):g.indented+(k?0:c):g.indented+(/^(?:case|default)\b/.test(e)?c:2*c)},electricChars:":{}",blockCommentStart:f?null:"/*",blockCommentEnd:f?null:"*/",lineComment:f?null:"//",fold:"brace",helperType:f?"json":"javascript",jsonldMode:e,jsonMode:f}}),CodeMirror.defineMIME("text/javascript","javascript"),CodeMirror.defineMIME("text/ecmascript","javascript"),CodeMirror.defineMIME("application/javascript","javascript"),CodeMirror.defineMIME("application/ecmascript","javascript"),CodeMirror.defineMIME("application/json",{name:"javascript",json:!0}),CodeMirror.defineMIME("application/x-json",{name:"javascript",json:!0}),CodeMirror.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),CodeMirror.defineMIME("text/typescript",{name:"javascript",typescript:!0}),CodeMirror.defineMIME("application/typescript",{name:"javascript",typescript:!0}),function(){function d(a,d,e){function r(d,e,f){if(d.text){var h=m?0:d.text.length-1,i=m?d.text.length:-1;if(d.text.length>g)return null;for(null!=f&&(h=f+n);h!=i;h+=n){var j=d.text.charAt(h);if(q.test(j)&&a.getTokenTypeAt(b(e,h+1))==o){var k=c[j];if(">"==k.charAt(1)==m)p.push(j);else{if(p.pop()!=k.charAt(0))return{pos:h,match:!1};if(!p.length)return{pos:h,match:!0}}}}}}var f=a.state.matchBrackets,g=f&&f.maxScanLineLength||1e4,h=f&&f.maxScanLines||100,i=d||a.getCursor(),j=a.getLineHandle(i.line),k=i.ch-1,l=k>=0&&c[j.text.charAt(k)]||c[j.text.charAt(++k)];if(!l)return null;var m=">"==l.charAt(1),n=m?1:-1;if(e&&m!=(k==i.ch))return null;for(var t,o=a.getTokenTypeAt(b(i.line,k+1)),p=[j.text.charAt(k)],q=/[(){}[\]]/,s=i.line,u=m?Math.min(s+h,a.lineCount()):Math.max(-1,s-h);s!=u&&!(t=s==i.line?r(j,s,k):r(a.getLineHandle(s),s));s+=n);return{from:b(i.line,k),to:t&&b(s,t.pos),match:t&&t.match,forward:m}}function e(c,e){var f=c.state.matchBrackets.maxHighlightLineLength||1e3,g=d(c);if(!(!g||c.getLine(g.from.line).length>f||g.to&&c.getLine(g.to.line).length>f)){var h=g.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket",i=c.markText(g.from,b(g.from.line,g.from.ch+1),{className:h}),j=g.to&&c.markText(g.to,b(g.to.line,g.to.ch+1),{className:h});a&&c.state.focused&&c.display.input.focus();var k=function(){c.operation(function(){i.clear(),j&&j.clear()})};return e?(setTimeout(k,800),void 0):k +}}function g(a){a.operation(function(){f&&(f(),f=null),a.somethingSelected()||(f=e(a,!1))})}var a=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),b=CodeMirror.Pos,c={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"},f=null;CodeMirror.defineOption("matchBrackets",!1,function(a,b,c){c&&c!=CodeMirror.Init&&a.off("cursorActivity",g),b&&(a.state.matchBrackets="object"==typeof b?b:{},a.on("cursorActivity",g))}),CodeMirror.defineExtension("matchBrackets",function(){e(this,!0)}),CodeMirror.defineExtension("findMatchingBracket",function(a,b){return d(this,a,b)})}(),CodeMirror.runMode=function(a,b,c,d){var e=CodeMirror.getMode(CodeMirror.defaults,b),f=/MSIE \d/.test(navigator.userAgent),g=f&&(null==document.documentMode||document.documentMode<9);if(1==c.nodeType){var h=d&&d.tabSize||CodeMirror.defaults.tabSize,i=c,j=0;i.innerHTML="",c=function(a,b){if("\n"==a)return i.appendChild(document.createTextNode(g?"\r":a)),j=0,void 0;for(var c="",d=0;;){var e=a.indexOf(" ",d);if(-1==e){c+=a.slice(d),j+=a.length-d;break}j+=e-d,c+=a.slice(d,e);var f=h-j%h;j+=f;for(var k=0;f>k;++k)c+=" ";d=e+1}if(b){var l=i.appendChild(document.createElement("span"));l.className="cm-"+b.replace(/ +/g," cm-"),l.appendChild(document.createTextNode(c))}else i.appendChild(document.createTextNode(c))}}for(var k=CodeMirror.splitLines(a),l=d&&d.state||CodeMirror.startState(e),m=0,n=k.length;n>m;++m){m&&c("\n");for(var o=new CodeMirror.StringStream(k[m]);!o.eol();){var p=e.token(o,l);c(o.current(),p,m,o.start,l),o.start=o.pos}}}; \ No newline at end of file diff --git a/addon-sdk/source/examples/actor-repl/data/codemirror.css b/addon-sdk/source/examples/actor-repl/data/codemirror.css new file mode 100644 index 000000000000..2b050e19f22a --- /dev/null +++ b/addon-sdk/source/examples/actor-repl/data/codemirror.css @@ -0,0 +1,264 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; +} +.CodeMirror-scroll { + /* Set scrolling behaviour here */ + overflow: auto; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* CURSOR */ + +.CodeMirror div.CodeMirror-cursor { + border-left: 1px solid black; + z-index: 3; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; + z-index: 1; +} +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} + +.cm-tab { display: inline-block; } + +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable {color: black;} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3 {color: #085;} +.cm-s-default .cm-property {color: black;} +.cm-s-default .cm-operator {color: black;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + line-height: 1; + position: relative; + overflow: hidden; + background: white; + color: black; +} + +.CodeMirror-scroll { + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actuall scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + padding-bottom: 30px; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + -moz-box-sizing: content-box; + box-sizing: content-box; + padding-bottom: 30px; + margin-bottom: -32px; + display: inline-block; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} + +.CodeMirror-lines { + cursor: text; +} +.CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; +} +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; +} + +.CodeMirror-widget {} + +.CodeMirror-wrap .CodeMirror-scroll { + overflow-x: hidden; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} +.CodeMirror-measure pre { position: static; } + +.CodeMirror div.CodeMirror-cursor { + position: absolute; + visibility: hidden; + border-right: none; + width: 0; +} +.CodeMirror-focused div.CodeMirror-cursor { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } + +.cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); +} + +/* IE7 hack to prevent it from returning funny offsetTops on the spans */ +.CodeMirror span { *vertical-align: text-bottom; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursor { + visibility: hidden; + } +} diff --git a/addon-sdk/source/examples/actor-repl/data/index.html b/addon-sdk/source/examples/actor-repl/data/index.html new file mode 100644 index 000000000000..07c47299d127 --- /dev/null +++ b/addon-sdk/source/examples/actor-repl/data/index.html @@ -0,0 +1,108 @@ + + + + + + + +
+

+            
+
+
+ + +

+  
+  
+  
+
diff --git a/addon-sdk/source/examples/actor-repl/data/main.css b/addon-sdk/source/examples/actor-repl/data/main.css
new file mode 100644
index 000000000000..03499944b0aa
--- /dev/null
+++ b/addon-sdk/source/examples/actor-repl/data/main.css
@@ -0,0 +1,117 @@
+/* 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/. */
+
+body
+{
+  position: absolute;
+  width: 100%;
+  margin: 0;
+  padding: 0;
+  background: white;
+}
+
+
+pre
+{
+  margin: 0;
+}
+
+section
+{
+  border-top: 1px solid rgba(150, 150, 150, 0.5);
+}
+
+.CodeMirror {
+  height: auto;
+}
+.CodeMirror-scroll {
+  overflow-y: hidden;
+  overflow-x: auto;
+}
+
+.request,
+.response,
+.input
+{
+  border-left: 5px solid;
+  padding-left: 10px;
+}
+
+.request:not(:empty),
+.response.pending
+{
+  padding: 5px;
+}
+
+.input
+{
+  padding-left: 6px;
+  border-color: lightgreen;
+}
+.input.invalid
+{
+  border-color: orange;
+}
+
+.request
+{
+  border-color: lightgrey;
+}
+
+.response
+{
+  border-color: grey;
+}
+.response.error
+{
+  border-color: red;
+}
+
+.response.message
+{
+    border-color: lightblue;
+}
+
+.response .one,
+.response .two,
+.response .three
+{
+  width: 0;
+  height: auto;
+}
+
+
+
+.response.pending .one,
+.response.pending .two,
+.response.pending .three
+{
+  width: 10px;
+  height: 10px;
+  background-color: rgba(150, 150, 150, 0.5);
+
+  border-radius: 100%;
+  display: inline-block;
+  animation: bouncedelay 1.4s infinite ease-in-out;
+  /* Prevent first frame from flickering when animation starts */
+  animation-fill-mode: both;
+}
+
+.response.pending .one
+{
+  animation-delay: -0.32s;
+}
+
+.response.pending .two
+{
+  animation-delay: -0.16s;
+}
+
+@keyframes bouncedelay {
+  0%, 80%, 100% {
+    transform: scale(0.0);
+  } 40% {
+    transform: scale(1.0);
+  }
+}
diff --git a/addon-sdk/source/examples/actor-repl/data/robot.png b/addon-sdk/source/examples/actor-repl/data/robot.png
new file mode 100644
index 0000000000000000000000000000000000000000..983516f981f2e0c2110e27d0c42961a5a6bb3d1d
GIT binary patch
literal 4184
zcmai02{@E(+a65WMcGr0$&zBmF0$_HX=<3nN
z30}<0r3zmsGIqP*l+oGhkx}>MppiO&`A!(H)z5}5L_Wuc`}0DJ-O*z`?Hly`oOB#E
zbj_1)Za{-?y7YrPB(?PPLc`9=_0NzH*ZMKZCUY^|@Lq5tSV>3ZFn~pGNKy5+7$1#3
z<#J_*fb1Ud^;)WgY^01VZw_&5(h_`l#$&T-lydU+
z!=pXwBUD3e5+JTD;lV?b!TgHii~_eay|_KDI|70tl+9~kjIS_i0G-neB0d^7=z|un
za>}s0YHaW*O)SU7%ij1tyLF1yF2-llSPOi4W}PkG6)T!6DUe4A_imv-n!xDyh($gW
zB26#p#4Z#f=gTkw0)&Scax&a!fEd!FG=a~x)Zguwpv*fu|2v+(fWgokZ-Ay@ioS>K
zfLEH?eOcK;3^Z9HTP{k|O@yMD!oG0woQkJrW-CSIFnI2@IONaN@26re`I36sv&h+$_V>7g{2G;3qN8AUfvxzNq9$Ie5~
z3T(umYWOoNay^KXYPWWZce+|Ze8%t&v3NmCpyBKU_j1^g7Tg!-Tf&Vj!9u|&DeNTgSVTEaZR_F`&cB;n+46;}f+
zKU~wntV|>uk&vGDsHw71t!AKRpw8n5r4-wSqX=q*|_TP}y@RaocfPgb?6
zMZokja#Nk}I%haXJKvd7=&%rNND57=K5AB^Ial#k^s%s@_Q2!7w>4EJRVwe1@1;)|
zDCKVtB+qrMo%%#tV@8T1uhP!YglK}a%GZ|;w@N#Gle;AFn2=1UC&Yi1pQ$BN$zzJ;
zD2KfUiPX)rK4)*Gf>Yg6=~Cm1jjb?4+(Vhg=wh=$X-_dvgy*Q|_7J2bj{Jm-&mw0!
z%I{6@M9o*!Mc=5|^8BN1UTr>EFhj6WP(aX1kSO1&Adumc(Vaodn3eCU@~~xn0koyr
z&c1MvPEG&ZYw0Fh8LOOATDJ5=s$V^SyhN?krLfY*J1y!n<~N}CPO(}KS_*Swa+(lXh`dRc)5VD;{b%!R^DcCr
zcX@d&W<{NPRjeX96P5&v>o&RkZg9fVsg7JlX7ify5R)%asPD?H_yC7L)gOMO+@|{K
zR$kzP&2y}3u{N=pyyLu%l1q}8r4}Sl!6o2_Y|vHn6`LK^HRYE5>>2P3y_)9P8k1v27VfwWxq76350nKmRlJ;Xy-O3!f%y`c?>3
zM)8~C&jw&mD4Fm+i9YteJXSWoFMNYi{Mi0$lQlxvM2IVd;27YWGiWuIO0`|s>NOdO
zoAqx;w~xP58{MthK6m8ekwk;ou9PRqvw~z+hr7h`D~VUitCKdImpzxCsH><)tH-Gy
zYxHj{34(q@?9%W0Z;gK)`7*mTvTX)D4}8k}i6tMX542`fXO(3>dgwZ^t%a_oKI|0q
zt)qzDATPc4j*fqXDzgHcJg_9o*f`#c
zymozX<+MJ*mH;YH<2`kp=cb51wrJz+_{Avd;uH(@Gepkr
ze&ynO>&9q*8y#CyAHFUZtB_SnGLawO4=s&3Ns&7>T+M7IEefB#I7%ai%k0K#P4V_Eb(4QIF2tij
zXv5JjJ^DRy$m0~Bn2AA)M-~;0P9BxZGo9MC+7^=}slKZm-W}dN-b>?dm8G6zM6g5u
zAI?2fF;ixuACeX*@SrQ3t3+N3+f9Y)`jeY7v7^{(cw
zR@YxyY_vvPz2)Wa2EH>5Az?h)oIq}`>^_OpK
zV{CJVKMY5|%vVI+G`>lh3mM2f(RV^h@61mXZSqDkWW%Z=3jlI+{~ZIZilcl#Hw{)Kc6qlv;s
z<*ng$^sMWr=>a@yx!_66L`kE@dgyM>w#!;q;@qOyH?!32I1T(Q=AG35F|^wZWh4CS
zwyX;L_WnO5v#%i>2LP}hI~a6;jEDRH07Eg#(#Frm#8|}zgN7hnG0sRx0NQsy8URoY
zP}!fNk$wnJ0NUFJrxKtB{t=-qq`~SeAP`6u
z>*}U*Nmu_Te1D||_VDxbRe?hBcsv9z2f<+7p)$(K%1~)psI08ieuNY*(8muEAmxKQ
z{U^y^Ji17n3l`<;hr;-P4tNpHnCpIOVDP~~e_ua!qJ2$F{yxeF_tV$DLudfP7b*jh
zhN98Xe?sE?E+K!3{6{3tGSC+Zy@bSJu47%0`{AemiD*A@|F?j@&FyPf-H$dgQPIV?
zTt_2){9wB3`x_8fl&gxClAN-89fSHnJABpotU~$L;6KdeUT>LKPK+lgfsGxjseh42IYW}Ud|7@KfyZgPP
z&a#jEs}I##9^G-10s!b4VY*tDhU^_yqt{xcIpf$4oj+ktfASuNsL5=urG1E*hyQHz
ziExf741yq&ezo)J%t0K%{&8nHEln}Wbs!w%&LQceo
zz;=gHYmsN7Y~}qP1j(NF{d~s|ic-CuT9krgt>prqrxaXxKR>;R!A-eT(S=|A!&p
z^GCf+^^A@-_lWi!4P&$GCQQ@4w`nLx)GFlqpz?`VaK~Q8m$zDXQ>i8b=GtQTp{;S@ksMpq%HGBK*@A{#0~k|r
nM?y4qog)1`;>@j9qbhz433Xti^oTd%;ByVrGu18Ab_)9+=>$;d

literal 0
HcmV?d00001

diff --git a/addon-sdk/source/examples/actor-repl/index.js b/addon-sdk/source/examples/actor-repl/index.js
new file mode 100644
index 000000000000..b99aaf8a2178
--- /dev/null
+++ b/addon-sdk/source/examples/actor-repl/index.js
@@ -0,0 +1,37 @@
+/* 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 { Panel } = require("dev/panel");
+const { Tool } = require("dev/toolbox");
+const { Class } = require("sdk/core/heritage");
+
+
+const REPLPanel = Class({
+  extends: Panel,
+  label: "Actor REPL",
+  tooltip: "Firefox debugging protocol REPL",
+  icon: "./robot.png",
+  url: "./index.html",
+  setup: function({debuggee}) {
+    this.debuggee = debuggee;
+  },
+  dispose: function() {
+    this.debuggee = null;
+  },
+  onReady: function() {
+    console.log("repl panel document is interactive");
+    this.debuggee.start();
+    this.postMessage("RDP", [this.debuggee]);
+  },
+  onLoad: function() {
+    console.log("repl panel document is fully loaded");
+  }
+});
+exports.REPLPanel = REPLPanel;
+
+
+const replTool = new Tool({
+  panels: { repl: REPLPanel }
+});
diff --git a/addon-sdk/source/examples/actor-repl/package.json b/addon-sdk/source/examples/actor-repl/package.json
new file mode 100644
index 000000000000..83a80d1b3cda
--- /dev/null
+++ b/addon-sdk/source/examples/actor-repl/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "actor-repl",
+  "id": "@actor-repl",
+  "title": "Actor REPL",
+  "description": "Actor REPL",
+  "version": "0.0.1",
+  "author": "Irakli Gozalishvili",
+  "main": "./index.js",
+  "license": "MPL 2.0"
+}
diff --git a/addon-sdk/source/examples/debug-client/data/client.js b/addon-sdk/source/examples/debug-client/data/client.js
new file mode 100644
index 000000000000..baec09105320
--- /dev/null
+++ b/addon-sdk/source/examples/debug-client/data/client.js
@@ -0,0 +1,816 @@
+/* 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/. */
+(function(exports) {
+"use strict";
+
+
+var describe = Object.getOwnPropertyDescriptor;
+var Class = fields => {
+  var constructor = fields.constructor || function() {};
+  var ancestor = fields.extends || Object;
+
+
+
+  var descriptor = {};
+  for (var key of Object.keys(fields))
+    descriptor[key] = describe(fields, key);
+
+  var prototype = Object.create(ancestor.prototype, descriptor);
+
+  constructor.prototype = prototype;
+  prototype.constructor = constructor;
+
+  return constructor;
+};
+
+
+var bus = function Bus() {
+  var parser = new DOMParser();
+  return parser.parseFromString("", "application/xml").documentElement;
+}();
+
+var GUID = new WeakMap();
+GUID.id = 0;
+var guid = x => GUID.get(x);
+var setGUID = x => {
+  GUID.set(x, ++ GUID.id);
+};
+
+var Emitter = Class({
+  extends: EventTarget,
+  constructor: function() {
+   this.setupEmitter();
+  },
+  setupEmitter: function() {
+    setGUID(this);
+  },
+  addEventListener: function(type, listener, capture) {
+    bus.addEventListener(type + "@" + guid(this),
+                         listener, capture);
+  },
+  removeEventListener: function(type, listener, capture) {
+    bus.removeEventListener(type + "@" + guid(this),
+                            listener, capture);
+  }
+});
+
+function dispatch(target, type, data) {
+  var event = new MessageEvent(type + "@" + guid(target), {
+    bubbles: true,
+    cancelable: false,
+    data: data
+  });
+  bus.dispatchEvent(event);
+}
+
+var supervisedWorkers = new WeakMap();
+var supervised = supervisor => {
+  if (!supervisedWorkers.has(supervisor)) {
+    supervisedWorkers.set(supervisor, new Map());
+    supervisor.connection.addActorPool(supervisor);
+  }
+  return supervisedWorkers.get(supervisor);
+};
+
+var Supervisor = Class({
+  extends: Emitter,
+  constructor: function(...params) {
+    this.setupEmitter(...params);
+    this.setupSupervisor(...params);
+  },
+  Supervisor: function(connection) {
+    this.connection = connection;
+  },
+  /**
+   * Return the parent pool for this client.
+   */
+  supervisor: function() {
+    return this.connection.poolFor(this.actorID);
+  },
+  /**
+   * Override this if you want actors returned by this actor
+   * to belong to a different actor by default.
+   */
+  marshallPool: function() { return this; },
+    /**
+   * Add an actor as a child of this pool.
+   */
+  supervise: function(actor) {
+    if (!actor.actorID)
+      actor.actorID = this.connection.allocID(actor.actorPrefix ||
+                                              actor.typeName);
+
+    supervised(this).set(actor.actorID, actor);
+    return actor;
+  },
+  /**
+   * Remove an actor as a child of this pool.
+   */
+  abandon: function(actor) {
+    supervised(this).delete(actor.actorID);
+  },
+  // true if the given actor ID exists in the pool.
+  has: function(actorID) {
+    return supervised(this).has(actorID);
+  },
+  // Same as actor, should update debugger connection to use 'actor'
+  // and then remove this.
+  get: function(actorID) {
+    return supervised(this).get(actorID);
+  },
+  actor: function(actorID) {
+    return supervised(this).get(actorID);
+  },
+  isEmpty: function() {
+    return supervised(this).size === 0;
+  },
+  /**
+   * For getting along with the debugger server pools, should be removable
+   * eventually.
+   */
+  cleanup: function() {
+    this.destroy();
+  },
+  destroy: function() {
+    var supervisor = this.supervisor();
+    if (supervisor)
+      supervisor.abandon(this);
+
+    for (var actor of supervised(this).values()) {
+      if (actor !== this) {
+        var destroy = actor.destroy;
+        // Disconnect destroy while we're destroying in case of (misbehaving)
+        // circular ownership.
+        if (destroy) {
+          actor.destroy = null;
+          destroy.call(actor);
+          actor.destroy = destroy;
+        }
+      }
+    }
+
+    this.connection.removeActorPool(this);
+    supervised(this).clear();
+  }
+
+});
+
+
+
+
+var mailbox = new WeakMap();
+var clientRequests = new WeakMap();
+
+var inbox = client => mailbox.get(client).inbox;
+var outbox = client => mailbox.get(client).outbox;
+var requests = client => clientRequests.get(client);
+
+
+var Receiver = Class({
+  receive: function(packet) {
+    if (packet.error)
+      this.reject(packet.error);
+    else
+      this.resolve(this.read(packet));
+  }
+});
+
+var Connection = Class({
+  constructor: function() {
+    // Queue of the outgoing messages.
+    this.outbox = [];
+    // Map of pending requests.
+    this.pending = new Map();
+    this.pools = new Set();
+  },
+  isConnected: function() {
+    return !!this.port
+  },
+  connect: function(port) {
+    this.port = port;
+    port.addEventListener("message", this);
+    port.start();
+
+    this.flush();
+  },
+  addPool: function(pool) {
+    this.pools.add(pool);
+  },
+  removePool: function(pool) {
+    this.pools.delete(pool);
+  },
+  poolFor: function(id) {
+    for (let pool of this.pools.values()) {
+      if pool.has(id)
+        return pool;
+    }
+  },
+  get: function(id) {
+    var pool = this.poolFor(id);
+    return pool && pool.get(id);
+  },
+  disconnect: function() {
+    this.port.stop();
+    this.port = null;
+    for (var request of this.pending.values()) {
+      request.catch(new Error("Connection closed"));
+    }
+    this.pending.clear();
+
+    var requests = this.outbox.splice(0);
+    for (var request of request) {
+      requests.catch(new Error("Connection closed"));
+    }
+  },
+  handleEvent: function(event) {
+    this.receive(event.data);
+  },
+  flush: function() {
+    if (this.isConnected()) {
+      for (var request of this.outbox) {
+        if (!this.pending.has(request.to)) {
+          this.outbox.splice(this.outbox.indexOf(request), 1);
+          this.pending.set(request.to, request);
+          this.send(request.packet);
+        }
+      }
+    }
+  },
+  send: function(packet) {
+    this.port.postMessage(packet);
+  },
+  request: function(packet) {
+    return new Promise(function(resolve, reject) {
+      this.outbox.push({
+        to: packet.to,
+        packet: packet,
+        receive: resolve,
+        catch: reject
+      });
+      this.flush();
+    });
+  },
+  receive: function(packet) {
+    var { from, type, why } = packet;
+    var receiver = this.pending.get(from);
+    if (!receiver) {
+      console.warn("Unable to handle received packet", data);
+    } else {
+      this.pending.delete(from);
+      if (packet.error)
+        receiver.catch(packet.error);
+      else
+        receiver.receive(packet);
+    }
+    this.flush();
+  },
+});
+
+/**
+ * Base class for client-side actor fronts.
+ */
+var Client = Class({
+  extends: Supervisor,
+  constructor: function(from=null, detail=null, connection=null) {
+    this.Client(from, detail, connection);
+  },
+  Client: function(form, detail, connection) {
+    this.Supervisor(connection);
+
+    if (form) {
+      this.actorID = form.actor;
+      this.from(form, detail);
+    }
+  },
+  connect: function(port) {
+    this.connection = new Connection(port);
+  },
+  actorID: null,
+  actor: function() {
+    return this.actorID;
+  },
+  /**
+   * Update the actor from its representation.
+   * Subclasses should override this.
+   */
+  form: function(form) {
+  },
+  /**
+   * Method is invokeid when packet received constitutes an
+   * event. By default such packets are demarshalled and
+   * dispatched on the client instance.
+   */
+  dispatch: function(packet) {
+  },
+  /**
+   * Method is invoked when packet is returned in response to
+   * a request. By default respond delivers response to a first
+   * request in a queue.
+   */
+  read: function(input) {
+    throw new TypeError("Subclass must implement read method");
+  },
+  write: function(input) {
+    throw new TypeError("Subclass must implement write method");
+  },
+  respond: function(packet) {
+    var [resolve, reject] = requests(this).shift();
+    if (packet.error)
+      reject(packet.error);
+    else
+      resolve(this.read(packet));
+  },
+  receive: function(packet) {
+    if (this.isEventPacket(packet)) {
+      this.dispatch(packet);
+    }
+    else if (requests(this).length) {
+      this.respond(packet);
+    }
+    else {
+      this.catch(packet);
+    }
+  },
+  send: function(packet) {
+    Promise.cast(packet.to || this.actor()).then(id => {
+      packet.to = id;
+      this.connection.send(packet);
+    })
+  },
+  request: function(packet) {
+    return this.connection.request(packet);
+  }
+});
+
+
+var Destructor = method => {
+  return function(...args) {
+    return method.apply(this, args).then(result => {
+      this.destroy();
+      return result;
+    });
+  };
+};
+
+var Profiled = (method, id) => {
+  return function(...args) {
+    var start = new Date();
+    return method.apply(this, args).then(result => {
+      var end = new Date();
+      this.telemetry.add(id, +end - start);
+      return result;
+    });
+  };
+};
+
+var Method = (request, response) => {
+  return response ? new BidirectionalMethod(request, response) :
+         new UnidirecationalMethod(request);
+};
+
+var UnidirecationalMethod = request => {
+  return function(...args) {
+    var packet = request.write(args, this);
+    this.connection.send(packet);
+    return Promise.resolve(void(0));
+  };
+};
+
+var BidirectionalMethod = (request, response) => {
+  return function(...args) {
+    var packet = request.write(args, this);
+    return this.connection.request(packet).then(packet => {
+      return response.read(packet, this);
+    });
+  };
+};
+
+
+Client.from = ({category, typeName, methods, events}) => {
+  var proto = {
+    constructor: function(...args) {
+      this.Client(...args);
+    },
+    extends: Client,
+    name: typeName
+  };
+
+  methods.forEach(({telemetry, request, response, name, oneway, release}) => {
+    var [reader, writer] = oneway ? [, new Request(request)] :
+                           [new Request(request), new Response(response)];
+    var method = new Method(request, response);
+    var profiler = telemetry ? new Profiler(method) : method;
+    var destructor = release ? new Destructor(profiler) : profiler;
+    proto[name] = destructor;
+  });
+
+  return Class(proto);
+};
+
+
+var defineType = (client, descriptor) => {
+  var type = void(0)
+  if (typeof(descriptor) === "string") {
+    if (name.indexOf(":") > 0)
+      type = makeCompoundType(descriptor);
+    else if (name.indexOf("#") > 0)
+      type = new ActorDetail(descriptor);
+    else if (client.specification[descriptor])
+      type = makeCategoryType(client.specification[descriptor]);
+  } else {
+    type = makeCategoryType(descriptor);
+  }
+
+  if (type)
+    client.types.set(type.name, type);
+  else
+    throw TypeError("Invalid type: " + descriptor);
+};
+
+
+var makeCompoundType = name => {
+  var index = name.indexOf(":");
+  var [baseType, subType] = [name.slice(0, index), parts.slice(1)];
+  return baseType === "array" ? new ArrayOf(subType) :
+         baseType === "nullable" ? new Maybe(subType) :
+         null;
+};
+
+var makeCategoryType = (descriptor) => {
+  var { category } = descriptor;
+  return category === "dict" ? new Dictionary(descriptor) :
+         category === "actor" ? new Actor(descriptor) :
+         null;
+};
+
+
+var typeFor = (client, type="primitive") => {
+  if (!client.types.has(type))
+    defineType(client, type);
+
+  return client.types.get(type);
+};
+
+
+var Client = Class({
+  constructor: function() {
+  },
+  setupTypes: function(specification) {
+    this.specification = specification;
+    this.types = new Map();
+  },
+  read: function(input, type) {
+    return typeFor(this, type).read(input, this);
+  },
+  write: function(input, type) {
+    return typeFor(this, type).write(input, this);
+  }
+});
+
+
+var Type = Class({
+  get name() {
+    return this.category ? this.category + ":" + this.type :
+           this.type;
+  },
+  read: function(input, client) {
+    throw new TypeError("`Type` subclass must implement `read`");
+  },
+  write: function(input, client) {
+    throw new TypeError("`Type` subclass must implement `write`");
+  }
+});
+
+
+var Primitve = Class({
+  extends: Type,
+  constuctor: function(type) {
+    this.type = type;
+  },
+  read: function(input, client) {
+    return input;
+  },
+  write: function(input, client) {
+    return input;
+  }
+});
+
+var Maybe = Class({
+  extends: Type,
+  category: "nullable",
+  constructor: function(type) {
+    this.type = type;
+  },
+  read: function(input, client) {
+    return input === null ? null :
+           input === void(0) ? void(0) :
+           client.read(input, this.type);
+  },
+  write: function(input, client) {
+    return input === null ? null :
+           input === void(0) ? void(0) :
+           client.write(input, this.type);
+  }
+});
+
+var ArrayOf = Class({
+  extends: Type,
+  category: "array",
+  constructor: function(type) {
+    this.type = type;
+  },
+  read: function(input, client) {
+    return input.map($ => client.read($, this.type));
+  },
+  write: function(input, client) {
+    return input.map($ => client.write($, this.type));
+  }
+});
+
+var Dictionary = Class({
+  exteds: Type,
+  category: "dict",
+  get name() { return this.type; },
+  constructor: function({typeName, specializations}) {
+    this.type = typeName;
+    this.types = specifications;
+  },
+  read: function(input, client) {
+    var output = {};
+    for (var key in input) {
+      output[key] = client.read(input[key], this.types[key]);
+    }
+    return output;
+  },
+  write: function(input, client) {
+    var output = {};
+    for (var key in input) {
+      output[key] = client.write(value, this.types[key]);
+    }
+    return output;
+  }
+});
+
+var Actor = Class({
+  exteds: Type,
+  category: "actor",
+  get name() { return this.type; },
+  constructor: function({typeName}) {
+    this.type = typeName;
+  },
+  read: function(input, client, detail) {
+    var id = value.actor;
+    var actor = void(0);
+    if (client.connection.has(id)) {
+      return client.connection.get(id).form(input, detail, client);
+    } else {
+      actor = Client.from(detail, client);
+      actor.actorID = id;
+      client.supervise(actor);
+    }
+  },
+  write: function(input, client, detail) {
+    if (input instanceof Actor) {
+      if (!input.actorID) {
+        client.supervise(input);
+      }
+      return input.from(detail);
+    }
+    return input.actorID;
+  }
+});
+
+var Root = Client.from({
+  "category": "actor",
+  "typeName": "root",
+  "methods": [
+    {"name": "listTabs",
+     "request": {},
+     "response": {
+     }
+    },
+    {"name": "listAddons"
+    },
+    {"name": "echo",
+
+    },
+    {"name": "protocolDescription",
+
+    }
+  ]
+});
+
+
+var ActorDetail = Class({
+  extends: Actor,
+  constructor: function(name, actor, detail) {
+    this.detail = detail;
+    this.actor = actor;
+  },
+  read: function(input, client) {
+    this.actor.read(input, client, this.detail);
+  },
+  write: function(input, client) {
+    this.actor.write(input, client, this.detail);
+  }
+});
+
+var registeredLifetimes = new Map();
+var LifeTime = Class({
+  extends: Type,
+  category: "lifetime",
+  constructor: function(lifetime, type) {
+    this.name = lifetime + ":" + type.name;
+    this.field = registeredLifetimes.get(lifetime);
+  },
+  read: function(input, client) {
+    return this.type.read(input, client[this.field]);
+  },
+  write: function(input, client) {
+    return this.type.write(input, client[this.field]);
+  }
+});
+
+var primitive = new Primitve("primitive");
+var string = new Primitve("string");
+var number = new Primitve("number");
+var boolean = new Primitve("boolean");
+var json = new Primitve("json");
+var array = new Primitve("array");
+
+
+var TypedValue = Class({
+  extends: Type,
+  constructor: function(name, type) {
+    this.TypedValue(name, type);
+  },
+  TypedValue: function(name, type) {
+    this.name = name;
+    this.type = type;
+  },
+  read: function(input, client) {
+    return this.client.read(input, this.type);
+  },
+  write: function(input, client) {
+    return this.client.write(input, this.type);
+  }
+});
+
+var Return = Class({
+  extends: TypedValue,
+  constructor: function(type) {
+    this.type = type
+  }
+});
+
+var Argument = Class({
+  extends: TypedValue,
+  constructor: function(...args) {
+    this.Argument(...args);
+  },
+  Argument: function(index, type) {
+    this.index = index;
+    this.TypedValue("argument[" + index + "]", type);
+  },
+  read: function(input, client, target) {
+    return target[this.index] = client.read(input, this.type);
+  }
+});
+
+var Option = Class({
+  extends: Argument,
+  constructor: function(...args) {
+    return this.Argument(...args);
+  },
+  read: function(input, client, target, name) {
+    var param = target[this.index] || (target[this.index] = {});
+    param[name] = input === void(0) ? input : client.read(input, this.type);
+  },
+  write: function(input, client, name) {
+    var value = input && input[name];
+    return value === void(0) ? value : client.write(value, this.type);
+  }
+});
+
+var Request = Class({
+  extends: Type,
+  constructor: function(template={}) {
+    this.type = template.type;
+    this.template = template;
+    this.params = findPlaceholders(template, Argument);
+  },
+  read: function(packet, client) {
+    var args = [];
+    for (var param of this.params) {
+      var {placeholder, path} = param;
+      var name = path[path.length - 1];
+      placeholder.read(getPath(packet, path), client, args, name);
+      // TODO:
+      // args[placeholder.index] = placeholder.read(query(packet, path), client);
+    }
+    return args;
+  },
+  write: function(input, client) {
+    return JSON.parse(JSON.stringify(this.template, (key, value) => {
+      return value instanceof Argument ? value.write(input[value.index],
+                                                     client, key) :
+             value;
+    }));
+  }
+});
+
+var Response = Class({
+  extends: Type,
+  constructor: function(template={}) {
+    this.template = template;
+    var [x] = findPlaceholders(template, Return);
+    var {placeholder, path} = x;
+    this.return = placeholder;
+    this.path = path;
+  },
+  read: function(packet, client) {
+    var value = query(packet, this.path);
+    return this.return.read(value, client);
+  },
+  write: function(input, client) {
+    return JSON.parse(JSON.stringify(this.template, (key, value) => {
+      return value instanceof Return ? value.write(input) :
+             input
+    }));
+  }
+});
+
+// Returns array of values for the given object.
+var values = object => Object.keys(object).map(key => object[key]);
+// Returns [key, value] pairs for the given object.
+var pairs = object => Object.keys(object).map(key => [key, object[key]]);
+// Queries an object for the field nested with in it.
+var query = (object, path) => path.reduce((object, entry) => object && object[entry],
+                                          object);
+
+
+var Root = Client.from({
+  "category": "actor",
+  "typeName": "root",
+  "methods": [
+    {
+      "name": "echo",
+      "request": {
+        "string": { "_arg": 0, "type": "string" }
+      },
+      "response": {
+        "string": { "_retval": "string" }
+      }
+    },
+    {
+      "name": "listTabs",
+      "request": {},
+      "response": { "_retval": "tablist" }
+    },
+    {
+      "name": "actorDescriptions",
+      "request": {},
+      "response": { "_retval": "json" }
+    }
+  ],
+  "events": {
+    "tabListChanged": {}
+  }
+});
+
+var Tab = Client.from({
+  "category": "dict",
+  "typeName": "tab",
+  "specifications": {
+    "title": "string",
+    "url": "string",
+    "outerWindowID": "number",
+    "console": "console",
+    "inspectorActor": "inspector",
+    "callWatcherActor": "call-watcher",
+    "canvasActor": "canvas",
+    "webglActor": "webgl",
+    "webaudioActor": "webaudio",
+    "styleSheetsActor": "stylesheets",
+    "styleEditorActor": "styleeditor",
+    "storageActor": "storage",
+    "gcliActor": "gcli",
+    "memoryActor": "memory",
+    "eventLoopLag": "eventLoopLag"
+
+    "trace": "trace", // missing
+  }
+});
+
+var tablist = Client.from({
+  "category": "dict",
+  "typeName": "tablist",
+  "specializations": {
+    "selected": "number",
+    "tabs": "array:tab"
+  }
+});
+
+})(this);
+
diff --git a/addon-sdk/source/examples/debug-client/data/index.html b/addon-sdk/source/examples/debug-client/data/index.html
new file mode 100644
index 000000000000..7788e3580f30
--- /dev/null
+++ b/addon-sdk/source/examples/debug-client/data/index.html
@@ -0,0 +1,50 @@
+
+
+  
+      
+      
+  
+  
+  
+  
+
diff --git a/addon-sdk/source/examples/debug-client/data/plugin.png b/addon-sdk/source/examples/debug-client/data/plugin.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a364a30a852c1cd9f54feba54220ef5605c1bb3
GIT binary patch
literal 3819
zcmai02{@GP8XipcwPZ^*O^gaN_99~&jIo4J#y-PfFh*lCBx{yz+1El+vScYL(b%)Z
zG0Bz+$-X5eyPVPA|JS+B|DW?+*ZY0%`+m=TzxVxI&+}bhl*u_H7rO{M007`Z>1m&*
zKSlNiD>MCGq;J>_0I+M~5eO3$0s%515uNcKH~>J8D?5#1ZZ;$kNu!>ozS<84iLZ!U
zVFSHBt9KA+8ifirVT=fa_-OCb<>xzj!O6UV0T~H))Zyp27K$BY`@(C|+Gwh+GdUdV
z&bCyl_;n;}rwu(iH2rjN$Ym*Dum)hV9SUqBTQUSIY(A~n%6>?&0O-8cB$MR!=
zc{Um1A6)XUvf!xZs4T$b+KJxY^;?Dj8U9TBu4zb~N0ginzwoE1FN^@zlosXZB<`3E
zW!D^lZ-L81G%yNz)#M!J8v#mnr&cZB~zM>#;*Gs(pIWCZ^#G+mlM-;7{t+p
zOxMK4Qqjdl^uUzsM*Yy}kwCK@c>9$ti)F|HEk`pp2R-Vs@Bl^?0IZ5x-8@`bmudm1
zA~0)Ajy*750s+4415}ON`g$b7!!D`iBc}vM%))|)H$$#FRC4C@R&FTqWqpM5T4v{`
ztqW%h1l2>1qYldBbS4Y#7Z_-Fb#Zd1)0}qJcz4Gel=1)SXqLK_+aS0cK4W1zlfo7j
zK_XdQj%a14$OAvcfD*62nbg;sYbE16X5{FaV9ZO^(%}4^VYnw
z?Co{WT}uqg7tWr(wLxnjCc*;BTcn8^b(YP!{Bqx%?r>Ma^)59T&R*4vkmZK
z1D6*EXE0KOJ)+S-hG8TG&l>uf_uw7P;sk-aJegVpyoan<{ScZaXZV?3Afgg@lQcG7
zK?;RVT`SH*n7~(#lSOJ+ZLe+KW_bltVBTQ}2;<9O?8R`s0XzvFsyHjkifroqpzV9`
z7K>oRyD|N00X6QYO@d>GJ_Dq}?VFNWHQHI3dUP#W4=rnJC0L3v@Evnc1m9&W(#cBT
zzI*6doL=Ik2`1*qJWPg=K&$Y0Bsz8sdjT_m)tBkdaLl-1C^)6$%qt(V5qb~X|FFPP
z;(@vkn-bs6IO&!P4)G4w73mL|-e4BaigLF#2!9my3al2gk@Hk613u*$jI9lxZ{`|<
zEc-q`HNw9X%G2om8GH3u9ea>y(2>#jqpkH432atC_fVc=X&^BVF>_uK)@jzAFuo=Q
z(~v@AGB|?Quf+y?^5Km)n$J<9kaNlWs0cB^^I|76t3u3CZeUvo96~*o+@a!xBnhE4
z?2OCAazXauJW1*%DJLNO#`>Zsv@07~%
zcDv6{rf!__Jash{oa&s)kQ!fXXhH1f@6RqK6dU)+xIx@7ZbNQc{m_y)+I<=&hn8)x
zusg9GIag5=b)|aK?OXF4d@fleOQcRjSj0jkU7=M`ILkAuBWp5iTA{7V)r#XW&}!0Z
z`mvo%YUZadb7%3&80Eauvc>z-J!*G{OW>uBg_V{r`R6LT57;I_txsz{wRvhr(K0rG
zS;FkgO_%c2Omj+SeO@`SC7fT6Lq@GJ-)uNGf(No&|8x25}PDr!+`acT$Z
zeCkR9VC$G2#vPx{;je?Ar#A<;jDcr>57=hd?*es!7g*Fds7s4;+W_P
zNn3fi1Qph-kS~L%d5Q1;WO3k*Mo*&Q32(G>ZN`o7hTrsJ#cqmULvvKRJsNRA;&NY_
zcJWQEOk_=Xb{_8d+OZX==&VS&>{93RJz~32@sm4uY4|{y&AVskD7K9?W8doL;|U;w
z-q7bx-Of1Np;6E1kv`MgrWJJ#u9Ztuty<5tOvk9w-PYV5FFX!OEK5L3P=l^su`)%91!TM1`P%lFq
z(+d{0BmAPzgWA_j+)FhHFEH=N9yHVD@66TIy9C(>X)o$6C(@AN$a`%~@t6D0_6?pc
zJe{J{6qnTcaQspmap%J~g#Uq(SrhsEXY0T-$CQ^pwyhss%HdQU@{0~Ao|V|iU48P(
zD%vV<;Qc_CIT20l&>+G_MvXRb^^m4o9XQZNc)U9oc^b(gcW!tj>*#XqWh@H5BBegkc
z_6vdd*~d!+>a17gPTF|sjk-=}^-os}DMs|8w
zig@hQyRMwsaourT7{4RIZhR`ISiN+oe|^xoh`O?Hd(eSadEF&Gq8b6)P2DIrZr(>L
zqDksj>CPcbk+j&2*x@S=S6+PXj7{$y53fJ@{mEKtPf2bdWsB;9?P&Sz-ZP)6u0K*(
zr@T3^N|<(j1L^;iY+ib3ZvcSfz}{d0WZe=10GNvL=9XkjBSRHOA_0nVB4Tk+UxF7s8URrB
zRiRG_I5Gz0OYrdYR`G>{e?+Lz=X={QFz81J*&PnHG%^7ph$I|H5vl-{0jsftKp<6;
zle5ZsZQY-6`U(zqC6m2WU@!`W0;R}9i6j@8tg^B)OhyhSCnrshkoNZTBx8J~J-v_r
zLGmY$HqP6Tg!dxjiJqW6UJRCanG6Sm_YV5&`l*xPWn}c%QJ&sEebF7ld@)`yS*Q$*
zK!E)n(wlr9_eH1*S_h%4qzd~l=&yYI
zNsA-leQ-{?BqHHQ;=C{HQ7*+oAM#DhLt|Lne~U
zi9`=I&AsjcnYa?kL~mE37YJdd2r|Mr;yw4)KP3J~_)jKP*j_dNR^5NJ&W~Ms@2IiU
zk$?7~8oOXArxLw2vryWa=6YO?4nm&6e8UKr?puC5{0B4+>^fkv;Oh|Psr@B6Y%$Jc
z0}cI(sKzR6ax-tUGhY{=_%*rmdU08+i_rMS*Xe!Vzwgu@DQsuR)ncFEmXVidk?VQ0
zKVeH$!zcJ-J3~vptk-R8tkC1@3x%RwH9fblMK-u%gIV?!an>*oGn}_YMr<+}-qvR;
kOiW7)kyMitMdk@v>ZbJ4KC1{o&W#<

literal 0
HcmV?d00001

diff --git a/addon-sdk/source/examples/debug-client/data/task.js b/addon-sdk/source/examples/debug-client/data/task.js
new file mode 100644
index 000000000000..b46feb10e992
--- /dev/null
+++ b/addon-sdk/source/examples/debug-client/data/task.js
@@ -0,0 +1,28 @@
+/* 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/. */
+
+(function(exports) {
+"use strict";
+
+const spawn = (task, ...args) => {
+  return new Promise((resolve, reject) => {
+    try {
+      const routine = task(...args);
+      const raise = error => routine.throw(error);
+      const step = data => {
+        const { done, value } = routine.next(data);
+        if (done)
+          resolve(value);
+        else
+          Promise.resolve(value).then(step, raise);
+      }
+      step();
+    } catch(error) {
+      reject(error);
+    }
+  });
+}
+exports.spawn = spawn;
+
+})(Task = {});
diff --git a/addon-sdk/source/examples/debug-client/index.js b/addon-sdk/source/examples/debug-client/index.js
new file mode 100644
index 000000000000..ff91ff8cdcaf
--- /dev/null
+++ b/addon-sdk/source/examples/debug-client/index.js
@@ -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 { Panel } = require("dev/panel");
+const { Tool } = require("dev/toolbox");
+const { Class } = require("sdk/core/heritage");
+
+
+const LadybugPanel = Class({
+  extends: Panel,
+  label: "Ladybug",
+  tooltip: "Debug client example",
+  icon: "./plugin.png",
+  url: "./index.html",
+  setup: function({debuggee}) {
+    this.debuggee = debuggee;
+  },
+  dispose: function() {
+    delete this.debuggee;
+  },
+  onReady: function() {
+    this.debuggee.start();
+    this.postMessage("RDP", [this.debuggee]);
+  },
+});
+exports.LadybugPanel = LadybugPanel;
+
+
+const ladybug = new Tool({
+  panels: { ladybug: LadybugPanel }
+});
diff --git a/addon-sdk/source/examples/debug-client/package.json b/addon-sdk/source/examples/debug-client/package.json
new file mode 100644
index 000000000000..078e494959b8
--- /dev/null
+++ b/addon-sdk/source/examples/debug-client/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "debug-client",
+  "id": "@debug-client",
+  "title": "Debug client",
+  "description": "Example debug client",
+  "version": "0.0.1",
+  "author": "Irakli Gozalishvili",
+  "main": "./index.js",
+  "license": "MPL 2.0"
+}
diff --git a/addon-sdk/source/lib/dev/debuggee.js b/addon-sdk/source/lib/dev/debuggee.js
new file mode 100644
index 000000000000..9c852de74a24
--- /dev/null
+++ b/addon-sdk/source/lib/dev/debuggee.js
@@ -0,0 +1,95 @@
+/* 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 { Cu } = require("chrome");
+const { Class } = require("../sdk/core/heritage");
+const { MessagePort, MessageChannel } = require("../sdk/messaging");
+const { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+
+const outputs = new WeakMap();
+const inputs = new WeakMap();
+const targets = new WeakMap();
+const transports = new WeakMap();
+
+const inputFor = port => inputs.get(port);
+const outputFor = port => outputs.get(port);
+const transportFor = port => transports.get(port);
+
+
+const fromTarget = target => {
+  const debuggee = new Debuggee();
+  const { port1, port2 } = new MessageChannel();
+  inputs.set(debuggee, port1);
+  outputs.set(debuggee, port2);
+  targets.set(debuggee, target);
+
+  return debuggee;
+};
+exports.fromTarget = fromTarget;
+
+const Debuggee = Class({
+  extends: MessagePort.prototype,
+  close: function() {
+    const server = transportFor(this);
+    if (server) {
+      transports.delete(this);
+      server.close();
+    }
+    outputFor(this).close();
+  },
+  start: function() {
+    const target = targets.get(this);
+    if (target.isLocalTab) {
+      // Since a remote protocol connection will be made, let's start the
+      // DebuggerServer here, once and for all tools.
+      if (!DebuggerServer.initialized) {
+        DebuggerServer.init();
+        DebuggerServer.addBrowserActors();
+      }
+
+      transports.set(this, DebuggerServer.connectPipe());
+    }
+    // TODO: Implement support for remote connections (See Bug 980421)
+    else {
+      throw Error("Remote targets are not yet supported");
+    }
+
+    // pipe messages send to the debuggee to an actual
+    // server via remote debugging protocol transport.
+    inputFor(this).addEventListener("message", ({data}) =>
+      transportFor(this).send(data));
+
+    // pipe messages received from the remote debugging
+    // server transport onto the this debuggee.
+    transportFor(this).hooks = {
+      onPacket: packet => inputFor(this).postMessage(packet),
+      onClosed: () => inputFor(this).close()
+    };
+
+    inputFor(this).start();
+    outputFor(this).start();
+  },
+  postMessage: function(data) {
+    return outputFor(this).postMessage(data);
+  },
+  get onmessage() {
+    return outputFor(this).onmessage;
+  },
+  set onmessage(onmessage) {
+    outputFor(this).onmessage = onmessage;
+  },
+  addEventListener: function(...args) {
+    return outputFor(this).addEventListener(...args);
+  },
+  removeEventListener: function(...args) {
+    return outputFor(this).removeEventListener(...args);
+  }
+});
+exports.Debuggee = Debuggee;
diff --git a/addon-sdk/source/lib/dev/frame-script.js b/addon-sdk/source/lib/dev/frame-script.js
new file mode 100644
index 000000000000..760fc96e90b5
--- /dev/null
+++ b/addon-sdk/source/lib/dev/frame-script.js
@@ -0,0 +1,115 @@
+/* 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";
+(function({content, sendSyncMessage, addMessageListener, sendAsyncMessage}) {
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const observerService = Cc["@mozilla.org/observer-service;1"]
+                        .getService(Ci.nsIObserverService);
+
+const channels = new Map();
+const handles = new WeakMap();
+
+// Takes remote port handle and creates a local one.
+// also set's up a messaging channel between them.
+// This is temporary workaround until Bug 914974 is fixed
+// and port can be transfered through message manager.
+const demarshal = (handle) => {
+  if (handle.type === "MessagePort") {
+    if (!channels.has(handle.id)) {
+      const channel = new content.MessageChannel();
+      channels.set(handle.id, channel);
+      handles.set(channel.port1, handle);
+      channel.port1.onmessage = onOutPort;
+    }
+    return channels.get(handle.id).port2;
+  }
+  return null;
+};
+
+const onOutPort = event => {
+  const handle = handles.get(event.target);
+  sendAsyncMessage("sdk/port/message", {
+    port: handle,
+    message: event.data
+  });
+};
+
+const onInPort = ({data}) => {
+  const channel = channels.get(data.port.id);
+  if (channel)
+    channel.port1.postMessage(data.message);
+};
+
+const onOutEvent = event =>
+  sendSyncMessage("sdk/event/" + event.type,
+                  { type: event.type,
+                    data: event.data });
+
+const onInMessage = (message) => {
+  const {type, data, origin, bubbles, cancelable, ports} = message.data;
+
+  const event = new content.MessageEvent(type, {
+    bubbles: bubbles,
+    cancelable: cancelable,
+    data: data,
+    origin: origin,
+    target: content,
+    source: content,
+    ports: ports.map(demarshal)
+  });
+  content.dispatchEvent(event);
+};
+
+const onReady = event => {
+  channels.clear();
+};
+
+addMessageListener("sdk/event/message", onInMessage);
+addMessageListener("sdk/port/message", onInPort);
+
+const observer = {
+  observe: (document, topic, data) => {
+    // When frame associated with message manager is removed from document `docShell`
+    // is set to `null` but observer is still kept alive. At this point accesing
+    // `content.document` throws "can't access dead object" exceptions. In order to
+    // avoid leaking observer and logged errors observer is going to be removed when
+    // `docShell` is set to `null`.
+    if (!docShell) {
+      observerService.removeObserver(observer, topic);
+    }
+    else if (document === content.document) {
+      if (topic === "content-document-interactive") {
+        sendAsyncMessage("sdk/event/ready", {
+          type: "ready",
+          readyState: document.readyState,
+          uri: document.documentURI
+        });
+      }
+      if (topic === "content-document-loaded") {
+        sendAsyncMessage("sdk/event/load", {
+          type: "load",
+          readyState: document.readyState,
+          uri: document.documentURI
+        });
+      }
+      if (topic === "content-page-hidden") {
+        channels.clear();
+        sendAsyncMessage("sdk/event/unload", {
+          type: "unload",
+          readyState: "uninitialized",
+          uri: document.documentURI
+        });
+      }
+    }
+  }
+};
+
+observerService.addObserver(observer, "content-document-interactive", false);
+observerService.addObserver(observer, "content-document-loaded", false);
+observerService.addObserver(observer, "content-page-hidden", false);
+
+})(this);
diff --git a/addon-sdk/source/lib/dev/panel.js b/addon-sdk/source/lib/dev/panel.js
new file mode 100644
index 000000000000..c6624932898c
--- /dev/null
+++ b/addon-sdk/source/lib/dev/panel.js
@@ -0,0 +1,223 @@
+/* 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 { Cu } = require("chrome");
+const { Class } = require("../sdk/core/heritage");
+const { curry } = require("../sdk/lang/functional");
+const { EventTarget } = require("../sdk/event/target");
+const { Disposable, setup, dispose } = require("../sdk/core/disposable");
+const { emit, off, setListeners } = require("../sdk/event/core");
+const { when } = require("../sdk/event/utils");
+const { getFrameElement } = require("../sdk/window/utils");
+const { contract, validate } = require("../sdk/util/contract");
+const { data: { url: resolve }} = require("../sdk/self");
+const { identify } = require("../sdk/ui/id");
+const { isLocalURL, URL } = require("../sdk/url");
+const { defer } = require("../sdk/core/promise");
+const { encode } = require("../sdk/base64");
+const { marshal, demarshal } = require("./ports");
+const { fromTarget } = require("./debuggee");
+const { removed } = require("../sdk/dom/events");
+const { id: addonID } = require("../sdk/self");
+
+const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html");
+const FRAME_SCRIPT = module.uri.replace("/panel.js", "/frame-script.js");
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+const makeID = name =>
+  ("dev-panel-" + addonID + "-" + name).
+  split("/").join("-").
+  split(".").join("-").
+  split(" ").join("-").
+  replace(/[^A-Za-z0-9_\-]/g, "");
+
+
+// Weak mapping between `Panel` instances and their frame's
+// `nsIMessageManager`.
+const managers = new WeakMap();
+// Return `nsIMessageManager` for the given `Panel` instance.
+const managerFor = x => managers.get(x);
+
+// Weak mappinging between iframe's and their owner
+// `Panel` instances.
+const panels = new WeakMap();
+const panelFor = frame => panels.get(frame);
+
+// Weak mapping between panels and debugees they're targeting.
+const debuggees = new WeakMap();
+const debuggeeFor = panel => debuggees.get(panel);
+
+const setAttributes = (node, attributes) => {
+  for (var key in attributes)
+    node.setAttribute(key, attributes[key]);
+};
+
+const onStateChange = ({target, data}) => {
+  const panel = panelFor(target);
+  panel.readyState = data.readyState;
+  emit(panel, data.type, { target: panel, type: data.type });
+};
+
+// port event listener on the message manager that demarshalls
+// and forwards to the actual receiver. This is a workaround
+// until Bug 914974 is fixed.
+const onPortMessage = ({data, target}) => {
+  const port = demarshal(target, data.port);
+  if (port)
+    port.postMessage(data.message);
+};
+
+// When frame is removed from the toolbox destroy panel
+// associated with it to release all the resources.
+const onFrameRemove = frame => {
+  panelFor(frame).destroy();
+};
+
+const onFrameInited = frame => {
+  frame.style.visibility = "visible";
+}
+
+const inited = frame => new Promise(resolve => {
+  const { messageManager } = frame.frameLoader;
+  const listener = message => {
+    messageManager.removeMessageListener("sdk/event/ready", listener);
+    resolve(frame);
+  };
+  messageManager.addMessageListener("sdk/event/ready", listener);
+});
+
+const getTarget = ({target}) => target;
+
+const Panel = Class({
+  extends: Disposable,
+  implements: [EventTarget],
+  get id() {
+    return makeID(this.name || this.label);
+  },
+  readyState: "uninitialized",
+  ready: function() {
+    const { readyState } = this;
+    const isReady = readyState === "complete" ||
+                    readyState === "interactive";
+    return isReady ? Promise.resolve(this) :
+           when(this, "ready").then(getTarget);
+  },
+  loaded: function() {
+    const { readyState } = this;
+    const isLoaded = readyState === "complete";
+    return isLoaded ? Promise.resolve(this) :
+           when(this, "load").then(getTarget);
+  },
+  unloaded: function() {
+    const { readyState } = this;
+    const isUninitialized = readyState === "uninitialized";
+    return isUninitialized ? Promise.resolve(this) :
+           when(this, "unload").then(getTarget);
+  },
+  postMessage: function(data, ports) {
+    const manager = managerFor(this);
+    manager.sendAsyncMessage("sdk/event/message", {
+      type: "message",
+      bubbles: false,
+      cancelable: false,
+      data: data,
+      origin: this.url,
+      ports: ports.map(marshal(manager))
+    });
+  }
+});
+exports.Panel = Panel;
+
+validate.define(Panel, contract({
+  label: {
+    is: ["string"],
+    msg: "The `option.label` must be a provided"
+  },
+  tooltip: {
+    is: ["string", "undefined"],
+    msg: "The `option.tooltip` must be a string"
+  },
+  icon: {
+    is: ["string"],
+    map: x => x && resolve(x),
+    ok: x => isLocalURL(x),
+    msg: "The `options.icon` must be a valid local URI."
+  },
+  url: {
+    map: x => resolve(x.toString()),
+    is: ["string"],
+    ok: x => isLocalURL(x),
+    msg: "The `options.url` must be a valid local URI."
+  }
+}));
+
+setup.define(Panel, (panel, {window, toolbox, url}) => {
+  // Hack: Given that iframe created by devtools API is no good for us,
+  // we obtain original iframe and replace it with the one that has
+  // desired configuration.
+  const original = getFrameElement(window);
+  const frame = original.cloneNode(true);
+
+  setAttributes(frame, {
+    "src": url,
+    "sandbox": "allow-scripts",
+    // It would be great if we could allow remote iframes for sandboxing
+    // panel documents in a content process, but for now platform implementation
+    // is buggy on linux so this is disabled.
+    // "remote": true,
+    "type": "content",
+    "transparent": true,
+    "seamless": "seamless"
+  });
+
+  original.parentNode.replaceChild(frame, original);
+  frame.style.visibility = "hidden";
+
+  // associate panel model with a frame view.
+  panels.set(frame, panel);
+
+  const debuggee = fromTarget(toolbox.target);
+  // associate debuggee with a panel.
+  debuggees.set(panel, debuggee);
+
+
+  // Setup listeners for the frame message manager.
+  const { messageManager } = frame.frameLoader;
+  messageManager.addMessageListener("sdk/event/ready", onStateChange);
+  messageManager.addMessageListener("sdk/event/load", onStateChange);
+  messageManager.addMessageListener("sdk/event/unload", onStateChange);
+  messageManager.addMessageListener("sdk/port/message", onPortMessage);
+  messageManager.loadFrameScript(FRAME_SCRIPT, false);
+
+  managers.set(panel, messageManager);
+
+  // destroy panel if frame is removed.
+  removed(frame).then(onFrameRemove);
+  // show frame when it is initialized.
+  inited(frame).then(onFrameInited);
+
+
+  // set listeners if there are ones defined on the prototype.
+  setListeners(panel, Object.getPrototypeOf(panel));
+
+
+  panel.setup({ debuggee: debuggee });
+});
+
+dispose.define(Panel, function(panel) {
+  debuggeeFor(panel).close();
+
+  debuggees.delete(panel);
+  managers.delete(panel);
+  panel.readyState = "destroyed";
+  panel.dispose();
+});
diff --git a/addon-sdk/source/lib/dev/ports.js b/addon-sdk/source/lib/dev/ports.js
new file mode 100644
index 000000000000..b4e983dc8b79
--- /dev/null
+++ b/addon-sdk/source/lib/dev/ports.js
@@ -0,0 +1,64 @@
+/* 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 module provides `marshal` and `demarshal` functions
+// that can be used to send  MessagePort's over `nsIFrameMessageManager`
+// until Bug 914974 is fixed.
+
+const { add, iterator } = require("../sdk/lang/weak-set");
+const { curry } = require("../sdk/lang/functional");
+
+let id = 0;
+const ports = new WeakMap();
+
+// Takes `nsIFrameMessageManager` and `MessagePort` instances
+// and returns a handle representing given `port`. Messages
+// received on given `port` will be forwarded to a message
+// manager under `sdk/port/message` and messages like:
+// { port: { type: "MessagePort", id: 2}, data: data }
+// Where id is an identifier associated with a given `port`
+// and `data` is an `event.data` received on port.
+const marshal = curry((manager, port) => {
+  if (!ports.has(port)) {
+    id = id + 1;
+    const handle = {type: "MessagePort", id: id};
+    // Bind id to the given port
+    ports.set(port, handle);
+
+    // Obtain a weak reference to a port.
+    add(exports, port);
+
+    port.onmessage = event => {
+      manager.sendAsyncMessage("sdk/port/message", {
+        port: handle,
+        message: event.data
+      });
+    };
+
+    return handle;
+  }
+  return ports.get(port);
+});
+exports.marshal = marshal;
+
+// Takes `nsIFrameMessageManager` instance and a handle returned
+// `marshal(manager, port)` returning a `port` that was passed
+// to it. Note that `port` may be GC-ed in which case returned
+// value will be `null`.
+const demarshal = curry((manager, {type, id}) => {
+  if (type === "MessagePort") {
+    for (let port of iterator(exports)) {
+      if (id === ports.get(port).id)
+        return port;
+    }
+  }
+  return null;
+});
+exports.demarshal = demarshal;
diff --git a/addon-sdk/source/lib/dev/toolbox.js b/addon-sdk/source/lib/dev/toolbox.js
new file mode 100644
index 000000000000..f88963466c6e
--- /dev/null
+++ b/addon-sdk/source/lib/dev/toolbox.js
@@ -0,0 +1,75 @@
+/* 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 { Cu, Cc, Ci } = require("chrome");
+const { Class } = require("../sdk/core/heritage");
+const { Disposable, setup } = require("../sdk/core/disposable");
+const { contract, validate } = require("../sdk/util/contract");
+const { each, pairs, values } = require("../sdk/util/sequence");
+
+const { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+
+// This is temporary workaround to allow loading of the developer tools client - volcan
+// into a toolbox panel, this hack won't be necessary as soon as devtools patch will be
+// shipped in nightly, after which it can be removed. Bug 1038517
+const registerSDKURI = () => {
+  const ioService = Cc['@mozilla.org/network/io-service;1']
+                      .getService(Ci.nsIIOService);
+  const resourceHandler = ioService.getProtocolHandler("resource")
+                                   .QueryInterface(Ci.nsIResProtocolHandler);
+
+  const uri = module.uri.replace("dev/toolbox.js", "");
+  resourceHandler.setSubstitution("sdk", ioService.newURI(uri, null, null));
+};
+
+registerSDKURI();
+
+
+const Tool = Class({
+  extends: Disposable,
+  setup: function(params={}) {
+    const { panels } = validate(this, params);
+
+    this.panels = panels;
+
+    each(([key, Panel]) => {
+      const { url, label, tooltip, icon } = validate(Panel.prototype);
+      const { id } = Panel.prototype;
+
+      gDevTools.registerTool({
+        id: id,
+        url: "about:blank",
+        label: label,
+        tooltip: tooltip,
+        icon: icon,
+        isTargetSupported: target => target.isLocalTab,
+        build: (window, toolbox) => {
+          const panel = new Panel();
+          setup(panel, { window: window,
+                         toolbox: toolbox,
+                         url: url });
+
+          return panel.ready();
+        }
+      });
+    }, pairs(panels));
+  },
+  dispose: function() {
+    each(Panel => gDevTools.unregisterTool(Panel.prototype.id),
+         values(this.panels));
+  }
+});
+
+validate.define(Tool, contract({
+  panels: {
+    is: ["object", "undefined"]
+  }
+}));
+exports.Tool = Tool;
diff --git a/addon-sdk/source/lib/dev/utils.js b/addon-sdk/source/lib/dev/utils.js
new file mode 100644
index 000000000000..f01c6fed83d0
--- /dev/null
+++ b/addon-sdk/source/lib/dev/utils.js
@@ -0,0 +1,38 @@
+/* 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 { Cu } = require("chrome");
+const { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+
+const { getActiveTab } = require("../sdk/tabs/utils");
+const { getMostRecentBrowserWindow } = require("../sdk/window/utils");
+
+const targetFor = target => {
+  target = target || getActiveTab(getMostRecentBrowserWindow());
+  return devtools.TargetFactory.forTab(target);
+};
+
+const getCurrentPanel = toolbox => toolbox.getCurrentPanel();
+exports.getCurrentPanel = getCurrentPanel;
+
+const openToolbox = (id, tab) => {
+  id = id.prototype.id || id.id || id;
+  return gDevTools.showToolbox(targetFor(tab), id);
+};
+exports.openToolbox = openToolbox;
+
+const closeToolbox = tab => gDevTools.closeToolbox(targetFor(tab));
+exports.closeToolbox = closeToolbox;
+
+const getToolbox = tab => gDevTools.getToolbox(targetFor(tab));
+exports.getToolbox = getToolbox;
+
+const openToolboxPanel = (id, tab) => {
+  id = id.prototype.id || id.id || id;
+  return gDevTools.showToolbox(targetFor(tab), id).then(getCurrentPanel);
+};
+exports.openToolboxPanel = openToolboxPanel;
diff --git a/addon-sdk/source/lib/dev/volcan.js b/addon-sdk/source/lib/dev/volcan.js
new file mode 100644
index 000000000000..cbead6af36f5
--- /dev/null
+++ b/addon-sdk/source/lib/dev/volcan.js
@@ -0,0 +1,3760 @@
+!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.volcan=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0 ? fields.constructor :
+                    function() {};
+  var ancestor = fields.extends || Object;
+
+  var descriptor = names.reduce(function(descriptor, key) {
+    descriptor[key] = describe(fields, key);
+    return descriptor;
+  }, {});
+
+  var prototype = Object.create(ancestor.prototype, descriptor);
+
+  constructor.prototype = prototype;
+  prototype.constructor = constructor;
+
+  return constructor;
+};
+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 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");
+}
+
+// Type to represent superviser actor relations to actors they supervise
+// in terms of lifetime management.
+var Supervisor = Class({
+  constructor: function(id) {
+    this.id = id;
+    this.workers = [];
+  }
+});
+
+var Telemetry = Class({
+  add: function(id, ms) {
+    console.log("telemetry::", id, ms)
+  }
+});
+
+// Consider making client a root actor.
+
+var Client = Class({
+  constructor: function() {
+    this.root = null;
+    this.telemetry = new Telemetry();
+
+    this.setupConnection();
+    this.setupLifeManagement();
+    this.setupTypeSystem();
+  },
+
+  setupConnection: function() {
+    this.requests = [];
+  },
+  setupLifeManagement: function() {
+    this.cache = Object.create(null);
+    this.graph = Object.create(null);
+    this.get = this.get.bind(this);
+    this.release = this.release.bind(this);
+  },
+  setupTypeSystem: function() {
+    this.typeSystem = new TypeSystem(this);
+    this.typeSystem.registerTypes(specification);
+  },
+
+  connect: function(port) {
+    var client = this;
+    return new Promise(function(resolve, reject) {
+      client.port = port;
+      port.onmessage = client.receive.bind(client);
+      client.onReady = resolve;
+      client.onFail = reject;
+
+      port.start();
+    });
+  },
+  send: function(packet) {
+    this.port.postMessage(packet);
+  },
+  request: function(packet) {
+    var client = this;
+    return new Promise(function(resolve, reject) {
+      client.requests.push(packet.to, { resolve: resolve, reject: reject });
+      client.send(packet);
+    });
+  },
+
+  receive: function(event) {
+    var packet = event.data;
+    if (!this.root) {
+      if (packet.from !== "root")
+        throw Error("Initial packet must be from root");
+      if (!("applicationType" in packet))
+        throw Error("Initial packet must contain applicationType field");
+
+      this.root = this.typeSystem.read("root", null, "root");
+      this.root
+          .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));
+      } 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);
+        } else {
+          console.error(Error("Unexpected packet " + JSON.stringify(packet, 2, 2)),
+                        packet,
+                        this.requests.slice(0));
+        }
+      }
+    }
+  },
+
+  get: function(id) {
+    return this.cache[id];
+  },
+  supervisorOf: function(actor) {
+    for (var id in this.graph) {
+      if (this.graph[id].indexOf(actor.id) >= 0) {
+        return id;
+      }
+    }
+  },
+  workersOf: function(actor) {
+    return this.graph[actor.id];
+  },
+  supervise: function(actor, worker) {
+    var workers = this.workersOf(actor)
+    if (workers.indexOf(worker.id) < 0) {
+      workers.push(worker.id);
+    }
+  },
+  unsupervise: function(actor, worker) {
+    var workers = this.workersOf(actor);
+    var index = workers.indexOf(worker.id)
+    if (index >= 0) {
+      workers.splice(index, 1)
+    }
+  },
+
+  register: function(actor) {
+    var registered = this.get(actor.id);
+    if (!registered) {
+      this.cache[actor.id] = actor;
+      this.graph[actor.id] = [];
+    } else if (registered !== actor) {
+      throw new Error("Different actor with same id is already registered");
+    }
+  },
+  unregister: function(actor) {
+    if (this.get(actor.id)) {
+      delete this.cache[actor.id];
+      delete this.graph[actor.id];
+    }
+  },
+
+  release: function(actor) {
+    var supervisor = this.supervisorOf(actor);
+    if (supervisor)
+      this.unsupervise(supervisor, actor);
+
+    var workers = this.workersOf(actor)
+
+    if (workers) {
+      workers.map(this.get).forEach(this.release)
+    }
+    this.unergister(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){
+"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");
+
+function makeHandler(handler) {
+  return function(event) {
+    handler.handleEvent(event);
+  }
+}
+
+var EventTarget = Class({
+  constructor: function() {
+    Object.defineProperty(this, $emitter, {
+      enumerable: false,
+      configurable: true,
+      writable: true,
+      value: new EventEmitter()
+    });
+  },
+  addEventListener: function(type, handler) {
+    if (typeof(handler) === "function") {
+      this[$emitter].on(type, handler);
+    }
+    else if (handler && typeof(handler) === "object") {
+      if (!handler[$bound]) handler[$bound] = makeHandler(handler);
+      this[$emitter].on(type, handler[$bound]);
+    }
+  },
+  removeEventListener: function(type, handler) {
+    if (typeof(handler) === "function")
+      this[$emitter].removeListener(type, handler);
+    else if (handler && handler[$bound])
+      this[$emitter].removeListener(type, handler[$bound]);
+  },
+  dispatchEvent: function(event) {
+    event.target = this;
+    this[$emitter].emit(event.type, event);
+  }
+});
+exports.EventTarget = EventTarget;
+
+var MessageEvent = Class({
+  constructor: function(type, options) {
+    options = options || {};
+    this.type = type;
+    this.data = options.data === void(0) ? null : options.data;
+
+    this.lastEventId = options.lastEventId || "";
+    this.origin = options.origin || "";
+    this.bubbles = options.bubbles || false;
+    this.cancelable = options.cancelable || false;
+  },
+  source: null,
+  ports: null,
+  preventDefault: function() {
+  },
+  stopPropagation: function() {
+  },
+  stopImmediatePropagation: function() {
+  }
+});
+exports.MessageEvent = MessageEvent;
+
+},{"./class":3,"es6-symbol":7,"events":6}],6:[function(_dereq_,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+function EventEmitter() {
+  this._events = this._events || {};
+  this._maxListeners = this._maxListeners || undefined;
+}
+module.exports = EventEmitter;
+
+// Backwards-compat with node 0.10.x
+EventEmitter.EventEmitter = EventEmitter;
+
+EventEmitter.prototype._events = undefined;
+EventEmitter.prototype._maxListeners = undefined;
+
+// By default EventEmitters will print a warning if more than 10 listeners are
+// added to it. This is a useful default which helps finding memory leaks.
+EventEmitter.defaultMaxListeners = 10;
+
+// Obviously not all Emitters should be limited to 10. This function allows
+// that to be increased. Set to zero for unlimited.
+EventEmitter.prototype.setMaxListeners = function(n) {
+  if (!isNumber(n) || n < 0 || isNaN(n))
+    throw TypeError('n must be a positive number');
+  this._maxListeners = n;
+  return this;
+};
+
+EventEmitter.prototype.emit = function(type) {
+  var er, handler, len, args, i, listeners;
+
+  if (!this._events)
+    this._events = {};
+
+  // If there is no 'error' event listener then throw.
+  if (type === 'error') {
+    if (!this._events.error ||
+        (isObject(this._events.error) && !this._events.error.length)) {
+      er = arguments[1];
+      if (er instanceof Error) {
+        throw er; // Unhandled 'error' event
+      } else {
+        throw TypeError('Uncaught, unspecified "error" event.');
+      }
+      return false;
+    }
+  }
+
+  handler = this._events[type];
+
+  if (isUndefined(handler))
+    return false;
+
+  if (isFunction(handler)) {
+    switch (arguments.length) {
+      // fast cases
+      case 1:
+        handler.call(this);
+        break;
+      case 2:
+        handler.call(this, arguments[1]);
+        break;
+      case 3:
+        handler.call(this, arguments[1], arguments[2]);
+        break;
+      // slower
+      default:
+        len = arguments.length;
+        args = new Array(len - 1);
+        for (i = 1; i < len; i++)
+          args[i - 1] = arguments[i];
+        handler.apply(this, args);
+    }
+  } else if (isObject(handler)) {
+    len = arguments.length;
+    args = new Array(len - 1);
+    for (i = 1; i < len; i++)
+      args[i - 1] = arguments[i];
+
+    listeners = handler.slice();
+    len = listeners.length;
+    for (i = 0; i < len; i++)
+      listeners[i].apply(this, args);
+  }
+
+  return true;
+};
+
+EventEmitter.prototype.addListener = function(type, listener) {
+  var m;
+
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  if (!this._events)
+    this._events = {};
+
+  // To avoid recursion in the case that type === "newListener"! Before
+  // adding it to the listeners, first emit "newListener".
+  if (this._events.newListener)
+    this.emit('newListener', type,
+              isFunction(listener.listener) ?
+              listener.listener : listener);
+
+  if (!this._events[type])
+    // Optimize the case of one listener. Don't need the extra array object.
+    this._events[type] = listener;
+  else if (isObject(this._events[type]))
+    // If we've already got an array, just append.
+    this._events[type].push(listener);
+  else
+    // Adding the second element, need to change to array.
+    this._events[type] = [this._events[type], listener];
+
+  // Check for listener leak
+  if (isObject(this._events[type]) && !this._events[type].warned) {
+    var m;
+    if (!isUndefined(this._maxListeners)) {
+      m = this._maxListeners;
+    } else {
+      m = EventEmitter.defaultMaxListeners;
+    }
+
+    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();
+    }
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+EventEmitter.prototype.once = function(type, listener) {
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  var fired = false;
+
+  function g() {
+    this.removeListener(type, g);
+
+    if (!fired) {
+      fired = true;
+      listener.apply(this, arguments);
+    }
+  }
+
+  g.listener = listener;
+  this.on(type, g);
+
+  return this;
+};
+
+// emits a 'removeListener' event iff the listener was removed
+EventEmitter.prototype.removeListener = function(type, listener) {
+  var list, position, length, i;
+
+  if (!isFunction(listener))
+    throw TypeError('listener must be a function');
+
+  if (!this._events || !this._events[type])
+    return this;
+
+  list = this._events[type];
+  length = list.length;
+  position = -1;
+
+  if (list === listener ||
+      (isFunction(list.listener) && list.listener === listener)) {
+    delete this._events[type];
+    if (this._events.removeListener)
+      this.emit('removeListener', type, listener);
+
+  } else if (isObject(list)) {
+    for (i = length; i-- > 0;) {
+      if (list[i] === listener ||
+          (list[i].listener && list[i].listener === listener)) {
+        position = i;
+        break;
+      }
+    }
+
+    if (position < 0)
+      return this;
+
+    if (list.length === 1) {
+      list.length = 0;
+      delete this._events[type];
+    } else {
+      list.splice(position, 1);
+    }
+
+    if (this._events.removeListener)
+      this.emit('removeListener', type, listener);
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.removeAllListeners = function(type) {
+  var key, listeners;
+
+  if (!this._events)
+    return this;
+
+  // not listening for removeListener, no need to emit
+  if (!this._events.removeListener) {
+    if (arguments.length === 0)
+      this._events = {};
+    else if (this._events[type])
+      delete this._events[type];
+    return this;
+  }
+
+  // emit removeListener for all listeners on all events
+  if (arguments.length === 0) {
+    for (key in this._events) {
+      if (key === 'removeListener') continue;
+      this.removeAllListeners(key);
+    }
+    this.removeAllListeners('removeListener');
+    this._events = {};
+    return this;
+  }
+
+  listeners = this._events[type];
+
+  if (isFunction(listeners)) {
+    this.removeListener(type, listeners);
+  } else {
+    // LIFO order
+    while (listeners.length)
+      this.removeListener(type, listeners[listeners.length - 1]);
+  }
+  delete this._events[type];
+
+  return this;
+};
+
+EventEmitter.prototype.listeners = function(type) {
+  var ret;
+  if (!this._events || !this._events[type])
+    ret = [];
+  else if (isFunction(this._events[type]))
+    ret = [this._events[type]];
+  else
+    ret = this._events[type].slice();
+  return ret;
+};
+
+EventEmitter.listenerCount = function(emitter, type) {
+  var ret;
+  if (!emitter._events || !emitter._events[type])
+    ret = 0;
+  else if (isFunction(emitter._events[type]))
+    ret = 1;
+  else
+    ret = emitter._events[type].length;
+  return ret;
+};
+
+function isFunction(arg) {
+  return typeof arg === 'function';
+}
+
+function isNumber(arg) {
+  return typeof arg === 'number';
+}
+
+function isObject(arg) {
+  return typeof arg === 'object' && arg !== null;
+}
+
+function isUndefined(arg) {
+  return arg === void 0;
+}
+
+},{}],7:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = _dereq_('./is-implemented')() ? Symbol : _dereq_('./polyfill');
+
+},{"./is-implemented":8,"./polyfill":22}],8:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = function () {
+	var symbol;
+	if (typeof Symbol !== 'function') return false;
+	symbol = Symbol('test symbol');
+	try {
+		if (String(symbol) !== 'Symbol (test symbol)') return false;
+	} catch (e) { return false; }
+	if (typeof Symbol.iterator === 'symbol') return true;
+
+	// Return 'true' for polyfills
+	if (typeof Symbol.isConcatSpreadable !== 'object') return false;
+	if (typeof Symbol.isRegExp !== 'object') return false;
+	if (typeof Symbol.iterator !== 'object') return false;
+	if (typeof Symbol.toPrimitive !== 'object') return false;
+	if (typeof Symbol.toStringTag !== 'object') return false;
+	if (typeof Symbol.unscopables !== 'object') return false;
+
+	return true;
+};
+
+},{}],9:[function(_dereq_,module,exports){
+'use strict';
+
+var assign        = _dereq_('es5-ext/object/assign')
+  , normalizeOpts = _dereq_('es5-ext/object/normalize-options')
+  , isCallable    = _dereq_('es5-ext/object/is-callable')
+  , contains      = _dereq_('es5-ext/string/#/contains')
+
+  , d;
+
+d = module.exports = function (dscr, value/*, options*/) {
+	var c, e, w, options, desc;
+	if ((arguments.length < 2) || (typeof dscr !== 'string')) {
+		options = value;
+		value = dscr;
+		dscr = null;
+	} else {
+		options = arguments[2];
+	}
+	if (dscr == null) {
+		c = w = true;
+		e = false;
+	} else {
+		c = contains.call(dscr, 'c');
+		e = contains.call(dscr, 'e');
+		w = contains.call(dscr, 'w');
+	}
+
+	desc = { value: value, configurable: c, enumerable: e, writable: w };
+	return !options ? desc : assign(normalizeOpts(options), desc);
+};
+
+d.gs = function (dscr, get, set/*, options*/) {
+	var c, e, options, desc;
+	if (typeof dscr !== 'string') {
+		options = set;
+		set = get;
+		get = dscr;
+		dscr = null;
+	} else {
+		options = arguments[3];
+	}
+	if (get == null) {
+		get = undefined;
+	} else if (!isCallable(get)) {
+		options = get;
+		get = set = undefined;
+	} else if (set == null) {
+		set = undefined;
+	} else if (!isCallable(set)) {
+		options = set;
+		set = undefined;
+	}
+	if (dscr == null) {
+		c = true;
+		e = false;
+	} else {
+		c = contains.call(dscr, 'c');
+		e = contains.call(dscr, 'e');
+	}
+
+	desc = { get: get, set: set, configurable: c, enumerable: e };
+	return !options ? desc : assign(normalizeOpts(options), desc);
+};
+
+},{"es5-ext/object/assign":10,"es5-ext/object/is-callable":13,"es5-ext/object/normalize-options":17,"es5-ext/string/#/contains":19}],10:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = _dereq_('./is-implemented')()
+	? Object.assign
+	: _dereq_('./shim');
+
+},{"./is-implemented":11,"./shim":12}],11:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = function () {
+	var assign = Object.assign, obj;
+	if (typeof assign !== 'function') return false;
+	obj = { foo: 'raz' };
+	assign(obj, { bar: 'dwa' }, { trzy: 'trzy' });
+	return (obj.foo + obj.bar + obj.trzy) === 'razdwatrzy';
+};
+
+},{}],12:[function(_dereq_,module,exports){
+'use strict';
+
+var keys  = _dereq_('../keys')
+  , value = _dereq_('../valid-value')
+
+  , max = Math.max;
+
+module.exports = function (dest, src/*, …srcn*/) {
+	var error, i, l = max(arguments.length, 2), assign;
+	dest = Object(value(dest));
+	assign = function (key) {
+		try { dest[key] = src[key]; } catch (e) {
+			if (!error) error = e;
+		}
+	};
+	for (i = 1; i < l; ++i) {
+		src = arguments[i];
+		keys(src).forEach(assign);
+	}
+	if (error !== undefined) throw error;
+	return dest;
+};
+
+},{"../keys":14,"../valid-value":18}],13:[function(_dereq_,module,exports){
+// Deprecated
+
+'use strict';
+
+module.exports = function (obj) { return typeof obj === 'function'; };
+
+},{}],14:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = _dereq_('./is-implemented')()
+	? Object.keys
+	: _dereq_('./shim');
+
+},{"./is-implemented":15,"./shim":16}],15:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = function () {
+	try {
+		Object.keys('primitive');
+		return true;
+	} catch (e) { return false; }
+};
+
+},{}],16:[function(_dereq_,module,exports){
+'use strict';
+
+var keys = Object.keys;
+
+module.exports = function (object) {
+	return keys(object == null ? object : Object(object));
+};
+
+},{}],17:[function(_dereq_,module,exports){
+'use strict';
+
+var assign = _dereq_('./assign')
+
+  , forEach = Array.prototype.forEach
+  , create = Object.create, getPrototypeOf = Object.getPrototypeOf
+
+  , process;
+
+process = function (src, obj) {
+	var proto = getPrototypeOf(src);
+	return assign(proto ? process(proto, obj) : obj, src);
+};
+
+module.exports = function (options/*, …options*/) {
+	var result = create(null);
+	forEach.call(arguments, function (options) {
+		if (options == null) return;
+		process(Object(options), result);
+	});
+	return result;
+};
+
+},{"./assign":10}],18:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = function (value) {
+	if (value == null) throw new TypeError("Cannot use null or undefined");
+	return value;
+};
+
+},{}],19:[function(_dereq_,module,exports){
+'use strict';
+
+module.exports = _dereq_('./is-implemented')()
+	? String.prototype.contains
+	: _dereq_('./shim');
+
+},{"./is-implemented":20,"./shim":21}],20:[function(_dereq_,module,exports){
+'use strict';
+
+var str = 'razdwatrzy';
+
+module.exports = function () {
+	if (typeof str.contains !== 'function') return false;
+	return ((str.contains('dwa') === true) && (str.contains('foo') === false));
+};
+
+},{}],21:[function(_dereq_,module,exports){
+'use strict';
+
+var indexOf = String.prototype.indexOf;
+
+module.exports = function (searchString/*, position*/) {
+	return indexOf.call(this, searchString, arguments[1]) > -1;
+};
+
+},{}],22:[function(_dereq_,module,exports){
+'use strict';
+
+var d = _dereq_('d')
+
+  , create = Object.create, defineProperties = Object.defineProperties
+  , generateName, Symbol;
+
+generateName = (function () {
+	var created = create(null);
+	return function (desc) {
+		var postfix = 0;
+		while (created[desc + (postfix || '')]) ++postfix;
+		desc += (postfix || '');
+		created[desc] = true;
+		return '@@' + desc;
+	};
+}());
+
+module.exports = Symbol = function (description) {
+	var symbol;
+	if (this instanceof Symbol) {
+		throw new TypeError('TypeError: Symbol is not a constructor');
+	}
+	symbol = create(Symbol.prototype);
+	description = (description === undefined ? '' : String(description));
+	return defineProperties(symbol, {
+		__description__: d('', description),
+		__name__: d('', generateName(description))
+	});
+};
+
+Object.defineProperties(Symbol, {
+	create: d('', Symbol('create')),
+	hasInstance: d('', Symbol('hasInstance')),
+	isConcatSpreadable: d('', Symbol('isConcatSpreadable')),
+	isRegExp: d('', Symbol('isRegExp')),
+	iterator: d('', Symbol('iterator')),
+	toPrimitive: d('', Symbol('toPrimitive')),
+	toStringTag: d('', Symbol('toStringTag')),
+	unscopables: d('', Symbol('unscopables'))
+});
+
+defineProperties(Symbol.prototype, {
+	properToString: d(function () {
+		return 'Symbol (' + this.__description__ + ')';
+	}),
+	toString: d('', function () { return this.__name__; })
+});
+Object.defineProperty(Symbol.prototype, Symbol.toPrimitive, d('',
+	function (hint) {
+		throw new TypeError("Conversion of symbol objects is not allowed");
+	}));
+Object.defineProperty(Symbol.prototype, Symbol.toStringTag, d('c', 'Symbol'));
+
+},{"d":9}],23:[function(_dereq_,module,exports){
+module.exports={
+  "types": {
+    "root": {
+      "category": "actor",
+      "typeName": "root",
+      "methods": [
+        {
+          "name": "echo",
+          "request": {
+            "string": { "_arg": 0, "type": "string" }
+          },
+          "response": {
+            "string": { "_retval": "string" }
+          }
+        },
+        {
+          "name": "listTabs",
+          "request": {},
+          "response": { "_retval": "tablist" }
+        },
+        {
+          "name": "protocolDescription",
+          "request": {},
+          "response": { "_retval": "json" }
+        }
+      ],
+      "events": {
+        "tabListChanged": {}
+      }
+    },
+    "tablist": {
+      "category": "dict",
+      "typeName": "tablist",
+      "specializations": {
+        "selected": "number",
+        "tabs": "array:tab",
+        "url": "string",
+        "consoleActor": "console",
+        "inspectorActor": "inspector",
+        "styleSheetsActor": "stylesheets",
+        "styleEditorActor": "styleeditor",
+        "memoryActor": "memory",
+        "eventLoopLagActor": "eventLoopLag",
+        "preferenceActor": "preference",
+        "deviceActor": "device",
+
+        "profilerActor": "profiler",
+        "chromeDebugger": "chromeDebugger",
+        "webappsActor": "webapps"
+      }
+    },
+    "tab": {
+      "category": "actor",
+      "typeName": "tab",
+      "fields": {
+        "title": "string",
+        "url": "string",
+        "outerWindowID": "number",
+        "inspectorActor": "inspector",
+        "callWatcherActor": "call-watcher",
+        "canvasActor": "canvas",
+        "webglActor": "webgl",
+        "webaudioActor": "webaudio",
+        "storageActor": "storage",
+        "gcliActor": "gcli",
+        "memoryActor": "memory",
+        "eventLoopLag": "eventLoopLag",
+        "styleSheetsActor": "stylesheets",
+        "styleEditorActor": "styleeditor",
+
+        "consoleActor": "console",
+        "traceActor": "trace"
+      }
+    }
+  }
+}
+
+},{}],24:[function(_dereq_,module,exports){
+module.exports={
+  "types": {
+    "longstractor": {
+      "category": "actor",
+      "typeName": "longstractor",
+      "methods": [
+        {
+          "name": "substring",
+          "request": {
+            "type": "substring",
+            "start": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "end": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "substring": {
+              "_retval": "primitive"
+            }
+          }
+        },
+        {
+          "name": "release",
+          "release": true,
+          "request": {
+            "type": "release"
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "stylesheet": {
+      "category": "actor",
+      "typeName": "stylesheet",
+      "methods": [
+        {
+          "name": "toggleDisabled",
+          "request": {
+            "type": "toggleDisabled"
+          },
+          "response": {
+            "disabled": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "getText",
+          "request": {
+            "type": "getText"
+          },
+          "response": {
+            "text": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "getOriginalSources",
+          "request": {
+            "type": "getOriginalSources"
+          },
+          "response": {
+            "originalSources": {
+              "_retval": "nullable:array:originalsource"
+            }
+          }
+        },
+        {
+          "name": "getOriginalLocation",
+          "request": {
+            "type": "getOriginalLocation",
+            "line": {
+              "_arg": 0,
+              "type": "number"
+            },
+            "column": {
+              "_arg": 1,
+              "type": "number"
+            }
+          },
+          "response": {
+            "_retval": "originallocationresponse"
+          }
+        },
+        {
+          "name": "update",
+          "request": {
+            "type": "update",
+            "text": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "transition": {
+              "_arg": 1,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        }
+      ],
+      "events": {
+        "property-change": {
+          "type": "propertyChange",
+          "property": {
+            "_arg": 0,
+            "type": "string"
+          },
+          "value": {
+            "_arg": 1,
+            "type": "json"
+          }
+        },
+        "style-applied": {
+          "type": "styleApplied"
+        }
+      }
+    },
+    "originalsource": {
+      "category": "actor",
+      "typeName": "originalsource",
+      "methods": [
+        {
+          "name": "getText",
+          "request": {
+            "type": "getText"
+          },
+          "response": {
+            "text": {
+              "_retval": "longstring"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "stylesheets": {
+      "category": "actor",
+      "typeName": "stylesheets",
+      "methods": [
+        {
+          "name": "getStyleSheets",
+          "request": {
+            "type": "getStyleSheets"
+          },
+          "response": {
+            "styleSheets": {
+              "_retval": "array:stylesheet"
+            }
+          }
+        },
+        {
+          "name": "addStyleSheet",
+          "request": {
+            "type": "addStyleSheet",
+            "text": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "styleSheet": {
+              "_retval": "stylesheet"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "originallocationresponse": {
+      "category": "dict",
+      "typeName": "originallocationresponse",
+      "specializations": {
+        "source": "string",
+        "line": "number",
+        "column": "number"
+      }
+    },
+    "domnode": {
+      "category": "actor",
+      "typeName": "domnode",
+      "methods": [
+        {
+          "name": "getNodeValue",
+          "request": {
+            "type": "getNodeValue"
+          },
+          "response": {
+            "value": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "setNodeValue",
+          "request": {
+            "type": "setNodeValue",
+            "value": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "getImageData",
+          "request": {
+            "type": "getImageData",
+            "maxDim": {
+              "_arg": 0,
+              "type": "nullable:number"
+            }
+          },
+          "response": {
+            "_retval": "imageData"
+          }
+        },
+        {
+          "name": "modifyAttributes",
+          "request": {
+            "type": "modifyAttributes",
+            "modifications": {
+              "_arg": 0,
+              "type": "array:json"
+            }
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "appliedstyle": {
+      "category": "dict",
+      "typeName": "appliedstyle",
+      "specializations": {
+        "rule": "domstylerule#actorid",
+        "inherited": "nullable:domnode#actorid"
+      }
+    },
+    "matchedselector": {
+      "category": "dict",
+      "typeName": "matchedselector",
+      "specializations": {
+        "rule": "domstylerule#actorid",
+        "selector": "string",
+        "value": "string",
+        "status": "number"
+      }
+    },
+    "matchedselectorresponse": {
+      "category": "dict",
+      "typeName": "matchedselectorresponse",
+      "specializations": {
+        "rules": "array:domstylerule",
+        "sheets": "array:stylesheet",
+        "matched": "array:matchedselector"
+      }
+    },
+    "appliedStylesReturn": {
+      "category": "dict",
+      "typeName": "appliedStylesReturn",
+      "specializations": {
+        "entries": "array:appliedstyle",
+        "rules": "array:domstylerule",
+        "sheets": "array:stylesheet"
+      }
+    },
+    "pagestyle": {
+      "category": "actor",
+      "typeName": "pagestyle",
+      "methods": [
+        {
+          "name": "getComputed",
+          "request": {
+            "type": "getComputed",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "markMatched": {
+              "_option": 1,
+              "type": "boolean"
+            },
+            "onlyMatched": {
+              "_option": 1,
+              "type": "boolean"
+            },
+            "filter": {
+              "_option": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "computed": {
+              "_retval": "json"
+            }
+          }
+        },
+        {
+          "name": "getMatchedSelectors",
+          "request": {
+            "type": "getMatchedSelectors",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "property": {
+              "_arg": 1,
+              "type": "string"
+            },
+            "filter": {
+              "_option": 2,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "matchedselectorresponse"
+          }
+        },
+        {
+          "name": "getApplied",
+          "request": {
+            "type": "getApplied",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "inherited": {
+              "_option": 1,
+              "type": "boolean"
+            },
+            "matchedSelectors": {
+              "_option": 1,
+              "type": "boolean"
+            },
+            "filter": {
+              "_option": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "appliedStylesReturn"
+          }
+        },
+        {
+          "name": "getLayout",
+          "request": {
+            "type": "getLayout",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "autoMargins": {
+              "_option": 1,
+              "type": "boolean"
+            }
+          },
+          "response": {
+            "_retval": "json"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "domstylerule": {
+      "category": "actor",
+      "typeName": "domstylerule",
+      "methods": [
+        {
+          "name": "modifyProperties",
+          "request": {
+            "type": "modifyProperties",
+            "modifications": {
+              "_arg": 0,
+              "type": "array:json"
+            }
+          },
+          "response": {
+            "rule": {
+              "_retval": "domstylerule"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "highlighter": {
+      "category": "actor",
+      "typeName": "highlighter",
+      "methods": [
+        {
+          "name": "showBoxModel",
+          "request": {
+            "type": "showBoxModel",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "region": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "hideBoxModel",
+          "request": {
+            "type": "hideBoxModel"
+          },
+          "response": {}
+        },
+        {
+          "name": "pick",
+          "request": {
+            "type": "pick"
+          },
+          "response": {}
+        },
+        {
+          "name": "cancelPick",
+          "request": {
+            "type": "cancelPick"
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "imageData": {
+      "category": "dict",
+      "typeName": "imageData",
+      "specializations": {
+        "data": "nullable:longstring",
+        "size": "json"
+      }
+    },
+    "disconnectedNode": {
+      "category": "dict",
+      "typeName": "disconnectedNode",
+      "specializations": {
+        "node": "domnode",
+        "newParents": "array:domnode"
+      }
+    },
+    "disconnectedNodeArray": {
+      "category": "dict",
+      "typeName": "disconnectedNodeArray",
+      "specializations": {
+        "nodes": "array:domnode",
+        "newParents": "array:domnode"
+      }
+    },
+    "dommutation": {
+      "category": "dict",
+      "typeName": "dommutation",
+      "specializations": {}
+    },
+    "domnodelist": {
+      "category": "actor",
+      "typeName": "domnodelist",
+      "methods": [
+        {
+          "name": "item",
+          "request": {
+            "type": "item",
+            "item": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "_retval": "disconnectedNode"
+          }
+        },
+        {
+          "name": "items",
+          "request": {
+            "type": "items",
+            "start": {
+              "_arg": 0,
+              "type": "nullable:number"
+            },
+            "end": {
+              "_arg": 1,
+              "type": "nullable:number"
+            }
+          },
+          "response": {
+            "_retval": "disconnectedNodeArray"
+          }
+        },
+        {
+          "name": "release",
+          "release": true,
+          "request": {
+            "type": "release"
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "domtraversalarray": {
+      "category": "dict",
+      "typeName": "domtraversalarray",
+      "specializations": {
+        "nodes": "array:domnode"
+      }
+    },
+    "domwalker": {
+      "category": "actor",
+      "typeName": "domwalker",
+      "methods": [
+        {
+          "name": "release",
+          "release": true,
+          "request": {
+            "type": "release"
+          },
+          "response": {}
+        },
+        {
+          "name": "pick",
+          "request": {
+            "type": "pick"
+          },
+          "response": {
+            "_retval": "disconnectedNode"
+          }
+        },
+        {
+          "name": "cancelPick",
+          "request": {
+            "type": "cancelPick"
+          },
+          "response": {}
+        },
+        {
+          "name": "highlight",
+          "request": {
+            "type": "highlight",
+            "node": {
+              "_arg": 0,
+              "type": "nullable:domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "document",
+          "request": {
+            "type": "document",
+            "node": {
+              "_arg": 0,
+              "type": "nullable:domnode"
+            }
+          },
+          "response": {
+            "node": {
+              "_retval": "domnode"
+            }
+          }
+        },
+        {
+          "name": "documentElement",
+          "request": {
+            "type": "documentElement",
+            "node": {
+              "_arg": 0,
+              "type": "nullable:domnode"
+            }
+          },
+          "response": {
+            "node": {
+              "_retval": "domnode"
+            }
+          }
+        },
+        {
+          "name": "parents",
+          "request": {
+            "type": "parents",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "sameDocument": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "nodes": {
+              "_retval": "array:domnode"
+            }
+          }
+        },
+        {
+          "name": "retainNode",
+          "request": {
+            "type": "retainNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "unretainNode",
+          "request": {
+            "type": "unretainNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "releaseNode",
+          "request": {
+            "type": "releaseNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "force": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "children",
+          "request": {
+            "type": "children",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "maxNodes": {
+              "_option": 1,
+              "type": "primitive"
+            },
+            "center": {
+              "_option": 1,
+              "type": "domnode"
+            },
+            "start": {
+              "_option": 1,
+              "type": "domnode"
+            },
+            "whatToShow": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "_retval": "domtraversalarray"
+          }
+        },
+        {
+          "name": "siblings",
+          "request": {
+            "type": "siblings",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "maxNodes": {
+              "_option": 1,
+              "type": "primitive"
+            },
+            "center": {
+              "_option": 1,
+              "type": "domnode"
+            },
+            "start": {
+              "_option": 1,
+              "type": "domnode"
+            },
+            "whatToShow": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "_retval": "domtraversalarray"
+          }
+        },
+        {
+          "name": "nextSibling",
+          "request": {
+            "type": "nextSibling",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "whatToShow": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "node": {
+              "_retval": "nullable:domnode"
+            }
+          }
+        },
+        {
+          "name": "previousSibling",
+          "request": {
+            "type": "previousSibling",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "whatToShow": {
+              "_option": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "node": {
+              "_retval": "nullable:domnode"
+            }
+          }
+        },
+        {
+          "name": "querySelector",
+          "request": {
+            "type": "querySelector",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "selector": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "_retval": "disconnectedNode"
+          }
+        },
+        {
+          "name": "querySelectorAll",
+          "request": {
+            "type": "querySelectorAll",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "selector": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "list": {
+              "_retval": "domnodelist"
+            }
+          }
+        },
+        {
+          "name": "getSuggestionsForQuery",
+          "request": {
+            "type": "getSuggestionsForQuery",
+            "query": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "completing": {
+              "_arg": 1,
+              "type": "primitive"
+            },
+            "selectorState": {
+              "_arg": 2,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "list": {
+              "_retval": "array:array:string"
+            }
+          }
+        },
+        {
+          "name": "addPseudoClassLock",
+          "request": {
+            "type": "addPseudoClassLock",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "pseudoClass": {
+              "_arg": 1,
+              "type": "primitive"
+            },
+            "parents": {
+              "_option": 2,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "hideNode",
+          "request": {
+            "type": "hideNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "unhideNode",
+          "request": {
+            "type": "unhideNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "removePseudoClassLock",
+          "request": {
+            "type": "removePseudoClassLock",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "pseudoClass": {
+              "_arg": 1,
+              "type": "primitive"
+            },
+            "parents": {
+              "_option": 2,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "clearPseudoClassLocks",
+          "request": {
+            "type": "clearPseudoClassLocks",
+            "node": {
+              "_arg": 0,
+              "type": "nullable:domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "innerHTML",
+          "request": {
+            "type": "innerHTML",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {
+            "value": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "outerHTML",
+          "request": {
+            "type": "outerHTML",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {
+            "value": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "setOuterHTML",
+          "request": {
+            "type": "setOuterHTML",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "value": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "removeNode",
+          "request": {
+            "type": "removeNode",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {
+            "nextSibling": {
+              "_retval": "nullable:domnode"
+            }
+          }
+        },
+        {
+          "name": "insertBefore",
+          "request": {
+            "type": "insertBefore",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            },
+            "parent": {
+              "_arg": 1,
+              "type": "domnode"
+            },
+            "sibling": {
+              "_arg": 2,
+              "type": "nullable:domnode"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "getMutations",
+          "request": {
+            "type": "getMutations",
+            "cleanup": {
+              "_option": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "mutations": {
+              "_retval": "array:dommutation"
+            }
+          }
+        },
+        {
+          "name": "isInDOMTree",
+          "request": {
+            "type": "isInDOMTree",
+            "node": {
+              "_arg": 0,
+              "type": "domnode"
+            }
+          },
+          "response": {
+            "attached": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "getNodeActorFromObjectActor",
+          "request": {
+            "type": "getNodeActorFromObjectActor",
+            "objectActorID": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "nodeFront": {
+              "_retval": "nullable:disconnectedNode"
+            }
+          }
+        }
+      ],
+      "events": {
+        "new-mutations": {
+          "type": "newMutations"
+        },
+        "picker-node-picked": {
+          "type": "pickerNodePicked",
+          "node": {
+            "_arg": 0,
+            "type": "disconnectedNode"
+          }
+        },
+        "picker-node-hovered": {
+          "type": "pickerNodeHovered",
+          "node": {
+            "_arg": 0,
+            "type": "disconnectedNode"
+          }
+        },
+        "highlighter-ready": {
+          "type": "highlighter-ready"
+        },
+        "highlighter-hide": {
+          "type": "highlighter-hide"
+        }
+      }
+    },
+    "inspector": {
+      "category": "actor",
+      "typeName": "inspector",
+      "methods": [
+        {
+          "name": "getWalker",
+          "request": {
+            "type": "getWalker"
+          },
+          "response": {
+            "walker": {
+              "_retval": "domwalker"
+            }
+          }
+        },
+        {
+          "name": "getPageStyle",
+          "request": {
+            "type": "getPageStyle"
+          },
+          "response": {
+            "pageStyle": {
+              "_retval": "pagestyle"
+            }
+          }
+        },
+        {
+          "name": "getHighlighter",
+          "request": {
+            "type": "getHighlighter",
+            "autohide": {
+              "_arg": 0,
+              "type": "boolean"
+            }
+          },
+          "response": {
+            "highligter": {
+              "_retval": "highlighter"
+            }
+          }
+        },
+        {
+          "name": "getImageDataFromURL",
+          "request": {
+            "type": "getImageDataFromURL",
+            "url": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "maxDim": {
+              "_arg": 1,
+              "type": "nullable:number"
+            }
+          },
+          "response": {
+            "_retval": "imageData"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "call-stack-item": {
+      "category": "dict",
+      "typeName": "call-stack-item",
+      "specializations": {
+        "name": "string",
+        "file": "string",
+        "line": "number"
+      }
+    },
+    "call-details": {
+      "category": "dict",
+      "typeName": "call-details",
+      "specializations": {
+        "type": "number",
+        "name": "string",
+        "stack": "array:call-stack-item"
+      }
+    },
+    "function-call": {
+      "category": "actor",
+      "typeName": "function-call",
+      "methods": [
+        {
+          "name": "getDetails",
+          "request": {
+            "type": "getDetails"
+          },
+          "response": {
+            "info": {
+              "_retval": "call-details"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "call-watcher": {
+      "category": "actor",
+      "typeName": "call-watcher",
+      "methods": [
+        {
+          "name": "setup",
+          "oneway": true,
+          "request": {
+            "type": "setup",
+            "tracedGlobals": {
+              "_option": 0,
+              "type": "nullable:array:string"
+            },
+            "tracedFunctions": {
+              "_option": 0,
+              "type": "nullable:array:string"
+            },
+            "startRecording": {
+              "_option": 0,
+              "type": "boolean"
+            },
+            "performReload": {
+              "_option": 0,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "finalize",
+          "oneway": true,
+          "request": {
+            "type": "finalize"
+          },
+          "response": {}
+        },
+        {
+          "name": "isRecording",
+          "request": {
+            "type": "isRecording"
+          },
+          "response": {
+            "_retval": "boolean"
+          }
+        },
+        {
+          "name": "resumeRecording",
+          "request": {
+            "type": "resumeRecording"
+          },
+          "response": {}
+        },
+        {
+          "name": "pauseRecording",
+          "request": {
+            "type": "pauseRecording"
+          },
+          "response": {
+            "calls": {
+              "_retval": "array:function-call"
+            }
+          }
+        },
+        {
+          "name": "eraseRecording",
+          "request": {
+            "type": "eraseRecording"
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "snapshot-image": {
+      "category": "dict",
+      "typeName": "snapshot-image",
+      "specializations": {
+        "index": "number",
+        "width": "number",
+        "height": "number",
+        "flipped": "boolean",
+        "pixels": "uint32-array"
+      }
+    },
+    "snapshot-overview": {
+      "category": "dict",
+      "typeName": "snapshot-overview",
+      "specializations": {
+        "calls": "array:function-call",
+        "thumbnails": "array:snapshot-image",
+        "screenshot": "snapshot-image"
+      }
+    },
+    "frame-snapshot": {
+      "category": "actor",
+      "typeName": "frame-snapshot",
+      "methods": [
+        {
+          "name": "getOverview",
+          "request": {
+            "type": "getOverview"
+          },
+          "response": {
+            "overview": {
+              "_retval": "snapshot-overview"
+            }
+          }
+        },
+        {
+          "name": "generateScreenshotFor",
+          "request": {
+            "type": "generateScreenshotFor",
+            "call": {
+              "_arg": 0,
+              "type": "function-call"
+            }
+          },
+          "response": {
+            "screenshot": {
+              "_retval": "snapshot-image"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "canvas": {
+      "category": "actor",
+      "typeName": "canvas",
+      "methods": [
+        {
+          "name": "setup",
+          "oneway": true,
+          "request": {
+            "type": "setup",
+            "reload": {
+              "_option": 0,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "finalize",
+          "oneway": true,
+          "request": {
+            "type": "finalize"
+          },
+          "response": {}
+        },
+        {
+          "name": "isInitialized",
+          "request": {
+            "type": "isInitialized"
+          },
+          "response": {
+            "initialized": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "recordAnimationFrame",
+          "request": {
+            "type": "recordAnimationFrame"
+          },
+          "response": {
+            "snapshot": {
+              "_retval": "frame-snapshot"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "gl-shader": {
+      "category": "actor",
+      "typeName": "gl-shader",
+      "methods": [
+        {
+          "name": "getText",
+          "request": {
+            "type": "getText"
+          },
+          "response": {
+            "text": {
+              "_retval": "string"
+            }
+          }
+        },
+        {
+          "name": "compile",
+          "request": {
+            "type": "compile",
+            "text": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "error": {
+              "_retval": "nullable:json"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "gl-program": {
+      "category": "actor",
+      "typeName": "gl-program",
+      "methods": [
+        {
+          "name": "getVertexShader",
+          "request": {
+            "type": "getVertexShader"
+          },
+          "response": {
+            "shader": {
+              "_retval": "gl-shader"
+            }
+          }
+        },
+        {
+          "name": "getFragmentShader",
+          "request": {
+            "type": "getFragmentShader"
+          },
+          "response": {
+            "shader": {
+              "_retval": "gl-shader"
+            }
+          }
+        },
+        {
+          "name": "highlight",
+          "oneway": true,
+          "request": {
+            "type": "highlight",
+            "tint": {
+              "_arg": 0,
+              "type": "array:number"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "unhighlight",
+          "oneway": true,
+          "request": {
+            "type": "unhighlight"
+          },
+          "response": {}
+        },
+        {
+          "name": "blackbox",
+          "oneway": true,
+          "request": {
+            "type": "blackbox"
+          },
+          "response": {}
+        },
+        {
+          "name": "unblackbox",
+          "oneway": true,
+          "request": {
+            "type": "unblackbox"
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "webgl": {
+      "category": "actor",
+      "typeName": "webgl",
+      "methods": [
+        {
+          "name": "setup",
+          "oneway": true,
+          "request": {
+            "type": "setup",
+            "reload": {
+              "_option": 0,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "finalize",
+          "oneway": true,
+          "request": {
+            "type": "finalize"
+          },
+          "response": {}
+        },
+        {
+          "name": "getPrograms",
+          "request": {
+            "type": "getPrograms"
+          },
+          "response": {
+            "programs": {
+              "_retval": "array:gl-program"
+            }
+          }
+        }
+      ],
+      "events": {
+        "program-linked": {
+          "type": "programLinked",
+          "program": {
+            "_arg": 0,
+            "type": "gl-program"
+          }
+        }
+      }
+    },
+    "audionode": {
+      "category": "actor",
+      "typeName": "audionode",
+      "methods": [
+        {
+          "name": "getType",
+          "request": {
+            "type": "getType"
+          },
+          "response": {
+            "type": {
+              "_retval": "string"
+            }
+          }
+        },
+        {
+          "name": "isSource",
+          "request": {
+            "type": "isSource"
+          },
+          "response": {
+            "source": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "setParam",
+          "request": {
+            "type": "setParam",
+            "param": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "value": {
+              "_arg": 1,
+              "type": "nullable:primitive"
+            }
+          },
+          "response": {
+            "error": {
+              "_retval": "nullable:json"
+            }
+          }
+        },
+        {
+          "name": "getParam",
+          "request": {
+            "type": "getParam",
+            "param": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "text": {
+              "_retval": "nullable:primitive"
+            }
+          }
+        },
+        {
+          "name": "getParamFlags",
+          "request": {
+            "type": "getParamFlags",
+            "param": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "flags": {
+              "_retval": "nullable:primitive"
+            }
+          }
+        },
+        {
+          "name": "getParams",
+          "request": {
+            "type": "getParams"
+          },
+          "response": {
+            "params": {
+              "_retval": "json"
+            }
+          }
+        }
+      ],
+      "events": {}
+    },
+    "webaudio": {
+      "category": "actor",
+      "typeName": "webaudio",
+      "methods": [
+        {
+          "name": "setup",
+          "oneway": true,
+          "request": {
+            "type": "setup",
+            "reload": {
+              "_option": 0,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "finalize",
+          "oneway": true,
+          "request": {
+            "type": "finalize"
+          },
+          "response": {}
+        }
+      ],
+      "events": {
+        "start-context": {
+          "type": "startContext"
+        },
+        "connect-node": {
+          "type": "connectNode",
+          "source": {
+            "_option": 0,
+            "type": "audionode"
+          },
+          "dest": {
+            "_option": 0,
+            "type": "audionode"
+          }
+        },
+        "disconnect-node": {
+          "type": "disconnectNode",
+          "source": {
+            "_arg": 0,
+            "type": "audionode"
+          }
+        },
+        "connect-param": {
+          "type": "connectParam",
+          "source": {
+            "_arg": 0,
+            "type": "audionode"
+          },
+          "param": {
+            "_arg": 1,
+            "type": "string"
+          }
+        },
+        "change-param": {
+          "type": "changeParam",
+          "source": {
+            "_option": 0,
+            "type": "audionode"
+          },
+          "param": {
+            "_option": 0,
+            "type": "string"
+          },
+          "value": {
+            "_option": 0,
+            "type": "string"
+          }
+        },
+        "create-node": {
+          "type": "createNode",
+          "source": {
+            "_arg": 0,
+            "type": "audionode"
+          }
+        }
+      }
+    },
+    "old-stylesheet": {
+      "category": "actor",
+      "typeName": "old-stylesheet",
+      "methods": [
+        {
+          "name": "toggleDisabled",
+          "request": {
+            "type": "toggleDisabled"
+          },
+          "response": {
+            "disabled": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "fetchSource",
+          "request": {
+            "type": "fetchSource"
+          },
+          "response": {}
+        },
+        {
+          "name": "update",
+          "request": {
+            "type": "update",
+            "text": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "transition": {
+              "_arg": 1,
+              "type": "boolean"
+            }
+          },
+          "response": {}
+        }
+      ],
+      "events": {
+        "property-change": {
+          "type": "propertyChange",
+          "property": {
+            "_arg": 0,
+            "type": "string"
+          },
+          "value": {
+            "_arg": 1,
+            "type": "json"
+          }
+        },
+        "source-load": {
+          "type": "sourceLoad",
+          "source": {
+            "_arg": 0,
+            "type": "string"
+          }
+        },
+        "style-applied": {
+          "type": "styleApplied"
+        }
+      }
+    },
+    "styleeditor": {
+      "category": "actor",
+      "typeName": "styleeditor",
+      "methods": [
+        {
+          "name": "newDocument",
+          "request": {
+            "type": "newDocument"
+          },
+          "response": {}
+        },
+        {
+          "name": "newStyleSheet",
+          "request": {
+            "type": "newStyleSheet",
+            "text": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "styleSheet": {
+              "_retval": "old-stylesheet"
+            }
+          }
+        }
+      ],
+      "events": {
+        "document-load": {
+          "type": "documentLoad",
+          "styleSheets": {
+            "_arg": 0,
+            "type": "array:old-stylesheet"
+          }
+        }
+      }
+    },
+    "cookieobject": {
+      "category": "dict",
+      "typeName": "cookieobject",
+      "specializations": {
+        "name": "string",
+        "value": "longstring",
+        "path": "nullable:string",
+        "host": "string",
+        "isDomain": "boolean",
+        "isSecure": "boolean",
+        "isHttpOnly": "boolean",
+        "creationTime": "number",
+        "lastAccessed": "number",
+        "expires": "number"
+      }
+    },
+    "cookiestoreobject": {
+      "category": "dict",
+      "typeName": "cookiestoreobject",
+      "specializations": {
+        "total": "number",
+        "offset": "number",
+        "data": "array:nullable:cookieobject"
+      }
+    },
+    "storageobject": {
+      "category": "dict",
+      "typeName": "storageobject",
+      "specializations": {
+        "name": "string",
+        "value": "longstring"
+      }
+    },
+    "storagestoreobject": {
+      "category": "dict",
+      "typeName": "storagestoreobject",
+      "specializations": {
+        "total": "number",
+        "offset": "number",
+        "data": "array:nullable:storageobject"
+      }
+    },
+    "idbobject": {
+      "category": "dict",
+      "typeName": "idbobject",
+      "specializations": {
+        "name": "nullable:string",
+        "db": "nullable:string",
+        "objectStore": "nullable:string",
+        "origin": "nullable:string",
+        "version": "nullable:number",
+        "objectStores": "nullable:number",
+        "keyPath": "nullable:string",
+        "autoIncrement": "nullable:boolean",
+        "indexes": "nullable:string",
+        "value": "nullable:longstring"
+      }
+    },
+    "idbstoreobject": {
+      "category": "dict",
+      "typeName": "idbstoreobject",
+      "specializations": {
+        "total": "number",
+        "offset": "number",
+        "data": "array:nullable:idbobject"
+      }
+    },
+    "storeUpdateObject": {
+      "category": "dict",
+      "typeName": "storeUpdateObject",
+      "specializations": {
+        "changed": "nullable:json",
+        "deleted": "nullable:json",
+        "added": "nullable:json"
+      }
+    },
+    "cookies": {
+      "category": "actor",
+      "typeName": "cookies",
+      "methods": [
+        {
+          "name": "getStoreObjects",
+          "request": {
+            "type": "getStoreObjects",
+            "host": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "names": {
+              "_arg": 1,
+              "type": "nullable:array:string"
+            },
+            "options": {
+              "_arg": 2,
+              "type": "nullable:json"
+            }
+          },
+          "response": {
+            "_retval": "cookiestoreobject"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "localStorage": {
+      "category": "actor",
+      "typeName": "localStorage",
+      "methods": [
+        {
+          "name": "getStoreObjects",
+          "request": {
+            "type": "getStoreObjects",
+            "host": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "names": {
+              "_arg": 1,
+              "type": "nullable:array:string"
+            },
+            "options": {
+              "_arg": 2,
+              "type": "nullable:json"
+            }
+          },
+          "response": {
+            "_retval": "storagestoreobject"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "sessionStorage": {
+      "category": "actor",
+      "typeName": "sessionStorage",
+      "methods": [
+        {
+          "name": "getStoreObjects",
+          "request": {
+            "type": "getStoreObjects",
+            "host": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "names": {
+              "_arg": 1,
+              "type": "nullable:array:string"
+            },
+            "options": {
+              "_arg": 2,
+              "type": "nullable:json"
+            }
+          },
+          "response": {
+            "_retval": "storagestoreobject"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "indexedDB": {
+      "category": "actor",
+      "typeName": "indexedDB",
+      "methods": [
+        {
+          "name": "getStoreObjects",
+          "request": {
+            "type": "getStoreObjects",
+            "host": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "names": {
+              "_arg": 1,
+              "type": "nullable:array:string"
+            },
+            "options": {
+              "_arg": 2,
+              "type": "nullable:json"
+            }
+          },
+          "response": {
+            "_retval": "idbstoreobject"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "storelist": {
+      "category": "dict",
+      "typeName": "storelist",
+      "specializations": {
+        "cookies": "cookies",
+        "localStorage": "localStorage",
+        "sessionStorage": "sessionStorage",
+        "indexedDB": "indexedDB"
+      }
+    },
+    "storage": {
+      "category": "actor",
+      "typeName": "storage",
+      "methods": [
+        {
+          "name": "listStores",
+          "request": {
+            "type": "listStores"
+          },
+          "response": {
+            "_retval": "storelist"
+          }
+        }
+      ],
+      "events": {
+        "stores-update": {
+          "type": "storesUpdate",
+          "data": {
+            "_arg": 0,
+            "type": "storeUpdateObject"
+          }
+        },
+        "stores-cleared": {
+          "type": "storesCleared",
+          "data": {
+            "_arg": 0,
+            "type": "json"
+          }
+        },
+        "stores-reloaded": {
+          "type": "storesRelaoded",
+          "data": {
+            "_arg": 0,
+            "type": "json"
+          }
+        }
+      }
+    },
+    "gcli": {
+      "category": "actor",
+      "typeName": "gcli",
+      "methods": [
+        {
+          "name": "specs",
+          "request": {
+            "type": "specs"
+          },
+          "response": {
+            "_retval": "json"
+          }
+        },
+        {
+          "name": "execute",
+          "request": {
+            "type": "execute",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "json"
+          }
+        },
+        {
+          "name": "state",
+          "request": {
+            "type": "state",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "start": {
+              "_arg": 1,
+              "type": "number"
+            },
+            "rank": {
+              "_arg": 2,
+              "type": "number"
+            }
+          },
+          "response": {
+            "_retval": "json"
+          }
+        },
+        {
+          "name": "typeparse",
+          "request": {
+            "type": "typeparse",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "param": {
+              "_arg": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "json"
+          }
+        },
+        {
+          "name": "typeincrement",
+          "request": {
+            "type": "typeincrement",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "param": {
+              "_arg": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "string"
+          }
+        },
+        {
+          "name": "typedecrement",
+          "request": {
+            "type": "typedecrement",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "param": {
+              "_arg": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "string"
+          }
+        },
+        {
+          "name": "selectioninfo",
+          "request": {
+            "type": "selectioninfo",
+            "typed": {
+              "_arg": 0,
+              "type": "string"
+            },
+            "param": {
+              "_arg": 1,
+              "type": "string"
+            },
+            "action": {
+              "_arg": 1,
+              "type": "string"
+            }
+          },
+          "response": {
+            "_retval": "json"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "memory": {
+      "category": "actor",
+      "typeName": "memory",
+      "methods": [
+        {
+          "name": "measure",
+          "request": {
+            "type": "measure"
+          },
+          "response": {
+            "_retval": "json"
+          }
+        }
+      ],
+      "events": {}
+    },
+    "eventLoopLag": {
+      "category": "actor",
+      "typeName": "eventLoopLag",
+      "methods": [
+        {
+          "name": "start",
+          "request": {
+            "type": "start"
+          },
+          "response": {
+            "success": {
+              "_retval": "number"
+            }
+          }
+        },
+        {
+          "name": "stop",
+          "request": {
+            "type": "stop"
+          },
+          "response": {}
+        }
+      ],
+      "events": {
+        "event-loop-lag": {
+          "type": "event-loop-lag",
+          "time": {
+            "_arg": 0,
+            "type": "number"
+          }
+        }
+      }
+    },
+    "preference": {
+      "category": "actor",
+      "typeName": "preference",
+      "methods": [
+        {
+          "name": "getBoolPref",
+          "request": {
+            "type": "getBoolPref",
+            "value": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "value": {
+              "_retval": "boolean"
+            }
+          }
+        },
+        {
+          "name": "getCharPref",
+          "request": {
+            "type": "getCharPref",
+            "value": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "value": {
+              "_retval": "string"
+            }
+          }
+        },
+        {
+          "name": "getIntPref",
+          "request": {
+            "type": "getIntPref",
+            "value": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {
+            "value": {
+              "_retval": "number"
+            }
+          }
+        },
+        {
+          "name": "getAllPrefs",
+          "request": {
+            "type": "getAllPrefs"
+          },
+          "response": {
+            "value": {
+              "_retval": "json"
+            }
+          }
+        },
+        {
+          "name": "setBoolPref",
+          "request": {
+            "type": "setBoolPref",
+            "name": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "value": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "setCharPref",
+          "request": {
+            "type": "setCharPref",
+            "name": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "value": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "setIntPref",
+          "request": {
+            "type": "setIntPref",
+            "name": {
+              "_arg": 0,
+              "type": "primitive"
+            },
+            "value": {
+              "_arg": 1,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        },
+        {
+          "name": "clearUserPref",
+          "request": {
+            "type": "clearUserPref",
+            "name": {
+              "_arg": 0,
+              "type": "primitive"
+            }
+          },
+          "response": {}
+        }
+      ],
+      "events": {}
+    },
+    "device": {
+      "category": "actor",
+      "typeName": "device",
+      "methods": [
+        {
+          "name": "getDescription",
+          "request": {
+            "type": "getDescription"
+          },
+          "response": {
+            "value": {
+              "_retval": "json"
+            }
+          }
+        },
+        {
+          "name": "getWallpaper",
+          "request": {
+            "type": "getWallpaper"
+          },
+          "response": {
+            "value": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "screenshotToDataURL",
+          "request": {
+            "type": "screenshotToDataURL"
+          },
+          "response": {
+            "value": {
+              "_retval": "longstring"
+            }
+          }
+        },
+        {
+          "name": "getRawPermissionsTable",
+          "request": {
+            "type": "getRawPermissionsTable"
+          },
+          "response": {
+            "value": {
+              "_retval": "json"
+            }
+          }
+        }
+      ],
+      "events": {}
+    }
+  },
+  "from": "root"
+}
+
+},{}],25:[function(_dereq_,module,exports){
+"use strict";
+
+var Class = _dereq_("./class").Class;
+var util = _dereq_("./util");
+var keys = util.keys;
+var values = util.values;
+var pairs = util.pairs;
+var query = util.query;
+var findPath = util.findPath;
+var EventTarget = _dereq_("./event").EventTarget;
+
+var TypeSystem = Class({
+  constructor: function(client) {
+    var types = Object.create(null);
+    var specification = Object.create(null);
+
+    this.specification = specification;
+    this.types = types;
+
+    var typeFor = function typeFor(typeName) {
+      typeName = typeName || "primitive";
+      if (!types[typeName]) {
+        defineType(typeName);
+      }
+
+      return types[typeName];
+    };
+    this.typeFor = typeFor;
+
+    var defineType = function(descriptor) {
+      var type = void(0);
+      if (typeof(descriptor) === "string") {
+        if (descriptor.indexOf(":") > 0)
+          type = makeCompoundType(descriptor);
+        else if (descriptor.indexOf("#") > 0)
+          type = new ActorDetail(descriptor);
+          else if (specification[descriptor])
+            type = makeCategoryType(specification[descriptor]);
+      } else {
+        type = makeCategoryType(descriptor);
+      }
+
+      if (type)
+        types[type.name] = type;
+      else
+        throw TypeError("Invalid type: " + descriptor);
+    };
+    this.defineType = defineType;
+
+
+    var makeCompoundType = function(name) {
+      var index = name.indexOf(":");
+      var baseType = name.slice(0, index);
+      var subType = name.slice(index + 1);
+
+      return baseType === "array" ? new ArrayOf(subType) :
+      baseType === "nullable" ? new Maybe(subType) :
+      null;
+    };
+
+    var makeCategoryType = function(descriptor) {
+      var category = descriptor.category;
+      return category === "dict" ? new Dictionary(descriptor) :
+      category === "actor" ? new Actor(descriptor) :
+      null;
+    };
+
+    var read = function(input, context, typeName) {
+      return typeFor(typeName).read(input, context);
+    }
+    this.read = read;
+
+    var write = function(input, context, typeName) {
+      return typeFor(typeName).write(input);
+    };
+    this.write = write;
+
+
+    var Type = Class({
+      constructor: function() {
+      },
+      get name() {
+        return this.category ? this.category + ":" + this.type :
+        this.type;
+      },
+      read: function(input, context) {
+        throw new TypeError("`Type` subclass must implement `read`");
+      },
+      write: function(input, context) {
+        throw new TypeError("`Type` subclass must implement `write`");
+      }
+    });
+
+    var Primitve = Class({
+      extends: Type,
+      constuctor: function(type) {
+        this.type = type;
+      },
+      read: function(input, context) {
+        return input;
+      },
+      write: function(input, context) {
+        return input;
+      }
+    });
+
+    var Maybe = Class({
+      extends: Type,
+      category: "nullable",
+      constructor: function(type) {
+        this.type = type;
+      },
+      read: function(input, context) {
+        return input === null ? null :
+        input === void(0) ? void(0) :
+        read(input, context, this.type);
+      },
+      write: function(input, context) {
+        return input === null ? null :
+        input === void(0) ? void(0) :
+        write(input, context, this.type);
+      }
+    });
+
+    var ArrayOf = Class({
+      extends: Type,
+      category: "array",
+      constructor: function(type) {
+        this.type = type;
+      },
+      read: function(input, context) {
+        var type = this.type;
+        return input.map(function($) { return read($, context, type) });
+      },
+      write: function(input, context) {
+        var type = this.type;
+        return input.map(function($) { return write($, context, type) });
+      }
+    });
+
+    var makeField = function makeField(name, type) {
+      return {
+        enumerable: true,
+        configurable: true,
+        get: function() {
+          Object.defineProperty(this, name, {
+            configurable: false,
+            value: read(this.state[name], this.context, type)
+          });
+          return this[name];
+        }
+      }
+    };
+
+    var makeFields = function(descriptor) {
+      return pairs(descriptor).reduce(function(fields, pair) {
+        var name = pair[0], type = pair[1];
+        fields[name] = makeField(name, type);
+        return fields;
+      }, {});
+    }
+
+    var DictionaryType = Class({});
+
+    var Dictionary = Class({
+      extends: Type,
+      category: "dict",
+      get name() { return this.type; },
+      constructor: function(descriptor) {
+        this.type = descriptor.typeName;
+        this.types = descriptor.specializations;
+
+        var proto = Object.defineProperties({
+          extends: DictionaryType,
+          constructor: function(state, context) {
+            Object.defineProperties(this, {
+              state: {
+                enumerable: false,
+                writable: true,
+                configurable: true,
+                value: state
+              },
+              context: {
+                enumerable: false,
+                writable: false,
+                configurable: true,
+                value: context
+              }
+            });
+          }
+        }, makeFields(this.types));
+
+        this.class = new Class(proto);
+      },
+      read: function(input, context) {
+        return new this.class(input, context);
+      },
+      write: function(input, context) {
+        var output = {};
+        for (var key in input) {
+          output[key] = write(value, context, types[key]);
+        }
+        return output;
+      }
+    });
+
+    var makeMethods = function(descriptors) {
+      return descriptors.reduce(function(methods, descriptor) {
+        methods[descriptor.name] = {
+          enumerable: true,
+          configurable: true,
+          writable: false,
+          value: makeMethod(descriptor)
+        };
+        return methods;
+      }, {});
+    };
+
+    var makeEvents = function(descriptors) {
+      return pairs(descriptors).reduce(function(events, pair) {
+        var name = pair[0], descriptor = pair[1];
+        var event = new Event(name, descriptor);
+        events[event.eventType] = event;
+        return events;
+      }, Object.create(null));
+    };
+
+    var Actor = Class({
+      extends: Type,
+      category: "actor",
+      get name() { return this.type; },
+      constructor: function(descriptor) {
+        this.type = descriptor.typeName;
+
+        var events = makeEvents(descriptor.events || {});
+        var fields = makeFields(descriptor.fields || {});
+        var methods = makeMethods(descriptor.methods || []);
+
+
+        var proto = {
+          extends: Front,
+          constructor: function() {
+            Front.apply(this, arguments);
+          },
+          events: events
+        };
+        Object.defineProperties(proto, fields);
+        Object.defineProperties(proto, methods);
+
+        this.class = Class(proto);
+      },
+      read: function(input, context, detail) {
+        var state = typeof(input) === "string" ? { actor: input } : input;
+
+        var actor = client.get(state.actor) || new this.class(state, context);
+        actor.form(state, detail, context);
+
+        return actor;
+      },
+      write: function(input, context, detail) {
+        return input.id;
+      }
+    });
+    exports.Actor = Actor;
+
+
+    var ActorDetail = Class({
+      extends: Actor,
+      constructor: function(name) {
+        var parts = name.split("#")
+        this.actorType = parts[0]
+        this.detail = parts[1];
+      },
+      read: function(input, context) {
+        return typeFor(this.actorType).read(input, context, this.detail);
+      },
+      write: function(input, context) {
+        return typeFor(this.actorType).write(input, context, this.detail);
+      }
+    });
+    exports.ActorDetail = ActorDetail;
+
+    var Method = Class({
+      extends: Type,
+      constructor: function(descriptor) {
+        this.type = descriptor.name;
+        this.path = findPath(descriptor.response, "_retval");
+        this.responseType = this.path && query(descriptor.response, this.path)._retval;
+        this.requestType = descriptor.request.type;
+
+        var params = [];
+        for (var key in descriptor.request) {
+          if (key !== "type") {
+            var param = descriptor.request[key];
+            var index = "_arg" in param ? param._arg : param._option;
+            var isParam = param._option === index;
+            var isArgument = param._arg === index;
+            params[index] = {
+              type: param.type,
+              key: key,
+              index: index,
+              isParam: isParam,
+              isArgument: isArgument
+            };
+          }
+        }
+        this.params = params;
+      },
+      read: function(input, context) {
+        return read(query(input, this.path), context, this.responseType);
+      },
+      write: function(input, context) {
+        return this.params.reduce(function(result, param) {
+          result[param.key] = write(input[param.index], context, param.type);
+          return result;
+        }, {type: this.type});
+      }
+    });
+    exports.Method = Method;
+
+    var profiler = function(method, id) {
+      return function() {
+        var start = new Date();
+        return method.apply(this, arguments).then(function(result) {
+          var end = new Date();
+          client.telemetry.add(id, +end - start);
+          return result;
+        });
+      };
+    };
+
+    var destructor = function(method) {
+      return function() {
+        return method.apply(this, arguments).then(function(result) {
+          client.release(this);
+          return result;
+        });
+      };
+    };
+
+    function makeMethod(descriptor) {
+      var type = new Method(descriptor);
+      var method = descriptor.oneway ? makeUnidirecationalMethod(descriptor, type) :
+                   makeBidirectionalMethod(descriptor, type);
+
+      if (descriptor.telemetry)
+        method = profiler(method);
+      if (descriptor.release)
+        method = destructor(method);
+
+      return method;
+    }
+
+    var makeUnidirecationalMethod = function(descriptor, type) {
+      return function() {
+        var packet = type.write(arguments, this);
+        packet.to = this.id;
+        client.send(packet);
+        return Promise.resolve(void(0));
+      };
+    };
+
+    var makeBidirectionalMethod = function(descriptor, type) {
+      return function() {
+        var context = this.context;
+        var packet = type.write(arguments, context);
+        var context = this.context;
+        packet.to = this.id;
+        return client.request(packet).then(function(packet) {
+          return type.read(packet, context);
+        });
+      };
+    };
+
+    var Event = Class({
+      constructor: function(name, descriptor) {
+        this.name = descriptor.type || name;
+        this.eventType = descriptor.type || name;
+        this.types = Object.create(null);
+
+        var types = this.types;
+        for (var key in descriptor) {
+          if (key === "type") {
+            types[key] = "string";
+          } else {
+            types[key] = descriptor[key].type;
+          }
+        }
+      },
+      read: function(input, context) {
+        var output = {};
+        var types = this.types;
+        for (var key in input) {
+          output[key] = read(input[key], context, types[key]);
+        }
+        return output;
+      },
+      write: function(input, context) {
+        var output = {};
+        var types = this.types;
+        for (var key in this.types) {
+          output[key] = write(input[key], context, types[key]);
+        }
+        return output;
+      }
+    });
+
+    var Front = Class({
+      extends: EventTarget,
+      EventTarget: EventTarget,
+      constructor: function(state) {
+        this.EventTarget();
+        Object.defineProperties(this,  {
+          state: {
+            enumerable: false,
+            writable: true,
+            configurable: true,
+            value: state
+          }
+        });
+
+        client.register(this);
+      },
+      get id() {
+        return this.state.actor;
+      },
+      get context() {
+        return this;
+      },
+      form: function(state, detail, context) {
+        if (this.state !== state) {
+          if (detail) {
+            this.state[detail] = state[detail];
+          } else {
+            pairs(state).forEach(function(pair) {
+              var key = pair[0], value = pair[1];
+              this.state[key] = value;
+            }, this);
+          }
+        }
+
+        if (context) {
+          client.supervise(context, this);
+        }
+      },
+      requestTypes: function() {
+        return client.request({
+          to: this.id,
+          type: "requestTypes"
+        }).then(function(packet) {
+          return packet.requestTypes;
+        });
+      }
+    });
+    types.primitive = new Primitve("primitive");
+    types.string = new Primitve("string");
+    types.number = new Primitve("number");
+    types.boolean = new Primitve("boolean");
+    types.json = new Primitve("json");
+    types.array = new Primitve("array");
+  },
+  registerTypes: function(descriptor) {
+    var specification = this.specification;
+    values(descriptor.types).forEach(function(descriptor) {
+      specification[descriptor.typeName] = descriptor;
+    });
+  }
+});
+exports.TypeSystem = TypeSystem;
+
+},{"./class":3,"./event":5,"./util":26}],26:[function(_dereq_,module,exports){
+"use strict";
+
+var keys = Object.keys;
+exports.keys = keys;
+
+// Returns array of values for the given object.
+var values = function(object) {
+  return keys(object).map(function(key) {
+    return object[key]
+  });
+};
+exports.values = values;
+
+// Returns [key, value] pairs for the given object.
+var pairs = function(object) {
+  return keys(object).map(function(key) {
+    return [key, object[key]]
+  });
+};
+exports.pairs = pairs;
+
+
+// Queries an object for the field nested with in it.
+var query = function(object, path) {
+  return path.reduce(function(object, entry) {
+    return object && object[entry]
+  }, object);
+};
+exports.query = query;
+
+var isObject = function(x) {
+  return x && typeof(x) === "object"
+}
+
+var findPath = function(object, key) {
+  var path = void(0);
+  if (object && typeof(object) === "object") {
+    var names = keys(object);
+    if (names.indexOf(key) >= 0) {
+      path = [];
+    } else {
+      var index = 0;
+      var count = names.length;
+      while (index < count && !path){
+        var head = names[index];
+        var tail = findPath(object[head], key);
+        path = tail ? [head].concat(tail) : tail;
+        index = index + 1
+      }
+    }
+  }
+  return path;
+};
+exports.findPath = findPath;
+
+},{}]},{},[1])
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vYnJvd3Nlci9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2Jyb3dzZXIvcHJvbWlzZS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL2NsYXNzLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vY2xpZW50LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vZXZlbnQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL2luZGV4LmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvaXMtaW1wbGVtZW50ZWQuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZC9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9hc3NpZ24vaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvYXNzaWduL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2Fzc2lnbi9zaGltLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2lzLWNhbGxhYmxlLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvb2JqZWN0L2tleXMvaW5kZXguanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qva2V5cy9pcy1pbXBsZW1lbnRlZC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L29iamVjdC9rZXlzL3NoaW0uanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3Qvbm9ybWFsaXplLW9wdGlvbnMuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9vYmplY3QvdmFsaWQtdmFsdWUuanMiLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9ub2RlX21vZHVsZXMvZXM2LXN5bWJvbC9ub2RlX21vZHVsZXMvZXM1LWV4dC9zdHJpbmcvIy9jb250YWlucy9pbmRleC5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL25vZGVfbW9kdWxlcy9lczUtZXh0L3N0cmluZy8jL2NvbnRhaW5zL2lzLWltcGxlbWVudGVkLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vbm9kZV9tb2R1bGVzL2VzNi1zeW1ib2wvbm9kZV9tb2R1bGVzL2VzNS1leHQvc3RyaW5nLyMvY29udGFpbnMvc2hpbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL25vZGVfbW9kdWxlcy9lczYtc3ltYm9sL3BvbHlmaWxsLmpzIiwiL1VzZXJzL2dvemFsYS9Qcm9qZWN0cy92b2xjYW4vc3BlY2lmaWNhdGlvbi9jb3JlLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi9zcGVjaWZpY2F0aW9uL3Byb3RvY29sLmpzb24iLCIvVXNlcnMvZ296YWxhL1Byb2plY3RzL3ZvbGNhbi90eXBlLXN5c3RlbS5qcyIsIi9Vc2Vycy9nb3phbGEvUHJvamVjdHMvdm9sY2FuL3V0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1U0E7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzdUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsaWVudCA9IHJlcXVpcmUoXCIuLi9jbGllbnRcIikuQ2xpZW50O1xuXG5mdW5jdGlvbiBjb25uZWN0KHBvcnQpIHtcbiAgdmFyIGNsaWVudCA9IG5ldyBDbGllbnQoKTtcbiAgcmV0dXJuIGNsaWVudC5jb25uZWN0KHBvcnQpO1xufVxuZXhwb3J0cy5jb25uZWN0ID0gY29ubmVjdDtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5leHBvcnRzLlByb21pc2UgPSBQcm9taXNlO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBkZXNjcmliZSA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3I7XG52YXIgQ2xhc3MgPSBmdW5jdGlvbihmaWVsZHMpIHtcbiAgdmFyIG5hbWVzID0gT2JqZWN0LmtleXMoZmllbGRzKTtcbiAgdmFyIGNvbnN0cnVjdG9yID0gbmFtZXMuaW5kZXhPZihcImNvbnN0cnVjdG9yXCIpID49IDAgPyBmaWVsZHMuY29uc3RydWN0b3IgOlxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHt9O1xuICB2YXIgYW5jZXN0b3IgPSBmaWVsZHMuZXh0ZW5kcyB8fCBPYmplY3Q7XG5cbiAgdmFyIGRlc2NyaXB0b3IgPSBuYW1lcy5yZWR1Y2UoZnVuY3Rpb24oZGVzY3JpcHRvciwga2V5KSB7XG4gICAgZGVzY3JpcHRvcltrZXldID0gZGVzY3JpYmUoZmllbGRzLCBrZXkpO1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9LCB7fSk7XG5cbiAgdmFyIHByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoYW5jZXN0b3IucHJvdG90eXBlLCBkZXNjcmlwdG9yKTtcblxuICBjb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gIHByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IGNvbnN0cnVjdG9yO1xuXG4gIHJldHVybiBjb25zdHJ1Y3Rvcjtcbn07XG5leHBvcnRzLkNsYXNzID0gQ2xhc3M7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG52YXIgVHlwZVN5c3RlbSA9IHJlcXVpcmUoXCIuL3R5cGUtc3lzdGVtXCIpLlR5cGVTeXN0ZW07XG52YXIgdmFsdWVzID0gcmVxdWlyZShcIi4vdXRpbFwiKS52YWx1ZXM7XG52YXIgUHJvbWlzZSA9IHJlcXVpcmUoXCJlczYtcHJvbWlzZVwiKS5Qcm9taXNlO1xuXG52YXIgc3BlY2lmaWNhdGlvbiA9IHJlcXVpcmUoXCIuL3NwZWNpZmljYXRpb24vY29yZS5qc29uXCIpO1xuXG5mdW5jdGlvbiByZWNvdmVyQWN0b3JEZXNjcmlwdGlvbnMoZXJyb3IpIHtcbiAgY29uc29sZS53YXJuKFwiRmFpbGVkIHRvIGZldGNoIHByb3RvY29sIHNwZWNpZmljYXRpb24gKHNlZSByZWFzb24gYmVsb3cpLiBcIiArXG4gICAgICAgICAgICAgICBcIlVzaW5nIGEgZmFsbGJhY2sgcHJvdG9jYWwgc3BlY2lmaWNhdGlvbiFcIixcbiAgICAgICAgICAgICAgIGVycm9yKTtcbiAgcmV0dXJuIHJlcXVpcmUoXCIuL3NwZWNpZmljYXRpb24vcHJvdG9jb2wuanNvblwiKTtcbn1cblxuLy8gVHlwZSB0byByZXByZXNlbnQgc3VwZXJ2aXNlciBhY3RvciByZWxhdGlvbnMgdG8gYWN0b3JzIHRoZXkgc3VwZXJ2aXNlXG4vLyBpbiB0ZXJtcyBvZiBsaWZldGltZSBtYW5hZ2VtZW50LlxudmFyIFN1cGVydmlzb3IgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihpZCkge1xuICAgIHRoaXMuaWQgPSBpZDtcbiAgICB0aGlzLndvcmtlcnMgPSBbXTtcbiAgfVxufSk7XG5cbnZhciBUZWxlbWV0cnkgPSBDbGFzcyh7XG4gIGFkZDogZnVuY3Rpb24oaWQsIG1zKSB7XG4gICAgY29uc29sZS5sb2coXCJ0ZWxlbWV0cnk6OlwiLCBpZCwgbXMpXG4gIH1cbn0pO1xuXG4vLyBDb25zaWRlciBtYWtpbmcgY2xpZW50IGEgcm9vdCBhY3Rvci5cblxudmFyIENsaWVudCA9IENsYXNzKHtcbiAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucm9vdCA9IG51bGw7XG4gICAgdGhpcy50ZWxlbWV0cnkgPSBuZXcgVGVsZW1ldHJ5KCk7XG5cbiAgICB0aGlzLnNldHVwQ29ubmVjdGlvbigpO1xuICAgIHRoaXMuc2V0dXBMaWZlTWFuYWdlbWVudCgpO1xuICAgIHRoaXMuc2V0dXBUeXBlU3lzdGVtKCk7XG4gIH0sXG5cbiAgc2V0dXBDb25uZWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlcXVlc3RzID0gW107XG4gIH0sXG4gIHNldHVwTGlmZU1hbmFnZW1lbnQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMuY2FjaGUgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIHRoaXMuZ3JhcGggPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuICAgIHRoaXMuZ2V0ID0gdGhpcy5nZXQuYmluZCh0aGlzKTtcbiAgICB0aGlzLnJlbGVhc2UgPSB0aGlzLnJlbGVhc2UuYmluZCh0aGlzKTtcbiAgfSxcbiAgc2V0dXBUeXBlU3lzdGVtOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnR5cGVTeXN0ZW0gPSBuZXcgVHlwZVN5c3RlbSh0aGlzKTtcbiAgICB0aGlzLnR5cGVTeXN0ZW0ucmVnaXN0ZXJUeXBlcyhzcGVjaWZpY2F0aW9uKTtcbiAgfSxcblxuICBjb25uZWN0OiBmdW5jdGlvbihwb3J0KSB7XG4gICAgdmFyIGNsaWVudCA9IHRoaXM7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgY2xpZW50LnBvcnQgPSBwb3J0O1xuICAgICAgcG9ydC5vbm1lc3NhZ2UgPSBjbGllbnQucmVjZWl2ZS5iaW5kKGNsaWVudCk7XG4gICAgICBjbGllbnQub25SZWFkeSA9IHJlc29sdmU7XG4gICAgICBjbGllbnQub25GYWlsID0gcmVqZWN0O1xuXG4gICAgICBwb3J0LnN0YXJ0KCk7XG4gICAgfSk7XG4gIH0sXG4gIHNlbmQ6IGZ1bmN0aW9uKHBhY2tldCkge1xuICAgIHRoaXMucG9ydC5wb3N0TWVzc2FnZShwYWNrZXQpO1xuICB9LFxuICByZXF1ZXN0OiBmdW5jdGlvbihwYWNrZXQpIHtcbiAgICB2YXIgY2xpZW50ID0gdGhpcztcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICBjbGllbnQucmVxdWVzdHMucHVzaChwYWNrZXQudG8sIHsgcmVzb2x2ZTogcmVzb2x2ZSwgcmVqZWN0OiByZWplY3QgfSk7XG4gICAgICBjbGllbnQuc2VuZChwYWNrZXQpO1xuICAgIH0pO1xuICB9LFxuXG4gIHJlY2VpdmU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgdmFyIHBhY2tldCA9IGV2ZW50LmRhdGE7XG4gICAgaWYgKCF0aGlzLnJvb3QpIHtcbiAgICAgIGlmIChwYWNrZXQuZnJvbSAhPT0gXCJyb290XCIpXG4gICAgICAgIHRocm93IEVycm9yKFwiSW5pdGlhbCBwYWNrZXQgbXVzdCBiZSBmcm9tIHJvb3RcIik7XG4gICAgICBpZiAoIShcImFwcGxpY2F0aW9uVHlwZVwiIGluIHBhY2tldCkpXG4gICAgICAgIHRocm93IEVycm9yKFwiSW5pdGlhbCBwYWNrZXQgbXVzdCBjb250YWluIGFwcGxpY2F0aW9uVHlwZSBmaWVsZFwiKTtcblxuICAgICAgdGhpcy5yb290ID0gdGhpcy50eXBlU3lzdGVtLnJlYWQoXCJyb290XCIsIG51bGwsIFwicm9vdFwiKTtcbiAgICAgIHRoaXMucm9vdFxuICAgICAgICAgIC5wcm90b2NvbERlc2NyaXB0aW9uKClcbiAgICAgICAgICAuY2F0Y2gocmVjb3ZlckFjdG9yRGVzY3JpcHRpb25zKVxuICAgICAgICAgIC50aGVuKHRoaXMudHlwZVN5c3RlbS5yZWdpc3RlclR5cGVzLmJpbmQodGhpcy50eXBlU3lzdGVtKSlcbiAgICAgICAgICAudGhlbih0aGlzLm9uUmVhZHkuYmluZCh0aGlzLCB0aGlzLnJvb3QpLCB0aGlzLm9uRmFpbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBhY3RvciA9IHRoaXMuZ2V0KHBhY2tldC5mcm9tKSB8fCB0aGlzLnJvb3Q7XG4gICAgICB2YXIgZXZlbnQgPSBhY3Rvci5ldmVudHNbcGFja2V0LnR5cGVdO1xuICAgICAgaWYgKGV2ZW50KSB7XG4gICAgICAgIGFjdG9yLmRpc3BhdGNoRXZlbnQoZXZlbnQucmVhZChwYWNrZXQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBpbmRleCA9IHRoaXMucmVxdWVzdHMuaW5kZXhPZihhY3Rvci5pZCk7XG4gICAgICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICAgICAgdmFyIHJlcXVlc3QgPSB0aGlzLnJlcXVlc3RzLnNwbGljZShpbmRleCwgMikucG9wKCk7XG4gICAgICAgICAgaWYgKHBhY2tldC5lcnJvcilcbiAgICAgICAgICAgIHJlcXVlc3QucmVqZWN0KHBhY2tldCk7XG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmVxdWVzdC5yZXNvbHZlKHBhY2tldCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihFcnJvcihcIlVuZXhwZWN0ZWQgcGFja2V0IFwiICsgSlNPTi5zdHJpbmdpZnkocGFja2V0LCAyLCAyKSksXG4gICAgICAgICAgICAgICAgICAgICAgICBwYWNrZXQsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RzLnNsaWNlKDApKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBnZXQ6IGZ1bmN0aW9uKGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuY2FjaGVbaWRdO1xuICB9LFxuICBzdXBlcnZpc29yT2Y6IGZ1bmN0aW9uKGFjdG9yKSB7XG4gICAgZm9yICh2YXIgaWQgaW4gdGhpcy5ncmFwaCkge1xuICAgICAgaWYgKHRoaXMuZ3JhcGhbaWRdLmluZGV4T2YoYWN0b3IuaWQpID49IDApIHtcbiAgICAgICAgcmV0dXJuIGlkO1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgd29ya2Vyc09mOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIHJldHVybiB0aGlzLmdyYXBoW2FjdG9yLmlkXTtcbiAgfSxcbiAgc3VwZXJ2aXNlOiBmdW5jdGlvbihhY3Rvciwgd29ya2VyKSB7XG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3RvcilcbiAgICBpZiAod29ya2Vycy5pbmRleE9mKHdvcmtlci5pZCkgPCAwKSB7XG4gICAgICB3b3JrZXJzLnB1c2god29ya2VyLmlkKTtcbiAgICB9XG4gIH0sXG4gIHVuc3VwZXJ2aXNlOiBmdW5jdGlvbihhY3Rvciwgd29ya2VyKSB7XG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3Rvcik7XG4gICAgdmFyIGluZGV4ID0gd29ya2Vycy5pbmRleE9mKHdvcmtlci5pZClcbiAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgd29ya2Vycy5zcGxpY2UoaW5kZXgsIDEpXG4gICAgfVxuICB9LFxuXG4gIHJlZ2lzdGVyOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIHZhciByZWdpc3RlcmVkID0gdGhpcy5nZXQoYWN0b3IuaWQpO1xuICAgIGlmICghcmVnaXN0ZXJlZCkge1xuICAgICAgdGhpcy5jYWNoZVthY3Rvci5pZF0gPSBhY3RvcjtcbiAgICAgIHRoaXMuZ3JhcGhbYWN0b3IuaWRdID0gW107XG4gICAgfSBlbHNlIGlmIChyZWdpc3RlcmVkICE9PSBhY3Rvcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGlmZmVyZW50IGFjdG9yIHdpdGggc2FtZSBpZCBpcyBhbHJlYWR5IHJlZ2lzdGVyZWRcIik7XG4gICAgfVxuICB9LFxuICB1bnJlZ2lzdGVyOiBmdW5jdGlvbihhY3Rvcikge1xuICAgIGlmICh0aGlzLmdldChhY3Rvci5pZCkpIHtcbiAgICAgIGRlbGV0ZSB0aGlzLmNhY2hlW2FjdG9yLmlkXTtcbiAgICAgIGRlbGV0ZSB0aGlzLmdyYXBoW2FjdG9yLmlkXTtcbiAgICB9XG4gIH0sXG5cbiAgcmVsZWFzZTogZnVuY3Rpb24oYWN0b3IpIHtcbiAgICB2YXIgc3VwZXJ2aXNvciA9IHRoaXMuc3VwZXJ2aXNvck9mKGFjdG9yKTtcbiAgICBpZiAoc3VwZXJ2aXNvcilcbiAgICAgIHRoaXMudW5zdXBlcnZpc2Uoc3VwZXJ2aXNvciwgYWN0b3IpO1xuXG4gICAgdmFyIHdvcmtlcnMgPSB0aGlzLndvcmtlcnNPZihhY3RvcilcblxuICAgIGlmICh3b3JrZXJzKSB7XG4gICAgICB3b3JrZXJzLm1hcCh0aGlzLmdldCkuZm9yRWFjaCh0aGlzLnJlbGVhc2UpXG4gICAgfVxuICAgIHRoaXMudW5lcmdpc3RlcihhY3Rvcik7XG4gIH1cbn0pO1xuZXhwb3J0cy5DbGllbnQgPSBDbGllbnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bWJvbCA9IHJlcXVpcmUoXCJlczYtc3ltYm9sXCIpXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcImV2ZW50c1wiKS5FdmVudEVtaXR0ZXI7XG52YXIgQ2xhc3MgPSByZXF1aXJlKFwiLi9jbGFzc1wiKS5DbGFzcztcblxudmFyICRib3VuZCA9IFN5bWJvbChcIkV2ZW50VGFyZ2V0L2hhbmRsZUV2ZW50XCIpO1xudmFyICRlbWl0dGVyID0gU3ltYm9sKFwiRXZlbnRUYXJnZXQvZW1pdHRlclwiKTtcblxuZnVuY3Rpb24gbWFrZUhhbmRsZXIoaGFuZGxlcikge1xuICByZXR1cm4gZnVuY3Rpb24oZXZlbnQpIHtcbiAgICBoYW5kbGVyLmhhbmRsZUV2ZW50KGV2ZW50KTtcbiAgfVxufVxuXG52YXIgRXZlbnRUYXJnZXQgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJGVtaXR0ZXIsIHtcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICB2YWx1ZTogbmV3IEV2ZW50RW1pdHRlcigpXG4gICAgfSk7XG4gIH0sXG4gIGFkZEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGhhbmRsZXIpIHtcbiAgICBpZiAodHlwZW9mKGhhbmRsZXIpID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRoaXNbJGVtaXR0ZXJdLm9uKHR5cGUsIGhhbmRsZXIpO1xuICAgIH1cbiAgICBlbHNlIGlmIChoYW5kbGVyICYmIHR5cGVvZihoYW5kbGVyKSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgaWYgKCFoYW5kbGVyWyRib3VuZF0pIGhhbmRsZXJbJGJvdW5kXSA9IG1ha2VIYW5kbGVyKGhhbmRsZXIpO1xuICAgICAgdGhpc1skZW1pdHRlcl0ub24odHlwZSwgaGFuZGxlclskYm91bmRdKTtcbiAgICB9XG4gIH0sXG4gIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGhhbmRsZXIpIHtcbiAgICBpZiAodHlwZW9mKGhhbmRsZXIpID09PSBcImZ1bmN0aW9uXCIpXG4gICAgICB0aGlzWyRlbWl0dGVyXS5yZW1vdmVMaXN0ZW5lcih0eXBlLCBoYW5kbGVyKTtcbiAgICBlbHNlIGlmIChoYW5kbGVyICYmIGhhbmRsZXJbJGJvdW5kXSlcbiAgICAgIHRoaXNbJGVtaXR0ZXJdLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGhhbmRsZXJbJGJvdW5kXSk7XG4gIH0sXG4gIGRpc3BhdGNoRXZlbnQ6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgZXZlbnQudGFyZ2V0ID0gdGhpcztcbiAgICB0aGlzWyRlbWl0dGVyXS5lbWl0KGV2ZW50LnR5cGUsIGV2ZW50KTtcbiAgfVxufSk7XG5leHBvcnRzLkV2ZW50VGFyZ2V0ID0gRXZlbnRUYXJnZXQ7XG5cbnZhciBNZXNzYWdlRXZlbnQgPSBDbGFzcyh7XG4gIGNvbnN0cnVjdG9yOiBmdW5jdGlvbih0eXBlLCBvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICB0aGlzLmRhdGEgPSBvcHRpb25zLmRhdGEgPT09IHZvaWQoMCkgPyBudWxsIDogb3B0aW9ucy5kYXRhO1xuXG4gICAgdGhpcy5sYXN0RXZlbnRJZCA9IG9wdGlvbnMubGFzdEV2ZW50SWQgfHwgXCJcIjtcbiAgICB0aGlzLm9yaWdpbiA9IG9wdGlvbnMub3JpZ2luIHx8IFwiXCI7XG4gICAgdGhpcy5idWJibGVzID0gb3B0aW9ucy5idWJibGVzIHx8IGZhbHNlO1xuICAgIHRoaXMuY2FuY2VsYWJsZSA9IG9wdGlvbnMuY2FuY2VsYWJsZSB8fCBmYWxzZTtcbiAgfSxcbiAgc291cmNlOiBudWxsLFxuICBwb3J0czogbnVsbCxcbiAgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkge1xuICB9LFxuICBzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuICB9LFxuICBzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuICB9XG59KTtcbmV4cG9ydHMuTWVzc2FnZUV2ZW50ID0gTWVzc2FnZUV2ZW50O1xuIiwiLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGFcbi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbi8vIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdFxuLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlXG4vLyBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZFxuLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTU1xuLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRlxuLy8gTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTlxuLy8gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sXG4vLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1Jcbi8vIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEVcbi8vIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuXG5cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgdGhpcy5fZXZlbnRzID0gdGhpcy5fZXZlbnRzIHx8IHt9O1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSB0aGlzLl9tYXhMaXN0ZW5lcnMgfHwgdW5kZWZpbmVkO1xufVxubW9kdWxlLmV4cG9ydHMgPSBFdmVudEVtaXR0ZXI7XG5cbi8vIEJhY2t3YXJkcy1jb21wYXQgd2l0aCBub2RlIDAuMTAueFxuRXZlbnRFbWl0dGVyLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fZXZlbnRzID0gdW5kZWZpbmVkO1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fbWF4TGlzdGVuZXJzID0gdW5kZWZpbmVkO1xuXG4vLyBCeSBkZWZhdWx0IEV2ZW50RW1pdHRlcnMgd2lsbCBwcmludCBhIHdhcm5pbmcgaWYgbW9yZSB0aGFuIDEwIGxpc3RlbmVycyBhcmVcbi8vIGFkZGVkIHRvIGl0LiBUaGlzIGlzIGEgdXNlZnVsIGRlZmF1bHQgd2hpY2ggaGVscHMgZmluZGluZyBtZW1vcnkgbGVha3MuXG5FdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycyA9IDEwO1xuXG4vLyBPYnZpb3VzbHkgbm90IGFsbCBFbWl0dGVycyBzaG91bGQgYmUgbGltaXRlZCB0byAxMC4gVGhpcyBmdW5jdGlvbiBhbGxvd3Ncbi8vIHRoYXQgdG8gYmUgaW5jcmVhc2VkLiBTZXQgdG8gemVybyBmb3IgdW5saW1pdGVkLlxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5zZXRNYXhMaXN0ZW5lcnMgPSBmdW5jdGlvbihuKSB7XG4gIGlmICghaXNOdW1iZXIobikgfHwgbiA8IDAgfHwgaXNOYU4obikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCduIG11c3QgYmUgYSBwb3NpdGl2ZSBudW1iZXInKTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gbjtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBlciwgaGFuZGxlciwgbGVuLCBhcmdzLCBpLCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gSWYgdGhlcmUgaXMgbm8gJ2Vycm9yJyBldmVudCBsaXN0ZW5lciB0aGVuIHRocm93LlxuICBpZiAodHlwZSA9PT0gJ2Vycm9yJykge1xuICAgIGlmICghdGhpcy5fZXZlbnRzLmVycm9yIHx8XG4gICAgICAgIChpc09iamVjdCh0aGlzLl9ldmVudHMuZXJyb3IpICYmICF0aGlzLl9ldmVudHMuZXJyb3IubGVuZ3RoKSkge1xuICAgICAgZXIgPSBhcmd1bWVudHNbMV07XG4gICAgICBpZiAoZXIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aHJvdyBlcjsgLy8gVW5oYW5kbGVkICdlcnJvcicgZXZlbnRcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IFR5cGVFcnJvcignVW5jYXVnaHQsIHVuc3BlY2lmaWVkIFwiZXJyb3JcIiBldmVudC4nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVyID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc1VuZGVmaW5lZChoYW5kbGVyKSlcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgaWYgKGlzRnVuY3Rpb24oaGFuZGxlcikpIHtcbiAgICBzd2l0Y2ggKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIC8vIGZhc3QgY2FzZXNcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdLCBhcmd1bWVudHNbMl0pO1xuICAgICAgICBicmVhaztcbiAgICAgIC8vIHNsb3dlclxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbGVuID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICAgICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICAgICAgZm9yIChpID0gMTsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgICAgICBoYW5kbGVyLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc09iamVjdChoYW5kbGVyKSkge1xuICAgIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuOyBpKyspXG4gICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcblxuICAgIGxpc3RlbmVycyA9IGhhbmRsZXIuc2xpY2UoKTtcbiAgICBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBtO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBUbyBhdm9pZCByZWN1cnNpb24gaW4gdGhlIGNhc2UgdGhhdCB0eXBlID09PSBcIm5ld0xpc3RlbmVyXCIhIEJlZm9yZVxuICAvLyBhZGRpbmcgaXQgdG8gdGhlIGxpc3RlbmVycywgZmlyc3QgZW1pdCBcIm5ld0xpc3RlbmVyXCIuXG4gIGlmICh0aGlzLl9ldmVudHMubmV3TGlzdGVuZXIpXG4gICAgdGhpcy5lbWl0KCduZXdMaXN0ZW5lcicsIHR5cGUsXG4gICAgICAgICAgICAgIGlzRnVuY3Rpb24obGlzdGVuZXIubGlzdGVuZXIpID9cbiAgICAgICAgICAgICAgbGlzdGVuZXIubGlzdGVuZXIgOiBsaXN0ZW5lcik7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgLy8gT3B0aW1pemUgdGhlIGNhc2Ugb2Ygb25lIGxpc3RlbmVyLiBEb24ndCBuZWVkIHRoZSBleHRyYSBhcnJheSBvYmplY3QuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdID0gbGlzdGVuZXI7XG4gIGVsc2UgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgLy8gSWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gYXJyYXksIGp1c3QgYXBwZW5kLlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZVxuICAgIC8vIEFkZGluZyB0aGUgc2Vjb25kIGVsZW1lbnQsIG5lZWQgdG8gY2hhbmdlIHRvIGFycmF5LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV0sIGxpc3RlbmVyXTtcblxuICAvLyBDaGVjayBmb3IgbGlzdGVuZXIgbGVha1xuICBpZiAoaXNPYmplY3QodGhpcy5fZXZlbnRzW3R5cGVdKSAmJiAhdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCkge1xuICAgIHZhciBtO1xuICAgIGlmICghaXNVbmRlZmluZWQodGhpcy5fbWF4TGlzdGVuZXJzKSkge1xuICAgICAgbSA9IHRoaXMuX21heExpc3RlbmVycztcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IEV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzO1xuICAgIH1cblxuICAgIGlmIChtICYmIG0gPiAwICYmIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGggPiBtKSB7XG4gICAgICB0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkID0gdHJ1ZTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJyhub2RlKSB3YXJuaW5nOiBwb3NzaWJsZSBFdmVudEVtaXR0ZXIgbWVtb3J5ICcgK1xuICAgICAgICAgICAgICAgICAgICAnbGVhayBkZXRlY3RlZC4gJWQgbGlzdGVuZXJzIGFkZGVkLiAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvIGluY3JlYXNlIGxpbWl0LicsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGgpO1xuICAgICAgY29uc29sZS50cmFjZSgpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICB2YXIgZmlyZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBnKCkge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG5cbiAgICBpZiAoIWZpcmVkKSB7XG4gICAgICBmaXJlZCA9IHRydWU7XG4gICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgfVxuXG4gIGcubGlzdGVuZXIgPSBsaXN0ZW5lcjtcbiAgdGhpcy5vbih0eXBlLCBnKTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vIGVtaXRzIGEgJ3JlbW92ZUxpc3RlbmVyJyBldmVudCBpZmYgdGhlIGxpc3RlbmVyIHdhcyByZW1vdmVkXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIGxpc3QsIHBvc2l0aW9uLCBsZW5ndGgsIGk7XG5cbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgbGlzdCA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgbGVuZ3RoID0gbGlzdC5sZW5ndGg7XG4gIHBvc2l0aW9uID0gLTE7XG5cbiAgaWYgKGxpc3QgPT09IGxpc3RlbmVyIHx8XG4gICAgICAoaXNGdW5jdGlvbihsaXN0Lmxpc3RlbmVyKSAmJiBsaXN0Lmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIGlmICh0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpXG4gICAgICB0aGlzLmVtaXQoJ3JlbW92ZUxpc3RlbmVyJywgdHlwZSwgbGlzdGVuZXIpO1xuXG4gIH0gZWxzZSBpZiAoaXNPYmplY3QobGlzdCkpIHtcbiAgICBmb3IgKGkgPSBsZW5ndGg7IGktLSA+IDA7KSB7XG4gICAgICBpZiAobGlzdFtpXSA9PT0gbGlzdGVuZXIgfHxcbiAgICAgICAgICAobGlzdFtpXS5saXN0ZW5lciAmJiBsaXN0W2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICAgICAgcG9zaXRpb24gPSBpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocG9zaXRpb24gPCAwKVxuICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICBpZiAobGlzdC5sZW5ndGggPT09IDEpIHtcbiAgICAgIGxpc3QubGVuZ3RoID0gMDtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpc3Quc3BsaWNlKHBvc2l0aW9uLCAxKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBrZXksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICByZXR1cm4gdGhpcztcblxuICAvLyBub3QgbGlzdGVuaW5nIGZvciByZW1vdmVMaXN0ZW5lciwgbm8gbmVlZCB0byBlbWl0XG4gIGlmICghdGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApXG4gICAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICBlbHNlIGlmICh0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gZW1pdCByZW1vdmVMaXN0ZW5lciBmb3IgYWxsIGxpc3RlbmVycyBvbiBhbGwgZXZlbnRzXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgZm9yIChrZXkgaW4gdGhpcy5fZXZlbnRzKSB7XG4gICAgICBpZiAoa2V5ID09PSAncmVtb3ZlTGlzdGVuZXInKSBjb250aW51ZTtcbiAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKGtleSk7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCdyZW1vdmVMaXN0ZW5lcicpO1xuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgbGlzdGVuZXJzID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGxpc3RlbmVycykpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVycyk7XG4gIH0gZWxzZSB7XG4gICAgLy8gTElGTyBvcmRlclxuICAgIHdoaWxlIChsaXN0ZW5lcnMubGVuZ3RoKVxuICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbbGlzdGVuZXJzLmxlbmd0aCAtIDFdKTtcbiAgfVxuICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gW107XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24odGhpcy5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSBbdGhpcy5fZXZlbnRzW3R5cGVdXTtcbiAgZWxzZVxuICAgIHJldCA9IHRoaXMuX2V2ZW50c1t0eXBlXS5zbGljZSgpO1xuICByZXR1cm4gcmV0O1xufTtcblxuRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghZW1pdHRlci5fZXZlbnRzIHx8ICFlbWl0dGVyLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gMDtcbiAgZWxzZSBpZiAoaXNGdW5jdGlvbihlbWl0dGVyLl9ldmVudHNbdHlwZV0pKVxuICAgIHJldCA9IDE7XG4gIGVsc2VcbiAgICByZXQgPSBlbWl0dGVyLl9ldmVudHNbdHlwZV0ubGVuZ3RoO1xuICByZXR1cm4gcmV0O1xufTtcblxuZnVuY3Rpb24gaXNGdW5jdGlvbihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdmdW5jdGlvbic7XG59XG5cbmZ1bmN0aW9uIGlzTnVtYmVyKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ251bWJlcic7XG59XG5cbmZ1bmN0aW9uIGlzT2JqZWN0KGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ29iamVjdCcgJiYgYXJnICE9PSBudWxsO1xufVxuXG5mdW5jdGlvbiBpc1VuZGVmaW5lZChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gdm9pZCAwO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpID8gU3ltYm9sIDogcmVxdWlyZSgnLi9wb2x5ZmlsbCcpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblx0dmFyIHN5bWJvbDtcblx0aWYgKHR5cGVvZiBTeW1ib2wgIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcblx0c3ltYm9sID0gU3ltYm9sKCd0ZXN0IHN5bWJvbCcpO1xuXHR0cnkge1xuXHRcdGlmIChTdHJpbmcoc3ltYm9sKSAhPT0gJ1N5bWJvbCAodGVzdCBzeW1ib2wpJykgcmV0dXJuIGZhbHNlO1xuXHR9IGNhdGNoIChlKSB7IHJldHVybiBmYWxzZTsgfVxuXHRpZiAodHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gJ3N5bWJvbCcpIHJldHVybiB0cnVlO1xuXG5cdC8vIFJldHVybiAndHJ1ZScgZm9yIHBvbHlmaWxsc1xuXHRpZiAodHlwZW9mIFN5bWJvbC5pc0NvbmNhdFNwcmVhZGFibGUgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cdGlmICh0eXBlb2YgU3ltYm9sLmlzUmVnRXhwICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC5pdGVyYXRvciAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblx0aWYgKHR5cGVvZiBTeW1ib2wudG9QcmltaXRpdmUgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG5cdGlmICh0eXBlb2YgU3ltYm9sLnRvU3RyaW5nVGFnICE9PSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuXHRpZiAodHlwZW9mIFN5bWJvbC51bnNjb3BhYmxlcyAhPT0gJ29iamVjdCcpIHJldHVybiBmYWxzZTtcblxuXHRyZXR1cm4gdHJ1ZTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBhc3NpZ24gICAgICAgID0gcmVxdWlyZSgnZXM1LWV4dC9vYmplY3QvYXNzaWduJylcbiAgLCBub3JtYWxpemVPcHRzID0gcmVxdWlyZSgnZXM1LWV4dC9vYmplY3Qvbm9ybWFsaXplLW9wdGlvbnMnKVxuICAsIGlzQ2FsbGFibGUgICAgPSByZXF1aXJlKCdlczUtZXh0L29iamVjdC9pcy1jYWxsYWJsZScpXG4gICwgY29udGFpbnMgICAgICA9IHJlcXVpcmUoJ2VzNS1leHQvc3RyaW5nLyMvY29udGFpbnMnKVxuXG4gICwgZDtcblxuZCA9IG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGRzY3IsIHZhbHVlLyosIG9wdGlvbnMqLykge1xuXHR2YXIgYywgZSwgdywgb3B0aW9ucywgZGVzYztcblx0aWYgKChhcmd1bWVudHMubGVuZ3RoIDwgMikgfHwgKHR5cGVvZiBkc2NyICE9PSAnc3RyaW5nJykpIHtcblx0XHRvcHRpb25zID0gdmFsdWU7XG5cdFx0dmFsdWUgPSBkc2NyO1xuXHRcdGRzY3IgPSBudWxsO1xuXHR9IGVsc2Uge1xuXHRcdG9wdGlvbnMgPSBhcmd1bWVudHNbMl07XG5cdH1cblx0aWYgKGRzY3IgPT0gbnVsbCkge1xuXHRcdGMgPSB3ID0gdHJ1ZTtcblx0XHRlID0gZmFsc2U7XG5cdH0gZWxzZSB7XG5cdFx0YyA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2MnKTtcblx0XHRlID0gY29udGFpbnMuY2FsbChkc2NyLCAnZScpO1xuXHRcdHcgPSBjb250YWlucy5jYWxsKGRzY3IsICd3Jyk7XG5cdH1cblxuXHRkZXNjID0geyB2YWx1ZTogdmFsdWUsIGNvbmZpZ3VyYWJsZTogYywgZW51bWVyYWJsZTogZSwgd3JpdGFibGU6IHcgfTtcblx0cmV0dXJuICFvcHRpb25zID8gZGVzYyA6IGFzc2lnbihub3JtYWxpemVPcHRzKG9wdGlvbnMpLCBkZXNjKTtcbn07XG5cbmQuZ3MgPSBmdW5jdGlvbiAoZHNjciwgZ2V0LCBzZXQvKiwgb3B0aW9ucyovKSB7XG5cdHZhciBjLCBlLCBvcHRpb25zLCBkZXNjO1xuXHRpZiAodHlwZW9mIGRzY3IgIT09ICdzdHJpbmcnKSB7XG5cdFx0b3B0aW9ucyA9IHNldDtcblx0XHRzZXQgPSBnZXQ7XG5cdFx0Z2V0ID0gZHNjcjtcblx0XHRkc2NyID0gbnVsbDtcblx0fSBlbHNlIHtcblx0XHRvcHRpb25zID0gYXJndW1lbnRzWzNdO1xuXHR9XG5cdGlmIChnZXQgPT0gbnVsbCkge1xuXHRcdGdldCA9IHVuZGVmaW5lZDtcblx0fSBlbHNlIGlmICghaXNDYWxsYWJsZShnZXQpKSB7XG5cdFx0b3B0aW9ucyA9IGdldDtcblx0XHRnZXQgPSBzZXQgPSB1bmRlZmluZWQ7XG5cdH0gZWxzZSBpZiAoc2V0ID09IG51bGwpIHtcblx0XHRzZXQgPSB1bmRlZmluZWQ7XG5cdH0gZWxzZSBpZiAoIWlzQ2FsbGFibGUoc2V0KSkge1xuXHRcdG9wdGlvbnMgPSBzZXQ7XG5cdFx0c2V0ID0gdW5kZWZpbmVkO1xuXHR9XG5cdGlmIChkc2NyID09IG51bGwpIHtcblx0XHRjID0gdHJ1ZTtcblx0XHRlID0gZmFsc2U7XG5cdH0gZWxzZSB7XG5cdFx0YyA9IGNvbnRhaW5zLmNhbGwoZHNjciwgJ2MnKTtcblx0XHRlID0gY29udGFpbnMuY2FsbChkc2NyLCAnZScpO1xuXHR9XG5cblx0ZGVzYyA9IHsgZ2V0OiBnZXQsIHNldDogc2V0LCBjb25maWd1cmFibGU6IGMsIGVudW1lcmFibGU6IGUgfTtcblx0cmV0dXJuICFvcHRpb25zID8gZGVzYyA6IGFzc2lnbihub3JtYWxpemVPcHRzKG9wdGlvbnMpLCBkZXNjKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9pcy1pbXBsZW1lbnRlZCcpKClcblx0PyBPYmplY3QuYXNzaWduXG5cdDogcmVxdWlyZSgnLi9zaGltJyk7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKCkge1xuXHR2YXIgYXNzaWduID0gT2JqZWN0LmFzc2lnbiwgb2JqO1xuXHRpZiAodHlwZW9mIGFzc2lnbiAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuIGZhbHNlO1xuXHRvYmogPSB7IGZvbzogJ3JheicgfTtcblx0YXNzaWduKG9iaiwgeyBiYXI6ICdkd2EnIH0sIHsgdHJ6eTogJ3RyenknIH0pO1xuXHRyZXR1cm4gKG9iai5mb28gKyBvYmouYmFyICsgb2JqLnRyenkpID09PSAncmF6ZHdhdHJ6eSc7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIga2V5cyAgPSByZXF1aXJlKCcuLi9rZXlzJylcbiAgLCB2YWx1ZSA9IHJlcXVpcmUoJy4uL3ZhbGlkLXZhbHVlJylcblxuICAsIG1heCA9IE1hdGgubWF4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChkZXN0LCBzcmMvKiwg4oCmc3JjbiovKSB7XG5cdHZhciBlcnJvciwgaSwgbCA9IG1heChhcmd1bWVudHMubGVuZ3RoLCAyKSwgYXNzaWduO1xuXHRkZXN0ID0gT2JqZWN0KHZhbHVlKGRlc3QpKTtcblx0YXNzaWduID0gZnVuY3Rpb24gKGtleSkge1xuXHRcdHRyeSB7IGRlc3Rba2V5XSA9IHNyY1trZXldOyB9IGNhdGNoIChlKSB7XG5cdFx0XHRpZiAoIWVycm9yKSBlcnJvciA9IGU7XG5cdFx0fVxuXHR9O1xuXHRmb3IgKGkgPSAxOyBpIDwgbDsgKytpKSB7XG5cdFx0c3JjID0gYXJndW1lbnRzW2ldO1xuXHRcdGtleXMoc3JjKS5mb3JFYWNoKGFzc2lnbik7XG5cdH1cblx0aWYgKGVycm9yICE9PSB1bmRlZmluZWQpIHRocm93IGVycm9yO1xuXHRyZXR1cm4gZGVzdDtcbn07XG4iLCIvLyBEZXByZWNhdGVkXG5cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob2JqKSB7IHJldHVybiB0eXBlb2Ygb2JqID09PSAnZnVuY3Rpb24nOyB9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpXG5cdD8gT2JqZWN0LmtleXNcblx0OiByZXF1aXJlKCcuL3NoaW0nKTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG5cdHRyeSB7XG5cdFx0T2JqZWN0LmtleXMoJ3ByaW1pdGl2ZScpO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9IGNhdGNoIChlKSB7IHJldHVybiBmYWxzZTsgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGtleXMgPSBPYmplY3Qua2V5cztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG5cdHJldHVybiBrZXlzKG9iamVjdCA9PSBudWxsID8gb2JqZWN0IDogT2JqZWN0KG9iamVjdCkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoJy4vYXNzaWduJylcblxuICAsIGZvckVhY2ggPSBBcnJheS5wcm90b3R5cGUuZm9yRWFjaFxuICAsIGNyZWF0ZSA9IE9iamVjdC5jcmVhdGUsIGdldFByb3RvdHlwZU9mID0gT2JqZWN0LmdldFByb3RvdHlwZU9mXG5cbiAgLCBwcm9jZXNzO1xuXG5wcm9jZXNzID0gZnVuY3Rpb24gKHNyYywgb2JqKSB7XG5cdHZhciBwcm90byA9IGdldFByb3RvdHlwZU9mKHNyYyk7XG5cdHJldHVybiBhc3NpZ24ocHJvdG8gPyBwcm9jZXNzKHByb3RvLCBvYmopIDogb2JqLCBzcmMpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucy8qLCDigKZvcHRpb25zKi8pIHtcblx0dmFyIHJlc3VsdCA9IGNyZWF0ZShudWxsKTtcblx0Zm9yRWFjaC5jYWxsKGFyZ3VtZW50cywgZnVuY3Rpb24gKG9wdGlvbnMpIHtcblx0XHRpZiAob3B0aW9ucyA9PSBudWxsKSByZXR1cm47XG5cdFx0cHJvY2VzcyhPYmplY3Qob3B0aW9ucyksIHJlc3VsdCk7XG5cdH0pO1xuXHRyZXR1cm4gcmVzdWx0O1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAodmFsdWUpIHtcblx0aWYgKHZhbHVlID09IG51bGwpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgdXNlIG51bGwgb3IgdW5kZWZpbmVkXCIpO1xuXHRyZXR1cm4gdmFsdWU7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoJy4vaXMtaW1wbGVtZW50ZWQnKSgpXG5cdD8gU3RyaW5nLnByb3RvdHlwZS5jb250YWluc1xuXHQ6IHJlcXVpcmUoJy4vc2hpbScpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgc3RyID0gJ3JhemR3YXRyenknO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICgpIHtcblx0aWYgKHR5cGVvZiBzdHIuY29udGFpbnMgIT09ICdmdW5jdGlvbicpIHJldHVybiBmYWxzZTtcblx0cmV0dXJuICgoc3RyLmNvbnRhaW5zKCdkd2EnKSA9PT0gdHJ1ZSkgJiYgKHN0ci5jb250YWlucygnZm9vJykgPT09IGZhbHNlKSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5kZXhPZiA9IFN0cmluZy5wcm90b3R5cGUuaW5kZXhPZjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc2VhcmNoU3RyaW5nLyosIHBvc2l0aW9uKi8pIHtcblx0cmV0dXJuIGluZGV4T2YuY2FsbCh0aGlzLCBzZWFyY2hTdHJpbmcsIGFyZ3VtZW50c1sxXSkgPiAtMTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBkID0gcmVxdWlyZSgnZCcpXG5cbiAgLCBjcmVhdGUgPSBPYmplY3QuY3JlYXRlLCBkZWZpbmVQcm9wZXJ0aWVzID0gT2JqZWN0LmRlZmluZVByb3BlcnRpZXNcbiAgLCBnZW5lcmF0ZU5hbWUsIFN5bWJvbDtcblxuZ2VuZXJhdGVOYW1lID0gKGZ1bmN0aW9uICgpIHtcblx0dmFyIGNyZWF0ZWQgPSBjcmVhdGUobnVsbCk7XG5cdHJldHVybiBmdW5jdGlvbiAoZGVzYykge1xuXHRcdHZhciBwb3N0Zml4ID0gMDtcblx0XHR3aGlsZSAoY3JlYXRlZFtkZXNjICsgKHBvc3RmaXggfHwgJycpXSkgKytwb3N0Zml4O1xuXHRcdGRlc2MgKz0gKHBvc3RmaXggfHwgJycpO1xuXHRcdGNyZWF0ZWRbZGVzY10gPSB0cnVlO1xuXHRcdHJldHVybiAnQEAnICsgZGVzYztcblx0fTtcbn0oKSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ltYm9sID0gZnVuY3Rpb24gKGRlc2NyaXB0aW9uKSB7XG5cdHZhciBzeW1ib2w7XG5cdGlmICh0aGlzIGluc3RhbmNlb2YgU3ltYm9sKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcignVHlwZUVycm9yOiBTeW1ib2wgaXMgbm90IGEgY29uc3RydWN0b3InKTtcblx0fVxuXHRzeW1ib2wgPSBjcmVhdGUoU3ltYm9sLnByb3RvdHlwZSk7XG5cdGRlc2NyaXB0aW9uID0gKGRlc2NyaXB0aW9uID09PSB1bmRlZmluZWQgPyAnJyA6IFN0cmluZyhkZXNjcmlwdGlvbikpO1xuXHRyZXR1cm4gZGVmaW5lUHJvcGVydGllcyhzeW1ib2wsIHtcblx0XHRfX2Rlc2NyaXB0aW9uX186IGQoJycsIGRlc2NyaXB0aW9uKSxcblx0XHRfX25hbWVfXzogZCgnJywgZ2VuZXJhdGVOYW1lKGRlc2NyaXB0aW9uKSlcblx0fSk7XG59O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTeW1ib2wsIHtcblx0Y3JlYXRlOiBkKCcnLCBTeW1ib2woJ2NyZWF0ZScpKSxcblx0aGFzSW5zdGFuY2U6IGQoJycsIFN5bWJvbCgnaGFzSW5zdGFuY2UnKSksXG5cdGlzQ29uY2F0U3ByZWFkYWJsZTogZCgnJywgU3ltYm9sKCdpc0NvbmNhdFNwcmVhZGFibGUnKSksXG5cdGlzUmVnRXhwOiBkKCcnLCBTeW1ib2woJ2lzUmVnRXhwJykpLFxuXHRpdGVyYXRvcjogZCgnJywgU3ltYm9sKCdpdGVyYXRvcicpKSxcblx0dG9QcmltaXRpdmU6IGQoJycsIFN5bWJvbCgndG9QcmltaXRpdmUnKSksXG5cdHRvU3RyaW5nVGFnOiBkKCcnLCBTeW1ib2woJ3RvU3RyaW5nVGFnJykpLFxuXHR1bnNjb3BhYmxlczogZCgnJywgU3ltYm9sKCd1bnNjb3BhYmxlcycpKVxufSk7XG5cbmRlZmluZVByb3BlcnRpZXMoU3ltYm9sLnByb3RvdHlwZSwge1xuXHRwcm9wZXJUb1N0cmluZzogZChmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuICdTeW1ib2wgKCcgKyB0aGlzLl9fZGVzY3JpcHRpb25fXyArICcpJztcblx0fSksXG5cdHRvU3RyaW5nOiBkKCcnLCBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLl9fbmFtZV9fOyB9KVxufSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoU3ltYm9sLnByb3RvdHlwZSwgU3ltYm9sLnRvUHJpbWl0aXZlLCBkKCcnLFxuXHRmdW5jdGlvbiAoaGludCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoXCJDb252ZXJzaW9uIG9mIHN5bWJvbCBvYmplY3RzIGlzIG5vdCBhbGxvd2VkXCIpO1xuXHR9KSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoU3ltYm9sLnByb3RvdHlwZSwgU3ltYm9sLnRvU3RyaW5nVGFnLCBkKCdjJywgJ1N5bWJvbCcpKTtcbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJ0eXBlc1wiOiB7XG4gICAgXCJyb290XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInJvb3RcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJlY2hvXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwic3RyaW5nXCI6IHsgXCJfYXJnXCI6IDAsIFwidHlwZVwiOiBcInN0cmluZ1wiIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzdHJpbmdcIjogeyBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIiB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwibGlzdFRhYnNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge30sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7IFwiX3JldHZhbFwiOiBcInRhYmxpc3RcIiB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwcm90b2NvbERlc2NyaXB0aW9uXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHt9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjogeyBcIl9yZXR2YWxcIjogXCJqc29uXCIgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInRhYkxpc3RDaGFuZ2VkXCI6IHt9XG4gICAgICB9XG4gICAgfSxcbiAgICBcInRhYmxpc3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJ0YWJsaXN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwic2VsZWN0ZWRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJ0YWJzXCI6IFwiYXJyYXk6dGFiXCIsXG4gICAgICAgIFwidXJsXCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiY29uc29sZUFjdG9yXCI6IFwiY29uc29sZVwiLFxuICAgICAgICBcImluc3BlY3RvckFjdG9yXCI6IFwiaW5zcGVjdG9yXCIsXG4gICAgICAgIFwic3R5bGVTaGVldHNBY3RvclwiOiBcInN0eWxlc2hlZXRzXCIsXG4gICAgICAgIFwic3R5bGVFZGl0b3JBY3RvclwiOiBcInN0eWxlZWRpdG9yXCIsXG4gICAgICAgIFwibWVtb3J5QWN0b3JcIjogXCJtZW1vcnlcIixcbiAgICAgICAgXCJldmVudExvb3BMYWdBY3RvclwiOiBcImV2ZW50TG9vcExhZ1wiLFxuICAgICAgICBcInByZWZlcmVuY2VBY3RvclwiOiBcInByZWZlcmVuY2VcIixcbiAgICAgICAgXCJkZXZpY2VBY3RvclwiOiBcImRldmljZVwiLFxuXG4gICAgICAgIFwicHJvZmlsZXJBY3RvclwiOiBcInByb2ZpbGVyXCIsXG4gICAgICAgIFwiY2hyb21lRGVidWdnZXJcIjogXCJjaHJvbWVEZWJ1Z2dlclwiLFxuICAgICAgICBcIndlYmFwcHNBY3RvclwiOiBcIndlYmFwcHNcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJ0YWJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwidGFiXCIsXG4gICAgICBcImZpZWxkc1wiOiB7XG4gICAgICAgIFwidGl0bGVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJ1cmxcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJvdXRlcldpbmRvd0lEXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiaW5zcGVjdG9yQWN0b3JcIjogXCJpbnNwZWN0b3JcIixcbiAgICAgICAgXCJjYWxsV2F0Y2hlckFjdG9yXCI6IFwiY2FsbC13YXRjaGVyXCIsXG4gICAgICAgIFwiY2FudmFzQWN0b3JcIjogXCJjYW52YXNcIixcbiAgICAgICAgXCJ3ZWJnbEFjdG9yXCI6IFwid2ViZ2xcIixcbiAgICAgICAgXCJ3ZWJhdWRpb0FjdG9yXCI6IFwid2ViYXVkaW9cIixcbiAgICAgICAgXCJzdG9yYWdlQWN0b3JcIjogXCJzdG9yYWdlXCIsXG4gICAgICAgIFwiZ2NsaUFjdG9yXCI6IFwiZ2NsaVwiLFxuICAgICAgICBcIm1lbW9yeUFjdG9yXCI6IFwibWVtb3J5XCIsXG4gICAgICAgIFwiZXZlbnRMb29wTGFnXCI6IFwiZXZlbnRMb29wTGFnXCIsXG4gICAgICAgIFwic3R5bGVTaGVldHNBY3RvclwiOiBcInN0eWxlc2hlZXRzXCIsXG4gICAgICAgIFwic3R5bGVFZGl0b3JBY3RvclwiOiBcInN0eWxlZWRpdG9yXCIsXG5cbiAgICAgICAgXCJjb25zb2xlQWN0b3JcIjogXCJjb25zb2xlXCIsXG4gICAgICAgIFwidHJhY2VBY3RvclwiOiBcInRyYWNlXCJcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgXCJ0eXBlc1wiOiB7XG4gICAgXCJsb25nc3RyYWN0b3JcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibG9uZ3N0cmFjdG9yXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic3Vic3RyaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN1YnN0cmluZ1wiLFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZW5kXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3Vic3RyaW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZWxlYXNlXCIsXG4gICAgICAgICAgXCJyZWxlYXNlXCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic3R5bGVzaGVldFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdHlsZXNoZWV0XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidG9nZ2xlRGlzYWJsZWRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidG9nZ2xlRGlzYWJsZWRcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImRpc2FibGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0T3JpZ2luYWxTb3VyY2VzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE9yaWdpbmFsU291cmNlc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwib3JpZ2luYWxTb3VyY2VzXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6YXJyYXk6b3JpZ2luYWxzb3VyY2VcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldE9yaWdpbmFsTG9jYXRpb25cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0T3JpZ2luYWxMb2NhdGlvblwiLFxuICAgICAgICAgICAgXCJsaW5lXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bWJlclwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjb2x1bW5cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwib3JpZ2luYWxsb2NhdGlvbnJlc3BvbnNlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidXBkYXRlXCIsXG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInRyYW5zaXRpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwicHJvcGVydHktY2hhbmdlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwcm9wZXJ0eUNoYW5nZVwiLFxuICAgICAgICAgIFwicHJvcGVydHlcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzdHlsZS1hcHBsaWVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdHlsZUFwcGxpZWRcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBcIm9yaWdpbmFsc291cmNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIm9yaWdpbmFsc291cmNlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwic3R5bGVzaGVldHNcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3R5bGVzaGVldHNcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdHlsZVNoZWV0c1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRTdHlsZVNoZWV0c1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3R5bGVTaGVldHNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpzdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJhZGRTdHlsZVNoZWV0XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFkZFN0eWxlU2hlZXRcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInN0eWxlU2hlZXRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJvcmlnaW5hbGxvY2F0aW9ucmVzcG9uc2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJvcmlnaW5hbGxvY2F0aW9ucmVzcG9uc2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJzb3VyY2VcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJsaW5lXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiY29sdW1uXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZG9tbm9kZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb21ub2RlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0Tm9kZVZhbHVlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE5vZGVWYWx1ZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXROb2RlVmFsdWVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0Tm9kZVZhbHVlXCIsXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRJbWFnZURhdGFcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0SW1hZ2VEYXRhXCIsXG4gICAgICAgICAgICBcIm1heERpbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJpbWFnZURhdGFcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1vZGlmeUF0dHJpYnV0ZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibW9kaWZ5QXR0cmlidXRlc1wiLFxuICAgICAgICAgICAgXCJtb2RpZmljYXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Ompzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiYXBwbGllZHN0eWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiYXBwbGllZHN0eWxlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwicnVsZVwiOiBcImRvbXN0eWxlcnVsZSNhY3RvcmlkXCIsXG4gICAgICAgIFwiaW5oZXJpdGVkXCI6IFwibnVsbGFibGU6ZG9tbm9kZSNhY3RvcmlkXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwibWF0Y2hlZHNlbGVjdG9yXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibWF0Y2hlZHNlbGVjdG9yXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwicnVsZVwiOiBcImRvbXN0eWxlcnVsZSNhY3RvcmlkXCIsXG4gICAgICAgIFwic2VsZWN0b3JcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJ2YWx1ZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInN0YXR1c1wiOiBcIm51bWJlclwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcIm1hdGNoZWRzZWxlY3RvcnJlc3BvbnNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwibWF0Y2hlZHNlbGVjdG9ycmVzcG9uc2VcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJydWxlc1wiOiBcImFycmF5OmRvbXN0eWxlcnVsZVwiLFxuICAgICAgICBcInNoZWV0c1wiOiBcImFycmF5OnN0eWxlc2hlZXRcIixcbiAgICAgICAgXCJtYXRjaGVkXCI6IFwiYXJyYXk6bWF0Y2hlZHNlbGVjdG9yXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiYXBwbGllZFN0eWxlc1JldHVyblwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImFwcGxpZWRTdHlsZXNSZXR1cm5cIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJlbnRyaWVzXCI6IFwiYXJyYXk6YXBwbGllZHN0eWxlXCIsXG4gICAgICAgIFwicnVsZXNcIjogXCJhcnJheTpkb21zdHlsZXJ1bGVcIixcbiAgICAgICAgXCJzaGVldHNcIjogXCJhcnJheTpzdHlsZXNoZWV0XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwicGFnZXN0eWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInBhZ2VzdHlsZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldENvbXB1dGVkXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldENvbXB1dGVkXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXJrTWF0Y2hlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm9ubHlNYXRjaGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZmlsdGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiY29tcHV0ZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRNYXRjaGVkU2VsZWN0b3JzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE1hdGNoZWRTZWxlY3RvcnNcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInByb3BlcnR5XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJmaWx0ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibWF0Y2hlZHNlbGVjdG9ycmVzcG9uc2VcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEFwcGxpZWRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0QXBwbGllZFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiaW5oZXJpdGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibWF0Y2hlZFNlbGVjdG9yc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcImZpbHRlclwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcHBsaWVkU3R5bGVzUmV0dXJuXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRMYXlvdXRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0TGF5b3V0XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJhdXRvTWFyZ2luc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZG9tc3R5bGVydWxlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRvbXN0eWxlcnVsZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1vZGlmeVByb3BlcnRpZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibW9kaWZ5UHJvcGVydGllc1wiLFxuICAgICAgICAgICAgXCJtb2RpZmljYXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Ompzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInJ1bGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21zdHlsZXJ1bGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImhpZ2hsaWdodGVyXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImhpZ2hsaWdodGVyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2hvd0JveE1vZGVsXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNob3dCb3hNb2RlbFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicmVnaW9uXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWRlQm94TW9kZWxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaGlkZUJveE1vZGVsXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjYW5jZWxQaWNrXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNhbmNlbFBpY2tcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiaW1hZ2VEYXRhXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW1hZ2VEYXRhXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiZGF0YVwiOiBcIm51bGxhYmxlOmxvbmdzdHJpbmdcIixcbiAgICAgICAgXCJzaXplXCI6IFwianNvblwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImRpc2Nvbm5lY3RlZE5vZGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibm9kZVwiOiBcImRvbW5vZGVcIixcbiAgICAgICAgXCJuZXdQYXJlbnRzXCI6IFwiYXJyYXk6ZG9tbm9kZVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcIm5vZGVzXCI6IFwiYXJyYXk6ZG9tbm9kZVwiLFxuICAgICAgICBcIm5ld1BhcmVudHNcIjogXCJhcnJheTpkb21ub2RlXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiZG9tbXV0YXRpb25cIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJkb21tdXRhdGlvblwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge31cbiAgICB9LFxuICAgIFwiZG9tbm9kZWxpc3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9tbm9kZWxpc3RcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpdGVtXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIml0ZW1cIixcbiAgICAgICAgICAgIFwiaXRlbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpdGVtc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpdGVtc1wiLFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpudW1iZXJcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiZW5kXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRpc2Nvbm5lY3RlZE5vZGVBcnJheVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVsZWFzZVwiLFxuICAgICAgICAgIFwicmVsZWFzZVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZWxlYXNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImRvbXRyYXZlcnNhbGFycmF5XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9tdHJhdmVyc2FsYXJyYXlcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJub2Rlc1wiOiBcImFycmF5OmRvbW5vZGVcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJkb213YWxrZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZG9td2Fsa2VyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVsZWFzZVwiLFxuICAgICAgICAgIFwicmVsZWFzZVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZWxlYXNlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRpc2Nvbm5lY3RlZE5vZGVcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImNhbmNlbFBpY2tcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2FuY2VsUGlja1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaGlnaGxpZ2h0XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJkb2N1bWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJkb2N1bWVudFwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJkb2N1bWVudEVsZW1lbnRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9jdW1lbnRFbGVtZW50XCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInBhcmVudHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicGFyZW50c1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic2FtZURvY3VtZW50XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZXNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZXRhaW5Ob2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJldGFpbk5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVucmV0YWluTm9kZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bnJldGFpbk5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlbGVhc2VOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlbGVhc2VOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJmb3JjZVwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiY2hpbGRyZW5cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2hpbGRyZW5cIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm1heE5vZGVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjZW50ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIndoYXRUb1Nob3dcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9tdHJhdmVyc2FsYXJyYXlcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNpYmxpbmdzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNpYmxpbmdzXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJtYXhOb2Rlc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiY2VudGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3RhcnRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ3aGF0VG9TaG93XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImRvbXRyYXZlcnNhbGFycmF5XCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJuZXh0U2libGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJuZXh0U2libGluZ1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwid2hhdFRvU2hvd1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwcmV2aW91c1NpYmxpbmdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJldmlvdXNTaWJsaW5nXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ3aGF0VG9TaG93XCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInF1ZXJ5U2VsZWN0b3JcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwicXVlcnlTZWxlY3RvclwiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic2VsZWN0b3JcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZGlzY29ubmVjdGVkTm9kZVwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicXVlcnlTZWxlY3RvckFsbFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJxdWVyeVNlbGVjdG9yQWxsXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzZWxlY3RvclwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImxpc3RcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJkb21ub2RlbGlzdFwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3VnZ2VzdGlvbnNGb3JRdWVyeVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRTdWdnZXN0aW9uc0ZvclF1ZXJ5XCIsXG4gICAgICAgICAgICBcInF1ZXJ5XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJjb21wbGV0aW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzZWxlY3RvclN0YXRlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibGlzdFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiYWRkUHNldWRvQ2xhc3NMb2NrXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFkZFBzZXVkb0NsYXNzTG9ja1wiLFxuICAgICAgICAgICAgXCJub2RlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImRvbW5vZGVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicHNldWRvQ2xhc3NcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmVudHNcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImhpZGVOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImhpZGVOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1bmhpZGVOb2RlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInVuaGlkZU5vZGVcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlbW92ZVBzZXVkb0NsYXNzTG9ja1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZW1vdmVQc2V1ZG9DbGFzc0xvY2tcIixcbiAgICAgICAgICAgIFwibm9kZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJkb21ub2RlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBzZXVkb0NsYXNzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJlbnRzXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjbGVhclBzZXVkb0NsYXNzTG9ja3NcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiY2xlYXJQc2V1ZG9DbGFzc0xvY2tzXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVsbGFibGU6ZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpbm5lckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaW5uZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJvdXRlckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwib3V0ZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJsb25nc3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRPdXRlckhUTUxcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0T3V0ZXJIVE1MXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVtb3ZlTm9kZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJyZW1vdmVOb2RlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibmV4dFNpYmxpbmdcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkb21ub2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpbnNlcnRCZWZvcmVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiaW5zZXJ0QmVmb3JlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJlbnRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzaWJsaW5nXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmRvbW5vZGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0TXV0YXRpb25zXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldE11dGF0aW9uc1wiLFxuICAgICAgICAgICAgXCJjbGVhbnVwXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwibXV0YXRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYXJyYXk6ZG9tbXV0YXRpb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlzSW5ET01UcmVlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzSW5ET01UcmVlXCIsXG4gICAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZG9tbm9kZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiYXR0YWNoZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXROb2RlQWN0b3JGcm9tT2JqZWN0QWN0b3JcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Tm9kZUFjdG9yRnJvbU9iamVjdEFjdG9yXCIsXG4gICAgICAgICAgICBcIm9iamVjdEFjdG9ySURcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJub2RlRnJvbnRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwibmV3LW11dGF0aW9uc1wiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwibmV3TXV0YXRpb25zXCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJwaWNrZXItbm9kZS1waWNrZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInBpY2tlck5vZGVQaWNrZWRcIixcbiAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwicGlja2VyLW5vZGUtaG92ZXJlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicGlja2VyTm9kZUhvdmVyZWRcIixcbiAgICAgICAgICBcIm5vZGVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0ZWROb2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiaGlnaGxpZ2h0ZXItcmVhZHlcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImhpZ2hsaWdodGVyLXJlYWR5XCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJoaWdobGlnaHRlci1oaWRlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJoaWdobGlnaHRlci1oaWRlXCJcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJpbnNwZWN0b3JcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW5zcGVjdG9yXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0V2Fsa2VyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFdhbGtlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwid2Fsa2VyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZG9td2Fsa2VyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYWdlU3R5bGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFnZVN0eWxlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwYWdlU3R5bGVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJwYWdlc3R5bGVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEhpZ2hsaWdodGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEhpZ2hsaWdodGVyXCIsXG4gICAgICAgICAgICBcImF1dG9oaWRlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImhpZ2hsaWd0ZXJcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJoaWdobGlnaHRlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0SW1hZ2VEYXRhRnJvbVVSTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRJbWFnZURhdGFGcm9tVVJMXCIsXG4gICAgICAgICAgICBcInVybFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibWF4RGltXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImltYWdlRGF0YVwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiY2FsbC1zdGFjay1pdGVtXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY2FsbC1zdGFjay1pdGVtXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcImZpbGVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJsaW5lXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY2FsbC1kZXRhaWxzXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY2FsbC1kZXRhaWxzXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwidHlwZVwiOiBcIm51bWJlclwiLFxuICAgICAgICBcIm5hbWVcIjogXCJzdHJpbmdcIixcbiAgICAgICAgXCJzdGFja1wiOiBcImFycmF5OmNhbGwtc3RhY2staXRlbVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImZ1bmN0aW9uLWNhbGxcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZnVuY3Rpb24tY2FsbFwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldERldGFpbHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0RGV0YWlsc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiaW5mb1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImNhbGwtZGV0YWlsc1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiY2FsbC13YXRjaGVyXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImNhbGwtd2F0Y2hlclwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0dXBcIixcbiAgICAgICAgICAgIFwidHJhY2VkR2xvYmFsc1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwidHJhY2VkRnVuY3Rpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzdGFydFJlY29yZGluZ1wiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBlcmZvcm1SZWxvYWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmaW5hbGl6ZVwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZpbmFsaXplXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImlzUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImlzUmVjb3JkaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwicmVzdW1lUmVjb3JkaW5nXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlc3VtZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJwYXVzZVJlY29yZGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJwYXVzZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiY2FsbHNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJhcnJheTpmdW5jdGlvbi1jYWxsXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJlcmFzZVJlY29yZGluZ1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJlcmFzZVJlY29yZGluZ1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJzbmFwc2hvdC1pbWFnZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInNuYXBzaG90LWltYWdlXCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwiaW5kZXhcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJ3aWR0aFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImhlaWdodFwiOiBcIm51bWJlclwiLFxuICAgICAgICBcImZsaXBwZWRcIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwicGl4ZWxzXCI6IFwidWludDMyLWFycmF5XCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwic25hcHNob3Qtb3ZlcnZpZXdcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzbmFwc2hvdC1vdmVydmlld1wiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImNhbGxzXCI6IFwiYXJyYXk6ZnVuY3Rpb24tY2FsbFwiLFxuICAgICAgICBcInRodW1ibmFpbHNcIjogXCJhcnJheTpzbmFwc2hvdC1pbWFnZVwiLFxuICAgICAgICBcInNjcmVlbnNob3RcIjogXCJzbmFwc2hvdC1pbWFnZVwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcImZyYW1lLXNuYXBzaG90XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImZyYW1lLXNuYXBzaG90XCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0T3ZlcnZpZXdcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0T3ZlcnZpZXdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIm92ZXJ2aWV3XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic25hcHNob3Qtb3ZlcnZpZXdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdlbmVyYXRlU2NyZWVuc2hvdEZvclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZW5lcmF0ZVNjcmVlbnNob3RGb3JcIixcbiAgICAgICAgICAgIFwiY2FsbFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJmdW5jdGlvbi1jYWxsXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzY3JlZW5zaG90XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic25hcHNob3QtaW1hZ2VcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImNhbnZhc1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjYW52YXNcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgICBcInJlbG9hZFwiOiB7XG4gICAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImZpbmFsaXplXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZmluYWxpemVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiaXNJbml0aWFsaXplZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpc0luaXRpYWxpemVkXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJpbml0aWFsaXplZFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInJlY29yZEFuaW1hdGlvbkZyYW1lXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInJlY29yZEFuaW1hdGlvbkZyYW1lXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJzbmFwc2hvdFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImZyYW1lLXNuYXBzaG90XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJnbC1zaGFkZXJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiZ2wtc2hhZGVyXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VGV4dFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUZXh0XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjb21waWxlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNvbXBpbGVcIixcbiAgICAgICAgICAgIFwidGV4dFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImVycm9yXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6anNvblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZ2wtcHJvZ3JhbVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJnbC1wcm9ncmFtXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VmVydGV4U2hhZGVyXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFZlcnRleFNoYWRlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic2hhZGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZ2wtc2hhZGVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRGcmFnbWVudFNoYWRlclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRGcmFnbWVudFNoYWRlclwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic2hhZGVyXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiZ2wtc2hhZGVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJoaWdobGlnaHRcIixcbiAgICAgICAgICAgIFwidGludFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJhcnJheTpudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidW5oaWdobGlnaHRcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bmhpZ2hsaWdodFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJibGFja2JveFwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImJsYWNrYm94XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInVuYmxhY2tib3hcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ1bmJsYWNrYm94XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcIndlYmdsXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIndlYmdsXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0dXBcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXR1cFwiLFxuICAgICAgICAgICAgXCJyZWxvYWRcIjoge1xuICAgICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmaW5hbGl6ZVwiLFxuICAgICAgICAgIFwib25ld2F5XCI6IHRydWUsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImZpbmFsaXplXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFByb2dyYW1zXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFByb2dyYW1zXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwcm9ncmFtc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImFycmF5OmdsLXByb2dyYW1cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJwcm9ncmFtLWxpbmtlZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwicHJvZ3JhbUxpbmtlZFwiLFxuICAgICAgICAgIFwicHJvZ3JhbVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdsLXByb2dyYW1cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJhdWRpb25vZGVcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiYXVkaW9ub2RlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0VHlwZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRUeXBlXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJpc1NvdXJjZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJpc1NvdXJjZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0UGFyYW1cIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0UGFyYW1cIixcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOnByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZXJyb3JcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYXJhbVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRQYXJhbVwiLFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudWxsYWJsZTpwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFBhcmFtRmxhZ3NcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFyYW1GbGFnc1wiLFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcImZsYWdzXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibnVsbGFibGU6cHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRQYXJhbXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UGFyYW1zXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJwYXJhbXNcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJ3ZWJhdWRpb1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJ3ZWJhdWRpb1wiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldHVwXCIsXG4gICAgICAgICAgXCJvbmV3YXlcIjogdHJ1ZSxcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic2V0dXBcIixcbiAgICAgICAgICAgIFwicmVsb2FkXCI6IHtcbiAgICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcImJvb2xlYW5cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZmluYWxpemVcIixcbiAgICAgICAgICBcIm9uZXdheVwiOiB0cnVlLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJmaW5hbGl6ZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwic3RhcnQtY29udGV4dFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3RhcnRDb250ZXh0XCJcbiAgICAgICAgfSxcbiAgICAgICAgXCJjb25uZWN0LW5vZGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcImNvbm5lY3ROb2RlXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJkZXN0XCI6IHtcbiAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiZGlzY29ubmVjdC1ub2RlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJkaXNjb25uZWN0Tm9kZVwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwiY29ubmVjdC1wYXJhbVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY29ubmVjdFBhcmFtXCIsXG4gICAgICAgICAgXCJzb3VyY2VcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJhdWRpb25vZGVcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcImNoYW5nZS1wYXJhbVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY2hhbmdlUGFyYW1cIixcbiAgICAgICAgICBcInNvdXJjZVwiOiB7XG4gICAgICAgICAgICBcIl9vcHRpb25cIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImF1ZGlvbm9kZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgIFwiX29wdGlvblwiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgXCJfb3B0aW9uXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJjcmVhdGUtbm9kZVwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiY3JlYXRlTm9kZVwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYXVkaW9ub2RlXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIFwib2xkLXN0eWxlc2hlZXRcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwib2xkLXN0eWxlc2hlZXRcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0b2dnbGVEaXNhYmxlZFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiZGlzYWJsZWRcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJib29sZWFuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJmZXRjaFNvdXJjZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJmZXRjaFNvdXJjZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJ1cGRhdGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidXBkYXRlXCIsXG4gICAgICAgICAgICBcInRleHRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInRyYW5zaXRpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwicHJvcGVydHktY2hhbmdlXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJwcm9wZXJ0eUNoYW5nZVwiLFxuICAgICAgICAgIFwicHJvcGVydHlcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgXCJzb3VyY2UtbG9hZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic291cmNlTG9hZFwiLFxuICAgICAgICAgIFwic291cmNlXCI6IHtcbiAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3R5bGUtYXBwbGllZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwic3R5bGVBcHBsaWVkXCJcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJzdHlsZWVkaXRvclwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdHlsZWVkaXRvclwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm5ld0RvY3VtZW50XCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcIm5ld0RvY3VtZW50XCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm5ld1N0eWxlU2hlZXRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibmV3U3R5bGVTaGVldFwiLFxuICAgICAgICAgICAgXCJ0ZXh0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3R5bGVTaGVldFwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm9sZC1zdHlsZXNoZWV0XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7XG4gICAgICAgIFwiZG9jdW1lbnQtbG9hZFwiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiZG9jdW1lbnRMb2FkXCIsXG4gICAgICAgICAgXCJzdHlsZVNoZWV0c1wiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImFycmF5Om9sZC1zdHlsZXNoZWV0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llb2JqZWN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiY29va2llb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInZhbHVlXCI6IFwibG9uZ3N0cmluZ1wiLFxuICAgICAgICBcInBhdGhcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJob3N0XCI6IFwic3RyaW5nXCIsXG4gICAgICAgIFwiaXNEb21haW5cIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwiaXNTZWN1cmVcIjogXCJib29sZWFuXCIsXG4gICAgICAgIFwiaXNIdHRwT25seVwiOiBcImJvb2xlYW5cIixcbiAgICAgICAgXCJjcmVhdGlvblRpbWVcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJsYXN0QWNjZXNzZWRcIjogXCJudW1iZXJcIixcbiAgICAgICAgXCJleHBpcmVzXCI6IFwibnVtYmVyXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llc3RvcmVvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjb29raWVzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOmNvb2tpZW9iamVjdFwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJzdG9yYWdlb2JqZWN0XCIsXG4gICAgICBcInNwZWNpYWxpemF0aW9uc1wiOiB7XG4gICAgICAgIFwibmFtZVwiOiBcInN0cmluZ1wiLFxuICAgICAgICBcInZhbHVlXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VzdG9yZW9iamVjdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0b3JhZ2VzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOnN0b3JhZ2VvYmplY3RcIlxuICAgICAgfVxuICAgIH0sXG4gICAgXCJpZGJvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpZGJvYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJuYW1lXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwiZGJcIjogXCJudWxsYWJsZTpzdHJpbmdcIixcbiAgICAgICAgXCJvYmplY3RTdG9yZVwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcIm9yaWdpblwiOiBcIm51bGxhYmxlOnN0cmluZ1wiLFxuICAgICAgICBcInZlcnNpb25cIjogXCJudWxsYWJsZTpudW1iZXJcIixcbiAgICAgICAgXCJvYmplY3RTdG9yZXNcIjogXCJudWxsYWJsZTpudW1iZXJcIixcbiAgICAgICAgXCJrZXlQYXRoXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwiYXV0b0luY3JlbWVudFwiOiBcIm51bGxhYmxlOmJvb2xlYW5cIixcbiAgICAgICAgXCJpbmRleGVzXCI6IFwibnVsbGFibGU6c3RyaW5nXCIsXG4gICAgICAgIFwidmFsdWVcIjogXCJudWxsYWJsZTpsb25nc3RyaW5nXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiaWRic3RvcmVvYmplY3RcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImRpY3RcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJpZGJzdG9yZW9iamVjdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcInRvdGFsXCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwib2Zmc2V0XCI6IFwibnVtYmVyXCIsXG4gICAgICAgIFwiZGF0YVwiOiBcImFycmF5Om51bGxhYmxlOmlkYm9iamVjdFwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JlVXBkYXRlT2JqZWN0XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJkaWN0XCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmVVcGRhdGVPYmplY3RcIixcbiAgICAgIFwic3BlY2lhbGl6YXRpb25zXCI6IHtcbiAgICAgICAgXCJjaGFuZ2VkXCI6IFwibnVsbGFibGU6anNvblwiLFxuICAgICAgICBcImRlbGV0ZWRcIjogXCJudWxsYWJsZTpqc29uXCIsXG4gICAgICAgIFwiYWRkZWRcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgIH1cbiAgICB9LFxuICAgIFwiY29va2llc1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJjb29raWVzXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiY29va2llc3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImxvY2FsU3RvcmFnZVwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJsb2NhbFN0b3JhZ2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRTdG9yZU9iamVjdHNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgICBcImhvc3RcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm5hbWVzXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmFycmF5OnN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcHRpb25zXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDIsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcIm51bGxhYmxlOmpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdG9yYWdlc3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcInNlc3Npb25TdG9yYWdlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInNlc3Npb25TdG9yYWdlXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RvcmFnZXN0b3Jlb2JqZWN0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH0sXG4gICAgXCJpbmRleGVkREJcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwiaW5kZXhlZERCXCIsXG4gICAgICBcIm1ldGhvZHNcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0U3RvcmVPYmplY3RzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldFN0b3JlT2JqZWN0c1wiLFxuICAgICAgICAgICAgXCJob3N0XCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJuYW1lc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTphcnJheTpzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwib3B0aW9uc1wiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAyLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJudWxsYWJsZTpqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiaWRic3RvcmVvYmplY3RcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcInN0b3JlbGlzdFwiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiZGljdFwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInN0b3JlbGlzdFwiLFxuICAgICAgXCJzcGVjaWFsaXphdGlvbnNcIjoge1xuICAgICAgICBcImNvb2tpZXNcIjogXCJjb29raWVzXCIsXG4gICAgICAgIFwibG9jYWxTdG9yYWdlXCI6IFwibG9jYWxTdG9yYWdlXCIsXG4gICAgICAgIFwic2Vzc2lvblN0b3JhZ2VcIjogXCJzZXNzaW9uU3RvcmFnZVwiLFxuICAgICAgICBcImluZGV4ZWREQlwiOiBcImluZGV4ZWREQlwiXG4gICAgICB9XG4gICAgfSxcbiAgICBcInN0b3JhZ2VcIjoge1xuICAgICAgXCJjYXRlZ29yeVwiOiBcImFjdG9yXCIsXG4gICAgICBcInR5cGVOYW1lXCI6IFwic3RvcmFnZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImxpc3RTdG9yZXNcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibGlzdFN0b3Jlc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0b3JlbGlzdFwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge1xuICAgICAgICBcInN0b3Jlcy11cGRhdGVcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0b3Jlc1VwZGF0ZVwiLFxuICAgICAgICAgIFwiZGF0YVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInN0b3JlVXBkYXRlT2JqZWN0XCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3RvcmVzLWNsZWFyZWRcIjoge1xuICAgICAgICAgIFwidHlwZVwiOiBcInN0b3Jlc0NsZWFyZWRcIixcbiAgICAgICAgICBcImRhdGFcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIFwic3RvcmVzLXJlbG9hZGVkXCI6IHtcbiAgICAgICAgICBcInR5cGVcIjogXCJzdG9yZXNSZWxhb2RlZFwiLFxuICAgICAgICAgIFwiZGF0YVwiOiB7XG4gICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJnY2xpXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImdjbGlcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzcGVjc1wiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzcGVjc1wiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImV4ZWN1dGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZXhlY3V0ZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdGF0ZVwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdGF0ZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3RhcnRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInJhbmtcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMixcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwibnVtYmVyXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidHlwZXBhcnNlXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInR5cGVwYXJzZVwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwidHlwZWluY3JlbWVudFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJ0eXBlaW5jcmVtZW50XCIsXG4gICAgICAgICAgICBcInR5cGVkXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJwYXJhbVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJzdHJpbmdcIlxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInR5cGVkZWNyZW1lbnRcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwidHlwZWRlY3JlbWVudFwiLFxuICAgICAgICAgICAgXCJ0eXBlZFwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJzdHJpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwicGFyYW1cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZWxlY3Rpb25pbmZvXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNlbGVjdGlvbmluZm9cIixcbiAgICAgICAgICAgIFwidHlwZWRcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInBhcmFtXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJhY3Rpb25cIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMSxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwic3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwianNvblwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwibWVtb3J5XCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcIm1lbW9yeVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcIm1lYXN1cmVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwibWVhc3VyZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHt9XG4gICAgfSxcbiAgICBcImV2ZW50TG9vcExhZ1wiOiB7XG4gICAgICBcImNhdGVnb3J5XCI6IFwiYWN0b3JcIixcbiAgICAgIFwidHlwZU5hbWVcIjogXCJldmVudExvb3BMYWdcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzdGFydFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdGFydFwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwic3VjY2Vzc1wiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcIm51bWJlclwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic3RvcFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzdG9wXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge31cbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiZXZlbnRzXCI6IHtcbiAgICAgICAgXCJldmVudC1sb29wLWxhZ1wiOiB7XG4gICAgICAgICAgXCJ0eXBlXCI6IFwiZXZlbnQtbG9vcC1sYWdcIixcbiAgICAgICAgICBcInRpbWVcIjoge1xuICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICBcInR5cGVcIjogXCJudW1iZXJcIlxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAgXCJwcmVmZXJlbmNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcInByZWZlcmVuY2VcIixcbiAgICAgIFwibWV0aG9kc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJnZXRCb29sUHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRCb29sUHJlZlwiLFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwiYm9vbGVhblwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0Q2hhclByZWZcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0Q2hhclByZWZcIixcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcInN0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwiZ2V0SW50UHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRJbnRQcmVmXCIsXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJudW1iZXJcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldEFsbFByZWZzXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldEFsbFByZWZzXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcInNldEJvb2xQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcInNldEJvb2xQcmVmXCIsXG4gICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJzZXRDaGFyUHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRDaGFyUHJlZlwiLFxuICAgICAgICAgICAgXCJuYW1lXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDAsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAxLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2V0SW50UHJlZlwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzZXRJbnRQcmVmXCIsXG4gICAgICAgICAgICBcIm5hbWVcIjoge1xuICAgICAgICAgICAgICBcIl9hcmdcIjogMCxcbiAgICAgICAgICAgICAgXCJ0eXBlXCI6IFwicHJpbWl0aXZlXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfYXJnXCI6IDEsXG4gICAgICAgICAgICAgIFwidHlwZVwiOiBcInByaW1pdGl2ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHt9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcIm5hbWVcIjogXCJjbGVhclVzZXJQcmVmXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImNsZWFyVXNlclByZWZcIixcbiAgICAgICAgICAgIFwibmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiX2FyZ1wiOiAwLFxuICAgICAgICAgICAgICBcInR5cGVcIjogXCJwcmltaXRpdmVcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7fVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJldmVudHNcIjoge31cbiAgICB9LFxuICAgIFwiZGV2aWNlXCI6IHtcbiAgICAgIFwiY2F0ZWdvcnlcIjogXCJhY3RvclwiLFxuICAgICAgXCJ0eXBlTmFtZVwiOiBcImRldmljZVwiLFxuICAgICAgXCJtZXRob2RzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldERlc2NyaXB0aW9uXCIsXG4gICAgICAgICAgXCJyZXF1ZXN0XCI6IHtcbiAgICAgICAgICAgIFwidHlwZVwiOiBcImdldERlc2NyaXB0aW9uXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImpzb25cIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFdhbGxwYXBlclwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJnZXRXYWxscGFwZXJcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgXCJyZXNwb25zZVwiOiB7XG4gICAgICAgICAgICBcInZhbHVlXCI6IHtcbiAgICAgICAgICAgICAgXCJfcmV0dmFsXCI6IFwibG9uZ3N0cmluZ1wiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJuYW1lXCI6IFwic2NyZWVuc2hvdFRvRGF0YVVSTFwiLFxuICAgICAgICAgIFwicmVxdWVzdFwiOiB7XG4gICAgICAgICAgICBcInR5cGVcIjogXCJzY3JlZW5zaG90VG9EYXRhVVJMXCJcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwicmVzcG9uc2VcIjoge1xuICAgICAgICAgICAgXCJ2YWx1ZVwiOiB7XG4gICAgICAgICAgICAgIFwiX3JldHZhbFwiOiBcImxvbmdzdHJpbmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibmFtZVwiOiBcImdldFJhd1Blcm1pc3Npb25zVGFibGVcIixcbiAgICAgICAgICBcInJlcXVlc3RcIjoge1xuICAgICAgICAgICAgXCJ0eXBlXCI6IFwiZ2V0UmF3UGVybWlzc2lvbnNUYWJsZVwiXG4gICAgICAgICAgfSxcbiAgICAgICAgICBcInJlc3BvbnNlXCI6IHtcbiAgICAgICAgICAgIFwidmFsdWVcIjoge1xuICAgICAgICAgICAgICBcIl9yZXR2YWxcIjogXCJqc29uXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImV2ZW50c1wiOiB7fVxuICAgIH1cbiAgfSxcbiAgXCJmcm9tXCI6IFwicm9vdFwiXG59XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIENsYXNzID0gcmVxdWlyZShcIi4vY2xhc3NcIikuQ2xhc3M7XG52YXIgdXRpbCA9IHJlcXVpcmUoXCIuL3V0aWxcIik7XG52YXIga2V5cyA9IHV0aWwua2V5cztcbnZhciB2YWx1ZXMgPSB1dGlsLnZhbHVlcztcbnZhciBwYWlycyA9IHV0aWwucGFpcnM7XG52YXIgcXVlcnkgPSB1dGlsLnF1ZXJ5O1xudmFyIGZpbmRQYXRoID0gdXRpbC5maW5kUGF0aDtcbnZhciBFdmVudFRhcmdldCA9IHJlcXVpcmUoXCIuL2V2ZW50XCIpLkV2ZW50VGFyZ2V0O1xuXG52YXIgVHlwZVN5c3RlbSA9IENsYXNzKHtcbiAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKGNsaWVudCkge1xuICAgIHZhciB0eXBlcyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gICAgdmFyIHNwZWNpZmljYXRpb24gPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuXG4gICAgdGhpcy5zcGVjaWZpY2F0aW9uID0gc3BlY2lmaWNhdGlvbjtcbiAgICB0aGlzLnR5cGVzID0gdHlwZXM7XG5cbiAgICB2YXIgdHlwZUZvciA9IGZ1bmN0aW9uIHR5cGVGb3IodHlwZU5hbWUpIHtcbiAgICAgIHR5cGVOYW1lID0gdHlwZU5hbWUgfHwgXCJwcmltaXRpdmVcIjtcbiAgICAgIGlmICghdHlwZXNbdHlwZU5hbWVdKSB7XG4gICAgICAgIGRlZmluZVR5cGUodHlwZU5hbWUpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHlwZXNbdHlwZU5hbWVdO1xuICAgIH07XG4gICAgdGhpcy50eXBlRm9yID0gdHlwZUZvcjtcblxuICAgIHZhciBkZWZpbmVUeXBlID0gZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgdmFyIHR5cGUgPSB2b2lkKDApO1xuICAgICAgaWYgKHR5cGVvZihkZXNjcmlwdG9yKSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBpZiAoZGVzY3JpcHRvci5pbmRleE9mKFwiOlwiKSA+IDApXG4gICAgICAgICAgdHlwZSA9IG1ha2VDb21wb3VuZFR5cGUoZGVzY3JpcHRvcik7XG4gICAgICAgIGVsc2UgaWYgKGRlc2NyaXB0b3IuaW5kZXhPZihcIiNcIikgPiAwKVxuICAgICAgICAgIHR5cGUgPSBuZXcgQWN0b3JEZXRhaWwoZGVzY3JpcHRvcik7XG4gICAgICAgICAgZWxzZSBpZiAoc3BlY2lmaWNhdGlvbltkZXNjcmlwdG9yXSlcbiAgICAgICAgICAgIHR5cGUgPSBtYWtlQ2F0ZWdvcnlUeXBlKHNwZWNpZmljYXRpb25bZGVzY3JpcHRvcl0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdHlwZSA9IG1ha2VDYXRlZ29yeVR5cGUoZGVzY3JpcHRvcik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlKVxuICAgICAgICB0eXBlc1t0eXBlLm5hbWVdID0gdHlwZTtcbiAgICAgIGVsc2VcbiAgICAgICAgdGhyb3cgVHlwZUVycm9yKFwiSW52YWxpZCB0eXBlOiBcIiArIGRlc2NyaXB0b3IpO1xuICAgIH07XG4gICAgdGhpcy5kZWZpbmVUeXBlID0gZGVmaW5lVHlwZTtcblxuXG4gICAgdmFyIG1ha2VDb21wb3VuZFR5cGUgPSBmdW5jdGlvbihuYW1lKSB7XG4gICAgICB2YXIgaW5kZXggPSBuYW1lLmluZGV4T2YoXCI6XCIpO1xuICAgICAgdmFyIGJhc2VUeXBlID0gbmFtZS5zbGljZSgwLCBpbmRleCk7XG4gICAgICB2YXIgc3ViVHlwZSA9IG5hbWUuc2xpY2UoaW5kZXggKyAxKTtcblxuICAgICAgcmV0dXJuIGJhc2VUeXBlID09PSBcImFycmF5XCIgPyBuZXcgQXJyYXlPZihzdWJUeXBlKSA6XG4gICAgICBiYXNlVHlwZSA9PT0gXCJudWxsYWJsZVwiID8gbmV3IE1heWJlKHN1YlR5cGUpIDpcbiAgICAgIG51bGw7XG4gICAgfTtcblxuICAgIHZhciBtYWtlQ2F0ZWdvcnlUeXBlID0gZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgdmFyIGNhdGVnb3J5ID0gZGVzY3JpcHRvci5jYXRlZ29yeTtcbiAgICAgIHJldHVybiBjYXRlZ29yeSA9PT0gXCJkaWN0XCIgPyBuZXcgRGljdGlvbmFyeShkZXNjcmlwdG9yKSA6XG4gICAgICBjYXRlZ29yeSA9PT0gXCJhY3RvclwiID8gbmV3IEFjdG9yKGRlc2NyaXB0b3IpIDpcbiAgICAgIG51bGw7XG4gICAgfTtcblxuICAgIHZhciByZWFkID0gZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQsIHR5cGVOYW1lKSB7XG4gICAgICByZXR1cm4gdHlwZUZvcih0eXBlTmFtZSkucmVhZChpbnB1dCwgY29udGV4dCk7XG4gICAgfVxuICAgIHRoaXMucmVhZCA9IHJlYWQ7XG5cbiAgICB2YXIgd3JpdGUgPSBmdW5jdGlvbihpbnB1dCwgY29udGV4dCwgdHlwZU5hbWUpIHtcbiAgICAgIHJldHVybiB0eXBlRm9yKHR5cGVOYW1lKS53cml0ZShpbnB1dCk7XG4gICAgfTtcbiAgICB0aGlzLndyaXRlID0gd3JpdGU7XG5cblxuICAgIHZhciBUeXBlID0gQ2xhc3Moe1xuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgICAgfSxcbiAgICAgIGdldCBuYW1lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYXRlZ29yeSA/IHRoaXMuY2F0ZWdvcnkgKyBcIjpcIiArIHRoaXMudHlwZSA6XG4gICAgICAgIHRoaXMudHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYFR5cGVgIHN1YmNsYXNzIG11c3QgaW1wbGVtZW50IGByZWFkYFwiKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcImBUeXBlYCBzdWJjbGFzcyBtdXN0IGltcGxlbWVudCBgd3JpdGVgXCIpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIFByaW1pdHZlID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogVHlwZSxcbiAgICAgIGNvbnN0dWN0b3I6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQ7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBpbnB1dDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHZhciBNYXliZSA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJudWxsYWJsZVwiLFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICByZXR1cm4gaW5wdXQgPT09IG51bGwgPyBudWxsIDpcbiAgICAgICAgaW5wdXQgPT09IHZvaWQoMCkgPyB2b2lkKDApIDpcbiAgICAgICAgcmVhZChpbnB1dCwgY29udGV4dCwgdGhpcy50eXBlKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0ID09PSBudWxsID8gbnVsbCA6XG4gICAgICAgIGlucHV0ID09PSB2b2lkKDApID8gdm9pZCgwKSA6XG4gICAgICAgIHdyaXRlKGlucHV0LCBjb250ZXh0LCB0aGlzLnR5cGUpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIEFycmF5T2YgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBUeXBlLFxuICAgICAgY2F0ZWdvcnk6IFwiYXJyYXlcIixcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbih0eXBlKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIHR5cGUgPSB0aGlzLnR5cGU7XG4gICAgICAgIHJldHVybiBpbnB1dC5tYXAoZnVuY3Rpb24oJCkgeyByZXR1cm4gcmVhZCgkLCBjb250ZXh0LCB0eXBlKSB9KTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgdmFyIHR5cGUgPSB0aGlzLnR5cGU7XG4gICAgICAgIHJldHVybiBpbnB1dC5tYXAoZnVuY3Rpb24oJCkgeyByZXR1cm4gd3JpdGUoJCwgY29udGV4dCwgdHlwZSkgfSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgbWFrZUZpZWxkID0gZnVuY3Rpb24gbWFrZUZpZWxkKG5hbWUsIHR5cGUpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgbmFtZSwge1xuICAgICAgICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHZhbHVlOiByZWFkKHRoaXMuc3RhdGVbbmFtZV0sIHRoaXMuY29udGV4dCwgdHlwZSlcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gdGhpc1tuYW1lXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgbWFrZUZpZWxkcyA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgIHJldHVybiBwYWlycyhkZXNjcmlwdG9yKS5yZWR1Y2UoZnVuY3Rpb24oZmllbGRzLCBwYWlyKSB7XG4gICAgICAgIHZhciBuYW1lID0gcGFpclswXSwgdHlwZSA9IHBhaXJbMV07XG4gICAgICAgIGZpZWxkc1tuYW1lXSA9IG1ha2VGaWVsZChuYW1lLCB0eXBlKTtcbiAgICAgICAgcmV0dXJuIGZpZWxkcztcbiAgICAgIH0sIHt9KTtcbiAgICB9XG5cbiAgICB2YXIgRGljdGlvbmFyeVR5cGUgPSBDbGFzcyh7fSk7XG5cbiAgICB2YXIgRGljdGlvbmFyeSA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjYXRlZ29yeTogXCJkaWN0XCIsXG4gICAgICBnZXQgbmFtZSgpIHsgcmV0dXJuIHRoaXMudHlwZTsgfSxcbiAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IGRlc2NyaXB0b3IudHlwZU5hbWU7XG4gICAgICAgIHRoaXMudHlwZXMgPSBkZXNjcmlwdG9yLnNwZWNpYWxpemF0aW9ucztcblxuICAgICAgICB2YXIgcHJvdG8gPSBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh7XG4gICAgICAgICAgZXh0ZW5kczogRGljdGlvbmFyeVR5cGUsXG4gICAgICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKHN0YXRlLCBjb250ZXh0KSB7XG4gICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCB7XG4gICAgICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBzdGF0ZVxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogY29udGV4dFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIG1ha2VGaWVsZHModGhpcy50eXBlcykpO1xuXG4gICAgICAgIHRoaXMuY2xhc3MgPSBuZXcgQ2xhc3MocHJvdG8pO1xuICAgICAgfSxcbiAgICAgIHJlYWQ6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHJldHVybiBuZXcgdGhpcy5jbGFzcyhpbnB1dCwgY29udGV4dCk7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB7fTtcbiAgICAgICAgZm9yICh2YXIga2V5IGluIGlucHV0KSB7XG4gICAgICAgICAgb3V0cHV0W2tleV0gPSB3cml0ZSh2YWx1ZSwgY29udGV4dCwgdHlwZXNba2V5XSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG91dHB1dDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHZhciBtYWtlTWV0aG9kcyA9IGZ1bmN0aW9uKGRlc2NyaXB0b3JzKSB7XG4gICAgICByZXR1cm4gZGVzY3JpcHRvcnMucmVkdWNlKGZ1bmN0aW9uKG1ldGhvZHMsIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgbWV0aG9kc1tkZXNjcmlwdG9yLm5hbWVdID0ge1xuICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgICAgICB2YWx1ZTogbWFrZU1ldGhvZChkZXNjcmlwdG9yKVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gbWV0aG9kcztcbiAgICAgIH0sIHt9KTtcbiAgICB9O1xuXG4gICAgdmFyIG1ha2VFdmVudHMgPSBmdW5jdGlvbihkZXNjcmlwdG9ycykge1xuICAgICAgcmV0dXJuIHBhaXJzKGRlc2NyaXB0b3JzKS5yZWR1Y2UoZnVuY3Rpb24oZXZlbnRzLCBwYWlyKSB7XG4gICAgICAgIHZhciBuYW1lID0gcGFpclswXSwgZGVzY3JpcHRvciA9IHBhaXJbMV07XG4gICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudChuYW1lLCBkZXNjcmlwdG9yKTtcbiAgICAgICAgZXZlbnRzW2V2ZW50LmV2ZW50VHlwZV0gPSBldmVudDtcbiAgICAgICAgcmV0dXJuIGV2ZW50cztcbiAgICAgIH0sIE9iamVjdC5jcmVhdGUobnVsbCkpO1xuICAgIH07XG5cbiAgICB2YXIgQWN0b3IgPSBDbGFzcyh7XG4gICAgICBleHRlbmRzOiBUeXBlLFxuICAgICAgY2F0ZWdvcnk6IFwiYWN0b3JcIixcbiAgICAgIGdldCBuYW1lKCkgeyByZXR1cm4gdGhpcy50eXBlOyB9LFxuICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICAgICAgdGhpcy50eXBlID0gZGVzY3JpcHRvci50eXBlTmFtZTtcblxuICAgICAgICB2YXIgZXZlbnRzID0gbWFrZUV2ZW50cyhkZXNjcmlwdG9yLmV2ZW50cyB8fCB7fSk7XG4gICAgICAgIHZhciBmaWVsZHMgPSBtYWtlRmllbGRzKGRlc2NyaXB0b3IuZmllbGRzIHx8IHt9KTtcbiAgICAgICAgdmFyIG1ldGhvZHMgPSBtYWtlTWV0aG9kcyhkZXNjcmlwdG9yLm1ldGhvZHMgfHwgW10pO1xuXG5cbiAgICAgICAgdmFyIHByb3RvID0ge1xuICAgICAgICAgIGV4dGVuZHM6IEZyb250LFxuICAgICAgICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIEZyb250LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBldmVudHM6IGV2ZW50c1xuICAgICAgICB9O1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhwcm90bywgZmllbGRzKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnRpZXMocHJvdG8sIG1ldGhvZHMpO1xuXG4gICAgICAgIHRoaXMuY2xhc3MgPSBDbGFzcyhwcm90byk7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQsIGRldGFpbCkge1xuICAgICAgICB2YXIgc3RhdGUgPSB0eXBlb2YoaW5wdXQpID09PSBcInN0cmluZ1wiID8geyBhY3RvcjogaW5wdXQgfSA6IGlucHV0O1xuXG4gICAgICAgIHZhciBhY3RvciA9IGNsaWVudC5nZXQoc3RhdGUuYWN0b3IpIHx8IG5ldyB0aGlzLmNsYXNzKHN0YXRlLCBjb250ZXh0KTtcbiAgICAgICAgYWN0b3IuZm9ybShzdGF0ZSwgZGV0YWlsLCBjb250ZXh0KTtcblxuICAgICAgICByZXR1cm4gYWN0b3I7XG4gICAgICB9LFxuICAgICAgd3JpdGU6IGZ1bmN0aW9uKGlucHV0LCBjb250ZXh0LCBkZXRhaWwpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0LmlkO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGV4cG9ydHMuQWN0b3IgPSBBY3RvcjtcblxuXG4gICAgdmFyIEFjdG9yRGV0YWlsID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogQWN0b3IsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24obmFtZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBuYW1lLnNwbGl0KFwiI1wiKVxuICAgICAgICB0aGlzLmFjdG9yVHlwZSA9IHBhcnRzWzBdXG4gICAgICAgIHRoaXMuZGV0YWlsID0gcGFydHNbMV07XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVGb3IodGhpcy5hY3RvclR5cGUpLnJlYWQoaW5wdXQsIGNvbnRleHQsIHRoaXMuZGV0YWlsKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVGb3IodGhpcy5hY3RvclR5cGUpLndyaXRlKGlucHV0LCBjb250ZXh0LCB0aGlzLmRldGFpbCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZXhwb3J0cy5BY3RvckRldGFpbCA9IEFjdG9yRGV0YWlsO1xuXG4gICAgdmFyIE1ldGhvZCA9IENsYXNzKHtcbiAgICAgIGV4dGVuZHM6IFR5cGUsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oZGVzY3JpcHRvcikge1xuICAgICAgICB0aGlzLnR5cGUgPSBkZXNjcmlwdG9yLm5hbWU7XG4gICAgICAgIHRoaXMucGF0aCA9IGZpbmRQYXRoKGRlc2NyaXB0b3IucmVzcG9uc2UsIFwiX3JldHZhbFwiKTtcbiAgICAgICAgdGhpcy5yZXNwb25zZVR5cGUgPSB0aGlzLnBhdGggJiYgcXVlcnkoZGVzY3JpcHRvci5yZXNwb25zZSwgdGhpcy5wYXRoKS5fcmV0dmFsO1xuICAgICAgICB0aGlzLnJlcXVlc3RUeXBlID0gZGVzY3JpcHRvci5yZXF1ZXN0LnR5cGU7XG5cbiAgICAgICAgdmFyIHBhcmFtcyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gZGVzY3JpcHRvci5yZXF1ZXN0KSB7XG4gICAgICAgICAgaWYgKGtleSAhPT0gXCJ0eXBlXCIpIHtcbiAgICAgICAgICAgIHZhciBwYXJhbSA9IGRlc2NyaXB0b3IucmVxdWVzdFtrZXldO1xuICAgICAgICAgICAgdmFyIGluZGV4ID0gXCJfYXJnXCIgaW4gcGFyYW0gPyBwYXJhbS5fYXJnIDogcGFyYW0uX29wdGlvbjtcbiAgICAgICAgICAgIHZhciBpc1BhcmFtID0gcGFyYW0uX29wdGlvbiA9PT0gaW5kZXg7XG4gICAgICAgICAgICB2YXIgaXNBcmd1bWVudCA9IHBhcmFtLl9hcmcgPT09IGluZGV4O1xuICAgICAgICAgICAgcGFyYW1zW2luZGV4XSA9IHtcbiAgICAgICAgICAgICAgdHlwZTogcGFyYW0udHlwZSxcbiAgICAgICAgICAgICAga2V5OiBrZXksXG4gICAgICAgICAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgICAgICAgICAgaXNQYXJhbTogaXNQYXJhbSxcbiAgICAgICAgICAgICAgaXNBcmd1bWVudDogaXNBcmd1bWVudFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5wYXJhbXMgPSBwYXJhbXM7XG4gICAgICB9LFxuICAgICAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHJlYWQocXVlcnkoaW5wdXQsIHRoaXMucGF0aCksIGNvbnRleHQsIHRoaXMucmVzcG9uc2VUeXBlKTtcbiAgICAgIH0sXG4gICAgICB3cml0ZTogZnVuY3Rpb24oaW5wdXQsIGNvbnRleHQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyYW1zLnJlZHVjZShmdW5jdGlvbihyZXN1bHQsIHBhcmFtKSB7XG4gICAgICAgICAgcmVzdWx0W3BhcmFtLmtleV0gPSB3cml0ZShpbnB1dFtwYXJhbS5pbmRleF0sIGNvbnRleHQsIHBhcmFtLnR5cGUpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sIHt0eXBlOiB0aGlzLnR5cGV9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBleHBvcnRzLk1ldGhvZCA9IE1ldGhvZDtcblxuICAgIHZhciBwcm9maWxlciA9IGZ1bmN0aW9uKG1ldGhvZCwgaWQpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHN0YXJ0ID0gbmV3IERhdGUoKTtcbiAgICAgICAgcmV0dXJuIG1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7XG4gICAgICAgICAgdmFyIGVuZCA9IG5ldyBEYXRlKCk7XG4gICAgICAgICAgY2xpZW50LnRlbGVtZXRyeS5hZGQoaWQsICtlbmQgLSBzdGFydCk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgZGVzdHJ1Y3RvciA9IGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykudGhlbihmdW5jdGlvbihyZXN1bHQpIHtcbiAgICAgICAgICBjbGllbnQucmVsZWFzZSh0aGlzKTtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIG1ha2VNZXRob2QoZGVzY3JpcHRvcikge1xuICAgICAgdmFyIHR5cGUgPSBuZXcgTWV0aG9kKGRlc2NyaXB0b3IpO1xuICAgICAgdmFyIG1ldGhvZCA9IGRlc2NyaXB0b3Iub25ld2F5ID8gbWFrZVVuaWRpcmVjYXRpb25hbE1ldGhvZChkZXNjcmlwdG9yLCB0eXBlKSA6XG4gICAgICAgICAgICAgICAgICAgbWFrZUJpZGlyZWN0aW9uYWxNZXRob2QoZGVzY3JpcHRvciwgdHlwZSk7XG5cbiAgICAgIGlmIChkZXNjcmlwdG9yLnRlbGVtZXRyeSlcbiAgICAgICAgbWV0aG9kID0gcHJvZmlsZXIobWV0aG9kKTtcbiAgICAgIGlmIChkZXNjcmlwdG9yLnJlbGVhc2UpXG4gICAgICAgIG1ldGhvZCA9IGRlc3RydWN0b3IobWV0aG9kKTtcblxuICAgICAgcmV0dXJuIG1ldGhvZDtcbiAgICB9XG5cbiAgICB2YXIgbWFrZVVuaWRpcmVjYXRpb25hbE1ldGhvZCA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IsIHR5cGUpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHBhY2tldCA9IHR5cGUud3JpdGUoYXJndW1lbnRzLCB0aGlzKTtcbiAgICAgICAgcGFja2V0LnRvID0gdGhpcy5pZDtcbiAgICAgICAgY2xpZW50LnNlbmQocGFja2V0KTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh2b2lkKDApKTtcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHZhciBtYWtlQmlkaXJlY3Rpb25hbE1ldGhvZCA9IGZ1bmN0aW9uKGRlc2NyaXB0b3IsIHR5cGUpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgICAgIHZhciBwYWNrZXQgPSB0eXBlLndyaXRlKGFyZ3VtZW50cywgY29udGV4dCk7XG4gICAgICAgIHZhciBjb250ZXh0ID0gdGhpcy5jb250ZXh0O1xuICAgICAgICBwYWNrZXQudG8gPSB0aGlzLmlkO1xuICAgICAgICByZXR1cm4gY2xpZW50LnJlcXVlc3QocGFja2V0KS50aGVuKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgICAgICAgIHJldHVybiB0eXBlLnJlYWQocGFja2V0LCBjb250ZXh0KTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuICAgIH07XG5cbiAgICB2YXIgRXZlbnQgPSBDbGFzcyh7XG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24obmFtZSwgZGVzY3JpcHRvcikge1xuICAgICAgICB0aGlzLm5hbWUgPSBkZXNjcmlwdG9yLnR5cGUgfHwgbmFtZTtcbiAgICAgICAgdGhpcy5ldmVudFR5cGUgPSBkZXNjcmlwdG9yLnR5cGUgfHwgbmFtZTtcbiAgICAgICAgdGhpcy50eXBlcyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbiAgICAgICAgdmFyIHR5cGVzID0gdGhpcy50eXBlcztcbiAgICAgICAgZm9yICh2YXIga2V5IGluIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgICBpZiAoa2V5ID09PSBcInR5cGVcIikge1xuICAgICAgICAgICAgdHlwZXNba2V5XSA9IFwic3RyaW5nXCI7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHR5cGVzW2tleV0gPSBkZXNjcmlwdG9yW2tleV0udHlwZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZWFkOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgb3V0cHV0ID0ge307XG4gICAgICAgIHZhciB0eXBlcyA9IHRoaXMudHlwZXM7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiBpbnB1dCkge1xuICAgICAgICAgIG91dHB1dFtrZXldID0gcmVhZChpbnB1dFtrZXldLCBjb250ZXh0LCB0eXBlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfSxcbiAgICAgIHdyaXRlOiBmdW5jdGlvbihpbnB1dCwgY29udGV4dCkge1xuICAgICAgICB2YXIgb3V0cHV0ID0ge307XG4gICAgICAgIHZhciB0eXBlcyA9IHRoaXMudHlwZXM7XG4gICAgICAgIGZvciAodmFyIGtleSBpbiB0aGlzLnR5cGVzKSB7XG4gICAgICAgICAgb3V0cHV0W2tleV0gPSB3cml0ZShpbnB1dFtrZXldLCBjb250ZXh0LCB0eXBlc1trZXldKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIEZyb250ID0gQ2xhc3Moe1xuICAgICAgZXh0ZW5kczogRXZlbnRUYXJnZXQsXG4gICAgICBFdmVudFRhcmdldDogRXZlbnRUYXJnZXQsXG4gICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24oc3RhdGUpIHtcbiAgICAgICAgdGhpcy5FdmVudFRhcmdldCgpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh0aGlzLCAge1xuICAgICAgICAgIHN0YXRlOiB7XG4gICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IHN0YXRlXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBjbGllbnQucmVnaXN0ZXIodGhpcyk7XG4gICAgICB9LFxuICAgICAgZ2V0IGlkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdGF0ZS5hY3RvcjtcbiAgICAgIH0sXG4gICAgICBnZXQgY29udGV4dCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICB9LFxuICAgICAgZm9ybTogZnVuY3Rpb24oc3RhdGUsIGRldGFpbCwgY29udGV4dCkge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZSAhPT0gc3RhdGUpIHtcbiAgICAgICAgICBpZiAoZGV0YWlsKSB7XG4gICAgICAgICAgICB0aGlzLnN0YXRlW2RldGFpbF0gPSBzdGF0ZVtkZXRhaWxdO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYWlycyhzdGF0ZSkuZm9yRWFjaChmdW5jdGlvbihwYWlyKSB7XG4gICAgICAgICAgICAgIHZhciBrZXkgPSBwYWlyWzBdLCB2YWx1ZSA9IHBhaXJbMV07XG4gICAgICAgICAgICAgIHRoaXMuc3RhdGVba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfSwgdGhpcyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbnRleHQpIHtcbiAgICAgICAgICBjbGllbnQuc3VwZXJ2aXNlKGNvbnRleHQsIHRoaXMpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVxdWVzdFR5cGVzOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIGNsaWVudC5yZXF1ZXN0KHtcbiAgICAgICAgICB0bzogdGhpcy5pZCxcbiAgICAgICAgICB0eXBlOiBcInJlcXVlc3RUeXBlc1wiXG4gICAgICAgIH0pLnRoZW4oZnVuY3Rpb24ocGFja2V0KSB7XG4gICAgICAgICAgcmV0dXJuIHBhY2tldC5yZXF1ZXN0VHlwZXM7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHR5cGVzLnByaW1pdGl2ZSA9IG5ldyBQcmltaXR2ZShcInByaW1pdGl2ZVwiKTtcbiAgICB0eXBlcy5zdHJpbmcgPSBuZXcgUHJpbWl0dmUoXCJzdHJpbmdcIik7XG4gICAgdHlwZXMubnVtYmVyID0gbmV3IFByaW1pdHZlKFwibnVtYmVyXCIpO1xuICAgIHR5cGVzLmJvb2xlYW4gPSBuZXcgUHJpbWl0dmUoXCJib29sZWFuXCIpO1xuICAgIHR5cGVzLmpzb24gPSBuZXcgUHJpbWl0dmUoXCJqc29uXCIpO1xuICAgIHR5cGVzLmFycmF5ID0gbmV3IFByaW1pdHZlKFwiYXJyYXlcIik7XG4gIH0sXG4gIHJlZ2lzdGVyVHlwZXM6IGZ1bmN0aW9uKGRlc2NyaXB0b3IpIHtcbiAgICB2YXIgc3BlY2lmaWNhdGlvbiA9IHRoaXMuc3BlY2lmaWNhdGlvbjtcbiAgICB2YWx1ZXMoZGVzY3JpcHRvci50eXBlcykuZm9yRWFjaChmdW5jdGlvbihkZXNjcmlwdG9yKSB7XG4gICAgICBzcGVjaWZpY2F0aW9uW2Rlc2NyaXB0b3IudHlwZU5hbWVdID0gZGVzY3JpcHRvcjtcbiAgICB9KTtcbiAgfVxufSk7XG5leHBvcnRzLlR5cGVTeXN0ZW0gPSBUeXBlU3lzdGVtO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBrZXlzID0gT2JqZWN0LmtleXM7XG5leHBvcnRzLmtleXMgPSBrZXlzO1xuXG4vLyBSZXR1cm5zIGFycmF5IG9mIHZhbHVlcyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cbnZhciB2YWx1ZXMgPSBmdW5jdGlvbihvYmplY3QpIHtcbiAgcmV0dXJuIGtleXMob2JqZWN0KS5tYXAoZnVuY3Rpb24oa2V5KSB7XG4gICAgcmV0dXJuIG9iamVjdFtrZXldXG4gIH0pO1xufTtcbmV4cG9ydHMudmFsdWVzID0gdmFsdWVzO1xuXG4vLyBSZXR1cm5zIFtrZXksIHZhbHVlXSBwYWlycyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cbnZhciBwYWlycyA9IGZ1bmN0aW9uKG9iamVjdCkge1xuICByZXR1cm4ga2V5cyhvYmplY3QpLm1hcChmdW5jdGlvbihrZXkpIHtcbiAgICByZXR1cm4gW2tleSwgb2JqZWN0W2tleV1dXG4gIH0pO1xufTtcbmV4cG9ydHMucGFpcnMgPSBwYWlycztcblxuXG4vLyBRdWVyaWVzIGFuIG9iamVjdCBmb3IgdGhlIGZpZWxkIG5lc3RlZCB3aXRoIGluIGl0LlxudmFyIHF1ZXJ5ID0gZnVuY3Rpb24ob2JqZWN0LCBwYXRoKSB7XG4gIHJldHVybiBwYXRoLnJlZHVjZShmdW5jdGlvbihvYmplY3QsIGVudHJ5KSB7XG4gICAgcmV0dXJuIG9iamVjdCAmJiBvYmplY3RbZW50cnldXG4gIH0sIG9iamVjdCk7XG59O1xuZXhwb3J0cy5xdWVyeSA9IHF1ZXJ5O1xuXG52YXIgaXNPYmplY3QgPSBmdW5jdGlvbih4KSB7XG4gIHJldHVybiB4ICYmIHR5cGVvZih4KSA9PT0gXCJvYmplY3RcIlxufVxuXG52YXIgZmluZFBhdGggPSBmdW5jdGlvbihvYmplY3QsIGtleSkge1xuICB2YXIgcGF0aCA9IHZvaWQoMCk7XG4gIGlmIChvYmplY3QgJiYgdHlwZW9mKG9iamVjdCkgPT09IFwib2JqZWN0XCIpIHtcbiAgICB2YXIgbmFtZXMgPSBrZXlzKG9iamVjdCk7XG4gICAgaWYgKG5hbWVzLmluZGV4T2Yoa2V5KSA+PSAwKSB7XG4gICAgICBwYXRoID0gW107XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBpbmRleCA9IDA7XG4gICAgICB2YXIgY291bnQgPSBuYW1lcy5sZW5ndGg7XG4gICAgICB3aGlsZSAoaW5kZXggPCBjb3VudCAmJiAhcGF0aCl7XG4gICAgICAgIHZhciBoZWFkID0gbmFtZXNbaW5kZXhdO1xuICAgICAgICB2YXIgdGFpbCA9IGZpbmRQYXRoKG9iamVjdFtoZWFkXSwga2V5KTtcbiAgICAgICAgcGF0aCA9IHRhaWwgPyBbaGVhZF0uY29uY2F0KHRhaWwpIDogdGFpbDtcbiAgICAgICAgaW5kZXggPSBpbmRleCArIDFcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHBhdGg7XG59O1xuZXhwb3J0cy5maW5kUGF0aCA9IGZpbmRQYXRoO1xuIl19
+(1)
+});
diff --git a/addon-sdk/source/lib/sdk/addon/runner.js b/addon-sdk/source/lib/sdk/addon/runner.js
index 7391c4c6169c..294c364c9184 100644
--- a/addon-sdk/source/lib/sdk/addon/runner.js
+++ b/addon-sdk/source/lib/sdk/addon/runner.js
@@ -7,6 +7,7 @@ module.metadata = {
 };
 
 const { Cc, Ci } = require('chrome');
+const { isNative } = require('@loader/options');
 const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
 const { once } = require('../system/events');
 const { exit, env, staticArgs } = require('../system');
@@ -104,7 +105,8 @@ function startup(reason, options) {
   require('../l10n/loader').
     load(rootURI).
     then(null, function failure(error) {
-      console.info("Error while loading localization: " + error.message);
+      if (!isNative)
+        console.info("Error while loading localization: " + error.message);
     }).
     then(function onLocalizationReady(data) {
       // Exports data to a pseudo module so that api-utils/l10n/core
diff --git a/addon-sdk/source/lib/sdk/content/loader.js b/addon-sdk/source/lib/sdk/content/loader.js
index 77e4a697e372..aac3660c27cb 100644
--- a/addon-sdk/source/lib/sdk/content/loader.js
+++ b/addon-sdk/source/lib/sdk/content/loader.js
@@ -9,81 +9,50 @@ module.metadata = {
 };
 
 const { EventEmitter } = require('../deprecated/events');
-const { validateOptions } = require('../deprecated/api-utils');
-const { isValidURI, URL } = require('../url');
+const { isValidURI, isLocalURL, URL } = require('../url');
 const file = require('../io/file');
 const { contract } = require('../util/contract');
-const { isString, instanceOf } = require('../lang/type');
+const { isString, isNil, instanceOf } = require('../lang/type');
+const { validateOptions,
+  string, array, object, either, required } = require('../deprecated/api-utils');
 
-const LOCAL_URI_SCHEMES = ['resource', 'data'];
+const isJSONable = (value) => {
+  try {
+    JSON.parse(JSON.stringify(value));
+  } catch (e) {
+    return false;
+  }
+  return true;
+};
 
-// Returns `null` if `value` is `null` or `undefined`, otherwise `value`.
-function ensureNull(value) value == null ? null : value
+const isValidScriptFile = (value) =>
+  (isString(value) || instanceOf(value, URL)) && isLocalURL(value);
 
 // map of property validations
 const valid = {
   contentURL: {
-    map: function(url) !url ? ensureNull(url) : url.toString(), 
-    is: ['undefined', 'null', 'string'],
-    ok: function (url) {
-      if (url === null)
-        return true;
-      return isValidURI(url);
-    },
+    is: either(string, object),
+    ok: url => isNil(url) || isLocalURL(url) || isValidURI(url),
     msg: 'The `contentURL` option must be a valid URL.'
   },
   contentScriptFile: {
-    is: ['undefined', 'null', 'string', 'array', 'object'],
-    map: ensureNull,
-    ok: function(value) {
-      if (value === null)
-        return true;
-
-      value = [].concat(value);
-
-      // Make sure every item is a string or an
-      // URL instance, and also a local file URL.
-      return value.every(function (item) {
-
-        if (!isString(item) && !(item instanceof URL)) 
-          return false;
-
-        try {
-          return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme);
-        }
-        catch(e) {
-          return false;
-        }
-      });
-
-    },
+    is: either(string, object, array),
+    ok: value => isNil(value) || [].concat(value).every(isValidScriptFile),
     msg: 'The `contentScriptFile` option must be a local URL or an array of URLs.'
   },
   contentScript: {
-    is: ['undefined', 'null', 'string', 'array'],
-    map: ensureNull,
-    ok: function(value) {
-      return !Array.isArray(value) || value.every(
-        function(item) { return typeof item === 'string' }
-      );
-    },
+    is: either(string, array),
+    ok: value => isNil(value) || [].concat(value).every(isString),
     msg: 'The `contentScript` option must be a string or an array of strings.'
   },
   contentScriptWhen: {
-    is: ['string'],
-    ok: function(value) { return ~['start', 'ready', 'end'].indexOf(value) },
-    map: function(value) {
-      return value || 'end';
-    },
+    is: required(string),
+    map: value => value || 'end',
+    ok: value => ~['start', 'ready', 'end'].indexOf(value),
     msg: 'The `contentScriptWhen` option must be either "start", "ready" or "end".'
   },
   contentScriptOptions: {
-    ok: function(value) {
-      if ( value === undefined ) { return true; }
-      try { JSON.parse( JSON.stringify( value ) ); } catch(e) { return false; }
-      return true;
-    },
-    map: function(value) 'undefined' === getTypeOf(value) ? null : value,
+    ok: value => isNil(value) || isJSONable(value),
     msg: 'The contentScriptOptions should be a jsonable value.'
   }
 };
diff --git a/addon-sdk/source/lib/sdk/content/sandbox.js b/addon-sdk/source/lib/sdk/content/sandbox.js
index 2764b400d3ae..d72e35adeaa2 100644
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -20,7 +20,7 @@ const { merge } = require('../util/object');
 const { getTabForContentWindow } = require('../tabs/utils');
 const { getInnerId } = require('../window/utils');
 const { PlainTextConsole } = require('../console/plain-text');
-
+const { data } = require('../self');
 // WeakMap of sandboxes so we can access private values
 const sandboxes = new WeakMap();
 
@@ -247,9 +247,12 @@ const WorkerSandbox = Class({
     // The order of `contentScriptFile` and `contentScript` evaluation is
     // intentional, so programs can load libraries like jQuery from script URLs
     // and use them in scripts.
-    let contentScriptFile = ('contentScriptFile' in worker) ? worker.contentScriptFile
+    let contentScriptFile = ('contentScriptFile' in worker)
+          ? worker.contentScriptFile
           : null,
-        contentScript = ('contentScript' in worker) ? worker.contentScript : null;
+        contentScript = ('contentScript' in worker)
+          ? worker.contentScript
+          : null;
 
     if (contentScriptFile)
       importScripts.apply(null, [this].concat(contentScriptFile));
@@ -285,7 +288,8 @@ exports.WorkerSandbox = WorkerSandbox;
 function importScripts (workerSandbox, ...urls) {
   let { worker, sandbox } = modelFor(workerSandbox);
   for (let i in urls) {
-    let contentScriptFile = urls[i];
+    let contentScriptFile = data.url(urls[i]);
+
     try {
       let uri = URL(contentScriptFile);
       if (uri.scheme === 'resource')
diff --git a/addon-sdk/source/lib/sdk/content/utils.js b/addon-sdk/source/lib/sdk/content/utils.js
index 8b53ca2afaf1..ae1cbf6cc7d2 100644
--- a/addon-sdk/source/lib/sdk/content/utils.js
+++ b/addon-sdk/source/lib/sdk/content/utils.js
@@ -8,13 +8,14 @@ module.metadata = {
 };
 
 let { merge } = require('../util/object');
-let assetsURI = require('../self').data.url();
+let { data } = require('../self');
+let assetsURI = data.url();
 let isArray = Array.isArray;
 let method = require('../../method/core');
 
-function isAddonContent({ contentURL }) {
-  return typeof(contentURL) === 'string' && contentURL.indexOf(assetsURI) === 0;
-}
+const isAddonContent = ({ contentURL }) =>
+  contentURL && data.url(contentURL).startsWith(assetsURI);
+
 exports.isAddonContent = isAddonContent;
 
 function hasContentScript({ contentScript, contentScriptFile }) {
diff --git a/addon-sdk/source/lib/sdk/context-menu.js b/addon-sdk/source/lib/sdk/context-menu.js
index 860adf8c0f7e..29d53a857177 100644
--- a/addon-sdk/source/lib/sdk/context-menu.js
+++ b/addon-sdk/source/lib/sdk/context-menu.js
@@ -25,6 +25,7 @@ const { EventTarget } = require("./event/target");
 const { emit } = require('./event/core');
 const { when } = require('./system/unload');
 const selection = require('./selection');
+const { contract: loaderContract } = require('./content/loader');
 
 // All user items we add have this class.
 const ITEM_CLASS = "addon-context-menu-item";
@@ -257,7 +258,7 @@ function populateCallbackNodeData(node) {
   }
 
   data.selectionText = selection.text;
-  
+
   data.srcURL = node.src || null;
   data.value = node.value || null;
 
@@ -265,7 +266,7 @@ function populateCallbackNodeData(node) {
     data.linkURL = node.href || null;
     node = node.parentNode;
   }
-  
+
   return data;
 }
 
@@ -298,30 +299,11 @@ let baseItemRules = {
     msg: "The 'context' option must be a Context object or an array of " +
          "Context objects."
   },
-  contentScript: {
-    is: ["string", "array", "undefined"],
-    ok: function (v) {
-      return !Array.isArray(v) ||
-             v.every(function (s) typeof(s) === "string");
-    }
-  },
-  contentScriptFile: {
-    is: ["string", "array", "undefined"],
-    ok: function (v) {
-      if (!v)
-        return true;
-      let arr = Array.isArray(v) ? v : [v];
-      return arr.every(function (s) {
-        return getTypeOf(s) === "string" &&
-               getScheme(s) === 'resource';
-      });
-    },
-    msg: "The 'contentScriptFile' option must be a local file URL or " +
-         "an array of local file URLs."
-  },
   onMessage: {
     is: ["function", "undefined"]
-  }
+  },
+  contentScript: loaderContract.rules.contentScript,
+  contentScriptFile: loaderContract.rules.contentScriptFile
 };
 
 let labelledItemRules =  mix(baseItemRules, {
diff --git a/addon-sdk/source/lib/sdk/deprecated/api-utils.js b/addon-sdk/source/lib/sdk/deprecated/api-utils.js
index c148ff2376e6..a89e773f0db0 100644
--- a/addon-sdk/source/lib/sdk/deprecated/api-utils.js
+++ b/addon-sdk/source/lib/sdk/deprecated/api-utils.js
@@ -172,6 +172,9 @@ exports.boolean = boolean;
 let object = { is: ['object', 'undefined', 'null'] };
 exports.object = object;
 
+let array = { is: ['array', 'undefined', 'null'] };
+exports.array = array;
+
 let isTruthyType = type => !(type === 'undefined' || type === 'null');
 let findTypes = v => { while (!isArray(v) && v.is) v = v.is; return v };
 
diff --git a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
index 750292c01115..90557d5dacdd 100644
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
@@ -143,11 +143,17 @@ TestFinder.prototype = {
           suiteModule = cuddlefish.main(loader, suite);
         }
         catch (e) {
-          // If `Unsupported Application` error thrown during test,
-          // skip the test suite
-          suiteModule = {
-            'test suite skipped': assert => assert.pass(e.message)
-          };
+          if (/Unsupported Application/i.test(e.message)) {
+            // If `Unsupported Application` error thrown during test,
+            // skip the test suite
+            suiteModule = {
+              'test suite skipped': assert => assert.pass(e.message)
+            };
+          }
+          else {
+            console.exception(e);
+            throw e;
+          }
         }
 
         if (this.testInProcess) {
diff --git a/addon-sdk/source/lib/sdk/dom/events.js b/addon-sdk/source/lib/sdk/dom/events.js
index 2a74e6de461c..bdf108312a0a 100644
--- a/addon-sdk/source/lib/sdk/dom/events.js
+++ b/addon-sdk/source/lib/sdk/dom/events.js
@@ -33,7 +33,7 @@ function getInitializerName(category) {
  *    [event type](https://developer.mozilla.org/en/DOM/event.type) to
  *    listen for.
  * @param {Function} listener
- *    Function that is called whenever an event of the specified `type` 
+ *    Function that is called whenever an event of the specified `type`
  *    occurs.
  * @param {Boolean} capture
  *    If true, indicates that the user wishes to initiate capture. After
@@ -62,7 +62,7 @@ exports.on = on;
  *    [event type](https://developer.mozilla.org/en/DOM/event.type) to
  *    listen for.
  * @param {Function} listener
- *    Function that is called whenever an event of the specified `type` 
+ *    Function that is called whenever an event of the specified `type`
  *    occurs.
  * @param {Boolean} capture
  *    If true, indicates that the user wishes to initiate capture. After
@@ -92,7 +92,7 @@ exports.once = once;
  *    [event type](https://developer.mozilla.org/en/DOM/event.type) to
  *    listen for.
  * @param {Function} listener
- *    Function that is called whenever an event of the specified `type` 
+ *    Function that is called whenever an event of the specified `type`
  *    occurs.
  * @param {Boolean} capture
  *    If true, indicates that the user wishes to initiate capture. After
@@ -137,3 +137,33 @@ function emit(element, type, { category, initializer, settings }) {
   element.dispatchEvent(event);
 };
 exports.emit = emit;
+
+// Takes DOM `element` and returns promise which is resolved
+// when given element is removed from it's parent node.
+const removed = element => {
+  return new Promise(resolve => {
+    const { MutationObserver } = element.ownerDocument.defaultView;
+    const observer = new MutationObserver(mutations => {
+      for (let mutation of mutations) {
+        for (let node of mutation.removedNodes || []) {
+          if (node === element) {
+            observer.disconnect();
+            resolve(element);
+          }
+        }
+      }
+    });
+    observer.observe(element.parentNode, {childList: true});
+  });
+};
+exports.removed = removed;
+
+const when = (element, eventName, capture=false) => new Promise(resolve => {
+  const listener = event => {
+    element.removeEventListener(eventName, listener, capture);
+    resolve(event);
+  };
+
+  element.addEventListener(eventName, listener, capture);
+});
+exports.when = when;
diff --git a/addon-sdk/source/lib/sdk/event/utils.js b/addon-sdk/source/lib/sdk/event/utils.js
index 38b9a75ab604..65456ff574a5 100644
--- a/addon-sdk/source/lib/sdk/event/utils.js
+++ b/addon-sdk/source/lib/sdk/event/utils.js
@@ -260,7 +260,7 @@ exports.Reactor = Reactor;
  * Takes an object used as options with potential keys like 'onMessage',
  * used to be called `require('sdk/event/core').setListeners` on.
  * This strips all keys that would trigger a listener to be set.
- * 
+ *
  * @params {Object} object
  * @return {Object}
  */
@@ -273,3 +273,8 @@ function stripListeners (object) {
   }, {});
 }
 exports.stripListeners = stripListeners;
+
+const when = (target, type) => new Promise(resolve => {
+  once(target, type, resolve);
+});
+exports.when = when;
diff --git a/addon-sdk/source/lib/sdk/l10n.js b/addon-sdk/source/lib/sdk/l10n.js
index c3290145e090..a7cab89296f9 100644
--- a/addon-sdk/source/lib/sdk/l10n.js
+++ b/addon-sdk/source/lib/sdk/l10n.js
@@ -34,7 +34,8 @@ exports.get = function get(k) {
   if (arguments.length <= 1)
     return localized;
 
-  let args = arguments;
+  let args = Array.slice(arguments);
+  let placeholders = [null, ...args.slice(typeof(n) === "number" ? 2 : 1)];
 
   if (typeof localized == "object" && "other" in localized) {
     // # Plural form:
@@ -76,11 +77,15 @@ exports.get = function get(k) {
   // in translation.
   // * In case of plural form, we has `%d` instead of `%s`.
   let offset = 1;
-  localized = localized.replace(/%(\d*)(s|d)/g, function (v, n) {
-      let rv = args[n != "" ? n : offset];
-      offset++;
-      return rv;
-    });
+  if (placeholders.length > 1) {
+    args = placeholders;
+  }
+
+  localized = localized.replace(/%(\d*)[sd]/g, (v, n) => {
+    let rv = args[n != "" ? n : offset];
+    offset++;
+    return rv;
+  });
 
   return localized;
 }
diff --git a/addon-sdk/source/lib/sdk/l10n/json/core.js b/addon-sdk/source/lib/sdk/l10n/json/core.js
index 314ae048755d..92665351f204 100644
--- a/addon-sdk/source/lib/sdk/l10n/json/core.js
+++ b/addon-sdk/source/lib/sdk/l10n/json/core.js
@@ -28,6 +28,7 @@ exports.get = function get(k) {
 exports.locale = function locale() {
   return bestMatchingLocale;
 }
+
 // Returns the short locale code: ja, en, fr
 exports.language = function language() {
   return bestMatchingLocale ? bestMatchingLocale.split("-")[0].toLowerCase()
diff --git a/addon-sdk/source/lib/sdk/l10n/properties/core.js b/addon-sdk/source/lib/sdk/l10n/properties/core.js
index 0e680d1bd1ac..240bd8355e08 100644
--- a/addon-sdk/source/lib/sdk/l10n/properties/core.js
+++ b/addon-sdk/source/lib/sdk/l10n/properties/core.js
@@ -66,6 +66,10 @@ function get(key, n, locales) {
     localized = getKey(locale, key);
   }
 
+  if (!localized) {
+    localized = getKey(locale, key + '[other]');
+  }
+
   if (localized) {
     return localized;
   }
diff --git a/addon-sdk/source/lib/sdk/messaging.js b/addon-sdk/source/lib/sdk/messaging.js
new file mode 100644
index 000000000000..07580eb33909
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/messaging.js
@@ -0,0 +1,12 @@
+/* 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 { window } = require("sdk/addon/window");
+exports.MessageChannel = window.MessageChannel;
+exports.MessagePort = window.MessagePort;
diff --git a/addon-sdk/source/lib/sdk/notifications.js b/addon-sdk/source/lib/sdk/notifications.js
index 87b33aaf027f..2d88c89c6f21 100644
--- a/addon-sdk/source/lib/sdk/notifications.js
+++ b/addon-sdk/source/lib/sdk/notifications.js
@@ -12,7 +12,8 @@ const { Cc, Ci, Cr } = require("chrome");
 const apiUtils = require("./deprecated/api-utils");
 const errors = require("./deprecated/errors");
 const { isString, isUndefined, instanceOf } = require('./lang/type');
-const { URL } = require('./url');
+const { URL, isLocalURL } = require('./url');
+const { data } = require('./self');
 
 const NOTIFICATION_DIRECTIONS  = ["auto", "ltr", "rtl"];
 
@@ -39,7 +40,10 @@ exports.notify = function notifications_notify(options) {
     }
   };
   function notifyWithOpts(notifyFn) {
-    notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver,
+    let { iconURL } = valOpts;
+    iconURL = iconURL && isLocalURL(iconURL) ? data.url(iconURL) : iconURL;
+
+    notifyFn(iconURL, valOpts.title, valOpts.text, !!clickObserver,
              valOpts.data, clickObserver, valOpts.tag, valOpts.dir, valOpts.lang);
   }
   try {
@@ -47,7 +51,7 @@ exports.notify = function notifications_notify(options) {
   }
   catch (err) {
     if (err instanceof Ci.nsIException && err.result == Cr.NS_ERROR_FILE_NOT_FOUND) {
-      console.warn("The notification icon named by " + valOpts.iconURL +
+      console.warn("The notification icon named by " + iconURL +
                    " does not exist.  A default icon will be used instead.");
       delete valOpts.iconURL;
       notifyWithOpts(notify);
diff --git a/addon-sdk/source/lib/sdk/page-worker.js b/addon-sdk/source/lib/sdk/page-worker.js
index 727043b50f4e..6a9d053483ee 100644
--- a/addon-sdk/source/lib/sdk/page-worker.js
+++ b/addon-sdk/source/lib/sdk/page-worker.js
@@ -26,6 +26,7 @@ const { contract: loaderContract } = require('./content/loader');
 const { has } = require('./util/array');
 const { Rules } = require('./util/rules');
 const { merge } = require('./util/object');
+const { data } = require('./self');
 
 const views = WeakMap();
 const workers = WeakMap();
@@ -92,10 +93,13 @@ const Page = Class({
   setup: function Page(options) {
     let page = this;
     options = pageContract(options);
+
+    let uri = options.contentURL;
+
     let view = makeFrame(window.document, {
       nodeName: 'iframe',
       type: 'content',
-      uri: options.contentURL,
+      uri: uri ? data.url(uri) : '',
       allowJavascript: options.allow.script,
       allowPlugins: true,
       allowAuth: true
@@ -124,12 +128,19 @@ const Page = Class({
     let allowJavascript = pageContract({ allow: value }).allow.script;
     return allowJavascript ? enableScript(this) : disableScript(this);
   },
-  get contentURL() { return viewFor(this).getAttribute('src'); },
+  get contentURL() { return viewFor(this).getAttribute("data-src") },
   set contentURL(value) {
     if (!isValidURL(this, value)) return;
     let view = viewFor(this);
     let contentURL = pageContract({ contentURL: value }).contentURL;
-    view.setAttribute('src', contentURL);
+
+    // page-worker doesn't have a model like other APIs, so to be consitent
+    // with the behavior "what you set is what you get", we need to store
+    // the original `contentURL` given. 
+    // Even if XUL elements doesn't support `dataset`, properties, to
+    // indicate that is a custom attribute the syntax "data-*" is used.
+    view.setAttribute('data-src', contentURL);
+    view.setAttribute('src', data.url(contentURL));
   },
   dispose: function () {
     if (isDisposed(this)) return;
diff --git a/addon-sdk/source/lib/sdk/panel.js b/addon-sdk/source/lib/sdk/panel.js
index f60430f198e1..9f1749841416 100644
--- a/addon-sdk/source/lib/sdk/panel.js
+++ b/addon-sdk/source/lib/sdk/panel.js
@@ -307,13 +307,13 @@ on(hides, "data", ({target}) => emit(panelFor(target), "hide"));
 on(ready, "data", ({target}) => {
   let panel = panelFor(target);
   let window = domPanel.getContentDocument(target).defaultView;
-  
+
   workerFor(panel).attach(window);
 });
 
 on(start, "data", ({target}) => {
   let panel = panelFor(target);
   let window = domPanel.getContentDocument(target).defaultView;
-  
+
   attach(styleFor(panel), window);
 });
diff --git a/addon-sdk/source/lib/sdk/panel/utils.js b/addon-sdk/source/lib/sdk/panel/utils.js
index 9b275f5058a5..e86a3a577290 100644
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -17,6 +17,8 @@ const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
 const { create: createFrame, swapFrameLoaders } = require("../frame/utils");
 const { window: addonWindow } = require("../addon/window");
 const { isNil } = require("../lang/type");
+const { data } = require('../self');
+
 const events = require("../system/events");
 
 
@@ -402,7 +404,10 @@ exports.getContentFrame = getContentFrame;
 function getContentDocument(panel) getContentFrame(panel).contentDocument
 exports.getContentDocument = getContentDocument;
 
-function setURL(panel, url) getContentFrame(panel).setAttribute("src", url)
+function setURL(panel, url) {
+  getContentFrame(panel).setAttribute("src", url ? data.url(url) : url);
+}
+
 exports.setURL = setURL;
 
 function allowContextMenu(panel, allow) {
diff --git a/addon-sdk/source/lib/sdk/self.js b/addon-sdk/source/lib/sdk/self.js
index af093819b3b9..a772447ee8a7 100644
--- a/addon-sdk/source/lib/sdk/self.js
+++ b/addon-sdk/source/lib/sdk/self.js
@@ -28,7 +28,7 @@ const permissions = metadata.permissions || {};
 const isPacked = rootURI && rootURI.indexOf("jar:") === 0;
 
 const uri = (path="") =>
-  path.contains(":") ? path : addonDataURI + path;
+  path.contains(":") ? path : addonDataURI + path.replace(/^\.\//, "");
 
 
 // Some XPCOM APIs require valid URIs as an argument for certain operations
diff --git a/addon-sdk/source/lib/sdk/stylesheet/style.js b/addon-sdk/source/lib/sdk/stylesheet/style.js
index 234d2ff93682..e08c01b799e8 100644
--- a/addon-sdk/source/lib/sdk/stylesheet/style.js
+++ b/addon-sdk/source/lib/sdk/stylesheet/style.js
@@ -9,24 +9,14 @@ module.metadata = {
 
 const { Cc, Ci } = require("chrome");
 const { Class } = require("../core/heritage");
-const { ns } = require("../core/namespace");
-const { URL } = require('../url');
+const { URL, isLocalURL } = require('../url');
 const events = require("../system/events");
 const { loadSheet, removeSheet, isTypeValid } = require("./utils");
 const { isString } = require("../lang/type");
 const { attachTo, detachFrom, getTargetWindow } = require("../content/mod");
+const { data } = require('../self');
 
 const { freeze, create } = Object;
-const LOCAL_URI_SCHEMES = ['resource', 'data'];
-
-function isLocalURL(item) {
-  try {
-    return LOCAL_URI_SCHEMES.indexOf(URL(item).scheme) > -1;
-  }
-  catch(e) {}
-
-  return false;
-}
 
 function Style({ source, uri, type }) {
   source = source == null ? null : freeze([].concat(source));
@@ -54,7 +44,7 @@ exports.Style = Style;
 attachTo.define(Style, function (style, window) {
   if (style.uri) {
     for (let uri of style.uri)
-      loadSheet(window, uri, style.type);
+      loadSheet(window, data.url(uri), style.type);
   }
 
   if (style.source) {
@@ -69,7 +59,7 @@ attachTo.define(Style, function (style, window) {
 detachFrom.define(Style, function (style, window) {
   if (style.uri)
     for (let uri of style.uri)
-      removeSheet(window, uri);
+      removeSheet(window, data.url(uri));
 
   if (style.source) {
     let uri = "data:text/css;charset=utf-8,";
diff --git a/addon-sdk/source/lib/sdk/tabs/common.js b/addon-sdk/source/lib/sdk/tabs/common.js
index d3e07e30d999..9ee512a7b9c0 100644
--- a/addon-sdk/source/lib/sdk/tabs/common.js
+++ b/addon-sdk/source/lib/sdk/tabs/common.js
@@ -3,16 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
-const { validateOptions } = require('../deprecated/api-utils');
+const { validateOptions } = require("../deprecated/api-utils");
+const { data } = require("../self");
 
 function Options(options) {
   if ('string' === typeof options)
     options = { url: options };
 
   return validateOptions(options, {
-    url: { is: ["string"] },
+    url: {
+      is: ["string"],
+      map: (v) => v ? data.url(v) : v
+    },
     inBackground: {
-      map: function(v) !!v,
+      map: Boolean,
       is: ["undefined", "boolean"]
     },
     isPinned: { is: ["undefined", "boolean"] },
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar.js b/addon-sdk/source/lib/sdk/ui/sidebar.js
index d1c1baf97e4b..685b7072073d 100644
--- a/addon-sdk/source/lib/sdk/ui/sidebar.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar.js
@@ -17,7 +17,7 @@ const { off, emit, setListeners } = require('../event/core');
 const { EventTarget } = require('../event/target');
 const { URL } = require('../url');
 const { add, remove, has, clear, iterator } = require('../lang/weak-set');
-const { id: addonID } = require('../self');
+const { id: addonID, data } = require('../self');
 const { WindowTracker } = require('../deprecated/window-utils');
 const { isShowing } = require('./sidebar/utils');
 const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../window/utils');
@@ -35,6 +35,8 @@ const { identify } = require('./id');
 const { uuid } = require('../util/uuid');
 const { viewFor } = require('../view/core');
 
+const resolveURL = (url) => url ? data.url(url) : url;
+
 const sidebarNS = ns();
 
 const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
@@ -107,7 +109,7 @@ const Sidebar = Class({
 
           let sbTitle = window.document.getElementById('sidebar-title');
           function onWebPanelSidebarCreated() {
-            if (panelBrowser.contentWindow.location != model.url ||
+            if (panelBrowser.contentWindow.location != resolveURL(model.url) ||
                 sbTitle.value != model.title) {
               return;
             }
@@ -264,6 +266,8 @@ const Sidebar = Class({
 exports.Sidebar = Sidebar;
 
 function validateTitleAndURLCombo(sidebar, title, url) {
+  url = resolveURL(url);
+  
   if (sidebar.title == title && sidebar.url == url) {
     return false;
   }
diff --git a/addon-sdk/source/lib/sdk/ui/sidebar/view.js b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
index 9d595ba0becd..77fbd39d768a 100644
--- a/addon-sdk/source/lib/sdk/ui/sidebar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
@@ -14,11 +14,13 @@ const { models, buttons, views, viewsFor, modelFor } = require('./namespace');
 const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../../window/utils');
 const { setStateFor } = require('../state');
 const { defer } = require('../../core/promise');
-const { isPrivateBrowsingSupported } = require('../../self');
+const { isPrivateBrowsingSupported, data } = require('../../self');
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
 
+const resolveURL = (url) => url ? data.url(url) : url;
+
 function create(window, details) {
   let id = makeID(details.id);
   let { document } = window;
@@ -29,7 +31,7 @@ function create(window, details) {
   let menuitem = document.createElementNS(XUL_NS, 'menuitem');
   menuitem.setAttribute('id', id);
   menuitem.setAttribute('label', details.title);
-  menuitem.setAttribute('sidebarurl', details.sidebarurl);
+  menuitem.setAttribute('sidebarurl', resolveURL(details.sidebarurl));
   menuitem.setAttribute('checked', 'false');
   menuitem.setAttribute('type', 'checkbox');
   menuitem.setAttribute('group', 'sidebar');
@@ -74,6 +76,8 @@ exports.updateTitle = updateTitle;
 function updateURL(sidebar, url) {
   let eleID = makeID(sidebar.id);
 
+  url = resolveURL(url);
+
   for (let window of windows(null, { includePrivate: true })) {
     // update the menuitem
     let mi = window.document.getElementById(eleID);
@@ -111,8 +115,10 @@ function isSidebarShowing(window, sidebar) {
   }
 
   if (sidebarTitle.value == modelFor(sidebar).title) {
+    let url = resolveURL(modelFor(sidebar).url);
+
     // checks if the sidebar is loading
-    if (win.gWebPanelURI == modelFor(sidebar).url) {
+    if (win.gWebPanelURI == url) {
       return true;
     }
 
@@ -122,11 +128,11 @@ function isSidebarShowing(window, sidebar) {
       return false;
     }
 
-    if (ele.getAttribute('cachedurl') ==  modelFor(sidebar).url) {
+    if (ele.getAttribute('cachedurl') == url) {
       return true;
     }
 
-    if (ele && ele.contentWindow && ele.contentWindow.location == modelFor(sidebar).url) {
+    if (ele && ele.contentWindow && ele.contentWindow.location == url) {
       return true;
     }
   }
@@ -154,7 +160,7 @@ function showSidebar(window, sidebar, newURL) {
     let menuitem = window.document.getElementById(makeID(model.id));
     menuitem.setAttribute('checked', true);
 
-    window.openWebPanel(model.title, newURL || model.url);
+    window.openWebPanel(model.title, resolveURL(newURL || model.url));
   }
 
   return promise;
diff --git a/addon-sdk/source/lib/sdk/util/contract.js b/addon-sdk/source/lib/sdk/util/contract.js
index 85a6028d93da..c689ea601d1a 100644
--- a/addon-sdk/source/lib/sdk/util/contract.js
+++ b/addon-sdk/source/lib/sdk/util/contract.js
@@ -9,6 +9,7 @@ module.metadata = {
 };
 
 const { validateOptions: valid } = require("../deprecated/api-utils");
+const method = require("method/core");
 
 // Function takes property validation rules and returns function that given
 // an `options` object will return validated / normalized options back. If
@@ -18,9 +19,9 @@ const { validateOptions: valid } = require("../deprecated/api-utils");
 // property getter and setters can be mixed into prototype. For more details
 // see `properties` function below.
 function contract(rules) {
-  function validator(options) {
-    return valid(options || {}, rules);
-  }
+  const validator = (instance, options) => {
+    return valid(options || instance || {}, rules);
+  };
   validator.rules = rules
   validator.properties = function(modelFor) {
     return properties(modelFor, rules);
@@ -48,4 +49,7 @@ function properties(modelFor, rules) {
   }, {});
   return Object.create(Object.prototype, descriptor);
 }
-exports.properties = properties
+exports.properties = properties;
+
+const validate = method("contract/validate");
+exports.validate = validate;
diff --git a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js b/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
index a661f3098c82..34090e99f6bf 100644
--- a/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
+++ b/addon-sdk/source/lib/sdk/windows/tabs-fennec.js
@@ -19,7 +19,7 @@ const { EventTarget } = require('../event/target');
 const { when: unload } = require('../system/unload');
 const { windowIterator } = require('../deprecated/window-utils');
 const { List, addListItem, removeListItem } = require('../util/list');
-const { isPrivateBrowsingSupported } = require('../self');
+const { isPrivateBrowsingSupported, data } = require('../self');
 const { isTabPBSupported, ignoreWindow } = require('../private-browsing/utils');
 
 const mainWindow = windowNS(browserWindows.activeWindow).window;
@@ -55,7 +55,8 @@ const Tabs = Class({
       console.error(ERR_FENNEC_MSG); // TODO
     }
 
-    let rawTab = openTab(windowNS(activeWin).window, options.url, {
+    let url = options.url ? data.url(options.url) : options.url;
+    let rawTab = openTab(windowNS(activeWin).window, url, {
       inBackground: options.inBackground,
       isPrivate: supportPrivateTabs && options.isPrivate
     });
diff --git a/addon-sdk/source/lib/sdk/windows/tabs-firefox.js b/addon-sdk/source/lib/sdk/windows/tabs-firefox.js
index e4b162c6dff3..639ebd801b1b 100644
--- a/addon-sdk/source/lib/sdk/windows/tabs-firefox.js
+++ b/addon-sdk/source/lib/sdk/windows/tabs-firefox.js
@@ -17,7 +17,7 @@ const { getOwnerWindow, getActiveTab, getTabs,
 const { Options } = require("../tabs/common");
 const { observer: tabsObserver } = require("../tabs/observer");
 const { ignoreWindow } = require("../private-browsing/utils");
-const { when: unload } = require('../system/unload');
+const { when: unload } = require("../system/unload");
 
 const TAB_BROWSER = "tabbrowser";
 
diff --git a/addon-sdk/source/python-lib/cuddlefish/tests/test_licenses.py b/addon-sdk/source/python-lib/cuddlefish/tests/test_licenses.py
index 60b5957b7aba..8acb259e1b95 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_licenses.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_licenses.py
@@ -27,6 +27,9 @@ skip = [
     "packages/api-utils/tests/test-querystring.js", # MIT
     "packages/api-utils/lib/promise.js", # MIT
     "packages/api-utils/tests/test-promise.js", # MIT
+    "examples/actor-repl/README.md", # It's damn readme file
+    "examples/actor-repl/data/codemirror-compressed.js", # MIT
+    "examples/actor-repl/data/codemirror.css", # MIT
     ]
 absskip = [from_sdk_top(os.path.join(*fn.split("/"))) for fn in skip]
 
diff --git a/addon-sdk/source/test/addons/l10n-properties/app-extension/locale/en-GB.properties b/addon-sdk/source/test/addons/l10n-properties/app-extension/locale/en-GB.properties
index 487fceb1d690..d14e6de0b8cf 100644
--- a/addon-sdk/source/test/addons/l10n-properties/app-extension/locale/en-GB.properties
+++ b/addon-sdk/source/test/addons/l10n-properties/app-extension/locale/en-GB.properties
@@ -20,3 +20,9 @@ explicitPlural[other]=other
 # file parser)
 unicodeEscape = \u0020\u0040\u0020
 # this string equals to " @ "
+
+# bug 1033309 plurals with multiple placeholders
+first_identifier[one]=first entry is %s and the second one is %s.
+first_identifier=the entries are %s and %s.
+second_identifier[other]=first entry is %s and the second one is %s.
+third_identifier=first entry is %s and the second one is %s.
diff --git a/addon-sdk/source/test/addons/l10n-properties/main.js b/addon-sdk/source/test/addons/l10n-properties/main.js
index e65b7dc9e8e4..b2ca0b19118e 100644
--- a/addon-sdk/source/test/addons/l10n-properties/main.js
+++ b/addon-sdk/source/test/addons/l10n-properties/main.js
@@ -163,6 +163,20 @@ exports.testEnUsLocaleName = createTest("en-GB", function(assert, loader, done)
                    "other",
                    "PluralForm form can be omitting generic key [i.e. without ...[other] at end of key)");
 
+  assert.equal(_("first_identifier", "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier no count");
+  assert.equal(_("first_identifier", 0, "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier with count = 0");
+  assert.equal(_("first_identifier", 1, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "first_identifier with count = 1");
+  assert.equal(_("first_identifier", 2, "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier with count = 2");
+
+  assert.equal(_("second_identifier", "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with no count");
+  assert.equal(_("second_identifier", 0, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 0");
+  assert.equal(_("second_identifier", 1, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 1");
+  assert.equal(_("second_identifier", 2, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 2");
+
+  assert.equal(_("third_identifier", "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with no count");
+  assert.equal(_("third_identifier", 0, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with count = 0");
+  assert.equal(_("third_identifier", 2, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with count = 2");
+
   done();
 });
 
diff --git a/addon-sdk/source/test/addons/l10n/locale/en-GB.properties b/addon-sdk/source/test/addons/l10n/locale/en-GB.properties
index 487fceb1d690..d14e6de0b8cf 100644
--- a/addon-sdk/source/test/addons/l10n/locale/en-GB.properties
+++ b/addon-sdk/source/test/addons/l10n/locale/en-GB.properties
@@ -20,3 +20,9 @@ explicitPlural[other]=other
 # file parser)
 unicodeEscape = \u0020\u0040\u0020
 # this string equals to " @ "
+
+# bug 1033309 plurals with multiple placeholders
+first_identifier[one]=first entry is %s and the second one is %s.
+first_identifier=the entries are %s and %s.
+second_identifier[other]=first entry is %s and the second one is %s.
+third_identifier=first entry is %s and the second one is %s.
diff --git a/addon-sdk/source/test/addons/l10n/main.js b/addon-sdk/source/test/addons/l10n/main.js
index 5bc1b39764e2..fa266126d980 100644
--- a/addon-sdk/source/test/addons/l10n/main.js
+++ b/addon-sdk/source/test/addons/l10n/main.js
@@ -87,7 +87,6 @@ exports.testExactMatching = createTest("fr-FR", function(assert, loader, done) {
 });
 
 exports.testHtmlLocalization = createTest("en-GB", function(assert, loader, done) {
-
   // Ensure initing html component that watch document creations
   // Note that this module is automatically initialized in
   // cuddlefish.js:Loader.main in regular addons. But it isn't for unit tests.
@@ -165,6 +164,20 @@ exports.testEnUsLocaleName = createTest("en-US", function(assert, loader, done)
                    "other",
                    "PluralForm form can be omitting generic key [i.e. without ...[other] at end of key)");
 
+  assert.equal(_("first_identifier", "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier no count");
+  assert.equal(_("first_identifier", 0, "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier with count = 0");
+  assert.equal(_("first_identifier", 1, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "first_identifier with count = 1");
+  assert.equal(_("first_identifier", 2, "ONE", "TWO"), "the entries are ONE and TWO.", "first_identifier with count = 2");
+
+  assert.equal(_("second_identifier", "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with no count");
+  assert.equal(_("second_identifier", 0, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 0");
+  assert.equal(_("second_identifier", 1, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 1");
+  assert.equal(_("second_identifier", 2, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "second_identifier with count = 2");
+
+  assert.equal(_("third_identifier", "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with no count");
+  assert.equal(_("third_identifier", 0, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with count = 0");
+  assert.equal(_("third_identifier", 2, "ONE", "TWO"), "first entry is ONE and the second one is TWO.", "third_identifier with count = 2");
+
   done();
 });
 
diff --git a/addon-sdk/source/test/addons/privileged-panel/data/index.html b/addon-sdk/source/test/addons/privileged-panel/data/index.html
deleted file mode 100644
index f37c96b2eb32..000000000000
--- a/addon-sdk/source/test/addons/privileged-panel/data/index.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/addon-sdk/source/test/addons/privileged-panel/main.js b/addon-sdk/source/test/addons/privileged-panel/main.js
deleted file mode 100644
index 8992a0a39244..000000000000
--- a/addon-sdk/source/test/addons/privileged-panel/main.js
+++ /dev/null
@@ -1,34 +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";
-
-const app = require("sdk/system/xul-app");
-
-exports["test addon globa"] = app.is("Firefox") ? testAddonGlobal : unsupported;
-
-function testAddonGlobal (assert, done) {
-  const { Panel } = require("sdk/panel")
-  const { data } = require("sdk/self")
-
-  let panel = Panel({
-    contentURL: //"data:text/html,now?",
-                data.url("./index.html"),
-    onMessage: function(message) {
-      assert.pass("got message from panel script");
-      panel.destroy();
-      done();
-    },
-    onError: function(error) {
-      assert.fail(Error("failed to recieve message"));
-      done();
-    }
-  });
-};
-
-function unsupported (assert) {
-  assert.pass("privileged-panel unsupported on platform");
-}
-
-require("sdk/test/runner").runTestsFromModule(module);
diff --git a/addon-sdk/source/test/addons/privileged-panel/package.json b/addon-sdk/source/test/addons/privileged-panel/package.json
deleted file mode 100644
index e35c3a0041ac..000000000000
--- a/addon-sdk/source/test/addons/privileged-panel/package.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "id": "test-privileged-addon"
-}
diff --git a/addon-sdk/source/test/fixtures.js b/addon-sdk/source/test/fixtures.js
index d845a64aa65f..6f91ad16eb64 100644
--- a/addon-sdk/source/test/fixtures.js
+++ b/addon-sdk/source/test/fixtures.js
@@ -2,5 +2,9 @@
  * 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/. */
 
-exports.url = path =>
-  module.uri.substr(0, module.uri.lastIndexOf("/") + 1) + "fixtures/" + path
+const { uri } = module;
+const prefix = uri.substr(0, uri.lastIndexOf("/") + 1) + "fixtures/";
+
+exports.url = (path="") => path && path.contains(":")
+  ? path 
+  : prefix + path.replace(/^\.\//, "");
diff --git a/addon-sdk/source/test/fixtures/border-style.css b/addon-sdk/source/test/fixtures/border-style.css
new file mode 100644
index 000000000000..42acd9fd7880
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/border-style.css
@@ -0,0 +1 @@
+div { border-style: dashed; }
\ No newline at end of file
diff --git a/addon-sdk/source/test/fixtures/css-include-file.css b/addon-sdk/source/test/fixtures/include-file.css
similarity index 100%
rename from addon-sdk/source/test/fixtures/css-include-file.css
rename to addon-sdk/source/test/fixtures/include-file.css
diff --git a/addon-sdk/source/test/fixtures/test-sidebar-addon-global.html b/addon-sdk/source/test/fixtures/test-sidebar-addon-global.html
index cfa073959c30..721add27896a 100644
--- a/addon-sdk/source/test/fixtures/test-sidebar-addon-global.html
+++ b/addon-sdk/source/test/fixtures/test-sidebar-addon-global.html
@@ -1,10 +1,12 @@
 
 SIDEBAR TEST
diff --git a/addon-sdk/source/test/pagemod-test-helpers.js b/addon-sdk/source/test/pagemod-test-helpers.js
index 132474fe3c94..9215c75a5cce 100644
--- a/addon-sdk/source/test/pagemod-test-helpers.js
+++ b/addon-sdk/source/test/pagemod-test-helpers.js
@@ -9,6 +9,8 @@ const timer = require("sdk/timers");
 const xulApp = require("sdk/system/xul-app");
 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");
 
 /**
  * A helper function that creates a PageMod, then opens the specified URL
@@ -31,7 +33,13 @@ exports.testPageMod = function testPageMod(assert, done, testURL, pageModOptions
     return null;
   }
 
-  let loader = Loader(module);
+  let loader = Loader(module, null, null, {
+    modules: {
+      "sdk/self": merge({}, self, {
+        data: merge({}, self.data, require("./fixtures"))
+      })
+    }
+  });
   let pageMod = loader.require("sdk/page-mod");
 
   var pageMods = [new pageMod.PageMod(opts) for each(opts in pageModOptions)];
diff --git a/addon-sdk/source/test/test-content-loader.js b/addon-sdk/source/test/test-content-loader.js
index 7bd455b97769..00b0ab701b61 100644
--- a/addon-sdk/source/test/test-content-loader.js
+++ b/addon-sdk/source/test/test-content-loader.js
@@ -12,13 +12,13 @@ exports['test:contentURL'] = function(assert) {
   let loader = Loader(),
       value, emitted = 0, changes = 0;
 
-  assert.throws(
-    function() loader.contentURL = 4,
+  assert.throws(() =>
+    loader.contentURL = 4,
     /The `contentURL` option must be a valid URL./,
     'Must throw an exception if `contentURL` is not URL.'
   );
- assert.throws(
-    function() loader.contentURL = { toString: function() 'Oops' },
+ assert.throws(() =>
+    loader.contentURL = { toString: function() 'Oops' },
     /The `contentURL` option must be a valid URL./,
     'Must throw an exception if `contentURL` is not URL.'
   );
@@ -78,6 +78,24 @@ exports['test:contentURL'] = function(assert) {
     'must not emit `propertyChange` if same value is set'
   );
 
+  loader.contentURL = value = './index.html';
+  assert.equal(
+    value,
+    '' + loader.contentURL,
+    'value must be set'
+  );
+  assert.equal(
+    ++ changes,
+    emitted,
+    'had to emit `propertyChange`'
+  );
+  loader.contentURL = value;
+  assert.equal(
+    changes,
+    emitted,
+    'must not emit `propertyChange` if same value is set'
+  );
+
   loader.removeListener('propertyChange', listener);
   loader.contentURL = value = 'about:blank';
   assert.equal(
@@ -133,39 +151,37 @@ exports['test:contentScriptWhen'] = function(assert) {
 
 exports['test:contentScript'] = function(assert) {
   let loader = Loader(), value;
+
   assert.equal(
     null,
     loader.contentScript,
     '`contentScript` defaults to `null`'
   );
+
   loader.contentScript = value = 'let test = {};';
   assert.equal(
     value,
     loader.contentScript
   );
-  try {
-    loader.contentScript = { 1: value }
-    test.fail('must throw when wrong value is set');
-  } catch(e) {
-    assert.equal(
-      'The `contentScript` option must be a string or an array of strings.',
-      e.message
-    );
-  }
-  try {
-    loader.contentScript = ['oue', 2]
-    test.fail('must throw when wrong value is set');
-  } catch(e) {
-    assert.equal(
-      'The `contentScript` option must be a string or an array of strings.',
-      e.message
-    );
-  }
+
+  assert.throws(() =>
+    loader.contentScript = { 1: value },
+    /The `contentScript` option must be a string or an array of strings/,
+    'must throw when wrong value is set'
+  );
+
+  assert.throws(() =>
+    loader.contentScript = ['oue', 2],
+    /The `contentScript` option must be a string or an array of strings/,
+    'must throw when wrong value is set'
+  );
+
   loader.contentScript = undefined;
   assert.equal(
     null,
     loader.contentScript
   );
+
   loader.contentScript = value = ["1;", "2;"];
   assert.equal(
     value,
@@ -185,36 +201,25 @@ exports['test:contentScriptFile'] = function(assert) {
     value,
     loader.contentScriptFile
   );
-  try {
-    loader.contentScriptFile = { 1: uri }
-    test.fail('must throw when wrong value is set');
-  } catch(e) {
-    assert.equal(
-      'The `contentScriptFile` option must be a local URL or an array of URLs.',
-      e.message
-    );
-  }
 
-  try {
-    loader.contentScriptFile = [ 'oue', uri ]
-    test.fail('must throw when wrong value is set');
-  } catch(e) {
-    assert.equal(
-      'The `contentScriptFile` option must be a local URL or an array of URLs.',
-      e.message
-    );
-  }
+  assert.throws(() =>
+    loader.contentScriptFile = { 1: uri },
+    /The `contentScriptFile` option must be a local URL or an array of URLs/,
+    'must throw when wrong value is set'
+  );
+
+  assert.throws(() =>
+    loader.contentScriptFile = [ 'oue', uri ],
+    /The `contentScriptFile` option must be a local URL or an array of URLs/,
+    'must throw when wrong value is set'
+  );
 
   let data = 'data:text/html,test';
-  try {
-    loader.contentScriptFile = [ { toString: () => data } ];
-    test.fail('must throw when non-URL object is set');
-  } catch(e) {
-    assert.equal(
-      'The `contentScriptFile` option must be a local URL or an array of URLs.',
-      e.message
-    );
-  }
+  assert.throws(() =>
+    loader.contentScriptFile = [ { toString: () => data } ],
+    /The `contentScriptFile` option must be a local URL or an array of URLs/,
+    'must throw when wrong value is set'
+  );
 
   loader.contentScriptFile = new URL(data);
   assert.ok(
@@ -222,11 +227,18 @@ exports['test:contentScriptFile'] = function(assert) {
     'must be able to set `contentScriptFile` to an instance of URL'
   );
   assert.equal(
-    data, 
+    data,
     loader.contentScriptFile.toString(),
     'setting `contentScriptFile` to an instance of URL should preserve the url'
   );
 
+  loader.contentScriptFile = './index.html';
+  assert.equal(
+    './index.html',
+    loader.contentScriptFile,
+    'setting `contentScriptFile` to relative path is allowed'
+  );
+
   loader.contentScriptFile = undefined;
   assert.equal(
     null,
diff --git a/addon-sdk/source/test/test-context-menu.js b/addon-sdk/source/test/test-context-menu.js
index 7eafc8b69164..6b732bc5b0b4 100644
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -879,6 +879,10 @@ exports.testContentContextMatchString = function (assert, done) {
 exports.testContentScriptFile = function (assert, done) {
   let test = new TestHelper(assert, done);
   let loader = test.newLoader();
+  let { defer, all } = require("sdk/core/promise");
+  let itemScript = [defer(), defer()];
+  let menuShown = defer();
+  let menuPromises = itemScript.concat(menuShown).map(({promise}) => promise);
 
   // Reject remote files
   assert.throws(function() {
@@ -887,20 +891,37 @@ exports.testContentScriptFile = function (assert, done) {
         contentScriptFile: "http://mozilla.com/context-menu.js"
       });
     },
-    new RegExp("The 'contentScriptFile' option must be a local file URL " +
-    "or an array of local file URLs."),
+    /The `contentScriptFile` option must be a local URL or an array of URLs/,
     "Item throws when contentScriptFile is a remote URL");
 
   // But accept files from data folder
   let item = new loader.cm.Item({
     label: "item",
-    contentScriptFile: data.url("test-context-menu.js")
+    contentScriptFile: data.url("test-contentScriptFile.js"),
+    onMessage: (message) => {
+      assert.equal(message, "msg from contentScriptFile",
+        "contentScriptFile loaded with absolute url");
+      itemScript[0].resolve();
+    }
   });
 
-  test.showMenu(null, function (popup) {
-    test.checkMenu([item], [], []);
-    test.done();
+  let item2 = new loader.cm.Item({
+    label: "item2",
+    contentScriptFile: "./test-contentScriptFile.js",
+    onMessage: (message) => {
+      assert.equal(message, "msg from contentScriptFile",
+        "contentScriptFile loaded with relative url");
+      itemScript[1].resolve();
+    }
   });
+  console.log(item.contentScriptFile, item2.contentScriptFile);
+
+  test.showMenu(null, function (popup) {
+    test.checkMenu([item, item2], [], []);
+    menuShown.resolve();
+  });
+
+  all(menuPromises).then(() => test.done());
 };
 
 
@@ -3944,7 +3965,15 @@ TestHelper.prototype = {
   // function that unloads the loader and associated resources.
   newLoader: function () {
     const self = this;
-    let loader = Loader(module);
+    const selfModule = require('sdk/self');
+    let loader = Loader(module, null, null, {
+      modules: {
+        "sdk/self": merge({}, selfModule, {
+          data: merge({}, selfModule.data, require("./fixtures"))
+        })
+      }
+    });
+
     let wrapper = {
       loader: loader,
       cm: loader.require("sdk/context-menu"),
diff --git a/addon-sdk/source/test/test-dev-panel.js b/addon-sdk/source/test/test-dev-panel.js
new file mode 100644
index 000000000000..b3cc82d5a1eb
--- /dev/null
+++ b/addon-sdk/source/test/test-dev-panel.js
@@ -0,0 +1,236 @@
+/* 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 = {
+  "engines": {
+    "Firefox": "*"
+  }
+};
+
+const { Tool } = require("dev/toolbox");
+const { Panel } = require("dev/panel");
+const { Class } = require("sdk/core/heritage");
+const { openToolbox, closeToolbox, getCurrentPanel } = require("dev/utils");
+const { MessageChannel } = require("sdk/messaging");
+const { when } = require("sdk/dom/events");
+
+const iconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAKQWlDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU9kWh8+9N73QEiIgJfQaegkg0jtIFQRRiUmAUAKGhCZ2RAVGFBEpVmRUwAFHhyJjRRQLg4Ji1wnyEFDGwVFEReXdjGsJ7601896a/cdZ39nnt9fZZ+9917oAUPyCBMJ0WAGANKFYFO7rwVwSE8vE9wIYEAEOWAHA4WZmBEf4RALU/L09mZmoSMaz9u4ugGS72yy/UCZz1v9/kSI3QyQGAApF1TY8fiYX5QKUU7PFGTL/BMr0lSkyhjEyFqEJoqwi48SvbPan5iu7yZiXJuShGlnOGbw0noy7UN6aJeGjjAShXJgl4GejfAdlvVRJmgDl9yjT0/icTAAwFJlfzOcmoWyJMkUUGe6J8gIACJTEObxyDov5OWieAHimZ+SKBIlJYqYR15hp5ejIZvrxs1P5YjErlMNN4Yh4TM/0tAyOMBeAr2+WRQElWW2ZaJHtrRzt7VnW5mj5v9nfHn5T/T3IevtV8Sbsz55BjJ5Z32zsrC+9FgD2JFqbHbO+lVUAtG0GQOXhrE/vIADyBQC03pzzHoZsXpLE4gwnC4vs7GxzAZ9rLivoN/ufgm/Kv4Y595nL7vtWO6YXP4EjSRUzZUXlpqemS0TMzAwOl89k/fcQ/+PAOWnNycMsnJ/AF/GF6FVR6JQJhIlou4U8gViQLmQKhH/V4X8YNicHGX6daxRodV8AfYU5ULhJB8hvPQBDIwMkbj96An3rWxAxCsi+vGitka9zjzJ6/uf6Hwtcim7hTEEiU+b2DI9kciWiLBmj34RswQISkAd0oAo0gS4wAixgDRyAM3AD3iAAhIBIEAOWAy5IAmlABLJBPtgACkEx2AF2g2pwANSBetAEToI2cAZcBFfADXALDIBHQAqGwUswAd6BaQiC8BAVokGqkBakD5lC1hAbWgh5Q0FQOBQDxUOJkBCSQPnQJqgYKoOqoUNQPfQjdBq6CF2D+qAH0CA0Bv0BfYQRmALTYQ3YALaA2bA7HAhHwsvgRHgVnAcXwNvhSrgWPg63whfhG/AALIVfwpMIQMgIA9FGWAgb8URCkFgkAREha5EipAKpRZqQDqQbuY1IkXHkAwaHoWGYGBbGGeOHWYzhYlZh1mJKMNWYY5hWTBfmNmYQM4H5gqVi1bGmWCesP3YJNhGbjS3EVmCPYFuwl7ED2GHsOxwOx8AZ4hxwfrgYXDJuNa4Etw/XjLuA68MN4SbxeLwq3hTvgg/Bc/BifCG+Cn8cfx7fjx/GvyeQCVoEa4IPIZYgJGwkVBAaCOcI/YQRwjRRgahPdCKGEHnEXGIpsY7YQbxJHCZOkxRJhiQXUiQpmbSBVElqIl0mPSa9IZPJOmRHchhZQF5PriSfIF8lD5I/UJQoJhRPShxFQtlOOUq5QHlAeUOlUg2obtRYqpi6nVpPvUR9Sn0vR5Mzl/OX48mtk6uRa5Xrl3slT5TXl3eXXy6fJ18hf0r+pvy4AlHBQMFTgaOwVqFG4bTCPYVJRZqilWKIYppiiWKD4jXFUSW8koGStxJPqUDpsNIlpSEaQtOledK4tE20Otpl2jAdRzek+9OT6cX0H+i99AllJWVb5SjlHOUa5bPKUgbCMGD4M1IZpYyTjLuMj/M05rnP48/bNq9pXv+8KZX5Km4qfJUilWaVAZWPqkxVb9UU1Z2qbapP1DBqJmphatlq+9Uuq43Pp893ns+dXzT/5PyH6rC6iXq4+mr1w+o96pMamhq+GhkaVRqXNMY1GZpumsma5ZrnNMe0aFoLtQRa5VrntV4wlZnuzFRmJbOLOaGtru2nLdE+pN2rPa1jqLNYZ6NOs84TXZIuWzdBt1y3U3dCT0svWC9fr1HvoT5Rn62fpL9Hv1t/ysDQINpgi0GbwaihiqG/YZ5ho+FjI6qRq9Eqo1qjO8Y4Y7ZxivE+41smsImdSZJJjclNU9jU3lRgus+0zwxr5mgmNKs1u8eisNxZWaxG1qA5wzzIfKN5m/krCz2LWIudFt0WXyztLFMt6ywfWSlZBVhttOqw+sPaxJprXWN9x4Zq42Ozzqbd5rWtqS3fdr/tfTuaXbDdFrtOu8/2DvYi+yb7MQc9h3iHvQ732HR2KLuEfdUR6+jhuM7xjOMHJ3snsdNJp9+dWc4pzg3OowsMF/AX1C0YctFx4bgccpEuZC6MX3hwodRV25XjWuv6zE3Xjed2xG3E3dg92f24+ysPSw+RR4vHlKeT5xrPC16Il69XkVevt5L3Yu9q76c+Oj6JPo0+E752vqt9L/hh/QL9dvrd89fw5/rX+08EOASsCegKpARGBFYHPgsyCRIFdQTDwQHBu4IfL9JfJFzUFgJC/EN2hTwJNQxdFfpzGC4sNKwm7Hm4VXh+eHcELWJFREPEu0iPyNLIR4uNFksWd0bJR8VF1UdNRXtFl0VLl1gsWbPkRoxajCCmPRYfGxV7JHZyqffS3UuH4+ziCuPuLjNclrPs2nK15anLz66QX8FZcSoeGx8d3xD/iRPCqeVMrvRfuXflBNeTu4f7kufGK+eN8V34ZfyRBJeEsoTRRJfEXYljSa5JFUnjAk9BteB1sl/ygeSplJCUoykzqdGpzWmEtPi000IlYYqwK10zPSe9L8M0ozBDuspp1e5VE6JA0ZFMKHNZZruYjv5M9UiMJJslg1kLs2qy3mdHZZ/KUcwR5vTkmuRuyx3J88n7fjVmNXd1Z752/ob8wTXuaw6thdauXNu5Tnddwbrh9b7rj20gbUjZ8MtGy41lG99uit7UUaBRsL5gaLPv5sZCuUJR4b0tzlsObMVsFWzt3WazrWrblyJe0fViy+KK4k8l3JLr31l9V/ndzPaE7b2l9qX7d+B2CHfc3em681iZYlle2dCu4F2t5czyovK3u1fsvlZhW3FgD2mPZI+0MqiyvUqvakfVp+qk6oEaj5rmvep7t+2d2sfb17/fbX/TAY0DxQc+HhQcvH/I91BrrUFtxWHc4azDz+ui6rq/Z39ff0TtSPGRz0eFR6XHwo911TvU1zeoN5Q2wo2SxrHjccdv/eD1Q3sTq+lQM6O5+AQ4ITnx4sf4H++eDDzZeYp9qukn/Z/2ttBailqh1tzWibakNml7THvf6YDTnR3OHS0/m/989Iz2mZqzymdLz5HOFZybOZ93fvJCxoXxi4kXhzpXdD66tOTSna6wrt7LgZevXvG5cqnbvfv8VZerZ645XTt9nX297Yb9jdYeu56WX+x+aem172296XCz/ZbjrY6+BX3n+l37L972un3ljv+dGwOLBvruLr57/17cPel93v3RB6kPXj/Mejj9aP1j7OOiJwpPKp6qP6391fjXZqm99Oyg12DPs4hnj4a4Qy//lfmvT8MFz6nPK0a0RupHrUfPjPmM3Xqx9MXwy4yX0+OFvyn+tveV0auffnf7vWdiycTwa9HrmT9K3qi+OfrW9m3nZOjk03dp76anit6rvj/2gf2h+2P0x5Hp7E/4T5WfjT93fAn88ngmbWbm3/eE8/syOll+AAAACXBIWXMAAAsTAAALEwEAmpwYAAADqmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPnhtcC5kaWQ6M0ExNEY4NjZBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0YW5jZUlEPnhtcC5paWQ6M0ExNEY4NjNBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3N0UmVmOmluc3RhbmNlSUQ+CiAgICAgICAgICAgIDxzdFJlZjpkb2N1bWVudElEPnhtcC5kaWQ6M0ExNEY4NjRBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3N0UmVmOmRvY3VtZW50SUQ+CiAgICAgICAgIDwveG1wTU06RGVyaXZlZEZyb20+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6M0ExNEY4NjVBNkU1MTFFMTlGMkFGQ0QyNTUyN0VDRjY8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2g8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ChetDDYAAACaSURBVEgNY2AYboAR3UNnzpx5DxQTQBP/YGJiIogmBuYSq54Ji2Z0S0BKsInBtGKTwxDDZhHMAKrSdLOIqq7GZxjj+fPnBf7+/bseqMgBn0IK5A4wMzMHMtHYEpD7HEB2gOLIAcSjMXCgW2IYtYjsqBwNutGgg4fAaGKABwWpDLoG3QFSXUeG+gNMoEoJqJGWloErPjIcR54WALqPHeiJgl15AAAAAElFTkSuQmCC";
+const makeHTML = fn =>
+  "data:text/html;charset=utf-8,";
+
+
+const test = function(unit) {
+  return function*(assert) {
+    assert.isRendered = (panel, toolbox) => {
+      const doc = toolbox.doc;
+      assert.ok(doc.querySelector("[value='" + panel.label + "']"),
+                "panel.label is found in the developer toolbox DOM");
+      assert.ok(doc.querySelector("[tooltiptext='" + panel.tooltip + "']"),
+                "panel.tooltip is found in the developer toolbox DOM");
+
+      assert.ok(doc.querySelector("#toolbox-panel-" + panel.id),
+                "toolbar panel with a matching id is present");
+    };
+
+
+    yield* unit(assert);
+  };
+};
+
+exports["test Panel API"] = test(function*(assert) {
+  const MyPanel = Class({
+    extends: Panel,
+    label: "test panel",
+    tooltip: "my test panel",
+    icon: iconURI,
+    url: makeHTML(() => {
+      document.documentElement.innerHTML = "hello world";
+    }),
+    setup: function({debuggee}) {
+      this.debuggee = debuggee;
+      assert.equal(this.readyState, "uninitialized",
+                   "at construction time panel document is not inited");
+    },
+    dispose: function() {
+      delete this.debuggee;
+    }
+  });
+  assert.ok(MyPanel, "panel is defined");
+
+  const myTool = new Tool({
+    panels: {
+      myPanel: MyPanel
+    }
+  });
+  assert.ok(myTool, "tool is defined");
+
+
+  var toolbox = yield openToolbox(MyPanel);
+  var panel = yield getCurrentPanel(toolbox);
+  assert.ok(panel instanceof MyPanel, "is instance of MyPanel");
+
+  assert.isRendered(panel, toolbox);
+
+  if (panel.readyState === "uninitialized") {
+    yield panel.ready();
+    assert.equal(panel.readyState, "interactive", "panel is ready");
+  }
+
+  yield panel.loaded();
+  assert.equal(panel.readyState, "complete", "panel is loaded");
+
+  yield closeToolbox();
+
+  assert.equal(panel.readyState, "destroyed", "panel is destroyed");
+});
+
+
+exports["test Panel communication"] = test(function*(assert) {
+  const MyPanel = Class({
+    extends: Panel,
+    label: "communication",
+    tooltip: "test palen communication",
+    icon: iconURI,
+    url: makeHTML(() => {
+      window.addEventListener("message", event => {
+        if (event.source === window) {
+          var port = event.ports[0];
+          port.start();
+          port.postMessage("ping");;
+          port.onmessage = (event) => {
+            if (event.data === "pong") {
+              port.postMessage("bye");
+              port.close();
+            }
+          };
+        }
+      });
+    }),
+    dispose: function() {
+      delete this.port;
+    }
+  });
+
+
+  const myTool = new Tool({
+    panels: {
+      myPanel: MyPanel
+    }
+  });
+
+
+  const toolbox = yield openToolbox(MyPanel);
+  const panel = yield getCurrentPanel(toolbox);
+  assert.ok(panel instanceof MyPanel, "is instance of MyPanel");
+
+  assert.isRendered(panel, toolbox);
+
+  yield panel.ready();
+  const { port1, port2 } = new MessageChannel();
+  panel.port = port1;
+  panel.postMessage("connect", [port2]);
+  panel.port.start();
+
+  const ping = yield when(panel.port, "message");
+
+  assert.equal(ping.data, "ping", "received ping from panel doc");
+
+  panel.port.postMessage("pong");
+
+  const bye = yield when(panel.port, "message");
+
+  assert.equal(bye.data, "bye", "received bye from panel doc");
+
+  panel.port.close();
+
+  yield closeToolbox();
+
+  assert.equal(panel.readyState, "destroyed", "panel is destroyed");
+});
+
+exports["test communication with debuggee"] = test(function*(assert) {
+  const MyPanel = Class({
+    extends: Panel,
+    label: "debuggee",
+    tooltip: "test debuggee",
+    icon: iconURI,
+    url: makeHTML(() => {
+      window.addEventListener("message", event => {
+        if (event.source === window) {
+          var debuggee = event.ports[0];
+          var port = event.ports[1];
+          debuggee.start();
+          port.start();
+
+
+          debuggee.onmessage = (event) => {
+            port.postMessage(event.data);
+          };
+          port.onmessage = (event) => {
+            debuggee.postMessage(event.data);
+          };
+        }
+      });
+    }),
+    setup: function({debuggee}) {
+      this.debuggee = debuggee;
+    },
+    onReady: function() {
+      const { port1, port2 } = new MessageChannel();
+      this.port = port1;
+      this.port.start();
+      this.debuggee.start();
+
+      this.postMessage("connect", [this.debuggee, port2]);
+    },
+    dispose: function() {
+      this.port.close();
+      this.debuggee.close();
+
+      delete this.port;
+      delete this.debuggee;
+    }
+  });
+
+
+  const myTool = new Tool({
+    panels: {
+      myPanel: MyPanel
+    }
+  });
+
+
+  const toolbox = yield openToolbox(MyPanel);
+  const panel = yield getCurrentPanel(toolbox);
+  assert.ok(panel instanceof MyPanel, "is instance of MyPanel");
+
+  assert.isRendered(panel, toolbox);
+
+  yield panel.ready();
+  const intro = yield when(panel.port, "message");
+
+  assert.equal(intro.data.from, "root", "intro message from root");
+
+  panel.port.postMessage({
+    to: "root",
+    type: "echo",
+    text: "ping"
+  });
+
+  const pong = yield when(panel.port, "message");
+
+  assert.deepEqual(pong.data, {
+    to: "root",
+    from: "root",
+    type: "echo",
+    text: "ping"
+  }, "received message back from root");
+
+  yield closeToolbox();
+
+  assert.equal(panel.readyState, "destroyed", "panel is destroyed");
+});
+
+require("test").run(exports);
diff --git a/addon-sdk/source/test/test-l10n-plural-rules.js b/addon-sdk/source/test/test-l10n-plural-rules.js
index 6c56ec49d594..953d977a467b 100644
--- a/addon-sdk/source/test/test-l10n-plural-rules.js
+++ b/addon-sdk/source/test/test-l10n-plural-rules.js
@@ -1,6 +1,7 @@
 /* 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 { getRulesForLocale } = require("sdk/l10n/plural-rules");
 
diff --git a/addon-sdk/source/test/test-page-mod.js b/addon-sdk/source/test/test-page-mod.js
index 0d43cb7269a7..0755d03db393 100644
--- a/addon-sdk/source/test/test-page-mod.js
+++ b/addon-sdk/source/test/test-page-mod.js
@@ -1028,20 +1028,20 @@ exports.testPageModCss = function(assert, done) {
     'data:text/html;charset=utf-8,
css test
', [{ include: ["*", "data:*"], contentStyle: "div { height: 100px; }", - contentStyleFile: data.url("css-include-file.css") + 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(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(); } ); @@ -1165,6 +1165,21 @@ exports.testPageModCssAutomaticDestroy = function(assert, 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"); + } + }], + (win, done) => done() + ); + +}; exports.testPageModTimeout = function(assert, done) { let tab = null diff --git a/addon-sdk/source/test/test-page-worker.js b/addon-sdk/source/test/test-page-worker.js index 8cc0db09cc94..bb603edd1003 100644 --- a/addon-sdk/source/test/test-page-worker.js +++ b/addon-sdk/source/test/test-page-worker.js @@ -268,6 +268,33 @@ exports.testLoadContentPage = function(assert, done) { }); } +exports.testLoadContentPageRelativePath = function(assert, done) { + const self = require("sdk/self"); + const { merge } = require("sdk/util/object"); + + let loader = Loader(module, null, null, { + modules: { + "sdk/self": merge({}, self, { + data: merge({}, self.data, fixtures) + }) + } + }); + + let page = loader.require("sdk/page-worker").Page({ + onMessage: function(message) { + // The message is an array whose first item is the test method to call + // and the rest of whose items are arguments to pass it. + let msg = message.shift(); + if (msg == "done") + return done(); + assert[msg].apply(assert, message); + }, + contentURL: "./test-page-worker.html", + contentScriptFile: "./test-page-worker.js", + contentScriptWhen: "ready" + }); +} + exports.testAllowScriptDefault = function(assert, done) { let page = Page({ onMessage: function(message) { diff --git a/addon-sdk/source/test/test-panel.js b/addon-sdk/source/test/test-panel.js index 289c3ce28ce4..7a4a233fe4e3 100644 --- a/addon-sdk/source/test/test-panel.js +++ b/addon-sdk/source/test/test-panel.js @@ -27,7 +27,6 @@ const { wait } = require('./event/helpers'); const fixtures = require('./fixtures') const SVG_URL = fixtures.url('mofo_logo.SVG'); -const CSS_URL = fixtures.url('css-include-file.css'); const Isolate = fn => '(' + fn + ')()'; @@ -979,7 +978,16 @@ exports['test panel can be constructed without any arguments'] = function (asser }; exports['test panel CSS'] = function(assert, done) { - const loader = Loader(module); + const { merge } = require("sdk/util/object"); + + let loader = Loader(module, null, null, { + modules: { + "sdk/self": merge({}, self, { + data: merge({}, self.data, fixtures) + }) + } + }); + const { Panel } = loader.require('sdk/panel'); const { getActiveView } = loader.require('sdk/view/core'); @@ -991,13 +999,19 @@ exports['test panel CSS'] = function(assert, done) { contentURL: 'data:text/html;charset=utf-8,' + '
css test
', contentStyle: 'div { height: 100px; }', - contentStyleFile: CSS_URL, + contentStyleFile: [fixtures.url("include-file.css"), "./border-style.css"], onShow: () => { - ready(getContentWindow(panel)).then(({ document }) => { + ready(getContentWindow(panel)).then(({ window, document }) => { let div = document.querySelector('div'); - assert.equal(div.clientHeight, 100, 'Panel contentStyle worked'); - assert.equal(div.offsetHeight, 120, 'Panel contentStyleFile worked'); + assert.equal(div.clientHeight, 100, + "Panel contentStyle worked"); + + assert.equal(div.offsetHeight, 120, + "Panel contentStyleFile worked"); + + assert.equal(window.getComputedStyle(div).borderTopStyle, "dashed", + "Panel contentStyleFile with relative path worked"); loader.unload(); done(); @@ -1008,6 +1022,53 @@ exports['test panel CSS'] = function(assert, done) { panel.show(); }; +exports['test panel contentScriptFile'] = function(assert, done) { + const { merge } = require("sdk/util/object"); + + let loader = Loader(module, null, null, { + modules: { + "sdk/self": merge({}, self, { + data: merge({}, self.data, {url: fixtures.url}) + }) + } + }); + + const { Panel } = loader.require('sdk/panel'); + const { getActiveView } = loader.require('sdk/view/core'); + + const getContentWindow = panel => + getActiveView(panel).querySelector('iframe').contentWindow; + + let whenMessage = defer(); + let whenShown = defer(); + + let panel = Panel({ + contentURL: './test.html', + contentScriptFile: "./test-contentScriptFile.js", + onMessage: (message) => { + assert.equal(message, "msg from contentScriptFile", + "Panel contentScriptFile with relative path worked"); + + whenMessage.resolve(); + }, + onShow: () => { + ready(getContentWindow(panel)).then(({ document }) => { + assert.equal(document.title, 'foo', + "Panel contentURL with relative path worked"); + + whenShown.resolve(); + }); + } + }); + + all([whenMessage.promise, whenShown.promise]). + then(loader.unload). + then(done, assert.fail); + + panel.show(); +}; + + exports['test panel CSS list'] = function(assert, done) { const loader = Loader(module); const { Panel } = loader.require('sdk/panel'); @@ -1186,6 +1247,36 @@ exports['test panel contextmenu disabled'] = function*(assert) { assert.equal(contextmenu.state, 'closed', 'contextmenu was never open'); + loader.unload(); +} + +exports["test panel addon global object"] = function*(assert) { + const { merge } = require("sdk/util/object"); + + let loader = Loader(module, null, null, { + modules: { + "sdk/self": merge({}, self, { + data: merge({}, self.data, {url: fixtures.url}) + }) + } + }); + + const { Panel } = loader.require('sdk/panel'); + + let panel = Panel({ + contentURL: "./test-trusted-document.html" + }); + + panel.show(); + + yield wait(panel, "show"); + + panel.port.emit('addon-to-document', 'ok'); + + yield wait(panel.port, "document-to-addon"); + + assert.pass("Received an event from the document"); + loader.unload(); } diff --git a/addon-sdk/source/test/test-tabs-common.js b/addon-sdk/source/test/test-tabs-common.js index ff6796380973..48b5c4963a48 100644 --- a/addon-sdk/source/test/test-tabs-common.js +++ b/addon-sdk/source/test/test-tabs-common.js @@ -40,6 +40,38 @@ exports.testTabCounts = function(assert, done) { }); }; +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, require("./fixtures")) + }) + } + }); + + 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); + } + }); + } + }); +}; // TEST: tabs.activeTab getter exports.testActiveTab_getter = function(assert, done) { diff --git a/addon-sdk/source/test/test-ui-sidebar.js b/addon-sdk/source/test/test-ui-sidebar.js index c3b01e6f256c..f0cd6385426d 100644 --- a/addon-sdk/source/test/test-ui-sidebar.js +++ b/addon-sdk/source/test/test-ui-sidebar.js @@ -370,6 +370,48 @@ exports.testSidebarUnload = function(assert, done) { assert.pass('showing the sidebar'); } +exports.testRelativeURL = 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, require('./fixtures')) + }) + } + }); + + const { Sidebar } = loader.require('sdk/ui/sidebar'); + + let testName = 'testRelativeURL'; + let sidebar = Sidebar({ + id: testName, + title: testName, + url: './test-sidebar-addon-global.html' + }); + + sidebar.on('attach', function(worker) { + assert.pass('sidebar was attached'); + assert.ok(!!worker, 'attach event has worker'); + + worker.port.once('Y', function(msg) { + assert.equal(msg, '1', 'got event from worker'); + + worker.port.on('X', function(msg) { + assert.equal(msg, '123', 'the final message is correct'); + + sidebar.destroy(); + + done(); + }); + worker.port.emit('X', msg + '2'); + }) + }); + + sidebar.show(); +} + exports.testRemoteContent = function(assert) { const { Sidebar } = require('sdk/ui/sidebar'); let testName = 'testRemoteContent'; diff --git a/addon-sdk/source/test/test-widget.js b/addon-sdk/source/test/test-widget.js index 56d409787be3..10666875b358 100644 --- a/addon-sdk/source/test/test-widget.js +++ b/addon-sdk/source/test/test-widget.js @@ -36,8 +36,6 @@ function openNewWindowTab(url, options) { if (options.onLoad) { options.onLoad({ target: { defaultView: window } }) } - - return newTab; }); } @@ -538,7 +536,7 @@ exports.testConstructor = function(assert, done) { assert.equal(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy"); close(browserWindow).then(doneTest); - }}); + }}).catch(assert.fail); }); // test window closing @@ -634,7 +632,7 @@ exports.testConstructor = function(assert, done) { browserWindow.setToolbarVisibility(container(), true); close(browserWindow2).then(doneTest); - }}); + }}).catch(assert.fail); }); } @@ -1179,7 +1177,7 @@ exports.testReinsertion = function(assert, done) { loader.unload(); done(); }); - }}); + }}).catch(assert.fail); }; exports.testWideWidget = function testWideWidget(assert) { diff --git a/addon-sdk/source/test/windows/test-firefox-windows.js b/addon-sdk/source/test/windows/test-firefox-windows.js index 49f63625bc35..0e873268ba24 100644 --- a/addon-sdk/source/test/windows/test-firefox-windows.js +++ b/addon-sdk/source/test/windows/test-firefox-windows.js @@ -42,6 +42,33 @@ exports.testOpenAndCloseWindow = function(assert, done) { }); }; +exports.testOpenRelativePathWindow = function(assert, done) { + assert.equal(browserWindows.length, 1, "Only one window open"); + + 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, require("./../fixtures")) + }) + } + }); + + loader.require("sdk/windows").browserWindows.open({ + url: "./test.html", + onOpen: (window) => { + window.tabs.activeTab.once("ready", (tab) => { + assert.equal(tab.title, "foo", + "tab opened a document with relative path"); + + window.close(done); + }); + } + }) +} + exports.testAutomaticDestroy = function(assert, done) { let windows = browserWindows;