diff --git a/local-cli/server/middleware/heapCapture/heapCapture.html b/local-cli/server/middleware/heapCapture/heapCapture.html
index 6cfbe840c..af900934a 100644
--- a/local-cli/server/middleware/heapCapture/heapCapture.html
+++ b/local-cli/server/middleware/heapCapture/heapCapture.html
@@ -3,8 +3,8 @@
JSC Heap Capture
-
-
+
+
diff --git a/local-cli/server/middleware/heapCapture/out/aggrow.js b/local-cli/server/middleware/heapCapture/out/aggrow.js
index d980d073e..e5eec1099 100644
--- a/local-cli/server/middleware/heapCapture/out/aggrow.js
+++ b/local-cli/server/middleware/heapCapture/out/aggrow.js
@@ -16,7 +16,7 @@
// pivot around frames in the middle of a stack by callers / callees
// graphing?
-function stringInterner(){// eslint-disable-line no-unused-vars
+function StringInterner(){// eslint-disable-line no-unused-vars
var strings=[];
var ids={};
return{
@@ -37,20 +37,16 @@ return strings[id];
}
-function stackData(stackIdMap,maxDepth){// eslint-disable-line no-unused-vars
-return{
-maxDepth:maxDepth,
-get:function getStack(id){
-return stackIdMap[id];
-}};
-
-}
-
-function stackRegistry(){// eslint-disable-line no-unused-vars
+function StackRegistry(){// eslint-disable-line no-unused-vars
return{
root:{id:0},
nodeCount:1,
+maxDepth:-1,
+stackIdMap:null,
insert:function insertNode(parent,frameId){
+if(this.stackIdMap!==null){
+throw'stacks already flattened';
+}
var node=parent[frameId];
if(node===undefined){
node={id:this.nodeCount};
@@ -59,7 +55,13 @@ parent[frameId]=node;
}
return node;
},
+get:function getStackArray(id){
+return this.stackIdMap[id];
+},
flatten:function flattenStacks(){
+if(this.stackIdMap!==null){
+return;
+}
var stackFrameCount=0;
function countStacks(tree,depth){
var leaf=true;
@@ -109,13 +111,150 @@ stackIdMap[id]=newStack;
return stackIdMap[id];
}
flattenStacksImpl(this.root,[]);
-
-return new stackData(stackIdMap,maxStackDepth);
+this.root=null;
+this.stackIdMap=stackIdMap;
+this.maxDepth=maxStackDepth;
}};
}
-function aggrow(numRows){// eslint-disable-line no-unused-vars
+function AggrowData(columns){// eslint-disable-line no-unused-vars
+var columnCount=columns.length;
+var columnConverter=columns.map(function(c){
+switch(c.type){
+case'int':// stores raw value
+return function(i){return i;};
+case'string':// stores interned id of string
+return function(s){return c.strings.intern(s);};
+case'stack':// stores id of stack node
+return function(s){return s.id;};
+default:
+throw'unknown AggrowData column type';}
+
+});
+return{
+data:new Int32Array(0),
+columns:columns,
+rowCount:0,
+rowInserter:function rowInserter(numRows){
+console.log(
+'increasing row data from '+(this.data.length*4).toLocaleString()+' B to '+
+(this.data.length*4+numRows*columnCount*4).toLocaleString()+' B');
+
+var newData=new Int32Array(this.data.length+numRows*columnCount);
+newData.set(this.data);
+var currOffset=this.data.length;
+var endOffset=newData.length;
+this.data=newData;
+this.rowCount=newData.length/columnCount;
+return{
+insertRow:function insertRow(){
+if(currOffset>=endOffset){
+throw'tried to insert data off end of added range';
+}
+if(arguments.length!==columnCount){
+throw'expected data for '+columnCount.toString()+' columns, got'+
+arguments.length.toString()+' columns';
+}
+for(var i=0;i>>0).toString();},
+function(rowA,rowB){return data[rowA*columnCount+index]-data[rowB*columnCount+index];});
+
+},
+addStackExpander:function addStackExpander(expanderName,columnName,formatter){
+// TODO: options for caller/callee, pivoting
+var index=columnIndex(columnName,'stack');
+var stacks=columns[index].stacks;
+return this.expander.addCalleeStackExpander(
+expanderName,
+stacks.maxDepth,
+function(row){return stacks.get(data[row*columnCount+index]);},
+formatter);
+
+}};
+
+}
+
+function AggrowExpander(numRows){// eslint-disable-line no-unused-vars
// expander ID definitions
var FIELD_EXPANDER_ID_MIN=0x0000;
var FIELD_EXPANDER_ID_MAX=0x7fff;
@@ -223,8 +362,8 @@ row.state|=NODE_REAGGREGATE_BIT;
function evaluateAggregates(row){
if((row.state&NODE_EXPANDED_BIT)!==0){
var children=row.children;
-for(var _i=0;_i=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){
if(id-FIELD_EXPANDER_ID_MIN>=state.fieldExpanders.length){
throw'field expander for id '+id.toString()+' does not exist!';
@@ -475,12 +614,12 @@ throw'stack expander for id '+id.toString()+' does not exist!';
}
}
}
-for(var _i9=0;_i9state.aggregators.length){
throw'aggregator id '+id.toString()+' not valid';
}
@@ -524,19 +663,19 @@ state.activeAggregators=ids.slice();
// so someone has to start with root, and it might as well be right away
evaluateAggregate(state.root);
var sorter=noSortOrder;var _loop2=function _loop2(
-_i12){
-var ascending=(ids[_i12]&ACTIVE_AGGREGATOR_ASC_BIT)!==0;
-var id=ids[_i12]&ACTIVE_AGGREGATOR_MASK;
+_i13){
+var ascending=(ids[_i13]&ACTIVE_AGGREGATOR_ASC_BIT)!==0;
+var id=ids[_i13]&ACTIVE_AGGREGATOR_MASK;
var comparer=state.aggregators[id].sorter;
var captureSorter=sorter;
-var captureIndex=_i12;
+var captureIndex=_i13;
sorter=function sorter(a,b){
var c=comparer(a.aggregates[captureIndex],b.aggregates[captureIndex]);
if(c===0){
return captureSorter(a,b);
}
return ascending?-c:c;
-};};for(var _i12=ids.length-1;_i12>=0;_i12--){_loop2(_i12);
+};};for(var _i13=ids.length-1;_i13>=0;_i13--){_loop2(_i13);
}
state.sorter=sorter;
state.root.state|=NODE_REORDER_BIT;
@@ -546,8 +685,8 @@ return state.activeAggregators.slice();
},
getRows:function getRows(top,height){
var result=new Array(height);
-for(var _i13=0;_i130){_loop();
}
}
-function captureRegistry(){
-var strings=stringInterner();
-var stacks=stackRegistry(strings);
-var data=new Int32Array(0);
-
-var idField=0;
-var typeField=1;
-var sizeField=2;
-var traceField=3;
-var pathField=4;
-var reactField=5;
-var valueField=6;
-var moduleField=7;
-var numFields=8;
-
-return{
-strings:strings,
-stacks:stacks,
-data:data,
-register:function registerCapture(captureId,capture){var _this2=this;
+function registerCapture(data,captureId,capture,stacks,strings){
// NB: capture.refs is potentially VERY large, so we try to avoid making
-// copies, even of iteration is a bit more annoying.
+// copies, even if iteration is a bit more annoying.
var rowCount=0;
for(var id in capture.refs){// eslint-disable-line no-unused-vars
rowCount++;
@@ -321,162 +302,80 @@ rowCount++;
for(var _id in capture.markedBlocks){// eslint-disable-line no-unused-vars
rowCount++;
}
-console.log(
-'increasing row data from '+(this.data.length*4).toString()+'B to '+
-(this.data.length*4+rowCount*numFields*4).toString()+'B');
-
-var newData=new Int32Array(this.data.length+rowCount*numFields);
-newData.set(data);
-var dataOffset=this.data.length;
-this.data=null;
-
-registerPathToRoot(capture.refs,this.stacks,this.strings);
-var internedCaptureId=this.strings.intern(captureId);
-var noneString=this.strings.intern('#none');
-var noneStack=this.stacks.insert(this.stacks.root,noneString);
+var inserter=data.rowInserter(rowCount);
+registerPathToRoot(capture.refs,stacks,strings);
+var noneString=strings.intern('#none');
+var noneStack=stacks.insert(stacks.root,noneString);
forEachRef(capture.refs,function(visitor){
+// want to data.append(value, value, value), not IDs
var ref=visitor.getRef();
var id=visitor.id;
-newData[dataOffset+idField]=parseInt(id,16);
-newData[dataOffset+typeField]=_this2.strings.intern(ref.type);
-newData[dataOffset+sizeField]=ref.size;
-newData[dataOffset+traceField]=internedCaptureId;
-if(ref.rootPath===undefined){
-newData[dataOffset+pathField]=noneStack.id;
-}else{
-newData[dataOffset+pathField]=ref.rootPath.id;
-}
-if(ref.reactTree===undefined){
-newData[dataOffset+reactField]=noneStack.id;
-}else{
-newData[dataOffset+reactField]=ref.reactTree.id;
-}
-newData[dataOffset+valueField]=_this2.strings.intern(visitor.getValue());
-if(ref.module){
-newData[dataOffset+moduleField]=_this2.strings.intern(ref.module);
-}else{
-newData[dataOffset+moduleField]=noneString;
-}
-dataOffset+=numFields;
+inserter.insertRow(
+parseInt(id,16),
+ref.type,
+ref.size,
+captureId,
+ref.rootPath===undefined?noneStack:ref.rootPath,
+ref.reactTree===undefined?noneStack:ref.reactTree,
+visitor.getValue(),
+ref.module===undefined?'#none':ref.module);
+
});
for(var _id2 in capture.markedBlocks){
var block=capture.markedBlocks[_id2];
-newData[dataOffset+idField]=parseInt(_id2,16);
-newData[dataOffset+typeField]=this.strings.intern('Marked Block Overhead');
-newData[dataOffset+sizeField]=block.capacity-block.size;
-newData[dataOffset+traceField]=internedCaptureId;
-newData[dataOffset+pathField]=noneStack.id;
-newData[dataOffset+reactField]=noneStack.id;
-newData[dataOffset+valueField]=this.strings.intern(
-'capacity: '+block.capacity+
-', size: '+block.size+
-', granularity: '+block.cellSize);
+inserter.insertRow(
+parseInt(_id2,16),
+'Marked Block Overhead',
+block.capacity-block.size,
+captureId,
+noneStack,
+noneStack,
+'capacity: '+block.capacity+', size: '+block.size+', granularity: '+block.cellSize,
+'#none');
-newData[dataOffset+moduleField]=noneString;
-dataOffset+=numFields;
}
-this.data=newData;
-},
-getAggrow:function getAggrow(){
-var agStrings=this.strings;
-var agStacks=this.stacks.flatten();
-var agData=this.data;
-var agNumRows=agData.length/numFields;
-var ag=new aggrow(agNumRows);
-
-ag.addFieldExpander('Id',
-function getId(row){
-var id=agData[row*numFields+idField];
-if(id<0){
-id+=0x100000000;// data is int32, id is uint32
+inserter.done();
}
-return'0x'+id.toString(16);
-},
-function compareAddress(rowA,rowB){
-return agData[rowA*numFields+idField]-agData[rowB*numFields+idField];
-});
-var typeExpander=ag.addFieldExpander('Type',
-function getType(row){return agStrings.get(agData[row*numFields+typeField]);},
-function compareType(rowA,rowB){
-return agData[rowA*numFields+typeField]-agData[rowB*numFields+typeField];
-});
+if(preLoadedCapture){
+var strings=StringInterner();
+var stacks=new StackRegistry();
+var columns=[
+{name:'id',type:'int'},
+{name:'type',type:'string',strings:strings},
+{name:'size',type:'int'},
+{name:'trace',type:'string',strings:strings},
+{name:'path',type:'stack',stacks:stacks},
+{name:'react',type:'stack',stacks:stacks},
+{name:'value',type:'string',strings:strings},
+{name:'module',type:'string',strings:strings}];
-ag.addFieldExpander('Size',
-function getSize(row){return agData[row*numFields+sizeField].toString();},
-function compareSize(rowA,rowB){
-return agData[rowA*numFields+sizeField]-agData[rowB*numFields+sizeField];
-});
-
-ag.addFieldExpander('Trace',
-function getSize(row){return agStrings.get(agData[row*numFields+traceField]);},
-function compareSize(rowA,rowB){
-return agData[rowA*numFields+traceField]-agData[rowB*numFields+traceField];
-});
-
-var pathExpander=ag.addCalleeStackExpander(
-'Path',
-agStacks.maxDepth,
-function getStack(row){return agStacks.get(agData[row*numFields+pathField]);},
-function getFrame(id){return agStrings.get(id);});
-
-
-var reactExpander=ag.addCalleeStackExpander(
-'React Tree',
-agStacks.maxDepth,
-function getStack(row){return agStacks.get(agData[row*numFields+reactField]);},
-function getFrame(id){return agStrings.get(id);});
-
-
-var valueExpander=ag.addFieldExpander('Value',
-function getValue(row){return agStrings.get(agData[row*numFields+valueField]);},
-function compareValue(rowA,rowB){
-return agData[rowA*numFields+valueField]-agData[rowB*numFields+valueField];
-});
-
-var moduleExpander=ag.addFieldExpander('Module',
-function getModule(row){return agStrings.get(agData[row*numFields+moduleField]);},
-function compareModule(rowA,rowB){
-return agData[rowA*numFields+moduleField]-agData[rowB*numFields+moduleField];
-});
-
-var sizeAggregator=ag.addAggregator('Size',
-function aggregateSize(indices){
-var size=0;
-for(var i=0;i':'...';
headers.push(
React.createElement(DropTarget,{
id:'expander:insert:'+(_i+1).toString(),
-dropFilter:function dropFilter(){return true;},
dropAction:this.props.dropAction},
React.createElement('div',{style:{
@@ -234,7 +224,7 @@ dropAction:React.PropTypes.func.isRequired};var
Table=function(_React$Component6){_inherits(Table,_React$Component6);// eslint-disable-line no-unused-vars
-function Table(props){_classCallCheck(this,Table);var _this7=_possibleConstructorReturn(this,Object.getPrototypeOf(Table).call(this,
+function Table(props){_classCallCheck(this,Table);var _this7=_possibleConstructorReturn(this,(Table.__proto__||Object.getPrototypeOf(Table)).call(this,
props));
_this7.state={
aggrow:props.aggrow,
@@ -547,5 +537,5 @@ document.body.addEventListener('keydown',this.keydown);
{
document.body.removeEventListener('keydown',this.keydown);
}}]);return Table;}(React.Component);
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy90YWJsZS5qcyJdLCJuYW1lcyI6WyJyb3dIZWlnaHQiLCJ0cmVlSW5kZW50IiwiRHJhZ2dhYmxlIiwicHJvcHMiLCJpZCIsImRyYWdTdGFydCIsImUiLCJkYXRhVHJhbnNmZXIiLCJzZXREYXRhIiwiUmVhY3QiLCJjbG9uZUVsZW1lbnQiLCJjaGlsZHJlbiIsImRyYWdnYWJsZSIsIm9uRHJhZ1N0YXJ0IiwiQ29tcG9uZW50IiwicHJvcFR5cGVzIiwiUHJvcFR5cGVzIiwiZWxlbWVudCIsImlzUmVxdWlyZWQiLCJzdHJpbmciLCJEcm9wVGFyZ2V0IiwidGhpc0lkIiwiZHJvcEZpbHRlciIsImRyb3BBY3Rpb24iLCJvbkRyYWdPdmVyIiwic291cmNlSWQiLCJnZXREYXRhIiwicHJldmVudERlZmF1bHQiLCJvbkRyb3AiLCJmdW5jIiwiRXhwYW5kZXJDb25maWd1cmF0aW9uIiwiYWdncm93IiwiZXhwYW5kZXIiLCJ0b1N0cmluZyIsIndpZHRoIiwiaGVpZ2h0IiwiYm9yZGVyIiwibWFyZ2luIiwiZ2V0RXhwYW5kZXJOYW1lIiwiVGFibGVDb25maWd1cmF0aW9uIiwic3RhdGUiLCJleHBhbmRlZCIsImV4IiwiZXhwYW5kZXJUZXh0IiwiY29uZmlnIiwiZ2V0RXhwYW5kZXJzIiwibWFwIiwicmVuZGVyRXhwYW5kZXIiLCJkaXNwbGF5IiwiZmxleERpcmVjdGlvbiIsIm92ZXJmbG93IiwiYm9yZGVyTGVmdCIsInNldFN0YXRlIiwib2JqZWN0IiwiVGFibGVIZWFkZXIiLCJhZ2dyZWdhdG9ycyIsImdldEFjdGl2ZUFnZ3JlZ2F0b3JzIiwiZXhwYW5kZXJzIiwiZ2V0QWN0aXZlRXhwYW5kZXJzIiwiaGVhZGVycyIsImkiLCJsZW5ndGgiLCJuYW1lIiwiZ2V0QWdncmVnYXRvck5hbWUiLCJwdXNoIiwicyIsInN0YXJ0c1dpdGgiLCJiYWNrZ3JvdW5kQ29sb3IiLCJmbGV4U2hyaW5rIiwidGV4dEFsaWduIiwiYmciLCJzZXAiLCJhbGlnbkl0ZW1zIiwiYm9yZGVyQm90dG9tIiwiVGFibGUiLCJ2aWV3cG9ydCIsInRvcCIsImN1cnNvciIsInRhcmdldCIsIk1hdGgiLCJmbG9vciIsInNjcm9sbFRvcCIsImNsaWVudEhlaWdodCIsImNlaWwiLCJyb3ciLCJuZXdDdXJzb3IiLCJjb250cmFjdCIsImNvbnNvbGUiLCJsb2ciLCJleHBhbmQiLCJfc2Nyb2xsRGl2Iiwic2Nyb2xsRGl2IiwiZ2V0Um93cyIsImtleUNvZGUiLCJfa2VlcEN1cnNvckluVmlld3BvcnQiLCJnZXRIZWlnaHQiLCJjYW5Db250cmFjdCIsIl9jb250cmFjdFJvdyIsImdldFJvd0luZGVudCIsImluZGVudCIsImNhbkV4cGFuZCIsIl9leHBhbmRSb3ciLCJkIiwic0luZGV4IiwicGFyc2VJbnQiLCJzdWJzdHIiLCJkSW5kZXgiLCJhY3RpdmUiLCJkcmFnZ2VkIiwic3BsaWNlIiwic2V0QWN0aXZlQWdncmVnYXRvcnMiLCJzZXRBY3RpdmVFeHBhbmRlcnMiLCJzRXhwYW5kZXIiLCJzdWJzdHJpbmciLCJmbGV4R3JvdyIsInNjcm9sbCIsImRpdiIsInBvc2l0aW9uIiwicmVuZGVyVmlydHVhbGl6ZWRSb3dzIiwicm93cyIsInJlbmRlclJvdyIsImNoaWxkIiwiY29sdW1ucyIsInJvd1RleHQiLCJhZ2dyZWdhdGVzIiwicGFyZW50IiwiYWdncmVnYXRlIiwiZ2V0Um93QWdncmVnYXRlIiwibWFyZ2luTGVmdCIsImdldFJvd0xhYmVsIiwid2hpdGVTcGFjZSIsIm1hcmdpblJpZ2h0Iiwia2V5ZG93biIsImJpbmQiLCJkb2N1bWVudCIsImJvZHkiLCJhZGRFdmVudExpc3RlbmVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7OztBQVNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQU1BLFdBQVksRUFBbEI7QUFDQSxHQUFNQyxZQUFhLEVBQW5CLEM7O0FBRU1DLFMsa0VBQW9DO0FBQ3hDLG1CQUFZQyxLQUFaLENBQW1CO0FBQ1hBLEtBRFc7QUFFbEIs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QUM1RSxVQUFZb0YsSUFBSVIsR0FBakIsRUFBc0IzQyxRQUF0QixHQUFtQyxJQUhuQztBQUlMZSxRQUFTLE1BSko7QUFLTEMsY0FBZSxLQUxWO0FBTUx1QixXQUFZLFFBTlA7QUFPTEwsZ0JBQWlCRyxFQVBaO0FBUUxHLGFBQWMsZ0JBUlQsQ0FGVDs7QUFZRSxRQUFVLGtCQUFNO0FBQ2QsUUFBS3JCLFFBQUwsQ0FBYyxDQUFDeUIsT0FBUU8sSUFBSVIsR0FBYixDQUFkO0FBQ0QsQ0FkSDtBQWVHOEMsT0FmSCxDQURGOzs7QUFtQkQsQzs7QUFFbUI7QUFDbEIsS0FBS1UsT0FBTCxDQUFlLEtBQUtBLE9BQUwsQ0FBYUMsSUFBYixDQUFrQixJQUFsQixDQUFmO0FBQ0FDLFNBQVNDLElBQVQsQ0FBY0MsZ0JBQWQsQ0FBK0IsU0FBL0IsQ0FBMEMsS0FBS0osT0FBL0M7QUFDRCxDOztBQUVzQjtBQUNyQkUsU0FBU0MsSUFBVCxDQUFjRSxtQkFBZCxDQUFrQyxTQUFsQyxDQUE2QyxLQUFLTCxPQUFsRDtBQUNELEMsbUJBelRpQjNILE1BQU1LLFMiLCJmaWxlIjoidGFibGUuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxNi1wcmVzZW50LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuLyplc2xpbnQgbm8tY29uc29sZS1kaXNhbGxvdzogXCJvZmZcIiovXG4vKmdsb2JhbCBSZWFjdDp0cnVlKi9cblxuLy8gVE9ETzpcbi8vIHNlbGVjdGlvbiBhbmQgYXJyb3cga2V5cyBmb3IgbmF2aWdhdGluZ1xuXG5jb25zdCByb3dIZWlnaHQgPSAyMDtcbmNvbnN0IHRyZWVJbmRlbnQgPSAxNjtcblxuY2xhc3MgRHJhZ2dhYmxlIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgIHN1cGVyKHByb3BzKTtcbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICBjb25zdCBpZCA9IHRoaXMucHJvcHMuaWQ7XG4gICAgZnVuY3Rpb24gZHJhZ1N0YXJ0KGUpIHtcbiAgICAgIGUuZGF0YVRyYW5zZmVyLnNldERhdGEoJ3RleHQvcGxhaW4nLCBpZCk7XG4gICAgfVxuICAgIHJldHVybiBSZWFjdC5jbG9uZUVsZW1lbnQoXG4gICAgICB0aGlzLnByb3BzLmNoaWxkcmVuLFxuICAgICAgeyBkcmFnZ2FibGU6ICd0cnVlJywgb25EcmFnU3RhcnQ6IGRyYWdTdGFydCB9XG4gICAgKTtcbiAgfVxufVxuRHJhZ2dhYmxlLnByb3BUeXBlcyA9IHtcbiAgY2hpbGRyZW46IFJlYWN0LlByb3BUeXBlcy5lbGVtZW50LmlzUmVxdWlyZWQsXG4gIGlkOiBSZWFjdC5Qcm9wVHlwZXMuc3RyaW5nLmlzUmVxdWlyZWQsXG59O1xuXG5jbGFzcyBEcm9wVGFyZ2V0IGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgIHN1cGVyKHByb3BzKTtcbiAgfVxuXG4gIHJlbmRlcigpIHtcbiAgICBjb25zdCB0aGlzSWQgPSB0aGlzLnByb3BzLmlkO1xuICAgIGNvbnN0IGRyb3BGaWx0ZXIgPSB0aGlzLnByb3BzLmRyb3BGaWx0ZXI7XG4gICAgY29uc3QgZHJvcEFjdGlvbiA9IHRoaXMucHJvcHMuZHJvcEFjdGlvbjtcbiAgICByZXR1cm4gUmVhY3QuY2xvbmVFbGVtZW50KFxuICAgICAgdGhpcy5wcm9wcy5jaGlsZHJlbixcbiAgICAgIHtcbiAgICAgICAgb25EcmFnT3ZlcjogKGUpID0+IHtcbiAgICAgICAgICBjb25zdCBzb3VyY2VJZCA9IGUuZGF0YVRyYW5zZmVyLmdldERhdGEoJ3RleHQvcGxhaW4nKTtcbiAgICAgICAgICBpZiAoZHJvcEZpbHRlcihzb3VyY2VJZCkpIHtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIG9uRHJvcDogKGUpID0+IHtcbiAgICAgICAgICBjb25zdCBzb3VyY2VJZCA9IGUuZGF0YVRyYW5zZmVyLmdldERhdGEoJ3RleHQvcGxhaW4nKTtcbiAgICAgICAgICBpZiAoZHJvcEZpbHRlcihzb3VyY2VJZCkpIHtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIGRyb3BBY3Rpb24oc291cmNlSWQsIHRoaXNJZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgfVxuICAgICk7XG4gIH1cbn1cblxuRHJvcFRhcmdldC5wcm9wVHlwZXMgPSB7XG4gIGNoaWxkcmVuOiBSZWFjdC5Qcm9wVHlwZXMuZWxlbWVudC5pc1JlcXVpcmVkLFxuICBpZDogUmVhY3QuUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICBkcm9wRmlsdGVyOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxuICBkcm9wQWN0aW9uOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxufTtcblxuY2xhc3MgRXhwYW5kZXJDb25maWd1cmF0aW9uIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gIH1cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IGFnZ3JvdyA9IHRoaXMucHJvcHMuYWdncm93O1xuICAgIGNvbnN0IGV4cGFuZGVyID0gdGhpcy5wcm9wcy5leHBhbmRlcjtcbiAgICByZXR1cm4gKFxuICAgICAgPERyYWdnYWJsZSBpZD17J2V4cGFuZGVyOmFkZDonICsgZXhwYW5kZXIudG9TdHJpbmcoKX0+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBzdHlsZT17e1xuICAgICAgICAgICAgd2lkdGg6ICdhdXRvJyxcbiAgICAgICAgICAgIGhlaWdodDogJzI2cHgnLFxuICAgICAgICAgICAgYm9yZGVyOiAnMXB4IHNvbGlkIGRhcmtHcmF5JyxcbiAgICAgICAgICAgIG1hcmdpbjogJzJweCcsXG4gICAgICAgICAgfX0+XG4gICAgICAgICAge2FnZ3Jvdy5nZXRFeHBhbmRlck5hbWUoZXhwYW5kZXIpfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvRHJhZ2dhYmxlPlxuICAgICk7XG4gIH1cbn1cblxuY2xhc3MgVGFibGVDb25maWd1cmF0aW9uIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGV4cGFuZGVkOiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIHJlbmRlckV4cGFuZGVyKGV4KSB7XG4gICAgcmV0dXJuICg8RXhwYW5kZXJDb25maWd1cmF0aW9uIGFnZ3Jvdz17dGhpcy5wcm9wcy5hZ2dyb3d9IGV4cGFuZGVyPXtleH0gLz4pO1xuICB9XG4gIHJlbmRlcigpIHtcbiAgICBjb25zdCBleHBhbmRlclRleHQgPSB0aGlzLnN0YXRlLmV4cGFuZGVkID8gJz4+JyA6ICc8PCc7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5wcm9wcy5hZ2dyb3c7XG4gICAgbGV0IGNvbmZpZyA9IFtdO1xuICAgIGlmICh0aGlzLnN0YXRlLmV4cGFuZGVkKSB7XG4gICAgICBjb25maWcgPSBhZ2dyb3cuZ2V0RXhwYW5kZXJzKCkubWFwKChleCkgPT4gdGhpcy5yZW5kZXJFeHBhbmRlcihleCkpO1xuICAgIH1cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLmV4cGFuZGVkID8gJzUxMnB4JyA6ICcyNnB4JyxcbiAgICAgICAgICBoZWlnaHQ6ICcxMDAlJyxcbiAgICAgICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICAgICAgZmxleERpcmVjdGlvbjogJ2NvbHVtbicsXG4gICAgICAgICAgb3ZlcmZsb3c6ICdoaWRkZW4nLFxuICAgICAgICAgIGJvcmRlckxlZnQ6ICcycHggc29saWQgYmxhY2snLFxuICAgICAgICB9fT5cbiAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgICAgd2lkdGg6ICcxMDAlJyxcbiAgICAgICAgICAgIGhlaWdodDogJzI2cHgnLFxuICAgICAgICAgICAgYm9yZGVyOiAnMXB4IHNvbGlkIGRhcmtHcmF5JyxcbiAgICAgICAgICB9fVxuICAgICAgICAgIG9uQ2xpY2s9eyAoZSkgPT4gdGhpcy5zZXRTdGF0ZSh7ZXhwYW5kZWQ6ICF0aGlzLnN0YXRlLmV4cGFuZGVkfSkgfT5cbiAgICAgICAgICB7IGV4cGFuZGVyVGV4dCB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgICB7IGNvbmZpZyB9XG4gICAgICA8L2Rpdj5cbiAgICApO1xuICB9XG59XG5cblRhYmxlQ29uZmlndXJhdGlvbi5wcm9wVHlwZXMgPSB7XG4gIGFnZ3JvdzogUmVhY3QuUHJvcFR5cGVzLm9iamVjdC5pc1JlcXVpcmVkLFxufTtcblxuY2xhc3MgVGFibGVIZWFkZXIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgIHN1cGVyKHByb3BzKTtcbiAgfVxuICByZW5kZXIoKSB7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5wcm9wcy5hZ2dyb3c7XG4gICAgY29uc3QgYWdncmVnYXRvcnMgPSBhZ2dyb3cuZ2V0QWN0aXZlQWdncmVnYXRvcnMoKTtcbiAgICBjb25zdCBleHBhbmRlcnMgPSBhZ2dyb3cuZ2V0QWN0aXZlRXhwYW5kZXJzKCk7XG4gICAgY29uc3QgaGVhZGVycyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYWdncmVnYXRvcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG5hbWUgPSBhZ2dyb3cuZ2V0QWdncmVnYXRvck5hbWUoYWdncmVnYXRvcnNbaV0pO1xuICAgICAgaGVhZGVycy5wdXNoKChcbiAgICAgICAgPERyb3BUYXJnZXRcbiAgICAgICAgICBpZD17J2FnZ3JlZ2F0ZTppbnNlcnQ6JyArIGkudG9TdHJpbmcoKX1cbiAgICAgICAgICBkcm9wRmlsdGVyPXsocykgPT4gcy5zdGFydHNXaXRoKCdhZ2dyZWdhdGUnKX1cbiAgICAgICAgICBkcm9wQWN0aW9uPXt0aGlzLnByb3BzLmRyb3BBY3Rpb259XG4gICAgICAgID5cbiAgICAgICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgICAgICB3aWR0aDogJzE2cHgnLFxuICAgICAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6ICdkYXJrR3JheScsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCcgfX1cbiAgICAgICAgICA+PC9kaXY+XG4gICAgICAgIDwvRHJvcFRhcmdldD4pKTtcbiAgICAgIGhlYWRlcnMucHVzaCgoPERyYWdnYWJsZSBpZD17J2FnZ3JlZ2F0ZTphY3RpdmU6JyArIGkudG9TdHJpbmcoKX0+XG4gICAgICAgICAgPGRpdiBzdHlsZT17eyB3aWR0aDogJzEyOHB4JywgdGV4dEFsaWduOiAnY2VudGVyJywgZmxleFNocmluazogJzAnIH19PntuYW1lfTwvZGl2PlxuICAgICAgICA8L0RyYWdnYWJsZT4pKTtcbiAgICB9XG4gICAgaGVhZGVycy5wdXNoKChcbiAgICAgIDxEcm9wVGFyZ2V0XG4gICAgICAgIGlkPVwiZGl2aWRlcjppbnNlcnRcIlxuICAgICAgICBkcm9wRmlsdGVyPXsocykgPT4gcy5zdGFydHNXaXRoKCdhZ2dyZWdhdGUnKSB8fCBzLnN0YXJ0c1dpdGgoJ2V4cGFuZGVyJyl9XG4gICAgICAgIGRyb3BBY3Rpb249e3RoaXMucHJvcHMuZHJvcEFjdGlvbn1cbiAgICAgID5cbiAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgIHdpZHRoOiAnMTZweCcsXG4gICAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiAnZ29sZCcsXG4gICAgICAgICAgZmxleFNocmluazogJzAnXG4gICAgICAgIH19PjwvZGl2PlxuICAgICAgPC9Ecm9wVGFyZ2V0PikpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZXhwYW5kZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBuYW1lID0gYWdncm93LmdldEV4cGFuZGVyTmFtZShleHBhbmRlcnNbaV0pO1xuICAgICAgY29uc3QgYmcgPSAoaSAlIDIgPT09IDApID8gJ3doaXRlJyA6ICdsaWdodEdyYXknO1xuICAgICAgaGVhZGVycy5wdXNoKCg8RHJhZ2dhYmxlIGlkPXsnZXhwYW5kZXI6YWN0aXZlOicgKyBpLnRvU3RyaW5nKCl9PlxuICAgICAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgICAgIHdpZHRoOiAnMTI4cHgnLFxuICAgICAgICAgICAgdGV4dEFsaWduOiAnY2VudGVyJyxcbiAgICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogYmcsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCdcbiAgICAgICAgICB9fT5cbiAgICAgICAgICAgIHtuYW1lfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L0RyYWdnYWJsZT4pKTtcbiAgICAgIGNvbnN0IHNlcCA9IGkgKyAxIDwgZXhwYW5kZXJzLmxlbmd0aCA/ICctPicgOiAnLi4uJztcbiAgICAgIGhlYWRlcnMucHVzaCgoXG4gICAgICAgIDxEcm9wVGFyZ2V0XG4gICAgICAgICAgaWQ9eydleHBhbmRlcjppbnNlcnQ6JyArIChpICsgMSkudG9TdHJpbmcoKX1cbiAgICAgICAgICBkcm9wRmlsdGVyPXsoKT0+e3JldHVybiB0cnVlOyB9fVxuICAgICAgICAgIGRyb3BBY3Rpb249e3RoaXMucHJvcHMuZHJvcEFjdGlvbn1cbiAgICAgICAgPlxuICAgICAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgICAgIGhlaWdodDogJ2luaGVyaXQnLFxuICAgICAgICAgICAgYmFja2dyb3VuZENvbG9yOiAnZGFya0dyYXknLFxuICAgICAgICAgICAgZmxleFNocmluazogJzAnXG4gICAgICAgICAgfX0+XG4gICAgICAgICAgICB7c2VwfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L0Ryb3BUYXJnZXQ+KVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIChcbiAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgd2lkdGg6ICcxMDAlJyxcbiAgICAgICAgaGVpZ2h0OiAnMjZweCcsXG4gICAgICAgIGRpc3BsYXk6ICdmbGV4JyxcbiAgICAgICAgZmxleERpcmVjdGlvbjogJ3JvdycsXG4gICAgICAgIGFsaWduSXRlbXM6ICdjZW50ZXInLFxuICAgICAgICBib3JkZXJCb3R0b206ICcycHggc29saWQgYmxhY2snLFxuICAgICAgfX0+XG4gICAgICAgIHtoZWFkZXJzfVxuICAgICAgPC9kaXY+XG4gICAgKTtcbiAgfVxufVxuXG5UYWJsZUhlYWRlci5wcm9wVHlwZXMgPSB7XG4gIGFnZ3JvdzogUmVhY3QuUHJvcFR5cGVzLm9iamVjdC5pc1JlcXVpcmVkLFxuICBkcm9wQWN0aW9uOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxufTtcblxuY2xhc3MgVGFibGUgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgc3VwZXIocHJvcHMpO1xuICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICBhZ2dyb3c6IHByb3BzLmFnZ3JvdyxcbiAgICAgIHZpZXdwb3J0OiB7IHRvcDogMCwgaGVpZ2h0OiAxMDAgfSxcbiAgICAgIGN1cnNvcjogMCxcbiAgICB9O1xuICB9XG5cbiAgc2Nyb2xsKGUpIHtcbiAgICBjb25zdCB2aWV3cG9ydCA9IGUudGFyZ2V0O1xuICAgIGNvbnN0IHRvcCA9IE1hdGguZmxvb3IoKHZpZXdwb3J0LnNjcm9sbFRvcCAtIHZpZXdwb3J0LmNsaWVudEhlaWdodCAqIDEuMCkgLyByb3dIZWlnaHQpO1xuICAgIGNvbnN0IGhlaWdodCA9IE1hdGguY2VpbCh2aWV3cG9ydC5jbGllbnRIZWlnaHQgKiAzLjAgLyByb3dIZWlnaHQpO1xuICAgIGlmICh0b3AgIT09IHRoaXMuc3RhdGUudmlld3BvcnQudG9wIHx8IGhlaWdodCAhPT0gdGhpcy5zdGF0ZS52aWV3cG9ydC5oZWlnaHQpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe3ZpZXdwb3J0OiB7dG9wLCBoZWlnaHR9fSk7XG4gICAgfVxuICB9XG5cbiAgX2NvbnRyYWN0Um93KHJvdykge1xuICAgIGxldCBuZXdDdXJzb3IgPSB0aGlzLnN0YXRlLmN1cnNvcjtcbiAgICBpZiAobmV3Q3Vyc29yID4gcm93LnRvcCAmJiBuZXdDdXJzb3IgPCByb3cudG9wICsgcm93LmhlaWdodCkgeyAvLyBpbiBjb250cmFjdGVkIHNlY3Rpb25cbiAgICAgIG5ld0N1cnNvciA9IHJvdy50b3A7XG4gICAgfSBlbHNlIGlmIChuZXdDdXJzb3IgPj0gcm93LnRvcCArIHJvdy5oZWlnaHQpIHsgLy8gYmVsb3cgY29udHJhY3RlZCBzZWN0aW9uXG4gICAgICBuZXdDdXJzb3IgLT0gcm93LmhlaWdodCAtIDE7XG4gICAgfVxuICAgIHRoaXMuc3RhdGUuYWdncm93LmNvbnRyYWN0KHJvdyk7XG4gICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOiBuZXdDdXJzb3J9KTtcbiAgICBjb25zb2xlLmxvZygnLScgKyByb3cudG9wKTtcbiAgfVxuXG4gIF9leHBhbmRSb3cocm93KSB7XG4gICAgbGV0IG5ld0N1cnNvciA9IHRoaXMuc3RhdGUuY3Vyc29yO1xuICAgIHRoaXMuc3RhdGUuYWdncm93LmV4cGFuZChyb3cpO1xuICAgIGlmIChuZXdDdXJzb3IgPiByb3cudG9wKSB7ICAvLyBiZWxvdyBleHBhbmRlZCBzZWN0aW9uXG4gICAgICBuZXdDdXJzb3IgKz0gcm93LmhlaWdodCAtIDE7XG4gICAgfVxuICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjogbmV3Q3Vyc29yfSk7XG4gICAgY29uc29sZS5sb2coJysnICsgcm93LnRvcCk7XG4gIH1cblxuICBfc2Nyb2xsRGl2OiBudWxsO1xuXG4gIF9rZWVwQ3Vyc29ySW5WaWV3cG9ydCgpIHtcbiAgICBpZiAodGhpcy5fc2Nyb2xsRGl2KSB7XG4gICAgICBjb25zdCBjdXJzb3IgPSB0aGlzLnN0YXRlLmN1cnNvcjtcbiAgICAgIGNvbnN0IHNjcm9sbERpdiA9IHRoaXMuX3Njcm9sbERpdjtcbiAgICAgIGlmIChjdXJzb3IgKiByb3dIZWlnaHQgPCBzY3JvbGxEaXYuc2Nyb2xsVG9wICsgc2Nyb2xsRGl2LmNsaWVudEhlaWdodCAqIDAuMSkge1xuICAgICAgICBzY3JvbGxEaXYuc2Nyb2xsVG9wID0gY3Vyc29yICogcm93SGVpZ2h0IC0gc2Nyb2xsRGl2LmNsaWVudEhlaWdodCAqIDAuMTtcbiAgICAgIH0gZWxzZSBpZiAoKGN1cnNvciArIDEpICogcm93SGVpZ2h0ID4gc2Nyb2xsRGl2LnNjcm9sbFRvcCArIHNjcm9sbERpdi5jbGllbnRIZWlnaHQgKiAwLjkpIHtcbiAgICAgICAgc2Nyb2xsRGl2LnNjcm9sbFRvcCA9IChjdXJzb3IgKyAxKSAqIHJvd0hlaWdodCAtIHNjcm9sbERpdi5jbGllbnRIZWlnaHQgKiAwLjk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAga2V5ZG93bihlKSB7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5zdGF0ZS5hZ2dyb3c7XG4gICAgbGV0IGN1cnNvciA9IHRoaXMuc3RhdGUuY3Vyc29yO1xuICAgIGxldCByb3cgPSBhZ2dyb3cuZ2V0Um93cyhjdXJzb3IsIDEpWzBdO1xuICAgIHN3aXRjaCAoZS5rZXlDb2RlKSB7XG4gICAgICBjYXNlIDM4OiAvLyB1cFxuICAgICAgICBpZiAoY3Vyc29yID4gMCkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjogY3Vyc29yIC0gMX0pO1xuICAgICAgICAgIHRoaXMuX2tlZXBDdXJzb3JJblZpZXdwb3J0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNDA6IC8vIGRvd25cbiAgICAgICAgaWYgKGN1cnNvciA8IGFnZ3Jvdy5nZXRIZWlnaHQoKSAtIDEpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtjdXJzb3I6IGN1cnNvciArIDF9KTtcbiAgICAgICAgICB0aGlzLl9rZWVwQ3Vyc29ySW5WaWV3cG9ydCgpO1xuICAgICAgICB9XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM3OiAvLyBsZWZ0XG4gICAgICAgIGlmIChhZ2dyb3cuY2FuQ29udHJhY3Qocm93KSkge1xuICAgICAgICAgIHRoaXMuX2NvbnRyYWN0Um93KHJvdyk7XG4gICAgICAgIH0gZWxzZSBpZiAoYWdncm93LmdldFJvd0luZGVudChyb3cpID4gMCkge1xuICAgICAgICAgIGNvbnN0IGluZGVudCA9IGFnZ3Jvdy5nZXRSb3dJbmRlbnQocm93KSAtIDE7XG4gICAgICAgICAgd2hpbGUgKGFnZ3Jvdy5nZXRSb3dJbmRlbnQocm93KSA+IGluZGVudCkge1xuICAgICAgICAgICAgY3Vyc29yLS07XG4gICAgICAgICAgICByb3cgPSBhZ2dyb3cuZ2V0Um93cyhjdXJzb3IsIDEpWzBdO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtjdXJzb3I6IGN1cnNvcn0pO1xuICAgICAgICAgIHRoaXMuX2tlZXBDdXJzb3JJblZpZXdwb3J0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzk6IC8vIHJpZ2h0XG4gICAgICAgIGlmIChhZ2dyb3cuY2FuRXhwYW5kKHJvdykpIHtcbiAgICAgICAgICB0aGlzLl9leHBhbmRSb3cocm93KTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJzb3IgPCBhZ2dyb3cuZ2V0SGVpZ2h0KCkgLSAxKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOiBjdXJzb3IgKyAxfSk7XG4gICAgICAgICAgdGhpcy5fa2VlcEN1cnNvckluVmlld3BvcnQoKTtcbiAgICAgICAgfVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIGRyb3BBY3Rpb24ocywgZCkge1xuICAgIGNvbnN0IGFnZ3JvdyA9IHRoaXMuc3RhdGUuYWdncm93O1xuICAgIGNvbnNvbGUubG9nKCdkcm9wcGVkICcgKyBzICsgJyB0byAnICsgZCk7XG4gICAgaWYgKHMuc3RhcnRzV2l0aCgnYWdncmVnYXRlOmFjdGl2ZTonKSkge1xuICAgICAgY29uc3Qgc0luZGV4ID0gcGFyc2VJbnQocy5zdWJzdHIoMTcpLCAxMCk7XG4gICAgICBsZXQgZEluZGV4ID0gLTE7XG4gICAgICBjb25zdCBhY3RpdmUgPSBhZ2dyb3cuZ2V0QWN0aXZlQWdncmVnYXRvcnMoKTtcbiAgICAgIGNvbnN0IGRyYWdnZWQgPSBhY3RpdmVbc0luZGV4XTtcbiAgICAgIGlmIChkLnN0YXJ0c1dpdGgoJ2FnZ3JlZ2F0ZTppbnNlcnQ6JykpIHtcbiAgICAgICAgZEluZGV4ID0gcGFyc2VJbnQoZC5zdWJzdHIoMTcpLCAxMCk7XG4gICAgICB9IGVsc2UgaWYgKGQgPT09ICdkaXZpZGVyOmluc2VydCcpIHtcbiAgICAgICAgZEluZGV4ID0gYWN0aXZlLmxlbmd0aDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93ICdub3QgYWxsb3dlZCB0byBkcmFnICcgKyBzICsgJyB0byAnICsgZDtcbiAgICAgIH1cbiAgICAgIGlmIChkSW5kZXggPiBzSW5kZXgpIHtcbiAgICAgICAgZEluZGV4LS07XG4gICAgICB9XG4gICAgICBhY3RpdmUuc3BsaWNlKHNJbmRleCwgMSk7XG4gICAgICBhY3RpdmUuc3BsaWNlKGRJbmRleCwgMCwgZHJhZ2dlZCk7XG4gICAgICBhZ2dyb3cuc2V0QWN0aXZlQWdncmVnYXRvcnMoYWN0aXZlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjowfSk7XG4gICAgfSBlbHNlIGlmIChzLnN0YXJ0c1dpdGgoJ2V4cGFuZGVyOmFjdGl2ZTonKSkge1xuICAgICAgY29uc3Qgc0luZGV4ID0gcGFyc2VJbnQocy5zdWJzdHIoMTYpLCAxMCk7XG4gICAgICBsZXQgZEluZGV4ID0gLTE7XG4gICAgICBjb25zdCBhY3RpdmUgPSBhZ2dyb3cuZ2V0QWN0aXZlRXhwYW5kZXJzKCk7XG4gICAgICBjb25zdCBkcmFnZ2VkID0gYWN0aXZlW3NJbmRleF07XG4gICAgICBpZiAoZC5zdGFydHNXaXRoKCdleHBhbmRlcjppbnNlcnQ6JykpIHtcbiAgICAgICAgZEluZGV4ID0gcGFyc2VJbnQoZC5zdWJzdHIoMTYpLCAxMCk7XG4gICAgICB9IGVsc2UgaWYgKGQgPT09ICdkaXZpZGVyOmluc2VydCcpIHtcbiAgICAgICAgZEluZGV4ID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93ICdub3QgYWxsb3dlZCB0byBkcmFnICcgKyBzICsgJyB0byAnICsgZDtcbiAgICAgIH1cbiAgICAgIGlmIChkSW5kZXggPiBzSW5kZXgpIHtcbiAgICAgICAgZEluZGV4LS07XG4gICAgICB9XG4gICAgICBhY3RpdmUuc3BsaWNlKHNJbmRleCwgMSk7XG4gICAgICBhY3RpdmUuc3BsaWNlKGRJbmRleCwgMCwgZHJhZ2dlZCk7XG4gICAgICBhZ2dyb3cuc2V0QWN0aXZlRXhwYW5kZXJzKGFjdGl2ZSk7XG4gICAgICB0aGlzLnNldFN0YXRlKHtjdXJzb3I6MH0pO1xuICAgIH0gZWxzZSBpZiAocy5zdGFydHNXaXRoKCdleHBhbmRlcjphZGQ6JykpIHtcbiAgICAgIGxldCBkSW5kZXggPSAtMTtcbiAgICAgIGNvbnN0IHNFeHBhbmRlciA9IHBhcnNlSW50KHMuc3Vic3RyaW5nKDEzKSwgMTApO1xuICAgICAgaWYgKGQuc3RhcnRzV2l0aCgnZXhwYW5kZXI6aW5zZXJ0OicpKSB7XG4gICAgICAgIGRJbmRleCA9IHBhcnNlSW50KGQuc3Vic3RyKDE2KSwgMTApO1xuICAgICAgfSBlbHNlIGlmIChkID09PSAnZGl2aWRlcjppbnNlcnQnKSB7XG4gICAgICAgIGRJbmRleCA9IDA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyAnbm90IGFsbG93ZWQgdG8gZHJhZyAnICsgcyArICcgdG8gJyArIGQ7XG4gICAgICB9XG4gICAgICBjb25zdCBhY3RpdmUgPSBhZ2dyb3cuZ2V0QWN0aXZlRXhwYW5kZXJzKCk7XG4gICAgICBhY3RpdmUuc3BsaWNlKGRJbmRleCwgMCwgc0V4cGFuZGVyKTtcbiAgICAgIGFnZ3Jvdy5zZXRBY3RpdmVFeHBhbmRlcnMoYWN0aXZlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjowfSk7XG4gICAgfVxuICB9XG5cbiAgcmVuZGVyKCkge1xuICAgIHJldHVybiAoXG4gICAgICA8ZGl2IHN0eWxlPXt7IHdpZHRoOiAnMTAwJScsIGhlaWdodDogJzEwMCUnLCBkaXNwbGF5OiAnZmxleCcsIGZsZXhEaXJlY3Rpb246ICdyb3cnIH19PlxuICAgICAgICA8ZGl2IHN0eWxlPXt7IHdpZHRoOiAnMTAwJScsIGhlaWdodDogJzEwMCUnLCBkaXNwbGF5OiAnZmxleCcsIGZsZXhEaXJlY3Rpb246ICdjb2x1bW4nLCBvdmVyZmxvdzogJ2hpZGRlbicsIH19PlxuICAgICAgICAgIDxUYWJsZUhlYWRlciBhZ2dyb3c9e3RoaXMuc3RhdGUuYWdncm93fSBkcm9wQWN0aW9uPXsocywgZCkgPT4gdGhpcy5kcm9wQWN0aW9uKHMsIGQpfSAvPlxuICAgICAgICAgIDxkaXZcbiAgICAgICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgICAgIHdpZHRoOiAnMTAwJScsXG4gICAgICAgICAgICAgIGZsZXhHcm93OiAnMScsXG4gICAgICAgICAgICAgIG92ZXJmbG93OiAnc2Nyb2xsJ1xuICAgICAgICAgICAgfX1cbiAgICAgICAgICAgIG9uU2Nyb2xsPXsgKGUpID0+IHRoaXMuc2Nyb2xsKGUpIH1cbiAgICAgICAgICAgIHJlZj17KGRpdikgPT4geyB0aGlzLl9zY3JvbGxEaXYgPSBkaXY7IH0gfT5cbiAgICAgICAgICAgIDxkaXYgc3R5bGU9e3sgcG9zaXRpb246ICdyZWxhdGl2ZScgfX0+XG4gICAgICAgICAgICAgIHsgdGhpcy5yZW5kZXJWaXJ0dWFsaXplZFJvd3MoKSB9XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxUYWJsZUNvbmZpZ3VyYXRpb24gYWdncm93PXt0aGlzLnN0YXRlLmFnZ3Jvd30gLz5cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cblxuICByZW5kZXJWaXJ0dWFsaXplZFJvd3MoKSB7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5zdGF0ZS5hZ2dyb3c7XG4gICAgY29uc3Qgdmlld3BvcnQgPSB0aGlzLnN0YXRlLnZpZXdwb3J0O1xuICAgIGNvbnN0IHJvd3MgPSBhZ2dyb3cuZ2V0Um93cyh2aWV3cG9ydC50b3AsIHZpZXdwb3J0LmhlaWdodCk7XG4gICAgcmV0dXJuIChcbiAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgIHdpZHRoOiAnMTAwJScsXG4gICAgICAgIGhlaWdodDogKHJvd0hlaWdodCAqIChhZ2dyb3cuZ2V0SGVpZ2h0KCkgKyAyMCkpLnRvU3RyaW5nKCkgKyAncHgnXG4gICAgICB9fT5cbiAgICAgICAgeyByb3dzLm1hcChjaGlsZCA9PiB0aGlzLnJlbmRlclJvdyhjaGlsZCkpIH1cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cblxuICByZW5kZXJSb3cocm93KSB7XG4gICAgaWYgKHJvdyA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGxldCBiZyA9ICdsaWdodEdyYXknO1xuICAgIGNvbnN0IGFnZ3JvdyA9IHRoaXMuc3RhdGUuYWdncm93O1xuICAgIGNvbnN0IGNvbHVtbnMgPSBbXTtcbiAgICBsZXQgcm93VGV4dCA9ICcnO1xuICAgIGNvbnN0IGluZGVudCA9IDQgKyBhZ2dyb3cuZ2V0Um93SW5kZW50KHJvdykgKiB0cmVlSW5kZW50O1xuICAgIGNvbnN0IGFnZ3JlZ2F0ZXMgPSBhZ2dyb3cuZ2V0QWN0aXZlQWdncmVnYXRvcnMoKTtcbiAgICBpZiAocm93LnBhcmVudCAhPT0gbnVsbCAmJiAocm93LnBhcmVudC5leHBhbmRlciAlIDIgPT09IDApKSB7XG4gICAgICBiZyA9ICd3aGl0ZSc7XG4gICAgfVxuICAgIGlmIChyb3cudG9wID09PSB0aGlzLnN0YXRlLmN1cnNvcikge1xuICAgICAgYmcgPSAnbGlnaHRibHVlJztcbiAgICB9XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhZ2dyZWdhdGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgYWdncmVnYXRlID0gYWdncm93LmdldFJvd0FnZ3JlZ2F0ZShyb3csIGkpO1xuICAgICAgY29sdW1ucy5wdXNoKChcbiAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgIHdpZHRoOiAnMTZweCcsXG4gICAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiAnZGFya0dyYXknLFxuICAgICAgICAgIGZsZXhTaHJpbms6ICcwJ1xuICAgICAgICB9fT48L2Rpdj5cbiAgICAgICkpO1xuICAgICAgY29sdW1ucy5wdXNoKChcbiAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgIHdpZHRoOiAnMTI4cHgnLFxuICAgICAgICAgIHRleHRBbGlnbjogJ3JpZ2h0JyxcbiAgICAgICAgICBmbGV4U2hyaW5rOiAnMCdcbiAgICAgICAgfX0+XG4gICAgICAgICAge2FnZ3JlZ2F0ZX1cbiAgICAgICAgPC9kaXY+XG4gICAgICApKTtcbiAgICB9XG4gICAgY29sdW1ucy5wdXNoKChcbiAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgd2lkdGg6ICcxNnB4JyxcbiAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgIGJhY2tncm91bmRDb2xvcjogJ2dvbGQnLFxuICAgICAgICBmbGV4U2hyaW5rOiAnMCdcbiAgICAgIH19PjwvZGl2PlxuICAgICkpO1xuICAgIGlmIChhZ2dyb3cuY2FuRXhwYW5kKHJvdykpIHtcbiAgICAgIGNvbHVtbnMucHVzaCgoXG4gICAgICAgIDxkaXZcbiAgICAgICAgICBzdHlsZT17e1xuICAgICAgICAgICAgbWFyZ2luTGVmdDogaW5kZW50LnRvU3RyaW5nKCkgKyAncHgnLFxuICAgICAgICAgICAgZmxleFNocmluazogJzAnLFxuICAgICAgICAgICAgd2lkdGg6ICcxMnB4JyxcbiAgICAgICAgICAgIHRleHRBbGlnbjogJ2NlbnRlcicsXG4gICAgICAgICAgICBib3JkZXI6ICcxcHggc29saWQgZ3JheScsXG4gICAgICAgICAgfX1cbiAgICAgICAgICBvbkNsaWNrPXsgKCkgPT4gdGhpcy5fZXhwYW5kUm93KHJvdykgfVxuICAgICAgICA+KzwvZGl2PlxuICAgICAgKSk7XG4gICAgfSBlbHNlIGlmIChhZ2dyb3cuY2FuQ29udHJhY3Qocm93KSkge1xuICAgICAgY29sdW1ucy5wdXNoKChcbiAgICAgICAgPGRpdlxuICAgICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgICBtYXJnaW5MZWZ0OiBpbmRlbnQudG9TdHJpbmcoKSArICdweCcsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCcsXG4gICAgICAgICAgICB3aWR0aDogJzEycHgnLFxuICAgICAgICAgICAgdGV4dEFsaWduOiAnY2VudGVyJyxcbiAgICAgICAgICAgIGJvcmRlcjogJzFweCBzb2xpZCBncmF5JyxcbiAgICAgICAgICB9fVxuICAgICAgICAgIG9uQ2xpY2s9eyAoKSA9PiB0aGlzLl9jb250cmFjdFJvdyhyb3cpIH1cbiAgICAgICAgPi08L2Rpdj5cbiAgICAgICkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgICA8ZGl2XG4gICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgIG1hcmdpbkxlZnQ6IGluZGVudC50b1N0cmluZygpICsgJ3B4JyxcbiAgICAgICAgICB9fVxuICAgICAgICA+PC9kaXY+XG4gICAgICApKTtcbiAgICB9XG4gICAgcm93VGV4dCArPSBhZ2dyb3cuZ2V0Um93TGFiZWwocm93KTtcbiAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICBmbGV4U2hyaW5rOiAnMCcsXG4gICAgICAgIHdoaXRlU3BhY2U6ICdub3dyYXAnLFxuICAgICAgICBtYXJnaW5SaWdodDogJzIwcHgnXG4gICAgICB9fT5cbiAgICAgICAge3Jvd1RleHR9XG4gICAgICA8L2Rpdj5cbiAgICApKTtcbiAgICByZXR1cm4gKFxuICAgICAgPGRpdlxuICAgICAgICBrZXk9e3Jvdy50b3B9XG4gICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgICAgaGVpZ2h0OiAocm93SGVpZ2h0IC0gMSkudG9TdHJpbmcoKSArICdweCcsXG4gICAgICAgICAgdG9wOiAocm93SGVpZ2h0ICogcm93LnRvcCkudG9TdHJpbmcoKSArICdweCcsXG4gICAgICAgICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgICAgICAgIGZsZXhEaXJlY3Rpb246ICdyb3cnLFxuICAgICAgICAgIGFsaWduSXRlbXM6ICdjZW50ZXInLFxuICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogYmcsXG4gICAgICAgICAgYm9yZGVyQm90dG9tOiAnMXB4IHNvbGlkIGdyYXknLFxuICAgICAgICB9fVxuICAgICAgICBvbkNsaWNrPXsgKCkgPT4ge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjogcm93LnRvcH0pO1xuICAgICAgICB9fT5cbiAgICAgICAge2NvbHVtbnN9XG4gICAgICA8L2Rpdj5cbiAgICApO1xuICB9XG5cbiAgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgdGhpcy5rZXlkb3duID0gdGhpcy5rZXlkb3duLmJpbmQodGhpcyk7XG4gICAgZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5rZXlkb3duKTtcbiAgfVxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIHRoaXMua2V5ZG93bik7XG4gIH1cbn1cbiJdfQ==
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy90YWJsZS5qcyJdLCJuYW1lcyI6WyJyb3dIZWlnaHQiLCJ0cmVlSW5kZW50IiwiRHJhZ2dhYmxlIiwicHJvcHMiLCJpZCIsIlJlYWN0IiwiY2xvbmVFbGVtZW50IiwiY2hpbGRyZW4iLCJkcmFnZ2FibGUiLCJvbkRyYWdTdGFydCIsImUiLCJkYXRhVHJhbnNmZXIiLCJzZXREYXRhIiwiQ29tcG9uZW50IiwicHJvcFR5cGVzIiwiUHJvcFR5cGVzIiwiZWxlbWVudCIsImlzUmVxdWlyZWQiLCJzdHJpbmciLCJEcm9wVGFyZ2V0IiwidGhpc0lkIiwiZHJvcEFjdGlvbiIsIm9uRHJhZ092ZXIiLCJwcmV2ZW50RGVmYXVsdCIsIm9uRHJvcCIsInNvdXJjZUlkIiwiZ2V0RGF0YSIsImZ1bmMiLCJFeHBhbmRlckNvbmZpZ3VyYXRpb24iLCJhZ2dyb3ciLCJleHBhbmRlciIsInRvU3RyaW5nIiwid2lkdGgiLCJoZWlnaHQiLCJib3JkZXIiLCJtYXJnaW4iLCJnZXRFeHBhbmRlck5hbWUiLCJUYWJsZUNvbmZpZ3VyYXRpb24iLCJzdGF0ZSIsImV4cGFuZGVkIiwiZXgiLCJleHBhbmRlclRleHQiLCJjb25maWciLCJnZXRFeHBhbmRlcnMiLCJtYXAiLCJyZW5kZXJFeHBhbmRlciIsImRpc3BsYXkiLCJmbGV4RGlyZWN0aW9uIiwib3ZlcmZsb3ciLCJib3JkZXJMZWZ0Iiwic2V0U3RhdGUiLCJvYmplY3QiLCJUYWJsZUhlYWRlciIsImFnZ3JlZ2F0b3JzIiwiZ2V0QWN0aXZlQWdncmVnYXRvcnMiLCJleHBhbmRlcnMiLCJnZXRBY3RpdmVFeHBhbmRlcnMiLCJoZWFkZXJzIiwiaSIsImxlbmd0aCIsIm5hbWUiLCJnZXRBZ2dyZWdhdG9yTmFtZSIsInB1c2giLCJiYWNrZ3JvdW5kQ29sb3IiLCJmbGV4U2hyaW5rIiwidGV4dEFsaWduIiwiYmciLCJzZXAiLCJhbGlnbkl0ZW1zIiwiYm9yZGVyQm90dG9tIiwiVGFibGUiLCJ2aWV3cG9ydCIsInRvcCIsImN1cnNvciIsInRhcmdldCIsIk1hdGgiLCJmbG9vciIsInNjcm9sbFRvcCIsImNsaWVudEhlaWdodCIsImNlaWwiLCJyb3ciLCJuZXdDdXJzb3IiLCJjb250cmFjdCIsImNvbnNvbGUiLCJsb2ciLCJleHBhbmQiLCJfc2Nyb2xsRGl2Iiwic2Nyb2xsRGl2IiwiZ2V0Um93cyIsImtleUNvZGUiLCJfa2VlcEN1cnNvckluVmlld3BvcnQiLCJnZXRIZWlnaHQiLCJjYW5Db250cmFjdCIsIl9jb250cmFjdFJvdyIsImdldFJvd0luZGVudCIsImluZGVudCIsImNhbkV4cGFuZCIsIl9leHBhbmRSb3ciLCJzIiwiZCIsInN0YXJ0c1dpdGgiLCJzSW5kZXgiLCJwYXJzZUludCIsInN1YnN0ciIsImRJbmRleCIsImFjdGl2ZSIsImRyYWdnZWQiLCJzcGxpY2UiLCJzZXRBY3RpdmVBZ2dyZWdhdG9ycyIsInNldEFjdGl2ZUV4cGFuZGVycyIsInNFeHBhbmRlciIsInN1YnN0cmluZyIsImZsZXhHcm93Iiwic2Nyb2xsIiwiZGl2IiwicG9zaXRpb24iLCJyZW5kZXJWaXJ0dWFsaXplZFJvd3MiLCJyb3dzIiwicmVuZGVyUm93IiwiY2hpbGQiLCJjb2x1bW5zIiwicm93VGV4dCIsImFnZ3JlZ2F0ZXMiLCJwYXJlbnQiLCJhZ2dyZWdhdGUiLCJnZXRSb3dBZ2dyZWdhdGUiLCJtYXJnaW5MZWZ0IiwiZ2V0Um93TGFiZWwiLCJ3aGl0ZVNwYWNlIiwibWFyZ2luUmlnaHQiLCJrZXlkb3duIiwiYmluZCIsImRvY3VtZW50IiwiYm9keSIsImFkZEV2ZW50TGlzdGVuZXIiLCJyZW1vdmVFdmVudExpc3RlbmVyIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7O0FBU0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsR0FBTUEsV0FBWSxFQUFsQjtBQUNBLEdBQU1DLFlBQWEsRUFBbkIsQzs7QUFFTUMsUyxrRUFBb0M7QUFDeEMsbUJBQVlDLEtBQVosQ0FBbUI7QUFDWEEsS0FEVztBQUVsQixDOztBQUVRO0FBQ1AsR0FBTUMsSUFBSyxL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bnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTYtcHJlc2VudCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICovXG5cbid1c2Ugc3RyaWN0Jztcbi8qZXNsaW50IG5vLWNvbnNvbGUtZGlzYWxsb3c6IFwib2ZmXCIqL1xuLypnbG9iYWwgUmVhY3Q6dHJ1ZSovXG5cbi8vIFRPRE86XG4vLyBzZWxlY3Rpb24gYW5kIGFycm93IGtleXMgZm9yIG5hdmlnYXRpbmdcblxuY29uc3Qgcm93SGVpZ2h0ID0gMjA7XG5jb25zdCB0cmVlSW5kZW50ID0gMTY7XG5cbmNsYXNzIERyYWdnYWJsZSBleHRlbmRzIFJlYWN0LkNvbXBvbmVudCB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgY29uc3QgaWQgPSB0aGlzLnByb3BzLmlkO1xuICAgIHJldHVybiBSZWFjdC5jbG9uZUVsZW1lbnQoXG4gICAgICB0aGlzLnByb3BzLmNoaWxkcmVuLFxuICAgICAge1xuICAgICAgICBkcmFnZ2FibGU6ICd0cnVlJyxcbiAgICAgICAgb25EcmFnU3RhcnQ6IChlKSA9PiB7XG4gICAgICAgICAgZS5kYXRhVHJhbnNmZXIuc2V0RGF0YSgndGV4dCcsIGlkKTtcbiAgICAgICAgfSxcbiAgICAgIH1cbiAgICApO1xuICB9XG59XG5EcmFnZ2FibGUucHJvcFR5cGVzID0ge1xuICBjaGlsZHJlbjogUmVhY3QuUHJvcFR5cGVzLmVsZW1lbnQuaXNSZXF1aXJlZCxcbiAgaWQ6IFJlYWN0LlByb3BUeXBlcy5zdHJpbmcuaXNSZXF1aXJlZCxcbn07XG5cbmNsYXNzIERyb3BUYXJnZXQgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgc3VwZXIocHJvcHMpO1xuICB9XG5cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IHRoaXNJZCA9IHRoaXMucHJvcHMuaWQ7XG4gICAgY29uc3QgZHJvcEFjdGlvbiA9IHRoaXMucHJvcHMuZHJvcEFjdGlvbjtcbiAgICByZXR1cm4gUmVhY3QuY2xvbmVFbGVtZW50KFxuICAgICAgdGhpcy5wcm9wcy5jaGlsZHJlbixcbiAgICAgIHtcbiAgICAgICAgb25EcmFnT3ZlcjogKGUpID0+IGUucHJldmVudERlZmF1bHQoKSxcbiAgICAgICAgb25Ecm9wOiAoZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHNvdXJjZUlkID0gZS5kYXRhVHJhbnNmZXIuZ2V0RGF0YSgndGV4dCcpO1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICBkcm9wQWN0aW9uKHNvdXJjZUlkLCB0aGlzSWQpO1xuICAgICAgICB9LFxuICAgICAgfVxuICAgICk7XG4gIH1cbn1cblxuRHJvcFRhcmdldC5wcm9wVHlwZXMgPSB7XG4gIGNoaWxkcmVuOiBSZWFjdC5Qcm9wVHlwZXMuZWxlbWVudC5pc1JlcXVpcmVkLFxuICBpZDogUmVhY3QuUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICBkcm9wQWN0aW9uOiBSZWFjdC5Qcm9wVHlwZXMuZnVuYy5pc1JlcXVpcmVkLFxufTtcblxuY2xhc3MgRXhwYW5kZXJDb25maWd1cmF0aW9uIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gIH1cbiAgcmVuZGVyKCkge1xuICAgIGNvbnN0IGFnZ3JvdyA9IHRoaXMucHJvcHMuYWdncm93O1xuICAgIGNvbnN0IGV4cGFuZGVyID0gdGhpcy5wcm9wcy5leHBhbmRlcjtcbiAgICByZXR1cm4gKFxuICAgICAgPERyYWdnYWJsZSBpZD17J2V4cGFuZGVyOmFkZDonICsgZXhwYW5kZXIudG9TdHJpbmcoKX0+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBzdHlsZT17e1xuICAgICAgICAgICAgd2lkdGg6ICdhdXRvJyxcbiAgICAgICAgICAgIGhlaWdodDogJzI2cHgnLFxuICAgICAgICAgICAgYm9yZGVyOiAnMXB4IHNvbGlkIGRhcmtHcmF5JyxcbiAgICAgICAgICAgIG1hcmdpbjogJzJweCcsXG4gICAgICAgICAgfX0+XG4gICAgICAgICAge2FnZ3Jvdy5nZXRFeHBhbmRlck5hbWUoZXhwYW5kZXIpfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvRHJhZ2dhYmxlPlxuICAgICk7XG4gIH1cbn1cblxuY2xhc3MgVGFibGVDb25maWd1cmF0aW9uIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50IHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGV4cGFuZGVkOiBmYWxzZSxcbiAgICB9O1xuICB9XG4gIHJlbmRlckV4cGFuZGVyKGV4KSB7XG4gICAgcmV0dXJuICg8RXhwYW5kZXJDb25maWd1cmF0aW9uIGFnZ3Jvdz17dGhpcy5wcm9wcy5hZ2dyb3d9IGV4cGFuZGVyPXtleH0gLz4pO1xuICB9XG4gIHJlbmRlcigpIHtcbiAgICBjb25zdCBleHBhbmRlclRleHQgPSB0aGlzLnN0YXRlLmV4cGFuZGVkID8gJz4+JyA6ICc8PCc7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5wcm9wcy5hZ2dyb3c7XG4gICAgbGV0IGNvbmZpZyA9IFtdO1xuICAgIGlmICh0aGlzLnN0YXRlLmV4cGFuZGVkKSB7XG4gICAgICBjb25maWcgPSBhZ2dyb3cuZ2V0RXhwYW5kZXJzKCkubWFwKChleCkgPT4gdGhpcy5yZW5kZXJFeHBhbmRlcihleCkpO1xuICAgIH1cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgIHdpZHRoOiB0aGlzLnN0YXRlLmV4cGFuZGVkID8gJzUxMnB4JyA6ICcyNnB4JyxcbiAgICAgICAgICBoZWlnaHQ6ICcxMDAlJyxcbiAgICAgICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICAgICAgZmxleERpcmVjdGlvbjogJ2NvbHVtbicsXG4gICAgICAgICAgb3ZlcmZsb3c6ICdoaWRkZW4nLFxuICAgICAgICAgIGJvcmRlckxlZnQ6ICcycHggc29saWQgYmxhY2snLFxuICAgICAgICB9fT5cbiAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgICAgd2lkdGg6ICcxMDAlJyxcbiAgICAgICAgICAgIGhlaWdodDogJzI2cHgnLFxuICAgICAgICAgICAgYm9yZGVyOiAnMXB4IHNvbGlkIGRhcmtHcmF5JyxcbiAgICAgICAgICB9fVxuICAgICAgICAgIG9uQ2xpY2s9eyAoZSkgPT4gdGhpcy5zZXRTdGF0ZSh7ZXhwYW5kZWQ6ICF0aGlzLnN0YXRlLmV4cGFuZGVkfSkgfT5cbiAgICAgICAgICB7IGV4cGFuZGVyVGV4dCB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgICB7IGNvbmZpZyB9XG4gICAgICA8L2Rpdj5cbiAgICApO1xuICB9XG59XG5cblRhYmxlQ29uZmlndXJhdGlvbi5wcm9wVHlwZXMgPSB7XG4gIGFnZ3JvdzogUmVhY3QuUHJvcFR5cGVzLm9iamVjdC5pc1JlcXVpcmVkLFxufTtcblxuY2xhc3MgVGFibGVIZWFkZXIgZXh0ZW5kcyBSZWFjdC5Db21wb25lbnQge1xuICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgIHN1cGVyKHByb3BzKTtcbiAgfVxuICByZW5kZXIoKSB7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5wcm9wcy5hZ2dyb3c7XG4gICAgY29uc3QgYWdncmVnYXRvcnMgPSBhZ2dyb3cuZ2V0QWN0aXZlQWdncmVnYXRvcnMoKTtcbiAgICBjb25zdCBleHBhbmRlcnMgPSBhZ2dyb3cuZ2V0QWN0aXZlRXhwYW5kZXJzKCk7XG4gICAgY29uc3QgaGVhZGVycyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYWdncmVnYXRvcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IG5hbWUgPSBhZ2dyb3cuZ2V0QWdncmVnYXRvck5hbWUoYWdncmVnYXRvcnNbaV0pO1xuICAgICAgaGVhZGVycy5wdXNoKChcbiAgICAgICAgPERyb3BUYXJnZXRcbiAgICAgICAgICBpZD17J2FnZ3JlZ2F0ZTppbnNlcnQ6JyArIGkudG9TdHJpbmcoKX1cbiAgICAgICAgICBkcm9wQWN0aW9uPXt0aGlzLnByb3BzLmRyb3BBY3Rpb259XG4gICAgICAgID5cbiAgICAgICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgICAgICB3aWR0aDogJzE2cHgnLFxuICAgICAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6ICdkYXJrR3JheScsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCcgfX1cbiAgICAgICAgICA+PC9kaXY+XG4gICAgICAgIDwvRHJvcFRhcmdldD4pKTtcbiAgICAgIGhlYWRlcnMucHVzaCgoPERyYWdnYWJsZSBpZD17J2FnZ3JlZ2F0ZTphY3RpdmU6JyArIGkudG9TdHJpbmcoKX0+XG4gICAgICAgICAgPGRpdiBzdHlsZT17eyB3aWR0aDogJzEyOHB4JywgdGV4dEFsaWduOiAnY2VudGVyJywgZmxleFNocmluazogJzAnIH19PntuYW1lfTwvZGl2PlxuICAgICAgICA8L0RyYWdnYWJsZT4pKTtcbiAgICB9XG4gICAgaGVhZGVycy5wdXNoKChcbiAgICAgIDxEcm9wVGFyZ2V0XG4gICAgICAgIGlkPVwiZGl2aWRlcjppbnNlcnRcIlxuICAgICAgICBkcm9wQWN0aW9uPXt0aGlzLnByb3BzLmRyb3BBY3Rpb259XG4gICAgICA+XG4gICAgICAgIDxkaXYgc3R5bGU9e3tcbiAgICAgICAgICB3aWR0aDogJzE2cHgnLFxuICAgICAgICAgIGhlaWdodDogJ2luaGVyaXQnLFxuICAgICAgICAgIGJhY2tncm91bmRDb2xvcjogJ2dvbGQnLFxuICAgICAgICAgIGZsZXhTaHJpbms6ICcwJ1xuICAgICAgICB9fT48L2Rpdj5cbiAgICAgIDwvRHJvcFRhcmdldD4pKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGV4cGFuZGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgbmFtZSA9IGFnZ3Jvdy5nZXRFeHBhbmRlck5hbWUoZXhwYW5kZXJzW2ldKTtcbiAgICAgIGNvbnN0IGJnID0gKGkgJSAyID09PSAwKSA/ICd3aGl0ZScgOiAnbGlnaHRHcmF5JztcbiAgICAgIGhlYWRlcnMucHVzaCgoPERyYWdnYWJsZSBpZD17J2V4cGFuZGVyOmFjdGl2ZTonICsgaS50b1N0cmluZygpfT5cbiAgICAgICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgICAgICB3aWR0aDogJzEyOHB4JyxcbiAgICAgICAgICAgIHRleHRBbGlnbjogJ2NlbnRlcicsXG4gICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6IGJnLFxuICAgICAgICAgICAgZmxleFNocmluazogJzAnXG4gICAgICAgICAgfX0+XG4gICAgICAgICAgICB7bmFtZX1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9EcmFnZ2FibGU+KSk7XG4gICAgICBjb25zdCBzZXAgPSBpICsgMSA8IGV4cGFuZGVycy5sZW5ndGggPyAnLT4nIDogJy4uLic7XG4gICAgICBoZWFkZXJzLnB1c2goKFxuICAgICAgICA8RHJvcFRhcmdldFxuICAgICAgICAgIGlkPXsnZXhwYW5kZXI6aW5zZXJ0OicgKyAoaSArIDEpLnRvU3RyaW5nKCl9XG4gICAgICAgICAgZHJvcEFjdGlvbj17dGhpcy5wcm9wcy5kcm9wQWN0aW9ufVxuICAgICAgICA+XG4gICAgICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICAgICAgaGVpZ2h0OiAnaW5oZXJpdCcsXG4gICAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6ICdkYXJrR3JheScsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCdcbiAgICAgICAgICB9fT5cbiAgICAgICAgICAgIHtzZXB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvRHJvcFRhcmdldD4pXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICB3aWR0aDogJzEwMCUnLFxuICAgICAgICBoZWlnaHQ6ICcyNnB4JyxcbiAgICAgICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgICAgICBmbGV4RGlyZWN0aW9uOiAncm93JyxcbiAgICAgICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXG4gICAgICAgIGJvcmRlckJvdHRvbTogJzJweCBzb2xpZCBibGFjaycsXG4gICAgICB9fT5cbiAgICAgICAge2hlYWRlcnN9XG4gICAgICA8L2Rpdj5cbiAgICApO1xuICB9XG59XG5cblRhYmxlSGVhZGVyLnByb3BUeXBlcyA9IHtcbiAgYWdncm93OiBSZWFjdC5Qcm9wVHlwZXMub2JqZWN0LmlzUmVxdWlyZWQsXG4gIGRyb3BBY3Rpb246IFJlYWN0LlByb3BUeXBlcy5mdW5jLmlzUmVxdWlyZWQsXG59O1xuXG5jbGFzcyBUYWJsZSBleHRlbmRzIFJlYWN0LkNvbXBvbmVudCB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW51c2VkLXZhcnNcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGFnZ3JvdzogcHJvcHMuYWdncm93LFxuICAgICAgdmlld3BvcnQ6IHsgdG9wOiAwLCBoZWlnaHQ6IDEwMCB9LFxuICAgICAgY3Vyc29yOiAwLFxuICAgIH07XG4gIH1cblxuICBzY3JvbGwoZSkge1xuICAgIGNvbnN0IHZpZXdwb3J0ID0gZS50YXJnZXQ7XG4gICAgY29uc3QgdG9wID0gTWF0aC5mbG9vcigodmlld3BvcnQuc2Nyb2xsVG9wIC0gdmlld3BvcnQuY2xpZW50SGVpZ2h0ICogMS4wKSAvIHJvd0hlaWdodCk7XG4gICAgY29uc3QgaGVpZ2h0ID0gTWF0aC5jZWlsKHZpZXdwb3J0LmNsaWVudEhlaWdodCAqIDMuMCAvIHJvd0hlaWdodCk7XG4gICAgaWYgKHRvcCAhPT0gdGhpcy5zdGF0ZS52aWV3cG9ydC50b3AgfHwgaGVpZ2h0ICE9PSB0aGlzLnN0YXRlLnZpZXdwb3J0LmhlaWdodCkge1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7dmlld3BvcnQ6IHt0b3AsIGhlaWdodH19KTtcbiAgICB9XG4gIH1cblxuICBfY29udHJhY3RSb3cocm93KSB7XG4gICAgbGV0IG5ld0N1cnNvciA9IHRoaXMuc3RhdGUuY3Vyc29yO1xuICAgIGlmIChuZXdDdXJzb3IgPiByb3cudG9wICYmIG5ld0N1cnNvciA8IHJvdy50b3AgKyByb3cuaGVpZ2h0KSB7IC8vIGluIGNvbnRyYWN0ZWQgc2VjdGlvblxuICAgICAgbmV3Q3Vyc29yID0gcm93LnRvcDtcbiAgICB9IGVsc2UgaWYgKG5ld0N1cnNvciA+PSByb3cudG9wICsgcm93LmhlaWdodCkgeyAvLyBiZWxvdyBjb250cmFjdGVkIHNlY3Rpb25cbiAgICAgIG5ld0N1cnNvciAtPSByb3cuaGVpZ2h0IC0gMTtcbiAgICB9XG4gICAgdGhpcy5zdGF0ZS5hZ2dyb3cuY29udHJhY3Qocm93KTtcbiAgICB0aGlzLnNldFN0YXRlKHtjdXJzb3I6IG5ld0N1cnNvcn0pO1xuICAgIGNvbnNvbGUubG9nKCctJyArIHJvdy50b3ApO1xuICB9XG5cbiAgX2V4cGFuZFJvdyhyb3cpIHtcbiAgICBsZXQgbmV3Q3Vyc29yID0gdGhpcy5zdGF0ZS5jdXJzb3I7XG4gICAgdGhpcy5zdGF0ZS5hZ2dyb3cuZXhwYW5kKHJvdyk7XG4gICAgaWYgKG5ld0N1cnNvciA+IHJvdy50b3ApIHsgIC8vIGJlbG93IGV4cGFuZGVkIHNlY3Rpb25cbiAgICAgIG5ld0N1cnNvciArPSByb3cuaGVpZ2h0IC0gMTtcbiAgICB9XG4gICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOiBuZXdDdXJzb3J9KTtcbiAgICBjb25zb2xlLmxvZygnKycgKyByb3cudG9wKTtcbiAgfVxuXG4gIF9zY3JvbGxEaXY6IG51bGw7XG5cbiAgX2tlZXBDdXJzb3JJblZpZXdwb3J0KCkge1xuICAgIGlmICh0aGlzLl9zY3JvbGxEaXYpIHtcbiAgICAgIGNvbnN0IGN1cnNvciA9IHRoaXMuc3RhdGUuY3Vyc29yO1xuICAgICAgY29uc3Qgc2Nyb2xsRGl2ID0gdGhpcy5fc2Nyb2xsRGl2O1xuICAgICAgaWYgKGN1cnNvciAqIHJvd0hlaWdodCA8IHNjcm9sbERpdi5zY3JvbGxUb3AgKyBzY3JvbGxEaXYuY2xpZW50SGVpZ2h0ICogMC4xKSB7XG4gICAgICAgIHNjcm9sbERpdi5zY3JvbGxUb3AgPSBjdXJzb3IgKiByb3dIZWlnaHQgLSBzY3JvbGxEaXYuY2xpZW50SGVpZ2h0ICogMC4xO1xuICAgICAgfSBlbHNlIGlmICgoY3Vyc29yICsgMSkgKiByb3dIZWlnaHQgPiBzY3JvbGxEaXYuc2Nyb2xsVG9wICsgc2Nyb2xsRGl2LmNsaWVudEhlaWdodCAqIDAuOSkge1xuICAgICAgICBzY3JvbGxEaXYuc2Nyb2xsVG9wID0gKGN1cnNvciArIDEpICogcm93SGVpZ2h0IC0gc2Nyb2xsRGl2LmNsaWVudEhlaWdodCAqIDAuOTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBrZXlkb3duKGUpIHtcbiAgICBjb25zdCBhZ2dyb3cgPSB0aGlzLnN0YXRlLmFnZ3JvdztcbiAgICBsZXQgY3Vyc29yID0gdGhpcy5zdGF0ZS5jdXJzb3I7XG4gICAgbGV0IHJvdyA9IGFnZ3Jvdy5nZXRSb3dzKGN1cnNvciwgMSlbMF07XG4gICAgc3dpdGNoIChlLmtleUNvZGUpIHtcbiAgICAgIGNhc2UgMzg6IC8vIHVwXG4gICAgICAgIGlmIChjdXJzb3IgPiAwKSB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOiBjdXJzb3IgLSAxfSk7XG4gICAgICAgICAgdGhpcy5fa2VlcEN1cnNvckluVmlld3BvcnQoKTtcbiAgICAgICAgfVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA0MDogLy8gZG93blxuICAgICAgICBpZiAoY3Vyc29yIDwgYWdncm93LmdldEhlaWdodCgpIC0gMSkge1xuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjogY3Vyc29yICsgMX0pO1xuICAgICAgICAgIHRoaXMuX2tlZXBDdXJzb3JJblZpZXdwb3J0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzc6IC8vIGxlZnRcbiAgICAgICAgaWYgKGFnZ3Jvdy5jYW5Db250cmFjdChyb3cpKSB7XG4gICAgICAgICAgdGhpcy5fY29udHJhY3RSb3cocm93KTtcbiAgICAgICAgfSBlbHNlIGlmIChhZ2dyb3cuZ2V0Um93SW5kZW50KHJvdykgPiAwKSB7XG4gICAgICAgICAgY29uc3QgaW5kZW50ID0gYWdncm93LmdldFJvd0luZGVudChyb3cpIC0gMTtcbiAgICAgICAgICB3aGlsZSAoYWdncm93LmdldFJvd0luZGVudChyb3cpID4gaW5kZW50KSB7XG4gICAgICAgICAgICBjdXJzb3ItLTtcbiAgICAgICAgICAgIHJvdyA9IGFnZ3Jvdy5nZXRSb3dzKGN1cnNvciwgMSlbMF07XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjogY3Vyc29yfSk7XG4gICAgICAgICAgdGhpcy5fa2VlcEN1cnNvckluVmlld3BvcnQoKTtcbiAgICAgICAgfVxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOTogLy8gcmlnaHRcbiAgICAgICAgaWYgKGFnZ3Jvdy5jYW5FeHBhbmQocm93KSkge1xuICAgICAgICAgIHRoaXMuX2V4cGFuZFJvdyhyb3cpO1xuICAgICAgICB9IGVsc2UgaWYgKGN1cnNvciA8IGFnZ3Jvdy5nZXRIZWlnaHQoKSAtIDEpIHtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlKHtjdXJzb3I6IGN1cnNvciArIDF9KTtcbiAgICAgICAgICB0aGlzLl9rZWVwQ3Vyc29ySW5WaWV3cG9ydCgpO1xuICAgICAgICB9XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgZHJvcEFjdGlvbihzLCBkKSB7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5zdGF0ZS5hZ2dyb3c7XG4gICAgY29uc29sZS5sb2coJ2Ryb3BwZWQgJyArIHMgKyAnIHRvICcgKyBkKTtcbiAgICBpZiAocy5zdGFydHNXaXRoKCdhZ2dyZWdhdGU6YWN0aXZlOicpKSB7XG4gICAgICBjb25zdCBzSW5kZXggPSBwYXJzZUludChzLnN1YnN0cigxNyksIDEwKTtcbiAgICAgIGxldCBkSW5kZXggPSAtMTtcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IGFnZ3Jvdy5nZXRBY3RpdmVBZ2dyZWdhdG9ycygpO1xuICAgICAgY29uc3QgZHJhZ2dlZCA9IGFjdGl2ZVtzSW5kZXhdO1xuICAgICAgaWYgKGQuc3RhcnRzV2l0aCgnYWdncmVnYXRlOmluc2VydDonKSkge1xuICAgICAgICBkSW5kZXggPSBwYXJzZUludChkLnN1YnN0cigxNyksIDEwKTtcbiAgICAgIH0gZWxzZSBpZiAoZCA9PT0gJ2RpdmlkZXI6aW5zZXJ0Jykge1xuICAgICAgICBkSW5kZXggPSBhY3RpdmUubGVuZ3RoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgJ25vdCBhbGxvd2VkIHRvIGRyYWcgJyArIHMgKyAnIHRvICcgKyBkO1xuICAgICAgfVxuICAgICAgaWYgKGRJbmRleCA+IHNJbmRleCkge1xuICAgICAgICBkSW5kZXgtLTtcbiAgICAgIH1cbiAgICAgIGFjdGl2ZS5zcGxpY2Uoc0luZGV4LCAxKTtcbiAgICAgIGFjdGl2ZS5zcGxpY2UoZEluZGV4LCAwLCBkcmFnZ2VkKTtcbiAgICAgIGFnZ3Jvdy5zZXRBY3RpdmVBZ2dyZWdhdG9ycyhhY3RpdmUpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOjB9KTtcbiAgICB9IGVsc2UgaWYgKHMuc3RhcnRzV2l0aCgnZXhwYW5kZXI6YWN0aXZlOicpKSB7XG4gICAgICBjb25zdCBzSW5kZXggPSBwYXJzZUludChzLnN1YnN0cigxNiksIDEwKTtcbiAgICAgIGxldCBkSW5kZXggPSAtMTtcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IGFnZ3Jvdy5nZXRBY3RpdmVFeHBhbmRlcnMoKTtcbiAgICAgIGNvbnN0IGRyYWdnZWQgPSBhY3RpdmVbc0luZGV4XTtcbiAgICAgIGlmIChkLnN0YXJ0c1dpdGgoJ2V4cGFuZGVyOmluc2VydDonKSkge1xuICAgICAgICBkSW5kZXggPSBwYXJzZUludChkLnN1YnN0cigxNiksIDEwKTtcbiAgICAgIH0gZWxzZSBpZiAoZCA9PT0gJ2RpdmlkZXI6aW5zZXJ0Jykge1xuICAgICAgICBkSW5kZXggPSAwO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgJ25vdCBhbGxvd2VkIHRvIGRyYWcgJyArIHMgKyAnIHRvICcgKyBkO1xuICAgICAgfVxuICAgICAgaWYgKGRJbmRleCA+IHNJbmRleCkge1xuICAgICAgICBkSW5kZXgtLTtcbiAgICAgIH1cbiAgICAgIGFjdGl2ZS5zcGxpY2Uoc0luZGV4LCAxKTtcbiAgICAgIGFjdGl2ZS5zcGxpY2UoZEluZGV4LCAwLCBkcmFnZ2VkKTtcbiAgICAgIGFnZ3Jvdy5zZXRBY3RpdmVFeHBhbmRlcnMoYWN0aXZlKTtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe2N1cnNvcjowfSk7XG4gICAgfSBlbHNlIGlmIChzLnN0YXJ0c1dpdGgoJ2V4cGFuZGVyOmFkZDonKSkge1xuICAgICAgbGV0IGRJbmRleCA9IC0xO1xuICAgICAgY29uc3Qgc0V4cGFuZGVyID0gcGFyc2VJbnQocy5zdWJzdHJpbmcoMTMpLCAxMCk7XG4gICAgICBpZiAoZC5zdGFydHNXaXRoKCdleHBhbmRlcjppbnNlcnQ6JykpIHtcbiAgICAgICAgZEluZGV4ID0gcGFyc2VJbnQoZC5zdWJzdHIoMTYpLCAxMCk7XG4gICAgICB9IGVsc2UgaWYgKGQgPT09ICdkaXZpZGVyOmluc2VydCcpIHtcbiAgICAgICAgZEluZGV4ID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93ICdub3QgYWxsb3dlZCB0byBkcmFnICcgKyBzICsgJyB0byAnICsgZDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGFjdGl2ZSA9IGFnZ3Jvdy5nZXRBY3RpdmVFeHBhbmRlcnMoKTtcbiAgICAgIGFjdGl2ZS5zcGxpY2UoZEluZGV4LCAwLCBzRXhwYW5kZXIpO1xuICAgICAgYWdncm93LnNldEFjdGl2ZUV4cGFuZGVycyhhY3RpdmUpO1xuICAgICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOjB9KTtcbiAgICB9XG4gIH1cblxuICByZW5kZXIoKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIDxkaXYgc3R5bGU9e3sgd2lkdGg6ICcxMDAlJywgaGVpZ2h0OiAnMTAwJScsIGRpc3BsYXk6ICdmbGV4JywgZmxleERpcmVjdGlvbjogJ3JvdycgfX0+XG4gICAgICAgIDxkaXYgc3R5bGU9e3sgd2lkdGg6ICcxMDAlJywgaGVpZ2h0OiAnMTAwJScsIGRpc3BsYXk6ICdmbGV4JywgZmxleERpcmVjdGlvbjogJ2NvbHVtbicsIG92ZXJmbG93OiAnaGlkZGVuJywgfX0+XG4gICAgICAgICAgPFRhYmxlSGVhZGVyIGFnZ3Jvdz17dGhpcy5zdGF0ZS5hZ2dyb3d9IGRyb3BBY3Rpb249eyhzLCBkKSA9PiB0aGlzLmRyb3BBY3Rpb24ocywgZCl9IC8+XG4gICAgICAgICAgPGRpdlxuICAgICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgICAgd2lkdGg6ICcxMDAlJyxcbiAgICAgICAgICAgICAgZmxleEdyb3c6ICcxJyxcbiAgICAgICAgICAgICAgb3ZlcmZsb3c6ICdzY3JvbGwnXG4gICAgICAgICAgICB9fVxuICAgICAgICAgICAgb25TY3JvbGw9eyAoZSkgPT4gdGhpcy5zY3JvbGwoZSkgfVxuICAgICAgICAgICAgcmVmPXsoZGl2KSA9PiB7IHRoaXMuX3Njcm9sbERpdiA9IGRpdjsgfSB9PlxuICAgICAgICAgICAgPGRpdiBzdHlsZT17eyBwb3NpdGlvbjogJ3JlbGF0aXZlJyB9fT5cbiAgICAgICAgICAgICAgeyB0aGlzLnJlbmRlclZpcnR1YWxpemVkUm93cygpIH1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPFRhYmxlQ29uZmlndXJhdGlvbiBhZ2dyb3c9e3RoaXMuc3RhdGUuYWdncm93fSAvPlxuICAgICAgPC9kaXY+XG4gICAgKTtcbiAgfVxuXG4gIHJlbmRlclZpcnR1YWxpemVkUm93cygpIHtcbiAgICBjb25zdCBhZ2dyb3cgPSB0aGlzLnN0YXRlLmFnZ3JvdztcbiAgICBjb25zdCB2aWV3cG9ydCA9IHRoaXMuc3RhdGUudmlld3BvcnQ7XG4gICAgY29uc3Qgcm93cyA9IGFnZ3Jvdy5nZXRSb3dzKHZpZXdwb3J0LnRvcCwgdmlld3BvcnQuaGVpZ2h0KTtcbiAgICByZXR1cm4gKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgICAgd2lkdGg6ICcxMDAlJyxcbiAgICAgICAgaGVpZ2h0OiAocm93SGVpZ2h0ICogKGFnZ3Jvdy5nZXRIZWlnaHQoKSArIDIwKSkudG9TdHJpbmcoKSArICdweCdcbiAgICAgIH19PlxuICAgICAgICB7IHJvd3MubWFwKGNoaWxkID0+IHRoaXMucmVuZGVyUm93KGNoaWxkKSkgfVxuICAgICAgPC9kaXY+XG4gICAgKTtcbiAgfVxuXG4gIHJlbmRlclJvdyhyb3cpIHtcbiAgICBpZiAocm93ID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgbGV0IGJnID0gJ2xpZ2h0R3JheSc7XG4gICAgY29uc3QgYWdncm93ID0gdGhpcy5zdGF0ZS5hZ2dyb3c7XG4gICAgY29uc3QgY29sdW1ucyA9IFtdO1xuICAgIGxldCByb3dUZXh0ID0gJyc7XG4gICAgY29uc3QgaW5kZW50ID0gNCArIGFnZ3Jvdy5nZXRSb3dJbmRlbnQocm93KSAqIHRyZWVJbmRlbnQ7XG4gICAgY29uc3QgYWdncmVnYXRlcyA9IGFnZ3Jvdy5nZXRBY3RpdmVBZ2dyZWdhdG9ycygpO1xuICAgIGlmIChyb3cucGFyZW50ICE9PSBudWxsICYmIChyb3cucGFyZW50LmV4cGFuZGVyICUgMiA9PT0gMCkpIHtcbiAgICAgIGJnID0gJ3doaXRlJztcbiAgICB9XG4gICAgaWYgKHJvdy50b3AgPT09IHRoaXMuc3RhdGUuY3Vyc29yKSB7XG4gICAgICBiZyA9ICdsaWdodGJsdWUnO1xuICAgIH1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFnZ3JlZ2F0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBhZ2dyZWdhdGUgPSBhZ2dyb3cuZ2V0Um93QWdncmVnYXRlKHJvdywgaSk7XG4gICAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgICAgd2lkdGg6ICcxNnB4JyxcbiAgICAgICAgICBoZWlnaHQ6ICdpbmhlcml0JyxcbiAgICAgICAgICBiYWNrZ3JvdW5kQ29sb3I6ICdkYXJrR3JheScsXG4gICAgICAgICAgZmxleFNocmluazogJzAnXG4gICAgICAgIH19PjwvZGl2PlxuICAgICAgKSk7XG4gICAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgICAgd2lkdGg6ICcxMjhweCcsXG4gICAgICAgICAgdGV4dEFsaWduOiAncmlnaHQnLFxuICAgICAgICAgIGZsZXhTaHJpbms6ICcwJ1xuICAgICAgICB9fT5cbiAgICAgICAgICB7YWdncmVnYXRlfVxuICAgICAgICA8L2Rpdj5cbiAgICAgICkpO1xuICAgIH1cbiAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgPGRpdiBzdHlsZT17e1xuICAgICAgICB3aWR0aDogJzE2cHgnLFxuICAgICAgICBoZWlnaHQ6ICdpbmhlcml0JyxcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiAnZ29sZCcsXG4gICAgICAgIGZsZXhTaHJpbms6ICcwJ1xuICAgICAgfX0+PC9kaXY+XG4gICAgKSk7XG4gICAgaWYgKGFnZ3Jvdy5jYW5FeHBhbmQocm93KSkge1xuICAgICAgY29sdW1ucy5wdXNoKChcbiAgICAgICAgPGRpdlxuICAgICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgICBtYXJnaW5MZWZ0OiBpbmRlbnQudG9TdHJpbmcoKSArICdweCcsXG4gICAgICAgICAgICBmbGV4U2hyaW5rOiAnMCcsXG4gICAgICAgICAgICB3aWR0aDogJzEycHgnLFxuICAgICAgICAgICAgdGV4dEFsaWduOiAnY2VudGVyJyxcbiAgICAgICAgICAgIGJvcmRlcjogJzFweCBzb2xpZCBncmF5JyxcbiAgICAgICAgICB9fVxuICAgICAgICAgIG9uQ2xpY2s9eyAoKSA9PiB0aGlzLl9leHBhbmRSb3cocm93KSB9XG4gICAgICAgID4rPC9kaXY+XG4gICAgICApKTtcbiAgICB9IGVsc2UgaWYgKGFnZ3Jvdy5jYW5Db250cmFjdChyb3cpKSB7XG4gICAgICBjb2x1bW5zLnB1c2goKFxuICAgICAgICA8ZGl2XG4gICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgIG1hcmdpbkxlZnQ6IGluZGVudC50b1N0cmluZygpICsgJ3B4JyxcbiAgICAgICAgICAgIGZsZXhTaHJpbms6ICcwJyxcbiAgICAgICAgICAgIHdpZHRoOiAnMTJweCcsXG4gICAgICAgICAgICB0ZXh0QWxpZ246ICdjZW50ZXInLFxuICAgICAgICAgICAgYm9yZGVyOiAnMXB4IHNvbGlkIGdyYXknLFxuICAgICAgICAgIH19XG4gICAgICAgICAgb25DbGljaz17ICgpID0+IHRoaXMuX2NvbnRyYWN0Um93KHJvdykgfVxuICAgICAgICA+LTwvZGl2PlxuICAgICAgKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbHVtbnMucHVzaCgoXG4gICAgICAgIDxkaXZcbiAgICAgICAgICBzdHlsZT17e1xuICAgICAgICAgICAgbWFyZ2luTGVmdDogaW5kZW50LnRvU3RyaW5nKCkgKyAncHgnLFxuICAgICAgICAgIH19XG4gICAgICAgID48L2Rpdj5cbiAgICAgICkpO1xuICAgIH1cbiAgICByb3dUZXh0ICs9IGFnZ3Jvdy5nZXRSb3dMYWJlbChyb3cpO1xuICAgIGNvbHVtbnMucHVzaCgoXG4gICAgICA8ZGl2IHN0eWxlPXt7XG4gICAgICAgIGZsZXhTaHJpbms6ICcwJyxcbiAgICAgICAgd2hpdGVTcGFjZTogJ25vd3JhcCcsXG4gICAgICAgIG1hcmdpblJpZ2h0OiAnMjBweCdcbiAgICAgIH19PlxuICAgICAgICB7cm93VGV4dH1cbiAgICAgIDwvZGl2PlxuICAgICkpO1xuICAgIHJldHVybiAoXG4gICAgICA8ZGl2XG4gICAgICAgIGtleT17cm93LnRvcH1cbiAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgICAgICBoZWlnaHQ6IChyb3dIZWlnaHQgLSAxKS50b1N0cmluZygpICsgJ3B4JyxcbiAgICAgICAgICB0b3A6IChyb3dIZWlnaHQgKiByb3cudG9wKS50b1N0cmluZygpICsgJ3B4JyxcbiAgICAgICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICAgICAgZmxleERpcmVjdGlvbjogJ3JvdycsXG4gICAgICAgICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXG4gICAgICAgICAgYmFja2dyb3VuZENvbG9yOiBiZyxcbiAgICAgICAgICBib3JkZXJCb3R0b206ICcxcHggc29saWQgZ3JheScsXG4gICAgICAgIH19XG4gICAgICAgIG9uQ2xpY2s9eyAoKSA9PiB7XG4gICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7Y3Vyc29yOiByb3cudG9wfSk7XG4gICAgICAgIH19PlxuICAgICAgICB7Y29sdW1uc31cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cblxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICB0aGlzLmtleWRvd24gPSB0aGlzLmtleWRvd24uYmluZCh0aGlzKTtcbiAgICBkb2N1bWVudC5ib2R5LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmtleWRvd24pO1xuICB9XG5cbiAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXlkb3duJywgdGhpcy5rZXlkb3duKTtcbiAgfVxufVxuIl19
// @generated
diff --git a/local-cli/server/middleware/heapCapture/src/aggrow.js b/local-cli/server/middleware/heapCapture/src/aggrow.js
index a6c51df55..4be1edeae 100644
--- a/local-cli/server/middleware/heapCapture/src/aggrow.js
+++ b/local-cli/server/middleware/heapCapture/src/aggrow.js
@@ -16,7 +16,7 @@
// pivot around frames in the middle of a stack by callers / callees
// graphing?
-function stringInterner() { // eslint-disable-line no-unused-vars
+function StringInterner() { // eslint-disable-line no-unused-vars
const strings = [];
const ids = {};
return {
@@ -37,20 +37,16 @@ function stringInterner() { // eslint-disable-line no-unused-vars
};
}
-function stackData(stackIdMap, maxDepth) { // eslint-disable-line no-unused-vars
- return {
- maxDepth: maxDepth,
- get: function getStack(id) {
- return stackIdMap[id];
- },
- };
-}
-
-function stackRegistry() { // eslint-disable-line no-unused-vars
+function StackRegistry() { // eslint-disable-line no-unused-vars
return {
root: { id: 0 },
nodeCount: 1,
+ maxDepth: -1,
+ stackIdMap: null,
insert: function insertNode(parent, frameId) {
+ if (this.stackIdMap !== null) {
+ throw 'stacks already flattened';
+ }
let node = parent[frameId];
if (node === undefined) {
node = { id: this.nodeCount };
@@ -59,7 +55,13 @@ function stackRegistry() { // eslint-disable-line no-unused-vars
}
return node;
},
+ get: function getStackArray(id) {
+ return this.stackIdMap[id];
+ },
flatten: function flattenStacks() {
+ if (this.stackIdMap !== null) {
+ return;
+ }
let stackFrameCount = 0;
function countStacks(tree, depth) {
let leaf = true;
@@ -109,13 +111,150 @@ function stackRegistry() { // eslint-disable-line no-unused-vars
return stackIdMap[id];
}
flattenStacksImpl(this.root, []);
-
- return new stackData(stackIdMap, maxStackDepth);
+ this.root = null;
+ this.stackIdMap = stackIdMap;
+ this.maxDepth = maxStackDepth;
},
};
}
-function aggrow(numRows) { // eslint-disable-line no-unused-vars
+function AggrowData(columns) { // eslint-disable-line no-unused-vars
+ const columnCount = columns.length;
+ const columnConverter = columns.map(c => {
+ switch (c.type) {
+ case 'int': // stores raw value
+ return (i) => i;
+ case 'string': // stores interned id of string
+ return (s) => c.strings.intern(s);
+ case 'stack': // stores id of stack node
+ return (s) => s.id;
+ default:
+ throw 'unknown AggrowData column type';
+ }
+ });
+ return {
+ data: new Int32Array(0),
+ columns: columns,
+ rowCount: 0,
+ rowInserter: function rowInserter(numRows) {
+ console.log(
+ 'increasing row data from ' + (this.data.length * 4).toLocaleString() + ' B to ' +
+ (this.data.length * 4 + numRows * columnCount * 4).toLocaleString() + ' B'
+ );
+ const newData = new Int32Array(this.data.length + numRows * columnCount);
+ newData.set(this.data);
+ let currOffset = this.data.length;
+ const endOffset = newData.length;
+ this.data = newData;
+ this.rowCount = newData.length / columnCount;
+ return {
+ insertRow: function insertRow() {
+ if (currOffset >= endOffset) {
+ throw 'tried to insert data off end of added range';
+ }
+ if (arguments.length !== columnCount) {
+ throw 'expected data for ' + columnCount.toString() + ' columns, got' +
+ arguments.length.toString() + ' columns';
+ }
+ for (let i = 0; i < arguments.length; i++) {
+ newData[currOffset + i] = columnConverter[i](arguments[i]);
+ }
+ currOffset += columnCount;
+ },
+ done: function done() {
+ if (currOffset !== endOffset) {
+ throw 'unfilled rows';
+ }
+ },
+ };
+ },
+ };
+}
+
+function Aggrow(aggrowData) {
+ const columns = aggrowData.columns;
+ const columnCount = columns.length;
+ const data = aggrowData.data;
+ function columnIndex(columnName, columnType) {
+ const index = columns.findIndex(c => c.name === columnName && c.type === columnType);
+ if (index < 0) {
+ throw 'did not find data column ' + columnName + ' with type ' + columnType;
+ }
+ return index;
+ }
+ for (let i = 0; i < columns.length; i++) {
+ if (columns[i].type === 'stack') {
+ columns[i].stacks.flatten();
+ }
+ }
+ return {
+ expander: new AggrowExpander(aggrowData.rowCount),
+ addSumAggregator: function addSumAggregator(aggregatorName, columnName) {
+ const index = columnIndex(columnName, 'int');
+ return this.expander.addAggregator(
+ aggregatorName,
+ function aggregateSize(indices) {
+ let size = 0;
+ for (let i = 0; i < indices.length; i++) {
+ const row = indices[i];
+ size += data[row * columnCount + index];
+ }
+ return size;
+ },
+ (value) => value.toLocaleString(),
+ (a, b) => b - a,
+ );
+ },
+ addCountAggregator: function addCountAggregator(aggregatorName) {
+ return this.expander.addAggregator(
+ aggregatorName,
+ function aggregateCount(indices) {
+ return indices.length;
+ },
+ (value) => value.toLocaleString(),
+ (a, b) => b - a,
+ );
+ },
+ addStringExpander: function addStringExpander(expanderName, columnName) {
+ const index = columnIndex(columnName, 'string');
+ const strings = columns[index].strings;
+ return this.expander.addFieldExpander(
+ expanderName,
+ (row) => strings.get(data[row * columnCount + index]),
+ (rowA, rowB) => data[rowA * columnCount + index] - data[rowB * columnCount + index],
+ );
+ },
+ addNumberExpander: function addNumberExpander(expanderName, columnName) {
+ const index = columnIndex(columnName, 'int');
+ return this.expander.addFieldExpander(
+ expanderName,
+ (row) => data[row * columnCount + index].toLocaleString(),
+ (rowA, rowB) => data[rowA * columnCount + index] - data[rowB * columnCount + index],
+ );
+ },
+ addPointerExpander: function addPointerExpander(expanderName, columnName) {
+ const index = columnIndex(columnName, 'int');
+ return this.expander.addFieldExpander(
+ expanderName,
+ (row) => '0x' + (data[row * columnCount + index] >>> 0).toString(),
+ (rowA, rowB) => data[rowA * columnCount + index] - data[rowB * columnCount + index],
+ );
+ },
+ addStackExpander: function addStackExpander(expanderName, columnName, formatter) {
+ // TODO: options for caller/callee, pivoting
+ const index = columnIndex(columnName, 'stack');
+ const stacks = columns[index].stacks;
+ return this.expander.addCalleeStackExpander(
+ expanderName,
+ stacks.maxDepth,
+ (row) => stacks.get(data[row * columnCount + index]),
+ formatter,
+ );
+ },
+ };
+}
+
+function AggrowExpander(numRows) { // eslint-disable-line no-unused-vars
// expander ID definitions
const FIELD_EXPANDER_ID_MIN = 0x0000;
const FIELD_EXPANDER_ID_MAX = 0x7fff;
diff --git a/local-cli/server/middleware/heapCapture/src/heapCapture.js b/local-cli/server/middleware/heapCapture/src/heapCapture.js
index 7af43b379..4d4099b19 100644
--- a/local-cli/server/middleware/heapCapture/src/heapCapture.js
+++ b/local-cli/server/middleware/heapCapture/src/heapCapture.js
@@ -8,7 +8,7 @@
*/
'use strict';
/*eslint no-console-disallow: "off"*/
-/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
+/*global React ReactDOM Table StringInterner StackRegistry AggrowData Aggrow preLoadedCapture:true*/
function RefVisitor(refs, id) {
this.refs = refs;
@@ -292,189 +292,88 @@ function registerPathToRoot(refs, registry, strings) {
}
}
-function captureRegistry() {
- const strings = stringInterner();
- const stacks = stackRegistry(strings);
- const data = new Int32Array(0);
-
- const idField = 0;
- const typeField = 1;
- const sizeField = 2;
- const traceField = 3;
- const pathField = 4;
- const reactField = 5;
- const valueField = 6;
- const moduleField = 7;
- const numFields = 8;
-
- return {
- strings: strings,
- stacks: stacks,
- data: data,
- register: function registerCapture(captureId, capture) {
- // NB: capture.refs is potentially VERY large, so we try to avoid making
- // copies, even of iteration is a bit more annoying.
- let rowCount = 0;
- for (const id in capture.refs) { // eslint-disable-line no-unused-vars
- rowCount++;
- }
- for (const id in capture.markedBlocks) { // eslint-disable-line no-unused-vars
- rowCount++;
- }
- console.log(
- 'increasing row data from ' + (this.data.length * 4).toString() + 'B to ' +
- (this.data.length * 4 + rowCount * numFields * 4).toString() + 'B'
- );
- const newData = new Int32Array(this.data.length + rowCount * numFields);
- newData.set(data);
- let dataOffset = this.data.length;
- this.data = null;
-
- registerPathToRoot(capture.refs, this.stacks, this.strings);
- const internedCaptureId = this.strings.intern(captureId);
- const noneString = this.strings.intern('#none');
- const noneStack = this.stacks.insert(this.stacks.root, noneString);
- forEachRef(capture.refs, (visitor) => {
- const ref = visitor.getRef();
- const id = visitor.id;
- newData[dataOffset + idField] = parseInt(id, 16);
- newData[dataOffset + typeField] = this.strings.intern(ref.type);
- newData[dataOffset + sizeField] = ref.size;
- newData[dataOffset + traceField] = internedCaptureId;
- if (ref.rootPath === undefined) {
- newData[dataOffset + pathField] = noneStack.id;
- } else {
- newData[dataOffset + pathField] = ref.rootPath.id;
- }
- if (ref.reactTree === undefined) {
- newData[dataOffset + reactField] = noneStack.id;
- } else {
- newData[dataOffset + reactField] = ref.reactTree.id;
- }
- newData[dataOffset + valueField] = this.strings.intern(visitor.getValue());
- if (ref.module) {
- newData[dataOffset + moduleField] = this.strings.intern(ref.module);
- } else {
- newData[dataOffset + moduleField] = noneString;
- }
- dataOffset += numFields;
- });
- for (const id in capture.markedBlocks) {
- const block = capture.markedBlocks[id];
- newData[dataOffset + idField] = parseInt(id, 16);
- newData[dataOffset + typeField] = this.strings.intern('Marked Block Overhead');
- newData[dataOffset + sizeField] = block.capacity - block.size;
- newData[dataOffset + traceField] = internedCaptureId;
- newData[dataOffset + pathField] = noneStack.id;
- newData[dataOffset + reactField] = noneStack.id;
- newData[dataOffset + valueField] = this.strings.intern(
- 'capacity: ' + block.capacity +
- ', size: ' + block.size +
- ', granularity: ' + block.cellSize
- );
- newData[dataOffset + moduleField] = noneString;
- dataOffset += numFields;
- }
- this.data = newData;
- },
- getAggrow: function getAggrow() {
- const agStrings = this.strings;
- const agStacks = this.stacks.flatten();
- const agData = this.data;
- const agNumRows = agData.length / numFields;
- const ag = new aggrow(agNumRows);
-
- ag.addFieldExpander('Id',
- function getId(row) {
- let id = agData[row * numFields + idField];
- if (id < 0) {
- id += 0x100000000; // data is int32, id is uint32
- }
- return '0x' + id.toString(16);
- },
- function compareAddress(rowA, rowB) {
- return agData[rowA * numFields + idField] - agData[rowB * numFields + idField];
- });
-
- const typeExpander = ag.addFieldExpander('Type',
- function getType(row) { return agStrings.get(agData[row * numFields + typeField]); },
- function compareType(rowA, rowB) {
- return agData[rowA * numFields + typeField] - agData[rowB * numFields + typeField];
- });
-
- ag.addFieldExpander('Size',
- function getSize(row) { return agData[row * numFields + sizeField].toString(); },
- function compareSize(rowA, rowB) {
- return agData[rowA * numFields + sizeField] - agData[rowB * numFields + sizeField];
- });
-
- ag.addFieldExpander('Trace',
- function getSize(row) { return agStrings.get(agData[row * numFields + traceField]); },
- function compareSize(rowA, rowB) {
- return agData[rowA * numFields + traceField] - agData[rowB * numFields + traceField];
- });
-
- const pathExpander = ag.addCalleeStackExpander(
- 'Path',
- agStacks.maxDepth,
- function getStack(row) { return agStacks.get(agData[row * numFields + pathField]); },
- function getFrame(id) { return agStrings.get(id); },
- );
-
- const reactExpander = ag.addCalleeStackExpander(
- 'React Tree',
- agStacks.maxDepth,
- function getStack(row) { return agStacks.get(agData[row * numFields + reactField]); },
- function getFrame(id) { return agStrings.get(id); },
- );
-
- const valueExpander = ag.addFieldExpander('Value',
- function getValue(row) { return agStrings.get(agData[row * numFields + valueField]); },
- function compareValue(rowA, rowB) {
- return agData[rowA * numFields + valueField] - agData[rowB * numFields + valueField];
- });
-
- const moduleExpander = ag.addFieldExpander('Module',
- function getModule(row) { return agStrings.get(agData[row * numFields + moduleField]); },
- function compareModule(rowA, rowB) {
- return agData[rowA * numFields + moduleField] - agData[rowB * numFields + moduleField];
- });
-
- const sizeAggregator = ag.addAggregator('Size',
- function aggregateSize(indices) {
- let size = 0;
- for (let i = 0; i < indices.length; i++) {
- const row = indices[i];
- size += agData[row * numFields + sizeField];
- }
- return size;
- },
- function formatSize(value) { return value.toString(); },
- function sortSize(a, b) { return b - a; } );
-
- const countAggregator = ag.addAggregator('Count',
- function aggregateCount(indices) {
- return indices.length;
- },
- function formatCount(value) { return value.toString(); },
- function sortCount(a, b) { return b - a; } );
-
- ag.setActiveExpanders([
- pathExpander,
- reactExpander,
- moduleExpander,
- typeExpander,
- valueExpander,
- ]);
- ag.setActiveAggregators([sizeAggregator, countAggregator]);
- return ag;
- },
- };
+function registerCapture(data, captureId, capture, stacks, strings) {
+ // NB: capture.refs is potentially VERY large, so we try to avoid making
+ // copies, even if iteration is a bit more annoying.
+ let rowCount = 0;
+ for (const id in capture.refs) { // eslint-disable-line no-unused-vars
+ rowCount++;
+ }
+ for (const id in capture.markedBlocks) { // eslint-disable-line no-unused-vars
+ rowCount++;
+ }
+ const inserter = data.rowInserter(rowCount);
+ registerPathToRoot(capture.refs, stacks, strings);
+ const noneString = strings.intern('#none');
+ const noneStack = stacks.insert(stacks.root, noneString);
+ forEachRef(capture.refs, (visitor) => {
+ // want to data.append(value, value, value), not IDs
+ const ref = visitor.getRef();
+ const id = visitor.id;
+ inserter.insertRow(
+ parseInt(id, 16),
+ ref.type,
+ ref.size,
+ captureId,
+ ref.rootPath === undefined ? noneStack : ref.rootPath,
+ ref.reactTree === undefined ? noneStack : ref.reactTree,
+ visitor.getValue(),
+ ref.module === undefined ? '#none' : ref.module,
+ );
+ });
+ for (const id in capture.markedBlocks) {
+ const block = capture.markedBlocks[id];
+ inserter.insertRow(
+ parseInt(id, 16),
+ 'Marked Block Overhead',
+ block.capacity - block.size,
+ captureId,
+ noneStack,
+ noneStack,
+ 'capacity: ' + block.capacity + ', size: ' + block.size + ', granularity: ' + block.cellSize,
+ '#none',
+ );
+ }
+ inserter.done();
}
if (preLoadedCapture) {
- const r = new captureRegistry();
- r.register('trace', preLoadedCapture);
+ const strings = StringInterner();
+ const stacks = new StackRegistry();
+ const columns = [
+ { name: 'id', type: 'int' },
+ { name: 'type', type: 'string', strings: strings },
+ { name: 'size', type: 'int' },
+ { name: 'trace', type: 'string', strings: strings },
+ { name: 'path', type: 'stack', stacks: stacks },
+ { name: 'react', type: 'stack', stacks: stacks },
+ { name: 'value', type: 'string', strings: strings },
+ { name: 'module', type: 'string', strings: strings },
+ ];
+ const data = new AggrowData(columns);
+ registerCapture(data, 'trace', preLoadedCapture, stacks, strings);
preLoadedCapture = undefined; // let GG clean up the capture
- ReactDOM.render(, document.body);
+ const aggrow = new Aggrow(data);
+ aggrow.addPointerExpander('Id', 'id');
+ const typeExpander = aggrow.addStringExpander('Type', 'type');
+ aggrow.addNumberExpander('Size', 'size');
+ aggrow.addStringExpander('Trace', 'trace');
+ const pathExpander = aggrow.addStackExpander('Path', 'path', strings.get);
+ const reactExpander = aggrow.addStackExpander('React Tree', 'react', strings.get);
+ const valueExpander = aggrow.addStringExpander('Value', 'value');
+ const moduleExpander = aggrow.addStringExpander('Module', 'module');
+ aggrow.expander.setActiveExpanders([
+ pathExpander,
+ reactExpander,
+ moduleExpander,
+ typeExpander,
+ valueExpander,
+ ]);
+ const sizeAggregator = aggrow.addSumAggregator('Size', 'size');
+ const countAggregator = aggrow.addCountAggregator('Count');
+ aggrow.expander.setActiveAggregators([
+ sizeAggregator,
+ countAggregator,
+ ]);
+ ReactDOM.render(, document.body);
}
diff --git a/local-cli/server/middleware/heapCapture/src/table.js b/local-cli/server/middleware/heapCapture/src/table.js
index 9820e1b05..f8c0921e7 100644
--- a/local-cli/server/middleware/heapCapture/src/table.js
+++ b/local-cli/server/middleware/heapCapture/src/table.js
@@ -24,12 +24,14 @@ class Draggable extends React.Component { // eslint-disable-line no-unused-vars
render() {
const id = this.props.id;
- function dragStart(e) {
- e.dataTransfer.setData('text/plain', id);
- }
return React.cloneElement(
this.props.children,
- { draggable: 'true', onDragStart: dragStart }
+ {
+ draggable: 'true',
+ onDragStart: (e) => {
+ e.dataTransfer.setData('text', id);
+ },
+ }
);
}
}
@@ -45,23 +47,15 @@ class DropTarget extends React.Component { // eslint-disable-line no-unused-vars
render() {
const thisId = this.props.id;
- const dropFilter = this.props.dropFilter;
const dropAction = this.props.dropAction;
return React.cloneElement(
this.props.children,
{
- onDragOver: (e) => {
- const sourceId = e.dataTransfer.getData('text/plain');
- if (dropFilter(sourceId)) {
- e.preventDefault();
- }
- },
+ onDragOver: (e) => e.preventDefault(),
onDrop: (e) => {
- const sourceId = e.dataTransfer.getData('text/plain');
- if (dropFilter(sourceId)) {
- e.preventDefault();
- dropAction(sourceId, thisId);
- }
+ const sourceId = e.dataTransfer.getData('text');
+ e.preventDefault();
+ dropAction(sourceId, thisId);
},
}
);
@@ -71,7 +65,6 @@ class DropTarget extends React.Component { // eslint-disable-line no-unused-vars
DropTarget.propTypes = {
children: React.PropTypes.element.isRequired,
id: React.PropTypes.string.isRequired,
- dropFilter: React.PropTypes.func.isRequired,
dropAction: React.PropTypes.func.isRequired,
};
@@ -156,7 +149,6 @@ class TableHeader extends React.Component {
headers.push((
s.startsWith('aggregate')}
dropAction={this.props.dropAction}
>
s.startsWith('aggregate') || s.startsWith('expander')}
dropAction={this.props.dropAction}
>
{return true; }}
dropAction={this.props.dropAction}
>