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} >